目录
*
– 卷积神经网络
–
+
* 前言
* 卷积运算:
* 卷积运算中几个常用的参数
*
– 1.padding
– 2.stride
– 3.Max Pooling Layer
* 实战演练
*
– 设计一个卷积神经网络
– GPU的使用
– 整体代码:
– 运行结果
卷积神经网络
前言
若将图像数据输入全连接层,可能会导致丧失一些位置信息
卷积神经网络将图像按照原有的空间结构保存,不会丧失位置信息。
卷积运算:
1.以单通道为例:
将将input中选中的部分与kernel进行数乘 :
以上图为例对应元素相乘结果为211,并将结果填入output矩阵的左上角
得到:
最终得到的结果为:
2.三通道卷积
三个通道分别利用三个卷积核进行计算,并将结果相加得到最终定格结果。
那么我们可以得到n个通道的卷积过程
若希望得到的卷积后结果通道数为m,则需要m个卷积核同时对原始数据进行处理,得到m个结果,并将其拼接起来,也得到了m个通道
注意:
1.每一个卷积核的通道数量和输入的通道数量是相同的
2.卷积核的总数与输出的通道数量相等
所以我们要构建一个卷积层,其权重的维度为:
代码演示:
**
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
import torch
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
)
conv_layer = torch.nn.Conv2d(in_channels,
out_channels,
kernel_size=kernel_size)
output = conv_layer(input)
print(input.shape)
print(output.shape)
print(conv_layer.weight.shape)
卷积运算中几个常用的参数
1.padding
不想改变输出矩阵的大小,可以向外填充,默认是填充零
代码演示:
import torch
input = [3, 4, 6, 5, 7,
2, 4, 6, 8, 2,
1, 6, 7, 8, 4,
9, 7, 4, 6, 2,
3, 7, 5, 4, 1]
input = torch.Tensor(input).view(1, 1, 5, 5)
conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False)
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)
2.stride
W*H框运动的步长,可以有效降低图像的宽度和高度
例如,当stride=2时,通过3*3卷积核计算得到的输出维度为2 * 2
代码演示:
conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, stride=2, bias=False)
3.Max Pooling Layer
最大池化层:将图像分成2*2的小块,在每一块中寻找最大值,返回给输出,如下图所示,将4 * 4的图像经过池化后变为了2 * 2的图像
作用:减少数据量,降低运算需求
注意:池化层操作只针对同一通道,对通道的数量等其他参数无影响
代码演示:
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(input)
print(output)
实战演练
数据采用MNIST,进行分类任务(懂得都懂)
设计一个卷积神经网络
如上图所示,将一个(1, 28, 28)的图像张量输入进卷积网络中
1.首先经过一个卷积核大小为(5, 5) 输出通道数为10的卷积层
2.经过一个(2, 2)的最大池化层(取出2*2范围内的最大值返回给输出)
3.再经过一个卷积核大小为(5, 5) 输出通道数为20的卷积层,在这里通道数由10变为20
4.又经过一个(2, 2)的最大池化层
5.最终通过一个输入为320维输出为10为的全连接层(作为分类器),得到10个概率值对应于10种类型 320由上一层的参数总数计算而来(20 * 4 * 4)
注:运算过程中,池化层不关注输入输出的维度,但是卷积层和全连接层的输入和输出维度一定要和前后层相对应。
由此,我们得到每一步的核心函数:
代码实现:
import torch
import torch.nn.functional as F
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)
self.fc = torch.nn.Linear(320, 10)
def forward(self, x):
batch_size = x.size(0)
x = F.relu(self.pooling(self.conv1(x)))
x = F.relu(self.pooling(self.conv2(x)))
x = x.view(batch_size, -1)
x = self.fc(x)
return x
model = Net()
GPU的使用
1.将模型迁移到GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
2.训练中将数据迁入GPU,包括inputs和target
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
inputs, target = inputs.to(device), target.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
3.测试中同样也需要将数据送入GPU中,代码同上
整体代码:
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307, ), (0.3081, ))
])
train_dataset = datasets.MNIST(root='../dataset/mnist/',
train=True,
download=True,
transform=transform
)
train_loader = DataLoader(train_dataset,
shuffle=True,
batch_size=batch_size
)
test_dataset = datasets.MNIST(root='../dataset/mnist/',
train=False,
download=True,
transform=transform
)
test_loader = DataLoader(test_dataset,
shuffle=False,
batch_size=batch_size
)
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
self.pooling = torch.nn.MaxPool2d(2)
self.fc = torch.nn.Linear(320, 10)
def forward(self, x):
batch_size = x.size(0)
x = F.relu(self.pooling(self.conv1(x)))
x = F.relu(self.pooling(self.conv2(x)))
x = x.view(batch_size, -1)
x = self.fc(x)
return x
model = Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
inputs, target = inputs.to(device), target.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
def test():
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy on test set:%d %%' % (100 * correct / total))
if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()
运行结果
我只进行了10轮迭代,准确率最终达到了98%,与单纯使用多层的全连接神经网络准确率97%相比提高了一个百分点,错误率降低了1/3,性能有了显著地提升
另外本次在GPU上运行十轮迭代的时间约为1-2分钟,请大家放心跑,无压力。
Original: https://blog.csdn.net/gary101818/article/details/122458932
Author: Unstoppable~~~
Title: 卷积神经网络CNN原理+代码(pytorch实现MNIST集手写数字分类任务)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/625816/
转载文章受原作者版权保护。转载请注明原作者出处!