用深度学习每次得到的结果都不一样,怎么办?

神经网络算法利用了随机性,比如初始化随机权重,因此用同样的数据训练同一个网络会得到不同的结果。

初学者可能会有些懵圈,因为算法表现得不太稳定。但实际上它们就是这么设计的。随机初始化可以让网络通过学习,得到一个所学函数的很好的近似。

然而, 有时候用同样的数据训练同一个网络,你需要每次都得到完全相同的结果。例如在教学和产品上。

在这个教程中,你会学到怎样设置随机数生成器,才能每次用同样的数据训练同一网络时,都能得到同样的结果。

我们开始。

教程概览

这个教程分为六部分:

  1. 为啥我每次得到的结果都不一样?
  2. 不同结果的演示
  3. 解决方法
  4. 用Theano 后端设置随机数种子
  5. 用TensorFlow 后端设置随机数种子
  6. 得到的结果还是不同,咋办?

运行环境

  • 该教程需要你安装了Python SciPy。你能用Python2或3来演示这个例子
  • 需要你安装Keras (v2.0.3+),后台为TensorFlow (v1.1.0+)或Theano (v0.9+)
  • 还需要你安装了scikit-learn,Pandas,NumPy以及Matplotlib

如果在Python环境的设置方面需要帮助,请看下面这个帖子:

How to Setup a Python Environment for Machine Learning and Deep Learning with Anaconda

为啥我每次得到的结果都不一样?

我发现这对神经网络和深度学习的初学者而言是个常见问题。

这种误解可能出于以下问题:

  • 我如何得到稳定的结果?
  • 我如何得到可重复的结果
  • 我应该如何设置种子点

神经网络特意用随机性来保证,能通过有效学习得到问题的近似函数。采用随机性的原因是:用它的机器学习算法,要比不用它的效果更好。

在神经网络中,最常见的利用随机性的方式是网络权值的随机初始化,尽管在其他地方也能利用随机性,这有一个简短的清单:

  • 初始化的随机性,比如权值
  • 正则化的随机性,比如dropout
  • 层的随机性,比如词嵌入
  • 最优化的随机性,比如随机优化

这些甚至更多的随机性来源意味着,当你对同一数据运行同一个神经网络算法时,注定得到不同的结果。

想了解更多关于随机算法的原委,参考下面的帖子

Embrace Randomness in Machine Learning

不同结果的演示

我们可以用一个小例子来演示神经网络的随机性.

在这一节中,我们会建立一个多层感知器模型来学习一个以0.1为间隔的从0.0到0.9的短序列。给出0.0,模型必须预测出0.1;给出0.1,模型必须预测出0.2;以此类推。

下面是准备数据的代码

 # create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df.shift(1), df], axis=1)
df.dropna(inplace=True)
# convert to MLPfriendly format
values = df.values
X, y = values[:,0], values[:,1]    

我们要用的网络,有1个输入,10个隐层节点和1个输出。这个网络将采用均方差作为损失函数,用高效的ADAM算法来训练数据

这个网络需要约1000轮才能有效的解决这个问题,但我们只对它训练100轮。这样是为了确保我们在预测时能得到一个有误差的模型。

网络训练完之后,我们要对数据集进行预测并且输出均方差

建立网络的代码如下

 # design network
model = Sequential()
model.add(Dense(10, input_dim=1))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
# fit network
model.fit(X, y, epochs=100, batch_size=len(X), verbose=0)
# forecast
yhat = model.predict(X, verbose=0)
print(mean_squared_error(y, yhat[:,0]))    

在这个例子中,我们要建立10次网络并且输出10个不同的网络得分

完整的代码如下

from pandas import DataFrame
from pandas import concat
from keras.models import Sequential
from keras.layers import Dense
from sklearn.metrics import mean_squared_error

# fit MLP to dataset and print error
def fit_model(X, y):
# design network
model = Sequential()
model.add(Dense(10, input_dim=1))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
# fit network
model.fit(X, y, epochs=100, batch_size=len(X), verbose=0)
# forecast
yhat = model.predict(X, verbose=0)
print(mean_squared_error(y, yhat[:,0]))

# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df.shift(1), df], axis=1)
df.dropna(inplace=True)
# convert to MLP friendly format
values = df.values
X, y = values[:,0], values[:,1]
# repeat experiment
repeats = 10
for _ in range(repeats):
fit_model(X, y)    

运行这个例子会在每一行输出一个不同的精确值,具体结果也都不同。

下面是一个输出的示例

0.0282584265697
0.0457025913022
0.145698137198
0.0873461454407
0.0309397604521
0.046649185173
0.0958450337178
0.0130660263779
0.00625176026631
0.00296055161492    

解决方案

下面是两个主要的解决方案。

解决方案#1:重复实验

解决这个问题传统且切实可行的方法是多次运行网络(30+),然后运用统计学方法概括模型的性能,并与其他模型作比较。

我强烈推荐这种方法,但是由于有些模型的训练时间太长,这种方法并不总是可行的。

解决方案#2:设置随机数字生成器的种子

另一种解决方案是为随机数字生成器使用固定的种子。

随机数由伪随机数生成器生成。一个随机生成器就是一个数学函数,该函数将生成一长串数字,这些数字对于一般目的的应用足够随机。

随机生成器需要一个种子点开启该进程,在大多数实现中,通常默认使用以毫秒为单位的当前时间。这是为了确保,默认情况下每次运行代码都会生成不同的随机数字序列。该种子点可以是指定数字,比如“1”,来保证每次代码运行时生成相同的随机数序列。只要运行代码时指定的种子的值不变,它是什么并不重要。

设置随机数生成器的具体方法取决于后端,我们将探究下在Theano和TensorFlow后端下怎样做到这点。

用Theano后端设置随机数种子

通常,Keras从NumPy随机数生成器中获得随机源。

大部分情况下,Theano后端也是这样。

我们可以通过从random模块中调用seed()函数的方式,设置NumPy随机数生成器的种子,如下面所示:

 from numpy.random import seed
seed(1)    

最好在代码文件的顶部导入和调用seed函数。

这是最佳的实现方式(best practice),这是因为当各种各样的Keras或者Theano(或者其他的)库作为初始化的一部分被导入时,甚至在直接使用他们之前,可能会用到一些随机性。

我们可以在上面示例的顶端再加两行,并运行两次。

每次运行代码时,可以看到相同的均方差值的列表(在不同的机器上可能会有一些微小变化,这取决于机器的精度),如下面的示例所示:

0.169326527063
2.75750621228e-05
0.0183287291562
1.93553737255e-07
0.0549871087449
0.0906326807824
0.00337575114075
0.00414857518259
8.14587362008e-08
0.0522927019639    

你的结果应该跟我的差不多(忽略微小的精度差异)。

用TensorFlow后端设置随机数种子

Keras从NumPy随机生成器中获得随机源,所以不管使用Theano或者TensorFlow后端的哪一个,都必须设置种子点。

必须在其他模块的导入或者其他代码之前,文件的顶端部分通过调用seed()函数设置种子点。

from numpy.random import seed
seed(1)    

另外,TensorFlow有自己的随机数生成器,该生成器也必须在NumPy随机数生成器之后通过立马调用 set_random_seed() 函数设置种子点。

from tensorflow import set_random_seed
set_random_seed(2)    

要明确的是,在代码文件的顶端,在其他之前,一定要有以下4行:

from numpy.random import seed
seed(1)
from tensorflow import set_random_seed
set_random_seed(2)    

你可以使用两个相同或者不同的种子。我认为这不会造成多大差别,因为随机源进入了不同的进程。

在以上示例中增加这4行,可以使代码每次运行时都产生相同的结果。你应该看到与下面列出的相同的均方差值(也许有一些微小差别,这取决于不同机器的精度):

0.224045112999
0.00154879478823
0.00387589994044
0.0292376881968
0.00945528404353
0.013305765525
0.0206255228201
0.0359538356108
0.00441943512128
0.298706569397    

你的结果应该与我的差不多(忽略精度的微小差异)。

如果我仍然得到不同的结果,怎么办?

为了重复迭代,报告结果和比较模型鲁棒性最好的做法是多次(30+)重复实验,并使用汇总统计。如果这是不可行的,你可以通过为代码使用的随机数发生器设置种子来获得100%可重复的结果。

