当前位置:   article > 正文

卷积神经网络(Basic CNN)(1)

卷积神经网络(Basic CNN)(1)

一:二维卷积神经网络

在之前提到,将一个张量对其进行全连接后,会出现例如第一行的最后一位与第二行的第一位最终会连接在一起,丧失了一些原有的空间信息。

二维卷积,按照其原始的空间结构进行保存。

目标:明确输入和输出的维度(方便我们进行不同的卷积操作)

方法:构建特征提取器feature extraction,构建分类器classification(全连接)

首先由于全连接会丢失空间信息,因此我们通常先对其进行特征提取,使用到卷积,下采样等(其中一些步骤信息可见上图)。

最后对其进行全连接,方便其进行分类操作。

以上细节部分详细操作如下。

1.1输入

输入的内容如下:

当我们输入一个图像,其实拿到的是一个3维的张量。CxWxH。

随后需要对其进行分块patch,对每一个patch都进行卷积等操作,最终将得到的结果拼在一起。

 

1.2 卷积过程

单通道的卷积核。

例如一个3x3的卷积核,将其放在input上,对应的数字进行相乘(数乘),得到的结果填入output的相应位置,以此类推得到output。过程如下

但是通常我们不会简单面对单通道的问题。 

以三通道为例。

输入通道数一定与核的通道数保持一致。

过程与单通道类似,多通道的每一个通道都安排一个核与其对应计算,最终将相应位置的数字进行相加。

大家可以观察一下输入3x5x5采用3x3x3的核计算后通道的变化,和宽高的变化。 

我们可以发现,如果我们选择一个卷积核,最终就会得到一个通道数为1的输出,如果需要得到n个输出,就需要n个卷积核。

总结注意:

(1)每一个卷积核的通道数要与输入的通道数相同

(2)卷积核的数量决定了输出的通道数,与输出的通道数相同

那当我们知道输入和输出的要求,就可以选择相应的卷积核。

二:计算过程

相关函数的简单使用:

  1. import torch
  2. in_channels, out_channels = 5, 10
  3. width, heigh = 100, 100
  4. kernel_size = 3
  5. batch_size = 1
  6. input = torch.randn(batch_size,in_channels,width,heigh)
  7. conv_layer = torch.nn.Conv2d(in_channels,out_channels,kernel_size = kernel_size)
  8. output = conv_layer(input)
  9. print(input.shape)
  10. print(output.shape)
  11. print(conv_layer.weight.shape)

在设定时,对batch_size,width,heigh都没有固定的要求,宽高都会随着卷积核大小变化,输入通道数,输出通道数,卷积核的大小需要进行设定。 

2.1padding

如果input是5x5,同时希望output也是5x5的,此时需要给inpput添一圈。padding=1

所有padding的相应值需要根据输入和输出来得到。

padding的填充通常填充0。

  1. import torch
  2. input = [3,4,6,5,7,
  3. 2,4,6,8,2,
  4. 1,6,7,8,4,
  5. 9,7,4,6,2,
  6. 3,7,5,4,1]
  7. input = torch.Tensor(input).view(1,1,5,5)#(1,1,5,5)分别是(B,C,W,H)
  8. conv_layer = torch.nn.Conv2d(1,1,kernel_size=3,padding=1,bias=False)
  9. kernel = torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
  10. conv_layer.weight.data = kernel.data
  11. output = conv_layer(input)
  12. print(output)

 

2.2stride 

除了改变padding,还可以改变步长stride。当stride=2时。

 

  1. import torch
  2. input = [3,4,6,5,7,
  3. 2,4,6,8,2,
  4. 1,6,7,8,4,
  5. 9,7,4,6,2,
  6. 3,7,5,4,1]
  7. input = torch.Tensor(input).view(1,1,5,5)#(1,1,5,5)分别是(B,C,W,H)
  8. conv_layer = torch.nn.Conv2d(1,1,kernel_size=3,stride=2,bias=False)
  9. kernel = torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
  10. conv_layer.weight.data = kernel.data
  11. output = conv_layer(input)
  12. print(output)

2.3下采样

常用的下采样是最大池化层。

