{"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":"import os\nimport json\nimport numpy as np\nimport pandas as pd\n\nfrom tensorflow.keras.utils import load_img, img_to_array\n\nimport tensorflow_addons as tfa\n\nfrom tensorflow.keras.models import Model\n\nfrom tensorflow.keras.layers import Input\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.layers import Conv2D\nfrom tensorflow.keras.layers import MaxPooling2D, AveragePooling2D\nfrom tensorflow.keras.layers import BatchNormalization\nfrom tensorflow.keras.layers import concatenate\nfrom tensorflow.keras.layers import Dropout\n\nfrom tensorflow.keras.activations import relu, softmax\nfrom tensorflow.keras.losses import categorical_crossentropy\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-03-10T09:21:34.906633Z","iopub.execute_input":"2022-03-10T09:21:34.906963Z","iopub.status.idle":"2022-03-10T09:21:34.917002Z","shell.execute_reply.started":"2022-03-10T09:21:34.906927Z","shell.execute_reply":"2022-03-10T09:21:34.915938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('../input/herbarium-2022-fgvc9/train_metadata.json', 'r') as meta_file:\n    train_meta = json.load(meta_file)","metadata":{"execution":{"iopub.status.busy":"2022-03-10T03:48:59.672845Z","iopub.execute_input":"2022-03-10T03:48:59.673243Z","iopub.status.idle":"2022-03-10T03:49:14.681109Z","shell.execute_reply.started":"2022-03-10T03:48:59.673213Z","shell.execute_reply":"2022-03-10T03:49:14.680471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# see what are the keys in metadata collection\ntrain_meta.keys()","metadata":{"execution":{"iopub.status.busy":"2022-03-10T03:49:14.682284Z","iopub.execute_input":"2022-03-10T03:49:14.682622Z","iopub.status.idle":"2022-03-10T03:49:14.690497Z","shell.execute_reply.started":"2022-03-10T03:49:14.682595Z","shell.execute_reply":"2022-03-10T03:49:14.689675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# see how many images to train\nlen(train_meta['annotations']), len(train_meta['images']), len(train_meta['categories']), len(\n    train_meta['genera']), len(train_meta['institutions']), len(train_meta['distances']), len(\n    train_meta['license'])","metadata":{"execution":{"iopub.status.busy":"2022-03-10T03:49:14.691865Z","iopub.execute_input":"2022-03-10T03:49:14.692597Z","iopub.status.idle":"2022-03-10T03:49:14.706437Z","shell.execute_reply.started":"2022-03-10T03:49:14.692515Z","shell.execute_reply":"2022-03-10T03:49:14.70562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_meta['annotations'][0],train_meta['images'][0],train_meta['categories'][0],train_meta['genera'][0],train_meta['institutions'][0],train_meta['distances'][0],train_meta['license'][0]","metadata":{"execution":{"iopub.status.busy":"2022-03-10T03:49:14.708312Z","iopub.execute_input":"2022-03-10T03:49:14.708599Z","iopub.status.idle":"2022-03-10T03:49:14.720176Z","shell.execute_reply.started":"2022-03-10T03:49:14.708569Z","shell.execute_reply":"2022-03-10T03:49:14.719291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_meta['annotations'][:10]","metadata":{"execution":{"iopub.status.busy":"2022-03-10T03:49:14.723133Z","iopub.execute_input":"2022-03-10T03:49:14.723567Z","iopub.status.idle":"2022-03-10T03:49:14.733315Z","shell.execute_reply.started":"2022-03-10T03:49:14.72352Z","shell.execute_reply":"2022-03-10T03:49:14.732751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# v-2 get average width and height\n\nfor i in range(len(train_meta['images'])):\n    category = train_meta['annotations'][i]['category_id']\n    file_path = train_meta['images'][i]['file_name']\n    img = load_img(os.path.join('../input/herbarium-2022-fgvc9/train_images', file_path), target_size=(334, 228))\n    dst_path = os.path.join('train', str(category), f\"{train_meta['images'][i]['image_id']}.jpg\")\n\n    if not os.path.isdir('train'):\n        os.mkdir('train')\n\n    if not os.path.isdir(f'train/{category}'):\n        os.mkdir(os.path.join(f'train/{category}'))\n\n    # save image to destination\n    img.save(dst_path)\n\n    print(f\"steps: {i + 1}/{len(train_meta['images'])} \", end='\\r')","metadata":{"execution":{"iopub.status.busy":"2022-03-10T03:49:14.734563Z","iopub.execute_input":"2022-03-10T03:49:14.735494Z","iopub.status.idle":"2022-03-10T09:15:27.850731Z","shell.execute_reply.started":"2022-03-10T03:49:14.735449Z","shell.execute_reply":"2022-03-10T09:15:27.847469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def inception(x, filters, projection, name=None):\n    f_1x1, f_3x3, f_3x3_reduce, f_5x5, f_5x5_reduce = filters\n    x1 = Conv2D(filters=f_1x1, kernel_size=(1, 1), strides=(1, 1), activation=relu, padding='same')(x)\n    x3_reducer = Conv2D(filters=f_3x3_reduce, kernel_size=(1, 1), strides=(1, 1), activation=relu, padding='same')(x)\n    x5_reducer = Conv2D(filters=f_5x5_reduce, kernel_size=(1, 1), strides=(1, 1), activation=relu, padding='same')(x)\n    pool = MaxPooling2D(pool_size=(3, 3), strides=(1, 1), padding='same')(x)\n\n    x3 = Conv2D(filters=f_3x3, kernel_size=(3, 3), strides=(1, 1), activation=relu, padding='same')(x3_reducer)\n    x5 = Conv2D(filters=f_5x5, kernel_size=(5, 5), strides=(1, 1), activation=relu, padding='same')(x5_reducer)\n    proj = Conv2D(filters=projection, kernel_size=(1, 1), strides=(1, 1), activation=relu, padding='same')(pool)\n\n    x = concatenate([x1, x3, x5, proj], axis=3, name=name)\n\n    return x","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def model_builder(shape, classes):\n    input_layer = Input(shape=shape)\n    x = Conv2D(filters=64, kernel_size=(7, 7), strides=(2, 2), activation=relu, padding='same')(input_layer)\n    x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='same')(x)\n    x = BatchNormalization()(x)\n    x = Conv2D(filters=64, kernel_size=(1, 1), strides=(1, 1), activation=relu, padding='same')(x)\n    x = Conv2D(filters=192, kernel_size=(3, 3), strides=(1, 1), activation=relu, padding='same')(x)\n    x = BatchNormalization()(x)\n    x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='same')(x)\n    x = inception(x, [64, 128, 96, 32, 16], projection=32, name='inception_3a')\n    x = inception(x, [128, 192, 128, 96, 32], projection=64, name='inception_3b')\n    x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='same')(x)\n    x = inception(x, [192, 208, 96, 48, 16], projection=64, name='inception_4a')\n    x = inception(x, [160, 224, 112, 64, 24], projection=64, name='inception_4b')\n    x = inception(x, [128, 256, 128, 64, 24], projection=64, name='inception_4c')\n    x = inception(x, [112, 288, 144, 64, 32], projection=64, name='inception_4d')\n    x = inception(x, [256, 320, 160, 128, 32], projection=128, name='inception_4e')\n    x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='same')(x)\n    x = inception(x, [256, 320, 160, 128, 32], projection=128, name='inception_5a')\n    x = inception(x, [384, 384, 192, 128, 48], projection=128, name='inception_5b')\n    x = AveragePooling2D(pool_size=(7, 7), strides=(1, 1))(x)\n    x = Dropout(rate=0.4)(x)\n    output_layer = Dense(units=classes, activation=softmax)(x)\n\n    model = Model(input_layer, output_layer)\n    model.compile(optimizer=Adam(), loss=categorical_crossentropy,\n                  metrics=['accuracy', tfa.metrics.F1Score(num_classes=classes, threshold=0.5)])\n    model.summary()\n\n    return model","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classes = len(os.listdir('train'))\nclasses","metadata":{"execution":{"iopub.status.busy":"2022-03-10T09:22:32.027548Z","iopub.execute_input":"2022-03-10T09:22:32.028146Z","iopub.status.idle":"2022-03-10T09:22:32.044609Z","shell.execute_reply.started":"2022-03-10T09:22:32.028106Z","shell.execute_reply":"2022-03-10T09:22:32.043625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = ImageDataGenerator(rescale=1 / 255.,\n                                     validation_split=0.3)\n\ntrain_set = train_generator.flow_from_directory('train',\n                                                target_size=(224, 224),\n                                                batch_size=128,\n                                                subset='training')\nval_set = train_generator.flow_from_directory('train',\n                                              target_size=(224, 224),\n                                              batch_size=128,\n                                              subset='validation')","metadata":{"execution":{"iopub.status.busy":"2022-03-10T09:22:54.386589Z","iopub.execute_input":"2022-03-10T09:22:54.387039Z","iopub.status.idle":"2022-03-10T09:23:56.726345Z","shell.execute_reply.started":"2022-03-10T09:22:54.387006Z","shell.execute_reply":"2022-03-10T09:23:56.725617Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = model_builder((224, 224, 3), classes)","metadata":{"execution":{"iopub.status.busy":"2022-03-10T09:24:12.608576Z","iopub.execute_input":"2022-03-10T09:24:12.608886Z","iopub.status.idle":"2022-03-10T09:24:13.821699Z","shell.execute_reply.started":"2022-03-10T09:24:12.608846Z","shell.execute_reply":"2022-03-10T09:24:13.821056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"early_stop = EarlyStopping(monitor='val_loss',\n                           patience='10',\n                           restore_best_weights=True)\n\nreduce_lr = ReduceLROnPlateau(monitor='val_loss',\n                              factor=0.1,\n                              patience=10)","metadata":{"execution":{"iopub.status.busy":"2022-03-10T09:24:38.467589Z","iopub.execute_input":"2022-03-10T09:24:38.467879Z","iopub.status.idle":"2022-03-10T09:24:38.474872Z","shell.execute_reply.started":"2022-03-10T09:24:38.467849Z","shell.execute_reply":"2022-03-10T09:24:38.473772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.fit(x=train_set,\n          validation_data=val_set,\n          epochs=25,\n          steps_per_epoch=50,\n          validation_steps=100,\n          batch_size=128,\n          validation_batch_size=128,\n          callbacks=[early_stop, reduce_lr])","metadata":{"execution":{"iopub.status.busy":"2022-03-10T09:24:42.317262Z","iopub.execute_input":"2022-03-10T09:24:42.317588Z","iopub.status.idle":"2022-03-10T09:24:43.860799Z","shell.execute_reply.started":"2022-03-10T09:24:42.317555Z","shell.execute_reply":"2022-03-10T09:24:43.859315Z"},"trusted":true},"execution_count":null,"outputs":[]}]}