这里有一份炼丹秘籍!

2024-01-05 20:20
文章标签 一份 秘籍 炼丹

本文主要是介绍这里有一份炼丹秘籍!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 Datawhale干货 

作者:欧泽彬,西湖大学,来源:极市平台

文章导读

 

炼丹总是效率低下该怎么办?本文作者总结了自己多年来的炼丹经验,给大家提供了一些常见问题的解决方法和一套自建的工作流程。

来源丨https://zhuanlan.zhihu.com/p/482876481

炼丹多年,辗转在不同地方待过,发现还是有相当部分的小伙伴在手动敲命令开所有的实验。高效一点的操作是写一个 bash script 然后用 for loop 把实验跑完,但似乎每次跑实验效率还是比较低,一轮下来也相当累人。

总结下来有以下问题:

  1. 效率。在迭代的早期通常会用小模型加小数据。单个模型往往只需占用一张卡,在常见的 8 卡服务器中便留着其他卡在那干等。

  2. 认知负载。训一个模型涉及到非常冗长的 pipeline 以及众多超参:数据处理,模型结构,模型参数,训练参数,测试参数。这些可调的节点通常分布在代码、数据或者命令行的参数里面。这让检查、排错和调整极其费劲。往往开完一组实验一天的精力就见底了,更不用说随时出现的错误会让这组实验的结果白白报废。

  3. 可用性。怎么在文件系统里面区分这些不同的实验?怎么样高效地区分并分析这些实验的结果?怎么样把在一个 project 里面开发的工具快速迁移到其他的 project?

  4. 鲁棒性。如果机器突然宕机,哪些实验需要重新跑一遍?

笔者深受这些痛点折磨,所以一直也在寻找解决方案。现在迭代的工作流感觉还算满意,欢迎评论指教:

  1. 把所有的模型、流程改动都映射到命令行参数。模型结构变化用 if/else 或者 switch/case 引出来。这符合把 operation 变成 code 的主流趋势,也能够无缝对接到大多数主流代码框架。

  2. 把不关心的默认参数放到一个“命令模板”里面,然后将感兴趣的参数变成变量,将感兴趣的的取值组合写到一个文件里面。把 baseline 取值也写到文件里,方便对比。

  3. 把文件当做任务池,用一组 worker (分配了 gpu 资源) 并发地去拉任务,跑任务。每个任务的中间结果写到以超参组合命名的文件夹中,这比时间戳更可读,也有足够区分不同实验,还可以查重防止重复跑实验。用 tensorboard 跟踪训练进程。

  4. 写一个评价标准和感兴趣指标的 parser 对所有实验的中间文件进行处理,再把结果拉到 jupyter notebook 或者 excel 表里做可视化和分析。

为了降低认知负担,1 做了第一层简化:把分散在各个地方的调节点全部抽象成命令行参数,这样只需在开发的时候保证每个调节点都正常 work 就行了,查错和决策就到了参数选择的层面。2 则是做了第二层简化:将无关的参数和实验相关的参数区分开,这样就避免了不小心改到别的参数而出错 -- 而写出这些无关的参数又迫使自己思考和过一遍所有可能的影响因子,查漏补缺。3 是实现层面的,任务池 + 并发的模式可以最大化硬件利用率,不需要惦记实验有没有跑完。处理完这几点后,基本上工作流就变成了白天读 paper、沟通、debug、分析结果,晚上回家前列好要跑的实验跑起来,到家后看一下实验是否正常运行,然后就可以倒头睡觉等第二天出结果了。

基本原则讲完之后也贴一个我的 python 实现。工具路径在这里,希望大家实验跑的比谁都快:

https://github.com/simtony/runner

