实验环境

系统基本配置

  • 实验进行于宿主机下的虚拟机实验环境
  • 宿主机主要硬件配置

    • CPU:QTB0(10900T ES,10C20T)
    • GPU:Tesla P4
  • 实验虚拟机硬件分配

    • CPU:16T
    • GPU:Tesla P4直通
    • RAM:8 GB
  • 实验虚拟机基础系统环境

    • CentOS 7.9.2009 GNU/Linux 3.10.0-1160.102.1.el7.x86_64
    • NVIDIA-SMI 520.61.05 Driver Version: 520.61.05 CUDA Version: 11.8
    • Python 3.9.0(conda env)

安装相关依赖包

  PyTorch安装参考官网指南

  • pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118(如此安装GPU版本PyTorch,否则无法调用GPU)
  • conda install cudatoolkit=11.8.0
  • conda install cudnn

下载数据集

  CIFAR数据集下载自CIFAR数据集说明网站

  • wget https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
  • tar -xzvf cifar-10-python.tar.gz
  • 也可通过torchvision自动下载

  CIFAR-10数据集由 10 类 60000 张 32x32 彩色图像组成,每类 6000 张图像。有 50000 张训练图像和 10000 张测试图像。数据集分为 5 个训练批次和 1 个测试批次,每个批次有 10000 张图像。测试批次正好包含从每个类中随机选择的 1000 张图像。训练批次以随机顺序包含剩余的图像,但某些训练批次可能包含来自一个类的图像多于另一个类。在它们之间,训练批次正好包含来自每个类的 5000 张图像。以下是数据集中的类,以及每个类的 10 张随机图像,这些类是完全互斥的。汽车和卡车之间没有重叠。“汽车”包括轿车、SUV等。“卡车”仅包括大型卡车。两者都不包括皮卡车:

CIFAR-10.png

图像分类Python代码

导入必要的库

  图像分类主要用到torch库和torchvision库

# 导入必要的库
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import time
import os

加载和预处理数据

  首先使用torchvision.transforms模块中的compose类完成训练集的数据转换操作:

# 加载和预处理数据
transform = transforms.Compose([  # 训练用
    transforms.RandomHorizontalFlip(),  # 以50%的概率对图像进行随机水平翻转
    transforms.RandomGrayscale(p=0.1),  # 以10%的概率将图像随机转换为灰度图像
    transforms.ToTensor(), # 将PIL图像或NumPy数组转换为PyTorch张量。
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))    # 对张量进行标准化
])

transform_test = transforms.Compose([  #测试验证用
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) 
])
  • transforms.RandomHorizontalFlip():以50%的概率对图像进行随机水平翻转。
  • transforms.RandomGrayscale(p=0.1):以10%的概率将图像随机转换为灰度图像。
  • transforms.ToTensor(): 这个转换将PIL图像或NumPy数组转换为PyTorch张量,图像的像素值将被缩放到范围 [0, 1]。
    * transforms.Normalize(mean, std): 这个转换对张量进行标准化,即将其像素值进行缩放和平移,使其均值为指定的 mean,标准差为指定的 std。在这里,我们将图像的每个通道标准化为均值为 0.5,标准差为 0.5。
  • 由于RandomHorizontalFlip()RandomGrayscale(p=0.1)通常只在训练集上使用,而在验证集和测试集上通常不使用,新建一个测试验证专用的只包含ToTensor()Normalize()transform_test

  接下来加载数据集并应用上述转换,然后创建数据加载器。数据加载器将数据集包装成可迭代对象,使我们能够方便地遍历数据集的批次:

# 训练集加载
train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=10, shuffle=True, num_workers=2)
# 测试集加载
test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=10000, shuffle=False, num_workers=2)
  • torchvision.datasets.CIFAR10:用于加载CIFAR10数据集,其中root='./data' 指定了数据集的存储目录,train=True 表示加载训练集,train=False 表示加载测试集,download=True 表示如果数据集不存在,则下载,transform=transform表示应用的转换方法。
  • torch.utils.data.DataLoader:用于创建数据加载器,batch_size=10 指定了每个批次包含的样本数。
    shuffle=True 表示在每个epoch开始时,数据加载器会打乱数据,以确保每个批次的样本是随机的。
    num_workers=2 表示使用多线程加载数据,以提高数据加载的效率。

