{"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":"# 一、查看Kaggle环境\n## 1、查看操作系统信息","metadata":{"_kg_hide-output":false,"_kg_hide-input":false}},{"cell_type":"markdown","source":"查看Linux内核版本","metadata":{}},{"cell_type":"code","source":"! uname -r","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"查看Linux发行版信息","metadata":{}},{"cell_type":"code","source":"! lsb_release -a","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2、查看Python信息","metadata":{}},{"cell_type":"code","source":"! python --version","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3、查看TensorFlow工具包信息","metadata":{}},{"cell_type":"code","source":"! pip show TensorFlow","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 二、导入必要的工具包","metadata":{}},{"cell_type":"code","source":"import os  # 文件/目录方模块\nimport cv2  # OpenCV模块\nimport random  # 随机模块\nimport numpy as np  # 数值计算模块\nimport pandas as pd  # 结构化数据分析模块\nimport seaborn as sns  # 统计绘图模块\nimport matplotlib.pyplot as plt  # 绘图模块\nimport zipfile  # zip文件处理模块\nfrom sklearn.model_selection import train_test_split  # 样本分割模块\nfrom sklearn.metrics import classification_report  # 分类评价模块\nfrom tqdm import tqdm  # 进度条模块\nfrom random import shuffle # 混洗模块\nfrom IPython.display import SVG\nfrom keras.utils.vis_utils import model_to_dot\nfrom keras.utils import plot_model\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.optimizers import RMSprop\n%matplotlib inline ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 三、参数设置\n- AlexNet网络模型的输入图像高度和宽度为227像素.\n- 样本文件位于/kaggle/input/dogs-vs-cats/train.zip压缩包之中\n- 我们有两个类别需要识别：狗、猫\n- 训练趟数设定为30趟\n- 每批训练样本数量为64","metadata":{}},{"cell_type":"code","source":"IMG_SIZE = 227\nSAMPlE_ZIP_FILE = '/kaggle/input/dogs-vs-cats/train.zip'\nNUM_CLASSES = 2\nEPOCHS = 100\nBATCH_SIZE = 128\nSAMPLE_PATH = '/kaggle/working/train/'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 四、了解Dogs vs. Cats数据集\n## 1、查看Kaggle数据集目录结构\n　　Kaggle数据集保存在/kaggle/input目录中，本例的Dogs vs. Cats数据集保存在/kaggle/input/dogs-vs-cats目录中，其中train.zip为训练样本图像压缩文件，test1.zip为测试样本图像压缩文件，sampleSubmission.csv为提交文件的样例。","metadata":{}},{"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2、查看train.zip内容","metadata":{}},{"cell_type":"code","source":"sample_zipfile = zipfile.ZipFile(SAMPlE_ZIP_FILE, 'r')    # 打开压缩包\nsample_image_file_list = sample_zipfile.namelist()        # 或缺压缩包的文件名称列表，包括目录名称\nsample_image_file_list.pop(0)                             # 删除目录名称，仅保留图像文件名称\nprint('样本图像文件总数：', len(sample_image_file_list))     # 输出样本总数量\ndata = sample_zipfile.read(sample_image_file_list[0])     # 将第一个图像样本文件内容读入内存缓冲区\nimage = cv2.imdecode(np.frombuffer(data, np.uint8), 1)    # 解码为OpenCV的BGR格式，1表示彩色图像\nimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)            # 转化为RGB格式\nplt.imshow(image)                                         # 绘制输出图像样本","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3、解压缩样本文件","metadata":{}},{"cell_type":"code","source":"with zipfile.ZipFile('/kaggle/input/dogs-vs-cats/train.zip', \"r\") as z:\n    z.extractall(\".\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"! ls","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3、训练集、校验集、测试集准备\n### a. 生成样本的pandas数据表（DataFrame）","metadata":{}},{"cell_type":"code","source":"sample_image_file_list = os.listdir(SAMPLE_PATH)\ncategories = []\nfor filename in sample_image_file_list:\n    category = filename.split(\".\")[0]\n    if category == \"dog\":\n        categories.append(\"dog\")\n    else:\n        categories.append(\"cat\")\ndf = pd.DataFrame({\n    \"filename\" : sample_image_file_list,\n    \"category\" : categories\n})","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### b. 输出前10个样本信息","metadata":{}},{"cell_type":"code","source":"df.head(10)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### c. 绘制个分类样本数量柱形图","metadata":{}},{"cell_type":"code","source":"df.category.value_counts().plot.bar()\ncats = len(df[df['category'] == 'cat'])\ndogs = len(df[df['category'] == 'dog'])\nplt.title(str(cats)+\" cats\" + \" | \" +str(dogs)+\" dogs\")\nplt.ylabel(len(df))\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### d. 输出后10个样本信息","metadata":{}},{"cell_type":"code","source":"df.tail(10)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### e. 分割训练集、校验集","metadata":{}},{"cell_type":"code","source":"train_df, validate_df = train_test_split(df, test_size = 0.2, random_state = 42)\ntrain_df = train_df.reset_index(drop=True)\nvalidate_df = validate_df.reset_index(drop=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### f. 创建训练集生成器","metadata":{}},{"cell_type":"code","source":"# 数据增强\ntrain_datagen = ImageDataGenerator(rotation_range=20,\n                                   rescale=1./255,\n                                   shear_range=0.15,\n                                   zoom_range=0.15,\n                                   horizontal_flip=True,\n                                   width_shift_range=0.2,\n                                   height_shift_range=0.2,\n                                   fill_mode=\"nearest\")\n\n# 数据集生成器\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    SAMPLE_PATH, \n    x_col='filename',\n    y_col='category',\n    target_size=(IMG_SIZE,IMG_SIZE),  # (227, 227)\n    class_mode='binary',\n    batch_size=BATCH_SIZE,\n    color_mode=\"rgb\",\n    shuffle=True\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### g. 创建校验集生成器","metadata":{}},{"cell_type":"code","source":"validation_datagen = ImageDataGenerator(rescale=1./255)\n\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validate_df, \n    SAMPLE_PATH, \n    x_col='filename',\n    y_col='category',\n    target_size=(IMG_SIZE,IMG_SIZE),  # (227, 227)\n    class_mode='binary',\n    batch_size=BATCH_SIZE,\n    color_mode=\"rgb\",\n    shuffle=True\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 五、定义AlexNet网络模型","metadata":{}},{"cell_type":"code","source":"# 导入必须的包\nimport tensorflow as tf\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input\nfrom tensorflow.keras.layers import Conv2D\nfrom tensorflow.keras.layers import MaxPooling2D\nfrom tensorflow.keras.layers import Activation\nfrom tensorflow.keras.layers import Flatten\nfrom tensorflow.keras.layers import Dropout\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.layers import BatchNormalization\n\n\n# 定义AlexNet类\nclass AlexNet:\n    @staticmethod\n    def build(height, width, channel):\n        \"\"\"\n        根据输入样本的维度（width、height、channel），分类数量创建AlexNet网络模型\n        Args:\n            height:  输入样本的高度\n            width:   输入样本的宽度\n            channel: 输入样本的通道\n        Returns:\n            AlexNet网络模型对象\n\n        \"\"\"\n\n        # 输入形状\n        shape = (height, width, channel)\n        inputs = Input(shape, name=\"input\")\n        # 第一层: CONV => RELU => LRN => POOL\n        x = Conv2D(filters=96,\n                   kernel_size=(11, 11),\n                   strides=(4, 4),\n                   input_shape=shape,\n                   padding=\"valid\",\n                   name=\"conv_1\")(inputs)\n        # 局部响应标准化\n        x = tf.nn.local_response_normalization(x, depth_radius=5, bias=2, alpha=0.0001, beta=0.75)\n        x = Activation(\"relu\", name=\"relu_1\")(x)\n        x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name=\"max_pooling_1\")(x)\n\n        # 第二层: CONV => RELU => LRN => POOL\n        x = Conv2D(filters=256,\n                   kernel_size=(5, 5),\n                   padding=\"same\",\n                   name=\"conv_2\")(x)\n        # 局部响应标准化\n        x = tf.nn.local_response_normalization(x, depth_radius=5, bias=2, alpha=0.0001, beta=0.75)\n        x = Activation(\"relu\", name=\"relu_2\")(x)\n        x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name=\"max_pooling_2\")(x)\n\n        # 第三层: CONV => RELU\n        x = Conv2D(filters=384,\n                   kernel_size=(3, 3),\n                   padding=\"same\",\n                   name=\"conv_3\")(x)\n        x = Activation(\"relu\", name=\"relu_3\")(x)\n\n        # 第四层: CONV => RELU\n        x = Conv2D(filters=384,\n                   kernel_size=(3, 3),\n                   padding=\"same\",\n                   name=\"conv_4\")(x)\n        x = Activation(\"relu\", name=\"relu_4\")(x)\n\n        # 第五层: CONV => RELU => POOL\n        x = Conv2D(filters=256,\n                   kernel_size=(3, 3),\n                   padding=\"same\",\n                   name=\"conv_5\")(x)\n        x = Activation(\"relu\", name=\"relu_5\")(x)\n        x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name=\"max_pooling_3\")(x)\n\n        # 第六层: FLATTEN => DENSE => RELU => 随机失活\n        x = Flatten()(x)\n        x = Dense(4096, name=\"fully_connect_1\")(x)\n        x = Activation(\"relu\", name=\"relu_6\")(x)\n        x = Dropout(0.5, name=\"drop_1\")(x)\n\n        # 第七层: DENSE => RELU => 随机失活\n        x = Dense(4096, name=\"fully_connect_2\")(x)\n        x = Activation(\"relu\", name=\"relu_7\")(x)\n        x = Dropout(0.5, name=\"drop_2\")(x)\n\n        # 第八层 DENSE => SOFTMAX\n        x = Dense(1, name=\"fully_connect_3\")(x)\n        outputs = Activation(\"sigmoid\", name=\"sigmoid\")(x)\n\n        return Model(inputs, outputs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 六、训练AlexNet模型","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.optimizers import SGD\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\nimport json\n\nmodel = AlexNet.build(IMG_SIZE, IMG_SIZE, 3)\nopt = SGD(learning_rate=0.01, momentum=0.9, decay=0.005)\nmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics = ['accuracy'])\n\n# 校验损失不下降时降低学习速率\nlr_reducer = ReduceLROnPlateau(monitor='val_loss', \n                               factor=0.1, \n                               patience=3, \n                               min_lr=0.0001, \n                               cooldown=1,\n                               verbose=1)\nhistory = model.fit(\n    train_generator,\n    steps_per_epoch=len(train_df)/BATCH_SIZE,\n    epochs=EPOCHS,\n    validation_data=validation_generator,\n    validation_steps=len(validate_df)/BATCH_SIZE,\n    callbacks=[lr_reducer]\n)\n\n# 将训练得到的模型保存到文件\nprint(\"[信息] 保存模型...\")\nMODEL_FILE = 'AlexNet.h5'\nmodel.save(MODEL_FILE, overwrite=True)\n\n# 保存训练历史数据\njson_path = \"AlexNet_Dogs_vs_Cat_Training_History.json\"\nf = open(json_path, \"w\")\nf.write(json.dumps(str(history.history), skipkeys=True))\nf.close()\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 七、绘制AlexNet模型训练性能图","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n\nfigure, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\nt = figure.suptitle('AlexNet Training Performance', fontsize=12)\nfigure.subplots_adjust(top=0.85, wspace=0.3)\n\nepoch_list = list(range(1, EPOCHS + 1))\nax1.plot(epoch_list, history.history['accuracy'], label='Train Accuracy')\nax1.plot(epoch_list, history.history['val_accuracy'], label='Validation Accuracy')\nax1.set_xticks(np.arange(0, EPOCHS + 1, 5))\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, EPOCHS + 1, 5))\nax2.set_ylabel('Loss Value')\nax2.set_xlabel('Epoch #')\nax2.set_title('Loss')\nl2 = ax2.legend(loc=\"best\")\n\nGRAPH_FILE = 'AlexNet_Training_Performance.pdf'\nfigure.savefig(GRAPH_FILE)\nfigure.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}