简体中文 | English
- EasyLossUtil
- LICENSE
在训练神经网路模型的过程中常常有loss数据,一般表现为一个epoch出现好几个
如果要使用tensorbord去可视化训练loss,我又懒得配置,
因此自己写了将loss保存为文件以及图片的程序。
在不同的项目之间往往需要复制粘贴完成,所以不如写一个自己喜欢的通用的库出来算了。
安装包在dist目录中, 安装命令如下:
pip install .\EasyLossUtil-0.9-py3-none-any.whl
前三个不用保持版本一致, 但是这几个库一定要有
torch的版本一定要高于1.11.0
开发这个库使用的第三方包:
pandas==1.0.5
numpy==1.21.4
matplotlib==3.2.2
torch>=1.11.0
import os
from EasyLossUtil.easyLossUtil import EasyLossUtil
root_path = os.path.dirname(__file__) # 本文件所在目录的绝对路径
# 需要处理的loss的名字
name_list = ["loss1", "loss2"]
# 初始化工具
lossUtil = EasyLossUtil(
# loss的名字
loss_name_list=name_list,
# loss保存的根目录
loss_root_dir=os.path.join(root_path, "test_loss")
)
# 模拟的loss数据, 共5个epoch的数据
loss1 = [1, 2, 3, 4]
loss2 = [5, 2, 3, 4]
# for循环模拟训练流程
total_epochs = len(loss1)
for i in range(total_epochs):
lossUtil.append(
loss_name=name_list,
# 数据的顺序要与名字一致
# 比如名字是loss1和loss2
# 那么数据也应该是loss1和loss2
loss_data=[
loss1[i],
loss2[i]
]
)
# 自动保存loss数据为csv文件以及折线图文件
lossUtil.autoSaveFileAndImage()
运行代码后会有以下提示:
EasyLossUtil---All the loss names:
loss1
loss2
loss1.csv:
1
2
3
4
loss1.csv:
5
2
3
4
这个功能是为了以下情况开发的:
假设使用本工具保存了200个epoch的数据时, 因为未知原因(停电或者主动中断)导致程序停止了
而我们想要在下一次训练时, 加载上一次训练的模型权重接续训练, 并且使得loss数据也能够连续, 前200个数据不会丢失(主要是折线图),
那么可以按照以下例子设置:
主要是需要在初始化工具时, 使用loadArchive=True进行设置, 工具会自行从设置的loss_root_dir目录中以往的日志文件中读取数据
import os
from EasyLossUtil.easyLossUtil import EasyLossUtil
root_path = os.path.dirname(__file__) # 本文件所在目录的绝对路径
# 需要处理的loss数据
name_list = ["loss1", "loss2"]
# 初始化工具,
lossUtil = EasyLossUtil(
loss_name_list=name_list,
loss_root_dir=os.path.join(root_path, "test_loss"),
# loadArchive=True表示从loss_root_dir目录下以往的csv文件中读取数据初始化工具
loadArchive=True
)
# 输出现有的数据查看是否初始化成功(data是一个字典)
print(lossUtil.data)
# 后续可以按照3.1节继续向工具中添加数据, 保存到文件
这个工具用于快速计算平均值,
例如一个epoch中有多次迭代, 计算多次迭代的loss平均值
from EasyLossUtil.quickAverageMethod import QuickAverageMethod
# 需要处理的loss的名字
name_list = ["loss1", "loss2"]
# 初始化工具
q = QuickAverageMethod(loss_name_list=name_list)
# 需要计算平均值的工具
loss1 = [1, 2, 3, 4, 0]
loss2 = [5, 2, 3, 4, 0]
# 模拟循环训练过程, 向工具类中添加数据
for i in range(len(loss1)):
q.append(loss_name=name_list, value=[loss1[i], loss2[i]])
# 获取loss数据的平均值
all_avg_loss = q.getAllAvgLoss()
print(all_avg_loss)
输出为:
[2.0, 2.8]
分别对应loss1的均值和loss2的均值
torchvision.utils中的保存图片的api在处理灰度图像数据时, 存储开销较大,
因此我根据博客做了更改, 链接如下
https://blog.csdn.net/nyist_yangguang/article/details/119935122
使用的例子
使用gray_image=True控制, 在保存前对灰度图像做处理
from EasyLossUtil.saveTensor2Img import save_image
import torch
a = torch.randn((10, 1, 64, 128))
save_image(
a,
'efficient_save_tensor.png',
gray_image=True,
nrow=2,
padding=5
)
注:
如果想要保存灰度图, 也可以在使用torchvision.utils.save_image函数前,
用torchvision.transforms.functional中的rgb_to_grayscale函数将rgb图像变成灰度图
例子如下:
import torch
from torchvision.transforms import functional as F
from torchvision.utils import save_image
rgb_image = torch.rand(3, 256, 256)
grayscale_image = F.rgb_to_grayscale(rgb_image)
assert grayscale_image.shape == (1, 256, 256)
save_image(grayscale_image, "image.png")
参数如下:
num: 给定的数字
n: 要求保留的位数
返回值: 结果字符串
注: 我发现这个功能其实可以使用python的字符串格式化函数format()来实现
参考资料:https://www.runoob.com/python/att-string-format.html
例子如下:
a = 3.1455926
print("a:{:.2f}".format(a)) # 或者print(f"a:{a:.2f}")
# 输出结果为3.15
各个参数类的父类, 实现了def repr(self)方法,
使得可以直接print该类的对象, 方便输出日志
示例代码:
from EasyLossUtil.global_utils import ParamsParent
class MyParams(ParamsParent):
my_param1 = 1
my_param2 = 2
my_params = MyParams()
print(my_params)
"""
程序的输出为:
---MyParams---
my_param1: 1
my_param2: 2
------------------
"""
将秒钟输出格式化, 大于60秒的用分钟表示
参数如下:
seconds: 要输出的秒钟
targetStr: 在输出秒钟格式化信息之前的提示字符串
返回值: 输出的字符串
注:
这个功能可以使用datetime中的timedelta函数实现
例子如下:
import os
import time
from datetime import timedelta
start_time = time.time() # 起始时间
time.sleep(1) # 延迟一秒钟
end_time = time.time() # 结束时间
# 输出消耗的时间<br>
# 在秒数不超过一天的情况下<br>
# str(timedelta(seconds=seconds_number))输出的结果是 hour:minute:second:microseconds<br>
# microseconds是微秒, 与秒的进率是1e6, 只有6位有效数字<br>
# 在hour为1位数时: h:mm:ss:ms , 此时[2:-7]得到mm:ss (ms有6位, -7是最后一个冒号)<br>
print(f"epoch time cost: {str(timedelta(seconds=end_time-start_time))[2:-7]}")
# 输出结果为00:01
# 也可以将秒钟化为整数再格式化
# print(f"epoch time cost: {str(timedelta(seconds=int(end_time-start_time)))}")
模型预测的概率向量中最大概率的类别作为预测类别, 与标签作比较, 计算预测正确的数量
pred_vector: 模型输出的概率向量,形状为[Batch_size, num_categories]
label: 标签,形状为[B_size], 例如1代表图像属于类别1
dir_path: 需要创建的目录
例程:
from EasyLossUtil.global_utils import checkDir
dir_path = "./test1/test2"
checkDir(dir_path)
# 如果当前目录下文件夹test1不存在,则创建test1文件夹, 并在其中创建test2文件夹
# 如果test1下不存在test2, 则创建test2文件夹
# 如果两个文件夹都存在,那么不做任何动作
Copyright [2023] [RSMung]
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.