keras¶
Keras是一个极度简化、高度模块化的神经网络第三方库。基于Python+Theano开发,充分发挥了GPU和CPU操作。其开发目的是为了更快的做神经网络实验。适合前期的网络原型设计、支持卷积网络和反复性网络以及两者的结果、支持人工设计的其他网络、在GPU和CPU上运行能够无缝连接。
基本概念¶
张量(tensor)¶
其维数从0到n,axis
则对应“轴”的概念。
1 2 3 4 5 6 7 8 |
|
Model模型方法¶
- evaluate_generator:使用一个生成器作为数据源,来评估模型,生成器应返回与test_on_batch的输入数据相同类型的数据。
数据增强¶
具体介绍 - featurewise_center的官方解释:"Set input mean to 0 over the dataset, feature-wise."
1. Core 常用层¶
Permute层¶
当需要将RNN和CNN链接时可能用到它。用来将输入的维度重排。
1 |
|
其中dims
指定重排的模式(不包括样本数的维度),默认下标从1开始。
Lambda层¶
1 |
|
output_shape
:函数应该返回的值的shape,可以是一个tuple,也可以是一个根据输入shape计算输出shape的函数
1 |
|
2. 卷积层¶
Convolution2D¶
1 |
|
举例子:
1 |
|
这里的前三个参数是64个3X3的filter的意思,
input_shape = (3,128,128)
代表128*128的彩色RGB图像.input_shape
不包含样本数的维度,在其内部实现中,实际上是(None,3,128,128)或者(None,128,128,3)
- ‘th’模式下,输入形如(samples,channels,rows,cols)的4D张量
- ‘tf’模式下,输入形如(samples,rows,cols,channels)的4D张量
所以现在model.output_shape == (None, 64, 256, 256)
- subsample:长为2的tuple,输出对输入的下采样因子,更普遍的称呼是“strides”
- border_mode=‘full’,same,valid
池化层¶
MaxPooling2D¶
1 |
|
规范层¶
BatchNormalization¶
1 |
|
上一层是激活函数,这一层对它的输出值进行规范化(均值接近0,标准差接近1)
- mode - 0 按样本规范化,默认输入为2D
- axis 指定规范化的轴 (samples,channels,rows,cols)
- 1 沿通道轴(channel) 规范化(4D图像张量)意味着对每个特征图进行规范化
自定义层¶
ANN¶
1 2 3 4 5 6 |
|
- sizes=[2,3,1]
- 权值w和偏置b是需要初始化,梯度下降算法是在某个点在梯度方向上开始不断迭代计算最优的w和b,所以w,b必须有一个初始值作为起始迭代点。 随机地初始化它们,我们调用了numpy中的函数生成符合高斯分布的数据。
1 2 3 4 5 6 |
|
其次这里的w,b表示成向量形式,原因是矢量化编程可以在线性代数库中加快速度,那么到底该怎么表示w,和b呢?让我们从最简单的问题开始,看看最简单的单个神经元:
激活函数¶
1 2 3 4 |
|
1 2 3 |
|
SGD¶
1 |
|
随机梯度下降的思想不是迭代所有的训练样本,而是挑一部分出来来代表所有的训练样本,这样可以加快训练速度。换句话说就是,原始梯度下降算法是一个一个地训练,而SGD是一批一批地训练,而这个批的大小就是mini_batch_size
,并且这个批是随机挑出来的,而等这些批都训练完了我们叫一次迭代,并且给了它一个更好听的名字叫epochs
,eta
是学习率\eta,test_data
是测试数据。看代码!
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
这里又用到了update_mini_batch方法,它直接把更新w和b的过程单独抽象了出来,这个函数是梯度下降的代码,而只有加上这个函数前面的代码才能叫随机梯度下降。过会我们再来分析这个函数,在迭代完一次(一个epoch)之后,我们使用了测试数据来检验我们的神经网络(已经根据mini-batch学习到了权值和偏置)的识别数字准确率。这里调用了一个函数叫evaluate,它定义为:
1 2 3 |
|
这个函数的主要作用就是返回识别正确的样本个数。其中np.argmax(a)是返回a中最大值的下标,这里我们可以看到self.feedforward(x),其中x是test_data中的输入图像,然后神经网络计算出最终的结果是分类数字的标签,它是一个shape=(1,10)矩阵,比如数字5表示为[0,0,0,0,0,1,0,0,0,0],这时1最大,就返回下标5,其实也就表示了数字5。然后将这个结果和test_data中的y作比较,如果相等就表示识别正确,sum就是用来计数的。
梯度下降算法¶
\Delta \nabla_b,\Delta \nabla_w, \nabla_b,\nabla_w
下面来看看梯度下降的代码update_mini_batch:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
BP算法¶
原始梯度下降是针对每个样本都计算出一个梯度,然后沿着这个梯度移动。
而随机梯度下降是针对多个样本(一个mini_batch)计算出一个平均梯度,然后这个梯度移动,那么这个epochs就是权值和偏置更新的次数了。
随机梯度下降学习算法的重点又在这个BP算法了:
1 2 3 |
|
前向计算¶
1 2 3 4 5 6 7 8 |
|
后向传递¶
1 |
|
因为这里的C=\frac 12 \sum_j(y_j-a_j)^2,(单个训练样本的损失函数),所以\frac{\partial C}{\partial y_j^L}=a_j-y_j
于是下面的cost_derivative就直接返回了这个式子。
这里我们使用了2个辅助函数:
1 2 3 4 5 |
|
其中zs[-1]表示最后一层神经元的输入,上述delta对应BP算法中的式子:
$
\delta_j^L=\frac{\partial C}{\partial y_jL}\sigma'z_jL
$
delta就是指最后一层的残差。代码接下来:
1 |
|
\frac{\partial C}{\partial b_j^L}=\delta_j^l
1 |
|
$
\frac{\partial C}{\partial a_{jk}L}=a_k\delta_j^l
$
以上算的是最后一层的相关变量。下面是反向计算前一层的梯度根据最后一层的梯度。
1 2 3 4 5 6 7 |
|
这便是BP算法的全部了。详细代码请看这里的[network.py][2]。
怎么保存Keras模型?¶
PyYAML==3.11¶
YAML is a data serialization format designed for human readability and interaction with scripting languages.
如果只保存模型结构,代码如下:
1 2 3 4 5 6 7 8 9 10 |
|
h5py==2.5.0¶
h5py:将数据储存在hdf5文件中。
如果需要保存数据:
1 2 |
|
1 2 |
|
Layer¶
layers模块包含了core、convolutional、recurrent、advanced_activations、normalization、embeddings这几种layer。
其中core里面包含了flatten(CNN的全连接层之前需要把二维特征图flatten成为一维的)、reshape(CNN输入时将一维的向量弄成二维的)、dense(就是隐藏层,dense是稠密的意思),还有其他的就不介绍了。convolutional层基本就是Theano的Convolution2D的封装。
- Convolution1D
nb_filter
: Number of convolution kernels to use (dimensionality of the output).filter_length
: The extension (spatial or temporal) of each filter.- MaxPooling1D
pool_length
: factor by which to downscale. 2 will halve the input.
core¶
- Dense
- Dropout
- Flatten
- Lambda
- TimeDistributedDense
Lambda层¶
-
keras.layers.core.Lambda(function, output_shape=None, arguments={}) 本函数用以对上一层的输入实现任何Theano/TensorFlow表达式
-
function:要实现的函数,该函数仅接受一个变量,即上一层的输出
- output_shape:函数应该返回的值的shape,可以是一个tuple,也可以是一个根据输入shape计算输出shape的函数
- arguments:可选,字典,用来记录向函数中传递的其他关键字参数 全连接网络
TimeDistributed层¶
1 |
|
为输入序列的每个时间步信号(即维度1)建立一个全连接层,当RNN网络设置为return_sequence=True时尤其有用
Preprocessing¶
这是预处理模块,包括序列数据的处理,文本数据的处理,图像数据的处理。重点看一下图像数据的处理,keras提供了ImageDataGenerator函数,实现data augmentation,数据集扩增,对图像做一些弹性变换,比如水平翻转,垂直翻转,旋转等。
Sequential¶
1 2 3 4 5 6 7 8 |
|
增加layer:
1 2 3 4 5 6 7 8 9 |
|
第一层需要知道输入的形状
Compilation¶
- an
optimizer
. This could be the string identifier of an existing optimizer (such as rmsprop or adagrad), or an instance of the Optimizer class. See: optimizers. - a loss function. This is the objective that the model will try to minimize. It can be the string identifier of an existing loss function (such as categorical_crossentropy or mse), or it can be an objective function. See: objectives.
-
a list of metrics. For any classification problem you will want to set this to metrics=['accuracy']. A metric could be the string identifier of an existing metric (only accuracy is supported at this point), or a custom metric function. ```python model.compile(
1 2 3
loss='binary_crossentropy', optimizer='adam', class_mode='binary',
)
1 2 3 4 |
|
keras.optimizers.SGD(lr=0.01, momentum=0.9, decay=0.9, nesterov=False)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
model.compile(loss='mean_squared_error', optimizer='sgd')
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 26 27 28 29 30 31 32 33 34 35 36 |
|
def sigmoid_relu(x):
"""
f(x) = x for x>0
f(x) = sigmoid(x)-0.5 for x<=0
"""
return K.relu(x)-K.relu(0.5-K.sigmoid(x))
1 |
|
def lambda_activation(x):
"""
f(x) = max(relu(x),sigmoid(x)-0.5)
"""
return K.maximum(K.relu(x),K.sigmoid(x)-0.5)
1 |
|
class My_activation(Layer):
"""
f(x) = x for x>0
f(x) = alpha1 x for theta<x<=0
f(x) = alpha2 x for x<=theta
"""
def init(self,theta=-5.0,alpha1=0.2,alpha2=0.1,**kwargs):
self.theta = theta
self.alpha1 = alpha1
self.alpha2 = alpha2
super(Myactivation,self).__init_(_*kwargs)
def call(self,x,mask=None):
fx_0 = K.relu(x) #for x>0
fx_1 = self.alpha1_x_K.cast(x>self.theta,K.floatx())_K.cast(x<=0.0,K.floatx()) #for theta<x<=0
fx_2 = self.alpha2_x_K.cast(x<=self.theta,K.floatx())#for x<=theta
return fx_0+fx_1+fx_2
def get_output_shape_for(self, input_shape):
1 2 |
|
alpha1,alpha2是可学习超参数¶
class Trainable_activation(Layer):
"""
f(x) = x for x>0
f(x) = alpha1 x for theta<x<=0
f(x) = alpha2 x for x<=theta
"""
def init(self,init='zero',theta=-5.0,**kwargs):
self.init = initializations.get(init)
self.theta = theta
super(Trainableactivation,self).__init_(_*kwargs)
def build(self,input_shape):
self.alpha1 = self.init(input_shape[1:],name='alpha1')#init alpha1 and alpha2 using ''zero''
self.alpha2 = self.init(input_shape[1:],name='alpha2')
self.trainable_weights = [self.alpha1,self.alpha2]
def call(self,x,mask=None):
fx_0 = K.relu(x) #for x>0
fx_1 = self.alpha1_x_K.cast(x>self.theta,K.floatx())_K.cast(x<=0.0,K.floatx()) #for theta<x<=0
fx_2 = self.alpha2_x_K.cast(x<=self.theta,K.floatx())#for x<=theta
return fx_0+fx_1+fx_2
def get_output_shape_for(self, input_shape):
1 2 |
|
1 |
|
model.add(Activation(sigmoid_relu))
model.add(Lambda(lambda_activation))
model.add(My_activation(theta=-5.0,alpha1=0.2,alpha2=0.1))
model.add(Trainable_activation(init='normal',theta=-5.0))
1 2 3 4 5 6 7 |
|
keras.callbacks.ModelCheckpoint(filepath,verbose=0, save_best_only=False)
```
用户每次epoch之后保存模型数据。如果save_best_only=True,则最近验证误差最好的模型数据会被保存下来。filepath是由epoch和logs的键构成的。比如filepath=weights.{epoch:02d}-{val_loss:.2f}.hdf5,那么会保存很多带有epoch和val_loss信息的文件;当然也可以是某个路径。
history¶
Returns a history object. Its history
attribute is a record of
training loss values at successive epochs,
as well as validation loss values (if applicable).
Arguments¶
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 26 27 28 29 30 31 |
|
Regularizers正则项¶
正则项在优化过程中层的参数或层的激活值添加惩罚项,这些惩罚项将与损失函数一起作为网络的最终优化目标.
惩罚项基于层进行惩罚,目前惩罚项的接口与层有关,但Dense, TimeDistributedDense, MaxoutDense, Covolution1D, Covolution2D具有共同的接口。
这些层有三个关键字参数以施加正则项:
- W_regularizer:施加在权重上的正则项,为WeightRegularizer对象
- b_regularizer:施加在偏置向量上的正则项,为WeightRegularizer对象
- activity_regularizer:施加在输出上的正则项,为ActivityRegularizer对象