如果你已经按照上面的说明去做,仍然用相同的数据从相同的算法中获得了不同的结果,怎么办?

这可能是有其他的随机源你还没有考虑到。

来自第三方库的随机性

也许你的代码使用了另外的库,该库使用不同的也必须设置种子的随机数生成器。

试着将你的代码简化到最低要求(例如,一个数据样本,一轮训练等等),并仔细阅读API文档,尽力减少可能引入随机性的第三方库。

使用GPU产生的随机性

以上所有示例都假设代码是在一个CPU上运行的。

这种情况也是有可能的,就是当使用GPU训练模型时,可能后端设置的是使用一套复杂的GPU库,这些库中有些可能会引入他们自己的随机源,你可能会或者不会考虑到这个。

例如,有证据显示如果你在堆栈中使用了 Nvidia cuDNN,这可能引入额外的随机源( introduce additional sources of randomness),并且使结果不能准确再现。

来自复杂模型的随机性

由于模型的复杂性和训练的并行性,你可能会得到不可复现的结果。

这很可能是由后端库的效率造成的,或者是不能在内核中使用随机数序列。我自己没有遇到过这个,但是在一些GitHub问题和StackOverflowde问题中看到了一些案例。

如果只是缩小成因的范围的话,你可以尝试降低模型的复杂度,看这样是否影响结果的再现。

我建议您阅读一下你的后端是怎么使用随机性的,并看一下是否有任何选项向你开放。在Theano中,参考:

在TensorFlow中,参考:

Constants, Sequences, and Random Values

tf.set_random_seed

另外,为了更深入地了解,考虑一下寻找拥有同样问题的其他人。一些很好的搜寻平台包括GitHub、StackOverflow 和 CrossValidated。

总 结

在本教程中,你了解了如何在Keras上得到神经网络模型的可重复结果。特别是,你学习到了:

  • 神经网络是有意设计成随机的,固定随机源可以使结果可复现。
  • 你可以为NumPy和TensorFlow的随机数生成器设置种子点,这将使大多数的Keras代码100%的可重复使用。
  • 在有些情况下存在另外的随机源,并且你知道如何找出他们,或许也是固定它们。

via machine learning mastery,雷锋网崔静闯、朱婷编译

====================================分割线================================

本文作者:崔静闯

本文转自雷锋网禁止二次转载,原文链接

时间: 2024-08-02 10:20:52

用深度学习每次得到的结果都不一样,怎么办?的相关文章

深度学习的这些坑你都遇到过吗?神经网络 11 大常见陷阱及应对方法

如果你的神经网络不工作,该怎么办?本文作者列举了搭建神经网络时可能遇到的11个常见问题,包括预处理数据.正则化.学习率.激活函数.网络权重设置等,并提供解决方法和原因解释,是深度学习实践的有用资料. 如果你的神经网络不工作,该怎么办?作者在这里列出了建神经网络时所有可能做错的事情,以及他自己的解决经验. 忘记规范化数据 忘记检查结果 忘记预处理数据 忘记使用正则化 使用的batch太大 使用了不正确的学习率 在最后层使用了错误的激活函数 你的网络包含了Bad Gradients 初始化网络权重不

第30届IROS正式开幕,深度学习当道的机器人会议都有什么精彩亮点?(多图)

2017年9月25日,全球机器人规模最大的学术会议之一.IROS(International Conference on Intelligent Robots and Systems,国际智能机器人与系统大会)在加拿大温哥华正式开幕,来自全球各地的2000多名机器人方面的专家和学者参加了本次会议. (展会现场的IROS历届举办城市海报) 自1988年在日本举办首届IROS以来,今年正好是第30届IROS,大会的主办方也特地收集了30年来的历届IROS照片和视频.随着正会的开场,今天的会场也进行了

深度学习盛会ICLR2017最佳论文都是啥?,雷锋网带你5min过重点(附论文链接)

