tensorflow 101

tensorflow的计算被表示为一个有向图(directed graph)

每一个运算操作(operation)将作为一个节点(node),节点与节点之间的连接称为边(edge)

每一个节点可以有任意多个输入和任意多个输出

每一个节点描述了一种运算操作,节点可看作运算操作的实例化(instance)

边中流动(flow)的数据被称为张量(tensor)

数据通信的问题转变为发送节点和接收节点的实现问题


 


 

tensorflow支持单独执行子图,可以选择任意子图,并沿某些边输入数据,同时从另一些边获取输出结果。

tensorflow用节点名加port的形式指定数据:例如bar:0表示名为bar的节点的第1个输出。

Session的Run方法执行子图。

几个概念


 


 

这些都是什么?


 

在本篇文章,我们将介绍一些深度学习中的常见概念,以帮助大家快速了解这个神奇的领域。


 

梯度可视化。图中红色箭头为蓝色函数对应的梯度。


 

梯度? (Nabla)


 

梯度是一个函数的偏导数,以多个向量作为输入,并输出一个单一的数值(即神经网络中的代价函数)。当我们需要使函数输出增加时,梯度能够告诉我们输入变量在图中的应变化的方向。我们在深度学习中应用梯度,并使用梯度的反方向来降低我们算法的损失。


 

后向传播


 

也称为反向传播,是指在网络中正向传播输入数据之后,反向传播误差并根据误差调整网络权重的过程。这种方法在实际应用时使用了微积分中的链式法则。


 

Sigmoid σ


 

用于将网络权重映射至[0, 1]区间的激活函数。该函数在图中的曲线类似一个字母’S’,函数因此得名,在希腊语中sigma表示字母S。该函数也被称为logistic函数。


 

Geoffrey Hinton定义的ReLU计算公式


 

校正线性单元或ReLU


 

sigmoid函数的值域限制在[0, 1]区间内,而ReLU的值域为0到正无穷。这意味着,sigmoid更适合logistic回归,而ReLU能够更好地表示正数输出。ReLU不会产生梯度消失问题。


 

Tanh函数


 

Tanh


 

Tanh函数是一个可将你的网络权重初始化为[-1, 1]区间内实数的函数。假设你的数据已经规范化,那么我们会得到一个更大的梯度:因为数据以0为中心分布,函数的导数更高。为了验证这点,我们计算tanh函数的导数,并观察函数在[0, 1]区间内的输入。tanh函数的值域为[-1, 1]区间,而sigmoid函数的值域为[0, 1]区间。这也避免了在梯度中的偏差。


 

LSTM/GRU


 

通常应用于递归神经网络,也可扩展至其他场景使用,其充当小型”记忆单元”,能够保持输入数据间的状态,用于模型训练,同时,也可解决梯度消失问题,梯度消失问题会导致递归神经网络在进行大约7次迭代后失去先前输入数据的上下文。


 


 

阅读全文请点击:http://click.aliyun.com/m/9025/


 

理解LSTM

Recurrent Neural Networks

人类并不是每时每刻都从一片空白的大脑开始他们的思考。在你阅读这篇文章时候,你都是基于自己已经拥有的对先前所见词的理解来推断当前词的真实含义。我们不会将所有的东西都全部丢弃,然后用空白的大脑进行思考。我们的思想拥有持久性。

传统的神经网络并不能做到这点,看起来也像是一种巨大的弊端。例如,假设你希望对电影中的每个时间点的时间类型进行分类。传统的神经网络应该很难来处理这个问题——使用电影中先前的事件推断后续的事件。

RNN 解决了这个问题。RNN 是包含循环的网络,允许信息的持久化。


 

RNN 包含循环

在上面的示例图中,神经网络的模块,A,正在读取某个输入 x_i,并输出一个值 h_i。循环可以使得信息可以从当前步传递到下一步。

这些循环使得 RNN 看起来非常神秘。然而,如果你仔细想想,这样也不比一个正常的神经网络难于理解。RNN 可以被看做是同一神经网络的多次复制,每个神经网络模块会把消息传递给下一个。所以,如果我们将这个循环展开:


 

展开的 RNN


 

链式的特征揭示了 RNN 本质上是与序列和列表相关的。他们是对于这类数据的最自然的神经网络架构。

并且 RNN 也已经被人们应用了!在过去几年中,应用 RNN 在语音识别,语言建模,翻译,图片描述等问题上已经取得一定成功,并且这个列表还在增长。我建议大家参考 Andrej Karpathy 的博客文章——The Unreasonable Effectiveness of Recurrent Neural Networks 来看看更丰富有趣的 RNN 的成功应用。

