├── LICENSE
├── README.md
├── lecture1
├── exercise.ipynb
└── tensor.ipynb
├── lecture2
├── exercise.ipynb
└── simple_dl.ipynb
├── lecture3
├── autograd.ipynb
├── dataloader.ipynb
└── exercise.ipynb
├── lecture4
├── cnn.ipynb
└── exercise.ipynb
├── lecture5
├── exercise.ipynb
├── image_generation.ipynb
└── simple_rnn.ipynb
├── lecture6
├── classifier
│ ├── Procfile
│ ├── classifier.py
│ ├── requirements.txt
│ ├── runtime.txt
│ ├── static
│ │ └── images
│ │ │ └── truck.jpg
│ └── templates
│ │ ├── index.html
│ │ ├── layout.html
│ │ └── result.html
└── train_cnn.ipynb
└── python_basic
├── 01_python_basic_1.ipynb
├── 02_python_basic_2.ipynb
├── 03_numpy.ipynb
└── 04_matplotlib.ipynb
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 yuky_az
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 【PyTorch+Colab】PyTorchで実装するディープラーニング -CNN、RNN、人工知能Webアプリの構築-
2 | 本講座のゴールは、PyTorchを使ってディープラーニングが実装できるようになることです。
3 | PyTorchを使ってCNN(畳み込みニューラルネットワーク)、RNN(再帰型ニューラルネットワーク)などの技術を順を追って幅広く習得し、人工知能を搭載したWebアプリの構築までを行います。
4 |
5 | Section1. イントロダクション
6 | → PyTorchの概要、ディープラーニングの概要、そしてPyTorchの基礎であるTensorについて解説します。
7 |
8 | Section2. PyTorchで実装する簡単なディープラーニング
9 | → 可能な限りシンプルなコードで、ディープラーニングを実装します。
10 |
11 | Section3. PyTorchの様々な機能
12 | → 自動微分、DataLoaderなどのPyTorch特有の機能について解説します。
13 |
14 | Section4. 畳み込みニューラルネットワーク(CNN)
15 | → CNNの原理を学んだ上で、CNNによる画像分類をデータ拡張、ドロップアウトとともに実装します。
16 |
17 | Section5. 再帰型ニューラルネットワーク(RNN)
18 | → RNNの原理を学んだ上で、シンプルなRNNの構築、およびRNNによる画像生成を行います。
19 |
20 | Section6. AIアプリのデプロイ
21 | → 学習済みモデルを活用した人工知能Webアプリを構築します。
22 |
23 | Udemyコース: [【PyTorch+Colab】PyTorchで実装するディープラーニング](https://www.udemy.com/course/ai-pytorch/?referralCode=5106F3FDA2C91D0C1CB5)
24 |
25 | ### 自由研究室 AIRS-Lab(コミュニティ)
26 | 「AI」をテーマに交流し、創造するWeb上のコミュニティです。
27 | https://www.airs-lab.jp/
28 |
29 | ### News! AIRS-Lab(メルマガ)
30 | AIの話題、講義動画、Udemyコース割引などのAIRS-Lab最新コンテンツをメールで配信します。
31 | https://www.airs-lab.jp/newsletter
32 |
33 | ### AI教室 AIRS-Lab(YouTubeチャンネル)
34 | 毎週月曜日21時に、YouTubeでライブ講義を開催しています。
35 | https://www.youtube.com/channel/UCT_HwlT8bgYrpKrEvw0jH7Q
36 |
37 | ### Udemyコース
38 | オンライン動画学習プラットフォームUdemyで、AI関連のコースを複数展開しています。
39 | https://www.airs-lab.jp/lectures
40 |
--------------------------------------------------------------------------------
/lecture1/exercise.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "exercise.ipynb",
7 | "provenance": [],
8 | "authorship_tag": "ABX9TyNCQ+l/BAGr/ETeRri0AyU6",
9 | "include_colab_link": true
10 | },
11 | "kernelspec": {
12 | "name": "python3",
13 | "display_name": "Python 3"
14 | }
15 | },
16 | "cells": [
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {
20 | "id": "view-in-github",
21 | "colab_type": "text"
22 | },
23 | "source": [
24 | ""
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {
30 | "id": "Gyk0pYx-GOTG",
31 | "colab_type": "text"
32 | },
33 | "source": [
34 | "# 演習\n",
35 | "第1講の演習です。"
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {
41 | "id": "l1iDDDhCGdRk",
42 | "colab_type": "text"
43 | },
44 | "source": [
45 | "## Tensor同士の演算\n",
46 | "以下のTensor`a`と`b`の間で、以下の演算子を使って演算を行い、結果を表示しましょう。 \n",
47 | "和: + \n",
48 | "差: - \n",
49 | "積: * \n",
50 | "商(小数): / \n",
51 | "商(整数): // \n",
52 | "余り: % \n",
53 | "`a`は行列で`b`はベクトルなので、ブロードキャストが必要になります。"
54 | ]
55 | },
56 | {
57 | "cell_type": "code",
58 | "metadata": {
59 | "id": "vQjm5IIwFzfQ",
60 | "colab_type": "code",
61 | "colab": {}
62 | },
63 | "source": [
64 | "import torch\n",
65 | "\n",
66 | "a = torch.tensor([[1, 2, 3],\n",
67 | " [4, 5, 6.]])\n",
68 | "b = torch.tensor([1, 2, 3.]) \n",
69 | "\n",
70 | "# 和\n",
71 | "\n",
72 | "\n",
73 | "# 差\n",
74 | "\n",
75 | "\n",
76 | "# 積\n",
77 | "\n",
78 | "\n",
79 | "# 商(小数)\n",
80 | "\n",
81 | "\n",
82 | "# 商(整数)\n",
83 | "\n",
84 | "\n",
85 | "# 余り\n"
86 | ],
87 | "execution_count": 0,
88 | "outputs": []
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "metadata": {
93 | "id": "BEW_lUs3PJCQ",
94 | "colab_type": "text"
95 | },
96 | "source": [
97 | "## 解答例\n",
98 | "以下は、どうしても手がかりがないときのみ参考にしましょう。"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "metadata": {
104 | "id": "imyJ_CUEPNgW",
105 | "colab_type": "code",
106 | "colab": {}
107 | },
108 | "source": [
109 | "import torch\n",
110 | "\n",
111 | "a = torch.tensor([[1, 2, 3],\n",
112 | " [4, 5, 6.]])\n",
113 | "b = torch.tensor([1, 2, 3.]) \n",
114 | "\n",
115 | "# 和\n",
116 | "print(a + b)\n",
117 | "\n",
118 | "# 差\n",
119 | "print(a - b)\n",
120 | "\n",
121 | "# 積\n",
122 | "print(a * b)\n",
123 | "\n",
124 | "# 商(小数)\n",
125 | "print(a / b)\n",
126 | "\n",
127 | "# 商(整数)\n",
128 | "print(a // b)\n",
129 | "\n",
130 | "# 余り\n",
131 | "print(a % b)"
132 | ],
133 | "execution_count": 0,
134 | "outputs": []
135 | }
136 | ]
137 | }
--------------------------------------------------------------------------------
/lecture1/tensor.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "tensor.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "authorship_tag": "ABX9TyOTxejBTppXvhM1e/CJHcYB",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | }
16 | },
17 | "cells": [
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {
21 | "id": "view-in-github",
22 | "colab_type": "text"
23 | },
24 | "source": [
25 | "
"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {
31 | "id": "qBeK8bWc4a_9",
32 | "colab_type": "text"
33 | },
34 | "source": [
35 | "# Tensor\n",
36 | "TensorはPyTorchにおいて最も基本となるデータ構造です。 \n",
37 | "今回は、Tensorを生成したり、Tensor同士の計算をしたりするコードを練習します。"
38 | ]
39 | },
40 | {
41 | "cell_type": "markdown",
42 | "metadata": {
43 | "id": "ztIkOM_N5Bu7",
44 | "colab_type": "text"
45 | },
46 | "source": [
47 | "## パッケージの確認\n",
48 | "インストール済みのパッケージを全て表示します。 \n",
49 | "PyTorch(torch)がインストールされていることを確認しましょう。"
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "metadata": {
55 | "id": "SLrzxL39qGie",
56 | "colab_type": "code",
57 | "colab": {}
58 | },
59 | "source": [
60 | "!pip list"
61 | ],
62 | "execution_count": 0,
63 | "outputs": []
64 | },
65 | {
66 | "cell_type": "markdown",
67 | "metadata": {
68 | "id": "EMC135bx6E3u",
69 | "colab_type": "text"
70 | },
71 | "source": [
72 | "## Tensorの生成\n",
73 | "torchのtensor関数によりTensorを生成します。 \n",
74 | "以下のセルではPythonのリストからTensorを生成します。 \n",
75 | "また、type( )により型を確認します。 "
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "metadata": {
81 | "id": "xCg7mgXPqBc8",
82 | "colab_type": "code",
83 | "colab": {}
84 | },
85 | "source": [
86 | "import torch\n",
87 | "a = torch.tensor([1,2,3])\n",
88 | "print(a, type(a))"
89 | ],
90 | "execution_count": 0,
91 | "outputs": []
92 | },
93 | {
94 | "cell_type": "markdown",
95 | "metadata": {
96 | "id": "6LcfIq4nWfG2",
97 | "colab_type": "text"
98 | },
99 | "source": [
100 | "他にも、様々な方法でTensorを生成することができます。"
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "metadata": {
106 | "id": "3X2TN2rYtCTO",
107 | "colab_type": "code",
108 | "colab": {}
109 | },
110 | "source": [
111 | "# 2重のリストから生成\n",
112 | "b = torch.tensor([[1, 2],\n",
113 | " [3, 4]])\n",
114 | "print(b)\n",
115 | "\n",
116 | "# dypeを指定し、倍精度のTensorにする\n",
117 | "c = torch.tensor([[1, 2],\n",
118 | " [3, 4]], dtype=torch.float64)\n",
119 | "print(c)\n",
120 | "\n",
121 | "# 0から9までの数値で初期化\n",
122 | "d = torch.arange(0, 10)\n",
123 | "print(d)\n",
124 | "\n",
125 | "# すべての値が0の、2×3のTensor\n",
126 | "e = torch.zeros(2, 3)\n",
127 | "print(e)\n",
128 | "\n",
129 | "# すべての値が乱数の、2×3のTensor\n",
130 | "f = torch.rand(2, 3)\n",
131 | "print(f)\n",
132 | "\n",
133 | "# Tensorの形状はsizeメソッドで取得\n",
134 | "print(f.size())"
135 | ],
136 | "execution_count": 0,
137 | "outputs": []
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "metadata": {
142 | "id": "b-TrDK5qewJp",
143 | "colab_type": "text"
144 | },
145 | "source": [
146 | "## TensorとNumPyの配列の変換\n",
147 | "numpy()メソッドでTensorをNumPyの配列に変換することができます。 \n",
148 | "また、from_numpy( )関数でNumPyの配列をTensorに変換することができます。"
149 | ]
150 | },
151 | {
152 | "cell_type": "code",
153 | "metadata": {
154 | "id": "VdQc9-L5gBFZ",
155 | "colab_type": "code",
156 | "colab": {}
157 | },
158 | "source": [
159 | "# Tensor → NumPy\n",
160 | "a = torch.tensor([[1, 2],\n",
161 | " [3, 4.]])\n",
162 | "b = a.numpy()\n",
163 | "print(b)\n",
164 | "\n",
165 | "# NumPy → Tensor\n",
166 | "c = torch.from_numpy(b)\n",
167 | "print(c)"
168 | ],
169 | "execution_count": 0,
170 | "outputs": []
171 | },
172 | {
173 | "cell_type": "markdown",
174 | "metadata": {
175 | "id": "CgpWSmhXnas_",
176 | "colab_type": "text"
177 | },
178 | "source": [
179 | "## 範囲を指定してアクセス\n",
180 | "様々な方法で、Tensorの要素に範囲を指定してアクセスすることができます。"
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "metadata": {
186 | "id": "MgWk6RXMoX_l",
187 | "colab_type": "code",
188 | "colab": {}
189 | },
190 | "source": [
191 | "a = torch.tensor([[1, 2, 3],\n",
192 | " [4, 5, 6]])\n",
193 | "\n",
194 | "# 2つのインデックスを指定\n",
195 | "print(a[0, 1])\n",
196 | "\n",
197 | "# 範囲を指定\n",
198 | "print(a[1:2, :2])\n",
199 | "\n",
200 | "# リストで複数のインデックスを指定\n",
201 | "print(a[:, [0, 2]])\n",
202 | "\n",
203 | "# 3より大きい要素のみを指定\n",
204 | "print(a[a>3])\n",
205 | "\n",
206 | "# 要素の変更\n",
207 | "a[0, 2] = 11\n",
208 | "print(a)\n",
209 | "\n",
210 | "# 要素の一括変更\n",
211 | "a[:, 1] = 22\n",
212 | "print(a)\n",
213 | "\n",
214 | "# 10より大きい要素のみ変更\n",
215 | "a[a>10] = 33\n",
216 | "print(a)"
217 | ],
218 | "execution_count": 0,
219 | "outputs": []
220 | },
221 | {
222 | "cell_type": "markdown",
223 | "metadata": {
224 | "id": "2HQMM_Fh02of",
225 | "colab_type": "text"
226 | },
227 | "source": [
228 | "## Tensorの演算\n",
229 | "Tensorによりベクトルや行列を表現することができます。 \n",
230 | "これらの演算は、一定のルールに基づき行われます。 "
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "metadata": {
236 | "id": "AQ5IsU0Fz-DJ",
237 | "colab_type": "code",
238 | "colab": {}
239 | },
240 | "source": [
241 | "# ベクトル\n",
242 | "a = torch.tensor([1, 2, 3]) \n",
243 | "b = torch.tensor([4, 5, 6])\n",
244 | "\n",
245 | "# 行列\n",
246 | "c = torch.tensor([[6, 5, 4],\n",
247 | " [3, 2, 1]])\n",
248 | "\n",
249 | "# ベクトルとスカラーの演算\n",
250 | "print(a + 3)\n",
251 | "\n",
252 | "# ベクトル同士の演算\n",
253 | "print(a + b) \n",
254 | "\n",
255 | "# 行列とスカラーの演算\n",
256 | "print(c + 2)\n",
257 | "\n",
258 | "# 行列とベクトルの演算(ブロードキャスト)\n",
259 | "print(c + a)\n",
260 | "\n",
261 | "# 行列同士の演算\n",
262 | "print(c + c)"
263 | ],
264 | "execution_count": 0,
265 | "outputs": []
266 | },
267 | {
268 | "cell_type": "markdown",
269 | "metadata": {
270 | "id": "r0S-nN_c8MKr",
271 | "colab_type": "text"
272 | },
273 | "source": [
274 | "## 様々な値の計算\n",
275 | "平均値、合計値、最大値、最小値など様々な値を計算する関数とメソッドが用意されています。\n"
276 | ]
277 | },
278 | {
279 | "cell_type": "code",
280 | "metadata": {
281 | "id": "X_LIWIwI59rI",
282 | "colab_type": "code",
283 | "colab": {}
284 | },
285 | "source": [
286 | "a = torch.tensor([[1, 2, 3],\n",
287 | " [4, 5, 6.]])\n",
288 | "\n",
289 | "# 平均値を求める関数\n",
290 | "m = torch.mean(a)\n",
291 | "print(m.item()) # item()で値を取り出す\n",
292 | "\n",
293 | "# 平均値を求めるメソッド\n",
294 | "m = a.mean()\n",
295 | "print(m.item())\n",
296 | "\n",
297 | "# 列ごとの平均値\n",
298 | "print(a.mean(0))\n",
299 | "\n",
300 | "# 合計値\n",
301 | "print(torch.sum(a).item())\n",
302 | "\n",
303 | "# 最大値\n",
304 | "print(torch.max(a).item())\n",
305 | "\n",
306 | "# 最小値\n",
307 | "print(torch.min(a).item())"
308 | ],
309 | "execution_count": 0,
310 | "outputs": []
311 | }
312 | ]
313 | }
--------------------------------------------------------------------------------
/lecture2/exercise.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "exercise.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "authorship_tag": "ABX9TyPDbtT3RYuZL9QWBBJD1HqN",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | }
16 | },
17 | "cells": [
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {
21 | "id": "view-in-github",
22 | "colab_type": "text"
23 | },
24 | "source": [
25 | "
"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {
31 | "id": "Niaz8_W6OX34",
32 | "colab_type": "text"
33 | },
34 | "source": [
35 | "# 演習\n",
36 | "第2講の演習です。 \n",
37 | "PyTorchを使ってモデルを構築し、最適化アルゴリズムを設定しましょう。\n"
38 | ]
39 | },
40 | {
41 | "cell_type": "markdown",
42 | "metadata": {
43 | "id": "w40h1X0FXmrh",
44 | "colab_type": "text"
45 | },
46 | "source": [
47 | "## データを訓練用とテスト用に分割"
48 | ]
49 | },
50 | {
51 | "cell_type": "code",
52 | "metadata": {
53 | "id": "GLGwXks542pJ",
54 | "colab_type": "code",
55 | "colab": {}
56 | },
57 | "source": [
58 | "import torch\n",
59 | "from sklearn import datasets\n",
60 | "from sklearn.model_selection import train_test_split\n",
61 | "\n",
62 | "digits_data = datasets.load_digits()\n",
63 | "\n",
64 | "digit_images = digits_data.data\n",
65 | "labels = digits_data.target\n",
66 | "x_train, x_test, t_train, t_test = train_test_split(digit_images, labels) # 25%がテスト用\n",
67 | "\n",
68 | "# Tensorに変換\n",
69 | "x_train = torch.tensor(x_train, dtype=torch.float32)\n",
70 | "t_train = torch.tensor(t_train, dtype=torch.int64) \n",
71 | "x_test = torch.tensor(x_test, dtype=torch.float32)\n",
72 | "t_test = torch.tensor(t_test, dtype=torch.int64) "
73 | ],
74 | "execution_count": 0,
75 | "outputs": []
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {
80 | "id": "FalXNYaJPkoE",
81 | "colab_type": "text"
82 | },
83 | "source": [
84 | "## モデルの構築\n",
85 | "`nn`モジュールの`Sequential`クラスを使い、`print(net)`で以下のように表示されるモデルを構築しましょう。\n",
86 | "```\n",
87 | "Sequential(\n",
88 | " (0): Linear(in_features=64, out_features=128, bias=True)\n",
89 | " (1): ReLU()\n",
90 | " (2): Linear(in_features=128, out_features=64, bias=True)\n",
91 | " (3): ReLU()\n",
92 | " (4): Linear(in_features=64, out_features=10, bias=True)\n",
93 | ")\n",
94 | "```"
95 | ]
96 | },
97 | {
98 | "cell_type": "code",
99 | "metadata": {
100 | "id": "SuqqZmsh_jNK",
101 | "colab_type": "code",
102 | "colab": {}
103 | },
104 | "source": [
105 | "from torch import nn\n",
106 | "\n",
107 | "net = nn.Sequential(\n",
108 | " # ------- ここからコードを記述 -------\n",
109 | "\n",
110 | "\n",
111 | "\n",
112 | "\n",
113 | "\n",
114 | " # ------- ここまで -------\n",
115 | ")\n",
116 | "print(net)"
117 | ],
118 | "execution_count": 0,
119 | "outputs": []
120 | },
121 | {
122 | "cell_type": "markdown",
123 | "metadata": {
124 | "id": "qsW5zCKhQE9p",
125 | "colab_type": "text"
126 | },
127 | "source": [
128 | "## 学習\n",
129 | "モデルを訓練します。 \n",
130 | "最適化アルゴリズムの設定をしましょう。 \n",
131 | "最適化アルゴリズムは、以下のページから好きなものを選択してください。 \n",
132 | "https://pytorch.org/docs/stable/optim.html\n",
133 | "\n",
134 | "\n"
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "metadata": {
140 | "id": "u6zwN3nArbGC",
141 | "colab_type": "code",
142 | "colab": {}
143 | },
144 | "source": [
145 | "from torch import optim\n",
146 | "\n",
147 | "# 交差エントロピー誤差関数\n",
148 | "loss_fnc = nn.CrossEntropyLoss()\n",
149 | "\n",
150 | "# 最適化アルゴリズム\n",
151 | "optimizer = # ここにコードを記述\n",
152 | "\n",
153 | "# 損失のログ\n",
154 | "record_loss_train = []\n",
155 | "record_loss_test = []\n",
156 | "\n",
157 | "# 1000エポック学習\n",
158 | "for i in range(1000):\n",
159 | "\n",
160 | " # 勾配を0に\n",
161 | " optimizer.zero_grad()\n",
162 | " \n",
163 | " # 順伝播\n",
164 | " y_train = net(x_train)\n",
165 | " y_test = net(x_test)\n",
166 | " \n",
167 | " # 誤差を求める\n",
168 | " loss_train = loss_fnc(y_train, t_train)\n",
169 | " loss_test = loss_fnc(y_test, t_test)\n",
170 | " record_loss_train.append(loss_train.item())\n",
171 | " record_loss_test.append(loss_test.item())\n",
172 | "\n",
173 | " # 逆伝播(勾配を求める)\n",
174 | " loss_train.backward()\n",
175 | " \n",
176 | " # パラメータの更新\n",
177 | " optimizer.step()\n",
178 | "\n",
179 | " if i%100 == 0:\n",
180 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train.item(), \"Loss_Test:\", loss_test.item())"
181 | ],
182 | "execution_count": 0,
183 | "outputs": []
184 | },
185 | {
186 | "cell_type": "markdown",
187 | "metadata": {
188 | "id": "rJwwrWTw43rx",
189 | "colab_type": "text"
190 | },
191 | "source": [
192 | "## 誤差の推移"
193 | ]
194 | },
195 | {
196 | "cell_type": "code",
197 | "metadata": {
198 | "id": "OaJx4swE45XI",
199 | "colab_type": "code",
200 | "colab": {}
201 | },
202 | "source": [
203 | "import matplotlib.pyplot as plt\n",
204 | "\n",
205 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
206 | "plt.plot(range(len(record_loss_test)), record_loss_test, label=\"Test\")\n",
207 | "plt.legend()\n",
208 | "\n",
209 | "plt.xlabel(\"Epochs\")\n",
210 | "plt.ylabel(\"Error\")\n",
211 | "plt.show()"
212 | ],
213 | "execution_count": 0,
214 | "outputs": []
215 | },
216 | {
217 | "cell_type": "markdown",
218 | "metadata": {
219 | "id": "iMrpac0m4Nct",
220 | "colab_type": "text"
221 | },
222 | "source": [
223 | "## 正解率"
224 | ]
225 | },
226 | {
227 | "cell_type": "code",
228 | "metadata": {
229 | "id": "IRkGCYMM_N35",
230 | "colab_type": "code",
231 | "colab": {}
232 | },
233 | "source": [
234 | "y_test = net(x_test)\n",
235 | "count = (y_test.argmax(1) == t_test).sum().item()\n",
236 | "print(\"正解率:\", str(count/len(y_test)*100) + \"%\")"
237 | ],
238 | "execution_count": 0,
239 | "outputs": []
240 | },
241 | {
242 | "cell_type": "markdown",
243 | "metadata": {
244 | "id": "maAJN2wa0l1D",
245 | "colab_type": "text"
246 | },
247 | "source": [
248 | "# 解答例\n",
249 | "以下は、どうしても手がかりがないときのみ参考にしましょう。"
250 | ]
251 | },
252 | {
253 | "cell_type": "code",
254 | "metadata": {
255 | "id": "rQagvzyDmDA5",
256 | "colab_type": "code",
257 | "colab": {}
258 | },
259 | "source": [
260 | "from torch import nn\n",
261 | "\n",
262 | "net = nn.Sequential(\n",
263 | " # ------- ここからコードを記述 -------\n",
264 | " nn.Linear(64, 128), # 全結合層\n",
265 | " nn.ReLU(), # ReLU\n",
266 | " nn.Linear(128, 64),\n",
267 | " nn.ReLU(),\n",
268 | " nn.Linear(64, 10)\n",
269 | " # ------- ここまで -------\n",
270 | ")\n",
271 | "print(net)"
272 | ],
273 | "execution_count": 0,
274 | "outputs": []
275 | },
276 | {
277 | "cell_type": "code",
278 | "metadata": {
279 | "id": "ARNSvRFTmDI1",
280 | "colab_type": "code",
281 | "colab": {}
282 | },
283 | "source": [
284 | "from torch import optim\n",
285 | "\n",
286 | "# 交差エントロピー誤差関数\n",
287 | "loss_fnc = nn.CrossEntropyLoss()\n",
288 | "\n",
289 | "# 最適化アルゴリズム\n",
290 | "optimizer = optim.Adam(net.parameters()) # ここにコードを記述\n",
291 | "\n",
292 | "# 損失のログ\n",
293 | "record_loss_train = []\n",
294 | "record_loss_test = []\n",
295 | "\n",
296 | "# 1000エポック学習\n",
297 | "for i in range(1000):\n",
298 | "\n",
299 | " # 勾配を0に\n",
300 | " optimizer.zero_grad()\n",
301 | " \n",
302 | " # 順伝播\n",
303 | " y_train = net(x_train)\n",
304 | " y_test = net(x_test)\n",
305 | " \n",
306 | " # 誤差を求める\n",
307 | " loss_train = loss_fnc(y_train, t_train)\n",
308 | " loss_test = loss_fnc(y_test, t_test)\n",
309 | " record_loss_train.append(loss_train.item())\n",
310 | " record_loss_test.append(loss_test.item())\n",
311 | "\n",
312 | " # 逆伝播(勾配を求める)\n",
313 | " loss_train.backward()\n",
314 | " \n",
315 | " # パラメータの更新\n",
316 | " optimizer.step()\n",
317 | "\n",
318 | " if i%100 == 0:\n",
319 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train.item(), \"Loss_Test:\", loss_test.item())"
320 | ],
321 | "execution_count": 0,
322 | "outputs": []
323 | }
324 | ]
325 | }
--------------------------------------------------------------------------------
/lecture2/simple_dl.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "simple_dl.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "authorship_tag": "ABX9TyOg38ElnatmFsST2pi+nOp9",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | }
16 | },
17 | "cells": [
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {
21 | "id": "view-in-github",
22 | "colab_type": "text"
23 | },
24 | "source": [
25 | "
"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {
31 | "id": "Niaz8_W6OX34",
32 | "colab_type": "text"
33 | },
34 | "source": [
35 | "# シンプルなディープラーニング\n",
36 | "PyTorchを使って簡単なディープラーニングを実装します。 \n",
37 | "今回は、ディープラーニングにより手書き文字の認識を行います。\n"
38 | ]
39 | },
40 | {
41 | "cell_type": "markdown",
42 | "metadata": {
43 | "colab_type": "text",
44 | "id": "x9Gzbn25XSlF"
45 | },
46 | "source": [
47 | "### 手書き文字画像の確認\n",
48 | "scikit-learnから、手書き数字の画像データを読み込んで表示します。 "
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "metadata": {
54 | "colab_type": "code",
55 | "id": "81Il03RNAmbS",
56 | "colab": {}
57 | },
58 | "source": [
59 | "import numpy as np\n",
60 | "import matplotlib.pyplot as plt\n",
61 | "from sklearn import datasets\n",
62 | "\n",
63 | "digits_data = datasets.load_digits()\n",
64 | "\n",
65 | "n_img = 10 # 表示する画像の数\n",
66 | "plt.figure(figsize=(10, 4))\n",
67 | "for i in range(n_img):\n",
68 | " ax = plt.subplot(2, 5, i+1)\n",
69 | " plt.imshow(digits_data.data[i].reshape(8, 8), cmap=\"Greys_r\")\n",
70 | " ax.get_xaxis().set_visible(False) # 軸を非表示に\n",
71 | " ax.get_yaxis().set_visible(False)\n",
72 | "plt.show()\n",
73 | "\n",
74 | "print(\"データの形状:\", digits_data.data.shape)\n",
75 | "print(\"ラベル:\", digits_data.target[:n_img])"
76 | ],
77 | "execution_count": 0,
78 | "outputs": []
79 | },
80 | {
81 | "cell_type": "markdown",
82 | "metadata": {
83 | "colab_type": "text",
84 | "id": "sFWHMOf2D4b1"
85 | },
86 | "source": [
87 | "8×8とサイズは小さいですが、0から9までの手書き数字の画像が表示されました。このような手書き数字の画像が、このデータセットには1797枚含まれています。 \n",
88 | "また、各画像は描かれた数字を表すラベルとペアになっています。 \n",
89 | "\n"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {
95 | "id": "w40h1X0FXmrh",
96 | "colab_type": "text"
97 | },
98 | "source": [
99 | "## データを訓練用とテスト用に分割\n",
100 | "scikit-learnのtrain_test_splitを使って、データを訓練用とテストに分割します。"
101 | ]
102 | },
103 | {
104 | "cell_type": "code",
105 | "metadata": {
106 | "id": "GLGwXks542pJ",
107 | "colab_type": "code",
108 | "colab": {}
109 | },
110 | "source": [
111 | "import torch\n",
112 | "from sklearn.model_selection import train_test_split\n",
113 | "\n",
114 | "digit_images = digits_data.data\n",
115 | "labels = digits_data.target\n",
116 | "x_train, x_test, t_train, t_test = train_test_split(digit_images, labels) # 25%がテスト用\n",
117 | "\n",
118 | "# Tensorに変換\n",
119 | "x_train = torch.tensor(x_train, dtype=torch.float32)\n",
120 | "t_train = torch.tensor(t_train, dtype=torch.int64) \n",
121 | "x_test = torch.tensor(x_test, dtype=torch.float32)\n",
122 | "t_test = torch.tensor(t_test, dtype=torch.int64) "
123 | ],
124 | "execution_count": 0,
125 | "outputs": []
126 | },
127 | {
128 | "cell_type": "markdown",
129 | "metadata": {
130 | "id": "FalXNYaJPkoE",
131 | "colab_type": "text"
132 | },
133 | "source": [
134 | "## モデルの構築\n",
135 | "`nn`モジュールの`Sequential`クラスによりモデルを構築します。"
136 | ]
137 | },
138 | {
139 | "cell_type": "code",
140 | "metadata": {
141 | "id": "SuqqZmsh_jNK",
142 | "colab_type": "code",
143 | "colab": {}
144 | },
145 | "source": [
146 | "from torch import nn\n",
147 | "\n",
148 | "net = nn.Sequential(\n",
149 | " nn.Linear(64, 32), # 全結合層\n",
150 | " nn.ReLU(), # ReLU\n",
151 | " nn.Linear(32, 16),\n",
152 | " nn.ReLU(),\n",
153 | " nn.Linear(16, 10)\n",
154 | ")\n",
155 | "print(net)"
156 | ],
157 | "execution_count": 0,
158 | "outputs": []
159 | },
160 | {
161 | "cell_type": "markdown",
162 | "metadata": {
163 | "id": "qsW5zCKhQE9p",
164 | "colab_type": "text"
165 | },
166 | "source": [
167 | "## 学習\n",
168 | "モデルを訓練します。 \n",
169 | "今回は、損失関数に交差エントロピー誤差を、最適化アルゴリズムにSGD(確率的勾配降下法)を設定します。 \n",
170 | "順伝播は訓練データ、テストデータ両者で行い誤差を計算します。 \n",
171 | "逆伝播を行うのは、訓練データのみです。 \n"
172 | ]
173 | },
174 | {
175 | "cell_type": "code",
176 | "metadata": {
177 | "id": "u6zwN3nArbGC",
178 | "colab_type": "code",
179 | "colab": {}
180 | },
181 | "source": [
182 | "from torch import optim\n",
183 | "\n",
184 | "# 交差エントロピー誤差関数\n",
185 | "loss_fnc = nn.CrossEntropyLoss()\n",
186 | "\n",
187 | "# SGD\n",
188 | "optimizer = optim.SGD(net.parameters(), lr=0.01) # 学習率は0.01\n",
189 | "\n",
190 | "# 損失のログ\n",
191 | "record_loss_train = []\n",
192 | "record_loss_test = []\n",
193 | "\n",
194 | "# 1000エポック学習\n",
195 | "for i in range(1000):\n",
196 | "\n",
197 | " # 勾配を0に\n",
198 | " optimizer.zero_grad()\n",
199 | " \n",
200 | " # 順伝播\n",
201 | " y_train = net(x_train)\n",
202 | " y_test = net(x_test)\n",
203 | " \n",
204 | " # 誤差を求める\n",
205 | " loss_train = loss_fnc(y_train, t_train)\n",
206 | " loss_test = loss_fnc(y_test, t_test)\n",
207 | " record_loss_train.append(loss_train.item())\n",
208 | " record_loss_test.append(loss_test.item())\n",
209 | "\n",
210 | " # 逆伝播(勾配を求める)\n",
211 | " loss_train.backward()\n",
212 | " \n",
213 | " # パラメータの更新\n",
214 | " optimizer.step()\n",
215 | "\n",
216 | " if i%100 == 0:\n",
217 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train.item(), \"Loss_Test:\", loss_test.item())"
218 | ],
219 | "execution_count": 0,
220 | "outputs": []
221 | },
222 | {
223 | "cell_type": "markdown",
224 | "metadata": {
225 | "id": "rJwwrWTw43rx",
226 | "colab_type": "text"
227 | },
228 | "source": [
229 | "## 誤差の推移\n",
230 | "訓練データ、テストデータで誤差の推移をグラフ表示します。 "
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "metadata": {
236 | "id": "OaJx4swE45XI",
237 | "colab_type": "code",
238 | "colab": {}
239 | },
240 | "source": [
241 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
242 | "plt.plot(range(len(record_loss_test)), record_loss_test, label=\"Test\")\n",
243 | "plt.legend()\n",
244 | "\n",
245 | "plt.xlabel(\"Epochs\")\n",
246 | "plt.ylabel(\"Error\")\n",
247 | "plt.show()"
248 | ],
249 | "execution_count": 0,
250 | "outputs": []
251 | },
252 | {
253 | "cell_type": "markdown",
254 | "metadata": {
255 | "id": "iMrpac0m4Nct",
256 | "colab_type": "text"
257 | },
258 | "source": [
259 | "## 正解率\n",
260 | "モデルの性能を把握するため、テストデータ使い正解率を測定します。 "
261 | ]
262 | },
263 | {
264 | "cell_type": "code",
265 | "metadata": {
266 | "id": "IRkGCYMM_N35",
267 | "colab_type": "code",
268 | "colab": {}
269 | },
270 | "source": [
271 | "y_test = net(x_test)\n",
272 | "count = (y_test.argmax(1) == t_test).sum().item()\n",
273 | "print(\"正解率:\", str(count/len(y_test)*100) + \"%\")"
274 | ],
275 | "execution_count": 0,
276 | "outputs": []
277 | },
278 | {
279 | "cell_type": "markdown",
280 | "metadata": {
281 | "id": "LrRAJzwD4zpN",
282 | "colab_type": "text"
283 | },
284 | "source": [
285 | "## 訓練済みのモデルを使った予測\n",
286 | "訓練済みのモデルを使ってみましょう。 \n",
287 | "画像を入力し、モデルが機能していることを確かめます。"
288 | ]
289 | },
290 | {
291 | "cell_type": "code",
292 | "metadata": {
293 | "id": "Pdy9nPckTDik",
294 | "colab_type": "code",
295 | "colab": {}
296 | },
297 | "source": [
298 | "img_id = 0\n",
299 | "x_pred = digit_images[img_id]\n",
300 | "image = x_pred.reshape(8, 8)\n",
301 | "plt.imshow(image, cmap=\"Greys_r\")\n",
302 | "plt.show()\n",
303 | "\n",
304 | "x_pred = torch.tensor(x_pred, dtype=torch.float32)\n",
305 | "y_pred = net(x_pred)\n",
306 | "print(\"正解:\", labels[img_id], \"予測結果:\", y_pred.argmax().item())"
307 | ],
308 | "execution_count": 0,
309 | "outputs": []
310 | },
311 | {
312 | "cell_type": "markdown",
313 | "metadata": {
314 | "id": "maAJN2wa0l1D",
315 | "colab_type": "text"
316 | },
317 | "source": [
318 | "このような訓練済みのモデルは、別途保存しWebアプリなどで活用することができます。"
319 | ]
320 | }
321 | ]
322 | }
--------------------------------------------------------------------------------
/lecture3/autograd.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "autograd.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "authorship_tag": "ABX9TyP9pXOTi5I2pvzOCY+CjsYB",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | }
16 | },
17 | "cells": [
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {
21 | "id": "view-in-github",
22 | "colab_type": "text"
23 | },
24 | "source": [
25 | "
"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {
31 | "id": "9FgvuyIa6oBQ",
32 | "colab_type": "text"
33 | },
34 | "source": [
35 | "# 自動微分\n",
36 | "自動微分により、ある値の微小変化が結果に与える影響を自動で計算することができます。 \n",
37 | "参考: https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html\n"
38 | ]
39 | },
40 | {
41 | "cell_type": "markdown",
42 | "metadata": {
43 | "id": "fpu9CjtSPaP8",
44 | "colab_type": "text"
45 | },
46 | "source": [
47 | "## 自動微分の開始\n",
48 | "Tensorは、requires_grad属性をTrueに設定することで計算過程が記録されるようになります。"
49 | ]
50 | },
51 | {
52 | "cell_type": "code",
53 | "metadata": {
54 | "id": "3loxKiFXYylA",
55 | "colab_type": "code",
56 | "colab": {}
57 | },
58 | "source": [
59 | "import torch\n",
60 | "\n",
61 | "x = torch.ones(2, 3, requires_grad=True)\n",
62 | "print(x)"
63 | ],
64 | "execution_count": 0,
65 | "outputs": []
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {
70 | "id": "z0aISTAIsbKK",
71 | "colab_type": "text"
72 | },
73 | "source": [
74 | "## Tensorの演算と自動微分\n",
75 | "requires_grad属性がTrueであれば、演算によりgrad_fnが記録されます。 \n",
76 | "grad_fnは、このTensorを作った演算です。 \n",
77 | "以下では、`x`に足し算を行って得られた`y`のgrad_fnを表示します。"
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "metadata": {
83 | "id": "xQpV46k3tx3R",
84 | "colab_type": "code",
85 | "colab": {}
86 | },
87 | "source": [
88 | "y = x + 2\n",
89 | "print(y)\n",
90 | "print(y.grad_fn)"
91 | ],
92 | "execution_count": 0,
93 | "outputs": []
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {
98 | "id": "9amPZxOid4w5",
99 | "colab_type": "text"
100 | },
101 | "source": [
102 | "掛け算、mean関数などの演算も、grad_fnに記録されます。"
103 | ]
104 | },
105 | {
106 | "cell_type": "code",
107 | "metadata": {
108 | "id": "EKs5LFQMt4zd",
109 | "colab_type": "code",
110 | "colab": {}
111 | },
112 | "source": [
113 | "z = y * 3\n",
114 | "print(z)\n",
115 | "\n",
116 | "out = z.mean()\n",
117 | "print(out)"
118 | ],
119 | "execution_count": 0,
120 | "outputs": []
121 | },
122 | {
123 | "cell_type": "markdown",
124 | "metadata": {
125 | "id": "83QbuM5xf2Of",
126 | "colab_type": "text"
127 | },
128 | "source": [
129 | "## 勾配の計算\n",
130 | "backwardメソッドは、逆伝播により勾配を計算します。 \n",
131 | "その際に、 記録されている演算と経路が使用されます。 \n",
132 | "以下の例では、aに2をかけてbとしていますが、backwardによりaの変化に対するbの変化の割合、すなわち勾配が計算されます。 \n"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "metadata": {
138 | "id": "7_HJnklKt7nt",
139 | "colab_type": "code",
140 | "colab": {}
141 | },
142 | "source": [
143 | "a = torch.tensor([1.0], requires_grad=True)\n",
144 | "b = a * 2 # bの変化量はaの2倍\n",
145 | "b.backward() # 逆伝播\n",
146 | "print(a.grad) # aの勾配(aの変化に対するbの変化の割合) "
147 | ],
148 | "execution_count": 0,
149 | "outputs": []
150 | },
151 | {
152 | "cell_type": "markdown",
153 | "metadata": {
154 | "id": "wBcAhTCnqA1Z",
155 | "colab_type": "text"
156 | },
157 | "source": [
158 | "より複雑な経路を持つ演算でも、backwardにより勾配を計算することができます。"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "metadata": {
164 | "id": "57kKqrGQt-SP",
165 | "colab_type": "code",
166 | "colab": {}
167 | },
168 | "source": [
169 | "def calc(a):\n",
170 | " b = a*2 + 1\n",
171 | " c = b*b \n",
172 | " d = c/(c + 2)\n",
173 | " e = d.mean()\n",
174 | " return e\n",
175 | "\n",
176 | "x = [1.0, 2.0, 3.0]\n",
177 | "x = torch.tensor(x, requires_grad=True)\n",
178 | "y = calc(x)\n",
179 | "y.backward()\n",
180 | "print(x.grad.tolist()) # xの勾配(xの各値の変化に対するyの変化の割合) "
181 | ],
182 | "execution_count": 0,
183 | "outputs": []
184 | },
185 | {
186 | "cell_type": "markdown",
187 | "metadata": {
188 | "id": "hRSyV5hSLZbO",
189 | "colab_type": "text"
190 | },
191 | "source": [
192 | "cの各値付近における勾配が計算できました。 \n",
193 | "勾配が正しく計算できていることを確認しましょう。 \n",
194 | "`x`を微小変化させて、`x`の微小変化に対する`y`の微小変化の割合を求めます。\n"
195 | ]
196 | },
197 | {
198 | "cell_type": "code",
199 | "metadata": {
200 | "id": "mtWE7zoduAnJ",
201 | "colab_type": "code",
202 | "colab": {}
203 | },
204 | "source": [
205 | "delta = 0.001 #xの微小変化\n",
206 | "\n",
207 | "x = [1.0, 2.0, 3.0]\n",
208 | "x = torch.tensor(x, requires_grad=True)\n",
209 | "y = calc(x).item()\n",
210 | "\n",
211 | "x_1 = [1.0+delta, 2.0, 3.0]\n",
212 | "x_1 = torch.tensor(x_1, requires_grad=True)\n",
213 | "y_1 = calc(x_1).item()\n",
214 | "\n",
215 | "x_2 = [1.0, 2.0+delta, 3.0]\n",
216 | "x_2 = torch.tensor(x_2, requires_grad=True)\n",
217 | "y_2 = calc(x_2).item()\n",
218 | "\n",
219 | "x_3 = [1.0, 2.0, 3.0+delta]\n",
220 | "x_3 = torch.tensor(x_3, requires_grad=True)\n",
221 | "y_3 = calc(x_3).item()\n",
222 | "\n",
223 | "# 勾配の計算\n",
224 | "grad_1 = (y_1 - y) / delta\n",
225 | "grad_2 = (y_2 - y) / delta\n",
226 | "grad_3 = (y_3 - y) / delta\n",
227 | "\n",
228 | "print(grad_1, grad_2, grad_3)"
229 | ],
230 | "execution_count": 0,
231 | "outputs": []
232 | },
233 | {
234 | "cell_type": "markdown",
235 | "metadata": {
236 | "id": "jwdACN7iWQiy",
237 | "colab_type": "text"
238 | },
239 | "source": [
240 | "`x`の微小変化を0.001という小さい値にしましたが、`y`の微小変化との割合は backwardによる計算結果とほぼ同じになりました。 \n",
241 | "backwardにより正しく勾配を計算できていることが確認できました。"
242 | ]
243 | }
244 | ]
245 | }
--------------------------------------------------------------------------------
/lecture3/dataloader.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "dataloader.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "toc_visible": true,
10 | "authorship_tag": "ABX9TyOCu7tyVRkTdeKcRjzzuBhq",
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "id": "Niaz8_W6OX34",
34 | "colab_type": "text"
35 | },
36 | "source": [
37 | "# DataLoader\n",
38 | "DataLoaderを使うと、データの読み込みやミニバッチ法の実装などが大幅に楽になります。 \n",
39 | "今回は、DataLoaderを使ってデータを扱い、手書き文字の認識を行います。 \n",
40 | "なお、今回から学習はGPUを使って行います。 \n"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {
46 | "colab_type": "text",
47 | "id": "x9Gzbn25XSlF"
48 | },
49 | "source": [
50 | "## データの読み込み\n",
51 | "`torchvision.datasets`を使って手書き文字のデータを読み込み、DataLoaderを設定します。 \n",
52 | "`torchvision.datasets`にはMNISTの他にも様々なデータセットが用意されています。 \n",
53 | "https://pytorch.org/docs/stable/torchvision/datasets.html\n"
54 | ]
55 | },
56 | {
57 | "cell_type": "code",
58 | "metadata": {
59 | "colab_type": "code",
60 | "id": "81Il03RNAmbS",
61 | "colab": {}
62 | },
63 | "source": [
64 | "import torch\n",
65 | "from torchvision.datasets import MNIST\n",
66 | "from torchvision import transforms\n",
67 | "from torch.utils.data import DataLoader\n",
68 | "\n",
69 | "# 訓練データを取得\n",
70 | "mnist_train = MNIST(\"./data\", \n",
71 | " train=True, download=True,\n",
72 | " transform=transforms.ToTensor())\n",
73 | "# テストデータの取得\n",
74 | "mnist_test = MNIST(\"./data\",\n",
75 | " train=False, download=True,\n",
76 | " transform=transforms.ToTensor())\n",
77 | "print(\"訓練データの数:\", len(mnist_train), \"テストデータの数:\", len(mnist_test))\n",
78 | "\n",
79 | "# DataLoaderの設定\n",
80 | "img_size = 28\n",
81 | "batch_size = 256\n",
82 | "train_loader = DataLoader(mnist_train, \n",
83 | " batch_size=batch_size,\n",
84 | " shuffle=True)\n",
85 | "test_loader = DataLoader(mnist_test,\n",
86 | " batch_size=batch_size,\n",
87 | " shuffle=False)"
88 | ],
89 | "execution_count": 0,
90 | "outputs": []
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {
95 | "colab_type": "text",
96 | "id": "sFWHMOf2D4b1"
97 | },
98 | "source": [
99 | "手書き文字の画像サイズは、28×28になります。 \n",
100 | "\n"
101 | ]
102 | },
103 | {
104 | "cell_type": "markdown",
105 | "metadata": {
106 | "id": "FalXNYaJPkoE",
107 | "colab_type": "text"
108 | },
109 | "source": [
110 | "## モデルの構築\n",
111 | "今回は、`nn.Module`モジュールを継承したクラスとして、モデルを構築します。 \n",
112 | "`.cuda()`により、モデルの計算はGPU上で行われるようになります。 "
113 | ]
114 | },
115 | {
116 | "cell_type": "code",
117 | "metadata": {
118 | "id": "SuqqZmsh_jNK",
119 | "colab_type": "code",
120 | "colab": {}
121 | },
122 | "source": [
123 | "import torch.nn as nn\n",
124 | "import torch.nn.functional as F\n",
125 | "\n",
126 | "class Net(nn.Module):\n",
127 | " def __init__(self):\n",
128 | " super().__init__()\n",
129 | " self.fc1 = nn.Linear(img_size*img_size, 1024) # 全結合層\n",
130 | " self.fc2 = nn.Linear(1024, 512)\n",
131 | " self.fc3 = nn.Linear(512, 10)\n",
132 | "\n",
133 | " def forward(self, x):\n",
134 | " x = x.view(-1, img_size*img_size) # バッチサイズ×入力の数\n",
135 | " x = F.relu(self.fc1(x))\n",
136 | " x = F.relu(self.fc2(x))\n",
137 | " x = self.fc3(x)\n",
138 | " return x\n",
139 | "\n",
140 | "net = Net()\n",
141 | "net.cuda() # GPU対応\n",
142 | "print(net)"
143 | ],
144 | "execution_count": 0,
145 | "outputs": []
146 | },
147 | {
148 | "cell_type": "markdown",
149 | "metadata": {
150 | "id": "qsW5zCKhQE9p",
151 | "colab_type": "text"
152 | },
153 | "source": [
154 | "## 学習\n",
155 | "モデルを訓練します。 \n",
156 | "DataLoaderを使い、ミニバッチを取り出して訓練および評価を行います。 \n",
157 | "1エポックの中で何度もミニバッチを使って訓練が行われるので、ミニバッチ法が実装されていることになります。 \n",
158 | "学習には時間がかかりますので、編集→ノートブックの設定のハードウェアアクセラレーターでGPUを選択しましょう。\n"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "metadata": {
164 | "id": "u6zwN3nArbGC",
165 | "colab_type": "code",
166 | "colab": {}
167 | },
168 | "source": [
169 | "from torch import optim\n",
170 | "\n",
171 | "# 交差エントロピー誤差関数\n",
172 | "loss_fnc = nn.CrossEntropyLoss()\n",
173 | "\n",
174 | "# SGD\n",
175 | "optimizer = optim.SGD(net.parameters(), lr=0.01)\n",
176 | "\n",
177 | "# 損失のログ\n",
178 | "record_loss_train = []\n",
179 | "record_loss_test = []\n",
180 | "\n",
181 | "# 学習\n",
182 | "for i in range(10): # 10エポック学習\n",
183 | " net.train() # 訓練モード\n",
184 | " loss_train = 0\n",
185 | " for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す\n",
186 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
187 | " y = net(x)\n",
188 | " loss = loss_fnc(y, t)\n",
189 | " loss_train += loss.item()\n",
190 | " optimizer.zero_grad()\n",
191 | " loss.backward()\n",
192 | " optimizer.step()\n",
193 | " loss_train /= j+1\n",
194 | " record_loss_train.append(loss_train)\n",
195 | "\n",
196 | " net.eval() # 評価モード\n",
197 | " loss_test = 0\n",
198 | " for j, (x, t) in enumerate(test_loader): # ミニバッチ(x, t)を取り出す\n",
199 | " x, t = x.cuda(), t.cuda()\n",
200 | " y = net(x)\n",
201 | " loss = loss_fnc(y, t)\n",
202 | " loss_test += loss.item()\n",
203 | " loss_test /= j+1\n",
204 | " record_loss_test.append(loss_test)\n",
205 | "\n",
206 | " if i%1 == 0:\n",
207 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train, \"Loss_Test:\", loss_test)"
208 | ],
209 | "execution_count": 0,
210 | "outputs": []
211 | },
212 | {
213 | "cell_type": "markdown",
214 | "metadata": {
215 | "id": "rJwwrWTw43rx",
216 | "colab_type": "text"
217 | },
218 | "source": [
219 | "## 誤差の推移\n",
220 | "訓練データ、テストデータで誤差の推移をグラフ表示します。 "
221 | ]
222 | },
223 | {
224 | "cell_type": "code",
225 | "metadata": {
226 | "id": "OaJx4swE45XI",
227 | "colab_type": "code",
228 | "colab": {}
229 | },
230 | "source": [
231 | "import matplotlib.pyplot as plt\n",
232 | "\n",
233 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
234 | "plt.plot(range(len(record_loss_test)), record_loss_test, label=\"Test\")\n",
235 | "plt.legend()\n",
236 | "\n",
237 | "plt.xlabel(\"Epochs\")\n",
238 | "plt.ylabel(\"Error\")\n",
239 | "plt.show()"
240 | ],
241 | "execution_count": 0,
242 | "outputs": []
243 | },
244 | {
245 | "cell_type": "markdown",
246 | "metadata": {
247 | "id": "iMrpac0m4Nct",
248 | "colab_type": "text"
249 | },
250 | "source": [
251 | "## 正解率\n",
252 | "モデルの性能を把握するため、テストデータ使い正解率を測定します。 "
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "metadata": {
258 | "id": "IRkGCYMM_N35",
259 | "colab_type": "code",
260 | "colab": {}
261 | },
262 | "source": [
263 | "correct = 0\n",
264 | "total = 0\n",
265 | "for i, (x, t) in enumerate(test_loader):\n",
266 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
267 | " x = x.view(-1, img_size*img_size)\n",
268 | " y = net(x)\n",
269 | " correct += (y.argmax(1) == t).sum().item()\n",
270 | " total += len(x)\n",
271 | "print(\"正解率:\", str(correct/total*100) + \"%\")"
272 | ],
273 | "execution_count": 0,
274 | "outputs": []
275 | }
276 | ]
277 | }
--------------------------------------------------------------------------------
/lecture3/exercise.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "exercise.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "toc_visible": true,
10 | "authorship_tag": "ABX9TyPF5BEFzOOufGQ17KC2OPFG",
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "id": "Niaz8_W6OX34",
34 | "colab_type": "text"
35 | },
36 | "source": [
37 | "# 演習\n",
38 | "DataLoaderの扱いに慣れていきましょう。 \n",
39 | "DataLoaderのコードを書いて、データの読み込みとミニバッチ法の実装を行います。\n",
40 | "\n"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {
46 | "colab_type": "text",
47 | "id": "x9Gzbn25XSlF"
48 | },
49 | "source": [
50 | "## データの読み込み\n",
51 | "以下のセルにコードを追記し、DataLoaderの設定を行いましょう。 \n",
52 | "以下のセルの`mnist_train`と`mnist_test`に対してDataLoaderを設定します。 "
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "metadata": {
58 | "colab_type": "code",
59 | "id": "81Il03RNAmbS",
60 | "colab": {}
61 | },
62 | "source": [
63 | "import torch\n",
64 | "from torchvision.datasets import MNIST\n",
65 | "from torchvision import transforms\n",
66 | "from torch.utils.data import DataLoader\n",
67 | "\n",
68 | "# 訓練データを取得\n",
69 | "mnist_train = MNIST(\"./data\", \n",
70 | " train=True, download=True,\n",
71 | " transform=transforms.ToTensor())\n",
72 | "# テストデータの取得\n",
73 | "mnist_test = MNIST(\"./data\",\n",
74 | " train=False, download=True,\n",
75 | " transform=transforms.ToTensor())\n",
76 | "print(\"訓練データの数:\", len(mnist_train), \"テストデータの数:\", len(mnist_test))\n",
77 | "\n",
78 | "# DataLoaderの設定\n",
79 | "img_size = 28\n",
80 | "batch_size = 128\n",
81 | "# ------- 以下にコードを書く -------\n",
82 | "\n",
83 | "\n",
84 | "\n",
85 | "\n",
86 | "# ------- ここまで -------"
87 | ],
88 | "execution_count": 0,
89 | "outputs": []
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {
94 | "id": "FalXNYaJPkoE",
95 | "colab_type": "text"
96 | },
97 | "source": [
98 | "## モデルの構築"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "metadata": {
104 | "id": "SuqqZmsh_jNK",
105 | "colab_type": "code",
106 | "colab": {}
107 | },
108 | "source": [
109 | "import torch.nn as nn\n",
110 | "import torch.nn.functional as F\n",
111 | "\n",
112 | "class Net(nn.Module):\n",
113 | " def __init__(self):\n",
114 | " super().__init__()\n",
115 | " self.fc1 = nn.Linear(img_size*img_size, 1024) # 全結合層\n",
116 | " self.fc2 = nn.Linear(1024, 512)\n",
117 | " self.fc3 = nn.Linear(512, 10)\n",
118 | "\n",
119 | " def forward(self, x):\n",
120 | " x = x.view(-1, img_size*img_size) # バッチサイズ×入力の数\n",
121 | " x = F.relu(self.fc1(x))\n",
122 | " x = F.relu(self.fc2(x))\n",
123 | " x = self.fc3(x)\n",
124 | " return x\n",
125 | "\n",
126 | "net = Net()\n",
127 | "net.cuda() # GPU対応\n",
128 | "print(net)"
129 | ],
130 | "execution_count": 0,
131 | "outputs": []
132 | },
133 | {
134 | "cell_type": "markdown",
135 | "metadata": {
136 | "id": "qsW5zCKhQE9p",
137 | "colab_type": "text"
138 | },
139 | "source": [
140 | "## 学習\n",
141 | "訓練および検証の箇所にfor文のコードを追記し、DataLoaderを使ったミニバッチ法を実装しましょう。 \n"
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "metadata": {
147 | "id": "u6zwN3nArbGC",
148 | "colab_type": "code",
149 | "colab": {}
150 | },
151 | "source": [
152 | "from torch import optim\n",
153 | "import time\n",
154 | "\n",
155 | "# 交差エントロピー誤差関数\n",
156 | "loss_fnc = nn.CrossEntropyLoss()\n",
157 | "\n",
158 | "# SGD\n",
159 | "optimizer = optim.SGD(net.parameters(), lr=0.01)\n",
160 | "\n",
161 | "# 損失のログ\n",
162 | "record_loss_train = []\n",
163 | "record_loss_test = []\n",
164 | "\n",
165 | "# 学習\n",
166 | "for i in range(10): # 10エポック学習\n",
167 | " net.train() # 訓練モード\n",
168 | " loss_train = 0\n",
169 | " # ← 左にfor文のコードを追記\n",
170 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
171 | " y = net(x)\n",
172 | " loss = loss_fnc(y, t)\n",
173 | " loss_train += loss.item()\n",
174 | " optimizer.zero_grad()\n",
175 | " loss.backward()\n",
176 | " optimizer.step()\n",
177 | " loss_train /= j+1\n",
178 | " record_loss_train.append(loss_train)\n",
179 | "\n",
180 | " net.eval() # 評価モード\n",
181 | " loss_test = 0\n",
182 | " # ← 左にfor文のコードを追記\n",
183 | " x, t = x.cuda(), t.cuda()\n",
184 | " y = net(x)\n",
185 | " loss = loss_fnc(y, t)\n",
186 | " loss_test += loss.item()\n",
187 | " loss_test /= j+1\n",
188 | " record_loss_test.append(loss_test)\n",
189 | "\n",
190 | " if i%1 == 0:\n",
191 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train, \"Loss_Test:\", loss_test)"
192 | ],
193 | "execution_count": 0,
194 | "outputs": []
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {
199 | "id": "rJwwrWTw43rx",
200 | "colab_type": "text"
201 | },
202 | "source": [
203 | "## 誤差の推移"
204 | ]
205 | },
206 | {
207 | "cell_type": "code",
208 | "metadata": {
209 | "id": "OaJx4swE45XI",
210 | "colab_type": "code",
211 | "colab": {}
212 | },
213 | "source": [
214 | "import matplotlib.pyplot as plt\n",
215 | "\n",
216 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
217 | "plt.plot(range(len(record_loss_test)), record_loss_test, label=\"Test\")\n",
218 | "plt.legend()\n",
219 | "\n",
220 | "plt.xlabel(\"Epochs\")\n",
221 | "plt.ylabel(\"Error\")\n",
222 | "plt.show()"
223 | ],
224 | "execution_count": 0,
225 | "outputs": []
226 | },
227 | {
228 | "cell_type": "markdown",
229 | "metadata": {
230 | "id": "iMrpac0m4Nct",
231 | "colab_type": "text"
232 | },
233 | "source": [
234 | "## 正解率"
235 | ]
236 | },
237 | {
238 | "cell_type": "code",
239 | "metadata": {
240 | "id": "IRkGCYMM_N35",
241 | "colab_type": "code",
242 | "colab": {}
243 | },
244 | "source": [
245 | "correct = 0\n",
246 | "total = 0\n",
247 | "for i, (x, t) in enumerate(test_loader):\n",
248 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
249 | " x = x.view(-1, img_size*img_size)\n",
250 | " y = net(x)\n",
251 | " correct += (y.argmax(1) == t).sum().item()\n",
252 | " total += len(x)\n",
253 | "print(\"正解率:\", str(correct/total*100) + \"%\")"
254 | ],
255 | "execution_count": 0,
256 | "outputs": []
257 | },
258 | {
259 | "cell_type": "markdown",
260 | "metadata": {
261 | "id": "maAJN2wa0l1D",
262 | "colab_type": "text"
263 | },
264 | "source": [
265 | "# 解答例\n",
266 | "以下は、どうしても手がかりがないときのみ参考にしましょう。"
267 | ]
268 | },
269 | {
270 | "cell_type": "code",
271 | "metadata": {
272 | "id": "rQagvzyDmDA5",
273 | "colab_type": "code",
274 | "colab": {}
275 | },
276 | "source": [
277 | "import torch\n",
278 | "from torchvision.datasets import MNIST\n",
279 | "from torchvision import transforms\n",
280 | "from torch.utils.data import DataLoader\n",
281 | "\n",
282 | "# 訓練データを取得\n",
283 | "mnist_train = MNIST(\"./data\", \n",
284 | " train=True, download=True,\n",
285 | " transform=transforms.ToTensor())\n",
286 | "# テストデータの取得\n",
287 | "mnist_test = MNIST(\"./data\",\n",
288 | " train=False, download=True,\n",
289 | " transform=transforms.ToTensor())\n",
290 | "print(\"訓練データの数:\", len(mnist_train), \"テストデータの数:\", len(mnist_test))\n",
291 | "\n",
292 | "# DataLoaderの設定\n",
293 | "img_size = 28\n",
294 | "batch_size = 128\n",
295 | "# ------- 以下にコードを書く -------\n",
296 | "train_loader = DataLoader(mnist_train, \n",
297 | " batch_size=batch_size,\n",
298 | " shuffle=True)\n",
299 | "test_loader = DataLoader(mnist_test,\n",
300 | " batch_size=batch_size,\n",
301 | " shuffle=False)\n",
302 | "# ------- ここまで -------"
303 | ],
304 | "execution_count": 0,
305 | "outputs": []
306 | },
307 | {
308 | "cell_type": "code",
309 | "metadata": {
310 | "id": "gYHIvyIijc5S",
311 | "colab_type": "code",
312 | "colab": {}
313 | },
314 | "source": [
315 | "from torch import optim\n",
316 | "import time\n",
317 | "\n",
318 | "# 交差エントロピー誤差関数\n",
319 | "loss_fnc = nn.CrossEntropyLoss()\n",
320 | "\n",
321 | "# SGD\n",
322 | "optimizer = optim.SGD(net.parameters(), lr=0.01)\n",
323 | "\n",
324 | "# 損失のログ\n",
325 | "record_loss_train = []\n",
326 | "record_loss_test = []\n",
327 | "\n",
328 | "# 学習\n",
329 | "for i in range(10): # 10エポック学習\n",
330 | " net.train() # 訓練モード\n",
331 | " loss_train = 0\n",
332 | " for j, (x, t) in enumerate(train_loader): # ← 左にfor文のコードを追記\n",
333 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
334 | " y = net(x)\n",
335 | " loss = loss_fnc(y, t)\n",
336 | " loss_train += loss.item()\n",
337 | " optimizer.zero_grad()\n",
338 | " loss.backward()\n",
339 | " optimizer.step()\n",
340 | " loss_train /= j+1\n",
341 | " record_loss_train.append(loss_train)\n",
342 | "\n",
343 | " net.eval() # 評価モード\n",
344 | " loss_test = 0\n",
345 | " for j, (x, t) in enumerate(test_loader): # ← 左にfor文のコードを追記\n",
346 | " x, t = x.cuda(), t.cuda()\n",
347 | " y = net(x)\n",
348 | " loss = loss_fnc(y, t)\n",
349 | " loss_test += loss.item()\n",
350 | " loss_test /= j+1\n",
351 | " record_loss_test.append(loss_test)\n",
352 | "\n",
353 | " if i%1 == 0:\n",
354 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train, \"Loss_Test:\", loss_test)"
355 | ],
356 | "execution_count": 0,
357 | "outputs": []
358 | }
359 | ]
360 | }
--------------------------------------------------------------------------------
/lecture4/cnn.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "cnn.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "toc_visible": true,
10 | "authorship_tag": "ABX9TyP1JUkF4cGqlrgSjejGCxlS",
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "id": "Niaz8_W6OX34",
34 | "colab_type": "text"
35 | },
36 | "source": [
37 | "# CNNの実装\n",
38 | "PyTorchを使って、畳み込みニューラルネットワーク(CNN)を実装します。 \n",
39 | "CNN自体はCNNの層を追加するのみで実装可能なのですが、今回はデータ拡張とドロップアウトの実装も行います。\n"
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {
45 | "id": "jpMObJX-c6CW",
46 | "colab_type": "text"
47 | },
48 | "source": [
49 | "## CIFAR-10\n",
50 | "torchvision.datasetsを使い、CIFAR-10を読み込みます。 \n",
51 | "CIFARは、約6万枚の画像にラベルをつけたたデータセットです。 \n",
52 | "以下のコードでは、CIFAR-10を読み込み、ランダムな25枚の画像を表示します。"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "metadata": {
58 | "id": "CbolmAveUtJ4",
59 | "colab_type": "code",
60 | "colab": {}
61 | },
62 | "source": [
63 | "from torchvision.datasets import CIFAR10\n",
64 | "import torchvision.transforms as transforms\n",
65 | "from torch.utils.data import DataLoader\n",
66 | "import numpy as np\n",
67 | "import matplotlib.pyplot as plt\n",
68 | "\n",
69 | "cifar10_data = CIFAR10(root=\"./data\",\n",
70 | " train=False,download=True,\n",
71 | " transform=transforms.ToTensor())\n",
72 | "cifar10_classes = np.array([\"airplane\", \"automobile\", \"bird\", \"cat\", \"deer\",\n",
73 | " \"dog\", \"frog\", \"horse\", \"ship\", \"truck\"])\n",
74 | "print(\"データの数:\", len(cifar10_data))\n",
75 | "\n",
76 | "n_image = 25 # 表示する画像の数\n",
77 | "cifar10_loader = DataLoader(cifar10_data, batch_size=n_image, shuffle=True)\n",
78 | "dataiter = iter(cifar10_loader) # イテレータ\n",
79 | "images, labels = dataiter.next() # 最初のバッチを取り出す\n",
80 | "\n",
81 | "plt.figure(figsize=(10,10)) # 画像の表示サイズ\n",
82 | "for i in range(n_image):\n",
83 | " plt.subplot(5,5,i+1)\n",
84 | " plt.imshow(np.transpose(images[i], (1, 2, 0))) # チャンネルを一番後ろに\n",
85 | " label = cifar10_classes[labels[i]]\n",
86 | " plt.title(label)\n",
87 | " plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False) # ラベルとメモリを非表示に\n",
88 | "\n",
89 | "plt.show()"
90 | ],
91 | "execution_count": 0,
92 | "outputs": []
93 | },
94 | {
95 | "cell_type": "markdown",
96 | "metadata": {
97 | "id": "24KV93msd3i-",
98 | "colab_type": "text"
99 | },
100 | "source": [
101 | "## データ拡張\n",
102 | "torchvision.transformsを使ってデータ拡張を行います。 \n",
103 | "今回は、cifar-10の画像に-30〜30°の回転、および0.8〜1.2倍のリサイズを行います。 \n",
104 | "これらの処理は、バッチを取り出す際に元の画像に対してランダムに加えられます。 \n"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "metadata": {
110 | "id": "TVWgInj2luno",
111 | "colab_type": "code",
112 | "colab": {}
113 | },
114 | "source": [
115 | "from torchvision.datasets import CIFAR10\n",
116 | "import torchvision.transforms as transforms\n",
117 | "from torch.utils.data import DataLoader\n",
118 | "import numpy as np\n",
119 | "import matplotlib.pyplot as plt\n",
120 | "\n",
121 | "transform = transforms.Compose([transforms.RandomAffine([-30, 30], scale=(0.8, 1.2)), # 回転とリサイズ\n",
122 | " transforms.ToTensor()])\n",
123 | "cifar10_data = CIFAR10(root=\"./data\",\n",
124 | " train=False,download=True,\n",
125 | " transform=transform)\n",
126 | "cifar10_classes = np.array([\"airplane\", \"automobile\", \"bird\", \"cat\", \"deer\",\n",
127 | " \"dog\", \"frog\", \"horse\", \"ship\", \"truck\"])\n",
128 | "print(\"データの数:\", len(cifar10_data))\n",
129 | "\n",
130 | "n_image = 25 # 表示する画像の数\n",
131 | "cifar10_loader = DataLoader(cifar10_data, batch_size=n_image, shuffle=True)\n",
132 | "dataiter = iter(cifar10_loader) # イテレータ\n",
133 | "images, labels = dataiter.next() # 最初のバッチを取り出す\n",
134 | "\n",
135 | "plt.figure(figsize=(10,10)) # 画像の表示サイズ\n",
136 | "for i in range(n_image):\n",
137 | " plt.subplot(5,5,i+1)\n",
138 | " plt.imshow(np.transpose(images[i], (1, 2, 0))) # チャンネルを一番後ろに\n",
139 | " label = cifar10_classes[labels[i]]\n",
140 | " plt.title(label)\n",
141 | " plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False) # ラベルとメモリを非表示に\n",
142 | "\n",
143 | "plt.show()"
144 | ],
145 | "execution_count": 0,
146 | "outputs": []
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {
151 | "id": "vsncPqQ-gZJr",
152 | "colab_type": "text"
153 | },
154 | "source": [
155 | "## データの前処理\n",
156 | "ここからCNNを実装します。 \n",
157 | "データ拡張として、回転とリサイズ、および左右反転を行います。 \n",
158 | "また、学習が効率的になるように入力の平均値を0、標準偏差を1にします(標準化)。 \n",
159 | "DataLoaderは、訓練データ、テストデータそれぞれで設定しますが、テストデータにはミニバッチ法を適用しないのでバッチサイズは元データのサンプル数にします。"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "metadata": {
165 | "id": "7t3NRHjhKyC0",
166 | "colab_type": "code",
167 | "colab": {}
168 | },
169 | "source": [
170 | "from torchvision.datasets import CIFAR10\n",
171 | "import torchvision.transforms as transforms\n",
172 | "from torch.utils.data import DataLoader\n",
173 | "\n",
174 | "affine = transforms.RandomAffine([-15, 15], scale=(0.8, 1.2)) # 回転とリサイズ\n",
175 | "flip = transforms.RandomHorizontalFlip(p=0.5) # 左右反転\n",
176 | "normalize = transforms.Normalize((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)) # 平均値を0、標準偏差を1に\n",
177 | "to_tensor = transforms.ToTensor()\n",
178 | "\n",
179 | "transform_train = transforms.Compose([affine, flip, to_tensor, normalize])\n",
180 | "transform_test = transforms.Compose([to_tensor, normalize])\n",
181 | "cifar10_train = CIFAR10(\"./data\", train=True, download=True, transform=transform_train)\n",
182 | "cifar10_test = CIFAR10(\"./data\", train=False, download=True, transform=transform_test)\n",
183 | "\n",
184 | "# DataLoaderの設定\n",
185 | "batch_size = 64\n",
186 | "train_loader = DataLoader(cifar10_train, batch_size=batch_size, shuffle=True)\n",
187 | "test_loader = DataLoader(cifar10_test, batch_size=len(cifar10_test), shuffle=False)"
188 | ],
189 | "execution_count": 0,
190 | "outputs": []
191 | },
192 | {
193 | "cell_type": "markdown",
194 | "metadata": {
195 | "id": "FalXNYaJPkoE",
196 | "colab_type": "text"
197 | },
198 | "source": [
199 | "## モデルの構築\n",
200 | "`nn.Module`モジュールを継承したクラスとして、モデルを構築します。 \n",
201 | "今回は、過学習を抑制するためにドロップアウトを導入します。 "
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "metadata": {
207 | "id": "SuqqZmsh_jNK",
208 | "colab_type": "code",
209 | "colab": {}
210 | },
211 | "source": [
212 | "import torch.nn as nn\n",
213 | "import torch.nn.functional as F\n",
214 | "\n",
215 | "class Net(nn.Module):\n",
216 | " def __init__(self):\n",
217 | " super().__init__()\n",
218 | " self.conv1 = nn.Conv2d(3, 6, 5) # 畳み込み層:(入力チャンネル数, フィルタ数、フィルタサイズ)\n",
219 | " self.pool = nn.MaxPool2d(2, 2) # プーリング層:(領域のサイズ, ストライド)\n",
220 | " self.conv2 = nn.Conv2d(6, 16, 5)\n",
221 | " self.fc1 = nn.Linear(16*5*5, 256) # 全結合層\n",
222 | " self.dropout = nn.Dropout(p=0.5) # ドロップアウト:(p=ドロップアウト率)\n",
223 | " self.fc2 = nn.Linear(256, 10)\n",
224 | "\n",
225 | " def forward(self, x):\n",
226 | " x = self.pool(F.relu(self.conv1(x)))\n",
227 | " x = self.pool(F.relu(self.conv2(x)))\n",
228 | " x = x.view(-1, 16*5*5)\n",
229 | " x = F.relu(self.fc1(x))\n",
230 | " x = self.dropout(x)\n",
231 | " x = self.fc2(x)\n",
232 | " return x\n",
233 | "\n",
234 | "net = Net()\n",
235 | "net.cuda() # GPU対応\n",
236 | "print(net)"
237 | ],
238 | "execution_count": 0,
239 | "outputs": []
240 | },
241 | {
242 | "cell_type": "markdown",
243 | "metadata": {
244 | "id": "qsW5zCKhQE9p",
245 | "colab_type": "text"
246 | },
247 | "source": [
248 | "## 学習\n",
249 | "モデルを訓練します。 \n",
250 | "DataLoaderを使い、ミニバッチを取り出して訓練および評価を行います。 \n",
251 | "今回は、評価時にミニバッチ法は使わず、テストデータ全体を使って一度に誤差を計算します。 \n",
252 | "学習には時間がかかりますので、編集→ノートブックの設定のハードウェアアクセラレーターでGPUを選択しましょう。\n"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "metadata": {
258 | "id": "u6zwN3nArbGC",
259 | "colab_type": "code",
260 | "colab": {}
261 | },
262 | "source": [
263 | "from torch import optim\n",
264 | "\n",
265 | "# 交差エントロピー誤差関数\n",
266 | "loss_fnc = nn.CrossEntropyLoss()\n",
267 | "\n",
268 | "# 最適化アルゴリズム\n",
269 | "optimizer = optim.Adam(net.parameters())\n",
270 | "\n",
271 | "# 損失のログ\n",
272 | "record_loss_train = []\n",
273 | "record_loss_test = []\n",
274 | "\n",
275 | "# 学習\n",
276 | "x_test, t_test = iter(test_loader).next()\n",
277 | "x_test, t_test = x_test.cuda(), t_test.cuda()\n",
278 | "for i in range(20): # 20エポック学習\n",
279 | " net.train() # 訓練モード\n",
280 | " loss_train = 0\n",
281 | " for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す\n",
282 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
283 | " y = net(x)\n",
284 | " loss = loss_fnc(y, t)\n",
285 | " loss_train += loss.item()\n",
286 | " optimizer.zero_grad()\n",
287 | " loss.backward()\n",
288 | " optimizer.step()\n",
289 | " loss_train /= j+1\n",
290 | " record_loss_train.append(loss_train)\n",
291 | "\n",
292 | " net.eval() # 評価モード\n",
293 | " y_test = net(x_test)\n",
294 | " loss_test = loss_fnc(y_test, t_test).item()\n",
295 | " record_loss_test.append(loss_test)\n",
296 | "\n",
297 | " if i%1 == 0:\n",
298 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train, \"Loss_Test:\", loss_test)"
299 | ],
300 | "execution_count": 0,
301 | "outputs": []
302 | },
303 | {
304 | "cell_type": "markdown",
305 | "metadata": {
306 | "id": "rJwwrWTw43rx",
307 | "colab_type": "text"
308 | },
309 | "source": [
310 | "## 誤差の推移\n",
311 | "訓練データ、テストデータで誤差の推移をグラフ表示します。 "
312 | ]
313 | },
314 | {
315 | "cell_type": "code",
316 | "metadata": {
317 | "id": "OaJx4swE45XI",
318 | "colab_type": "code",
319 | "colab": {}
320 | },
321 | "source": [
322 | "import matplotlib.pyplot as plt\n",
323 | "\n",
324 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
325 | "plt.plot(range(len(record_loss_test)), record_loss_test, label=\"Test\")\n",
326 | "plt.legend()\n",
327 | "\n",
328 | "plt.xlabel(\"Epochs\")\n",
329 | "plt.ylabel(\"Error\")\n",
330 | "plt.show()"
331 | ],
332 | "execution_count": 0,
333 | "outputs": []
334 | },
335 | {
336 | "cell_type": "markdown",
337 | "metadata": {
338 | "id": "iMrpac0m4Nct",
339 | "colab_type": "text"
340 | },
341 | "source": [
342 | "## 正解率\n",
343 | "モデルの性能を把握するため、テストデータ使い正解率を測定します。 "
344 | ]
345 | },
346 | {
347 | "cell_type": "code",
348 | "metadata": {
349 | "id": "IRkGCYMM_N35",
350 | "colab_type": "code",
351 | "colab": {}
352 | },
353 | "source": [
354 | "correct = 0\n",
355 | "total = 0\n",
356 | "net.eval() # 評価モード\n",
357 | "for i, (x, t) in enumerate(test_loader):\n",
358 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
359 | " y = net(x)\n",
360 | " correct += (y.argmax(1) == t).sum().item()\n",
361 | " total += len(x)\n",
362 | "print(\"正解率:\", str(correct/total*100) + \"%\")"
363 | ],
364 | "execution_count": 0,
365 | "outputs": []
366 | },
367 | {
368 | "cell_type": "markdown",
369 | "metadata": {
370 | "id": "LrRAJzwD4zpN",
371 | "colab_type": "text"
372 | },
373 | "source": [
374 | "## 訓練済みのモデルを使った予測\n",
375 | "訓練済みのモデルを使ってみましょう。 \n",
376 | "画像を入力し、モデルが機能していることを確かめます。"
377 | ]
378 | },
379 | {
380 | "cell_type": "code",
381 | "metadata": {
382 | "id": "Pdy9nPckTDik",
383 | "colab_type": "code",
384 | "colab": {}
385 | },
386 | "source": [
387 | "cifar10_loader = DataLoader(cifar10_test, batch_size=1, shuffle=True)\n",
388 | "dataiter = iter(cifar10_loader)\n",
389 | "images, labels = dataiter.next() # サンプルを1つだけ取り出す\n",
390 | "\n",
391 | "plt.imshow(np.transpose(images[0], (1, 2, 0))) # チャンネルを一番後ろに\n",
392 | "plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False) # ラベルとメモリを非表示に\n",
393 | "plt.show()\n",
394 | "\n",
395 | "net.eval() # 評価モード\n",
396 | "x, t = images.cuda(), labels.cuda() # GPU対応\n",
397 | "y = net(x)\n",
398 | "print(\"正解:\", cifar10_classes[labels[0]],\n",
399 | " \"予測結果:\", cifar10_classes[y.argmax().item()])"
400 | ],
401 | "execution_count": 0,
402 | "outputs": []
403 | }
404 | ]
405 | }
--------------------------------------------------------------------------------
/lecture4/exercise.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "exercise.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "toc_visible": true,
10 | "authorship_tag": "ABX9TyOh/sBj5jvoGU7U5d6pgQvY",
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "id": "Niaz8_W6OX34",
34 | "colab_type": "text"
35 | },
36 | "source": [
37 | "# 演習\n",
38 | "新たなデータ拡張を追加し、CNNのモデルを構築しましょう。 \n"
39 | ]
40 | },
41 | {
42 | "cell_type": "markdown",
43 | "metadata": {
44 | "id": "24KV93msd3i-",
45 | "colab_type": "text"
46 | },
47 | "source": [
48 | "## 領域のランダムな消去\n",
49 | "新たにデータ拡張を追加します。 \n",
50 | "transforms.RandomErasingにより、画像の領域がランダムに消去されます。 \n",
51 | "https://pytorch.org/docs/stable/torchvision/transforms.html#torchvision.transforms.RandomErasing\n"
52 | ]
53 | },
54 | {
55 | "cell_type": "code",
56 | "metadata": {
57 | "id": "TVWgInj2luno",
58 | "colab_type": "code",
59 | "colab": {}
60 | },
61 | "source": [
62 | "from torchvision.datasets import CIFAR10\n",
63 | "import torchvision.transforms as transforms\n",
64 | "from torch.utils.data import DataLoader\n",
65 | "import numpy as np\n",
66 | "import matplotlib.pyplot as plt\n",
67 | "\n",
68 | "transform = transforms.Compose([\n",
69 | " transforms.RandomAffine([-30, 30], scale=(0.8, 1.2)), # 回転とリサイズ\n",
70 | " transforms.ToTensor(),\n",
71 | " transforms.RandomErasing(p=0.5)]) # 確率0.5でランダムに領域を消去\n",
72 | "cifar10_data = CIFAR10(root=\"./data\",\n",
73 | " train=False,download=True,\n",
74 | " transform=transform)\n",
75 | "cifar10_classes = np.array([\"airplane\", \"automobile\", \"bird\", \"cat\", \"deer\",\n",
76 | " \"dog\", \"frog\", \"horse\", \"ship\", \"truck\"])\n",
77 | "print(\"データの数:\", len(cifar10_data))\n",
78 | "\n",
79 | "n_image = 25 # 表示する画像の数\n",
80 | "cifar10_loader = DataLoader(cifar10_data, batch_size=n_image, shuffle=True)\n",
81 | "dataiter = iter(cifar10_loader) # イテレータ\n",
82 | "images, labels = dataiter.next() # 最初のバッチを取り出す\n",
83 | "\n",
84 | "plt.figure(figsize=(10,10)) # 画像の表示サイズ\n",
85 | "for i in range(n_image):\n",
86 | " plt.subplot(5,5,i+1)\n",
87 | " plt.imshow(np.transpose(images[i], (1, 2, 0))) # チャンネルを一番後ろに\n",
88 | " label = cifar10_classes[labels[i]]\n",
89 | " plt.title(label)\n",
90 | " plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False) # ラベルとメモリを非表示に\n",
91 | "\n",
92 | "plt.show()"
93 | ],
94 | "execution_count": 0,
95 | "outputs": []
96 | },
97 | {
98 | "cell_type": "markdown",
99 | "metadata": {
100 | "id": "vsncPqQ-gZJr",
101 | "colab_type": "text"
102 | },
103 | "source": [
104 | "## データの前処理\n",
105 | "ここからCNNを実装していきます。 \n",
106 | "以下のセルにコードを追記し、データ拡張の一環としてtransforms.RandomErasingによるランダムな画像領域の消去を実装しましょう。"
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "metadata": {
112 | "id": "7t3NRHjhKyC0",
113 | "colab_type": "code",
114 | "colab": {}
115 | },
116 | "source": [
117 | "from torchvision.datasets import CIFAR10\n",
118 | "import torchvision.transforms as transforms\n",
119 | "from torch.utils.data import DataLoader\n",
120 | "\n",
121 | "affine = transforms.RandomAffine([-15, 15], scale=(0.8, 1.2)) # 回転とリサイズ\n",
122 | "flip = transforms.RandomHorizontalFlip(p=0.5) # 左右反転\n",
123 | "normalize = transforms.Normalize((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)) # 平均値を0、標準偏差を1に\n",
124 | "to_tensor = transforms.ToTensor()\n",
125 | "erase = # ← 左にコードを追記\n",
126 | "\n",
127 | "transform_train = transforms.Compose([affine, flip, to_tensor, normalize, erase])\n",
128 | "transform_test = transforms.Compose([to_tensor, normalize])\n",
129 | "cifar10_train = CIFAR10(\"./data\", train=True, download=True, transform=transform_train)\n",
130 | "cifar10_test = CIFAR10(\"./data\", train=False, download=True, transform=transform_test)\n",
131 | "\n",
132 | "# DataLoaderの設定\n",
133 | "batch_size = 64\n",
134 | "train_loader = DataLoader(cifar10_train, batch_size=batch_size, shuffle=True)\n",
135 | "test_loader = DataLoader(cifar10_test, batch_size=len(cifar10_test), shuffle=False)"
136 | ],
137 | "execution_count": 0,
138 | "outputs": []
139 | },
140 | {
141 | "cell_type": "markdown",
142 | "metadata": {
143 | "id": "FalXNYaJPkoE",
144 | "colab_type": "text"
145 | },
146 | "source": [
147 | "## モデルの構築\n",
148 | "以下のセルで、forwardメソッドの内部にコードを記述しCNNのモデルを構築しましょう。"
149 | ]
150 | },
151 | {
152 | "cell_type": "code",
153 | "metadata": {
154 | "id": "SuqqZmsh_jNK",
155 | "colab_type": "code",
156 | "colab": {}
157 | },
158 | "source": [
159 | "import torch.nn as nn\n",
160 | "import torch.nn.functional as F\n",
161 | "\n",
162 | "class Net(nn.Module):\n",
163 | " def __init__(self):\n",
164 | " super().__init__()\n",
165 | " self.conv1 = nn.Conv2d(3, 8, 5) # 畳み込み層:(入力チャンネル数, フィルタ数、フィルタサイズ)\n",
166 | " self.pool = nn.MaxPool2d(2, 2) # プーリング層:(領域のサイズ, ストライド)\n",
167 | " self.conv2 = nn.Conv2d(8, 32, 5)\n",
168 | " self.fc1 = nn.Linear(32*5*5, 256) # 全結合層\n",
169 | " self.dropout = nn.Dropout(p=0.5) # ドロップアウト:(p=ドロップアウト率)\n",
170 | " self.fc2 = nn.Linear(256, 10)\n",
171 | "\n",
172 | " def forward(self, x):\n",
173 | " # ------- 以下にコードを書く -------\n",
174 | "\n",
175 | "\n",
176 | "\n",
177 | "\n",
178 | "\n",
179 | "\n",
180 | " # ------- ここまで -------\n",
181 | " return x\n",
182 | "\n",
183 | "net = Net()\n",
184 | "net.cuda() # GPU対応\n",
185 | "print(net)"
186 | ],
187 | "execution_count": 0,
188 | "outputs": []
189 | },
190 | {
191 | "cell_type": "markdown",
192 | "metadata": {
193 | "id": "qsW5zCKhQE9p",
194 | "colab_type": "text"
195 | },
196 | "source": [
197 | "## 学習\n",
198 | "モデルを訓練します。 \n",
199 | "エラーが発生せず、学習に伴い訓練誤差とテスト誤差が共に減少することを確認しましょう。 \n",
200 | "学習には時間がかかりますので、編集→ノートブックの設定のハードウェアアクセラレーターでGPUを選択しましょう。\n"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "metadata": {
206 | "id": "u6zwN3nArbGC",
207 | "colab_type": "code",
208 | "colab": {}
209 | },
210 | "source": [
211 | "from torch import optim\n",
212 | "\n",
213 | "# 交差エントロピー誤差関数\n",
214 | "loss_fnc = nn.CrossEntropyLoss()\n",
215 | "\n",
216 | "# 最適化アルゴリズム\n",
217 | "optimizer = optim.Adam(net.parameters())\n",
218 | "\n",
219 | "# 損失のログ\n",
220 | "record_loss_train = []\n",
221 | "record_loss_test = []\n",
222 | "\n",
223 | "# 学習\n",
224 | "x_test, t_test = iter(test_loader).next()\n",
225 | "x_test, t_test = x_test.cuda(), t_test.cuda()\n",
226 | "for i in range(20): # 20エポック学習\n",
227 | " net.train() # 訓練モード\n",
228 | " loss_train = 0\n",
229 | " for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す\n",
230 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
231 | " y = net(x)\n",
232 | " loss = loss_fnc(y, t)\n",
233 | " loss_train += loss.item()\n",
234 | " optimizer.zero_grad()\n",
235 | " loss.backward()\n",
236 | " optimizer.step()\n",
237 | " loss_train /= j+1\n",
238 | " record_loss_train.append(loss_train)\n",
239 | "\n",
240 | " net.eval() # 評価モード\n",
241 | " y_test = net(x_test)\n",
242 | " loss_test = loss_fnc(y_test, t_test).item()\n",
243 | " record_loss_test.append(loss_test)\n",
244 | "\n",
245 | " if i%1 == 0:\n",
246 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train, \"Loss_Test:\", loss_test)"
247 | ],
248 | "execution_count": 0,
249 | "outputs": []
250 | },
251 | {
252 | "cell_type": "markdown",
253 | "metadata": {
254 | "id": "rJwwrWTw43rx",
255 | "colab_type": "text"
256 | },
257 | "source": [
258 | "## 誤差の推移\n",
259 | "訓練データ、テストデータで誤差の推移をグラフ表示します。 "
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "metadata": {
265 | "id": "OaJx4swE45XI",
266 | "colab_type": "code",
267 | "colab": {}
268 | },
269 | "source": [
270 | "import matplotlib.pyplot as plt\n",
271 | "\n",
272 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
273 | "plt.plot(range(len(record_loss_test)), record_loss_test, label=\"Test\")\n",
274 | "plt.legend()\n",
275 | "\n",
276 | "plt.xlabel(\"Epochs\")\n",
277 | "plt.ylabel(\"Error\")\n",
278 | "plt.show()"
279 | ],
280 | "execution_count": 0,
281 | "outputs": []
282 | },
283 | {
284 | "cell_type": "markdown",
285 | "metadata": {
286 | "id": "iMrpac0m4Nct",
287 | "colab_type": "text"
288 | },
289 | "source": [
290 | "## 正解率\n",
291 | "モデルの性能を把握するため、テストデータ使い正解率を測定します。 "
292 | ]
293 | },
294 | {
295 | "cell_type": "code",
296 | "metadata": {
297 | "id": "IRkGCYMM_N35",
298 | "colab_type": "code",
299 | "colab": {}
300 | },
301 | "source": [
302 | "correct = 0\n",
303 | "total = 0\n",
304 | "net.eval() # 評価モード\n",
305 | "for i, (x, t) in enumerate(test_loader):\n",
306 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
307 | " y = net(x)\n",
308 | " correct += (y.argmax(1) == t).sum().item()\n",
309 | " total += len(x)\n",
310 | "print(\"正解率:\", str(correct/total*100) + \"%\")"
311 | ],
312 | "execution_count": 0,
313 | "outputs": []
314 | },
315 | {
316 | "cell_type": "markdown",
317 | "metadata": {
318 | "id": "LrRAJzwD4zpN",
319 | "colab_type": "text"
320 | },
321 | "source": [
322 | "## 訓練済みのモデルを使った予測\n",
323 | "画像を入力し、モデルが機能していることを確かめます。"
324 | ]
325 | },
326 | {
327 | "cell_type": "code",
328 | "metadata": {
329 | "id": "Pdy9nPckTDik",
330 | "colab_type": "code",
331 | "colab": {}
332 | },
333 | "source": [
334 | "cifar10_loader = DataLoader(cifar10_test, batch_size=1, shuffle=True)\n",
335 | "dataiter = iter(cifar10_loader)\n",
336 | "images, labels = dataiter.next() # サンプルを1つだけ取り出す\n",
337 | "\n",
338 | "plt.imshow(np.transpose(images[0], (1, 2, 0))) # チャンネルを一番後ろに\n",
339 | "plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False) # ラベルとメモリを非表示に\n",
340 | "plt.show()\n",
341 | "\n",
342 | "net.eval() # 評価モード\n",
343 | "x, t = images.cuda(), labels.cuda() # GPU対応\n",
344 | "y = net(x)\n",
345 | "print(\"正解:\", cifar10_classes[labels[0]],\n",
346 | " \"予測結果:\", cifar10_classes[y.argmax().item()])"
347 | ],
348 | "execution_count": 0,
349 | "outputs": []
350 | },
351 | {
352 | "cell_type": "markdown",
353 | "metadata": {
354 | "id": "VEBDnUbHZ21y",
355 | "colab_type": "text"
356 | },
357 | "source": [
358 | "# 解答例\n",
359 | "以下は、どうしても手がかりがないときのみ参考にしましょう。"
360 | ]
361 | },
362 | {
363 | "cell_type": "code",
364 | "metadata": {
365 | "id": "JTHeygFKscPI",
366 | "colab_type": "code",
367 | "colab": {}
368 | },
369 | "source": [
370 | "from torchvision.datasets import CIFAR10\n",
371 | "import torchvision.transforms as transforms\n",
372 | "from torch.utils.data import DataLoader\n",
373 | "\n",
374 | "affine = transforms.RandomAffine([-15, 15], scale=(0.8, 1.2)) # 回転とリサイズ\n",
375 | "flip = transforms.RandomHorizontalFlip(p=0.5) # 左右反転\n",
376 | "normalize = transforms.Normalize((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)) # 平均値を0、標準偏差を1に\n",
377 | "to_tensor = transforms.ToTensor()\n",
378 | "erase = transforms.RandomErasing(p=0.5) # ← 左にコードを追記\n",
379 | "\n",
380 | "transform_train = transforms.Compose([affine, flip, to_tensor, normalize, erase])\n",
381 | "transform_test = transforms.Compose([to_tensor, normalize])\n",
382 | "cifar10_train = CIFAR10(\"./data\", train=True, download=True, transform=transform_train)\n",
383 | "cifar10_test = CIFAR10(\"./data\", train=False, download=True, transform=transform_test)\n",
384 | "\n",
385 | "# DataLoaderの設定\n",
386 | "batch_size = 64\n",
387 | "train_loader = DataLoader(cifar10_train, batch_size=batch_size, shuffle=True)\n",
388 | "test_loader = DataLoader(cifar10_test, batch_size=len(cifar10_test), shuffle=False)"
389 | ],
390 | "execution_count": 0,
391 | "outputs": []
392 | },
393 | {
394 | "cell_type": "code",
395 | "metadata": {
396 | "id": "ZbtDEl0GscZK",
397 | "colab_type": "code",
398 | "colab": {}
399 | },
400 | "source": [
401 | "import torch.nn as nn\n",
402 | "import torch.nn.functional as F\n",
403 | "\n",
404 | "class Net(nn.Module):\n",
405 | " def __init__(self):\n",
406 | " super().__init__()\n",
407 | " self.conv1 = nn.Conv2d(3, 8, 5) # 畳み込み層:(入力チャンネル数, フィルタ数、フィルタサイズ)\n",
408 | " self.pool = nn.MaxPool2d(2, 2) # プーリング層:(領域のサイズ, ストライド)\n",
409 | " self.conv2 = nn.Conv2d(8, 32, 5)\n",
410 | " self.fc1 = nn.Linear(32*5*5, 256) # 全結合層\n",
411 | " self.dropout = nn.Dropout(p=0.5) # ドロップアウト:(p=ドロップアウト率)\n",
412 | " self.fc2 = nn.Linear(256, 10)\n",
413 | "\n",
414 | " def forward(self, x):\n",
415 | " # ------- 以下にコードを書く -------\n",
416 | " x = self.pool(F.relu(self.conv1(x)))\n",
417 | " x = self.pool(F.relu(self.conv2(x)))\n",
418 | " x = x.view(-1, 32*5*5)\n",
419 | " x = F.relu(self.fc1(x))\n",
420 | " x = self.dropout(x)\n",
421 | " x = self.fc2(x)\n",
422 | " # ------- ここまで -------\n",
423 | " return x\n",
424 | "\n",
425 | "net = Net()\n",
426 | "net.cuda() # GPU対応\n",
427 | "print(net)"
428 | ],
429 | "execution_count": 0,
430 | "outputs": []
431 | }
432 | ]
433 | }
--------------------------------------------------------------------------------
/lecture5/exercise.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "exercise.ipynb ",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "authorship_tag": "ABX9TyN51sbW3YKnL4X3KKU0qU+i",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | },
16 | "accelerator": "GPU"
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "id": "Niaz8_W6OX34",
33 | "colab_type": "text"
34 | },
35 | "source": [
36 | "# 演習\n",
37 | "RNNの層にGRUを使用して、画像の生成を行いましょう。 \n",
38 | "GRUを使用したモデルのクラスを記述します。\n"
39 | ]
40 | },
41 | {
42 | "cell_type": "markdown",
43 | "metadata": {
44 | "id": "vvRgf3-j2k76",
45 | "colab_type": "text"
46 | },
47 | "source": [
48 | "## データの前処理\n",
49 | "画像データをRNNに適した形に整えます。 "
50 | ]
51 | },
52 | {
53 | "cell_type": "code",
54 | "metadata": {
55 | "id": "bUcJiVtDV7Ad",
56 | "colab_type": "code",
57 | "colab": {}
58 | },
59 | "source": [
60 | "import torch\n",
61 | "from torchvision.datasets import FashionMNIST\n",
62 | "import torchvision.transforms as transforms\n",
63 | "from torch.utils.data import DataLoader\n",
64 | "import numpy as np\n",
65 | "import matplotlib.pyplot as plt\n",
66 | "\n",
67 | "img_size = 28\n",
68 | "n_time = 14 # 時系列の数\n",
69 | "n_in = img_size # 入力層のニューロン数\n",
70 | "n_mid = 256 # 中間層のニューロン数\n",
71 | "n_out = img_size # 出力層のニューロン数\n",
72 | "n_sample_in_img = img_size-n_time # 1枚の画像中のサンプル数\n",
73 | "\n",
74 | "fmnist_data = FashionMNIST(root=\"./data\",\n",
75 | " train=True,download=True,\n",
76 | " transform=transforms.ToTensor())\n",
77 | "dataloader = DataLoader(fmnist_data, batch_size=len(fmnist_data), shuffle=False)\n",
78 | "dataiter = iter(dataloader) # イテレータ\n",
79 | "train_imgs, labels = dataiter.next() # データを取り出す\n",
80 | "train_imgs = train_imgs.reshape(-1, img_size, img_size)\n",
81 | "\n",
82 | "n_sample = len(train_imgs) * n_sample_in_img # サンプル数\n",
83 | "\n",
84 | "input_data = np.zeros((n_sample, n_time, n_in)) # 入力\n",
85 | "correct_data = np.zeros((n_sample, n_out)) # 正解\n",
86 | "for i in range(len(train_imgs)):\n",
87 | " for j in range(n_sample_in_img):\n",
88 | " sample_id = i*n_sample_in_img + j\n",
89 | " input_data[sample_id] = train_imgs[i, j:j+n_time]\n",
90 | " correct_data[sample_id] = train_imgs[i, j+n_time]\n",
91 | "\n",
92 | "input_data = torch.tensor(input_data, dtype=torch.float) # テンソルに変換\n",
93 | "correct_data = torch.tensor(correct_data, dtype=torch.float)\n",
94 | "dataset = torch.utils.data.TensorDataset(input_data, correct_data) # データセットの作成\n",
95 | "\n",
96 | "train_loader = DataLoader(dataset, batch_size=128, shuffle=True) # DataLoaderの設定"
97 | ],
98 | "execution_count": 0,
99 | "outputs": []
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {
104 | "id": "d8pnaugFDnLN",
105 | "colab_type": "text"
106 | },
107 | "source": [
108 | "## テスト用のデータ\n",
109 | "今回は、訓練済みのモデルが機能することを確かめるために使用します。"
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "metadata": {
115 | "id": "xISsKRTAp7QG",
116 | "colab_type": "code",
117 | "colab": {}
118 | },
119 | "source": [
120 | "n_disp = 10 # 生成し表示する画像の数\n",
121 | "\n",
122 | "disp_data = FashionMNIST(root=\"./data\",\n",
123 | " train=False,download=True,\n",
124 | " transform=transforms.ToTensor())\n",
125 | "disp_loader = DataLoader(disp_data, batch_size=n_disp, shuffle=False)\n",
126 | "dataiter = iter(disp_loader) # イテレータ\n",
127 | "disp_imgs, labels = dataiter.next() # データを取り出す\n",
128 | "disp_imgs = disp_imgs.reshape(-1, img_size, img_size)"
129 | ],
130 | "execution_count": 0,
131 | "outputs": []
132 | },
133 | {
134 | "cell_type": "markdown",
135 | "metadata": {
136 | "id": "NyLBjYjr3RXu",
137 | "colab_type": "text"
138 | },
139 | "source": [
140 | "## 画像生成用の関数\n",
141 | "以下の関数は、オリジナルの画像`disp_imgs`と、この画像の上半分をもとに下半分を生成した`gen_imgs`を並べて表示します。 "
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "metadata": {
147 | "id": "dFmq4Oy6apUC",
148 | "colab_type": "code",
149 | "colab": {}
150 | },
151 | "source": [
152 | "def generate_images():\n",
153 | " # オリジナルの画像\n",
154 | " print(\"Original:\")\n",
155 | " plt.figure(figsize=(20, 2))\n",
156 | " for i in range(n_disp):\n",
157 | " ax = plt.subplot(1, n_disp, i+1)\n",
158 | " plt.imshow(disp_imgs[i], cmap=\"Greys_r\", vmin=0.0, vmax=1.0)\n",
159 | " ax.get_xaxis().set_visible(False) # 軸を非表示に\n",
160 | " ax.get_yaxis().set_visible(False)\n",
161 | " plt.show()\n",
162 | "\n",
163 | " # 下半分をRNNにより生成した画像\n",
164 | " print(\"Generated:\")\n",
165 | " gen_imgs = disp_imgs.clone()\n",
166 | " plt.figure(figsize=(20, 2))\n",
167 | " for i in range(n_disp):\n",
168 | " for j in range(n_sample_in_img):\n",
169 | " x = gen_imgs[i, j:j+n_time].reshape(1, n_time, img_size)\n",
170 | " x = x.cuda() # GPU対応\n",
171 | " gen_imgs[i, j+n_time] = net(x)[0]\n",
172 | " ax = plt.subplot(1, n_disp, i+1)\n",
173 | " plt.imshow(gen_imgs[i].detach(), cmap=\"Greys_r\", vmin=0.0, vmax=1.0)\n",
174 | " ax.get_xaxis().set_visible(False) # 軸を非表示に\n",
175 | " ax.get_yaxis().set_visible(False)\n",
176 | " plt.show()"
177 | ],
178 | "execution_count": 0,
179 | "outputs": []
180 | },
181 | {
182 | "cell_type": "markdown",
183 | "metadata": {
184 | "id": "FalXNYaJPkoE",
185 | "colab_type": "text"
186 | },
187 | "source": [
188 | "## モデルの構築\n",
189 | "以下のセルで、Netクラスの内部にコードを記述しGRUを使ったRNNのモデルを構築しましょう。 \n",
190 | "GRUの実装方法は、以下の公式ドキュメントが詳しいです。 \n",
191 | "https://pytorch.org/docs/stable/nn.html#gru"
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "metadata": {
197 | "id": "SuqqZmsh_jNK",
198 | "colab_type": "code",
199 | "colab": {}
200 | },
201 | "source": [
202 | "import torch.nn as nn\n",
203 | "import torch.nn.functional as F\n",
204 | "\n",
205 | "class Net(nn.Module):\n",
206 | " # ------- 以下にコードを書く -------\n",
207 | "\n",
208 | "\n",
209 | "\n",
210 | "\n",
211 | "\n",
212 | "\n",
213 | "\n",
214 | "\n",
215 | "\n",
216 | "\n",
217 | "\n",
218 | "\n",
219 | "\n",
220 | " # ------- ここまで -------\n",
221 | "\n",
222 | "net = Net()\n",
223 | "net.cuda() # GPU対応\n",
224 | "print(net)"
225 | ],
226 | "execution_count": 0,
227 | "outputs": []
228 | },
229 | {
230 | "cell_type": "markdown",
231 | "metadata": {
232 | "id": "qsW5zCKhQE9p",
233 | "colab_type": "text"
234 | },
235 | "source": [
236 | "## 学習\n",
237 | "モデルを訓練します。 \n",
238 | "学習には時間がかかりますので、編集→ノートブックの設定のハードウェアアクセラレーターでGPUを選択しましょう。"
239 | ]
240 | },
241 | {
242 | "cell_type": "code",
243 | "metadata": {
244 | "id": "u6zwN3nArbGC",
245 | "colab_type": "code",
246 | "colab": {}
247 | },
248 | "source": [
249 | "from torch import optim\n",
250 | "\n",
251 | "# 交差エントロピー誤差関数\n",
252 | "loss_fnc = nn.MSELoss()\n",
253 | "\n",
254 | "# 最適化アルゴリズム\n",
255 | "optimizer = optim.Adam(net.parameters()) # 学習率は0.01\n",
256 | "\n",
257 | "# 損失のログ\n",
258 | "record_loss_train = []\n",
259 | "\n",
260 | "# 学習\n",
261 | "for i in range(25): # 25エポック学習\n",
262 | " net.train() # 訓練モード\n",
263 | " loss_train = 0\n",
264 | " for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す\n",
265 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
266 | " y = net(x)\n",
267 | " loss = loss_fnc(y, t)\n",
268 | " loss_train += loss.item()\n",
269 | " optimizer.zero_grad()\n",
270 | " loss.backward()\n",
271 | " optimizer.step()\n",
272 | " loss_train /= j+1\n",
273 | " record_loss_train.append(loss_train)\n",
274 | "\n",
275 | " if i%1 == 0:\n",
276 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train)\n",
277 | " generate_images()"
278 | ],
279 | "execution_count": 0,
280 | "outputs": []
281 | },
282 | {
283 | "cell_type": "markdown",
284 | "metadata": {
285 | "id": "rJwwrWTw43rx",
286 | "colab_type": "text"
287 | },
288 | "source": [
289 | "## 誤差の推移\n",
290 | "誤差の推移をグラフ表示します。 "
291 | ]
292 | },
293 | {
294 | "cell_type": "code",
295 | "metadata": {
296 | "id": "OaJx4swE45XI",
297 | "colab_type": "code",
298 | "colab": {}
299 | },
300 | "source": [
301 | "import matplotlib.pyplot as plt\n",
302 | "\n",
303 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
304 | "plt.legend()\n",
305 | "\n",
306 | "plt.xlabel(\"Epochs\")\n",
307 | "plt.ylabel(\"Error\")\n",
308 | "plt.show()"
309 | ],
310 | "execution_count": 0,
311 | "outputs": []
312 | },
313 | {
314 | "cell_type": "markdown",
315 | "metadata": {
316 | "id": "xBNiERnQxexU",
317 | "colab_type": "text"
318 | },
319 | "source": [
320 | "# 解答例\n",
321 | "以下は、どうしても手がかりがないときのみ参考にしましょう。"
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "metadata": {
327 | "id": "NQDXjjVS3ppJ",
328 | "colab_type": "code",
329 | "colab": {}
330 | },
331 | "source": [
332 | "import torch.nn as nn\n",
333 | "import torch.nn.functional as F\n",
334 | "\n",
335 | "class Net(nn.Module):\n",
336 | " # ------- 以下にコードを書く -------\n",
337 | " def __init__(self):\n",
338 | " super().__init__()\n",
339 | " self.rnn = nn.GRU( # GRU層\n",
340 | " input_size=n_in, # 入力サイズ\n",
341 | " hidden_size=n_mid, # ニューロン数\n",
342 | " batch_first=True, # 入力を (バッチサイズ, 時系列の数, 入力の数) にする\n",
343 | " )\n",
344 | " self.fc = nn.Linear(n_mid, n_out) # 全結合層\n",
345 | "\n",
346 | " def forward(self, x):\n",
347 | " y_rnn, h = self.rnn(x, None) # hは次の時刻に渡される値\n",
348 | " y = self.fc(y_rnn[:, -1, :]) # yは最後の時刻の出力\n",
349 | " return y\n",
350 | " # ------- ここまで -------\n",
351 | "\n",
352 | "net = Net()\n",
353 | "net.cuda() # GPU対応\n",
354 | "print(net)"
355 | ],
356 | "execution_count": 0,
357 | "outputs": []
358 | }
359 | ]
360 | }
--------------------------------------------------------------------------------
/lecture5/image_generation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "image_generation.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "authorship_tag": "ABX9TyP2+3Tx8Fs/SZHWqlxT6h7n",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | },
16 | "accelerator": "GPU"
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "id": "Niaz8_W6OX34",
33 | "colab_type": "text"
34 | },
35 | "source": [
36 | "# RNNによる画像生成\n",
37 | "画像を時系列のデータと捉えることで、RNNにより画像を生成することが可能になります。 \n",
38 | "今回は、画像データを使ってRNNを訓練し、画像の上半分をもとに画像の下半分を生成します。 \n",
39 | "RNNの層にはLSTMを使用します。 \n"
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {
45 | "colab_type": "text",
46 | "id": "LoISGl864sy9"
47 | },
48 | "source": [
49 | "## Fashion-MNIST\n",
50 | "torchvision.datasetsを使い、Fashion-MNISTを読み込みます。 \n",
51 | "Fashion-MNISTは、6万枚のファッションアイテム画像にラベルをつけたたデータセットです。 \n",
52 | "以下のコードでは、Fashion-MNISTを読み込み、ランダムな25枚の画像を表示します。"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "metadata": {
58 | "colab_type": "code",
59 | "id": "sQ1S5UNy-rpY",
60 | "colab": {}
61 | },
62 | "source": [
63 | "from torchvision.datasets import FashionMNIST\n",
64 | "import torchvision.transforms as transforms\n",
65 | "from torch.utils.data import DataLoader\n",
66 | "import numpy as np\n",
67 | "import matplotlib.pyplot as plt\n",
68 | "\n",
69 | "fmnist_data = FashionMNIST(root=\"./data\",\n",
70 | " train=True,download=True,\n",
71 | " transform=transforms.ToTensor())\n",
72 | "fmnist_classes = np.array([\"T-shirt/top\", \"Trouser\", \"Pullover\", \"Dress\", \"Coat\",\n",
73 | " \"Sandal\", \"Shirt\", \"Sneaker\", \"Bag\", \"Ankle boot\"])\n",
74 | "print(\"データの数:\", len(fmnist_data))\n",
75 | "\n",
76 | "n_image = 25 # 表示する画像の数\n",
77 | "fmnist_loader = DataLoader(fmnist_data, batch_size=n_image, shuffle=True)\n",
78 | "dataiter = iter(fmnist_loader) # イテレータ\n",
79 | "images, labels = dataiter.next() # 最初のバッチを取り出す\n",
80 | "\n",
81 | "img_size = 28\n",
82 | "plt.figure(figsize=(10,10)) # 画像の表示サイズ\n",
83 | "for i in range(n_image):\n",
84 | " plt.subplot(5,5,i+1)\n",
85 | " plt.imshow(images[i].reshape(img_size, img_size), cmap=\"Greys_r\")\n",
86 | " label = fmnist_classes[labels[i]]\n",
87 | " plt.title(label)\n",
88 | " plt.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False) # ラベルとメモリを非表示に\n",
89 | "\n",
90 | "plt.show()"
91 | ],
92 | "execution_count": 0,
93 | "outputs": []
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {
98 | "id": "vvRgf3-j2k76",
99 | "colab_type": "text"
100 | },
101 | "source": [
102 | "## データの前処理\n",
103 | "画像データをRNNに適した形に整えます。 \n",
104 | "画像を時系列データに変換しますが、正解は時系列の次の行にします。 "
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "metadata": {
110 | "id": "bUcJiVtDV7Ad",
111 | "colab_type": "code",
112 | "colab": {}
113 | },
114 | "source": [
115 | "import torch\n",
116 | "from torch.utils.data import DataLoader\n",
117 | "\n",
118 | "n_time = 14 # 時系列の数\n",
119 | "n_in = img_size # 入力層のニューロン数\n",
120 | "n_mid = 256 # 中間層のニューロン数\n",
121 | "n_out = img_size # 出力層のニューロン数\n",
122 | "n_sample_in_img = img_size-n_time # 1枚の画像中のサンプル数\n",
123 | "\n",
124 | "dataloader = DataLoader(fmnist_data, batch_size=len(fmnist_data), shuffle=False)\n",
125 | "dataiter = iter(dataloader) # イテレータ\n",
126 | "train_imgs, labels = dataiter.next() # データを取り出す\n",
127 | "train_imgs = train_imgs.reshape(-1, img_size, img_size)\n",
128 | "\n",
129 | "n_sample = len(train_imgs) * n_sample_in_img # サンプル数\n",
130 | "\n",
131 | "input_data = np.zeros((n_sample, n_time, n_in)) # 入力\n",
132 | "correct_data = np.zeros((n_sample, n_out)) # 正解\n",
133 | "for i in range(len(train_imgs)):\n",
134 | " for j in range(n_sample_in_img):\n",
135 | " sample_id = i*n_sample_in_img + j\n",
136 | " input_data[sample_id] = train_imgs[i, j:j+n_time]\n",
137 | " correct_data[sample_id] = train_imgs[i, j+n_time]\n",
138 | "\n",
139 | "input_data = torch.tensor(input_data, dtype=torch.float) # テンソルに変換\n",
140 | "correct_data = torch.tensor(correct_data, dtype=torch.float)\n",
141 | "dataset = torch.utils.data.TensorDataset(input_data, correct_data) # データセットの作成\n",
142 | "\n",
143 | "train_loader = DataLoader(dataset, batch_size=128, shuffle=True) # DataLoaderの設定"
144 | ],
145 | "execution_count": 0,
146 | "outputs": []
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {
151 | "id": "d8pnaugFDnLN",
152 | "colab_type": "text"
153 | },
154 | "source": [
155 | "## テスト用のデータ\n",
156 | "今回は、訓練済みのモデルが機能することを確かめるために使用します。"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "metadata": {
162 | "id": "xISsKRTAp7QG",
163 | "colab_type": "code",
164 | "colab": {}
165 | },
166 | "source": [
167 | "n_disp = 10 # 生成し表示する画像の数\n",
168 | "\n",
169 | "disp_data = FashionMNIST(root=\"./data\",\n",
170 | " train=False,download=True,\n",
171 | " transform=transforms.ToTensor())\n",
172 | "disp_loader = DataLoader(disp_data, batch_size=n_disp, shuffle=False)\n",
173 | "dataiter = iter(disp_loader) # イテレータ\n",
174 | "disp_imgs, labels = dataiter.next() # データを取り出す\n",
175 | "disp_imgs = disp_imgs.reshape(-1, img_size, img_size)"
176 | ],
177 | "execution_count": 0,
178 | "outputs": []
179 | },
180 | {
181 | "cell_type": "markdown",
182 | "metadata": {
183 | "id": "NyLBjYjr3RXu",
184 | "colab_type": "text"
185 | },
186 | "source": [
187 | "## 画像生成用の関数\n",
188 | "以下の関数は、オリジナルの画像`disp_imgs`と、この画像の上半分をもとに下半分を生成した`gen_imgs`を並べて表示します。 \n",
189 | "最初は画像の上半分をシードにして新たな行を生成しますが、次はその新たな行を含む直近の時系列からさらに次の行を生成します。 \n",
190 | "これを繰り返すことで、下半分の画像が生成されます。 "
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "metadata": {
196 | "id": "dFmq4Oy6apUC",
197 | "colab_type": "code",
198 | "colab": {}
199 | },
200 | "source": [
201 | "def generate_images():\n",
202 | " # オリジナルの画像\n",
203 | " print(\"Original:\")\n",
204 | " plt.figure(figsize=(20, 2))\n",
205 | " for i in range(n_disp):\n",
206 | " ax = plt.subplot(1, n_disp, i+1)\n",
207 | " plt.imshow(disp_imgs[i], cmap=\"Greys_r\", vmin=0.0, vmax=1.0)\n",
208 | " ax.get_xaxis().set_visible(False) # 軸を非表示に\n",
209 | " ax.get_yaxis().set_visible(False)\n",
210 | " plt.show()\n",
211 | "\n",
212 | " # 下半分をRNNにより生成した画像\n",
213 | " print(\"Generated:\")\n",
214 | " gen_imgs = disp_imgs.clone()\n",
215 | " plt.figure(figsize=(20, 2))\n",
216 | " for i in range(n_disp):\n",
217 | " for j in range(n_sample_in_img):\n",
218 | " x = gen_imgs[i, j:j+n_time].reshape(1, n_time, img_size)\n",
219 | " x = x.cuda() # GPU対応\n",
220 | " gen_imgs[i, j+n_time] = net(x)[0]\n",
221 | " ax = plt.subplot(1, n_disp, i+1)\n",
222 | " plt.imshow(gen_imgs[i].detach(), cmap=\"Greys_r\", vmin=0.0, vmax=1.0)\n",
223 | " ax.get_xaxis().set_visible(False) # 軸を非表示に\n",
224 | " ax.get_yaxis().set_visible(False)\n",
225 | " plt.show()"
226 | ],
227 | "execution_count": 0,
228 | "outputs": []
229 | },
230 | {
231 | "cell_type": "markdown",
232 | "metadata": {
233 | "id": "FalXNYaJPkoE",
234 | "colab_type": "text"
235 | },
236 | "source": [
237 | "## モデルの構築\n",
238 | "`nn.Module`モジュールを継承したクラスとして、モデルを構築します。 \n",
239 | "LSTMは`nn.LSTM`を使って実装することができます。"
240 | ]
241 | },
242 | {
243 | "cell_type": "code",
244 | "metadata": {
245 | "id": "SuqqZmsh_jNK",
246 | "colab_type": "code",
247 | "colab": {}
248 | },
249 | "source": [
250 | "import torch.nn as nn\n",
251 | "import torch.nn.functional as F\n",
252 | "\n",
253 | "class Net(nn.Module):\n",
254 | " def __init__(self):\n",
255 | " super().__init__()\n",
256 | " self.rnn = nn.LSTM( # LSTM層\n",
257 | " input_size=n_in, # 入力サイズ\n",
258 | " hidden_size=n_mid, # ニューロン数\n",
259 | " batch_first=True, # 入力を (バッチサイズ, 時系列の数, 入力の数) にする\n",
260 | " )\n",
261 | " self.fc = nn.Linear(n_mid, n_out) # 全結合層\n",
262 | "\n",
263 | " def forward(self, x):\n",
264 | " y_rnn, (h, c) = self.rnn(x, None) # hは次の時刻に渡される値、 cは記憶セル\n",
265 | " y = self.fc(y_rnn[:, -1, :]) # yは最後の時刻の出力\n",
266 | " return y\n",
267 | "\n",
268 | "net = Net()\n",
269 | "net.cuda() # GPU対応\n",
270 | "print(net)"
271 | ],
272 | "execution_count": 0,
273 | "outputs": []
274 | },
275 | {
276 | "cell_type": "markdown",
277 | "metadata": {
278 | "id": "qsW5zCKhQE9p",
279 | "colab_type": "text"
280 | },
281 | "source": [
282 | "## 学習\n",
283 | "モデルを訓練します。 \n",
284 | "DataLoaderを使い、ミニバッチを取り出して訓練および評価を行います。 \n",
285 | "学習中、一定のエポック間隔ごとに誤差の表示と画像の生成が行われます。 \n",
286 | "学習には時間がかかりますので、編集→ノートブックの設定のハードウェアアクセラレーターでGPUを選択しましょう。"
287 | ]
288 | },
289 | {
290 | "cell_type": "code",
291 | "metadata": {
292 | "id": "u6zwN3nArbGC",
293 | "colab_type": "code",
294 | "colab": {}
295 | },
296 | "source": [
297 | "from torch import optim\n",
298 | "\n",
299 | "# 交差エントロピー誤差関数\n",
300 | "loss_fnc = nn.MSELoss()\n",
301 | "\n",
302 | "# 最適化アルゴリズム\n",
303 | "optimizer = optim.Adam(net.parameters()) # 学習率は0.01\n",
304 | "\n",
305 | "# 損失のログ\n",
306 | "record_loss_train = []\n",
307 | "\n",
308 | "# 学習\n",
309 | "for i in range(25): # 25エポック学習\n",
310 | " net.train() # 訓練モード\n",
311 | " loss_train = 0\n",
312 | " for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す\n",
313 | " x, t = x.cuda(), t.cuda() # GPU対応\n",
314 | " y = net(x)\n",
315 | " loss = loss_fnc(y, t)\n",
316 | " loss_train += loss.item()\n",
317 | " optimizer.zero_grad()\n",
318 | " loss.backward()\n",
319 | " optimizer.step()\n",
320 | " loss_train /= j+1\n",
321 | " record_loss_train.append(loss_train)\n",
322 | "\n",
323 | " if i%1 == 0:\n",
324 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train)\n",
325 | " generate_images()"
326 | ],
327 | "execution_count": 0,
328 | "outputs": []
329 | },
330 | {
331 | "cell_type": "markdown",
332 | "metadata": {
333 | "id": "rJwwrWTw43rx",
334 | "colab_type": "text"
335 | },
336 | "source": [
337 | "## 誤差の推移\n",
338 | "誤差の推移をグラフ表示します。 "
339 | ]
340 | },
341 | {
342 | "cell_type": "code",
343 | "metadata": {
344 | "id": "OaJx4swE45XI",
345 | "colab_type": "code",
346 | "colab": {}
347 | },
348 | "source": [
349 | "import matplotlib.pyplot as plt\n",
350 | "\n",
351 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
352 | "plt.legend()\n",
353 | "\n",
354 | "plt.xlabel(\"Epochs\")\n",
355 | "plt.ylabel(\"Error\")\n",
356 | "plt.show()"
357 | ],
358 | "execution_count": 0,
359 | "outputs": []
360 | },
361 | {
362 | "cell_type": "markdown",
363 | "metadata": {
364 | "id": "iMrpac0m4Nct",
365 | "colab_type": "text"
366 | },
367 | "source": [
368 | "滑らかに誤差が減少していることが確認できます。"
369 | ]
370 | }
371 | ]
372 | }
--------------------------------------------------------------------------------
/lecture5/simple_rnn.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "colab_type": "text",
7 | "id": "view-in-github"
8 | },
9 | "source": [
10 | "
"
11 | ]
12 | },
13 | {
14 | "cell_type": "markdown",
15 | "metadata": {
16 | "colab_type": "text",
17 | "id": "Niaz8_W6OX34"
18 | },
19 | "source": [
20 | "# シンプルなRNNの実装\n",
21 | "PyTorchを使って、シンプルな再帰型ニューラルネットワーク(RNN)を実装します。 \n",
22 | "RNNにノイズ付きサインカーブを学習させて、1つ先の未来を予測することによる曲線の描画を行います。\n"
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {
28 | "colab_type": "text",
29 | "id": "LoISGl864sy9"
30 | },
31 | "source": [
32 | "## 訓練用データの作成\n",
33 | "まずは、サインカーブに乱数でノイズを加えてRNNに用いる訓練用のデータを作成します。"
34 | ]
35 | },
36 | {
37 | "cell_type": "code",
38 | "execution_count": null,
39 | "metadata": {
40 | "colab": {},
41 | "colab_type": "code",
42 | "id": "sQ1S5UNy-rpY"
43 | },
44 | "outputs": [],
45 | "source": [
46 | "import numpy as np\n",
47 | "import matplotlib.pyplot as plt\n",
48 | "\n",
49 | "sin_x = np.linspace(-2*np.pi, 2*np.pi) # -2πから2πまで\n",
50 | "sin_y = np.sin(sin_x) + 0.1*np.random.randn(len(sin_x)) # sin関数に乱数でノイズを加える\n",
51 | "plt.plot(sin_x, sin_y)\n",
52 | "plt.show()"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {
58 | "colab_type": "text",
59 | "id": "NyLBjYjr3RXu"
60 | },
61 | "source": [
62 | "このようなノイズ付きサインカーブの一部を切り取って入力の時系列とし、次の値を予測するようにRNNを訓練します。 \n",
63 | "sin波自体は単純な時系列データですが、このようなsin波をニューラルネットワークで学習することができれば、例えば音声認識などに応用することも可能です。 \n",
64 | "今回の扱う対象はシンプルですが、現実社会で広く応用が可能することができます。"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {
70 | "colab_type": "text",
71 | "id": "vvRgf3-j2k76"
72 | },
73 | "source": [
74 | "## データの前処理\n",
75 | "入力、正解データをRNNに適した形に整えます。 \n",
76 | "時系列から次の値を予測できるように、時系列を入力として正解はその1つ後の値とします。 "
77 | ]
78 | },
79 | {
80 | "cell_type": "code",
81 | "execution_count": null,
82 | "metadata": {
83 | "colab": {},
84 | "colab_type": "code",
85 | "id": "dFmq4Oy6apUC"
86 | },
87 | "outputs": [],
88 | "source": [
89 | "import torch\n",
90 | "from torch.utils.data import DataLoader\n",
91 | "\n",
92 | "n_time = 10 # 時系列の数\n",
93 | "n_sample = len(sin_x)-n_time # サンプル数\n",
94 | "\n",
95 | "input_data = np.zeros((n_sample, n_time, 1)) # 入力\n",
96 | "correct_data = np.zeros((n_sample, 1)) # 正解\n",
97 | "for i in range(n_sample):\n",
98 | " input_data[i] = sin_y[i:i+n_time].reshape(-1, 1)\n",
99 | " correct_data[i] = sin_y[i+n_time:i+n_time+1] # 正解は入力よりも一つ後\n",
100 | "\n",
101 | "input_data = torch.tensor(input_data, dtype=torch.float) # テンソルに変換\n",
102 | "correct_data = torch.tensor(correct_data, dtype=torch.float)\n",
103 | "dataset = torch.utils.data.TensorDataset(input_data, correct_data) # データセットの作成\n",
104 | "\n",
105 | "train_loader = DataLoader(dataset, batch_size=8, shuffle=True) # DataLoaderの設定"
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {
111 | "colab_type": "text",
112 | "id": "FalXNYaJPkoE"
113 | },
114 | "source": [
115 | "## モデルの構築\n",
116 | "`nn.Module`モジュールを継承したクラスとして、モデルを構築します。 \n",
117 | "RNNは`nn.RNN`を使って実装することができます。"
118 | ]
119 | },
120 | {
121 | "cell_type": "code",
122 | "execution_count": null,
123 | "metadata": {
124 | "colab": {},
125 | "colab_type": "code",
126 | "id": "SuqqZmsh_jNK"
127 | },
128 | "outputs": [],
129 | "source": [
130 | "import torch.nn as nn\n",
131 | "import torch.nn.functional as F\n",
132 | "\n",
133 | "class Net(nn.Module):\n",
134 | " def __init__(self):\n",
135 | " super().__init__()\n",
136 | " self.rnn = nn.RNN( # RNN層\n",
137 | " input_size=1, # 入力サイズ\n",
138 | " hidden_size=64, # ニューロン数\n",
139 | " batch_first=True, # 入力を (バッチサイズ, 時系列の数, 入力の数) にする\n",
140 | " )\n",
141 | " self.fc = nn.Linear(64, 1) # 全結合層\n",
142 | "\n",
143 | " def forward(self, x):\n",
144 | " y_rnn, h = self.rnn(x, None) # hは次の時刻に渡される値、 Noneでその初期値が0に\n",
145 | " y = self.fc(y_rnn[:, -1, :]) # yは最後の時刻の出力\n",
146 | " return y\n",
147 | "\n",
148 | "net = Net()\n",
149 | "print(net)"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {
155 | "colab_type": "text",
156 | "id": "qsW5zCKhQE9p"
157 | },
158 | "source": [
159 | "## 学習\n",
160 | "モデルを訓練します。 \n",
161 | "DataLoaderを使い、ミニバッチを取り出して訓練および評価を行います。 \n",
162 | "訓練したモデルを使い、直近の時系列を使った予測結果を次々と時系列に加えていくことにより、曲線が生成されます。 \n",
163 | "学習が進むとともに次第にサインカーブが生成されるようになりますが、曲線は一定のエポック間隔でグラフとして描画されます。 "
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {
170 | "colab": {},
171 | "colab_type": "code",
172 | "id": "u6zwN3nArbGC"
173 | },
174 | "outputs": [],
175 | "source": [
176 | "from torch import optim\n",
177 | "\n",
178 | "# 平均二乗誤差関数\n",
179 | "loss_fnc = nn.MSELoss()\n",
180 | "\n",
181 | "# 最適化アルゴリズム\n",
182 | "optimizer = optim.SGD(net.parameters(), lr=0.01) # 学習率は0.01\n",
183 | "\n",
184 | "# 損失のログ\n",
185 | "record_loss_train = []\n",
186 | "\n",
187 | "# 学習\n",
188 | "for i in range(50): # 50エポック学習\n",
189 | " net.train() # 訓練モード\n",
190 | " loss_train = 0\n",
191 | " for j, (x, t) in enumerate(train_loader): # ミニバッチ(x, t)を取り出す\n",
192 | " y = net(x)\n",
193 | " loss = loss_fnc(y, t)\n",
194 | " loss_train += loss.item()\n",
195 | " optimizer.zero_grad()\n",
196 | " loss.backward()\n",
197 | " optimizer.step()\n",
198 | " loss_train /= j+1\n",
199 | " record_loss_train.append(loss_train)\n",
200 | "\n",
201 | " if i%2 == 0:\n",
202 | " print(\"Epoch:\", i, \"Loss_Train:\", loss_train)\n",
203 | " predicted = list(input_data[0].reshape(-1)) # 最初の入力\n",
204 | " for i in range(n_sample):\n",
205 | " x = torch.tensor(predicted[-n_time:]) # 直近の時系列を取り出す\n",
206 | " x = x.reshape(1, n_time, 1) # (バッチサイズ, 時系列の数, 入力の数)\n",
207 | " y = net(x)\n",
208 | " predicted.append(y[0].item()) # 予測結果をpredictedに追加する\n",
209 | "\n",
210 | " plt.plot(range(len(sin_y)), sin_y, label=\"Correct\")\n",
211 | " plt.plot(range(len(predicted)), predicted, label=\"Predicted\")\n",
212 | " plt.legend()\n",
213 | " plt.show()\n",
214 | " "
215 | ]
216 | },
217 | {
218 | "cell_type": "markdown",
219 | "metadata": {
220 | "colab_type": "text",
221 | "id": "rJwwrWTw43rx"
222 | },
223 | "source": [
224 | "## 誤差の推移\n",
225 | "訓練データ、テストデータで誤差の推移をグラフ表示します。 "
226 | ]
227 | },
228 | {
229 | "cell_type": "code",
230 | "execution_count": null,
231 | "metadata": {
232 | "colab": {},
233 | "colab_type": "code",
234 | "id": "OaJx4swE45XI"
235 | },
236 | "outputs": [],
237 | "source": [
238 | "import matplotlib.pyplot as plt\n",
239 | "\n",
240 | "plt.plot(range(len(record_loss_train)), record_loss_train, label=\"Train\")\n",
241 | "plt.legend()\n",
242 | "\n",
243 | "plt.xlabel(\"Epochs\")\n",
244 | "plt.ylabel(\"Error\")\n",
245 | "plt.show()"
246 | ]
247 | },
248 | {
249 | "cell_type": "markdown",
250 | "metadata": {
251 | "colab_type": "text",
252 | "id": "iMrpac0m4Nct"
253 | },
254 | "source": [
255 | "滑らかに誤差が減少していることが確認できます。"
256 | ]
257 | }
258 | ],
259 | "metadata": {
260 | "colab": {
261 | "authorship_tag": "ABX9TyPEtjK7A8DPxbWUXkqmaSUU",
262 | "collapsed_sections": [],
263 | "include_colab_link": true,
264 | "name": "simple_rnn.ipynb",
265 | "provenance": []
266 | },
267 | "kernelspec": {
268 | "display_name": "Python 3 (ipykernel)",
269 | "language": "python",
270 | "name": "python3"
271 | },
272 | "language_info": {
273 | "codemirror_mode": {
274 | "name": "ipython",
275 | "version": 3
276 | },
277 | "file_extension": ".py",
278 | "mimetype": "text/x-python",
279 | "name": "python",
280 | "nbconvert_exporter": "python",
281 | "pygments_lexer": "ipython3",
282 | "version": "3.9.6"
283 | }
284 | },
285 | "nbformat": 4,
286 | "nbformat_minor": 4
287 | }
288 |
--------------------------------------------------------------------------------
/lecture6/classifier/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn classifier:app --log-file -
--------------------------------------------------------------------------------
/lecture6/classifier/classifier.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, redirect, url_for, render_template, Markup
2 | from werkzeug.utils import secure_filename
3 |
4 | import torch
5 | import torch.nn as nn
6 | import torch.nn.functional as F
7 | import torchvision.transforms as transforms
8 |
9 | import os
10 | import shutil
11 | from PIL import Image
12 | import numpy as np
13 |
14 | UPLOAD_FOLDER = "./static/images/"
15 | ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif"}
16 |
17 | labels = ["飛行機", "自動車", "鳥", "猫", "鹿", "犬", "カエル", "馬", "船", "トラック"]
18 | n_class = len(labels)
19 | img_size = 32
20 | n_result = 3 # 上位3つの結果を表示
21 |
22 | app = Flask(__name__)
23 | app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
24 |
25 |
26 | class Net(nn.Module):
27 | def __init__(self):
28 | super().__init__()
29 | self.conv1 = nn.Conv2d(3, 6, 5)
30 | self.pool = nn.MaxPool2d(2, 2)
31 | self.conv2 = nn.Conv2d(6, 16, 5)
32 | self.fc1 = nn.Linear(16*5*5, 256)
33 | self.dropout = nn.Dropout(p=0.5)
34 | self.fc2 = nn.Linear(256, 10)
35 |
36 | def forward(self, x):
37 | x = self.pool(F.relu(self.conv1(x)))
38 | x = self.pool(F.relu(self.conv2(x)))
39 | x = x.view(-1, 16*5*5)
40 | x = F.relu(self.fc1(x))
41 | x = self.dropout(x)
42 | x = self.fc2(x)
43 | return x
44 |
45 |
46 | def allowed_file(filename):
47 | return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
48 |
49 |
50 | @app.route("/", methods=["GET", "POST"])
51 | def index():
52 | return render_template("index.html")
53 |
54 |
55 | @app.route("/result", methods=["GET", "POST"])
56 | def result():
57 | if request.method == "POST":
58 | # ファイルの存在と形式を確認
59 | if "file" not in request.files:
60 | print("File doesn't exist!")
61 | return redirect(url_for("index"))
62 | file = request.files["file"]
63 | if not allowed_file(file.filename):
64 | print(file.filename + ": File not allowed!")
65 | return redirect(url_for("index"))
66 |
67 | # ファイルの保存
68 | if os.path.isdir(UPLOAD_FOLDER):
69 | shutil.rmtree(UPLOAD_FOLDER)
70 | os.mkdir(UPLOAD_FOLDER)
71 | filename = secure_filename(file.filename) # ファイル名を安全なものに
72 | filepath = os.path.join(UPLOAD_FOLDER, filename)
73 | file.save(filepath)
74 |
75 | # 画像の読み込み
76 | image = Image.open(filepath)
77 | image = image.convert("RGB")
78 | image = image.resize((img_size, img_size))
79 |
80 | normalize = transforms.Normalize(
81 | (0.0, 0.0, 0.0), (1.0, 1.0, 1.0)) # 平均値を0、標準偏差を1に
82 | to_tensor = transforms.ToTensor()
83 | transform = transforms.Compose([to_tensor, normalize])
84 |
85 | x = transform(image)
86 | x = x.reshape(1, 3, img_size, img_size)
87 |
88 | # 予測
89 | net = Net()
90 | net.load_state_dict(torch.load(
91 | "model_cnn.pth", map_location=torch.device("cpu")))
92 | net.eval() # 評価モード
93 |
94 | y = net(x)
95 | y = F.softmax(y, dim=1)[0]
96 | sorted_idx = torch.argsort(-y) # 降順でソート
97 | result = ""
98 | for i in range(n_result):
99 | idx = sorted_idx[i].item()
100 | ratio = y[idx].item()
101 | label = labels[idx]
102 | result += "
" + str(round(ratio*100, 1)) + \ 103 | "%の確率で" + label + "です。
" 104 | return render_template("result.html", result=Markup(result), filepath=filepath) 105 | else: 106 | return redirect(url_for("index")) 107 | 108 | 109 | if __name__ == "__main__": 110 | app.run(debug=True) 111 | -------------------------------------------------------------------------------- /lecture6/classifier/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==1.1.2 2 | Jinja2==2.11.2 3 | Werkzeug==1.0.1 4 | gunicorn==20.0.4 5 | numpy==1.18.1 6 | Pillow==7.1.2 7 | http://download.pytorch.org/whl/cpu/torch-1.3.1%2Bcpu-cp37-cp37m-linux_x86_64.whl 8 | torchvision==0.4.2 9 | -------------------------------------------------------------------------------- /lecture6/classifier/runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.7.7 -------------------------------------------------------------------------------- /lecture6/classifier/static/images/truck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yukinaga/lecture_pytorch/22e7a1d5dab29937fa4d2f574ee1ef1b58fbd065/lecture6/classifier/static/images/truck.jpg -------------------------------------------------------------------------------- /lecture6/classifier/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block content %} 3 |