{"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":"markdown","source":"# 使用预训练模型\n前面使用了数据增强和Dropout来抑制过拟合，但是这种方法太贵了，需要花费大量时间来训练。\n\n这里介绍一种更为通用的方法，使用预训练模型来训练模型。它是这样一种思想：\n- 前面的卷积网络都是先有卷积层和池化层构成的，然后再有全连接层构成的。\n- 我们把前面的叫做卷积基，它是用来识别图像的通用特征的，比如说，它可以识别图像的边缘，边缘的纹理，边缘的细节等等。\n- 后面的全连接层是用来分类的，它识别的是图像的高级特征，直接能识别出来图像的模型\n- 所以预训练就是这样一种思想，使用在大型数据集上训练好的模型，保持卷积基的结构，然后在训练的时候，只训练全连接层，不训练卷积基。","metadata":{}},{"cell_type":"code","source":"#  解压文件\n# kaggle会将文件解压到根目录下的working路径下\nimport zipfile\nwith zipfile.ZipFile('../input/dogs-vs-cats/train.zip', 'r') as z:\n    z.extractall('.')\nwith zipfile.ZipFile('../input/dogs-vs-cats/test1.zip', 'r') as z:\n    z.extractall('.')","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:12:20.9337Z","iopub.execute_input":"2022-04-14T13:12:20.934017Z","iopub.status.idle":"2022-04-14T13:12:38.417027Z","shell.execute_reply.started":"2022-04-14T13:12:20.933934Z","shell.execute_reply":"2022-04-14T13:12:38.416005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls ../working","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:12:38.418794Z","iopub.execute_input":"2022-04-14T13:12:38.419104Z","iopub.status.idle":"2022-04-14T13:12:39.133419Z","shell.execute_reply.started":"2022-04-14T13:12:38.419061Z","shell.execute_reply":"2022-04-14T13:12:39.132372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 准备数据集，将原来比较大的数据集进行抽样，形成一个比较小的数据集\nimport os, shutil\noriginal_dataset_dir = '../working/train'\nbase_dir = '../working/cats_and_dogs_small'\nos.mkdir(base_dir)\ntrain_dir = os.path.join(base_dir, 'train')\nvalid_dir = os.path.join(base_dir, 'valid')\ntest_dir = os.path.join(base_dir, 'test')\nos.mkdir(train_dir)\nos.mkdir(valid_dir)\nos.mkdir(test_dir)\n\ntrain_dir_dogs = os.path.join(train_dir, 'dogs')\nvalid_dir_dogs = os.path.join(valid_dir, 'dogs')\ntest_dir_dogs = os.path.join(test_dir, 'dogs')\ntrain_dir_cats = os.path.join(train_dir, 'cats')\nvalid_dir_cats = os.path.join(valid_dir, 'cats')\ntest_dir_cats = os.path.join(test_dir, 'cats')\nos.mkdir(train_dir_cats)\nos.mkdir(valid_dir_cats)\nos.mkdir(test_dir_cats)\nos.mkdir(train_dir_dogs)\nos.mkdir(valid_dir_dogs)\nos.mkdir(test_dir_dogs)\n\n# Copy first 1000 cat images to train_cats\nfnames = ['cat.{}.jpg'.format(i) for i in range(1000)]\nfor fname in fnames:\n    src = os.path.join(original_dataset_dir, fname)\n    dst = os.path.join(train_dir_cats, fname)\n    shutil.copyfile(src, dst)\n# Copy next 500 cat images to valid_cats\nfnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]\nfor fname in fnames:\n    src = os.path.join(original_dataset_dir, fname)\n    dst = os.path.join(valid_dir_cats, fname)\n    shutil.copyfile(src, dst)\n# Copy next 500 cat images to test_cats\nfnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]\nfor fname in fnames:\n    src = os.path.join(original_dataset_dir, fname)\n    dst = os.path.join(test_dir_cats, fname)\n    shutil.copyfile(src, dst)\n# Copy first 1000 dog images to train_dogs\nfnames = ['dog.{}.jpg'.format(i) for i in range(1000)]\nfor fname in fnames:\n    src = os.path.join(original_dataset_dir, fname)\n    dst = os.path.join(train_dir_dogs, fname)\n    shutil.copyfile(src, dst)\n# Copy next 500 dog images to valid_dogs\nfnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]\nfor fname in fnames:\n    src = os.path.join(original_dataset_dir, fname)\n    dst = os.path.join(valid_dir_dogs, fname)\n    shutil.copyfile(src, dst)\n# Copy next 500 dog images to test_dogs\nfnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]\nfor fname in fnames:\n    src = os.path.join(original_dataset_dir, fname)\n    dst = os.path.join(test_dir_dogs, fname)\n    shutil.copyfile(src, dst)","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:12:39.135001Z","iopub.execute_input":"2022-04-14T13:12:39.135262Z","iopub.status.idle":"2022-04-14T13:12:39.598584Z","shell.execute_reply.started":"2022-04-14T13:12:39.13522Z","shell.execute_reply":"2022-04-14T13:12:39.597759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.applications import vgg16\nconv_base = vgg16.VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:12:39.600223Z","iopub.execute_input":"2022-04-14T13:12:39.600765Z","iopub.status.idle":"2022-04-14T13:12:46.66616Z","shell.execute_reply.started":"2022-04-14T13:12:39.600726Z","shell.execute_reply":"2022-04-14T13:12:46.665372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"conv_base.summary()","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:12:46.668377Z","iopub.execute_input":"2022-04-14T13:12:46.668996Z","iopub.status.idle":"2022-04-14T13:12:46.681341Z","shell.execute_reply.started":"2022-04-14T13:12:46.668958Z","shell.execute_reply":"2022-04-14T13:12:46.6806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nfrom keras.preprocessing.image import ImageDataGenerator\n\ndatagen = ImageDataGenerator(rescale=1./255)\nbatch_size = 20\ndef extract_features(directory, sample_count):\n    # vgg16中的卷积基最后的一层输出的是4x4x512的特征图，所以这里的特征图尺寸是4x4x512\n    features = np.zeros(shape=(sample_count, 4, 4, 512))\n    labels = np.zeros(shape=(sample_count))\n    generator = datagen.flow_from_directory(\n        directory,\n        target_size=(150, 150),\n        batch_size=batch_size,\n        class_mode='binary')\n    i = 0\n    for inputs_batch, labels_batch in generator:\n        features_batch = conv_base.predict(inputs_batch)\n        features[i * batch_size : (i + 1) * batch_size] = features_batch\n        labels[i * batch_size : (i + 1) * batch_size] = labels_batch\n        i += 1\n        if i * batch_size >= sample_count:\n            break\n    return features, labels","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:12:46.682985Z","iopub.execute_input":"2022-04-14T13:12:46.683298Z","iopub.status.idle":"2022-04-14T13:12:46.696084Z","shell.execute_reply.started":"2022-04-14T13:12:46.683242Z","shell.execute_reply":"2022-04-14T13:12:46.695198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 使用上面的函数分别作用在训练集、验证集和测试集上，得到特征数据\ntrain_features, train_labels = extract_features(train_dir, 2000)\nvalid_features, valid_labels = extract_features(valid_dir, 1000)\ntest_features, test_labels = extract_features(test_dir, 1000)","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:13:34.044081Z","iopub.execute_input":"2022-04-14T13:13:34.044787Z","iopub.status.idle":"2022-04-14T13:20:57.349546Z","shell.execute_reply.started":"2022-04-14T13:13:34.044732Z","shell.execute_reply":"2022-04-14T13:20:57.348913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_features = np.reshape(train_features, (2000, 4 * 4 * 512))\nvalid_features = np.reshape(valid_features, (1000, 4 * 4 * 512))\ntest_features = np.reshape(test_features, (1000, 4 * 4 * 512))","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:26:53.435327Z","iopub.execute_input":"2022-04-14T13:26:53.435616Z","iopub.status.idle":"2022-04-14T13:26:53.441214Z","shell.execute_reply.started":"2022-04-14T13:26:53.435587Z","shell.execute_reply":"2022-04-14T13:26:53.44024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras import models, layers, optimizers\n\nmodel = models.Sequential()\nmodel.add(layer=layers.Dense(256, activation='relu', input_dim=4 * 4 * 512))\nmodel.add(layer=layers.Dropout(0.5))\nmodel.add(layer=layers.Dense(1, activation='sigmoid'))\n\nmodel.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])\nhistory = model.fit(train_features, train_labels, epochs=30, batch_size=20, validation_data=(valid_features, valid_labels))","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:31:32.199351Z","iopub.execute_input":"2022-04-14T13:31:32.199644Z","iopub.status.idle":"2022-04-14T13:32:09.941079Z","shell.execute_reply.started":"2022-04-14T13:31:32.19961Z","shell.execute_reply":"2022-04-14T13:32:09.940244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\n\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'b', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'b', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:39:54.676832Z","iopub.execute_input":"2022-04-14T13:39:54.677147Z","iopub.status.idle":"2022-04-14T13:39:55.108621Z","shell.execute_reply.started":"2022-04-14T13:39:54.677114Z","shell.execute_reply":"2022-04-14T13:39:55.107681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history.history","metadata":{"execution":{"iopub.status.busy":"2022-04-14T13:40:10.771509Z","iopub.execute_input":"2022-04-14T13:40:10.771775Z","iopub.status.idle":"2022-04-14T13:40:10.77934Z","shell.execute_reply.started":"2022-04-14T13:40:10.771747Z","shell.execute_reply":"2022-04-14T13:40:10.778719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}