而这些成功应用的关键之处就是 LSTM 的使用,这是一种特别的 RNN,比标准的 RNN 在很多的任务上都表现得更好。几乎所有的令人振奋的关于 RNN 的结果都是通过 LSTM 达到的。这篇博文也会就 LSTM 进行展开。

长期依赖(Long-Term Dependencies)问题

RNN 的关键点之一就是他们可以用来连接先前的信息到当前的任务上,例如使用过去的视频段来推测对当前段的理解。如果 RNN 可以做到这个,他们就变得非常有用。但是真的可以么?答案是,还有很多依赖因素。

有时候,我们仅仅需要知道先前的信息来执行当前的任务。例如,我们有一个语言模型用来基于先前的词来预测下一个词。如果我们试着预测 “the clouds are in the sky” 最后的词,我们并不需要任何其他的上下文 —— 因此下一个词很显然就应该是 sky。在这样的场景中,相关的信息和预测的词位置之间的间隔是非常小的,RNN 可以学会使用先前的信息。


 

不太长的相关信息和位置间隔

但是同样会有一些更加复杂的场景。假设我们试着去预测”I grew up in France… I speak fluent French”最后的词。当前的信息建议下一个词可能是一种语言的名字,但是如果我们需要弄清楚是什么语言,我们是需要先前提到的离当前位置很远的 France 的上下文的。这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。

不幸的是,在这个间隔不断增大时,RNN 会丧失学习到连接如此远的信息的能力。


 

相当长的相关信息和位置间隔

在理论上,RNN 绝对可以处理这样的 长期依赖 问题。人们可以仔细挑选参数来解决这类问题中的最初级形式,但在实践中,RNN 肯定不能够成功学习到这些知识。Bengio, et al. (1994)等人对该问题进行了深入的研究,他们发现一些使训练 RNN 变得非常困难的相当根本的原因。

然而,幸运的是,LSTM 并没有这个问题!

LSTM 网络

Long Short Term 网络—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型,可以学习长期依赖信息。LSTM 由Hochreiter & Schmidhuber (1997)提出,并在近期被Alex Graves进行了改良和推广。在很多问题,LSTM 都取得相当巨大的成功,并得到了广泛的使用。

LSTM 通过刻意的设计来避免长期依赖问题。记住长期的信息在实践中是 LSTM 的默认行为,而非需要付出很大代价才能获得的能力!

所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层。


 

标准 RNN 中的重复模块包含单一的层


 

LSTM 同样是这样的结构,但是重复的模块拥有一个不同的结构。不同于 单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。


 

LSTM 中的重复模块包含四个交互的层


 

不必担心这里的细节。我们会一步一步地剖析 LSTM 解析图。现在,我们先来熟悉一下图中使用的各种元素的图标。


 

LSTM 中的图标


 

在上面的图例中,每一条黑线传输着一整个向量,从一个节点的输出到其他节点的输入。粉色的圈代表 pointwise 的操作,诸如向量的和,而黄色的矩阵就是学习到的神经网络层。合在一起的线表示向量的连接,分开的线表示内容被复制,然后分发到不同的位置。

LSTM 的核心思想

LSTM 的关键就是细胞状态,水平线在图上方贯穿运行。

细胞状态类似于传送带。直接在整个链上运行,只有一些少量的线性交互。信息在上面流传保持不变会很容易。


 

Paste_Image.png

LSTM 有通过精心设计的称作为”门”的结构来去除或者增加信息到细胞状态的能力。门是一种让信息选择式通过的方法。他们包含一个 sigmoid 神经网络层和一个 pointwise 乘法操作。


 

Paste_Image.png


 

Sigmoid 层输出 0 到 1 之间的数值,描述每个部分有多少量可以通过。0 代表”不许任何量通过”,1 就指”允许任意量通过”!

LSTM 拥有三个门,来保护和控制细胞状态。

逐步理解 LSTM

在我们 LSTM 中的第一步是决定我们会从细胞状态中丢弃什么信息。这个决定通过一个称为忘记门层完成。该门会读取 h_{t-1} 和 x_t,输出一个在 0 到 1 之间的数值给每个在细胞状态 C_{t-1} 中的数字。1 表示”完全保留”,0 表示”完全舍弃”。

让我们回到语言模型的例子中来基于已经看到的预测下一个词。在这个问题中,细胞状态可能包含当前主语的性别,因此正确的代词可以被选择出来。当我们看到新的主语,我们希望忘记旧的主语


 

决定丢弃信息


 

