入门
安装
推荐使用 uv 安装。
uv add git+https://github.com/wliafe/mltools.git
或者使用 pip 安装。
pip install git+https://github.com/wliafe/mltools.git
编写一个项目
项目名称为 mlp,项目内容为利用 mlp 对 mnist 数据集进行分类。
项目结构
project
├── data
│ ├── MNIST
│ └── .gitignore
├── results
│ ├── <time_str>-<file_name>
│ │ ├── <file_name>.json
│ │ ├── <file_name>.log
│ │ ├── <file_name>.png
│ │ └── <file_name>.pt
│ └── .gitignore
├── src
│ ├── dataloader.py
│ └── <file_name>.ipynb
├── .gitignore
└── README.md
其中,src 目录下存放的是 mlp 的代码,results 目录下存放的是 mlp 的结果,data 目录下存放的是 mnist 数据集。
数据集获取
def mnist(path='../data', batch_size=100):
download = False if Path(f'{path}/MNIST').exists() else True
trans = transforms.ToTensor() # 数据集格式转换
train_data = datasets.MNIST(root=path, train=True, transform=trans, download=download)
test_data = datasets.MNIST(root=path, train=False, transform=trans, download=download)
train_data, val_data = mltools.split_data(train_data, [9, 1]) # 训练集和验证集比例9:1
return mltools.iter_data([train_data, val_data, test_data], batch_size) # 返回数据迭代器
使用 split_data() 按比例划分数据集。
使用 iter_data() 构建 DataLoader 类。
参数设置
device = torch.device("cuda")
train_iter, val_iter, test_iter = dl.mnist(batch_size=1000) # 获取训练集、验证集、测试集
model = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10)) # 设置模型结构
model.to(device)
loss = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=1e-1)
ml = mltools.MachineLearning("mlp")
ml.add_model(model)
epoch, timer, recorder = ml.batch_create()
每次初始化 MachineLearning 类时都将生成 results/<time_str>-<file_name> 文件夹,文件夹的命名格式为 时间-文件名,其中时间格式为 年-月-日-时-分-秒,文件夹中包含的文件如下:
文件名.json:训练结果文件名.log:训练日志文件名.png:训练曲线文件名.pt:模型参数
v1.0.11 新增创建 data 目录,并在 results 和 data 目录中自动创建
.gitignore文件,以在 git 版本控制中忽略整个文件夹。 v1.0.11 模型参数文件后缀为.pth。
使用 add_model() 将模型纳入管理。
使用 batch_create() 创建 Epoch、Timer、Recorder 实例。
使用 create_epoch()、create_timer()、create_recorder() 分别创建 Epoch、Timer、Recorder 实例。
训练模型
# 训练模型
num_epochs = epoch(20)
animator = ml.create_animator(
xlabel="epoch", xlim=[0, epoch.totol_epoch + 1], ylim=-0.1, legend=["train loss", "train acc", "val acc"]
) # 创建动画器
for current_epoch in range(1, num_epochs + 1):
timer.start() # 开始计时
# 计算训练集
metric_train = mltools.Accumulator(3) # 累加器:(train_loss, train_acc, train_size)
model.train() # 训练模式
for x, y in train_iter:
x, y = x.to(device), y.to(device) # 转换x、y
y_train = model(x) # 计算模型
train_loss = loss(y_train, y) # 计算损失
train_pred = y_train.argmax(dim=1) # 计算预测值
train_acc = (train_pred == y).sum() # 计算准确数
# 梯度更新
optimizer.zero_grad()
train_loss.backward()
optimizer.step()
metric_train.add(train_loss * y.numel(), train_acc, y.numel()) # 累加损失、准确数、样本数
recorder[0].append(metric_train[0] / metric_train[2]) # 计算平均损失
recorder[1].append(metric_train[1] / metric_train[2]) # 计算准确率
# 计算验证集
metric_val = mltools.Accumulator(2) # 累加器:(val_loss, val_size)
model.eval() # 验证模式
with torch.no_grad():
for x, y in val_iter:
x, y = x.to(device), y.to(device) # 转换x、y
y_val = model(x) # 计算模型
val_pred = y_val.argmax(dim=1) # 计算预测值
val_acc = (val_pred == y).sum() # 计算准确数
metric_val.add(val_acc, y.numel()) # 累加准确数、样本数
recorder[2].append(metric_val[0] / metric_val[1]) # 计算准确率
timer.stop() # 停止计时
# 打印输出值
ml.logger.info(f"train loss {recorder[0][-1]:.3f}, train acc {recorder[1][-1]:.3f}, val acc {recorder[2][-1]:.3f}")
ml.print_training_time_massage(timer, num_epochs, current_epoch)
ml.logger.info(f"trained on {str(device)}")
animator.show(recorder.data)
else:
# 打印输出值
ml.logger.info(f"train loss {recorder[0][-1]:.3f}, train acc {recorder[1][-1]:.3f}, val acc {recorder[2][-1]:.3f}")
ml.print_training_time_massage(timer, num_epochs, current_epoch)
ml.logger.info(f"trained on {str(device)}")
animator.show(recorder.data)
ml.save()
Epoch 是循环器,用于循环训练模型。其中参数 num_epochs 为训练迭代总次数,并不是训练次数,因此当你已经迭代20次想再迭代20次时, num_epochs 应该为40。
使用 create_animator() 创建 Animator 实例。
Animator 是动画器,用于绘制训练过程中的变化趋势。
Accumulator 是累加器,这里初始化参数为3,因此创建的是三元累加器。
Recorder 是记录器,记录每一次循环的数据,例如:训练损失、训练集准确率、验证集准确率等。Recorder 记录的数据可以作为动画器画图的数据来源。
Timer 是计时器,用于记录训练时间。
所有的打印输出一律使用 logger 打印,方便记入日志。
print_training_time_massage() 是打印训练时间的函数,用于打印已训练时长、平均训练时长、预估剩余训练时长。
save() 用于保存所有 MachineLearning 创建和添加的工具的信息,具体的说就是 epoch、timer、recorder、model、animator 等信息。
使用 load() 加载之前保存的 MachineLearning 实例,可以在上次训练的基础上继续训练。
测试模型
model.eval()
metric = mltools.Accumulator(2) # 累加器:(test_acc, test_size)
with torch.no_grad():
for x, y in test_iter:
x, y = x.to(device), y.to(device) # 转换x、y
y_test = model(x) # 计算模型
test_pred = y_test.argmax(dim=1) # 计算预测值
test_acc = (test_pred == y).sum() # 计算准确数
metric.add(test_acc, y.numel()) # 累加准确数、样本数
ml.logger.info(f"test acc {metric[0] / metric[1]:.3f}") # 计算准确率并输出
预测模型
model.eval()
x, y = next(iter(test_iter)) # 从测试中取一个批量
x, y = x[:10].to(device), y[:10].to(device) # 转换x、y
y_pred = model(x) # 计算模型
y_pred = y_pred.argmax(dim=1) # 计算预测值
labels = [f"real:{y[index]}\npred:{y_pred[index]}" for index in range(y.numel())]
mltools.images(x.squeeze(1), labels, shape=(2, 5))
images() 用于绘制图片。