紧接着是对该数据库数据进行归一化等等预处理。nnsetup建立一个网络,里面会有许多参数初始化,同时在设置下opts.numepochs = 1; 该参数个人感觉就是将所有数据重复试验次数,设置1就是实验一次。opts.batchsize = 100;该参数是将大量样本每随机100个作为一波送进去实验。再就是训练测试了。Ok来看看nnsetup:
function nn = nnsetup(architecture)
nn.size = architecture;
nn.n = numel(nn.size);
nn.activation_function = 'tanh_opt';
nn.learningRate = 2;
nn.momentum = 0.5;
nn.scaling_learningRate = 1;
nn.weightPenaltyL2 = 0;
nn.nonSparsityPenalty = 0;
nn.sparsityTarget = 0.05;
nn.inputZeroMaskedFraction = 0;
nn.dropoutFraction = 0;
nn.testing = 0;
nn.output = 'sigm';
for i = 2 : nn.n
nn.W{i - 1} = (rand(nn.size(i), nn.size(i - 1)+1) - 0.5) * 2 * 4 * sqrt(6 / (nn.size(i) + nn.size(i - 1)));
nn.vW{i - 1} = zeros(size(nn.W{i - 1}));
nn.p{i} = zeros(1, nn.size(i));
end
end
- 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
- 27
- 28
- 29
- 30
- 31
- 32
- 33
这个函数理解起来很简单,初始化网络,网络需要什么初始化什么,一大堆初始化是适应所有的网络的(cnn,dbn等等),有些用到了再说吧,现在你只需要知道网络的结构,以及与稀疏编码表示有关的参数: nn.nonSparsityPenalty ,nn.sparsityTarget,这也就是上节说到的,为什么稀疏表示,具体怎么样不用管,实际使用的时候只是这么几个参数设置,其他的交给程序吧。再有就是注意下激活函数 nn.activation_function。,然后网络权值随机初始化。
紧接着是nntrain了,关于这部分,前面说的那个博主介绍的很好,里面注释也多,可以去看看(看完回来哦):
http://blog.csdn.net/dark_scope/article/details/9421061
这里再说下这个函数整体:[nn, L] = nntrain(nn, train_x, train_y, opts);
可以看到nntrain需要的是设计的网络nn,训练数据train_x,训练对应的目标值train_y,以及附加参数opts。附加参数包括:重复训练次数opts.numepochs,训练数据每一块大小opts.batchsize等等。函数出来的就是训练好的网络nn,这个很重要,训练好的nn为结构体,里面包括你所需要的所有信息,比如说每一层网络的权值系数,训练误差,等等都可以找到,并且在nntest也是用这个训练好的nn。nntrain的具体实现细节见上面那个博客的介绍吧。
nntrain
setup大概就这样一个过程,下面就到了train了,打开\NN\nntrain.m
我们跳过那些检验传入数据是否正确的代码,直接到关键的部分
denoising 的部分请参考论文:Extracting and Composing Robust Features with Denoising Autoencoders
- m = size(train_x, 1);
-
-
- batchsize = opts.batchsize; numepochs = opts.numepochs;
- numbatches = m / batchsize;
- assert(rem(numbatches, 1) == 0, 'numbatches must be a integer');//即上一步 对总数据进行分组,组数应是一个整数
- L = zeros(numepochs*numbatches,1);
- n = 1;
-
- for i = 1 : numepochs
- tic; // tic用来保存当前时间,而后使用toc来记录程序完成时间。
- kk = randperm(m);
-
- for l = 1 : numbatches
- batch_x = train_x(kk((l - 1) * batchsize + 1 : l * batchsize), :);
-
-
-
-
- if(nn.inputZeroMaskedFraction ~= 0)
- batch_x = batch_x*
- (rand(size(batch_x))>nn.inputZeroMaskedFraction);
- end
- batch_y = train_y(kk((l - 1) * batchsize + 1 : l * batchsize), :);
-
-
-
- nn = nnff(nn, batch_x, batch_y);
- nn = nnbp(nn);
- nn = nnapplygrads(nn);
- L(n) = nn.L;
- n = n + 1;
- end
-
- t = toc;
- if ishandle(fhandle)
- if opts.validation == 1
- loss = nneval(nn, loss, train_x, train_y, val_x, val_y);
- else
- loss = nneval(nn, loss, train_x, train_y);
- end
- nnupdatefigures(nn, fhandle, loss, opts, i);
- end
-
- disp(['epoch ' num2str(i) '/' num2str(opts.numepochs) '. Took ' num2str(t) ' seconds' '. Mean squared error on training set is ' num2str(mean(L((n-numbatches):(n-1))))]);
- nn.learningRate = nn.learningRate * nn.scaling_learningRate;
- end
下面分析三个函数nnff,nnbp和nnapplygrads
nnff
nnff就是进行feedforward pass,其实非常简单,就是整个网络正向跑一次就可以了
当然其中有dropout和sparsity的计算
具体的参见论文“Improving Neural Networks with Dropout“和Autoencoders and Sparsity
- function nn = nnff(nn, x, y)
-
-
-
-
- n = nn.n;
- m = size(x, 1);
-
- x = [ones(m,1) x];
- nn.a{1} = x;
-
-
- for i = 2 : n-1
-
-
-
-
- switch nn.activation_function
- case 'sigm'
-
- nn.a{i} = sigm(nn.a{i - 1} * nn.W{i - 1}');
- case 'tanh_opt'
- nn.a{i} = tanh_opt(nn.a{i - 1} * nn.W{i - 1}');
- end
-
-
- if(nn.dropoutFraction > 0)
- if(nn.testing)
- nn.a{i} = nn.a{i}.*(1 - nn.dropoutFraction);
- else
- nn.dropOutMask{i} = (rand(size(nn.a{i}))>nn.dropoutFraction);
- nn.a{i} = nn.a{i}.*nn.dropOutMask{i};
- end
- end
-
-
- if(nn.nonSparsityPenalty>0)
- nn.p{i} = 0.99 * nn.p{i} + 0.01 * mean(nn.a{i}, 1);
- end
-
-
- nn.a{i} = [ones(m,1) nn.a{i}];
- end
- switch nn.output
- case 'sigm'
- nn.a{n} = sigm(nn.a{n - 1} * nn.W{n - 1}');
- case 'linear'
- nn.a{n} = nn.a{n - 1} * nn.W{n - 1}';
- case 'softmax'
- nn.a{n} = nn.a{n - 1} * nn.W{n - 1}';//这里的n就是循环n-1里时那个具体的数,代表最后一层输出层(不参与循环)
- nn.a{n} = exp(bsxfun(@minus, nn.a{n}, max(nn.a{n},[],2)));
- //max这种表达的意思比较并取每一行的最大值,结果为列向量。
- nn.a{n} = bsxfun(@rdivide, nn.a{n}, sum(nn.a{n}, 2));
- // bsxfun代表高效运算,指两个数组间元素逐个计算的二值操作,@rdivide 这里指左除;@minus是减法
- end
-
-
-
- nn.e = y - nn.a{n};
- //计算计算loss 函数
- switch nn.output
- case {'sigm', 'linear'}
- nn.L = 1/2 * sum(sum(nn.e .^ 2)) / m;
- case 'softmax'
- nn.L = -sum(sum(y .* log(nn.a{n}))) / m;
- end
- end
nnbp
代码:\NN\nnbp.m
nnbp呢是进行back propagation的过程,过程还是比较中规中矩,和ufldl中的Neural Network讲的基本一致
值得注意的还是dropout和sparsity的部分
- if(nn.nonSparsityPenalty>0)
- pi = repmat(nn.p{i}, size(nn.a{i}, 1), 1);
- sparsityError = [zeros(size(nn.a{i},1),1) nn.nonSparsityPenalty * (-nn.sparsityTarget ./ pi + (1 - nn.sparsityTarget) ./ (1 - pi))];
- end
-
-
- if i+1==n % in this case in d{n} there is not the bias term to be removed
- d{i} = (d{i + 1} * nn.W{i} + sparsityError) .* d_act;
- else
- d{i} = (d{i + 1}(:,2:end) * nn.W{i} + sparsityError) .* d_act;
- end
-
- if(nn.dropoutFraction>0)
- d{i} = d{i} .* [ones(size(d{i},1),1) nn.dropOutMask{i}];
- end
这只是实现的内容,代码中的d{i}就是这一层的delta值,在ufldl中有讲的
dW{i}基本就是计算的gradient了,只是后面还要加入一些东西,进行一些修改
具体原理参见论文“Improving Neural Networks with Dropout“ 以及 Autoencoders and Sparsity的内容
nnapplygrads
代码文件:\NN\nnapplygrads.m
- for i = 1 : (nn.n - 1)
- if(nn.weightPenaltyL2>0)
- dW = nn.dW{i} + nn.weightPenaltyL2 * nn.W{i};
- else
- dW = nn.dW{i};
- end
-
- dW = nn.learningRate * dW;
-
- if(nn.momentum>0)
- nn.vW{i} = nn.momentum*nn.vW{i} + dW;
- dW = nn.vW{i};
- end
-
- nn.W{i} = nn.W{i} - dW;
- end
这个内容就简单了,nn.weightPenaltyL2 是weight decay的部分,也是nnsetup时可以设置的一个参数
有的话就加入weight Penalty,防止过拟合,然后再根据momentum的大小调整一下,最后改变nn.W{i}即可
nntest
Ok再来看看nntest,如下:
function [ri, right] = nntest(nn, x, y)
labels = nnpredict(nn, x);
[~, expected] = max(y,[],2);
right = find(labels == expected);
ri = numel(right) / size(x, 1);
end
调用一下nnpredict。函数需要的就是测试数据x和标签y,如果有y的话那么可以计算准确率,如果没有y的话那么你可以自己直接调用 labels = nnpredict(nn, x)可以得到预测的标签。
nnpredict
代码文件:\NN\nnpredict.m
- function labels = nnpredict(nn, x)
- nn.testing = 1;
- nn = nnff(nn, x, zeros(size(x,1), nn.size(end)));
- nn.testing = 0;
-
- [~, i] = max(nn.a{end},[],2);
- labels = i;
- end
继续非常简单,predict不过是nnff一次,得到最后的output~~
max(nn.a{end},[],2); 是返回每一行的最大值以及所在的列数,所以labels返回的就是标号啦
(这个test好像是专门用来test 分类问题的,我们知道nnff得到最后的值即可)
总结
Ok这就是一个简单的一般化的神经网络了,和我们第三节的matlab自带的神经网络工具箱实现的功能差不多。然而复杂的带稀疏自编码的深度学习网络,自带的就不行了。下一节再来看看同过该工具箱建立稀疏自编码的网络。