前言
机器学习通常涉及在训练期间可视化和度量模型的性能。 有许多工具可用于此任务。 在本文中,我们将重点介绍 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 swanlabswanlab.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 - offsetloss = 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 = 0logged_images = []for images, labels in loader:# images: batch of images, labels: batch of labelsfor 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 += 1else:breakif images_logged >= num_images:breakswanlab.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 = 0total = 0with 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__":#检测是否支持mpstry:use_mps = torch.backends.mps.is_available()except AttributeError:use_mps = False#检测是否支持cudaif torch.cuda.is_available():device = "cuda"elif use_mps:device = "mps"else:device = "cpu"# 初始化swanlabrun = 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/