当前位置:   article > 正文

残差网络的搭建_torch.nn.sequential torch.nn.conv2d torch.nn.cross

torch.nn.sequential torch.nn.conv2d torch.nn.crossentropyloss

使用残差网络(ResNets)可以构建非常深的卷积网络。理论上讲,更深的网络可以表现更复杂的特征。但网络的加深往往会出现训练损失的上升,使用残差网络可以较好解决这一问题。

残差网络的一个简单的结构如下:

本文所搭建残差网络结构如下:

残差网络如下:

  1. class Residual(torch.nn.Module):
  2. def __init__(self, in_channels, out_channels, stride=1):
  3. super(Residual, self).__init__()
  4. self.stride = stride
  5. # 卷积层使用same填充,由于pytorch没有提供自动填充的操作,需要手算填充的大小
  6. self.before_relu = torch.nn.Sequential(
  7. torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1),#stride=2时,h与w减半
  8. torch.nn.BatchNorm2d(out_channels),
  9. torch.nn.ReLU(inplace=True),
  10. torch.nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
  11. torch.nn.BatchNorm2d(out_channels),
  12. )
  13. self.relu1 = torch.nn.ReLU(inplace=True)
  14. # 输入和输出通道数不同时,需要通过1x1卷积改变输入数据的通道数
  15. if in_channels != out_channels:
  16. self.conv1x1 = torch.nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride)
  17. else:
  18. self.conv1x1 = None
  19. def forward(self, x):
  20. out1 = self.before_relu(x)
  21. if self.conv1x1:
  22. x = self.conv1x1(x)
  23. out = self.relu1(out1 + x)
  24. return out

前向传播经过 卷积层1,输入卷积核大小为3*3,padding为1,stride=1时,输入与输出的H和W不变,stride=2时,输入与输出的H和W减半。之后经过bn,对上一层输出的每一通道进行归一化,输入与输出大小不变,再经过激活函数,在经过卷积层2,输入输出的H与W不变,最后经过bn层。由于经过残差网络后输入输出的通道数可能会不一致,因此需要使用1*1的卷积确保输入输出的通道数一致。

添加残差网络的卷积网络(输入图像的大小为64*64*3):

  1. class ResNet(torch.nn.Module):
  2. def __init__(self, in_channels, num_classes):
  3. super(ResNet,self).__init__()
  4. self.conv1 = torch.nn.Sequential(
  5. torch.nn.Conv2d(in_channels, 64, kernel_size=7, stride=2, padding=3),#32*32*64
  6. torch.nn.BatchNorm2d(64),
  7. torch.nn.ReLU(inplace=True)
  8. )
  9. self.conv2 = torch.nn.Sequential(
  10. torch.nn.MaxPool2d(kernel_size=3, stride=2, padding=1),#16*16*64
  11. Residual(64, 64),
  12. Residual(64, 64),
  13. Residual(64, 64)
  14. )
  15. self.conv3 = torch.nn.Sequential(
  16. Residual(64, 128, stride=2),#8*8*128
  17. Residual(128, 128),
  18. Residual(128, 128),
  19. Residual(128, 128),
  20. Residual(128, 128)
  21. )
  22. self.conv4 = torch.nn.Sequential(
  23. Residual(128, 256, stride=2),#4*4*256
  24. Residual(256, 256),
  25. Residual(256, 256),
  26. Residual(256, 256),
  27. Residual(256, 256),
  28. Residual(256, 256)
  29. )
  30. self.conv5 = torch.nn.Sequential(
  31. Residual(256, 512, stride=2),#2*2*512
  32. Residual(512, 512),
  33. Residual(512, 512)
  34. )
  35. self.avg_pool = torch.nn.AdaptiveAvgPool2d(1)#1*1*512
  36. self.fc = torch.nn.Linear(512, num_classes)
  37. def forward(self, x):
  38. out = self.conv1(x)
  39. out = self.conv2(out)
  40. out = self.conv3(out)
  41. out = self.conv4(out)
  42. out = self.conv5(out)
  43. out = self.avg_pool(out)
  44. out = out.view(out.size()[0], -1)#minibatch*(H*W*C)
  45. out = self.fc(out)
  46. return out

 torch.nn.AdaptiveAvgPool2d(1)可以将上层的输出转化为1*1*上一层输出的通道数,方便连接全连接层。

  1. m = torch.nn.AdaptiveAvgPool2d((1))
  2. input = torch.randn(1, 64, 8, 9)
  3. output = m(input)
  4. print(output.shape)
  5. #输出:torch.Size([1, 64, 1, 1]),通道数不发生变化,输出数据相当于 minibatch x channels x height x width