下一步是确定什么样的新信息被存放在细胞状态中。这里包含两个部分。第一,sigmoid 层称 “输入门层” 决定什么值我们将要更新。然后,一个 tanh 层创建一个新的候选值向量,\tilde{C}_t,会被加入到状态中。下一步,我们会讲这两个信息来产生对状态的更新。

在我们语言模型的例子中,我们希望增加新的主语的性别到细胞状态中,来替代旧的需要忘记的主语。


 

确定更新的信息

现在是更新旧细胞状态的时间了,C_{t-1} 更新为 C_t。前面的步骤已经决定了将会做什么,我们现在就是实际去完成。

我们把旧状态与 f_t 相乘,丢弃掉我们确定需要丢弃的信息。接着加上 i_t * \tilde{C}_t。这就是新的候选值,根据我们决定更新每个状态的程度进行变化。

在语言模型的例子中,这就是我们实际根据前面确定的目标,丢弃旧代词的性别信息并添加新的信息的地方。


 

更新细胞状态

最终,我们需要确定输出什么值。这个输出将会基于我们的细胞状态,但是也是一个过滤后的版本。首先,我们运行一个 sigmoid 层来确定细胞状态的哪个部分将输出出去。接着,我们把细胞状态通过 tanh 进行处理(得到一个在 -1 到 1 之间的值)并将它和 sigmoid 门的输出相乘,最终我们仅仅会输出我们确定输出的那部分。

在语言模型的例子中,因为他就看到了一个 代词,可能需要输出与一个 动词 相关的信息。例如,可能输出是否代词是单数还是负数,这样如果是动词的话,我们也知道动词需要进行的词形变化。


 

输出信息

LSTM 的变体

我们到目前为止都还在介绍正常的 LSTM。但是不是所有的 LSTM 都长成一个样子的。实际上,几乎所有包含 LSTM 的论文都采用了微小的变体。差异非常小,但是也值得拿出来讲一下。

其中一个流形的 LSTM 变体,就是由 Gers & Schmidhuber (2000) 提出的,增加了 “peephole connection”。是说,我们让 门层 也会接受细胞状态的输入。


 

peephole 连接

上面的图例中,我们增加了 peephole 到每个门上,但是许多论文会加入部分的 peephole 而非所有都加。

另一个变体是通过使用 coupled 忘记和输入门。不同于之前是分开确定什么忘记和需要添加什么新的信息,这里是一同做出决定。我们仅仅会当我们将要输入在当前位置时忘记。我们仅仅输入新的值到那些我们已经忘记旧的信息的那些状态 。


 

coupled 忘记门和输入门


 

另一个改动较大的变体是 Gated Recurrent Unit (GRU),这是由 Cho, et al. (2014) 提出。它将忘记门和输入门合成了一个单一的 更新门。同样还混合了细胞状态和隐藏状态,和其他一些改动。最终的模型比标准的 LSTM 模型要简单,也是非常流行的变体。


 

GRU


 

这里只是部分流行的 LSTM 变体。当然还有很多其他的,如Yao, et al. (2015) 提出的 Depth Gated RNN。还有用一些完全不同的观点来解决长期依赖的问题,如Koutnik, et al. (2014) 提出的 Clockwork RNN。

要问哪个变体是最好的?其中的差异性真的重要吗?Greff, et al. (2015) 给出了流行变体的比较,结论是他们基本上是一样的。Jozefowicz, et al. (2015) 则在超过 1 万种 RNN 架构上进行了测试,发现一些架构在某些任务上也取得了比 LSTM 更好的结果。


 

Jozefowicz等人论文截图

结论

刚开始,我提到通过 RNN 得到重要的结果。本质上所有这些都可以使用 LSTM 完成。对于大多数任务确实展示了更好的性能!

由于 LSTM 一般是通过一系列的方程表示的,使得 LSTM 有一点令人费解。然而本文中一步一步地解释让这种困惑消除了不少。

LSTM 是我们在 RNN 中获得的重要成功。很自然地,我们也会考虑:哪里会有更加重大的突破呢?在研究人员间普遍的观点是:”Yes! 下一步已经有了——那就是注意力!” 这个想法是让 RNN 的每一步都从更加大的信息集中挑选信息。例如,如果你使用 RNN 来产生一个图片的描述,可能会选择图片的一个部分,根据这部分信息来产生输出的词。实际上,Xu, et al.(2015)已经这么做了——如果你希望深入探索注意力可能这就是一个有趣的起点!还有一些使用注意力的相当振奋人心的研究成果,看起来有更多的东西亟待探索……

