├── .gitignore ├── LICENSE.md ├── README.md ├── ch01 ├── README.md ├── hungry.py ├── images │ ├── fig 1-1.png │ ├── fig 1-2.png │ ├── fig 1-3.png │ ├── fig 1-4.png │ └── fig 1-5.png ├── img_show.py ├── man.py ├── simple_graph.py ├── sin_cos_graph.py └── sin_graph.py ├── ch02 ├── README.md ├── and_gate.py ├── nand_gate.py ├── or_gate.py └── xor_gate.py ├── ch03 ├── README.md ├── mnist_show.py ├── neuralnet_mnist.py ├── neuralnet_mnist_batch.py ├── relu.py ├── sample_weight.pkl ├── sig_step_compare.py ├── sigmoid.py └── step_function.py ├── ch04 ├── README.md ├── gradient_1d.py ├── gradient_2d.py ├── gradient_method.py ├── gradient_simplenet.py ├── train_neuralnet.py ├── train_neuralnet_2.py └── two_layer_net.py ├── ch05 ├── README.md ├── buy_apple.py ├── buy_apple_orange.py ├── gradient_check.py ├── layer_naive.py ├── train_neuralnet.py └── two_layer_net.py ├── ch06 ├── README.md ├── batch_norm_gradient_check.py ├── batch_norm_test.py ├── batch_norm_test_multi.py ├── hyperparameter_optimization.py ├── optimizer_compare_mnist.py ├── optimizer_compare_naive.py ├── overfit.py ├── overfit_dropout.py ├── overfit_weight_decay.py ├── show_optimizer_adagrad.py ├── show_optimizer_adam.py ├── show_optimizer_momentum.py ├── show_optimizer_sgd.py ├── weight_init_activation_histogram.py └── weight_init_compare.py ├── ch07 ├── README.md ├── apply_filter.py ├── gradient_check.py ├── params.pkl ├── simple_convnet.py ├── train_convnet.py └── visualize_filter.py ├── ch08 ├── README.md ├── awesome_net.py ├── deep_convnet.py ├── deep_convnet_params.pkl ├── half_float_network.py ├── misclassified_mnist.py └── train_deepnet.py ├── common ├── __init__.py ├── functions.py ├── gradient.py ├── layers.py ├── multi_layer_net.py ├── multi_layer_net_extend.py ├── optimizer.py ├── trainer.py └── util.py ├── cover.jpeg ├── cover_image.jpg ├── dataset ├── __init__.py ├── cactus.png ├── cactus_gray.png ├── mnist.py ├── t10k-images-idx3-ubyte.gz ├── t10k-labels-idx1-ubyte.gz ├── train-images-idx3-ubyte.gz └── train-labels-idx1-ubyte.gz ├── equations_and_figures.zip ├── map.png └── remastered.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | *.gz 4 | *.pyc 5 | __pycache__/ 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Koki Saitoh 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 | # 『밑바닥부터 시작하는 딥러닝 1(리마스터판)』 2 | 3 | 4 | 5 | [미리보기] | [알려진 오류(정오표)] | [본문 그림과 수식 이미지 모음] 6 | 7 | :red_circle: **[공지]** 2025년 1월에 '리마스터판'이 출간되었습니다. 리마스터판의 예제 코드는 초판의 예제 코드와 호환되므로, 초판 독자 분들도 이 저장소의 코드를 그대로 활용하시면 됩니다. 또한, 본질이 달라진 게 아니므로 다시 구매하실 필요 없습니다. 달라진 점은 제작 뒷이야기에 정리했습니다. 8 | 9 | :red_circle: **[공지]** 종종 실습용 손글씨 데이터셋 다운로드 사이트( http://yann.lecun.com/exdb/mnist/ )가 연결되지 않습니다. 10 | 그래서 예제 수행에 필요한 데이터셋 파일을 /dataset/ 디렉터리에 올려뒀습니다. 11 | 혹 사이트가 다운되어 데이터를 받을 수 없다면 아래 파일 4개를 각자의 <예제 소스 홈>/dataset/ 디렉터리 밑에 복사해두면 됩니다. 12 | 13 | * [t10k-images-idx3-ubyte.gz](https://github.com/WegraLee/deep-learning-from-scratch/raw/master/dataset/t10k-images-idx3-ubyte.gz) 14 | * [t10k-labels-idx1-ubyte.gz](https://github.com/WegraLee/deep-learning-from-scratch/raw/master/dataset/t10k-labels-idx1-ubyte.gz) 15 | * [train-images-idx3-ubyte.gz](https://github.com/WegraLee/deep-learning-from-scratch/raw/master/dataset/train-images-idx3-ubyte.gz) 16 | * [train-labels-idx1-ubyte.gz](https://github.com/WegraLee/deep-learning-from-scratch/raw/master/dataset/train-labels-idx1-ubyte.gz) 17 | 18 | --- 19 | 20 | ## 파일 구성 21 | |폴더 이름 |설명                         | 22 | |:-- |:-- | 23 | |ch01       |1장에서 사용하는 소스 코드 | 24 | |ch02 |2장에서 사용하는 소스 코드 | 25 | |... |... | 26 | |ch08 |8장에서 사용하는 소스 코드 | 27 | |common     |공통으로 사용하는 소스 코드  | 28 | |dataset   |데이터셋용 소스 코드 | 29 | 30 | ## 주피터 노트북 31 | 이 책의 코드는 주피터 노트북으로도 제공됩니다. 다음 링크를 클릭하면 구글 콜랩에서 노트북을 실행할 수 있습니다. 32 | | 장 | 구글 콜랩에서 열기 | 33 | | :--- | :--- | 34 | | 1장 헬로 파이썬 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1p_pBspaD0U2lDddKQj3m0HS0gIcJ4GNH?usp=drive_link) | 35 | | 2장 퍼셉트론 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1AUKNoYENHXAsnA6lQikOAm_Hx6Tc2zTk?usp=drive_link) | 36 | | 3장 신경망 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1k-R8IvCp2rdMdYMuZ84HcoM0lCzxCfPP?usp=drive_link) | 37 | | 4장 신경망 학습 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1yftb83a6nGRuxNUOwnBjPMAV1h7BM8w8?usp=drive_link) | 38 | | 5장 오차역전파법 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1ocP0omkB2QY9yg1KOqgFtq9R8ApY-7RV?usp=drive_link) | 39 | | 6장 학습 관련 기술들 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1cj88ux7BKceGK3vt-VB5dHu8oBPq2FDQ?usp=drive_link) | 40 | | 7장 합성곱 신경망(CNN) | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1SQyMbVbqNvmODy4_CIFlcFfgUH9R2oIt?usp=drive_link) | 41 | | 8장 딥러닝 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1GXNAB0hnlbBGtsmS0BnSmTavQLAYyz7d?usp=drive_link) | 42 | 43 | 44 | ## 요구사항 45 | 소스 코드를 실행하려면 아래의 소프트웨어가 설치되어 있어야 합니다. 46 | 47 | * 파이썬 3.x 48 | * NumPy 49 | * Matplotlib 50 | 51 | 52 | ## 실행 방법 (리마스터판) 53 | 어디서든 실행할 수 있습니다. 54 | ``` 55 | $ python deep-learning-from-scratch-master/ch01/img_show.py 56 | 57 | $ cd deep-learning-from-scratch-master 58 | $ python ch01/img_show.py 59 | 60 | $ cd ch01 61 | $ python img_show.py 62 | ``` 63 | 64 | ## 실행 방법 (초판) 65 | 각 장의 디렉터리로 이동 후 실행해야 합니다(**다른 디렉터리에서는 제대로 실행되지 않을 수 있습니다!**). 66 | ``` 67 | $ cd ch01 68 | $ python man.py 69 | 70 | $ cd ../ch05 71 | $ python train_nueralnet.py 72 | ``` 73 | 74 | --- 75 | 76 | ## 동영상 강의 77 | 수원대학교 한경훈 교수님께서 『밑바닥부터 시작하는 딥러닝』 1, 2편을 교재로 진행하신 강의를 공개해주셨습니다. 책만으로 부족하셨던 분들께 많은 도움이 되길 바랍니다. 78 | 79 | 딥러닝 I - [강의 홈페이지] 80 | 81 | [![시리즈 1](https://img.youtube.com/vi/8Gpa_pdHrPE/0.jpg)](https://www.youtube.com/watch?v=8Gpa_pdHrPE&list=PLBiQZMT3oSxW1RS1hn2jWBgswh0nlcgQZ) 82 | 83 | 딥러닝 II - [강의 홈페이지] 84 | 85 | [![시리즈 1](https://img.youtube.com/vi/5fwD1p9ymx8/0.jpg)](https://www.youtube.com/watch?v=5fwD1p9ymx8&list=PLBiQZMT3oSxXNGcmAwI7vzh2LzwcwJpxU) 86 | 87 | 딥러닝 III - [강의 홈페이지] 88 | 89 | [![시리즈 1](https://img.youtube.com/vi/kIobK76on3s/0.jpg)](https://www.youtube.com/watch?v=kIobK76on3s&list=PLBiQZMT3oSxV3RxoFgNcUNV4R7AlvUMDx) 90 | 91 | --- 92 | 93 | ## 팬픽 - 바닷속 딥러닝 어드벤처 (5부작) 94 | 95 | 96 | 97 | "<밑바닥부터 시작하는 딥러닝>의 주인공 생선들은 딥러닝 기술로 바닷속 생태계를 어떻게 혁신하고 있을까요? 어공지능의 첨단을 이끌어가는 밑시딥 생선들과 신나는 모험을 떠나보세요." 98 | 99 | 바닷속 세계를 배경으로, 해양 생물들이 자신의 특성과 필요에 맞는 딥러닝 기술을 개발하여 문제를 해결해 나가는 모험을 그린 연작 소설입니다. 시리즈를 읽으신 분은 더 많은 재미를 느끼실 수 있도록 딥러닝 요소들을 곳곳에 삽입하였습니다. 100 | 101 | 각 편의 주인공과 주제는 다음과 같습니다. 102 | 103 | 1. **시야를 찾아서**: 쏨뱅이(쏨)가 **이미지 처리 기술**을 개발하여 주변 환경을 선명하게 파악 104 | 1. **상어공주**: 괭이상어 공주(꽹)가 **자연어 처리** 기술로 돌고래 왕자와의 사랑을 쟁취 105 | 1. **DeZero의 창조자**: 나뭇잎해룡(잎룡)이 **딥러닝 프레임워크**를 만들어 기술 보급과 협업 촉진 106 | 1. **제발, 가즈아!**: 가자미(가즈아)가 **심층 강화 학습**으로 먹이가 풍부한 새로운 바다 개척 107 | 1. **피쉬카소와 천재의 초상**: 유령실고기(피쉬카소)가 **이미지 생성 모델**로 바닷속 예술계 혁신 108 | 109 | 소설 보러 가기 110 | 111 | --- 112 | 113 | ## 라이선스 114 | 115 | 이 저장소의 소스 코드는 [MIT 라이선스](http://www.opensource.org/licenses/MIT)를 따릅니다. 116 | 상업적 목적으로도 자유롭게 이용하실 수 있습니다. 117 | -------------------------------------------------------------------------------- /ch01/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | hungry.py | 단순한 문자열("I'm hungry!")을 출력합니다.| 1.4.1 파일로 저장하기 | 34 | 5 | | img_show.py | 이미지를 화면에 보여줍니다. | 1.6.3 이미지 표시하기 | 44 | 6 | | man.py | 파이썬 클래스 정의 예제입니다. | 1.4.2 클래스 | 35 | 7 | | simple_graph.py | 그래프 그리기 예제입니다(sin_graph.py와 같음). | 1.6.1 단순한 그래프 그리기 | 42 | 8 | | sin_cos_graph.py | 사인(sin) 그래프와 코사인(cos) 그래프를 그립니다. | 1.6.2 pyplot의 기능 | 43 | 9 | | sin_graph.py | 사인(sin) 그래프를 그립니다. | 1.6.1 단순한 그래프 그리기 | 42 | 10 | 11 | ## 1장 헬로 파이썬 12 | 파이썬이라는 프로그래밍 언어가 세상에 등장한 지도 이미 20년이 훌쩍 넘었습니다. 그 사이 파이썬은 독자적인 진화를 이루며 많은 개발자를 끌어들였습니다. 그리고 현재는 가장 인기 있고 많은 사람이 애용하는 프로그래밍 언어가 되었습니다. 13 | 14 | 앞으로 파이썬을 사용하여 딥러닝 시스템을 구현할 것입니다. 그에 앞서 이번 장에서는 파이썬에 대해서 간략히 소개하면서 그 사용법을 익혀보겠습니다. 파이썬과 넘파이(_NumPy_) , matplotlib을 잘 아는 분은 이번 장을 건너뛰어도 상관없습니다. 15 | 16 | > **목차** 17 | ``` 18 | 1.1 파이썬이란? 19 | 1.2 파이썬 설치하기 20 | __1.2.1 파이썬 버전 21 | __1.2.2 사용하는 외부 라이브러리 22 | __1.2.3 아나콘다 배포판 23 | 1.3 파이썬 인터프리터 24 | __1.3.1 산술 연산 25 | __1.3.2 자료형 26 | __1.3.3 변수 27 | __1.3.4 리스트 28 | __1.3.5 딕셔너리 29 | __1.3.6 bool 30 | __1.3.7 if 문 31 | __1.3.8 for 문 32 | __1.3.9 함수 33 | 1.4 파이썬 스크립트 파일 34 | __1.4.1 파일로 저장하기 35 | __1.4.2 클래스 36 | 1.5 넘파이 37 | __1.5.1 넘파이 가져오기 38 | __1.5.2 넘파이 배열 생성하기 39 | __1.5.3 넘파이의 산술 연산 40 | __1.5.4 넘파이의 N차원 배열 41 | __1.5.5 브로드캐스트 42 | __1.5.6 원소 접근 43 | 1.6 matplotlib 44 | __1.6.1 단순한 그래프 그리기 45 | __1.6.2 pyplot의 기능 46 | __1.6.3 이미지 표시하기 47 | ``` 48 | 49 | ### 1.1 파이썬이란? 50 | 파이썬은 간단하고 배우기 쉬운 프로그래밍 언어입니다. 오픈 소스라 무료로 자유롭게 이용할 수도 있지요. 영어와 유사한 문법으로 프로그램을 작성할 수 있고 불편한 컴파일 과정도 없어서 편리합니다. 그래서 프로그래밍 입문자에게 최적인 언어입니다. 실제로도 많은 대학교의 컴퓨터 과학 관련 학과에서 처음 가르치는 언어로 파이썬을 채용하는 사례가 아주 많습니다. 51 | 52 | 또, 파이썬 코드는 읽기 쉽고 성능도 뛰어납니다. 데이터가 많거나 빠른 응답이 필요할 때도 파이썬은 제 몫을 톡톡히 해냅니다. 그래서 초보자뿐 아니라 전문가들도 애용하죠. 실제로 구글과 마이크로소프트, 페이스북 등 IT의 첨단에서 겨루는 기업들은 파이썬을 자주 사용하고 있답니다. 53 | 54 | 파이썬은 과학 분야, 특히 기계학습과 데이터 과학 분야에서 널리 쓰입니다. 파이썬 자체의 뛰어난 성능에 넘파이와 [사이파이(_SciPy_)](https://www.scipy.org/) 같은 수치 계산과 통계 처리를 다루는 탁월한 라이브러리가 더해져 데이터 과학 분야에서 확고한 위치를 차지하고 있죠. 나아가 딥러닝 프레임워크 쪽에서도 파이썬을 애용합니다. 예를 들어 [카페(_Caffe_)](http://caffe.berkeleyvision.org/), [텐서플로(_TensorFlow_)](https://www.tensorflow.org/), [체이너(_Chainer_)](http://chainer.org/), [테아노(_Theano_)](http://deeplearning.net/software/theano) 같은 유명 딥러닝 프레임워크들이 파이썬용 API를 제공합니다. 그래서 파이썬을 배우면 딥러닝 프레임워크를 사용할 때도 반드시 도움이 될 것입니다. 55 | 56 | 이처럼 파이썬은 특히 데이터 과학 분야에 아주 적합한 프로그래밍 언어입니다. 그래서 이 책의 목표인 ‘딥러닝을 밑바닥부터 만들기’를 달성하기 위한 언어로 선택된 것이죠. 57 | 58 | ### 1.2 파이썬 설치하기 59 | 그럼 파이썬을 PC에 설치합시다. 이번 절은 설치할 때 주의할 점을 설명합니다. 60 | 61 | #### 1.2.1 파이썬 버전 62 | 현재의 파이썬은 2.x와 3.x라는 두 가지 버전이 공존합니다. 3 버전이 나왔지만 아직 2 버전도 많이 이용되고 있죠. 그래서 파이썬을 처음 배울 때는 어느 버전을 설치할지 신중하게 선택해야 합니다. 이 둘은 100% 호환되는 게 아니니까요(정확히 말하면 ‘하위 호환성’이 없습니다). 즉, 파이썬 3로 짠 프로그램을 파이썬 2에서는 실행하지 못하는 일이 일어납니다. 이 책에서는 파이썬 3를 사용합니다. 만약 파이썬 2만 설치했다면, 파이썬 3도 추가로 설치하시기 바랍니다. 63 | 64 | #### 1.2.2 사용하는 외부 라이브러리 65 | 누차 강조했듯이 이 책의 목표는 딥러닝을 밑바닥부터 구현하는 것입니다. 그래서 외부 라이브러리는 최소한만 사용한다는 것이 기본 방침이지만, 다음의 두 라이브러리는 예외로 하겠습니다. 하나는 넘파이, 다른 하나는 matplotlib입니다. 이들 라이브러리를 사용하는 이유는 효율적으로 딥러닝을 구현하기 위해서입니다. 66 | 67 | 넘파이는 수치 계산용 라이브러리입니다. 넘파이에는 고도의 수학 알고리즘과 배열(행렬)을 조작하기 위한 편리한 메서드가 많이 준비되어 있습니다. 이들 메서드를 이용하면 딥러닝을 훨씬 효율적으로 구현할 수 있습니다. 68 | 69 | matplotlib은 그래프를 그려주는 라이브러리입니다. matplotlib을 이용하면 실험 결과를 시각화하거나 딥러닝 실행 과정의 중간 데이터를 시각적으로, 즉 눈으로 확인할 수 있습니다. 이 책에서는 이러한 라이브러리를 사용하여 딥러닝을 구현합니다. 70 | 71 | > **노트:** 이 책에서는 다음의 프로그래밍 언어와 라이브러리를 사용합니다. 72 | * 파이썬 3 73 | * 넘파이 74 | * matplotlib 75 | 76 | 다음으로 파이썬 설치 방법을 설명합니다. 이미 설치한 분은 건너뛰시면 됩니다. 77 | 78 | #### 1.2.3 아나콘다 배포판 79 | 파이썬을 설치하는 방법은 다양하지만, 이 책에서는 아나콘다Anaconda라는 배포판을 이용하기를 권합니다. 배포판이란 사용자가 설치를 한 번에 수행할 수 있도록 필요한 라이브러리 등을 하나로 정리해둔 것입니다. 그중 아나콘다는 데이터 분석에 중점을 둔 배포판입니다. 방금 설명한 넘파이와 matplotlib을 포함해 데이터 분석에 유용한 라이브러리가 포함되어 있습니다. 80 | 81 | 앞서 말한 것처럼 이 책에서는 파이썬 3를 사용합니다. 그래서 아나콘다 배포판도 3 버전용을 설치합니다. 그럼, 다음 주소에서 자신의 OS에 맞는 배포판을 내려받아 설치하세요. 82 | 83 | > https://www.continuum.io/downloads 84 | 85 | ### 1.3 파이썬 인터프리터 86 | 파이썬을 설치했다면 파이썬 버전을 먼저 확인합니다. 터미널에서 python --version 명령어를 실행해보세요. 이 명령은 설치된 파이썬의 버전을 출력합니다. 87 | 88 | ``` 89 | $ python --version 90 | Python 3.5.2 :: Anaconda 4.2.0 (x86 _64) 91 | ``` 92 | 93 | 이처럼 “Python 3.x.x”라 표시되면 파이썬 3가 제대로 설치된 것입니다(설치한 버전에 따라 숫자는 달라지겠죠?). 이어서 python이라고 입력하여 파이썬 인터프리터를 시작해보세요. 94 | 95 | ``` 96 | $ python 97 | Python 3.5.2 |Anaconda 4.2.0 (x86 _64)| (default, Jul 2 2016, 17:52:12) 98 | [GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwin 99 | Type "help", "copyright", "credits" or "license" for more information. 100 | >>> 101 | ``` 102 | 103 | 파이썬 인터프리터는 ‘대화 모드’라 하여, 개발자와 파이썬이 대화하듯 프로그래밍할 수 있습니다. ‘대화하듯’이라는 것은, 예를 들면 개발자가 “1+2는?”이라고 물으면 파이썬 인터프리터가 곧바로 “3입니다”라고 대답한다는 의미입니다. 그럼 실제로 입력해보겠습니다. 104 | 105 | ```python 106 | >>> 1 + 2 107 | 3 108 | ``` 109 | 110 | 이처럼 파이썬 인터프리터에서는 대화식으로 프로그래밍할 수 있습니다. 이번 장에서는 이 대화 모드를 사용하여 파이썬 프로그래밍을 간단히 실습해보려 합니다. 111 | 112 | #### 1.3.1 산술 연산 113 | 덧셈과 곱셈 등의 산술 연산은 다음과 같이 할 수 있습니다. 114 | 115 | ```python 116 | >>> 1 - 2 117 | -1 118 | >>> 4 * 5 119 | 20 120 | >>> 7 / 5 121 | 1.4 122 | >>> 3 ** 2 123 | 9 124 | ``` 125 | 126 | *은 곱셈, /는 나눗셈, **는 거듭제곱을 의미합니다(3 ** 2는 3의 2제곱). 참고로, 파이썬 2에서는 정수끼리 계산한 결과는 정수입니다. 예를 들어 7 ÷ 5의 결과는 1입니다. 한편, 파이썬 3에서는 정수를 나눈 결과는 실수(부동소수점 수)가 됩니다. 127 | 128 | #### 1.3.2 자료형 129 | 프로그래밍 언어에는 **자료형**(_data type_)이라는 것이 있습니다. 자료형이란 데이터의 성질을 나타내는 것으로, 예를 들어 정수, 실수, 문자열과 같은 형태가 있습니다. 파이썬에는 type() 함수로 특정 데이터의 자료형을 알아볼 수 있습니다. 130 | 131 | ```python 132 | >>> type(10) 133 | 134 | >>> type(2.718) 135 | 136 | >>> type("hello") 137 | 138 | ``` 139 | 140 | 즉, 10은 int(정수), 2.718은 float(실수), “hello”는 str(문자열)형임을 알 수 있습니다. 또한 자료형과 클래스(_class_)라는 말을 같은 의미로 사용하는 경우가 있습니다. 방금 예에서의 는 “10은 int라는 클래스(자료형)다”로 해석하면 됩니다. 141 | 142 | #### 1.3.3 변수 143 | x와 y 등의 알파벳을 사용하여 **변수**(_variable_)를 정의할 수 있습니다. 또한, 변수를 사용하여 계산하거나 변수에 다른 값을 대입할 수도 있습니다. 144 | 145 | ```python 146 | >>> x = 10 # 초기화 147 | >>> print(x) # x의 값 출력 148 | 10 149 | >>> x = 100 # 변수에 값 대입 150 | >>> print(x) 151 | 100 152 | >>> y = 3.14 153 | >>> x * y 154 | 314.0 155 | >>> type(x * y) 156 | 157 | ``` 158 | 159 | 파이썬은 **동적 언어**로 분류되는 프로그래밍 언어입니다. 동적이라 함은 변수의 자료형을 상황에 맞게 자동으로 결정한다는 뜻입니다. 앞의 예에서 x의 자료형이 int (정수)라는 것을 사용자가 명시한 적이 없죠? 하지만 10이라는 정수로 초기화할 때, x의 형태가 int임을 파이썬이 스스로 판단하는 것입니다. 또, 정수와 실수를 곱한 결과는 실수가 되었습니다(자동 형변환). 마지막으로 #은 주석의 시작을 알리는 문자입니다. # 이후의 문자는 모두 무시해버립니다. 160 | 161 | #### 1.3.4 리스트 162 | 여러 데이터를 **리스트**(_list_)로도 정리할 수 있습니다. 163 | 164 | ```python 165 | >>> a = [1, 2, 3, 4, 5] # 리스트 생성 166 | >>> print(a) # 리스트의 내용 출력 167 | [1, 2, 3, 4, 5] 168 | >>> len(a # 리스트의 길이 출력 169 | 5 170 | >>> a[0] # 첫 원소에 접근 171 | 1 172 | >>> a[4] # 다섯 번째 원소에 접근 173 | 5 174 | >>> a[4] = 99 # 값 대입 175 | >>> print(a) 176 | [1, 2, 3, 4, 99] 177 | ``` 178 | 179 | 원소에 접근할 때는 a[0]처럼 합니다. [] 안의 수를 인덱스(색인)라 하며 인덱스는 0부터 시작합니다(인덱스 0이 첫 번째 원소를 가리킵니다). 또 파이썬 리스트에는 **슬라이싱**(_slicing_)이라는 편리한 기법이 준비되어 있습니다. 슬라이싱을 이용하면 범위를 지정해 원하는 부분 리스트를 얻을 수 있습니다. 180 | 181 | ```python 182 | >>> print(a) 183 | [1, 2, 3, 4, 99] 184 | >>> a[0:2] # 인덱스 0부터 2까지 얻기(2번째는 포함하지 않는다!) 185 | [1, 2] 186 | >>> a[1:] # 인덱스 1부터 끝까지 얻기 187 | [2, 3, 4, 99] 188 | >>> a[:3] # 처음부터 인덱스 3까지 얻기(3번째는 포함하지 않는다!) 189 | [1, 2, 3] 190 | >>> a[:-1] # 처음부터 마지막 원소의 1개 앞까지 얻기 191 | [1, 2, 3, 4] 192 | >>> a[:-2] # 처음부터 마지막 원소의 2개 앞까지 얻기 193 | [1, 2, 3] 194 | ``` 195 | 196 | 리스트를 슬라이싱하려면 a[0:2]처럼 씁니다. a[0:2]는 인덱스 0부터 1(2보다 하나 앞)까지의 원소를 꺼냅니다. 인덱스 번호 -1은 마지막 원소, -2는 끝에서 한 개 앞의 원소에 해당합니다. 197 | 198 | #### 1.3.5 딕셔너리 199 | 리스트는 인덱스 번호로 0, 1, 2, ... 순으로 값을 저장하는 반면, **딕셔너리**(_dictionary_)는 키(_key_)와 값(_value_)을 한 쌍으로 저장합니다. 즉, 영한사전처럼 단어와 그 의미를 짝지어 저장합니다. 200 | 201 | ```python 202 | >>> me = {'height':180} # 딕셔너리 생성 203 | >>> me['height'] # 원소에 접근 204 | 180 205 | >>> me['weight'] = 70 # 새 원소 추가 206 | >>> print(me) 207 | {'weight': 70, 'height': 180} 208 | ``` 209 | 210 | #### 1.3.6 bool 211 | 파이썬에는 **bool**(_불 혹은 불리언_)이라는 자료형이 있습니다. 이 자료형은 True(참)와 False(거짓)라는 두 값 중 하나를 취합니다. 또 bool에는 and, or, not 연산자를 사용할 수 있습니다(수치용 연산자로는 +, -, *, / 등이 있듯이 자료형에 따라 사용할 수 있는 연산자가 정해져 있습니다). 212 | 213 | ```python 214 | >>> hungry = True # 배가 고프다. 215 | >>> sleepy = False # 졸리지 않다. 216 | >>> type(hungry) 217 | 218 | >>> not hungry 219 | False 220 | >>> hungry and sleepy # 배가 고프다 그리고 졸리지 않다. 221 | False 222 | >>> hungry or sleepy # 배가 고프다 또는 졸리지 않다. 223 | True 224 | ``` 225 | 226 | #### 1.3.7 if 문 227 | 조건에 따라서 달리 처리하려면 **if/else 문**을 사용합니다. 228 | 229 | ```python 230 | >>> hungry = True 231 | >>> if hungry: 232 | ... print("I'm hungry") 233 | ... 234 | I'm hungry 235 | >>> hungry = False 236 | >>> if hungry: 237 | ... print("I'm hungry") # 들여쓰기는 공백 문자로 238 | ... else: 239 | ... print("I'm not hungry") 240 | ... print("I'm sleepy") 241 | ... 242 | I'm not hungry 243 | I'm sleepy 244 | ``` 245 | 246 | 파이썬에서는 공백 문자가 중요한 의미를 지닙니다. 이번 if 문에서도 if hungry: 다음 줄은 앞쪽에 4개의 공백 문자가 있습니다. 이 들여쓰기는 지난 조건(if hungry)이 충족될 때 실행되는 코드를 표현합니다. 247 | 248 | > **주의:** 공백 대신 탭(_tab_) 문자를 써도 되지만 파이썬에서는 공백 문자 쪽을 권장합니다. 그리고 한 단계 더 들여 쓸 때마다 공백 4개씩을 더 추가하는 것이 일반적입니다. 249 | 250 | #### 1.3.8 for 문 251 | 반복(루프) 처리에는 **for 문**을 사용합니다. 252 | 253 | ```python 254 | >>> for i in[1, 2, 3]: 255 | ... print(i) 256 | ... 257 | 1 258 | 2 259 | 3 260 | ``` 261 | 262 | 여기에서는 [1, 2, 3]이라는 리스트 안의 원소를 하나씩 출력하는 예를 보여줬습니다. for ... in ... : 구문을 사용하면 리스트 등 데이터 집합의 각 원소에 차례로 접근할 수 있습니다. 263 | 264 | #### 1.3.9 함수 265 | 특정 기능을 수행하는 일련의 명령들을 묶어 하나의 **함수**(_function_)로 정의할 수 있습니다. 266 | 267 | ```python 268 | >>> def hello(): 269 | ... print("Hello World!") 270 | ... 271 | >>> hello() 272 | Hello World! 273 | ``` 274 | 275 | 함수는 인수를 취할 수 있습니다. 또한, + 연산자를 사용하여 문자열을 이어 붙일 수 있습니다. 276 | 277 | ```python 278 | >>> def hello(object): 279 | ... print("Hello " + object + "!") 280 | ... 281 | >>> hello("cat") 282 | Hello cat! 283 | ``` 284 | 285 | 파이썬 인터프리터를 종료하려면 리눅스와 맥에서는 Ctrl + D(Ctrl 키를 누른 상태에서 D 키를 누른다)를 입력합니다. 윈도우에서는 Ctrl + Z를 입력하고 키를 누릅니다. 286 | 287 | ### 1.4 파이썬 스크립트 파일 288 | 지금까지 파이썬 인터프리터를 활용하는 예를 보았습니다. 파이썬 인터프리터는 파이썬 코드를 대화식으로 실행해보며 간단한 실험을 수행하기에 딱 좋습니다. 그러나 긴 작업을 수행해야 한다면, 매번 코드를 입력해야 하는 이 방식은 조금 불편하겠죠. 이럴 때는 파이썬 프로그램을 파일로 저장하고 그 파일을 (함께) 실행하는 방법이 있습니다. 이번 절에서는 그런 파이썬 스크립트 파일의 예를 살펴보겠습니다. 289 | 290 | #### 1.4.1 파일로 저장하기 291 | 텍스트 편집기를 열고 hungry.py라는 파일을 작성합니다. hungry.py는 다음의 한 줄만으로 구성된 파일입니다. 292 | 293 | ```python 294 | print("I'm hungry!") 295 | ``` 296 | 297 | 이어서 터미널을 열고 앞의 hungry.py를 저장한 디렉터리로 이동합니다. 그런 다음 파일 이름인 “hungry.py”를 인수로 python 명령을 실행합니다. 여기에서는 hungry.py가 ~/deep-learning-from-scratch/ch01 디렉터리에 있다고 가정합니다. 298 | 299 | ``` 300 | $ cd ~/deep-learning-from-scratch/ch01 # 디렉터리로 이동 301 | $ python hungry.py 302 | I'm hungry! 303 | ``` 304 | 305 | 이처럼 파이썬 코드를 담은 파일을 인수로 지정해 파이썬 프로그램을 실행할 수 있습니다. 306 | 307 | #### 1.4.2 클래스 308 | 지금까지 int와 str 등의 자료형을 살펴봤습니다(그리고 type ( ) 함수로는 원하는 데이터의 자료형을 알아낼 수 있었죠). 이들은 내장된 자료형, 즉 파이썬이 기본으로 제공하는 자료형입니다. 이번 절에서는 새로운 **클래스**를 정의합니다. 개발자가 직접 클래스를 정의하면 독자적인 자료형을 만들 수 있습니다. 또한, 클래스에는 그 클래스만의 전용 함수(메서드)와 속성을 정의할 수도 있습니다. 309 | 310 | 파이썬에서는 class라는 키워드를 사용하여 클래스를 정의합니다. 클래스의 구조는 다음과 같습니다. 311 | 312 | ```python 313 | class 클래스 이름: 314 | def __init__(self, 인수, ...): # 생성자 315 | ... 316 | def 메서드 이름 1(self, 인수, ...): # 메서드 1 317 | ... 318 | def 메서드 이름 2(self, 인수, ...): # 메서드 2 319 | ... 320 | ``` 321 | 322 | 클래스 정의에는 **\_\_init\_\_**라는 특별한 메서드가 있는데, 클래스를 초기화하는 방법을 정의합니다. 이 초기화용 메서드를 **생성자**(_constructor_)라고도 하며, 클래스의 인스턴스가 만들어질 때 한 번만 불립니다. 또, 파이썬에서는 메서드의 첫 번째 인수로 자신(자신의 인스턴스)을 나타내는 self를 명시적으로 쓰는 것이 특징입니다(다른 언어를 쓰던 사람은 이처럼 self를 쓰는 규칙을 기묘하게 느낄지도 모르겠네요). 323 | 324 | 그럼 간단한 클래스를 하나 만들어보겠습니다. 다음 코드를 man.py 파일로 저장하세요. 325 | 326 | ```python 327 | class Man: 328 | def __init__(self, name): 329 | self.name = name 330 | print("Initialized!") 331 | 332 | def hello(self): 333 | print("Hello " + self.name + "!") 334 | 335 | def goodbye(self): 336 | print("Good-bye " + self.name + "!") 337 | 338 | m = Man("David") 339 | m.hello() 340 | m.goodbye() 341 | ``` 342 | 343 | 이제 터미널에서 man.py를 실행합니다. 344 | 345 | ``` 346 | $ python man.py 347 | Initialized! 348 | Hello David! 349 | Good-bye David! 350 | ``` 351 | 352 | 여기에서는 Man이라는 새로운 클래스를 정의했습니다. 그리고 Man 클래스에서 m이라는 인스턴스(객체)를 생성합니다. 353 | 354 | Man의 생성자(초기화 메서드)는 name이라는 인수를 받고, 그 인수로 인스턴스 변수인 self.name을 초기화합니다. **인스턴스 변수**는 인스턴스별로 저장되는 변수입니다. 파이썬에서는 self.name처럼 self 다음에 속성 이름을 써서 인스턴스 변수를 작성하거나 접근할 수 있습니다. 355 | 356 | ### 1.5 넘파이 357 | 딥러닝을 구현하다 보면 배열이나 행렬 계산이 많이 등장합니다. **넘파이**의 배열 클래스인 numpy.array에는 편리한 메서드가 많이 준비되어 있어, 딥러닝을 구현할 때 이들 메서드를 이용합니다. 이번 절에서는 앞으로 사용할 넘파이에 대해서 간략히 설명합니다. 358 | 359 | #### 1.5.1 넘파이 가져오기 360 | 넘파이는 외부 라이브러리입니다. 여기서 말하는 ‘외부’는 표준 파이썬에는 포함되지 않는다는 것입니다. 그래서 우선 넘파이 라이브러리를 쓸 수 있도록 가져와야(_import_) 합니다. 361 | 362 | ```python 363 | >>> import numpy as np 364 | ``` 365 | 366 | 파이썬에서는 라이브러리를 읽기 위해서 import 문을 이용합니다. 여기에서는 import numpy as np라고 썼는데, 직역하면 “numpy를 np라는 이름으로 가져와라”가 됩니다. 이렇게 해두면 앞으로 넘파이가 제공하는 메서드를 np를 통해 참조할 수 있습니다. 367 | 368 | #### 1.5.2 넘파이 배열 생성하기 369 | **넘파이 배열**을 만들 때는 np.array ( ) 메서드를 이용합니다. np.array ( )는 파이썬의 리스트를 인수로 받아 넘파이 라이브러리가 제공하는 특수한 형태의 배열(numpy.ndarray )을 반환합니다. 370 | 371 | ```python 372 | >>> x = np.array([1.0, 2.0, 3.0]) 373 | >>> print(x) 374 | [1. 2. 3.] 375 | >>> type(x) 376 | 377 | ``` 378 | 379 | #### 1.5.3 넘파이의 산술 연산 380 | 다음은 넘파이 배열로 산술 연산을 수행하는 예입니다. 381 | 382 | ```python 383 | >>> x = np.array([1.0, 2.0, 3.0]) 384 | >>> y = np.array([2.0, 4.0, 6.0]) 385 | >>> x + y # 원소별 덧셈 386 | array([ 3., 6., 9.]) 387 | >>> x - y 388 | array([ -1., -2., -3.]) 389 | >>> x * y # 원소별 곱셈 390 | array([ 2., 8., 18.]) 391 | >>> x / y 392 | array([ 0.5, 0.5, 0.5]) 393 | ``` 394 | 395 | 여기에서 주의할 점은 배열 x와 y의 원소 수가 같다는 것입니다(둘 다 원소를 3개씩 갖는 1차원 배열). x와 y의 원소 수가 같다면 산술 연산은 각 원소에 대해서 행해집니다. 원소 수가 다르면 오류가 발생하니 원소 수 맞추기는 중요하답니다. 참고로, ‘원소별’이라는 말은 영어로 element-wise라고 합니다. 예컨대 ‘원소별 곱셈’은 element-wise product라고 합니다. 396 | 397 | 넘파이 배열은 원소별 계산뿐 아니라 넘파이 배열과 수치 하나(스칼라값)의 조합으로 된 산술 연산도 수행할 수 있습니다. 이 경우 스칼라값과의 계산이 넘파이 배열의 원소별로 한 번씩 수행됩니다. 이 기능을 **브로드캐스트**라고 합니다(자세한 것은 1.5.5절에서 설명하겠습니다). 398 | 399 | ```python 400 | >>> x = np.array([1.0, 2.0, 3.0]) 401 | >>> x / 2.0 402 | array([ 0.5, 1., 1.5]) 403 | ``` 404 | 405 | #### 1.5.4 넘파이의 N차원 배열 406 | 넘파이는 1차원 배열(1줄로 늘어선 배열)뿐 아니라 다차원 배열도 작성할 수 있습니다. 예를 들어 2차원 배열(행렬)은 다음처럼 작성합니다. 407 | 408 | ```python 409 | >>> A = np.array([[1, 2], [3, 4]]) 410 | >>> print(A) 411 | [[1 2] 412 | [3 4]] 413 | >>> A.shape 414 | (2, 2) 415 | >>> A.dtype 416 | dtype('int64') 417 | ``` 418 | 419 | 방금 2×2의 A라는 행렬을 작성했습니다. 행렬의 형상은 shape으로, 행렬에 담긴 원소의 자료형은 dtype으로 알 수 있습니다. 이어서 행렬의 산술 연산을 봅시다. 420 | 421 | > **옮긴이:** 이 책에서는 행렬을 포함한 N차원 배열에서 그 배열의 ‘각 차원의 크기(원소 수)’를 배열의 ‘형상’이라 하겠습니다. 422 | 423 | 424 | ```python 425 | >>> B = np.array([[3, 0], [0, 6]]) 426 | >>> A + B 427 | array([[ 4, 2], 428 | [ 3, 10]]) 429 | >>> A * B 430 | array([[ 3, 0], 431 | [ 0, 24]]) 432 | ``` 433 | 434 | 형상이 같은 행렬끼리면 행렬의 산술 연산도 대응하는 원소별로 계산됩니다. 배열과 마찬가지로 말이죠. 행렬과 스칼라값의 산술 연산도 가능합니다. 이때도 배열과 마찬가지로 브로드캐스트 기능이 작동합니다. 435 | 436 | ```python 437 | >>> print(A) 438 | [[1 2] 439 | [3 4]] 440 | >>> A * 10 441 | array([[ 10, 20], 442 | [ 30, 40]]) 443 | ``` 444 | 445 | > **노트:** 넘파이 배열(np.array )은 N차원 배열을 작성할 수 있습니다. 1차원 배열, 2차원 배열, 3차원 배열처럼 원하는 차수의 배열을 만들 수 있다는 뜻입니다. 수학에서는 1차원 배열은 **벡터**(_vector_), 2차원 배열은 **행렬**(_matrix_)이라고 부릅니다. 또 벡터와 행렬을 일반화한 것을 **텐서**(_tensor_)라 합니다. 이 책에서는 기본적으로 2차원 배열을 ‘행렬’, 3차원 이상의 배열을 ‘다차원 배열’이라 하겠습니다. 446 | 447 | #### 1.5.5 브로드캐스트 448 | 넘파이에서는 형상이 다른 배열끼리도 계산할 수 있습니다. 앞의 예에서는 2×2 행렬 A에 스칼라값 10을 곱했습니다. 이때 [그림 1-1]과 같이 10이라는 스칼라값이 2×2 행렬로 확대된 후 연산이 이뤄집니다. 이 똑똑한 기능을 **브로드캐스트**(_broadcast_)라고 합니다. 449 | 450 | **그림 1-1** 브로드캐스트의 예 : 스칼라값인 10이 2×2 행렬로 확대된다. 451 | ![그림 1-1](images/fig 1-1.png) 452 | 453 | 다른 예를 살펴봅시다. 454 | 455 | ```python 456 | >>> A = np.array([[1, 2], [3, 4]]) 457 | >>> B = np.array([10, 20]) 458 | >>> A * B 459 | array([[ 10, 40], 460 | [ 30, 80]]) 461 | ``` 462 | 463 | 여기에서는 [그림 1-2]처럼 1차원 배열인 B가 ‘똑똑하게도’ 2차원 배열 A와 똑같은 형상으로 변형된 후 원소별 연산이 이뤄집니다. 464 | 465 | **그림 1-2** 브로드캐스트의 예 2 466 | ![그림 1-1](images/fig 1-2.png) 467 | 468 | 이처럼 넘파이가 제공하는 브로드캐스트 기능 덕분에 형상이 다른 배열끼리의 연산을 스마트하게 할 수 있습니다. 469 | 470 | #### 1.5.6 원소 접근 471 | 원소의 인덱스는 0부터 시작합니다(기억하시죠?). 그리고 각 원소에 접근하려면 다음과 같이 합니다. 472 | 473 | ```python 474 | >>> X = np.array([[51, 55], [14, 19], [0, 4]]) 475 | >>> print(X) 476 | [[51 55] 477 | [14 19] 478 | [ 0 4]] 479 | >>> X[0] # 0행 480 | array([51, 55]) 481 | >>> X[0][1] # (0, 1) 위치의 원소 482 | 55 483 | ``` 484 | 485 | for 문으로도 각 원소에 접근할 수 있습니다. 486 | 487 | ```python 488 | >>> for row in X: 489 | ... print(row) 490 | ... 491 | [51 55] 492 | [14 19] 493 | [0 4] 494 | ``` 495 | 496 | 넘파이는 지금까지의 방법 외에도, 인덱스를 배열로 지정해 한 번에 여러 원소에 접근할 수도 있습니다. 497 | 498 | ```python 499 | >>> X = X.flatten() # X를 1차원 배열로 변환(평탄화) 500 | >>> print(X) 501 | [51 55 14 19 0 4] 502 | >>> X[np.array([0, 2, 4])] # 인덱스가 0, 2, 4인 원소 얻기 503 | array([51, 14, 0]) 504 | ``` 505 | 506 | 이 기법을 응용하면 특정 조건을 만족하는 원소만 얻을 수 있습니다. 예컨대 다음과 같이 배열 X에서 15 이상인 값만 구할 수 있습니다. 507 | 508 | ```python 509 | >>> X > 15 510 | array([ True, True, False, True, False, False], dtype = bool) 511 | >>> X[X>15] 512 | array([51, 55, 19]) 513 | ``` 514 | 515 | 넘파이 배열에 부등호 연산자를 사용한(앞 예에서 X>15) 결과는 bool 배열입니다. 여기에서는 이 bool 배열을 사용해 배열 X에서 True에 해당하는 원소, 즉 값이 15보다 큰 원소만 꺼내고 있습니다. 516 | 517 | > **노트:** 파이썬 같은 동적 언어는 C나 C++ 같은 정적 언어(컴파일 언어)보다 처리 속도가 늦다고 합니다. 실제로 무거운 작업을 할 때는 C/C++로 작성한 프로그램을 쓰는 편이 좋습니다. 그래서 파이썬에서 빠른 성능이 요구될 경우 해당 부분을 C/C++로 구현하곤 합니다. 그때 파이썬은 C/C++로 쓰인 프로그램을 호출해주는, 이른바 ‘중개자’ 같은 역할을 합니다. 넘파이도 주된 처리는 C와 C++로 구현했습니다. 그래서 성능을 해치지 않으면서 파이썬의 편리한 문법을 사용할 수 있는 것이죠. 518 | 519 | ### 1.6 matplotlib 520 | 딥러닝 실험에서는 그래프 그리기와 데이터 시각화도 중요하답니다. **matplotlib**은 그래프를 그려주는 라이브러리입니다. matplotlib을 사용하면 그래프 그리기와 데이터 시각화가 쉬워집니다. 이번 절에서는 그래프를 그리고 이미지를 화면에 표시하는 방법을 설명합니다. 521 | 522 | #### 1.6.1 단순한 그래프 그리기 523 | 그래프를 그리려면 matplotlib의 **pyplot** 모듈을 이용합니다. 당장 sin 함수를 그리는 예를 살펴봅시다. 524 | 525 | ```python 526 | import numpy as np 527 | import matplotlib.pyplot as plt 528 | 529 | # 데이터 준비 530 | x = np.arange(0, 6, 0.1) # 0에서 6까지 0.1 간격으로 생성 531 | y = np.sin(x) 532 | 533 | # 그래프 그리기 534 | plt.plot(x, y) 535 | plt.show() 536 | ``` 537 | 538 | 이 코드에서는 넘파이의 arange 메서드로 [0, 0.1, 0.2, ..., 5.8, 5.9]라는 데이터를 생성하여 변수 x에 할당했습니다. 그다음 줄에서는 x의 각 원소에 넘파이의 sin 함수인 np.sin ( )을 적용하여 변수 y에 할당합니다. 이제 x와 y를 인수로 plt.plot 메서드를 호출해 그래프를 그립니다. 마지막으로 plt.show( )를 호출해 그래프를 화면에 출력하고 끝납니다. 이 코드를 실행하면 [그림 1-3]의 이미지가 그려집니다. 539 | 540 | **그림 1-3** sin 함수 그래프 541 | ![그림 1-3](images/fig 1-3.png) 542 | 543 | #### 1.6.2 pyplot의 기능 544 | 여기에 cos 함수도 추가로 그려보겠습니다. 또, 제목과 각 축의 이름(레이블) 표시 등, **pyplot**의 다른 기능도 사용해보겠습니다. 545 | 546 | ```python 547 | import numpy as np 548 | import matplotlib.pyplot as plt 549 | 550 | # 데이터 준비 551 | x = np.arange(0, 6, 0.1) # 0에서 6까지 0.1 간격으로 생성 552 | y1 = np.sin(x) 553 | y2 = np.cos(x) 554 | 555 | # 그래프 그리기 556 | plt.plot(x, y1, label="sin") 557 | plt.plot(x, y2, linestyle = "--", label="cos") # cos 함수는 점선으로 그리기 558 | plt.xlabel("x") # x축 이름 559 | plt.ylabel("y") # y축 이름 560 | plt.title('sin & cos') # 제목 561 | plt.legend() 562 | plt.show() 563 | ``` 564 | 565 | 결과는 [그림 1-4]와 같습니다. 그래프의 제목과 축 이름이 보일 겁니다. 566 | 567 | **그림 1-4** sin 함수와 cos 함수 그래프 568 | ![그림 1-4](images/fig 1-4.png) 569 | 570 | #### 1.6.3 이미지 표시하기 571 | pyplot에는 이미지를 표시해주는 메서드인 imshow()도 준비되어 있습니다. 이미지를 읽어들일 때는 matplotlib.image 모듈의 imread() 메서드를 이용합니다. 예를 보시죠. 572 | 573 | ```python 574 | import matplotlib.pyplot as plt 575 | from matplotlib.image import imread 576 | 577 | img = imread('cactus.png') # 이미지 읽어오기(적절한 경로를 설정하세요!) 578 | 579 | plt.imshow(img) 580 | plt.show() 581 | ``` 582 | 583 | 이 코드를 실행하면 [그림 1-5]처럼 읽어들인 이미지가 표시됩니다. 584 | 585 | **그림 1-5** 이미지 표시하기 586 | ![그림 1-5](images/fig 1-5.png) 587 | 588 | 앞의 코드에서는 cactus.png라는 이미지 파일이 현재 작업 디렉터리에 있다고 가정했습니다. 여러분은 자신의 환경에 맞게 파일 이름과 경로를 적절히 수정해야 합니다. 이 책이 제공하는 소스 코드에서는 dataset 디렉터리에서 이 cactus.png 파일을 찾을 수 있습니다. 예를 들어 파이썬 인터프리터로 ch01 디렉터리에서 이 코드를 실행한다면 이미지 경로를 ‘cactus.png’에서 ‘../dataset/cactus.png’로 변경하면 올바르게 작동합니다. 589 | 590 | ### 1.7 정리 591 | 이번 장은 딥러닝으로의 본격적인 여정을 위한 준비 과정입니다. 특히, 딥러닝(신경망)을 구현하는 데 필요한 프로그래밍의 기본을 중심으로 살펴보았습니다. 다음 장에서 파이썬으로 실제로 작동하는 코드를 작성해보면서 딥러닝의 세계로 떠나볼 겁니다. 592 | 593 | 이번 장에서는 파이썬에 대해 우리에게 필요한 최소한만 설명했습니다. 더 깊게 알고 싶은 분을 위해 좋은 책을 두 권 소개해드리죠. 먼저 [『처음 시작하는 파이썬』(한빛미디어, 2015)](http://www.hanbit.co.kr/store/books/look.php?p_code=B2827459900)입니다. 이 책은 파이썬 프로그래밍을 기초부터 응용까지 친절하게 설명해주는 실천적인 입문서입니다. 넘파이에 대해서는 [『파이썬 라이브러리를 활용한 데이터 분석』(한빛미디어, 2013)](http://www.hanbit.co.kr/store/books/look.php?p_code=B6540908288)을 추천합니다. 책 외에는 [Scipy 강의 노트](http://www.turbare.net/transl/scipy-lecture-notes/index.html)라는 웹 사이트가 과학 기술에서의 계산을 주제로 넘파이와 matplotlib을 잘 설명하고 있으니 참고하시기 바랍니다. 594 | 595 | 596 | > **이번 장에서 배운 내용** 597 | * 파이썬은 간단하고 익히기 쉬운 프로그래밍 언어다. 598 | * 파이썬은 오픈 소스여서 자유롭게 사용할 수 있다. 599 | * 이 책은 딥러닝 구현에 파이썬 3 버전을 이용한다. 600 | * 외부 라이브러리로는 넘파이와 matplotlib을 이용한다. 601 | * 파이썬을 실행하는 방식에는 ‘인터프리터’와 ‘스크립트 파일’ 두 가지가 있다. 602 | * 파이썬에서는 함수와 클래스 같은 모듈로 구현을 정리할 수 있다. 603 | * 넘파이는 다차원 배열을 다루는 편리한 메서드를 많이 제공한다. 604 | -------------------------------------------------------------------------------- /ch01/hungry.py: -------------------------------------------------------------------------------- 1 | print("I'm hungry!") 2 | -------------------------------------------------------------------------------- /ch01/images/fig 1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch01/images/fig 1-1.png -------------------------------------------------------------------------------- /ch01/images/fig 1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch01/images/fig 1-2.png -------------------------------------------------------------------------------- /ch01/images/fig 1-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch01/images/fig 1-3.png -------------------------------------------------------------------------------- /ch01/images/fig 1-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch01/images/fig 1-4.png -------------------------------------------------------------------------------- /ch01/images/fig 1-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch01/images/fig 1-5.png -------------------------------------------------------------------------------- /ch01/img_show.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import os, matplotlib.pyplot as plt 3 | from matplotlib.image import imread 4 | 5 | img = imread(os.path.dirname(__file__) 6 | + '/../dataset/cactus.png') # 이미지 읽어오기 7 | plt.imshow(img) 8 | 9 | plt.show() 10 | -------------------------------------------------------------------------------- /ch01/man.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class Man: 3 | """샘플 클래스""" 4 | 5 | def __init__(self, name): 6 | self.name = name 7 | print("Initilized!") 8 | 9 | def hello(self): 10 | print("Hello " + self.name + "!") 11 | 12 | def goodbye(self): 13 | print("Good-bye " + self.name + "!") 14 | 15 | m = Man("David") 16 | m.hello() 17 | m.goodbye() 18 | -------------------------------------------------------------------------------- /ch01/simple_graph.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | # 데이터 준비 6 | x = np.arange(0, 6, 0.1) # 0에서 6까지 0.1 간격으로 생성 7 | y = np.sin(x) 8 | 9 | # 그래프 그리기 10 | plt.plot(x, y) 11 | plt.show() 12 | -------------------------------------------------------------------------------- /ch01/sin_cos_graph.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | # 데이터 준비 6 | x = np.arange(0, 6, 0.1) # 0에서 6까지 0.1 간격으로 생성 7 | y1 = np.sin(x) 8 | y2 = np.cos(x) 9 | 10 | # 그래프 그리기 11 | plt.plot(x, y1, label="sin") 12 | plt.plot(x, y2, linestyle = "--", label="cos") # cos 함수는 점선으로 그리기 13 | plt.xlabel("x") # x축 이름 14 | plt.ylabel("y") # y축 이름 15 | plt.title('sin & cos') 16 | plt.legend() 17 | plt.show() 18 | -------------------------------------------------------------------------------- /ch01/sin_graph.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | # 데이터 준비 6 | x = np.arange(0, 6, 0.1) # 0에서 6까지 0.1 간격으로 생성 7 | y = np.sin(x) 8 | 9 | # 그래프 그리기 10 | plt.plot(x, y) 11 | plt.show() 12 | -------------------------------------------------------------------------------- /ch02/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | and_gate.py | 단층 퍼셉트론으로 AND 게이트를 구현합니다. | 2.3.3 가중치와 편향 구현하기 | 53 | 5 | | nand_gate.py | 단층 퍼셉트론으로 NAND 게이트를 구현합니다. | 2.3.3 가중치와 편향 구현하기 | 53 | 6 | | or_gate.py | 단층 퍼셉트론으로 OR 게이트를 구현합니다. | 2.3.3 가중치와 편향 구현하기 | 53 | 7 | | xor_gate.py | 2층 퍼셉트론으로 XOR 게이트를 구현합니다. | 2.5.2 XOR 게이트 구현하기 | 59 | 8 | 9 | ## 2장 퍼셉트론 10 | 이번 장에서는 퍼셉트론(_perceptron_) 알고리즘을 설명합니다. 퍼셉트론은 프랑크 로젠블라트(_Frank Rosenblatt_)가 1957년에 고안한 알고리즘입니다. 고대 화석 같은 이 알고리즘을 지금 시점에 왜 배우는가 하면, 퍼셉트론이 신경망(딥러닝)의 기원이 되는 알고리즘이기 때문입니다. 그래서 퍼셉트론의 구조를 배우는 것은 신경망과 딥러닝으로 나아가는 데 중요한 아이디어를 배우는 일도 됩니다. 11 | 12 | 이번 장에서는 퍼셉트론을 설명하고 퍼셉트론을 써서 간단한 문제를 풀어갑니다. 여정의 첫 목적지인 만큼 가볍고 즐거운 여행이 될 겁니다. 13 | 14 | > **목차** 15 | ``` 16 | 2.1 퍼셉트론이란? 17 | 2.2 단순한 논리 회로 18 | __2.2.1 AND 게이트 19 | __2.2.2 NAND 게이트와 OR 게이트 20 | 2.3 퍼셉트론 구현하기 21 | __2.3.1 간단한 구현부터 22 | __2.3.2 가중치와 편향 도입 23 | __2.3.3 가중치와 편향 구현하기 24 | 2.4 퍼셉트론의 한계 25 | __2.4.1 도전! XOR 게이트 26 | __2.4.2 선형과 비선형 27 | 2.5 다층 퍼셉트론이 출동한다면 28 | __2.5.1 기존 게이트 조합하기 29 | __2.5.2 XOR 게이트 구현하기 30 | 2.6 NAND에서 컴퓨터까지 31 | ``` 32 | 33 | ### 정리 34 | 이번 장에서는 퍼셉트론을 배웠습니다.  퍼셉트론은 간단한 알고리즘이라 그 구조를 쉽게 이해할 수 있습니다. 퍼셉트론은 다음 장에서 배울 신경망의 기초가 됩니다. 그러니 이번 장에서 배운 내용은 아주 중요합니다. 35 | 36 | > **이번 장에서 배운 내용** 37 | * 퍼셉트론은 입출력을 갖춘 알고리즘이다. 입력을 주면 정해진 규칙에 따른 값을 출력한다. 38 | * 퍼셉트론에서는 ‘가중치’와 ‘편향’을 매개변수로 설정한다. 39 | * 퍼셉트론으로 AND, OR 게이트 등의 논리 회로를 표현할 수 있다. 40 | * XOR 게이트는 단층 퍼셉트론으로는 표현할 수 없다. 41 | * 2층 퍼셉트론을 이용하면 XOR 게이트를 표현할 수 있다. 42 | * 단층 퍼셉트론은 직선형 영역만 표현할 수 있고, 다층 퍼셉트론은 비선형 영역도 표현할 수 있다. 43 | * 다층 퍼셉트론은 (이론상) 컴퓨터를 표현할 수 있다. 44 | -------------------------------------------------------------------------------- /ch02/and_gate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | 5 | def AND(x1, x2): 6 | x = np.array([x1, x2]) 7 | w = np.array([0.5, 0.5]) 8 | b = -0.7 9 | tmp = np.sum(w*x) + b 10 | if tmp <= 0: 11 | return 0 12 | else: 13 | return 1 14 | 15 | if __name__ == '__main__': 16 | for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]: 17 | y = AND(xs[0], xs[1]) 18 | print(str(xs) + " -> " + str(y)) 19 | -------------------------------------------------------------------------------- /ch02/nand_gate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | 5 | def NAND(x1, x2): 6 | x = np.array([x1, x2]) 7 | w = np.array([-0.5, -0.5]) 8 | b = 0.7 9 | tmp = np.sum(w*x) + b 10 | if tmp <= 0: 11 | return 0 12 | else: 13 | return 1 14 | 15 | if __name__ == '__main__': 16 | for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]: 17 | y = NAND(xs[0], xs[1]) 18 | print(str(xs) + " -> " + str(y)) 19 | -------------------------------------------------------------------------------- /ch02/or_gate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | 5 | def OR(x1, x2): 6 | x = np.array([x1, x2]) 7 | w = np.array([0.5, 0.5]) 8 | b = -0.2 9 | tmp = np.sum(w*x) + b 10 | if tmp <= 0: 11 | return 0 12 | else: 13 | return 1 14 | 15 | if __name__ == '__main__': 16 | for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]: 17 | y = OR(xs[0], xs[1]) 18 | print(str(xs) + " -> " + str(y)) -------------------------------------------------------------------------------- /ch02/xor_gate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from and_gate import AND 3 | from or_gate import OR 4 | from nand_gate import NAND 5 | 6 | 7 | def XOR(x1, x2): 8 | s1 = NAND(x1, x2) 9 | s2 = OR(x1, x2) 10 | y = AND(s1, s2) 11 | return y 12 | 13 | if __name__ == '__main__': 14 | for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]: 15 | y = XOR(xs[0], xs[1]) 16 | print(str(xs) + " -> " + str(y)) -------------------------------------------------------------------------------- /ch03/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | mnist_show.py | MNIST 데이터셋을 읽어와 훈련 데이터 중 0번째 이미지를 화면에 출력합니다. | 3.6.1 손글씨 데이터셋 | 99 | 5 | | neuralnet_mnist.py | 신경망으로 손글씨 숫자 그림을 추론합니다. 입력층, 은닉층1, 은닉층2, 출력층의 뉴런 수는 각각 784, 50, 100, 10입니다. | 3.6.2 신경망의 추론 처리 | 100 | 6 | | neuralnet_mnist_batch.py | neuralnet_mnist.py에 배치 처리 기능을 더했습니다. | 3.6.3 배치 처리 | 104 | 7 | | relu.py | ReLU 함수를 구현한 코드입니다. | 3.2.7 ReLU 함수 | 76 | 8 | | sample_weight.pkl | 미리 학습해둔 가중치 매개변수의 값들입니다. | 3.6.2 신경망의 추론 처리 | 100 | 9 | | sig_step_compare.py | 시그모이드 함수와 계단 함수의 그래프 모양을 비교해봅니다. | 3.2.5 시그모이드 함수와 계단 함수 비교 | 74 | 10 | | sigmoid.py | 시그모이드 함수를 구현한 코드입니다. | 3.2.4 시그모이드 함수 구현하기 | 72 | 11 | | step_function.py | 계단 함수를 구현한 코드입니다. | 3.2.3 계단 함수의 그래프 | 70 | 12 | 13 | ## 3장 신경망 14 | 앞 장 배운 퍼셉트론 관련해서는 좋은 소식과 나쁜 소식이 있었습니다. 좋은 소식은 퍼셉트론으로 복잡한 함수도 표현할 수 있다는 것입니다. 그 예로 컴퓨터가 수행하는 복잡한 처리도 퍼셉트론으로 (이론상) 표현할 수 있음을 앞 장에서 설명했습니다. 나쁜 소식은 가중치를 설정하는 작업(원하는 결과를 출력하도록 가중치 값을 적절히 정하는 작업)은 여전히 사람이 수동으로 한다는 것입니다. 앞 장에서는 AND, OR 게이트의 진리표를 보면서 우리 인간이 적절한 가중치 값을 정했습니다. 15 | 16 | 신경망은 이 나쁜 소식을 해결해줍니다. 무슨 말인고 하니, 가중치 매개변수의 적절한 값을 데이터로부터 자동으로 학습하는 능력이 이제부터 살펴볼 신경망의 중요한 성질입니다. 이번 장에서는 신경망의 개요를 설명하고, 신경망이 입력 데이터가 무엇인지 식별하는 처리 과정을 자세히 알아봅니다. 아쉽지만 데이터에서 가중치 매개변수 값을 학습하는 방법은 다음 장까지 기다리셔야 합니다. 17 | 18 | ## 목차 19 | ``` 20 | 3.1 퍼셉트론에서 신경망으로 21 | __3.1.1 신경망의 예 22 | __3.1.2 퍼셉트론 복습 23 | __3.1.3 활성화 함수의 등장 24 | 3.2 활성화 함수 25 | __3.2.1 시그모이드 함수 26 | __3.2.2 계단 함수 구현하기 27 | __3.2.3 계단 함수의 그래프 28 | __3.2.4 시그모이드 함수 구현하기 29 | __3.2.5 시그모이드 함수와 계단 함수 비교 30 | __3.2.6 비선형 함수 31 | __3.2.7 ReLU 함수 32 | 3.3 다차원 배열의 계산 33 | __3.3.1 다차원 배열 34 | __3.3.2 행렬의 내적 35 | __3.3.3 신경망의 내적 36 | 3.4 3층 신경망 구현하기 37 | __3.4.1 표기법 설명 38 | __3.4.2 각 층의 신호 전달 구현하기 39 | __3.4.3 구현 정리 40 | 3.5 출력층 설계하기 41 | __3.5.1 항등 함수와 소프트맥스 함수 구현하기 42 | __3.5.2 소프트맥스 함수 구현 시 주의점 43 | __3.5.3 소프트맥스 함수의 특징 44 | __3.5.4 출력층의 뉴런 수 정하기 45 | 3.6 손글씨 숫자 인식 46 | __3.6.1 MNIST 데이터셋 47 | __3.6.2 신경망의 추론 처리 48 | __3.6.3 배치 처리 49 | ``` 50 | 51 | ## 이번 장에서 배운 내용 52 | * 신경망에서는 활성화 함수로 시그모이드 함수와 ReLU 함수 같은 매끄럽게 변화하는 함수를 이용한다. 53 | * 넘파이의 다차원 배열을 잘 사용하면 신경망을 효율적으로 구현할 수 있다. 54 | * 기계학습 문제는 크게 회귀와 분류로 나눌 수 있다. 55 | * 출력층의 활성화 함수로는 회귀에서는 주로 항등 함수를, 분류에서는 주로 소프트맥스 함수를 이용한다. 56 | * 분류에서는 출력층의 뉴런 수를 분류하려는 클래스 수와 같게 설정한다. 57 | * 입력 데이터를 묶은 것을 배치라 하며, 추론 처리를 이 배치 단위로 진행하면 결과를 훨씬 빠르게 얻을 수 있다. 58 | -------------------------------------------------------------------------------- /ch03/mnist_show.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 4 | 5 | import numpy as np 6 | from dataset.mnist import load_mnist 7 | from PIL import Image 8 | 9 | 10 | def img_show(img): 11 | pil_img = Image.fromarray(np.uint8(img)) 12 | pil_img.show() 13 | 14 | (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False) 15 | 16 | img = x_train[0] 17 | label = t_train[0] 18 | print(label) # 5 19 | 20 | print(img.shape) # (784,) 21 | img = img.reshape(28, 28) # 형상을 원래 이미지의 크기로 변형 22 | print(img.shape) # (28, 28) 23 | 24 | img_show(img) 25 | -------------------------------------------------------------------------------- /ch03/neuralnet_mnist.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 4 | import numpy as np 5 | import pickle 6 | from dataset.mnist import load_mnist 7 | from common.functions import sigmoid, softmax 8 | 9 | 10 | def get_data(): 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False) 12 | return x_test, t_test 13 | 14 | 15 | def init_network(): 16 | with open(os.path.dirname(__file__) + "/sample_weight.pkl", 'rb') as f: 17 | network = pickle.load(f) 18 | return network 19 | 20 | 21 | def predict(network, x): 22 | W1, W2, W3 = network['W1'], network['W2'], network['W3'] 23 | b1, b2, b3 = network['b1'], network['b2'], network['b3'] 24 | 25 | a1 = np.dot(x, W1) + b1 26 | z1 = sigmoid(a1) 27 | a2 = np.dot(z1, W2) + b2 28 | z2 = sigmoid(a2) 29 | a3 = np.dot(z2, W3) + b3 30 | y = softmax(a3) 31 | 32 | return y 33 | 34 | 35 | x, t = get_data() 36 | network = init_network() 37 | accuracy_cnt = 0 38 | for i in range(len(x)): 39 | y = predict(network, x[i]) 40 | p= np.argmax(y) # 확률이 가장 높은 원소의 인덱스를 얻는다. 41 | if p == t[i]: 42 | accuracy_cnt += 1 43 | 44 | print("Accuracy:" + str(float(accuracy_cnt) / len(x))) 45 | -------------------------------------------------------------------------------- /ch03/neuralnet_mnist_batch.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # 부모 디렉터리의 파일을 가져올 수 있도록 4 | import numpy as np 5 | import pickle 6 | from dataset.mnist import load_mnist 7 | from common.functions import sigmoid, softmax 8 | 9 | 10 | def get_data(): 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False) 12 | return x_test, t_test 13 | 14 | 15 | def init_network(): 16 | with open(os.path.dirname(__file__) + "/sample_weight.pkl", 'rb') as f: 17 | network = pickle.load(f) 18 | return network 19 | 20 | 21 | def predict(network, x): 22 | w1, w2, w3 = network['W1'], network['W2'], network['W3'] 23 | b1, b2, b3 = network['b1'], network['b2'], network['b3'] 24 | 25 | a1 = np.dot(x, w1) + b1 26 | z1 = sigmoid(a1) 27 | a2 = np.dot(z1, w2) + b2 28 | z2 = sigmoid(a2) 29 | a3 = np.dot(z2, w3) + b3 30 | y = softmax(a3) 31 | 32 | return y 33 | 34 | 35 | x, t = get_data() 36 | network = init_network() 37 | 38 | batch_size = 100 # 배치 크기 39 | accuracy_cnt = 0 40 | 41 | for i in range(0, len(x), batch_size): 42 | x_batch = x[i:i+batch_size] 43 | y_batch = predict(network, x_batch) 44 | p = np.argmax(y_batch, axis=1) 45 | accuracy_cnt += np.sum(p == t[i:i+batch_size]) 46 | 47 | print("Accuracy:" + str(float(accuracy_cnt) / len(x))) 48 | -------------------------------------------------------------------------------- /ch03/relu.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | 6 | def relu(x): 7 | return np.maximum(0, x) 8 | 9 | x = np.arange(-5.0, 5.0, 0.1) 10 | y = relu(x) 11 | plt.plot(x, y) 12 | plt.ylim(-1.0, 5.5) 13 | plt.show() 14 | -------------------------------------------------------------------------------- /ch03/sample_weight.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch03/sample_weight.pkl -------------------------------------------------------------------------------- /ch03/sig_step_compare.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | 6 | def sigmoid(x): 7 | return 1 / (1 + np.exp(-x)) 8 | 9 | 10 | def step_function(x): 11 | return np.array(x > 0, dtype=int) 12 | 13 | x = np.arange(-5.0, 5.0, 0.1) 14 | y1 = sigmoid(x) 15 | y2 = step_function(x) 16 | 17 | plt.plot(x, y1) 18 | plt.plot(x, y2, 'k--') 19 | plt.ylim(-0.1, 1.1) # y축 범위 지정 20 | plt.show() 21 | -------------------------------------------------------------------------------- /ch03/sigmoid.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | 6 | def sigmoid(x): 7 | return 1 / (1 + np.exp(-x)) 8 | 9 | X = np.arange(-5.0, 5.0, 0.1) 10 | Y = sigmoid(X) 11 | plt.plot(X, Y) 12 | plt.ylim(-0.1, 1.1) 13 | plt.show() 14 | -------------------------------------------------------------------------------- /ch03/step_function.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | 6 | def step_function(x): 7 | return np.array(x > 0, dtype=int) 8 | 9 | X = np.arange(-5.0, 5.0, 0.1) 10 | Y = step_function(X) 11 | plt.plot(X, Y) 12 | plt.ylim(-0.1, 1.1) # y축의 범위 지정 13 | plt.show() 14 | -------------------------------------------------------------------------------- /ch04/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | gradient_1d.py | 수치 미분으로 기울기를 구합니다. | 4.3.2 수치 미분의 예 | 124 | 5 | | gradient_2d.py | 수치 미분으로 기울기를 구합니다(두 편미분을 동시에 계산). | 4.4 기울기 | 129 | 6 | | gradient_method.py | 경사하강법의 갱신 과정을 보여줍니다. | 4.4.1 경사법(경사 하강법) | 132 | 7 | | gradient_simplenet.py | simpleNet 클래스 | 4.4.2 신경망에서의 기울기 | 134 | 8 | | train_neuralnet.py | 미치배치 방식으로 학습하고 시험 데이터로 평가합니다. | 4.5.2 미니배치 학습 구현하기 / 4.5.3 시험 데이터로 평가하기 | 141, 143 | 9 | | two_layer_net.py | 2층 신경망 클래스 | 4.5.1 2층 신경망 클래스 구현하기 | 137 | 10 | 11 | ## 4장 신경망 학습 12 | 이번 장의 주제는 신경망 학습입니다. 여기서 **학습**이란 훈련 데이터로부터 가중치 매개변수의 13 | 최적값을 자동으로 획득하는 것을 뜻합니다. 이번 장에서는 신경망이 학습할 수 있도록 해주는 14 | **지표**인 손실 함수를 소개합니다. 이 손실 함수의 결괏값을 가장 작게 만드는 가중치 매개변수를 15 | 찾는 것이 학습의 목표입니다. 이번 장에서는 손실 함수의 값을 가급적 작게 만드는 기법으로, 16 | 함수의 기울기를 활용하는 경사법을 소개합니다. 17 | 18 | ## 목차 19 | ``` 20 | 4.1 데이터에서 학습한다! 21 | __4.1.1 데이터 주도 학습 22 | __4.1.2 훈련 데이터와 시험 데이터 23 | 4.2 손실 함수 24 | __4.2.1 평균 제곱 오차 25 | __4.2.2 교차 엔트로피 오차 26 | __4.2.3 미니배치 학습 27 | __4.2.4 (배치용) 교차 엔트로피 오차 구현하기 28 | __4.2.5 왜 손실 함수를 설정하는가? 29 | 4.3 수치 미분 30 | __4.3.1 미분 31 | __4.3.2 수치 미분의 예 32 | __4.3.3 편미분 33 | 4.4 기울기 34 | __4.4.1 경사법(경사 하강법) 35 | __4.4.2 신경망에서의 기울기 36 | 4.5 학습 알고리즘 구현하기 37 | __4.5.1 2층 신경망 클래스 구현하기 38 | __4.5.2 미니배치 학습 구현하기 39 | __4.5.3 시험 데이터로 평가하기 40 | ``` 41 | 42 | ## 이번 장에서 배운 내용 43 | * 기계학습에서 사용하는 데이터셋은 훈련 데이터와 시험 데이터로 나눠 사용한다. 44 | * 훈련 데이터로 학습한 모델의 범용 능력을 시험 데이터로 평가한다. 45 | * 신경망 학습은 손실 함수를 지표로, 손실 함수의 값이 작아지는 방향으로 가중치 매개변수를 갱신한다. 46 | * 가중치 매개변수를 갱신할 때는 가중치 매개변수의 기울기를 이용하고, 기울어진 방향으로 가중치의 값을 갱신하는 작업을 반복한다. 47 | * 아주 작은 값을 주었을 때의 차분으로 미분하는 것을 수치 미분이라고 한다. 48 | * 수치 미분을 이용해 가중치 매개변수의 기울기를 구할 수 있다. 49 | * 수치 미분을 이용한 계산에는 시간이 걸리지만, 그 구현은 간단하다. 한편, 다음 장에서 구현하는 (다소 복잡한) 오차역전파법은 기울기를 고속으로 구할 수 있다. 50 | -------------------------------------------------------------------------------- /ch04/gradient_1d.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | 6 | def numerical_diff(f, x): 7 | h = 1e-4 # 0.0001 8 | return (f(x+h) - f(x-h)) / (2*h) 9 | 10 | 11 | def function_1(x): 12 | return 0.01*x**2 + 0.1*x 13 | 14 | 15 | def tangent_line(f, x): 16 | d = numerical_diff(f, x) 17 | print(d) 18 | y = f(x) - d*x 19 | return lambda t: d*t + y 20 | 21 | x = np.arange(0.0, 20.0, 0.1) 22 | y = function_1(x) 23 | 24 | plt.xlabel("x") 25 | plt.ylabel("f(x)") 26 | 27 | # 접선 없이 그리기(x = 5) 28 | plt.plot(x, y) 29 | plt.show() 30 | 31 | # 접선 그리기(x = 5) 32 | tf = tangent_line(function_1, 5) 33 | y2 = tf(x) 34 | 35 | plt.plot(x, y) 36 | plt.plot(x, y2) 37 | plt.show() 38 | 39 | # 접선 그리기(x = 10) 40 | tf = tangent_line(function_1, 10) 41 | y2 = tf(x) 42 | 43 | plt.plot(x, y) 44 | plt.plot(x, y2) 45 | plt.show() 46 | -------------------------------------------------------------------------------- /ch04/gradient_2d.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # cf.http://d.hatena.ne.jp/white_wheels/20100327/p3 3 | import numpy as np 4 | import matplotlib.pylab as plt 5 | from mpl_toolkits.mplot3d import Axes3D 6 | 7 | 8 | def _numerical_gradient_no_batch(f, x): 9 | h = 1e-4 # 0.0001 10 | grad = np.zeros_like(x) # x와 형상이 같은 배열을 생성 11 | 12 | for idx in range(x.size): 13 | tmp_val = x[idx] 14 | 15 | # f(x+h) 계산 16 | x[idx] = float(tmp_val) + h 17 | fxh1 = f(x) 18 | 19 | # f(x-h) 계산 20 | x[idx] = tmp_val - h 21 | fxh2 = f(x) 22 | 23 | grad[idx] = (fxh1 - fxh2) / (2*h) 24 | x[idx] = tmp_val # 값 복원 25 | 26 | return grad 27 | 28 | 29 | def numerical_gradient(f, X): 30 | if X.ndim == 1: 31 | return _numerical_gradient_no_batch(f, X) 32 | else: 33 | grad = np.zeros_like(X) 34 | 35 | for idx, x in enumerate(X): 36 | grad[idx] = _numerical_gradient_no_batch(f, x) 37 | 38 | return grad 39 | 40 | 41 | def function_2(x): 42 | if x.ndim == 1: 43 | return np.sum(x**2) 44 | else: 45 | return np.sum(x**2, axis=1) 46 | 47 | 48 | def tangent_line(f, x): 49 | d = numerical_gradient(f, x) 50 | print(d) 51 | y = f(x) - d*x 52 | return lambda t: d*t + y 53 | 54 | if __name__ == '__main__': 55 | x0 = np.arange(-2, 2.5, 0.25) 56 | x1 = np.arange(-2, 2.5, 0.25) 57 | X, Y = np.meshgrid(x0, x1) 58 | 59 | X = X.flatten() 60 | Y = Y.flatten() 61 | 62 | grad = numerical_gradient(function_2, np.array([X, Y]) ) 63 | 64 | plt.figure() 65 | plt.quiver(X, Y, -grad[0], -grad[1], angles="xy",color="#666666")#,headwidth=10,scale=40,color="#444444") 66 | plt.xlim([-2, 2]) 67 | plt.ylim([-2, 2]) 68 | plt.xlabel('x0') 69 | plt.ylabel('x1') 70 | plt.grid() 71 | plt.legend() 72 | plt.draw() 73 | plt.show() 74 | -------------------------------------------------------------------------------- /ch04/gradient_method.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | from gradient_2d import numerical_gradient 5 | 6 | 7 | def gradient_descent(f, init_x, lr=0.01, step_num=100): 8 | x = init_x 9 | x_history = [] 10 | 11 | for i in range(step_num): 12 | x_history.append( x.copy() ) 13 | 14 | grad = numerical_gradient(f, x) 15 | x -= lr * grad 16 | 17 | return x, np.array(x_history) 18 | 19 | 20 | def function_2(x): 21 | return x[0]**2 + x[1]**2 22 | 23 | init_x = np.array([-3.0, 4.0]) 24 | 25 | lr = 0.1 26 | step_num = 20 27 | x, x_history = gradient_descent(function_2, init_x, lr=lr, step_num=step_num) 28 | 29 | plt.plot( [-5, 5], [0,0], '--b') 30 | plt.plot( [0,0], [-5, 5], '--b') 31 | plt.plot(x_history[:,0], x_history[:,1], 'o') 32 | 33 | plt.xlim(-3.5, 3.5) 34 | plt.ylim(-4.5, 4.5) 35 | plt.xlabel("X0") 36 | plt.ylabel("X1") 37 | plt.show() 38 | -------------------------------------------------------------------------------- /ch04/gradient_simplenet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 4 | 5 | import numpy as np 6 | from common.functions import softmax, cross_entropy_error 7 | from common.gradient import numerical_gradient 8 | 9 | 10 | class simpleNet: 11 | def __init__(self): 12 | self.W = np.random.randn(2,3) # 정규분포로 초기화 13 | 14 | def predict(self, x): 15 | return np.dot(x, self.W) 16 | 17 | def loss(self, x, t): 18 | z = self.predict(x) 19 | y = softmax(z) 20 | loss = cross_entropy_error(y, t) 21 | 22 | return loss 23 | 24 | x = np.array([0.6, 0.9]) 25 | t = np.array([0, 0, 1]) 26 | 27 | net = simpleNet() 28 | 29 | f = lambda w: net.loss(x, t) 30 | dW = numerical_gradient(f, net.W) 31 | 32 | print(dW) 33 | -------------------------------------------------------------------------------- /ch04/train_neuralnet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from two_layer_net import TwoLayerNet 9 | 10 | # 데이터 읽기 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) 12 | 13 | train_loss_list = [] 14 | 15 | # 하이퍼파라미터 16 | iters_num = 10000 # 반복 횟수를 적절히 설정한다. 17 | train_size = x_train.shape[0] 18 | batch_size = 100 # 미니배치 크기 19 | learning_rate = 0.1 20 | 21 | network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) 22 | 23 | for i in range(iters_num): 24 | # 미니배치 획득 25 | batch_mask = np.random.choice(train_size, batch_size) 26 | x_batch = x_train[batch_mask] 27 | t_batch = t_train[batch_mask] 28 | 29 | # 기울기 계산 30 | #grad = network.numerical_gradient(x_batch, t_batch) 31 | grad = network.gradient(x_batch, t_batch) 32 | 33 | # 매개변수 갱신 34 | for key in ('W1', 'b1', 'W2', 'b2'): 35 | network.params[key] -= learning_rate * grad[key] 36 | 37 | # 학습 경과 기록 38 | loss = network.loss(x_batch, t_batch) 39 | train_loss_list.append(loss) 40 | 41 | # 그래프 그리기 42 | x = np.arange(len(train_loss_list)) 43 | plt.plot(x, train_loss_list) 44 | plt.xlabel("iteration") 45 | plt.ylabel("loss") 46 | plt.ylim(0, 9) 47 | plt.xlim(0, 10000) 48 | plt.show() 49 | -------------------------------------------------------------------------------- /ch04/train_neuralnet_2.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # 부모 디렉터리의 파일을 가져올 수 있도록 설정 3 | import sys, os 4 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 5 | 6 | import numpy as np 7 | import matplotlib.pyplot as plt 8 | from dataset.mnist import load_mnist 9 | from two_layer_net import TwoLayerNet 10 | 11 | # 데이터 읽기 12 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) 13 | 14 | network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) 15 | 16 | # 하이퍼파라미터 17 | iters_num = 10000 # 반복 횟수를 적절히 설정한다. 18 | train_size = x_train.shape[0] 19 | batch_size = 100 # 미니배치 크기 20 | learning_rate = 0.1 21 | 22 | train_loss_list = [] 23 | train_acc_list = [] 24 | test_acc_list = [] 25 | 26 | # 1에폭당 반복 수 27 | iter_per_epoch = max(train_size / batch_size, 1) 28 | 29 | for i in range(iters_num): 30 | # 미니배치 획득 31 | batch_mask = np.random.choice(train_size, batch_size) 32 | x_batch = x_train[batch_mask] 33 | t_batch = t_train[batch_mask] 34 | 35 | # 기울기 계산 36 | #grad = network.numerical_gradient(x_batch, t_batch) 37 | grad = network.gradient(x_batch, t_batch) 38 | 39 | # 매개변수 갱신 40 | for key in ('W1', 'b1', 'W2', 'b2'): 41 | network.params[key] -= learning_rate * grad[key] 42 | 43 | # 학습 경과 기록 44 | loss = network.loss(x_batch, t_batch) 45 | train_loss_list.append(loss) 46 | 47 | # 1에폭당 정확도 계산 48 | if i % iter_per_epoch == 0: 49 | train_acc = network.accuracy(x_train, t_train) 50 | test_acc = network.accuracy(x_test, t_test) 51 | train_acc_list.append(train_acc) 52 | test_acc_list.append(test_acc) 53 | print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc)) 54 | 55 | # 그래프 그리기 56 | x = np.arange(len(train_acc_list)) 57 | plt.plot(x, train_acc_list, label='train acc') 58 | plt.plot(x, test_acc_list, label='test acc', linestyle='--') 59 | plt.xlabel("epochs") 60 | plt.ylabel("accuracy") 61 | plt.ylim(0, 1.0) 62 | plt.xlim(0, 16) 63 | plt.legend(loc='lower right') 64 | plt.show() 65 | -------------------------------------------------------------------------------- /ch04/two_layer_net.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 4 | 5 | from common.functions import * 6 | from common.gradient import numerical_gradient 7 | 8 | 9 | class TwoLayerNet: 10 | 11 | def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01): 12 | # 가중치 초기화 13 | self.params = {} 14 | self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size) 15 | self.params['b1'] = np.zeros(hidden_size) 16 | self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) 17 | self.params['b2'] = np.zeros(output_size) 18 | 19 | def predict(self, x): 20 | W1, W2 = self.params['W1'], self.params['W2'] 21 | b1, b2 = self.params['b1'], self.params['b2'] 22 | 23 | a1 = np.dot(x, W1) + b1 24 | z1 = sigmoid(a1) 25 | a2 = np.dot(z1, W2) + b2 26 | y = softmax(a2) 27 | 28 | return y 29 | 30 | # x : 입력 데이터, t : 정답 레이블 31 | def loss(self, x, t): 32 | y = self.predict(x) 33 | 34 | return cross_entropy_error(y, t) 35 | 36 | def accuracy(self, x, t): 37 | y = self.predict(x) 38 | y = np.argmax(y, axis=1) 39 | t = np.argmax(t, axis=1) 40 | 41 | accuracy = np.sum(y == t) / float(x.shape[0]) 42 | return accuracy 43 | 44 | # x : 입력 데이터, t : 정답 레이블 45 | def numerical_gradient(self, x, t): 46 | loss_W = lambda W: self.loss(x, t) 47 | 48 | grads = {} 49 | grads['W1'] = numerical_gradient(loss_W, self.params['W1']) 50 | grads['b1'] = numerical_gradient(loss_W, self.params['b1']) 51 | grads['W2'] = numerical_gradient(loss_W, self.params['W2']) 52 | grads['b2'] = numerical_gradient(loss_W, self.params['b2']) 53 | 54 | return grads 55 | 56 | def gradient(self, x, t): 57 | W1, W2 = self.params['W1'], self.params['W2'] 58 | b1, b2 = self.params['b1'], self.params['b2'] 59 | grads = {} 60 | 61 | batch_num = x.shape[0] 62 | 63 | # forward 64 | a1 = np.dot(x, W1) + b1 65 | z1 = sigmoid(a1) 66 | a2 = np.dot(z1, W2) + b2 67 | y = softmax(a2) 68 | 69 | # backward 70 | dy = (y - t) / batch_num 71 | grads['W2'] = np.dot(z1.T, dy) 72 | grads['b2'] = np.sum(dy, axis=0) 73 | 74 | da1 = np.dot(dy, W2.T) 75 | dz1 = sigmoid_grad(a1) * da1 76 | grads['W1'] = np.dot(x.T, dz1) 77 | grads['b1'] = np.sum(dz1, axis=0) 78 | 79 | return grads 80 | -------------------------------------------------------------------------------- /ch05/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | buy_apple.py | 사과 2개를 구입하는 예제의 순전파와 역전파 구현입니다. | 5.4.1 곱셈 계층 | 162 | 5 | | buy_apple_orange.py | 사과와 오랜지를 구입하는 예제의 순전파와 역전파 구현입니다. | 5.4.2 덧셈 계층 | 163 | 6 | | gradient_check.py | 수치 미분 방식과 비교하여 오차역전파법으로 구한 기울기를 검증합니다(기울기 확인). | 5.7.3 오차역전파법으로 구한 기울기 검증하기 | 184 | 7 | | layer_naive.py | 곱셈 계층과 덧셈 계층의 구현입니다. | 5.4.1 곱셈 계층 / 5.4.2 덧셈 계층 | 161, 163 | 8 | | train_neuralnet.py | 4장의 train_neuralnet.py와 같습니다. 단, 수치 미분 대신 오차역전파법으로 기울기를 구합니다. | 5.7.4 오차역전파법을 사용한 학습 구현하기 | 186 | 9 | | two_layer_net.py | 오차역전파법을 적용한 2층 신경망 클래스 | 5.7.2 오차역전파법을 적용한 신경망 구현하기 | 181 | 10 | 11 | ## 5장 오차역전파법 12 | 앞 장에서는 신경망 학습에 대해서 설명했습니다. 그때 신경망의 가중치 매개변수의 기울기(정확히는 가중치 매개변수에 대한 손실 함수의 기울기)는 수치 미분을 사용해 구했습니다. 수치 미분은 단순하고 구현하기도 쉽지만 계산 시간이 오래 걸린다는 게 단점입니다. 이번 장에서는 가중치 매개변수의 기울기를 효율적으로 계산하는 ‘오차역전파법backpropagation’을 배워보겠습니다. 13 | 오차역전파법을 제대로 이해하는 방법은 두 가지가 있을 것입니다. 하나는 수식을 통한 것이고, 다른 하나는 계산 그래프를 통한 것입니다. 전자 쪽이 일반적인 방법으로, 특히 기계학습을 다루는 책 대부분은 수식을 중심으로 이야기를 전개합니다. 확실히 수식을 사용한 설명은 정확하고 간결하므로 올바른 방법이라 할 수 있겠죠. 하지만 졸업 후 너무 오랜만에 수식을 중심으로 생각하다 보면 본질을 놓치거나, 수많은 수식에 당황하는 일이 벌어지기도 합니다. 그래서 이번 장에서는 계산 그래프를 사용해서 ‘시각적’으로 이해시켜드리겠습니다. 그런 다음 실제로 코드를 작성해보면 ‘과연!’이란 탄성과 함께 더 깊이 이해하게 될 것입니다. 14 | 15 | *옮긴이_ 오차역전파법을 풀어쓰면 ‘오차를 역(반대 방향)으로 전파하는 방법(backward propagation of errors )’입니다. 너무 길고 쓸데없이 어려운 느낌이라 줄여서 ‘역전파법’ 혹은 그냥 ‘역전파’라고 쓰기도 합니다.* 16 | 17 | ## 목차 18 | ``` 19 | 5.1 계산 그래프 20 | __5.1.1 계산 그래프로 풀다 21 | __5.1.2 국소적 계산 22 | __5.1.3 왜 계산 그래프로 푸는가? 23 | 5.2 연쇄법칙 24 | __5.2.1 계산 그래프에서의 역전파 25 | __5.2.2 연쇄법칙이란? 26 | __5.2.3 연쇄법칙과 계산 그래프 27 | 5.3 역전파 28 | __5.3.1 덧셈 노드의 역전파 29 | __5.3.2 곱셈 노드의 역전파 30 | __5.3.3 사과 쇼핑의 예 31 | 5.4 단순한 계층 구현하기 32 | __5.4.1 곱셈 계층 33 | __5.4.2 덧셈 계층 34 | 5.5 활성화 함수 계층 구현하기 35 | __5.5.1 ReLU 계층 36 | __5.5.2 Sigmoid 계층 37 | 5.6 Affine/Softmax 계층 구현하기 38 | __5.6.1 Affine 계층 39 | __5.6.2 배치용 Affine 계층 40 | __5.6.3 Softmax-with-Loss 계층 41 | 5.7 오차역전파법 구현하기 42 | __5.7.1 신경망 학습의 전체 그림 43 | __5.7.2 오차역전파법을 적용한 신경망 구현하기 44 | __5.7.3 오차역전파법으로 구한 기울기 검증하기 45 | __5.7.4 오차역전파법을 사용한 학습 구현하기 46 | ``` 47 | 48 | ## 이번 장에서 배운 내용 49 | * 계산 그래프를 이용하면 계산 과정을 시각적으로 파악할 수 있다. 50 | * 계산 그래프의 노드는 국소적 계산으로 구성된다. 국소적 계산을 조합해 전체 계산을 구성한다. 51 | * 계산 그래프의 순전파는 통상의 계산을 수행한다. 한편, 계산 그래프의 역전파로는 각 노드의 미분을 구할 수 있다. 52 | * 신경망의 구성 요소를 계층으로 구현하여 기울기를 효율적으로 계산할 수 있다(오차역전파법). 53 | * 수치 미분과 오차역전파법의 결과를 비교하면 오차역전파법의 구현에 잘못이 없는지 확인할 수 있다(기울기 확인). 54 | -------------------------------------------------------------------------------- /ch05/buy_apple.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from layer_naive import * 3 | 4 | 5 | apple = 100 6 | apple_num = 2 7 | tax = 1.1 8 | 9 | mul_apple_layer = MulLayer() 10 | mul_tax_layer = MulLayer() 11 | 12 | # forward 13 | apple_price = mul_apple_layer.forward(apple, apple_num) 14 | price = mul_tax_layer.forward(apple_price, tax) 15 | 16 | # backward 17 | dprice = 1 18 | dapple_price, dtax = mul_tax_layer.backward(dprice) 19 | dapple, dapple_num = mul_apple_layer.backward(dapple_price) 20 | 21 | print("price:", int(price)) 22 | print("dApple:", dapple) 23 | print("dApple_num:", int(dapple_num)) 24 | print("dTax:", dtax) 25 | -------------------------------------------------------------------------------- /ch05/buy_apple_orange.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from layer_naive import * 3 | 4 | apple = 100 5 | apple_num = 2 6 | orange = 150 7 | orange_num = 3 8 | tax = 1.1 9 | 10 | # layer 11 | mul_apple_layer = MulLayer() 12 | mul_orange_layer = MulLayer() 13 | add_apple_orange_layer = AddLayer() 14 | mul_tax_layer = MulLayer() 15 | 16 | # forward 17 | apple_price = mul_apple_layer.forward(apple, apple_num) # (1) 18 | orange_price = mul_orange_layer.forward(orange, orange_num) # (2) 19 | all_price = add_apple_orange_layer.forward(apple_price, orange_price) # (3) 20 | price = mul_tax_layer.forward(all_price, tax) # (4) 21 | 22 | # backward 23 | dprice = 1 24 | dall_price, dtax = mul_tax_layer.backward(dprice) # (4) 25 | dapple_price, dorange_price = add_apple_orange_layer.backward(dall_price) # (3) 26 | dorange, dorange_num = mul_orange_layer.backward(dorange_price) # (2) 27 | dapple, dapple_num = mul_apple_layer.backward(dapple_price) # (1) 28 | 29 | print("price:", int(price)) 30 | print("dApple:", dapple) 31 | print("dApple_num:", int(dapple_num)) 32 | print("dOrange:", dorange) 33 | print("dOrange_num:", int(dorange_num)) 34 | print("dTax:", dtax) 35 | -------------------------------------------------------------------------------- /ch05/gradient_check.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | import numpy as np 5 | from dataset.mnist import load_mnist 6 | from two_layer_net import TwoLayerNet 7 | 8 | # 데이터 읽기 9 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) 10 | 11 | network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) 12 | 13 | x_batch = x_train[:3] 14 | t_batch = t_train[:3] 15 | 16 | grad_numerical = network.numerical_gradient(x_batch, t_batch) 17 | grad_backprop = network.gradient(x_batch, t_batch) 18 | 19 | # 각 가중치의 절대 오차의 평균을 구한다. 20 | for key in grad_numerical.keys(): 21 | diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) ) 22 | print(key + ":" + str(diff)) 23 | -------------------------------------------------------------------------------- /ch05/layer_naive.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | class MulLayer: 5 | def __init__(self): 6 | self.x = None 7 | self.y = None 8 | 9 | def forward(self, x, y): 10 | self.x = x 11 | self.y = y 12 | out = x * y 13 | 14 | return out 15 | 16 | def backward(self, dout): 17 | dx = dout * self.y # x와 y를 바꾼다. 18 | dy = dout * self.x 19 | 20 | return dx, dy 21 | 22 | 23 | class AddLayer: 24 | def __init__(self): 25 | pass 26 | 27 | def forward(self, x, y): 28 | out = x + y 29 | 30 | return out 31 | 32 | def backward(self, dout): 33 | dx = dout * 1 34 | dy = dout * 1 35 | 36 | return dx, dy 37 | -------------------------------------------------------------------------------- /ch05/train_neuralnet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | from dataset.mnist import load_mnist 7 | from two_layer_net import TwoLayerNet 8 | 9 | # 데이터 읽기 10 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) 11 | 12 | network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) 13 | 14 | iters_num = 10000 15 | train_size = x_train.shape[0] 16 | batch_size = 100 17 | learning_rate = 0.1 18 | 19 | train_loss_list = [] 20 | train_acc_list = [] 21 | test_acc_list = [] 22 | 23 | iter_per_epoch = max(train_size / batch_size, 1) 24 | 25 | for i in range(iters_num): 26 | batch_mask = np.random.choice(train_size, batch_size) 27 | x_batch = x_train[batch_mask] 28 | t_batch = t_train[batch_mask] 29 | 30 | # 기울기 계산 31 | #grad = network.numerical_gradient(x_batch, t_batch) # 수치 미분 방식 32 | grad = network.gradient(x_batch, t_batch) # 오차역전파법 방식(훨씬 빠르다) 33 | 34 | # 갱신 35 | for key in ('W1', 'b1', 'W2', 'b2'): 36 | network.params[key] -= learning_rate * grad[key] 37 | 38 | loss = network.loss(x_batch, t_batch) 39 | train_loss_list.append(loss) 40 | 41 | if i % iter_per_epoch == 0: 42 | train_acc = network.accuracy(x_train, t_train) 43 | test_acc = network.accuracy(x_test, t_test) 44 | train_acc_list.append(train_acc) 45 | test_acc_list.append(test_acc) 46 | print(train_acc, test_acc) 47 | -------------------------------------------------------------------------------- /ch05/two_layer_net.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | import numpy as np 5 | from common.layers import * 6 | from common.gradient import numerical_gradient 7 | from collections import OrderedDict 8 | 9 | 10 | class TwoLayerNet: 11 | 12 | def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01): 13 | # 가중치 초기화 14 | self.params = {} 15 | self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size) 16 | self.params['b1'] = np.zeros(hidden_size) 17 | self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) 18 | self.params['b2'] = np.zeros(output_size) 19 | 20 | # 계층 생성 21 | self.layers = OrderedDict() 22 | self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1']) 23 | self.layers['Relu1'] = Relu() 24 | self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2']) 25 | 26 | self.lastLayer = SoftmaxWithLoss() 27 | 28 | def predict(self, x): 29 | for layer in self.layers.values(): 30 | x = layer.forward(x) 31 | 32 | return x 33 | 34 | # x : 입력 데이터, t : 정답 레이블 35 | def loss(self, x, t): 36 | y = self.predict(x) 37 | return self.lastLayer.forward(y, t) 38 | 39 | def accuracy(self, x, t): 40 | y = self.predict(x) 41 | y = np.argmax(y, axis=1) 42 | if t.ndim != 1 : t = np.argmax(t, axis=1) 43 | 44 | accuracy = np.sum(y == t) / float(x.shape[0]) 45 | return accuracy 46 | 47 | # x : 입력 데이터, t : 정답 레이블 48 | def numerical_gradient(self, x, t): 49 | loss_W = lambda W: self.loss(x, t) 50 | 51 | grads = {} 52 | grads['W1'] = numerical_gradient(loss_W, self.params['W1']) 53 | grads['b1'] = numerical_gradient(loss_W, self.params['b1']) 54 | grads['W2'] = numerical_gradient(loss_W, self.params['W2']) 55 | grads['b2'] = numerical_gradient(loss_W, self.params['b2']) 56 | 57 | return grads 58 | 59 | def gradient(self, x, t): 60 | # forward 61 | self.loss(x, t) 62 | 63 | # backward 64 | dout = 1 65 | dout = self.lastLayer.backward(dout) 66 | 67 | layers = list(self.layers.values()) 68 | layers.reverse() 69 | for layer in layers: 70 | dout = layer.backward(dout) 71 | 72 | # 결과 저장 73 | grads = {} 74 | grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db 75 | grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db 76 | 77 | return grads 78 | -------------------------------------------------------------------------------- /ch06/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | batch_norm_gradient_check.py | 배치 정규화를 구현한 신경망의 오차역전파법 방식의 기울기 계산이 정확한지 확인합니다(기울기 확인). | | | 5 | | batch_norm_test.py | MNIST 데이터셋 학습에 배치 정규화를 적용해봅니다. | 6.3.2 배치 정규화의 효과 | 212 | 6 | | hyperparameter_optimization.py | 무작위로 추출한 값부터 시작하여 두 하이퍼파라미터(가중치 감소 계수, 학습률)를 최적화해봅니다. | 6.5.3 하이퍼파라미터 최적화 구현하기 | 224 | 7 | | optimizer_compare_mnist.py | SGD, 모멘텀, AdaGrad, Adam의 학습 속도를 비교합니다. | 6.1.8 MNIST 데이터셋으로 본 갱신 방법 비교 | 201 | 8 | | optimizer_compare_naive.py | SGD, 모멘텀, AdaGrad, Adam의 학습 패턴을 비교합니다. | 6.1.7 어느 갱신 방법을 이용할 것인가? | 200 | 9 | | overfit_dropout.py | 일부러 오버피팅을 일으킨 후 드롭아웃(dropout)의 효과를 관찰합니다. | 6.4.3 드롭아웃 | 219 | 10 | | overfit_weight_decay.py | 일부러 오버피팅을 일으킨 후 가중치 감소(weight_decay)의 효과를 관찰합니다. | 6.4.1 오버피팅 | 215 | 11 | | weight_init_activation_histogram.py | 활성화 함수로 시그모이드 함수를 사용하는 5층 신경망에 무작위로 생성한 입력 데이터를 흘리며 각 층의 활성화값 분포를 히스토그램으로 그려봅니다. | 6.2.2 은닉층의 활성화값 분포 | 203 | 12 | | weight_init_compare.py | 가중치 초깃값(std=0.01, He, Xavier)에 따른 학습 속도를 비교합니다. | 6.2.4 MNIST 데이터셋으로 본 가중치 초깃값 비교 | 209 | 13 | 14 | ## 6장 학습 관련 기술들 15 | 이번 장에서는 신경망 학습의 핵심 개념들을 만나봅니다. 이번 장에서 다룰 주제는 가중치 매개변수의 최적값을 탐색하는 최적화 방법, 가중치 매개변수 초깃값, 하이퍼파라미터 설정 방법 등, 모두가 신경망 학습에서 중요한 주제입니다. 오버피팅의 대응책인 가중치 감소와 드롭아웃 등의 정규화 방법도 간략히 설명하고 구현해봅니다. 마지막으로 최근 많은 연구에서 사용하는 배치 정규화도 짧게 알아봅니다. 이번 장에서 설명하는 기법을 이용하면 신경망(딥러닝) 학습의 효율과 정확도를 높일 수 있습니다. 그럼 본론으로 들어가 볼까요? 16 | 17 | ## 목차 18 | ``` 19 | 6.1 매개변수 갱신 20 | __6.1.1 모험가 이야기 21 | __6.1.2 확률적 경사 하강법(SGD) 22 | __6.1.3 SGD의 단점 23 | __6.1.4 모멘텀 24 | __6.1.5 AdaGrad 25 | __6.1.6 Adam 26 | __6.1.7 어느 갱신 방법을 이용할 것인가? 27 | __6.1.8 MNIST 데이터셋으로 본 갱신 방법 비교 28 | 6.2 가중치의 초깃값 29 | __6.2.1 초깃값을 0으로 하면? 30 | __6.2.2 은닉층의 활성화 분포 31 | __6.2.3 ReLU를 사용할 때의 가중치 초깃값 32 | __6.2.4 MNIST 데이터셋으로 본 가중치 초깃값 비교 33 | 6.3 배치 정규화 34 | __6.3.1 배치 정규화 알고리즘 35 | __6.3.2 배치 정규화의 효과 36 | 6.4 바른 학습을 위해 37 | __6.4.1 오버피팅 38 | __6.4.2 가중치 감소 39 | __6.4.3 드롭아웃 40 | 6.5 적절한 하이퍼파라미터 값 찾기 41 | __6.5.1 검증 데이터 42 | __6.5.2 하이퍼파라미터 최적화 43 | __6.5.3 하이퍼파라미터 최적화 구현하기 44 | ``` 45 | 46 | ## 이번 장에서 배운 내용 47 | * 매개변수 갱신 방법에는 확률적 경사 하강법(SGD) 외에도 모멘텀, AdaGrad, Adam 등이 있다. 48 | * 가중치 초깃값을 정하는 방법은 올바른 학습을 하는 데 매우 중요하다. 49 | * 가중치의 초깃값으로는 ‘Xavier 초깃값’과 ‘He 초깃값’이 효과적이다. 50 | * 배치 정규화를 이용하면 학습을 빠르게 진행할 수 있으며, 초깃값에 영향을 덜 받게 된다. 51 | * 오버피팅을 억제하는 정규화 기술로는 가중치 감소와 드롭아웃이 있다. 52 | * 하이퍼파라미터 값 탐색은 최적 값이 존재할 법한 범위를 점차 좁히면서 하는 것이 효과적이다. 53 | -------------------------------------------------------------------------------- /ch06/batch_norm_gradient_check.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | from dataset.mnist import load_mnist 7 | from common.multi_layer_net_extend import MultiLayerNetExtend 8 | 9 | # 데이터 읽기 10 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) 11 | 12 | network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100], output_size=10, 13 | use_batchnorm=True) 14 | 15 | x_batch = x_train[:1] 16 | t_batch = t_train[:1] 17 | 18 | grad_backprop = network.gradient(x_batch, t_batch) 19 | grad_numerical = network.numerical_gradient(x_batch, t_batch) 20 | 21 | 22 | for key in grad_numerical.keys(): 23 | diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) ) 24 | print(key + ":" + str(diff)) 25 | -------------------------------------------------------------------------------- /ch06/batch_norm_test.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.multi_layer_net_extend import MultiLayerNetExtend 9 | from common.optimizer import SGD, Adam 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 12 | 13 | # 학습 데이터를 줄임 14 | x_train = x_train[:1000] 15 | t_train = t_train[:1000] 16 | 17 | max_epochs = 20 18 | train_size = x_train.shape[0] 19 | batch_size = 100 20 | learning_rate = 0.01 21 | 22 | 23 | def __train(weight_init_std): 24 | bn_network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10, 25 | weight_init_std=weight_init_std, use_batchnorm=True) 26 | network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10, 27 | weight_init_std=weight_init_std) 28 | optimizer = SGD(lr=learning_rate) 29 | 30 | train_acc_list = [] 31 | bn_train_acc_list = [] 32 | 33 | iter_per_epoch = max(train_size / batch_size, 1) 34 | epoch_cnt = 0 35 | 36 | for i in range(1000000000): 37 | batch_mask = np.random.choice(train_size, batch_size) 38 | x_batch = x_train[batch_mask] 39 | t_batch = t_train[batch_mask] 40 | 41 | for _network in (bn_network, network): 42 | grads = _network.gradient(x_batch, t_batch) 43 | optimizer.update(_network.params, grads) 44 | 45 | if i % iter_per_epoch == 0: 46 | train_acc = network.accuracy(x_train, t_train) 47 | bn_train_acc = bn_network.accuracy(x_train, t_train) 48 | train_acc_list.append(train_acc) 49 | bn_train_acc_list.append(bn_train_acc) 50 | 51 | print("epoch:" + str(epoch_cnt) + " | " + str(train_acc) + " - " + str(bn_train_acc)) 52 | 53 | epoch_cnt += 1 54 | if epoch_cnt >= max_epochs: 55 | break 56 | 57 | return train_acc_list, bn_train_acc_list 58 | 59 | 60 | # 그래프 그리기========== 61 | weight_scale_list = np.logspace(0, -4, num=16) 62 | x = np.arange(max_epochs) 63 | 64 | train_acc_list, bn_train_acc_list = __train(weight_scale_list[4]) 65 | 66 | plt.title("Training Accuracy") 67 | plt.plot(x, bn_train_acc_list, label='Batch Normalization', markevery=2) 68 | plt.plot(x, train_acc_list, linestyle = "--", label='Normal(without BatchNorm)', markevery=2) 69 | plt.ylim(0, 1.0) 70 | plt.xlim(0, max_epochs) 71 | plt.ylabel("accuracy") 72 | plt.xlabel("epochs") 73 | plt.legend(loc='lower right') 74 | 75 | plt.show() 76 | -------------------------------------------------------------------------------- /ch06/batch_norm_test_multi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.multi_layer_net_extend import MultiLayerNetExtend 9 | from common.optimizer import SGD, Adam 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 12 | 13 | # 학습 데이터를 줄임 14 | x_train = x_train[:1000] 15 | t_train = t_train[:1000] 16 | 17 | max_epochs = 20 18 | train_size = x_train.shape[0] 19 | batch_size = 100 20 | learning_rate = 0.01 21 | 22 | 23 | def __train(weight_init_std): 24 | bn_network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10, 25 | weight_init_std=weight_init_std, use_batchnorm=True) 26 | network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10, 27 | weight_init_std=weight_init_std) 28 | optimizer = SGD(lr=learning_rate) 29 | 30 | train_acc_list = [] 31 | bn_train_acc_list = [] 32 | 33 | iter_per_epoch = max(train_size / batch_size, 1) 34 | epoch_cnt = 0 35 | 36 | for i in range(1000000000): 37 | batch_mask = np.random.choice(train_size, batch_size) 38 | x_batch = x_train[batch_mask] 39 | t_batch = t_train[batch_mask] 40 | 41 | for _network in (bn_network, network): 42 | grads = _network.gradient(x_batch, t_batch) 43 | optimizer.update(_network.params, grads) 44 | 45 | if i % iter_per_epoch == 0: 46 | train_acc = network.accuracy(x_train, t_train) 47 | bn_train_acc = bn_network.accuracy(x_train, t_train) 48 | train_acc_list.append(train_acc) 49 | bn_train_acc_list.append(bn_train_acc) 50 | 51 | print("epoch:" + str(epoch_cnt) + " | " + str(train_acc) + " - " + str(bn_train_acc)) 52 | 53 | epoch_cnt += 1 54 | if epoch_cnt >= max_epochs: 55 | break 56 | 57 | return train_acc_list, bn_train_acc_list 58 | 59 | 60 | # 그래프 그리기========== 61 | weight_scale_list = np.logspace(0, -4, num=16) 62 | x = np.arange(max_epochs) 63 | 64 | plt.figure(figsize=(8, 8)) 65 | 66 | for i, w in enumerate(weight_scale_list): 67 | print( "============== " + str(i+1) + "/16" + " ==============") 68 | train_acc_list, bn_train_acc_list = __train(w) 69 | 70 | plt.subplot(4,4,i+1) 71 | plt.title("W:" + str(w), fontsize=6.5) 72 | plt.plot(x, bn_train_acc_list, markevery=2) 73 | plt.plot(x, train_acc_list, linestyle="--", markevery=2) 74 | 75 | plt.ylim(0, 1.0) 76 | if i % 4: 77 | plt.yticks([]) 78 | else: 79 | plt.ylabel("accuracy", fontsize=6.5) 80 | if i < 12: 81 | plt.xticks([]) 82 | else: 83 | plt.xlabel("epochs", fontsize=6.5) 84 | 85 | plt.subplots_adjust(wspace=0.2, hspace=0.3) 86 | plt.show() 87 | -------------------------------------------------------------------------------- /ch06/hyperparameter_optimization.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.multi_layer_net import MultiLayerNet 9 | from common.util import shuffle_dataset 10 | from common.trainer import Trainer 11 | 12 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 13 | 14 | # 결과를 빠르게 얻기 위해 훈련 데이터를 줄임 15 | x_train = x_train[:500] 16 | t_train = t_train[:500] 17 | 18 | # 20%를 검증 데이터로 분할 19 | validation_rate = 0.20 20 | validation_num = int(x_train.shape[0] * validation_rate) 21 | x_train, t_train = shuffle_dataset(x_train, t_train) 22 | x_val = x_train[:validation_num] 23 | t_val = t_train[:validation_num] 24 | x_train = x_train[validation_num:] 25 | t_train = t_train[validation_num:] 26 | 27 | 28 | def __train(lr, weight_decay, epocs=50): 29 | network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], 30 | output_size=10, weight_decay_lambda=weight_decay) 31 | trainer = Trainer(network, x_train, t_train, x_val, t_val, 32 | epochs=epocs, mini_batch_size=100, 33 | optimizer='sgd', optimizer_param={'lr': lr}, verbose=False) 34 | trainer.train() 35 | 36 | return trainer.test_acc_list, trainer.train_acc_list 37 | 38 | 39 | # 하이퍼파라미터 무작위 탐색====================================== 40 | optimization_trial = 100 41 | results_val = {} 42 | results_train = {} 43 | for _ in range(optimization_trial): 44 | # 탐색한 하이퍼파라미터의 범위 지정=============== 45 | weight_decay = 10 ** np.random.uniform(-8, -4) 46 | lr = 10 ** np.random.uniform(-6, -2) 47 | # ================================================ 48 | 49 | val_acc_list, train_acc_list = __train(lr, weight_decay) 50 | print("val acc:" + str(val_acc_list[-1]) + " | lr:" + str(lr) + ", weight decay:" + str(weight_decay)) 51 | key = "lr:" + str(lr) + ", weight decay:" + str(weight_decay) 52 | results_val[key] = val_acc_list 53 | results_train[key] = train_acc_list 54 | 55 | # 그래프 그리기======================================================== 56 | print("=========== Hyper-Parameter Optimization Result ===========") 57 | graph_draw_num = 20 58 | col_num = 5 59 | row_num = int(np.ceil(graph_draw_num / col_num)) 60 | i = 0 61 | 62 | plt.figure(figsize=(10, 8)) 63 | 64 | for key, val_acc_list in sorted(results_val.items(), key=lambda x:x[1][-1], reverse=True): 65 | print("Best-" + str(i+1) + "(val acc:" + str(val_acc_list[-1]) + ") | " + key) 66 | 67 | plt.subplot(row_num, col_num, i+1) 68 | plt.title("Best-" + str(i+1)) 69 | plt.ylim(0.0, 1.0) 70 | if i % 5: plt.yticks([]) 71 | plt.xticks([]) 72 | x = np.arange(len(val_acc_list)) 73 | plt.plot(x, val_acc_list) 74 | plt.plot(x, results_train[key], "--") 75 | i += 1 76 | 77 | if i >= graph_draw_num: 78 | break 79 | 80 | plt.subplots_adjust(wspace=0.2, hspace=0.3) 81 | plt.show() 82 | -------------------------------------------------------------------------------- /ch06/optimizer_compare_mnist.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import matplotlib.pyplot as plt 6 | from dataset.mnist import load_mnist 7 | from common.util import smooth_curve 8 | from common.multi_layer_net import MultiLayerNet 9 | from common.optimizer import * 10 | 11 | 12 | # 0. MNIST 데이터 읽기========== 13 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 14 | 15 | train_size = x_train.shape[0] 16 | batch_size = 128 17 | max_iterations = 2000 18 | 19 | 20 | # 1. 실험용 설정========== 21 | optimizers = {} 22 | optimizers['SGD'] = SGD() 23 | optimizers['Momentum'] = Momentum() 24 | optimizers['AdaGrad'] = AdaGrad() 25 | optimizers['Adam'] = Adam() 26 | #optimizers['RMSprop'] = RMSprop() 27 | 28 | networks = {} 29 | train_loss = {} 30 | for key in optimizers.keys(): 31 | networks[key] = MultiLayerNet( 32 | input_size=784, hidden_size_list=[100, 100, 100, 100], 33 | output_size=10) 34 | train_loss[key] = [] 35 | 36 | 37 | # 2. 훈련 시작========== 38 | for i in range(max_iterations): 39 | batch_mask = np.random.choice(train_size, batch_size) 40 | x_batch = x_train[batch_mask] 41 | t_batch = t_train[batch_mask] 42 | 43 | for key in optimizers.keys(): 44 | grads = networks[key].gradient(x_batch, t_batch) 45 | optimizers[key].update(networks[key].params, grads) 46 | 47 | loss = networks[key].loss(x_batch, t_batch) 48 | train_loss[key].append(loss) 49 | 50 | if i % 100 == 0: 51 | print( "===========" + "iteration:" + str(i) + "===========") 52 | for key in optimizers.keys(): 53 | loss = networks[key].loss(x_batch, t_batch) 54 | print(key + ":" + str(loss)) 55 | 56 | 57 | # 3. 그래프 그리기========== 58 | markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"} 59 | x = np.arange(max_iterations) 60 | for key in optimizers.keys(): 61 | plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key) 62 | plt.xlabel("iterations") 63 | plt.ylabel("loss") 64 | plt.ylim(0, 1) 65 | plt.legend() 66 | plt.show() 67 | -------------------------------------------------------------------------------- /ch06/optimizer_compare_naive.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from collections import OrderedDict 8 | from common.optimizer import * 9 | 10 | 11 | def f(x, y): 12 | return x**2 / 20.0 + y**2 13 | 14 | 15 | def df(x, y): 16 | return x / 10.0, 2.0*y 17 | 18 | init_pos = (-7.0, 2.0) 19 | params = {} 20 | params['x'], params['y'] = init_pos[0], init_pos[1] 21 | grads = {} 22 | grads['x'], grads['y'] = 0, 0 23 | 24 | 25 | optimizers = OrderedDict() 26 | optimizers["SGD"] = SGD(lr=0.95) 27 | optimizers["Momentum"] = Momentum(lr=0.1) 28 | optimizers["AdaGrad"] = AdaGrad(lr=1.5) 29 | optimizers["Adam"] = Adam(lr=0.3) 30 | 31 | plt.figure(figsize=(12, 8)) 32 | 33 | idx = 1 34 | 35 | for key in optimizers: 36 | optimizer = optimizers[key] 37 | x_history = [] 38 | y_history = [] 39 | params['x'], params['y'] = init_pos[0], init_pos[1] 40 | 41 | for i in range(30): 42 | x_history.append(params['x']) 43 | y_history.append(params['y']) 44 | 45 | grads['x'], grads['y'] = df(params['x'], params['y']) 46 | optimizer.update(params, grads) 47 | 48 | 49 | x = np.arange(-10, 10, 0.01) 50 | y = np.arange(-5, 5, 0.01) 51 | 52 | X, Y = np.meshgrid(x, y) 53 | Z = f(X, Y) 54 | 55 | # 외곽선 단순화 56 | mask = Z > 7 57 | Z[mask] = 0 58 | 59 | # 그래프 그리기 60 | plt.subplot(2, 2, idx) 61 | idx += 1 62 | plt.plot(x_history, y_history, 'o-', color="red") 63 | plt.contour(X, Y, Z) 64 | plt.ylim(-10, 10) 65 | plt.xlim(-10, 10) 66 | plt.plot(0, 0, '+') 67 | plt.title(key) 68 | plt.xlabel("x") 69 | plt.ylabel("y") 70 | 71 | plt.subplots_adjust(wspace=0.3, hspace=0.4) 72 | plt.show() 73 | -------------------------------------------------------------------------------- /ch06/overfit.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.multi_layer_net import MultiLayerNet 9 | from common.optimizer import SGD 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 12 | 13 | # 과대적합을 재현하기 위해 학습 데이터 수를 줄임 14 | x_train = x_train[:300] 15 | t_train = t_train[:300] 16 | 17 | network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10) 18 | optimizer = SGD(lr=0.01) # 학습률이 0.01인 SGD로 매개변수 갱신 19 | 20 | max_epochs = 201 21 | train_size = x_train.shape[0] 22 | batch_size = 100 23 | 24 | train_loss_list = [] 25 | train_acc_list = [] 26 | test_acc_list = [] 27 | 28 | iter_per_epoch = max(train_size / batch_size, 1) 29 | epoch_cnt = 0 30 | 31 | for i in range(1000000000): 32 | batch_mask = np.random.choice(train_size, batch_size) 33 | x_batch = x_train[batch_mask] 34 | t_batch = t_train[batch_mask] 35 | 36 | grads = network.gradient(x_batch, t_batch) 37 | optimizer.update(network.params, grads) 38 | 39 | if i % iter_per_epoch == 0: 40 | train_acc = network.accuracy(x_train, t_train) 41 | test_acc = network.accuracy(x_test, t_test) 42 | train_acc_list.append(train_acc) 43 | test_acc_list.append(test_acc) 44 | 45 | print("epoch:" + str(epoch_cnt) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc)) 46 | 47 | epoch_cnt += 1 48 | if epoch_cnt >= max_epochs: 49 | break 50 | 51 | 52 | # 그래프 그리기========== 53 | markers = {'train': 'o', 'test': 's'} 54 | x = np.arange(max_epochs) 55 | plt.plot(x, train_acc_list, marker='o', label='train', markevery=10) 56 | plt.plot(x, test_acc_list, marker='s', label='test', markevery=10) 57 | plt.xlabel("epochs") 58 | plt.ylabel("accuracy") 59 | plt.ylim(0, 1.0) 60 | plt.legend(loc='lower right') 61 | plt.show() 62 | -------------------------------------------------------------------------------- /ch06/overfit_dropout.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.multi_layer_net_extend import MultiLayerNetExtend 9 | from common.trainer import Trainer 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 12 | 13 | # 오버피팅을 재현하기 위해 학습 데이터 수를 줄임 14 | x_train = x_train[:300] 15 | t_train = t_train[:300] 16 | 17 | # 드롭아웃 사용 유무와 비율 설정 ======================== 18 | use_dropout = True # 드롭아웃을 쓰지 않을 때는 False 19 | dropout_ratio = 0.2 20 | # ==================================================== 21 | 22 | network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], 23 | output_size=10, use_dropout=use_dropout, dropout_ration=dropout_ratio) 24 | trainer = Trainer(network, x_train, t_train, x_test, t_test, 25 | epochs=301, mini_batch_size=100, 26 | optimizer='sgd', optimizer_param={'lr': 0.01}, verbose=True) 27 | trainer.train() 28 | 29 | train_acc_list, test_acc_list = trainer.train_acc_list, trainer.test_acc_list 30 | 31 | # 그래프 그리기========== 32 | markers = {'train': 'o', 'test': 's'} 33 | x = np.arange(len(train_acc_list)) 34 | plt.plot(x, train_acc_list, marker='o', label='train', markevery=10) 35 | plt.plot(x, test_acc_list, marker='s', label='test', markevery=10) 36 | plt.xlabel("epochs") 37 | plt.ylabel("accuracy") 38 | plt.ylim(0, 1.0) 39 | plt.legend(loc='lower right') 40 | plt.show() 41 | -------------------------------------------------------------------------------- /ch06/overfit_weight_decay.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.multi_layer_net import MultiLayerNet 9 | from common.optimizer import SGD 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 12 | 13 | # 과대적합을 재현하기 위해 학습 데이터 수를 줄임 14 | x_train = x_train[:300] 15 | t_train = t_train[:300] 16 | 17 | weight_decay_lambda = 0.1 # 가중치 감쇠 설정 18 | 19 | network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10, 20 | weight_decay_lambda=weight_decay_lambda) 21 | optimizer = SGD(lr=0.01) # 학습률이 0.01인 SGD로 매개변수 갱신 22 | 23 | max_epochs = 201 24 | train_size = x_train.shape[0] 25 | batch_size = 100 26 | 27 | train_loss_list = [] 28 | train_acc_list = [] 29 | test_acc_list = [] 30 | 31 | iter_per_epoch = max(train_size / batch_size, 1) 32 | epoch_cnt = 0 33 | 34 | for i in range(1000000000): 35 | batch_mask = np.random.choice(train_size, batch_size) 36 | x_batch = x_train[batch_mask] 37 | t_batch = t_train[batch_mask] 38 | 39 | grads = network.gradient(x_batch, t_batch) 40 | optimizer.update(network.params, grads) 41 | 42 | if i % iter_per_epoch == 0: 43 | train_acc = network.accuracy(x_train, t_train) 44 | test_acc = network.accuracy(x_test, t_test) 45 | train_acc_list.append(train_acc) 46 | test_acc_list.append(test_acc) 47 | 48 | print("epoch:" + str(epoch_cnt) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc)) 49 | 50 | epoch_cnt += 1 51 | if epoch_cnt >= max_epochs: 52 | break 53 | 54 | 55 | # 그래프 그리기========== 56 | markers = {'train': 'o', 'test': 's'} 57 | x = np.arange(max_epochs) 58 | plt.plot(x, train_acc_list, marker='o', label='train', markevery=10) 59 | plt.plot(x, test_acc_list, marker='s', label='test', markevery=10) 60 | plt.xlabel("epochs") 61 | plt.ylabel("accuracy") 62 | plt.ylim(0, 1.0) 63 | plt.legend(loc='lower right') 64 | plt.show() 65 | -------------------------------------------------------------------------------- /ch06/show_optimizer_adagrad.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from collections import OrderedDict 8 | from common.optimizer import * 9 | 10 | 11 | def f(x, y): 12 | return x**2 / 20.0 + y**2 13 | 14 | 15 | def df(x, y): 16 | return x / 10.0, 2.0*y 17 | 18 | init_pos = (-7.0, 2.0) 19 | params = {} 20 | params['x'], params['y'] = init_pos[0], init_pos[1] 21 | grads = {} 22 | grads['x'], grads['y'] = 0, 0 23 | 24 | 25 | optimizers = OrderedDict() 26 | optimizers["AdaGrad"] = AdaGrad(lr=1.5) 27 | 28 | idx = 1 29 | 30 | for key in optimizers: 31 | optimizer = optimizers[key] 32 | x_history = [] 33 | y_history = [] 34 | params['x'], params['y'] = init_pos[0], init_pos[1] 35 | 36 | for i in range(30): 37 | x_history.append(params['x']) 38 | y_history.append(params['y']) 39 | 40 | grads['x'], grads['y'] = df(params['x'], params['y']) 41 | optimizer.update(params, grads) 42 | 43 | 44 | x = np.arange(-10, 10, 0.01) 45 | y = np.arange(-5, 5, 0.01) 46 | 47 | X, Y = np.meshgrid(x, y) 48 | Z = f(X, Y) 49 | 50 | # 외곽선 단순화 51 | mask = Z > 7 52 | Z[mask] = 0 53 | 54 | # 그래프 그리기 55 | plt.subplot(1, 1, idx) 56 | idx += 1 57 | plt.plot(x_history, y_history, 'o-', color="red") 58 | plt.contour(X, Y, Z) 59 | plt.ylim(-10, 10) 60 | plt.xlim(-10, 10) 61 | plt.plot(0, 0, '+') 62 | plt.title(key) 63 | plt.xlabel("x") 64 | plt.ylabel("y") 65 | 66 | plt.show() 67 | -------------------------------------------------------------------------------- /ch06/show_optimizer_adam.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from collections import OrderedDict 8 | from common.optimizer import * 9 | 10 | 11 | def f(x, y): 12 | return x**2 / 20.0 + y**2 13 | 14 | 15 | def df(x, y): 16 | return x / 10.0, 2.0*y 17 | 18 | init_pos = (-7.0, 2.0) 19 | params = {} 20 | params['x'], params['y'] = init_pos[0], init_pos[1] 21 | grads = {} 22 | grads['x'], grads['y'] = 0, 0 23 | 24 | 25 | optimizers = OrderedDict() 26 | optimizers["Adam"] = Adam(lr=0.3) 27 | 28 | idx = 1 29 | 30 | for key in optimizers: 31 | optimizer = optimizers[key] 32 | x_history = [] 33 | y_history = [] 34 | params['x'], params['y'] = init_pos[0], init_pos[1] 35 | 36 | for i in range(30): 37 | x_history.append(params['x']) 38 | y_history.append(params['y']) 39 | 40 | grads['x'], grads['y'] = df(params['x'], params['y']) 41 | optimizer.update(params, grads) 42 | 43 | 44 | x = np.arange(-10, 10, 0.01) 45 | y = np.arange(-5, 5, 0.01) 46 | 47 | X, Y = np.meshgrid(x, y) 48 | Z = f(X, Y) 49 | 50 | # 외곽선 단순화 51 | mask = Z > 7 52 | Z[mask] = 0 53 | 54 | # 그래프 그리기 55 | plt.subplot(1, 1, idx) 56 | idx += 1 57 | plt.plot(x_history, y_history, 'o-', color="red") 58 | plt.contour(X, Y, Z) 59 | plt.ylim(-10, 10) 60 | plt.xlim(-10, 10) 61 | plt.plot(0, 0, '+') 62 | plt.title(key) 63 | plt.xlabel("x") 64 | plt.ylabel("y") 65 | 66 | plt.show() 67 | -------------------------------------------------------------------------------- /ch06/show_optimizer_momentum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from collections import OrderedDict 8 | from common.optimizer import * 9 | 10 | 11 | def f(x, y): 12 | return x**2 / 20.0 + y**2 13 | 14 | 15 | def df(x, y): 16 | return x / 10.0, 2.0*y 17 | 18 | init_pos = (-7.0, 2.0) 19 | params = {} 20 | params['x'], params['y'] = init_pos[0], init_pos[1] 21 | grads = {} 22 | grads['x'], grads['y'] = 0, 0 23 | 24 | 25 | optimizers = OrderedDict() 26 | optimizers["Momentum"] = Momentum(lr=0.1) 27 | 28 | idx = 1 29 | 30 | for key in optimizers: 31 | optimizer = optimizers[key] 32 | x_history = [] 33 | y_history = [] 34 | params['x'], params['y'] = init_pos[0], init_pos[1] 35 | 36 | for i in range(30): 37 | x_history.append(params['x']) 38 | y_history.append(params['y']) 39 | 40 | grads['x'], grads['y'] = df(params['x'], params['y']) 41 | optimizer.update(params, grads) 42 | 43 | 44 | x = np.arange(-10, 10, 0.01) 45 | y = np.arange(-5, 5, 0.01) 46 | 47 | X, Y = np.meshgrid(x, y) 48 | Z = f(X, Y) 49 | 50 | # 외곽선 단순화 51 | mask = Z > 7 52 | Z[mask] = 0 53 | 54 | # 그래프 그리기 55 | plt.subplot(1, 1, idx) 56 | idx += 1 57 | plt.plot(x_history, y_history, 'o-', color="red") 58 | plt.contour(X, Y, Z) 59 | plt.ylim(-10, 10) 60 | plt.xlim(-10, 10) 61 | plt.plot(0, 0, '+') 62 | plt.title(key) 63 | plt.xlabel("x") 64 | plt.ylabel("y") 65 | 66 | plt.show() 67 | -------------------------------------------------------------------------------- /ch06/show_optimizer_sgd.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from collections import OrderedDict 8 | from common.optimizer import * 9 | 10 | 11 | def f(x, y): 12 | return x**2 / 20.0 + y**2 13 | 14 | 15 | def df(x, y): 16 | return x / 10.0, 2.0*y 17 | 18 | init_pos = (-7.0, 2.0) 19 | params = {} 20 | params['x'], params['y'] = init_pos[0], init_pos[1] 21 | grads = {} 22 | grads['x'], grads['y'] = 0, 0 23 | 24 | 25 | optimizers = OrderedDict() 26 | optimizers["SGD"] = SGD(lr=0.95) 27 | 28 | idx = 1 29 | 30 | for key in optimizers: 31 | optimizer = optimizers[key] 32 | x_history = [] 33 | y_history = [] 34 | params['x'], params['y'] = init_pos[0], init_pos[1] 35 | 36 | for i in range(30): 37 | x_history.append(params['x']) 38 | y_history.append(params['y']) 39 | 40 | grads['x'], grads['y'] = df(params['x'], params['y']) 41 | optimizer.update(params, grads) 42 | 43 | 44 | x = np.arange(-10, 10, 0.01) 45 | y = np.arange(-5, 5, 0.01) 46 | 47 | X, Y = np.meshgrid(x, y) 48 | Z = f(X, Y) 49 | 50 | # 외곽선 단순화 51 | mask = Z > 7 52 | Z[mask] = 0 53 | 54 | # 그래프 그리기 55 | plt.subplot(1, 1, idx) 56 | idx += 1 57 | plt.plot(x_history, y_history, 'o-', color="red") 58 | plt.contour(X, Y, Z) 59 | plt.ylim(-10, 10) 60 | plt.xlim(-10, 10) 61 | plt.plot(0, 0, '+') 62 | plt.title(key) 63 | plt.xlabel("x") 64 | plt.ylabel("y") 65 | 66 | plt.show() 67 | -------------------------------------------------------------------------------- /ch06/weight_init_activation_histogram.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | def sigmoid(x): 7 | return 1 / (1 + np.exp(-x)) 8 | 9 | 10 | def ReLU(x): 11 | return np.maximum(0, x) 12 | 13 | 14 | def tanh(x): 15 | return np.tanh(x) 16 | 17 | input_data = np.random.randn(1000, 100) # 1000개의 데이터 18 | node_num = 100 # 각 은닉층의 노드(뉴런) 수 19 | hidden_layer_size = 5 # 은닉층이 5개 20 | activations = {} # 이곳에 활성화 결과를 저장 21 | 22 | x = input_data 23 | 24 | for i in range(hidden_layer_size): 25 | if i != 0: 26 | x = activations[i-1] 27 | 28 | # 초깃값을 다양하게 바꿔가며 실험해보자! 29 | w = np.random.randn(node_num, node_num) * 1 30 | # w = np.random.randn(node_num, node_num) * 0.01 31 | # w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num) 32 | # w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num) 33 | 34 | 35 | a = np.dot(x, w) 36 | 37 | 38 | # 활성화 함수도 바꿔가며 실험해보자! 39 | z = sigmoid(a) 40 | # z = ReLU(a) 41 | # z = tanh(a) 42 | 43 | activations[i] = z 44 | 45 | # 히스토그램 그리기 46 | for i, a in activations.items(): 47 | plt.subplot(1, len(activations), i+1) 48 | plt.title(str(i+1) + "-layer") 49 | if i != 0: plt.yticks([], []) 50 | # plt.xlim(0.1, 1) 51 | # plt.ylim(0, 7000) 52 | plt.hist(a.flatten(), 30, range=(0,1)) 53 | plt.show() 54 | -------------------------------------------------------------------------------- /ch06/weight_init_compare.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from common.util import smooth_curve 9 | from common.multi_layer_net import MultiLayerNet 10 | from common.optimizer import SGD 11 | 12 | 13 | # 0. MNIST 데이터 읽기========== 14 | (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) 15 | 16 | train_size = x_train.shape[0] 17 | batch_size = 128 18 | max_iterations = 2000 19 | 20 | 21 | # 1. 실험용 설정========== 22 | weight_init_types = {'std=0.01': 0.01, 'Xavier': 'sigmoid', 'He': 'relu'} 23 | optimizer = SGD(lr=0.01) 24 | 25 | networks = {} 26 | train_loss = {} 27 | for key, weight_type in weight_init_types.items(): 28 | networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100], 29 | output_size=10, weight_init_std=weight_type) 30 | train_loss[key] = [] 31 | 32 | 33 | # 2. 훈련 시작========== 34 | for i in range(max_iterations): 35 | batch_mask = np.random.choice(train_size, batch_size) 36 | x_batch = x_train[batch_mask] 37 | t_batch = t_train[batch_mask] 38 | 39 | for key in weight_init_types.keys(): 40 | grads = networks[key].gradient(x_batch, t_batch) 41 | optimizer.update(networks[key].params, grads) 42 | 43 | loss = networks[key].loss(x_batch, t_batch) 44 | train_loss[key].append(loss) 45 | 46 | if i % 100 == 0: 47 | print("===========" + "iteration:" + str(i) + "===========") 48 | for key in weight_init_types.keys(): 49 | loss = networks[key].loss(x_batch, t_batch) 50 | print(key + ":" + str(loss)) 51 | 52 | 53 | # 3. 그래프 그리기========== 54 | markers = {'std=0.01': 'o', 'Xavier': 's', 'He': 'D'} 55 | x = np.arange(max_iterations) 56 | for key in weight_init_types.keys(): 57 | plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key) 58 | plt.xlabel("iterations") 59 | plt.ylabel("loss") 60 | plt.ylim(0, 2.5) 61 | plt.legend() 62 | plt.show() 63 | -------------------------------------------------------------------------------- /ch07/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | apply_filter.py | cactus_gray.png 파일에 필터를 적용합니다. | | | 5 | | gradient_check.py | SimpleCovNet이 기울기를 올바로 계산하는지 확인합니다. | | | 6 | | params.pkl | 미리 학습된 가중치 값들입니다. | | | 7 | | simple_convnet.py | “Convolution-ReLU-Pooling-Affine-ReLU-Affine-Softmax” 순으로 흐르는 단순한 합성곱 신경망(CNN)입니다. | 7.5 CNN 구현하기 | 251 | 8 | | train_convnet.py | SimpleConvNet으로 MNIST 데이터셋을 학습합니다. | 7.5 CNN 구현하기 | 254 | 9 | | visualize_filter.py | 합성곱 1번째 층의 가중치를 학습 전과 후로 나눠 시각화해봅니다. 이미 학습된 가중치 값(params.pkl)을 읽어서 사용하므로 학습 과정은 생략됩니다. | 7.6.1 1번째 층의 가중치 시각화하기 | 254 | 10 | 11 | ## 7장 합성곱 신경망(CNN) 12 | 이번 장의 주제는 합성곱 신경망(convolutional neural network, CNN)입니다. CNN은 이미지 인식과 음성 인식 등 다양한 곳에서 사용되는데, 특히 이미지 인식 분야에서 딥러닝을 활용한 기법은 거의 다 CNN을 기초로 하죠. 이번 장에서는 CNN의 메커니즘을 자세히 설명하고 이를 파이썬으로 구현해보겠습니다. 13 | 14 | *옮긴이_ 합성곱은 공학과 물리학에서 널리 쓰이는 수학적 개념으로, 간단히 정의해보면 다음과 같습니다. 15 | “두 함수 중 하나를 반전(reverse), 이동(shift)시켜가며 나머지 함수와의 곱을 연이어 적분한다.” 16 | 합성곱 신경망을 영어 발음 그대로 ‘컨벌루션 신경망’으로도 많이 씁니다만, 위 정의와 이번 장에서 설명할 동작 원리를 이해하고 나면 ‘합성곱 신경망’이란 용어가 더 직관적으로 다가올 수도 있을 겁니다.* 17 | 18 | ## 목차 19 | ``` 20 | 7.1 전체 구조 21 | 7.2 합성곱 계층 22 | __7.2.1 완전연결 계층의 문제점 23 | __7.2.2 합성곱 연산 24 | __7.2.3 패딩 25 | __7.2.4 스트라이드 26 | __7.2.5 3차원 데이터의 합성곱 연산 27 | __7.2.6 블록으로 생각하기 28 | __7.2.7 배치 처리 29 | 7.3 풀링 계층 30 | __7.3.1 풀링 계층의 특징 31 | 7.4 합성곱/풀링 계층 구현하기 32 | __7.4.1 4차원 배열 33 | __7.4.2 im2col로 데이터 전개하기 34 | __7.4.3 합성곱 계층 구현하기 35 | __7.4.4 풀링 계층 구현하기 36 | 7.5 CNN 구현하기 37 | 7.6 CNN 시각화하기 38 | __7.6.1 1번째 층의 가중치 시각화하기 39 | __7.6.2 층 깊이에 따른 추출 정보 변화 40 | 7.7 대표적인 CNN 41 | __7.7.1 LeNet 42 | __7.7.2 AlexNet 43 | ``` 44 | 45 | ## 이번 장에서 배운 내용 46 | * CNN은 지금까지의 완전연결 계층 네트워크에 합성곱 계층과 풀링 계층을 새로 추가한다. 47 | * 합성곱 계층과 풀링 계층은 im2col (이미지를 행렬로 전개하는 함수)을 이용하면 간단하고 효율적으로 구현할 수 있다. 48 | * CNN을 시각화해보면 계층이 깊어질수록 고급 정보가 추출되는 모습을 확인할 수 있다. 49 | * 대표적인 CNN에는 LeNet과 AlexNet이 있다. 50 | * 딥러닝의 발전에는 빅 데이터와 GPU가 크게 기여했다. 51 | -------------------------------------------------------------------------------- /ch07/apply_filter.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from simple_convnet import SimpleConvNet 8 | from matplotlib.image import imread 9 | from common.layers import Convolution 10 | 11 | def filter_show(filters, nx=4, show_num=16): 12 | """ 13 | c.f. https://gist.github.com/aidiary/07d530d5e08011832b12#file-draw_weight-py 14 | """ 15 | FN, C, FH, FW = filters.shape 16 | ny = int(np.ceil(show_num / nx)) 17 | 18 | fig = plt.figure() 19 | fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05) 20 | 21 | for i in range(show_num): 22 | ax = fig.add_subplot(4, 4, i+1, xticks=[], yticks=[]) 23 | ax.imshow(filters[i, 0], cmap=plt.cm.gray_r, interpolation='nearest') 24 | 25 | 26 | network = SimpleConvNet(input_dim=(1,28,28), 27 | conv_param = {'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1}, 28 | hidden_size=100, output_size=10, weight_init_std=0.01) 29 | 30 | # 학습된 가중치 31 | network.load_params("params.pkl") 32 | 33 | filter_show(network.params['W1'], 16) 34 | 35 | img = imread(os.path.dirname(__file__) + '/../dataset/cactus_gray.png') 36 | img = img.reshape(1, 1, *img.shape) 37 | 38 | fig = plt.figure() 39 | 40 | w_idx = 1 41 | 42 | for i in range(16): 43 | w = network.params['W1'][i] 44 | b = 0 # network.params['b1'][i] 45 | 46 | w = w.reshape(1, *w.shape) 47 | #b = b.reshape(1, *b.shape) 48 | conv_layer = Convolution(w, b) 49 | out = conv_layer.forward(img) 50 | out = out.reshape(out.shape[2], out.shape[3]) 51 | 52 | ax = fig.add_subplot(4, 4, i+1, xticks=[], yticks=[]) 53 | ax.imshow(out, cmap=plt.cm.gray_r, interpolation='nearest') 54 | 55 | plt.show() 56 | -------------------------------------------------------------------------------- /ch07/gradient_check.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | from simple_convnet import SimpleConvNet 4 | 5 | network = SimpleConvNet(input_dim=(1,10, 10), 6 | conv_param = {'filter_num':10, 'filter_size':3, 'pad':0, 'stride':1}, 7 | hidden_size=10, output_size=10, weight_init_std=0.01) 8 | 9 | X = np.random.rand(100).reshape((1, 1, 10, 10)) 10 | T = np.array([1]).reshape((1,1)) 11 | 12 | grad_num = network.numerical_gradient(X, T) 13 | grad = network.gradient(X, T) 14 | 15 | for key, val in grad_num.items(): 16 | print(key, np.abs(grad_num[key] - grad[key]).mean()) -------------------------------------------------------------------------------- /ch07/params.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch07/params.pkl -------------------------------------------------------------------------------- /ch07/simple_convnet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import pickle 6 | import numpy as np 7 | from collections import OrderedDict 8 | from common.layers import * 9 | from common.gradient import numerical_gradient 10 | 11 | 12 | class SimpleConvNet: 13 | """단순한 합성곱 신경망 14 | 15 | conv - relu - pool - affine - relu - affine - softmax 16 | 17 | Parameters 18 | ---------- 19 | input_size : 입력 크기(MNIST의 경우엔 784) 20 | hidden_size_list : 각 은닉층의 뉴런 수를 담은 리스트(e.g. [100, 100, 100]) 21 | output_size : 출력 크기(MNIST의 경우엔 10) 22 | activation : 활성화 함수 - 'relu' 혹은 'sigmoid' 23 | weight_init_std : 가중치의 표준편차 지정(e.g. 0.01) 24 | 'relu'나 'he'로 지정하면 'He 초깃값'으로 설정 25 | 'sigmoid'나 'xavier'로 지정하면 'Xavier 초깃값'으로 설정 26 | """ 27 | def __init__(self, input_dim=(1, 28, 28), 28 | conv_param={'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1}, 29 | hidden_size=100, output_size=10, weight_init_std=0.01): 30 | filter_num = conv_param['filter_num'] 31 | filter_size = conv_param['filter_size'] 32 | filter_pad = conv_param['pad'] 33 | filter_stride = conv_param['stride'] 34 | input_size = input_dim[1] 35 | conv_output_size = (input_size - filter_size + 2*filter_pad) / filter_stride + 1 36 | pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2)) 37 | 38 | # 가중치 초기화 39 | self.params = {} 40 | self.params['W1'] = weight_init_std * \ 41 | np.random.randn(filter_num, input_dim[0], filter_size, filter_size) 42 | self.params['b1'] = np.zeros(filter_num) 43 | self.params['W2'] = weight_init_std * \ 44 | np.random.randn(pool_output_size, hidden_size) 45 | self.params['b2'] = np.zeros(hidden_size) 46 | self.params['W3'] = weight_init_std * \ 47 | np.random.randn(hidden_size, output_size) 48 | self.params['b3'] = np.zeros(output_size) 49 | 50 | # 계층 생성 51 | self.layers = OrderedDict() 52 | self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'], 53 | conv_param['stride'], conv_param['pad']) 54 | self.layers['Relu1'] = Relu() 55 | self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2) 56 | self.layers['Affine1'] = Affine(self.params['W2'], self.params['b2']) 57 | self.layers['Relu2'] = Relu() 58 | self.layers['Affine2'] = Affine(self.params['W3'], self.params['b3']) 59 | 60 | self.last_layer = SoftmaxWithLoss() 61 | 62 | def predict(self, x): 63 | for layer in self.layers.values(): 64 | x = layer.forward(x) 65 | 66 | return x 67 | 68 | def loss(self, x, t): 69 | """손실 함수를 구한다. 70 | 71 | Parameters 72 | ---------- 73 | x : 입력 데이터 74 | t : 정답 레이블 75 | """ 76 | y = self.predict(x) 77 | return self.last_layer.forward(y, t) 78 | 79 | def accuracy(self, x, t, batch_size=100): 80 | if t.ndim != 1 : t = np.argmax(t, axis=1) 81 | 82 | acc = 0.0 83 | 84 | for i in range(int(x.shape[0] / batch_size)): 85 | tx = x[i*batch_size:(i+1)*batch_size] 86 | tt = t[i*batch_size:(i+1)*batch_size] 87 | y = self.predict(tx) 88 | y = np.argmax(y, axis=1) 89 | acc += np.sum(y == tt) 90 | 91 | return acc / x.shape[0] 92 | 93 | def numerical_gradient(self, x, t): 94 | """기울기를 구한다(수치미분). 95 | 96 | Parameters 97 | ---------- 98 | x : 입력 데이터 99 | t : 정답 레이블 100 | 101 | Returns 102 | ------- 103 | 각 층의 기울기를 담은 사전(dictionary) 변수 104 | grads['W1']、grads['W2']、... 각 층의 가중치 105 | grads['b1']、grads['b2']、... 각 층의 편향 106 | """ 107 | loss_w = lambda w: self.loss(x, t) 108 | 109 | grads = {} 110 | for idx in (1, 2, 3): 111 | grads['W' + str(idx)] = numerical_gradient(loss_w, self.params['W' + str(idx)]) 112 | grads['b' + str(idx)] = numerical_gradient(loss_w, self.params['b' + str(idx)]) 113 | 114 | return grads 115 | 116 | def gradient(self, x, t): 117 | """기울기를 구한다(오차역전파법). 118 | 119 | Parameters 120 | ---------- 121 | x : 입력 데이터 122 | t : 정답 레이블 123 | 124 | Returns 125 | ------- 126 | 각 층의 기울기를 담은 사전(dictionary) 변수 127 | grads['W1']、grads['W2']、... 각 층의 가중치 128 | grads['b1']、grads['b2']、... 각 층의 편향 129 | """ 130 | # 순전파 131 | self.loss(x, t) 132 | 133 | # 역전파 134 | dout = 1 135 | dout = self.last_layer.backward(dout) 136 | 137 | layers = list(self.layers.values()) 138 | layers.reverse() 139 | for layer in layers: 140 | dout = layer.backward(dout) 141 | 142 | # 결과 저장 143 | grads = {} 144 | grads['W1'], grads['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].db 145 | grads['W2'], grads['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].db 146 | grads['W3'], grads['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].db 147 | 148 | return grads 149 | 150 | def save_params(self, file_name="params.pkl"): 151 | params = {} 152 | for key, val in self.params.items(): 153 | params[key] = val 154 | with open(file_name, 'wb') as f: 155 | pickle.dump(params, f) 156 | 157 | def load_params(self, file_name="params.pkl"): 158 | with open(os.path.dirname(__file__) + '/' + file_name, 'rb') as f: 159 | params = pickle.load(f) 160 | for key, val in params.items(): 161 | self.params[key] = val 162 | 163 | for i, key in enumerate(['Conv1', 'Affine1', 'Affine2']): 164 | self.layers[key].W = self.params['W' + str(i+1)] 165 | self.layers[key].b = self.params['b' + str(i+1)] 166 | -------------------------------------------------------------------------------- /ch07/train_convnet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from simple_convnet import SimpleConvNet 9 | from common.trainer import Trainer 10 | 11 | # 데이터 읽기 12 | (x_train, t_train), (x_test, t_test) = load_mnist(flatten=False) 13 | 14 | # 시간이 오래 걸릴 경우 데이터를 줄인다. 15 | #x_train, t_train = x_train[:5000], t_train[:5000] 16 | #x_test, t_test = x_test[:1000], t_test[:1000] 17 | 18 | max_epochs = 20 19 | 20 | network = SimpleConvNet(input_dim=(1,28,28), 21 | conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1}, 22 | hidden_size=100, output_size=10, weight_init_std=0.01) 23 | 24 | trainer = Trainer(network, x_train, t_train, x_test, t_test, 25 | epochs=max_epochs, mini_batch_size=100, 26 | optimizer='Adam', optimizer_param={'lr': 0.001}, 27 | evaluate_sample_num_per_epoch=1000) 28 | trainer.train() 29 | 30 | # 매개변수 보존 31 | network.save_params("params.pkl") 32 | print("Saved Network Parameters!") 33 | 34 | # 그래프 그리기 35 | markers = {'train': 'o', 'test': 's'} 36 | x = np.arange(max_epochs) 37 | plt.plot(x, trainer.train_acc_list, marker='o', label='train', markevery=2) 38 | plt.plot(x, trainer.test_acc_list, marker='s', label='test', markevery=2) 39 | plt.xlabel("epochs") 40 | plt.ylabel("accuracy") 41 | plt.ylim(0, 1.0) 42 | plt.legend(loc='lower right') 43 | plt.show() 44 | -------------------------------------------------------------------------------- /ch07/visualize_filter.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from simple_convnet import SimpleConvNet 5 | 6 | def filter_show(filters, nx=8, margin=3, scale=10): 7 | """ 8 | c.f. https://gist.github.com/aidiary/07d530d5e08011832b12#file-draw_weight-py 9 | """ 10 | FN, C, FH, FW = filters.shape 11 | ny = int(np.ceil(FN / nx)) 12 | 13 | fig = plt.figure() 14 | fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05) 15 | 16 | for i in range(FN): 17 | ax = fig.add_subplot(ny, nx, i+1, xticks=[], yticks=[]) 18 | ax.imshow(filters[i, 0], cmap=plt.cm.gray_r, interpolation='nearest') 19 | plt.show() 20 | 21 | 22 | network = SimpleConvNet() 23 | # 무작위(랜덤) 초기화 후의 가중치 24 | filter_show(network.params['W1']) 25 | 26 | # 학습된 가중치 27 | network.load_params("params.pkl") 28 | filter_show(network.params['W1']) 29 | -------------------------------------------------------------------------------- /ch08/README.md: -------------------------------------------------------------------------------- 1 | ## 파일 설명 2 | | 파일명 | 파일 용도 | 관련 절 | 페이지 | 3 | |:-- |:-- |:-- |:-- | 4 | | awesome_net.py | 빈 파일입니다. 여기에 여러분만의 멋진 신경망을 구현해보세요! | | | 5 | | deep_convnet.py | [그림 8-1]의 깊은 신경망을 구현한 소스입니다. | 8.1.1 더 깊은 신경망으로 | 262 | 6 | | deep_convnet_params.pkl | deep_convnet.py용 학습된 가중치입니다. | | | 7 | | half_float_network.py | 수치 정밀도를 반정밀도(16비트)로 낮춰 계산하여 배정밀도(64비트)일 때와 정확도를 비교해본다. | 8.3.4 연산 정밀도와 비트 줄이기 | 278 | 8 | | misclassified_mnist.py | 이번 장에서 구현한 신경망이 인식에 실패한 손글씨 이미지들을 화면에 보여줍니다. | 8.1.1 더 깊은 신경망으로 | 263 | 9 | | train_deepnet.py | deep_convnet.py의 신경망을 학습시킵니다. 몇 시간은 걸리기 때문에 다른 코드에서는 미리 학습된 가중치인 deep_convnet_params.pkl을 읽어서 사용합니다. | 8.1.1 더 깊은 신경망으로 | 262 | 10 | 11 | ## 8장 딥러닝 12 | 딥러닝은 층을 깊게 한 심층 신경망입니다. 심층 신경망은 지금까지 설명한 신경망을 바탕으로 뒷단에 층을 추가하기만 하면 만들 수 있지만, 커다란 문제가 몇 개 있습니다. 이번 장에서는 딥러닝의 특징과 과제, 그리고 가능성을 살펴봅니다. 또 오늘날의 첨단 딥러닝에 대한 설명도 준비했습니다. 13 | 14 | ## 목차 15 | ``` 16 | 8.1 더 깊게 17 | __8.1.1 더 깊은 네트워크로 18 | __8.1.2 정확도를 더 높이려면 19 | __8.1.3 깊게 하는 이유 20 | 8.2 딥러닝의 초기 역사 21 | __8.2.1 이미지넷 22 | __8.2.2 VGG 23 | __8.2.3 GoogLeNet 24 | __8.2.4 ResNet 25 | 8.3 더 빠르게(딥러닝 고속화) 26 | __8.3.1 풀어야 할 숙제 27 | __8.3.2 GPU를 활용한 고속화 28 | __8.3.3 분산 학습 29 | __8.3.4 연산 정밀도와 비트 줄이기 30 | 8.4 딥러닝의 활용 31 | __8.4.1 사물 검출 32 | __8.4.2 분할 33 | __8.4.3 사진 캡션 생성 34 | 8.5 딥러닝의 미래 35 | __8.5.1 이미지 스타일(화풍) 변환 36 | __8.5.2 이미지 생성 37 | __8.5.3 자율 주행 38 | __8.5.4 Deep Q-Network(강화학습) 39 | ``` 40 | 41 | ## 이번 장에서 배운 내용 42 | * 수많은 문제에서 신경망을 더 깊게 하여 성능을 개선할 수 있다. 43 | * 이미지 인식 기술 대회인 ILSVRC에서는 최근 딥러닝 기반 기법이 상위권을 독점하고 있으며, 그 깊이도 더 깊어지는 추세다. 44 | * 유명한 신경망으로는 VGG, GoogLeNet, ResNet이 있다. 45 | * GPU와 분산 학습, 비트 정밀도 감소 등으로 딥러닝을 고속화할 수 있다. 46 | * 딥러닝(신경망)은 사물 인식뿐 아니라 사물 검출과 분할에도 이용할 수 있다. 47 | * 딥러닝의 응용 분야로는 사진의 캡션 생성, 이미지 생성, 강화학습 등이 있다. 최근에는 자율 주행에도 딥러닝을 접목하고 있어 기대된다. 48 | -------------------------------------------------------------------------------- /ch08/awesome_net.py: -------------------------------------------------------------------------------- 1 | # Create your awesome net!! -------------------------------------------------------------------------------- /ch08/deep_convnet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import pickle 6 | import numpy as np 7 | from collections import OrderedDict 8 | from common.layers import * 9 | 10 | 11 | class DeepConvNet: 12 | """정확도 99% 이상의 고정밀 합성곱 신경망 13 | 14 | 신경망 구성은 아래와 같음 15 | conv - relu - conv- relu - pool - 16 | conv - relu - conv- relu - pool - 17 | conv - relu - conv- relu - pool - 18 | affine - relu - dropout - affine - dropout - softmax 19 | """ 20 | def __init__(self, input_dim=(1, 28, 28), 21 | conv_param_1 = {'filter_num':16, 'filter_size':3, 'pad':1, 'stride':1}, 22 | conv_param_2 = {'filter_num':16, 'filter_size':3, 'pad':1, 'stride':1}, 23 | conv_param_3 = {'filter_num':32, 'filter_size':3, 'pad':1, 'stride':1}, 24 | conv_param_4 = {'filter_num':32, 'filter_size':3, 'pad':2, 'stride':1}, 25 | conv_param_5 = {'filter_num':64, 'filter_size':3, 'pad':1, 'stride':1}, 26 | conv_param_6 = {'filter_num':64, 'filter_size':3, 'pad':1, 'stride':1}, 27 | hidden_size=50, output_size=10): 28 | # 가중치 초기화=========== 29 | # 각 층의 뉴런 하나당 앞 층의 몇 개 뉴런과 연결되는가(TODO: 자동 계산되게 바꿀 것) 30 | pre_node_nums = np.array([1*3*3, 16*3*3, 16*3*3, 32*3*3, 32*3*3, 64*3*3, 64*4*4, hidden_size]) 31 | wight_init_scales = np.sqrt(2.0 / pre_node_nums) # ReLU를 사용할 때의 권장 초깃값 32 | 33 | self.params = {} 34 | pre_channel_num = input_dim[0] 35 | for idx, conv_param in enumerate([conv_param_1, conv_param_2, conv_param_3, conv_param_4, conv_param_5, conv_param_6]): 36 | self.params['W' + str(idx+1)] = wight_init_scales[idx] * np.random.randn(conv_param['filter_num'], pre_channel_num, conv_param['filter_size'], conv_param['filter_size']) 37 | self.params['b' + str(idx+1)] = np.zeros(conv_param['filter_num']) 38 | pre_channel_num = conv_param['filter_num'] 39 | self.params['W7'] = wight_init_scales[6] * np.random.randn(64*4*4, hidden_size) 40 | self.params['b7'] = np.zeros(hidden_size) 41 | self.params['W8'] = wight_init_scales[7] * np.random.randn(hidden_size, output_size) 42 | self.params['b8'] = np.zeros(output_size) 43 | 44 | # 계층 생성=========== 45 | self.layers = [] 46 | self.layers.append(Convolution(self.params['W1'], self.params['b1'], 47 | conv_param_1['stride'], conv_param_1['pad'])) 48 | self.layers.append(Relu()) 49 | self.layers.append(Convolution(self.params['W2'], self.params['b2'], 50 | conv_param_2['stride'], conv_param_2['pad'])) 51 | self.layers.append(Relu()) 52 | self.layers.append(Pooling(pool_h=2, pool_w=2, stride=2)) 53 | self.layers.append(Convolution(self.params['W3'], self.params['b3'], 54 | conv_param_3['stride'], conv_param_3['pad'])) 55 | self.layers.append(Relu()) 56 | self.layers.append(Convolution(self.params['W4'], self.params['b4'], 57 | conv_param_4['stride'], conv_param_4['pad'])) 58 | self.layers.append(Relu()) 59 | self.layers.append(Pooling(pool_h=2, pool_w=2, stride=2)) 60 | self.layers.append(Convolution(self.params['W5'], self.params['b5'], 61 | conv_param_5['stride'], conv_param_5['pad'])) 62 | self.layers.append(Relu()) 63 | self.layers.append(Convolution(self.params['W6'], self.params['b6'], 64 | conv_param_6['stride'], conv_param_6['pad'])) 65 | self.layers.append(Relu()) 66 | self.layers.append(Pooling(pool_h=2, pool_w=2, stride=2)) 67 | self.layers.append(Affine(self.params['W7'], self.params['b7'])) 68 | self.layers.append(Relu()) 69 | self.layers.append(Dropout(0.5)) 70 | self.layers.append(Affine(self.params['W8'], self.params['b8'])) 71 | self.layers.append(Dropout(0.5)) 72 | 73 | self.last_layer = SoftmaxWithLoss() 74 | 75 | def predict(self, x, train_flg=False): 76 | for layer in self.layers: 77 | if isinstance(layer, Dropout): 78 | x = layer.forward(x, train_flg) 79 | else: 80 | x = layer.forward(x) 81 | return x 82 | 83 | def loss(self, x, t): 84 | y = self.predict(x, train_flg=True) 85 | return self.last_layer.forward(y, t) 86 | 87 | def accuracy(self, x, t, batch_size=100): 88 | if t.ndim != 1 : t = np.argmax(t, axis=1) 89 | 90 | acc = 0.0 91 | 92 | for i in range(int(x.shape[0] / batch_size)): 93 | tx = x[i*batch_size:(i+1)*batch_size] 94 | tt = t[i*batch_size:(i+1)*batch_size] 95 | y = self.predict(tx, train_flg=False) 96 | y = np.argmax(y, axis=1) 97 | acc += np.sum(y == tt) 98 | 99 | return acc / x.shape[0] 100 | 101 | def gradient(self, x, t): 102 | # forward 103 | self.loss(x, t) 104 | 105 | # backward 106 | dout = 1 107 | dout = self.last_layer.backward(dout) 108 | 109 | tmp_layers = self.layers.copy() 110 | tmp_layers.reverse() 111 | for layer in tmp_layers: 112 | dout = layer.backward(dout) 113 | 114 | # 결과 저장 115 | grads = {} 116 | for i, layer_idx in enumerate((0, 2, 5, 7, 10, 12, 15, 18)): 117 | grads['W' + str(i+1)] = self.layers[layer_idx].dW 118 | grads['b' + str(i+1)] = self.layers[layer_idx].db 119 | 120 | return grads 121 | 122 | def save_params(self, file_name="params.pkl"): 123 | params = {} 124 | for key, val in self.params.items(): 125 | params[key] = val 126 | with open(file_name, 'wb') as f: 127 | pickle.dump(params, f) 128 | 129 | def load_params(self, file_name="params.pkl"): 130 | with open(os.path.dirname(__file__) + '/' + file_name, 'rb') as f: 131 | params = pickle.load(f) 132 | for key, val in params.items(): 133 | self.params[key] = val 134 | 135 | for i, layer_idx in enumerate((0, 2, 5, 7, 10, 12, 15, 18)): 136 | self.layers[layer_idx].W = self.params['W' + str(i+1)] 137 | self.layers[layer_idx].b = self.params['b' + str(i+1)] 138 | -------------------------------------------------------------------------------- /ch08/deep_convnet_params.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/ch08/deep_convnet_params.pkl -------------------------------------------------------------------------------- /ch08/half_float_network.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from deep_convnet import DeepConvNet 8 | from dataset.mnist import load_mnist 9 | 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(flatten=False) 12 | 13 | network = DeepConvNet() 14 | network.load_params("deep_convnet_params.pkl") 15 | 16 | sampled = 10000 # 고속화를 위한 표본추출 17 | x_test = x_test[:sampled] 18 | t_test = t_test[:sampled] 19 | 20 | print("caluculate accuracy (float64) ... ") 21 | print(network.accuracy(x_test, t_test)) 22 | 23 | # float16(반정밀도)로 형변환 24 | x_test = x_test.astype(np.float16) 25 | for param in network.params.values(): 26 | param[...] = param.astype(np.float16) 27 | 28 | print("caluculate accuracy (float16) ... ") 29 | print(network.accuracy(x_test, t_test)) 30 | -------------------------------------------------------------------------------- /ch08/misclassified_mnist.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from deep_convnet import DeepConvNet 8 | from dataset.mnist import load_mnist 9 | 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(flatten=False) 12 | 13 | network = DeepConvNet() 14 | network.load_params("deep_convnet_params.pkl") 15 | 16 | print("calculating test accuracy ... ") 17 | #sampled = 1000 18 | #x_test = x_test[:sampled] 19 | #t_test = t_test[:sampled] 20 | 21 | classified_ids = [] 22 | 23 | acc = 0.0 24 | batch_size = 100 25 | 26 | for i in range(int(x_test.shape[0] / batch_size)): 27 | tx = x_test[i*batch_size:(i+1)*batch_size] 28 | tt = t_test[i*batch_size:(i+1)*batch_size] 29 | y = network.predict(tx, train_flg=False) 30 | y = np.argmax(y, axis=1) 31 | classified_ids.append(y) 32 | acc += np.sum(y == tt) 33 | 34 | acc = acc / x_test.shape[0] 35 | print("test accuracy:" + str(acc)) 36 | 37 | classified_ids = np.array(classified_ids) 38 | classified_ids = classified_ids.flatten() 39 | 40 | max_view = 20 41 | current_view = 1 42 | 43 | fig = plt.figure() 44 | fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.2, wspace=0.2) 45 | 46 | mis_pairs = {} 47 | for i, val in enumerate(classified_ids == t_test): 48 | if not val: 49 | ax = fig.add_subplot(4, 5, current_view, xticks=[], yticks=[]) 50 | ax.imshow(x_test[i].reshape(28, 28), cmap=plt.cm.gray_r, interpolation='nearest') 51 | mis_pairs[current_view] = (t_test[i], classified_ids[i]) 52 | 53 | current_view += 1 54 | if current_view > max_view: 55 | break 56 | 57 | print("======= misclassified result =======") 58 | print("{view index: (label, inference), ...}") 59 | print(mis_pairs) 60 | 61 | plt.show() 62 | -------------------------------------------------------------------------------- /ch08/train_deepnet.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | from dataset.mnist import load_mnist 8 | from deep_convnet import DeepConvNet 9 | from common.trainer import Trainer 10 | 11 | (x_train, t_train), (x_test, t_test) = load_mnist(flatten=False) 12 | 13 | network = DeepConvNet() 14 | trainer = Trainer(network, x_train, t_train, x_test, t_test, 15 | epochs=20, mini_batch_size=100, 16 | optimizer='Adam', optimizer_param={'lr':0.001}, 17 | evaluate_sample_num_per_epoch=1000) 18 | trainer.train() 19 | 20 | # 매개변수 보관 21 | network.save_params("deep_convnet_params.pkl") 22 | print("Saved Network Parameters!") 23 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/common/__init__.py -------------------------------------------------------------------------------- /common/functions.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | 5 | def identity_function(x): 6 | return x 7 | 8 | 9 | def step_function(x): 10 | return np.array(x > 0, dtype=np.int) 11 | 12 | 13 | def sigmoid(x): 14 | return 1 / (1 + np.exp(-x)) 15 | 16 | 17 | def sigmoid_grad(x): 18 | return (1.0 - sigmoid(x)) * sigmoid(x) 19 | 20 | 21 | def relu(x): 22 | return np.maximum(0, x) 23 | 24 | 25 | def relu_grad(x): 26 | grad = np.zeros(x) 27 | grad[x>=0] = 1 28 | return grad 29 | 30 | 31 | def softmax(x): 32 | x = x - np.max(x, axis=-1, keepdims=True) # 오버플로 대책 33 | return np.exp(x) / np.sum(np.exp(x), axis=-1, keepdims=True) 34 | 35 | def mean_squared_error(y, t): 36 | return 0.5 * np.sum((y-t)**2) 37 | 38 | 39 | def cross_entropy_error(y, t): 40 | if y.ndim == 1: 41 | t = t.reshape(1, t.size) 42 | y = y.reshape(1, y.size) 43 | 44 | # 훈련 데이터가 원-핫 벡터라면 정답 레이블의 인덱스로 반환 45 | if t.size == y.size: 46 | t = t.argmax(axis=1) 47 | 48 | batch_size = y.shape[0] 49 | return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size 50 | 51 | 52 | def softmax_loss(X, t): 53 | y = softmax(X) 54 | return cross_entropy_error(y, t) 55 | -------------------------------------------------------------------------------- /common/gradient.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | def _numerical_gradient_1d(f, x): 5 | h = 1e-4 # 0.0001 6 | grad = np.zeros_like(x) 7 | 8 | for idx in range(x.size): 9 | tmp_val = x[idx] 10 | x[idx] = float(tmp_val) + h 11 | fxh1 = f(x) # f(x+h) 12 | 13 | x[idx] = tmp_val - h 14 | fxh2 = f(x) # f(x-h) 15 | grad[idx] = (fxh1 - fxh2) / (2*h) 16 | 17 | x[idx] = tmp_val # 값 복원 18 | 19 | return grad 20 | 21 | 22 | def numerical_gradient_2d(f, X): 23 | if X.ndim == 1: 24 | return _numerical_gradient_1d(f, X) 25 | else: 26 | grad = np.zeros_like(X) 27 | 28 | for idx, x in enumerate(X): 29 | grad[idx] = _numerical_gradient_1d(f, x) 30 | 31 | return grad 32 | 33 | 34 | def numerical_gradient(f, x): 35 | h = 1e-4 # 0.0001 36 | grad = np.zeros_like(x) 37 | 38 | it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) 39 | while not it.finished: 40 | idx = it.multi_index 41 | tmp_val = x[idx] 42 | x[idx] = float(tmp_val) + h 43 | fxh1 = f(x) # f(x+h) 44 | 45 | x[idx] = tmp_val - h 46 | fxh2 = f(x) # f(x-h) 47 | grad[idx] = (fxh1 - fxh2) / (2*h) 48 | 49 | x[idx] = tmp_val # 값 복원 50 | it.iternext() 51 | 52 | return grad 53 | -------------------------------------------------------------------------------- /common/layers.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | from common.functions import * 4 | from common.util import im2col, col2im 5 | 6 | 7 | class Relu: 8 | def __init__(self): 9 | self.mask = None 10 | 11 | def forward(self, x): 12 | self.mask = (x <= 0) 13 | out = x.copy() 14 | out[self.mask] = 0 15 | 16 | return out 17 | 18 | def backward(self, dout): 19 | dout[self.mask] = 0 20 | dx = dout 21 | 22 | return dx 23 | 24 | 25 | class Sigmoid: 26 | def __init__(self): 27 | self.out = None 28 | 29 | def forward(self, x): 30 | out = sigmoid(x) 31 | self.out = out 32 | return out 33 | 34 | def backward(self, dout): 35 | dx = dout * (1.0 - self.out) * self.out 36 | 37 | return dx 38 | 39 | 40 | class Affine: 41 | def __init__(self, W, b): 42 | self.W = W 43 | self.b = b 44 | 45 | self.x = None 46 | self.original_x_shape = None 47 | # 가중치와 편향 매개변수의 미분 48 | self.dW = None 49 | self.db = None 50 | 51 | def forward(self, x): 52 | # 텐서 대응 53 | self.original_x_shape = x.shape 54 | x = x.reshape(x.shape[0], -1) 55 | self.x = x 56 | 57 | out = np.dot(self.x, self.W) + self.b 58 | 59 | return out 60 | 61 | def backward(self, dout): 62 | dx = np.dot(dout, self.W.T) 63 | self.dW = np.dot(self.x.T, dout) 64 | self.db = np.sum(dout, axis=0) 65 | 66 | dx = dx.reshape(*self.original_x_shape) # 입력 데이터 모양 변경(텐서 대응) 67 | return dx 68 | 69 | 70 | class SoftmaxWithLoss: 71 | def __init__(self): 72 | self.loss = None # 손실함수 73 | self.y = None # softmax의 출력 74 | self.t = None # 정답 레이블(원-핫 인코딩 형태) 75 | 76 | def forward(self, x, t): 77 | self.t = t 78 | self.y = softmax(x) 79 | self.loss = cross_entropy_error(self.y, self.t) 80 | 81 | return self.loss 82 | 83 | def backward(self, dout=1): 84 | batch_size = self.t.shape[0] 85 | if self.t.size == self.y.size: # 정답 레이블이 원-핫 인코딩 형태일 때 86 | dx = (self.y - self.t) / batch_size 87 | else: 88 | dx = self.y.copy() 89 | dx[np.arange(batch_size), self.t] -= 1 90 | dx = dx / batch_size 91 | 92 | return dx 93 | 94 | 95 | class Dropout: 96 | """ 97 | http://arxiv.org/abs/1207.0580 98 | """ 99 | def __init__(self, dropout_ratio=0.5): 100 | self.dropout_ratio = dropout_ratio 101 | self.mask = None 102 | 103 | def forward(self, x, train_flg=True): 104 | if train_flg: 105 | self.mask = np.random.rand(*x.shape) > self.dropout_ratio 106 | return x * self.mask 107 | else: 108 | return x * (1.0 - self.dropout_ratio) 109 | 110 | def backward(self, dout): 111 | return dout * self.mask 112 | 113 | 114 | class BatchNormalization: 115 | """ 116 | http://arxiv.org/abs/1502.03167 117 | """ 118 | def __init__(self, gamma, beta, momentum=0.9, running_mean=None, running_var=None): 119 | self.gamma = gamma 120 | self.beta = beta 121 | self.momentum = momentum 122 | self.input_shape = None # 합성곱 계층은 4차원, 완전연결 계층은 2차원 123 | 124 | # 시험할 때 사용할 평균과 분산 125 | self.running_mean = running_mean 126 | self.running_var = running_var 127 | 128 | # backward 시에 사용할 중간 데이터 129 | self.batch_size = None 130 | self.xc = None 131 | self.std = None 132 | self.dgamma = None 133 | self.dbeta = None 134 | 135 | def forward(self, x, train_flg=True): 136 | self.input_shape = x.shape 137 | if x.ndim != 2: 138 | N, C, H, W = x.shape 139 | x = x.reshape(N, -1) 140 | 141 | out = self.__forward(x, train_flg) 142 | 143 | return out.reshape(*self.input_shape) 144 | 145 | def __forward(self, x, train_flg): 146 | if self.running_mean is None: 147 | N, D = x.shape 148 | self.running_mean = np.zeros(D) 149 | self.running_var = np.zeros(D) 150 | 151 | if train_flg: 152 | mu = x.mean(axis=0) 153 | xc = x - mu 154 | var = np.mean(xc**2, axis=0) 155 | std = np.sqrt(var + 10e-7) 156 | xn = xc / std 157 | 158 | self.batch_size = x.shape[0] 159 | self.xc = xc 160 | self.xn = xn 161 | self.std = std 162 | self.running_mean = self.momentum * self.running_mean + (1-self.momentum) * mu 163 | self.running_var = self.momentum * self.running_var + (1-self.momentum) * var 164 | else: 165 | xc = x - self.running_mean 166 | xn = xc / ((np.sqrt(self.running_var + 10e-7))) 167 | 168 | out = self.gamma * xn + self.beta 169 | return out 170 | 171 | def backward(self, dout): 172 | if dout.ndim != 2: 173 | N, C, H, W = dout.shape 174 | dout = dout.reshape(N, -1) 175 | 176 | dx = self.__backward(dout) 177 | 178 | dx = dx.reshape(*self.input_shape) 179 | return dx 180 | 181 | def __backward(self, dout): 182 | dbeta = dout.sum(axis=0) 183 | dgamma = np.sum(self.xn * dout, axis=0) 184 | dxn = self.gamma * dout 185 | dxc = dxn / self.std 186 | dstd = -np.sum((dxn * self.xc) / (self.std * self.std), axis=0) 187 | dvar = 0.5 * dstd / self.std 188 | dxc += (2.0 / self.batch_size) * self.xc * dvar 189 | dmu = np.sum(dxc, axis=0) 190 | dx = dxc - dmu / self.batch_size 191 | 192 | self.dgamma = dgamma 193 | self.dbeta = dbeta 194 | 195 | return dx 196 | 197 | 198 | class Convolution: 199 | def __init__(self, W, b, stride=1, pad=0): 200 | self.W = W 201 | self.b = b 202 | self.stride = stride 203 | self.pad = pad 204 | 205 | # 중간 데이터(backward 시 사용) 206 | self.x = None 207 | self.col = None 208 | self.col_W = None 209 | 210 | # 가중치와 편향 매개변수의 기울기 211 | self.dW = None 212 | self.db = None 213 | 214 | def forward(self, x): 215 | FN, C, FH, FW = self.W.shape 216 | N, C, H, W = x.shape 217 | out_h = 1 + int((H + 2*self.pad - FH) / self.stride) 218 | out_w = 1 + int((W + 2*self.pad - FW) / self.stride) 219 | 220 | col = im2col(x, FH, FW, self.stride, self.pad) 221 | col_W = self.W.reshape(FN, -1).T 222 | 223 | out = np.dot(col, col_W) + self.b 224 | out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2) 225 | 226 | self.x = x 227 | self.col = col 228 | self.col_W = col_W 229 | 230 | return out 231 | 232 | def backward(self, dout): 233 | FN, C, FH, FW = self.W.shape 234 | dout = dout.transpose(0,2,3,1).reshape(-1, FN) 235 | 236 | self.db = np.sum(dout, axis=0) 237 | self.dW = np.dot(self.col.T, dout) 238 | self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW) 239 | 240 | dcol = np.dot(dout, self.col_W.T) 241 | dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad) 242 | 243 | return dx 244 | 245 | 246 | class Pooling: 247 | def __init__(self, pool_h, pool_w, stride=2, pad=0): 248 | self.pool_h = pool_h 249 | self.pool_w = pool_w 250 | self.stride = stride 251 | self.pad = pad 252 | 253 | self.x = None 254 | self.arg_max = None 255 | 256 | def forward(self, x): 257 | N, C, H, W = x.shape 258 | out_h = int(1 + (H - self.pool_h) / self.stride) 259 | out_w = int(1 + (W - self.pool_w) / self.stride) 260 | 261 | col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad) 262 | col = col.reshape(-1, self.pool_h*self.pool_w) 263 | 264 | arg_max = np.argmax(col, axis=1) 265 | out = np.max(col, axis=1) 266 | out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2) 267 | 268 | self.x = x 269 | self.arg_max = arg_max 270 | 271 | return out 272 | 273 | def backward(self, dout): 274 | dout = dout.transpose(0, 2, 3, 1) 275 | 276 | pool_size = self.pool_h * self.pool_w 277 | dmax = np.zeros((dout.size, pool_size)) 278 | dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten() 279 | dmax = dmax.reshape(dout.shape + (pool_size,)) 280 | 281 | dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1) 282 | dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad) 283 | 284 | return dx 285 | -------------------------------------------------------------------------------- /common/multi_layer_net.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | from collections import OrderedDict 7 | from common.layers import * 8 | from common.gradient import numerical_gradient 9 | 10 | 11 | class MultiLayerNet: 12 | """완전연결 다층 신경망 13 | 14 | Parameters 15 | ---------- 16 | input_size : 입력 크기(MNIST의 경우엔 784) 17 | hidden_size_list : 각 은닉층의 뉴런 수를 담은 리스트(e.g. [100, 100, 100]) 18 | output_size : 출력 크기(MNIST의 경우엔 10) 19 | activation : 활성화 함수 - 'relu' 혹은 'sigmoid' 20 | weight_init_std : 가중치의 표준편차 지정(e.g. 0.01) 21 | 'relu'나 'he'로 지정하면 'He 초깃값'으로 설정 22 | 'sigmoid'나 'xavier'로 지정하면 'Xavier 초깃값'으로 설정 23 | weight_decay_lambda : 가중치 감소(L2 법칙)의 세기 24 | """ 25 | def __init__(self, input_size, hidden_size_list, output_size, 26 | activation='relu', weight_init_std='relu', weight_decay_lambda=0): 27 | self.input_size = input_size 28 | self.output_size = output_size 29 | self.hidden_size_list = hidden_size_list 30 | self.hidden_layer_num = len(hidden_size_list) 31 | self.weight_decay_lambda = weight_decay_lambda 32 | self.params = {} 33 | 34 | # 가중치 초기화 35 | self.__init_weight(weight_init_std) 36 | 37 | # 계층 생성 38 | activation_layer = {'sigmoid': Sigmoid, 'relu': Relu} 39 | self.layers = OrderedDict() 40 | for idx in range(1, self.hidden_layer_num+1): 41 | self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)], 42 | self.params['b' + str(idx)]) 43 | self.layers['Activation_function' + str(idx)] = activation_layer[activation]() 44 | 45 | idx = self.hidden_layer_num + 1 46 | self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)], 47 | self.params['b' + str(idx)]) 48 | 49 | self.last_layer = SoftmaxWithLoss() 50 | 51 | def __init_weight(self, weight_init_std): 52 | """가중치 초기화 53 | 54 | Parameters 55 | ---------- 56 | weight_init_std : 가중치의 표준편차 지정(e.g. 0.01) 57 | 'relu'나 'he'로 지정하면 'He 초깃값'으로 설정 58 | 'sigmoid'나 'xavier'로 지정하면 'Xavier 초깃값'으로 설정 59 | """ 60 | all_size_list = [self.input_size] + self.hidden_size_list + [self.output_size] 61 | for idx in range(1, len(all_size_list)): 62 | scale = weight_init_std 63 | if str(weight_init_std).lower() in ('relu', 'he'): 64 | scale = np.sqrt(2.0 / all_size_list[idx - 1]) # ReLU를 사용할 때의 권장 초깃값 65 | elif str(weight_init_std).lower() in ('sigmoid', 'xavier'): 66 | scale = np.sqrt(1.0 / all_size_list[idx - 1]) # sigmoid를 사용할 때의 권장 초깃값 67 | self.params['W' + str(idx)] = scale * np.random.randn(all_size_list[idx-1], all_size_list[idx]) 68 | self.params['b' + str(idx)] = np.zeros(all_size_list[idx]) 69 | 70 | def predict(self, x): 71 | for layer in self.layers.values(): 72 | x = layer.forward(x) 73 | 74 | return x 75 | 76 | def loss(self, x, t): 77 | """손실 함수를 구한다. 78 | 79 | Parameters 80 | ---------- 81 | x : 입력 데이터 82 | t : 정답 레이블 83 | 84 | Returns 85 | ------- 86 | 손실 함수의 값 87 | """ 88 | y = self.predict(x) 89 | 90 | weight_decay = 0 91 | for idx in range(1, self.hidden_layer_num + 2): 92 | W = self.params['W' + str(idx)] 93 | weight_decay += 0.5 * self.weight_decay_lambda * np.sum(W ** 2) 94 | 95 | return self.last_layer.forward(y, t) + weight_decay 96 | 97 | def accuracy(self, x, t): 98 | y = self.predict(x) 99 | y = np.argmax(y, axis=1) 100 | if t.ndim != 1 : t = np.argmax(t, axis=1) 101 | 102 | accuracy = np.sum(y == t) / float(x.shape[0]) 103 | return accuracy 104 | 105 | def numerical_gradient(self, x, t): 106 | """기울기를 구한다(수치 미분). 107 | 108 | Parameters 109 | ---------- 110 | x : 입력 데이터 111 | t : 정답 레이블 112 | 113 | Returns 114 | ------- 115 | 각 층의 기울기를 담은 딕셔너리(dictionary) 변수 116 | grads['W1']、grads['W2']、... 각 층의 가중치 117 | grads['b1']、grads['b2']、... 각 층의 편향 118 | """ 119 | loss_W = lambda W: self.loss(x, t) 120 | 121 | grads = {} 122 | for idx in range(1, self.hidden_layer_num+2): 123 | grads['W' + str(idx)] = numerical_gradient(loss_W, self.params['W' + str(idx)]) 124 | grads['b' + str(idx)] = numerical_gradient(loss_W, self.params['b' + str(idx)]) 125 | 126 | return grads 127 | 128 | def gradient(self, x, t): 129 | """기울기를 구한다(오차역전파법). 130 | 131 | Parameters 132 | ---------- 133 | x : 입력 데이터 134 | t : 정답 레이블 135 | 136 | Returns 137 | ------- 138 | 각 층의 기울기를 담은 딕셔너리(dictionary) 변수 139 | grads['W1']、grads['W2']、... 각 층의 가중치 140 | grads['b1']、grads['b2']、... 각 층의 편향 141 | """ 142 | # forward 143 | self.loss(x, t) 144 | 145 | # backward 146 | dout = 1 147 | dout = self.last_layer.backward(dout) 148 | 149 | layers = list(self.layers.values()) 150 | layers.reverse() 151 | for layer in layers: 152 | dout = layer.backward(dout) 153 | 154 | # 결과 저장 155 | grads = {} 156 | for idx in range(1, self.hidden_layer_num+2): 157 | grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.layers['Affine' + str(idx)].W 158 | grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db 159 | 160 | return grads 161 | -------------------------------------------------------------------------------- /common/multi_layer_net_extend.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | from collections import OrderedDict 7 | from common.layers import * 8 | from common.gradient import numerical_gradient 9 | 10 | class MultiLayerNetExtend: 11 | """완전 연결 다층 신경망(확장판) 12 | 가중치 감소, 드롭아웃, 배치 정규화 구현 13 | 14 | Parameters 15 | ---------- 16 | input_size : 입력 크기(MNIST의 경우엔 784) 17 | hidden_size_list : 각 은닉층의 뉴런 수를 담은 리스트(e.g. [100, 100, 100]) 18 | output_size : 출력 크기(MNIST의 경우엔 10) 19 | activation : 활성화 함수 - 'relu' 혹은 'sigmoid' 20 | weight_init_std : 가중치의 표준편차 지정(e.g. 0.01) 21 | 'relu'나 'he'로 지정하면 'He 초깃값'으로 설정 22 | 'sigmoid'나 'xavier'로 지정하면 'Xavier 초깃값'으로 설정 23 | weight_decay_lambda : 가중치 감소(L2 법칙)의 세기 24 | use_dropout : 드롭아웃 사용 여부 25 | dropout_ration : 드롭아웃 비율 26 | use_batchNorm : 배치 정규화 사용 여부 27 | """ 28 | def __init__(self, input_size, hidden_size_list, output_size, 29 | activation='relu', weight_init_std='relu', weight_decay_lambda=0, 30 | use_dropout = False, dropout_ration = 0.5, use_batchnorm=False): 31 | self.input_size = input_size 32 | self.output_size = output_size 33 | self.hidden_size_list = hidden_size_list 34 | self.hidden_layer_num = len(hidden_size_list) 35 | self.use_dropout = use_dropout 36 | self.weight_decay_lambda = weight_decay_lambda 37 | self.use_batchnorm = use_batchnorm 38 | self.params = {} 39 | 40 | # 가중치 초기화 41 | self.__init_weight(weight_init_std) 42 | 43 | # 계층 생성 44 | activation_layer = {'sigmoid': Sigmoid, 'relu': Relu} 45 | self.layers = OrderedDict() 46 | for idx in range(1, self.hidden_layer_num+1): 47 | self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)], 48 | self.params['b' + str(idx)]) 49 | if self.use_batchnorm: 50 | self.params['gamma' + str(idx)] = np.ones(hidden_size_list[idx-1]) 51 | self.params['beta' + str(idx)] = np.zeros(hidden_size_list[idx-1]) 52 | self.layers['BatchNorm' + str(idx)] = BatchNormalization(self.params['gamma' + str(idx)], self.params['beta' + str(idx)]) 53 | 54 | self.layers['Activation_function' + str(idx)] = activation_layer[activation]() 55 | 56 | if self.use_dropout: 57 | self.layers['Dropout' + str(idx)] = Dropout(dropout_ration) 58 | 59 | idx = self.hidden_layer_num + 1 60 | self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)], self.params['b' + str(idx)]) 61 | 62 | self.last_layer = SoftmaxWithLoss() 63 | 64 | def __init_weight(self, weight_init_std): 65 | """가중치 초기화 66 | 67 | Parameters 68 | ---------- 69 | weight_init_std : 가중치의 표준편차 지정(e.g. 0.01) 70 | 'relu'나 'he'로 지정하면 'He 초깃값'으로 설정 71 | 'sigmoid'나 'xavier'로 지정하면 'Xavier 초깃값'으로 설정 72 | """ 73 | all_size_list = [self.input_size] + self.hidden_size_list + [self.output_size] 74 | for idx in range(1, len(all_size_list)): 75 | scale = weight_init_std 76 | if str(weight_init_std).lower() in ('relu', 'he'): 77 | scale = np.sqrt(2.0 / all_size_list[idx - 1]) # ReLUを使う場合に推奨される初期値 78 | elif str(weight_init_std).lower() in ('sigmoid', 'xavier'): 79 | scale = np.sqrt(1.0 / all_size_list[idx - 1]) # sigmoidを使う場合に推奨される初期値 80 | self.params['W' + str(idx)] = scale * np.random.randn(all_size_list[idx-1], all_size_list[idx]) 81 | self.params['b' + str(idx)] = np.zeros(all_size_list[idx]) 82 | 83 | def predict(self, x, train_flg=False): 84 | for key, layer in self.layers.items(): 85 | if "Dropout" in key or "BatchNorm" in key: 86 | x = layer.forward(x, train_flg) 87 | else: 88 | x = layer.forward(x) 89 | 90 | return x 91 | 92 | def loss(self, x, t, train_flg=False): 93 | """손실 함수를 구한다. 94 | 95 | Parameters 96 | ---------- 97 | x : 입력 데이터 98 | t : 정답 레이블 99 | """ 100 | y = self.predict(x, train_flg) 101 | 102 | weight_decay = 0 103 | for idx in range(1, self.hidden_layer_num + 2): 104 | W = self.params['W' + str(idx)] 105 | weight_decay += 0.5 * self.weight_decay_lambda * np.sum(W**2) 106 | 107 | return self.last_layer.forward(y, t) + weight_decay 108 | 109 | def accuracy(self, X, T): 110 | Y = self.predict(X, train_flg=False) 111 | Y = np.argmax(Y, axis=1) 112 | if T.ndim != 1 : T = np.argmax(T, axis=1) 113 | 114 | accuracy = np.sum(Y == T) / float(X.shape[0]) 115 | return accuracy 116 | 117 | def numerical_gradient(self, X, T): 118 | """기울기를 구한다(수치 미분). 119 | 120 | Parameters 121 | ---------- 122 | x : 입력 데이터 123 | t : 정답 레이블 124 | 125 | Returns 126 | ------- 127 | 각 층의 기울기를 담은 사전(dictionary) 변수 128 | grads['W1']、grads['W2']、... 각 층의 가중치 129 | grads['b1']、grads['b2']、... 각 층의 편향 130 | """ 131 | loss_W = lambda W: self.loss(X, T, train_flg=True) 132 | 133 | grads = {} 134 | for idx in range(1, self.hidden_layer_num+2): 135 | grads['W' + str(idx)] = numerical_gradient(loss_W, self.params['W' + str(idx)]) 136 | grads['b' + str(idx)] = numerical_gradient(loss_W, self.params['b' + str(idx)]) 137 | 138 | if self.use_batchnorm and idx != self.hidden_layer_num+1: 139 | grads['gamma' + str(idx)] = numerical_gradient(loss_W, self.params['gamma' + str(idx)]) 140 | grads['beta' + str(idx)] = numerical_gradient(loss_W, self.params['beta' + str(idx)]) 141 | 142 | return grads 143 | 144 | def gradient(self, x, t): 145 | # forward 146 | self.loss(x, t, train_flg=True) 147 | 148 | # backward 149 | dout = 1 150 | dout = self.last_layer.backward(dout) 151 | 152 | layers = list(self.layers.values()) 153 | layers.reverse() 154 | for layer in layers: 155 | dout = layer.backward(dout) 156 | 157 | # 결과 저장 158 | grads = {} 159 | for idx in range(1, self.hidden_layer_num+2): 160 | grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.params['W' + str(idx)] 161 | grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db 162 | 163 | if self.use_batchnorm and idx != self.hidden_layer_num+1: 164 | grads['gamma' + str(idx)] = self.layers['BatchNorm' + str(idx)].dgamma 165 | grads['beta' + str(idx)] = self.layers['BatchNorm' + str(idx)].dbeta 166 | 167 | return grads 168 | -------------------------------------------------------------------------------- /common/optimizer.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | class SGD: 5 | 6 | """확률적 경사 하강법(Stochastic Gradient Descent)""" 7 | 8 | def __init__(self, lr=0.01): 9 | self.lr = lr 10 | 11 | def update(self, params, grads): 12 | for key in params.keys(): 13 | params[key] -= self.lr * grads[key] 14 | 15 | 16 | class Momentum: 17 | 18 | """모멘텀 SGD""" 19 | 20 | def __init__(self, lr=0.01, momentum=0.9): 21 | self.lr = lr 22 | self.momentum = momentum 23 | self.v = None 24 | 25 | def update(self, params, grads): 26 | if self.v is None: 27 | self.v = {} 28 | for key, val in params.items(): 29 | self.v[key] = np.zeros_like(val) 30 | 31 | for key in params.keys(): 32 | self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] 33 | params[key] += self.v[key] 34 | 35 | 36 | class Nesterov: 37 | 38 | """Nesterov's Accelerated Gradient (http://arxiv.org/abs/1212.0901)""" 39 | # NAG는 모멘텀에서 한 단계 발전한 방법이다. (http://newsight.tistory.com/224) 40 | 41 | def __init__(self, lr=0.01, momentum=0.9): 42 | self.lr = lr 43 | self.momentum = momentum 44 | self.v = None 45 | 46 | def update(self, params, grads): 47 | if self.v is None: 48 | self.v = {} 49 | for key, val in params.items(): 50 | self.v[key] = np.zeros_like(val) 51 | 52 | for key in params.keys(): 53 | self.v[key] *= self.momentum 54 | self.v[key] -= self.lr * grads[key] 55 | params[key] += self.momentum * self.momentum * self.v[key] 56 | params[key] -= (1 + self.momentum) * self.lr * grads[key] 57 | 58 | 59 | class AdaGrad: 60 | 61 | """AdaGrad""" 62 | 63 | def __init__(self, lr=0.01): 64 | self.lr = lr 65 | self.h = None 66 | 67 | def update(self, params, grads): 68 | if self.h is None: 69 | self.h = {} 70 | for key, val in params.items(): 71 | self.h[key] = np.zeros_like(val) 72 | 73 | for key in params.keys(): 74 | self.h[key] += grads[key] * grads[key] 75 | params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7) 76 | 77 | 78 | class RMSprop: 79 | 80 | """RMSprop""" 81 | 82 | def __init__(self, lr=0.01, decay_rate = 0.99): 83 | self.lr = lr 84 | self.decay_rate = decay_rate 85 | self.h = None 86 | 87 | def update(self, params, grads): 88 | if self.h is None: 89 | self.h = {} 90 | for key, val in params.items(): 91 | self.h[key] = np.zeros_like(val) 92 | 93 | for key in params.keys(): 94 | self.h[key] *= self.decay_rate 95 | self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key] 96 | params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7) 97 | 98 | 99 | class Adam: 100 | 101 | """Adam (http://arxiv.org/abs/1412.6980v8)""" 102 | 103 | def __init__(self, lr=0.001, beta1=0.9, beta2=0.999): 104 | self.lr = lr 105 | self.beta1 = beta1 106 | self.beta2 = beta2 107 | self.iter = 0 108 | self.m = None 109 | self.v = None 110 | 111 | def update(self, params, grads): 112 | if self.m is None: 113 | self.m, self.v = {}, {} 114 | for key, val in params.items(): 115 | self.m[key] = np.zeros_like(val) 116 | self.v[key] = np.zeros_like(val) 117 | 118 | self.iter += 1 119 | lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter) 120 | 121 | for key in params.keys(): 122 | #self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key] 123 | #self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2) 124 | self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key]) 125 | self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key]) 126 | 127 | params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7) 128 | 129 | #unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias 130 | #unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias 131 | #params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7) 132 | -------------------------------------------------------------------------------- /common/trainer.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import sys, os 3 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 4 | 5 | import numpy as np 6 | from common.optimizer import * 7 | 8 | class Trainer: 9 | """신경망 훈련을 대신 해주는 클래스 10 | """ 11 | def __init__(self, network, x_train, t_train, x_test, t_test, 12 | epochs=20, mini_batch_size=100, 13 | optimizer='SGD', optimizer_param={'lr':0.01}, 14 | evaluate_sample_num_per_epoch=None, verbose=True): 15 | self.network = network 16 | self.verbose = verbose 17 | self.x_train = x_train 18 | self.t_train = t_train 19 | self.x_test = x_test 20 | self.t_test = t_test 21 | self.epochs = epochs 22 | self.batch_size = mini_batch_size 23 | self.evaluate_sample_num_per_epoch = evaluate_sample_num_per_epoch 24 | 25 | # optimzer 26 | optimizer_class_dict = {'sgd':SGD, 'momentum':Momentum, 'nesterov':Nesterov, 27 | 'adagrad':AdaGrad, 'rmsprpo':RMSprop, 'adam':Adam} 28 | self.optimizer = optimizer_class_dict[optimizer.lower()](**optimizer_param) 29 | 30 | self.train_size = x_train.shape[0] 31 | self.iter_per_epoch = max(self.train_size / mini_batch_size, 1) 32 | self.max_iter = int(epochs * self.iter_per_epoch) 33 | self.current_iter = 0 34 | self.current_epoch = 0 35 | 36 | self.train_loss_list = [] 37 | self.train_acc_list = [] 38 | self.test_acc_list = [] 39 | 40 | def train_step(self): 41 | batch_mask = np.random.choice(self.train_size, self.batch_size) 42 | x_batch = self.x_train[batch_mask] 43 | t_batch = self.t_train[batch_mask] 44 | 45 | grads = self.network.gradient(x_batch, t_batch) 46 | self.optimizer.update(self.network.params, grads) 47 | 48 | loss = self.network.loss(x_batch, t_batch) 49 | self.train_loss_list.append(loss) 50 | if self.verbose: print("train loss:" + str(loss)) 51 | 52 | if self.current_iter % self.iter_per_epoch == 0: 53 | self.current_epoch += 1 54 | 55 | x_train_sample, t_train_sample = self.x_train, self.t_train 56 | x_test_sample, t_test_sample = self.x_test, self.t_test 57 | if not self.evaluate_sample_num_per_epoch is None: 58 | t = self.evaluate_sample_num_per_epoch 59 | x_train_sample, t_train_sample = self.x_train[:t], self.t_train[:t] 60 | x_test_sample, t_test_sample = self.x_test[:t], self.t_test[:t] 61 | 62 | train_acc = self.network.accuracy(x_train_sample, t_train_sample) 63 | test_acc = self.network.accuracy(x_test_sample, t_test_sample) 64 | self.train_acc_list.append(train_acc) 65 | self.test_acc_list.append(test_acc) 66 | 67 | if self.verbose: print("=== epoch:" + str(self.current_epoch) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc) + " ===") 68 | self.current_iter += 1 69 | 70 | def train(self): 71 | for i in range(self.max_iter): 72 | self.train_step() 73 | 74 | test_acc = self.network.accuracy(self.x_test, self.t_test) 75 | 76 | if self.verbose: 77 | print("=============== Final Test Accuracy ===============") 78 | print("test acc:" + str(test_acc)) 79 | 80 | -------------------------------------------------------------------------------- /common/util.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import numpy as np 3 | 4 | 5 | def smooth_curve(x): 6 | """손실 함수의 그래프를 매끄럽게 하기 위해 사용 7 | 8 | 참고:http://glowingpython.blogspot.jp/2012/02/convolution-with-numpy.html 9 | """ 10 | window_len = 11 11 | s = np.r_[x[window_len-1:0:-1], x, x[-1:-window_len:-1]] 12 | w = np.kaiser(window_len, 2) 13 | y = np.convolve(w/w.sum(), s, mode='valid') 14 | return y[5:len(y)-5] 15 | 16 | 17 | def shuffle_dataset(x, t): 18 | """데이터셋을 뒤섞는다. 19 | 20 | Parameters 21 | ---------- 22 | x : 훈련 데이터 23 | t : 정답 레이블 24 | 25 | Returns 26 | ------- 27 | x, t : 뒤섞은 훈련 데이터와 정답 레이블 28 | """ 29 | permutation = np.random.permutation(x.shape[0]) 30 | x = x[permutation,:] if x.ndim == 2 else x[permutation,:,:,:] 31 | t = t[permutation] 32 | 33 | return x, t 34 | 35 | def conv_output_size(input_size, filter_size, stride=1, pad=0): 36 | return (input_size + 2*pad - filter_size) / stride + 1 37 | 38 | 39 | def im2col(input_data, filter_h, filter_w, stride=1, pad=0): 40 | """다수의 이미지를 입력받아 2차원 배열로 변환한다(평탄화). 41 | 42 | Parameters 43 | ---------- 44 | input_data : 4차원 배열 형태의 입력 데이터(이미지 수, 채널 수, 높이, 너비) 45 | filter_h : 필터의 높이 46 | filter_w : 필터의 너비 47 | stride : 스트라이드 48 | pad : 패딩 49 | 50 | Returns 51 | ------- 52 | col : 2차원 배열 53 | """ 54 | N, C, H, W = input_data.shape 55 | out_h = (H + 2*pad - filter_h)//stride + 1 56 | out_w = (W + 2*pad - filter_w)//stride + 1 57 | 58 | img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant') 59 | col = np.zeros((N, C, filter_h, filter_w, out_h, out_w)) 60 | 61 | for y in range(filter_h): 62 | y_max = y + stride*out_h 63 | for x in range(filter_w): 64 | x_max = x + stride*out_w 65 | col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride] 66 | 67 | col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1) 68 | return col 69 | 70 | 71 | def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0): 72 | """(im2col과 반대) 2차원 배열을 입력받아 다수의 이미지 묶음으로 변환한다. 73 | 74 | Parameters 75 | ---------- 76 | col : 2차원 배열(입력 데이터) 77 | input_shape : 원래 이미지 데이터의 형상(예:(10, 1, 28, 28)) 78 | filter_h : 필터의 높이 79 | filter_w : 필터의 너비 80 | stride : 스트라이드 81 | pad : 패딩 82 | 83 | Returns 84 | ------- 85 | img : 변환된 이미지들 86 | """ 87 | N, C, H, W = input_shape 88 | out_h = (H + 2*pad - filter_h)//stride + 1 89 | out_w = (W + 2*pad - filter_w)//stride + 1 90 | col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2) 91 | 92 | img = np.zeros((N, C, H + 2*pad + stride - 1, W + 2*pad + stride - 1)) 93 | for y in range(filter_h): 94 | y_max = y + stride*out_h 95 | for x in range(filter_w): 96 | x_max = x + stride*out_w 97 | img[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :] 98 | 99 | return img[:, :, pad:H + pad, pad:W + pad] 100 | -------------------------------------------------------------------------------- /cover.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/cover.jpeg -------------------------------------------------------------------------------- /cover_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/cover_image.jpg -------------------------------------------------------------------------------- /dataset/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/__init__.py -------------------------------------------------------------------------------- /dataset/cactus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/cactus.png -------------------------------------------------------------------------------- /dataset/cactus_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/cactus_gray.png -------------------------------------------------------------------------------- /dataset/mnist.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | try: 3 | import urllib.request 4 | except ImportError: 5 | raise ImportError('You should use Python 3.x') 6 | import os.path 7 | import gzip 8 | import pickle 9 | import os 10 | import numpy as np 11 | 12 | 13 | url_base = 'http://yann.lecun.com/exdb/mnist/' 14 | key_file = { 15 | 'train_img':'train-images-idx3-ubyte.gz', 16 | 'train_label':'train-labels-idx1-ubyte.gz', 17 | 'test_img':'t10k-images-idx3-ubyte.gz', 18 | 'test_label':'t10k-labels-idx1-ubyte.gz' 19 | } 20 | 21 | dataset_dir = os.path.dirname(os.path.abspath(__file__)) 22 | save_file = dataset_dir + "/mnist.pkl" 23 | 24 | train_num = 60000 25 | test_num = 10000 26 | img_dim = (1, 28, 28) 27 | img_size = 784 28 | 29 | 30 | def _download(file_name): 31 | file_path = dataset_dir + "/" + file_name 32 | 33 | if os.path.exists(file_path): 34 | return 35 | 36 | print("Downloading " + file_name + " ... ") 37 | urllib.request.urlretrieve(url_base + file_name, file_path) 38 | print("Done") 39 | 40 | def download_mnist(): 41 | for v in key_file.values(): 42 | _download(v) 43 | 44 | def _load_label(file_name): 45 | file_path = dataset_dir + "/" + file_name 46 | 47 | print("Converting " + file_name + " to NumPy Array ...") 48 | with gzip.open(file_path, 'rb') as f: 49 | labels = np.frombuffer(f.read(), np.uint8, offset=8) 50 | print("Done") 51 | 52 | return labels 53 | 54 | def _load_img(file_name): 55 | file_path = dataset_dir + "/" + file_name 56 | 57 | print("Converting " + file_name + " to NumPy Array ...") 58 | with gzip.open(file_path, 'rb') as f: 59 | data = np.frombuffer(f.read(), np.uint8, offset=16) 60 | data = data.reshape(-1, img_size) 61 | print("Done") 62 | 63 | return data 64 | 65 | def _convert_numpy(): 66 | dataset = {} 67 | dataset['train_img'] = _load_img(key_file['train_img']) 68 | dataset['train_label'] = _load_label(key_file['train_label']) 69 | dataset['test_img'] = _load_img(key_file['test_img']) 70 | dataset['test_label'] = _load_label(key_file['test_label']) 71 | 72 | return dataset 73 | 74 | def init_mnist(): 75 | download_mnist() 76 | dataset = _convert_numpy() 77 | print("Creating pickle file ...") 78 | with open(save_file, 'wb') as f: 79 | pickle.dump(dataset, f, -1) 80 | print("Done!") 81 | 82 | def _change_one_hot_label(X): 83 | T = np.zeros((X.size, 10)) 84 | for idx, row in enumerate(T): 85 | row[X[idx]] = 1 86 | 87 | return T 88 | 89 | 90 | def load_mnist(normalize=True, flatten=True, one_hot_label=False): 91 | """MNIST 데이터셋 읽기 92 | 93 | Parameters 94 | ---------- 95 | normalize : 이미지의 픽셀 값을 0.0~1.0 사이의 값으로 정규화할지 정한다. 96 | one_hot_label : 97 | one_hot_label이 True면、레이블을 원-핫(one-hot) 배열로 돌려준다. 98 | one-hot 배열은 예를 들어 [0,0,1,0,0,0,0,0,0,0]처럼 한 원소만 1인 배열이다. 99 | flatten : 입력 이미지를 1차원 배열로 만들지를 정한다. 100 | 101 | Returns 102 | ------- 103 | (훈련 이미지, 훈련 레이블), (시험 이미지, 시험 레이블) 104 | """ 105 | if not os.path.exists(save_file): 106 | init_mnist() 107 | 108 | with open(save_file, 'rb') as f: 109 | dataset = pickle.load(f) 110 | 111 | if normalize: 112 | for key in ('train_img', 'test_img'): 113 | dataset[key] = dataset[key].astype(np.float32) 114 | dataset[key] /= 255.0 115 | 116 | if one_hot_label: 117 | dataset['train_label'] = _change_one_hot_label(dataset['train_label']) 118 | dataset['test_label'] = _change_one_hot_label(dataset['test_label']) 119 | 120 | if not flatten: 121 | for key in ('train_img', 'test_img'): 122 | dataset[key] = dataset[key].reshape(-1, 1, 28, 28) 123 | 124 | return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label']) 125 | 126 | 127 | if __name__ == '__main__': 128 | init_mnist() 129 | -------------------------------------------------------------------------------- /dataset/t10k-images-idx3-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/t10k-images-idx3-ubyte.gz -------------------------------------------------------------------------------- /dataset/t10k-labels-idx1-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/t10k-labels-idx1-ubyte.gz -------------------------------------------------------------------------------- /dataset/train-images-idx3-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/train-images-idx3-ubyte.gz -------------------------------------------------------------------------------- /dataset/train-labels-idx1-ubyte.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/dataset/train-labels-idx1-ubyte.gz -------------------------------------------------------------------------------- /equations_and_figures.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/equations_and_figures.zip -------------------------------------------------------------------------------- /map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/map.png -------------------------------------------------------------------------------- /remastered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WegraLee/deep-learning-from-scratch/4fafa7151783f31c9ebc8fb24a4193dfb0e0a2ec/remastered.png --------------------------------------------------------------------------------