model.zero_grad() VS. optimzer.zero_grad()

引言 在模型训练时,每个Batch反向传播完成后我们需要手动清除计算图上本次迭代的所有梯度 在阅读不同的代码时,总能看到不同的清空代码: model.zero_grad() optimizer.zero_grad() 正文 上述两种梯度清空的方式均有效,区别在于起作用的范围不同 model.zero_grad() 此时mdoel包含的所有参数上的梯度均被清空 optimizer.zero_grad() 此时该优化器中负责更新的模型参数上的梯度被清空,即不一定是全部的梯度被清空 若模型训练过程中只有一个优化器,即优化器构造时使用 optimizer = optim.Optimiers(model.parameters(), lr=args.lr) 此时上述两种梯度清空方式完全等价 总结 两种不同的梯度清零方式在多数场景下基本等价,其区别在于作用范围不同 对于多任务训练、多优化器的训练中,需要根据具体训练策略的不同对参数梯度进行不同作用范围的清空
Read more →

python中的print()函数深度使用

背景 今天读代码的过程中发现了一种很有意思的print()写法 每一个程序员对每一种语言最熟悉的不过于各种“hello world”,这也不可避免的造成了我们对最熟悉的print()语句最为“陌生” 主题 对于python中print()函数的参数深度使用方法 语法 print(*values, [sep="", end="", file="", flush=""]) 参数 *values 必需 要输出的内容,可以是任何类型对象 同时输出多个对象时,需要用,隔开 sep 可选 同时输出多个对象时的分隔符 默认空格 end 可选 输出最后一个对象之后的结尾符 默认是一个\n,即换行 file 可选 要打印输出到的“设备” 默认为输出到当前终端,可以指定已打开的文件对象 对文件是否追加更新由上下文的open()中的a/w参数指定 flush 可选 整成情况下输出是否被缓存(是否等待文件对象关闭前同一写入)由file对象决定,但如果指定为Ture则print()会强制立即将内容刷新进文件 一般用不到
Read more →

Pytorch使用单机多卡训练

需求 对基于pytorch的深度学习模型进行多卡训练以加速训练过程 由于显卡版本过于老旧,安装配置NCCL工程量过于庞大,希望使用简单的pytorch代码实现单机多卡训练,不考虑多机多卡的显卡通信 训练完成后保存的checkpoint需要能够在任何设备上进行加载、推理 实现 训练 pytorch提供了简单的单机多卡训练api,只需要在初始化模型之后执行下列语句将模型复制到多卡上 # initiate multi-gpu training model = nn.DataParallel(model, device_ids=<ids of the gpus you want to use>) 其他操作与单卡训练完全一致 加载checkpoint 上述操作后保存的checkpoint如果按照常规方法直接进行加载会报错 RuntimeError: Error(s) in loading state_dict for <ModelName>: Missing key(s) in state_dict:... debug遍历后发现其实其状态字典是完全一致的,只是因为我们在训练过程中将模型定义为了多卡并行模型。这里只需要按照训练过程中转换为多卡模型的代码初始化当前模型结构即可,即执行: # initiate multi-gpu training model = nn.DataParallel(model, device_ids=<ids of the gpus you want to use>) 其他操作与征程推理完全一致,若不想使用多卡/只想使用cpu,只需要按照常规将device = torch.device("<cpu/cuda:id>")即可 Note:查阅资料过程中发现有解答建议使用参数强行忽略模型加载的错误torch.load(<checkpoint>, strict=False),经测试,这样加载的模型啥也不是…不知道为什么pytorch官方要提供这个接口
Read more →

Pytorch单机多卡(DP)训练之后的模型“货不对板”

背景 之前介绍过Pytoch的单机多卡训练,当时采用的是内置的nn.DataParallel()方法 经过单机多卡训练的模型保存checkpoint之后再次加载需要同样使用DP()对模型进行封装之后才能正常加载,否则会报错状态词典的键值对不上 原因 经过DP()封装之后的模型,其状态词典分别添加了module.的前缀,例如原参数为hr_branch.conv_hr.1.layers.0.weight,封装之后变成了module.hr_branch.conv_hr.1.layers.0.weight。 解决方案 在加载状态词典之前将该前缀进行替换,得到纯净的状态词典,则不再需要重新对模型进行DP()封装 ckp_state_dict = torch.load(args.ckp, map_location=torch.device("cpu"))["model"] ckp_state = {} for k, v in ckp_state_dict.items(): k = k.replace("module.", "") ckp_state[k] = v 参考 文章
Read more →

关于python协程销毁、超时

概念 协程 通过async/await语法进行声明,是书写python异步应用的推荐方式 可等待对象 如果一个对象可以在await中使用,那么它就是可等待/awaitable对象 类型:协程、任务、Future async.sleep(delay, result=None, *, loop=None) 阻塞delay指定的秒数 sleep()总是为挂起当前任务,以允许其他任务运行 场景 Sanic后台任务执行失败被挂起,不报错,影响后续任务的进行 解决方案 对后台任务中可能出现失败的协程增设超时 asyncio.wait_for(aw,, timeout, *, loop=None) 等待aw可等待对象完成,指定timeout秒数后超时取消 timeout可以为None,也可以为float/int数值表示的等待秒数。如果timeout为None,则等待直到协程返回 如果发生超时,任务将取消并引发asyncio.TimeoutError 要避免任务取消,可以加上shield() 简单等待 asyncio.wait(aws, *, loop=None, return_when=ALL_CONPLETED) 并发地运行aws可迭代对象中的可等待对象并进入阻塞状态直到满足return_when所执行的条件 aws可迭代对象必须不为空 此函数不会引发asyncio.TimeoutError,当超时发生时,未完成的Future/Task将在指定秒数后返回;与wait_for()不同,wait()在超时后不会取消可等待对象
Read more →