注意力也不是 RNN 研究领域中唯一的发展方向。例如,Kalchbrenner, et al. (2015) 提出的 Grid LSTM 看起来也是很有前途。使用生成模型的 RNN,诸如Gregor, et al. (2015) Chung, et al. (2015) 和 Bayer & Osendorfer (2015) 提出的模型同样很有趣。在过去几年中,RNN 的研究已经相当的燃,而研究成果当然也会更加丰富!

致谢

I’m grateful to a number of people for helping me better understand LSTMs, commenting on the visualizations, and providing feedback on this post.

I’m very grateful to my colleagues at Google for their helpful feedback, especially Oriol Vinyals,Greg CorradoJon ShlensLuke Vilnis, and Ilya Sutskever. I’m also thankful to many other friends and colleagues for taking the time to help me, including Dario Amodei, and Jacob Steinhardt. I’m especially thankful to Kyunghyun Cho for extremely thoughtful correspondence about my diagrams.

Before this post, I practiced explaining LSTMs during two seminar series I taught on neural networks. Thanks to everyone who participated in those for their patience with me, and for their feedback.

keras模块介绍

http://www.2cto.com/kf/201610/559189.html

keras的模块介绍


 


 

keras是一个开源是的python深度学习库,可以基于theano或者tenserflow,下面大体介绍下keras的几个重要模块。


 

重要的模块


 

1、优化器(optimizers)


 

优化器是调整每个节点权重的方法,看一个代码示例:


 

?


 

1

2

3

4

model = Sequential()

model.add(Dense(64, init=’uniform’, input_dim=10)) model.add(Activation(‘tanh’))

model.add(Activation(‘softmax’))

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) model.compile(loss=’mean_squared_error’, optimizer=sgd)

可以看到优化器在模型编译前定义,作为编译时的两个参数之一


 

代码中的sgd是随机梯度下降算法


 

lr表示学习速率


 

momentum表示动量项


 

decay是学习速率的衰减系数(每个epoch衰减一次)


 

Nesterov的值是False或者True,表示使不使用Nesterov momentum


 

以上4个参数以后具体学习了再解析


 

除了sgd,还可以选择的优化器有RMSprop(适合递归神经网络)、Adagrad、Adadelta、Adam、Adamax、Nadam


 

2、目标函数(objectives)


 

目标函数又称损失函数(loss),目的是计算神经网络的输出样本标记的差的一种方法,代码示例:


 


 


 

1

2

3

4

model = Sequential()

model.add(Dense(64, init=’uniform’, input_dim=10)) model.add(Activation(‘tanh’))

model.add(Activation(‘softmax’))

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) model.compile(loss=’mean_squared_error’, optimizer=sgd)

mean_squared_error就是损失函数的名称


 

可以选择的损失函数有:


 

mean_squared_error,mean_absolute_error,squared_hinge,hinge,binary_crossentropy,categorical_crossentropy


 

这里binary_crossentropy 和 categorical_crossentropy也就是logloss


 

3、激活函数(activations)


 

每一个神经网络层都需要一个激活函数,代码示例:


 


 

1

2

3

4

5

6

7

8

from keras.layers.core importActivation, Dense

model.add(Dense(64))

model.add(Activation(‘tanh’))

或把上面两行合并为:

model.add(Dense(64, activation=’tanh’))

可以选择的激活函数有:


 

linear、sigmoid、hard_sigmoid、tanh、softplus、relu、 softplus,softmax、softsign


 

还有一些高级激活函数,比如如PReLU,LeakyReLU等


 

4、参数初始化(Initializations)


 

这个模块的作用是在添加layer时调用init进行这一层的权重初始化,有两种初始化方法


 

4.1 通过制定初始化方法的名称:


 

示例代码:


 


 

1

model.add(Dense(64, init=’uniform’))

可以选择的初始化方法有:


 

uniform、lecun_uniform、normal、orthogonal、zero、glorot_normal、he_normal等


 

4.2 通过调用对象:


 

该对象必须包含两个参数:shape(待初始化的变量的shape)和name(该变量的名字),该可调用对象必须返回一个(Keras)变量,例如K.variable()返回的就是这种变量,示例代码:


 


 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

from keras importbackend as K

importnumpy as np

def my_init(shape, name=None):

value = np.random.random(shape)

returnK.variable(value, name=name)

model.add(Dense(64, init=my_init))

或者

from keras importinitializations

def my_init(shape, name=None):

returninitializations.normal(shape, scale=0.01, name=name)

model.add(Dense(64, init=my_init))

所以说可以通过库中的方法设定每一层的初始化权重,


 

也可以自己初始化权重,自己设定的话可以精确到每个节点的权重,


 

