深度学习的3个主要步骤如下:

  1. 定义一个函数集F。
  2. 定义一个评价函数:其输入是F中的某个函数f(实际上是决定了函数表达式的参数),输出是f的好坏。
  3. 从F中找到一个最好的函数。

神经网络其实就是一个函数集,我们通过定义神经网络的结构,决定了函数的一般形式。神经网络的参数则决定了 函数的表达式,这些参数是计算机根据一定的规则学习的。

定义函数集

在上一节中,我们已经定义了一个简易的神经网络,其代码如下:

#神经网络
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import torch.utils.data as Data

#神经网络需要定义两个函数
#分别是构造函数,前向传播
#自定义的神经网络需要继承nn.Module
class Net(nn.Module):

    #构造函数
    def __init__(self):
        super(Net, self).__init__()
        #卷积层三个参数:in_channel, out_channels, 5*5 kernal
        self.con1 = nn.Conv2d(3, 10, 5)
        self.con2 = nn.Conv2d(10, 10, 5)
        #全连接层两个参数:in_channels, out_channels
        self.fc1 = nn.Linear(10 * 5 * 5, 10)
        self.fc2 = nn.Linear(10, 10)
        self.fc3 = nn.Linear(10, 10)

    #前向传播
    def forward(self, input):
        #卷积 --> 激活函数(Relu) --> 池化
        x = self.con1(input)
        x = F.relu(x)
        x = F.max_pool2d(x, (2, 2))

        #重复上述过程
        x = self.con2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, (2, 2))

        #展平
        x = x.view(-1, self.num_flat_features(x))

        #全连接层
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x


    #展平
    def num_flat_features(self, x):
        size = x.size()[1:]
        num_features = 1
        for i in size:
            num_features = num_features * i
        return num_features

定义评价函数

通常使用损失函数(Loss Function)来定义一个函数的好坏。损失函数的值越大,则该函数越不好。
常见的损失函数有交叉熵(常用于分类问题)、均方根误差(常用于回归问题)等。
在torch.nn中定义了常见的损失函数。

#交叉熵
criterion = nn.CrossEntropyLoss()

寻找最优函数

寻找最优函数本质是一个无约束优化问题,目标是求损失函数的最小值。
神经网络训练一维数据代码 训练一个神经网络_卷积神经网络
其中神经网络训练一维数据代码 训练一个神经网络_深度学习_02的自变量是F中的某个函数,实际上就是决定了函数具体表达形式的参数,如权重w和表差b。我们的目标就是求使得L最小的参数w和b。

最朴素的优化方法是梯度下降,常见的方法还有SGD,SGDM,Adam,Adagrad等,常见的优化函数定义在torch.optim中。他们的核心都是求导。torch为我们提供了自动求导功能,就是其特点之一。

自动求导的步骤如下:

  1. 设置优化器种类:如Adam等。
  2. 梯度清零:清楚缓存中的梯度。
  3. 前向传播:计算输出和损失函数。
  4. 向后传播:本质是链式法则
  5. 参数更新

具体训练的代码如下:

#开始训练
#初始化神经网络中的参数
net = Net()
#定义损失函数种类:交叉熵
criterion = nn.CrossEntropyLoss()
#定义优化器种类:Adam
optimizer = optim.Adam(net.parameters(), lr = 0.001)
#定义变换:转化成Tensor。必须转化成张量形式才能求导。
transform = transforms.Compose(
    [transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]
)

#用于训练的训练集和测试集
transet = torchvision.datasets.CIFAR10(root = './data', train = True, download=True, transform = transform)
testset = torchvision.datasets.CIFAR10(root = './data', train=False, download=True, transform = transform)

trainLoader = Data.DataLoader(dataset = transet, batch_size = 40, shuffle = True)
testLoader = Data.DataLoader(dataset = testset, batch_size = 40, shuffle = False)

num_peochs = 1


