{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from google.colab import drive\n", "\n", "drive.mount('/content/drive', force_remount=True)\n", "\n", "# 输入daseCV所在的路径\n", "# 'daseCV' 文件夹包括 '.py', 'classifiers' 和'datasets'文件夹\n", "# 例如 'CV/assignments/assignment1/daseCV/'\n", "FOLDERNAME = None\n", "\n", "assert FOLDERNAME is not None, \"[!] Enter the foldername.\"\n", "\n", "%cd drive/My\\ Drive\n", "%cp -r $FOLDERNAME ../../\n", "%cd ../../\n", "%cd daseCV/datasets/\n", "!bash get_datasets.sh\n", "%cd ../../" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "pdf-title" ] }, "source": [ "# Dropout\n", "Dropout [1] 是一种通过在正向传播中将一些输出随机设置为零,神经网络正则化的方法。在这个练习中,你将实现一个dropout层,并修改你的全连接网络使其可选择的使用dropout\n", "\n", "[1] [Geoffrey E. Hinton et al, \"Improving neural networks by preventing co-adaptation of feature detectors\", arXiv 2012](https://arxiv.org/abs/1207.0580)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "pdf-ignore" ] }, "outputs": [], "source": [ "# As usual, a bit of setup\n", "from __future__ import print_function\n", "import time\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from daseCV.classifiers.fc_net import *\n", "from daseCV.data_utils import get_CIFAR10_data\n", "from daseCV.gradient_check import eval_numerical_gradient, eval_numerical_gradient_array\n", "from daseCV.solver import Solver\n", "\n", "%matplotlib inline\n", "plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots\n", "plt.rcParams['image.interpolation'] = 'nearest'\n", "plt.rcParams['image.cmap'] = 'gray'\n", "\n", "# for auto-reloading external modules\n", "# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython\n", "%load_ext autoreload\n", "%autoreload 2\n", "\n", "\n", "def rel_error(x, y):\n", " \"\"\" returns relative error \"\"\"\n", " return np.max(np.abs(x - y) / (np.maximum(1e-8, np.abs(x) + np.abs(y))))\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "pdf-ignore" ] }, "outputs": [], "source": [ "# Load the (preprocessed) CIFAR10 data.\n", "\n", "data = get_CIFAR10_data()\n", "for k, v in data.items():\n", " print('%s: ' % k, v.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Dropout 正向传播\n", "在文件 `daseCV/layers.py` 中完成dropout的正向传播过程。由于dropout在训练和测试期间的行为是不同的,因此请确保两种模式下都实现完成。\n", "\n", "完成此操作后,运行下面的cell以测试你的代码。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.random.seed(231)\n", "x = np.random.randn(500, 500) + 10\n", "\n", "for p in [0.25, 0.4, 0.7]:\n", " out, _ = dropout_forward(x, {'mode': 'train', 'p': p})\n", " out_test, _ = dropout_forward(x, {'mode': 'test', 'p': p})\n", "\n", " print('Running tests with p = ', p)\n", " print('Mean of input: ', x.mean())\n", " print('Mean of train-time output: ', out.mean())\n", " print('Mean of test-time output: ', out_test.mean())\n", " print('Fraction of train-time output set to zero: ', (out == 0).mean())\n", " print('Fraction of test-time output set to zero: ', (out_test == 0).mean())\n", " print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Dropout 反向传播\n", "在文件 `daseCV/layers.py` 中完成dropout的反向传播。完成之后运行以下cell以对你的实现代码进行梯度检查。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.random.seed(231)\n", "x = np.random.randn(10, 10) + 10\n", "dout = np.random.randn(*x.shape)\n", "\n", "dropout_param = {'mode': 'train', 'p': 0.2, 'seed': 123}\n", "out, cache = dropout_forward(x, dropout_param)\n", "dx = dropout_backward(dout, cache)\n", "dx_num = eval_numerical_gradient_array(lambda xx: dropout_forward(xx, dropout_param)[0], x, dout)\n", "\n", "# Error should be around e-10 or less\n", "print('dx relative error: ', rel_error(dx, dx_num))" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "pdf-inline" ] }, "source": [ "## 问题 1:\n", "如果我们不利用inverted dropout,在训练的时候直接将dropout后的值除以 `p`,会发生什么?为什么会这样呢?\n", "\n", "\n", "\n", "## 回答:\n", "[FILL THIS IN]\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 全连接网络的Dropout\n", "\n", "修改`daseCV/classifiers/fc_net.py`文件完成使用dropout的部分。具体来说,如果网络的构造函数收到的`dropout`参数值不为1,则应在每个ReLU之后添加一个dropout层。完成之后,运行以下命令以对你的代码进行梯度检查。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.random.seed(231)\n", "N, D, H1, H2, C = 2, 15, 20, 30, 10\n", "X = np.random.randn(N, D)\n", "y = np.random.randint(C, size=(N,))\n", "\n", "for dropout in [1, 0.75, 0.5]:\n", " print('Running check with dropout = ', dropout)\n", " model = FullyConnectedNet([H1, H2], input_dim=D, num_classes=C,\n", " weight_scale=5e-2, dtype=np.float64,\n", " dropout=dropout, seed=123)\n", "\n", " loss, grads = model.loss(X, y)\n", " print('Initial loss: ', loss)\n", " \n", " # Relative errors should be around e-6 or less; Note that it's fine\n", " # if for dropout=1 you have W2 error be on the order of e-5.\n", " for name in sorted(grads):\n", " f = lambda _: model.loss(X, y)[0]\n", " grad_num = eval_numerical_gradient(f, model.params[name], verbose=False, h=1e-5)\n", " print('%s relative error: %.2e' % (name, rel_error(grad_num, grads[name])))\n", " print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 正则化实验\n", "作为实验,我们将在500个样本上训练一对双层网络:一个不使用dropout,另一个使用概率为0.25的dropout。之后,我们将可视化这两个网络训练和验证的准确度。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Train two identical nets, one with dropout and one without\n", "np.random.seed(231)\n", "num_train = 500\n", "small_data = {\n", " 'X_train': data['X_train'][:num_train],\n", " 'y_train': data['y_train'][:num_train],\n", " 'X_val': data['X_val'],\n", " 'y_val': data['y_val'],\n", "}\n", "\n", "solvers = {}\n", "dropout_choices = [1, 0.25]\n", "for dropout in dropout_choices:\n", " model = FullyConnectedNet([500], dropout=dropout)\n", " print(dropout)\n", "\n", " solver = Solver(model, small_data,\n", " num_epochs=25, batch_size=100,\n", " update_rule='adam',\n", " optim_config={\n", " 'learning_rate': 5e-4,\n", " },\n", " verbose=True, print_every=100)\n", " solver.train()\n", " solvers[dropout] = solver\n", " print()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot train and validation accuracies of the two models\n", "\n", "train_accs = []\n", "val_accs = []\n", "for dropout in dropout_choices:\n", " solver = solvers[dropout]\n", " train_accs.append(solver.train_acc_history[-1])\n", " val_accs.append(solver.val_acc_history[-1])\n", "\n", "plt.subplot(3, 1, 1)\n", "for dropout in dropout_choices:\n", " plt.plot(solvers[dropout].train_acc_history, 'o', label='%.2f dropout' % dropout)\n", "plt.title('Train accuracy')\n", "plt.xlabel('Epoch')\n", "plt.ylabel('Accuracy')\n", "plt.legend(ncol=2, loc='lower right')\n", " \n", "plt.subplot(3, 1, 2)\n", "for dropout in dropout_choices:\n", " plt.plot(solvers[dropout].val_acc_history, 'o', label='%.2f dropout' % dropout)\n", "plt.title('Val accuracy')\n", "plt.xlabel('Epoch')\n", "plt.ylabel('Accuracy')\n", "plt.legend(ncol=2, loc='lower right')\n", "\n", "plt.gcf().set_size_inches(15, 15)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "pdf-inline" ] }, "source": [ "## 问题 2:\n", "对比有无dropout的验证和训练的精度,你对使用dropout作为正则化有何建议?\n", "\n", "## 回答:\n", "[FILL THIS IN]\n" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "pdf-inline" ] }, "source": [ "## 问题三 3:\n", "假设我们正在训练一个深层的全连接网络用以进行图像分类,并隐层之后dropout(通过使用概率p进行参数化)。如果我们担心过度拟合而决定减小隐层的大小(即每层中的节点数)时,应该如何修改p(如果有的话)?\n", "\n", "## 回答:\n", "[FILL THIS IN]\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "# 重要\n", "\n", "这里是作业的结尾处,请执行以下步骤:\n", "\n", "1. 点击`File -> Save`或者用`control+s`组合键,确保你最新的的notebook的作业已经保存到谷歌云。\n", "2. 执行以下代码确保 `.py` 文件保存回你的谷歌云。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "\n", "FOLDER_TO_SAVE = os.path.join('drive/My Drive/', FOLDERNAME)\n", "FILES_TO_SAVE = ['daseCV/classifiers/cnn.py', 'daseCV/classifiers/fc_net.py']\n", "\n", "for files in FILES_TO_SAVE:\n", " with open(os.path.join(FOLDER_TO_SAVE, '/'.join(files.split('/')[1:])), 'w') as f:\n", " f.write(''.join(open(files).readlines()))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 2 }