那么是否可以在这儿做文章优化特征呢?我觉得可以针对不同的task深入试验看看


 

5、层(layer)


 

keras的层主要包括:


 

常用层(Core)、卷积层(Convolutional)、池化层(Pooling)、局部连接层、递归层(Recurrent)、嵌入层( Embedding)、高级激活层、规范层、噪声层、包装层,当然也可以编写自己的层


 

5.1对于层的操作


 


 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

layer.get_weights() #返回该层的权重

layer.set_weights(weights)#将权重加载到该层

config = layer.get_config()#保存该层的配置

layer = layer_from_config(config)#加载一个配置到该层

#该层有一个节点时,获得输入张量、输出张量、及各自的形状:

layer.input

layer.output

layer.input_shape

layer.output_shape

#该层有多个节点时(node_index为节点序号):

layer.get_input_at(node_index)

layer.get_output_at(node_index)

layer.get_input_shape_at(node_index)

layer.get_output_shape_at(node_index)

5.2 Dense层(全连接层)


 


 

1

keras.layers.core.Dense(output_dim, init=’glorot_uniform’, activation=’linear’, weights=None, W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None, bias=True, input_dim=None)

output_dim:输出数据的维度


 

init:初始化该层权重的方法


 

activation:该层的激活函数


 

weights:numpy array的list。该list应含有一个形如(input_dim,output_dim)的权重矩阵和一个形如(output_dim,)的偏置向量


 

regularizer:正则项,w为权重的、b为偏执的,activity为输出的


 

constraints:约束项


 

bias:是否包含偏执向量,是布尔值


 

input_dim:输入数据的维度


 

5.3 dropout层


 

keras.layers.core.Dropout(p)


 

为输入数据施加Dropout。Dropout将在训练过程中每次更新参数时随机断开一定百分比(p)的输入神经元连接,Dropout层用于防止过拟合。


 

参考文章:http://blog.csdn.net/stdcoutzyx/article/details/49022443理解dropout


 

5.4 递归层(Recurrent)


 

递归层包含三种模型:LSTM、GRU和SimpleRNN


 

5.4.1抽象层,不能直接使用


 


 

1

keras.layers.recurrent.Recurrent(weights=None, return_sequences=False, go_backwards=False, stateful=False, unroll=False, consume_less=’cpu’, input_dim=None, input_length=None)

return_sequences:True返回整个序列,false返回输出序列的最后一个输出


 

go_backwards:True,逆向处理输入序列,默认为False


 

stateful:布尔值,默认为False,若为True,则一个batch中下标为i的样本的最终状态将会用作下一个batch同样下标的样本的初始状态


 

5.4.2全连接RNN网络


 


 

1

keras.layers.recurrent.SimpleRNN(output_dim, init=’glorot_uniform’, inner_init=’orthogonal’, activation=’tanh’, W_regularizer=None, U_regularizer=None, b_regularizer=None, dropout_W=0.0, dropout_U=0.0)

inner_init:内部单元的初始化方法


 

dropout_W:0~1之间的浮点数,控制输入单元到输入门的连接断开比例


 

dropout_U:0~1之间的浮点数,控制输入单元到递归连接的断开比例


 

5.4.3 LSTM层


 


 

1

keras.layers.recurrent.LSTM(output_dim, init=’glorot_uniform’, inner_init=’orthogonal’, forget_bias_init=’one’, activation=’tanh’, inner_activation=’hard_sigmoid’, W_regularizer=None, U_regularizer=None, b_regularizer=None, dropout_W=0.0, dropout_U=0.0)

forget_bias_init:遗忘门偏置的初始化函数,Jozefowicz et al.建议初始化为全1元素


 

inner_activation:内部单元激活函数


 

5.5 Embedding层


 


 

1

keras.layers.embeddings.Embedding(input_dim, output_dim, init=’uniform’, input_length=None, W_regularizer=None, activity_regularizer=None, W_constraint=None, mask_zero=False, weights=None, dropout=0.0)

只能作为模型第一层


 

mask_zero:布尔值,确定是否将输入中的’0’看作是应该被忽略的’填充’(padding)值,该参数在使用递归层处理变长输入时有用。设置为True的话,模型中后续的层必须都支持masking,否则会抛出异常


 

5.6 model层(最重要)


 

model层是最主要的模块,model层可以将上面定义了各种基本组件组合起来


 

model的方法:


 

model.summary() : 打印出模型概况


 

model.get_config() :返回包含模型配置信息的Python字典


 

model.get_weights():返回模型权重张量的列表,类型为numpy array


 

model.set_weights():从numpy array里将权重载入给模型


 

