电子说
编者按:机器学习科学家分享了使用git管理数据科学试验的经验。
引言
版本控制是管理数据科学试验的关键工具。但是,魔鬼在细节之中。这篇文章将讨论如何在数据科学项目中实现版本控制。
git的使用有好几种范式,就数据科学试验而言,我基本上根据的是特性分支这一范式。简单来说,特性分支意味着有一个master分支(主分支)作为基础,新特性通过在主分支上分支的方式加入代码基,做出实现特性需要的所有改动后,合并新分支至主分支。
策略
我为每个试验或者想要尝试的新建模思路创建一个新分支。这时你需要有意识地决策:代码的修改只适用于这次试验,还是希望在这次试验和之前的试验上都适用?换一种表述方式:你是打算替换,还是增益?这个问题的答案将决定你是否可以把新分支合并回主分支。
我建议额外花一点功夫,将关键组件提取出来,作为一个库,在多次试验中复用。这比有许多份相同(或者更糟,略有不同)的代码要好很多,不用分别维护,也不易导致错误。俗话说得好,最好的代码是没有代码。将关键组件提取至一个共享库,你可以逐渐做出改进,并最终得到一个内聚的代码基,可以在一系列试验复用。相反,如果你不断引入不向后兼容的改动,你会发现自己频繁地在分支间跳转,以便复制/粘贴有用的代码片段,接着却需要加以修改,因为组件没有设计成能够一起工作的。在较大的试验中,这会变得很难操作。
特性分支这一方法的优势在于你可以将试验分支合并回主分支,接着运行任何试验。这么做的代价是,当你对核心库进行改动时,你也许需要同时修改其他试验的实现。所以,和所有事情一样,这是一个需要做出权衡的决策。在我的经验中,这个方法能够自然地演化,我发现,每当我想要复制粘贴的时候,都会想一下能否提取公共代码。
例子
我推荐如下的目录结构:
|-- core/
|-- tests/
|-- test_pull_data.py
|-- test_prepare_data.py
|-- test_model.py
|-- test_deploy.py
|-- test_utils.py
|-- pull_data.py
|-- prepare_data.py
|-- model.py
|-- deploy.py
|-- utils.py
|-- experiment_1/
|-- data/
|-- training.csv
|-- validation.csv
|-- test.csv
|-- output/
|-- results.json
|-- models/
|-- model1
|-- model2
|-- job_config.py
|-- build_data.py
|-- train.py
|-- evaluate.py
|-- prod.py
|-- experiment_2/
|-- data/
|-- training.csv
|-- validation.csv
|-- test.csv
|-- output/
|-- results.json
|-- models/
|-- model1
|-- model2
|-- job_config.py
|-- build_data.py
|-- train.py
|-- evaluate.py
|-- prod.py
在这一情形中,主要逻辑位于core目录下。试验以目录的形式组织,其中包含为试验执行核心逻辑的代码,以及相应的输入、输出文件。实现代码应该极为简单,只做具体试验特定的事情。例如,如果试验是要比较A方法和B方法,那么它会引入A和B的配置,从核心实例化相关代码,并调用每个示例的run方法。
注意这个结构很自然地提供了实现单元/功能/集成测试的地方。此外,单是提取通用组件至可复用的库这一行动就有助于使代码更容易测试。由于代码倾向于基于参数,而非依赖硬编码的试验细节,为测试创建玩具样本就要容易很多。以后我会写一篇文章,深入讨论如何为数据科学项目写测试。
窍门
下面是一些我觉得在实践中比较有用的简单窍门。
.gitignore
.gitignore告诉git忽略哪些文件。在开始一个新项目时,应该优先配置.gitignore。因为一旦你提交了蠢物,它就会永远呆在代码仓库之中(除非你采取了一些特殊行动)。
最重要的是除外敏感信息,比如密码和API密钥。如果你早早地提交了包含敏感信息的文件,那么它很快就会变成一场噩梦。从当前快照删除文件无济于事——你需要从所有之前的提交中清除敏感信息。对自己好一点,避免去学如何做到这一点。
下一步是忽略非常大的数据文件和你不需要追踪的不重要文件(例如,notebook检查点,IDE的配置文件,pycache,.pyc,等等)。在上面的例子中,所有输入输出文件也应该忽略,因为它们完全可以由代码本身确定,如果需要,可以重新生成。
频繁提交
如果你完成了合理数量的工作,提交一次。不要吝啬,频繁提交也许能帮助你避免堵塞。
明晰的提交信息
如果你提交得足够频繁,那么你的工作大概也会相当集中,这样提交信息可以写得更清晰。回溯不想要的改动时,再没有比根据恰当注解的提交历史快速找到目标更令人满足的了。如果你找到的描述是这样的:“实现了3个新特性,增加了dropout,创建了交叉验证组件,同时重构了训练逻辑”,那么你提交得不够频繁。
反馈
我在尝试不同策略的过程中逐渐积累了这些想法。如果你有不同的做法,欢迎留言分享!
全部0条评论
快来发表一下你的评论吧 !