卷积神经网络它的优点在于,需要调优的参数比全连接神经网络少的多,因此他的训练速度会快很多。一般多用于做视觉识别。
下面我们来看一下这张图片,从下图我们可以看到
padding的中文意思是填充,大概意识是要不要在图像周围用0填充。padding有两种,一种是valid,另一种是same。valid模 式即是输出的图像不需要与原图像大小相等,same模式即是输出的图像需要与原图像大小相等。但是要在图像周围填充多少层0才能保证输出的图像与原图像等大小呢。
假设加一圈0则P = 1,那么图像的大小又原来的6变成了吧,即N+2P。上面我已经给出了计算输出图像大小的公式:输出图像大小 : (N-F+1)(N-F+1),现在变成了(N+2P-F+1) (N+2P-F+1).因为输入的大小等于输出的大小所以:
N+2P-F+1)= N,推出 P = (F-1)/2
上面原图像与卷积核做卷积时是一格一格的移动的,其实我们可以定义2格2格的移动。如下图所示:
同时我们也发现了,如果2格2格移动,输出的图像更小的,77的输入图像,最后输出是33的图像,因此输入与输出图像之间的关系,公式需要更新为:
以上讲的都是CONV2D,即是2维矩阵,那么如果是彩色图片的话,那么它就是一个NN3的三维矩阵,分别代表RGB三个不同的通道。比如下面这个图,输入的图像是三通道的图像,663,对应的卷积核的通道也要等于3,一个卷积核产生一个一维的输出图像。如果有两个卷积核,则产生2维的输出图像,如果有1000个卷积核则输出1000维(即相当于通道数)的图像。
池化层的作用主要是减小模型的大小,提高运算速度。我们从远处看下面这两个图形,其实右边的图形就是左边的缩小版。那它是怎么运算的呢?下面的运算使用的是最大池化即是Max Pooling,我们从下图可以看到这个最大池化使用的是22的窗口,步长是2.取得是窗口中最大的那个数,而卷积取得是卷积和。我们也能得出一个44的输入图像,输出后大小减半了。
为什么是-5而不是-6呢,其实5是代表了网络层数,卷积层+池化层算一层。所以我们可以看到:
**第一层:**输入是32321的图像,卷积输出的是6个2828的图像,卷积核为6个55大小的卷积核,步长为1。通过池化层图片缩小为6个1414的图像。窗口大小为22,步长为2.
**第二层:**输入的是14146的图像,卷积输出的是16个1010的图像,卷积核为16个55大小的卷积核,步长为1。通过池化层图片缩小为16个55图像。窗口大小为22,步长为2.
**第三层:**输入为1655 = 400个神经元,输出120个神经元。
**第四层:**输入为120个神经元,输出84个神经元。
**第五层:**输入为84个神经元,输出为10个标签值。
import torch
from torch.autograd import Variable
import numpy as np
import torch.nn as nn
from torchvision import datasets,transforms
#MNIST Dataset
train_dataset = datasets.MNIST(root='./mnist_data/',
train=True,
transform=transforms.ToTensor(),
download=False)
test_dataset = datasets.MNIST(root='./mnist_data/',
train=False,
transform=transforms.ToTensor())
# Data Loader (Input Pipeline)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=128,
shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=100,
shuffle=False)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 6, kernel_size=5, padding=2)
self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
self.mp = nn.MaxPool2d(2)
self.relu = nn.ReLU()
self.fc1 = nn.Linear(16*5*5,120) # 必须为16*5*5
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
self.logsoftmax = nn.LogSoftmax()
def forward(self, x):
in_size = x.size(0)
out = self.relu(self.mp(self.conv1(x)))
out = self.relu(self.mp(self.conv2(out)))
out = self.relu(self.conv3(out))
out = out.view(in_size, -1)
out = self.relu(self.fc1(out))
out = self.relu(self.fc2(out))
out = self.fc3(out)
return self.logsoftmax(out)
model = Net()
#定义损失
loss_func = torch.nn.CrossEntropyLoss()
#定义优化器
opt = torch.optim.Adam(model.parameters(),lr=0.001)
def train(epoch):
model.train()
for batch_index,(data,target) in enumerate(train_loader):
data,target = Variable(data), Variable(target)
opt.zero_grad()
output = model(data)
loss = loss_func(output, target)
#误差反向传播
loss.backward()
#将参数更新值施加到net的parmeters上
opt.step()
if batch_index%20 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_index * len(data), len(train_loader.dataset),
100. * batch_index / len(train_loader), loss.item()))
def test():
model.eval()
test_loss = 0
correct = 0
for data,target in test_loader:
data , target = Variable(data,volatile=True) ,Variable(target)
output = model(data)
# sum up batch loss
test_loss += loss_func(output, target).item()
# get the index of the max log-probability
pred = torch.max(output.data,1)[1]
correct += pred.eq(target.data.view_as(pred)).cpu().sum()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
for epoch in range(1, 10):
train(epoch)
test()
参考资料:
https://zhuanlan.zhihu.com/p/30117574
吴恩达系列卷积神经网络视频:
https://www.bilibili.com/video/BV1F4411y7o7?p=9