以2x2的最大池化层举例。将输入分成2x2的块,每个块中找到最大值,做为输出。

  1. import torch
  2. input = [3,4,6,5,
  3. 2,4,6,8,
  4. 1,6,7,8,
  5. 9,7,4,6]
  6. input = torch.Tensor(input).view(1,1,4,4)
  7. maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)
  8. output = maxpooling_layer(input)
  9. print(output)

 

 2.4整体流程

 注意在(batch,20,4,4)到(batch,320)这一步需要进行view。

代码如下:

  1. class Net(torch.nn.Module):
  2. def __init__(self):
  3. super(Net, self).__init__()
  4. self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
  5. self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
  6. self.pooling = torch.nn.MaxPool2d(2)
  7. self.fc = torch.nn.Linear(320, 10)
  8. def forward(self, x):
  9. batch_size = x.size(0) #把维度取出来
  10. x = F.relu(self.pooling(self.conv1(x)))
  11. x = F.relu(self.pooling(self.conv2(x)))
  12. x = x.view(batch_size, -1)
  13. x = self.fc(x)
  14. return x
  15. model = Net()

这样整个流程就结束了。

如果有Gpu的话,可以实现迁移。

  1. device = torch.device("cuda:0"if torch.cuda.is_available()else"cpu")
  2. model.to(device)
  1. import torch
  2. from torch.utils.data import DataLoader
  3. from torchvision import transforms
  4. from torchvision import datasets
  5. import torch.nn.functional as F
  6. import torch.optim as optim
  7. batch_size = 64
  8. transform = transforms.Compose([transforms.ToTensor()])
  9. train_dataset = datasets.MNIST(root='./dataset/MNIST', train=True, download=False, transform=transform)
  10. train_loader = DataLoader(dataset=train_dataset, shuffle=True, batch_size=batch_size)
  11. test_dataset = datasets.MNIST(root='./dataset/MNIST', train=False, download=False, transform=transform)
  12. test_loader = DataLoader(dataset=test_dataset, shuffle=False, batch_size=batch_size)
  13. class Net(torch.nn.Module):
  14. def __init__(self):
  15. super(Net, self).__init__()
  16. self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
  17. self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
  18. self.pooling = torch.nn.MaxPool2d(2)
  19. self.fc = torch.nn.Linear(320, 10)
  20. #下面就是计算的过程
  21. def forward(self, x):
  22. batch_size = x.size(0)
  23. x = F.relu(self.pooling(self.conv1(x)))
  24. x = F.relu(self.pooling(self.conv2(x)))
  25. x = x.view(batch_size, -1)
  26. x = self.fc(x)
  27. return x
  28. model = Net()
  29. #把计算迁移到GPU
  30. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  31. model.to(device)
  32. criterion = torch.nn.CrossEntropyLoss()
  33. optimizer = optim.SGD(model.parameters(),lr=0.1,momentum=0.5)
  34. def train(epoch):
  35. running_loss = 0.0
  36. for batch_idx, data in enumerate(train_loader, 0):#每次取一个样本
  37. inputs, target = data
  38. inputs, target = inputs.to(device), target.to(device)
  39. #优化器清零
  40. optimizer.zero_grad()
  41. # 正向计算一下
  42. outputs = model(inputs)
  43. #计算损失
  44. loss = criterion(outputs, target)
  45. #反向求梯度
  46. loss.backward()
  47. #更新权重
  48. optimizer.step()
  49. #把损失加起来
  50. running_loss += loss.item()
  51. #每300次输出一下数据
  52. if batch_idx % 300 == 299:
  53. print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 2000))
  54. running_loss = 0.0
  55. def test():
  56. correct = 0
  57. total = 0
  58. with torch.no_grad():#不用算梯度
  59. for data in test_loader:
  60. inputs, target = data
  61. inputs, target = inputs.to(device), target.to(device)
  62. outputs = model(inputs)
  63. #我们取概率最大的那个数作为输出
  64. _, predicted = torch.max(outputs.data, dim=1)
  65. total += target.size(0)
  66. #计算正确率
  67. correct += (predicted == target).sum().item()
  68. print('Accuracy on test set: %d %% [%d/%d]' % (100 * correct / total, correct, total))
  69. if __name__=='__main__':
  70. for epoch in range(10):
  71. train(epoch)
  72. if epoch % 10 == 9:
  73. test()

 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/983749
推荐阅读
  

闽ICP备14008679号