当前位置:   article > 正文

Pytorch搭建全卷积网络训练mstar数据集

mstar数据集

处理数据集

本文用到的mstar数据集文件格式为mat格式,且图像像素为88×88,即数据是以numpy形式存储的。为了后面处理方便,我们需要将numpy数据读取并转换为tensor格式。代码如下:

  1. # 从mat格式文件中读取numpy数据并转换为tensor格式(方法!!!)
  2. data88 = scipy.io.loadmat('./mstar_data/88_88.mat')
  3. train_data = data88['train_data']
  4. train_label = data88['train_labels']
  5. test_data = data88['test_data']
  6. test_label = data88['test_labels']
  7. print(train_data.shape, train_label.shape, test_data.shape,
  8. test_label.shape) # (3671, 88, 88) (1, 3671) (3203, 88, 88) (1, 3203)
  9. train_data = train_data.reshape(3671, 1, 88, 88) # 灰度图像
  10. test_data = test_data.reshape(3203, 1, 88, 88)
  11. print(train_data.shape, train_label.shape, test_data.shape, test_label.shape)
  12. train_data, train_label, test_data, test_label = map(torch.tensor, (
  13. train_data, train_label.squeeze(), test_data, test_label.squeeze()))
  14. print(train_data.shape, train_label.shape, test_data.shape, test_label.shape) # numpy转tensor

可以看到,将数据reshape为(图片个数,通道数,88,88),这里通道数为1。

数据集标准化

标准化处理输⼊数据使各个特征的分布相近,这往往更容易训练出有效的模型。因此我们对数据集进行标准化,代码如下:

  1. # 数据集标准化
  2. mean = train_data.mean()
  3. std = train_data.std()
  4. print(mean, std)
  5. train_data = (train_data - mean) / std
  6. test_data = (test_data - mean) / std
  7. print(train_data.mean(), train_data.std(), test_data.mean(), test_data.std())

训练集10中样本可视化

先编写显示并保存图像的函数:

  1. def plot_image(img, label, img_name, clas):
  2. fig = plt.figure()
  3. for i in range(10):
  4. plt.subplot(2, 5, i + 1)
  5. # plt.tight_layout()
  6. plt.imshow(img[i].view(88, 88), cmap='gray')
  7. plt.title("{}:{}".format(img_name, label[i].item())) # item()的作用是取出tensor格式的元素值并返回该值,保持原元素类型不变
  8. plt.xticks([])
  9. plt.yticks([])
  10. plt.savefig('fig' + clas)
  11. plt.show()

之后我们可以输出训练集的10张图片看一下。将训练集中train_label为0~9的第一张图片都输出,代码及输出结果如下:

  1. # 训练集10种样本可视化
  2. train_data09 = []
  3. train_label09 = []
  4. for i in range(10):
  5. train_data09.append(train_data[train_label == i][0]) # 这里要再加[0]才能正常显示label=i时的第一组图片
  6. train_label09.append(torch.tensor(i)) # 因为此时train_label就等于i,但train_label是tensor格式,因此需要将i转换为tensor格式
  7. print(len(train_data09), train_label09)
  8. plot_image(train_data09, train_label09, 'label', '88_88')

加载数据集

与能够在Pytorch官网下载的数据集(如CIFAR10、MNIST)处理方式不同,因为之前已经将其转换为了Tensor格式,所以需要先将其图片和标签打包在一起,然后再用DataLoader进行batch打包,代码如下:

  1. # 加载数据集
  2. train_xy = TensorDataset(train_data, train_label) # 相当于将图片和对应的标签打包在了一起
  3. test_xy = TensorDataset(test_data, test_label)
  4. train = DataLoader(train_xy, batch_size=64, shuffle=True) # shuffle=True用于打乱数据集,每次都会以不同的顺序返回
  5. test = DataLoader(test_xy, batch_size=256)
  6. print(len(train_xy), len(train), len(test_xy), len(test))

这里的shuffle可以将数据集随机打乱,每次训练都以不同的batch顺序进行。这里笔者将训练集和测试集的batch_size分别设置为64和256。

搭建神经网络

本文的神经网络结构参考了Target Classification Using the Deep Convolutional Networks for SAR Images Sizhe Chen, Student Member, IEEE, Haipeng Wang, Member, IEEE,FengXu,Senior Member, IEEE,and Ya-Qiu Jin, Fellow, IEEE这篇文章,该神经网络的特点是没有设置全连接层,整个网络全部是由卷积层构成的,网络结构如下:

由于网络中全是卷积层,因此需要对每一层的卷积核、最大池化层的参数进行设置,从而使输出的维度为10×1×1,网络如下:

  1. class mstar88_cnn(nn.Module): # n=88
  2. def __init__(self):
  3. super(mstar88_cnn, self).__init__()
  4. self.model_cnn = nn.Sequential(
  5. nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=0), # n=84
  6. nn.BatchNorm2d(16),
  7. nn.ReLU(),
  8. nn.MaxPool2d(kernel_size=2, stride=2), # 42
  9. nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, stride=1, padding=0), # 38
  10. nn.BatchNorm2d(32),
  11. nn.ReLU(),
  12. nn.MaxPool2d(kernel_size=2, stride=2), # 19
  13. nn.Conv2d(in_channels=32, out_channels=64, kernel_size=6, stride=1, padding=0), # 14
  14. nn.BatchNorm2d(64),
  15. nn.ReLU(),
  16. nn.MaxPool2d(kernel_size=2, stride=2), # 7
  17. nn.Dropout(0.5), # 这里用Dropout2d应该也可以
  18. nn.Conv2d(in_channels=64, out_channels=128, kernel_size=5, stride=1, padding=0), # 3
  19. nn.BatchNorm2d(128),
  20. nn.ReLU(),
  21. nn.Conv2d(in_channels=128, out_channels=10, kernel_size=3, stride=1, padding=0), # 1
  22. nn.BatchNorm2d(10)
  23. )
  24. def forward(self, x):
  25. x = self.model_cnn(x)
  26. x = x.view(x.shape[0], -1) # 矩阵的每一行就是这个批量中每张图片的各个参数,即矩阵中一行对应一张图片
  27. x = F.softmax(x, 1)
  28. return x