model.to_json:返回代表模型的JSON字符串,仅包含网络结构,不包含权值。可以从JSON字符串中重构原模型:


 


 

1

2

3

4

from models importmodel_from_json

json_string = model.to_json()

model = model_from_json(json_string)

model.to_yaml:与model.to_json类似,同样可以从产生的YAML字符串中重构模型


 


 

1

2

3

4

from models importmodel_from_yaml

yaml_string = model.to_yaml()

model = model_from_yaml(yaml_string)

model.save_weights(filepath):将模型权重保存到指定路径,文件类型是HDF5(后缀是.h5)


 

model.load_weights(filepath, by_name=False):从HDF5文件中加载权重到当前模型中, 默认情况下模型的结构将保持不变。如果想将权重载入不同的模型(有些层相同)中,则设置by_name=True,只有名字匹配的层才会载入权重


 

keras有两种model,分别是Sequential模型和泛型模型


 

5.6.1 Sequential模型


 

Sequential是多个网络层的线性堆叠


 

可以通过向Sequential模型传递一个layer的list来构造该模型:


 


 

1

2

3

4

5

6

7

8

9

from keras.models importSequential

from keras.layers importDense, Activation

model = Sequential([

Dense(32, input_dim=784),

Activation(‘relu’),

Dense(10),

Activation(‘softmax’),

])

也可以通过.add()方法一个个的将layer加入模型中:


 


 

1

2

3

model = Sequential()

model.add(Dense(32, input_dim=784))

model.add(Activation(‘relu’))

还可以通过merge将两个Sequential模型通过某种方式合并


 

Sequential模型的方法:


 


 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

compile(self, optimizer, loss, metrics=[], sample_weight_mode=None)

fit(self, x, y, batch_size=32, nb_epoch=10, verbose=1, callbacks=[], validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None)

evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None)

#按batch获得输入数据对应的输出,函数的返回值是预测值的numpy array

predict(self, x, batch_size=32, verbose=0)

#按batch产生输入数据的类别预测结果,函数的返回值是类别预测结果的numpy array或numpy

predict_classes(self, x, batch_size=32, verbose=1)

#本函数按batch产生输入数据属于各个类别的概率,函数的返回值是类别概率的numpy array

predict_proba(self, x, batch_size=32, verbose=1)

train_on_batch(self, x, y, class_weight=None, sample_weight=None)

test_on_batch(self, x, y, sample_weight=None)

predict_on_batch(self, x)

fit_generator(self, generator, samples_per_epoch, nb_epoch, verbose=1, callbacks=[], validation_data=None, nb_val_samples=None, class_weight=None, max_q_size=10)

evaluate_generator(self, generator, val_samples, max_q_size=10)

5.6.2 泛型模型


 

Keras泛型模型接口是:


 

用户定义多输出模型、非循环有向模型或具有共享层的模型等复杂模型的途径


 

适用于实现:全连接网络和多输入多输出模型


 

多输入多输出,官方例子给出:预测一条新闻的点赞转发数,主要输入是新闻本身,还可以加入额外输入,比如新闻发布日期,新闻作者等,具体的实现还是看官网文档吧:


 

http://keras-cn.readthedocs.io/en/latest/getting_started/functional_API/


 

所以感觉这个模型可以针对特定task搞一些创新哦


 

泛型模型model的属性:


 

model.layers:组成模型图的各个层


 

model.inputs:模型的输入张量列表


 

model.outputs:模型的输出张量列表


 

方法:类似序列模型的方法


 

补充get_layer


 

get_layer(self, name=None, index=None)


 

本函数依据模型中层的下标或名字获得层对象,泛型模型中层的下标依据自底向上,水平遍历的顺序。


 

name:字符串,层的名字


 

index: 整数,层的下标


 

函数的返回值是层对象

深度学习如何优化神经网络结构

优化是非常困难的一类问题,而这正是深度学习的核心。优化问题是如此困难,以至于在神经网络引入几十年后,深度神经网络的优化问题仍阻碍着它们的推广,并导致了其 20 世纪 90 年代到 21 世纪初的衰落。自那以后,我们解决了这个问题。在这篇文章中,我会探讨优化神经网络的「困难度(hardness)」,并发掘其背后的理论。简而言之:网络越深,优化问题就越难。


 

最简单的神经网络是单节点感知器,其优化问题是凸优化的。凸优化问题的好处是其所有的局部最小值也是全局最小值。现在有各种各样的优化算法来处理凸优化问题,且每隔几年就有更好用于凸优化理论的多项式时间算法(polynomial-time algorithms)出现。运用凸优化很容易得到单个神经元的优化权重(见下图)。从单个神经元开始,让我们看看会发生什么。

