目录
一、数据加载
二、数据集类构建
三、模型构建
四、模型训练
五、模型评价及预测
附完整可运行代码:
实验大体步骤:
注:
在自己电脑的CPU跑代码×
连接远程服务器跑代码√
本次实验由于数据量巨大,我的笔记本上还没有GPU,跑代码一直跑不出来,一直停在如下这个位置不动:
于是我想到了连接远程服务器来跑代码。
如果你的电脑上有GPU,那么可以参考学长的博客跑:学长本次实验的博客
我这里使用的是AutoDL算力云,租个3080的服务器,跑个七八分钟就能出来,而且租一小时才1块多!安利!
我在这里也附上如何使用远程服务器的方法
进入AutoDL官网后,点击算力市场:
随便租个就可以
基础镜像这边选个Pytorch的某个版本就行
接下来就跟着这个视频做吧:Pycharm连接远程GPU服务器跑深度学习_哔哩哔哩_bilibili
有几点需要注意的地方:
1.pycharm必须是专业版,社区版没有连接远程服务器的功能。pycharm专业版参考这个链接:Pycharm专业版
2.连接成功之后,可能会遇到一些安装包安装不上的问题,比如我在import torch的这里一直报错,显示安装错误,多安装几次就好了,安装的时候尽量不要连hbu的校园网,不是很稳定,容易下载出错。
3.在自己笔记本就能运行,也没有报错,为什么连接个远程服务器会出现size不匹配的错误?还有numpy也会出错?
第一个问题,这个错误是因为模型中的输入和权重在不同的设备上进行计算,导致了类型不匹配。我的模型使用了GPU(torch.cuda.FloatTensor),而输入数据却是CPU上的张量(torch.FloatTensor)。PyTorch要求输入和模型的权重在相同的设备上,才能进行有效的计算。所以,需要时时刻刻确保输入数据和模型在同一个设备上。
于是要多处添加如下的代码:
第二个问题,出现在 nndl_3.py 文件中的 self.metric.update(logits, y) 这一行,具体是因为尝试将一个在 GPU 上的 tensor 转换为 NumPy 数组。由于 NumPy 不支持在 GPU 上的 tensor,所以必须先将其移动到 CPU 上。代码改成如下:
一、数据加载
本实验的数据集使用计算机视觉领域的经典数据集:CIFAR-10数据集,数据集下载位置:数据集下载
代码如下:
def load_cifar10_batch(folder_path, batch_id=1, mode='train'):
if mode == 'test':
file_path = os.path.join(folder_path, 'test_batch')
else:
file_path = os.path.join(folder_path, 'data_batch_' + str(batch_id))
# 加载数据集文件
with open(file_path, 'rb') as batch_file:
batch = pickle.load(batch_file, encoding='latin1')
imgs = batch['data'].reshape((len(batch['data']), 3, 32, 32)) / 255.
labels = batch['labels']
return np.array(imgs, dtype='float32'), np.array(labels)
imgs_batch, labels_batch = load_cifar10_batch(folder_path=r'cifar-10-batches-py',
batch_id=1, mode='train')
# 打印一下每个batch中X和y的维度
print("batch of imgs shape: ", imgs_batch.shape, "batch of labels shape: ", labels_batch.shape)
print(torch.__version__)
print(torch.cuda.is_available())
# ==========可视化观察其中的一张样本图像和对应的标签=================================
import matplotlib.pyplot as plt
image, label = imgs_batch[1], labels_batch[1]
print("The label in the picture is {}".format(label))
plt.figure(figsize=(2, 2))
plt.imshow(image.transpose(1, 2, 0))
plt.show()
运行结果:
二、数据集类构建
代码如下:
# =====构建Dataset类======================================================
import torch
from torch.utils.data import Dataset, DataLoader
import torchvision.transforms as transforms
class CIFAR10Dataset(Dataset):
def __init__(self, folder_path=r'cifar-10-batches-py', mode='train', device=None):
if mode == 'train':
self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=1, mode='train')
for i in range(2, 5):
imgs_batch, labels_batch = load_cifar10_batch(folder_path=folder_path, batch_id=i, mode='train')
self.imgs, self.labels = np.concatenate([self.imgs, imgs_batch]), np.concatenate(
[self.labels, labels_batch])
elif mode == 'dev':
self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=5, mode='dev')
elif mode == 'test':
self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, mode='test')
self.transforms = transforms.Compose([transforms.Resize(32), transforms.ToTensor(),
transforms.Normalize(mean=[0.4914, 0.4822, 0.4465],
std=[0.2023, 0.1994, 0.2010])])
self.device = device # 保存设备信息
def __getitem__(self, idx):
img, label = self.imgs[idx], self.labels[idx]
img, label = torch.tensor(img).float(), torch.tensor(label).long() # 转为Tensor
if self.device:
img, label = img.to(self.device), label.to(self.device) # 将数据传输到目标设备
return img, label
def __len__(self):
return len(self.imgs)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
# 创建数据集时传递设备信息
train_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='train', device=device)
dev_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='dev', device=device)
test_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='test', device=device)
三、模型构建
使用PyTorch API中的Resnet18进行图像分类实验。
代码如下:
# =======模型构建========================================
from torchvision.models import resnet18
time1 = time.time()
resnet18_model = resnet18(pretrained=True)
四、模型训练
代码如下:
# =======模型训练================================================
import torch.nn.functional as F
import torch.optim as opt
from nndl_3 import RunnerV3, Accuracy
# 学习率大小
lr = 0.001
# 批次大小
batch_size = 64
# 加载数据
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
dev_loader = DataLoader(dev_dataset, batch_size=batch_size)
test_loader = DataLoader(test_dataset, batch_size=batch_size)
# 定义网络
model = resnet18_model.to(device)
# 定义优化器,这里使用Adam优化器以及l2正则化策略,相关内容在7.3.3.2和7.6.2中会进行详细介绍
optimizer = opt.Adam(lr=lr, params=model.parameters(), weight_decay=0.005)
# 定义损失函数
loss_fn = F.cross_entropy
loss_fn = loss_fn
# 定义评价指标
metric = Accuracy(is_logist=True)
# 在训练和评估时,将数据传输到设备上
for data, labels in train_loader:
data, labels = data.to(device), labels.to(device) # 将数据和标签都发送到相同的设备
logits = model(data) # 进行前向传播
loss = loss_fn(logits, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 实例化RunnerV3
runner = RunnerV3(model, optimizer, loss_fn, metric)
# 启动训练
log_steps = 3000
eval_steps = 3000
runner.train(train_loader, dev_loader, num_epochs=30, log_steps=log_steps,
eval_steps=eval_steps, save_path="best_model.pdparams")
from nndl_3 import plot
plot(runner, fig_name='cnn-loss4.pdf')
运行结果:
五、模型评价及预测
代码如下:
# ========模型评价============================================
# 加载最优模型
runner.load_model('best_model.pdparams')
# 模型评价
score, loss = runner.evaluate(test_loader)
print("[Test] accuracy/loss: {:.4f}/{:.4f}".format(score, loss))
# ==========模型预测================================================
import matplotlib.pyplot as plt
# 获取测试集中的一个batch的数据
X, label = next(iter(test_loader))
X = X.to(device)
logits = runner.predict(X, dim=1)
# 多分类,使用softmax计算预测概率
pred = F.softmax(logits)
# print(pred)
# 获取概率最大的类别
pred_class = torch.argmax(pred[2][0]).cpu().numpy()
label = label[2].item()
# 输出真实类别与预测类别
print("The true category is {} and the predicted category is {}".format(label, pred_class))
# 可视化图片
plt.figure(figsize=(2, 2))
imgs, labels = load_cifar10_batch(folder_path=r'cifar-10-batches-py', mode='test')
plt.imshow(imgs[2].transpose(1, 2, 0))
plt.savefig('cnn-test-vis.pdf')
time2 = time.time()
print('使用预训练模型的训练时间:{}'.format(time2-time1))
运行结果:
运行时间:
以上是使用预训练的结果,对比不适用预训练,只需要修改这一行代码:
resnet18_model = resnet18(pretrained=True)
把True改为False即可。
不使用预训练的结果如下:
对比可以看出:使用预训练运行时间变短了,准确率变高了,那么这是为什么呢?
首先来说,什么是预训练?什么是迁移学习呢?
预训练:
“预训练”的做法一般是将大量低成本收集的训练数据放在一起,经过某种预训方法去学习其中的共性,然后将其中的共性“移植”到特定任务的模型中,再使用相关特定领域的少量标注数据进行“微调”,这样的话,模型只需要从“共性”出发,去学习该特定任务的“特殊”部分即可。
因为预训练模型已经在大规模数据集上学到了一般性的特征表示(如边缘、纹理、颜色等),所以参数已经初始化为较优值,只需对少部分参数进行调整,模型无需从零开始学习,因而训练过程更快。
迁移学习:
迁移学习主要思想:
迁移学习的核心思想是:在一个任务上训练得到的模型包含的知识可以部分或全部地转移到另一个任务上。这通常涉及以下两个主要步骤:
·源任务学习: 在源任务上训练模型,这个任务通常有大量的数据可用。
·知识迁移: 将从源任务学到的知识(如网络参数、特征表示等)应用到目标任务上。
迁移学习通过重复利用已有的知识,不仅提高了学习效率和模型性能,还降低了对标注数据的需求和整体训练成本。它在小数据集、跨领域应用和解决复杂问题方面展现了显著的优势。
普通训练、预训练、迁移学习的对比:
实验过程中,使用的优化器不是SGD了,而是换成了Adam,那么Adam优化器和SGD优化器有什么区别呢?
Adam是一种常用的自适应优化算法,它结合了动量和自适应学习率机制。Adam是基于梯度下降法的,它通过调整每个参数的学习率来加速训练并避免一些常见问题(如梯度消失或爆炸)。
Adam优化器和SGD的对比:
Adam优化器自动调整每个参数的学习率,尤其适合大规模的深度学习任务。所以本次实验选择了Adam优化器。
本次实验中还用到了权重衰减,用来防止过拟合,那么它的原理是什么呢?
权重衰减是一种正则化方法,旨在防止模型的过拟合。它通过在损失函数中添加一个项,使得模型的参数保持较小的值,从而避免模型过度依赖某些特征,导致过拟合。
权重衰减的公式:
对于一个损失函数J(θ),在应用权重衰减后,损失函数变为:
λ 是权重衰减的超参数(通常称为正则化强度),决定了对权重的惩罚程度。是模型权重的L2范数,即权重的平方和。
L2正则化和权重衰减本质上是相同的,区别在于在实现时是否将其明确作为正则化项添加到损失函数中。通常,现代优化器(如Adam、SGD)会通过直接修改损失函数来实现这一点,从而形成权重衰减。
附完整可运行代码:
主程序:
import os
import pickle
import time
import numpy as np
import torch
def load_cifar10_batch(folder_path, batch_id=1, mode='train'):
if mode == 'test':
file_path = os.path.join(folder_path, 'test_batch')
else:
file_path = os.path.join(folder_path, 'data_batch_' + str(batch_id))
# 加载数据集文件
with open(file_path, 'rb') as batch_file:
batch = pickle.load(batch_file, encoding='latin1')
imgs = batch['data'].reshape((len(batch['data']), 3, 32, 32)) / 255.
labels = batch['labels']
return np.array(imgs, dtype='float32'), np.array(labels)
imgs_batch, labels_batch = load_cifar10_batch(folder_path=r'cifar-10-batches-py',
batch_id=1, mode='train')
# 打印一下每个batch中X和y的维度
print("batch of imgs shape: ", imgs_batch.shape, "batch of labels shape: ", labels_batch.shape)
print(torch.__version__)
print(torch.cuda.is_available())
# ==========可视化观察其中的一张样本图像和对应的标签=================================
import matplotlib.pyplot as plt
image, label = imgs_batch[1], labels_batch[1]
print("The label in the picture is {}".format(label))
plt.figure(figsize=(2, 2))
plt.imshow(image.transpose(1, 2, 0))
plt.show()
# =====构建Dataset类======================================================
import torch
from torch.utils.data import Dataset, DataLoader
import torchvision.transforms as transforms
class CIFAR10Dataset(Dataset):
def __init__(self, folder_path=r'cifar-10-batches-py', mode='train', device=None):
if mode == 'train':
self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=1, mode='train')
for i in range(2, 5):
imgs_batch, labels_batch = load_cifar10_batch(folder_path=folder_path, batch_id=i, mode='train')
self.imgs, self.labels = np.concatenate([self.imgs, imgs_batch]), np.concatenate(
[self.labels, labels_batch])
elif mode == 'dev':
self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, batch_id=5, mode='dev')
elif mode == 'test':
self.imgs, self.labels = load_cifar10_batch(folder_path=folder_path, mode='test')
self.transforms = transforms.Compose([transforms.Resize(32), transforms.ToTensor(),
transforms.Normalize(mean=[0.4914, 0.4822, 0.4465],
std=[0.2023, 0.1994, 0.2010])])
self.device = device # 保存设备信息
def __getitem__(self, idx):
img, label = self.imgs[idx], self.labels[idx]
img, label = torch.tensor(img).float(), torch.tensor(label).long() # 转为Tensor
if self.device:
img, label = img.to(self.device), label.to(self.device) # 将数据传输到目标设备
return img, label
def __len__(self):
return len(self.imgs)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
# 创建数据集时传递设备信息
train_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='train', device=device)
dev_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='dev', device=device)
test_dataset = CIFAR10Dataset(folder_path=r'cifar-10-batches-py', mode='test', device=device)
# =======模型构建========================================
from torchvision.models import resnet18
time1 = time.time()
resnet18_model = resnet18(pretrained=True)
# =======模型训练================================================
import torch.nn.functional as F
import torch.optim as opt
from nndl_3 import RunnerV3, Accuracy
# 学习率大小
lr = 0.001
# 批次大小
batch_size = 64
# 加载数据
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
dev_loader = DataLoader(dev_dataset, batch_size=batch_size)
test_loader = DataLoader(test_dataset, batch_size=batch_size)
# 定义网络
model = resnet18_model.to(device)
# 定义优化器,这里使用Adam优化器以及l2正则化策略,相关内容在7.3.3.2和7.6.2中会进行详细介绍
optimizer = opt.Adam(lr=lr, params=model.parameters(), weight_decay=0.005)
# 定义损失函数
loss_fn = F.cross_entropy
loss_fn = loss_fn
# 定义评价指标
metric = Accuracy(is_logist=True)
# 在训练和评估时,将数据传输到设备上
for data, labels in train_loader:
data, labels = data.to(device), labels.to(device) # 将数据和标签都发送到相同的设备
logits = model(data) # 进行前向传播
loss = loss_fn(logits, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 实例化RunnerV3
runner = RunnerV3(model, optimizer, loss_fn, metric)
# 启动训练
log_steps = 3000
eval_steps = 3000
runner.train(train_loader, dev_loader, num_epochs=30, log_steps=log_steps,
eval_steps=eval_steps, save_path="best_model.pdparams")
from nndl_3 import plot
plot(runner, fig_name='cnn-loss4.pdf')
# ========模型评价============================================
# 加载最优模型
runner.load_model('best_model.pdparams')
# 模型评价
score, loss = runner.evaluate(test_loader)
print("[Test] accuracy/loss: {:.4f}/{:.4f}".format(score, loss))
# ==========模型预测================================================
import matplotlib.pyplot as plt
# 获取测试集中的一个batch的数据
X, label = next(iter(test_loader))
X = X.to(device)
logits = runner.predict(X, dim=1)
# 多分类,使用softmax计算预测概率
pred = F.softmax(logits)
# print(pred)
# 获取概率最大的类别
pred_class = torch.argmax(pred[2][0]).cpu().numpy()
label = label[2].item()
# 输出真实类别与预测类别
print("The true category is {} and the predicted category is {}".format(label, pred_class))
# 可视化图片
plt.figure(figsize=(2, 2))
imgs, labels = load_cifar10_batch(folder_path=r'cifar-10-batches-py', mode='test')
plt.imshow(imgs[2].transpose(1, 2, 0))
plt.savefig('cnn-test-vis.pdf')
time2 = time.time()
print('使用预训练模型的训练时间:{}'.format(time2-time1))
nndl_3的代码:
import torch
from matplotlib import pyplot as plt
from torch import nn
class Op(object):
def __init__(self):
pass
def __call__(self, inputs):
return self.forward(inputs)
def forward(self, inputs):
raise NotImplementedError
def backward(self, inputs):
raise NotImplementedError
# 实现一个两层前馈神经网络
class Model_MLP_L2_V3(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(Model_MLP_L2_V3, self).__init__()
self.fc1 = torch.nn.Linear(input_size, hidden_size)
w_ = torch.normal(0, 0.01, size=(hidden_size, input_size), requires_grad=True)
self.fc1.weight = torch.nn.Parameter(w_)
self.fc1.bias = torch.nn.init.constant_(self.fc1.bias, val=1.0)
self.fc2 = torch.nn.Linear(hidden_size, output_size)
w2 = torch.normal(0, 0.01, size=(output_size, hidden_size), requires_grad=True)
self.fc2.weight = nn.Parameter(w2)
self.fc2.bias = torch.nn.init.constant_(self.fc2.bias, val=1.0)
self.act = torch.sigmoid
def forward(self, inputs):
outputs = self.fc1(inputs)
outputs = self.act(outputs)
outputs = self.fc2(outputs)
return outputs
class RunnerV3(object):
def __init__(self, model, optimizer, loss_fn, metric, **kwargs):
self.model = model
self.optimizer = optimizer
self.loss_fn = loss_fn
self.metric = metric # 只用于计算评价指标
# 记录训练过程中的评价指标变化情况
self.dev_scores = []
# 记录训练过程中的损失函数变化情况
self.train_epoch_losses = [] # 一个epoch记录一次loss
self.train_step_losses = [] # 一个step记录一次loss
self.dev_losses = []
# 记录全局最优指标
self.best_score = 0
def train(self, train_loader, dev_loader=None, **kwargs):
# 将模型切换为训练模式
self.model.train()
# 传入训练轮数,如果没有传入值则默认为0
num_epochs = kwargs.get("num_epochs", 0)
# 传入log打印频率,如果没有传入值则默认为100
log_steps = kwargs.get("log_steps", 100)
# 评价频率
eval_steps = kwargs.get("eval_steps", 0)
# 传入模型保存路径,如果没有传入值则默认为"best_model.pdparams"
save_path = kwargs.get("save_path", "best_model.pdparams")
custom_print_log = kwargs.get("custom_print_log", None)
# 训练总的步数
num_training_steps = num_epochs * len(train_loader)
if eval_steps:
if self.metric is None:
raise RuntimeError('Error: Metric can not be None!')
if dev_loader is None:
raise RuntimeError('Error: dev_loader can not be None!')
# 运行的step数目
global_step = 0
# 进行num_epochs轮训练
for epoch in range(num_epochs):
# 用于统计训练集的损失
total_loss = 0
for step, data in enumerate(train_loader):
X, y = data
# 获取模型预测
logits = self.model(X)
loss = self.loss_fn(logits, y.long()) # 默认求mean
total_loss += loss
# 训练过程中,每个step的loss进行保存
self.train_step_losses.append((global_step, loss.item()))
if log_steps and global_step % log_steps == 0:
print(
f"[Train] epoch: {epoch}/{num_epochs}, step: {global_step}/{num_training_steps}, loss: {loss.item():.5f}")
# 梯度反向传播,计算每个参数的梯度值
loss.backward()
if custom_print_log:
custom_print_log(self)
# 小批量梯度下降进行参数更新
self.optimizer.step()
# 梯度归零
self.optimizer.zero_grad()
# 判断是否需要评价
if eval_steps > 0 and global_step > 0 and \
(global_step % eval_steps == 0 or global_step == (num_training_steps - 1)):
dev_score, dev_loss = self.evaluate(dev_loader, global_step=global_step)
print(f"[Evaluate] dev score: {dev_score:.5f}, dev loss: {dev_loss:.5f}")
# 将模型切换为训练模式
self.model.train()
# 如果当前指标为最优指标,保存该模型
if dev_score > self.best_score:
self.save_model(save_path)
print(
f"[Evaluate] best accuracy performence has been updated: {self.best_score:.5f} --> {dev_score:.5f}")
self.best_score = dev_score
global_step += 1
# 当前epoch 训练loss累计值
trn_loss = (total_loss / len(train_loader)).item()
# epoch粒度的训练loss保存
self.train_epoch_losses.append(trn_loss)
print("[Train] Training done!")
# 模型评估阶段,使用'torch.no_grad()'控制不计算和存储梯度
@torch.no_grad()
def evaluate(self, dev_loader, **kwargs):
assert self.metric is not None
# 将模型设置为评估模式
self.model.eval()
global_step = kwargs.get("global_step", -1)
# 用于统计训练集的损失
total_loss = 0
# 重置评价
self.metric.reset()
# 遍历验证集每个批次
for batch_id, data in enumerate(dev_loader):
X, y = data
# 计算模型输出
logits = self.model(X)
# 计算损失函数
loss = self.loss_fn(logits, y).item()
# 累积损失
total_loss += loss
# 累积评价
self.metric.update(logits, y)
dev_loss = (total_loss / len(dev_loader))
dev_score = self.metric.accumulate()
# 记录验证集loss
if global_step != -1:
self.dev_losses.append((global_step, dev_loss))
self.dev_scores.append(dev_score)
return dev_score, dev_loss
# 模型评估阶段,使用'torch.no_grad()'控制不计算和存储梯度
@torch.no_grad()
def predict(self, x, **kwargs):
# 将模型设置为评估模式
self.model.eval()
# 运行模型前向计算,得到预测值
logits = self.model(x)
return logits
def save_model(self, save_path):
torch.save(self.model.state_dict(), save_path)
def load_model(self, model_path):
model_state_dict = torch.load(model_path)
self.model.load_state_dict(model_state_dict)
class Accuracy():
def __init__(self, is_logist=True):
# 用于统计正确的样本个数
self.num_correct = 0
# 用于统计样本的总数
self.num_count = 0
self.is_logist = is_logist
def update(self, outputs, labels):
if outputs.shape[1] == 1: # 二分类
outputs = torch.squeeze(outputs, dim=-1)
if self.is_logist:
# logist判断是否大于0
preds = torch.tensor((outputs >= 0), dtype=torch.float32)
else:
# 如果不是logist,判断每个概率值是否大于0.5,当大于0.5时,类别为1,否则类别为0
preds = torch.tensor((outputs >= 0.5), dtype=torch.float32)
else:
# 多分类时,使用'torch.argmax'计算最大元素索引作为类别
preds = torch.argmax(outputs, dim=1)
# 获取本批数据中预测正确的样本个数
labels = torch.squeeze(labels, dim=-1)
batch_correct = torch.sum(torch.tensor(preds == labels, dtype=torch.float32)).cpu().numpy()
batch_count = len(labels)
# 更新num_correct 和 num_count
self.num_correct += batch_correct
self.num_count += batch_count
def accumulate(self):
# 使用累计的数据,计算总的指标
if self.num_count == 0:
return 0
return self.num_correct / self.num_count
def reset(self):
# 重置正确的数目和总数
self.num_correct = 0
self.num_count = 0
def name(self):
return "Accuracy"
# 可视化
def plot(runner, fig_name):
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
train_items = runner.train_step_losses[::30]
train_steps = [x[0] for x in train_items]
train_losses = [x[1] for x in train_items]
plt.plot(train_steps, train_losses, color='#8E004D', label="Train loss")
if runner.dev_losses[0][0] != -1:
dev_steps = [x[0] for x in runner.dev_losses]
dev_losses = [x[1] for x in runner.dev_losses]
plt.plot(dev_steps, dev_losses, color='#E20079', linestyle='--', label="Dev loss")
# 绘制坐标轴和图例
plt.ylabel("loss", fontsize='x-large')
plt.xlabel("step", fontsize='x-large')
plt.legend(loc='upper right', fontsize='x-large')
plt.subplot(1, 2, 2)
# 绘制评价准确率变化曲线
if runner.dev_losses[0][0] != -1:
plt.plot(dev_steps, runner.dev_scores,
color='#E20079', linestyle="--", label="Dev accuracy")
else:
plt.plot(list(range(len(runner.dev_scores))), runner.dev_scores,
color='#E20079', linestyle="--", label="Dev accuracy")
# 绘制坐标轴和图例
plt.ylabel("score", fontsize='x-large')
plt.xlabel("step", fontsize='x-large')
plt.legend(loc='lower right', fontsize='x-large')
plt.savefig(fig_name)
plt.show()
今天的分享就到这里,下次再见~