{"cells":[{"metadata":{},"cell_type":"markdown","source":"# EDA CSV"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\nimport numpy as np \nimport pandas as pd \nimport gc\nimport os\nimport PIL\n\nfrom scipy import stats\nfrom multiprocessing import Pool\nfrom PIL import ImageOps, ImageFilter\nfrom tqdm import tqdm\npd.set_option(\"max_columns\",300)\npd.set_option(\"max_rows\",1103)\nfrom wordcloud import WordCloud\n\ntqdm.pandas()","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/imet-2019-fgvc6/train.csv')\ntrain_path = '../input/imet-2019-fgvc6/train/'\nlabel_df = pd.read_csv('../input/imet-2019-fgvc6/labels.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_names = label_df['attribute_name'].values\n\nnum_labels = np.zeros((df_train.shape[0],))\ntrain_labels = np.zeros((df_train.shape[0], len(label_names)))\n\nfor row_index, row in enumerate(df_train['attribute_ids']):\n    num_labels[row_index] = len(row.split())    \n    for label in row.split():\n        train_labels[row_index, int(label)] = 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"culture, tag, unknown = 0, 0, 0\n\nfor l in label_names:\n    if l[:3] == 'cul':\n        culture += 1\n    elif l[:3] == 'tag':\n        tag += 1\n    else:\n        unknown += 1\n        \nprint(f'Culture : {culture}')\nprint(f'Tag     : {tag}')\nprint(f'Unknown : {unknown}')\nprint(f'Total   : {culture + tag + unknown}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_df['is_culture'] = label_df['attribute_name'].apply(lambda x: 1 if 'culture' in x else 0)\nattribute_count = label_df['is_culture'].value_counts()\n\nax = sns.barplot(['Tag', 'Culture'], attribute_count.values, alpha=0.8)\nfor p in ax.patches:\n    ax.annotate(f'{p.get_height()}\\n{p.get_height() * 100 / label_df.shape[0]:.2f}%',\n                (p.get_x() + p.get_width()/2., p.get_height()), \n                ha='center', \n                va='center', \n                fontsize=12, \n                color='black',\n                xytext=(2,-20), \n                textcoords='offset points')\nplt.title('Culture/Tag')\nplt.xlabel('attribute type')\nplt.ylabel('Frequency')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_sum = np.sum(train_labels, axis=0)\n\nculture_sequence = label_sum[:398].argsort()[::-1]\ntag_sequence = label_sum[398:].argsort()[::-1]\n\nculture_labels = [label_names[x][9:] for x in culture_sequence]\nculture_counts = [label_sum[x] for x in culture_sequence]\n\ntag_labels = [label_names[x + 398][5:] for x in tag_sequence]\ntag_counts = [label_sum[x + 398] for x in tag_sequence]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(culture_labels)):\n    print(culture_labels[i],':',culture_counts[i])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.DataFrame({'Culture_label': culture_labels,'Culture_count': culture_counts})\ndf.to_csv('cutr_labe.csv',index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(tag_labels)):\n    print(tag_labels[i],':',tag_counts[i])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.DataFrame({'Tags_label': tag_labels,'Tags_count': tag_counts})\ndf.to_csv('tags_label.csv',index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(20,15))\n\nplt.subplot(1,2,1)\nax1 = sns.barplot(y=culture_labels[:20], x=culture_counts[:20], orient=\"h\")\nplt.title('Label Counts by Culture (Top 20)',fontsize=15)\nplt.xlim((0, max(culture_counts)*1.15))\nplt.yticks(fontsize=15)\n\nfor p in ax1.patches:\n    ax1.annotate(f'{int(p.get_width())}\\n{p.get_width() * 100 / df_train.shape[0]:.2f}%',\n                (p.get_width(), p.get_y() + p.get_height() / 2.), \n                ha='left', \n                va='center', \n                fontsize=12, \n                color='black',\n                xytext=(7,0), \n                textcoords='offset points')\n\nplt.subplot(1,2,2)    \nax2 = sns.barplot(y=tag_labels[:20], x=tag_counts[:20], orient=\"h\")\nplt.title('Label Counts by Tag (Top 20)',fontsize=15)\nplt.xlim((0, max(tag_counts)*1.15))\nplt.yticks(fontsize=15)\n\nfor p in ax2.patches:\n    ax2.annotate(f'{int(p.get_width())}\\n{p.get_width() * 100 / df_train.shape[0]:.2f}%',\n                (p.get_width(), p.get_y() + p.get_height() / 2.), \n                ha='left', \n                va='center', \n                fontsize=12, \n                color='black',\n                xytext=(7,0), \n                textcoords='offset points')\n\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(20,8))\n\nax = sns.countplot(num_labels)\nplt.xlabel('Number of Labels')\nplt.title('Number of Labels per Image', fontsize=20)\n\nfor p in ax.patches:\n    ax.annotate(f'{p.get_height() * 100 / df_train.shape[0]:.3f}%',\n            (p.get_x() + p.get_width() / 2., p.get_height()), \n            ha='center', \n            va='center', \n            fontsize=11, \n            color='black',\n            xytext=(0,7), \n            textcoords='offset points')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_attr_ohot = np.zeros((len(df_train), len(label_df)), dtype=int)\n\nfor idx, attr_arr in enumerate(df_train.attribute_ids.str.split(\" \").apply(lambda l: list(map(int, l))).values):\n    train_attr_ohot[idx, attr_arr] = 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"names_arr = label_df.attribute_name.values\ndf_train[\"attribute_names\"] = [\", \".join(names_arr[arr == 1]) for arr in train_attr_ohot]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train[\"attr_num\"] = train_attr_ohot.sum(axis=1)\ndf_train[\"culture_attr_num\"] = train_attr_ohot[:, :398].sum(axis=1)\ndf_train[\"tag_attr_num\"] = train_attr_ohot[:, 398:].sum(axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#for i in range(len(df_train[\"attribute_names\"])):\n#    print(df_train[\"attribute_names\"][i],':',df_train[\"culture_attr_num\"][i])","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(15, 10))\nfig.subplots_adjust(hspace=0.4)\nax2 = fig.add_subplot(3,1,2,)\nsns.countplot(df_train.culture_attr_num, ax=ax2)\nax2.set_title(\"number of 'culture' attributes each art has\")\nfor p in ax2.patches:\n    ax2.annotate(f'{p.get_height() * 100 / df_train.shape[0]:.3f}%',\n            (p.get_x() + p.get_width() / 2., p.get_height()), \n            ha='center', \n            va='center', \n            fontsize=11, \n            color='black',\n            xytext=(0,7), \n            textcoords='offset points')\nax3 = fig.add_subplot(3,1,3,)\nax3.set_title(\"number of 'tag' attributes each art has\")\nsns.countplot(df_train.tag_attr_num, ax=ax3)\nfor p in ax3.patches:\n    ax3.annotate(f'{p.get_height() * 100 / df_train.shape[0]:.3f}%',\n            (p.get_x() + p.get_width() / 2., p.get_height()), \n            ha='center', \n            va='center', \n            fontsize=11, \n            color='black',\n            xytext=(0,7), \n            textcoords='offset points')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# EDA by Visualize Images"},{"metadata":{},"cell_type":"markdown","source":"Example of images with tags"},{"metadata":{"trusted":true},"cell_type":"code","source":"from cv2 import cv2\ni = 1\ndf_train[\"attribute_ids\"]=df_train[\"attribute_ids\"].apply(lambda x:x.split(\" \"))\ndf_train[\"id\"]=df_train[\"id\"].apply(lambda x:x+\".png\")\nplt.figure(figsize=[30,30])\nfor img_name in os.listdir(\"../input/imet-2019-fgvc6/train/\")[5:10]:   \n    img = cv2.imread(\"../input/imet-2019-fgvc6/train/%s\" % img_name)[...,[2, 1, 0]]\n    plt.subplot(5, 1, i)\n    plt.imshow(img)\n    ids = df_train[df_train[\"id\"] == img_name][\"attribute_ids\"]\n    print(ids)\n    title_val = []\n    for tag_id in ids.values[0]:\n        att_name = label_df[label_df['attribute_id'].astype(str) == tag_id]['attribute_name'].values[0]\n        title_val.append(att_name)\n    plt.title(title_val)\n    i += 1\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Check duplicated images"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport numpy as np\nfrom PIL import Image\nimport pandas as pd\nimport hashlib","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def check_md5(fname):\n    hash_md5 = hashlib.md5()\n    with open(fname, \"rb\") as f:\n        for chunk in iter(lambda: f.read(4096), b\"\"):\n            hash_md5.update(chunk)\n    return hash_md5.hexdigest()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"file_names = []\npath_root = '../input/imet-2019-fgvc6/train/'\nfor filename in os.listdir(path_root)[0:20]:\n    file_names.append(check_md5(path_root+filename))\nprint(len(file_names))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"unit = np.unique(file_names,return_counts=True)\ncount = 0\nfor i in range(len(unit[1])):\n    if unit[1][i]>1:\n        count += 1\n        print('Duplicated Images')\nif count == 0:\n    print('NOT Duplicated Images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Padding image"},{"metadata":{"trusted":true},"cell_type":"code","source":"def padding_image(path_img):\n    image_old = Image.open(path_img)\n    width, height = image_old.size\n\n    if width > height:\n        distance_max = width\n        array = np.zeros([distance_max, distance_max, 3], dtype=np.uint8)\n        array.fill(0)\n        image_new = Image.fromarray(array)\n\n        xmin = 0\n        ymin = int((distance_max / 2) - (height / 2))\n        xmax = distance_max\n        ymax = int((distance_max / 2) + (height / 2))\n\n        image_new.paste(image_old, (xmin, ymin, xmax, ymax))\n        return image_new\n\n    elif width < height:\n        distance_max = height\n        array = np.zeros([distance_max, distance_max, 3], dtype=np.uint8)\n        array.fill(0)\n        image_new = Image.fromarray(array)\n\n        xmin = int((distance_max / 2) - (width / 2))\n        ymin = 0\n        xmax = int((distance_max / 2) + (width / 2))\n        ymax = distance_max\n\n        image_new.paste(image_old, (xmin, ymin, xmax, ymax))\n        return image_new\n\n    else:\n        return image_old","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import random\nrandom_filenames = random.choices(os.listdir(path_root), k=5)\nfor filename in random_filenames:\n    plt.imshow(np.array(Image.open(path_root+filename)))\n    plt.figure()\n    plt.imshow(padding_image(path_root+filename))\n    plt.figure()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import fastai\nfrom fastai.vision import *\nfastai.__version__","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Setup"},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH  = 126\nSIZE   = 250\npath = Path('../input/imet-2019-fgvc6/') # iMet data path","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls ../input/resnet50/","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Making pretrained weights work without needing to find the default filename\nfrom torch.utils import model_zoo\nPath('models').mkdir(exist_ok=True)\n!cp '../input/resnet50/resnet50.pth' 'models/'\ndef load_url(*args, **kwargs):\n    model_dir = Path('models')\n    filename  = 'resnet50.pth'\n    if not (model_dir/filename).is_file(): raise FileNotFoundError\n    return torch.load(model_dir/filename)\nmodel_zoo.load_url = load_url","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load train dataframe\ntrain_df = pd.read_csv(path/'train.csv')\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load labels dataframe\nlabels_df = pd.read_csv(path/'labels.csv')\nlabels_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load sample submission\ntest_df = pd.read_csv(path/'sample_submission.csv')\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Create data object using datablock API"},{"metadata":{"trusted":true},"cell_type":"code","source":"tfms = get_transforms(do_flip=True, flip_vert=False, max_rotate=0.10, max_zoom=1.5, max_warp=0.2, max_lighting=0.2,\n                     xtra_tfms=[(symmetric_warp(magnitude=(-0,0), p=0)),])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train, test = [ImageList.from_df(df, path=path, cols='id', folder=folder, suffix='.png') \n               for df, folder in zip([train_df, test_df], ['train', 'test'])]\ndata = (train.split_by_rand_pct(0.05, seed=42)\n        .label_from_df(cols='attribute_ids', label_delim=' ')\n        .add_test(test)\n        .transform(tfms, size=SIZE, resize_method=ResizeMethod.PAD, padding_mode='border',)\n        .databunch(path=Path('.'), bs=BATCH).normalize(imagenet_stats))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Create learner with pretrenet model and FocalLoss\nFor problems with high class imbalance Focal Loss is usually a better choice than the usual Cross Entropy Loss."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# Source: https://www.kaggle.com/c/human-protein-atlas-image-classification/discussion/78109\nclass FocalLoss(nn.Module):\n    def __init__(self, gamma=2):\n        super().__init__()\n        self.gamma = gamma\n\n    def forward(self, logit, target):\n        target = target.float()\n        max_val = (-logit).clamp(min=0)\n        loss = logit - logit * target + max_val + \\\n               ((-max_val).exp() + (-logit - max_val).exp()).log()\n\n        invprobs = F.logsigmoid(-logit * (target * 2.0 - 1.0))\n        loss = (invprobs * self.gamma).exp() * loss\n        if len(loss.size())==2:\n            loss = loss.sum(dim=1)\n        return loss.mean()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn = cnn_learner(data, base_arch=models.resnet50, loss_func=FocalLoss(), metrics=fbeta)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ls ../input","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!cp '../input/models2/stage-1.pth' 'models/'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def find_best_fixed_threshold(preds, targs, do_plot=True):\n    score = []\n    thrs = np.arange(0, 0.5, 0.01)\n    for thr in progress_bar(thrs):\n        score.append(fbeta(valid_preds[0],valid_preds[1], thresh=thr))\n    score = np.array(score)\n    pm = score.argmax()\n    best_thr, best_score = thrs[pm], score[pm].item()\n    print(f'thr={best_thr:.3f}', f'F2={best_score:.3f}')\n    if do_plot:\n        plt.plot(thrs, score)\n        plt.vlines(x=best_thr, ymin=score.min(), ymax=score.max())\n        plt.text(best_thr+0.03, best_score-0.01, f'$F_{2}=${best_score:.3f}', fontsize=14);\n        plt.show()\n    return best_thr\n\ni2c = np.array([[i, c] for c, i in learn.data.train_ds.y.c2i.items()]).astype(int) # indices to class number correspondence\n\ndef join_preds(preds, thr):\n    return [' '.join(i2c[np.where(t==1)[0],1].astype(str)) for t in (preds[0].sigmoid()>thr).long()]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.load('stage-1')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Validation predictions\nvalid_preds = learn.get_preds(DatasetType.Valid)\nbest_thr = find_best_fixed_threshold(*valid_preds)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Find a good learning rate\nlearn.lr_find()\nlearn.recorder.plot()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.unfreeze()\nlearn.fit_one_cycle(16, slice(1e-4,1e-3))\nlearn.freeze()\nlearn.save('stage-2', return_path=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Validation predictions\nvalid_preds = learn.get_preds(DatasetType.Valid)\nbest_thr = find_best_fixed_threshold(*valid_preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.recorder.plot()\nlearn.recorder.plot_losses()\nlearn.recorder.plot_metrics()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.export()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Get predictions"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test predictions\n#test_preds = learn.get_preds(DatasetType.Test)\n#test_df.attribute_ids = join_preds(test_preds, best_thr)\n#test_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#test_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## TTA"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Validation predictions with TTA\n#valid_preds = learn.TTA(ds_type=DatasetType.Valid)\n#best_thr = find_best_fixed_threshold(*valid_preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test predictions with TTA\ntest_preds = learn.TTA(ds_type=DatasetType.Test)\ntest_df.attribute_ids = join_preds(test_preds, best_thr)\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.to_csv('submission.csv', index=False) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Find a good learning rate\nlearn.lr_find()\nlearn.recorder.plot()","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"nbformat":4,"nbformat_minor":1}