CNN(卷积神经网络)介绍 - 知乎 (zhihu.com)
CNN:卷积层、池化层、下采样层
1、卷积层:原图像的每个规定大小的块块跟filter矩阵相乘,存入对应位置
因此卷积不是全连接的,是通过filter来提取一小块的局部特征
filter中每个数字都是学出来的
Image x filter/kernel = feature
2、池化层(上采样)--减少参数
计算方式:
①max pool:选出规定网格当中最大的
②平均池化:规定网格所有元素相加再求平均
卷积神经网络的学习方式依然是反向传播和梯度下降
前馈算出loss,反馈往回传,梯度下降法就继续调整神经元权重,直至loss(误差)最小
====================================================================
一、卷积层
输入一个图像,channel=3(rgb)
图像张量=channel * 宽 * 高
卷积是对取出的图像块patch做的,规定大小在图像上滑动,在每个通道上都滑动,然后对每一个块进行卷积(扫过的区域乘以卷积核),最后把输出结果拼到一起。
做完卷积,输出通道可能会变,通道个数取决于卷积核个数(卷积核是权重矩阵,可随着学习变化)
例如:
①单通道:输入:1 * 5 * 5 卷积核: 1 * 3 * 3 输出:1 * 3 * 3
②三通道:输入:3 * 5 *5 卷积核:3 * 3 *3(1个卷积核) 输出:1 * 3 * 3
输入的通道1 * 卷积核的1通道 = 输出1
输入的通道2 * 卷积核的2通道 = 输出2
输入的通道3 * 卷积核的3通道 = 输出3
然后 输出 = 输出1 + 输出2 + 输出3
以上过程中 各通道 * 卷积核 = 各输出(各输出再相加) = 输出------------------红色部分为卷积
1个卷积核,所以输出的通道也是1.
同理,如果输入有n个通道,想得到m个通道的输出,就要准备m个n通道的卷积核与输入相乘。
各卷积核得到的输出们都是1 * 3 *3 的,
最后将m个输出们拼接在一起,就得到了m个通道的最输出。
发现:
①卷积核的通道数得与输入图得通道数一致
②卷积核有几个,最终输出的通道就有几个
m个n通道的卷积核,可拼成个张量:m * n * 宽 * 高
代码表示
import torch
# 想要输入通道5,输出通道10
in_channels,out_channels=5,10
width,height = 100,100
# 卷积核大小
kernel_size=3
# 一次处理几张图
batch_size=1
# 用随机生成的数模拟图像的像素点
input = torch.randn(batch_size,in_channels,width,height)
#卷积层,Conv2d模块: (输入图的通道n,输出的通道m,卷积核的大小)
conv_layer = torch.nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size)
# 把input送入卷积层
output = conv_layer(input)
print(input.shape)
print(output.shape)
print(conv_layer.weight.shape)
最终input.shape=[1,5,10,10]-----------------1个5通道的高度宽度为10的输入
cpnv_layer.weight.shape=[10,5,3,3]--------10个通道数为5的卷积核,宽高为3
output.shape=[1,10,98,98]---------------------1个10通道的输出,宽高为98
2、padding
padding就是保持输出的宽高不变,与输入的宽高一样
例如:原本是输入:5 * 5,卷积核:3 * 3 输出:3 * 3
padding=1:在输入图外圈加一圈0,变成7 * 7
此时输入7 * 7 卷积核3 * 3,输出就变成了 5 * 5
import torch
input = [3,4,6,5,7
2,4,6,8,2
1,6,7,8,3
9,7,4,6,2
3,5,1,7,3]
#将输入变为能处理的张量 1个beach,1个通道,5 * 5
input = torch.Tensor(input).view(1,1,5,5)
#卷积层,输入的通道数,输出的通道数,padding1,bias是偏执量
conv_layer = torch.nn.Conv2d(1,1,kernel_size=3,padding=1,bias=False)
#卷积核,1 * 3 *3
kernel = torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
#把做出来的卷积核作为卷积层的权重
conv_layer.weight.data = kernel.data
#把输入输到卷积层
output = conv_layer(input)
print(output)
3、stride 步长
kernel每次移动的大小
二、池化层(上采样)
减少参数
计算方式:
1、max pooling
选出规定网格当中最大的
例如 4 * 4 的矩阵,分成1234四块区域,每个区域都选出其中最大的一个,就变成了2 * 2的矩阵
这是每个通道分别做的操作,因此max pooling后通道数不变,宽高变为原来的一半
import torch
input = [3,4,6,5
2,4,6,8
1,6,7,8
9,7,4,6]
input = torch.Tensor(input).view(1,1,4,4)
# 池化层
maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)
output = maxpooling_layer(intput)
print(output)
输出为[4,8,
9,8]
2、平均池化
规定网格所有元素相加再求平均
2D卷积过程变化:
①原图:(batch,1,28,28)
②经过卷积层(1,10,5,5)步长1,不做padding-------此时变为(batch,10,24,24)
③经过池化层,------此时变为(batch,10,12,12)
④经过卷积层(10,20,5,5)步长1,不做padding------此时变为(batch,20,8,8)
⑤经过池化层------此时变为(batch,20,4,4)
结束,再变为线性输出,共有元素 20 * 4 * 4 = 320个,将其变为一个向量,经过全连接层最终映射成想要的输出个数
池化层没权重,做一个重复用,不同卷积层有权重,分开做 conv1,conv2