定义神经网络模型

  定义一个简单的卷积神经网络模型用以实现CIFAR-10的图像分类:

# 定义神经网络模型
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(128 * 8 * 8, 512)
        self.fc2 = nn.Linear(512, 10)

    def forward(self, x):
        x = self.pool(torch.relu(self.conv1(x)))
        x = self.pool(torch.relu(self.conv2(x)))
        x = x.view(-1, 128 * 8 * 8)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x
  1. class SimpleCNN(nn.Module)::定义了一个继承自nn.Module的类,表示要构建一个PyTorch模型。
  2. super(SimpleCNN, self).__init__():用于调用父类(或超类)构造函数,确保在子类中可以正确地继承和初始化父类的属性。在 PyTorch 中,nn.Module 类有一些必要的初始化工作,例如为模型的参数(parameters)和子模块(submodules)创建容器等。通过调用 super(SimpleCNN, self).__init__(),可以确保这些初始化工作得以执行。
  3. __init__(self):: 模型的构造函数,定义了模型的各个层次和参数。

    • self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1): 第一个卷积层,输入通道数为3(对应RGB图像),输出通道数为64,卷积核大小为3x3,padding为1。
    • self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1): 第二个卷积层,输入通道数为64,输出通道数为128,卷积核大小为3x3,padding为1。
    • self.pool = nn.MaxPool2d(kernel_size=2, stride=2): 最大池化层,池化核大小为2x2,步幅为2。
    • self.fc1 = nn.Linear(128 * 8 * 8, 512): 第一个全连接层,输入大小为128 8 8,输出大小为512。
    • self.fc2 = nn.Linear(512, 10): 第二个全连接层,输入大小为512,输出大小为类别数(对应CIFAR-10有10个类别)。
  4. def forward(self, x):: 定义了前向传播函数,描述了数据在模型中的流动过程。

    • x = self.pool(torch.relu(self.conv1(x))): 第一层卷积,应用ReLU激活函数,然后进行最大池化。
    • x = self.pool(torch.relu(self.conv2(x))): 第二层卷积,同样应用ReLU激活函数,然后再次进行最大池化。
    • x = x.view(-1, 128 * 8 * 8): 将特征图展平,准备传递给全连接层。
    • x = torch.relu(self.fc1(x)): 第一个全连接层,应用ReLU激活函数。
    • x = self.fc2(x): 第二个全连接层,最终输出模型的预测结果。

附. ReLU激活函数

ReLU(Rectified Linear Unit)是一种常用的激活函数,被广泛用于深度学习模型中。ReLU函数的定义如下:

$$ \text{ReLU}(x) = \max(0, x) $$

即,对于输入x,ReLU 返回x和0中的较大值。图形化表示就是在x大于零时,输出为x,在x小于等于零时,输出为零。

ReLU激活函数的主要特点和优势包括:

  1. 非线性: ReLU引入了非线性因素,使得神经网络可以更好地拟合复杂的数据。
  2. 计算简单: 相比一些复杂的激活函数,如 sigmoid 或 tanh,ReLU的计算非常简单,只需判断输入是否大于零。
  3. 缓解梯度消失问题: 在反向传播过程中,一些传统的激活函数可能会导致梯度消失的问题,而ReLU的导数在输入大于零时为1,从而缓解了梯度消失的情况。
  4. 稀疏激活性: ReLU在正区域上的输出是输入本身,因此对于激活的神经元,输出是非零的,具有一定的稀疏性,有助于模型的泛化和表示能力。

然而,ReLU也存在一些问题,主要是:

  1. 神经元死亡: 当输入为负数时,ReLU的输出为零,这可能导致一些神经元在训练过程中永远不会被激活,称为神经元死亡问题。
  2. 不适用于所有情况: 对于某些场景,如图像生成任务,有时 Leaky ReLU、Parametric ReLU 或 Exponential Linear Unit (ELU) 等激活函数可能更适合。

在实践中,ReLU是一个常用的默认选择,但根据具体的任务和数据,可以尝试其他激活函数以优化模型性能。

定义损失函数和优化器

  完成模型训练还需要定义损失函数和优化器:

# 定义损失函数和优化器
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
net = SimpleCNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
  1. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu"): 这一行代码用于检查是否有可用的CUDA(GPU)。如果有,将 device 设置为GPU,否则设置为CPU。torch.device 是一个表示设备的对象,它用于将模型和数据移动到指定的设备上。
  2. net = SimpleCNN().to(device): 创建了一个 SimpleCNN 类的实例,并将其移动到之前定义的设备上。这是为了确保模型在训练时使用的是正确的设备。
  3. criterion = nn.CrossEntropyLoss(): 定义了交叉熵损失函数。对于多类别分类问题(如CIFAR-10,有10个类别),交叉熵损失是一个常见的选择。它对模型输出的概率分布与真实标签之间的差异进行惩罚。
  4. optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9): 定义了随机梯度下降(SGD)优化器。net.parameters() 提供了模型中所有可学习参数的迭代器,这些参数将在训练过程中进行更新。lr=0.001 设置学习率,而 momentum=0.9 则是动量项,有助于加速优化过程并避免陷入局部最小值。

在训练过程中,我们将使用 criterion 来计算模型输出与真实标签之间的损失,并使用 optimizer 来更新模型参数,以减小损失。这是训练深度学习模型的标准步骤。

训练模型

  完成上述准备工作后便可以开始编写训练模型的代码:

# 训练模型
num_epochs = 20
for epoch in range(num_epochs):
    timestart = time.time()
    running_loss = 0.0
    correct = 0
    total = 0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data[0].to(device), data[1].to(device)

        optimizer.zero_grad()  # 梯度清零

        outputs = net(inputs)  # 前向传播

        loss = criterion(outputs, labels)  # 计算损失

        loss.backward()  # 反向传播

        optimizer.step()  # 更新参数

        running_loss += loss.item()
        
        _, predicted = torch.max(outputs.data, 1)  # 获取预测结果
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

        if i % 1000 == 999:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 1000))
            running_loss = 0.0
            print('Accuracy on the train images: %d %%' % (100 * correct / total))
            correct = 0
            total = 0
    print('epoch %d cost %3f sec' %(epoch,time.time()-timestart))
print('Finished Training')

  详细解释:

  1. num_epochs = 5: 设置训练的总epoch数,表示整个训练数据集将被模型遍历的次数。
  2. for epoch in range(num_epochs):: 外层循环迭代每个epoch。在每个epoch内,整个训练数据集将被模型遍历一次。
  3. timestart = time.time():初始化跟踪训练时间的变量;running_loss = 0.0: 初始化用于跟踪每个epoch的累计损失的变量;correct = 0total = 0:初始化计算误差的变量
  4. for i, data in enumerate(train_loader, 0):: 内层循环遍历训练数据加载器,其中 enumerate 提供了数据批次的索引(i)和数据本身(data)。
  5. inputs, labels = data[0].to(device), data[1].to(device): 将输入数据和标签移动到之前定义的设备上(GPU或CPU)。
  6. optimizer.zero_grad(): 在每个批次开始时,将优化器中的梯度清零,以防止梯度累积。
  7. outputs = net(inputs): 执行前向传播,计算模型的输出。
  8. loss = criterion(outputs, labels): 使用之前定义的交叉熵损失函数计算模型输出与真实标签之间的损失。
  9. loss.backward(): 执行反向传播,计算损失对模型参数的梯度。
  10. optimizer.step(): 根据计算得到的梯度更新模型参数,执行优化步骤。
  11. running_loss += loss.item(): 累加每个batch的损失,用于后续打印训练进度。_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item():获取当前模型预测情况,
  12. if i % 1000 == 999:: 每1000个batch打印一次当前损失,以监控训练进度。此处1000*batch数=每批次数据量
  13. print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 1000)): 打印当前epoch、iteration和batch的平均损失。print('Accuracy on the train images: %d %%' % (100 * correct / total)):查看当前模型正确率
  14. running_loss = 0.0: 重置累计损失,准备下一个1000个batch的损失计算。correct = 0total = 0:重置正确率。
  15. print('epoch %d cost %3f sec' %(epoch,time.time()-timestart)):完成每次epoch的训练后,打印训练耗时。
  16. print('Finished Training'): 完成所有epoch的训练后,打印训练结束的消息。

在这个循环过程中,模型通过多次迭代训练数据集,不断地更新参数以减小损失。整个过程中,使用了梯度下降优化器(SGD)和交叉熵损失函数来推动模型学习。

评估模型

