{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\nimport matplotlib.pyplot as plt\nfrom collections import Counter\nfrom fastai.vision.all import *\nimport albumentations\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path='/kaggle/input/expertclass2/'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\ntrain_df = pd.read_csv(\"/kaggle/input/expertclass2/train_data.csv\", sep=',')\ntrain_df = pd.concat([train_df['emotion'],train_df['pixels'].str.split(' ', expand=True)], axis=1)\ntest_df = pd.read_csv(\"/kaggle/input/expertclass2/test_data.csv\", sep=',')\ntest_df = pd.concat([test_df['pixels'].str.split(' ', expand=True)], axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = pd.read_csv(\"/kaggle/input/expertclass2/example_submission.csv\", sep=',')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = train_df.astype(np.uint8)\ntrain_df.head(1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = test_df.astype(np.uint8)\ntest_df.head(1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Train_df shape : {train_df.shape}')\nprint(f'Test_df shape  : {test_df.shape}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def split_df(df):\n    '''return a tuple (X, y) \n    \n        X : the training inputs which is in (samples, height, width, channel) shape\n        y : the label which is flatten\n    '''\n    if 'emotion' in df.columns:\n        y = df['emotion'].values.flatten()\n        X = df.drop('emotion', axis=1).values\n    else:\n        X = df.values\n        y = None\n        \n    X = X.reshape(X.shape[0], 48, 48)\n#     X = np.stack((X,) * 3, axis=-1)\n    return (X,y)\n\nclass AlbumentationsTransform(RandTransform):\n    \"A transform handler for multiple `Albumentation` transforms\"\n    split_idx,order=None,2\n    def __init__(self, train_aug, valid_aug): store_attr()\n    \n    def before_call(self, b, split_idx):\n        self.idx = split_idx\n    \n    def encodes(self, img: PILImage):\n        if self.idx == 0:\n            aug_img = self.train_aug(image=np.array(img))['image']\n        else:\n            aug_img = self.valid_aug(image=np.array(img))['image']\n        return PILImage.create(aug_img)\n            \ndef get_train_aug(): return albumentations.Compose([\n            albumentations.Transpose(p=0.2),\n            albumentations.VerticalFlip(p=0.2),\n            albumentations.ShiftScaleRotate(p=0.2),\n            albumentations.CoarseDropout(p=0.5),\n            albumentations.Cutout(p=0.5)\n])\n\ndef get_valid_aug(): return albumentations.Compose([\n    albumentations.Resize(224,224)\n], p=1.)\nitem_tfms = [Resize(224)]#, AlbumentationsTransform(get_train_aug(), get_valid_aug())]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train, y_train = split_df(train_df)\nX_test, _   = split_df(test_df)\n# X_train = np.stack((X_train,) * 3, axis=-1)\n# X_test  = np.stack((X_test,) * 3, axis=-1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Train set shape : {X_train.shape, y_train.shape}')\nprint(f'Test  set shape  : {X_test.shape}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"emotions = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"index = 3\nplt.imshow(X_train[index,], cmap='gray')\nplt.title(emotions[y_train[index]]);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Thanks to nghiaho12 (http://nghiaho.com/?p=2741)\n\ndef make_dataloaders_from_numpy_data(image, label):\n    def pass_index(idx):\n        return idx\n\n    def get_x(i):\n        # NOTE: This is a grayscale image that appears to just work with a network expecting RGB.\n        # I suspect this is due to tensor broadcasting rules.\n        return image[i]\n\n    def get_y(i):\n        return label[i]\n\n    dblock = DataBlock(\n        blocks=(ImageBlock, CategoryBlock),\n        get_items=pass_index,\n#         item_tfms=Resize(224),\n        batch_tfms=aug_transforms(size=224),\n        get_x=get_x,\n        get_y=get_y)\n\n    # pass in a list of index\n    num_images = image.shape[0]\n    dls = dblock.dataloaders(list(range(num_images)), valid_pct=0.2, seed=42)\n\n    return dls\n\ndls = make_dataloaders_from_numpy_data(X_train, y_train)\n\n# sanity check\ndls.train.show_batch(max_n=9, cmap='gray')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn = cnn_learner(dls,\n                    models.resnet34,\n                    metrics=accuracy,\n                    pretrained=False,\n                    n_in=1 # 1 channel - grayscale images\n                   )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.unfreeze()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr_min, lr_step = learn.lr_find()\nprint(lr_min, lr_step)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.fit_one_cycle(50, lr_max=lr_min*1.1, cbs=[EarlyStoppingCallback(patience=5, monitor='accuracy')])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.show_results(cmap='gray')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_interp = ClassificationInterpretation.from_learner(learn)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_interp.plot_top_losses(9, figsize=(15,10), cmap='gray')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_interp.plot_confusion_matrix()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.save('fer_model_resnet34')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# predict and submit\n# learn.predict()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions, *_ = learn.get_preds(dl=dls.test_dl(X_test))\nlabels = np.argmax(predictions, 1)\nCounter(labels.cpu().detach().numpy())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Test Time Augmentation","metadata":{}},{"cell_type":"code","source":"tta, *_ = learn.tta(dl=dls.test_dl(X_test), use_max=True)\nlabels_tta = np.argmax(tta, 1)\nCounter(labels_tta.cpu().detach().numpy())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Submission","metadata":{}},{"cell_type":"code","source":"submission_df['Emotion'] = labels_tta\nsubmission_df.to_csv(\"submission.csv\", index=False)\nsubmission_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}