Keras入门尝试
Keras的基础模型
简单解释模型建立过程中语句,加深记忆!
模型示例
简单模型代码如下:
def model(input_shape):
# Define the input placeholder as a tensor with shape input_shape. Think of this as your input image!
X_input = Input(input_shape)
# Zero-Padding: pads the border of X_input with zeroes
X = ZeroPadding2D((3, 3))(X_input)
# CONV -> BN -> RELU Block applied to X
X = Conv2D(32, (7, 7), strides = (1, 1), name = 'conv0')(X)
X = BatchNormalization(axis = 3, name = 'bn0')(X)
X = Activation('relu')(X)
# MAXPOOL
X = MaxPooling2D((2, 2), name='max_pool')(X)
# FLATTEN X (means convert it to a vector) + FULLYCONNECTED
X = Flatten()(X)
X = Dense(1, activation='sigmoid', name='fc')(X)
# Create model. This creates your Keras model instance, you'll use this instance to train/test the model.
model = Model(inputs = X_input, outputs = X, name='HappyModel')
return model
上述代码的主要步骤:
- 输入图片
X_input = Input(input_shape)
- 对输入的图片进行预处理,补零,使卷积可以提取到图片的边缘特征
X = ZeroPadding2D((3, 3))(X_input)
第一维参数:(1,0)指的是在行的最前和最后面补一行零,(1,1)指的是在行和列的最前和最后都进行补一行零,(3,3)即在行和列的最前和最后都补三行和三列零
- 对输入的图片进行预处理,补零,使卷积可以提取到图片的边缘特征
X = Conv2D(32, (7, 7), strides = (1, 1), name = ‘conv0’)(X)
32指的是卷积使用了32个filters,卷积核是7x7,卷积时行和列移动的步长是1
X = BatchNormalization(axis = 3, name = ‘bn0’)(X)
记住归一化的位置,处于卷积核非线性激活函数的中间,axis=3指的就是通道那个维度
X = Activation(‘relu’)(X)
激活函数可以自己选择
- 进入池化层
X = MaxPooling2D((2, 2), name=‘max_pool’)(X)
padding=‘valid’ 不补零,padding='SAME’输入与输出维度相同
(2,2)指的是卷积核大小,采用最大池化操作
- 全连接层有两个操作:现将X转化为向量,再做全连接操作
X = Flatten()(X)
X = Dense(1, activation=‘sigmoid’, name=‘fc’)(X)
- 创建Keras模型,定义输入输出
model = Model(inputs = X_input, outputs = X, name=‘HappyModel’)
参数:输入与输出,最后函数的返回值是模型
建立实际模型
代码片段如下:
def HappyModel(input_shape):
"""
Implementation of the HappyModel.
Arguments:
input_shape -- shape of the images of the dataset
Returns:
model -- a Model() instance in Keras
"""
### START CODE HERE ###
# Feel free to use the suggested outline in the text above to get started, and run through the whole
# exercise (including the later portions of this notebook) once. The come back also try out other
# network architectures as well.
X_input = Input(shape=input_shape)
X = ZeroPadding2D(padding=(1, 1))(X_input)
X = Conv2D(8, kernel_size=(3,3), strides=(1,1))(X)
X = BatchNormalization(axis=3)(X)
X = Activation('relu')(X)
X = MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid')(X)
X = ZeroPadding2D(padding=(1, 1))(X)
X = Conv2D(16, kernel_size=(3,3), strides=(1,1))(X)
X = BatchNormalization(axis=3)(X)
X = Activation('relu')(X)
X = MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid')(X)
X = ZeroPadding2D(padding=(1, 1))(X)
X = Conv2D(32, kernel_size=(3,3), strides=(1,1))(X)
X = BatchNormalization(axis=3)(X)
X = Activation('relu')(X)
X = MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='valid')(X)
# FC
X = Flatten()(X)
Y = Dense(1, activation='sigmoid')(X)
model = Model(inputs = X_input, outputs = Y, name='HappyModel')
### END CODE HERE ###
return model
数据处理的顺序:
第一层
输入 -->补零–>卷积–>归一化–>激活函数
第L层
输入 -->补零–>卷积–>归一化–>激活函数
每一层的操作都是一样的,**不同之处:**每一层的补零方式,卷积操作的滤波器的个数,卷积核的大小,卷积核移动的步长,激活函数的选择,池化层的具体操作按照实际需要有所不同,根据实际需要定义。
最后一层
池化层
训练以及测试模型
上面已经完成建立一个基础模型,接下来需要训练和测试模型。
训练和测试模型的步骤:
- 调用已经建立的模型函数
happyModel = HappyModel((64, 64, 3))
模型只有一个参数需要传入,就是输入的尺寸,输入图片的尺寸是64x64x3
- 通过语句 model.compile(optimizer = “…”, loss = “…”, metrics = [“accuracy”]),编译模型函数
happyModel.compile(optimizer=keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0), loss=‘binary_crossentropy’, metrics=[‘accuracy’])
这里需要选择优化器,一般使用Adam优化器,效果比较好,然后设置优化器的参数,lr是学习率,还有4个参数beta1,beta2,epsilon
设定好优化器之后,设定损失函数和优化器的度量
- 通过语句 model.fit(x = …, y = …, epochs = …, batch_size = …),训练模型
happyModel.fit(x=X_train, y=Y_train, batch_size=16, epochs=20)
给定输入和标签,数据包划分的大小,以及优化次数。训练过程在jupyter notebook会不断输出每一次优化得到的损失和正确率。总体上,损失函数应该越来越小,准确率最终越来越接近于1。
- 通过语句 model.evaluate(x = …, y = …), 测试模型
preds = happyModel.evaluate(x=X_test, y=Y_test)
给定测试数据,测试模型,这个步骤有两个返回值,第一个是损失函数,第二个是正确率,可以将测试结果打印出来,以判定模型对于测试样本的泛化能力。
print ("Loss = " + str(preds[0]))
print ("Test Accuracy = " + str(preds[1]))
宏观分析模型的实现过程
- 卷积层
输入的图片从尺寸是64x64x3,补零操作对图片进行行和列的补零,步长为1,卷积核的大小是3x3,其实ZeroPadding2D和Conv2D这两个步骤等价于padding=‘SAME’。这三个卷积层的补零操作都不改变n_H和n_W,但输出的通道数在不断改变。
卷积层的功能
- 卷积的根本目的是从输入图片中提取特征
- 池化层
这个模型的卷积层没有改变X_train的n_H和n_W,实现对这两个维度的改变需要池化层。池化层不断地将n-H和n_W减半,每通过一层就将宽度和高度减半,但是池化层不改变通道数。
- 池化层的功能:逐步减少输入表征的空间尺寸
- 使特征维度减小而易操作
- 减少网络中的参数与计算数量,从而遏制过拟合
- 增强网络对输入图像中的小变形、扭曲、平移的鲁棒性(输入里的微小扭曲不会改变池化输出——因为我们在局部邻域已经取了最大值/平均值)。
- 帮助我们获得不因尺寸而改变的等效图片表征。这非常有用,因为这样我们就可以探测到图片里的物体,不论那个物体在哪
- 全连接层:对上一层的神经元进行全部连接,实现特征的非线性组合
Dense就是常用的全连接层,所实现的运算是output = activation(dot(input, kernel)+bias)。其中activation是逐元素计算的激活函数,kernel````是本层的权值矩阵,bias为偏置向量,只有当use_bias=True```才会添加。
全连接”表示上一层的每一个神经元,都和下一层的每一个神经元是相互连接的
- 全连接层的功能
- 卷积层和池化层提取输入图像的高级特征。全连接层的目的就是用这些特征进行分类,类别基于训练集。全连接层的函数Dense函数的第一个参数就是用来指定输出的维度,即输出的类别。如果是只有两个分类,输出就为1。
- BN:使得每一层神经网络的输入保持相同分布的
BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。
- 对于每一层来说,当权重随着反向传播的Dw不断更新,对于第L层来说,输入会随着其他参数的改变而不断改变,但通过归一化可以使得输入的均值、方差不变。即,也许下一次的输入产生了变化,但是他们的均值、方差不改变。从某种意义上来说,BN使得网络的输入保持相对稳定,增强了网络的适应能力。
- 从另一个层面来说,当前面层改变时,其迫使后面层适应的程度变小了,它减弱了前层参数与后层参数作用之间的联系。它使得网络的每一层都稍微独立于其它层。
- 在每个mini_batch上使用BN,每个mini_batch的均值。方差不同,所以会有不同效果的缩放。对mini_batch的批量标准化会给每个层的输入增加噪音。类似于Dropout,Dropout会随机给某个隐藏层的某个单元乘以0或者1使其消失或存在,减弱后层对于前层的依赖,BN也是如此。两者都会增加噪声,BN给每一层的输入增加噪声,Dropout给隐藏层单元的激活函数增加噪声。
BatchNorm的本质思想:
(1)神经网络为什么层数越深,训练速度越慢呢?
因为深层神经网络在做非线性变换前的激活输入值X(就是那个Z=WX+b),随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动。之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这导致反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因。
(2)批量标准化改变了什么?
BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。