{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# 自分用。\n# ただ誰かの理解の助けになればと思い公開します。\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport zipfile\n\nwith zipfile.ZipFile('../input/dogs-vs-cats/train.zip', 'r') as Z:\n    Z.extractall('.')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport random\nfrom keras.preprocessing.image import load_img\n\nfilenames = os.listdir('./train/')\nfile = random.choice(filenames)\nimg = load_img('./train/' + file)\nplt.imshow(img)\nplt.axis('off')\n\nprint('Img size: {},\\nImg channel: {}'.format(img.size, img.mode))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"categories = []\n\nfor filename in filenames:\n    if 'dog' in filename:\n        categories.append('dog')\n    else:\n        categories.append('cat')\n        \ndf = pd.DataFrame({\n    'filenames': filenames,\n    'categories':categories\n})\n\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom keras.preprocessing.image import ImageDataGenerator\n\ntrain_df, validate_df = train_test_split(df, test_size=0.20, random_state=42)\ntrain_df = train_df.reset_index(drop=True)\nvalidate_df = validate_df.reset_index(drop=True)\n\ntrain_datagen = ImageDataGenerator(\n    rotation_range=15, \n    rescale=1./255, \n    shear_range=0.1, \n    zoom_range=0.2, \n    horizontal_flip=True, \n    width_shift_range=0.1,\n    height_shift_range=0.1\n)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    \"./train/\", \n    x_col='filenames',\n    y_col='categories',\n    target_size=(224,224),\n    class_mode='categorical',\n    batch_size=32\n)\n\nvalidation_datagen = ImageDataGenerator(rescale=1./255)\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validate_df, \n    \"./train/\", \n    x_col='filenames',\n    y_col='categories',\n    target_size=(224, 224),\n    class_mode='categorical',\n    batch_size=32\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# カスタムモデルを複数宣言するとコンフリクトを起こす。\n# だから、なるべくカスタムレイヤを用いて作成したほうが良い。\n# また、カスタムレイヤ内で引数からレイヤに名前をつけようとするとコンフリクトを起こす。\n# なので、出力レイヤに名前をつける時はカスタムレイヤ外で名前をつける。\n\n# 下記のようにモデルを作成する時は、各出力レイヤに名前をつけなければいけない？...\n\n# 次は重みやパラメータを保存できるように手を加えたい\n\nfrom keras.layers import Dense, Conv2D, AveragePooling2D, Flatten,\\\n                           MaxPool2D, Dropout, BatchNormalization,\\\n                             Lambda, Layer, Input,Concatenate, \\\n                                MaxPooling2D, serialize\nfrom keras.models import Model\n# from keras import Model as MODEL\nfrom keras.layers.core import Activation\nfrom keras.optimizers import Nadam\nfrom keras.activations import serialize as a_serialize\n\n# batchnormalization付きレイヤ 作成\nclass BatchNormDense(Layer):\n    def __init__(self, x, kernel_initializer='he_normal', **kwargs):\n        super().__init__(**kwargs)\n        self.x = x\n        self.kernel_initializer = kernel_initializer\n        self.dense = Dense(self.x, kernel_initializer=self.kernel_initializer)\n        self.batch_norm = BatchNormalization()\n        self.activation = Activation('elu')\n    \n    def call(self, inputs):\n        Z = self.dense(inputs)\n        Z = self.batch_norm(Z)\n        Z = self.activation(Z)\n        \n        return Z\n    \n    def get_config(self):\n        base_config = super().get_config()\n        return {**base_config, 'units': self.x,\n                'kernel_initializer': self.kernel_initializer,\n                'activation': a_serialize(self.activation),\n                'batch_norm': serialize(self.batch_norm),\n                'layer': serialize(self.dense)\n               }\n    \nclass BatchNormConv2D(Layer):\n    def __init__(self, x, kernel_size=(3,3), strides=1,\n                 padding='same', kernel_initializer='he_normal', **kwargs):\n        super().__init__(**kwargs)\n        self.x = x\n        self.kernel_size = kernel_size\n        self.strides = strides\n        self.padding = padding\n        self.kernel_initializer = kernel_initializer\n        \n        self.conv = Conv2D(self.x, kernel_size=self.kernel_size,\n                  strides=self.strides, padding=self.padding,\n                  kernel_initializer=self.kernel_initializer)\n        self.batch_norm = BatchNormalization()\n        self.activation = Activation('relu')\n        \n    def call(self, inputs):\n        Z = self.conv(inputs)\n        Z = self.batch_norm(Z)\n        Z = self.activation(Z)\n        \n        return Z\n    \n    def get_config(self):\n        base_config = super().get_config()\n        return {**base_config, 'units': self.x,\n                'kernel_size': self.kernel_size,\n                'kernel_initializer': self.kernel_initializer,\n                'strides': self.strides,\n                'padding': self.padding,\n                'activation': a_serialize(self.activation),\n                'batch_norm': serialize(self.batch_norm),\n                'layer': serialize(self.conv)\n               }\n    \n# inception層作成\nclass Inception(Layer):\n    def __init__(self, filters, **kwargs):\n        super().__init__(**kwargs)\n        self.l1, self.l2, self.l3, self.l4 = filters\n        \n        self.conv1 = BatchNormConv2D(x=self.l1, kernel_size=(1,1))\n\n        # 1x1->3x3\n        self.conv2_1 = BatchNormConv2D(x=self.l2[0], kernel_size=(1,1))\n        self.conv2_2 = BatchNormConv2D(x=self.l2[1])\n\n        # 1x1->5x5\n        self.conv3_1 = BatchNormConv2D(x=self.l3[0], kernel_size=(1,1))\n        self.conv3_2 = BatchNormConv2D(x=self.l3[1], kernel_size=(5,5))\n\n        # 3x3->1x1\n        self.maxpool = MaxPooling2D(pool_size=(3,3), strides=1, padding='same')\n        self.conv4 = BatchNormConv2D(x=self.l4, kernel_size=(1,1))\n        \n    def call(self, inputs):\n        path1 = self.conv1(inputs)\n\n        # 1x1->3x3\n        path2 = self.conv2_1(inputs)\n        path2 = self.conv2_2(path2)\n\n        # 1x1->5x5\n        path3 = self.conv3_1(inputs)\n        path3 = self.conv3_2(path3)\n\n        # 3x3->1x1\n        path4 = self.maxpool(inputs)\n        path4 = self.conv4(path4)\n\n        return Concatenate(axis=-1)([path1,path2,path3,path4])\n    \n    def get_config(self):\n        base_config = super().get_config()\n        return {**base_config, \n                'layer1': serialize(self.conv1),\n                '1_units': self.l1,\n                'layer2_1': serialize(self.conv2_1),\n                'layer2_2': serialize(self.conv2_2),\n                '2_units': self.l2,\n                'layer3_1': serialize(self.conv3_1),\n                'layer3_2': serialize(self.conv3_2),\n                '3_units': self.l3,\n                'layer4': serialize(self.conv4),\n                '4_units': self.l4,\n                'pool_layer': serialize(self.maxpool)\n               }   \n    \n# auxiliary層作成    \nclass Auxiliary(Layer):\n    def __init__(self, **kwargs):\n        super().__init__(**kwargs)\n        # self.layer_name = layer_name\n        \n        self.AvePool = AveragePooling2D(pool_size=(5,5), strides=3, padding='valid')\n        self.conv1 = BatchNormConv2D(128, kernel_size=(1,1))\n        self.flatten = Flatten()\n        self.dense = BatchNormDense(256)\n        self.dropout = Dropout(0.5)\n        # self.output = Dense(2, activation='softmax') #, name=self.layer_name)\n        \n    def call(self, inputs):\n        layer = self.AvePool(inputs)\n        layer = self.conv1(layer)\n        layer = self.flatten(layer)\n        layer = self.dense(layer)\n        layer = self.dropout(layer)\n        # layer = sef.output(layer)\n        \n        return layer\n    \n    def get_config(self):\n        base_config = super().get_config()\n        return {**base_config, \n                'pool_layer': serialize(self.AvePool),\n                'norm_conv': serialize(self.conv1),\n                'flatten': serialize(self.flatten),\n                'norm_dense': serialize(self.dense),\n                'dropout': serialize(self.dropout),\n               }   \n\ndef create_GoogLeNet(Image_shape=(224,224,3)):\n    layer_in = Input(shape=Image_shape)\n    \n    # stage-1\n    layer = BatchNormConv2D(64, kernel_size=(7,7), strides=2)(layer_in)\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n\n    # stage-2\n    layer = BatchNormConv2D(64, kernel_size=(1,1))(layer)\n    layer = BatchNormConv2D(192)(layer)\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n\n    # stage-3\n    layer = Inception([ 64,  (96,128), (16,32), 32])(layer) #3a\n    layer = Inception([128, (128,192), (32,96), 64])(layer) #3b\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n    \n    # stage-4\n    layer = Inception([192,  (96,208),  (16,48),  64])(layer) #4a\n    aux1 = Auxiliary()(layer)\n    aux1 = Dense(2, activation='softmax', name='aux1')(aux1) \n    \n    layer = Inception([160, (112,224),  (24,64),  64])(layer) #4b\n    layer = Inception([128, (128,256),  (24,64),  64])(layer) #4c\n    layer = Inception([112, (144,288),  (32,64),  64])(layer) #4d\n    \n    aux2 = Auxiliary()(layer)\n    aux2 = Dense(2, activation='softmax', name='aux2')(aux2)\n    \n    layer = Inception([256, (160,320), (32,128), 128])(layer) #4e\n    layer = MaxPooling2D(pool_size=(3,3), strides=2, padding='same')(layer)\n    \n    # stage-5\n    layer = Inception([256, (160,320), (32,128), 128])(layer) #5a\n    layer = Inception([384, (192,384), (48,128), 128])(layer) #5b\n    layer = AveragePooling2D(pool_size=(7,7), strides=1, padding='valid')(layer)\n    \n    # stage-6\n    layer = Flatten()(layer)\n    layer = Dropout(0.5)(layer)\n    layer = BatchNormDense(256)(layer)\n    main = Dense(2, activation='softmax', name='main')(layer)\n    \n    model = Model(inputs=[layer_in], outputs=[main, aux1, aux2])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = create_GoogLeNet()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer=Nadam(lr=0.01), loss='categorical_crossentropy',\n             metrics=['accuracy'])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.callbacks import EarlyStopping, ModelCheckpoint,\\\n                              ReduceLROnPlateau\n\ncb_es = EarlyStopping(monitor='val_loss', patience=3)\ncb_cp = ModelCheckpoint('googlenet.h5', save_best_only=True)\ncb_rl = ReduceLROnPlateau(monitor='val_loss', verbose=1, factor=0.5, patience=2)\n\ncallbacks=[cb_es, cb_cp, cb_rl]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(\n    train_generator, \n    epochs=50,\n    validation_data=validation_generator,\n    #validation_steps=len(train_df)//128,\n    #steps_per_epoch=len(validate_df)//128,\n    callbacks=callbacks\n)","execution_count":null,"outputs":[]},{"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}