图 1。左:凸函数。右:非凸函数。沿着函数表面,凸函数比非凸函数更容易找到表面的最小值。(来源: Reza Zadeh)


 

下一步是保持单层网络下添加多个神经元。对于单层、n 节点的感知机神经网络,如果存在一组边权重使得网络可以正确地分类给定的训练集,则这样的权重可以通过线性规划用 n 的多项式时间找到,这也是凸优化的特殊例子。所以下个问题是:对于更深的多层神经网络,我们是否可以类似地使用这种多项式时间方法?不幸的是,我们无法保证


 

能够有效解决两层或多层的广义神经网络的优化问题并不容易,这些算法将会涉及计算机科学中的一些最棘手的开放性问题。因此,要想机器学习研究人员找到可靠的深度网络最佳优化算法可能性十分渺茫。因为该问题是 NP-hard(非确定性多项式困难 non-deterministic polynomial hard)的,也就意味着如果可以在多项式时间的计算复杂度中解决它,也将解决数十年来悬而未决的几千个开放性问题。事实上,1988 年 J.Stephen Judd 阐述的以下问题就是 NP-hard:


 

给定一个广义神经网络和一组训练集样本,是否存在一组网络边权重(edge weight),使网络能够为所有的训练样本产生正确的输出结果?


 

Judd 还表明,即使只需要神经网络正确输出三分之二的训练样本,但还是 NP-hard 的,这意味着即使在最坏的情况下,训练一个不精确的神经网络在本质上也是困难的。1993 年,Blum 和 Rivest 证明了更坏的消息:即使训练一个只有两层和三个节点的简单神经网络也是 NP-hard!


 

理论上,对比深度学习与机器学习中的许多更简单的模型(例如支持向量机和逻辑回归),这些模型可以在数学上保证优化能在多项式时间中执行。对于这些更简单的模型,我们能够保证优化算法在多项式时间内就会找到最佳模型。但是,对于深度神经网络的优化算法,并没有这样的保证。根据你的设置来看,你不知道你训练的深度神经网络是否是你可以找到的最好的模型。所以你也并不知道如果继续训练是否能得到更好的模型。


 

幸运的是,实践中我们可以非常有效地解决这些「困难」结果:运用典型梯度下降(gradient descent)优化方法可以给出足够好的局部最小值,让我们在许多问题上取得了巨大进步,例如图像识别、语音识别和机器翻译。我们只是忽略困难的部分,在时间允许下尽可能多地运用梯度下降迭代。


 

似乎最优化问题的传统理论结果是很笨拙的,我们很大程度上可以通过工程和数学技巧、启发式方法、增加更多的机器或使用新的硬件(如 GPU)来解决它们。有意思的是,仍有很多人研究为什么典型的优化算法如此有用,当然除了那些困难的部分。


 

深度学习流行的原因远远不止是解决了优化问题。深度学习在许多机器学习任务中获得领先,它的网络的架构、训练的数据量、损失函数和正则化都起着关键作用。

优化方法(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)

https://zhuanlan.zhihu.com/p/22252270


 

SGD

此处的SGD指mini-batch gradient descent,关于batch gradient descent, stochastic gradient descent, 以及 mini-batch gradient descent的具体区别就不细说了。现在的SGD一般都指mini-batch gradient descent。


 

SGD就是每一次迭代计算mini-batch的梯度,然后对参数进行更新,是最常见的优化方法了。即:


 


 


 


 

其中,


 

是学习率,


 

是梯度SGD完全依赖于当前batch的梯度,所以


 

可理解为允许当前batch的梯度多大程度影响参数更新


 

缺点:(正因为有这些缺点才让这么多大神发展出了后续的各种算法)


 

Momentum

momentum是模拟物理里动量的概念,积累之前的动量来替代真正的梯度。公式如下:


 


 


 

其中,


 

是动量因子


 

特点:


 

能够进行很好的加速

使得更新幅度增大,跳出陷阱

能够减少更新总而言之,momentum项能够在相关方向加速SGD,抑制振荡,从而加快收敛

Nesterov

nesterov项在梯度更新时做一个校正,避免前进太快,同时提高灵敏度。 将上一节中的公式展开可得:


 

可以看出,


 

并没有直接改变当前梯度


 

,所以Nesterov的改进就是让之前的动量直接影响当前的动量。即:


 


 


 


 


 

所以,加上nesterov项后,梯度在大的跳跃后,进行计算对当前梯度进行校正。如下图:


 