欢迎使用,star,二次开发,提 issue。非常相似的工具有微软的 NNI(https://github.com/microsoft/nni),但是作为跑实验的工具来说太重了,而且做了太多抽象,很难对某个实验的结果做直观的分析。另外这个回答(https://www.zhihu.com/question/384519338/answer/2152639948)提到的工具虽然实现了并发实验的功能,但感觉不太够用。如果有更好的方案可以评论区分享一下。

举个栗子

假设现在我们开发了一个新的 normalization 层叫 “newnorm”,baseline 是 batchnorm。每一个实验涉及 train、checkpoint average 和 test 三个流程。现在希望看不同的 normalization 以及不同的 momentum 参数对结果的影响,对应的配置文件如下:

---
template:train: >python train.py data-bin/{data}--seed 1--criterion label_smoothed_cross_entropy--arch transformer_iwslt_de_en --share-all-embeddings--optimizer adam --adam-betas '(0.9,0.98)' --clip-norm 0.0--dropout 0.3 --lr-scheduler inverse_sqrt --warmup-updates 8000--lr 0.0015 --min-lr 1e-09--label-smoothing 0.1 --weight-decay 0.0001--max-tokens 4096 --save-dir {_output}--tensorboard-logdir {_output}--no-save-optimizer-state--update-freq 1 --log-format simple --log-interval 50--ddp-backend no_c10d--keep-last-epochs 5 --early-stop 5--normalization {norm} [moment]avg: >python scripts/average_checkpoints.py --inputs {_output}--num-epoch-checkpoints 5 --output {_output}/averaged_model.pttest: >python generate.py data-bin/{data}--max-tokens 4096 --beam 5 --lenpen 1.0 --remove-bpe--path {_output}/averaged_model.pt --gen-subset testdefault:data: iwslt14norm: batchmoment: 0.1resource: [ 0, 1, 2, 3 ]---
norm: [ new, batch ]
moment: [ 0.1, 0.05 ]

第一个 yaml doc 作为实验的 specification。template 下面指定了 train, checkpoint average 和 test 的模板命令,其中需要调的参数用 {param} 作为占位符。工具还定义了一些默认的参数,比如这个实验对应的路径 {_output}。指定了要调的超参后,default 里面指定了这些超参的 baseline 值,最后在 resource 里指定了 4 个 worker,每个 worker 对应一个 GPU。

从第二个 yaml doc 开始指定要格点搜的超参。默认会把所有超参组合跑一遍。这里有 4 个任务。同步代码和配置文件到服务器后,直接 run 并发地跑这4个任务:

$ run
Orphan params: set()
Tasks: 4, commands to run: 12
START   gpu: 0, train: 1/ 4, output/Norm_new-Moment_0.1
START   gpu: 1, train: 2/ 4, output/Norm_new-Moment_0.05
START   gpu: 2, train: 3/ 4, output/Norm_batch-Moment_0.1
START   gpu: 3, train: 4/ 4, output/Norm_power-Moment_0.05
START   gpu: 2, avg  : 3/ 4, output/Norm_batch-Moment_0.1
FAIL    gpu: 2, avg  : 3/ 4, output/Norm_batch-Moment_0.1
...

每个输出文件夹里面会写入相应的文件

$ ls output/Norm_batch-Moment_0.1
checkpoint51.pt
checkpoint52.pt
averaged_model.pt
log.train.20220316.030151
log.avg.20220316.030151
log.test.20220316.030151
param
stat

其中 log.* 是每个任务本来会打到命令行里面的 log。param 是每个任务对应的一些参数设定,方便 debug,stat 则是任务状态,分为successfail。这可以用来帮助工具判断是否需要重跑,也可以后期debug。跑实验的过程可以开 tensorboard 跟踪结果,一旦不对劲马上 kill。

实验跑完之后可以开一个 jupyter notebook 写实验结果分析的 parser。在这个例子里面只需要从 log.test 里面读出 BLEU 就好了。写完之后可以调用 Examiner 对所有结果做分析:

from runner.examine import Examiner, latest_log# define a metric parser for each directory (experiment)
def add_bleu(output_dir, experiment, caches):# Each parser follows the same signature# It can read/write to a global cache dict `caches`, # and read/write each experiment: # collections.namedtuple("Experiment", ["cache", "metric", "param"])latest_test_log = latest_log("test", output_dir)bleu = parse_bleu(latest_test_log) #  a user-defined log parserexperiment.metric["test_bleu"] = bleuexaminer = Examiner()  # container for parsed results
# register parser for each directory (experiment)
examiner.add(add_bleu)
# run all parsers for directories matched by regex 
examiner.exam(output="output", regex=".*batch.*")
# print the tsv table with all (different) params and metrics of each experiment
examiner.table()

为什么这样写

格点搜索可以适配大多数调参的场景。首先随机暴力格点搜比较有效的调参方式,特别是当计算资源比较充足的时候。其次做对比实验的时候也会用到参数的格点组合。最后如果不想格点搜,可以手动把想跑的超参组合各自写到配置文件里。

每一个实验都是由一系列顺序执行的命令组成的,比如上述例子的 train - checkpoint average - test。所以相比简单的命令,打包后的顺序执行的命令是更好的任务池的单元。

超参配置模式先后有两个版本。一开始是直接定义一个 config 类并对其操作。但是这样会跟当前 project 深度耦合,换一个代码库就得改很多地方,还会出错,并发部分也不好迁移到其他任务。最后将任务抽象成了一组命令,把修改超参转化成修改任务命令,然后借用了 python 调用 bash 的接口进行并发跑任务。这个方案完美匹配各大主流框架。

并发部分前后迭代了三个版本。第一版的 multiprocessing 最简单,但是对主进程 Ctrl + C 后经常出现 orphan process,还需要查 pid 手动去 kill。第二版的 thread 虽然没有 orphan process 的问题,但是和 multiprocessing 一样需要对全局共享的队列和 io 加锁,也很麻烦。最后收敛到了 asyncio 的 coroutine。后续加 cursor 的用户界面也好写一点。

一些不怎么高级的进阶功能

单个 worker 需要多 GPU 的话可以在 resource 里面用引号框起来:resource: ["0,1", "2,3"]

日常需要一组实验在多个机器跑。不同机器卡数不同,需要跑的任务也不同。我先是用了 pycharm 的 deployment -> server group 的配置,让每次 Ctrl + S都会把本地代码 push 到所有服务器上。在上述工具方面做了几个改动:在命令行工具 run 中增加了 -t-r。其中 -t 可以指定跑 yaml 文件中对应_title 参数的任务。-r 指定 gpu index,这样在不同机器通过命令行参数修改资源和 worker 数量。

经常会出现跑一个 train 和多个 test 的情况。为了避免每次 test 都得从头跑一次 train,加了 -c 命令来选择要跑的 command。同时在 yaml 文件里面也加了 _cmd 字段方便按每组实验配置。

一个参数打包很多超参的情况也非常常见。典型的如 Transformer 的 pre/post layernorm 需要同时改 encoder 和 decoder 的 normalization 方式。在切换数据集的时候也是如此,不同数据往往意味着一整套超参的改变。所以在 yaml 的第一个文档中加了 alias 字段,用来将某一个参数的取值映射到一组参数的取值。

有的时候快速试一些改进的时候会懒得把它引到命令行参数里面。这个时候为了将当前结果和已有结果区分开,可以在参数选择中引入 template 里面不用的参数。这些参数只会起到改输出路径名的作用。

推荐阅读:

我的2022届互联网校招分享

我的2021总结

浅谈算法岗和开发岗的区别

互联网校招研发薪资汇总

2022届互联网求职现状,金9银10快变成铜9铁10!!

公众号:AI蜗牛车

保持谦逊、保持自律、保持进步

481c59fd72b9859e09157cda5321b462.png

发送【蜗牛】获取一份《手把手AI项目》(AI蜗牛车著)

发送【1222】获取一份不错的leetcode刷题笔记

发送【AI四大名著】获取四本经典AI电子书

这篇关于这里有一份炼丹秘籍!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/574048

相关文章

高效传输秘籍,揭秘Rsync和SCP的优劣,助你做出明智选择!

在日常的运维工作中,文件传输任务频繁出现,而选择合适的工具能显著提高工作效率。Rsync 和 SCP 是两款常见的文件传输工具,但它们各具优缺点,适合不同的场景。本文将通过深入分析这两款工具的特性、使用场景和性能,帮助你做出明智的选择,从而在文件传输中省时省力。 Rsync 与 SCP 简介 Rsync:增量传输的强大工具 Rsync 是一款支持文件同步的工具,广泛应用于备份和传输

08_Tensorflow2图像处理秘籍:让图片‘听话’,AI也能成艺术家!

1. 图像数据处理 图像处理是指图像在神经网络训练之前的预处理,是人工智能视觉领域的重要组成部分。通过图像处理技术对图像数据集进行处理有两方面的作用:(1)将原始数据集处理成合格的、规范是数据集;(2)通过图像处理技术实现对原始数据集的增广。 # 库引入import matplotlib.pyplot as pltimport tensorflow as tf# 图像读取image_

2024 数学建模高教社杯 国赛(D题)| 反潜航空深弹 | 建模秘籍文章代码思路大全

铛铛!小秘籍来咯! 小秘籍团队独辟蹊径,运用等多目标规划等强大工具,构建了这一题的详细解答哦! 为大家量身打造创新解决方案。小秘籍团队,始终引领着建模问题求解的风潮。 抓紧小秘籍,我们出发吧~ 完整内容可以在文章末尾领取! 第一个问题: 分析投弹最大命中概率与投弹落点平面坐标及定深引信引爆深度之间的关系,并给出使得投弹命中概率最大的投弹方案,及相应的最大命中概率表达式。 要建立深水炸弹

lazada自养号秘籍:一次成号测评环境系统全解析

lazada自养号一次成号测评环境系统对于卖家来说算是一种低成本、高回报的推广营销方式,旨在通过模拟真实买家的行为来提升lazada平台上店铺的权重、排名和销量。以下是对该系统的详细介绍: 一、系统概述 lazada自养号测评环境系统是指卖家通过自行创建和管理买家账号,在模拟真实购物环境的基础上,进行产品浏览、收藏、加购、下单及评价等操作,以提升店铺的综合表现。该系统要求高度的稳定性和安全

网工必知的《网络端口号大全》,看这一份足够了

号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部 下午好,我的网工朋友。 咱作为网工,了解和掌握常用的网络端口知识可以说是必不可少的技能。 熟悉各类网络服务和应用程序所使用的端口,可以帮助我们在工作里更高效地配置网络设备、优化网络性能、诊断网络故障等。 在遇到无法访问某个网络服务的问题时,检查相关端口的状态往往是排查问题的第一步。 今天就来说说端口这

2024 数学建模高教社杯 国赛(C题)| 农作物的种植策略 | 建模秘籍文章代码思路大全

铛铛!小秘籍来咯! 小秘籍团队独辟蹊径,运用等多目标规划等强大工具,构建了这一题的详细解答哦! 为大家量身打造创新解决方案。小秘籍团队,始终引领着建模问题求解的风潮。 抓紧小秘籍,我们出发吧~ 完整内容可以在文章末尾领取! 第一个问题是:假定各种农作物未来的预期销售量、种植成本、亩产量和销售价格相对于2023年保持稳定,每季种植的农作物在当季销售。要求针对以下两种情况,分别给出该乡村20

【圣诞营销秘籍】Newsbreak上引爆欧美圣诞饰品电商广告的创意攻略

【圣诞营销秘籍】Newsbreak上引爆欧美圣诞饰品电商广告的创意攻略 随着冬日雪花的悄然飘落,欧美大地迎来了最为温馨浪漫的节日——圣诞节。对于电商行业而言,这不仅是销售旺季的巅峰,更是品牌展示创意与魅力的绝佳时机。Newsbreak,作为知名的新闻聚合与推送平台,其庞大的用户基数和精准的推送机制,为圣诞饰品电商提供了前所未有的营销舞台。本文将为您揭秘,如何在Newsbreak上策划

火狐浏览器设置秘籍:让https协议下的ws不加密时运行无阻(WebSocket connection HTTPS)

Uncaught (in promise) DOMException: Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. 明确指出了一个常见的安全限制:当尝试从一个通过HTTPS加载的页面上发起一个不安

Tiktok测评防关联秘籍:矩阵自养号策略全面解析

TikTok测评自养号矩阵防关联引流系统是一种为TikTok平台设计的全方位营销解决方案,具备完全AI自动化养号、自动关注回关、批量私信、批量点赞评论、批量上传视频、增加橱窗等,全部都是自动化操作,替代了所有人工操作,旨在帮助用户高效、安全地管理多个账号,提升账号权重,实现精准引流和快速增长。以下是对该系统的详细解析: 一、系统概述 TikTok测评自养号矩阵防关联引流系统结合了硬件(如防

如何制作一份可以快速拿下国外客户的报价表(附报价单模板)

做外贸报价技巧是每个外贸业务员必须学会的一个东西,外贸报价也是有很多技巧何需要注意的地方,今天就来给大家分享一下,如何制作一个让国外客户快速下单的报价表。这个是外贸小白变销冠的第六篇--报价篇,建议收藏,文末有报价单模板。 往期回顾:如何从外贸小白如何变成外贸销冠 往期回顾:外贸干货:如何写出一封高回复率的开发信 往期回顾:如何高效回复国外客户,让客户快速下单 往期回顾:做外贸如何判断国外