作者简介:刘子瑛,阿里巴巴操作系统框架专家;CSDN 博客专家。工作十余年,一直对数学与人工智能算法相关、新编程语言、新开发方法等相关领域保持浓厚的兴趣。乐于通过技术分享促进新技术进步。
作为一个程序员,我们可以像学习编程一样学习深度学习模型开发。我们以 Keras 为例来说明。
我们可以用 5 步 + 4 种基本元素 + 9 种基本层结构,这 5-4-9 模型来总结。
5步法:
1. 构造网络模型
2. 编译模型
3. 训练模型
4. 评估模型
5. 使用模型进行预测
4种基本元素:
1. 网络结构:由10种基本层结构和其他层结构组成
2. 激活函数:如relu, softmax。口诀: 最后输出用softmax,其余基本都用relu
3. 损失函数:categorical_crossentropy多分类对数损失,binary_crossentropy对数损失,mean_squared_error平均方差损失, mean_absolute_error平均绝对值损失
4. 优化器:如SGD随机梯度下降, RMSProp, Adagrad, Adam, Adadelta等
9种基本层模型
包括3种主模型:
1. 全连接层Dense
2. 卷积层:如conv1d, conv2d
3. 循环层:如lstm, gru
3种辅助层:
1. Activation层
2. Dropout层
3. 池化层
3种异构网络互联层:
1. 嵌入层:用于第一层,输入数据到其他网络的转换
2. Flatten层:用于卷积层到全连接层之间的过渡
3. Permute层:用于RNN与CNN之间的接口
我们通过一张图来理解下它们之间的关系
▌
五步法
五步法是用深度学习来解决问题的五个步骤:
1. 构造网络模型
2. 编译模型
3. 训练模型
4. 评估模型
5. 使用模型进行预测
在这五步之中,其实关键的步骤主要只有第一步,这一步确定了,后面的参数都可以根据它来设置。
过程化方法构造网络模型
我们先学习最容易理解的,过程化方法构造网络模型的过程。
Keras中提供了Sequential容器来实现过程式构造。只要用Sequential的add方法把层结构加进来就可以了。10种基本层结构我们会在后面详细讲。
例:
from keras.models import Sequential
from keras.layers import Dense, Activation
model = Sequential()
model.add(Dense(units=64, input_dim=100))
model.add(Activation("relu"))
model.add(Dense(units=10))
model.add(Activation("softmax"))
对于什么样的问题构造什么样的层结构,我们会在后面的例子中介绍。
编译模型
模型构造好之后,下一步就可以调用Sequential的compile方法来编译它。
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
编译时需要指定两个基本元素:loss是损失函数,optimizer是优化函数。
如果只想用最基本的功能,只要指定字符串的名字就可以了。如果想配置更多的参数,调用相应的类来生成对象。例:我们想为随机梯度下降配上Nesterov动量,就生成一个SGD的对象就好了:
from keras.optimizers import SGD
model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.01, momentum=0.9, nesterov=True))
lr是学习率,learning rate。
训练模型
调用fit函数,将输出的值X,打好标签的值y,epochs训练轮数,batch_size批次大小设置一下就可以了:
model.fit(x_train, y_train, epochs=5, batch_size=32)
评估模型
模型训练的好不好,训练数据不算数,需要用测试数据来评估一下:
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=128)
用模型来预测
一切训练的目的是在于预测:
classes = model.predict(x_test, batch_size=128)
▌
4种基本元素
网络结构
主要用后面的层结构来拼装。网络结构如何设计呢? 可以参考论文,比如这篇中不管是左边的19层的VGG-19,还是右边34层的resnet,只要按图去实现就好了。
激活函数
-
对于多分类的情况,最后一层是softmax。
-
其它深度学习层中多用relu。
-
二分类可以用sigmoid。
-
另外浅层神经网络也可以用tanh。
损失函数
对于多分类来说,主要用categorical_crossentropy。
优化器
本文将着重介绍后两种教程。
深度学习中的函数式编程
前面介绍的各种基本层,除了可以add进Sequential容器串联之外,它们本身也是callable对象,被调用之后,返回的还是callable对象。所以可以将它们视为函数,通过调用的方式来进行串联。
来个官方例子:
from keras.layers import Input, Dense
from keras.models import Model
inputs = Input(shape=(784,))
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels)
为什么要用函数式编程?
答案是,复杂的网络结构并不是都是线性的add进容器中的。并行的,重用的,什么情况都有。这时候callable的优势就发挥出来了。
比如下面的Google Inception模型,就是带并联的:
我们的代码自然是以并联应对并联了,一个输入input_img被三个模型所重用:
from keras.layers import Conv2D, MaxPooling2D, Input
input_img = Input(shape=(256, 256, 3))
tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1)
tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2)
tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img)
tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3)
output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)
▌
案例教程
CNN处理MNIST手写识别
光说不练是假把式。我们来看看符合五步法的处理MNIST的例子。
首先解析一下核心模型代码,因为模型是线性的,我们还是用Sequential容器
核心是两个卷积层:
model.add(Conv2D(32
, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
为了防止过拟合,我们加上一个最大池化层,再加上一个Dropout层:
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
下面要进入全连接层输出了,这两个中间的数据转换需要一个Flatten层:
下面是全连接层,激活函数是relu。
还怕过拟合,再来个Dropout层!
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
最后通过一个softmax激活函数的全连接网络输出:
model.add(Dense(num_classes, activation='softmax'))
下面是编译这个模型,损失函数是categorical_crossentropy多类对数损失函数,优化器选用Adadelta。
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
下面是可以运行的完整代码:
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
batch_size = 128
num_classes = 10
epochs = 12
# input image dimensions
img_rows, img_cols = 28, 28
# the data, split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
if K.image_data_format() == 'channels_first'