# 工程工作流程研究

原文链接：[工程工作流程研究](http://dustintran.com/blog/a-research-to-engineering-workflow?from=hackcv&hmsr=hackcv.com&utm_medium=hackcv.com&utm_source=hackcv.com)

从研究理念到实验是至关重要的。但是这个步骤通常只有很少的明确建议。在学术界，研究生常常会分散各种各样的代码，各种各样的笔记和散落的LaTeX文章。新项目通常会产生全新的代码库，如果它们依赖于过去的代码，则难以适当地扩展到这些新项目。

受此启发，我认为概述我个人从研究思路到实验所采取的步骤，以及如何改善我的研究理解，以便我可以修改这个想法。这个过程至关重要：给出一个初步的想法，我所有的时间都用在这个过程上; 至少对我来说，实验是学习和解决我无法预测的问题的关键。[1](http://dustintran.com/blog/a-research-to-engineering-workflow?from=hackcv&hmsr=hackcv.com&utm_medium=hackcv.com&utm_source=hackcv.com#references)

## 找到正确的问题

在开展项目之前，有必要决定如何将想法推向更正式的事物。有时它就像导师建议一个项目一样简单; 或处理特定数据集或应用问题; 或者与频繁的合作者进行对话，然后找出有用的问题一起工作。更常见的是，我发现研究是一系列思想的结果，这些思想不断被迭代 - 通过频繁的对话，最近的工作，对我不熟悉的科目的长期阅读（例如，[Pearl（2000）](http://dustintran.com/blog/a-research-to-engineering-workflow?from=hackcv&hmsr=hackcv.com&utm_medium=hackcv.com&utm_source=hackcv.com#pearl2000causality)），以及最喜欢的我想重温的论文（例如，[Wainwright＆Jordan（2008）](http://dustintran.com/blog/a-research-to-engineering-workflow?from=hackcv&hmsr=hackcv.com&utm_medium=hackcv.com&utm_source=hackcv.com#wainwright2008graphical)，[Neal（1994）](http://dustintran.com/blog/a-research-to-engineering-workflow?from=hackcv&hmsr=hackcv.com&utm_medium=hackcv.com&utm_source=hackcv.com#neal1994bayesian)）。

[![IMG](https://camo.githubusercontent.com/f4f85e4b2e1b8fa4c5a0fa8ca7b3716fdd13010d/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967302e706e67)](https://camo.githubusercontent.com/f4f85e4b2e1b8fa4c5a0fa8ca7b3716fdd13010d/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967302e706e67)

*我所有未开发的研究思路的主文件。*

我发现一种非常有用的技术是维护一个主文档。[2](http://dustintran.com/blog/a-research-to-engineering-workflow?from=hackcv&hmsr=hackcv.com&utm_medium=hackcv.com&utm_source=hackcv.com#references)它做了一些事情。

首先，它有一个包含所有想法，问题和主题的项目符号列表，我想更仔细地考虑一下（图中的1.3节）。有时它们与“强化学习的贝叶斯/生成方法”或“解决机器学习的公平性”一样高; 或者它们与“用于处理EP中的存储器复杂性的推理网络”或“尺寸偏差与对称Dirichlet先验的分析”一样具体。我试着保持清单简洁：后续部分深入讨论特定条目（图中的第2节）。

其次，根据我接下来要做的工作对想法列表进行排序。这引导我理解我的研究超越当前工作的总体方向。我可以根据我是否认为方向与我更广泛的研究愿景一致，以及我是否认为这个方向对整个社会有一定影响而不断修改我的优先事项。重要的是，该列表不仅仅是关于下一个可以发表的可发表的想法，而且通常是我接下来要学习的内容。这有助于长期发现重要问题并找到简单或新颖的解决方案。

每隔一段时间，我就会重新审视清单，诉诸事物，添加内容，删除内容。最终，我可能会详细阐述一个想法，使其成为一份正式的论文。总的来说，我发现这个在一个位置（和一种格式）内迭代思想的过程使得向正式的论文写作和实验过渡成为一种流畅的体验。

## 管理论文

[![IMG](https://camo.githubusercontent.com/0c2534e468fd58112614fffc66d0cdd4bc1c5737/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967352e706e67)](https://camo.githubusercontent.com/0c2534e468fd58112614fffc66d0cdd4bc1c5737/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967352e706e67)

好的研究需要阅读*大量*论文。如果没有一个好的方式来组织你的阅读，你很容易被这个领域的匆忙节奏所淹没。（过去几周在试图赶上向arXiv发布的大量NIPS提交文件时尤其臭名昭着。）

我已经尝试了很多方法，最终我得到了我强烈推荐的[Papers应用程序](http://papersapp.com/)

良好管理系统中最基本的实用程序是集中式存储库，可以回来参考。无论是8页会议论文，期刊论文，调查甚至教科书，都有一个位置的优势不容小觑。此外，Papers是一个实际阅读PDF的好工具，它可以在我阅读和平板电脑或笔记本电脑上的东西时方便地同步设备。当我写作时，我会引用论文，我可以回到Papers并获得相应的BibTeX文件（配置文件）和citekey。

我个人喜欢在组织论文时付出艰辛的努力。在上面的截图中，我有一个庞大的主题列表纸质标签。这些范围从`applications（应用程序）`，`models（模型）`，`inference（推理）`（每个子标签），并且也有杂主题，如`information-theory（信息论）`和`experimental-design（实验设计）`。截图中未显示的一个重要集合是一个名为的标签`research`，我将所有与特定研究主题相关的论文都包含在内。例如，目前突出显示[的PixelGAN论文](https://arxiv.org/abs/1706.00531)被标记为我目前一直在思考的两个主题 - 这些主题分为`research→alignment-semi`和`research→generative-images`。

## 管理项目

[![IMG](https://camo.githubusercontent.com/b36c06c4a5c8578dff3414cb9d7f009582aef0df/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967312e706e67)](https://camo.githubusercontent.com/b36c06c4a5c8578dff3414cb9d7f009582aef0df/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967312e706e67)

*我们用于最近的arXiv预印本的存储库。*

我想在一个Github存储库中维护一个研究项目。它们不仅可用于跟踪代码，还可用于跟踪一般研究进展，论文写作以及与其他人的协作联系起来。如何组织Github存储库是一个常见的痛点。我喜欢以下结构，最初来自[Dave Blei的首选](http://www.cs.columbia.edu/~blei/seminar/2016_discrete_data/notes/week_01.pdf)结构：

```
-- doc/
  -- 2017-nips/
    -- preamble/
    -- img/
    -- main.pdf
    -- main.tex
    -- introduction.tex
-- etc/
  -- 2017-03-25-whiteboard.jpg
  -- 2017-04-03-whiteboard.jpg
  -- 2017-04-06-dustin-comments.md
  -- 2017-04-08-dave-comments.pdf
-- src/
  -- checkpoints/
  -- codebase/
  -- log/
  -- out/
  -- script1.py
  -- script2.py
-- README.md
```

`README.md`为我自己和合作者维护一份待办事项列表。这使得如何继续前进以及阻碍工作的方式变得透明。

`doc/`包含所有的报道。每个子目录对应于特定的会议或日记提交，其中`main.tex`主要文档和各个部分用不同的文件编写，例如`introduction.tex`。保留每个文件一个部分使多个人可以轻松地同时处理不同的部分并避免合并冲突。有些人喜欢在主要实验完成后写完整篇论文。我个人更喜欢写一篇论文作为当前想法的总结，并且与想法本身一样，它随着实验的进行而不断修订。

`etc/`是与其他目录无关的内容的转储。我通常用它来存储关于项目的对话的白板图片。或者有时因为我正在处理我的日常工作，我对一堆想法很震惊，因此我将它们转储到Markdown文档中。它也是处理有关工作的各种评论的便利位置，例如来自协作者的一般反馈或纸质标记。

`src/`是所有代码存放的地方。Runnable脚本直接编写`src/`，并编写类和实用程序`codebase/`。我接下来会详细说明。（其他三个是从脚本输出的目录，我也将详细说明。）

## 编写代码

[![IMG](https://camo.githubusercontent.com/8044da6bcb1fce3603e59588316d3caffa1f6f1d/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967322e706e67)](https://camo.githubusercontent.com/8044da6bcb1fce3603e59588316d3caffa1f6f1d/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967322e706e67)

我现在写的任何代码都使用[Edward](http://edwardlib.org/)。我发现它是快速试验现代概率模型和算法的最佳框架。

在概念层面上，爱德华的吸引力是因为语言明确地遵循了数学：模型的生成过程转化为爱德华代码的特定线; 然后，所提出的算法转换为下一行; 当试图用自然研究问题扩展代码时，这种干净的翻译避免了未来的抽象难题：例如，如果我使用不同的先验，或调整梯度估计，或尝试不同的神经网络架构，或在大规模数据集上应用该方法该怎么办？

在实践层面上，我通过建立预先存在的模型示例（in [`edward/examples/`](https://github.com/blei-lab/edward/tree/master/examples)或[`edward/notebooks/`](https://github.com/blei-lab/edward/tree/master/notebooks)），然后使其适应我的问题，从而最大程度上受益于Edward 。如果我也在实现一个新算法，我会使用预先存在的算法的源代码（in [`edward/inferences/`](https://github.com/blei-lab/edward/tree/master/edward/inferences)），将其粘贴为我的研究项目`codebase/`目录中的新文件，然后我调整它。这个过程使得从模板重新开始并避免低级细节变得非常容易。

在编写代码时，我总是遵循PEP8（我特别喜欢这个[`pep8`](https://pypi.python.org/pypi/pep8)包），并尝试将各个脚本与脚本之间共享的类和函数定义分开; 后者放在里面`codebase/`然后导入。从一开始就保持代码质量始终是一项很好的投资，我发现这个过程可以很好地扩展，因为代码变得越来越复杂并且与其他人一起工作。

**在Jupyter笔记本上。**许多人使用[Jupyter笔记本](http://jupyter.org/)作为交互式代码开发的方法，并且作为嵌入可视化和LaTeX的简单方法。我个人没有成功将其集成到我的工作流程中。我喜欢在Python脚本中编写所有代码，然后运行脚本。但我可以看到为什么其他人喜欢互动。

## 管理实验

[![IMG](https://camo.githubusercontent.com/ae3e351706f9e0ff04a8ee0e067021555e9c98a1/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967332e706e67)](https://camo.githubusercontent.com/ae3e351706f9e0ff04a8ee0e067021555e9c98a1/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967332e706e67)

投资一个好的工作站或云服务是必须的。GPU等功能基本上应该具有[广泛的可用性](http://timdettmers.com/2017/04/09/which-gpu-for-deep-learning/)，并且应该能够并行运行多个作业。

在我的本地计算机上完成脚本编写后，我的典型工作流程是：

1. 运行`rsync`以将本地计算机的Github存储库（包括未提交的文件）与服务器中的目录同步;
2. `ssh` 进入服务器。
3. 启动`tmux`并运行脚本。在许多方面，`tmux`让您分离会话，这样您就不必在再次与服务器交互之前等待作业完成。

当脚本合情合理时，我开始深入研究多个超参数配置的实验。一个有用的工具是[`argparse`](https://docs.python.org/3/library/argparse.html)。它使用命令行参数扩充Python脚本，您可以在脚本中添加以下内容：

```
parser = argparse.ArgumentParser()
parser.add_argument('--batch_size', type=int, default=128,
                    help='Minibatch during training')
parser.add_argument('--lr', type=float, default=1e-5,
                    help='Learning rate step-size')
args = parser.parse_args()

batch_size = args.batch_size
lr = args.lr
```

然后你可以运行终端命令，如

```
python script1.py --batch_size=256 --lr=1e-4
```

这使得提交改变这些超参数的服务器作业变得容易。

最后，我们来谈谈管理实验的输出。回想一下`src/`上面的目录结构：

```
-- src/
  -- checkpoints/
  -- codebase/
  -- log/
  -- out/
  -- script1.py
  -- script2.py
```

我们描述了各个脚本和`codebase/`。其他三个目录用于组织实验输出：

- `checkpoints/`记录训练期间保存的模型参数。使用`tf.train.Saver`的算法运行的迭代的每一个固定号码，储存的参数。这有助于运行长时间的实验，您可能希望缩短实验并稍后恢复参数。每个实验都输出一个`checkpoints/`带有约定的子目录`20170524_192314_batch_size_25_lr_1e-4/`。第一个数字是date（`YYYYMMDD`）; 第二个是时间戳（`%H%M%S`）; 其余的是超参数。
- `log/`记录可视化学习的日志。每个实验都属于一个子目录，其约定与`checkpoints/`。爱德华的一个好处是，对于日志记录，您可以简单地将参数传递为`inference.initialize(logdir='log/' + subdir)`。跟踪默认的TensorFlow摘要，然后可以使用TensorBoard对其进行可视化（接下来将详细介绍）。
- `out/`记录训练结束后的探索性输出; 例如，生成的图像或matplotlib图。每个实验都属于一个子目录，其约定与`checkpoints/`。

**在数据集上。**数据集用于许多研究项目。我更喜欢将它们存储在主目录中`~/data`。

**在软件容器上。** [virtualenv](http://python-guide-pt-br.readthedocs.io/en/latest/dev/virtualenvs/)是管理Python依赖项和避免系统范围Python安装困难的必备工具。如果你喜欢编写Python 2/3不可知代码，那就特别好了。如果您需要更多设置，[Docker容器](https://www.docker.com/)是一个更强大的工具。

## 探索，调试和诊断

[![IMG](https://camo.githubusercontent.com/de52d78ff8d22cdb62af0ed9fd2c2d9c33595337/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967342e706e67)](https://camo.githubusercontent.com/de52d78ff8d22cdb62af0ed9fd2c2d9c33595337/687474703a2f2f64757374696e7472616e2e636f6d2f626c6f672f6173736574732f323031372d30362d30332d666967342e706e67)

[Tensorboard](https://www.tensorflow.org/get_started/summaries_and_tensorboard)是用于可视化和探索模型训练的出色工具。通过TensorBoard的交互性，我发现它特别方便，因为我不需要配置一堆matplotlib函数来理解训练。人们只需要`tf.summary`在代码中渗透一堆张量。

Edward默认记录了一堆摘要，以便可视化损失函数值，渐变和参数在训练迭代中的变化。TensorBoard还包括壁时间比较，并且充分装饰的TensorFlow代码库提供了一个可以盯着的漂亮计算图。对于细微问题，我无法专门用TensorBoard诊断，我只是在`out/`目录中输出内容并检查这些结果。

**调试错误消息。**我的调试工作流程非常糟糕。我在我的代码中渗透打印语句，并通过消除过程发现错误。这是原始的。虽然我没有尝试过，但我听说[TensorFlow的调试器](https://www.tensorflow.org/programmers_guide/debugger)很好。

## 提高研究理解

通过询问您的模型，算法以及学习过程，您可以更好地了解工作的成功和失败模式。这使您可以回到绘图板，深入思考方法以及如何进一步改进。由于该方法表明成功，人们可以从解决简单的玩具配置到越来越大规模和高维度的问题。

从更高的层面来看，这个工作流程实际上是关于在现实世界中实施科学方法。在实验过程的每次迭代中都不一定要丢弃重要的想法，而是在科学的理想中，你从基础知识开始，并在你对现实有更强的把握时反复扩展它们。

在这个过程中，实验并不孤单。协作，与其他领域的专家交流，阅读论文，研究短期和长期的想法，参加会谈和会议，有助于拓宽您找到正确问题和解决问题的视角。

## 注解和参考

1此工作流程专门用于实证研究。理论是另一种蠕虫，但其中一些思想仍然概括。

2可以使用主文档的模板[`here`](https://github.com/dustinvtran/latex-templates)。

3 Papers有一点需要注意。我将它用于所有事情：我的帐户中至少存储了2,000篇论文，并且有相当多的密集教科书。该应用程序至少可以筛选出6个千兆字节，因此在阅读/引用许多文件时会遇到一些小问题。我不知道这是否是一个错误或只是固有的对我论文利用几乎*过*了。

1. Neal，RM（1994）。*神经网络的贝叶斯学习*（博士论文）。多伦多大学。
2. Pearl，J。（2000）。*因果关系*。剑桥大学出版社。
3. Wainwright，MJ，＆Jordan，MI（2008）。图形模型，指数族和变分推理。*机器学习的基础和趋势*，*1*（1-2），1-305。