{"cells":[{"metadata":{},"cell_type":"markdown","source":"##### For the first time, load data"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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\n\n# You can write up to 5GB 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\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        if filename.endswith('.jpg'):\n            break\n        print(os.path.join(dirname, filename))\n        \ndf = pd.read_csv('../input/herbarium-2020-fgvc7/sample_submission.csv')\nimport json,codecs\nwith codecs.open(\"../input/herbarium-2020-fgvc7/nybg2020/train/metadata.json\", 'r',\n                 encoding='utf-8', errors='ignore') as f:\n    train_meta = json.load(f)\n    \nwith codecs.open(\"../input/herbarium-2020-fgvc7/nybg2020/test/metadata.json\", 'r',\n                 encoding='utf-8', errors='ignore') as f:\n    test_meta = json.load(f)\n\ntrain_df = pd.DataFrame(train_meta['annotations'])\ntrain_cat = pd.DataFrame(train_meta['categories'])\ntrain_cat.columns =['family','genus','category_id','category_name']\ntrain_img = pd.DataFrame(train_meta['images'])\ntrain_img.columns = ['file_name', 'height', 'image_id', 'license', 'width']\ntrain_reg = pd.DataFrame(train_meta['regions'])\ntrain_reg.columns = ['region_id', 'region_name']\ntrain_df = train_df.merge(train_cat, on='category_id', how='outer')\ntrain_df = train_df.merge(train_img, on='image_id', how='outer')\ntrain_df = train_df.merge(train_reg, on='region_id', how='outer')\nna = train_df.file_name.isna()\n#display(na) #各行をチェックしNaNならTrueを返す\n\nkeep = [x for x in range(train_df.shape[0]) if not na[x]] \ntrain_df = train_df.iloc[keep]\n\ndtypes = ['int32', 'int32', 'int32', 'int32', 'object', 'object', 'object', 'object', 'int32', 'int32', 'int32', 'object']\nfor n, col in enumerate(train_df.columns): #n -> 行数 col -> Index\n    train_df[col] = train_df[col].astype(dtypes[n]) #型の変換\n    \ntest_df = pd.DataFrame(test_meta['images'])\ntest_df.columns = ['file_name', 'height', 'image_id', 'license', 'width']\n\ntrain_df.to_csv('full_train_data.csv', index=False)\ntest_df.to_csv('full_test_data.csv', index=False)\n\n# print(\"Total Unique Values for each columns:\")\n# print(\"{0:10s} \\t {1:10d}\".format('train_df', len(train_df)))\n\n#Data Explpration\n\nfor col in train_df.columns:\n    print(\"{0:10s} \\t {1:10d}\".format(col, len(train_df[col].unique())))\n\nfamily = train_df[['family', 'genus', 'category_name']].groupby(['family', 'genus']).count()\n\nprint(\"Sequence End\")\nprint(train_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Model Creation"},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow.keras as keras\nfrom tensorflow.keras.models import Model,Sequential\nfrom tensorflow.keras.layers import Dense, Dropout, Conv2D, MaxPool2D, Flatten, BatchNormalization, Input, concatenate,add,Add\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.utils import plot_model\nfrom sklearn.model_selection import train_test_split as tts\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### This is refarence model"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\n## Model function\ndef fg_model(shape,lr=0.001):\n    i = Input(shape)\n    \n    x = Conv2D(3,(3,3),activation='relu',padding='same',kernel_initializer='he_normal')(i)\n    x = Conv2D(3,(5,5),activation='relu',padding='same',kernel_initializer='he_normal')(x)\n    x = MaxPool2D(pool_size=(3,3),strides=(3,3))(x)\n    x = Dropout(0.5)(x)\n    x = Conv2D(16,(5,5),activation='relu',padding='same',kernel_initializer='he_normal')(x)\n    x = MaxPool2D(pool_size=(5,5),strides=(5,5))(x)\n    x = BatchNormalization()(x)\n    x = Dropout(0.5)(x)\n    x = Flatten()(x)\n    \n    o1 = Dense(310,activation='softmax',name='family',kernel_initializer='he_normal')(x)\n    \n    o2 = concatenate([o1,x])\n    o2 = Dense(3678,activation='softmax',name='genus',kernel_initializer='he_normal')(o2)\n    \n    o3 = concatenate([o1,o2,x])\n    o3 = Dense(32094,activation='softmax',name='category_id',kernel_initializer='he_normal')(o3)\n    \n    x = Model(inputs=i, outputs=[o1,o2,o3])\n    \n    opt = Adam(lr=lr,amsgrad=True)\n    x.compile(optimizer=opt,loss=['sparse_categorical_crossentropy', \n                                   'sparse_categorical_crossentropy', \n                                   'sparse_categorical_crossentropy'],\n                 metrics=['accuracy'])\n    \n    return x\n\nmodel = fg_model((120,120,3))\nmodel.summary()\nplot_model(model, to_file='full_model_plot.png',show_shapes=True,show_layer_names=True)\n\"\"\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## ニューラルネットワークにおける重みの初期値\n## Ref\n## https://ai-trend.jp/basic-study/neural-network/initial_value/#Xivier\n## sigmoid関数やtanh関数を活性化関数として用いる時、このXavierの初期値を用いるとよい\n\nin_out_size = (120*120) + 3 #We will resize the image to 120*120 and we have 3 outputs\ndef xavier(shape, dtype=None):\n    return np.random.rand(*shape)*np.sqrt(1/in_out_size)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### This is my model"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nfunction imformation\nname:fg_model\nargment:\n1: shape -> (120,120,3)\n2: lr -> learning rate 0.001 is default value\n\nThis model was based on dl4us lesson2_sec4\n\"\"\"\ndef fg_model(shape,lr=0.001):\n\n    i = Input(shape)\n\n    x = (Conv2D(3, kernel_size=(3, 3), activation='relu',padding='same',\n                     kernel_initializer='xavier'))(i) #120*120*3 -> 120*120*5\n    #x = (MaxPool2D(pool_size=(2, 2)))(x) # 120*120*5 -> 60*60*5\n    x = (Conv2D(3, kernel_size=(5, 5), activation='relu',padding='same',\n                     kernel_initializer='xavier'))(x) # 60*60*5 -> 60*60*5\n    \n    # 勾配消失の対策(深層学習の時の層が深いときに起こる問題)\n    # x = add([x,i])\n    # 勾配消失の終了\n    \n    x = (MaxPool2D(pool_size=(3, 3),strides=(3,3)))(x) #60*60*5 -> 30*30*5\n    x = BatchNormalization()(x)\n    x = Dropout(0.5)(x)\n    x = Conv2D(16, (5, 5), activation='relu', padding='same', kernel_initializer=xavier)(x)\n    x = MaxPool2D(pool_size=(5, 5), strides=(5,5))(x)\n    x = BatchNormalization()(x)\n    x = Dropout(0.5)(x)\n    x = (Flatten())(x) #30*30*5 -> 4500\n    #x = (Dense(600, activation='relu', \n    #                kernel_initializer='he_normal'))(x)\n    #x = (Dense(32094, activation='softmax'))(x) # category_name \t      32093\n\n    o1 = Dense(310,activation='softmax',name='family',kernel_initializer='xavier')(x)\n    o2 = concatenate([o1, x])\n    o2 = Dense(3678, activation='softmax', name='genus', kernel_initializer='xavier')(o2)\n    o3 = concatenate([o1, o2, x])\n    o3 = Dense(32094, activation='softmax',name='category_id', kernel_initializer='xavier')(o3)\n    y = Model(inputs=i,outputs=[o1,o2,o3])\n    opt = Adam(lr=lr, amsgrad=True)\n    y.compile(\n        #loss=keras.losses.sparse_categorical_crossentropy,\n        loss=['sparse_categorical_crossentropy', \n               'sparse_categorical_crossentropy', \n               'sparse_categorical_crossentropy'],\n        optimizer=opt,\n        metrics=['accuracy']\n    )\n              \n    return y\n              \nmodel = fg_model((120,120,3))\nmodel.summary()\nplot_model(model, to_file='full_model_plot.png',show_shapes=True,show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data Generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\ndatagen = ImageDataGenerator(featurewise_center=False,\n                                      featurewise_std_normalization=False,\n                                      rotation_range=180,\n                                      width_shift_range=0.1,\n                                      height_shift_range=0.1,\n                                      zoom_range=0.2)\n\n\"\"\"\nImageDataGenerator -> 画像データの角度を変えたり、移動・回転させたりすることのできる亜種画像が生成できる\n\n\n\"\"\"\ndisplay(datagen)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"m = train_df[['file_name','family','genus','category_id']]\ndisplay(m)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#m = train_df[['file_name','family','genus','category_id']]\n## family genusが文字列となっているので数値に置き換える\nfam = m.family.unique().tolist()\nm.family = m.family.map(lambda x:fam.index(x))\ngen = m.genus.unique().tolist()\nm.genus = m.genus.map(lambda x:gen.index(x))\ndisplay(m)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Train"},{"metadata":{},"cell_type":"markdown","source":"#### This train is refarence code"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\ntrain,verif = tts(m,test_size=0.2,shuffle=True,random_state=17)\ntrain = train[:40000]\nverif = verif[:10000]\nshape = (120,120,3)\nepochs = 2\nbatch_size = 32\n\nmodel = fg_model(shape,0.007)\n\nfor layers in model.layers:\n    if layers.name == 'genus' or layers.name == 'category_id':\n        layers.trainable = False\n\n#Train Family for 2 epochs\nmodel.fit_generator(train_datagen.flow_from_dataframe(dataframe=train,\n                                                      directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                                                      x_col=\"file_name\",\n                                                      y_col=[\"family\", \"genus\", \"category_id\"],\n                                                      target_size=(120, 120),\n                                                      batch_size=batch_size,\n                                                      class_mode='multi_output'),\n                    validation_data=train_datagen.flow_from_dataframe(\n                        dataframe=verif,\n                        directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                        x_col=\"file_name\",\n                        y_col=[\"family\", \"genus\", \"category_id\"],\n                        target_size=(120, 120),\n                        batch_size=batch_size,\n                        class_mode='multi_output'),\n                    epochs=epochs,\n                    steps_per_epoch=len(train)//batch_size,\n                    validation_steps=len(verif)//batch_size,\n                    verbose=1,\n                    workers=8,\n                    use_multiprocessing=False)\n\n#Reshuffle the inputs\ntrain, verif = tts(m, test_size=0.2, shuffle=True, random_state=17)\ntrain = train[:40000]\nverif = verif[:10000]\n\n#Make the Genus layer Trainable\nfor layers in model.layers:\n    if layers.name == 'genus':\n        layers.trainable = True\n        \n#Train Family and Genus for 2 epochs\nmodel.fit_generator(train_datagen.flow_from_dataframe(dataframe=train,\n                                                      directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                                                      x_col=\"file_name\",\n                                                      y_col=[\"family\", \"genus\", \"category_id\"],\n                                                      target_size=(120, 120),\n                                                      batch_size=batch_size,\n                                                      class_mode='multi_output'),\n                    validation_data=train_datagen.flow_from_dataframe(\n                        dataframe=verif,\n                        directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                        x_col=\"file_name\",\n                        y_col=[\"family\", \"genus\", \"category_id\"],\n                        target_size=(120, 120),\n                        batch_size=batch_size,\n                        class_mode='multi_output'),\n                    epochs=epochs,\n                    steps_per_epoch=len(train)//batch_size,\n                    validation_steps=len(verif)//batch_size,\n                    verbose=1,\n                    workers=8,\n                    use_multiprocessing=False)\n\n#Reshuffle the inputs\ntrain, verif = tts(m, test_size=0.2, shuffle=True, random_state=17)\ntrain = train[:40000]\nverif = verif[:10000]\n\n#Make the category_id layer Trainable\nfor layers in model.layers:\n    if layers.name == 'category_id':\n        layers.trainable = True\n        \n#Train them all for 2 epochs\nmodel.fit_generator(train_datagen.flow_from_dataframe(dataframe=train,\n                                                      directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                                                      x_col=\"file_name\",\n                                                      y_col=[\"family\", \"genus\", \"category_id\"],\n                                                      target_size=(120, 120),\n                                                      batch_size=batch_size,\n                                                      class_mode='multi_output'),\n                    validation_data=train_datagen.flow_from_dataframe(\n                        dataframe=verif,\n                        directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                        x_col=\"file_name\",\n                        y_col=[\"family\", \"genus\", \"category_id\"],\n                        target_size=(120, 120),\n                        batch_size=batch_size,\n                        class_mode='multi_output'),\n                    epochs=epochs,\n                    steps_per_epoch=len(train)//batch_size,\n                    validation_steps=len(verif)//batch_size,\n                    verbose=1,\n                    workers=8,\n                    use_multiprocessing=False)\n\"\"\"\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### This train is my code"},{"metadata":{"trusted":true},"cell_type":"code","source":"# 一回分けてみてもいいかもしれない\n# fit_generatorの引数をそれぞれ説明する\n# fit_generator(generator, steps_per_epoch=None, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False, shuffle=True, initial_epoch=0)\n# generator -> バッチ毎に生成されたデータ(訓練用のデータとして使用)\n# validation_data -> 検証用データ\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train, Testようにそれぞれデータの用意\ntrain,test = tts(m,test_size=0.2,shuffle=True,random_state=17)\ntrain = train[:40000]\ntest = test[:10000]\nshape = (120,120,3)\nepochs = 3\nbatch_size = 32\n\nmodel = fg_model(shape,0.001)\n\nfor layer in model.layers:\n    layer.trainable = True\n\n# model.fit_generator(datagen.flow(x_train, y_train, batch_size=100),\n#                     steps_per_epoch=x_train.shape[0] // 100, epochs=30, validation_data=(x_valid, y_valid))\n\n# refarence URL about keras flow_from_dataframe\n# https://keras.io/ja/preprocessing/image/\n\n# refarence URL about validation_data\n# https://keras.io/ja/models/model/\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_generator = datagen.flow_from_dataframe(\n                        dataframe=train,\n                        directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                        x_col=\"file_name\",\n                        y_col=[\"family\", \"genus\", \"category_id\"],\n                        target_size=(120,120),\n                        batch_size=batch_size,\n                        class_mode='multi_output') #default\n                                                \n\ndata_validation = datagen.flow_from_dataframe(\n                        dataframe=test,\n                        directory='../input/herbarium-2020-fgvc7/nybg2020/train/',\n                        x_col=\"file_name\",\n                        y_col=[\"family\", \"genus\", \"category_id\"],\n                        target_size=(120, 120),\n                        batch_size=batch_size,\n                        class_mode='multi_output')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.fit_generator(generator=data_generator,validation_data=data_validation,steps_per_epoch=len(train)//batch_size,\n                       epochs=epochs,validation_steps=len(test)//batch_size,verbose=1,use_multiprocessing=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":""},{"metadata":{"trusted":true},"cell_type":"code","source":"# モデルの評価\nscore = model.evaluate(test.x_col, test.y_col,verbose=0)\nprint('Test Data loss:', score[0])\nprint('Test Data accuracy:', score[1])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Predict"},{"metadata":{"trusted":true},"cell_type":"code","source":"# This is same as refarence code\nbatch_size = 32\ntest_datagen = ImageDataGenerator(featurewise_center=False,\n                                  featurewise_std_normalization=False)\n\ngenerator = test_datagen.flow_from_dataframe(\n        dataframe = test_df.iloc[:10000], #Limiting the test to the first 10,000 items\n        directory = '../input/herbarium-2020-fgvc7/nybg2020/test/',\n        x_col = 'file_name',\n        target_size=(120, 120),\n        batch_size=batch_size,\n        class_mode=None,  # only data, no labels\n        shuffle=False)\n\nfamily, genus, category = model.predict_generator(generator, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"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":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"raw","source":""},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}