#开始训练:num_peochs是训练周期数
for epoch in range(num_peochs):
    correct = 0
    total = 0
    run_loss = 0.0
    for i, data in enumerate(trainLoader):
        input, label = data
        input, label = input, label
        #梯度清零
        optimizer.zero_grad()
        #前向传播:计算输出
        outputs = net(input)
        #计算损失函数
        lossValue = criterion(outputs, label)
        #反向传播
        lossValue.backward()
        #参数更新
        optimizer.step()

        run_loss += lossValue.item()

        num = 20

        if i % num == num - 1:
            print('[%d, %5d] loss : %.3f' % (epoch + 1, i + 1, run_loss / num))
            run_loss = 0

        #训练集准确率
        _, pred = outputs.max(1)
        correct += (pred == label).sum().item()
        total += label.size()[0]

    print("训练集准确率:", correct / total)

#打印训练结束标识符
print("finished training!")

完整代码

#神经网络
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import torch.utils.data as Data

#神经网络需要定义两个函数
#分别是构造函数,前向传播
#自定义的神经网络需要继承nn.Module
class Net(nn.Module):

    #构造函数
    def __init__(self):
        super(Net, self).__init__()
        #卷积层三个参数:in_channel, out_channels, 5*5 kernal
        self.con1 = nn.Conv2d(3, 10, 5)
        self.con2 = nn.Conv2d(10, 10, 5)
        #全连接层两个参数:in_channels, out_channels
        self.fc1 = nn.Linear(10 * 5 * 5, 10)
        self.fc2 = nn.Linear(10, 10)
        self.fc3 = nn.Linear(10, 10)

    #前向传播
    def forward(self, input):
        #卷积 --> 激活函数(Relu) --> 池化
        x = self.con1(input)
        x = F.relu(x)
        x = F.max_pool2d(x, (2, 2))

        #重复上述过程
        x = self.con2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, (2, 2))

        #展平
        x = x.view(-1, self.num_flat_features(x))

        #全连接层
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x


    #展平
    def num_flat_features(self, x):
        size = x.size()[1:]
        num_features = 1
        for i in size:
            num_features = num_features * i
        return num_features


#开始训练
#初始化神经网络中的参数
net = Net()
#定义损失函数种类:交叉熵
criterion = nn.CrossEntropyLoss()
#定义优化器种类:Adam
optimizer = optim.Adam(net.parameters(), lr = 0.001)
#定义变换:转化成Tensor。必须转化成张量形式才能求导。
transform = transforms.Compose(
    [transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]
)

#用于训练的训练集和测试集
transet = torchvision.datasets.CIFAR10(root = './data', train = True, download=True, transform = transform)
testset = torchvision.datasets.CIFAR10(root = './data', train=False, download=True, transform = transform)

trainLoader = Data.DataLoader(dataset = transet, batch_size = 40, shuffle = True)
testLoader = Data.DataLoader(dataset = testset, batch_size = 40, shuffle = False)

num_peochs = 1


#开始训练:num_peochs是训练周期数
for epoch in range(num_peochs):
    correct = 0
    total = 0
    run_loss = 0.0
    for i, data in enumerate(trainLoader):
        input, label = data
        input, label = input, label
        #梯度清零
        optimizer.zero_grad()
        #前向传播:计算输出
        outputs = net(input)
        #计算损失函数
        lossValue = criterion(outputs, label)
        #反向传播
        lossValue.backward()
        #参数更新
        optimizer.step()

        run_loss += lossValue.item()

        num = 20

        if i % num == num - 1:
            print('[%d, %5d] loss : %.3f' % (epoch + 1, i + 1, run_loss / num))
            run_loss = 0

        #训练集准确率
        _, pred = outputs.max(1)
        correct += (pred == label).sum().item()
        total += label.size()[0]

    print("训练集准确率:", correct / total)

#打印训练结束标识符
print("finished training!")