前言
机器学习通常涉及在训练期间可视化和度量模型的性能。 有许多工具可用于此任务。 在本文中,我们将重点介绍 SwanLab 开源工具,它可以服务于各种深度学习训练任务(计算机视觉、自然语言处理、音频处理等等),也适配了PyTorch、Transformers、Keras这样的框架。
一、什么是SwanLab?
SwanLab (https://swanlab.cn)是一个用于AI模型训练过程可视化的工具。SwanLab的主要功能包括:
- 跟踪模型指标,如损失和准确性等
- 同时支持云端和离线使用,支持远程查看训练过程,比如可以在手机上看远程服务器上跑的训练
- 记录训练超参数,如batch_size和learning_rate等
- 自动记录训练过程中的日志、硬件环境、Python库以及GPU(支持英伟达显卡)、NPU(支持华为昇腾卡)、内存的硬件信息
- 支持团队多人协作,很适合打Kaggle等比赛的队伍
SwanLab库来自一个中国团队(情感机器),最早的出发点是其开发团队的内部训练需求,后来逐渐开源并且发展成面向公众的产品。SwanLab库在2024年向公众发布。SwanLab刚出现时只有离线版本(对标Tensorboard),后来经过迭代和努力已经有了云端版和各项功能,并且集成了接近30+个深度学习框架,包括PyTorch、HuggingFace Transformers、Keras、XGBoost等等,其中还包括同样是中国团队开发的LLaMA Factory、Modelscope Swift、PaddleYOLO等框架,具有了很全面的功能。
二、如何安装SwanLab?
要安装 SwanLab 可以使用如下命令:
pip install swanlab
要查看是否安装成功,可以打开命令行输入:
swanlab -v
如果打印出了版本号,就说明已经安装成功。
三、登录SwanLab账号(详细)
SwanLab的云端版体验是比较好的(非常推荐),能够支持你在随时随地访问训练过程。
要使用云端版之前需要先注册一下账号:
- 在电脑或手机浏览器访问SwanLab官网:https://swanlab.cn
- 点击右上角的黑色按钮「注册/登录」:
- 填写手机号后,点击「发送短信验证码」按钮
- 填写你的信息
- 用户名称:你的个人昵称,中英文均可
- 用户ID:你的英文名,可由数字、字母、下划线、中横线组成
- 邮箱:你的邮箱
- 机构/院校:你所在的企业、机构或学校
- 您从哪了解到SwanLab? :(选填项)了解到SwanLab的渠道,比如朋友介绍
- 复制API Key
完成填写后点击「完成」按钮,会进入到下面的页面。然后点击左边的「设置」:
在 API Key 这个地方,点击复制按钮:
- 登录(方式一)
打开命令行,输入下面的命令:
swanlab login
在出现的提示里把API Key粘贴进去(粘贴完不显示密码是正常的,这是命令行的特性),然后按回车,完成登录。
7. 登录(方式二)
创建一个Python脚本,输入下面的代码:
import swanlab
swanlab.login(api_key="把API Key粘贴到这里")
把API Key粘贴到对应的位置,然后运行一下这个脚本,完成登录。
四、快速开始:Hello World代码
SwanLab最核心的功能是深度学习训练过程可视化。要搞清楚怎么用,其实只需要掌握 init 和 log 这两大法宝的用法。
- init:负责创建一个实验
- log:负责将学习率、损失值等指标上传到实验中。log()里传入的是一个字典。
举个简单例子:
import swanlab
# 创建1个实验
run = swanlab.init()
for i in range(10):
# 将指标loss,上传到这个实验中
run.log({"loss": i})
这里做了3件事:
- 引入
swanlab
库 - 使用
swanlab.init()
创建了1个实验 - 将指标loss,循环上传到这个实验中
让我们运行看看效果!点击这个链接:
可以看到,这里创建了1个叫swan-1
的实验,实验中有1个loss
折线图,里面记录了这次循环中记录的值。
让我们升级一下代码:
import swanlab
import random
# 创建SwanLab实验
run = swanlab.init(
# 设置将记录此次运行的项目信息
project="my-ml-project",
experiment_name="hello_world",
# 跟踪超参数和运行元数据
config={
"learning_rate": 0.02,
"architecture": "CNN",
"dataset": "CIFAR-100",
"epochs": 10
}
)
# 模拟训练
epochs = 10
offset = random.random() / 5
for epoch in range(2, epochs):
acc = 1 - 2 ** -epoch - random.random() / epoch - offset
loss = 2 ** -epoch + random.random() / epoch + offset
# 向swanlab上传训练指标
run.log({"acc": acc, "loss": loss})
这段代码引入了几个新概念:
- project参数:SwanLab用项目作为区分单位。实验可以理解为「文件」,项目就是「文件夹」。project参数用于指定这次的实验创建在哪个项目下。
- experiment_name参数:这个参数用于指定本次实验的名称。实验名称也可以在网页上修改。
- config参数:这个参数的作用是记录「超参数」,传入是1个字典。
项目、实验、图表、超参数等的关系如下:
ok,这里我们运行一下上面的代码,会得到下面的效果!
至此,我们就大致盘清楚了swanlab的基本用法,总体上来说还是非常简易好上手的。
五、SwanLab仪表板都有什么东西
SwanLab 仪表板由用于可视化数据的不同组件组成。我们将研究几个常用的组件。
上面的图只是部分可视化功能,全部可视化功能还有很多很多,如下:
1. 可视化图表
折线图
机器学习过程需要跟踪与模型性能相关的不同指标。这对于快速发现问题并确定模型是否过度拟合等非常重要。
使用 SwanLab 的 折线图看板,可以可视化这些指标并更轻松地调试模型:
折线图看板是最常用的看板,主要用于将神经网络训练过程中的acc(训练集准确率)val_acc(验证集准确率),loss(损失值),weight(权重)等等变化情况绘制成折线图。
图像图
在处理图像数据时,如果希望查看数据查找问题,或者查看样本以确保数据质量,则可以使用 SwanLab 的 Image API。
文本图
在进行NLP训练任务时,如果希望查看数据查找问题,或者查看模型的输出内容,则可以使用 SwanLab 的 Text API。
2. 日志记录
训练过程中,很多有用的信息打印在日志中。SwanLab会在实验的「日志」选项卡中展示自动记录下的完整日志。
3. 硬件监控
训练时的GPU显存变化等指标,都会被自动记录在「系统」选项卡下面,能帮你找到一些诡异的爆显存原因,分析训练效率的瓶颈在哪里。硬件监控这一块支持的英伟达和华为昇腾两种训练卡。
4. 实验对比
实验表格会把每个实验的超参数、最终指标展示在一个统一的表格中,方便对比不同参数对于实验的影响。
图表对比视图能帮直观的分析不同实验的指标差异,应该是机器学习训练时最最常用的功能。
六、将 SwanLab 与 PyTorch结合使用
PyTorch 是另一个深受研究人员欢迎的深度学习框架。 使用PyTorch来训练深度学习模型时,用SwanLab来监控非常方便。
下面展示一个使用PyTorch框架进行MNIST手写体识别训练的案例:
import os
import torch
from torch import nn, optim, utils
from torchvision.datasets import MNIST
from torchvision.transforms import ToTensor
import swanlab
from torchvision.models import resnet18
# 捕获并可视化前20张图像
def log_images(loader, num_images=16):
images_logged = 0
logged_images = []
for images, labels in loader:
# images: batch of images, labels: batch of labels
for i in range(images.shape[0]):
if images_logged < num_images:
# 使用swanlab.Image将图像转换为可视化格式
logged_images.append(swanlab.Image(images[i], caption=f"Label: {labels[i]}"))
images_logged += 1
else:
break
if images_logged >= num_images:
break
swanlab.log({"MNIST-Preview": logged_images})
def train(model, device, train_dataloader, optimizer, criterion, epoch, num_epochs):
model.train()
# 1. 循环调用train_dataloader,每次取出1个batch_size的图像和标签
for iter, (inputs, labels) in enumerate(train_dataloader):
inputs = inputs.repeat(1, 3, 1, 1) # 将单通道图像转换为3通道
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
# 2. 传入到resnet18模型中得到预测结果
outputs = model(inputs)
# 3. 将结果和标签传入损失函数中计算交叉熵损失
loss = criterion(outputs, labels)
# 4. 根据损失计算反向传播
loss.backward()
# 5. 优化器执行模型参数更新
optimizer.step()
print('Epoch [{}/{}], Iteration [{}/{}], Loss: {:.4f}'.format(epoch, num_epochs, iter + 1, len(train_dataloader),
loss.item()))
# 6. 每20次迭代,用SwanLab记录一下loss的变化
if iter % 20 == 0:
swanlab.log({"train/loss": loss.item()})
def test(model, device, val_dataloader, epoch):
model.eval()
correct = 0
total = 0
with torch.no_grad():
# 1. 循环调用val_dataloader,每次取出1个batch_size的图像和标签
for inputs, labels in val_dataloader:
inputs = inputs.repeat(1, 3, 1, 1) # 将单通道图像转换为3通道
inputs, labels = inputs.to(device), labels.to(device)
# 2. 传入到resnet18模型中得到预测结果
outputs = model(inputs)
# 3. 获得预测的数字
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
# 4. 计算与标签一致的预测结果的数量
correct += (predicted == labels).sum().item()
# 5. 得到最终的测试准确率
accuracy = correct / total
# 6. 用SwanLab记录一下准确率的变化
swanlab.log({"val/accuracy": accuracy}, step=epoch)
if __name__ == "__main__":
#检测是否支持mps
try:
use_mps = torch.backends.mps.is_available()
except AttributeError:
use_mps = False
#检测是否支持cuda
if torch.cuda.is_available():
device = "cuda"
elif use_mps:
device = "mps"
else:
device = "cpu"
# 初始化swanlab
run = swanlab.init(
project="MNIST-example",
experiment_name="resnet18",
config={
"model": "ResNet18",
"optim": "Adam",
"lr": 1e-4,
"batch_size": 256,
"num_epochs": 10,
"device": device,
},
)
# 设置MNIST训练集和验证集
dataset = MNIST(os.getcwd(), train=True, download=True, transform=ToTensor())
train_dataset, val_dataset = utils.data.random_split(dataset, [55000, 5000])
train_dataloader = utils.data.DataLoader(train_dataset, batch_size=run.config.batch_size, shuffle=True)
val_dataloader = utils.data.DataLoader(val_dataset, batch_size=8, shuffle=False)
# (可选)看一下数据集的前16张图像
log_images(train_dataloader, 16)
# 初始化模型
model = resnet18(pretrained=True)
model.fc = nn.Linear(512, 10) # 修改最后一层以适应10个类别
model.to(torch.device(device))
# 打印模型
print(model)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=run.config.lr)
# 开始训练和测试循环
for epoch in range(1, run.config.num_epochs+1):
swanlab.log({"train/epoch": epoch}, step=epoch)
train(model, device, train_dataloader, optimizer, criterion, epoch, run.config.num_epochs)
if epoch % 2 == 0:
test(model, device, val_dataloader, epoch)
# 保存模型
# 如果不存在checkpoint文件夹,则自动创建一个
if not os.path.exists("checkpoint"):
os.makedirs("checkpoint")
torch.save(model.state_dict(), 'checkpoint/latest_checkpoint.pth')
运行此程序后,转到 SwanLab 并查看训练过程:
参考链接
- SwanLab官方文档:https://docs.swanlab.cn/