模型参数如下:

  1. RN=ResNet(3,6)
  2. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  3. RN.to(device)
  4. num = torch.cuda.device_count()
  5. epoch_num = 40
  6. learning_rate = 0.01
  7. batch_size = 32
  8. seed = 3
  9. costs = []
  10. optimizer = torch.optim.Adam(RN.parameters(), lr=learning_rate)
  11. loss_func = torch.nn.CrossEntropyLoss()

数据集来自吴恩达手势识别数据集。

  1. train_signs_data_path = '/content/drive/MyDrive/Colab Notebooks/吴恩达L2HW3/dataset/train_signs.h5'
  2. train_data = Image_Data(train_signs_data_path)
  3. train_data_loader = DataLoader(train_data, shuffle=True, batch_size=32)
  4. test_signs_data_path = '/content/drive/MyDrive/Colab Notebooks/吴恩达L2HW3/dataset/test_signs.h5'
  5. test_data = Image_Data(test_signs_data_path)
  6. test_data_loader = DataLoader(test_data, shuffle=False, batch_size=32)

读取训练集和测试集。 

  1. class Image_Data(Dataset):
  2. def __init__(self, data_path):
  3. super(Image_Data, self).__init__()
  4. # 读取数据集
  5. dataset = h5py.File(data_path, "r")
  6. if data_path == "/content/drive/MyDrive/Colab Notebooks/吴恩达L2HW3/dataset/train_signs.h5":
  7. data_set_x_orig = np.array(dataset["train_set_x"][:])
  8. data_set_y_orig = np.array(dataset["train_set_y"][:])
  9. else:
  10. data_set_x_orig = np.array(dataset["test_set_x"][:])
  11. data_set_y_orig = np.array(dataset["test_set_y"][:])
  12. data_set_x_orig = data_set_x_orig.astype("float32") / 255
  13. data_set_y_orig = data_set_y_orig.astype("float32")
  14. self.x_data = torch.from_numpy(data_set_x_orig)
  15. self.y_data = torch.from_numpy(data_set_y_orig)
  16. self.len = self.y_data.size()[0]
  17. def __getitem__(self, item):
  18. return self.x_data[item], self.y_data[item]
  19. def __len__(self):
  20. return self.len
  21. def get_shape(self):
  22. return self.x_data.size(), self.y_data.size()

模型训练:

  1. RN.train()
  2. for epoch in range(epoch_num):
  3. cost = 0
  4. for i, data in enumerate(train_data_loader):
  5. img_data, img_label = data
  6. img_data = img_data.permute(0, 3, 1, 2)#维度的互换,本来是0,1,2,3,即样本数,高,宽,通道数,转换成0,3,1,2,样本数,通道数,高,宽
  7. img_data = img_data.to(device)
  8. img_label = img_label.to(device)
  9. #mmm=m.cnn(img_data)
  10. optimizer.zero_grad()
  11. y_pred = RN.forward(img_data)
  12. #print(y_pred.shape)
  13. #print(img_label.shape)
  14. loss = loss_func(y_pred, img_label.long())
  15. loss.backward()#反向传播
  16. optimizer.step()#参数更新
  17. cost = cost + loss.item()
  18. costs.append(cost / (i + 1))
  19. if epoch % 5 == 0:
  20. print("epoch=" + str(epoch) + ": " + "loss=" + str(cost / (i + 1)))
  21. plt.plot(costs)
  22. plt.ylabel("cost")
  23. plt.xlabel('iterations (per tens)')
  24. plt.title("Learning rate =" + str(learning_rate))
  25. plt.show()

输出:在较小的epoch上得到较小的训练损失。

epoch=0:  loss=3.1251472795710846
epoch=5:  loss=0.8047693231526543
epoch=10:  loss=0.41270597980302925
epoch=15:  loss=0.26181215551846165
epoch=20:  loss=0.09259872174109607
epoch=25:  loss=0.07002952140208114
epoch=30:  loss=0.05526945255662534
epoch=35:  loss=0.04294046186259948

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/73066
推荐阅读
相关标签
  

闽ICP备14008679号