卷积神经网络CNN相关代码注释.docx
- 文档编号:18378869
- 上传时间:2023-08-16
- 格式:DOCX
- 页数:17
- 大小:21.84KB
卷积神经网络CNN相关代码注释.docx
《卷积神经网络CNN相关代码注释.docx》由会员分享,可在线阅读,更多相关《卷积神经网络CNN相关代码注释.docx(17页珍藏版)》请在冰点文库上搜索。
卷积神经网络CNN相关代码注释
cnnexamples.m
[plain] viewplaincopy
1.clear all; close all; clc;
2.addpath('../data');
3.addpath('../util');
4.load mnist_uint8;
5.
6.train_x = double(reshape(train_x',28,28,60000))/255;
7.test_x = double(reshape(test_x',28,28,10000))/255;
8.train_y = double(train_y');
9.test_y = double(test_y');
10.
11.%% ex1
12.%will run 1 epoch in about 200 second and get around 11% error.
13.%With 100 epochs you'll get around 1.2% error
14.
n.layers = {
16. struct('type', 'i') %input layer
17. struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer
18. struct('type', 's', 'scale', 2) %sub sampling layer
19. struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer
20. struct('type', 's', 'scale', 2) %subsampling layer
21.};
22.
23.% 这里把cnn的设置给cnnsetup,它会据此构建一个完整的CNN网络,并返回
n = cnnsetup(cnn, train_x, train_y);
25.
26.% 学习率
27.opts.alpha = 1;
28.% 每次挑出一个batchsize的batch来训练,也就是每用batchsize个样本就调整一次权值,而不是
29.% 把所有样本都输入了,计算所有样本的误差了才调整一次权值
30.opts.batchsize = 50;
31.% 训练次数,用同样的样本集。
我训练的时候:
32.% 1的时候 11.41% error
33.% 5的时候 4.2% error
34.% 10的时候 2.73% error
35.opts.numepochs = 10;
36.
37.% 然后开始把训练样本给它,开始训练这个CNN网络
n = cnntrain(cnn, train_x, train_y, opts);
39.
40.% 然后就用测试样本来测试
41.[er, bad] = cnntest(cnn, test_x, test_y);
42.
43.%plot mean squared error
44.plot(cnn.rL);
45.%show test error
46.disp([num2str(er*100) '% error']);
cnnsetup.m
[plain] viewplaincopy
1.function net = cnnsetup(net, x, y)
2. inputmaps = 1;
3. % B=squeeze(A) 返回和矩阵A相同元素但所有单一维都移除的矩阵B,单一维是满足size(A,dim)=1的维。
4. % train_x中图像的存放方式是三维的reshape(train_x',28,28,60000),前面两维表示图像的行与列,
5. % 第三维就表示有多少个图像。
这样squeeze(x(:
:
1))就相当于取第一个图像样本后,再把第三维
6. % 移除,就变成了28x28的矩阵,也就是得到一幅图像,再size一下就得到了训练样本图像的行数与列数了
7. mapsize = size(squeeze(x(:
:
1)));
8.
9. % 下面通过传入net这个结构体来逐层构建CNN网络
10. % n = numel(A)返回数组A中元素个数
11. % net.layers中有五个struct类型的元素,实际上就表示CNN共有五层,这里范围的是5
12. for l = 1 :
numel(net.layers) % layer
13. if strcmp(net.layers{l}.type, 's') % 如果这层是 子采样层
14. % subsampling层的mapsize,最开始mapsize是每张图的大小28*28
15. % 这里除以scale=2,就是pooling之后图的大小,pooling域之间没有重叠,所以pooling后的图像为14*14
16. % 注意这里的右边的mapsize保存的都是上一层每张特征map的大小,它会随着循环进行不断更新
17. mapsize = floor(mapsize / net.layers{l}.scale);
18. for j = 1 :
inputmaps % inputmap就是上一层有多少张特征图
19. net.layers{l}.b{j} = 0; % 将偏置初始化为0
20. end
21. end
22. if strcmp(net.layers{l}.type, 'c') % 如果这层是 卷积层
23. % 旧的mapsize保存的是上一层的特征map的大小,那么如果卷积核的移动步长是1,那用
24. % kernelsize*kernelsize大小的卷积核卷积上一层的特征map后,得到的新的map的大小就是下面这样
25. mapsize = mapsize - net.layers{l}.kernelsize + 1;
26. % 该层需要学习的参数个数。
每张特征map是一个(后层特征图数量)*(用来卷积的patch图的大小)
27. % 因为是通过用一个核窗口在上一个特征map层中移动(核窗口每次移动1个像素),遍历上一个特征map
28. % 层的每个神经元。
核窗口由kernelsize*kernelsize个元素组成,每个元素是一个独立的权值,所以
29. % 就有kernelsize*kernelsize个需要学习的权值,再加一个偏置值。
另外,由于是权值共享,也就是
30. % 说同一个特征map层是用同一个具有相同权值元素的kernelsize*kernelsize的核窗口去感受输入上一
31. % 个特征map层的每个神经元得到的,所以同一个特征map,它的权值是一样的,共享的,权值只取决于
32. % 核窗口。
然后,不同的特征map提取输入上一个特征map层不同的特征,所以采用的核窗口不一样,也
33. % 就是权值不一样,所以outputmaps个特征map就有(kernelsize*kernelsize+1)* outputmaps那么多的权值了
34. % 但这里fan_out只保存卷积核的权值W,偏置b在下面独立保存
35. fan_out = net.layers{l}.outputmaps * net.layers{l}.kernelsize ^ 2;
36. for j = 1 :
net.layers{l}.outputmaps % output map
37. % fan_out保存的是对于上一层的一张特征map,我在这一层需要对这一张特征map提取outputmaps种特征,
38. % 提取每种特征用到的卷积核不同,所以fan_out保存的是这一层输出新的特征需要学习的参数个数
39. % 而,fan_in保存的是,我在这一层,要连接到上一层中所有的特征map,然后用fan_out保存的提取特征
40. % 的权值来提取他们的特征。
也即是对于每一个当前层特征图,有多少个参数链到前层
41. fan_in = inputmaps * net.layers{l}.kernelsize ^ 2;
42. for i = 1 :
inputmaps % input map
43. % 随机初始化权值,也就是共有outputmaps个卷积核,对上层的每个特征map,都需要用这么多个卷积核
44. % 去卷积提取特征。
45. % rand(n)是产生n×n的 0-1之间均匀取值的数值的矩阵,再减去0.5就相当于产生-0.5到0.5之间的随机数
46. % 再 *2 就放大到 [-1, 1]。
然后再乘以后面那一数,why?
47. % 反正就是将卷积核每个元素初始化为[-sqrt(6 / (fan_in + fan_out)), sqrt(6 / (fan_in + fan_out))]
48. % 之间的随机数。
因为这里是权值共享的,也就是对于一张特征map,所有感受野位置的卷积核都是一样的
49. % 所以只需要保存的是 inputmaps * outputmaps 个卷积核。
50. net.layers{l}.k{i}{j} = (rand(net.layers{l}.kernelsize) - 0.5) * 2 * sqrt(6 / (fan_in + fan_out));
51. end
52. net.layers{l}.b{j} = 0; % 将偏置初始化为0
53. end
54. % 只有在卷积层的时候才会改变特征map的个数,pooling的时候不会改变个数。
这层输出的特征map个数就是
55. % 输入到下一层的特征map个数
56. inputmaps = net.layers{l}.outputmaps;
57. end
58. end
59.
60. % fvnum 是输出层的前面一层的神经元个数。
61. % 这一层的上一层是经过pooling后的层,包含有inputmaps个特征map。
每个特征map的大小是mapsize。
62. % 所以,该层的神经元个数是 inputmaps * (每个特征map的大小)
63. % prod:
Product of elements.
64. % For vectors, prod(X) is the product of the elements of X
65. % 在这里 mapsize = [特征map的行数 特征map的列数],所以prod后就是 特征map的行*列
66. fvnum = prod(mapsize) * inputmaps;
67. % onum 是标签的个数,也就是输出层神经元的个数。
你要分多少个类,自然就有多少个输出神经元
68. onum = size(y, 1);
69.
70. % 这里是最后一层神经网络的设定
71. % ffb 是输出层每个神经元对应的基biases
72. net.ffb = zeros(onum, 1);
73. % ffW 输出层前一层 与 输出层 连接的权值,这两层之间是全连接的
74. net.ffW = (rand(onum, fvnum) - 0.5) * 2 * sqrt(6 / (onum + fvnum));
75.end
cnntrain.m
[plain] viewplaincopy
1.function net = cnntrain(net, x, y, opts)
2. m = size(x, 3); % m 保存的是 训练样本个数
3. numbatches = m / opts.batchsize;
4. % rem:
Remainder after division. rem(x,y) is x - n.*y 相当于求余
5. % rem(numbatches, 1) 就相当于取其小数部分,如果为0,就是整数
6. if rem(numbatches, 1) ~= 0
7. error('numbatches not integer');
8. end
9.
10. net.rL = [];
11. for i = 1 :
opts.numepochs
12. % disp(X) 打印数组元素。
如果X是个字符串,那就打印这个字符串
13. disp(['epoch ' num2str(i) '/' num2str(opts.numepochs)]);
14. % tic 和 toc 是用来计时的,计算这两条语句之间所耗的时间
15. tic;
16. % P = randperm(N) 返回[1, N]之间所有整数的一个随机的序列,例如
17. % randperm(6) 可能会返回 [2 4 5 6 1 3]
18. % 这样就相当于把原来的样本排列打乱,再挑出一些样本来训练
19. kk = randperm(m);
20. for l = 1 :
numbatches
21. % 取出打乱顺序后的batchsize个样本和对应的标签
22. batch_x = x(:
:
kk((l - 1) * opts.batchsize + 1 :
l * opts.batchsize));
23. batch_y = y(:
kk((l - 1) * opts.batchsize + 1 :
l * opts.batchsize));
24.
25. % 在当前的网络权值和网络输入下计算网络的输出
26. net = cnnff(net, batch_x); % Feedforward
27. % 得到上面的网络输出后,通过对应的样本标签用bp算法来得到误差对网络权值
28. %(也就是那些卷积核的元素)的导数
29. net = cnnbp(net, batch_y); % Backpropagation
30. % 得到误差对权值的导数后,就通过权值更新方法去更新权值
31. net = cnnapplygrads(net, opts);
32. if isempty(net.rL)
33. net.rL
(1) = net.L; % 代价函数值,也就是误差值
34. end
35. net.rL(end + 1) = 0.99 * net.rL(end) + 0.01 * net.L; % 保存历史的误差值,以便画图分析
36. end
37. toc;
38. end
39.
40.end
cnnff.m
[plain] viewplaincopy
1.function net = cnnff(net, x)
2. n = numel(net.layers); % 层数
3. net.layers{1}.a{1} = x; % 网络的第一层就是输入,但这里的输入包含了多个训练图像
4. inputmaps = 1; % 输入层只有一个特征map,也就是原始的输入图像
5.
6. for l = 2 :
n % for each layer
7. if strcmp(net.layers{l}.type, 'c') % 卷积层
8. % !
!
below can probably be handled by insane matrix operations
9. % 对每一个输入map,或者说我们需要用outputmaps个不同的卷积核去卷积图像
10. for j = 1 :
net.layers{l}.outputmaps % for each output map
11. % create temp output map
12. % 对上一层的每一张特征map,卷积后的特征map的大小就是
13. % (输入map宽 - 卷积核的宽 + 1)* (输入map高 - 卷积核高 + 1)
14. % 对于这里的层,因为每层都包含多张特征map,对应的索引保存在每层map的第三维
15. % 所以,这里的z保存的就是该层中所有的特征map了
16. z = zeros(size(net.layers{l - 1}.a{1}) - [net.layers{l}.kernelsize - 1 net.layers{l}.kernelsize - 1 0]);
17. for i = 1 :
inputmaps % for each input map
18. % convolve with corresponding kernel and add to temp output map
19. % 将上一层的每一个特征map(也就是这层的输入map)与该层的卷积核进行卷积
20. % 然后将对上一层特征map的所有结果加起来。
也就是说,当前层的一张特征map,是
21. % 用一种卷积核去卷积上一层中所有的特征map,然后所有特征map对应位置的卷积值的和
22. % 另外,有些论文或者实际应用中,并不是与全部的特征map链接的,有可能只与其中的某几个连接
23. z = z + convn(net.layers{l - 1}.a{i}, net.layers{l}.k{i}{j}, 'valid');
24. end
25. % add bias, pass through nonlinearity
26. % 加上对应位置的基b,然后再用sigmoid函数算出特征map中每个位置的激活值,作为该层输出特征map
27. net.layers{l}.a{j} = sigm(z + net.layers{l}.b{j});
28. end
29. % set number of input maps to this layers number of outputmaps
30. inputmaps = net.layers{l}.outputmaps;
31. elseif strcmp(net.layers{l}.type, 's') % 下采样层
32. % downsample
33. for j = 1 :
inputmaps
34. % !
!
replace with variable
35. % 例如我们要在scale=2的域上面执行mean pooling,那么可以卷积大小为2*2,每个元素都是1/4的卷积核
36. z = convn(net.layers{l - 1}.a{j}, ones(net.layers{l}.scale) / (net.layers{l}.scale ^ 2), 'valid');
37. % 因为convn函数的默认卷积步长为1,而pooling操作的域是没有重叠的,所以对于上面的卷积结果
38. % 最终pooling的结果需要从上面得到的卷积结果中以scale=2为步长,跳着把mean pooling的值读出来
39. net.layers{l}.a{j} = z(1 :
net.la
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 卷积 神经网络 CNN 相关 代码 注释