{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 程序说明\n", "时间:2016年11月17日\n", "\n", "名称:迁移学习例程\n", "\n", "说明:该程序演示将一个预训练好的模型在新数据集上重新fine-tuning的过程。我们冻结卷积层,只调整全连接层。\n", "1. 在MNIST数据集上使用前五个数字[0...4]训练一个卷积网络。\n", "2. 在后五个数字[5...9]用卷积网络做分类,冻结卷积层并且微调全连接层\n", "\n", "数据集:MNIST" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.加载keras模块" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Using TensorFlow backend.\n" ] } ], "source": [ "from __future__ import print_function\n", "import numpy as np\n", "import datetime\n", "\n", "np.random.seed(1337) # for reproducibility\n", "\n", "from keras.datasets import mnist\n", "from keras.models import Sequential\n", "from keras.layers import Dense, Dropout, Activation, Flatten\n", "from keras.layers import Convolution2D, MaxPooling2D\n", "from keras.utils import np_utils\n", "from keras import backend as K" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2.变量初始化" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "now = datetime.datetime.now\n", "\n", "batch_size = 128\n", "nb_classes = 5\n", "nb_epoch = 5\n", "\n", "# 输入图像的维度\n", "img_rows, img_cols = 28, 28\n", "# 使用卷积滤波器的数量\n", "nb_filters = 32\n", "# 用于max pooling的pooling面积的大小\n", "pool_size = 2\n", "# 卷积核的尺度\n", "kernel_size = 3\n", "\n", "if K.image_dim_ordering() == 'th':\n", " input_shape = (1, img_rows, img_cols)\n", "else:\n", " input_shape = (img_rows, img_cols, 1)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3.准备数据\n", "将MNIST划分为两个数据集,分别用于预训练模型和迁移学习模型。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# 数据,在训练和测试数据集上混洗和拆分\n", "(X_train, y_train), (X_test, y_test) = mnist.load_data()\n", "\n", "# create two datasets one with digits below 5 and one with 5 and above\n", "X_train_lt5 = X_train[y_train < 5]\n", "y_train_lt5 = y_train[y_train < 5]\n", "X_test_lt5 = X_test[y_test < 5]\n", "y_test_lt5 = y_test[y_test < 5]\n", "\n", "X_train_gte5 = X_train[y_train >= 5]\n", "y_train_gte5 = y_train[y_train >= 5] - 5 # make classes start at 0 for\n", "X_test_gte5 = X_test[y_test >= 5] # np_utils.to_categorical\n", "y_test_gte5 = y_test[y_test >= 5] - 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 模型的训练函数" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def train_model(model, train, test, nb_classes):\n", " X_train = train[0].reshape((train[0].shape[0],) + input_shape)\n", " X_test = test[0].reshape((test[0].shape[0],) + input_shape)\n", " X_train = X_train.astype('float32')\n", " X_test = X_test.astype('float32')\n", " X_train /= 255\n", " X_test /= 255\n", " print('X_train shape:', X_train.shape)\n", " print(X_train.shape[0], 'train samples')\n", " print(X_test.shape[0], 'test samples')\n", "\n", " # convert class vectors to binary class matrices\n", " Y_train = np_utils.to_categorical(train[1], nb_classes)\n", " Y_test = np_utils.to_categorical(test[1], nb_classes)\n", "\n", " model.compile(loss='categorical_crossentropy',\n", " optimizer='adadelta',\n", " metrics=['accuracy'])\n", "\n", " t = now()\n", " model.fit(X_train, Y_train,\n", " batch_size=batch_size, nb_epoch=nb_epoch,\n", " verbose=1,\n", " validation_data=(X_test, Y_test))\n", " print('Training time: %s' % (now() - t))\n", " score = model.evaluate(X_test, Y_test, verbose=0)\n", " print('Test score:', score[0])\n", " print('Test accuracy:', score[1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4.建立模型\n", "### 构建卷积层(特征层)和全连接层(分类层)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# define two groups of layers: feature (convolutions) and classification (dense)\n", "feature_layers = [\n", " Convolution2D(nb_filters, kernel_size, kernel_size,\n", " border_mode='valid',\n", " input_shape=input_shape),\n", " Activation('relu'),\n", " Convolution2D(nb_filters, kernel_size, kernel_size),\n", " Activation('relu'),\n", " MaxPooling2D(pool_size=(pool_size, pool_size)),\n", " Dropout(0.25),\n", " Flatten(),\n", "]\n", "classification_layers = [\n", " Dense(128),\n", " Activation('relu'),\n", " Dropout(0.5),\n", " Dense(nb_classes),\n", " Activation('softmax')\n", "]\n", "\n", "# create complete model\n", "model = Sequential(feature_layers + classification_layers)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5.训练预训练模型用于5个数字[0...4]的分类任务" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "X_train shape: (30596, 28, 28, 1)\n", "30596 train samples\n", "5139 test samples\n", "Train on 30596 samples, validate on 5139 samples\n", "Epoch 1/5\n", "30596/30596 [==============================] - 5s - loss: 0.2148 - acc: 0.9349 - val_loss: 0.0398 - val_acc: 0.9868\n", "Epoch 2/5\n", "30596/30596 [==============================] - 4s - loss: 0.0631 - acc: 0.9810 - val_loss: 0.0234 - val_acc: 0.9924\n", "Epoch 3/5\n", "30596/30596 [==============================] - 4s - loss: 0.0457 - acc: 0.9869 - val_loss: 0.0192 - val_acc: 0.9926\n", "Epoch 4/5\n", "30596/30596 [==============================] - 4s - loss: 0.0367 - acc: 0.9885 - val_loss: 0.0150 - val_acc: 0.9946\n", "Epoch 5/5\n", "30596/30596 [==============================] - 4s - loss: 0.0304 - acc: 0.9911 - val_loss: 0.0157 - val_acc: 0.9947\n", "Training time: 0:00:24.128250\n", "Test score: 0.0156876081334\n", "Test accuracy: 0.994746059545\n" ] } ], "source": [ "# train model for 5-digit classification [0..4]\n", "train_model(model,\n", " (X_train_lt5, y_train_lt5),\n", " (X_test_lt5, y_test_lt5), nb_classes)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6.冻结特征层" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# freeze feature layers and rebuild model\n", "for l in feature_layers:\n", " l.trainable = False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7.fine-tuning分类层" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "X_train shape: (29404, 28, 28, 1)\n", "29404 train samples\n", "4861 test samples\n", "Train on 29404 samples, validate on 4861 samples\n", "Epoch 1/5\n", "29404/29404 [==============================] - 3s - loss: 0.3601 - acc: 0.8942 - val_loss: 0.0906 - val_acc: 0.9704\n", "Epoch 2/5\n", "29404/29404 [==============================] - 2s - loss: 0.1231 - acc: 0.9625 - val_loss: 0.0584 - val_acc: 0.9809\n", "Epoch 3/5\n", "29404/29404 [==============================] - 3s - loss: 0.0917 - acc: 0.9732 - val_loss: 0.0480 - val_acc: 0.9837\n", "Epoch 4/5\n", "29404/29404 [==============================] - 3s - loss: 0.0753 - acc: 0.9777 - val_loss: 0.0387 - val_acc: 0.9856\n", "Epoch 5/5\n", "29404/29404 [==============================] - 3s - loss: 0.0654 - acc: 0.9805 - val_loss: 0.0347 - val_acc: 0.9875\n", "Training time: 0:00:15.838667\n", "Test score: 0.0347462616509\n", "Test accuracy: 0.98745114163\n" ] } ], "source": [ "# transfer: train dense layers for new classification task [5..9]\n", "train_model(model,\n", " (X_train_gte5, y_train_gte5),\n", " (X_test_gte5, y_test_gte5), nb_classes)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.12" }, "ssap_exp_config": { "error_alert": "Error Occurs!", "initial": [], "max_iteration": 1000, "recv_id": "", "running": [], "summary": [], "version": "1.1.1" } }, "nbformat": 4, "nbformat_minor": 0 }