为什么CNN的准确性无法重现?

时间:2017-02-19 11:07:07

标签: python numpy tensorflow

我希望我训练的CNN可重现的结果。因此我将种子设置在my script

import tensorflow as tf
tf.set_random_seed(0)  # make sure results are reproducible
import numpy as np
np.random.seed(0)  # make sure results are reproducible

set_random_seednp.random.seed的文档不会报告0种子的任何特殊行为。

当我在几分钟内在同一台机器上运行相同的脚本两次并且没有进行更新时,我希望得到相同的结果。但事实并非如此:

运行1:

0;0.001733;0.001313
500;0.390164;0.388188

运行2:

0;0.006986;0.007000
500;0.375288;0.374250

如何让网络产生可重复的结果?

系统

$ python -c "import tensorflow;print(tensorflow.__version__)"                
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 locally
1.0.0

$ python -c "import numpy;print(numpy.__version__)"
1.12.0

2 个答案:

答案 0 :(得分:4)

虽然我没有解决问题,但可能的原因可能是为什么结果并不总是相同的(大致从最可能/最容易修复到最不可能/最难修复的顺序)。我也试着在问题出现后给出一个解决方案。

  1. 人为错误 - 当您将结果从一个shell复制到纸张时,您错过了一个数字/输错:记录。为您运行的每个实验创建2017-12-31-23-54-experiment-result.log。不是手动的, 但实验创造了它。是的,名称中的时间戳更容易找到它。对于每个单独的实验,所有以下内容都应记录到该文件中。
  2. 代码已更改:版本控制(例如git)
  3. 配置文件已更改:版本控制
  4. 伪随机数已更改:为random / tensorflow / numpy设置种子(是的,您可能需要设置多个种子)
  5. 数据加载不同/以不同的顺序:版本控制+种子(预处理真的一样吗?)
  6. 环境变量已更改:Docker
  7. 软件(版本)已更改:Docker
  8. 驱动程序(版本)已更改:正在记录
  9. 硬件已更改:正在记录
  10. 硬件/软件存在一些重复性问题。例如,floating point multiplication is not associative和GPU上的不同核心可能在不同时间完成计算(我不确定)
  11. 硬件有错误
  12. 在任何情况下,多次运行“相同”的东西可能有助于深入了解不同的东西。

    写论文

    如果你写论文,我认为以下是重复性的最佳实践:

    1. 添加指向存储库的链接(例如git),其中所有代码均为
    2. 代码必须容器化(例如Docker)
    3. 如果有Python代码和requirements.txt,您必须提供完全软件版本,而不是tensorflow>=1.0.0tensorflow==1.2.3
    4. 添加您用于实验的版本的 git hash 。如果你改变了某些东西,它可能是不同的哈希。
    5. 始终记录有关驱动程序(例如like this for nVidia)和硬件的信息。将其添加到论文的附录中。因此,如果以后进行更改,至少可以检查是否存在可能导致数字不同的更改。
    6. 要记录版本,您可能希望使用以下内容:

      #!/usr/bin/env python
      
      # core modules
      import subprocess
      
      
      def get_logstring():
          """
          Get important environment information that might influence experiments.
      
          Returns
          -------
          logstring : str
          """
          logstring = []
          with open('/proc/cpuinfo') as f:
              cpuinfo = f.readlines()
          for line in cpuinfo:
              if "model name" in line:
                  logstring.append("CPU: {}".format(line.strip()))
                  break
      
          with open('/proc/driver/nvidia/version') as f:
              version = f.read().strip()
          logstring.append("GPU driver: {}".format(version))
          logstring.append("VGA: {}".format(find_vga()))
          return "\n".join(logstring)
      
      
      def find_vga():
          vga = subprocess.check_output("lspci | grep -i 'vga\|3d\|2d'",
                                        shell=True,
                                        executable='/bin/bash')
          return vga
      
      
      print(get_logstring())
      

      给出类似

      的内容
      CPU: model name    : Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
      GPU driver: NVRM version: NVIDIA UNIX x86_64 Kernel Module  384.90  Tue Sep 19 19:17:35 PDT 2017
      GCC version:  gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5)
      VGA: 00:02.0 VGA compatible controller: Intel Corporation Skylake Integrated Graphics (rev 06)
      02:00.0 3D controller: NVIDIA Corporation GM108M [GeForce 940MX] (rev a2)
      

答案 1 :(得分:1)

可能是范围问题。确保在您使用图表的范围内设置种子,例如:之后

with tf.Graph().as_default()
 tf.set_random_seed(0)

这也必须在致电tf.reset_default_graph()后完成。

有关完整示例,请参阅How to get stable results with TensorFlow, setting random seed