输入的维度为1×88×88,经过每一层后像素为(n-f+2*p)/s+1。最终输出一个列向量,其每一行代表一张图像。这里的BatchNorm归一化运算一般加在卷积运算和ReLU函数之间,使得数据在进行Relu之前不会因为数据过大而导致网络性能的不稳定

训练网络

设置好网络、损失函数、优化器、训练次数等,并初始化好存放loss和accuracy的列表,后面画训练损失和准确度图时会用到。这里需要注意以下几点:

1.如果在设置损失函数是使用的是nn.CrossEntropyLoss(),那么在搭建多分类神经网络的最后就不用再进行softmax运算,因为这个“交叉熵”函数内部会自动进行softmax运算;

2.训练的一般步骤就是梯度清零(optimizer.zero_grad())、反向传播(loss.backward())、参数优化(optimizer.step())。

3.enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,因此它给每个batch都标了序号,存放在batch_idx中。

笔者是每轮整个训练和测试结束后再输出训练和测试各自的loss和accuracy值。代码如下:
 

  1. model = mstar88_cnn()
  2. model.to(device)
  3. loss_fn = nn.CrossEntropyLoss()
  4. loss_fn.to(device)
  5. learning_rate = 0.001
  6. # optimizer=torch.optim.SGD(params=model.parameters(),lr=learning_rate,momentum=0.9)
  7. train_acc_list = []
  8. train_loss_list = []
  9. test_acc_list = []
  10. test_loss_list = []
  11. epochs = 10
  12. for epoch in range(epochs):
  13. if (epoch + 1) == 50:
  14. learning_rate = learning_rate * 0.9
  15. optimizer = torch.optim.SGD(params=model.parameters(), lr=learning_rate, momentum=0.9)
  16. print("-----第{}轮训练开始------".format(epoch + 1))
  17. train_loss = 0.0
  18. test_loss = 0.0
  19. train_sum, train_cor, test_sum, test_cor = 0, 0, 0, 0
  20. # 训练步骤开始
  21. model.train()
  22. for batch_idx, data in enumerate(train):
  23. inputs, labels = data
  24. inputs, labels=inputs.to(device),labels.to(device)
  25. labels = torch.tensor(labels, dtype=torch.long) # 需要将label转换成long类型
  26. optimizer.zero_grad()
  27. outputs = model(inputs.float()) # 需要加.float(),否则会报错
  28. loss = loss_fn(outputs, labels)
  29. loss.backward()
  30. optimizer.step()
  31. # 计算每轮训练集的Loss
  32. train_loss += loss.item()
  33. # 计算每轮训练集的准确度
  34. _, predicted = torch.max(outputs.data, 1) # 选择最大的(概率)值所在的列数就是他所对应的类别数,
  35. train_cor += (predicted == labels).sum().item() # 正确分类个数
  36. train_sum += labels.size(0) # train_sum+=predicted.shape[0]
  37. # 测试步骤开始
  38. model.eval()
  39. # with torch.no_grad():
  40. for batch_idx1, data in enumerate(test):
  41. inputs, labels = data
  42. inputs, labels = inputs.to(device), labels.to(device)
  43. labels = torch.tensor(labels, dtype=torch.long)
  44. outputs = model(inputs.float())
  45. loss = loss_fn(outputs, labels)
  46. test_loss += loss.item()
  47. _, predicted = torch.max(outputs.data, 1)
  48. test_cor += (predicted == labels).sum().item()
  49. test_sum += labels.size(0)
  50. print("Train loss:{} Train accuracy:{}% Test loss:{} Test accuracy:{}%".format(train_loss / batch_idx,
  51. 100 * train_cor / train_sum,
  52. test_loss / batch_idx1,
  53. 100 * test_cor / test_sum))
  54. train_loss_list.append(train_loss / batch_idx)
  55. train_acc_list.append(100 * train_cor / train_sum)
  56. test_acc_list.append(100 * test_cor / test_sum)
  57. test_loss_list.append(test_loss / batch_idx1)
  58. # 保存网络
  59. torch.save(model, "mstar_88_epoch{}.pth".format(epochs))

画出曲线

最后,画出损失和准确率的曲线,代码及图像如下:
 

  1. fig = plt.figure()
  2. plt.plot(range(len(train_loss_list)), train_loss_list, 'blue')
  3. plt.plot(range(len(test_loss_list)), test_loss_list, 'red')
  4. plt.legend(['Train Loss', 'Test Loss'], fontsize=14, loc='best')
  5. plt.xlabel('Epoch', fontsize=14)
  6. plt.ylabel('Loss', fontsize=14)
  7. plt.grid()
  8. plt.savefig('figLOSS')
  9. plt.show()
  10. fig = plt.figure()
  11. plt.plot(range(len(train_acc_list)), train_acc_list, 'blue')
  12. plt.plot(range(len(test_acc_list)), test_acc_list, 'red')
  13. plt.legend(['Train Accuracy', 'Test Accuracy'], fontsize=14, loc='best')
  14. plt.xlabel('Epoch', fontsize=14)
  15. plt.ylabel('Accuracy(%)', fontsize=14)
  16. plt.grid()
  17. plt.savefig('figAccuracy')
  18. plt.show()

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

闽ICP备14008679号