(10) PyTorch deep learning: convolutional neural network (simple residual convolutional neural network)

1. Sometimes data training is performed in a convolutional neural network, and the more and more complex the neural network layer, the better the performance, which may be due to overfitting. Gradient disappearance is also an important reason. When the chain rule multiplies a series of gradients (if gradient <1), the gradient will tend to 0, and the weights will not be effectively updated (Plain net as shown in the figure below). In order to solve this problem, the residual network appeared, and the following simple residual network (Residual net) structure:

insert image description here

In the above figure, the residual network (Residual net) has one more jump connection than the pure connection network (Plain net). When finding the gradient, Plain net: d[H(x)] / dx; Residual net: d[H(x)] / dx = d[F(x)] / dx + 1. Therefore, if d[F(x)] / x is very less than 1, but the total gradient is 1 more, multiplying several times can solve the problem of gradient disappearance.

Build a simple convolutional residual neural network:

insert image description here

Code for a simple residual neural network:

insert image description here

Construct a residual network:

insert image description here

The complete code for constructing the residual network:

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),      # 将PIL格式图像转换成Tensor矩阵向量(维度28x28转换成1x28x28,1:为RGB通道)【 [0...255]--->[0,1]
    transforms.Normalize((0.1307, ), (0.3081, ))   # 均一化处理(均值、标准差)
])
# 训练集数据
train_dataset = datasets.MNIST(root='../dataset/mnist/',
                               train=True,
                               download=True,
                               transform=transform)
# 加载训练集数据
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)
# 测试集数据集
test_dataset = datasets.MNIST(root='../dataset/mnist/',
                              train=False,
                              download=True,
                              transform=transform)
# 加载测试集数据集
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)

class ResidualBlock(torch.nn.Module):
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.channels = channels
        self.conv1 = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.conv2 = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1)

    def forward(self, x):
        y = F.relu(self.conv1(x))
        y = self.conv2(y)
        return F.relu(x+y)

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 16, kernel_size=5)
        self.conv2 = torch.nn.Conv2d(16, 32, kernel_size=5)
        self.mp = torch.nn.MaxPool2d(2)

        self.rblock1 = ResidualBlock(16)
        self.rblock2 = ResidualBlock(32)

        self.fc = torch.nn.Linear(512, 10)


    def forward(self, x):
        in_size = x.size(0)
        x = self.mp(F.relu(self.conv1(x)))
        x = self.rblock1(x)
        x = self.mp(F.relu(self.conv2(x)))
        x = self.rblock2(x)
        x = x.view(in_size, -1)
        x = self.fc(x)
        return x


model = Net()

# 将模型放到GPU上运行,需要加如下两行代码(训练集、测试集中的输入值、实际值也需要加载到GPU上)
# device = torch.device("cude:0" if torch.cuda.is_available() else "cpu")
# model.to(device)

###################3 构建损失函数、优化器###############################
criterion = torch.nn.CrossEntropyLoss()          # 交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)   # 参数优化

#####################4 循环训练 #########################
def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        # 准备数据(input:输入,target:实际值)
        inputs, target = data
        # 将输入、实际值加载到GPU
        # inputs, target = inputs.to(device), target.to(device)
        # 梯度清0
        optimizer.zero_grad()
        # 前向传播
        outputs = model(inputs)
        # 交叉熵损失函数计算
        loss = criterion(outputs, target)
        # 反向传播
        loss.backward()
        # 参数优化
        optimizer.step()
        # 累计loss
        running_loss += loss.item()
        # 数据集一共有batch_idx个数据,每隔300个打印一次平均损失函数值
        if batch_idx % 300 ==299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0

def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            # 将输入、实际值加载到GPU
            # inputs, target = inputs.to(device), target.to(device)
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
        print('Accuracy on test set: %d %%' % (100 * correct / total))

if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

operation result:

insert image description here

Guess you like

Origin blog.csdn.net/K_AAbb/article/details/125843958