├── .gitignore
├── AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》
├── AI从入门到放弃:BP神经网络算法推导及代码实现笔记.html
├── AI从入门到放弃:BP神经网络算法推导及代码实现笔记.pdf
├── AI从入门到放弃:BP神经网络算法推导及代码实现笔记.png
├── NeuralNetwork.py
└── resources
│ ├── 10DA03D78180BD0686C0CB9E691BF459.png
│ ├── 32F79E55C7B0FF938AA82D2D69E3F97B.png
│ ├── 41D98819C2BD4A40EF5FEC7B2221FE29.png
│ ├── 43A0B27F2362DA18F8AEF4E007D6D2DD.png
│ ├── 46B66C214BF95AC6EADC4F4120729397.jpg
│ ├── 49839165F7B45F38E876D865D80D8E04.jpg
│ ├── 5D2344074BC281BA3B5582A65BCCC4B5.jpg
│ ├── 62990B82CC910688B813103D80FCB509.jpg
│ ├── 6EC3CD5AC3B342C739D267519B2BEA57.png
│ ├── 837AA91C395EAE98C77FE7B75E4A6100.jpg
│ ├── 89D527539F0A7055D369F32C68B1F981.png
│ ├── 8B74CF49BA388F18402444C8A7AAAC4F.png
│ ├── AF2E4DBD05E044A145DBA1E169E7594C.jpg
│ ├── D53615C119E3112D9200732F7DDC5643.png
│ ├── E0D33265A98E034A16574FA99388225A.png
│ └── E68468BFF0B3210F75F5293104007E66.jpg
├── AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》
├── AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html
│ ├── AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?.html
│ └── resources
│ │ ├── 18911F9E66B3C88DEC4109AA4E8ED5FB.png
│ │ ├── 31E1ECF3F19D72C84CA3DA925C0CB9DD.png
│ │ ├── 5352CC63BE1E522FF056853AA1A26253.png
│ │ ├── 630243EC928C70E4417306DFBB39A9D1.jpg
│ │ ├── A3E4523C6F2874F6555CD9A1EAEBE5B0.png
│ │ ├── BCDD7CADA14ADFC183B9AFBCCB0B8A1C.png
│ │ ├── C557C61880CBC43A9C4E776802CC06D0.jpg
│ │ └── CBCBF0C20D17CDDAC3EE968D43FC0B54.png
├── AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?.pdf
├── cat_pics_my.png
├── cat_pics_my_predict.png
├── cat_pics_test.png
├── cat_pics_test_predict.png
├── cat_pics_train.png
├── cat_pics_train_predict.png
├── datasets
│ ├── my_cat_misu.h5
│ ├── test_catvnoncat.h5
│ └── train_catvnoncat.h5
├── misu.jpg
└── picture_classification.py
├── AI从入门到放弃:《手撕神经卷积网络(CNN)》
├── AI从入门到放弃:手撕卷积神经网络(CNN).pdf
├── CNN-Network
│ ├── .idea
│ │ ├── CNN-Network.iml
│ │ ├── inspectionProfiles
│ │ │ └── Project_Default.xml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ └── workspace.xml
│ ├── Data
│ │ └── mnist
│ │ │ ├── get_mnist.sh
│ │ │ ├── t10k-images-idx3-ubyte
│ │ │ ├── t10k-labels-idx1-ubyte
│ │ │ ├── train-images-idx3-ubyte
│ │ │ └── train-labels-idx1-ubyte
│ ├── Layers
│ │ ├── Convolution.py
│ │ ├── Flatten.py
│ │ ├── FullConnection.py
│ │ ├── MnistInput.py
│ │ ├── NetworkBuilder.py
│ │ ├── Pooling.py
│ │ ├── Relu.py
│ │ ├── SoftmaxLoss.py
│ │ └── __init__.py
│ ├── Model
│ │ └── model.h5
│ ├── OutputImages
│ │ ├── conv1_output.png
│ │ ├── conv2_output.png
│ │ ├── fc1_output.png
│ │ ├── fc2_output.png
│ │ ├── flatten_output.png
│ │ ├── mnist_data_output.png
│ │ ├── pool1_output.png
│ │ ├── pool2_output.png
│ │ ├── relu1_output.png
│ │ ├── softmax_loss_output.png
│ │ └── train_pics.png
│ └── main.py
├── Html版本
│ ├── AI从入门到放弃:手撕卷积神经网络(CNN).html
│ └── resources
│ │ ├── 04C9E0B3DDFFAE6DBF0692451F6992D1.gif
│ │ ├── 08E51AD720981A718F79635F3C175469.jpg
│ │ ├── 173BE7B5673987828414CBAB75111379.jpg
│ │ ├── 1E97985A1B2BB3FE1B5C98D77AC5A403.png
│ │ ├── 24170F1D134952DFD522B4CADC1FFD8F.jpg
│ │ ├── 29CED44A9D37FEC25A2448EE9B041256.jpg
│ │ ├── 2B3B1E8B6725BE2CBEDC4466384042A7.jpg
│ │ ├── 2FA771C954BE667E95561579518D46F0.jpg
│ │ ├── 3BA9904D9A93E639A6577E317A295DD0.jpg
│ │ ├── 45C1395B84E554772D1AFB28C80EE7C9.jpg
│ │ ├── 49FDC432141B5F7D59B17F93E594A777.jpg
│ │ ├── 53081124276177707263BF45B962832D.jpg
│ │ ├── 705305FEE5A050575544C64067405FCE.gif
│ │ ├── 7CED4CBD723175E6811557CA99B83837.jpg
│ │ ├── 85182DA6962E2C26664D03DC1647AB31.jpg
│ │ ├── 8645FA96B78267F6B995D7909C263CE4.gif
│ │ ├── 8D72F4E6CDD66BC654D440390E42F922.jpg
│ │ ├── 965FBFC2D682036ED178B7DD1EDD50FA.gif
│ │ ├── 9EEC442D8B126FD3F3B53E19704201A9.jpg
│ │ ├── A5BFC0E4FDD254F431C6B702CFB6E463.jpg
│ │ ├── ACB9841BC14C57C09CA27F6ED6BBEC5C.jpg
│ │ ├── B9663FCC0A0B42FA0E7082FFC1BFF9E3.jpg
│ │ ├── BAAF3CFE34D7CFE2F69F7F8AE0D42735.jpg
│ │ ├── BCBCEFAF634DEA7AEA8B53898F1BA866.jpg
│ │ ├── CA203A8C36C14AE9C2DC0870C1ECE8E6.jpg
│ │ ├── CB3DF2830392E247AA78C4F33230483C.jpg
│ │ ├── D6893085EC1FE4A0AD20F68589BE1768.gif
│ │ ├── DC6921D73DAB14ED98A26032A73F0AA9.gif
│ │ ├── E351E2E6EDC5210A4C60E2E09DC1C43C.jpg
│ │ ├── E5189072F39325215235950E90F6F9EF.jpg
│ │ ├── E61DF3C6A20A5F78F43CE5789F7FD9FF.jpg
│ │ ├── EBD4E3242A6B9AB67BE41F808DD2FD8E.jpg
│ │ ├── FA8B0532561AD9A74CAAF78BD7175437.jpg
│ │ ├── FB2E612B54BB961753B87FDCBC9D1E68.jpg
│ │ ├── FD3AADAD7C3BF1F8C190E84BCAB47DF9.jpg
│ │ ├── FDE7CEEA3FB146BDDCA545DB6BD3B6CC.jpg
│ │ ├── FE0DB3B95EB7135EB37A8EE627A6FE08.jpg
│ │ └── FFE5AA9D3CA5F3A1248F531F72E20B1A.jpg
└── Markdown版本
│ ├── AI从入门到放弃:手撕卷积神经网络(CNN).md
│ └── resources
│ ├── 04C9E0B3DDFFAE6DBF0692451F6992D1.gif
│ ├── 08E51AD720981A718F79635F3C175469.jpg
│ ├── 173BE7B5673987828414CBAB75111379.jpg
│ ├── 1E97985A1B2BB3FE1B5C98D77AC5A403.png
│ ├── 24170F1D134952DFD522B4CADC1FFD8F.jpg
│ ├── 29CED44A9D37FEC25A2448EE9B041256.jpg
│ ├── 2B3B1E8B6725BE2CBEDC4466384042A7.jpg
│ ├── 2FA771C954BE667E95561579518D46F0.jpg
│ ├── 3BA9904D9A93E639A6577E317A295DD0.jpg
│ ├── 45C1395B84E554772D1AFB28C80EE7C9.jpg
│ ├── 49FDC432141B5F7D59B17F93E594A777.jpg
│ ├── 53081124276177707263BF45B962832D.jpg
│ ├── 705305FEE5A050575544C64067405FCE.gif
│ ├── 7CED4CBD723175E6811557CA99B83837.jpg
│ ├── 85182DA6962E2C26664D03DC1647AB31.jpg
│ ├── 8645FA96B78267F6B995D7909C263CE4.gif
│ ├── 8D72F4E6CDD66BC654D440390E42F922.jpg
│ ├── 965FBFC2D682036ED178B7DD1EDD50FA.gif
│ ├── 9EEC442D8B126FD3F3B53E19704201A9.jpg
│ ├── A5BFC0E4FDD254F431C6B702CFB6E463.jpg
│ ├── ACB9841BC14C57C09CA27F6ED6BBEC5C.jpg
│ ├── B9663FCC0A0B42FA0E7082FFC1BFF9E3.jpg
│ ├── BAAF3CFE34D7CFE2F69F7F8AE0D42735.jpg
│ ├── BCBCEFAF634DEA7AEA8B53898F1BA866.jpg
│ ├── CA203A8C36C14AE9C2DC0870C1ECE8E6.jpg
│ ├── CB3DF2830392E247AA78C4F33230483C.jpg
│ ├── D6893085EC1FE4A0AD20F68589BE1768.gif
│ ├── DC6921D73DAB14ED98A26032A73F0AA9.gif
│ ├── E351E2E6EDC5210A4C60E2E09DC1C43C.jpg
│ ├── E5189072F39325215235950E90F6F9EF.jpg
│ ├── E61DF3C6A20A5F78F43CE5789F7FD9FF.jpg
│ ├── EBD4E3242A6B9AB67BE41F808DD2FD8E.jpg
│ ├── FA8B0532561AD9A74CAAF78BD7175437.jpg
│ ├── FB2E612B54BB961753B87FDCBC9D1E68.jpg
│ ├── FD3AADAD7C3BF1F8C190E84BCAB47DF9.jpg
│ ├── FDE7CEEA3FB146BDDCA545DB6BD3B6CC.jpg
│ ├── FE0DB3B95EB7135EB37A8EE627A6FE08.jpg
│ └── FFE5AA9D3CA5F3A1248F531F72E20B1A.jpg
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/AI从入门到放弃:BP神经网络算法推导及代码实现笔记.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/AI从入门到放弃:BP神经网络算法推导及代码实现笔记.pdf
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/AI从入门到放弃:BP神经网络算法推导及代码实现笔记.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/AI从入门到放弃:BP神经网络算法推导及代码实现笔记.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/NeuralNetwork.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | import sklearn.datasets
3 | import sklearn.linear_model
4 | import matplotlib
5 | import matplotlib.font_manager as fm
6 | import matplotlib.pyplot as plt
7 | import numpy as np
8 |
9 | np.random.seed(1)
10 |
11 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
12 | matplotlib.rcParams['figure.figsize'] = (10.0, 8.0)
13 |
14 | def sigmoid(input_sum):
15 | """
16 | 函数:
17 | 激活函数Sigmoid
18 | 输入:
19 | input_sum: 输入,即神经元的加权和
20 | 返回:
21 | output: 激活后的输出
22 | input_sum: 把输入缓存起来返回
23 | """
24 | output = 1.0/(1+np.exp(-input_sum))
25 | return output, input_sum
26 |
27 |
28 | def sigmoid_back_propagation(derror_wrt_output, input_sum):
29 | """
30 | 函数:
31 | 误差关于神经元输入的偏导: dE/dIn = dE/dOut * dOut/dIn 参照式(5.6)
32 | 其中: dOut/dIn 就是激活函数的导数 dy=y(1 - y),见式(5.9)
33 | dE/dOut 误差对神经元输出的偏导,见式(5.8)
34 | 输入:
35 | derror_wrt_output:误差关于神经元输出的偏导: dE/dyⱼ = 1/2(d(expect_to_output - output)**2/doutput) = -(expect_to_output - output)
36 | input_sum: 输入加权和
37 | 返回:
38 | derror_wrt_dinputs: 误差关于输入的偏导,见式(5.13)
39 | """
40 | output = 1.0/(1 + np.exp(- input_sum))
41 | doutput_wrt_dinput = output * (1 - output)
42 | derror_wrt_dinput = derror_wrt_output * doutput_wrt_dinput
43 |
44 | return derror_wrt_dinput
45 |
46 |
47 | def relu(input_sum):
48 | """
49 | 函数:
50 | 激活函数ReLU
51 | 输入:
52 | input_sum: 输入,即神经元的加权和
53 | 返回:
54 | outputs: 激活后的输出
55 | input_sum: 把输入缓存起来返回
56 | """
57 | output = np.maximum(0, input_sum)
58 | return output, input_sum
59 |
60 |
61 | def relu_back_propagation(derror_wrt_output, input_sum):
62 | """
63 | 函数:
64 | 误差关于神经元输入的偏导: dE/dIn = dE/dOut * dOut/dIn
65 | 其中: dOut/dIn 就是激活函数的导数
66 | dE/dOut 误差对神经元输出的偏导
67 | 输入:
68 | derror_wrt_output:误差关于神经元输出的偏导
69 | input_sum: 输入加权和
70 | 返回:
71 | derror_wrt_dinputs: 误差关于输入的偏导
72 | """
73 | derror_wrt_dinputs = np.array(derror_wrt_output, copy=True)
74 | derror_wrt_dinputs[input_sum <= 0] = 0
75 |
76 | return derror_wrt_dinputs
77 |
78 |
79 | def tanh(input_sum):
80 | """
81 | 函数:
82 | 激活函数 tanh
83 | 输入:
84 | input_sum: 输入,即神经元的加权和
85 | 返回:
86 | output: 激活后的输出
87 | input_sum: 把输入缓存起来返回
88 | """
89 | output = np.tanh(input_sum)
90 | return output, input_sum
91 |
92 |
93 | def tanh_back_propagation(derror_wrt_output, input_sum):
94 | """
95 | 函数:
96 | 误差关于神经元输入的偏导: dE/dIn = dE/dOut * dOut/dIn
97 | 其中: dOut/dIn 就是激活函数的导数 tanh'(x) = 1 - x²
98 | dE/dOut 误差对神经元输出的偏导
99 | 输入:
100 | derror_wrt_output:误差关于神经元输出的偏导: dE/dyⱼ = 1/2(d(expect_to_output - output)**2/doutput) = -(expect_to_output - output)
101 | input_sum: 输入加权和
102 | 返回:
103 | derror_wrt_dinputs: 误差关于输入的偏导
104 | """
105 | output = np.tanh(input_sum)
106 | doutput_wrt_dinput = 1 - np.power(output, 2)
107 | derror_wrt_dinput = derror_wrt_output * doutput_wrt_dinput
108 |
109 | return derror_wrt_dinput
110 |
111 |
112 | def activated(activation_choose, input):
113 | """把正向激活包装一下"""
114 | if activation_choose == "sigmoid":
115 | return sigmoid(input)
116 | elif activation_choose == "relu":
117 | return relu(input)
118 | elif activation_choose == "tanh":
119 | return tanh(input)
120 |
121 | return sigmoid(input)
122 |
123 | def activated_back_propagation(activation_choose, derror_wrt_output, output):
124 | """包装反向激活传播"""
125 | if activation_choose == "sigmoid":
126 | return sigmoid_back_propagation(derror_wrt_output, output)
127 | elif activation_choose == "relu":
128 | return relu_back_propagation(derror_wrt_output, output)
129 | elif activation_choose == "tanh":
130 | return tanh_back_propagation(derror_wrt_output, output)
131 |
132 | return sigmoid_back_propagation(derror_wrt_output, output)
133 |
134 | class NeuralNetwork:
135 | """
136 | 神经网络
137 | 支持深度网络,例如,设计一个5层网络,则layers_strcuture=[2,10,7,5,2]
138 | """
139 | def __init__(self, layers_strcuture, print_cost = False):
140 | self.layers_strcuture = layers_strcuture
141 | self.layers_num = len(layers_strcuture)
142 |
143 | # 除掉输入层的网络层数,因为其他层才是真正的神经元层
144 | self.param_layers_num = self.layers_num - 1
145 |
146 | self.learning_rate = 0.0618
147 | self.num_iterations = 2000
148 | self.x = None
149 | self.y = None
150 | self.w = dict()
151 | self.b = dict()
152 | self.costs = []
153 | self.print_cost = print_cost
154 |
155 | self.init_w_and_b()
156 |
157 | def set_learning_rate(self, learning_rate):
158 | """设置学习率"""
159 | self.learning_rate = learning_rate
160 |
161 | def set_num_iterations(self, num_iterations):
162 | """设置迭代次数"""
163 | self.num_iterations = num_iterations
164 |
165 | def set_xy(self, input, expected_output):
166 | """设置神经网络的输入和期望的输出"""
167 | self.x = input
168 | self.y = expected_output
169 |
170 | def init_w_and_b(self):
171 | """
172 | 函数:
173 | 初始化神经网络所有参数
174 | 输入:
175 | layers_strcuture: 神经网络的结构,例如[2,4,3,1],4层结构:
176 | 第0层输入层接收2个数据,第1层隐藏层4个神经元,第2层隐藏层3个神经元,第3层输出层1个神经元
177 | 返回: 神经网络各层参数的索引表,用来定位权值 wᵢ 和偏置 bᵢ,i为网络层编号
178 | """
179 | np.random.seed(3)
180 |
181 | # 当前神经元层的权值为 n_i x n_(i-1)的矩阵,i为网络层编号,n为下标i代表的网络层的节点个数
182 | # 例如[2,4,3,1],4层结构:第0层输入层为2,那么第1层隐藏层神经元个数为4
183 | # 那么第1层的权值w是一个 4x2 的矩阵,如:
184 | # w1 = array([ [-0.96927756, -0.59273074],
185 | # [ 0.58227367, 0.45993021],
186 | # [-0.02270222, 0.13577601],
187 | # [-0.07912066, -1.49802751] ])
188 | # 当前层的偏置一般给0就行,偏置是个1xnᵢ的矩阵,nᵢ为第i层的节点个数,例如第1层为4个节点,那么:
189 | # b1 = array([ 0., 0., 0., 0.])
190 |
191 | for l in range(1, self.layers_num):
192 | self.w["w" + str(l)] = np.random.randn(self.layers_strcuture[l], self.layers_strcuture[l-1])/np.sqrt(self.layers_strcuture[l-1])
193 | self.b["b" + str(l)] = np.zeros((self.layers_strcuture[l], 1))
194 |
195 | return self.w, self.b
196 |
197 | def layer_activation_forward(self, x, w, b, activation_choose):
198 | """
199 | 函数:
200 | 网络层的正向传播
201 | 输入:
202 | x: 当前网络层输入(即上一层的输出),一般是所有训练数据,即输入矩阵
203 | w: 当前网络层的权值矩阵
204 | b: 当前网络层的偏置矩阵
205 | activation_choose: 选择激活函数 "sigmoid", "relu", "tanh"
206 | 返回:
207 | output: 网络层的激活输出
208 | cache: 缓存该网络层的信息,供后续使用: (x, w, b, input_sum) -> cache
209 | """
210 |
211 | # 对输入求加权和,见式(5.1)
212 | input_sum = np.dot(w, x) + b
213 |
214 | # 对输入加权和进行激活输出
215 | output, _ = activated(activation_choose, input_sum)
216 |
217 | return output, (x, w, b, input_sum)
218 |
219 | def forward_propagation(self, x):
220 | """
221 | 函数:
222 | 神经网络的正向传播
223 | 输入:
224 |
225 | 返回:
226 | output: 正向传播完成后的输出层的输出
227 | caches: 正向传播过程中缓存每一个网络层的信息: (x, w, b, input_sum),... -> caches
228 | """
229 | caches = []
230 |
231 | #作为输入层,输出 = 输入
232 | output_prev = x
233 |
234 | #第0层为输入层,只负责观察到输入的数据,并不需要处理,正向传播从第1层开始,一直到输出层输出为止
235 | # range(1, n) => [1, 2, ..., n-1]
236 | L = self.param_layers_num
237 | for l in range(1, L):
238 | # 当前网络层的输入来自前一层的输出
239 | input_cur = output_prev
240 | output_prev, cache = self.layer_activation_forward(input_cur, self.w["w"+ str(l)], self.b["b" + str(l)], "relu")
241 | caches.append(cache)
242 |
243 | output, cache = self.layer_activation_forward(output_prev, self.w["w" + str(L)], self.b["b" + str(L)], "sigmoid")
244 | caches.append(cache)
245 |
246 | return output, caches
247 |
248 | def show_caches(self, caches):
249 | """显示网络层的缓存参数信息"""
250 | i = 1
251 | for cache in caches:
252 | print("%dtd Layer" % i)
253 | print(" input: %s" % cache[0])
254 | print(" w: %s" % cache[1])
255 | print(" b: %s" % cache[2])
256 | print(" input_sum: %s" % cache[3])
257 | print("----------")
258 | i += 1
259 |
260 | def compute_error(self, output):
261 | """
262 | 函数:
263 | 计算档次迭代的输出总误差
264 | 输入:
265 |
266 | 返回:
267 |
268 | """
269 |
270 | m = self.y.shape[1]
271 |
272 | # 计算误差,见式(5.5): E = Σ1/2(期望输出-实际输出)²
273 | #error = np.sum(0.5 * (self.y - output) ** 2) / m
274 |
275 | # 交叉熵作为误差函数
276 | error = -np.sum(np.multiply(np.log(output),self.y) + np.multiply(np.log(1 - output), 1 - self.y)) / m
277 | error = np.squeeze(error)
278 |
279 | return error
280 |
281 | def layer_activation_backward(self, derror_wrt_output, cache, activation_choose):
282 | """
283 | 函数:
284 | 网络层的反向传播
285 | 输入:
286 | derror_wrt_output: 误差关于输出的偏导
287 | cache: 网络层的缓存信息 (x, w, b, input_sum)
288 | activation_choose: 选择激活函数 "sigmoid", "relu", "tanh"
289 | 返回: 梯度信息,即
290 | derror_wrt_output_prev: 反向传播到上一层的误差关于输出的梯度
291 | derror_wrt_dw: 误差关于权值的梯度
292 | derror_wrt_db: 误差关于偏置的梯度
293 | """
294 | input, w, b, input_sum = cache
295 | output_prev = input # 上一层的输出 = 当前层的输入; 注意是'输入'不是输入的加权和(input_sum)
296 | m = output_prev.shape[1] # m是输入的样本数量,我们要取均值,所以下面的求值要除以m
297 |
298 | # 实现式(5.13)-> 误差关于权值w的偏导数
299 | derror_wrt_dinput = activated_back_propagation(activation_choose, derror_wrt_output, input_sum)
300 | derror_wrt_dw = np.dot(derror_wrt_dinput, output_prev.T) / m
301 |
302 | # 实现式 (5.32)-> 误差关于偏置b的偏导数
303 | derror_wrt_db = np.sum(derror_wrt_dinput, axis=1, keepdims=True)/m
304 |
305 | # 为反向传播到上一层提供误差传递,见式(5.28)的 (Σδ·w) 部分
306 | derror_wrt_output_prev = np.dot(w.T, derror_wrt_dinput)
307 |
308 | return derror_wrt_output_prev, derror_wrt_dw, derror_wrt_db
309 |
310 | def back_propagation(self, output, caches):
311 | """
312 | 函数:
313 | 神经网络的反向传播
314 | 输入:
315 | output:神经网络输
316 | caches:所有网络层(输入层不算)的缓存参数信息 [(x, w, b, input_sum), ...]
317 | 返回:
318 | grads: 返回当前迭代的梯度信息
319 | """
320 | grads = {}
321 | L = self.param_layers_num #
322 | output = output.reshape(output.shape) # 把输出层输出输出重构成和期望输出一样的结构
323 |
324 | expected_output = self.y
325 |
326 | # 见式(5.8)
327 | #derror_wrt_output = -(expected_output - output)
328 |
329 | # 交叉熵作为误差函数
330 | derror_wrt_output = - (np.divide(expected_output, output) - np.divide(1 - expected_output, 1 - output))
331 |
332 | # 反向传播:输出层 -> 隐藏层,得到梯度:见式(5.8), (5.13), (5.15)
333 | current_cache = caches[L - 1] # 取最后一层,即输出层的参数信息
334 | grads["derror_wrt_output" + str(L)], grads["derror_wrt_dw" + str(L)], grads["derror_wrt_db" + str(L)] = \
335 | self.layer_activation_backward(derror_wrt_output, current_cache, "sigmoid")
336 |
337 | # 反向传播:隐藏层 -> 隐藏层,得到梯度:见式 (5.28)的(Σδ·w), (5.28), (5.32)
338 | for l in reversed(range(L - 1)):
339 | current_cache = caches[l]
340 | derror_wrt_output_prev_temp, derror_wrt_dw_temp, derror_wrt_db_temp = \
341 | self.layer_activation_backward(grads["derror_wrt_output" + str(l + 2)], current_cache, "relu")
342 |
343 | grads["derror_wrt_output" + str(l + 1)] = derror_wrt_output_prev_temp
344 | grads["derror_wrt_dw" + str(l + 1)] = derror_wrt_dw_temp
345 | grads["derror_wrt_db" + str(l + 1)] = derror_wrt_db_temp
346 |
347 | return grads
348 |
349 | def update_w_and_b(self, grads):
350 | """
351 | 函数:
352 | 根据梯度信息更新w,b
353 | 输入:
354 | grads:当前迭代的梯度信息
355 | 返回:
356 |
357 | """
358 | # 权值w和偏置b的更新,见式:(5.16),(5.18)
359 | for l in range(self.param_layers_num):
360 | self.w["w" + str(l + 1)] = self.w["w" + str(l + 1)] - self.learning_rate * grads["derror_wrt_dw" + str(l + 1)]
361 | self.b["b" + str(l + 1)] = self.b["b" + str(l + 1)] - self.learning_rate * grads["derror_wrt_db" + str(l + 1)]
362 |
363 | def training_modle(self):
364 | """训练神经网络模型"""
365 |
366 | np.random.seed(5)
367 | for i in range(0, self.num_iterations):
368 | # 正向传播,得到网络输出,以及每一层的参数信息
369 | output, caches = self.forward_propagation(self.x)
370 |
371 | # 计算网络输出误差
372 | cost = self.compute_error(output)
373 |
374 | # 反向传播,得到梯度信息
375 | grads = self.back_propagation(output, caches)
376 |
377 | # 根据梯度信息,更新权值w和偏置b
378 | self.update_w_and_b(grads)
379 |
380 | # 当次迭代结束,打印误差信息
381 | if self.print_cost and i % 100 == 0:
382 | print ("Cost after iteration %i: %f" % (i, cost))
383 | if self.print_cost and i % 100 == 0:
384 | self.costs.append(cost)
385 |
386 | # 模型训练完后显示误差曲线
387 | if False:
388 | plt.plot(np.squeeze(self.costs))
389 | plt.ylabel(u'神经网络误差', fontproperties = font)
390 | plt.xlabel(u'迭代次数 (*100)', fontproperties = font)
391 | plt.title(u"学习率 =" + str(self.learning_rate), fontproperties = font)
392 | plt.show()
393 |
394 | return self.w, self.b
395 |
396 | def predict_by_modle(self, x):
397 | """使用训练好的模型(即最后求得w,b参数)来决策输入的样本的结果"""
398 | output, _ = self.forward_propagation(x.T)
399 | output = output.T
400 | result = output / np.sum(output, axis=1, keepdims=True)
401 | return np.argmax(result, axis=1)
402 |
403 |
404 | def plot_decision_boundary(xy, colors, pred_func):
405 | # xy是坐标点的集合,把集合的范围算出来
406 | # 加减0.5相当于扩大画布的范围,不然画出来的图坐标点会落在图的边缘,逼死强迫症患者
407 | x_min, x_max = xy[:, 0].min() - 0.5, xy[:, 0].max() + 0.5
408 | y_min, y_max = xy[:, 1].min() - 0.5, xy[:, 1].max() + 0.5
409 |
410 | # 以h为分辨率,生成采样点的网格,就像一张网覆盖所有颜色点
411 | h = .01
412 | xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
413 |
414 | # 把网格点集合作为输入到模型,也就是预测这个采样点是什么颜色的点,从而得到一个决策面
415 | Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
416 | Z = Z.reshape(xx.shape)
417 |
418 | # 利用等高线,把预测的结果画出来,效果上就是画出红蓝点的分界线
419 | plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
420 |
421 | # 训练用的红蓝点点也画出来
422 | plt.scatter(xy[:, 0], xy[:, 1], c=colors, marker='o', cmap=plt.cm.Spectral, edgecolors='black')
423 |
424 |
425 | if __name__ == "__main__":
426 | plt.figure(figsize=(16, 32))
427 |
428 | # 用sklearn的数据样本集,产生2种颜色的坐标点,noise是噪声系数,噪声越大,2种颜色的点分布越凌乱
429 | xy, colors = sklearn.datasets.make_moons(60, noise=1.0)
430 |
431 | # 因为点的颜色是1bit,我们设计一个神经网络,输出层有2个神经元。
432 | # 标定输出[1,0]为红色点,输出[0,1]为蓝色点
433 | expect_outputed = []
434 | for c in colors:
435 | if c == 1:
436 | expect_outputed.append([0,1])
437 | else:
438 | expect_outputed.append([1,0])
439 |
440 | expect_outputed = np.array(expect_outputed).T
441 |
442 | # 设计3层网络,改变隐藏层神经元的个数,观察神经网络分类红蓝点的效果
443 | hidden_layer_neuron_num_list = [1,2,4,10,20,50]
444 | for i, hidden_layer_neuron_num in enumerate(hidden_layer_neuron_num_list):
445 | plt.subplot(5, 2, i + 1)
446 | plt.title(u'隐藏层神经元数量: %d' % hidden_layer_neuron_num, fontproperties = font)
447 |
448 | nn = NeuralNetwork([2, hidden_layer_neuron_num, 2], True)
449 |
450 | # 输出和输入层都是2个节点,所以输入和输出的数据集合都要是 nx2的矩阵
451 | nn.set_xy(xy.T, expect_outputed)
452 | nn.set_num_iterations(25000)
453 | nn.set_learning_rate(0.1)
454 | w, b = nn.training_modle()
455 | plot_decision_boundary(xy, colors, nn.predict_by_modle)
456 |
457 | plt.show()
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/10DA03D78180BD0686C0CB9E691BF459.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/10DA03D78180BD0686C0CB9E691BF459.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/32F79E55C7B0FF938AA82D2D69E3F97B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/32F79E55C7B0FF938AA82D2D69E3F97B.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/41D98819C2BD4A40EF5FEC7B2221FE29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/41D98819C2BD4A40EF5FEC7B2221FE29.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/43A0B27F2362DA18F8AEF4E007D6D2DD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/43A0B27F2362DA18F8AEF4E007D6D2DD.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/46B66C214BF95AC6EADC4F4120729397.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/46B66C214BF95AC6EADC4F4120729397.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/49839165F7B45F38E876D865D80D8E04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/49839165F7B45F38E876D865D80D8E04.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/5D2344074BC281BA3B5582A65BCCC4B5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/5D2344074BC281BA3B5582A65BCCC4B5.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/62990B82CC910688B813103D80FCB509.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/62990B82CC910688B813103D80FCB509.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/6EC3CD5AC3B342C739D267519B2BEA57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/6EC3CD5AC3B342C739D267519B2BEA57.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/837AA91C395EAE98C77FE7B75E4A6100.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/837AA91C395EAE98C77FE7B75E4A6100.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/89D527539F0A7055D369F32C68B1F981.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/89D527539F0A7055D369F32C68B1F981.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/8B74CF49BA388F18402444C8A7AAAC4F.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/8B74CF49BA388F18402444C8A7AAAC4F.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/AF2E4DBD05E044A145DBA1E169E7594C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/AF2E4DBD05E044A145DBA1E169E7594C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/D53615C119E3112D9200732F7DDC5643.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/D53615C119E3112D9200732F7DDC5643.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/E0D33265A98E034A16574FA99388225A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/E0D33265A98E034A16574FA99388225A.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/E68468BFF0B3210F75F5293104007E66.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《BP神经网络算法推导及代码实现笔记》/resources/E68468BFF0B3210F75F5293104007E66.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/18911F9E66B3C88DEC4109AA4E8ED5FB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/18911F9E66B3C88DEC4109AA4E8ED5FB.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/31E1ECF3F19D72C84CA3DA925C0CB9DD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/31E1ECF3F19D72C84CA3DA925C0CB9DD.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/5352CC63BE1E522FF056853AA1A26253.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/5352CC63BE1E522FF056853AA1A26253.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/630243EC928C70E4417306DFBB39A9D1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/630243EC928C70E4417306DFBB39A9D1.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/A3E4523C6F2874F6555CD9A1EAEBE5B0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/A3E4523C6F2874F6555CD9A1EAEBE5B0.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/BCDD7CADA14ADFC183B9AFBCCB0B8A1C.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/BCDD7CADA14ADFC183B9AFBCCB0B8A1C.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/C557C61880CBC43A9C4E776802CC06D0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/C557C61880CBC43A9C4E776802CC06D0.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/CBCBF0C20D17CDDAC3EE968D43FC0B54.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?--html/resources/CBCBF0C20D17CDDAC3EE968D43FC0B54.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?.pdf
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_my.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_my.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_my_predict.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_my_predict.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_test.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_test_predict.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_test_predict.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_train.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_train.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_train_predict.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/cat_pics_train_predict.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/datasets/my_cat_misu.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/datasets/my_cat_misu.h5
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/datasets/test_catvnoncat.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/datasets/test_catvnoncat.h5
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/datasets/train_catvnoncat.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/datasets/train_catvnoncat.h5
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/misu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/misu.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《CNN的导火索,用MLP做图像分类识别?》/picture_classification.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | import h5py
3 | import matplotlib.font_manager as fm
4 | import matplotlib.pyplot as plt
5 | import numpy as np
6 | from NeuralNetwork import *
7 |
8 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
9 |
10 | def load_Cat_dataset():
11 | train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
12 | train_set_x_orig = np.array(train_dataset["train_set_x"][:])
13 | train_set_y_orig = np.array(train_dataset["train_set_y"][:])
14 |
15 | test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
16 | test_set_x_orig = np.array(test_dataset["test_set_x"][:])
17 | test_set_y_orig = np.array(test_dataset["test_set_y"][:])
18 |
19 | mycat_dataset = h5py.File('datasets/my_cat_misu.h5', "r")
20 | mycat_set_x_orig = np.array(mycat_dataset["mycat_set_x"][:])
21 | mycat_set_y_orig = np.array(mycat_dataset["mycat_set_y"][:])
22 |
23 | classes = np.array(test_dataset["list_classes"][:])
24 |
25 | train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
26 | test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
27 | mycat_set_y_orig = mycat_set_y_orig.reshape((1, mycat_set_y_orig.shape[0]))
28 |
29 | return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, mycat_set_x_orig, mycat_set_y_orig,classes
30 |
31 |
32 | def predict_by_modle(x, y, nn):
33 |
34 | m = x.shape[1]
35 | p = np.zeros((1,m))
36 |
37 | output, caches = nn.forward_propagation(x)
38 |
39 | for i in range(0, output.shape[1]):
40 | if output[0,i] > 0.5:
41 | p[0,i] = 1
42 | else:
43 | p[0,i] = 0
44 |
45 | # 预测出来的结果和期望的结果比对,看看准确率多少:
46 | # 比如100张预测图片里有50张猫的图片,只识别出40张,那么识别率就是80%
47 | print(u"识别率: " + str(np.sum((p == y)/float(m))))
48 | return np.array(p[0], dtype=np.int), (p==y)[0], np.sum((p == y)/float(m))*100
49 |
50 |
51 | def save_imgs_to_h5file(h5_fname, x_label, y_label, img_paths_list, img_label_list):
52 | data_imgs = np.random.rand(len(img_paths_list), 64, 64, 3).astype('int')
53 | label_imgs = np.random.rand(len(img_paths_list), 1).astype('int')
54 |
55 | for i in range(len(img_paths_list)):
56 | data_imgs[i] = np.array(plt.imread(img_paths_list[i]))
57 | label_imgs[i] = np.array(img_label_list[i])
58 |
59 | f = h5py.File(h5_fname, 'w')
60 | f.create_dataset(x_label, data=data_imgs)
61 | f.create_dataset(y_label, data=label_imgs)
62 | f.close()
63 |
64 | return data_imgs, label_imgs
65 |
66 | if __name__ == "__main__":
67 | # 图片label为1代表这是一张喵星人的图片,0代表不是
68 | #save_imgs_to_h5file('datasets/my_cat_misu.h5', 'mycat_set_x', 'mycat_set_y', ['misu.jpg'],[1])
69 |
70 | train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, mycat_set_x_orig, mycat_set_y_orig, classes = load_Cat_dataset()
71 |
72 | train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
73 | test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T
74 | mycat_x_flatten = mycat_set_x_orig.reshape(mycat_set_x_orig.shape[0], -1).T
75 | train_set_x = train_x_flatten / 255.
76 | test_set_x = test_x_flatten / 255.
77 | mycat_set_x = mycat_x_flatten / 255.
78 |
79 | print(u"训练图片数量: %d" % len(train_set_x_orig))
80 | print(u"测试图片数量: %d" % len(test_set_x_orig))
81 |
82 | plt.figure(figsize=(10, 20))
83 | plt.subplots_adjust(wspace=0,hspace=0.15)
84 | for i in range(len(train_set_x_orig)):
85 | plt.subplot(21,10, i+1)
86 | plt.imshow(train_set_x_orig[i],interpolation='none',cmap='Reds_r',vmin=0.6,vmax=.9)
87 | plt.xticks([])
88 | plt.yticks([])
89 | plt.savefig("cat_pics_train.png")
90 | plt.show()
91 |
92 | plt.figure(figsize=(8, 8))
93 | plt.subplots_adjust(wspace=0, hspace=0.1)
94 | for i in range(len(test_set_x_orig)):
95 | ax = plt.subplot(8, 8, i + 1)
96 | im = ax.imshow(test_set_x_orig[i], interpolation='none', cmap='Reds_r', vmin=0.6, vmax=.9)
97 | plt.xticks([])
98 | plt.yticks([])
99 |
100 | plt.savefig("cat_pics_test.png")
101 | plt.show()
102 |
103 | plt.figure(figsize=(2, 2))
104 | plt.subplots_adjust(wspace=0, hspace=0)
105 | for i in range(len(mycat_set_x_orig)):
106 | ax = plt.subplot(1, 1, i + 1)
107 | im = ax.imshow(mycat_set_x_orig[i], interpolation='none', cmap='Reds_r', vmin=0.6, vmax=.9)
108 | plt.xticks([])
109 | plt.yticks([])
110 |
111 | plt.savefig("cat_pics_my.png")
112 | plt.show()
113 |
114 | # 用训练图片集训练模型
115 | layers_dims = [12288, 20, 7, 5, 1]
116 | nn = NeuralNetwork(layers_dims, True)
117 | nn.set_xy(train_set_x, train_set_y_orig)
118 | nn.set_num_iterations(10000)
119 | nn.set_learning_rate(0.0075)
120 | nn.training_modle()
121 |
122 | # 结果展示说明:
123 | # 【识别正确】:
124 | # 1.原图是猫,识别为猫 --> 原图显示
125 | # 2.原图不是猫,识别为不是猫 --> 降低显示亮度
126 |
127 | # 【识别错误】:
128 | # 1.原图是猫,但是识别为不是猫 --> 标红显示
129 | # 2.原图不是猫, 但是识别成猫 --> 标红显示
130 |
131 | # 训练用的图片走一遍模型,观察其识别率
132 | plt.figure(figsize=(10, 20))
133 | plt.subplots_adjust(wspace=0, hspace=0.15)
134 |
135 | pred_train, true, accuracy = predict_by_modle(train_set_x, train_set_y_orig, nn)
136 |
137 | for i in range(len(train_set_x_orig)):
138 | ax = plt.subplot(21, 10, i + 1)
139 |
140 | x_data = train_set_x_orig[i]
141 | if pred_train[i] == 0 and train_set_y_orig[0][i] == 0:
142 | x_data = x_data/5
143 |
144 | if true[i] == False:
145 | x_data[:, :, 0] = x_data[:, :, 0] + (255 - x_data[:, :, 0])
146 |
147 | im = plt.imshow(x_data,interpolation='none',cmap='Reds_r',vmin=0.6,vmax=.9)
148 |
149 | plt.xticks([])
150 | plt.yticks([])
151 |
152 | plt.suptitle(u"Num Of Pictrues: %d\n Accuracy: %.2f%%" % (len(train_set_x_orig), accuracy), y=0.92, fontsize=20)
153 | plt.savefig("cat_pics_train_predict.png")
154 | plt.show()
155 |
156 | # 不属于训练图片集合的测试图片,走一遍模型,观察其识别率
157 | plt.figure(figsize=(8, 8))
158 | plt.subplots_adjust(wspace=0, hspace=0.1)
159 |
160 | pred_test, true, accuracy = predict_by_modle(test_set_x, test_set_y_orig, nn)
161 |
162 | for i in range(len(test_set_x_orig)):
163 | ax = plt.subplot(8, 8, i + 1)
164 |
165 | x_data = test_set_x_orig[i]
166 | if pred_test[i] == 0 and test_set_y_orig[0][i] == 0:
167 | x_data = x_data/5
168 |
169 | if true[i] == False:
170 | x_data[:, :, 0] = x_data[:, :, 0] + (255 - x_data[:, :, 0])
171 |
172 | im = ax.imshow(x_data, interpolation='none', cmap='Reds_r', vmin=0.6, vmax=.9)
173 |
174 | plt.xticks([])
175 | plt.yticks([])
176 |
177 | plt.suptitle(u"Num Of Pictrues: %d\n Accuracy: %.2f%%" % (len(mycat_set_x_orig), accuracy), fontsize=20)
178 | plt.savefig("cat_pics_test_predict.png")
179 | plt.show()
180 |
181 | # 用我家主子的照骗,走一遍模型,观察其识别率,因为只有一张图片,所以识别率要么 100% 要么 0%
182 | plt.figure(figsize=(2, 2.6))
183 | plt.subplots_adjust(wspace=0, hspace=0.1)
184 |
185 | pred_mycat, true, accuracy = predict_by_modle(mycat_set_x, mycat_set_y_orig, nn)
186 | for i in range(len(mycat_set_x_orig)):
187 | ax = plt.subplot(1, 1, i+1)
188 |
189 | x_data = mycat_set_x_orig[i]
190 | if pred_mycat[i] == 0 and mycat_set_y_orig[0][i] == 0:
191 | x_data = x_data/5
192 |
193 | if true[i] == False:
194 | x_data[:, :, 0] = x_data[:, :, 0] + (255 - x_data[:, :, 0])
195 |
196 | im = ax.imshow(x_data, interpolation='none', cmap='Reds_r', vmin=0.6, vmax=.9)
197 |
198 | plt.xticks([])
199 | plt.yticks([])
200 |
201 | if pred_mycat[i] == 1:
202 | plt.suptitle(u"我:'我主子是喵星人吗?'\nA I :'是滴'", fontproperties = font)
203 | else:
204 | plt.suptitle(u"我:'我主子是喵星人吗?'\nA I :'唔系~唔系~'", fontproperties = font)
205 | plt.savefig("cat_pics_my_predict.png")
206 | plt.show()
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/AI从入门到放弃:手撕卷积神经网络(CNN).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/AI从入门到放弃:手撕卷积神经网络(CNN).pdf
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/.idea/CNN-Network.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 | true
36 | DEFINITION_ORDER
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | 1535741535313
90 |
91 |
92 | 1535741535313
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/get_mnist.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | DIR="$( cd "$(dirname "$0")" ; pwd -P )"
4 | cd "$DIR"
5 |
6 | echo "Downloading..."
7 |
8 | for fname in train-images-idx3-ubyte train-labels-idx1-ubyte t10k-images-idx3-ubyte t10k-labels-idx1-ubyte
9 | do
10 | if [ ! -e $fname ]; then
11 | wget --no-check-certificate http://yann.lecun.com/exdb/mnist/${fname}.gz
12 | gunzip ${fname}.gz
13 | fi
14 | done
15 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/t10k-images-idx3-ubyte:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/t10k-images-idx3-ubyte
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/t10k-labels-idx1-ubyte:
--------------------------------------------------------------------------------
1 | '
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/train-images-idx3-ubyte:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/train-images-idx3-ubyte
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/train-labels-idx1-ubyte:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Data/mnist/train-labels-idx1-ubyte
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/Convolution.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | import math
4 | import numpy as np
5 | import matplotlib.pyplot as plt
6 | import matplotlib.font_manager as fm
7 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
8 |
9 |
10 | class ConvLayer(object):
11 | def __init__(self, upper_layer, kn = 1, k = 2, p = 0, s = 1, TEST = "", name = ''):
12 | '''
13 | :param input_shape: 图片尺寸参数:深度(RBG通道), 宽度, 高度
14 | :param kn: 卷积核个数
15 | :param k: 卷积核尺寸
16 | :param s: 步长
17 | :param p: 边界填充大小
18 | '''
19 | self.name = name
20 | self.type = 'conv'
21 | self.upper_layer = upper_layer
22 | self.show_and_save_images = False
23 |
24 | self.batch_size = self.upper_layer.batch_size
25 |
26 | self.c_input, self.h_input,self.w_input = self.upper_layer.output_shape()
27 |
28 | self.kn = kn
29 | self.k = k
30 | self.s = s
31 | self.p = p
32 |
33 | self.w_output = int((self.w_input - self.k + 2 * self.p) / self.s + 1)
34 | self.h_output = int((self.h_input - self.k + 2 * self.p) / self.s + 1)
35 | self.c_output = self.kn
36 |
37 | if TEST == "TEST":
38 | self.weight = np.ones((self.kn, self.c_input, self.k, self.k))
39 | self.bias = np.zeros((self.kn))
40 | else:
41 | weights_scale = math.sqrt(reduce(lambda x, y: x * y, self.upper_layer.output_shape()) / self.c_output)
42 | self.weight = np.random.standard_normal((self.kn, self.c_input, self.k, self.k)) / weights_scale
43 | self.bias = np.random.standard_normal(self.kn) / weights_scale
44 |
45 | self.weight_diff_history = np.zeros(self.weight.shape)
46 | self.bias_diff_history = np.zeros(self.bias.shape)
47 | self.diff = None
48 |
49 | self.input_data = None
50 | self.output_data = None
51 |
52 | def forward(self):
53 | self.input_data = self.upper_layer.forward()
54 | self.batch_size = self.upper_layer.batch_size
55 |
56 | X_col = self.im2col(self.input_data, self.k, padding=self.p, stride=self.s)
57 | W_col = self.weight.reshape(self.kn, -1)
58 |
59 | # 计算卷积: conv = X * W + b
60 | self.output_data = (np.dot(W_col, X_col).T + self.bias).T
61 | self.output_data = self.output_data.reshape(self.c_output, self.h_output, self.w_output, self.batch_size)
62 | self.output_data = self.output_data.transpose(3, 0, 1, 2)
63 | self.show_forward_img(self.output_data)
64 | return self.output_data
65 |
66 | def backward(self, diff):
67 | self.diff = np.zeros(self.input_data.shape)
68 |
69 | weight_diff = np.zeros(self.weight.shape)
70 | weight_diff = weight_diff.reshape(weight_diff.shape[0], -1)
71 | bias_diff = np.zeros((self.c_output))
72 |
73 | weight_raws = self.weight.reshape(self.weight.shape[0], -1).T
74 |
75 | for i in range(self.batch_size):
76 | # dW_(l) = a_(l-1) * diff_(l)
77 | input_data_col = self.im2col(self.input_data[[i]], self.k, self.p, self.s)
78 | weight_diff = weight_diff + diff[i].reshape(diff[i].shape[0], -1).dot(input_data_col.T)
79 |
80 | # db_(l) = sum(diff_(l))
81 | bias_diff = bias_diff + np.sum(diff[i].reshape(diff[i].shape[0], -1), 1)
82 |
83 | # diff_(l-1) = diff_(l) * rot180(W_(l))
84 | diff_cols = weight_raws.dot(diff[i].reshape(diff[i].shape[0], -1))
85 | self.diff[i, ...] = self.col2im(diff_cols, self.input_data.shape[1:], self.k, self.p, self.s)
86 |
87 | # 更新 W, b
88 | self.weight_diff_history = 0.9 * self.weight_diff_history + weight_diff.reshape(self.weight.shape)
89 | #self.weight_diff_history = weight_diff.reshape(self.weight.shape)
90 | self.weight = self.weight * 0.9995 - self.weight_diff_history
91 |
92 | self.bias_diff_history = 0.9 * self.bias_diff_history + 2 * bias_diff
93 | #self.bias_diff_history = bias_diff
94 | self.bias = self.bias * 0.9995 - self.bias_diff_history
95 |
96 | self.upper_layer.backward(self.diff)
97 |
98 | def show_forward_img(self, imgs):
99 | if not self.show_and_save_images:
100 | return
101 | imgs_data = imgs
102 | batch_size = imgs_data.shape[0]
103 | channel = imgs_data.shape[1]
104 | pic_wh = int(channel)
105 | plt.figure(figsize=(pic_wh, pic_wh))
106 |
107 | imgs_data = imgs_data.transpose(1, 0, 2, 3)
108 | imgs_data = imgs_data.reshape(batch_size * channel, imgs_data.shape[2], imgs_data.shape[3])
109 |
110 | for i in range(batch_size * channel):
111 | plt.subplot(channel, batch_size, i+1)
112 | plt.imshow(imgs_data[i], interpolation='none', cmap='binary')
113 | plt.xticks([])
114 | plt.yticks([])
115 |
116 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
117 | plt.savefig("OutputImages/%s_output.png" % self.name)
118 | plt.show()
119 |
120 | def output_data(self):
121 | return self.output_data
122 |
123 | def output_shape(self):
124 | return (self.c_output, self.h_output, self.w_output)
125 |
126 | def im2col(self, x, kernel_size, padding=0, stride=1):
127 | '''
128 | 把图片按照卷积区切割后堆叠
129 | :param x: 图像输入
130 | :param kernel_size: 卷积核尺寸
131 | :param padding: 边界填充大小
132 | :param stride: 卷积步长
133 | :return: 图片按照卷积区切割后堆叠后的数据,用来和卷积核做卷积运算
134 | '''
135 | p = padding
136 | x_padded = np.pad(x, ((0, 0), (0, 0), (p, p), (p, p)), mode='constant')
137 | channel_idx, raw_idx, col_idx = self.im2col_indexes(x.shape, kernel_size, padding, stride)
138 | cols = x_padded[:, channel_idx, raw_idx, col_idx]
139 | C = x.shape[1]
140 | cols = cols.transpose(1, 2, 0).reshape(kernel_size ** 2 * C, -1)
141 | return cols
142 |
143 | def col2im(self, x, img_shape, kernel_size, padding=0, stride=1):
144 | '''
145 | :param img_shape: 还原出的图像的大小:深度(RBG通道), 宽度, 高度
146 | :param kernel_size: 卷积核尺寸
147 | :param padding: 边界填充大小
148 | :param stride: 步长
149 | :return: 还原后的图像数据
150 |
151 | 该函数用在卷积层反向传播时,把误差矩阵按照卷积运算的方式堆叠,就能得到卷积层的上一层误差
152 | 举例:
153 | 假设卷积层输入的图片大小是3x3,通道数为1,卷积核大小是2x2,那么卷积层输出的图片大小 2x2
154 | 卷积层上一层传来的误差是4x4的(因为卷积核从左到右从上到下需要滑动4次,卷积核参数是2x2=4)
155 | x=[[1 2 3 4 ]
156 | [5 6 7 8 ]
157 | [9 10 11 12]
158 | [13 14 15 16]]
159 |
160 | x_row_num, x_col_num = x.shape =(4,4)
161 | channels, img_height, img_width = img_shape = (1, 3, 3)
162 |
163 | x_width = img_width - kernel_size + padding + 1 = 3 - 2 + 0 + 1 = 2
164 | x_height = img_height - kernel_size + padding + 1 = 3 - 2 + 0 + 1 = 2
165 |
166 | 即卷积层输出大小是2x2的,卷积核是2x2的,所以按照卷积区域变换成5维矩阵,通道数是1
167 | x_reshape = x.T.reshape(x_height, x_width, channels, kernel_size, kernel_size)
168 | = x.T.reshape(2, 2, 1, 2, 2)
169 | = [
170 | [
171 | [
172 | [
173 | [ 1 5]
174 | [ 9 13]
175 | ]
176 | ]
177 |
178 | [
179 | [
180 | [ 2 6]
181 | [10 14]
182 | ]
183 | ]
184 | ]
185 |
186 | [
187 | [
188 | [
189 | [ 3 7]
190 | [11 15]
191 | ]
192 | ]
193 |
194 | [
195 | [
196 | [ 4 8]
197 | [12 16]
198 | ]
199 | ]
200 | ]
201 | ]
202 |
203 | 按照卷积运算方式,把卷积区域堆叠后,就还原出卷积层输入图像的大小,这种计算方式本身就满足了卷积核旋转180度的要求
204 | for i in range(x_height):
205 | for j in range(x_width):
206 | 从左到右从上到下
207 | [[[0 0 0]
208 | [0 0 0]
209 | [0 0 0]]]
210 |
211 | [[[ 1 5 0]
212 | [ 9 13 0]
213 | [ 0 0 0]]]
214 |
215 | [[[ 1 5+2=7 6]
216 | [ 9 13+10=23 14]
217 | [ 0 0 0]]]
218 |
219 | [[[ 1 7 6]
220 | [9+3=12 23+7=30 14]
221 | [ 11 15 0]]]
222 |
223 | [[[ 1 7 6]
224 | [12 30+4 =34 14+8=22]
225 | [11 15+12=27 16]]]
226 |
227 |
228 | 最后得到的 output_padded.shape = (1, 3, 3)
229 | output_padded = [[
230 | [ 1 7 6 ]
231 | [12 34 22]
232 | [11 27 16]
233 | ]]
234 | 这样就求得了卷积层传播给上一层的误差矩阵 d_(l-1) = d_(l) * rot180[w_(l)]
235 | '''
236 | x_row_num, x_col_num = x.shape
237 |
238 | channels, img_height, img_width = img_shape
239 |
240 | x_width = int((img_width - kernel_size + 2*padding)/stride + 1)
241 | x_height = int((img_height - kernel_size + 2*padding)/stride + 1)
242 |
243 | assert channels * kernel_size ** 2 == x_row_num
244 | assert x_width * x_height == x_col_num
245 |
246 | x_reshape = x.T.reshape(x_height, x_width, channels, kernel_size, kernel_size)
247 | output_padded = np.zeros((channels, img_height + 2 * padding, img_width + 2 * padding))
248 | for i in range(x_height):
249 | for j in range(x_width):
250 | output_padded[:, i * stride: i * stride + kernel_size, j * stride: j * stride + kernel_size] = \
251 | output_padded[:, i * stride: i * stride + kernel_size, j * stride: j * stride + kernel_size] + \
252 | x_reshape[i, j, ...]
253 | return output_padded[:, padding: img_height + padding, padding: img_width + padding]
254 |
255 | def im2col_indexes(self, x_shape, kernel_size, padding=0, stride=1):
256 | '''
257 | :param x_shape: 输入图像的尺寸参数:通道数, 宽度, 高度
258 | :param kernel_size: 卷积核大小
259 | :param padding: 边界填充大小
260 | :param stride: 步长
261 | :return: 图像按卷积区切割后堆叠的数据
262 |
263 | 解释一下这个函数的原理,这是卷积计算的核心
264 | 1. 假设输入的数据x.shape=(1,1,6,6)
265 | W (列)
266 | o -------->
267 | | |
268 | H | | (行)
269 | | |
270 | ---------
271 |
272 | x= [[[
273 | [ 0 1 2 3 4 5]
274 | [ 6 7 8 9 10 11]
275 | [12 13 14 15 16 17]
276 | [18 19 20 21 22 23]
277 | [24 25 26 27 28 29]
278 | [30 31 32 33 34 35]
279 | ]]]
280 |
281 | 那么: N, C, H, W = 1, 1, 6, 6
282 | out_height = ((H + 2p -k)/s + 1) = ((6 + 2*0 - 2)/1 + 1) = 5
283 | out_width = ((W + 2p -k)/s + 1) = ((6 + 2*0 - 2)/1 + 1) = 5
284 |
285 | 2. 无padding的情况下 x_padded = x
286 |
287 | 3. kernel大小是 2x2,那么卷积结果输出大小是 5x5
288 |
289 | 4. 行(raw)位移索引矩阵
290 | 4.1 因为卷积核大小是2x2,所以行(raw)索引位移只跨两行,偏移量就是0或1
291 | kernel_raw_idx = np.repeat(np.arange(kernel_size), kernel_size) = [0 0 1 1]
292 |
293 | 4.2 因为步长 stride = 1,而行数 out_height = 5。 所以卷积区域的行(raw)索引范围是 [0, 4],
294 | 复制和列数 out_width 相等的份数,因为卷积核向右滑动时需要滑动 right_slip_times = out_width 次
295 | convregion_raw_idx = stride * np.repeat(np.arange(out_height), out_width)
296 | = [0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4]
297 |
298 | 4.3 得出行(raw)索引
299 | 偏移+卷积区域范围,因为卷积核在行(raw)的行为是从左到右滑动的
300 | raw_idx = kernel_raw_idx.reshape(-1, 1) + convregion_raw_idx.reshape(1, -1)
301 | = [
302 | [0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4]
303 | [0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4]
304 | [1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5]
305 | [1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5]
306 | ]
307 |
308 | 5. 列(column)位移索引矩阵
309 | 5.1 因为卷积核大小是2x2,通道数C=1,所以行索引位移只跨两两列,偏移量就是0或1
310 | kernel_col_idx = np.tile(np.arange(kernel_size), kernel_size * C) = [0 1 0 1]
311 |
312 | 5.2 因为步长 stride = 1,而行数 out_width = 5。 所以卷积区域的列(column)索引范围是 [0, 4],
313 | 并复制和行数 out_height 相等的份数,因为卷积核向下滑动时需要滑动 left_slip_times = out_height 次
314 | convregion_col_idx = stride * np.tile(np.arange(out_width), out_height)
315 | = [0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4]
316 |
317 | 5.3 得出列(column)索引
318 | col_indx = kernel_col_idx.reshape(-1, 1) + convregion_col_idx.reshape(1, -1)
319 | =[
320 | [0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4]
321 | [1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5]
322 | [0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4]
323 | [1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5]
324 | ]
325 |
326 | 6. 利用行列索引矩阵,取得做卷积运算的所有卷积面数据,每个数据大小是 kernel_size*kernel_size = 2*2 = 4
327 | 怎么利用k,i,j呢?
328 | 因为通道C=1个,所以k始终是索引0下标的数据:
329 | channel_idx = np.repeat(np.arange(C), kernel_size * kernel_size).reshape(-1, 1)
330 | = [
331 | [0]
332 | [0]
333 | [0]
334 | [0]
335 | ]
336 |
337 | 看输入数据:
338 | x= [[[
339 | [ 0 1 2 3 4 5]
340 | [ 6 7 8 9 10 11]
341 | [12 13 14 15 16 17]
342 | [18 19 20 21 22 23]
343 | [24 25 26 27 28 29]
344 | [30 31 32 33 34 35]
345 | ]]]
346 |
347 | 那么2x2的卷积核,第一次卷积的数据应该是 :
348 | [ 0 1 ]
349 | [ 6 7 ]
350 |
351 | 这个数据怎么拿呢?记住padding=0,x_padded = x
352 | 行索引 raw_idx[0][0] = 0
353 | 列索引 col_indx[0][0] = 0
354 | 所以 x 的第一行第一列数据是 x_padded[:, 0, 0, 0] = 0
355 |
356 | 行索引 raw_idx[1][0] = 0
357 | 列索引 col_indx[1][0] = 1
358 | 所以 x 的第一行第二列数据是 x_padded[:, 0, 0, 1] = 1
359 |
360 | 行索引 raw_idx[2][0] = 1
361 | 列索引 col_indx[2][0] = 0
362 | 所以 x 的第二行第一列的数据是 x_padded[:, 0, 1, 0] = 6
363 |
364 | 行索引 raw_idx[3][0] = 1
365 | 列索引 col_indx[3][0] = 1
366 | 所以 x 的第二行第二列的数据是 x_padded[:, 0, 1, 1] = 7
367 |
368 | 所以cols的第一列数据是 0,1,6,7
369 | 同理计算 i[n][1],j[n][1],即移动raw_idx,col_indx的列,就相当于把卷积核从左到右从上到下把图像扫描了一遍
370 |
371 |
372 | cols = x_padded[:, channel_idx, raw_idx, col_indx] = [[[
373 | [ 0 1 2 3 4 6 7 8 9 10 12 13 14 15 16 18 19 20 21 22 24 25 26 27 28]
374 | [ 1 2 3 4 5 7 8 9 10 11 13 14 15 16 17 19 20 21 22 23 25 26 27 28 29]
375 | [ 6 7 8 9 10 12 13 14 15 16 18 19 20 21 22 24 25 26 27 28 30 31 32 33 34]
376 | [ 7 8 9 10 11 13 14 15 16 17 19 20 21 22 23 25 26 27 28 29 31 32 33 34 35]
377 | ]]]
378 |
379 | 7. 为什么用这么复杂的方式呢,因为高效,用矩阵点乘就完成了卷积计算。简单粗暴的实现方式就是for循环,
380 | 按照步长左到右从上到下循环一遍。契合公式比较直观,但缺点就是慢
381 | '''
382 | N, C, H, W = x_shape
383 |
384 | assert (H + 2 * padding - kernel_size) % stride == 0
385 | assert (W + 2 * padding - kernel_size) % stride == 0
386 |
387 | out_height = int((H + 2 * padding - kernel_size) / stride + 1)
388 | out_width = int((W + 2 * padding - kernel_size) / stride + 1)
389 |
390 | kernel_raw_idx = np.repeat(np.arange(kernel_size), kernel_size)
391 | kernel_raw_idx = np.tile(kernel_raw_idx, C)
392 |
393 | convregion_raw_idx = stride * np.repeat(np.arange(out_height), out_width)
394 |
395 | kernel_col_idx = np.tile(np.arange(kernel_size), kernel_size * C)
396 | convregion_col_idx = stride * np.tile(np.arange(out_width), out_height)
397 |
398 | raw_idx = kernel_raw_idx.reshape(-1, 1) + convregion_raw_idx.reshape(1, -1)
399 | col_indx = kernel_col_idx.reshape(-1, 1) + convregion_col_idx.reshape(1, -1)
400 |
401 | channel_idx = np.repeat(np.arange(C), kernel_size * kernel_size).reshape(-1, 1)
402 |
403 | return (channel_idx.astype(int), raw_idx.astype(int), col_indx.astype(int))
404 |
405 | def load_params(self, weight, bias):
406 | self.weight = weight
407 | self.bias = bias
408 |
409 | def set_show_and_save_images(self, enable = False):
410 | self.show_and_save_images = enable
411 |
412 | class UpperLayerForConvTest(object):
413 | def __init__(self):
414 | self.batch_size = 2
415 | self.c_input = 3
416 | self.h_input = 3
417 | self.w_input = 3
418 |
419 | self.output_data = np.array([[[
420 | [1.,1.,1.],
421 | [1.,1.,1.],
422 | [1.,1.,1.]
423 | ],[
424 | [1.,1.,1.],
425 | [1.,1.,1.],
426 | [1.,1.,1.]
427 | ],[
428 | [1.,1.,1.],
429 | [1.,1.,1.],
430 | [1.,1.,1.]
431 | ]],[[
432 | [1.,1.,1.],
433 | [1.,1.,1.],
434 | [1.,1.,1.]
435 | ],[
436 | [1.,1.,1.],
437 | [1.,1.,1.],
438 | [1.,1.,1.]
439 | ],[
440 | [1.,1.,1.],
441 | [1.,1.,1.],
442 | [1.,1.,1.]
443 | ]]])
444 |
445 | self.c_output, self.w_output , self.h_output = self.output_data.shape[1:]
446 |
447 | def forward(self):
448 | return self.output_data
449 |
450 | def backward(self, diff):
451 | pass
452 |
453 | def output_shape(self):
454 | return (self.c_output, self.h_output, self.w_output)
455 |
456 | def set_show_and_save_images(self, enable = False):
457 | print self.name, enable
458 | self.show_and_save_images = enable
459 |
460 |
461 | if __name__ == '__main__':
462 | upper_layer = UpperLayerForConvTest()
463 |
464 | conv_input = upper_layer.forward()
465 | print("\ninput to conv layer:\n%s,\nshape: %s\n" % (conv_input, conv_input.shape))
466 |
467 | conv = ConvLayer(upper_layer, 1, 3, 1, 1, "TEST")
468 |
469 | # 测试前向传播
470 | conv_output = conv.forward()
471 |
472 | expect_forward = np.array([[[
473 | [4., 4.],
474 | [4., 4.]
475 | ]]])
476 | print("conv forward expect output:\n%s,\nshape: %s\n" % (expect_forward, expect_forward.shape))
477 | print("conv forward output:\n%s,\nshape: %s\n" % (conv_output, conv_output.shape))
478 |
479 | # 测试后向传播
480 | diff_next = np.array([[[
481 | [1., 1., 1.],
482 | [1., 1., 1.],
483 | [1., 1., 1.],
484 | ]], [[
485 | [1., 1., 1.],
486 | [1., 1., 1.],
487 | [1., 1., 1.],
488 | ]]])
489 | print("conv diff:\n%s,\nshape: %s\n" % (diff_next, diff_next.shape))
490 |
491 | conv.backward(diff_next)
492 |
493 | expect_backward = np.array([[[
494 | [1., 2., 1.],
495 | [2., 4., 2.],
496 | [1., 2., 1.]
497 | ]],[[
498 | [1., 2., 1.],
499 | [2., 4., 2.],
500 | [1., 2., 1.]
501 | ]],[[
502 | [1., 2., 1.],
503 | [2., 4., 2.],
504 | [1., 2., 1.]
505 | ]]])
506 | print("conv backward, expect diff:\n%s,\nshape: %s\n" % (expect_backward, expect_backward.shape))
507 | print("conv backward, diff:\n%s,\nshape: %s\n" % (conv.diff, conv.diff.shape))
508 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/Flatten.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import numpy as np
3 | import matplotlib.pyplot as plt
4 | import matplotlib.font_manager as fm
5 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
6 |
7 |
8 | class FlattenLayer(object):
9 | def __init__(self, upper_layer, name = ''):
10 | self.name = name
11 | self.type = 'flatten'
12 | self.upper_layer = upper_layer
13 | self.show_and_save_images = False
14 |
15 | self.batch_size = self.upper_layer.batch_size
16 |
17 | self.c_input, self.h_input, self.w_input = self.upper_layer.output_shape()
18 |
19 | self.w_output = 1
20 | self.h_output = 1
21 | self.c_output = self.c_input * self.h_input * self.w_input
22 |
23 | self.input_data = None
24 | self.output_data = None
25 | self.diff = None
26 |
27 | def forward(self):
28 | self.input_data = self.upper_layer.forward()
29 | self.batch_size = self.upper_layer.batch_size
30 | self.output_data = self.input_data.reshape(self.input_data.shape[0], -1)
31 | self.show_forward_img(self.output_data)
32 | return self.output_data
33 |
34 | def backward(self, diff):
35 | self.diff = diff.reshape(self.input_data.shape)
36 | self.upper_layer.backward(self.diff)
37 |
38 | def show_forward_img(self, imgs):
39 | if not self.show_and_save_images:
40 | return
41 | imgs_data = imgs
42 | channel = imgs_data.shape[0]
43 | pic_wh = int(channel)
44 | plt.figure(figsize=(pic_wh, imgs_data.shape[1]/10))
45 | for i in range(channel):
46 | plt.subplot(1, channel, i + 1)
47 | img = imgs_data[i].reshape(imgs_data.shape[1], 1)
48 | plt.imshow(img, interpolation='none', cmap='binary')
49 | plt.xticks([])
50 | plt.yticks([])
51 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
52 | plt.savefig("OutputImages/%s_output.png" % self.name)
53 | plt.show()
54 |
55 | def output_data(self):
56 | return self.output_data
57 |
58 | def output_shape(self):
59 | return (self.c_output, self.h_output, self.w_output)
60 |
61 | def load_params(self, weight, bias):
62 | pass
63 |
64 | def set_show_and_save_images(self, enable = False):
65 | self.show_and_save_images = enable
66 |
67 |
68 | class UpperLayerForFlattenTest(object):
69 | def __init__(self):
70 | self.batch_size = 1
71 | self.c_input = 1
72 | self.h_input = 4
73 | self.w_input = 4
74 |
75 | self.output_data = np.array([[[
76 | [1, 2, 3],
77 | [4, 5, 6],
78 | [7, 8, 9]
79 | ]]])
80 |
81 | self.c_output, self.w_output, self.h_output = self.output_data.shape[1:]
82 |
83 | def forward(self):
84 | return self.output_data
85 |
86 | def backward(self, diff):
87 | pass
88 |
89 | def output_shape(self):
90 | return (self.c_output, self.h_output, self.w_output)
91 |
92 |
93 | if __name__ == '__main__':
94 | upper_layer = UpperLayerForFlattenTest()
95 |
96 | flatten_input = upper_layer.forward()
97 | print("\ninput to flatten layer:\n%s,\nshape: %s\n" % (flatten_input, flatten_input.shape))
98 |
99 | flatten = FlattenLayer(upper_layer)
100 |
101 | # 测试前向传播
102 | flatten_output = flatten.forward()
103 | expect_forward = np.array([[[
104 | [1, 2, 3, 4, 5, 6, 7, 8, 9]
105 | ]]])
106 |
107 | print("flatten forward expect output:\n%s,\nshape: %s\n" % (expect_forward, expect_forward.shape))
108 | print("flatten forward output:\n%s,\nshape: %s\n" % (flatten_output, flatten_output.shape))
109 |
110 | # 测试后向传播
111 | diff_next = np.array([[[
112 | [1, 2, 3, 4, 5, 6, 7, 8, 9]
113 | ]]])
114 |
115 | print("flattene diff:\n%s,\nshape: %s\n" % (diff_next, diff_next.shape))
116 |
117 | flatten.backward(diff_next)
118 |
119 | expect_backward = np.array([[[
120 | [1, 2, 3],
121 | [4, 5, 6],
122 | [7, 8, 9]
123 | ]]])
124 | print("flatten backward, expect diff:\n%s,\nshape: %s\n" % (expect_backward, expect_backward.shape))
125 | print("flatten backward, diff:\n%s,\nshape: %s\n" % (flatten.diff, flatten.diff.shape))
126 |
127 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/FullConnection.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | import math
4 | import numpy as np
5 | import matplotlib.pyplot as plt
6 | import matplotlib.font_manager as fm
7 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
8 |
9 |
10 | class FullConnectionLayer(object):
11 | def __init__(self, upper_layer, c_output = 1, TEST = "", name = ''):
12 | self.name = name
13 | self.type = 'fc'
14 | self.upper_layer = upper_layer
15 | self.show_and_save_images = False
16 |
17 | self.batch_size = self.upper_layer.batch_size
18 |
19 | self.c_input, self.h_input, self.w_input = self.upper_layer.output_shape()
20 |
21 | self.w_output = self.w_input
22 | self.h_output = self.h_input
23 | self.c_output = c_output
24 |
25 | if TEST == "TEST":
26 | self.weight = np.ones((self.c_input, self.c_output))
27 | self.bias = np.zeros(self.c_output)
28 | else:
29 | weights_scale = math.sqrt(reduce(lambda x, y: x * y, (self.c_input, self.c_output)) / self.c_output)
30 | self.weight = np.random.standard_normal((self.c_input, self.c_output)) / weights_scale
31 | self.bias = np.random.standard_normal(self.c_output) / weights_scale
32 |
33 | self.weight_diff_history = np.zeros(self.weight.shape)
34 | self.bias_diff_history = np.zeros(self.bias.shape)
35 | self.diff = None
36 |
37 | self.input_data = None
38 | self.output_data = None
39 |
40 | def forward(self):
41 | self.input_data = self.upper_layer.forward()
42 | self.batch_size = self.upper_layer.batch_size
43 |
44 | input_cols = self.input_data.reshape(self.input_data.shape[0], -1)
45 | self.output_data = input_cols.dot(self.weight) + self.bias
46 |
47 | self.show_forward_img(self.output_data)
48 | return self.output_data
49 |
50 | def backward(self, diff):
51 | weight_diff = self.input_data.T.dot(diff)
52 | bias_diff = np.sum(diff, axis = 0)
53 |
54 | self.diff = diff.dot(self.weight.T)
55 |
56 | self.weight_diff_history = 0.9 * self.weight_diff_history + weight_diff
57 | #self.weight_diff_history = weight_diff
58 | self.weight = self.weight * 0.9995 - self.weight_diff_history
59 |
60 | self.bias_diff_history = 0.9 * self.bias_diff_history + 2 * bias_diff
61 | #self.bias_diff_history = bias_diff
62 | self.bias = self.bias * 0.9995 - self.bias_diff_history
63 |
64 | self.upper_layer.backward(self.diff)
65 |
66 | def show_forward_img(self, imgs):
67 | if not self.show_and_save_images:
68 | return
69 | imgs_data = imgs
70 | channel = imgs_data.shape[0]
71 | pic_wh = int(channel)
72 | plt.figure(figsize=(pic_wh, imgs_data.shape[1]/10))
73 | for i in range(channel):
74 | plt.subplot(1, channel, i + 1)
75 | img = imgs_data[i].reshape(imgs_data.shape[1], 1)
76 | plt.imshow(img, interpolation='none', cmap='binary')
77 | plt.xticks([])
78 | plt.yticks([])
79 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
80 | plt.savefig("OutputImages/%s_output.png" % self.name)
81 | plt.show()
82 |
83 | def get_output(self):
84 | return self.output_data
85 |
86 | def output_shape(self):
87 | return (self.c_output, self.h_output, self.w_output)
88 |
89 | def load_params(self, weight, bias):
90 | self.weight = weight
91 | self.bias = bias
92 |
93 | def set_show_and_save_images(self, enable = False):
94 | self.show_and_save_images = enable
95 |
96 |
97 | class UpperLayerForFullconnectionTest(object):
98 | def __init__(self):
99 | self.batch_size = 1
100 | self.c_input = 4
101 | self.h_input = 1
102 | self.w_input = 1
103 |
104 | self.output_data = np.array([
105 | [1, 2, 3, 4]
106 | ])
107 |
108 | self.c_output = self.c_input
109 | self.w_output = 1
110 | self.h_output = 1
111 |
112 | def forward(self):
113 | return self.output_data
114 |
115 | def backward(self, diff):
116 | pass
117 |
118 | def output_shape(self):
119 | return (self.c_output, self.h_output, self.w_output)
120 |
121 |
122 | if __name__ == '__main__':
123 | upper_layer = UpperLayerForFullconnectionTest()
124 |
125 | full_connection_input = upper_layer.forward()
126 | print("\ninput to full_connection layer:\n%s,\nshape: %s\n" % (full_connection_input, full_connection_input.shape))
127 |
128 | full_connection = FullConnectionLayer(upper_layer, c_output = 2, TEST = "TEST")
129 |
130 | # 测试前向传播
131 | full_connection_output = full_connection.forward()
132 | expect_forward = np.array([
133 | [10, 10]
134 | ])
135 |
136 | print("full_connection forward expect output:\n%s,\nshape: %s\n" % (expect_forward, expect_forward.shape))
137 | print("full_connection forward output:\n%s,\nshape: %s\n" % (full_connection_output, full_connection_output.shape))
138 |
139 | # 测试后向传播
140 | diff_next = np.array([
141 | [1, 2]
142 | ])
143 | print("full_connectione diff:\n%s,\nshape: %s\n" % (diff_next, diff_next.shape))
144 |
145 | full_connection.backward(diff_next)
146 |
147 | expect_backward = np.array([
148 | [3, 3, 3, 3]
149 | ])
150 |
151 | print("full_connection backward, expect diff:\n%s,\nshape: %s\n" % (expect_backward, expect_backward.shape))
152 | print("full_connection backward, diff:\n%s,\nshape: %s\n" % (full_connection.diff, full_connection.diff.shape))
153 |
154 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/MnistInput.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 | import os
4 | import struct
5 | import numpy as np
6 | import matplotlib.pyplot as plt
7 | import matplotlib.font_manager as fm
8 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
9 |
10 | class MnistInput:
11 | def __init__(self, data_dir = "", batch_size = 32, test_size = 100, name = ''):
12 | self.name = name
13 | self.type = 'input'
14 | self.train_batch_count = 0
15 | self.test_batch_count = 0
16 |
17 | self.train_num = batch_size
18 | self.test_num = test_size
19 |
20 | self.batch_size = self.train_num
21 |
22 | self.c_output = 1 # 输出通道数,黑白图像颜色通道是1
23 |
24 | self.train_images = self.read_images(os.path.join(data_dir, 'train-images-idx3-ubyte')) / 256.
25 | self.train_labels = self.read_labels(os.path.join(data_dir, 'train-labels-idx1-ubyte'))
26 |
27 | self.test_images = self.read_images(os.path.join(data_dir, 't10k-images-idx3-ubyte')) / 256.
28 | self.test_labels = self.read_labels(os.path.join(data_dir, 't10k-labels-idx1-ubyte'))
29 |
30 | self.train_img_num, self.h_output, self.w_output = self.train_images.shape
31 | self.test_img_num, _, _ = self.test_images.shape
32 |
33 | self.train_cur_index = 0
34 | self.test_cur_index = 0
35 |
36 | self.output_images = None
37 | self.output_labels = None
38 |
39 | self.sets = 'train'
40 |
41 | self.batch_num_per_epoch = len(self.train_labels)/self.batch_size
42 |
43 | self.show_and_save_images = False
44 |
45 | def set_train_data(self):
46 | self.batch_size = self.train_num
47 | if self.train_cur_index + self.batch_size >= self.train_img_num:
48 | idx1 = np.arange(self.train_cur_index, self.train_img_num)
49 | idx2 = np.arange(0, self.train_cur_index + self.batch_size - self.train_img_num)
50 | output_index = np.append(idx1, idx2)
51 |
52 | self.train_batch_count = self.train_batch_count + 1
53 | self.train_cur_index = self.train_cur_index + self.batch_size - self.train_img_num
54 | else:
55 | output_index = np.arange(self.train_cur_index, self.train_cur_index + self.batch_size)
56 | self.train_cur_index = self.train_cur_index + self.batch_size
57 |
58 | self.output_images = self.train_images[output_index].reshape(self.batch_size, self.c_output, self.h_output,
59 | self.w_output)
60 | self.output_labels = self.train_labels[output_index].reshape(-1)
61 | return (self.output_images, self.output_labels)
62 |
63 | def set_test_data(self):
64 | self.batch_size = self.test_num
65 | if self.test_cur_index + self.batch_size >= self.test_img_num:
66 | idx1 = np.arange(self.test_cur_index, self.test_img_num)
67 | idx2 = np.arange(0, self.test_cur_index + self.batch_size - self.test_img_num)
68 | output_index = np.append(idx1, idx2)
69 |
70 | self.test_batch_count = self.test_batch_count = + 1
71 | self.test_cur_index = self.test_cur_index + self.batch_size - self.test_img_num
72 | else:
73 | output_index = np.arange(self.test_cur_index, self.test_cur_index + self.batch_size)
74 | self.test_cur_index = self.test_cur_index + self.batch_size
75 |
76 | self.output_images = self.test_images[output_index].reshape(self.batch_size, self.c_output, self.h_output,
77 | self.w_output)
78 | self.output_labels = self.test_labels[output_index].reshape(-1)
79 |
80 | return (self.output_images, self.output_labels)
81 |
82 | def forward(self):
83 | if self.sets == 'train':
84 | self.set_train_data()
85 |
86 | elif self.sets == 'test':
87 | self.set_test_data()
88 | else:
89 | return None
90 |
91 | self.show_forward_img(self.output_images)
92 | return self.output_images
93 |
94 | def backward(self, diff):
95 | pass
96 |
97 | def read_images(self, bin_img_f):
98 | f = open(bin_img_f, 'rb')
99 | buf = f.read()
100 | head = struct.unpack_from('>IIII', buf, 0)
101 | offset = struct.calcsize('>IIII')
102 | img_num = head[1]
103 | img_width = head[2]
104 | img_height = head[3]
105 | bits_size = img_num * img_height * img_width
106 | raw_imgs = struct.unpack_from('>' + str(bits_size) + 'B', buf, offset)
107 | f.close()
108 | imgs = np.reshape(raw_imgs, head[1:])
109 | return imgs
110 |
111 | def read_labels(self, bin_img_f):
112 | f = open(bin_img_f, 'rb')
113 | buf = f.read()
114 | head = struct.unpack_from('>II', buf, 0)
115 | img_num = head[1]
116 | offset = struct.calcsize('>II')
117 | raw_labels = struct.unpack_from('>' + str(img_num) + 'B', buf, offset)
118 | f.close()
119 | labels = np.reshape(raw_labels, [img_num, 1])
120 | return labels
121 |
122 | def show_imgs(self, show_num):
123 | imgs_data = self.train_images
124 | pic_wh = int(np.sqrt(show_num))
125 | plt.figure(figsize=(pic_wh, pic_wh))
126 | plt.subplots_adjust(wspace=0, hspace=0.15)
127 | for i in range(show_num):
128 | plt.subplot(show_num/10, 10, i + 1)
129 | plt.imshow(imgs_data[i], interpolation='none', cmap='binary')
130 | plt.xticks([])
131 | plt.yticks([])
132 | plt.savefig("OutputImages/train_pics.png")
133 | plt.show()
134 |
135 | def show_forward_img(self, imgs):
136 | if not self.show_and_save_images:
137 | return
138 | imgs_data = imgs
139 | show_num = imgs_data.shape[0]
140 | pic_wh = show_num
141 | plt.figure(figsize=(pic_wh, pic_wh))
142 | for i in range(show_num):
143 | plt.subplot(show_num, 1, i + 1)
144 | plt.imshow(imgs_data[i][0], interpolation='none', cmap='binary')
145 | plt.xticks([])
146 | plt.yticks([])
147 |
148 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
149 | plt.savefig("OutputImages/%s_output.png" % self.name)
150 | plt.show()
151 |
152 | def output_shape(self):
153 | return (self.c_output, self.w_output, self.h_output)
154 |
155 | def get_images(self):
156 | return self.output_images
157 |
158 | def get_labels(self):
159 | return self.output_labels
160 |
161 | def get_batch_setting(self):
162 | return self.batch_size, self.test_num
163 |
164 | def choose_dataset(self, set = 'train'):
165 | if set.lower() != "train" and set.lower() != "test":
166 | print("Data Set Must Be 'train' or 'test', Set It With 'train' Default.")
167 | self.sets = 'train'
168 | return
169 | self.sets = set.lower()
170 |
171 | def sample_info(self):
172 | return (len(self.train_labels), len(self.test_labels), self.batch_num_per_epoch)
173 |
174 | def load_params(self, weight, bias):
175 | pass
176 |
177 | def set_show_and_save_images(self, enable = False):
178 | self.show_and_save_images = enable
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/NetworkBuilder.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import sys
3 | import numpy as np
4 | import h5py
5 | import matplotlib.pyplot as plt
6 | import matplotlib.font_manager as fm
7 | from Layers.MnistInput import MnistInput
8 | from Layers.Convolution import ConvLayer
9 | from Layers.Pooling import PoolingLayer
10 | from Layers.Relu import ReLuLayer
11 | from Layers.Flatten import FlattenLayer
12 | from Layers.FullConnection import FullConnectionLayer
13 | from Layers.SoftmaxLoss import SoftmaxLossLayer, SoftmaxLayer
14 |
15 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
16 |
17 | class CNN_Network(object):
18 | def __init__(self, layer_list, base_lr = 1e-4, l2_regulation = 4e-6, epoch_period = 5):
19 | self.layers = []
20 |
21 | self.base_lr = np.float32(base_lr)
22 | self.lr = np.float32(base_lr)
23 | self.l2_regulation = np.float32(l2_regulation)
24 |
25 | self.epoch_period = epoch_period
26 | self.epoch_count = 1
27 |
28 | self.input_layer = None
29 | self.output_layer = None
30 |
31 | self.avg_loss_list = list()
32 | self.accuracy_list = list()
33 |
34 | self.batch_size = 0
35 | self.test_size = 0
36 |
37 | self.train_data_total_num = 0
38 | self.test_data_total_num = 0
39 |
40 | self.batch_size_per_epoch = 0
41 |
42 | self.stop_when_epoches_gte = 5
43 | self.stop_when_accuracy_gte = 0.995
44 |
45 | self.show_and_save_images = False
46 |
47 | self.dataset = 'train'
48 |
49 | for i in range(0, len(layer_list)):
50 | layer = layer_list[i]
51 |
52 | # 第一层是输入层
53 | if i == 0 and layer['type'] != "input_layer":
54 | print("Type Of First Layer Must Be 'input_layer'")
55 | self.layers = []
56 | break
57 | elif i == 0 and layer['type'] == "input_layer":
58 | layer.pop('type')
59 | self.input_layer = MnistInput(**layer)
60 | self.layers.append(self.input_layer)
61 | self.batch_size, self.test_size = self.input_layer.get_batch_setting()
62 | self.test_data_total_num, self.test_data_total_num, self.batch_size_per_epoch = self.input_layer.sample_info()
63 | print(self.batch_size, self.test_size)
64 | print(self.train_data_total_num, self.test_data_total_num, self.batch_size_per_epoch)
65 | continue
66 |
67 | if i == len(layer_list) - 1 and layer['type'] != "softmax_loss":
68 | print("Type Of First Layer Must Be 'input_layer'")
69 | self.layers = []
70 | break
71 | elif i == len(layer_list) - 1 and layer['type'] == "softmax_loss":
72 | layer.pop('type')
73 | self.output_layer = SoftmaxLossLayer(self.layers[i-1], self.layers[0], **layer)
74 | self.layers.append(self.output_layer )
75 | continue
76 |
77 | if layer['type'] == 'conv':
78 | layer.pop('type')
79 | self.layers.append(ConvLayer(self.layers[i-1], **layer))
80 |
81 | elif layer['type'] == 'pool':
82 | layer.pop('type')
83 | self.layers.append(PoolingLayer(self.layers[i-1], **layer))
84 |
85 | elif layer['type'] == 'flatten':
86 | layer.pop('type')
87 | self.layers.append(FlattenLayer(self.layers[i-1], **layer))
88 |
89 | elif layer['type'] == 'relu':
90 | layer.pop('type')
91 | self.layers.append(ReLuLayer(self.layers[i-1], **layer))
92 |
93 | elif layer['type'] == 'fc':
94 | layer.pop('type')
95 | self.layers.append(FullConnectionLayer(self.layers[i-1], **layer))
96 |
97 | else:
98 | print("Unknow Layer-Type, Skip!")
99 |
100 | def show_data_images(self, num):
101 | self.input_layer.show_imgs(num)
102 |
103 | def show_network_info(self):
104 | layer_name_list = []
105 | for layer in self.layers:
106 | layer_name_list.append(layer.name)
107 | print("\n")
108 | print(' => '.join(layer_name_list))
109 | print("\n")
110 |
111 | print(u"训练集图片总数: %d" % self.train_data_total_num)
112 | print(u"测试集图片总数: %d" % self.test_data_total_num)
113 | print(u"batch_size: %d" % self.batch_size)
114 | print(u"一次迭代(epoch)需要训练的 batch 数: %d" % self.batch_size_per_epoch)
115 |
116 | def choose_dataset(self, dataset):
117 | if dataset != 'test' and dataset != 'train':
118 | print(u'数据集名称必须为:test/train')
119 | sys.exit(-1)
120 | self.dataset = dataset
121 |
122 | def predict(self):
123 | print(u"测试 ...")
124 | self.input_layer.choose_dataset(self.dataset)
125 | accuracy = self.calc_accuracy(self.output_layer.predict(), self.input_layer.get_labels())
126 | self.accuracy_list.append(accuracy)
127 | print(u"迭代次数: %d\t准确率 = %.2f%%" % (self.epoch_count, accuracy*100))
128 | return accuracy
129 |
130 | def train(self, epoch = 5):
131 | avg_loss = -1
132 | for i in range(epoch*self.batch_size_per_epoch):
133 | self.lr = self.base_lr / (1 + 1e-4 * i) ** 0.75
134 |
135 | #if i % self.batch_size_per_epoch == 0:
136 | # 训练集太大了,这里让他早点结束,相当于跳过一些训练数据,当然也可以使用上面的语句
137 | if i % 100 == 0:
138 | accuracy = self.predict()
139 | if accuracy >= self.stop_when_accuracy_gte and self.epoch_count >= self.stop_when_epoches_gte:
140 | self.snapshot('Model/model.h5')
141 | print(u"模型参数已经保存!")
142 | plt.plot(np.arange(0, len(self.accuracy_list), 1), self.accuracy_list)
143 | plt.xlabel(u'迭代次数', fontproperties=font)
144 | plt.ylabel(u'准确率', fontproperties=font)
145 | plt.title(u'CNN训练准确率曲线', fontproperties=font)
146 | plt.grid(True)
147 | plt.show()
148 | plt.plot(np.arange(0, len(self.avg_loss_list), 1), self.avg_loss_list)
149 | plt.xlabel(u'迭代次数', fontproperties=font)
150 | plt.ylabel(u'误差值', fontproperties=font)
151 | plt.title(u'CNN训练误差值曲线', fontproperties=font)
152 | plt.grid(True)
153 | plt.show()
154 | break
155 | self.epoch_count += 1
156 |
157 | self.input_layer.choose_dataset(self.dataset)
158 | self.output_layer.forward()
159 | if avg_loss == -1:
160 | avg_loss = self.output_layer.get_loss()
161 | else:
162 | avg_loss = avg_loss * 0.9 + 0.1 * self.output_layer.get_loss()
163 |
164 | self.avg_loss_list.append(avg_loss)
165 |
166 | print(u"batch计数 = %-5d\t平均误差 = %.4f\t 学习率 = %f" % (i + 1, avg_loss, self.lr))
167 | self.output_layer.backward(self.lr)
168 |
169 | def run(self, stop_when_epoches_gte = 5, stop_when_accuracy_gte = 0.995):
170 | self.stop_when_epoches_gte = stop_when_epoches_gte
171 | self.stop_when_accuracy_gte = stop_when_accuracy_gte
172 | self.train(self.epoch_period)
173 |
174 | def calc_accuracy(self, prediction, truth):
175 | n = np.size(truth)
176 | return np.sum(prediction.argmax(1) == truth.reshape(-1)) / (n + 0.)
177 |
178 | def snapshot(self, model_fname):
179 | f = h5py.File(model_fname, "w")
180 | for layer in self.layers:
181 | if layer.type == 'conv' or layer.type == 'fc':
182 | g = f.create_group(layer.name)
183 | g.create_dataset('w', data = layer.weight)
184 | g.create_dataset('b', data = layer.bias)
185 | f.close()
186 |
187 | def load_model(self, model_fname):
188 | data_set = h5py.File(model_fname, "r")
189 | for layer in self.layers:
190 | if layer.name in data_set.keys():
191 | w = data_set[layer.name]['w'][:]
192 | b = data_set[layer.name]['b'][:]
193 | layer.load_params(w, b)
194 |
195 | def set_show_and_save_images(self, enable = False):
196 | for layer in self.layers:
197 | layer.set_show_and_save_images(enable)
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/Pooling.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | import math
4 | import numpy as np
5 | import matplotlib.pyplot as plt
6 | import matplotlib.font_manager as fm
7 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
8 |
9 |
10 | class PoolingLayer(object):
11 | def __init__(self, upper_layer, k = 2, s = 2, name = ''):
12 | self.name = name
13 | self.type = 'pool'
14 | self.upper_layer = upper_layer
15 | self.show_and_save_images = False
16 |
17 | self.batch_size = self.upper_layer.batch_size
18 |
19 | self.c_input, self.h_input, self.w_input = self.upper_layer.output_shape()
20 |
21 | self.k = k
22 | self.s = s
23 |
24 | self.w_output = int(math.ceil((self.w_input - self.k + 0.) / self.s)) + 1
25 | self.h_output = int(math.ceil((self.h_input - self.k + 0.) / self.s)) + 1
26 | self.c_output = self.c_input
27 |
28 | self.input_data = None
29 | self.output_data = None
30 | self.max_index = None
31 | self.diff = None
32 |
33 | def forward(self):
34 | '''
35 | 举例:
36 | input_data = [[[
37 | [0 1 2 3 4 5 ]
38 | [6 7 8 9 10 11]
39 | [12 13 14 15 16 17]
40 | [18 19 20 21 22 23]
41 | [24 25 26 27 28 29]
42 | [30 31 32 33 34 35]
43 | ]]]
44 |
45 | 池化核大小2,步长2
46 | input_col = im2col(input_data, 2, 2)
47 | = [[ 0 1 6 7]
48 | [ 2 3 8 9]
49 | [ 4 5 10 11]
50 | [12 13 18 19]
51 | [14 15 20 21]
52 | [16 17 22 23]
53 | [24 25 30 31]
54 | [26 27 32 33]
55 | [28 29 34 35]]
56 | 很明显的,当kernerl_size=2, stride=2, 输入为(6x6)时,切割出的池化区域的数量为9,每个池化区大小为4,所以
57 | input_col.shape = (9, 4)
58 |
59 | 生成input_col的下标矩阵
60 | temp_index = np.tile(np.arange(input_col.shape[1]),input_col.shape[0]).reshape(input_col.shape)
61 | = [
62 | [0 1 2 3]
63 | [0 1 2 3]
64 | [0 1 2 3]
65 | [0 1 2 3]
66 | [0 1 2 3]
67 | [0 1 2 3]
68 | [0 1 2 3]
69 | [0 1 2 3]
70 | [0 1 2 3]
71 | ]
72 |
73 | 标记出每个池化区的最大元素的位置
74 | max_index = tmp_index == input_col.argmax(1).reshape(-1,1)
75 | = [
76 | [False False False True]
77 | [False False False True]
78 | [False False False True]
79 | [False False False True]
80 | [False False False True]
81 | [False False False True]
82 | [False False False True]
83 | [False False False True]
84 | [False False False True]
85 | ]
86 |
87 | 池化区个数时9,那么输出就是(3x3)
88 | output_data = input_col[max_index].reshape(num, num_input, output_h, output_w)
89 | = input_col[max_index].reshape(1, 1, 3, 3)
90 | = [[[
91 | [ 7 9 11]
92 | [19 21 23]
93 | [31 33 35]
94 | ]]]
95 |
96 | max_index 被保存起来,池化成做反向传播的时候用
97 | '''
98 | self.input_data = self.upper_layer.forward()
99 | self.batch_size = self.upper_layer.batch_size
100 |
101 | input_col = self.im2col(self.input_data, self.k, self.s)
102 | tmp_index = np.tile(np.arange(input_col.shape[1]),input_col.shape[0]).reshape(input_col.shape)
103 | self.max_index = tmp_index == input_col.argmax(1).reshape(-1,1)
104 |
105 | self.output_data = input_col[self.max_index].reshape(self.batch_size, self.c_output, self.h_output, self.w_output)
106 | self.show_forward_img(self.output_data)
107 | return self.output_data
108 |
109 | def backward(self, diff):
110 | '''
111 | :param diff: 上一层误差
112 | :return: 池化层误差
113 |
114 | 举例:
115 | diff = [[[
116 | [ 7 9 11]
117 | [19 21 23]
118 | [31 33 35]
119 | ]]]
120 |
121 | diff_col = np.zeros((1 * 1 * 3 * 3, 2**2))
122 | = [
123 | [0. 0. 0. 0.]
124 | [0. 0. 0. 0.]
125 | [0. 0. 0. 0.]
126 | [0. 0. 0. 0.]
127 | [0. 0. 0. 0.]
128 | [0. 0. 0. 0.]
129 | [0. 0. 0. 0.]
130 | [0. 0. 0. 0.]
131 | [0. 0. 0. 0.]
132 | ]
133 |
134 | diff_col[self.max_index] = diff.reshape(-1)
135 |
136 | diff_col = [
137 | [ 0. 0. 0. 7.]
138 | [ 0. 0. 0. 9.]
139 | [ 0. 0. 0. 11.]
140 | [ 0. 0. 0. 19.]
141 | [ 0. 0. 0. 21.]
142 | [ 0. 0. 0. 23.]
143 | [ 0. 0. 0. 31.]
144 | [ 0. 0. 0. 33.]
145 | [ 0. 0. 0. 35.]
146 | ]
147 |
148 | diff = col2ims(diff_col, input_data.shape, kernel_size, stride)
149 | = col2ims(diff_col, (1,1,6,6), 2, 2)
150 | = [[[
151 | [ 0. 0. 0. 0. 0. 0.]
152 | [ 0. 7. 0. 9. 0. 11.]
153 | [ 0. 0. 0. 0. 0. 0.]
154 | [ 0. 19. 0. 21. 0. 23.]
155 | [ 0. 0. 0. 0. 0. 0.]
156 | [ 0. 31. 0. 33. 0. 35.]
157 | ]]]
158 |
159 | '''
160 | diff_col = np.zeros((self.batch_size * self.c_output * self.h_output * self.w_output, self.k**2))
161 | diff_col[self.max_index] = diff.reshape(-1)
162 | self.diff = self.col2ims(diff_col, self.input_data.shape, self.k, self.s)
163 | self.upper_layer.backward(self.diff)
164 |
165 | def show_forward_img(self, imgs):
166 | if not self.show_and_save_images:
167 | return
168 | imgs_data = imgs
169 | batch_size = imgs_data.shape[0]
170 | channel = imgs_data.shape[1]
171 | pic_wh = int(channel)
172 | plt.figure(figsize=(pic_wh, pic_wh))
173 |
174 | imgs_data = imgs_data.transpose(1, 0, 2, 3)
175 | imgs_data = imgs_data.reshape(batch_size * channel, imgs_data.shape[2], imgs_data.shape[3])
176 |
177 | for i in range(batch_size * channel):
178 | plt.subplot(channel, batch_size, i+1)
179 | plt.imshow(imgs_data[i], interpolation='none', cmap='binary')
180 | plt.xticks([])
181 | plt.yticks([])
182 |
183 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
184 | plt.savefig("OutputImages/%s_output.png" % self.name)
185 | plt.show()
186 |
187 | def output_data(self):
188 | return self.output_data
189 |
190 | def output_shape(self):
191 | return (self.c_output, self.h_output, self.w_output)
192 |
193 | def im2col(self, X, kernel_size=1, stride=1):
194 | '''
195 | 把图片按照卷积区切割后堆叠
196 | :param x: 图像输入
197 | :param kernel_size: 卷积核尺寸
198 | :param padding: 边界填充大小
199 | :param stride: 卷积步长
200 | :return: 图片按照卷积区切割后堆叠后的数据,用来和卷积核做卷积运算
201 | '''
202 | num, channels, height, width = X.shape
203 | surplus_height = (height - kernel_size) % stride
204 | surplus_width = (width - kernel_size) % stride
205 | pad_h = (kernel_size - surplus_height) % kernel_size
206 | pad_w = (kernel_size - surplus_width) % kernel_size
207 | X = np.pad(X, ((0, 0), (0, 0), (0, pad_h), (0, pad_w)), mode='constant')
208 | channel_idx, raw_idx, col_idx = self.im2col_indexes(X.shape, kernel_size, stride=stride)
209 | X_col = X[:, channel_idx, raw_idx, col_idx].reshape(num * channels, kernel_size ** 2, -1)
210 | X_col = X_col.transpose(0, 2, 1)
211 | return X_col.reshape(-1, kernel_size ** 2)
212 |
213 | def im2col_indexes(self, x_shape, kernel_size, padding=0, stride=1):
214 | '''
215 | :param x_shape: 输入图像的尺寸参数:通道数, 宽度, 高度
216 | :param kernel_size: 卷积核大小
217 | :param padding: 边界填充大小
218 | :param stride: 步长
219 | :return: 图像按卷积区切割后堆叠的数据
220 | '''
221 | N, C, H, W = x_shape
222 | assert (H + 2 * padding - kernel_size) % stride == 0
223 | assert (W + 2 * padding - kernel_size) % stride == 0
224 |
225 | out_height = int((H + 2 * padding - kernel_size) / stride + 1)
226 | out_width = int((W + 2 * padding - kernel_size) / stride + 1)
227 |
228 | kernel_raw_idx = np.repeat(np.arange(kernel_size), kernel_size)
229 | kernel_raw_idx = np.tile(kernel_raw_idx, C)
230 |
231 | convregion_raw_idx = stride * np.repeat(np.arange(out_height), out_width)
232 |
233 | kernel_col_idx = np.tile(np.arange(kernel_size), kernel_size * C)
234 | convregion_col_idx = stride * np.tile(np.arange(out_width), out_height)
235 |
236 | raw_idx = kernel_raw_idx.reshape(-1, 1) + convregion_raw_idx.reshape(1, -1)
237 | col_indx = kernel_col_idx.reshape(-1, 1) + convregion_col_idx.reshape(1, -1)
238 |
239 | channel_idx = np.repeat(np.arange(C), kernel_size * kernel_size).reshape(-1, 1)
240 |
241 | return (channel_idx.astype(int), raw_idx.astype(int), col_indx.astype(int))
242 |
243 | def col2ims(self, x, img_shape, kernel_size, stride):
244 | '''
245 | :param img_shape: 还原出的图像的大小:深度(RBG通道), 宽度, 高度
246 | :param kernel_size: 卷积核尺寸
247 | :param padding: 边界填充大小
248 | :param stride: 步长
249 | :return: 还原后的图像数据
250 | '''
251 | x_row_num, x_col_num = x.shape
252 | img_n, img_c, img_h, img_w = img_shape
253 | o_h = int(math.ceil((img_h - kernel_size + 0.) / stride)) + 1
254 | o_w = int(math.ceil((img_w - kernel_size + 0.) / stride)) + 1
255 | assert img_n * img_c * o_h * o_w == x_row_num
256 | assert kernel_size ** 2 == x_col_num
257 | surplus_h = (img_h - kernel_size) % stride
258 | surplus_w = (img_w - kernel_size) % stride
259 | pad_h = (kernel_size - surplus_h) % stride
260 | pad_w = (kernel_size - surplus_w) % stride
261 | output_padded = np.zeros((img_n, img_c, img_h + pad_h, img_w + pad_w))
262 | x_reshape = x.reshape(img_n, img_c, o_h, o_w, kernel_size, kernel_size)
263 | for n in range(img_n):
264 | for i in range(o_h):
265 | for j in range(o_w):
266 | output_padded[n, :, i * stride: i * stride + kernel_size, j * stride: j * stride + kernel_size] = \
267 | output_padded[n, :, i * stride: i * stride + kernel_size,
268 | j * stride: j * stride + kernel_size] + \
269 | x_reshape[n, :, i, j, ...]
270 | return output_padded[:, :, 0: img_h + pad_h, 0: img_w + pad_w]
271 |
272 | def load_params(self, weight, bias):
273 | pass
274 |
275 | def set_show_and_save_images(self, enable = False):
276 | self.show_and_save_images = enable
277 |
278 | class UpperLayerForPoolingTest(object):
279 | def __init__(self):
280 | self.batch_size = 1
281 | self.c_input = 1
282 | self.h_input = 6
283 | self.w_input = 6
284 |
285 | self.output_data = np.array([[[
286 | [0,1,2,3,4,5],
287 | [6,7,8,9,10,11],
288 | [12,13,14,15,16,17],
289 | [18,19,20,21,22,23],
290 | [24,25,26,27,28,29],
291 | [30,31,32,33,34,35]
292 | ]]])
293 |
294 | self.c_output, self.w_output , self.h_output = self.output_data.shape[1:]
295 |
296 | def forward(self):
297 | return self.output_data
298 |
299 | def backward(self, diff):
300 | pass
301 |
302 | def output_shape(self):
303 | return (self.c_output, self.h_output, self.w_output)
304 |
305 |
306 | if __name__ == '__main__':
307 | upper_layer = UpperLayerForPoolingTest()
308 |
309 | pooling_input = upper_layer.forward()
310 | print("\ninput to pooling layer:\n%s,\nshape: %s\n" % (pooling_input, pooling_input.shape))
311 |
312 | pooling = PoolingLayer(upper_layer, 2, 2)
313 |
314 | # 测试前向传播
315 | pooling_output = pooling.forward()
316 |
317 | expect_forward = np.array([[[
318 | [ 7, 9, 11],
319 | [19, 21, 23],
320 | [31, 33, 35]
321 | ]]])
322 | print("pooling forward expect output:\n%s,\nshape: %s\n" % (expect_forward, expect_forward.shape))
323 | print("pooling forward output:\n%s,\nshape: %s\n" % (pooling_output, pooling_output.shape))
324 |
325 | # 测试后向传播
326 | diff_next = np.array([[[
327 | [7, 9, 11],
328 | [19, 21, 23],
329 | [31, 33, 35]
330 | ]]])
331 | print("pooling diff:\n%s,\nshape: %s\n" % (diff_next, diff_next.shape))
332 |
333 | pooling.backward(diff_next)
334 |
335 | expect_backward = np.array([[[
336 | [ 0., 0., 0., 0., 0., 0.],
337 | [ 0., 7., 0., 9., 0., 11.],
338 | [ 0., 0., 0., 0., 0., 0.],
339 | [ 0., 19., 0., 21., 0., 23.],
340 | [ 0., 0., 0., 0., 0., 0.],
341 | [ 0., 31., 0., 33., 0., 35.]
342 | ]]])
343 | print("pooling backward, expect diff:\n%s,\nshape: %s\n" % (expect_backward, expect_backward.shape))
344 | print("pooling backward, diff:\n%s,\nshape: %s\n" % (pooling.diff, pooling.diff.shape))
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/Relu.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import numpy as np
3 | import matplotlib.pyplot as plt
4 | import matplotlib.font_manager as fm
5 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
6 |
7 |
8 | class ReLuLayer(object):
9 | def __init__(self, upper_layer, name = ''):
10 | self.name = name
11 | self.type = 'relu'
12 | self.upper_layer = upper_layer
13 | self.show_and_save_images = False
14 |
15 | self.batch_size = self.upper_layer.batch_size
16 |
17 | self.c_input, self.h_input, self.w_input = self.upper_layer.output_shape()
18 |
19 | self.w_output = self.w_input
20 | self.h_output = self.h_input
21 | self.c_output = self.c_input
22 |
23 | self.input_data = None
24 | self.output_data = None
25 | self.diff = None
26 |
27 | def forward(self):
28 | self.input_data = self.upper_layer.forward()
29 | self.batch_size = self.upper_layer.batch_size
30 |
31 | self.output_data = self.input_data.copy()
32 | self.output_data[self.output_data < 0] = 0
33 | self.show_forward_img(self.output_data)
34 | return self.output_data
35 |
36 | def backward(self, diff):
37 | self.diff = diff.copy()
38 | self.diff[self.input_data < 0] = 0
39 | self.upper_layer.backward(self.diff)
40 |
41 | def show_forward_img(self, imgs):
42 | if not self.show_and_save_images:
43 | return
44 | imgs_data = imgs
45 | channel = imgs_data.shape[0]
46 | pic_wh = int(channel)
47 | plt.figure(figsize=(pic_wh, imgs_data.shape[1]/10))
48 | for i in range(channel):
49 | plt.subplot(1, channel, i + 1)
50 | img = imgs_data[i].reshape(imgs_data.shape[1], 1)
51 | plt.imshow(img, interpolation='none', cmap='binary')
52 | plt.xticks([])
53 | plt.yticks([])
54 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
55 | plt.savefig("OutputImages/%s_output.png" % self.name)
56 | plt.show()
57 |
58 | def output_data(self):
59 | return self.output_data
60 |
61 | def output_shape(self):
62 | return (self.c_output, self.h_output, self.w_output)
63 |
64 | def load_params(self, weight, bias):
65 | pass
66 |
67 | def set_show_and_save_images(self, enable = False):
68 | self.show_and_save_images = enable
69 |
70 |
71 | class UpperLayerForReluTest(object):
72 | def __init__(self):
73 | self.batch_size = 1
74 | self.c_input = 1
75 | self.h_input = 4
76 | self.w_input = 4
77 |
78 | self.output_data = np.array([[[
79 | [1, 1, 1, 1],
80 | [1, -1, -1, 1],
81 | [1, -1, -1, 1],
82 | [1, 1, 1, 1]
83 | ]]])
84 |
85 | self.c_output, self.w_output , self.h_output = self.output_data.shape[1:]
86 |
87 | self.diff_next = np.array([[[
88 | [1, 1, 1, 1],
89 | [1, 2, -2, 1],
90 | [1, 2, -2, 1],
91 | [1, 1, 1, 1]
92 | ]]])
93 |
94 | def forward(self):
95 | return self.output_data
96 |
97 | def backward(self, diff):
98 | pass
99 |
100 | def output_shape(self):
101 | return (self.c_output, self.h_output, self.w_output)
102 |
103 |
104 | if __name__ == '__main__':
105 | upper_layer = UpperLayerForReluTest()
106 |
107 | relu_input = upper_layer.forward()
108 | print("\ninput to relu layer:\n%s,\nshape: %s\n" % (relu_input, relu_input.shape))
109 |
110 | relu = ReLuLayer(upper_layer)
111 |
112 | # 测试前向传播
113 | relu_output = relu.forward()
114 | expect_forward = np.array([[[
115 | [1, 1, 1, 1],
116 | [1, 0, 0, 1],
117 | [1, 0, 0, 1],
118 | [1, 1, 1, 1]
119 | ]]])
120 | print("relu forward expect output:\n%s,\nshape: %s\n" % (expect_forward, expect_forward.shape))
121 | print("relu forward output:\n%s,\nshape: %s\n" % (relu_output, relu_output.shape))
122 |
123 | # 测试后向传播
124 | print("relue diff:\n%s,\nshape: %s\n" % (upper_layer.diff_next, upper_layer.diff_next.shape))
125 | relu.backward(upper_layer.diff_next)
126 | expect_backward =np.array([[[
127 | [1, 1, 1, 1],
128 | [1, 0, 0, 1],
129 | [1, 0, 0, 1],
130 | [1, 1, 1, 1]
131 | ]]])
132 | print("relu backward, expect diff:\n%s,\nshape: %s\n" % (expect_backward, expect_backward.shape))
133 | print("relu backward, diff:\n%s,\nshape: %s\n" % (relu.diff, relu.diff.shape))
134 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/SoftmaxLoss.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import numpy as np
3 | import matplotlib.pyplot as plt
4 | import matplotlib.font_manager as fm
5 | font = fm.FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
6 |
7 |
8 | class SoftmaxLayer(object):
9 | def __init__(self, upper_layer, name = ''):
10 | self.name = name
11 | self.upper_layer = upper_layer
12 | self.show_and_save_images = False
13 | self.batch_size = self.upper_layer.batch_size
14 |
15 | def forward(self):
16 | self.input_data = self.upper_layer.forward()
17 | self.batch_size = self.upper_layer.batch_size
18 | t = np.exp(self.input_data - self.input_data.max(1).reshape(-1, 1))
19 | self.output_data = t / t.sum(1).reshape(-1, 1)
20 |
21 | self.show_forward_img(self.output_data)
22 | return self.output_data
23 |
24 | def show_forward_img(self, imgs):
25 | if not self.show_and_save_images:
26 | return
27 | imgs_data = imgs
28 | channel = imgs_data.shape[0]
29 | pic_wh = int(channel)
30 | plt.figure(figsize=(pic_wh, imgs_data.shape[1]/10))
31 | for i in range(channel):
32 | plt.subplot(1, channel, i + 1)
33 | img = imgs_data[i].reshape(imgs_data.shape[1], 1)
34 | plt.imshow(img, interpolation='none', cmap='binary')
35 | plt.xticks([])
36 | plt.yticks([])
37 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
38 | plt.savefig("OutputImages/%s_output.png" % self.name)
39 | plt.show()
40 |
41 | def get_output(self):
42 | return self.output_data
43 |
44 | def set_show_and_save_images(self, enable = False):
45 | self.show_and_save_images = enable
46 |
47 |
48 | class SoftmaxLossLayer(object):
49 | def __init__(self, upper_layer, data_input_layer, name = ''):
50 | self.name = name
51 | self.type = 'softmax'
52 | self.upper_layer = upper_layer
53 | self.data_input_layer = data_input_layer
54 |
55 | self.batch_size = self.upper_layer.batch_size
56 |
57 | self.w_output = 1
58 | self.h_output = 1
59 | self.c_output = 1
60 |
61 | self.input_data = None
62 | self.output_data = None
63 | self.diff = None
64 |
65 | self.loss = 0
66 |
67 | self.softmax = SoftmaxLayer(upper_layer, name = self.name)
68 |
69 | def forward(self):
70 | self.input_data = self.upper_layer.forward()
71 | self.batch_size = self.upper_layer.batch_size
72 |
73 | _, dim = self.input_data.shape
74 |
75 | # 减去最大值防止溢出
76 | t = np.exp(self.input_data - self.input_data.max(1).reshape(-1 ,1))
77 | softmax_data = t / t.sum(1).reshape(-1 ,1)
78 |
79 | # 太小的数置0
80 | softmax_data[softmax_data < 1e-30] = 1e-30
81 |
82 | s = np.tile(np.arange(dim), self.batch_size).reshape(self.input_data.shape)
83 |
84 | gt_index = s == self.data_input_layer.get_labels().reshape(-1, 1)
85 |
86 | # 根据标定值lable索引到输出位置,然后计算全局误差
87 | self.loss = 0 - np.average(np.log(softmax_data[gt_index]))
88 |
89 | self.diff = softmax_data.copy()
90 |
91 | self.output_data = softmax_data.copy()
92 |
93 | # d_softmax_loss = (softmax_output - 1) / m
94 | self.diff[gt_index] = self.diff[gt_index] - 1.
95 | self.diff = self.diff / self.batch_size
96 | return self.loss
97 |
98 | def backward(self, learning_rate):
99 | # 这里直接把学习率乘以误差梯度进行反向传播
100 | self.upper_layer.backward(self.diff * learning_rate)
101 |
102 | def show_forward_img(self, imgs):
103 | if not self.show_and_save_images:
104 | return
105 | imgs_data = imgs
106 | channel = imgs_data.shape[0]
107 | pic_wh = int(channel)
108 | plt.figure(figsize=(pic_wh, imgs_data.shape[1]/10))
109 | for i in range(channel):
110 | plt.subplot(1, channel, i + 1)
111 | img = imgs_data[i].reshape(imgs_data.shape[1], 1)
112 | plt.imshow(img, interpolation='none', cmap='binary')
113 | plt.xticks([])
114 | plt.yticks([])
115 | #plt.suptitle("%s_output" % self.name, fontproperties = font, fontsize=8)
116 | plt.savefig("OutputImages/%s_output.png" % self.name)
117 | plt.show()
118 |
119 | def predict(self):
120 | return self.softmax.forward()
121 |
122 | def get_output(self):
123 | return self.output_data
124 |
125 | def get_loss(self):
126 | return self.loss
127 |
128 | def output_shape(self):
129 | return (self.c_output, self.h_output, self.w_output)
130 |
131 | def load_params(self, weight, bias):
132 | pass
133 |
134 | def set_show_and_save_images(self, enable = False):
135 | self.show_and_save_images = enable
136 | self.softmax.set_show_and_save_images(enable)
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Layers/__init__.py
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Model/model.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/Model/model.h5
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/conv1_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/conv1_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/conv2_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/conv2_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/fc1_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/fc1_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/fc2_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/fc2_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/flatten_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/flatten_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/mnist_data_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/mnist_data_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/pool1_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/pool1_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/pool2_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/pool2_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/relu1_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/relu1_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/softmax_loss_output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/softmax_loss_output.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/train_pics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/OutputImages/train_pics.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/CNN-Network/main.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 |
4 | from Layers.NetworkBuilder import CNN_Network
5 |
6 |
7 | if __name__ == '__main__':
8 | print('CNN Network Building...')
9 | cnn = CNN_Network([
10 | {'name': 'mnist_data', 'type': 'input_layer', 'data_dir': 'data/mnist', 'batch_size': 64, 'test_size': 1},
11 | {'name': 'conv1', 'type': 'conv', 'kn': 20, 'k': 5, 's': 1, 'p': 0},
12 | {'name': 'pool1', 'type': 'pool', 'k': 2, 's': 2},
13 | {'name': 'conv2', 'type': 'conv', 'kn': 20, 'k': 5, 's': 1, 'p': 0},
14 | {'name': 'pool2', 'type': 'pool', 'k': 2, 's': 2},
15 | {'name': 'flatten', 'type': 'flatten'},
16 | {'name': 'fc1', 'type': 'fc', 'c_output': 500},
17 | {'name': 'relu1', 'type': 'relu'},
18 | {'name': 'fc2', 'type': 'fc', 'c_output': 10},
19 | {'name': 'softmax_loss','type': 'softmax_loss'}
20 |
21 | ], base_lr = 1e-2, l2_regulation = 8e-6, epoch_period = 10)
22 |
23 | # 显示cnn网络结构信息
24 | cnn.show_network_info()
25 |
26 | # 挑前n张训练集合的图片显示
27 | #cnn.show_data_images(100)
28 |
29 | # 训练打开下面3行代码
30 | #cnn.choose_dataset('train')
31 | #cnn.set_show_and_save_images(enable=False)
32 | #cnn.run(stop_when_epoches_gte = 9000, stop_when_accuracy_gte = 0.995)
33 |
34 | # 用现成模型测试打开下面4行代码
35 | cnn.choose_dataset('test')
36 | cnn.load_model('Model/model.h5')
37 | cnn.set_show_and_save_images(enable=True)
38 | cnn.predict()
39 |
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/04C9E0B3DDFFAE6DBF0692451F6992D1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/04C9E0B3DDFFAE6DBF0692451F6992D1.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/08E51AD720981A718F79635F3C175469.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/08E51AD720981A718F79635F3C175469.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/173BE7B5673987828414CBAB75111379.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/173BE7B5673987828414CBAB75111379.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/1E97985A1B2BB3FE1B5C98D77AC5A403.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/1E97985A1B2BB3FE1B5C98D77AC5A403.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/24170F1D134952DFD522B4CADC1FFD8F.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/24170F1D134952DFD522B4CADC1FFD8F.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/29CED44A9D37FEC25A2448EE9B041256.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/29CED44A9D37FEC25A2448EE9B041256.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/2B3B1E8B6725BE2CBEDC4466384042A7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/2B3B1E8B6725BE2CBEDC4466384042A7.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/2FA771C954BE667E95561579518D46F0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/2FA771C954BE667E95561579518D46F0.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/3BA9904D9A93E639A6577E317A295DD0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/3BA9904D9A93E639A6577E317A295DD0.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/45C1395B84E554772D1AFB28C80EE7C9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/45C1395B84E554772D1AFB28C80EE7C9.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/49FDC432141B5F7D59B17F93E594A777.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/49FDC432141B5F7D59B17F93E594A777.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/53081124276177707263BF45B962832D.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/53081124276177707263BF45B962832D.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/705305FEE5A050575544C64067405FCE.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/705305FEE5A050575544C64067405FCE.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/7CED4CBD723175E6811557CA99B83837.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/7CED4CBD723175E6811557CA99B83837.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/85182DA6962E2C26664D03DC1647AB31.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/85182DA6962E2C26664D03DC1647AB31.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/8645FA96B78267F6B995D7909C263CE4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/8645FA96B78267F6B995D7909C263CE4.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/8D72F4E6CDD66BC654D440390E42F922.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/8D72F4E6CDD66BC654D440390E42F922.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/965FBFC2D682036ED178B7DD1EDD50FA.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/965FBFC2D682036ED178B7DD1EDD50FA.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/9EEC442D8B126FD3F3B53E19704201A9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/9EEC442D8B126FD3F3B53E19704201A9.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/A5BFC0E4FDD254F431C6B702CFB6E463.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/A5BFC0E4FDD254F431C6B702CFB6E463.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/ACB9841BC14C57C09CA27F6ED6BBEC5C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/ACB9841BC14C57C09CA27F6ED6BBEC5C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/B9663FCC0A0B42FA0E7082FFC1BFF9E3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/B9663FCC0A0B42FA0E7082FFC1BFF9E3.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/BAAF3CFE34D7CFE2F69F7F8AE0D42735.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/BAAF3CFE34D7CFE2F69F7F8AE0D42735.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/BCBCEFAF634DEA7AEA8B53898F1BA866.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/BCBCEFAF634DEA7AEA8B53898F1BA866.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/CA203A8C36C14AE9C2DC0870C1ECE8E6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/CA203A8C36C14AE9C2DC0870C1ECE8E6.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/CB3DF2830392E247AA78C4F33230483C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/CB3DF2830392E247AA78C4F33230483C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/D6893085EC1FE4A0AD20F68589BE1768.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/D6893085EC1FE4A0AD20F68589BE1768.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/DC6921D73DAB14ED98A26032A73F0AA9.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/DC6921D73DAB14ED98A26032A73F0AA9.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/E351E2E6EDC5210A4C60E2E09DC1C43C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/E351E2E6EDC5210A4C60E2E09DC1C43C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/E5189072F39325215235950E90F6F9EF.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/E5189072F39325215235950E90F6F9EF.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/E61DF3C6A20A5F78F43CE5789F7FD9FF.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/E61DF3C6A20A5F78F43CE5789F7FD9FF.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/EBD4E3242A6B9AB67BE41F808DD2FD8E.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/EBD4E3242A6B9AB67BE41F808DD2FD8E.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FA8B0532561AD9A74CAAF78BD7175437.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FA8B0532561AD9A74CAAF78BD7175437.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FB2E612B54BB961753B87FDCBC9D1E68.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FB2E612B54BB961753B87FDCBC9D1E68.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FD3AADAD7C3BF1F8C190E84BCAB47DF9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FD3AADAD7C3BF1F8C190E84BCAB47DF9.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FDE7CEEA3FB146BDDCA545DB6BD3B6CC.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FDE7CEEA3FB146BDDCA545DB6BD3B6CC.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FE0DB3B95EB7135EB37A8EE627A6FE08.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FE0DB3B95EB7135EB37A8EE627A6FE08.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FFE5AA9D3CA5F3A1248F531F72E20B1A.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Html版本/resources/FFE5AA9D3CA5F3A1248F531F72E20B1A.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/AI从入门到放弃:手撕卷积神经网络(CNN).md:
--------------------------------------------------------------------------------
1 | # 导语:
2 | > 很多人习惯于用ML框架来玩CNN,但是具体的算法细节不甚关心。本文着手于CNN的运作原理的详解,到算法推导以及算法的代码实现,带你走进更为广阔的AI世界。
3 | ---
4 |
5 | # 一. 我是谁,我在哪:
6 | - 阅读本文的基础:
7 | 我会认为你对BP神经网络有充分的了解,看过我前两篇文章,有些点我会直接从前文直取而引。
8 |
9 | - 上两篇笔记的传送门:
10 | - [**《AI从入门到放弃:BP神经网络算法推导及代码实现笔记》**](http://km.oa.com/articles/view/366930)
11 | - [**《CNN的导火索,用MLP做图像分类识别?》**](http://km.oa.com/group/21327/articles/show/344164)
12 |
13 | - CNN算法难点主要还是在卷积层的反向传播上,其他的还好。
14 | - 文章会从CNN的原理介绍开始,然后过渡到算法推导,最后是算法的实现。
15 | - 如果要使用既有框架,首选caffe
16 | ---
17 |
18 | # 二. 卷积神经网络的基本结构和效果体验
19 | ## 1. LeNet-5
20 | - 在这篇笔记里,我打算用 **LeNet-5** 这一经典结构作为范例,来说明卷积神经网络的原理。
21 |
22 | - **LeNet-5** 是 **Yann LeCun** 在1998年设计的用于手写数字识别的卷积神经网络,当年美国大多数银行就是用它来识别支票上面的手写数字的,它是早期卷积神经网络中最有代表性的实验系统之一。
23 |
24 | - **Yann LeCun** 的 【[**主页**](http://yann.lecun.com)】,见文献[1]。**LeNet-5** 的 【[**论文**](http://yann.lecun.com/exdb/publis/pdf/bengio-95.pdf )】,见文献[2]
25 |
26 | ## 2. LeNet-5结构图:
27 | 我先不会细说这个图,放图的目的是先有个感性认识。我们可以看到,卷积神经网络的基本构成是:
28 |
29 | - 数据输入(Input)
30 | - 卷积层 (Convolution Layer)
31 | - 池化层(Pooling Layer)
32 | - 全链接层 (Fullconnection Layer)
33 | - 结果输出 (output)
34 |
35 | 
36 |
37 | 以CNN识别手写数字的经典范例来体验一下:
38 | - 一个是LeCun主页里的,动态图左边依次是各个网络层输出数据的模样,右边是LeNet-5的数字识别结果:【[**传送门**](http://yann.lecun.com/exdb/lenet/index.html)】[3]
39 |
40 | 
41 |
42 | - 还有这个,你可以自己改变网络结构,验证模型的效果,强烈推荐!【[**传送门**](https://cs.stanford.edu/people/karpathy/convnetjs/demo/mnist.html)】[4]
43 | 
44 |
45 | - 一个更好玩的是,自己用鼠标写数字,可以看到每一层的输出,并且是3D的,可以自己随意调整观察角度:【[**传送门**](http://scs.ryerson.ca/~aharley/vis/conv/)】[5]
46 | 
47 |
48 |
49 | # 三. 一层一层的剥洋葱
50 | ## 1. 卷积层(Convolution Layer)
51 | ### 1.1 什么是卷积
52 |
53 | **一维卷积:**
54 | 经常用在信号处理中,用于计算信号的延迟累积。其实没那么抽象和高深,举例(先声明,本人拒绝暴力):
55 | > - 电影《我的野蛮女友》里,男主牵牛经常被女主明熙揍,以牵牛打脸举例
56 | >
57 | > - 牵牛惹明熙生气了,明熙反手就是一巴掌打在牵牛脸上,牵牛脸肿了,完全消肿是需要一定时间的
58 | >
59 | > - 但是明熙没有给牵牛时间,一巴掌没过瘾,反手又是一巴掌打在相同位置上。那么问题来了,这个时候怎么计算牵牛的脸肿到什么程度呢?要知道上一巴掌还没消肿,一波未平一波又起。
60 | >
61 | > - 为了计算这个肿的程度,就得用卷积。因为显然的,牵牛的脸肿的程度,和上一个巴掌也有关系,所以卷积的计算需要沿时间轴翻转;又因为上一个巴掌的肿是会随着时间消退的,所以卷积计算需要沿着时间轴滑动,然后计算出延迟累积,就得到了打第n个巴掌后,牵牛脸肿的程度。
62 | >
63 | > - 牵牛真可怜...
64 | >
65 | >上面就是对卷积的直观解释,这个时候再看公式,应该很简单了:
66 | \begin{aligned}
67 | &y(n) = w(n)*x(n) = \sum_{i=-\infty}^{\infty}w(i)\ x(n-i) \qquad (1.1)\\&
68 | 其中,*号代表卷积运算, n代表第几次打脸\\&
69 | y(n)代表打第n个巴掌造成的脸肿程度\\&
70 | w(n)代表打第n个巴掌的姿势,姿势不同,力度不同,打脸效果会不一样\\&
71 | x(n)代表打第n个巴掌时候的脸,x(n-i)代表翻转,当前时刻的脸的模样是和前n次被打有关联的
72 | \end{aligned}
73 |
74 | **二维卷积:**
75 | 说白了就是给图片上滤镜,爱自拍的美女鲜肉们,你们没少用吧?
76 | >\begin{aligned}
77 | &给定一个图像\ X\in \mathbb{R}^{M\times N}, 滤波器\ W\in \mathbb{R}^{m\times n},\\&
78 | 一般\ m << M,\ n << N, 其卷积为:\\&
79 | y(n) = w(n)*x(n) = \sum_{a=1}^{m}\sum_{b=1}^{n} w_{ab} \cdot x_{i-a+1,\ j-b+1} \qquad (1.2) \\&
80 | 其中,*号代表卷积运算\\&
81 | \end{aligned}
82 | > 二维卷积的公式要这样理解,w认为是卷积核,由于卷积是满足交换律的,即A*B=B*A,上面的公式x需要翻转,但一般做法是,翻转卷积核180度,然后做滑动累积求和。下面的图告诉你怎么做,GIF做得略简陋,凑合着看吧:
83 | >- 先把卷积核翻转180度
84 | >
85 | >
86 | >- 然后从左到右从上到下滑动,每个窗口各个元素相乘后求和,就是当前位置的卷积输出。
87 | > 例如: 1x(-1)+ 3x0 + 2x0 + 6x1 = 5,其他同理。
88 | >
89 |
90 | ###1.2 什么是互相关,为什么机器学习其实用的是互相关而不是卷积,却号称是使用卷积
91 | 定义:**互相关(cross-correlation)** 是一个衡量两个序列相关性的函数,通常是用滑动窗口的点积计算来实现。
92 | >Tips:
93 | >- 在机器学习领域,卷积的主要功能是在一个图像或一个特征上滑动卷积核(滤波器),以得到一组新的特征。
94 | >
95 | >- 看过Andrew Ng的深度学习视频的同学都知道。他在视频中提到过,机器学习场景下,卷积其实是不需要做卷积核翻转180度的操作的。
96 | >
97 | >- 不翻转的卷积,是不满足卷积的交换性的,但是对于机器学习来说,满不满足交换律根本无关紧要,反而省略掉卷积核的翻转操作,可以简化实现。
98 | >
99 | >- 所以机器学习里提到的卷积其实不是真正的卷积,严谨的来说叫“互相关”,或者成为“不翻转卷积”,只是大家在写论文的时候习惯了用卷积这个名词,来显得好听高大上点而已。
100 |
101 | 看看互相关的公式,注意看和公式(1.2)的差异,符号变为正号,说明互相关和卷积的差别在于,互相个是不需要做翻转操作的:
102 | \begin{aligned}
103 | &给定一个图像\ X\in \mathbb{R}^{M\times N}, 滤波器\ W\in \mathbb{R}^{m\times n},\\&
104 | 一般\ m << M,\ n << N, 其卷积为:\\&
105 | y_{i,\ j} = \sum_{a=1}^{m}\sum_{b=1}^{n} w_{ab} \cdot x_{i+a-1,\ j+b-1} \qquad (1.3) \\&
106 | 把上式表述为:
107 | Y = W\otimes X,\quad 其中\otimes代表互相关运算, \ Y \in \mathbb{R}^{M-m+1,\ N-n+1} \qquad (1.4)\\&
108 | 下文按照习惯,不再用“互相关”的叫法,而是用“卷积”;\\&
109 | 如果没有特殊说明,下文说的卷积就是互相关,也就是不翻转卷积
110 | \end{aligned}
111 | 看看不翻转时,卷积结果如何:
112 | 
113 |
114 | ###1.3 为什么要用卷积
115 | - **局部连接 - 可以使得网络能提取到局部特征,而不再只是全局的:**
116 | 上一篇文章[**《CNN的导火索,用MLP做图像分类识别?》**](http://km.oa.com/group/21327/articles/show/344164) 已经说过,全连接会使得神经网络权重呈指数级膨胀,会让计算量陡增,网络难以训练。卷积采用的是局部连接的方式,即卷积层输出对应看成是一个神经元在输出,每个神经元只感受局部,相当于它的“视野”只关注特定区域。这样使得神经层之间的连接数量大大减少。局部连接的思想,也是受启发于生物学里面的视觉系统结构,视觉皮层的神经元就是局部接受信息的。
117 | > 举例子:假设卷积层的输入是 3x3 = 9 的,卷积核大小是 2x2 = 4
118 | > - 如果使用全连接方式,那么该层神经元的连接数是 9x4 = 36
119 | > - 如果使用局部连接方式,那么该层神经元的连接数是 ((3-2)+ 1)x4 = 16
120 | > 局部连接的计算公式后面再说。
121 | >
122 | >4
123 | >
124 | > 卷积层的输出也是 Z = 2x2 = 4的,可以理解层有4个神经元,那么每个神经元关注的视野可以看下图:
125 | > 当卷积核在图像上从左到右从上到下滑动时,就可以看出,每个神经元只对特定区域的感兴趣,也就是所谓的“局部野”。
126 | > $$卷积层输出:Z = W\otimes a+b $$
127 | > 
128 | >
129 |
130 | - **权重共享 - 可以降低计算量**
131 | > 一个2x2大小卷积核,那么卷积层的权重w个数就是4个,可以卷积层和上一层的连接是共享权重的,当做卷积操作时,观察卷积核的每一个权重扫描过的位置,就知道那些输入是共享同一个权重了。
132 | >
133 | > 
134 | >
135 | >如果画成我们熟悉的神经元连接图,那就可以很直观的看到权重是怎么共享的了:
136 | >
137 | >
138 | >总的来说,权重共享的意义在于:
139 | > - 降低参数数量,从而大大降低运算量
140 | >
141 | > - 从生物学的角度去理解权重共享,相邻神经元的活性相似,从而可以它们共享相同的连接权值。并且卷积核就是一个滤波器,某个滤波器提取特定的特征,这种提取方式与图像等数据的位置无关。所以,对于同一个卷积核,它在一个区域提取到的特征,也能适用于于其他区域。
142 | >
143 | > - 由于参数共享,即使图片进行了一定的位移,其原来的特征仍然可以被提取到,这一“平移不变性”使得神经网络泛化能力更强。
144 |
145 | ### 1.4 卷积是怎么做到特征提取的?
146 | 卷积核(滤波器)其实就是通过增强特定区域,过滤掉不感兴趣的区域,达到特征提取的功能。比如做水平边缘特征提取,那滤波器设计就沿着水平方向保留原始特征,垂直方向的特征则弱化或过滤。所以水平边缘特征提取的卷积核,水平方向的数值是不变的,看滤波器数值,水平方向都是[1,1,1],[0,0,0],[-1,-1,-1];而垂直方向都是[1,0,-1],当做卷积计算时,垂直方向的信息就被求和弱化,自然就过滤掉了垂直方向的信息。
147 |
148 | 
149 |
150 | 举例,对图像分别做水平,垂直方向的特征提取。仔细观察卷积输出图像的效果差别,水平和垂直的特征在使用不同的卷积核分别被提取了出来。
151 | 
152 |
153 | ###1.5 卷积的类型
154 | 我们是上面举的例子,都是没有做边界填充,并且卷积核移动的步长都是1。但是原始图像经过卷积后,图像大小会变小,随着网络加深,那么处理后的图像会越来越小,会不断的损失边缘信息。那么有些场合下,是需要通过边界零填充,来保障卷积计算前后图像尺寸维持不变。
155 | 卷积输出图像尺寸的计算公式如下:
156 | >\begin{aligned}
157 | &o = \frac{n+2p-k_{}}{s}+1\\&
158 | 其中,o为输出大小,n为输入图片大小,p为边界填充大小,k为卷积核大小,s为步长\\&
159 | 例如:输入图片尺寸是3\times 3,卷积核是2\times 2,边界填充p=0,步长为1,那么输出图像大小就是:\\&
160 | o=\frac{3+2*0-2}{1}+1=2, 正方形图像,那么输出就是2\times 2大小
161 | \end{aligned}
162 |
163 | **具体类型的效果**
164 | >- 窄卷积(无边界零填充卷积),我们上面举例的卷积都没有做边界零填充(Zero Padding),移动的步长是1,看图:
165 | 
166 | >
167 | >- 宽卷积(有边界零填充卷积),可以看到做了边界填充,卷积后输出图像和输入图像尺寸是一样的
168 | >
169 | >
170 | >- 步长不是1时,下图是个步长为2的卷积示例:
171 | >
172 | >
173 | >- 还有很多种类型的卷积,比如转置卷积,空洞卷积等,这里就不介绍了。
174 |
175 | ###1.6 卷积层小结
176 | - 本节介绍了卷积层的工作原理和计算方式
177 | - 卷积层就是一堆卷积核(滤波器)提取不同的图像特征
178 | - 卷积层通过局部连接和权重共享,达到降低参数数量,简化计算的目的
179 | - 由于卷积“局部野”作用,图像产生一定位移,变形,也不会影响到特征的提取,使得网络泛化能力得到提高。
180 |
181 |
182 | ## 2. 池化层(Pooling Layer)
183 | ### 2.1 什么是池化层:
184 | 池化层的上一层一般是卷积层,即卷积层的输出就是池化层的输入。池化层也可以成为“降采样”层,降采样就是选取出每个区域中的最大值(max-pooling)或是平均值(mean-pooling)。本文以max-pooling为例讲解。
185 |
186 | ### 2.2 池化层的运作原理:
187 | 先上公式,池化层输入和输出的关系:
188 | >\begin{aligned}
189 | &o = \frac{n+2p-k_{}}{s}+1\\&
190 | 其中,o为输出大小,n为输入图片大小,p为边界填充大小,k为池化窗口大小,s为步长\\&
191 | 例如:输入图片尺寸是6\times 6,池化窗口大小是3\times 3,边界填充p=0,步长为3,那么输出图像大小就是:\\&
192 | o=\frac{6+2*0-3}{3}+1=2, 正方形图像,那么池化输出就是2\times 2大小
193 | \end{aligned}
194 |
195 | 直观一点的效果:左边的图片是卷积层的输出图片,输入到池化层后得出的效果为右边图片:
196 | 
197 |
198 | **max-pooling的计算过层,把每个池化窗口的最大值取出来,这就是所谓的降采样过程:**
199 | 
200 |
201 | ### 2.3 池化层的作用:
202 | - 可以从上面的数字计算图看到,max-pooling就是挑选特定区域中的最大值的过程。通过消除非极大值,进一步的减少了参数数量,降低了上层的计算复杂度,防止因参数过多带来的过拟合。
203 |
204 | - 在同一区域,最大值不论在区域的任何位置,池化的结果都不会改变。比如上图的最大值换了个位置,池化输出都能保留该区域最显著的特征,这样的好处就是,即便图片发生了一定的位移,旋转,形变,神经网络都能正确的识别图像的结果,神经网络的鲁棒性大大提高。
205 | 就和人写字一样,字写歪了写丑了一点,但没关系,依然能看得出来是哪一个字。
206 | 
207 |
208 | ### 2.4 池化层小结:
209 | 池化层原理是比较简单的,但是好处也是明显的。减少参数的同时保留住了图像的显著特征。所谓降采样,作用更像是一个降噪的过程,对网络的稳定性提供了保障。但是池化层也有缺点,在网络的反向传播过程中,不管是max-pooling还是mean-pooling,都无法还原全部原始的信息。个人理解,在做梯度下降计算误差时,由于丢失了一部分原始信息,所以得到的误差更类似于一个最大似然的值。虽然对网络训练有影响,但是影响程度不大。
210 |
211 |
212 | ## 3. 扁平化层(Flatten Layer)
213 | Flatten层一般在卷积层或者池化层之后,全连接层之前。作用就是降维,把2D的数据1D化,也就是扁平化的意思。因为全连接层的输入一般是1维的,所以在数据进入全连接层前,Flatten层就充当了数据预处理的角色。
214 |
215 | 
216 |
217 | ## 4. 全连接层(Full Connection Layer)
218 | 全连接层应该都很熟悉了,参考我之前写的[**《AI从入门到放弃:BP神经网络算法推导及代码实现笔记》**](http://km.oa.com/articles/view/366930)。经过卷积层和池化层后,得到一系列特征图,全连接层的作用就是特征分类器,经过特征分类后得到类型的概率分布,最后将全连接层的输出经softmax处理得到具体的判定类型的概率值。
219 | 
220 |
221 | ## 5.Softmax层(Softmax Layer)
222 | Softmax一般是在全连接层后。以手写数字分类,数字从0到9,经过全连接层分类后,有十个输出,分别对应10个分类特征,但是并不直观。softmax函数的作用就是把这10个特征映射成概率(0,1)的10个概率值,概率最高的就对应某个数字,如下图:
223 |
224 | 
225 |
226 | 再拿网上的一张图,可以看到softmax的算法结构,原来输出是3,1,-3通过softmax函数一作用,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质)。可能有的同学会问,为什么还要softmax,直接看全连接层的输出,挑最大的也可以得到结果啊?答案是这一切都是为了算法服务的,别忘了后面还有梯度下降算法,softmax就是把统计输出在概率上归一化,神经网络误差计算需要这么做。另外,softmax函数使用指数函数,误差求导的时候也便利很多,因为指数函数的导数就是它本身。
227 | 
228 |
229 | # 四. CNN的正向传播算法
230 | ## 1.卷积层(Convolution Layer)的正向传播计算
231 | ###1.1 正向传播
232 | 
233 | 前面介绍过了,在CNN中,所谓的卷积运算是“互相关”,或者称为“不翻转卷积”。如上图所示,那么卷积层的前向传播过程为:
234 | >\begin{aligned}
235 | &假设第l层为卷积层,为不失一般性,假设前一层(第l-1层)使用了激活函数\sigma\ ;\\&
236 | 来自前一层(第l-1层)的输出\ z^{l-1}经过激活函数激活后作为卷积层的输入,即:\\&
237 | a^{l-1} = \sigma(z^{l-1}),\ 且\ a^{l-1}\in \mathbb{R}^{M\times N};\\&
238 | 设卷积核\ W\in \mathbb{R}^{m\times n},\ 一般\ m << M,\ n << N;\\&
239 | 卷积输入的下标为i \in \mathbb{R}^M,\ j \in \mathbb{R}^N,那么卷积层的正向传播输出 z^l 表示为:\\&
240 | z_{\ i,\ j}^{l} = W^l \ast a_{i,\ j}^{l-1}+b_{i,\ j}^l = W^l \ast \sigma(z_{i,\ j}^{l-1})+b_{i,\ j}^l = \sum_{u=1}^{m}\sum_{v=1}^{n} w_{uv} \sigma(z_{i+u-1,\ j+v-1}^{l-1})+b_{i,\ j}^l \qquad (4.1)\\&
241 | 注:用下标索引到卷积核的元素是,用小写的w加下标表示。
242 | \end{aligned}
243 |
244 | ###1.2 反向传播
245 | ####1.2.1 卷积层误差的梯度算法
246 | **思路:** 可以对比MLP的BP算法,反向传播过来的误差,通过矩阵运算将误差往前传递。观察卷积层,在反向传播时,误差可以类比为通过卷积运算往前传递。让我们开始吧:
247 | 
248 | >\begin{aligned}
249 | &如上图,假设第l层为卷积层,且第(l-1)层输出使用了激活函数\sigma;\\&
250 | 卷积层的误差为\delta^l, 反向传播后到上一层的误差为\delta^{l-1};\\&
251 | 从正向传播计算知:a^{l-1} = \sigma(z^{l-1}),\ 且\ a^{l-1}\in \mathbb{R}^{M\times N};\\&
252 | 设卷积核\ W\in \mathbb{R}^{m\times n},\ 一般\ m << M,\ n << N;\\&
253 | 卷积输入的下标为i \in \mathbb{R}^M,\ j \in \mathbb{R}^N;\\&
254 | 卷积层的误差为J(W,b),梯度为\delta^l;\\&
255 | 我们的目标是:计算出经过卷积层反向传播到第(l-1)层的误差的梯度\delta^{l-1}:\\&
256 | \delta^{l-1}_{i,\ j}=\frac{\partial J(W,b)}{\partial z^{l-1}_{i,\ j}},\ 根据链式求导法则:\\&
257 | \quad\ \ =\sum_{i^{\prime}=1}^{m}\sum_{j^{\prime}=1}^{n} \frac {\partial J(W,b)}{\partial z^l_{i^{\prime},\ j^{\prime}}}\frac {\partial z^l_{i^{\prime},\ j^{\prime}}}{\partial z^{l-1}_{i,\ j}}\\& \quad\ \ 其中i^{\prime},j^{\prime}为卷积层(l层)的卷积运算下标,\\&
258 | \quad\ \ 撇号这里只是为了和第(l-1)层的i, \ j做区分,并不是导数,将式(4.1)代入,接着算:\\&
259 | \quad\ \ = \sum_{i^{\prime}=1}^{m}\sum_{j^{\prime}=1}^{n} \delta^l_{i^{\prime},\ j^{\prime}}\frac {\partial (\sum_{u=1}^{m}\sum_{v=1}^{n}w^l_{u,\ v}\sigma(z^{l-1}_{i^{\prime}+u-1,\ j^{\prime}+v-1})+b^l_{i^{\prime},\ j^{\prime}})}{\partial z^{l-1}_{i,\ j}}\\&
260 | \quad\ \ 注意这个式子,不要怂一起上,求关于\ z^{l-1}_{i,\ j}\ 的偏导,偏置\ b^l_{i^{\prime}}\ 为常数,求导数的时候为0;\\&
261 | \quad\ \ w^l_{u,\ v}也为常数,现在关键看\frac {\partial (\sigma(z^{l-1}_{i^{\prime}+u-1,\ j^{\prime}+v-1}))}{\partial z^{l-1}_{i,\ j}}是什么东西,\\&
262 | \quad\ \ 这明显是第(l-1)层激活函数\sigma关于第(l-1)层的输出z^{l-1}的导数;\\&
263 | \quad\ \ 注意观察,根据求导法则,求和序列的偏导数是和顺序无关的,这里必然满足: i=i^{\prime}+u-1,\ j=j^{\prime}+v-1;\\&
264 | \quad\ \ = \sum_{i^{\prime}=1}^{m}\sum_{j^{\prime}=1}^{n}\delta^l_{i^{\prime},\ j^{\prime}}w^{l}_{u,\ v}\sigma^{\prime}(z^{l-1}_{i,\ j})\\&
265 | \quad\ \ 卷积层的下标: u=i-i^{\prime}+1,\ v=j-j^{\prime}+1,\ 代入换算后的坐标继续算:\\&
266 | \quad\ \ =\sum_{i^{\prime}=1}^{m}\sum_{j^{\prime}=1}^{n}\delta^l_{i^{\prime},\ j^{\prime}}w^{l}_{i-i^{\prime}+1,\ j-j^{\prime}+1}\sigma^{\prime}(z^{l-1}_{i,\ j})\\&\\&
267 | \quad【敲黑板时间】:翻回去看式(1.2),是不是和真正的卷积计算表达一样?\\&
268 | \quad\ \ 也就是说,如果CNN使用的是真正的卷积,那么我们的结果直接写成\ \delta^l*\ w^l_{i,\ j}\sigma^{\prime}(z^{l-1}_{i,\ j}),\\&
269 | \quad\ \ 但是!CNN里用的是“不翻转卷积”,所以CNN中的运算符\ `*`\ 不是表达为真正的卷积,\\&
270 | \quad\ \ 所以我门的最终结果是:\\&
271 | \quad\ \ \delta^{l-1}=\delta^l*\ w_{-i,\ -j}^l\sigma^{\prime}(z^{l-1}_{i,\ j})\\&
272 | \quad\ \ 显然:-i,\ -j\ 说明卷积核\ w\ 的横轴和纵轴相位相反,二维上的说法就是整个儿翻转了180^\circ,\\&
273 | \quad\ \ 这里用\ ROT180\ 表示这个操作,即:\\&
274 | \quad\ \ \delta^{l-1}=\delta^l*\ ROT180(w^l)\odot\sigma^{\prime}(z^{l-1}_{i,\ j}),\ \quad\quad\ \ (4.2)\\&
275 | \quad 【这里特别说明一下,当公式的运算量不是用标出下标的写法而是矩阵时,\odot表示为矩阵的Hadamard积,\\&
276 | \quad\ \ 不是矩阵乘法,这里不赘述,请自行度娘;下文遇到该运算符同此,不再做说明】\\&\\&
277 | \quad\ \ 如果第l-1层没有激活函数的话,即\sigma(z^{l-1})=z^{l-1},那么激活函数的导数:\sigma^{\prime}(z^{l-1}_{i,\ j})=1,那么此时:\\&
278 | \quad\ \ \delta^{l-1}=\delta^l*\ ROT180(w^l) \quad\quad\quad\quad\quad\quad\quad (4.3)\\&\\&
279 | \quad\ \ 【卷积层误差梯度计算说明】:注意这里设偏置b为0,所以表达的是偏置为0的卷积计算。\delta^l是上一层的反向误差梯度,\\&
280 | \quad\ \ 是已经计算出来了的,它对卷积层而言就是一个常数,而且卷积核\ w\ 也是已知量。所以卷积层的误差梯度计算就是,\\&
281 | \quad\ \ 拿\delta^l与卷积核\ w\ 旋转180^\circ后做“不翻转卷积”计算即可,是不是很简单。
282 | \end{aligned}
283 |
284 | ####1.2.2 卷积核 w 的误差梯度算法
285 | 模型要更新,那么同样需要卷积层的卷积核w和偏置b的梯度。有了误差梯度计算的基础,算卷积核的梯度就容易理解的多了,开始吧。
286 | >\begin{aligned}
287 | &\frac {\partial J(W,b)}{\partial w^l_{i,\ j}}= \sum_{i=1}^{m}\sum_{j=1}^{n} \frac {\partial J(W,b)}{\partial z^l_{i,\ j}}\frac {\partial z^l_{i,\ j}}{\partial z^{l-1}_{i,\ j}},\quad 根据链式求导法则:\\&
288 | \quad\quad\quad\quad = \sum_{i=1}^{m}\sum_{j=1}^{n} \delta^l_{i,\ j}\frac {\partial (\sum_{u=1}^{m}\sum_{v=1}^{n}w^l_{u,\ v}\sigma(z^{l}_{i+u-1,\ j+v-1})+b^l_{i,\ j})}{\partial w^{l}_{i,\ j}}\\&
289 | \quad\quad\quad\quad = \sum_{i=1}^{m}\sum_{j=1}^{n} \delta^l_{i,\ j}\sigma(z^{l}_{i+u-1,\ j+v-1}),\ 此时偏导量为w,因为w对自身求导,导数为1。\\&
290 | \quad\quad\quad\quad = \delta^l*\sigma(z^{l}) \quad\quad\quad\quad\quad\quad\quad\quad\ (4.4)\\&
291 | 【卷积核梯度计算说明】:注意这里设偏置b为0,所以参考式(4.1)就知道是偏置为0的卷积的表达式
292 | \end{aligned}
293 |
294 | ####1.2.3 卷积层偏置 b 的误差梯度算法
295 | 同理,计算偏置b的梯度:
296 | >\begin{aligned}
297 | &\frac {\partial J(W,b)}{\partial b^l_{i,\ j}}= \sum_{i=1}^{m}\sum_{j=1}^{n} \frac {\partial J(W,b)}{\partial z^l_{i,\ j}}\frac {\partial z^l_{i,\ j}}{\partial b^{l-1}_{i,\ j}},\quad 根据链式求导法则:\\&
298 | \quad\quad\quad\quad = \sum_{i=1}^{m}\sum_{j=1}^{n} \delta^l_{i,\ j}\frac {\partial (\sum_{u=1}^{m}\sum_{v=1}^{n}w^l_{u,\ v}\sigma(z^{l}_{i+u-1,\ j+v-1})+b^l_{i,\ j})}{\partial b^{l}_{i,\ j}}\\&
299 | \quad\quad\quad\quad此时偏导量为b因为b对自身求导,导数为1;而\sum_{u=1}^{m}\sum_{v=1}^{n}w^l_{u,\ v}\sigma(z^{l}_{i+u-1,\ j+v-1})\\&
300 | \quad\quad\quad\quad不包含b,对b的偏导数为0,所以最终计算结果为:\\&
301 | \quad\quad\quad\quad = \sum_{i=1}^{m}\sum_{j=1}^{n} \delta^l_{i,\ j}(0+1)\\&
302 | \quad\quad\quad\quad = \sum_{i=1}^{m}\sum_{j=1}^{n} \delta^l_{i,\ j} \quad\quad\quad\quad\quad\quad\ (4.5)\\&
303 | 【卷积层偏置的梯度计算说明】:所以偏置b的梯度更简单,就是卷积层的误差\delta^l
304 | \end{aligned}
305 |
306 | **卷积层反向传播算法总结:**
307 | - 卷积层的反向传播计算,就是套用链式求导法则计算偏导数而已,CNN的卷积运算指的是“不翻转卷积”,一定要理解这种卷积计算和信号系统中的卷积计算的区别。
308 |
309 | - CNN之所以使用“不翻转卷积”,是因为神经网络的场景真的不需要满足卷积的交换律,少了一次反转,简化计算,降低实现难度,要知道卷积神经网络的计算量大的惊人,任何看似简单的计算,算的次数多了,那它就是个性能杀手。
310 |
311 | - 需要求出误差的梯度,卷积核的梯度,以及偏置的梯度,这几个梯度是做模型训练的核心依据。
312 |
313 | - 如何使用这些梯度去更新卷积层的卷积核w和偏置b,有很多种优化算法,如SDGA,Adagrad,Adadelta,Adam,RMSprop等。这些优化算法可以有效帮助CNN模型快而稳的收敛。
314 |
315 | - CNN的反向传播算法最难的就是卷积层了,其实也没多难嘛。搞明白了卷积层的反向传播计算,其他层的反向传播算法就简单的多了。
316 |
317 |
318 | ## 2. 池化层(Pooling Layer)的正向传播计算
319 | ###2.1 正向传播
320 | 以最大池化为例,如下图所示,按照池化窗口和指定的步长,取窗口内最大值作为池化层正向传播的结果。这里假设输入为变长为n的正方形图片,池化窗口大小k=2,步长s=2,无零填充p=0,那么池化层输出的图片大小为 (n + 2p - k)/2s=(4 + 2*0 - 2)/(2*1) = 2 。
321 | 在数字信号处理中,我们把这种处理称为下采样(Subsampled)或降采样(Downsampled)。作用是缩小图像到一定的大小,去除冗余信息,保留图像的重要特征。目的是降低图像后续处理的数据处理量,进一步提取有效特征。
322 |
323 | 
324 |
325 | >\begin{aligned}
326 | &如上图,假设假设第l层为池层,池化层使用最大池化法(Max\ Pooling);上一层的输出为\\&
327 | a^{l-1};池化层输出为z^l;设池化层下采样算子表达为\ SubSample();则池化层正向传播计算式为:\\&
328 | z^l\ =\ SubSample(a^{l-1}) \quad\quad\quad\quad\quad\quad (4.6) \\&
329 | 如果池化层的上一层(l-1)层有激活函数,那么\ a^{l-1}=\sigma(z^{l-1}),则:\\&
330 | z^l\ =\ SubSample(\sigma(z^{l-1})) \quad\quad\quad\quad\quad\quad (4.7)
331 | \end{aligned}
332 |
333 | >Tips: 我知道,肯定有小伙伴可能在想一个问题,为什么有了卷积层,还得要个池化层,毕竟卷积层也可以缩小图像,提取特征啊?
334 | >
335 | >答:卷积层通过卷积核提取的多为边缘特征,深度更深的模型下,为了保留图像信息,通常会让其中有些卷积层使用零进行边界填充(Zero Padding)图像后再进行卷积计算,这样输出的图像大小是不变的。和卷积层不同,池化层通常是紧接在卷积层的下一层,图像经过池化层后,图像会变小,但是得到的是卷积层输出图像整体的概要统计特征 。得到的特征维度较低,整体特征保留较好。这点其实也很重要,因为特征完整度保留住了,使得结果得到改善,神经网络不那么容易过拟合,这是池化层存在的意义。
336 |
337 | ###2.2 反向传播
338 | 池化层的反向传播也不难,以最大池化法为例:实现方法是记录下正向传播的时候记录下池化窗口最大值在图像的位置,反向传播的时候,把误差值按照记录好的位置放置,其余位置的值为零,池化层的反向传播的计算就完成了。在数字信号处理中,这种处理称为上采样,这里用 DownSample() 算子做表达。如下图所示:
339 |
340 | 
341 |
342 | >\begin{aligned}
343 | &如上图,假设假设第l层为池层,池化层使用最大池化法(Max\ Pooling);池化层的误差梯度为\delta^l,\\&
344 | ;经池化层反向传播后,上一层的误差记为J;误差的梯度为\delta^{l-1}。且池化层上一层的输出限定\\&
345 | 为\ a^{l-1}\in \mathbb{R}^{M\times N};池化后的输出z^l \in \mathbb{R}^{m\times n};一般\ m << M,\ n << N;\\&
346 | 池化层记录下的最大池化的元素位置下标集合记为\ \{Max\ Index\}\ ;\\&
347 | 那么有:\\&
348 | \delta^{l-1}_{i,\ j}=\frac{\partial J}{\partial z^{l-1}_{i,\ j}} \\&
349 | \quad\ \ = \frac {\partial J}{\partial z^l_{i^\prime,\ j^\prime}}\frac {\partial z^l_{i^\prime,\ j^\prime}}{\partial z^{l-1}_{i,\ j}} \\&
350 | \quad\ \ = \delta^l_{i^\prime,\ j^\prime}\frac {\partial (UpSample(\sigma(z^{l-1}_{i,\ j})))}{\partial z^{l-1}_{i,\ j}} \\&
351 | \quad\ \ = \ \begin{cases} \delta^l_{i^\prime,\ j^\prime} \sigma^\prime(z^{l-1}_{i,\ j}), \quad\quad\quad\quad i^\prime \in \mathbb{R}^m,\ j^\prime \in \mathbb{R}^n\quad When\ i,j \in \{Max\ Index\} \\
352 | 0, \quad\quad\quad\quad\quad\quad\quad\quad i,\ j \not\in \{Max\ Index\} \end{cases}\\&
353 | \quad\ \ = \ DownSample(\delta^{l})\cdot\sigma^\prime(z^{l-1}_{i,\ j}) \quad\quad\quad\ \ (4.8)\\&
354 | \quad\ \ 把上面的式子简化一下,使用下采样算子\ DownSample()\ 代替;\\&
355 | \quad\ \ 该算子包含对索引下标的映射处理,所以\ \delta^l\ 没有标出下标;\\&
356 | \quad\ \ 如果池化层上一层(一般是卷积层)没有使用激活函数\ \sigma,那么\sigma^\prime(z^{l-1}_{i,\ j})=1,这一点一定要清楚。
357 | \end{aligned}
358 |
359 | ## 3. 扁平化层(Flatten Layer)的正向传播计算
360 | - 所谓的Flatten Layer,其实不能算是真正意义的“层”,通常用在从卷积层到全连接层的数据维度的转换适配。所以它的正向传播就是把图像降维,方向传播就是把数据升维到原来的样子,如下图:
361 |
362 | 
363 |
364 | - 如果真要写成数学表达式
365 | >\begin{aligned}
366 | &正向传播:\\&
367 | 设第\ l\ 层为Flatten层,第l-1层的激活输出记为a^{l-1};且有\ a=\sigma(z^{l-1}),其中\sigma为激活函数,\\&
368 | z^{l-1}为第l-1层的输出,那么Flatten层的正向传播输出为:\\&
369 | z^{l}\ = \ Flattened(a^{l-1})\ = \ Flattened(\sigma(z^{l-1})) \quad\quad (4.9)\\&\\&
370 | 反向传播:\\&
371 | 第l层的误差梯度为\delta^l,求第l-1层的梯度\delta^{l-1},不闹腾,直接写出式子:\\&
372 | \delta^{l-1}\ = \ UnFlattened(\delta^l)\cdot\sigma^\prime(z^{l-1}) \quad\quad\quad\quad\quad (4.10)
373 | \end{aligned}
374 |
375 | ## 4. 全连接层(Full Connection Layer)的正向传播计算
376 | ###4.1 正向传播
377 | 其实不想写全连接层,之前写的文章里介绍得很详细了。为了文章的完整性,这里简单写一下。
378 | 全连接层可以由若干个隐藏层。第一层是输入层,最后一层是输出层。看下图,其实就是一个多层神经网络。
379 |
380 | 
381 |
382 | >\begin{aligned}
383 | &设全连接层的激活函数为\sigma,一共有L层全连接层,构成DNN;\\&
384 | 设输入层数据为x;训练数据集的标定输出为y;\\&
385 | 输出层为第L层,输出层的激活输出为a^{L}; \\&
386 | w为神经元权重,权重向量大写表示为W;b为神经元偏置;那么DNN的正向传播算法分层表示为:\\&
387 | 1.\ 输入层:\\&
388 | a^{1}=x \quad\quad\quad\quad\quad\quad (4.11) \\&\\&
389 | 2.\ 隐藏层和输出层:\\&
390 | a^{l} = \sigma(z^l)=\sigma(W^la^{l-1}+b^l)\quad ,其中\ l \in \{2,3,..,L\} \quad\quad\quad (4.12)
391 | \end{aligned}
392 |
393 | ###4.2 反向传播
394 | >\begin{aligned}
395 | &设全连接层的激活函数为\sigma,一共有L层全连接层,构成DNN;\\&
396 | 设输入层数据为x;训练数据集的标定输出为y;\\&
397 | 输出层为第L层,输出层的激活输出为a^{L}; \\&
398 | w为神经元权重,权重向量大写表示为W;b为神经元偏置;\\&
399 | 这里偷个懒,不用交叉熵作为误差函数,而是使用简单的均方差函数;\\&
400 | 其实代码实现的时候,换代价函数只是替换掉公式对应误差层函数的导数结果的部分就行了。\\&
401 | 记均方差误差函数\ J(W,b,x,y)=\frac{1}{2}\begin{Vmatrix}a^{L}-y\end{Vmatrix}^2_2;\\&
402 | 又因为上面推导的输出层的正向输出为\ a^L=\sigma(z^L)=\sigma(W^{L-1}a^{L-1}+b^L),那么: \\&\\&
403 | 1.\ 输出层(第L层)的误差的梯度计算:\\&
404 | \delta^L=\frac{\partial J(W,b,x,y)}{\partial z^L}=(a^L-y)\odot\sigma^\prime(z^L)\\&\\&
405 | 2.\ 输出层(第L层)的神经元权重W的梯度计算:\\&
406 | J(W,b,x,y)=\frac{1}{2}\begin{Vmatrix}a^{L}-y\end{Vmatrix}^2_2=\frac{1}{2}\begin{Vmatrix}\sigma(W^La^{L-1}+b^L)-y\end{Vmatrix}^2_2,那么输出层的误差梯度:\\&
407 | \frac{\partial J(W,b,x,y)}{\partial W^L}= \frac{\partial J(W,b,x,y)}{\partial z^L}\frac{\partial z^L}{\partial W^L}= (a^L-y)\odot\sigma^\prime(z^L)(a^{L-1})^T \quad\quad\quad (4.13)\\&
408 | 注:T表示矩阵转置运算。\\&\\&
409 | 3.\ 输出层(第L层)的神经元偏置b的梯度计算:\\&
410 | \frac{\partial J(W,b,x,y)}{\partial b^L}= \frac{\partial J(W,b,x,y)}{\partial z^L}\frac{\partial z^L}{\partial b^L} =(a^L-y)\odot\sigma^\prime(z^L) \quad\quad\quad\quad\quad\quad (4.14)\\&\\&
411 | 4.\ 注意到隐藏层,和输出层不一样,隐藏层的误差是经过输出层(第L层)逆向层层传递的;\\&
412 | 用递推法,隐藏层(第l层,l \in \{2,3,..,L-1\})的误差梯度计算:\\&
413 | \delta^l = \frac{\partial J(W,b,x,y)}{\partial z^l}=\frac{\partial J(W,b,x,y)}{\partial z^L}\frac{\partial z^L}{\partial z^{L-1}}\frac{\partial z^{L-2}}{\partial z^{L-3}}...\frac{\partial z^{l+1}}{\partial z^{l}} \quad\quad\quad\quad\quad (4.15)\\&
414 | 我们要求第l层的误差梯度\delta^l, 由于第l+1层的误差梯度\delta^{l+1}是已经求出来了的已知量,又因为: \\&
415 | \delta^l=\frac{\partial J(W,b,x,y)}{\partial z^l}=\frac{\partial J(W,b,x,y)}{\partial z^{l+1}}\frac{\partial z^{l+1}}{\partial z^{l}}=\delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}} \quad\quad\quad\quad\quad\quad\ (4.16)\\&
416 | 现在的关键就是把\frac{\partial z^{l+1}}{\partial z^{l}}求出来,然后利用归纳法就能求出第l层的误差梯度。\\&
417 | z^{l+1}=W^{l+1}a^l+b^l=W^{l+1}\sigma(z^l)+b^l\quad,所以求其偏导\\&
418 | \frac{\partial z^{l+1}}{\partial z^{l}}=(W^{l+1})^T\odot\sigma^\prime(z^l) \quad,代入式(4.16)得到:\\&
419 | \delta^l=\delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}}=(W^{l+1})
420 | ^T\delta^{l+1}\odot\sigma^\prime(z^l) \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad (4.17) \\&\\&
421 | 5.\ 隐藏层(第l层,l \in \{2,3,..,L-1\})的W,b的梯度;注意到\ \delta^l = \frac{\partial J(W,b,x,y)}{\partial z^l},则:\\&
422 | \frac{\partial J(W,b,x,y)}{\partial W^l}= \frac{\partial J(W,b,x,y)}{\partial z^l}\frac{\partial z^l}{\partial W^l} =\delta^l(a^{l-1})^T \quad\quad\quad\quad\quad\quad\quad\quad\quad (4.18)\\&
423 | \frac{\partial J(W,b,x,y)}{\partial b^l}= \frac{\partial J(W,b,x,y)}{\partial z^l}\frac{\partial z^l}{\partial b^l} =\delta^l \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\ (4.19) \\&
424 | 所以,利用公式(4.17),(4.18),(4.19);层层递推,遍历一遍所有的隐藏层,所有的梯度都能算出来。
425 | \end{aligned}
426 | ## 5. Softmax层(Softmax Layer)的正向传播计算
427 | ###5.1 正向传播
428 | 看刚才的图:
429 | 
430 | > \begin{aligned}
431 | &输入特征向量z \in \{0,n\},那么softmax值为:\\&
432 | y_i = \frac{e^{z_i}}{\sum_j e^{z_j}},其中:j \in [1,n] \qquad\qquad\qquad\qquad\qquad\qquad\ (4.20) \\&
433 | 从式子上可以看到,输入特征对输出概率的计算是乘性的,指数e也提供了良好的导数性质,\\&
434 | 给计算带来很多便利。
435 | \end{aligned}
436 |
437 | ###5.2 反向传播
438 | > \begin{aligned}
439 | &在之前的文章说过,在分类问题中,会选一个损失函数计算误差,常用的是交叉熵函数:\\&
440 | Loss_i = -\sum t_i\ln y_i \qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\ (4.21) \\&
441 | 其中,t_i表示真实值,y_i表示softmax输出值。当预测第i个特征的概率的时候,必然认为t_i=1。此时损失函数变成:\\&
442 | Loos_i=-\ln y_i \qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad (4.22)\\&
443 | 然后我们要做的是,将误差进行反向传播,即对损失函数进行求导。由于:\\&
444 | y_i = \frac{e^{z_i}}{\sum_je^{z_j}},要清楚一点,softmax已经将输出映射到了区间[0,1],那么:\\&
445 | \sum y_i = \sum \frac{e^{z_i}}{\sum_j e^{z_j}} = 1 \qquad\qquad\qquad\qquad\qquad\qquad\qquad\quad (4.23)\\&
446 | 所以第softmax第i个输出值可以表示为:\\&
447 | \frac{e^{z_i}}{\sum_j e^{z_j}}=1 - \frac{\sum_{j \neq i}e^{z_j}}{\sum_j e^{z_j}} \qquad\qquad\qquad\qquad\qquad\qquad\qquad\quad (4.24)\\&
448 | 对式(4.21)偏导数:\\&
449 | \frac{\partial Loss_i}{\partial i} = -\frac{\partial \ln y_i}{\partial i}\\&
450 | \quad\quad\quad = \frac{\partial (-\ln \frac{e^{z_i}}{\sum_j e^{z_j}})}{\partial i}\\&
451 | \quad\quad\quad = -\frac{1}{\frac{e^{z_i}}{\sum_j e^{z_j}}}\cdot\frac{\partial(\frac{e^{z_i}}{\sum_j e^{z_j}})}{\partial i} \\&
452 | \quad\quad\quad = -\frac{\sum_j e^{z_j}}{e^{z_i}}\cdot\frac{\partial(1-\frac{\sum_{j\neq i}e^j}{\sum_j e^{z_j}})}{\partial i} \\&
453 | \quad\quad\quad = -\frac{\sum_j e^{z_j}}{e^{z_i}}\cdot (-\sum_{j\neq i}e^{z_j})\cdot \frac{\partial (\frac{1}{\sum_je^{z_j}})}{\partial i} \\&
454 | \quad\quad\quad = \frac{\sum_j e^{z_j}\cdot\sum_{j\neq i}e^{z_j}}{e^{z_i}}\cdot\frac{-e^{z_i}}{(\sum_j e^{z_j})^2} \\&
455 | \quad\quad\quad = -\frac{\sum_{j\neq i}e^{z_j}}{\sum_j e^{z_j}}, 这时候观察式子(4.24) \\&
456 | \quad\quad\quad = 1 - \frac{e^{z_i}}{\sum_j e^{z_j}} \\&
457 | \quad\quad\quad = y_i-1 \\&
458 | 所以第i个特征的误差梯度就是它的softmax输出减去1,很简单。
459 | \end{aligned}
460 |
461 | #五.程序设计和效果
462 | ##5.1 核心思路
463 | ###5.1.1 分层设计
464 | > 按照LeNet-5所设计的网络层逐一实现,每一层都有正向传播,反向传播,以及获取上一层的输出以及自己正向传播输出的接口,例如全连接层的设计,其他层均具备这些接口
465 | 
466 |
467 | ###5.1.2 链表式连接
468 | > 把所有网络层的输入和输出通过链表节点传递,通过实例化CNN_Network,把所有网络层按顺序声明,每一层的参数没有做强校验,所以网络上下文参数自己要算好,否则网络无法运行。
469 | PS:
470 | >- batch_szie: 训练时使用多大的图片集合,卷积网络不是使用单张图片进行梯度下降训练的,而是每次一小批送入
471 | >- test_size: 测试网络模型使用多少张图片,可以同时观察N张图片的预测结果
472 | >- epoch:最大迭代周期数,一次迭代周期 = 训练集合图片总数/batch_size
473 | >- base_lr:初始化学习率
474 | >- l2_regulation: l2正则项(暂时没有用到...)
475 | >
476 | >
477 | >当调用forward接口进行正向传播时,每一层网络的正向传播接口得以调用,反向传播同理
478 | >
479 |
480 | ##5.2 程序使用方法
481 | 注释写得很清楚了,要注意的一点就是,训练的时候,会定义early-stop的条件,当满足条件时,会调用snapshot()函数,将训练好的网络模型快照下来保存到Model/model.h5中。
482 | 
483 |
484 | ##5.3 关于代码实现的建议
485 | - 网络层的实现时严格按照上文的算法推导出来的公式做的,所以想要看懂代码,必须先看懂数学算法的推导原理和过程。
486 | - 卷积层的卷积运算使用到了一些巧妙的设计,设计到的核心函数我都写了十分详细的注释在代码中,文章篇幅有限,请自行阅读。
487 |
488 |
489 | ##5.4 程序效果
490 | 按上面代码截图,网络结果设计为:
491 | >mnist_data(输入层) => 卷积层conv1 => 池化层pool1 => 卷积层conv2 => 池化层pool2 => 扁平层flatten => 全连接层fc1 => 激活层relu1 => 全连接层fc2 => 输出层softmax
492 |
493 | >想要程序把运行过程中每一层的输出可视化,那么需要打开开关:
494 | 
495 |
496 | >程序输出效果如下,可以直观看到每一层输出特征,一直到最后的输出层,把结果标定出来。网络层次越深,特征被抽象得越来越反人类,已经没法直观的知道神经网络是怎么运用抽象特征的了:
497 | 
498 |
499 | ##5.5 卷积网络模型训练的精确度和误差
500 | - 误差和精度随着迭代加深,网络平均误差也已经很难往0值收敛。
501 | - 我写的这份代码,在计算梯度的时候,使用了类似退火算法来保证网络尽快而好的收敛,学习率也采取了同样的做法。但是要造好一个轮子,还是有很多事情要做的,比如梯度算法可以使用SGD;引入dropout层等等,通过这一系列措施来优化网络,网络质量会更高。
502 |
503 | 
504 | 
505 |
506 | #6.尾声
507 | 篇幅有限,无法面面俱到。关于代码实现,我还是坚持一点,只有自己实现过一遍CNN,任何关于算法的细节,任何参数的作用你就会一清二楚。只有吃透算法的任何一个细节,后面再接触LSTM,RNN,GAN等各种花式玩法的时候,慌是不可能慌的,这辈子都不可能慌的,搞AI的个个都是人才,说话又好听,我超想放弃AI的。
508 |
509 |
510 | # 参考资料
511 | [1] http://yann.lecun.com
512 | [2] http://yann.lecun.com/exdb/publis/pdf/bengio-95.pdf
513 | [3] http://yann.lecun.com/exdb/lenet/index.html
514 | [4] https://cs.stanford.edu/people/karpathy/convnetjs/demo/mnist.html
515 | [5] http://scs.ryerson.ca/~aharley/vis/conv/
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/04C9E0B3DDFFAE6DBF0692451F6992D1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/04C9E0B3DDFFAE6DBF0692451F6992D1.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/08E51AD720981A718F79635F3C175469.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/08E51AD720981A718F79635F3C175469.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/173BE7B5673987828414CBAB75111379.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/173BE7B5673987828414CBAB75111379.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/1E97985A1B2BB3FE1B5C98D77AC5A403.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/1E97985A1B2BB3FE1B5C98D77AC5A403.png
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/24170F1D134952DFD522B4CADC1FFD8F.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/24170F1D134952DFD522B4CADC1FFD8F.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/29CED44A9D37FEC25A2448EE9B041256.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/29CED44A9D37FEC25A2448EE9B041256.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/2B3B1E8B6725BE2CBEDC4466384042A7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/2B3B1E8B6725BE2CBEDC4466384042A7.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/2FA771C954BE667E95561579518D46F0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/2FA771C954BE667E95561579518D46F0.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/3BA9904D9A93E639A6577E317A295DD0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/3BA9904D9A93E639A6577E317A295DD0.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/45C1395B84E554772D1AFB28C80EE7C9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/45C1395B84E554772D1AFB28C80EE7C9.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/49FDC432141B5F7D59B17F93E594A777.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/49FDC432141B5F7D59B17F93E594A777.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/53081124276177707263BF45B962832D.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/53081124276177707263BF45B962832D.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/705305FEE5A050575544C64067405FCE.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/705305FEE5A050575544C64067405FCE.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/7CED4CBD723175E6811557CA99B83837.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/7CED4CBD723175E6811557CA99B83837.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/85182DA6962E2C26664D03DC1647AB31.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/85182DA6962E2C26664D03DC1647AB31.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/8645FA96B78267F6B995D7909C263CE4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/8645FA96B78267F6B995D7909C263CE4.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/8D72F4E6CDD66BC654D440390E42F922.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/8D72F4E6CDD66BC654D440390E42F922.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/965FBFC2D682036ED178B7DD1EDD50FA.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/965FBFC2D682036ED178B7DD1EDD50FA.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/9EEC442D8B126FD3F3B53E19704201A9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/9EEC442D8B126FD3F3B53E19704201A9.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/A5BFC0E4FDD254F431C6B702CFB6E463.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/A5BFC0E4FDD254F431C6B702CFB6E463.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/ACB9841BC14C57C09CA27F6ED6BBEC5C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/ACB9841BC14C57C09CA27F6ED6BBEC5C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/B9663FCC0A0B42FA0E7082FFC1BFF9E3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/B9663FCC0A0B42FA0E7082FFC1BFF9E3.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/BAAF3CFE34D7CFE2F69F7F8AE0D42735.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/BAAF3CFE34D7CFE2F69F7F8AE0D42735.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/BCBCEFAF634DEA7AEA8B53898F1BA866.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/BCBCEFAF634DEA7AEA8B53898F1BA866.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/CA203A8C36C14AE9C2DC0870C1ECE8E6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/CA203A8C36C14AE9C2DC0870C1ECE8E6.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/CB3DF2830392E247AA78C4F33230483C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/CB3DF2830392E247AA78C4F33230483C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/D6893085EC1FE4A0AD20F68589BE1768.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/D6893085EC1FE4A0AD20F68589BE1768.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/DC6921D73DAB14ED98A26032A73F0AA9.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/DC6921D73DAB14ED98A26032A73F0AA9.gif
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/E351E2E6EDC5210A4C60E2E09DC1C43C.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/E351E2E6EDC5210A4C60E2E09DC1C43C.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/E5189072F39325215235950E90F6F9EF.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/E5189072F39325215235950E90F6F9EF.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/E61DF3C6A20A5F78F43CE5789F7FD9FF.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/E61DF3C6A20A5F78F43CE5789F7FD9FF.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/EBD4E3242A6B9AB67BE41F808DD2FD8E.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/EBD4E3242A6B9AB67BE41F808DD2FD8E.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FA8B0532561AD9A74CAAF78BD7175437.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FA8B0532561AD9A74CAAF78BD7175437.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FB2E612B54BB961753B87FDCBC9D1E68.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FB2E612B54BB961753B87FDCBC9D1E68.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FD3AADAD7C3BF1F8C190E84BCAB47DF9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FD3AADAD7C3BF1F8C190E84BCAB47DF9.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FDE7CEEA3FB146BDDCA545DB6BD3B6CC.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FDE7CEEA3FB146BDDCA545DB6BD3B6CC.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FE0DB3B95EB7135EB37A8EE627A6FE08.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FE0DB3B95EB7135EB37A8EE627A6FE08.jpg
--------------------------------------------------------------------------------
/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FFE5AA9D3CA5F3A1248F531F72E20B1A.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zsysuper/AI_Notes/3f321cf266f2fb270f02c6b440a27843b43d5a18/AI从入门到放弃:《手撕神经卷积网络(CNN)》/Markdown版本/resources/FFE5AA9D3CA5F3A1248F531F72E20B1A.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AI_Notes
2 | AI算法学习笔记
3 |
4 | 所有文章使用的Markdown软件为Quiver
5 | Python代码使用pycharm
6 |
--------------------------------------------------------------------------------