{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 勾配\n", "\n", "* すべての変数の偏微分をベクトルとしてまとめたもの\n", "* 関数の値を最も減らす方向を指すことができる" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "def numerical_gradient(f, x):\n", " \"\"\"\n", " 勾配を求めます\n", " \n", " Parameters\n", " ----------\n", " f : function\n", " 勾配を求めたい、1つの引数を持つ関数\n", " x : np.array\n", " 一つの引数に与える値の配列\n", " \"\"\"\n", " h = 1e-4 # 0.0001\n", " grad = np.zeros_like(x) # 同じ長さ・形状の配列を0で埋めたもの\n", " \n", " for idx in range(x.size):\n", " tmp_val = float(x[idx]) # 元の値を保存する\n", " # f(x+h) の計算\n", " x[idx] = tmp_val + h\n", " fxh1 = f(x)\n", " \n", " # f(x-h) の計算\n", " x[idx] = tmp_val - h\n", " fxh2 = f(x)\n", " \n", " grad[idx] = (fxh1 - fxh2) / (2*h)\n", " x[idx] = tmp_val # 値を元に戻す\n", " \n", " return grad" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def function_2(x):\n", " return x[0]**2 + x[1]**2" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([6., 8.])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numerical_gradient(function_2, np.array([3.0, 4.0]))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0., 4.])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numerical_gradient(function_2, np.array([0.0, 2.0]))" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([6., 0.])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numerical_gradient(function_2, np.array([3.0, 0.0]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 勾配を可視化する" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def numerical_gradient_batch(f, X):\n", " if X.ndim == 1:\n", " return numerical_gradient(f, X)\n", " else:\n", " grad = np.zeros_like(X)\n", " \n", " for idx, x in enumerate(X):\n", " grad[idx] = numerical_gradient(f, x)\n", " \n", " return grad" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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Wbbbtm1bR3xqWHfr9XrHdadGdXtWVhZms5mcnBzFBbBXr14lPz8fm81GSkqK4n12duzY4fAVs1+DcikqKmLTpk3A/79HlPQOIyMjOXnyJCaTiaZNmzJgwADZSaS8vJyPP/6YvLw8ysrKuP/++xk9erTsJHLy5EnWrl2LxWKhrKyM+fPnM2bMGNWTCNz+OpI/HLvXVk5ODrm5uezatQuj0SjbG2vQoEG0aNGCtLQ0UlNTWbVqFS+88IKsbrKvry9z5swhPj6euLg4vvvuO/z8/GRZ3QP07t2b5s2bc/z4cU6dOkVYWBhz5syRbU3/yP4oCusAACAASURBVCOP0Lt3b7Zv305MTAz33XefbN8oT09PXnrpJfbv38+OHTs4ceKE7B6YPb4XX3yRDz/8kNzcXMVW7V5eXowdO5avv/5alUTSrl07RzW0GhP49pgmTJiguOGvqqqisLAQf39/5s6dq3gnwxMnTuDs7MyECRO47777FDXUGRkZnDp1isDAQMaNG6fINt9u+a7X6xkyZAh33303fn5+svViY2OJiIigR48edO3alW7dusle5FJRUcHKlSvR6/WEhITQtm1bRcd66NAhYmJi6NmzJ82aNaNZs2aKtwf4VeROrvyZXwEBAbc47VSD2WxWbZK2urpalJeX/+bnbmXyrbq6WqSkpKgSm8ViET/88IPIzs6u09/dLE6bzSbi4uLErl27FMclhBBpaWliyZIljolJOdjjLC4uFm+++abIzMxUHJfVahWLFi0SR48eVawlhBAbNmwQ3377rSpaBw4cEB988IEq10ZKSop45513fnLdyp0crqqqEkuWLFHl+7fZbOK777771QnmusR57do1cfHiRWG1WhXHZrVaRXJy8i1fs78VZ1lZmaiurlYclxA135ucBRjcqZPtfxRq7U8NNU+KalUw6/V6OnTooIqWk5MTPXv2VEVLkiS6du1Kly5dVJk4btOmDS+99BLV1dWKlzQ2aNCAl19+2eFoqwSdTsejjz6qypbFAN26dVNNy93dnSlTpqhiI2IymWRvynYzrb/97W+q3QPjxo1TzSpFqSFobXQ6naItb3+OmhbvkiSp2qbdCloi0ZCNml5ISodTatOwYUPV9jFv27atY38YpXTp0oVTp06potWnTx/VakfU8iUDVFsFBJrX1l+Jv0Jlu4bGbUWtBtvd3V21xvH3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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import matplotlib.pylab as plt\n", "from mpl_toolkits.mplot3d import Axes3D\n", "x0 = np.arange(-2, 2.5, 0.25)\n", "x1 = np.arange(-2, 2.5, 0.25)\n", "X, Y = np.meshgrid(x0, x1)\n", "\n", "X = X.flatten()\n", "Y = Y.flatten()\n", "\n", "grad = numerical_gradient_batch(function_2, np.array([X, Y]).T).T\n", "\n", "plt.figure()\n", "plt.quiver(X, Y, -grad[0], -grad[1], angles=\"xy\",color=\"#666666\")\n", "plt.xlim([-2, 2])\n", "plt.ylim([-2, 2])\n", "plt.xlabel('x0')\n", "plt.ylabel('x1')\n", "plt.grid()\n", "plt.draw()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 勾配法 (gradient method)\n", "\n", "* 機械学習では、学習時に最適なパラメータを探索\n", "* ニューラルネットワークでは、重みとバイアスを学習時に探索する\n", "* ニューラルネットワークでの最適なパラメータとは、**損失関数が最小値をとる**とき\n", "* 関数の最小値を探索するために、勾配を使うのが勾配法\n", " * ただし実際は、複雑な関数になると勾配が指す方向が必ず最小値になるわけではない\n", " * 最小値、極小値(関数が一番小さい値を返す引数)、鞍点(saddle point)の可能性がある\n", " * また、「プラトー」と呼ばれる、平坦な値しか出ず学習が進まない場合もある\n", "* 最小値を探す場合を**勾配降下法 (gradient decrent method)**という\n", "* 最大値を探す場合を**勾配上昇法 (gradient ascent method)**という" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "勾配法 (勾配降下法) の数式は、\n", "* $\\eta$(イタまたはエータ) を更新の量\n", "* $\\frac{\\partial f}{\\partial x_0}$ と $\\frac{\\partial f}{\\partial x_1}$は 関数$f(x)$の偏微分\n", "$$\n", " x_0 = x_0 - \\eta\\frac{\\partial f}{\\partial x_0}\n", "$$\n", "$$\n", " x_1 = x_1 - \\eta\\frac{\\partial f}{\\partial x_1}\n", "$$\n", "\n", "* 更新の量 $\\eta$ はニューラルネットワークの学習において、**学習率 (learning rate)** という\n", "* 学習率の値は事前に決める必要がある\n", " * 大きすぎても、小さすぎてもだめ\n", " * 学習率の値を変更しながら、学習できているのかを確認していく必要がある\n", "* 学習率のようなパラメータを、**ハイパーパラメーター**という" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def gradient_descent(f, init_x, lr=0.01, step_num=100):\n", " \"\"\"\n", " 勾配法による関数の極小値(または最小値)を求めます\n", " \n", " \n", " Parameters\n", " ----------\n", " f : function\n", " 勾配を求めたい、1つの引数を持つ関数\n", " init_x : np.array\n", " 引数の初期値\n", " lr : float\n", " 学習率 (learning rate)\n", " step_num : int\n", " 勾配法による繰り返しの数\n", " \"\"\"\n", " x = init_x\n", " \n", " for i in range(step_num):\n", " grad = numerical_gradient_batch(f, x)\n", " x -= lr * grad\n", " \n", " return x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$f(x_0, x_1) = x_0^2 + x_1^2$ の最小値を勾配法で求める):" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def function_2(x): # 関数の最小値は 0\n", " return x[0]**2 + x[1]**2" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([-6.11110793e-10, 8.14814391e-10])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "init_x = np.array([-3.0, 4.0])\n", "gradient_descent(function_2, init_x, lr=0.1, step_num=100)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 2.34235971e+12, -3.96091057e+12])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 学習率が大きいと?\n", "gradient_descent(function_2, init_x, lr=10.0, step_num=100)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 2.34235971e+12, -3.96091057e+12])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 学習率が小さいと?\n", "gradient_descent(function_2, init_x, lr=1e-10, step_num=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ニューラルネットワークに対する勾配" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "import sys, os\n", "sys.path.append(os.path.abspath(os.path.join('..', 'sample')))\n", "import numpy as np\n", "from common.functions import softmax, cross_entropy_error\n", "from common.gradient import numerical_gradient\n", "\n", "class simpleNet:\n", " \"\"\"\n", " 勾配法による、ニューラルネットワークの学習\n", " \n", " Attributes\n", " ----------\n", " W : np.array\n", " 2 × 3 の重みパラメータ\n", " \"\"\"\n", " def __init__(self):\n", " self.W = np.random.randn(2,3)\n", "\n", " def predict(self, x):\n", " \"\"\"\n", " 予測するためのメソッド\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 入力データ\n", " \"\"\"\n", " return np.dot(x, self.W)\n", "\n", " def loss(self, x, t):\n", " \"\"\"\n", " 損失関数の値を求めます\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 入力データ\n", " t : np.array\n", " 正解ラベル\n", " \"\"\"\n", " z = self.predict(x)\n", " y = softmax(z)\n", " loss = cross_entropy_error(y, t)\n", "\n", " return loss" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 0.24055208 -0.08417877 0.10270625]\n", " [ 0.57949381 0.17237454 0.73158598]]\n" ] } ], "source": [ "net = simpleNet()\n", "print(net.W)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0.66587567 0.10462982 0.72005113]\n" ] } ], "source": [ "x = np.array([0.6, 0.9])\n", "p = net.predict(x)\n", "print(p)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.argmax(p) # 最大値のインデックス" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9113499186284006" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = np.array([0, 0, 1]) # 正解ラベル\n", "net.loss(x, t)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 0.22846974 0.1303415 -0.35881124]\n", " [ 0.34270461 0.19551225 -0.53821686]]\n" ] } ], "source": [ "# 勾配を求める\n", "f = lambda w: net.loss(x, t)\n", "dW = numerical_gradient(f, net.W)\n", "print(dW)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 学習アルゴリズムの実装\n", "\n", "1. 訓練データを無作為に選択し、そのデータをミニバッチとする\n", "2. ミニバッチの損失関数を減らすために、各重みパラメータの勾配を求める\n", "3. 重みパラメータを勾配方向に、微小値だけ更新する\n", "\n", "これを繰り返す\n", "\n", "* ミニバッチとして、無作為に選ばれたデータを使用している方法を**確率的勾配降下法 (strochastic gradient descent)** という\n", "* 頭文字をとって**SGD** と呼ばれる関数で実装されるのが一般的、" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "from common.functions import *\n", "from common.gradient import numerical_gradient\n", "\n", "class TwoLayerNet:\n", " \"\"\"\n", " 2層ニューラルネットワーク\n", " \n", " Attributes\n", " ----------\n", " params : dictionary object\n", " ニューラルネットワークで保持する重みとバイアス\n", " \"\"\"\n", " def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):\n", " \"\"\"\n", " Parameters\n", " ----------\n", " input_size : int\n", " 入力層のニューロンの数\n", " hidden_size : int\n", " 隠れ層のニューロンの数\n", " output_size : int\n", " 出力層のニューロンの数\n", " \"\"\"\n", " # 重みの初期化\n", " self.params = {}\n", " self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)\n", " self.params['b1'] = np.zeros(hidden_size)\n", " self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)\n", " self.params['b2'] = np.zeros(output_size)\n", "\n", " def predict(self, x):\n", " \"\"\"\n", " 推論を行います\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 画像データ\n", " \"\"\"\n", " W1, W2 = self.params['W1'], self.params['W2']\n", " b1, b2 = self.params['b1'], self.params['b2']\n", " \n", " a1 = np.dot(x, W1) + b1\n", " z1 = sigmoid(a1)\n", " a2 = np.dot(z1, W2) + b2\n", " y = softmax(a2)\n", " \n", " return y\n", " \n", " def loss(self, x, t):\n", " \"\"\"\n", " 損失関数の値を求めます\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 画像データ\n", " t : np.array\n", " 画像データの正解ラベル\n", " \"\"\"\n", " y = self.predict(x)\n", " \n", " return cross_entropy_error(y, t)\n", " \n", " def accuracy(self, x, t):\n", " \"\"\"\n", " 認識精度を求めます\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 画像データ\n", " t : np.array\n", " 画像データの正解ラベル\n", " \"\"\"\n", " y = self.predict(x)\n", " y = np.argmax(y, axis=1)\n", " t = np.argmax(t, axis=1)\n", " \n", " accuracy = np.sum(y == t) / float(x.shape[0])\n", " return accuracy\n", " \n", " def numerical_gradient(self, x, t):\n", " \"\"\"\n", " 重みパラメータに対する勾配を求めます\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 画像データ\n", " t : np.array\n", " 画像データの正解ラベル\n", " \"\"\"\n", " loss_W = lambda W: self.loss(x, t)\n", " \n", " grads = {}\n", " grads['W1'] = numerical_gradient(loss_W, self.params['W1'])\n", " grads['b1'] = numerical_gradient(loss_W, self.params['b1'])\n", " grads['W2'] = numerical_gradient(loss_W, self.params['W2'])\n", " grads['b2'] = numerical_gradient(loss_W, self.params['b2'])\n", " \n", " return grads\n", " \n", " def gradient(self, x, t):\n", " \"\"\"\n", " 重みパラメータに対する勾配を求めます\n", " numerical_gradient の高速版\n", " \n", " Parameters\n", " ----------\n", " x : np.array\n", " 画像データ\n", " t : np.array\n", " 画像データの正解ラベル\n", " \"\"\"\n", " W1, W2 = self.params['W1'], self.params['W2']\n", " b1, b2 = self.params['b1'], self.params['b2']\n", " grads = {}\n", " \n", " batch_num = x.shape[0]\n", " \n", " # forward\n", " a1 = np.dot(x, W1) + b1\n", " z1 = sigmoid(a1)\n", " a2 = np.dot(z1, W2) + b2\n", " y = softmax(a2)\n", " \n", " # backward\n", " dy = (y - t) / batch_num\n", " grads['W2'] = np.dot(z1.T, dy)\n", " grads['b2'] = np.sum(dy, axis=0)\n", " \n", " dz1 = np.dot(dy, W2.T)\n", " da1 = sigmoid_grad(a1) * dz1\n", " grads['W1'] = np.dot(x.T, da1)\n", " grads['b1'] = np.sum(da1, axis=0)\n", "\n", " return grads" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "写経" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "W1.shape = (784, 100)\n", "b1.shape = (100,)\n", "W2.shape = (100, 10)\n", "b2.shape = (10,)\n", "grads[W1].shape = (784, 100)\n", "grads[b1].shape = (100,)\n", "grads[W2].shape = (100, 10)\n", "grads[b2].shape = (10,)\n" ] } ], "source": [ "net = TwoLayerNet(input_size=784, hidden_size=100, output_size=10)\n", "\n", "print(\"{0}.shape = {1}\".format('W1', net.params['W1'].shape))\n", "print(\"{0}.shape = {1}\".format('b1', net.params['b1'].shape))\n", "print(\"{0}.shape = {1}\".format('W2', net.params['W2'].shape))\n", "print(\"{0}.shape = {1}\".format('b2', net.params['b2'].shape))\n", "\n", "\n", "# ダミーの入力データ\n", "x = np.random.rand(100, 784)\n", "\n", "# ダミーの正解ラベル\n", "t = np.random.rand(100, 10)\n", "\n", "# 勾配を計算\n", "grads = net.numerical_gradient(x, t)\n", "\n", "print(\"{0}.shape = {1}\".format('grads[W1]', grads['W1'].shape))\n", "print(\"{0}.shape = {1}\".format('grads[b1]', grads['b1'].shape))\n", "print(\"{0}.shape = {1}\".format('grads[W2]', grads['W2'].shape))\n", "print(\"{0}.shape = {1}\".format('grads[b2]', grads['b2'].shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ミニバッチ学習の実装" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "train acc, test acc | 0.18345, 0.1865\n", "train acc, test acc | 0.7884666666666666, 0.7935\n", "train acc, test acc | 0.8772833333333333, 0.881\n", "train acc, test acc | 0.8993, 0.9007\n", "train acc, test acc | 0.9088666666666667, 0.9115\n", "train acc, test acc | 0.9153833333333333, 0.9174\n", "train acc, test acc | 0.9207166666666666, 0.9226\n", "train acc, test acc | 0.9244, 0.9265\n", "train acc, test acc | 0.9281, 0.9301\n", "train acc, test acc | 0.9309, 0.9333\n", "train acc, test acc | 0.93425, 0.9352\n", "train acc, test acc | 0.9372, 0.9355\n", "train acc, test acc | 0.9397666666666666, 0.9385\n", "train acc, test acc | 0.94195, 0.9407\n", "train acc, test acc | 0.94375, 0.9413\n", "train acc, test acc | 0.9455, 0.9445\n", "train acc, test acc | 0.9468, 0.9455\n" ] }, { "data": { "image/png": "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CyUl/7rF7d/+9jdefvll/vnPf/Lee++x9957d9l3v6DgX3dDDIfDJBKJzdaZNm0al112GR988AH33HPPxu24+2ZdQbua1xNUCEREOhk4cCDr16/f4vKGhgbKysooLi7mo48+4o033tjufTU0NFBZmb5n14MPPrhx/tFHH83tt9++cbquro4DDzyQ1157jYULFwL02KkhFQIRkU7Ky8s5+OCDmTRpEldeeeVmy4899lgSiQR77LEHP/nJTzjggAO2e1/XX389p59+OoceeigVFRUb5//4xz+mrq6OSZMmseeee/Lqq68ydOhQ7r33Xp/zYMgAAAqZSURBVE499VT23HNPzjzzzO3eb0cafVRE+py5c+ey2267BR1jh9XV67e10Ud1RCAikudUCERE8pwKgYhInlMhEBHJcyoEIiJ5ToVARCTPqRCIiHTyeYahBrjttttobm7uwUS5pUIgItJJvhUCDTonIn3fb47ffN7uJ8P+F0O8GR4+ffPle50De58LTWvgsQs2XXbRn7a6u87DUN96663ceuutPPbYY7S1tXHKKadwww030NTUxBlnnEFNTQ3JZJKf/OQnrFy5kmXLlnHEEUdQUVHBq6++usm2f/rTn/Lss8/S0tLCQQcdxD333IOZMX/+fC699FJqa2sJh8M8/vjjjB8/nltuuYWHHnqIUCjElClTuPnmm7v76m2TCoGISCedh6F+6aWXmDdvHm+99Rbuzoknnsjrr79ObW0to0aN4k9/SheWhoYGSktL+cUvfsGrr766yZARG1x22WVce+21AJx//vk899xzfO1rX+Pcc8/l6quv5pRTTqG1tZVUKsWf//xnnnnmGd58802Ki4t7bGyhzlQIRKTv29on+Fjx1peXlG/zCGBbXnrpJV566SX23ntvABobG5k3bx6HHnooP/zhD7nqqqs44YQTOPTQQ7e5rVdffZVbbrmF5uZm1q5dy+67787hhx/OZ599ximnnAJAYWEhkB6K+qKLLqK4uBjouWGnO1MhEBHZBnfnmmuu4ZJLLtls2cyZM3n++ee55pprOProozd+2u9Ka2sr3/nOd5gxYwajR4/m+uuvp7W1lS2N+ZarYac7U2OxiEgnnYehPuaYY5g+fTqNjY0AfPbZZ6xatYply5ZRXFzMeeedxw9/+EPeeeedLp+/wYZ7DVRUVNDY2MgTTzwBwKBB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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import sys, os\n", "sys.path.append(os.path.abspath(os.path.join('..', 'sample')))\n", "sys.path.append(os.path.abspath(os.path.join('..', 'sample', 'ch04')))\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from dataset.mnist import load_mnist\n", "from two_layer_net import TwoLayerNet\n", "\n", "# データの読み込み\n", "(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)\n", "\n", "network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)\n", "\n", "iters_num = 10000 # 繰り返しの回数を適宜設定する\n", "train_size = x_train.shape[0]\n", "batch_size = 100\n", "learning_rate = 0.1\n", "\n", "train_loss_list = [] # 損失関数の結果\n", "train_acc_list = [] # 学習データの認識精度\n", "test_acc_list = [] # テストデータの認識精度\n", "\n", "iter_per_epoch = max(train_size / batch_size, 1)\n", "\n", "for i in range(iters_num):\n", " batch_mask = np.random.choice(train_size, batch_size)\n", " x_batch = x_train[batch_mask]\n", " t_batch = t_train[batch_mask]\n", " \n", " # 勾配の計算\n", " #grad = network.numerical_gradient(x_batch, t_batch)\n", " grad = network.gradient(x_batch, t_batch)\n", " \n", " # パラメータの更新\n", " for key in ('W1', 'b1', 'W2', 'b2'):\n", " network.params[key] -= learning_rate * grad[key]\n", " \n", " # 学習経過を損失関数の結果として記録\n", " loss = network.loss(x_batch, t_batch)\n", " train_loss_list.append(loss)\n", " \n", " # 1エポック(訓練データをすべて使い切った回数)ごとに認識精度を計算\n", " if i % iter_per_epoch == 0:\n", " train_acc = network.accuracy(x_train, t_train)\n", " test_acc = network.accuracy(x_test, t_test)\n", " train_acc_list.append(train_acc)\n", " test_acc_list.append(test_acc)\n", " print(\"train acc, test acc | \" + str(train_acc) + \", \" + str(test_acc))\n", "\n", "# グラフの描画\n", "markers = {'train': 'o', 'test': 's'}\n", "x = np.arange(len(train_acc_list))\n", "plt.plot(x, train_acc_list, label='train acc')\n", "plt.plot(x, test_acc_list, label='test acc', linestyle='--')\n", "plt.xlabel(\"epochs\")\n", "plt.ylabel(\"accuracy\")\n", "plt.ylim(0, 1.0)\n", "plt.legend(loc='lower right')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* 訓練データとテストデータの認識精度が向上しているのがわかる\n", "* 二つの認識精度に差がない = 過学習が起きていない" ] } ], "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.8.3" } }, "nbformat": 4, "nbformat_minor": 4 }