momentum首先计算一个梯度(短的蓝色向量),然后在加速更新梯度的方向进行一个大的跳跃(长的蓝色向量),nesterov项首先在之前加速的梯度方向进行一个大的跳跃(棕色向量),计算梯度然后进行校正(绿色梯向量)


 

其实,momentum项和nesterov项都是为了使梯度更新更加灵活,对不同情况有针对性。但是,人工设置一些学习率总还是有些生硬,接下来介绍几种自适应学习率的方法


 

Adagrad

Adagrad其实是对学习率进行了一个约束。即:


 


 


 

此处,对


 

从1到


 

进行一个递推形成一个约束项regularizer,


 


 

用来保证分母非0


 

特点:


 

较小的时候, regularizer较大,能够放大梯度

较大的时候,regularizer较小,能够约束梯度

缺点:


 

,使得训练提前结束

Adadelta

Adadelta是对Adagrad的扩展,最初方案依然是对学习率进行自适应约束,但是进行了计算上的简化。Adagrad会累加之前所有的梯度平方,而Adadelta只累加固定大小的项,并且也不直接存储这些项,仅仅是近似计算对应的平均值。即:


 


 


 

在此处Adadelta其实还是依赖于全局学习率的,但是作者做了一定处理,经过近似牛顿迭代法之后:


 


 


 

其中,


 

代表求期望。


 

此时,可以看出Adadelta已经不用依赖于全局学习率了。


 

特点:


 

RMSprop

RMSprop可以算作Adadelta的一个特例:


 


 

时,


 

就变为了求梯度平方和的平均数。


 

如果再求根的话,就变成了RMS(均方根):


 

此时,这个RMS就可以作为学习率


 

的一个约束:


 

特点:


 

Adam

Adam(Adaptive Moment Estimation)本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。公式如下:


 


 


 


 


 


 


 


 


 

其中,


 


 

分别是对梯度的一阶矩估计和二阶矩估计,可以看作对期望


 


 

的估计;


 


 

是对


 


 

的校正,这样可以近似为对期望的无偏估计。可以看出,直接对梯度的矩估计对内存没有额外的要求,而且可以根据梯度进行动态调整,而


 

对学习率形成一个动态约束,而且有明确的范围。


 

特点:


 

Adamax

Adamax是Adam的一种变体,此方法对学习率的上限提供了一个更简单的范围。公式上的变化如下:


 


 


 

可以看出,Adamax学习率的边界范围更简单


 

Nadam

Nadam类似于带有Nesterov动量项的Adam。公式如下:


 


 


 


 


 


 


 


 


 


 


 

可以看出,Nadam对学习率有了更强的约束,同时对梯度的更新也有更直接的影响。一般而言,在想使用带动量的RMSprop,或者Adam的地方,大多可以使用Nadam取得更好的效果。


 

经验之谈

最后展示两张可厉害的图,一切尽在图中啊,上面的都没啥用了… …


 

损失平面等高线


 

在鞍点处的比较


 

转载须全文转载且注明作者和原文链接,否则保留维权权利


 

引用

[1]Adagrad


 

[2]RMSprop[Lecture 6e]


 

[3]Adadelta


 

[4]Adam


 

[5]Nadam


 

[6]On the importance of initialization and momentum in deep learning


 

[7]Keras中文文档


 

[8]Alec Radford(图)


 

[9]An overview of gradient descent optimization algorithms


 

[10]Gradient Descent Only Converges to Minimizers


 

[11]Deep Learning:Nature

tensorflow/models/im2txt

tensorflow/models/im2txt:

https://github.com/tensorflow/models/tree/master/im2txt#prepare-the-training-data


 


 

https://www.oreilly.com/learning/caption-this-with-tensorflow

https://github.com/mlberkeley/oreilly-captions

http://www.sohu.com/a/131094920_610300


 

docker build -t showandtell_cpu -f ./dockerfiles/Dockerfile.cpu ./dockerfiles/


 

docker run -it -p 8888:8888 -v <path to repo>:/root showandtell_<image_type>

<docker run -it -p 8888:8888 -v /Users/chenhongyu/code/oreilly-captions-master:/root showandtell_cpu>


 

jupyter notebook –ip 0.0.0.0 –allow-root


 


 

ML in Docker or Cloud

https://github.com/floydhub/dl-docker

这里面提供了一个集成了很多主流深度学习框架的docker。可以在本地直接用。

www.floydhub.com

可以使用它提供的服务来在云端执行自己的深度学习项目,不用在本地部署环境。


 

本地使用命令:docker run -it -p 8888:8888 -p 6006:6006 -v /sharedfolder:/root/sharedfolder floydhub/dl-docker:cpu bash