1 Keras概述
1.1 为什么选择Keras
Keras是用于构造神经网络模型的API,Keras由纯Python编写而成,并基于Tensorflow、Theano和CNTK后端,因此Keras是一个移植性较强的框架。Keras的优点如下:
- 语法简洁,原型设计简易,模型结构清晰明了。
- 封装程度高。网络层、损失函数、优化器、初始化策略、激活函数、正则化方法都是独立的模块。
- 支持CPU和GPU,以及多核场景的并行数据处理和并行设备处理。
对于多核并行数据处理,Keras包含与之对应的API,配置并行模型的具体代码:
# 引用多GPU模型专用的封装类multi_gpu_model
from keras.utils import multi_gpu_model
# 假设存在8个gpu,通过调用封装类,将复制模型并分配到8个gpu上面
parallel_model = multi_gpu_model(model,gpus=8)
并行模型的代码实现如下:
# 模型通过共享一个GRU层,对两个不同序列数据进行编码
input_a = keras.Input(shape=(100,512))
input_b = keras.Input(shape=(100,512))
# 共享GRU层
share_gru = keras.layers.GRU(128)
# 第一个序列数据在gpu:0上做处理
with tf.device_scope('/gpu:0'):
gru_a=shared_GRU(data_1)
# 第二个序列数据在gpu:1上做处理
with tf.device_scope('/gpu:1'):
gru_b=shared_GRU(data_2)
# 将二者的计算结果在cpu:0上做合并
with tf.device_scope('/cpu:0'):
merged_layer=keras.layers.concatenate((gru_a,gru_b),axis=-1)
- 十分适合快速迭代的开发场景。相对于Tensorflow等其他深度神经网络库而言,Keras能够以更少的代码实现相同的功能。
1.2 Keras的安装
命令行窗口中输入以下命令:
Python -m pip install keras
验证
import keras
2 序列模型和函数式模型
在Keras中,模型存在两种不同的实现方式:序列模型和函数式模型。
- 序列模型的实现方式如下:
-
首先,创建一个容器对象Sequential(),可以视为一个堆栈的效果。
-
其次,将所需要的神经网络层(layers)以add()的方式堆叠到容器中,因为这些神经网络层具有先后顺序,首层为输入层(Input),接下来是神经网络层(Layer),最后一层作为输出层(Output),其他的都为该模型的隐藏层。序列模型的原理图如下表所示。
Sequential() add() Sequential() add( ) Sequential() ...,add( ) Sequential() ... 在序列模型中,需要调用的类为keras.models.Sequential
-
函数式模型
函数式模型(keras.models.Model)没有这种序列关系,它的每一层都可以是一个独立的变量,但是为了使得层与层之间存在某种序列关系,需要将上一层得变量引用到本层变量中。所有的层,除了输入层,都需要引入上一层的变量。函数式模型的原理图如下表所示。
Layer(input) ...,Layer(layerN-1) ...
2.1 两种模型的代码实现
针对一个深度神经网络模型,输入层为全连接层,之后依次为全连接层、激活函数层(实际上,激活函数并不是严格意义上的感知器层)、全连接层及全连接输出层。
- 全连接输入层
- 全连接层
- 激活函数层
- 全连接层
- 全连接输出层
-
序列模型实现的代码:Activation('relu')
from keras.models import Sequential from keras.layers import Dense,Activation # 声明Sequential() model = Sequential() # 设置输入层,输入维度为784 model.add(Dense(32,input_dim=28**2)) # 设置全连接隐藏层 model.add(Dense(32)) # 设置激活函数ReLU model.add(Activation('relu')) model.add(Dense(32)) # 输出层也为全连接层 model.add(Dense(32))
-
函数式模型实现的代码:activation='relu'
from keras.layers import Input,Dense,Activation from keras.models import Model # 设置输入层变量,维度为784 inputs=Input(shape=(784,)) # 设置全连接隐藏层变量 x=Dense(32)(inputs) # 设置全连接隐藏层,将激活函数以属性的方式作为设置,ReLU x=Dense(32,activation='relu')(x) # 设置全连接隐藏层变量 x=Dense(32)(x) x=Dense(32)(x) # 设置全连接层输出变量 outputs=Dense(32)(x) # 设置整体模型的输入与输出 model=Model(inputs=inputs,outputs=outputs)
⭐注意字母大小写:函数式模型中设置激活函数层使用的是小写,而序列模型中则是大写。
序列模型在代码的可读性优于函数式模型,搭建过程像是对模型的叠加,但是不适合更加灵活的应用场景;而函数式模型牺牲了一部分代码的可读性,提升了代码的灵活性。尤其是在多输入多输出的情况下,通常采用的是函数式模型的构建方式。对应的函数式模型的代码实现如下:
# 引入需要的层类,输入层、全连接层以及激活层
from keras.layers import Input,Dense,Activation
import keras
# 引用可视化工具类
from keras.utils.vis_utils import plot_model
# 引用模型
from keras.models import Model
# 设置输入层,输入维度是784
inputsA=Input(shape=(784,))
inputsB=Input(shape=(784,))
# 将输入合并
x=keras.layers.concatenate([inputsA,inputsB])
# 设置全连接隐藏层
x=Dense(32)(x)
# 设置全连接层输出
outputsA=Dense(32)(x)
outputsB=Dense(32)(x)
# 设置整体模型的输入与输出
model=Model(inputs=[inputsA,inputsB],outputs=[outputsA,outputsB])
plot_model(model,to_file='model.png',show_shapes=True)
2.2 模型的其他API
序列模型和函数式模型的主要操作函数都相同,具体如下。
1 模型编译model.compile
将配置模型的优化器(梯度下降算法)、损失函数、指标列表等用于模型的编译,其主要参数如下。
- optimizer 配置优化器对象,存在多种梯度下降算法
- loss 配置目标函数,可参考损失函数
- metrics 配置评估模型在训练和测试时的网络性能指标
- sample_weight_mode 如果需要则为样本赋上权重
2 模型训练model.fit
对模型进行训练,配置训练过程中的相关参数、训练轮数等,具体参数如下。
-
x 输入数据
-
y 数据的标签
-
batch_size 设定进行梯度下降时每个批量包含的样本数。训练时一个batch的样本会被计算一次梯度下降,使目标函数优化一步
-
epochs 训练的轮数,每轮都会把训练集执行一边
-
verbose 日志显示,0为不在标准输出流输出日志信息,1为输出进度条记录,2为每个epoch输出一行记录
-
callbacks 输出为列表(list),其中的元素是keras.callbacks.Callback的对象。这个列表中的回调函数会在训练过程中的适当时机被调用。
-
validation_split 用来设定指定训练集中作为验证集的比例。验证集将不参与训练,并在每个epoch结束后测试模型的指标,如损失函数、精确度等。
⭐注意:validation_split的划分在shuffle之前,因此数据本身如果是有序的,需要先手动打乱再指定validation_split,否则可能会出现验证集样本不均匀。
-
validation_data 形式为(X,y)的元组(tuple)类型数据,是指定的验证集。此参数将覆盖validation_split。
-
shuffle 表示在训练过程中是否随机打乱输入样本的顺序。若为字符串"batch",则用来处理HDF5数据的特殊情况,它将会在batch内部将数据打乱。
-
class_weight 输入为字典类型,将不同的类别映射为不同的权值,该参数用于在训练过程中调整损失函数(只能用于训练)
-
initial_epoch 从该参数指定的epoch开始训练,在继续之前的训练时有用
3 模型验证model.evaluate
模型完成训练后,需要对模型进行验证,在模型训练阶段使用的数据集是训练集,而在验证时采用的是测试集。当验证完成后,会返回损失值及指标值,其具体参数如下。
- x 输入数据
- y 数据的标签
- batch_size 设定进行梯度下降时每个批量包含的样本数。训练时一个batch的样本会被计算一次梯度下降,使目标函数优化一步
- verbose 日志显示,0为不在标准输出流输出日志信息,1为输出进度条记录
- sample_weight numpy array,含义与fit的同名参数相同
4 模型预测model.predict
模型对新的数据进行预测,可以设置预测批量及批量步长,以提升预测效率,其参数如下。
- 函数的返回值是预测值的数组
- predict_classes 函数按批量产生输入数据的类别预测结果
- predict_proba 函数按批量产生输入数据属于各个类别的概率
综上,模型代码流程结构为:
- 模型搭建——序列模型(Sequential) 函数式模型(Model)
- 模型编译.compile()
- 模型训练.fit()
- 模型验证.evaluate()
- 模型预测.predict()
首先,需要完成模型的搭建,可以选择序列模型或者函数式模型实现,并添加相应的感知器层,确定输入层、隐藏层和输出层之后,模型的雏形已经完成,后面还需要进行训练,并满足实际场景的性能指标,模型才算完成。
其次,对模型进行编译,因为在训练过程中要确定优化函数、损失函数等才可以进行训练。
再次,就是对模型进行训练了。默认情况下,只需要配置训练集、批量数(batch_size)和训练轮数(epochs)。
当训练完成后,就可以对模型的实际效果进行测试。
最后,如果结果符合标准,那么模型就可以用于预测。
以序列模型为例,其整体代码模板的实现如下:
# 模型搭建
model=Sequential()
model.add(...)
...
# 模型编译
model.compile(...)
# 模型训练
model.fit(...)
# 模型评估验证
model.evaluate(...)
# 模型预测
model.predict(...)
在实际情况中,按照代码模型给出的顺序即可实现绝大多数模型的开发需求。
4 网络层概述
以下网络层的划分依据为用途。
4.1 核心层 Core
在模型构建过程中,核心层常被用到,这些所谓的“层”,除全连接层外,其他的并不是严格的感知器层。这些非感知器层的作用也各异:有的用于数据变化,如扁化层、变形层、Lambda层等;有的用于对感知器层做结构上的调整,如Dropout;有的专门用于激活函数,如Activation。
核心层的库为 keras.layers.core,实际使用时引用该库并调用其中的类即可完成相应层的创建。
keras.layers.core | |||
---|---|---|---|
全连接层 Dense() | 激活函数层 Activation() | Dropout层 Dropout() | 扁化层 Flatten() |
变形层 Reshape() | 重排层 Permute() | 复制向量层 RepeatVector() | Lambda层 Lambda() |
激活值规则层 ActivityRegularization() | 屏蔽层 Masking() | 一维空间Dropout层 SpatialDropout1D() | 二维空间Dropout层 SpatialDropout2D() |
-
全连接层——上一层的每一个输出与本层的每个神经元都有连接
keras.layers.Dense(units,activation=None,use_bias=True, kernel_initializer='glorot_uniform',bias_initializer='zeros', kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None, kernel_constraint=None,bias_constraint=None)
-
激活函数层——对上一层的输出施加激活函数
keras.layers.Activation(activation)
-
Dropout层——按照一定的比例将上层的输出设置为0,防止过拟合
kears.layers.Dropout(rate,noise_shape=None,seed=None)
-
扁化层——将多维数据输入变成一维数据,但是不影响批量的大小
kears.layers.Flatten(data_format=None)
-
变形层——将输入数据的形状(shape)转化为特定的形状
kears.layers.Reshape(target_shape)
-
重排层——改变原有数据的维度排序。例如,处理图片数据时,三原色的维度排序为RGB,通过重排层处理后,数据的维度排序变为GBR
kears.layers.Peremute(dims)
-
复制向量层——将数据复制n份
kears.layers.RepeatVector(n)
-
Lambda层——将任意表达式封装成层对象
kears.layers.Lambda(function,output_shape=None,mask=None,arguments=None)
-
激活值规则层——用于更新基于损失函数的激活值
kears.layers.ActivityRegularization(l1=0.0,l2=0.0)
-
屏蔽层——对特定的值予以屏蔽,从而跳过相应的时间步进(timesteps)
kears.layers.Masking(mask_value=0.0)
-
一维空间Dropout层——一维版的Dropout层,删除了整个一维特征映射,而并非单个元素。如果特征映射中的相邻帧是强相关的,那么规则的Dropout将不会使规则化激活,会导致有效的学习效率下降。此时,空间Dropout1D将有助于促进特征映射之间的独立性。
kears.layers.SpatialDropout1D(rate)
二维空间Dropout层与一维空间Dropout层调用方式相同,不再赘述。
4.2 卷积层 Convolutional
与卷积层同时出现的还有池化层,二者是构建卷积神经网络模型的主要组成部分。在处理图像数据时,卷积层可以很好地提取特征,并且能够起到压缩的作用。
在keras中,卷积层的库为 keras.layers.convolutional,该库中存在卷积层、裁剪、重复、填充等方法。实际编程中引用该库并调用相应的类即可完成相应层的创建。卷积层主要用于提取数据特征,其中的卷积核可以看作一个过滤器,提取部分特征之后,再将原有稀疏的特征进行有压缩,这些被压缩的特征再放入新的矩阵中。
# 一维卷积层
keras.layers.Conv1D(filters,kernel_size,strides=1,padding='valid',
data_format='channels_last',dilation_rate=1,activation=None,use_bias=True,
kernel_initializer='glorot_uniform',bias_initializer='zeros',
kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None,
kernel_constraint=None,bias_constraint=None)
# 二维卷积层
keras.layers.Conv2D(filters,kernel_size,strides=(1,1),padding='valid',
data_format=None,dilation_rate=(1,1),activation=None,use_bias=True,
kernel_initializer='glorot_uniform',bias_initializer='zeros',
kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None,
kernel_constraint=None,bias_constraint=None)
# 三维卷积层
keras.layers.Conv3D(filters,kernel_size,strides=(1,1,1),padding='valid',
data_format=None,dilation_rate=(1,1,1),activation=None,use_bias=True,
kernel_initializer='glorot_uniform',bias_initializer='zeros',
kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None,
kernel_constraint=None,bias_constraint=None)
4.3 池化层 Pooling
池化层和卷积层相似,唯一不同之处在于没有卷积核,但是有一个广义的核(Kernel),核是有长宽的,核的大小称为窗口。核一般采用最大值(Max Pooling)或者平均值(Average Pooling),在窗口内输入数据进行处理的过程称之为池化(Pooling)。⭐如果是针对时间数据,则要使用全局池化层。
# 最大值池化以及全局最大值池化
keras.layers.MaxPooling1D(pool_size=2,strizes=None,padding='valid')
keras.layers.GlobalMaxPooling1D()
keras.layers.MaxPooling2D(pool_size=(2,2),strizes=None,padding='valid',
data_format=None)
keras.layers.GlobalMaxPooling2D(data_format=None)
keras.layers.MaxPooling3D(pool_size=(2,2,2),strizes=None,padding='valid',
data_format=None)
keras.layers.GlobalMaxPooling3D(data_format=None)
# 平均值池化以及全局平均值池化
keras.layers.AveragePooling1D(pool_size=2,strizes=None,padding='valid')
keras.layers.GlobalAveragePooling1D()
keras.layers.AveragePooling2D(pool_size=(2,2),strizes=None,padding='valid',
data_format=None)
keras.layers.GlobalAveragePooling2D(data_format=None)
keras.layers.AveragePooling3D(pool_size=(2,2,2),strizes=None,padding='valid',
data_format=None)
keras.layers.GlobalAveragePooling3D(data_format=None)
4.4 局部连接层 Locally-connected
局部连接层的工作原理和卷积层的工作原理类似,但是局部连接层的权重是不共享的,即在不同的输入簇上会应用一组不同的过滤器。
4.5 循环层 Recurrent
相较于普通的深度神经网络,循环神经网络对序列结构样本的处理具有一定的优势。因为这些数据前后并不是相互独立的,而是具有高度的相关性,但是传统模型的最小关联关系的粒度是层级的,即层与层之间存在联系,而循环神经网络的最小关联关系的粒度是感知器级的,即神经元之间就存在联系。
-
RNN层——循环层的基类
keras.layers.RNN(cell,return_sequences=False,return_state=False, go_backwards=False,stateful=False,unroll=False)
-
SimpleRNN 层——全连接RNN层,其中输出被反馈到输入。
keras.layers.SimpleRNN(units,activation='tanh',use_bias=True, kernel_initializer='glorot_uniform',recurrent_initializer='orthogonal', bias_initializer='zeros', kernel_regularizer=None,recurrent_regularizer=None, bias_regularizer=None,activity_regularizer=None, kernel_constraint=None,recurrent_constraint=None,bias_constraint=None, dropout=0.0,recurrent_dropout=0.0,return_sequences=False,return_state=False, go_backwards=False,stateful=False,unroll=False)
-
LSTM层——长短期记忆单元层
keras.layers.LSTM(units,activation='tanh', recurrent_activation='hard_sigmoid',use_bias=True, kernel_initializer='glorot_uniform',recurrent_initializer='orthogonal', bias_initializer='zeros',unit_forget_bias=True, kernel_regularizer=None,recurrent_regularizer=None, bias_regularizer=None,activity_regularizer=None, kernel_constraint=None,recurrent_constraint=None,bias_constraint=None, dropout=0.0,recurrent_dropout=0.0,implementation=1, return_sequences=False,return_state=False, go_backwards=False,stateful=False,unroll=False)
-
GRU(Gated Recurrent Unit)层——门控循环单元层
keras.layers.GRU(units,activation='tanh', recurrent_activation='hard_sigmoid',use_bias=True, kernel_initializer='glorot_uniform',recurrent_initializer='orthogonal', bias_initializer='zeros',kernel_regularizer=None,recurrent_regularizer=None, bias_regularizer=None,activity_regularizer=None, kernel_constraint=None,recurrent_constraint=None,bias_constraint=None, dropout=0.0,recurrent_dropout=0.0,implementation=1, return_sequences=False,return_state=False, go_backwards=False,stateful=False,unroll=False,reset_after=False)
4.6 嵌入层 Embedding
在处理文本数据时,通常需要将文本中的字或词转化为相应的整数索引,进而将索引与字或词存储到字典中,在训练完相应的数据索引后,根据字典将数据索引转化回原来的字或词。这样的处理方式存在一个问题,就是整数索引在训练过程中会被认为存在某种数学关系,并且极有可能被视为线性的。所以,需要对这种整数化的线性关系进行调整,而嵌入式则是解决这种潜在问题的方案之一,将这些整数索引转化为固定维度的向量,而嵌入层则将索引储存到向量的映射关系中。
keras.layers.Embedding(input_dim,output_dim,embeddings_initializer='uniform',
embeddings_regularizer=None,activity_regularizer=None,
embeddings_constraint=None,mask_zero=False,input_length=None)
4.7 融合层 Merge
通常情况下,模型某一层的上级输入是来自于单个输入源——输入层或者上层输出,但是实际场景中存在需要多个模型融合或者多输入学习的情况,如分别以图像和文本作为样本的深度神经网络模型进行融合学习。
keras提供了多种融合方式,如相加、相减、点乘、平均、最大等。
keras.layers.Add()
keras.layers.Subtract()
keras.layers.Multiply()
keras.layers.Average()
keras.layers.Maximum()
keras.layers.Concatenate(axis=-1)
⭐实现融合层的时候,需要将模型容器设置为函数式模型,此处以相加融合层为例,两个输入层input1和input2分别接入两个输出维度为8的全连接层,融合层added将两个全连接层融合在一起,并接入全连接层,最后输出。
from keras.layers import Input,Dense
from keras.models import Model
from keras.utils.vis_utils import plot_model
import keras
input1=keras.layers.Input(shape=(16,))
x1=keras.layers.Dense(8,activation='relu')(input1)
input2=keras.layers.Input(shape=(32,))
x2=keras.layers.Dense(8,activation='relu')(input2)
added=keras.layers.Add()([x1,x2])
out=keras.layers.Dense(4)(added)
model=keras.models.Model(inputs=[input1,input2],outputs=out)
plot_model(model,to_file='modelAdd.png',show_shapes=True)
4.8 高级激活层 Advanced Activations
激活函数实际上不是严格意义上的层,也可以通过层属性的方式实现。
# 激活函数ELU的实现
keras.layers.ELU(alpha=1.0)
4.9 规范化层 Normalization
规范化层通常设置在激活层之前,其目的是解决数据分布的问题。规范化层(一般是批量规范化)的具体作用是将该层的输入数据进行转化,使其平均值为0,标准差为1。
keras.layers.BatchNormalization(axis=-1,momentum=0.99,epsilon=0.001,center=True,
scale=True,beta_initializer='zeros',gamma_initializer='ones',
moving_mean_initializer='zeros',moving_variance_initializer='ones',
beta_regularizer=None,gamma_regularizer=None,
beta_constraint=None,gamma_constraint=None)
4.10 噪声层 Noise
在神经网络模型中,参数过多会导致过拟合。在训练过程中添加噪声可以指示神经网络模型学习更强大的特征表示,来消除或者减弱噪声的影响。正则化的方法就是通过向训练数据中添加噪声来防止过拟合。
高斯噪声(GaussianNoise)层——为输入加上均值为0的高斯噪声,这对减少过拟合十分有用(可以将其视作随机数据增强的一种形式)。
keras.layers.noise.GaussianNoise(stddev)
高斯Dropout层——一个丢失率(Drop Rate)基于高斯分布的Dropout层。但是它作为一个正则化层,只在训练时处于激活状态。
keras.layers.GaussianDropout(rate)
AlphaDropout——Alpha Dropout是一种保持输入均值和方差不变的Dropout,该层的作用是在Dropout时也保持数据的自规范性。通过随机对负的饱和值进行激活,Alpha Dropout和ReLU激活函数配合较好。
4.11 ⭐层级包装器 Layer Wrappers
时间分布(TimeDistributed)包装器——输入的每个时间片段在一个层上,输入至少是三维的,第一个索引是时间维度。
keras.layers.wrappers.TimeDistributed(layer)
5 配置项
除了搭建模型时使用的网络层,模型训练时还涉及损失函数、优化器、激活函数、初始化方法、正则项、约束项。
5.1 损失函数
损失函数又称为目标函数,用于估量模型的预测值和真实值之间的不一致程度。是一个非负实值函数,损失函数越小,其健壮性就越高。损失函数是在模型编译时设置的。
model.compile(loss='mean_squared_error',optimizer='sgd')
# 或者表现为如下形式
from keras import losses
model.compile(loss=losses.mean_squared_error,optimizer='sgd')
实际场景中损失函数并不是通用的。有的用于回归问题,有的用于分类问题。
-
均方差损失(Mean Squared Error,MSE)
主要用于回归问题的损失函数,将预测值$$y_i$$与实际值$$\dot{y}{i}$$之差的平方和除以总样本数n:
$$
MSE=\frac{1}{n} \sum{i=1}^{n} (y_i-\dot{y}_i)^2
$$ -
绝对均值损失(Mean Absolute Error,MAE)
主要用于回归问题的损失函数,将预测值$$y_i$$与实际值$$\dot{y}{i}$$之差的绝对值之和除以总样本数n:
$$
MAE=\frac{1}{n} \sum{i=1}^{n} |y_i-\dot{y}_i|
$$ -
绝对百分比均方差损失(Mean Absolute Percentage Error,MAPE)
将预测值$$y_i$$与实际值$$\dot{y}{i}$$之差的绝对值除以实际值的绝对值,并求其平均值,得到值得百分比,主要用于回归问题的损失函数。
$$
MAPE=(\frac{1}{n} \sum{i=1}^{n} \frac{|y_i-\dot{y}_i|}{|\dot{y}_i|})×100%
$$ -
转折点损失(Hinge)
用于分类问题的损失函数
$$
H=\frac{1}{n} \sum_{i=1}^{n} max(1,y_i·\dot{y}_i)
$$ -
平方转折点损失(Squared Hinge)
在转折点损失的基础上,其平方亦用于分类问题
$$
H^2=\frac{1}{n} \sum_{i=1}^{n} max(1,y_i·\dot{y}_i)^2
$$ -
⭐交叉熵(Cross Entropy)
很好地解决分类问题,可在神经网络(机器学习)中作为损失函数,p表示真是标记的分布,q为训练后模型的预测标记分布,交叉熵损失函数可以衡量p与q的相似性。交叉熵作为损失函数还可以使用Sigmoid函数在梯度下降时避免均方误差损失函数学习速率降低的问题,因为学习速率是可以被输出的误差所控制。
在信息论中,信源输出的数据是随机的,即在未收到信息之前,无法肯定信源发送的是什么样的信息。而通信的目的就是使接收者接收到信息后,尽可能多地解除接收者对信源所存在的疑义(不确定性),因此这个被解除的不确定性实际上就是通信中所要传送的信息量。
于是,假设存在离散型随机变量集合$$x{x_1,x_2,...,x_n}$$,则概率分布函数为
$$
p(x)=P(X=x),x\in \chi
$$
定义事件$$x_i$$的信息量为
$$
I(x_i)=-ln(p(x_i))
$$
有了信息量的定义之后,熵(Entropy)的定义为
$$
H(X)=\sum_{i=1}^{n} p(x_i)·I(x_i)
$$
再引入预测值和真实值的相关函数,如$$P(X=x)$$表示样本的真实分布,而$$Q(X=x)$$表示样本的预测分布,此时可以得到相对熵的概念,也成为KL散度(Kullback Leibler Divergence,KL Divergence),在keras中的实现函数为kullback_leibler_divergence(),用于表示预测分布和真实分布之间的关系
$$
D(p,q)=\sum_{i=1}^{n} p(x_i)·ln \frac{p(x_i)}{q(x_i)}
$$
从上式可以看出,当预测分布和实际分布相等时,对数部分为0,此时相对熵就是0,对上式进行变形如下:
$$
D(p,q)=\sum_{i=1}{n}p(x_i)·ln[p(x_i)]-\sum_{i=1}{n}p(x_i)·ln[q(x_i)]
$$$$
D(p,q)=-H(X)-\sum_{i=1}^{n}p(x_i)·ln[q(x_i)]
$$将相对熵的后半部分记为交叉熵,于是有
$$
H(p,q)=-\sum_{i=1}^{n}p(x_i)·ln[q(x_i)]
$$
这里只取交叉熵作为度量函数,因为$$-H(X)$$反映的是真实分布的熵,所以其值是不变的。在keras中,对不同形式的分类进行疯转,其原理都是基于交叉熵。
- 分类交叉熵损失(Categorical Crossentropy)
- 稀疏分类交叉熵损失(Sparse Categorical Crossentropy)
- 二进制交叉熵损失(Binary Crossentropy)
- 泊松损失(Poisson)
5.2 验证指标
当模型搭建完毕并训练结束时,最关心的是模型的效果,这也是模型验证的意义所在。keras可以在模型编译阶段,在编译函数.compile()的metrics属性中配置。
model.compile(loss='mean_squared_error',
optimizer='sgd',metrics=['mae','acc'])
# 或者下面这种方式
from keras import metrics
model.compile(loss='mean_squared_error',optimizer='sgd',
metrics=[metrics.mae,metrics.categorical_accuracy])
- binary_accuracy——针对二分类问题,计算在所有预测值上的平均正确率
- categorical_accuracy——针对多分类问题,计算在所有预测值上的平均正确率
- sparse_categorical_accuracy——针对多分类问题,在对稀疏的目标值进行预测时有用
- top_k_categorical_accuracy——计算top_k正确率,当预测值的前k个值中存在目标类别即认为预测正确
- sparse_top_k_categorical_accuracy——在对稀疏的目标值进行预测时有用
还可以自定义指标,具体如下:
def custom(y_true,y_pred):
return (y_true-y_pred)
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',metrics=['accuracy',custom])
5.3 初始化函数
模型权重的初始化对神经网络模型的训练十分重要,不恰当的初始化参数会引发梯度问题,产生诸如梯度消失或者梯度爆炸等问题,从而降低了整体的训练效率;因此选择合适的初始化参数可以快速收敛至最优解。
在一开始构建神经网络模型时,通常都是默认模型的权重初始设置,比如网络层的权重和偏移的默认值都是0,这并不是一个好的策略,因为这样的话所有的神经元节点开始做的都是相同的计算,最后同层的每个神经元会得到相同的权重。另一种想法是进行随机初始化的处理,将随机值作为网络层权重的初始值,这样做可以排除第一种问题,但是神经网络通常是很多层的,在经过非线性激活函数后,会出现梯度问题。
因此,需要对随机初始化加以限制——均值为0,方差为1,这样可以在源头上缓解上述梯度问题,如果是深度神经网络,则还需要利用的是规范化层。
不好的初始化策略有:
keras.initializers.Zeros()
keras.initializers.Ones()
keras.initializers.Constant(value=0)
主流的初始化函数
# 正态随机,产生的随机数满足正态分布
keras.initializers.RandomNormal(mean=0.0,stddev=0.05,seed=None)
# 均匀随机,产生的随机数满足均与分布
keras.initializers.RandomUniform(minval=-0.05,maxval=0.05,seed=None)
# 截断正态随机,与正态随机类似,不同之处在于两个以上的偏离平均值的标准差被丢弃
# 建议将其作为神经网络权重初始化器
keras.initializers.TruncatedNormal(mean=0.0,stddev=0.05,seed=None)
5.4 约束项
Constraints的主要作用是在调优过程中对网络中的参数进行约束,Sklearn中模型调参时,通常会用一些惩罚项对其进行约束,如L1,L2等,这是针对模型整体进行的约束,如果仅是想对神经网络的某一层进行约束而不是整个模型,就需要使用到keras提供的专门函数——约束项类。
-
最大值正则 Max Norm
对每个隐藏单元的权重进行约束,使其具有小于或者等于期望值的范数。
keras.constraints.MaxNorm(max_value=2,axis=0)
-
非负约束 Non Negative
对每个隐藏单元的权重进行约束,使其具有非负的数值。
keras.constraints.NonNeg()
-
单位正则 Unit Norm
对每个隐藏单元的权重进行约束,使其具有单位正则的数值。
keras.constraints.UnitNorm(axis=0)
-
最小值最大值正则 Min-Max Norm
对每个隐藏单元的权重进行约束,使其具有取值范围不超过最值的数值。
keras.constraints.MinMaxNorm(min_value=0.0,max_value=1.0,rate=1.0,axis=0)
其中参数rate为强制约束率,即当rate为最大值1时,强制约束到最值之内;当其小于1时,该权重将在每一步重新标度,以便在一定的间隔内移动到某一个值。
约束项作用在层上的方式,在每个层中都有相应的constraint配置项,如kernel_constraint、bias_constraint等,定义好一个约束项之后,即可配置到相应层的配置项中,具体如下:
import keras max_norm=keras.constraints.MaxNorm(max_value=2.4,axis=0) non_neg=keras.constraints.NonNeg() model.add(Dense(64,kernel_constraint=max_norm,bias_constraint=non_neg))
5.5 ⭐⭐回调函数
Callback Functions是在训练过程的给定阶段应用的一组函数,能够在训练期间使用回调函数获取模型的内部状态和统计信息——通过将回调函数列表(作为关键字参数回调)传递给序列(Sequential)或者函数(Model)类中的.fit()方法,然后就可以在训练的每个阶段调用回调的相关方法。
回调函数存在一个基类keras.callbacks.Callback(),所有涉及的回调函数都会集成该类,此外,还可以通过这个类自定义回调函数,其基本结构由以下几类函数组成。
- 每轮开始时执行的函数 on_epoch_begin()
- 每轮结束时执行的函数 on_epoch_end()
- 每次批量开始时执行的函数 on_batch_begin()
- 每次批量结束时执行的函数 on_batch_end()
- 每次训练开始时执行的函数 on_train_begin()
- 每次训练结束时执行的函数 on_train_end()
其配置十分简单,首先定义一个自定义回调类,在类中定义上述函数,具体如下:
class
标签:layers,None,函数,keras,模型,Keras,part1,API,model
From: https://www.cnblogs.com/olin25/p/17023196.html