• 【动手学深度学习】卷积神经网络CNN的研究详情


    目录

    🌊1. 研究目的

    🌊2. 研究准备

    🌊3. 研究内容

    🌍3.1 卷积神经网络

    🌍3.2 练习

    🌊4. 研究体会


    🌊1. 研究目的

    • 特征提取和模式识别:CNN 在计算机视觉领域被广泛用于提取图像中的特征和进行模式识别;
    • 目标检测和物体识别:CNN 在目标检测和物体识别方面表现出色;
    • 图像分割和语义分析:CNN 可以用于图像分割任务,即将图像分割成不同的区域或对象,并对它们进行语义分析;
    • 图像生成和样式转换:CNN 还可以用于图像生成和样式转换,例如生成逼真的图像、图像风格迁移等。

    🌊2. 研究准备

    • 根据GPU安装pytorch版本实现GPU运行研究代码;
    • 配置环境用来运行 Python、Jupyter Notebook和相关库等相关库。

    🌊3. 研究内容

    启动jupyter notebook,使用新增的pytorch环境新建ipynb文件,为了检查环境配置是否合理,输入import torch以及torch.cuda.is_available() ,若返回TRUE则说明研究环境配置正确,若返回False但可以正确导入torch则说明pytorch配置成功,但研究运行是在CPU进行的,结果如下:


    🌍3.1 卷积神经网络

    (1)使用jupyter notebook新增的pytorch环境新建ipynb文件,完成基本数据操作的研究代码与练习结果如下:

    代码实现如下:

    导入必要库及实现部分

    1. %matplotlib inline
    2. import torch
    3. from torch import nn
    4. from d2l import torch as d2l

    LeNet

    1. net = nn.Sequential(
    2. nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    3. nn.AvgPool2d(kernel_size=2, stride=2),
    4. nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    5. nn.AvgPool2d(kernel_size=2, stride=2),
    6. nn.Flatten(),
    7. nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    8. nn.Linear(120, 84), nn.Sigmoid(),
    9. nn.Linear(84, 10))
    10. X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
    11. for layer in net:
    12. X = layer(X)
    13. print(layer.__class__.__name__,'output shape: \t',X.shape)

    模型训练

    1. batch_size = 256
    2. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    3. def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
    4. """使用GPU计算模型在数据集上的精度"""
    5. if isinstance(net, nn.Module):
    6. net.eval() # 设置为评估模式
    7. if not device:
    8. device = next(iter(net.parameters())).device
    9. # 正确预测的数量,总预测的数量
    10. metric = d2l.Accumulator(2)
    11. with torch.no_grad():
    12. for X, y in data_iter:
    13. if isinstance(X, list):
    14. # BERT微调所需的(之后将介绍)
    15. X = [x.to(device) for x in X]
    16. else:
    17. X = X.to(device)
    18. y = y.to(device)
    19. metric.add(d2l.accuracy(net(X), y), y.numel())
    20. return metric[0] / metric[1]
    21. #@save
    22. def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    23. """用GPU训练模型(在第六章定义)"""
    24. def init_weights(m):
    25. if type(m) == nn.Linear or type(m) == nn.Conv2d:
    26. nn.init.xavier_uniform_(m.weight)
    27. net.apply(init_weights)
    28. print('training on', device)
    29. net.to(device)
    30. optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    31. loss = nn.CrossEntropyLoss()
    32. animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
    33. legend=['train loss', 'train acc', 'test acc'])
    34. timer, num_batches = d2l.Timer(), len(train_iter)
    35. for epoch in range(num_epochs):
    36. # 训练损失之和,训练准确率之和,样本数
    37. metric = d2l.Accumulator(3)
    38. net.train()
    39. for i, (X, y) in enumerate(train_iter):
    40. timer.start()
    41. optimizer.zero_grad()
    42. X, y = X.to(device), y.to(device)
    43. y_hat = net(X)
    44. l = loss(y_hat, y)
    45. l.backward()
    46. optimizer.step()
    47. with torch.no_grad():
    48. metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
    49. timer.stop()
    50. train_l = metric[0] / metric[2]
    51. train_acc = metric[1] / metric[2]
    52. if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
    53. animator.add(epoch + (i + 1) / num_batches,
    54. (train_l, train_acc, None))
    55. test_acc = evaluate_accuracy_gpu(net, test_iter)
    56. animator.add(epoch + 1, (None, None, test_acc))
    57. print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
    58. f'test acc {test_acc:.3f}')
    59. print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
    60. f'on {str(device)}')
    61. lr, num_epochs = 0.9, 10
    62. train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())


    🌍3.2 练习

    1.将平均汇聚层替换为最大汇聚层,会发生什么?

    LeNet网络使用的是平均汇聚层(Average Pooling),将其替换为最大汇聚层(Max Pooling)会对网络的性能产生一些影响。

    具体而言,将平均汇聚层替换为最大汇聚层会使网络更加注重图像中的突出特征。最大汇聚层在每个汇聚窗口中选择最大的值作为输出,而平均汇聚层则是取汇聚窗口中的平均值作为输出。因此,最大汇聚层更容易捕捉到图像中的显著特征,如边缘、纹理等。

    从实验结果来看,使用最大汇聚层可能会导致网络的准确率提高。然而,这也取决于具体的数据集和任务。有时平均汇聚层在某些情况下可能更适用,因为它能够提供更平滑的特征表示。

    总之,将LeNet网络中的平均汇聚层替换为最大汇聚层可能会改善网络的性能,特别是在突出图像中显著特征的任务中。但对于其他任务和数据集,可能需要进行实验和调整以确定最佳的汇聚方式。

    当将LeNet网络中的平均汇聚层替换为最大汇聚层时,只需要将nn.AvgPool2d替换为nn.MaxPool2d即可。以下是修改后的代码:

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. net = nn.Sequential(
    5. nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    6. nn.MaxPool2d(kernel_size=2, stride=2), # 替换为最大汇聚层
    7. nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    8. nn.MaxPool2d(kernel_size=2, stride=2), # 替换为最大汇聚层
    9. nn.Flatten(),
    10. nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    11. nn.Linear(120, 84), nn.Sigmoid(),
    12. nn.Linear(84, 10)
    13. )
    14. X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
    15. for layer in net:
    16. X = layer(X)
    17. print(layer.__class__.__name__, 'output shape: \t', X.shape)
    18. batch_size = 256
    19. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    20. def evaluate_accuracy_gpu(net, data_iter, device=None):
    21. """使用GPU计算模型在数据集上的精度"""
    22. if isinstance(net, nn.Module):
    23. net.eval() # 设置为评估模式
    24. if not device:
    25. device = next(iter(net.parameters())).device
    26. # 正确预测的数量,总预测的数量
    27. metric = d2l.Accumulator(2)
    28. with torch.no_grad():
    29. for X, y in data_iter:
    30. if isinstance(X, list):
    31. # BERT微调所需的(之后将介绍)
    32. X = [x.to(device) for x in X]
    33. else:
    34. X = X.to(device)
    35. y = y.to(device)
    36. metric.add(d2l.accuracy(net(X), y), y.numel())
    37. return metric[0] / metric[1]
    38. def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    39. """用GPU训练模型(在第六章定义)"""
    40. def init_weights(m):
    41. if type(m) == nn.Linear or type(m) == nn.Conv2d:
    42. nn.init.xavier_uniform_(m.weight)
    43. net.apply(init_weights)
    44. print('training on', device)
    45. net.to(device)
    46. optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    47. loss = nn.CrossEntropyLoss()
    48. animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
    49. legend=['train loss', 'train acc', 'test acc'])
    50. timer, num_batches = d2l.Timer(), len(train_iter)
    51. for epoch in range(num_epochs):
    52. # 训练损失之和,训练准确率之和,样本数
    53. metric = d2l.Accumulator(3)
    54. net.train()
    55. for i, (X, y) in enumerate(train_iter):
    56. timer.start()
    57. optimizer.zero_grad()
    58. X, y = X.to(device), y.to(device)
    59. y_hat = net(X)
    60. l = loss(y_hat, y)
    61. l.backward()
    62. optimizer.step()
    63. with torch.no_grad():
    64. metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
    65. timer.stop()
    66. train_l = metric[0] / metric[2]
    67. train_acc = metric[1] / metric[2]
    68. if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
    69. animator.add(epoch + (i + 1) / num_batches,
    70. (train_l, train_acc, None))
    71. test_acc = evaluate_accuracy_gpu(net, test_iter)
    72. animator.add(epoch + 1, (None, None, test_acc))
    73. print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
    74. f'test acc {test_acc:.3f}')
    75. print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
    76. f'on {str(device)}')
    77. lr, num_epochs = 0.9, 10
    78. train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

    2.尝试构建一个基于LeNet的更复杂的网络,以提高其准确性。

    2.1.调整卷积窗口大小。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. class ComplexLeNet(nn.Module):
    5. def __init__(self):
    6. super(ComplexLeNet, self).__init__()
    7. self.conv1 = nn.Conv2d(1, 6, kernel_size=5, padding=2)
    8. self.relu1 = nn.ReLU()
    9. self.maxpool1 = nn.MaxPool2d(kernel_size=2, stride=2)
    10. self.conv2 = nn.Conv2d(6, 16, kernel_size=3, padding=1)
    11. self.relu2 = nn.ReLU()
    12. self.maxpool2 = nn.MaxPool2d(kernel_size=2, stride=2)
    13. self.conv3 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
    14. self.relu3 = nn.ReLU()
    15. self.maxpool3 = nn.MaxPool2d(kernel_size=2, stride=2)
    16. self.flatten = nn.Flatten()
    17. self.fc1 = nn.Linear(32 * 3 * 3, 120)
    18. self.relu4 = nn.ReLU()
    19. self.fc2 = nn.Linear(120, 84)
    20. self.relu5 = nn.ReLU()
    21. self.fc3 = nn.Linear(84, 10)
    22. def forward(self, x):
    23. out = self.maxpool1(self.relu1(self.conv1(x)))
    24. out = self.maxpool2(self.relu2(self.conv2(out)))
    25. out = self.maxpool3(self.relu3(self.conv3(out)))
    26. out = self.flatten(out)
    27. out = self.relu4(self.fc1(out))
    28. out = self.relu5(self.fc2(out))
    29. out = self.fc3(out)
    30. return out
    31. net = ComplexLeNet()
    32. # 打印网络结构
    33. print(net)

    在这个网络中,增加了一个卷积层和汇聚层。第一个卷积层使用5x5的卷积窗口,第二个和第三个卷积层使用3x3的卷积窗口。这样可以增加网络的深度和复杂度,提高特征提取的能力。可以根据实际情况进一步调整网络结构和超参数,以提高准确性。

    2.2.调整输出通道的数量。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. class ComplexLeNet(nn.Module):
    5. def __init__(self):
    6. super(ComplexLeNet, self).__init__()
    7. self.conv1 = nn.Conv2d(1, 10, kernel_size=5, padding=2)
    8. self.relu1 = nn.ReLU()
    9. self.maxpool1 = nn.MaxPool2d(kernel_size=2, stride=2)
    10. self.conv2 = nn.Conv2d(10, 20, kernel_size=3, padding=1)
    11. self.relu2 = nn.ReLU()
    12. self.maxpool2 = nn.MaxPool2d(kernel_size=2, stride=2)
    13. self.conv3 = nn.Conv2d(20, 40, kernel_size=3, padding=1)
    14. self.relu3 = nn.ReLU()
    15. self.maxpool3 = nn.MaxPool2d(kernel_size=2, stride=2)
    16. self.flatten = nn.Flatten()
    17. self.fc1 = nn.Linear(40 * 3 * 3, 120)
    18. self.relu4 = nn.ReLU()
    19. self.fc2 = nn.Linear(120, 84)
    20. self.relu5 = nn.ReLU()
    21. self.fc3 = nn.Linear(84, 10)
    22. def forward(self, x):
    23. out = self.maxpool1(self.relu1(self.conv1(x)))
    24. out = self.maxpool2(self.relu2(self.conv2(out)))
    25. out = self.maxpool3(self.relu3(self.conv3(out)))
    26. out = self.flatten(out)
    27. out = self.relu4(self.fc1(out))
    28. out = self.relu5(self.fc2(out))
    29. out = self.fc3(out)
    30. return out
    31. net = ComplexLeNet()
    32. # 打印网络结构
    33. print(net)

    在这个示例中,我们增加了每个卷积层的输出通道数量。第一个卷积层输出10个通道,第二个卷积层输出20个通道,第三个卷积层输出40个通道。通过增加输出通道的数量,网络可以更好地捕捉和表示输入数据中的特征。你可以根据实际情况进一步调整网络结构和超参数,以提高准确性。

    2.3.调整激活函数(如ReLU)。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. class ComplexLeNet(nn.Module):
    5. def __init__(self):
    6. super(ComplexLeNet, self).__init__()
    7. self.conv1 = nn.Conv2d(1, 6, kernel_size=5, padding=2)
    8. self.relu1 = nn.LeakyReLU()
    9. self.maxpool1 = nn.MaxPool2d(kernel_size=2, stride=2)
    10. self.conv2 = nn.Conv2d(6, 16, kernel_size=3, padding=1)
    11. self.relu2 = nn.LeakyReLU()
    12. self.maxpool2 = nn.MaxPool2d(kernel_size=2, stride=2)
    13. self.conv3 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
    14. self.relu3 = nn.LeakyReLU()
    15. self.maxpool3 = nn.MaxPool2d(kernel_size=2, stride=2)
    16. self.flatten = nn.Flatten()
    17. self.fc1 = nn.Linear(32 * 3 * 3, 120)
    18. self.relu4 = nn.LeakyReLU()
    19. self.fc2 = nn.Linear(120, 84)
    20. self.relu5 = nn.LeakyReLU()
    21. self.fc3 = nn.Linear(84, 10)
    22. def forward(self, x):
    23. out = self.maxpool1(self.relu1(self.conv1(x)))
    24. out = self.maxpool2(self.relu2(self.conv2(out)))
    25. out = self.maxpool3(self.relu3(self.conv3(out)))
    26. out = self.flatten(out)
    27. out = self.relu4(self.fc1(out))
    28. out = self.relu5(self.fc2(out))
    29. out = self.fc3(out)
    30. return out
    31. net = ComplexLeNet()
    32. # 打印网络结构
    33. print(net)

    2.4调整卷积层的数量。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. class ComplexLeNet(nn.Module):
    5. def __init__(self):
    6. super(ComplexLeNet, self).__init__()
    7. self.features = nn.Sequential(
    8. nn.Conv2d(1, 32, kernel_size=3, padding=1), # 卷积层1
    9. nn.ReLU(),
    10. nn.Conv2d(32, 64, kernel_size=3, padding=1), # 卷积层2
    11. nn.ReLU(),
    12. nn.MaxPool2d(kernel_size=2, stride=2), # 汇聚层1
    13. nn.Conv2d(64, 128, kernel_size=3, padding=1), # 卷积层3
    14. nn.ReLU(),
    15. nn.Conv2d(128, 256, kernel_size=3, padding=1), # 卷积层4
    16. nn.ReLU(),
    17. nn.MaxPool2d(kernel_size=2, stride=2), # 汇聚层2
    18. )
    19. self.fc = nn.Sequential(
    20. nn.Linear(256 * 7 * 7, 512), # 全连接层1
    21. nn.ReLU(),
    22. nn.Linear(512, 256), # 全连接层2
    23. nn.ReLU(),
    24. nn.Linear(256, 10) # 输出层
    25. )
    26. def forward(self, x):
    27. x = self.features(x)
    28. x = torch.flatten(x, 1)
    29. x = self.fc(x)
    30. return x
    31. # 创建复杂LeNet模型实例
    32. net = ComplexLeNet()
    33. # 打印网络结构
    34. print(net)

    2.5.调整全连接层的数量。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. class ComplexLeNet(nn.Module):
    5. def __init__(self):
    6. super(ComplexLeNet, self).__init__()
    7. self.features = nn.Sequential(
    8. nn.Conv2d(1, 32, kernel_size=3, padding=1), # 卷积层1
    9. nn.ReLU(),
    10. nn.Conv2d(32, 64, kernel_size=3, padding=1), # 卷积层2
    11. nn.ReLU(),
    12. nn.MaxPool2d(kernel_size=2, stride=2), # 汇聚层1
    13. nn.Conv2d(64, 128, kernel_size=3, padding=1), # 卷积层3
    14. nn.ReLU(),
    15. nn.Conv2d(128, 256, kernel_size=3, padding=1), # 卷积层4
    16. nn.ReLU(),
    17. nn.MaxPool2d(kernel_size=2, stride=2), # 汇聚层2
    18. )
    19. self.fc = nn.Sequential(
    20. nn.Linear(256 * 7 * 7, 512), # 全连接层1
    21. nn.ReLU(),
    22. nn.Linear(512, 256), # 全连接层2
    23. nn.ReLU(),
    24. nn.Linear(256, 128), # 全连接层3
    25. nn.ReLU(),
    26. nn.Linear(128, 10) # 输出层
    27. )
    28. def forward(self, x):
    29. x = self.features(x)
    30. x = torch.flatten(x, 1)
    31. x = self.fc(x)
    32. return x
    33. # 创建复杂LeNet模型实例
    34. net = ComplexLeNet()
    35. # 打印网络结构
    36. print(net)
    37. # 训练和评估复杂LeNet模型的代码与之前的示例相似,可以根据需要进行调整

    2.6.调整学习率和其他训练细节(例如,初始化和轮数)。

    学习率调整为0.001。 训练轮数调整为20。 添加了权重初始化函数init_weights,使用Xavier初始化方法对线性层和卷积层的权重进行初始化。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. net = nn.Sequential(
    5. nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    6. nn.AvgPool2d(kernel_size=2, stride=2),
    7. nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    8. nn.AvgPool2d(kernel_size=2, stride=2),
    9. nn.Flatten(),
    10. nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    11. nn.Linear(120, 84), nn.Sigmoid(),
    12. nn.Linear(84, 10))
    13. X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
    14. for layer in net:
    15. X = layer(X)
    16. print(layer.__class__.__name__,'output shape: \t',X.shape)
    17. batch_size = 256
    18. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    19. def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
    20. """使用GPU计算模型在数据集上的精度"""
    21. if isinstance(net, nn.Module):
    22. net.eval() # 设置为评估模式
    23. if not device:
    24. device = next(iter(net.parameters())).device
    25. # 正确预测的数量,总预测的数量
    26. metric = d2l.Accumulator(2)
    27. with torch.no_grad():
    28. for X, y in data_iter:
    29. if isinstance(X, list):
    30. # BERT微调所需的(之后将介绍)
    31. X = [x.to(device) for x in X]
    32. else:
    33. X = X.to(device)
    34. y = y.to(device)
    35. metric.add(d2l.accuracy(net(X), y), y.numel())
    36. return metric[0] / metric[1]
    37. #@save
    38. def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    39. """用GPU训练模型(在第六章定义)"""
    40. def init_weights(m):
    41. if type(m) == nn.Linear or type(m) == nn.Conv2d:
    42. nn.init.xavier_uniform_(m.weight)
    43. net.apply(init_weights)
    44. print('training on', device)
    45. net.to(device)
    46. optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    47. loss = nn.CrossEntropyLoss()
    48. animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
    49. legend=['train loss', 'train acc', 'test acc'])
    50. timer, num_batches = d2l.Timer(), len(train_iter)
    51. for epoch in range(num_epochs):
    52. # 训练损失之和,训练准确率之和,样本数
    53. metric = d2l.Accumulator(3)
    54. net.train()
    55. for i, (X, y) in enumerate(train_iter):
    56. timer.start()
    57. optimizer.zero_grad()
    58. X, y = X.to(device), y.to(device)
    59. y_hat = net(X)
    60. l = loss(y_hat, y)
    61. l.backward()
    62. optimizer.step()
    63. with torch.no_grad():
    64. metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
    65. timer.stop()
    66. train_l = metric[0] / metric[2]
    67. train_acc = metric[1] / metric[2]
    68. if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
    69. animator.add(epoch + (i + 1) / num_batches,
    70. (train_l, train_acc, None))
    71. test_acc = evaluate_accuracy_gpu(net, test_iter)
    72. animator.add(epoch + 1, (None, None, test_acc))
    73. print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
    74. f'test acc {test_acc:.3f}')
    75. print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
    76. f'on {str(device)}')
    77. lr, num_epochs = 0.001, 20
    78. train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

    3.在MNIST数据集上尝试以上改进的网络。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. # 定义更复杂的LeNet网络
    5. net = nn.Sequential(
    6. nn.Conv2d(1, 10, kernel_size=5),
    7. nn.ReLU(),
    8. nn.MaxPool2d(kernel_size=2, stride=2),
    9. nn.Conv2d(10, 20, kernel_size=5),
    10. nn.ReLU(),
    11. nn.MaxPool2d(kernel_size=2, stride=2),
    12. nn.Flatten(),
    13. nn.Linear(320, 120),
    14. nn.ReLU(),
    15. nn.Linear(120, 84),
    16. nn.ReLU(),
    17. nn.Linear(84, 10)
    18. )
    19. # 数据集加载和准备
    20. batch_size = 256
    21. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    22. # 定义训练函数
    23. def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    24. def init_weights(m):
    25. if type(m) == nn.Linear or type(m) == nn.Conv2d:
    26. nn.init.xavier_uniform_(m.weight)
    27. net.apply(init_weights)
    28. net.to(device)
    29. optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    30. loss = nn.CrossEntropyLoss()
    31. animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs], legend=['train loss', 'train acc', 'test acc'])
    32. timer, num_batches = d2l.Timer(), len(train_iter)
    33. for epoch in range(num_epochs):
    34. metric = d2l.Accumulator(3)
    35. net.train()
    36. for i, (X, y) in enumerate(train_iter):
    37. timer.start()
    38. optimizer.zero_grad()
    39. X, y = X.to(device), y.to(device)
    40. y_hat = net(X)
    41. l = loss(y_hat, y)
    42. l.backward()
    43. optimizer.step()
    44. with torch.no_grad():
    45. metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
    46. timer.stop()
    47. train_loss = metric[0] / metric[2]
    48. train_accuracy = metric[1] / metric[2]
    49. if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
    50. animator.add(epoch + (i + 1) / num_batches, (train_loss, train_accuracy, None))
    51. test_accuracy = evaluate_accuracy_gpu(net, test_iter, device)
    52. animator.add(epoch + 1, (None, None, test_accuracy))
    53. print(f"第 {epoch+1} 轮:训练损失 {train_loss:.4f},训练准确率 {train_accuracy:.4f},测试准确率 {test_accuracy:.4f}")
    54. print("训练完成!")
    55. # 模型训练
    56. lr, num_epochs = 0.01, 10
    57. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    58. train_ch6(net, train_iter, test_iter, num_epochs, lr, device)

    4.显示不同输入(例如毛衣和外套)时,LeNet第一层和第二层的激活值。

    1. import torch
    2. from torch import nn
    3. from d2l import torch as d2l
    4. # 定义LeNet网络
    5. net = nn.Sequential(
    6. nn.Conv2d(1, 6, kernel_size=5, padding=2),
    7. nn.Sigmoid(),
    8. nn.AvgPool2d(kernel_size=2, stride=2),
    9. nn.Conv2d(6, 16, kernel_size=5),
    10. nn.Sigmoid(),
    11. nn.AvgPool2d(kernel_size=2, stride=2),
    12. nn.Flatten(),
    13. nn.Linear(16 * 5 * 5, 120),
    14. nn.Sigmoid(),
    15. nn.Linear(120, 84),
    16. nn.Sigmoid(),
    17. nn.Linear(84, 10)
    18. )
    19. # 加载Fashion-MNIST数据集
    20. batch_size = 256
    21. train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
    22. # 获取一个样本的输入数据
    23. data = next(iter(test_iter))
    24. X = data[0][:16] # 选择前16个样本进行展示
    25. # 计算第一层和第二层的激活值
    26. activation1 = net[0](X)
    27. activation2 = net[3](net[2](net[0](X)))
    28. # 打印激活值
    29. print("第一层的激活值:", activation1.shape)
    30. print("第二层的激活值:", activation2.shape)

    上述代码将打印LeNet网络的第一层和第二层的激活值的形状。可以通过调整X的选择来查看不同样本 的激活值。这里选择了测试集中的样本作为示例输入。


    🌊4. 研究体会

    通过这次课程的实验,我深入学习了卷积神经网络,通过使用Python和MXNet深度学习框架进行实验,对CNN的工作原理和实际应用有了更加深入的理解。以下是我在实验过程中的一些心得体会。

    首先卷积层是CNN的核心组件之一,它能够有效地捕捉图像中的局部特征。在实验中,通过调整卷积核的大小和数量,探索了不同的特征提取方式。发现较小的卷积核可以捕捉到更细粒度的特征,而较大的卷积核则可以捕捉到更宏观的特征。此外,增加卷积核的数量可以提高模型的表达能力,但也会增加计算复杂度。

    其次,池化层是CNN中另一个重要的组件,它可以减小特征图的尺寸,同时保留主要特征。在实验中,我尝试了最大池化和平均池化等不同的池化方式,并观察它们对模型性能的影响。发现最大池化能够更好地保留图像中的主要特征,并在一定程度上提高了模型的鲁棒性。

    此外,我还学习了卷积神经网络中的一些关键技术,如批量归一化(Batch Normalization)和残差连接(Residual Connection)。批量归一化可以加速网络的训练过程,并提高模型的稳定性;而残差连接则可以解决深层网络中的梯度消失问题,有效提高了模型的准确性。在实验中,我应用了这些技术,并发现它们确实能够改善模型的性能。

    在实验过程中,我深刻认识到CNN模型在处理图像数据时具有出色的特征提取和表示能力。通过卷积层和池化层的组合,模型能够有效地捕捉图像的局部和全局特征,并通过堆叠多个卷积层来提取更高级的特征。同时,卷积神经网络的参数共享和局部感受野的设计赋予它良好的平移不变性和空间层次性,使其非常适合处理具有空间结构的图像数据。

    通过这次实验,我不仅加深了对CNN的理论理解,还学会了如何将理论知识应用于实际项目中。我通过编写代码、训练模型和分析结果,逐步掌握了CNN的实际操作技巧。

  • 相关阅读:
    STL之优先级队列(priority_queue)
    132.【MySQL_进阶篇】
    【数字IC设计】DC自动添加门控时钟
    C++多态详解
    sql注入基本概念
    Win11自动更新怎么永久关闭?
    QT实现动态翻译切换
    node-@hapi/joi校验前端数据
    【数据分享】1901-2022年我国省市县镇四级的逐年最低气温数据(免费获取/Shp/Excel格式)
    haas506 2.0开发教程-hota(仅支持2.2以上版本)
  • 原文地址:https://blog.csdn.net/m0_57532432/article/details/139480662