雷锋网编者按:万众瞩目的2017年ICLR 于今天在法国召开.该大会是Yann LeCun .Yoshua Bengio 等几位行业顶级专家于2013年发起.别看它历史不长,影响力却不小,如今已成为深度学习领域一个至关重要的学术盛事. 据雷锋网消息,ICLR论文评选结果于今日新鲜出炉.经过列为评委的火眼金睛,在507份论文中共有15篇论文成功进入口头展示阶段,181篇进入海报展示阶段.                                除了这些被选入ICLR 2017的论文,还有三篇

【深度学习框架大PK】褚晓文教授:五大深度学习框架三类神经网络全面测评(23PPT)

香港浸会大学褚晓文教授团队在2016年推出深度学习工具评测的研究报告,并在2017年年初发布更新,引起广泛关注.见新智元报道< 基准评测 TensorFlow.Caffe.CNTK.MXNet.Torch 在三类流行深度神经网络上的表现(论文)>,2017年初版本的评测的主要发现可概括如下: 总体上,多核CPU的性能并无很好的可扩展性.在很多实验结果中,使用16核CPU的性能仅比使用4核或8核稍好.TensorFlow在CPU环境有相对较好的可扩展性. 仅用一块GPU卡的话,FCN上Caffe

深度学习网络大杀器之Dropout(II)——将丢弃学习视为集成学习之我见

首发地址:https://yq.aliyun.com/articles/110002 更多深度文章,请关注云计算频道:https://yq.aliyun.com/cloud 关于dropout的分析,可以见博主的另外一篇文章: <深度学习网络大杀器之Dropout--深入解析Dropout> 1.引言 随着2012年Hiton的文章<ImageNet classification with deep convolutional neural networks>[1]的问世,掀开了学

深度学习在美团点评推荐平台排序中的运用

引言 自2012年ImageNet大赛技惊四座后,深度学习已经成为近年来机器学习和人工智能领域中关注度最高的技术.在深度学习出现之前,人们借助SIFT.HOG等算法提取具有良好区分性的特征,再结合SVM等机器学习算法进行图像识别.然而SIFT这类算法提取的特征是有局限性的,导致当时比赛的最好结果的错误率也在26%以上.卷积神经网络(CNN)的首次亮相就将错误率一下由26%降低到15%,同年微软团队发布的论文中显示,通过深度学习可以将ImageNet 2012资料集的错误率降到4.94%. 随后的

Caffe2:移动计算的深度学习框架

文章讲的是Caffe2:移动计算的深度学习框架,Caffe2是Facebook新的开源深度学习框架.与之前的PyTorch不同,Caffe2专门用于将深度学习移植到移动应用程序中,这将会让智能手机更"深入".更智能! 如果你认为深度学习还只是一个概念,你就错了.世界各地的研究实验室都试图开发高效快速的软件框架,使研究人员或程序员能够实施和测试深度学习模型.现在,每个新的高效深度学习框架的发布,都意味着研究有了新进展,Caffe2就是最好的证明. Caffe2是Facebook为移动计算

中国人工智能学会通讯——深度学习在自然语言处理领域的最新进展

下面我来介绍一下深度学习在自然语言处理(NLP)的最新进展.我主要想针对机器翻译.聊天机器人和阅读理解这三个最活跃的方向来探讨深度学习在NLP领域的发展到了什么水平,还存在什么问题,然后再引申出未来的研究方向. 上图是自然语言处理主要技术的一览图.从左开始,第一列是自然语言的基本技术,包括词汇级.短语级.句子级和篇章级的表示,比如词的多维向量表示(word embedding).句子的多维向量表示,还有就是分词.词性标记.句法分析和篇章分析.第二列和第三列是自然语言的核心技术,包括机器翻译.提问

2017就在眼前,深度学习有哪十大趋势值得关注?

雷锋网按:本文作者 Carlos E. Perez ,他来自机器学习技术公司 Intuition Machine,主要研究深度学习类型.方法论.以及行业战略. 发布于 Medium 的这篇文章主要对 2017 年深度学习的十大趋势做出了预测,雷锋网(公众号:雷锋网)编译,未经许可不得转载. 作为一名人工智能领域里的圈内人士,上次写科技预测要追溯到 6 年前了,当时我写了一篇"2011 软件开发趋势及预测"的文章,文中对行业做了十点预测,其中六个预测准确,分别是 Javascript V