1
    1
    1
    1

    1. import torch
    2. import torch.nn as nn
    3. import torch.nn.functional as F
    4. import torch.optim as optim
    5. class Net(nn.Module):
    6. def __init__(self):
    7. super(Net, self).__init__()
    8. # 输入图像channel: 1; 输出channel: 6; 5*5卷积核 # 计算公式 W - d + 1
    9. self.conv1 = nn.Conv2d(1, 6, 5) # Conv2d 接收4个参数, (batch_size, channel, height, width)
    10. self.conv2 = nn.Conv2d(6, 16, 5)
    11. # 线性映射关系: y = Wx + b
    12. self.fc1 = nn.Linear(16*5*5, 120)
    13. self.fc2 = nn.Linear(120, 84)
    14. self.fc3 = nn.Linear(84, 10)
    15. # backward 函数在使用 autograd 时自动定义
    16. def forward(self, x):
    17. # 2*2 pooling
    18. x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # pool 的默认 stride 为池化矩阵的宽度 # 32 -> 28 -> 14
    19. # pool方阵可以用一个数指定大小
    20. x = F.max_pool2d(F.relu(self.conv2(x)), 2) # 14 -> 10 -> 5, 16*5*5
    21. x = x.view(-1, self.num_flat_features(x)) # 计算了x的维数之后, 展开成一维的
    22. x = F.relu(self.fc1(x))
    23. x = F.relu(self.fc2(x))
    24. x = self.fc3(x)
    25. return x
    26. def num_flat_features(self, x):
    27. size = x.size()[1:] # 出去批处理维度的其他所有维度
    28. num_features = 1
    29. for s in size:
    30. num_features *= s
    31. return num_features
    32. net = Net()
    33. params = list(net.parameters()) # len(params) = 10
    34. input = torch.randn(1, 1, 32, 32)
    35. out = net(input)
    36. '''
    37. 损失函数
    38. '''
    39. target = torch.randn(10)
    40. target = target.view(1, -1) # 使目标值与数据值尺寸一致
    41. criterion = nn.MSELoss()
    42. loss = criterion(out, target)
    43. '''
    44. 反向传播
    45. '''
    46. # print("conv1.bias.grad before zero\n", net.conv1.bias.grad) # None
    47. net.zero_grad() # 清除所有参数的梯度缓存。
    48. # print("conv1.bias.grad before backward\n", net.conv1.bias.grad) # None
    49. loss.backward() # 随机梯度的反向传播
    50. # print("conv1.bias.grad after backward\n", net.conv1.bias.grad) # Tensor 1*6
    51. '''
    52. 反向传播过程
    53. input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
    54. -> view -> linear -> relu -> linear -> relu -> linear
    55. -> MSELoss
    56. -> loss
    57. '''
    58. '''
    59. 更新权重
    60. weight = weight - learning_rate * gradient
    61. '''
    62. learning_rate = 0.01
    63. optimizer = optim.SGD(net.parameters(), lr=learning_rate)
    64. optimizer.zero_grad()
    65. optimizer.step() # 更新参数
    66. # print("after update conv1's .weight---\n", params[0]) # 没变

    过程框架:
    导入数据集 —>> 编写模型 —>> 定义损失函数、优化函数 —>> 进行训练,得到损失值,进行优化,更新参数,再训练 —>> 测试 (每个epoch 训练一次、测试一次??)

    1. import torch
    2. import torch.nn as nn
    3. import torch.nn.functional as F
    4. import torch.optim as optim
    5. import torchvision
    6. import torchvision.transforms as transforms
    7. import matplotlib.pyplot as plt
    8. import numpy as np
    9. transform = transforms.Compose(
    10. [transforms.ToTensor(),
    11. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) # 均值, 标准差。使图像在(-1, 1)范围内归一化
    12. trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=False, transform=transform)
    13. trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=0)
    14. testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transform)
    15. testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=0)
    16. classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    17. def imshow(img):
    18. img = img / 2 + 0.5
    19. npimg = img.numpy()
    20. plt.imshow(np.transpose(npimg, (1, 2, 0)))
    21. plt.show()
    22. class Net(nn.Module):
    23. def __init__(self):
    24. super(Net, self).__init__()
    25. self.conv1 = nn.Conv2d(3, 6, 5)
    26. self.pool = nn.MaxPool2d(2, 2)
    27. self.conv2 = nn.Conv2d(6, 16, 5)
    28. self.fc1 = nn.Linear(16*5*5, 120)
    29. self.fc2 = nn.Linear(120, 84)
    30. self.fc3 = nn.Linear(84, 10)
    31. def forward(self, x):
    32. x = self.pool(F.relu(self.conv1(x)))
    33. x = self.pool(F.relu(self.conv2(x)))
    34. x = x.view(-1, 16*5*5)
    35. x = F.relu(self.fc1(x))
    36. x = F.relu(self.fc2(x))
    37. x = self.fc3(x)
    38. return x
    39. net = Net()
    40. criterion = nn.CrossEntropyLoss()
    41. optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) # momentum ?
    42. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    43. net.to(device)
    44. def train():
    45. for epoch in range(4):
    46. running_loss = 0.0
    47. for i, data in enumerate(trainloader, 0):
    48. inputs, labels = data
    49. inputs, labels = inputs.to(device), labels.to(device)
    50. optimizer.zero_grad() # 将参数的梯度清零。
    51. # 因为训练的过程通常使用mini-batch方法,所以如果不将梯度清零的话,梯度会与上一个batch的数据相关
    52. # 前向传播 + 反向传播 + 优化
    53. outputs = net(inputs)
    54. loss = criterion(outputs, labels)
    55. loss.backward() # 通过 autograd 包,自动运算 tensor 的梯度
    56. optimizer.step() # 得到前一步的梯度,再通过梯度下降 更新参数(step() 执行一次优化步骤)
    57. running_loss += loss.item()
    58. if i % 2000 == 1999:
    59. print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))
    60. running_loss = 0.0
    61. correct = 0
    62. total = 0
    63. # 不用梯度来更新参数,提高运算性能
    64. with torch.no_grad():
    65. for data in testloader:
    66. # images.size() = [4, 3, 32, 32]; labels.size() = [4]
    67. images, labels = data
    68. images, labels = images.to(device), labels.to(device)
    69. outputs = net(images)
    70. # outputs.data 是一个4*10的tensor
    71. _, predicted = torch.max(outputs.data, 1) # 获得最大值的(具体值, 下标)
    72. total += labels.size(0)
    73. # predicted 和 labels 为什么是一个四维向量? <= batch_size = 4
    74. # predicted == labels 为 tensor([ True, True, False, False], device='cuda:0')等
    75. correct += (predicted == labels).sum().item() # .sum() 计算出为真的个数
    76. print("Accuracy of the network on the 10000 test images: %d %%" % (100 * correct / total))
    77. print("Finished training")
    78. if __name__ == '__main__':
    79. train()