训练好的模型需要进行评估以查看训练成效:

# 评估模型
correct = 0
total = 0
with torch.no_grad():  # 在评估阶段不需要计算梯度
    for data in test_loader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = net(images)  # 前向传播
        _, predicted = torch.max(outputs.data, 1)  # 获取预测结果
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy on the test images: %d %%' % (100 * correct / total))

以下是每个步骤的详细解释:

  1. correct = 0total = 0: 初始化两个变量,用于跟踪正确分类的样本数和总样本数。
  2. with torch.no_grad():: 进入一个 torch.no_grad() 上下文管理器,表示在此范围内的操作不会计算梯度。在评估阶段,我们通常不需要计算梯度,因为我们只是对模型进行前向传播,而不进行参数更新。
  3. for data in test_loader:: 遍历测试数据加载器中的所有测试样本。
  4. images, labels = data[0].to(device), data[1].to(device): 将测试样本的输入图像和标签移动到之前定义的设备上。
  5. outputs = net(images): 执行前向传播,获取模型对测试样本的预测输出。
  6. _, predicted = torch.max(outputs.data, 1): 通过 torch.max 函数获取每个样本输出的最大值及其索引,即模型预测的类别。
  7. total += labels.size(0): 累加总样本数。
  8. correct += (predicted == labels).sum().item(): 累加正确分类的样本数。通过比较模型预测的类别和真实标签,可以判断哪些样本被正确分类。
  9. print('Accuracy on the test images: %d %%' % (100 * correct / total)): 计算并打印模型在测试集上的准确度。准确度计算为正确分类的样本数除以总样本数,然后乘以100以得到百分比。

在评估阶段,主要关注模型在测试集上的准确度,以了解模型在未见过的数据上的性能表现。

代码汇总

# 导入必要的库
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import time
import os

# 加载和预处理数据
transform = transforms.Compose([  # 训练用
    transforms.RandomHorizontalFlip(),  # 以50%的概率对图像进行随机水平翻转
    transforms.RandomGrayscale(p=0.1),  # 以10%的概率将图像随机转换为灰度图像
    transforms.ToTensor(), # 将PIL图像或NumPy数组转换为PyTorch张量。
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))    # 对张量进行标准化
])

transform_test = transforms.Compose([  #测试验证用
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) 
])

# 训练集加载
train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=10, shuffle=True, num_workers=2)
# 测试集加载
test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=10000, shuffle=False, num_workers=2)


# 定义神经网络模型
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(128 * 8 * 8, 512)
        self.fc2 = nn.Linear(512, 10)

    def forward(self, x):
        x = self.pool(torch.relu(self.conv1(x)))
        x = self.pool(torch.relu(self.conv2(x)))
        x = x.view(-1, 128 * 8 * 8)
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

# 定义损失函数和优化器
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
net = SimpleCNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

# 训练模型
num_epochs = 20
for epoch in range(num_epochs):
    timestart = time.time()
    running_loss = 0.0
    correct = 0
    total = 0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data[0].to(device), data[1].to(device)

        optimizer.zero_grad()  # 梯度清零

        outputs = net(inputs)  # 前向传播

        loss = criterion(outputs, labels)  # 计算损失

        loss.backward()  # 反向传播

        optimizer.step()  # 更新参数

        running_loss += loss.item()
        
        _, predicted = torch.max(outputs.data, 1)  # 获取预测结果
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

        if i % 1000 == 999:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 1000))
            running_loss = 0.0
            print('Accuracy on the train images: %d %%' % (100 * correct / total))
            correct = 0
            total = 0
    print('epoch %d cost %3f sec' %(epoch,time.time()-timestart))
print('Finished Training')

# 评估模型
correct = 0
total = 0
with torch.no_grad():  # 在评估阶段不需要计算梯度
    for data in test_loader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = net(images)  # 前向传播
        _, predicted = torch.max(outputs.data, 1)  # 获取预测结果
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy on the test images: %d %%' % (100 * correct / total))

代码执行

  代码由slurm提交执行,slurm脚本如下:

#!/bin/bash
#SBATCH -J CIFAR10
#SBATCH -p C79T-P4
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=2

cd $SLURM_SUBMIT_DIR
python CIFAR10.py

  调整epoch数和batch_size数及对应的运行监控参数,发现epoch=20、batch_size=10时训练效率最佳,其运行输出日志如下:

