卷积神经网络:总结
Posted 智能航空发动机
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了卷积神经网络:总结相关的知识,希望对你有一定的参考价值。
01
原理
CNN的前向传播过程和DNN类似,但由于CNN用了其特有的卷积层和池化层,因此在计算过程上会与DNN有所不同。
参考:https://blog.csdn.net/weixin_30298497/article/details/95756601
1)输入:一张image的大小是28*28,minibatch的大小是150,所以输入就是一个28*28*150的矩阵。
2)Wc1,bc1:第一层卷积的权重和偏置。一共8个filter(卷积核),每个核的大小为5*5。
3)activations1:通过第一层卷积得到的feature map,大小为(28-5+1)*(28-5+1)*8*150,其中8是第一层卷积filter的个数,150是输入的image的个数。
4)activationsPooled1:将第一层卷积后的feature map进行采样后的feature map,大小为(24/2)*(24/2)*8*150=12*12*8*150。
5)Wc2,bc2:第二层卷积的权重和偏置。一共10个filter,每个大小为5*5*8。
注意第二层的权重是三维的。对于每张图像,第一层卷积+池化后输出的feature map是12*12*8,而第二层的一个filter和这个feature map卷积后得到一张8*8的feature map,所以第二层的filter都是三维的。
6)activations2:通过第二层卷积得到的feature map,大小为(12-5+1)*(12-5+1)*10*150=8*8*10*150,其中10是第二层卷积filter的个数,150是输入的image的个数。
7)activationsPooled2:将卷积后的feature map进行采样后的feature map,大小为(8/2)*(8/2)*10*150=4*4*10*150。
8)activationsPooled2':第二层卷积完了之后,要把一张image对应的所有feature map reshape成一列,那么这一列的长度就是4*4*10=160,所以reshape后得到一个160*150的大feature map
9)Wd,bd:softmax层的权重和偏执。
10)probs:对所有图像所属分类的预测结果,每一列对应一张图像,一共10行,第i行代表这张图像属于第i类的概率。
卷积操作就是将卷积核在图片上从左到右、从上到下依次滑动,在每次滑动后,将对应位置的元素相乘再相加。对于卷积核是三维的情况,计算过程类似,只不过是将三维卷积核在三维图片上依次滑动。卷积核中的参数和DNN中的权重一样,是需要通过网络学习得到的。
CNN的池化层很简单,分为最大池化和平均池化。池化层所起的作用是降维,即将大的图片转化为小的图片。池化层和卷积层类似,也是用一个类似“卷积核”的局部方框在图片上从左到右、从上到下依次滑动。换一个角度理解,其实池化层也相当于一种卷积核,只不过这种“池化卷积核”的参数比较特殊:如果是最大池化,则该卷积核的参数只在最大元素处为1,其余位置为0;如果是平均池化,则该卷积核的参数都为1/(k*k),其中k为“池化卷积核”的大小。
与深度神经网络(DNN)的反向传播过程类似,CNN的反向传播过程包括求解目标函数关于参数的导数以及更新参数这两个步骤。CNN主要由卷积层、池化层和全连接层组成。其中,只有卷积层和全连接层有参数,而池化层没有参数。因此,只需要更新卷积层和全连接层的参数。
全连接层的反向传播过程与DNN一致,直接将后一层的误差导数乘以它之前的权重,即可得到前一层的误差导数。
若要计算误差E相对于池化层输入的导数,则需要先将池化层输出的误差矩阵还原成池化层输入的形状。若采用平均池化,则池化层输出的误差矩阵中的每个元素由池化方框中的所有元素均分;若采用最大池化,则池化层输出的误差矩阵中的每个元素只由池化方框中的最大元素负责。
卷积层的误差递推公式由下图可知。
有了三种类型层的误差递推公式,则可进一步求出误差关于参数的导数。值得注意的是,卷积层的误差递推公式需要旋转180度,而在计算误差关于参数的导数时,则不需要旋转。
02
代码
编码原则:先搭整体框架,再填充细节。
以一层卷积 + 一层池化 + 一层全连接层为例,给出前向传播和反向传播的代码实现。
% cnnConvolve代表卷积操作,需自己实现
activations = cnnConvolve(filterDim, numFilters, mb_data, Wc, bc);
% cnnPool代表池化操作,需自己实现
activationsPooled = cnnPool(poolDim, activations);
% reshape代表将池化后的输出展开成一个列向量,是matlab自带函数
activationsPooled = reshape(activationsPooled,[],numImages);
% 计算全连接层的输出,并采用softmax函数作为输出层
h = exp(bsxfun(@plus,Wd * activationsPooled,bd));
probs = bsxfun(@rdivide,h,sum(h,1));
cnnConvolve():需要理解conv2()函数内部实现的细节
function convolvedFeatures = cnnConvolve(filterDim, numFilters, images, W, b)
% cnnConvolve() Returns the convolution of the features
%
% Parameters:
% filterDim - filter dimension
% numFilters - number of filters
% images - large images to convolve with, matrix in the form
% images(r, c, image number)
% W, b - W is of shape (filterDim,filterDim,numFilters)
% b is of shape (numFilters,1)
%
% Returns:
% convolvedFeatures - matrix of convolved features in the form
% convolvedFeatures(imageRow, imageCol, numFilters, imageNum)
imageDim = size(images,1);
numImages = size(images,3);
convDim = imageDim - filterDim + 1;
% Instructions:
% Convolve every filter with every image here to produce the
% (imageDim - filterDim + 1) x (imageDim - filterDim + 1) x numFeatures x numImages
% matrix convolvedFeatures, such that
% convolvedFeatures(imageRow, imageCol, numFilters, imageNum) is the
% value of the convolved (numFilters)_th feature for the (imageNum)_th image over
% the region (imageRow, imageCol) to (imageRow + filterDim - 1, imageCol + filterDim - 1)
convolvedFeatures = zeros(convDim, convDim, numFilters, numImages);
for imageNum = 1:numImages
for filterNum = 1:numFilters
% Obtain the filter
filter = squeeze(W(:,:,filterNum));
% Flip the feature matrix because of the definition of convolution, as explained later
% 因为在conv2()函数内部会自动逆时针旋转了180度,因此这里也需要逆时针旋转180度保持不变
filter = rot90(squeeze(filter),2);
% Obtain the image
im = squeeze(images(:, :, imageNum));
% Convolve "filter" with "im", adding the result to convolvedImage
% be sure to do a 'valid' convolution
convolvedImage = conv2(im,filter,'valid');
% Add the bias unit
convolvedImage = bsxfun(@plus,convolvedImage,b(filterNum));
% Then, apply the sigmoid function to get the hidden activation
convolvedImage = 1 ./ (1+exp(-convolvedImage));
convolvedFeatures(:, :, filterNum, imageNum) = convolvedImage;
end
end
end
cnnPool():池化层也相当于一种卷积核,只不过这种“池化卷积核”的参数比较特殊:如果是最大池化,则该卷积核的参数只在最大元素处为1,其余位置为0;如果是平均池化,则该卷积核的参数都为1/(k*k),其中k为“池化卷积核”的大小。因此,依然可以采用conv2()或convn()实现池化操作。
function pooledFeatures = cnnPool(poolDim, convolvedFeatures)
% cnnPool() Pools the given convolved features
%
% Parameters:
% poolDim - dimension of pooling region
% convolvedFeatures - convolved features to pool (as given by cnnConvolve)
% convolvedFeatures(imageRow, imageCol, featureNum, imageNum)
%
% Returns:
% pooledFeatures - matrix of pooled features in the form
% pooledFeatures(poolRow, poolCol, featureNum, imageNum)
%
convolvedDim = size(convolvedFeatures, 1);
numFilters = size(convolvedFeatures, 3);
numImages = size(convolvedFeatures, 4);
pooledFeatures = zeros(convolvedDim / poolDim, ...
convolvedDim / poolDim, numFilters, numImages);
% Instructions:
% Now pool the convolved features in regions of poolDim x poolDim,
% to obtain the
% (convolvedDim/poolDim) x (convolvedDim/poolDim) x numFeatures x numImages
% matrix pooledFeatures, such that
% pooledFeatures(poolRow, poolCol, featureNum, imageNum) is the
% value of the featureNum feature for the imageNum image pooled over the
% corresponding (poolRow, poolCol) pooling region.
% Use mean pooling here.
for imageNum = 1:numImages
for featureNum = 1:numFilters
featuremap = squeeze(convolvedFeatures(:,:,featureNum,imageNum));
pooledFeaturemap = conv2(featuremap,ones(poolDim)/(poolDim^2),'valid');
pooledFeatures(:,:,featureNum,imageNum) = pooledFeaturemap(1:poolDim:end,1:poolDim:end);
end
end
end
定义并计算目标函数:梯度下降要优化的目标函数,主要分为两部分:一部分是由于分类器输出结果和真实结果的差异引起的误差,另一部分是对权重w的正则约束。
logp = log(probs);
index = sub2ind(size(logp),mb_labels',1:size(probs,2));
ceCost = -sum(logp(index));
wCost = lambda/2 * (sum(Wd(:).^2)+sum(Wc(:).^2));
cost = ceCost/numImages + wCost;
output = zeros(size(probs));
output(index) = 1;
DeltaSoftmax = probs - output;
Wd_grad = (1./numImages) .* DeltaSoftmax*activationsPooled'+lambda*Wd;
bd_grad = (1./numImages) .* sum(DeltaSoftmax,2);
DeltaPool = reshape(Wd' * DeltaSoftmax,outputDim,outputDim,numFilters,numImages);
DeltaUnpool = zeros(convDim,convDim,numFilters,numImages);
for imNum = 1:numImages
for FilterNum = 1:numFilters
unpool = DeltaPool(:,:,FilterNum,imNum);
DeltaUnpool(:,:,FilterNum,imNum) = kron(unpool,ones(poolDim))./(poolDim ^ 2);
end
end
% 在求出误差关于池化层输入的导数后,再点乘激活函数的导数。
DeltaConv = DeltaUnpool .* activations .* (1 - activations);
% 卷积层偏置的代码
bc_grad = zeros(size(bc));
for filterNum = 1:numFilters
error = DeltaConv(:,:,filterNum,:);
bc_grad(filterNum) = (1./numImages) .* sum(error(:));
end
% 卷积层权重的代码
Wc_grad = zeros(filterDim,filterDim,numFilters);
% 旋转所有DealtaConv:下面的conv2在函数内部会自动旋转180度,
% 所以在这里旋转是为了抵消conv2旋转的影响。
for filterNum = 1:numFilters
for imNum = 1:numImages
error = DeltaConv(:,:,filterNum,imNum);
DeltaConv(:,:,filterNum,imNum) = rot90(error,2);
end
end
for filterNum = 1:numFilters
for imNum = 1:numImages
Wc_grad(:,:,filterNum) = Wc_grad(:,:,filterNum) + conv2(images(:,:,imNum),DeltaConv(:,:,filterNum,imNum),'valid');
end
end
Wc_grad = (1./numImages) .* Wc_grad + lambda*Wc;
以上是关于卷积神经网络:总结的主要内容,如果未能解决你的问题,请参考以下文章