From 245822c8d50361d7b0db102fb7bc7691b3678b36 Mon Sep 17 00:00:00 2001 From: keon Date: Sat, 19 May 2018 08:36:50 -0400 Subject: [PATCH] add jupyter-notebook compilation --- 01-Deep-Learning-And-PyTorch/README.md | 7 + 02-Getting-Started-With-PyTorch/README.md | 7 + .../mat_mul.py | 0 .../tensor_basic.py | 0 .../README.md | 7 + .../basic_feed_forward_nn.py | 0 .../01-fashion-mnist.ipynb | 442 ++++++++++++++++++ .../01-fashion-mnist.py | 118 +++++ .../02-neural-network.ipynb | 411 ++++++++++++++++ .../02-neural-network.py | 141 ++++++ .../4-fasion-mnist.ipynb | 366 --------------- 04-Neural-Network-For-Fashion/README.md | 9 + 05-CNN-For-Image-Classification/01-cnn.ipynb | 400 ++++++++++++++++ 05-CNN-For-Image-Classification/01-cnn.py | 132 ++++++ 05-CNN-For-Image-Classification/README.md | 7 + 06-Getting-Deeper/README.md | 10 + 07-Autoencoder/README.md | 8 + 08-Generative-Adversarial-Networks/README.md | 8 + 09-RNN-For-Sequential-Data/README.md | 8 + 10-DQN-Learns-From-Environment/README.md | 8 + 11-Mini-Self-Driving-Car/README.md | 10 + README.md | 31 +- compile_notebooks.py | 41 ++ 23 files changed, 1788 insertions(+), 383 deletions(-) create mode 100644 01-Deep-Learning-And-PyTorch/README.md create mode 100644 02-Getting-Started-With-PyTorch/README.md rename mat_mul.py => 02-Getting-Started-With-PyTorch/mat_mul.py (100%) rename tensor_basic.py => 02-Getting-Started-With-PyTorch/tensor_basic.py (100%) create mode 100644 03-Coding-Neural-Networks-In-PyTorch/README.md rename basic_feed_forward_nn.py => 03-Coding-Neural-Networks-In-PyTorch/basic_feed_forward_nn.py (100%) create mode 100644 04-Neural-Network-For-Fashion/01-fashion-mnist.ipynb create mode 100644 04-Neural-Network-For-Fashion/01-fashion-mnist.py create mode 100644 04-Neural-Network-For-Fashion/02-neural-network.ipynb create mode 100644 04-Neural-Network-For-Fashion/02-neural-network.py delete mode 100644 04-Neural-Network-For-Fashion/4-fasion-mnist.ipynb create mode 100644 04-Neural-Network-For-Fashion/README.md create mode 100644 05-CNN-For-Image-Classification/01-cnn.ipynb create mode 100644 05-CNN-For-Image-Classification/01-cnn.py create mode 100644 05-CNN-For-Image-Classification/README.md create mode 100644 06-Getting-Deeper/README.md create mode 100644 07-Autoencoder/README.md create mode 100644 08-Generative-Adversarial-Networks/README.md create mode 100644 09-RNN-For-Sequential-Data/README.md create mode 100644 10-DQN-Learns-From-Environment/README.md create mode 100644 11-Mini-Self-Driving-Car/README.md create mode 100644 compile_notebooks.py diff --git a/01-Deep-Learning-And-PyTorch/README.md b/01-Deep-Learning-And-PyTorch/README.md new file mode 100644 index 0000000..f50be18 --- /dev/null +++ b/01-Deep-Learning-And-PyTorch/README.md @@ -0,0 +1,7 @@ +# 딥러닝과 파이토치 + +딥러닝의 기본 지식을 쌓고 파이토치의 장단점에 대해 알아봅니다. + + * [개념] 신경망의 원리 + * [개념] 딥러닝과 신경망 + * [개념] 왜 파이토치인가? diff --git a/02-Getting-Started-With-PyTorch/README.md b/02-Getting-Started-With-PyTorch/README.md new file mode 100644 index 0000000..91a2ca6 --- /dev/null +++ b/02-Getting-Started-With-PyTorch/README.md @@ -0,0 +1,7 @@ +# 파이토치 시작하기 + +파이토치 환경설정과 사용법을 익혀봅니다 + + * [프로젝트 1] 파이토치 설치 & 환경구성 + * [프로젝트 2] 파이토치 예제 내려받고 실행해보기 + * [프로젝트 3] 토치비전과 토치텍스트로 데이터셋 불러오기 diff --git a/mat_mul.py b/02-Getting-Started-With-PyTorch/mat_mul.py similarity index 100% rename from mat_mul.py rename to 02-Getting-Started-With-PyTorch/mat_mul.py diff --git a/tensor_basic.py b/02-Getting-Started-With-PyTorch/tensor_basic.py similarity index 100% rename from tensor_basic.py rename to 02-Getting-Started-With-PyTorch/tensor_basic.py diff --git a/03-Coding-Neural-Networks-In-PyTorch/README.md b/03-Coding-Neural-Networks-In-PyTorch/README.md new file mode 100644 index 0000000..91c69df --- /dev/null +++ b/03-Coding-Neural-Networks-In-PyTorch/README.md @@ -0,0 +1,7 @@ +# 파이토치로 구현하는 신경망 + +파이토치를 이용하여 가장 기본적인 신경망을 만들어봅니다. + + * [개념] 텐서와 Autograd + * [Hello World] 신경망 모델 구현하기 + * [Hello World] 모델 저장, 재사용 diff --git a/basic_feed_forward_nn.py b/03-Coding-Neural-Networks-In-PyTorch/basic_feed_forward_nn.py similarity index 100% rename from basic_feed_forward_nn.py rename to 03-Coding-Neural-Networks-In-PyTorch/basic_feed_forward_nn.py diff --git a/04-Neural-Network-For-Fashion/01-fashion-mnist.ipynb b/04-Neural-Network-For-Fashion/01-fashion-mnist.ipynb new file mode 100644 index 0000000..d00b967 --- /dev/null +++ b/04-Neural-Network-For-Fashion/01-fashion-mnist.ipynb @@ -0,0 +1,442 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4.1 Fashion MNIST 데이터셋 알아보기" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "from torchvision import datasets, transforms, utils\n", + "from torch.utils import data\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## [개념] Fashion MNIST 데이터셋 설명" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "transform = transforms.Compose([\n", + " transforms.ToTensor()\n", + "])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "trainset = datasets.FashionMNIST(\n", + " root = './.data/', \n", + " train = True,\n", + " download = True,\n", + " transform = transform\n", + ")\n", + "testset = datasets.FashionMNIST(\n", + " root = './.data/', \n", + " train = False,\n", + " download = True,\n", + " transform = transform\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "batch_size = 16\n", + "\n", + "train_loader = data.DataLoader(\n", + " dataset = trainset,\n", + " batch_size = batch_size,\n", + " shuffle = True,\n", + " num_workers = 2\n", + ")\n", + "test_loader = data.DataLoader(\n", + " dataset = testset,\n", + " batch_size = batch_size,\n", + " shuffle = True,\n", + " num_workers = 2\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "dataiter = iter(train_loader)\n", + "images, labels = next(dataiter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 멀리서 살펴보기\n", + "\n", + "누군가 \"숲을 먼저 보고 나무를 보라\"고 했습니다. 데이터셋을 먼저 전체적으로 살펴보며 어떤 느낌인지 알아보겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "img = utils.make_grid(images, padding=0)\n", + "npimg = img.numpy()\n", + "plt.figure(figsize=(10, 7))\n", + "plt.imshow(np.transpose(npimg, (1,2,0)))\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "앵클부츠\n", + "샌들\n", + "바지\n", + "셔츠\n", + "스웨터\n", + "가방\n", + "스웨터\n", + "샌들\n", + "앵클부츠\n", + "스웨터\n", + "운동화\n", + "앵클부츠\n", + "바지\n", + "샌들\n", + "티셔츠\n", + "샌들\n" + ] + } + ], + "source": [ + "CLASSES = {\n", + " 0: 'T-shirt/top',\n", + " 1: 'Trouser',\n", + " 2: 'Pullover',\n", + " 3: 'Dress',\n", + " 4: 'Coat',\n", + " 5: 'Sandal',\n", + " 6: 'Shirt',\n", + " 7: 'Sneaker',\n", + " 8: 'Bag',\n", + " 9: 'Ankle boot'\n", + "}\n", + "\n", + "KR_CLASSES = {\n", + " 0: '티셔츠',\n", + " 1: '바지',\n", + " 2: '스웨터',\n", + " 3: '드레스',\n", + " 4: '코트',\n", + " 5: '샌들',\n", + " 6: '셔츠',\n", + " 7: '운동화',\n", + " 8: '가방',\n", + " 9: '앵클부츠'\n", + "}\n", + "\n", + "for label in labels:\n", + " index = label.item()\n", + " print(KR_CLASSES[index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 가까이서 살펴보기\n", + "\n", + "또 누군가는 \"숲만 보지 말고 나무를 보라\"고 합니다. 이제 전체적인 느낌을 알았으니 개별적으로 살펴보겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "idx = 0\n", + "\n", + "item_img = images[idx]\n", + "item_npimg = img.squeeze().numpy()\n", + "plt.title(CLASSES[labels[idx].item()])\n", + "plt.imshow(item_npimg, cmap='gray')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([1, 28, 28])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "img.size()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(1.)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "img.max()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "img.min()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0039, 0.0000,\n", + " 0.0000, 0.6078, 0.6431, 0.6078, 0.5804, 0.5922, 0.5804,\n", + " 0.6000, 0.4902, 0.4000, 0.2980, 0.1922, 0.1529, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0118, 0.0000,\n", + " 0.0000, 0.9373, 0.8588, 0.9020, 0.8980, 0.9059, 0.9020,\n", + " 0.8941, 0.9137, 0.9608, 0.8588, 0.8314, 0.8157, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0078, 0.0000,\n", + " 0.0902, 0.9137, 0.8039, 0.8196, 0.8078, 0.8196, 0.7843,\n", + " 0.7686, 0.7765, 0.7843, 0.7961, 0.8078, 0.6039, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0078, 0.0000,\n", + " 0.3569, 0.8471, 0.8275, 0.8118, 0.8314, 0.8510, 0.8078,\n", + " 0.7922, 0.8235, 0.8353, 0.7922, 0.8118, 0.4941, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.5882, 0.8235, 0.8431, 0.8118, 0.8157, 0.8392, 0.8078,\n", + " 0.8039, 0.8196, 0.8039, 0.7804, 0.8275, 0.3765, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.8157, 0.8235, 0.8588, 0.7961, 0.8235, 0.8431, 0.8039,\n", + " 0.8000, 0.7961, 0.7765, 0.7843, 0.8471, 0.3843, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.3137,\n", + " 0.9882, 0.8118, 0.8588, 0.8275, 0.8275, 0.8471, 0.8078,\n", + " 0.7922, 0.7882, 0.8275, 0.7725, 0.8157, 0.4745, 0.0000],\n", + " [ 0.0039, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0039,\n", + " 0.0000, 0.0000, 0.0039, 0.0039, 0.0000, 0.0000, 0.8157,\n", + " 0.8039, 0.8275, 0.8510, 0.8431, 0.8235, 0.8235, 0.8275,\n", + " 0.7765, 0.7333, 0.7765, 0.7804, 0.8000, 0.5922, 0.0000],\n", + " [ 0.0000, 0.0039, 0.0039, 0.0039, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0078, 0.0000, 0.0000, 0.5843, 0.8902,\n", + " 0.7804, 0.8353, 0.8314, 0.8235, 0.8157, 0.8118, 0.8196,\n", + " 0.7882, 0.7608, 0.7686, 0.7059, 0.8039, 0.7647, 0.0000],\n", + " [ 0.0039, 0.0039, 0.0000, 0.0039, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0078, 0.0000, 0.0000, 0.3529, 0.9294, 0.7333,\n", + " 0.7804, 0.8000, 0.7961, 0.8039, 0.8275, 0.7882, 0.8078,\n", + " 0.8314, 0.7922, 0.8118, 0.7294, 0.6549, 0.8196, 0.0667],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0039, 0.0000, 0.0000,\n", + " 0.0078, 0.0000, 0.0000, 0.1608, 0.8000, 0.7176, 0.7255,\n", + " 0.7529, 0.7922, 0.7961, 0.8118, 0.8235, 0.8039, 0.7961,\n", + " 0.7686, 0.7176, 0.7569, 0.6980, 0.5608, 0.7882, 0.2314],\n", + " [ 0.0000, 0.0039, 0.0118, 0.0118, 0.0078, 0.0118, 0.0078,\n", + " 0.0000, 0.0000, 0.1725, 0.7882, 0.7059, 0.6941, 0.7294,\n", + " 0.7412, 0.7804, 0.8157, 0.7804, 0.8039, 0.7882, 0.7647,\n", + " 0.6392, 0.6627, 0.7020, 0.6549, 0.5922, 0.7922, 0.3569],\n", + " [ 0.0157, 0.0039, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.3412, 0.8118, 0.7098, 0.7216, 0.7137, 0.7451,\n", + " 0.7804, 0.7804, 0.7765, 0.7373, 0.7647, 0.7686, 0.7608,\n", + " 0.7020, 0.7098, 0.6784, 0.6353, 0.5922, 0.7647, 0.3176],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0706, 0.3686,\n", + " 0.6667, 0.7765, 0.6627, 0.7255, 0.7451, 0.7137, 0.7765,\n", + " 0.7804, 0.7804, 0.8000, 0.8078, 0.7765, 0.7725, 0.7412,\n", + " 0.7137, 0.6980, 0.7333, 0.7137, 0.6902, 0.8824, 0.2667],\n", + " [ 0.0000, 0.4118, 0.5647, 0.5294, 0.6000, 0.7255, 0.7137,\n", + " 0.6471, 0.6039, 0.6667, 0.7569, 0.7020, 0.7529, 0.7647,\n", + " 0.7569, 0.7804, 0.7412, 0.7216, 0.7765, 0.8235, 0.7608,\n", + " 0.7686, 0.8118, 0.8078, 0.8118, 0.7451, 0.8745, 0.2510],\n", + " [ 0.2941, 0.7725, 0.6588, 0.6471, 0.6353, 0.6392, 0.6314,\n", + " 0.6627, 0.6745, 0.7059, 0.7373, 0.7608, 0.7412, 0.7373,\n", + " 0.7098, 0.7333, 0.7765, 0.9686, 1.0000, 0.6745, 0.7686,\n", + " 0.8196, 0.7804, 0.7765, 0.7569, 0.7059, 0.8196, 0.2078],\n", + " [ 0.4078, 0.8471, 0.8078, 0.8196, 0.7843, 0.7765, 0.7569,\n", + " 0.7294, 0.7137, 0.7176, 0.7020, 0.7098, 0.7216, 0.7686,\n", + " 0.8118, 0.9686, 0.7569, 0.4000, 0.0118, 0.0000, 0.5686,\n", + " 0.8078, 0.7098, 0.7412, 0.7608, 0.7255, 0.8588, 0.1804],\n", + " [ 0.0000, 0.1098, 0.4431, 0.6353, 0.7804, 0.8824, 0.9529,\n", + " 0.9490, 0.9333, 0.9137, 0.8941, 0.8941, 0.9373, 0.9294,\n", + " 0.6235, 0.1176, 0.0000, 0.0000, 0.0000, 0.0000, 0.6235,\n", + " 0.9882, 0.7725, 0.8353, 0.8392, 0.8118, 0.9216, 0.1608],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0471,\n", + " 0.1686, 0.2549, 0.3765, 0.4667, 0.3843, 0.2588, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0039, 0.0000, 0.0000, 0.2863,\n", + " 0.8627, 0.6627, 0.6824, 0.6824, 0.6941, 0.6980, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],\n", + " [ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,\n", + " 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]])" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "img" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/04-Neural-Network-For-Fashion/01-fashion-mnist.py b/04-Neural-Network-For-Fashion/01-fashion-mnist.py new file mode 100644 index 0000000..d5fad8e --- /dev/null +++ b/04-Neural-Network-For-Fashion/01-fashion-mnist.py @@ -0,0 +1,118 @@ + +# coding: utf-8 + +# # 4.1 Fashion MNIST 데이터셋 알아보기 + +get_ipython().run_line_magic('matplotlib', 'inline') +from torchvision import datasets, transforms, utils +from torch.utils import data + +import matplotlib.pyplot as plt +import numpy as np + + +# ## [개념] Fashion MNIST 데이터셋 설명 + +transform = transforms.Compose([ + transforms.ToTensor() +]) + + +trainset = datasets.FashionMNIST( + root = './.data/', + train = True, + download = True, + transform = transform +) +testset = datasets.FashionMNIST( + root = './.data/', + train = False, + download = True, + transform = transform +) + + +batch_size = 16 + +train_loader = data.DataLoader( + dataset = trainset, + batch_size = batch_size, + shuffle = True, + num_workers = 2 +) +test_loader = data.DataLoader( + dataset = testset, + batch_size = batch_size, + shuffle = True, + num_workers = 2 +) + + +dataiter = iter(train_loader) +images, labels = next(dataiter) + + +# ## 멀리서 살펴보기 +# 누군가 "숲을 먼저 보고 나무를 보라"고 했습니다. 데이터셋을 먼저 전체적으로 살펴보며 어떤 느낌인지 알아보겠습니다. + +img = utils.make_grid(images, padding=0) +npimg = img.numpy() +plt.figure(figsize=(10, 7)) +plt.imshow(np.transpose(npimg, (1,2,0))) +plt.show() + + +CLASSES = { + 0: 'T-shirt/top', + 1: 'Trouser', + 2: 'Pullover', + 3: 'Dress', + 4: 'Coat', + 5: 'Sandal', + 6: 'Shirt', + 7: 'Sneaker', + 8: 'Bag', + 9: 'Ankle boot' +} + +KR_CLASSES = { + 0: '티셔츠', + 1: '바지', + 2: '스웨터', + 3: '드레스', + 4: '코트', + 5: '샌들', + 6: '셔츠', + 7: '운동화', + 8: '가방', + 9: '앵클부츠' +} + +for label in labels: + index = label.item() + print(KR_CLASSES[index]) + + +# ## 가까이서 살펴보기 +# 또 누군가는 "숲만 보지 말고 나무를 보라"고 합니다. 이제 전체적인 느낌을 알았으니 개별적으로 살펴보겠습니다. + +idx = 0 + +item_img = images[idx] +item_npimg = img.squeeze().numpy() +plt.title(CLASSES[labels[idx].item()]) +plt.imshow(item_npimg, cmap='gray') +plt.show() + + +img.size() + + +img.max() + + +img.min() + + +img + diff --git a/04-Neural-Network-For-Fashion/02-neural-network.ipynb b/04-Neural-Network-For-Fashion/02-neural-network.ipynb new file mode 100644 index 0000000..f17ce2d --- /dev/null +++ b/04-Neural-Network-For-Fashion/02-neural-network.ipynb @@ -0,0 +1,411 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4. 딥러닝으로 패션 아이템 구분하기\n", + "Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다.\n", + "\n", + "본 튜토리얼은 PyTorch의 공식 튜토리얼 (https://github.com/pytorch/examples/blob/master/mnist/main.py)을 참고하여 만들어졌습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torchvision\n", + "import torch.nn.functional as F\n", + "from torch import nn, optim\n", + "from torch.autograd import Variable\n", + "from torchvision import transforms, datasets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "use_cuda = torch.cuda.is_available()\n", + "device = torch.device(\"cuda\" if use_cuda else \"cpu\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "batch_size = 64" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "transform = transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.1307,), (0.3081,))\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 데이터셋 불러오기" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "trainset = datasets.FashionMNIST(\n", + " root = './.data/', \n", + " train = True,\n", + " download = True,\n", + " transform = transform\n", + ")\n", + "testset = datasets.FashionMNIST(\n", + " root = './.data/', \n", + " train = False,\n", + " download = True,\n", + " transform = transform\n", + ")\n", + "\n", + "train_loader = torch.utils.data.DataLoader(\n", + " dataset = trainset,\n", + " batch_size = batch_size,\n", + " shuffle = True,\n", + ")\n", + "test_loader = torch.utils.data.DataLoader(\n", + " dataset = testset,\n", + " batch_size = batch_size,\n", + " shuffle = True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 뉴럴넷으로 Fashion MNIST 학습하기\n", + "\n", + "입력 `x` 는 `[배치크기, 색, 높이, 넓이]`로 이루어져 있습니다.\n", + "`x.size()`를 해보면 `[64, 1, 28, 28]`이라고 표시되는 것을 보실 수 있습니다.\n", + "Fashion MNIST에서 이미지의 크기는 28 x 28, 색은 흑백으로 1 가지 입니다.\n", + "그러므로 입력 x의 총 특성값 갯수는 28 x 28 x 1, 즉 784개 입니다.\n", + "\n", + "우리가 사용할 모델은 3개의 레이어를 가진 뉴럴네트워크 입니다. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "class Net(nn.Module):\n", + " def __init__(self):\n", + " super(Net, self).__init__()\n", + " self.fc1 = nn.Linear(784, 256)\n", + " self.fc2 = nn.Linear(256, 256)\n", + " self.fc3 = nn.Linear(256, 10)\n", + "\n", + " def forward(self, x):\n", + " x = x.view(-1, 784)\n", + " x = F.relu(self.fc1(x))\n", + " x = F.relu(self.fc2(x))\n", + " x = self.fc3(x)\n", + " return x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 하이퍼파라미터 \n", + "\n", + "`to()` 함수는 모델의 파라미터들을 지정한 곳으로 보내는 역할을 합니다.\n", + "일반적으로 CPU 1개만 사용할 경우 필요는 없지만,\n", + "GPU를 사용하고자 하는 경우 `to(\"cuda\")`로 지정하여 GPU로 보내야 합니다.\n", + "지정하지 않을 경우 계속 CPU에 남아 있게 되며 빠른 훈련의 이점을 누리실 수 없습니다.\n", + "\n", + "최적화 알고리즘으로 파이토치에 내장되어 있는 `optim.SGD`를 사용하겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "model = Net().to(device)\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)\n", + "epochs = 10\n", + "log_interval = 100" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 훈련하기" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def train(model, device, train_loader, optimizer, epoch):\n", + " model.train()\n", + " for batch_idx, (data, target) in enumerate(train_loader):\n", + " data, target = data.to(device), target.to(device)\n", + " optimizer.zero_grad()\n", + " output = model(data)\n", + " loss = F.cross_entropy(output, target)\n", + " loss.backward()\n", + " optimizer.step()\n", + " if batch_idx % log_interval == 0:\n", + " print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n", + " epoch, batch_idx * len(data), len(train_loader.dataset),\n", + " 100. * batch_idx / len(train_loader), loss.item()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 테스트하기\n", + "\n", + "아무리 훈련이 잘 되었다고 해도 실제 데이터를 만났을때 성능이 낮다면 쓸모 없는 모델일 것입니다.\n", + "우리가 진정 원하는 것은 훈련 데이터에 최적화한 모델이 아니라 모든 데이터에서 높은 성능을 보이는 모델이기 때문입니다.\n", + "세상에 존재하는 모든 데이터에 최적화 하는 것을 \"일반화\"라고 부르고\n", + "모델이 얼마나 실제 데이터에 적응하는지를 수치로 나타낸 것을 \"일반화 오류\"(Generalization Error) 라고 합니다. \n", + "\n", + "우리가 만든 모델이 얼마나 일반화를 잘 하는지 알아보기 위해,\n", + "그리고 언제 훈련을 멈추어야 할지 알기 위해\n", + "매 이포크가 끝날때 마다 테스트셋으로 모델의 성능을 측정해보겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def test(model, device, test_loader):\n", + " model.eval()\n", + " test_loss = 0\n", + " correct = 0\n", + " with torch.no_grad():\n", + " for data, target in test_loader:\n", + " data, target = data.to(device), target.to(device)\n", + " output = model(data)\n", + " test_loss += F.cross_entropy(output, target, size_average=False).item() # sum up batch loss\n", + " pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability\n", + " correct += pred.eq(target.view_as(pred)).sum().item()\n", + "\n", + " test_loss /= len(test_loader.dataset)\n", + " print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", + " test_loss, correct, len(test_loader.dataset),\n", + " 100. * correct / len(test_loader.dataset)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 코드 돌려보기\n", + "\n", + "자, 이제 모든 준비가 끝났습니다. 코드를 돌려서 실제로 훈련이 되는지 확인해봅시다!" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Epoch: 1 [0/60000 (0%)]\tLoss: 2.297793\n", + "Train Epoch: 1 [6400/60000 (11%)]\tLoss: 0.879420\n", + "Train Epoch: 1 [12800/60000 (21%)]\tLoss: 0.707845\n", + "Train Epoch: 1 [19200/60000 (32%)]\tLoss: 0.491728\n", + "Train Epoch: 1 [25600/60000 (43%)]\tLoss: 0.746743\n", + "Train Epoch: 1 [32000/60000 (53%)]\tLoss: 0.598782\n", + "Train Epoch: 1 [38400/60000 (64%)]\tLoss: 0.523441\n", + "Train Epoch: 1 [44800/60000 (75%)]\tLoss: 0.399858\n", + "Train Epoch: 1 [51200/60000 (85%)]\tLoss: 0.577800\n", + "Train Epoch: 1 [57600/60000 (96%)]\tLoss: 0.614767\n", + "\n", + "Test set: Average loss: 0.5003, Accuracy: 8229/10000 (82%)\n", + "\n", + "Train Epoch: 2 [0/60000 (0%)]\tLoss: 0.451823\n", + "Train Epoch: 2 [6400/60000 (11%)]\tLoss: 0.364500\n", + "Train Epoch: 2 [12800/60000 (21%)]\tLoss: 0.264642\n", + "Train Epoch: 2 [19200/60000 (32%)]\tLoss: 0.635316\n", + "Train Epoch: 2 [25600/60000 (43%)]\tLoss: 0.487202\n", + "Train Epoch: 2 [32000/60000 (53%)]\tLoss: 0.658737\n", + "Train Epoch: 2 [38400/60000 (64%)]\tLoss: 0.532459\n", + "Train Epoch: 2 [44800/60000 (75%)]\tLoss: 0.288026\n", + "Train Epoch: 2 [51200/60000 (85%)]\tLoss: 0.449904\n", + "Train Epoch: 2 [57600/60000 (96%)]\tLoss: 0.482623\n", + "\n", + "Test set: Average loss: 0.4316, Accuracy: 8439/10000 (84%)\n", + "\n", + "Train Epoch: 3 [0/60000 (0%)]\tLoss: 0.331988\n", + "Train Epoch: 3 [6400/60000 (11%)]\tLoss: 0.245480\n", + "Train Epoch: 3 [12800/60000 (21%)]\tLoss: 0.491709\n", + "Train Epoch: 3 [19200/60000 (32%)]\tLoss: 0.395424\n", + "Train Epoch: 3 [25600/60000 (43%)]\tLoss: 0.382458\n", + "Train Epoch: 3 [32000/60000 (53%)]\tLoss: 0.322766\n", + "Train Epoch: 3 [38400/60000 (64%)]\tLoss: 0.301913\n", + "Train Epoch: 3 [44800/60000 (75%)]\tLoss: 0.318479\n", + "Train Epoch: 3 [51200/60000 (85%)]\tLoss: 0.267777\n", + "Train Epoch: 3 [57600/60000 (96%)]\tLoss: 0.416187\n", + "\n", + "Test set: Average loss: 0.4085, Accuracy: 8511/10000 (85%)\n", + "\n", + "Train Epoch: 4 [0/60000 (0%)]\tLoss: 0.347194\n", + "Train Epoch: 4 [6400/60000 (11%)]\tLoss: 0.420034\n", + "Train Epoch: 4 [12800/60000 (21%)]\tLoss: 0.557871\n", + "Train Epoch: 4 [19200/60000 (32%)]\tLoss: 0.157676\n", + "Train Epoch: 4 [25600/60000 (43%)]\tLoss: 0.444332\n", + "Train Epoch: 4 [32000/60000 (53%)]\tLoss: 0.443144\n", + "Train Epoch: 4 [38400/60000 (64%)]\tLoss: 0.518663\n", + "Train Epoch: 4 [44800/60000 (75%)]\tLoss: 0.300901\n", + "Train Epoch: 4 [51200/60000 (85%)]\tLoss: 0.314376\n", + "Train Epoch: 4 [57600/60000 (96%)]\tLoss: 0.365263\n", + "\n", + "Test set: Average loss: 0.3886, Accuracy: 8594/10000 (86%)\n", + "\n", + "Train Epoch: 5 [0/60000 (0%)]\tLoss: 0.258622\n", + "Train Epoch: 5 [6400/60000 (11%)]\tLoss: 0.323684\n", + "Train Epoch: 5 [12800/60000 (21%)]\tLoss: 0.242623\n", + "Train Epoch: 5 [19200/60000 (32%)]\tLoss: 0.304207\n", + "Train Epoch: 5 [25600/60000 (43%)]\tLoss: 0.430161\n", + "Train Epoch: 5 [32000/60000 (53%)]\tLoss: 0.380617\n", + "Train Epoch: 5 [38400/60000 (64%)]\tLoss: 0.453532\n", + "Train Epoch: 5 [44800/60000 (75%)]\tLoss: 0.639302\n", + "Train Epoch: 5 [51200/60000 (85%)]\tLoss: 0.345414\n", + "Train Epoch: 5 [57600/60000 (96%)]\tLoss: 0.440118\n", + "\n", + "Test set: Average loss: 0.3828, Accuracy: 8623/10000 (86%)\n", + "\n", + "Train Epoch: 6 [0/60000 (0%)]\tLoss: 0.297733\n", + "Train Epoch: 6 [6400/60000 (11%)]\tLoss: 0.313359\n", + "Train Epoch: 6 [12800/60000 (21%)]\tLoss: 0.296536\n", + "Train Epoch: 6 [19200/60000 (32%)]\tLoss: 0.194678\n", + "Train Epoch: 6 [25600/60000 (43%)]\tLoss: 0.354127\n", + "Train Epoch: 6 [32000/60000 (53%)]\tLoss: 0.360125\n", + "Train Epoch: 6 [38400/60000 (64%)]\tLoss: 0.367713\n", + "Train Epoch: 6 [44800/60000 (75%)]\tLoss: 0.301126\n", + "Train Epoch: 6 [51200/60000 (85%)]\tLoss: 0.361885\n", + "Train Epoch: 6 [57600/60000 (96%)]\tLoss: 0.286500\n", + "\n", + "Test set: Average loss: 0.3586, Accuracy: 8701/10000 (87%)\n", + "\n", + "Train Epoch: 7 [0/60000 (0%)]\tLoss: 0.276611\n", + "Train Epoch: 7 [6400/60000 (11%)]\tLoss: 0.427675\n", + "Train Epoch: 7 [12800/60000 (21%)]\tLoss: 0.251460\n", + "Train Epoch: 7 [19200/60000 (32%)]\tLoss: 0.242846\n", + "Train Epoch: 7 [25600/60000 (43%)]\tLoss: 0.379731\n", + "Train Epoch: 7 [32000/60000 (53%)]\tLoss: 0.467081\n", + "Train Epoch: 7 [38400/60000 (64%)]\tLoss: 0.359526\n", + "Train Epoch: 7 [44800/60000 (75%)]\tLoss: 0.286382\n", + "Train Epoch: 7 [51200/60000 (85%)]\tLoss: 0.251880\n", + "Train Epoch: 7 [57600/60000 (96%)]\tLoss: 0.212195\n", + "\n", + "Test set: Average loss: 0.3587, Accuracy: 8714/10000 (87%)\n", + "\n", + "Train Epoch: 8 [0/60000 (0%)]\tLoss: 0.289801\n", + "Train Epoch: 8 [6400/60000 (11%)]\tLoss: 0.317002\n", + "Train Epoch: 8 [12800/60000 (21%)]\tLoss: 0.265676\n", + "Train Epoch: 8 [19200/60000 (32%)]\tLoss: 0.374449\n", + "Train Epoch: 8 [25600/60000 (43%)]\tLoss: 0.283620\n", + "Train Epoch: 8 [32000/60000 (53%)]\tLoss: 0.423949\n", + "Train Epoch: 8 [38400/60000 (64%)]\tLoss: 0.340573\n", + "Train Epoch: 8 [44800/60000 (75%)]\tLoss: 0.410054\n", + "Train Epoch: 8 [51200/60000 (85%)]\tLoss: 0.416204\n", + "Train Epoch: 8 [57600/60000 (96%)]\tLoss: 0.374269\n", + "\n", + "Test set: Average loss: 0.3445, Accuracy: 8747/10000 (87%)\n", + "\n", + "Train Epoch: 9 [0/60000 (0%)]\tLoss: 0.291795\n", + "Train Epoch: 9 [6400/60000 (11%)]\tLoss: 0.330994\n", + "Train Epoch: 9 [12800/60000 (21%)]\tLoss: 0.228712\n", + "Train Epoch: 9 [19200/60000 (32%)]\tLoss: 0.232579\n", + "Train Epoch: 9 [25600/60000 (43%)]\tLoss: 0.269398\n", + "Train Epoch: 9 [32000/60000 (53%)]\tLoss: 0.231449\n", + "Train Epoch: 9 [38400/60000 (64%)]\tLoss: 0.278414\n", + "Train Epoch: 9 [44800/60000 (75%)]\tLoss: 0.235476\n", + "Train Epoch: 9 [51200/60000 (85%)]\tLoss: 0.263410\n", + "Train Epoch: 9 [57600/60000 (96%)]\tLoss: 0.325505\n", + "\n", + "Test set: Average loss: 0.3491, Accuracy: 8738/10000 (87%)\n", + "\n", + "Train Epoch: 10 [0/60000 (0%)]\tLoss: 0.255661\n", + "Train Epoch: 10 [6400/60000 (11%)]\tLoss: 0.358245\n", + "Train Epoch: 10 [12800/60000 (21%)]\tLoss: 0.256200\n", + "Train Epoch: 10 [19200/60000 (32%)]\tLoss: 0.244674\n", + "Train Epoch: 10 [25600/60000 (43%)]\tLoss: 0.242888\n", + "Train Epoch: 10 [32000/60000 (53%)]\tLoss: 0.384486\n", + "Train Epoch: 10 [38400/60000 (64%)]\tLoss: 0.199211\n", + "Train Epoch: 10 [44800/60000 (75%)]\tLoss: 0.213740\n", + "Train Epoch: 10 [51200/60000 (85%)]\tLoss: 0.239941\n", + "Train Epoch: 10 [57600/60000 (96%)]\tLoss: 0.319814\n", + "\n", + "Test set: Average loss: 0.3401, Accuracy: 8738/10000 (87%)\n", + "\n" + ] + } + ], + "source": [ + "for epoch in range(1, epochs + 1):\n", + " train(model, device, train_loader, optimizer, epoch)\n", + " test(model, device, test_loader)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/04-Neural-Network-For-Fashion/02-neural-network.py b/04-Neural-Network-For-Fashion/02-neural-network.py new file mode 100644 index 0000000..04439ce --- /dev/null +++ b/04-Neural-Network-For-Fashion/02-neural-network.py @@ -0,0 +1,141 @@ + +# coding: utf-8 + +# # 4. 딥러닝으로 패션 아이템 구분하기 +# Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다. +# 본 튜토리얼은 PyTorch의 공식 튜토리얼 (https://github.com/pytorch/examples/blob/master/mnist/main.py)을 참고하여 만들어졌습니다. + +import torch +import torchvision +import torch.nn.functional as F +from torch import nn, optim +from torch.autograd import Variable +from torchvision import transforms, datasets + + +use_cuda = torch.cuda.is_available() +device = torch.device("cuda" if use_cuda else "cpu") + + +batch_size = 64 + + +transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.1307,), (0.3081,)) +]) + + +# ## 데이터셋 불러오기 + +trainset = datasets.FashionMNIST( + root = './.data/', + train = True, + download = True, + transform = transform +) +testset = datasets.FashionMNIST( + root = './.data/', + train = False, + download = True, + transform = transform +) + +train_loader = torch.utils.data.DataLoader( + dataset = trainset, + batch_size = batch_size, + shuffle = True, +) +test_loader = torch.utils.data.DataLoader( + dataset = testset, + batch_size = batch_size, + shuffle = True, +) + + +# ## 뉴럴넷으로 Fashion MNIST 학습하기 +# 입력 `x` 는 `[배치크기, 색, 높이, 넓이]`로 이루어져 있습니다. +# `x.size()`를 해보면 `[64, 1, 28, 28]`이라고 표시되는 것을 보실 수 있습니다. +# Fashion MNIST에서 이미지의 크기는 28 x 28, 색은 흑백으로 1 가지 입니다. +# 그러므로 입력 x의 총 특성값 갯수는 28 x 28 x 1, 즉 784개 입니다. +# 우리가 사용할 모델은 3개의 레이어를 가진 뉴럴네트워크 입니다. + +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.fc1 = nn.Linear(784, 256) + self.fc2 = nn.Linear(256, 256) + self.fc3 = nn.Linear(256, 10) + + def forward(self, x): + x = x.view(-1, 784) + x = F.relu(self.fc1(x)) + x = F.relu(self.fc2(x)) + x = self.fc3(x) + return x + + +# ## 하이퍼파라미터 +# `to()` 함수는 모델의 파라미터들을 지정한 곳으로 보내는 역할을 합니다. +# 일반적으로 CPU 1개만 사용할 경우 필요는 없지만, +# GPU를 사용하고자 하는 경우 `to("cuda")`로 지정하여 GPU로 보내야 합니다. +# 지정하지 않을 경우 계속 CPU에 남아 있게 되며 빠른 훈련의 이점을 누리실 수 없습니다. +# 최적화 알고리즘으로 파이토치에 내장되어 있는 `optim.SGD`를 사용하겠습니다. + +model = Net().to(device) +optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5) +epochs = 10 +log_interval = 100 + + +# ## 훈련하기 + +def train(model, device, train_loader, optimizer, epoch): + model.train() + for batch_idx, (data, target) in enumerate(train_loader): + data, target = data.to(device), target.to(device) + optimizer.zero_grad() + output = model(data) + loss = F.cross_entropy(output, target) + loss.backward() + optimizer.step() + if batch_idx % log_interval == 0: + print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( + epoch, batch_idx * len(data), len(train_loader.dataset), + 100. * batch_idx / len(train_loader), loss.item())) + + +# ## 테스트하기 +# 아무리 훈련이 잘 되었다고 해도 실제 데이터를 만났을때 성능이 낮다면 쓸모 없는 모델일 것입니다. +# 우리가 진정 원하는 것은 훈련 데이터에 최적화한 모델이 아니라 모든 데이터에서 높은 성능을 보이는 모델이기 때문입니다. +# 세상에 존재하는 모든 데이터에 최적화 하는 것을 "일반화"라고 부르고 +# 모델이 얼마나 실제 데이터에 적응하는지를 수치로 나타낸 것을 "일반화 오류"(Generalization Error) 라고 합니다. +# 우리가 만든 모델이 얼마나 일반화를 잘 하는지 알아보기 위해, +# 그리고 언제 훈련을 멈추어야 할지 알기 위해 +# 매 이포크가 끝날때 마다 테스트셋으로 모델의 성능을 측정해보겠습니다. + +def test(model, device, test_loader): + model.eval() + test_loss = 0 + correct = 0 + with torch.no_grad(): + for data, target in test_loader: + data, target = data.to(device), target.to(device) + output = model(data) + test_loss += F.cross_entropy(output, target, size_average=False).item() # sum up batch loss + pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability + correct += pred.eq(target.view_as(pred)).sum().item() + + test_loss /= len(test_loader.dataset) + print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( + test_loss, correct, len(test_loader.dataset), + 100. * correct / len(test_loader.dataset))) + + +# ## 코드 돌려보기 +# 자, 이제 모든 준비가 끝났습니다. 코드를 돌려서 실제로 훈련이 되는지 확인해봅시다! + +for epoch in range(1, epochs + 1): + train(model, device, train_loader, optimizer, epoch) + test(model, device, test_loader) + diff --git a/04-Neural-Network-For-Fashion/4-fasion-mnist.ipynb b/04-Neural-Network-For-Fashion/4-fasion-mnist.ipynb deleted file mode 100644 index d421ffd..0000000 --- a/04-Neural-Network-For-Fashion/4-fasion-mnist.ipynb +++ /dev/null @@ -1,366 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 4. 딥러닝으로 패션 아이템 구분하기\n", - "Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import torch\n", - "import torchvision\n", - "import torchvision.transforms as transforms\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "import torch.optim as optim\n", - "from torch.autograd import Variable\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "cuda = True" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "batch_size = 256" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "transform = transforms.Compose([\n", - " transforms.RandomHorizontalFlip(),\n", - " transforms.ColorJitter(),\n", - " transforms.RandomRotation(35),\n", - " transforms.ToTensor(),\n", - " transforms.Normalize((0.5,), (0.5,))\n", - "])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## [개념] Fashion MNIST 데이터셋 설명" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz\n", - "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-labels-idx1-ubyte.gz\n", - "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-images-idx3-ubyte.gz\n", - "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz\n", - "Processing...\n", - "Done!\n" - ] - } - ], - "source": [ - "trainset = torchvision.datasets.FashionMNIST(\n", - " root = './.data/', \n", - " train = True,\n", - " download = True,\n", - " transform = transform\n", - ")\n", - "trainloader = torch.utils.data.DataLoader(\n", - " dataset = trainset,\n", - " batch_size = batch_size,\n", - " shuffle = True,\n", - " num_workers = 2\n", - ")\n", - "testset = torchvision.datasets.FashionMNIST(\n", - " root = './.data/', \n", - " train = False,\n", - " download = True,\n", - " transform = transform\n", - ")\n", - "testloader = torch.utils.data.DataLoader(\n", - " dataset = testset,\n", - " batch_size = batch_size,\n", - " shuffle = True,\n", - " num_workers = 2\n", - ")\n", - "classes = (\n", - " 'top',\n", - " 'trouser',\n", - " 'pullover',\n", - " 'dress',\n", - " 'coat',\n", - " 'sandal',\n", - " 'shirt',\n", - " 'sneaker',\n", - " 'bag',\n", - " 'boot'\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "def show(img):\n", - " img = img / 2 + 0.5\n", - " npimg = img.numpy()\n", - " plt.figure(figsize=(20, 8))\n", - " plt.imshow(np.transpose(npimg, (1,2,0)),\n", - " interpolation='nearest')\n", - " plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "dataiter = iter(trainloader)\n", - "images, labels = dataiter.next()" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "show(torchvision.utils.make_grid(images[:64], padding=0))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'pullover, pullover, sneaker, sneaker, trouser, shirt, sandal, sneaker, dress, sandal, dress, dress, top, bag, top, pullover, pullover, sandal, trouser, sneaker, pullover, shirt, top, pullover, coat, coat, top, coat, pullover, boot, trouser, top, top, boot, dress, top, shirt, dress, sneaker, boot, sneaker, trouser, sneaker, coat, shirt, pullover, trouser, dress, sandal, sneaker, top, coat, trouser, coat, trouser, boot, bag, top, top, dress, sandal, shirt, shirt, sneaker, trouser, dress, trouser, shirt, sandal, top, bag, pullover, sneaker, shirt, dress, boot, trouser, dress, sandal, bag, sandal, boot, dress, boot, pullover, sandal, shirt, shirt, shirt, boot, trouser, dress, pullover, boot, boot, dress, dress, bag, coat, sandal, pullover, sneaker, shirt, shirt, trouser, bag, pullover, dress, dress, trouser, coat, bag, trouser, sneaker, sneaker, boot, sneaker, dress, trouser, sneaker, boot, shirt, trouser, shirt, dress, top, dress, top, top, top, shirt, sandal, sneaker, top, sandal, top, top, coat, boot, shirt, coat, bag, dress, bag, boot, sandal, bag, top, coat, coat, dress, bag, bag, top, boot, sandal, sneaker, dress, sandal, trouser, sandal, sandal, trouser, pullover, boot, dress, pullover, dress, trouser, coat, pullover, sandal, top, bag, pullover, sandal, top, sandal, boot, coat, dress, bag, bag, shirt, pullover, dress, top, trouser, coat, dress, bag, bag, bag, top, sneaker, bag, dress, pullover, coat, sneaker, bag, trouser, shirt, pullover, shirt, pullover, trouser, sneaker, dress, shirt, sandal, top, boot, trouser, shirt, boot, coat, trouser, shirt, pullover, sneaker, top, coat, shirt, bag, coat, sneaker, coat, bag, trouser, dress, shirt, sneaker, shirt, sandal, trouser, sneaker, dress, sandal, sneaker, top, dress, trouser, sandal, shirt, coat, top, pullover, trouser, bag, shirt, pullover, top, boot, boot, trouser'" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "', '.join(classes[c] for c in labels)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## [프로젝트 1] Fashion MNIST 학습하기" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "class CNN(nn.Module):\n", - " def __init__(self):\n", - " super(CNN, self).__init__()\n", - " self.conv1 = nn.Conv2d(1 , 64 , 3, padding = 1)\n", - " self.conv2 = nn.Conv2d(64 , 64 , 3, padding = 1)\n", - " self.conv3 = nn.Conv2d(64 , 64 , 3, padding = 1)\n", - " self.conv4 = nn.Conv2d(64 , 128 , 3, padding = 1)\n", - " self.conv5 = nn.Conv2d(128, 128, 3, padding = 1)\n", - " self.conv6 = nn.Conv2d(128, 128, 3, padding = 1)\n", - " self.fc1 = nn.Linear(128 * 7 * 7, 512)\n", - " self.fc2 = nn.Linear(512, 512)\n", - " self.fc3 = nn.Linear(512, 512)\n", - " self.fc4 = nn.Linear(512, 10)\n", - " self.bn1 = nn.BatchNorm2d(64)\n", - " self.bn2 = nn.BatchNorm2d(64)\n", - " self.bn3 = nn.BatchNorm2d(64)\n", - " self.bn4 = nn.BatchNorm2d(128)\n", - " self.bn5 = nn.BatchNorm2d(128)\n", - " self.bn6 = nn.BatchNorm2d(128)\n", - " self.bn7 = nn.BatchNorm1d(512)\n", - " self.bn8 = nn.BatchNorm1d(512)\n", - " self.bn9 = nn.BatchNorm1d(512)\n", - " \n", - " def forward(self, x):\n", - " x = F.dropout(F.relu(self.bn1(self.conv1(x))), 0.7)\n", - " x = F.dropout(F.relu(self.bn2(self.conv2(x))), 0.7)\n", - " x = F.dropout(F.relu(self.bn3(self.conv3(x))), 0.7)\n", - " x = F.max_pool2d(x, (2, 2))\n", - " x = F.dropout(F.relu(self.bn4(self.conv4(x))), 0.5)\n", - " x = F.dropout(F.relu(self.bn5(self.conv5(x))), 0.5)\n", - " x = F.dropout(F.relu(self.bn6(self.conv6(x))), 0.5)\n", - " x = F.max_pool2d(x, (2, 2))\n", - " x = x.view(-1, 128 * 7 * 7)\n", - " x = F.dropout(F.relu(self.bn7(self.fc1(x))), 0.3)\n", - " x = F.dropout(F.relu(self.bn8(self.fc2(x))), 0.3)\n", - " x = F.dropout(F.relu(self.bn9(self.fc3(x))), 0.3)\n", - " x = self.fc4(x)\n", - " \n", - " return x" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "cnn = CNN().cuda() if cuda else CNN()\n", - "criterion = nn.CrossEntropyLoss()\n", - "optimizer = optim.Adam(cnn.parameters())\n", - "epoch = 40\n", - "print_int = 100" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def validate_model(train = True):\n", - " cnn.eval()\n", - " total_loss = 0.0\n", - " total_prediction = 0\n", - " total_good_prediction = 0\n", - " batch_number = 0\n", - " for X, y in trainloader if train else testloader:\n", - " X, y = Variable(X), Variable(y)\n", - " X, y = (X.cuda(), y.cuda()) if cuda else (X, y)\n", - "\n", - " y_pred = cnn(X)\n", - " total_loss += criterion(y_pred, y).data[0]\n", - " total_prediction += y_pred.size()[0]\n", - " total_good_prediction += (y_pred.max(dim = 1)[1].data.cpu() == y.data.cpu()).sum()\n", - " batch_number += 1\n", - " \n", - " return total_loss / batch_number, 100 * total_good_prediction / total_prediction " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.5/dist-packages/ipykernel_launcher.py:12: UserWarning: invalid index of a 0-dim tensor. This will be an error in PyTorch 0.5. Use tensor.item() to convert a 0-dim tensor to a Python number\n", - " if sys.path[0] == '':\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "running_loss: 2.3096609115600586 train_loss: 2.3027710914611816 valid_loss: 2.3027379512786865 valid_acc: 10\n", - "running_loss: 0.6036235809326171 train_loss: 0.45867541432380676 valid_loss: 0.4806478023529053 valid_acc: 81\n", - "running_loss: 0.41543949127197266 train_loss: 0.3720729649066925 valid_loss: 0.40128812193870544 valid_acc: 85\n", - "running_loss: 0.34497180581092834 train_loss: 0.3654119074344635 valid_loss: 0.40196844935417175 valid_acc: 85\n", - "running_loss: 0.34459724426269533 train_loss: 0.36590418219566345 valid_loss: 0.41220685839653015 valid_acc: 85\n", - "running_loss: 0.3207188415527344 train_loss: 0.3225734829902649 valid_loss: 0.3546592891216278 valid_acc: 87\n", - "running_loss: 0.28065937757492065 train_loss: 0.33713236451148987 valid_loss: 0.36395105719566345 valid_acc: 86\n" - ] - } - ], - "source": [ - "for i in range(epoch):\n", - " running_loss = 0\n", - " for j, (X_train, y_train) in enumerate(trainloader):\n", - " cnn.train()\n", - " X_train, y_train = Variable(X_train), Variable(y_train)\n", - " X_train, y_train = (X_train.cuda(), y_train.cuda()) if cuda else (X_train, y_train)\n", - " \n", - " optimizer.zero_grad()\n", - " y_pred = cnn(X_train)\n", - " loss = criterion(y_pred, y_train)\n", - " loss.backward()\n", - " optimizer.step()\n", - " \n", - " running_loss += loss\n", - " if j % print_int == 0:\n", - " train_loss, train_acc = validate_model(True)\n", - " val_loss, val_acc = validate_model(False)\n", - " print(\n", - " \"running_loss:\", running_loss.item() / (print_int if j != 0 else 1),\n", - " \"train_loss:\", train_loss.item(),\n", - " \"valid_loss:\", val_loss.item(), \"valid_acc:\", val_acc.item()\n", - " )\n", - " running_loss = 0" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.5.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/04-Neural-Network-For-Fashion/README.md b/04-Neural-Network-For-Fashion/README.md new file mode 100644 index 0000000..b5ad079 --- /dev/null +++ b/04-Neural-Network-For-Fashion/README.md @@ -0,0 +1,9 @@ +# 딥러닝으로 패션 아이템 구분하기 + +Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다. + + * [개념] Fashion MNIST 데이터셋 설명 + * [프로젝트 1] [Fashion MNIST 학습하기](04-Neural-Network-For-Fashion/4-fasion-mnist.ipynb) + * [팁] 성능 측정법 알아보기 (Train/Validation/Test) + * [프로젝트 2] Dropout + * 더 보기 diff --git a/05-CNN-For-Image-Classification/01-cnn.ipynb b/05-CNN-For-Image-Classification/01-cnn.ipynb new file mode 100644 index 0000000..5aaf9e2 --- /dev/null +++ b/05-CNN-For-Image-Classification/01-cnn.ipynb @@ -0,0 +1,400 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4. 딥러닝으로 패션 아이템 구분하기\n", + "Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다.\n", + "\n", + "본 튜토리얼은 PyTorch의 공식 튜토리얼 (https://github.com/pytorch/examples/blob/master/mnist/main.py)을 참고하여 만들어졌습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import torchvision\n", + "import torch.nn.functional as F\n", + "from torch import nn, optim\n", + "from torch.autograd import Variable\n", + "from torchvision import transforms, datasets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "use_cuda = torch.cuda.is_available()\n", + "device = torch.device(\"cuda\" if use_cuda else \"cpu\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "batch_size = 64" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "transform = transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.1307,), (0.3081,))\n", + "])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 데이터셋 불러오기" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "trainset = datasets.FashionMNIST(\n", + " root = './.data/', \n", + " train = True,\n", + " download = True,\n", + " transform = transform\n", + ")\n", + "testset = datasets.FashionMNIST(\n", + " root = './.data/', \n", + " train = False,\n", + " download = True,\n", + " transform = transform\n", + ")\n", + "\n", + "train_loader = torch.utils.data.DataLoader(\n", + " dataset = trainset,\n", + " batch_size = batch_size,\n", + " shuffle = True,\n", + ")\n", + "test_loader = torch.utils.data.DataLoader(\n", + " dataset = testset,\n", + " batch_size = batch_size,\n", + " shuffle = True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 뉴럴넷으로 Fashion MNIST 학습하기" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "class Net(nn.Module):\n", + " def __init__(self):\n", + " super(Net, self).__init__()\n", + " self.conv1 = nn.Conv2d(1, 10, kernel_size=5)\n", + " self.conv2 = nn.Conv2d(10, 20, kernel_size=5)\n", + " self.conv2_drop = nn.Dropout2d()\n", + " self.fc1 = nn.Linear(320, 50)\n", + " self.fc2 = nn.Linear(50, 10)\n", + "\n", + " def forward(self, x):\n", + " x = F.relu(F.max_pool2d(self.conv1(x), 2))\n", + " x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))\n", + " x = x.view(-1, 320)\n", + " x = F.relu(self.fc1(x))\n", + " x = F.dropout(x, training=self.training)\n", + " x = self.fc2(x)\n", + " return F.log_softmax(x, dim=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 하이퍼파라미터 \n", + "\n", + "`to()` 함수는 모델의 파라미터들을 지정한 곳으로 보내는 역할을 합니다. 일반적으로 CPU 1개만 사용할 경우 필요는 없지만, GPU를 사용하고자 하는 경우 `to(\"cuda\")`로 지정하여 GPU로 보내야 합니다. 지정하지 않을 경우 계속 CPU에 남아 있게 되며 빠른 훈련의 이점을 누리실 수 없습니다.\n", + "\n", + "최적화 알고리즘으로 파이토치에 내장되어 있는 `optim.SGD`를 사용하겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "model = Net().to(device)\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)\n", + "epochs = 10\n", + "log_interval = 100" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 훈련하기" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def train(model, device, train_loader, optimizer, epoch):\n", + " model.train()\n", + " for batch_idx, (data, target) in enumerate(train_loader):\n", + " data, target = data.to(device), target.to(device)\n", + " optimizer.zero_grad()\n", + " output = model(data)\n", + " loss = F.cross_entropy(output, target)\n", + " loss.backward()\n", + " optimizer.step()\n", + " if batch_idx % log_interval == 0:\n", + " print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n", + " epoch, batch_idx * len(data), len(train_loader.dataset),\n", + " 100. * batch_idx / len(train_loader), loss.item()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 테스트하기\n", + "\n", + "아무리 훈련이 잘 되었다고 해도 실제 데이터를 만났을때 성능이 낮다면 쓸모 없는 모델일 것입니다. 우리가 진정 원하는 것은 훈련 데이터에 최적화한 모델이 아니라 모든 데이터에서 높은 성능을 보이는 모델이기 때문입니다. 세상에 존재하는 모든 데이터에 최적화 하는 것을 \"일반화\"라고 부르고 모델이 얼마나 실제 데이터에 적응하는지를 수치로 나타낸 것을 \"일반화 오류\"(Generalization Error) 라고 합니다. \n", + "\n", + "우리가 만든 모델이 얼마나 일반화를 잘 하는지 알아보기 위해, 그리고 언제 훈련을 멈추어야 할지 알기 위해 매 이포크가 끝날때 마다 테스트셋으로 모델의 성능을 측정해보겠습니다." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def test(model, device, test_loader):\n", + " model.eval()\n", + " test_loss = 0\n", + " correct = 0\n", + " with torch.no_grad():\n", + " for data, target in test_loader:\n", + " data, target = data.to(device), target.to(device)\n", + " output = model(data)\n", + " test_loss += F.cross_entropy(output, target, size_average=False).item() # sum up batch loss\n", + " pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability\n", + " correct += pred.eq(target.view_as(pred)).sum().item()\n", + "\n", + " test_loss /= len(test_loader.dataset)\n", + " print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", + " test_loss, correct, len(test_loader.dataset),\n", + " 100. * correct / len(test_loader.dataset)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 코드 돌려보기\n", + "\n", + "자, 이제 모든 준비가 끝났습니다. 코드를 돌려서 실제로 훈련이 되는지 확인해봅시다!" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Epoch: 1 [0/60000 (0%)]\tLoss: 0.395137\n", + "Train Epoch: 1 [6400/60000 (11%)]\tLoss: 0.659705\n", + "Train Epoch: 1 [12800/60000 (21%)]\tLoss: 0.628428\n", + "Train Epoch: 1 [19200/60000 (32%)]\tLoss: 0.599772\n", + "Train Epoch: 1 [25600/60000 (43%)]\tLoss: 0.598361\n", + "Train Epoch: 1 [32000/60000 (53%)]\tLoss: 0.344298\n", + "Train Epoch: 1 [38400/60000 (64%)]\tLoss: 0.654967\n", + "Train Epoch: 1 [44800/60000 (75%)]\tLoss: 0.467520\n", + "Train Epoch: 1 [51200/60000 (85%)]\tLoss: 0.585845\n", + "Train Epoch: 1 [57600/60000 (96%)]\tLoss: 0.394873\n", + "\n", + "Test set: Average loss: 0.4110, Accuracy: 8512/10000 (85%)\n", + "\n", + "Train Epoch: 2 [0/60000 (0%)]\tLoss: 0.439056\n", + "Train Epoch: 2 [6400/60000 (11%)]\tLoss: 0.842455\n", + "Train Epoch: 2 [12800/60000 (21%)]\tLoss: 0.458263\n", + "Train Epoch: 2 [19200/60000 (32%)]\tLoss: 0.312101\n", + "Train Epoch: 2 [25600/60000 (43%)]\tLoss: 0.517731\n", + "Train Epoch: 2 [32000/60000 (53%)]\tLoss: 0.641963\n", + "Train Epoch: 2 [38400/60000 (64%)]\tLoss: 0.533004\n", + "Train Epoch: 2 [44800/60000 (75%)]\tLoss: 0.524670\n", + "Train Epoch: 2 [51200/60000 (85%)]\tLoss: 0.717691\n", + "Train Epoch: 2 [57600/60000 (96%)]\tLoss: 0.521111\n", + "\n", + "Test set: Average loss: 0.4040, Accuracy: 8548/10000 (85%)\n", + "\n", + "Train Epoch: 3 [0/60000 (0%)]\tLoss: 0.481447\n", + "Train Epoch: 3 [6400/60000 (11%)]\tLoss: 0.567634\n", + "Train Epoch: 3 [12800/60000 (21%)]\tLoss: 0.617210\n", + "Train Epoch: 3 [19200/60000 (32%)]\tLoss: 0.579217\n", + "Train Epoch: 3 [25600/60000 (43%)]\tLoss: 0.519561\n", + "Train Epoch: 3 [32000/60000 (53%)]\tLoss: 0.589345\n", + "Train Epoch: 3 [38400/60000 (64%)]\tLoss: 0.486435\n", + "Train Epoch: 3 [44800/60000 (75%)]\tLoss: 0.413084\n", + "Train Epoch: 3 [51200/60000 (85%)]\tLoss: 0.359715\n", + "Train Epoch: 3 [57600/60000 (96%)]\tLoss: 0.560672\n", + "\n", + "Test set: Average loss: 0.3950, Accuracy: 8588/10000 (86%)\n", + "\n", + "Train Epoch: 4 [0/60000 (0%)]\tLoss: 0.564569\n", + "Train Epoch: 4 [6400/60000 (11%)]\tLoss: 0.646862\n", + "Train Epoch: 4 [12800/60000 (21%)]\tLoss: 0.433267\n", + "Train Epoch: 4 [19200/60000 (32%)]\tLoss: 0.450921\n", + "Train Epoch: 4 [25600/60000 (43%)]\tLoss: 0.360204\n", + "Train Epoch: 4 [32000/60000 (53%)]\tLoss: 0.480422\n", + "Train Epoch: 4 [38400/60000 (64%)]\tLoss: 0.462870\n", + "Train Epoch: 4 [44800/60000 (75%)]\tLoss: 0.533468\n", + "Train Epoch: 4 [51200/60000 (85%)]\tLoss: 0.533091\n", + "Train Epoch: 4 [57600/60000 (96%)]\tLoss: 0.360096\n", + "\n", + "Test set: Average loss: 0.3872, Accuracy: 8619/10000 (86%)\n", + "\n", + "Train Epoch: 5 [0/60000 (0%)]\tLoss: 0.464424\n", + "Train Epoch: 5 [6400/60000 (11%)]\tLoss: 0.423988\n", + "Train Epoch: 5 [12800/60000 (21%)]\tLoss: 0.560726\n", + "Train Epoch: 5 [19200/60000 (32%)]\tLoss: 0.553083\n", + "Train Epoch: 5 [25600/60000 (43%)]\tLoss: 0.322233\n", + "Train Epoch: 5 [32000/60000 (53%)]\tLoss: 0.582334\n", + "Train Epoch: 5 [38400/60000 (64%)]\tLoss: 0.605551\n", + "Train Epoch: 5 [44800/60000 (75%)]\tLoss: 0.395979\n", + "Train Epoch: 5 [51200/60000 (85%)]\tLoss: 0.445228\n", + "Train Epoch: 5 [57600/60000 (96%)]\tLoss: 0.544800\n", + "\n", + "Test set: Average loss: 0.3847, Accuracy: 8599/10000 (86%)\n", + "\n", + "Train Epoch: 6 [0/60000 (0%)]\tLoss: 0.401315\n", + "Train Epoch: 6 [6400/60000 (11%)]\tLoss: 0.506271\n", + "Train Epoch: 6 [12800/60000 (21%)]\tLoss: 0.493354\n", + "Train Epoch: 6 [19200/60000 (32%)]\tLoss: 0.416464\n", + "Train Epoch: 6 [25600/60000 (43%)]\tLoss: 0.602188\n", + "Train Epoch: 6 [32000/60000 (53%)]\tLoss: 0.302987\n", + "Train Epoch: 6 [38400/60000 (64%)]\tLoss: 0.623980\n", + "Train Epoch: 6 [44800/60000 (75%)]\tLoss: 0.525368\n", + "Train Epoch: 6 [51200/60000 (85%)]\tLoss: 0.448616\n", + "Train Epoch: 6 [57600/60000 (96%)]\tLoss: 0.500235\n", + "\n", + "Test set: Average loss: 0.3730, Accuracy: 8647/10000 (86%)\n", + "\n", + "Train Epoch: 7 [0/60000 (0%)]\tLoss: 0.341961\n", + "Train Epoch: 7 [6400/60000 (11%)]\tLoss: 0.600264\n", + "Train Epoch: 7 [12800/60000 (21%)]\tLoss: 0.459716\n", + "Train Epoch: 7 [19200/60000 (32%)]\tLoss: 0.555852\n", + "Train Epoch: 7 [25600/60000 (43%)]\tLoss: 0.544332\n", + "Train Epoch: 7 [32000/60000 (53%)]\tLoss: 0.618401\n", + "Train Epoch: 7 [38400/60000 (64%)]\tLoss: 0.504729\n", + "Train Epoch: 7 [44800/60000 (75%)]\tLoss: 0.506612\n", + "Train Epoch: 7 [51200/60000 (85%)]\tLoss: 0.384831\n", + "Train Epoch: 7 [57600/60000 (96%)]\tLoss: 0.312490\n", + "\n", + "Test set: Average loss: 0.3730, Accuracy: 8658/10000 (87%)\n", + "\n", + "Train Epoch: 8 [0/60000 (0%)]\tLoss: 0.545678\n", + "Train Epoch: 8 [6400/60000 (11%)]\tLoss: 0.416011\n", + "Train Epoch: 8 [12800/60000 (21%)]\tLoss: 0.508845\n", + "Train Epoch: 8 [19200/60000 (32%)]\tLoss: 0.462218\n", + "Train Epoch: 8 [25600/60000 (43%)]\tLoss: 0.311496\n", + "Train Epoch: 8 [32000/60000 (53%)]\tLoss: 0.475791\n", + "Train Epoch: 8 [38400/60000 (64%)]\tLoss: 0.347734\n", + "Train Epoch: 8 [44800/60000 (75%)]\tLoss: 0.453348\n", + "Train Epoch: 8 [51200/60000 (85%)]\tLoss: 0.467951\n", + "Train Epoch: 8 [57600/60000 (96%)]\tLoss: 0.337807\n", + "\n", + "Test set: Average loss: 0.3700, Accuracy: 8650/10000 (86%)\n", + "\n", + "Train Epoch: 9 [0/60000 (0%)]\tLoss: 0.293932\n", + "Train Epoch: 9 [6400/60000 (11%)]\tLoss: 0.458819\n", + "Train Epoch: 9 [12800/60000 (21%)]\tLoss: 0.528565\n", + "Train Epoch: 9 [19200/60000 (32%)]\tLoss: 0.458353\n", + "Train Epoch: 9 [25600/60000 (43%)]\tLoss: 0.565586\n", + "Train Epoch: 9 [32000/60000 (53%)]\tLoss: 0.528283\n", + "Train Epoch: 9 [38400/60000 (64%)]\tLoss: 0.516340\n", + "Train Epoch: 9 [44800/60000 (75%)]\tLoss: 0.552283\n", + "Train Epoch: 9 [51200/60000 (85%)]\tLoss: 0.443691\n", + "Train Epoch: 9 [57600/60000 (96%)]\tLoss: 0.460450\n", + "\n", + "Test set: Average loss: 0.3631, Accuracy: 8673/10000 (87%)\n", + "\n", + "Train Epoch: 10 [0/60000 (0%)]\tLoss: 0.565033\n", + "Train Epoch: 10 [6400/60000 (11%)]\tLoss: 0.666153\n", + "Train Epoch: 10 [12800/60000 (21%)]\tLoss: 0.321708\n", + "Train Epoch: 10 [19200/60000 (32%)]\tLoss: 0.434098\n", + "Train Epoch: 10 [25600/60000 (43%)]\tLoss: 0.478469\n", + "Train Epoch: 10 [32000/60000 (53%)]\tLoss: 0.348336\n", + "Train Epoch: 10 [38400/60000 (64%)]\tLoss: 0.476882\n", + "Train Epoch: 10 [44800/60000 (75%)]\tLoss: 0.464265\n", + "Train Epoch: 10 [51200/60000 (85%)]\tLoss: 0.377241\n", + "Train Epoch: 10 [57600/60000 (96%)]\tLoss: 0.461487\n", + "\n", + "Test set: Average loss: 0.3611, Accuracy: 8703/10000 (87%)\n", + "\n" + ] + } + ], + "source": [ + "for epoch in range(1, epochs + 1):\n", + " train(model, device, train_loader, optimizer, epoch)\n", + " test(model, device, test_loader)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/05-CNN-For-Image-Classification/01-cnn.py b/05-CNN-For-Image-Classification/01-cnn.py new file mode 100644 index 0000000..f779dea --- /dev/null +++ b/05-CNN-For-Image-Classification/01-cnn.py @@ -0,0 +1,132 @@ + +# coding: utf-8 + +# # 4. 딥러닝으로 패션 아이템 구분하기 +# Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다. +# 본 튜토리얼은 PyTorch의 공식 튜토리얼 (https://github.com/pytorch/examples/blob/master/mnist/main.py)을 참고하여 만들어졌습니다. + +import torch +import torchvision +import torch.nn.functional as F +from torch import nn, optim +from torch.autograd import Variable +from torchvision import transforms, datasets + + +use_cuda = torch.cuda.is_available() +device = torch.device("cuda" if use_cuda else "cpu") + + +batch_size = 64 + + +transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Normalize((0.1307,), (0.3081,)) +]) + + +# ## 데이터셋 불러오기 + +trainset = datasets.FashionMNIST( + root = './.data/', + train = True, + download = True, + transform = transform +) +testset = datasets.FashionMNIST( + root = './.data/', + train = False, + download = True, + transform = transform +) + +train_loader = torch.utils.data.DataLoader( + dataset = trainset, + batch_size = batch_size, + shuffle = True, +) +test_loader = torch.utils.data.DataLoader( + dataset = testset, + batch_size = batch_size, + shuffle = True, +) + + +# ## 뉴럴넷으로 Fashion MNIST 학습하기 + +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.conv1 = nn.Conv2d(1, 10, kernel_size=5) + self.conv2 = nn.Conv2d(10, 20, kernel_size=5) + self.conv2_drop = nn.Dropout2d() + self.fc1 = nn.Linear(320, 50) + self.fc2 = nn.Linear(50, 10) + + def forward(self, x): + x = F.relu(F.max_pool2d(self.conv1(x), 2)) + x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2)) + x = x.view(-1, 320) + x = F.relu(self.fc1(x)) + x = F.dropout(x, training=self.training) + x = self.fc2(x) + return F.log_softmax(x, dim=1) + + +# ## 하이퍼파라미터 +# `to()` 함수는 모델의 파라미터들을 지정한 곳으로 보내는 역할을 합니다. 일반적으로 CPU 1개만 사용할 경우 필요는 없지만, GPU를 사용하고자 하는 경우 `to("cuda")`로 지정하여 GPU로 보내야 합니다. 지정하지 않을 경우 계속 CPU에 남아 있게 되며 빠른 훈련의 이점을 누리실 수 없습니다. +# 최적화 알고리즘으로 파이토치에 내장되어 있는 `optim.SGD`를 사용하겠습니다. + +model = Net().to(device) +optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5) +epochs = 10 +log_interval = 100 + + +# ## 훈련하기 + +def train(model, device, train_loader, optimizer, epoch): + model.train() + for batch_idx, (data, target) in enumerate(train_loader): + data, target = data.to(device), target.to(device) + optimizer.zero_grad() + output = model(data) + loss = F.cross_entropy(output, target) + loss.backward() + optimizer.step() + if batch_idx % log_interval == 0: + print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( + epoch, batch_idx * len(data), len(train_loader.dataset), + 100. * batch_idx / len(train_loader), loss.item())) + + +# ## 테스트하기 +# 아무리 훈련이 잘 되었다고 해도 실제 데이터를 만났을때 성능이 낮다면 쓸모 없는 모델일 것입니다. 우리가 진정 원하는 것은 훈련 데이터에 최적화한 모델이 아니라 모든 데이터에서 높은 성능을 보이는 모델이기 때문입니다. 세상에 존재하는 모든 데이터에 최적화 하는 것을 "일반화"라고 부르고 모델이 얼마나 실제 데이터에 적응하는지를 수치로 나타낸 것을 "일반화 오류"(Generalization Error) 라고 합니다. +# 우리가 만든 모델이 얼마나 일반화를 잘 하는지 알아보기 위해, 그리고 언제 훈련을 멈추어야 할지 알기 위해 매 이포크가 끝날때 마다 테스트셋으로 모델의 성능을 측정해보겠습니다. + +def test(model, device, test_loader): + model.eval() + test_loss = 0 + correct = 0 + with torch.no_grad(): + for data, target in test_loader: + data, target = data.to(device), target.to(device) + output = model(data) + test_loss += F.cross_entropy(output, target, size_average=False).item() # sum up batch loss + pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability + correct += pred.eq(target.view_as(pred)).sum().item() + + test_loss /= len(test_loader.dataset) + print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( + test_loss, correct, len(test_loader.dataset), + 100. * correct / len(test_loader.dataset))) + + +# ## 코드 돌려보기 +# 자, 이제 모든 준비가 끝났습니다. 코드를 돌려서 실제로 훈련이 되는지 확인해봅시다! + +for epoch in range(1, epochs + 1): + train(model, device, train_loader, optimizer, epoch) + test(model, device, test_loader) + diff --git a/05-CNN-For-Image-Classification/README.md b/05-CNN-For-Image-Classification/README.md new file mode 100644 index 0000000..0555071 --- /dev/null +++ b/05-CNN-For-Image-Classification/README.md @@ -0,0 +1,7 @@ +# 이미지 인식능력이 탁월한 CNN + + * [개념] CNN 기초 + * [프로젝트 1] 모델 구현하기 + * [프로젝트 2] 컬러 데이터셋에 적용하기 + * [팁] 토치비전으로 복잡한 모델 사용하기 + * 더 보기 diff --git a/06-Getting-Deeper/README.md b/06-Getting-Deeper/README.md new file mode 100644 index 0000000..76d34a5 --- /dev/null +++ b/06-Getting-Deeper/README.md @@ -0,0 +1,10 @@ +# 신경망 깊게 쌓아보기 + +CNN의 발전사와 함께 발전된 형태의 모델들을 알아봅니다. + + * [개념] 복잡한 CNN모델들 + * [개념 or 프로젝트] Alexnet + * [개념 or 프로젝트] Residual Networks (ResNet) + * [개념 or 프로젝트] Inception + * [프로젝트] High Level API 사용법 익히기 + * 더 보기 diff --git a/07-Autoencoder/README.md b/07-Autoencoder/README.md new file mode 100644 index 0000000..4238eba --- /dev/null +++ b/07-Autoencoder/README.md @@ -0,0 +1,8 @@ +# 사람의 지도 없이 학습하는 Autoencoder + +레이블이 없는 상태서 특징추출을 하는 오토인코더에 대해 배워봅니다. + + * [개념] 오토인코더 기초 + * [프로젝트 1] 오토인코더로 이미지의 특징을 압축해보기 + * [프로젝트 2] Latent 공간 탐험하기 + * 더 보기 diff --git a/08-Generative-Adversarial-Networks/README.md b/08-Generative-Adversarial-Networks/README.md new file mode 100644 index 0000000..ca562e3 --- /dev/null +++ b/08-Generative-Adversarial-Networks/README.md @@ -0,0 +1,8 @@ +# 경쟁을 통해 성장하는 GAN + +GAN을 이용하여 새로운 패션 아이템을 만들어봅니다. + + * [개념] GAN 기초 + * [프로젝트 1] GAN으로 새로운 패션아이템 생성하기 + * [프로젝트 2] Conditional GAN으로 생성 컨트롤하기 + * 더 보기 diff --git a/09-RNN-For-Sequential-Data/README.md b/09-RNN-For-Sequential-Data/README.md new file mode 100644 index 0000000..effb05b --- /dev/null +++ b/09-RNN-For-Sequential-Data/README.md @@ -0,0 +1,8 @@ +# 순차적인 데이터를 처리하는 RNN + +RNN을 활용하여 영화 리뷰 감정 분석과 기계번역을 해봅니다. + + * [개념] RNN 기초 + * [프로젝트 1] 영화 리뷰 감정 분석 + * [프로젝트 2] Seq2Seq 기계 번역 + * 더 보기 diff --git a/10-DQN-Learns-From-Environment/README.md b/10-DQN-Learns-From-Environment/README.md new file mode 100644 index 0000000..89fb85a --- /dev/null +++ b/10-DQN-Learns-From-Environment/README.md @@ -0,0 +1,8 @@ +# 주어진 환경과 상호작용을 통해 성장하는 DQN + +간단한 게임환경 안에서 스스로 성장하는 DQN 에이전트를 만들어봅니다. + + * [개념] 강화학습과 DQN기초 + * [팁] OpenAI Gym + * [프로젝트 1] 카트폴 게임 마스터하기 + * 더 보기 diff --git a/11-Mini-Self-Driving-Car/README.md b/11-Mini-Self-Driving-Car/README.md new file mode 100644 index 0000000..a222bd7 --- /dev/null +++ b/11-Mini-Self-Driving-Car/README.md @@ -0,0 +1,10 @@ +# 간단한 자율주행차 만들기 + +앞서 배운 CNN, RNN, 그리고 DQN을 활용하여 간단한 자율주행차를 만들어봅니다. + + + * [개념] 자율주행차란? + * [팁] 자율주행 시뮬레이터 소개 + * [팁] 설치와 환경설정 + * [프로젝트 1] 딥러닝으로 자동차 조종하기 + * 더 보기 diff --git a/README.md b/README.md index 5364c53..efed5d0 100644 --- a/README.md +++ b/README.md @@ -7,45 +7,33 @@ * PyTorch 1.0 * Python >= 3.6.1 -## 목차 -1. [딥러닝과 파이토치](01-Deep-Learning-And-PyTorch) +## 목차 - 딥러닝의 기본 지식을 쌓고 파이토치의 장단점에 대해 알아봅니다. +1. [딥러닝과 파이토치](01-Deep-Learning-And-PyTorch) - 딥러닝의 기본 지식을 쌓고 파이토치의 장단점에 대해 알아봅니다. * [개념] 신경망의 원리 * [개념] 딥러닝과 신경망 * [개념] 왜 파이토치인가? - -2. [파이토치 시작하기](02-Getting-Started-With-PyTorch) - - 파이토치 환경설정과 사용법을 익혀봅니다. +2. [파이토치 시작하기](02-Getting-Started-With-PyTorch) - 파이토치 환경설정과 사용법을 익혀봅니다 * [프로젝트 1] 파이토치 설치 & 환경구성 * [프로젝트 2] 파이토치 예제 내려받고 실행해보기 * [프로젝트 3] 토치비전과 토치텍스트로 데이터셋 불러오기 - -3. [파이토치로 구현하는 신경망](03-Coding-Neural-Networks-In-PyTorch) - - 파이토치를 이용하여 가장 기본적인 신경망을 만들어봅니다. +3. [파이토치로 구현하는 신경망](03-Coding-Neural-Networks-In-PyTorch) - 파이토치를 이용하여 가장 기본적인 신경망을 만들어봅니다. * [개념] 텐서와 Autograd * [Hello World] 신경망 모델 구현하기 * [Hello World] 모델 저장, 재사용 - -4. [딥러닝으로 패션 아이템 구분하기](04-Neural-Network-For-Fashion) - - Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다. +4. [딥러닝으로 패션 아이템 구분하기](04-Neural-Network-For-Fashion) - Fashion MNIST 데이터셋과 앞서 배운 인공신경망을 이용하여 패션아이템을 구분해봅니다. * [개념] Fashion MNIST 데이터셋 설명 * [프로젝트 1] [Fashion MNIST 학습하기](04-Neural-Network-For-Fashion/4-fasion-mnist.ipynb) * [팁] 성능 측정법 알아보기 (Train/Validation/Test) * [프로젝트 2] Dropout * 더 보기 - 5. [이미지 인식능력이 탁월한 CNN](05-CNN-For-Image-Classification) * [개념] CNN 기초 * [프로젝트 1] 모델 구현하기 * [프로젝트 2] 컬러 데이터셋에 적용하기 * [팁] 토치비전으로 복잡한 모델 사용하기 * 더 보기 - 6. [신경망 깊게 쌓아보기](06-Getting-Deeper) - CNN의 발전사와 함께 발전된 형태의 모델들을 알아봅니다. * [개념] 복잡한 CNN모델들 * [개념 or 프로젝트] Alexnet @@ -80,6 +68,15 @@ * [프로젝트 1] 딥러닝으로 자동차 조종하기 * 더 보기 +## 참여하기 + +**`중요!`** 모든 코드는 주피터 노트북 파일인 `.ipynb`로 쓰여져야 합니다. + +주피터 노트북으로 작성 후 `compile_notebook.py`를 실행시키면 주석과 코드 모두 파이썬 파일로 예쁘게 변환됩니다. + +일반 파이썬 포멧으로 쓰여진 `.py` 파일은 변환과정에서 삭제될 수 있으니 주의바랍니다. + + ## 참고 [홍콩과기대 김성훈 교수님의 모두를 위한 머신러닝/딥러닝 강의](https://www.youtube.com/watch?v=BS6O0zOGX4E&list=PLlMkM4tgfjnLSOjrEJN31gZATbcj_MpUm) diff --git a/compile_notebooks.py b/compile_notebooks.py new file mode 100644 index 0000000..3ae8fa7 --- /dev/null +++ b/compile_notebooks.py @@ -0,0 +1,41 @@ +""" +(본 스크립트는 튜토리얼과 관계 없는 개발용 코드 입니다.) +Ipynb 파일을 Python파일로 변환합니다. +아래와 같이 nbconvert를 써도 가능하지만, 불필요한 내용(# In[4]:) 들이 포함되어 있습니다. +``` +for i in *.ipynb **/*.ipynb; do + echo "$i" + jupyter nbconvert --to script "$i" "$i" +done +``` +이 스크립트는 불필요한 내용을 골라 삭제하고 +각 폴더 내에 있는 모든 .ipynb파일을 .py파일로 변환합니다. +""" + +import io +import os +import glob +import re +from nbconvert.exporters.script import ScriptExporter + + +def main(): + exporter = ScriptExporter() + cell_pattern = "#\s(In)\[(.*)\]:\n\n\n" # # In [*]: + comment_pattern = "(#(\s*)\n)" + + for nbpath in glob.iglob('**/*.ipynb', recursive=True): + base, ext = os.path.splitext(nbpath) + script, resources = exporter.from_filename(nbpath) + + # remove unecessary patterns + script = re.sub(cell_pattern, "", script) + script = re.sub(comment_pattern, "", script) + pypath = (base + resources.get('output_extension', '.txt')) + print("Saving script %s" % pypath) + with io.open(pypath, 'w', encoding='utf-8') as f: + f.write(script) + + +if __name__ == "__main__": + main()