Files already downloaded and verified
Files already downloaded and verified
[1,  1000] loss: 1.983
Accuracy on the train images: 28 %
[1,  2000] loss: 1.633
Accuracy on the train images: 40 %
[1,  3000] loss: 1.460
Accuracy on the train images: 47 %
[1,  4000] loss: 1.359
Accuracy on the train images: 51 %
[1,  5000] loss: 1.300
Accuracy on the train images: 53 %
epoch 0 cost 28.178991 sec
[2,  1000] loss: 1.215
Accuracy on the train images: 56 %
[2,  2000] loss: 1.181
Accuracy on the train images: 58 %
[2,  3000] loss: 1.133
Accuracy on the train images: 60 %
[2,  4000] loss: 1.075
Accuracy on the train images: 61 %
[2,  5000] loss: 1.028
Accuracy on the train images: 63 %
epoch 1 cost 26.351369 sec
[3,  1000] loss: 0.978
Accuracy on the train images: 65 %
[3,  2000] loss: 0.956
Accuracy on the train images: 66 %
[3,  3000] loss: 0.931
Accuracy on the train images: 67 %
[3,  4000] loss: 0.909
Accuracy on the train images: 68 %
[3,  5000] loss: 0.896
Accuracy on the train images: 68 %
epoch 2 cost 26.919209 sec
[4,  1000] loss: 0.829
Accuracy on the train images: 70 %
[4,  2000] loss: 0.828
Accuracy on the train images: 71 %
[4,  3000] loss: 0.816
Accuracy on the train images: 71 %
[4,  4000] loss: 0.807
Accuracy on the train images: 71 %
[4,  5000] loss: 0.800
Accuracy on the train images: 72 %
epoch 3 cost 26.236697 sec
[5,  1000] loss: 0.713
Accuracy on the train images: 75 %
[5,  2000] loss: 0.732
Accuracy on the train images: 74 %
[5,  3000] loss: 0.728
Accuracy on the train images: 74 %
[5,  4000] loss: 0.714
Accuracy on the train images: 75 %
[5,  5000] loss: 0.705
Accuracy on the train images: 75 %
epoch 4 cost 27.205158 sec
[6,  1000] loss: 0.660
Accuracy on the train images: 77 %
[6,  2000] loss: 0.648
Accuracy on the train images: 77 %
[6,  3000] loss: 0.631
Accuracy on the train images: 78 %
[6,  4000] loss: 0.611
Accuracy on the train images: 78 %
[6,  5000] loss: 0.631
Accuracy on the train images: 78 %
epoch 5 cost 26.969712 sec
[7,  1000] loss: 0.557
Accuracy on the train images: 80 %
[7,  2000] loss: 0.554
Accuracy on the train images: 80 %
[7,  3000] loss: 0.550
Accuracy on the train images: 80 %
[7,  4000] loss: 0.582
Accuracy on the train images: 79 %
[7,  5000] loss: 0.569
Accuracy on the train images: 80 %
epoch 6 cost 27.100053 sec
[8,  1000] loss: 0.487
Accuracy on the train images: 83 %
[8,  2000] loss: 0.482
Accuracy on the train images: 83 %
[8,  3000] loss: 0.478
Accuracy on the train images: 83 %
[8,  4000] loss: 0.503
Accuracy on the train images: 82 %
[8,  5000] loss: 0.518
Accuracy on the train images: 82 %
epoch 7 cost 27.739774 sec
[9,  1000] loss: 0.412
Accuracy on the train images: 86 %
[9,  2000] loss: 0.426
Accuracy on the train images: 85 %
[9,  3000] loss: 0.432
Accuracy on the train images: 85 %
[9,  4000] loss: 0.447
Accuracy on the train images: 83 %
[9,  5000] loss: 0.440
Accuracy on the train images: 84 %
epoch 8 cost 26.864728 sec
[10,  1000] loss: 0.342
Accuracy on the train images: 88 %
[10,  2000] loss: 0.369
Accuracy on the train images: 87 %
[10,  3000] loss: 0.371
Accuracy on the train images: 87 %
[10,  4000] loss: 0.375
Accuracy on the train images: 87 %
[10,  5000] loss: 0.384
Accuracy on the train images: 87 %
epoch 9 cost 27.668614 sec
[11,  1000] loss: 0.300
Accuracy on the train images: 89 %
[11,  2000] loss: 0.306
Accuracy on the train images: 89 %
[11,  3000] loss: 0.310
Accuracy on the train images: 89 %
[11,  4000] loss: 0.325
Accuracy on the train images: 89 %
[11,  5000] loss: 0.336
Accuracy on the train images: 88 %
epoch 10 cost 26.508494 sec
[12,  1000] loss: 0.250
Accuracy on the train images: 91 %
[12,  2000] loss: 0.259
Accuracy on the train images: 91 %
[12,  3000] loss: 0.277
Accuracy on the train images: 91 %
[12,  4000] loss: 0.272
Accuracy on the train images: 90 %
[12,  5000] loss: 0.289
Accuracy on the train images: 90 %
epoch 11 cost 27.607921 sec
[13,  1000] loss: 0.210
Accuracy on the train images: 93 %
[13,  2000] loss: 0.218
Accuracy on the train images: 92 %
[13,  3000] loss: 0.225
Accuracy on the train images: 92 %
[13,  4000] loss: 0.234
Accuracy on the train images: 92 %
[13,  5000] loss: 0.228
Accuracy on the train images: 92 %
epoch 12 cost 26.941943 sec
[14,  1000] loss: 0.169
Accuracy on the train images: 94 %
[14,  2000] loss: 0.188
Accuracy on the train images: 93 %
[14,  3000] loss: 0.188
Accuracy on the train images: 94 %
[14,  4000] loss: 0.191
Accuracy on the train images: 93 %
[14,  5000] loss: 0.188
Accuracy on the train images: 93 %
epoch 13 cost 26.939472 sec
[15,  1000] loss: 0.148
Accuracy on the train images: 95 %
[15,  2000] loss: 0.153
Accuracy on the train images: 94 %
[15,  3000] loss: 0.152
Accuracy on the train images: 94 %
[15,  4000] loss: 0.169
Accuracy on the train images: 94 %
[15,  5000] loss: 0.151
Accuracy on the train images: 94 %
epoch 14 cost 27.116099 sec
[16,  1000] loss: 0.109
Accuracy on the train images: 96 %
[16,  2000] loss: 0.129
Accuracy on the train images: 96 %
[16,  3000] loss: 0.121
Accuracy on the train images: 96 %
[16,  4000] loss: 0.131
Accuracy on the train images: 95 %
[16,  5000] loss: 0.139
Accuracy on the train images: 95 %
epoch 15 cost 26.486545 sec
[17,  1000] loss: 0.091
Accuracy on the train images: 97 %
[17,  2000] loss: 0.107
Accuracy on the train images: 96 %
[17,  3000] loss: 0.111
Accuracy on the train images: 96 %
[17,  4000] loss: 0.122
Accuracy on the train images: 96 %
[17,  5000] loss: 0.122
Accuracy on the train images: 96 %
epoch 16 cost 26.817941 sec
[18,  1000] loss: 0.083
Accuracy on the train images: 97 %
[18,  2000] loss: 0.091
Accuracy on the train images: 97 %
[18,  3000] loss: 0.090
Accuracy on the train images: 97 %
[18,  4000] loss: 0.098
Accuracy on the train images: 96 %
[18,  5000] loss: 0.096
Accuracy on the train images: 96 %
epoch 17 cost 26.632846 sec
[19,  1000] loss: 0.078
Accuracy on the train images: 97 %
[19,  2000] loss: 0.065
Accuracy on the train images: 98 %
[19,  3000] loss: 0.073
Accuracy on the train images: 97 %
[19,  4000] loss: 0.081
Accuracy on the train images: 97 %
[19,  5000] loss: 0.086
Accuracy on the train images: 97 %
epoch 18 cost 27.076205 sec
[20,  1000] loss: 0.061
Accuracy on the train images: 98 %
[20,  2000] loss: 0.057
Accuracy on the train images: 98 %
[20,  3000] loss: 0.070
Accuracy on the train images: 97 %
[20,  4000] loss: 0.071
Accuracy on the train images: 97 %
[20,  5000] loss: 0.075
Accuracy on the train images: 97 %
epoch 19 cost 25.807146 sec
Finished Training
Accuracy on the test images: 78 %

  可以看到在训练末期已到极限,出现少量过拟合。

文章目录