在深度/机器学习模型训练时,有必要展示或者记录每个batch/epoch的各种损失以及精度信息。除了最简单的print方式,目前有多种库提供了高级的API实现方式。下面就scGPT项目的学习过程,整理三种方式。
1. logging库#
- logging库时python的内置模块,设计用于打印输出多种用户自定义的日志信息
1
2
3
4
5
6
|
import sys
import logging
# 创建一个日志记录器对象,并设置name
logger = logging.getLogger("test_log")
logger.setLevel(logging.INFO)
# 设置输出级别为INFO及以上
|
DEBUG: 详细的信息,通常只在诊断问题时使用。
INFO: 确认一切按预期工作的消息。
WARNING: 表示某些不期望的情况或潜在问题。
ERROR: 更严重的问题,程序未能执行某些功能。
CRITICAL: 严重错误,程序可能无法继续运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# 创建控制台处理器
console_handler = logging.StreamHandler() # 默认sys.stderr (sys.stdout备选)
# 创建格式器并添加到处理器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
# 将处理器添加到 logger
logger.addHandler(console_handler)
logger.info("This is one info")
# 2024-10-22 21:05:16,441 - test_log - INFO - This is one info
epoch = 0
batch = 1
total_batch = 100
acc = 0.85
logger.info(
f"| epoch {epoch:3d} | {batch:3d}/{total_batch:3d} batches | "
f"Accuray {acc}"
)
# 2024-10-22 21:10:02,747 - test_log - INFO - | epoch 0 | 1/100 batches | Accuray 0.85
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 额外设置一个handler,将log同时保存到本地日志文件中
logger.handlers
# [<StreamHandler stderr (NOTSET)>]
file_handler = logging.FileHandler('test.log')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.handlers
# [<StreamHandler stderr (NOTSET)>,
# <FileHandler /home00/liss/Study/cellxgene/test.log (NOTSET)>]
# 删除刚才新增的handler
# logger.removeHandler(logger.handlers[2])
|
2. tensorboard库#
TensorBoard
是一个用于可视化机器学习实验的工具,可与 PyTorch 等框架结合使用。
参考:
https://pytorch.org/docs/stable/tensorboard.html
https://pytorch.org/tutorials/recipes/recipes/tensorboard_with_pytorch.html
https://pytorch.org/tutorials/intermediate/tensorboard_profiler_tutorial.html?highlight=tensorboard 介绍了如何使用tensorboard记录GPU相关数据,暂不记录。
1
2
3
4
5
|
import numpy as np
import torch
from torch.utils.data import TensorDataset, DataLoader
from torch.utils.tensorboard import SummaryWriter
# from tensorboardX import SummaryWriter
|
- 创建一个SummaryWriter对象,其中设置log文件的保存路径
- 一级目录
runs
: 表示本次模型相关的日志组
- 二级目录
experiment_1
: 表示本次训练的日志内容
1
|
writer = SummaryWriter(log_dir='runs/experiment_1')
|
一级目录(runs)下可以放置多次训练(experiment_2, experiment_3, …)的日志结果,用于比较分析。
- 然后在每次迭代训练过程,使用
writer.add_scalar()
记录目标的性能指标、训练参数等信息
- 参数1
tag
:例如Loss/train, 进行命名。若使用/
,则会进行分组标注,例如 Loss类、Accuracy类
- 参数2
scalar_value
:记录的标量值
- 参数3
global_step
:当前的step数
- 当训练完成后,需要显式的关闭tensorboard
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
x = torch.arange(-5, 5, 0.1).view(-1, 1)
y = -5 * x + 3 * x * x + 0.1 * torch.randn(x.size())
dataloader = DataLoader(TensorDataset(x, y), batch_size=5, shuffle=True)
model = torch.nn.Linear(1, 1)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 0.1)
def train_model(iter):
for epoch in range(iter):
for i, (x_dat, y_dat) in enumerate(dataloader):
y_hat = model(x_dat)
loss = criterion(y_hat, y_dat)
writer.add_scalar("Loss/train", loss.item(), epoch*len(dataloader) + i)
# random value just for demonstration
writer.add_scalar("Loss/test", np.random.random(), epoch*len(dataloader) + i)
writer.add_scalar("Accuracy/train", np.random.random(), epoch*len(dataloader) + i)
writer.add_scalar("Accuracy/test", np.random.random(), epoch*len(dataloader) + i)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_model(5)
writer.flush() # make sure that all pending events have been written to disk.
writer.close() # close tensorboard
|
此外,还有其他记录方式,例如add_histogram等。但觉得还是add_scalar最常用。
- 最后在linux终端,通过命令打开网页可视化结果。
1
2
3
|
# linux命令行运行,指定日志组路径
tensorboard --logdir=runs
# http://localhost:6006/
|
3. wandb库#
Weights & Biases (WandB) 是一个用于机器学习实验管理的工具,提供了一系列功能来帮助开发者跟踪、可视化和分享实验结果。
参考:
https://wandb.ai/site
https://docs.wandb.ai/tutorials/pytorch/
- 初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
import wandb
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 登陆账户,使用用户的API
wandb.login(key="User settings → API keys")
# 初始化 WandB
wandb.init(
project="pytorch-simulated-data",
config={
"epochs": 5,
"batch_size": 16,
"learning_rate": 0.01
}
)
# 获取配置
config = wandb.config
|
- 加载数据和模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
# 模拟数据
X = torch.randn(1000, 20) # 1000个样本,每个样本有20个特征
y = (torch.sum(X, dim=1) > 0).long() # 简单的线性可分任务
# 创建数据集和数据加载器
dataset = TensorDataset(X, y)
train_loader = DataLoader(dataset, batch_size=config.batch_size, shuffle=True)
# 定义简单的模型
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(20, 64)
self.fc2 = nn.Linear(64, 2)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x
model = SimpleNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=config.learning_rate)
|
- 记录训练损失以及其它个性化参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 训练模型
for epoch in range(config.epochs):
model.train()
total_loss = 0
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
total_loss += loss.item()
# 记录损失
wandb.log({"epoch": epoch, "loss": total_loss / len(train_loader)})
# 结束 WandB 运行
wandb.finish()
|
上面只记录了最简单的用法,有时间再学习下其它高级功能。
wandb使用教程(持续更新ing…)_wandb 官网-CSDN博客