{"cells":[{"metadata":{},"cell_type":"markdown","source":"### 一、了解数据集\n\n　　该数据集为猫狗图像数据集，训练集由50000张照片（其中猫25000张，狗25000张），测试集25000张照片（其中其中猫12500张，狗12500张）。"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import glob\n\n# 了解数据集的组成\n\ntrain_files = glob.glob('/kaggle/input/dogs-vs-cats/train/train/*')\ntest_files = glob.glob('/kaggle/input/dogs-vs-cats/test1/test1/*')\n\ntrain_cat_files = [file_name for file_name in train_files if 'cat' in file_name]\ntrain_dog_files = [file_name for file_name in train_files if 'dog' in file_name]\n\nprint('train samples of cat:', len(train_cat_files))\nprint('train samples of dog:', len(train_dog_files))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 二、构建小数据集\n\n　　现在我们构造一个小型数据集，即训练图像包含10000张图片，校验图像包含2000张图片，测试图像包含2000张图片（每类中猫狗图片数量相同）。"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom random import shuffle\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nfrom sklearn.preprocessing import LabelEncoder\n\n# 从猫训练数据中随机抽取1500张训练样本\ncat_train = list(np.random.choice(train_cat_files, size=5000, replace=False))\n\n# 从狗训练数据中随机抽取1500张训练样本\ndog_train = list(np.random.choice(train_dog_files, size=5000, replace=False))\n\n# 从猫训练数据中剔除已经抽取的训练样本\ntrain_cat_files = list(set(train_cat_files) - set(cat_train))\n\n# 从狗训练数据中剔除已经抽取的训练样本\ntrain_dog_files = list(set(train_dog_files) - set(dog_train))\n\n# 从猫训练数据中随机抽取500张校验样本\ncat_val = list(np.random.choice(train_cat_files, size=1000, replace=False))\n\n# 从狗训练数据中随机抽取500张校验样本\ndog_val = list(np.random.choice(train_dog_files, size=1000, replace=False))\n\n# 从猫训练数据中剔除已经抽取的校验样本\ntrain_cat_files = list(set(train_cat_files) - set(cat_val))\n\n# 从狗训练数据中剔除已经抽取的校验样本\ntrain_dog_files = list(set(train_dog_files) - set(dog_val))\n\n# 从猫训练数据中随机抽取500张测试样本\ncat_test = list(np.random.choice(train_cat_files, size=1000, replace=False))\n\n# 从狗训练数据中随机抽取500张测试样本\ndog_test = list(np.random.choice(train_dog_files, size=1000, replace=False))\n\n# 合并猫狗训练集\ntrain_files = cat_train + dog_train\n# 合并猫狗校验集\nval_files = cat_val + dog_val\n# 合并猫狗测试集\ntest_files = cat_test + dog_test\n\n# 随机化猫狗训练集\nshuffle(train_files)\n\n# 样本尺寸\nIMG_DIM = (160, 160)\n# 从磁盘加载训练集\nx_train = np.array([img_to_array(load_img(image_file, target_size=IMG_DIM)) for image_file in train_files])\n# 从磁盘加载校验集\nx_val = np.array([img_to_array(load_img(image_file, target_size=IMG_DIM)) for image_file in val_files])\n# 从磁盘加载测试集\nx_test = np.array([img_to_array(load_img(image_file, target_size=IMG_DIM)) for image_file in test_files])\n\n# 将训练集列表转换为numpy矩阵\nx_train = np.array(x_train)\n# 将校验集列表转换为numpy矩阵\nx_val = np.array(x_val)\n# 将测试集列表转换为numpy矩阵\nx_test = np.array(x_test)\n\n# 标签编码\ntrain_labels = [fn.split('/')[-1].split('.')[0].strip() for fn in train_files]\nval_labels = [fn.split('/')[-1].split('.')[0].strip() for fn in val_files]\ntest_labels = [fn.split('/')[-1].split('.')[0].strip() for fn in test_files]\nle = LabelEncoder()\nle.fit(train_labels)\ny_train = le.transform(train_labels)\ny_val = le.transform(val_labels)\ny_test = le.transform(test_labels)\n\n\nprint('x_train shape:', x_train.shape)\nprint('y_train shape:', y_train.shape)\nprint('x_validate shape:', x_val.shape)\nprint('y_validate shape:', y_val.shape)\nprint('x_test shape:', x_test.shape)\nprint('y_test shape:', y_test.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 三、数据增强"},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\ntrain_datagen = ImageDataGenerator(rescale=1./255, \n                                   zoom_range=0.3, \n                                   rotation_range=50,\n                                   width_shift_range=0.2, \n                                   height_shift_range=0.2, \n                                   shear_range=0.2, \n                                   horizontal_flip=True, \n                                   fill_mode='nearest')\n\nval_datagen = ImageDataGenerator(rescale=1./255)\n\nimg_id = 3\ngenerator = train_datagen.flow(x_train[img_id:img_id+1], train_labels[img_id:img_id+1])\nimages = [next(generator) for i in range(0,5)]\nfig, ax = plt.subplots(1,5, figsize=(16, 6))\nprint('Labels:', [item[1][0] for item in images])\nl = [ax[i].imshow(images[i][0][0]) for i in range(0,5)]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 四、设置MobileNetV2网络"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras.layers import Flatten\nfrom tensorflow.keras.models import Model\nimport pandas as pd\n\n\ninput_shape = (160, 160, 3)\nmobilenet_model = MobileNetV2(include_top=False, weights='imagenet', input_shape=input_shape)\n#output = mobilenet.layers[-1].output\n#output = Flatten()(output)\n#mobilenet_model = Model(mobilenet.input, output)\n\nmobilenet_model.trainable = True\n#fine_tune_at = 100\n# Freeze all the layers before the `fine_tune_at` layer\n#for layer in mobilenet_model.layers[:fine_tune_at]:\n#    layer.trainable =  False\n\nmobilenet_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"layers = [(layer, layer.name, layer.trainable) for layer in mobilenet_model.layers]\npd.DataFrame(layers, columns=['Layer Type', 'Layer Name', 'Layer Trainable'])  ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 五、定义迁移学习网络模型"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(x_train.shape[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, InputLayer, GlobalAveragePooling2D\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras import optimizers\n\nBATCH_SIZE = 32\nTRAIN_SAMPLE_NUMBER = x_train.shape[0]\nVAL_SAMPLE_NUMBER = x_val.shape[0]\nsteps_per_epoch = TRAIN_SAMPLE_NUMBER // BATCH_SIZE\nepochs = 20\nvalidation_steps = VAL_SAMPLE_NUMBER // BATCH_SIZE\n\ntrain_generator = train_datagen.flow(x_train, y_train, batch_size=BATCH_SIZE)\nval_generator = val_datagen.flow(x_val, y_val, batch_size=BATCH_SIZE)\n\nmodel = Sequential()\nmodel.add(mobilenet_model)\nmodel.add(GlobalAveragePooling2D())\n'''\nmodel.add(Dense(512, activation='relu', input_dim=input_shape))\nmodel.add(Dropout(0.3))\nmodel.add(Dense(512, activation='relu'))\nmodel.add(Dropout(0.3))\n'''\nmodel.add(Dense(units=2, activation='softmax'))\n\nmodel.compile(loss='sparse_categorical_crossentropy',\n              optimizer=optimizers.RMSprop(lr=1e-5),\n              metrics=['accuracy'])\n              \nhistory = model.fit_generator(train_generator, \n                              steps_per_epoch=steps_per_epoch, \n                              epochs=epochs,\n                              validation_data=val_generator, \n                              validation_steps=validation_steps, \n                              verbose=1)    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 六、绘制模型训练的准确度和损失图"},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nf, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\nt = f.suptitle('Pre-trained MobileNetV2 Transfer Learn with Fine-Tuning & Image Augmentation Performance ', fontsize=12)\nf.subplots_adjust(top=0.85, wspace=0.3)\n\nepoch_list = list(range(1,21))\nax1.plot(epoch_list, history.history['acc'], label='Train Accuracy')\nax1.plot(epoch_list, history.history['val_acc'], label='Validation Accuracy')\nax1.set_xticks(np.arange(0, 21, 1))\nax1.set_ylabel('Accuracy Value')\nax1.set_xlabel('Epoch #')\nax1.set_title('Accuracy')\nl1 = ax1.legend(loc=\"best\")\n\nax2.plot(epoch_list, history.history['loss'], label='Train Loss')\nax2.plot(epoch_list, history.history['val_loss'], label='Validation Loss')\nax2.set_xticks(np.arange(0, 21, 1))\nax2.set_ylabel('Loss Value')\nax2.set_xlabel('Epoch #')\nax2.set_title('Loss')\nl2 = ax2.legend(loc=\"best\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 七、保存模型\n　　保存模型以便后面我们用测试集对该模型的性能进行评估。"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.save('Cats_Dogs_MobileNetV2_Fine_Tuning_Transfer_Learning.h5')","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":1}