前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何从零开发一个复杂深度学习模型

如何从零开发一个复杂深度学习模型

作者头像
朱晓霞
发布2018-04-18 15:53:15
3.2K0
发布2018-04-18 15:53:15
举报
深度学习框架中涉及很多参数,如果一些基本的参数如果不了解,那么你去看任何一个深度学习框架是都会觉得很困难,下面介绍几个新手常问的几个参数。

batch

深度学习的优化算法,说白了就是梯度下降。每次的参数更新有两种方式。

第一种,遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度。这种方法每更新一次参数都要把数据集里的所有样本都看一遍,计算量开销大,计算速度慢,不支持在线学习,这称为Batch gradient descent,批梯度下降。

另一种,每看一个数据就算一下损失函数,然后求梯度更新参数,这个称为随机梯度下降,stochastic gradient descent。这个方法速度比较快,但是收敛性能不太好,可能在最优点附近晃来晃去,hit不到最优点。两次参数的更新也有可能互相抵消掉,造成目标函数震荡的比较剧烈。

为了克服两种方法的缺点,现在一般采用的是一种折中手段,mini-batch gradient decent,小批的梯度下降,这种方法把数据分为若干个批,按批来更新参数,这样,一个批中的一组数据共同决定了本次梯度的方向,下降起来就不容易跑偏,减少了随机性。另一方面因为批的样本数与整个数据集相比小了很多,计算量也不是很大。

基本上现在的梯度下降都是基于mini-batch的,所以深度学习框架的函数中经常会出现batch_size,就是指这个。

iterations

iterations(迭代):每一次迭代都是一次权重更新,每一次权重更新需要batch_size个数据进行Forward运算得到损失函数,再BP算法更新参数。1个iteration等于使用batchsize个样本训练一次。

epochs

epochs被定义为向前和向后传播中所有批次的单次训练迭代。这意味着1个周期是整个输入数据的单次向前和向后传递。简单说,epochs指的就是训练过程中数据将被“轮”多少次,就这样。

举个例子

训练集有1000个样本,batchsize=10,那么: 训练完整个样本集需要: 100次iteration,1次epoch。

具体的计算公式为: one epoch = numbers of iterations = N = 训练样本的数量/batch_size

注:

在LSTM中我们还会遇到一个seq_length,其实 batch_size = num_steps * seq_length

tensor:张量,是tensorflow的数据模型。在tensorflow中可以简单理解为多位数组,表示计算节点,是tensorflow管理数据的形式。但是在tensorflow中,张量的实现并不是直接采用数组的形式,它仅仅是对运算结果的引用。 张量的三个主要属性:name、shape(维度)、type(类型)。 (Note:常量可以看成是一种永远输出固定值的计算,所以可以用计算表示数据) flow:以流的方式 TensorFlow保持节点不变,仅仅改变节点的数据,或者说数据在节点之间流动。 tensorflow支持n台机器m个cpu,k个gpu(n,m,k为任意整数)。 计算图:计算图是tensorflow的基础,在计算图中,节点表示计算,而边表示相互之间的依赖关系。 计算图的使用: 使用分为两个阶段:构建计算图和执行计算 (1)构建计算图 定义数据和计算节点以及它们之间的依赖。通过tf.get_default_graph来维护默认的计算图,通过g = tf.Graph来生成计算图,通过g.device()来查看gpu。 (2)执行计算

tensorflow运行模型:会话 会话拥有和管理TensorFlow程序运行时的所有资源。 使用会话来管理资源时,要注意释放资源。 TensorFlow可以自动生成默认的计算图,但不能自动生成默认的会话,需要手动指定默认的会话。 ConfigProto Protocol Buffer工具:可以配置需要生成的会话,类似并行的线程数、gpu分配策略和运算超时时间等参数。

使用TensorFlow来构建神经网络 前向传播算法: 最简单的前向传播算法是全连接网络结构的前向传播算法。 全连接:相邻两层之间任意两个节点之间都有连接。 W表示神经网络的参数。 在TensorFlow中,声明函数tf.Variable给权重赋初始值。使用tf.initialize_all_variables函数,不需要将变量一个一个初始化,而且会自动处理变量之间的依赖关系。 集合(collection):管理不同类别的资源。表3-1表示了TensorFlow维护的所有集合的列表。

变量的两个重要属性:维度和类型。 类型一旦被确定,不能改变,不同类型的赋值将会报错。 虽然TensorFlow支持更改变量的维度,但是这种应用在实践中比较罕见。

神经网络优化算法中,最常用的是反向传播算法(backpropagation) TensorFlow提供了placeholder机制来避免因为常量过多而导致的计算图过大的问题。placeholder机制用于提供输入数据,相当于定义了一个位置,这个位置中的数据在程序运行时再指定。palceholder的类型需要指定,同时也不可以改变。维度信息可以根据提供的数据推导得出,所以不一定给出。在运行时,需要提供一个feed_dict(一种字典类型的)类型的数据赋值。 TensorFlow支持7种不同的优化器,可以对TRAINABLE_VARIABLES集合中的变量进行优化。

深度学习两个重要特性:多层、非线性 多层:加入隐藏层,可以认为从输入特征中提取了更高维的特征,实际上具有组合特征提取的功能。 TensorFlow支持7种不同的非线性激活函数,同时用户也可以使用自己定义的激活函数,来保证深度学习的非线性。

经典损失函数:通常使用交叉熵来描述两个概率之间的距离,通过刻画概率分布q来表达概率分布p的困难程度,当交叉熵作为神经网络的损失函数时,则p代表的是正确答案,q代表的是预测值。为了将神经网络的输出变成概率分布,softmax回归是最常用的方法。对于回归问题,最常用的损失函数是均方误差。回归问题一般只有一个输出节点。 在TensorFlow中还可以自定义损失函数。

神经网络优化算法:反向传播算法和梯度下降算法 反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法,是训练神经网络的核心算法。梯度下降算法的计算时间太长,通常采用随机梯度下降和梯度下降方法的折中:batch梯度下降。 注:梯度下降算法不一定能保证达到局部最优值。 学习率的设置 Tensorflow使用集合来解决因参数过多而带来的损失函数过长容易出错的问题。 滑动平均模型:在tensorflow中,使用tf.train.ExponentialMovingAverage来实现。初始化时,需要提供衰减率(decay)来控制更新的速度。

数据集: train:训练模型。 validation:从train数据集中分离出来,在训练过程中作为测试数据,因为选用测试集来选取参数可能会导致神经网络模型过度拟合测试数据。 test:判断一个神经网络的模型的效果最终是通过测试数据来评判的。 tensorflow中主要通过tf.get_variable和tf.variable_scope来通过变量名称获取变量。tf.get_variable变量名称是一个必填的参数,tf.Variable变量名称是一个可选的参数。 通过命名空间可以解决变量名冲突的问题,比如第一层和第二层神经网络中都定义了weights这个变量,则会冲突,如果先定义两个命名空间:layer1和layer2,则在各自的命名空间中定义变量解决命名冲突问题。

模型持久化 目的:让训练结果可以复用(将训练结果保存下来以便以后直接使用) 方式:tf.train.Saver() API 应用:saver.save(path)函数会保存生成三个文件,这是因为tensorflow会将计算图上的结构和参数取值分开保存。 (1)*.ckpt.meta保存计算图的结构 数据格式:元图(MetaGraph) 通过元图来记录计算图中节点的信息以及运行计算图中节点所需要的元数据。MetaGraph是由MetaGraphDef Protocol Buffer定义的,构成了TensorFlow持久化时的第一个文件。MetaGraphDef类型的定义如下所示:

save保存的是二进制文件,可以通过export_meta_graph函数以json格式导出meta文件来查看。 (2)*.ckpt保存程序中每一个变量的取值 文件列表的第一行描述了文件的元信息,比如在这个文件中存储的变量列表。列表剩下的每一行保存了一个变量的片段。TensorFlow提供tf.train.NewCheckpointReader类来查看ckpt文件中保存的变量信息。 (3)checkpoint保存了一个目录下所有的模型文件列表。 该文件的名字是固定的,是tf.train.Saver类自动生成且自动维护的。该文件维护了由tf.train.Saver类持久话的所有TensorFlow生成的模型文件的文件名。 程序默认保存和加载了TensorFlow计算图上定义的全部变量,但有时可能需要保存或加载部分变量。在声明tf.train.Saver类使可以提供一个列表来指定需要保存或加载的变量,同时该类也可以在保存或加载变量时支持对变量的重命名。 TensorFlow也提供了convert_variables_to_constants函数,通过该函数可以将计算图中的变量及其取值通过常量的方式保存,整个计算图可以统一存放在一个文件中。

图像识别问题经典数据集: MNIST、Cifar、ImageNet

图像识别与卷积神经网络 全连接神经网络无法很好地处理图像数据的原因: 1.全连接神经网络处理图像的最大问题在于全连接层的参数太多,导致计算速度低,还容易导致过拟合的问题。

卷积神经网络相邻两层之间只有部分节点相连。卷积神经网络和全连接神经网络的唯一区别就是神经网络中相邻两层的连接方式。

卷积神经网络主要由5中结构组成: 1.输入层 整个神经网络的输入,在图像处理中,输入一般代表一张图片的像素矩阵。在图6-7中,最左侧的三维矩阵就代表一张图片。三维矩阵的长和宽代表图像的大小,深度代表了图像的色彩通道。从输入层开始,卷积神经网络通过不同的神经网络结构将上一层的三维矩阵转化为下一层的三维矩阵,知道最后的全连接层。 2.卷积层 卷积层是卷积神经网络中最重要的部分。卷积层中每一个节点的输入只是上一层神经网络的一小块,这个小块常用的大小有3∗3或5∗5,一般来说经过卷积层处理过的节点矩阵会变得更深。 3.池化层 池化层神经网络不会改变三维矩阵的深度,但是它可以缩小矩阵的大小。池化操作可以认为是将一张分辨率较高的图片转化为分辨率较低的图片。池化层可以进一步缩小最好全连接层中节点的个数,从而达到减少整个神经网络中参数的目的。 4.全连接层 经过多轮卷积层和池化层的处理之后,卷积神经网络的最后一般会是由1-2个全连接层来给出最后的分类结果。经过几轮卷积层和池化层处理只好,可以认为图像中的信息已经被抽象成了信息含量更高的特征。 5.Softmax层(pooling层) Softmax层主要用于分类问题。

Keras

Keras 是提供一些高可用的 Python API ,能帮助你快速的构建和训练自己的深度学习模型,它的后端是 TensorFlow 或者 Theano 。本文假设你已经熟悉了 TensorFlow 和卷积神经网络,如果,你还没有熟悉,那么可以先看看这个10分钟入门 TensorFlow 教程

http://cv-tricks.com/artificial-intelligence/deep-learning/deep-learning-frameworks/tensorflow-tutorial/

和卷积神经网络教程

http://cv-tricks.com/tensorflow-tutorial/training-convolutional-neural-network-for-image-classification/

然后再回来阅读这个文章。

在这个教程中,我们将学习以下几个方面:

  1. 为什么选择 Keras?为什么 Keras 被认为是深度学习的未来?
  2. 在Ubuntu上面一步一步安装Keras。
  3. Keras TensorFlow教程:Keras基础知识。
  4. 了解 Keras 序列模型 4.1 实际例子讲解线性回归问题
  5. 使用 Keras 保存和回复预训练的模型
  6. Keras API 6.1 使用Keras API开发VGG卷积神经网络 6.2 使用Keras API构建并运行SqueezeNet卷积神经网络

1. 为什么选择Keras?

Keras 是 Google 的一位工程师 François Chollet 开发的一个框架,可以帮助你在 Theano 上面进行快速原型开发。后来,这被扩展为 TensorFlow 也可以作为后端。并且最近,TensorFlow决定将其作为 contrib 文件中的一部分进行提供。

Keras 被认为是构建神经网络的未来,以下是一些它流行的原因:

  1. 轻量级和快速开发:Keras 的目的是在消除样板代码。几行 Keras 代码就能比原生的 TensorFlow 代码实现更多的功能。你也可以很轻松的实现 CNN 和 RNN,并且让它们运行在 CPU 或者 GPU 上面。
  2. 框架的“赢者”:Keras 是一个API,运行在别的深度学习框架上面。这个框架可以是 TensorFlow 或者 Theano。Microsoft 也计划让 CNTK 作为 Keras 的一个后端。目前,神经网络框架世界是非常分散的,并且发展非常快。

想象一下,我们每年都要去学习一个新的框架,这是多么的痛苦。到目前为止,TensorFlow 似乎成为了一种潮流,并且越来越多的框架开始为 Keras 提供支持,它可能会成为一种标准。

目前,Keras 是成长最快的一种深度学习框架。因为可以使用不同的深度学习框架作为后端,这也使得它成为了流行的一个很大的原因。你可以设想这样一个场景,如果你阅读到了一篇很有趣的论文,并且你想在你自己的数据集上面测试这个模型。让我们再次假设,你对TensorFlow 非常熟悉,但是对Theano了解的非常少。那么,你必须使用TensorFlow 对这个论文进行复现,但是这个周期是非常长的。但是,如果现在代码是采用Keras写的,那么你只要将后端修改为TensorFlow就可以使用代码了。这将是对社区发展的一个巨大的推动作用。

2. 怎么安装Keras,并且把TensorFlow作为后端

a) 依赖安装

安装 h5py,用于模型的保存和载入:

代码语言:javascript
复制
pip install h5py

还有一些依赖包也要安装。

代码语言:javascript
复制
pip install numpy scipypip install pillow

你安装完成了 TensorFlow,你只需要使用 pip 很容易的安装 Keras。

代码语言:javascript
复制
sudo pip install keras

使用以下命令来查看 Keras 版本。

代码语言:javascript
复制
>>> import kerasUsing TensorFlow backend.>>> keras.__version__'2.0.4'

一旦,Keras 被安装完成,你需要去修改后端文件,也就是去确定,你需要 TensorFlow 作为后端,还是 Theano 作为后端,修改的配置文件位于 ~/.keras/keras.json 。具体配置如下:

代码语言:javascript
复制
{    "floatx": "float32",    "epsilon": 1e-07,    "backend": "tensorflow",    "image_data_format": "channels_last"}

请注意,参数 image_data_formatchannels_last ,也就是说这个后端是 TensorFlow。因为,在TensorFlow中图像的存储方式是[height, width, channels],但是在Theano中是完全不同的,也就是 [channels, height, width]。因此,如果你没有正确的设置这个参数,那么你模型的中间结果将是非常奇怪的。对于Theano来说,这个参数就是channels_first

那么,至此你已经准备好了,使用Keras来构建模型,并且把TensorFlow作为后端。

3. Keras基础知识

在Keras中主要的数据结构是 model ,该结构定义了一个完整的图。你可以向已经存在的图中加入任何的网络结构。

代码语言:javascript
复制
import keras

Keras 有两种不同的建模方式:

  1. Sequential models:这种方法用于实现一些简单的模型。你只需要向一些存在的模型中添加层就行了。
  2. Functional API:Keras的API是非常强大的,你可以利用这些API来构造更加复杂的模型,比如多输出模型,有向无环图等等。

在本文的下一节中,我们将学习Keras的Sequential models 和 Functional API的理论和实例。

4. Keras Sequential models

在这一部分中,我将来介绍Keras Sequential models的理论。我将快速的解释它是如何工作的,还会利用具体代码来解释。之后,我们将解决一个简单的线性回归问题,你可以在阅读的同时运行代码,来加深印象。

以下代码是如何开始导入和构建序列模型。

代码语言:javascript
复制
from keras.models import Sequentialmodels = Sequential()

接下来我们可以向模型中添加 Dense(full connected layer),Activation,Conv2D,MaxPooling2D函数。

代码语言:javascript
复制
from keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten, Dropoutmodel.add(Conv2D(64, (3,3), activation='relu', input_shape = (100,100,32)))# This ads a Convolutional layer with 64 filters of size 3 * 3 to the graph

以下是如何将一些最流行的图层添加到网络中。

1. 卷积层

这里我们使用一个卷积层,64个卷积核,维度是33的,之后采用 relu 激活函数进行激活,输入数据的维度是 `100100*32`。注意,如果是第一个卷积层,那么必须加上输入数据的维度,后面几个这个参数可以省略。

代码语言:javascript
复制
model.add(Conv2D(64, (3,3), activation='relu', input_shape = (100,100,32)))

2. MaxPooling 层

指定图层的类型,并且指定赤的大小,然后自动完成赤化操作,酷毙了!

代码语言:javascript
复制
model.add(MaxPooling2D(pool_size=(2,2)))

3. 全连接层

这个层在 Keras 中称为被称之为 Dense 层,我们只需要设置输出层的维度,然后Keras就会帮助我们自动完成了。

代码语言:javascript
复制
model.add(Dense(256, activation='relu'))

4. Dropout

代码语言:javascript
复制
model.add(Dropout(0.5))

5. 扁平层

代码语言:javascript
复制
model.add(Flatten())

数据输入

网络的第一层需要读入训练数据。因此我们需要去制定输入数据的维度。因此,input_shape参数被用于制定输入数据的维度大小。

代码语言:javascript
复制
model.add(Conv2D(32, (3,3), activation='relu', input_shape=(224, 224, 3)))

在这个例子中,数据输入的第一层是一个卷积层,输入数据的大小是 224*224*3

以上操作就帮助你利用序列模型构建了一个模型。接下来,让我们学习最重要的一个部分。一旦你指定了一个网络架构,你还需要指定优化器和损失函数。我们在Keras中使用compile函数来达到这个功能。比如,在下面的代码中,我们使用 rmsprop 来作为优化器,binary_crossentropy 来作为损失函数值。

代码语言:javascript
复制
model.compile(loss='binary_crossentropy', optimizer='rmsprop')

如果你想要使用随机梯度下降,那么你需要选择合适的初始值和超参数:

代码语言:javascript
复制
from keras.optimizers import SGDsgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)model.compile(loss='categorical_crossentropy', optimizer=sgd)

现在,我们已经构建完了模型。接下来,让我们向模型中输入数据,在Keras中是通过 fit 函数来实现的。你也可以在该函数中指定 batch_sizeepochs 来训练。

代码语言:javascript
复制
model.fit(x_train, y_train, batch_size = 32, epochs = 10, validation_data(x_val, y_val))

最后,我们使用 evaluate 函数来测试模型的性能。

代码语言:javascript
复制
score = model.evaluate(x_test, y_test, batch_size = 32)

这些就是使用序列模型在Keras中构建神经网络的具体操作步骤。现在,我们来构建一个简单的线性回归模型。

4.1 实际例子讲解线性回归问题
问题陈述

在线性回归问题中,你可以得到很多的数据点,然后你需要使用一条直线去拟合这些离散点。在这个例子中,我们创建了100个离散点,然后用一条直线去拟合它们。

a) 创建训练数据

TrainX 的数据范围是 -1 到 1,TrainY 与 TrainX 的关系是3倍,并且我们加入了一些噪声点。

代码语言:javascript
复制
import kerasfrom keras.models import Sequentialfrom keras.layers import Denseimport numpy as nptrX = np.linspace(-1, 1, 101)trY = 3 * trX + np.random.randn(*trX.shape) * 0.33

b) 构建模型

首先我们需要构建一个序列模型。我们需要的只是一个简单的链接,因此我们只需要使用一个 Dense 层就够了,然后用线性函数进行激活。

代码语言:javascript
复制
model = Sequential()model.add(Dense(input_dim=1, output_dim=1, init='uniform', activation='linear'))

下面的代码将设置输入数据 x,权重 w 和偏置项 b。然我们来看看具体的初始化工作。如下:

代码语言:javascript
复制
weights = model.layers[0].get_weights()w_init = weights[0][0][0]b_init = weights[1][0]print('Linear regression model is initialized with weights w: %.2f, b: %.2f' % (w_init, b_init)) ## Linear regression model is initialized with weight w: -0.03, b: 0.00

现在,我们可以l利用自己构造的数据 trXtrY 来训练这个线性模型,其中 trYtrX 的3倍。因此,权重 w 的值应该是 3。

我们使用简单的梯度下降来作为优化器,均方误差(MSE)作为损失值。如下:

代码语言:javascript
复制
model.compile(optimizer='sgd', loss='mse')

最后,我们使用 fit 函数来输入数据。

代码语言:javascript
复制
model.fit(trX, trY, nb_epoch=200, verbose=1)

在经过训练之后,我们再次打印权重:

代码语言:javascript
复制
weights = model.layers[0].get_weights()w_final = weights[0][0][0]b_final = weights[1][0]print('Linear regression model is trained to have weight w: %.2f, b: %.2f' % (w_final, b_final))##Linear regression model is trained to have weight w: 2.94, b: 0.08

正如你所看到的,在运行 200 轮之后,现在权重非常接近于 3。你可以将运行的轮数修改为区间 [100, 300] 之间,然后观察输出结构有什么变化。现在,你已经学会了利用很少的代码来构建一个线性回归模型,如果要构建一个相同的模型,在 TensorFlow 中需要用到更多的代码。

5. 使用 Keras 保存和回复预训练的模型

HDF5 二进制格式

一旦你利用Keras完成了训练,你可以将你的网络保存在HDF5里面。当然,你需要先安装 h5py。HDF5 格式非常适合存储大量的数字收,并从 numpy 处理这些数据。比如,我们可以轻松的将存储在磁盘上的多TB数据集进行切片,就好像他们是真正的 numpy 数组一样。你还可以将多个数据集存储在单个文件中,遍历他们或者查看 .shape.dtype 属性。

如果你需要信心,那么告诉你,NASA也在使用 HDF5 进行数据存储。h5py 是python对HDF5 C API 的封装。几乎你可以用C在HDF5上面进行的任何操作都可以用python在h5py上面操作。

保存权重

如果你要保存训练好的权重,那么你可以直接使用 save_weights 函数。

代码语言:javascript
复制
model.save_weights("my_model.h5")

载入预训练权重

如果你想要载入以前训练好的模型,那么你可以使用 load_weights 函数。

代码语言:javascript
复制
model.load_weights('my_model_weights.h5')

6. Keras API

如果对于简单的模型和问题,那么序列模型是非常好的方式。但是如果你要构建一个现实世界中复杂的网络,那么你就需要知道一些功能性的API,在很多流行的神经网络中,我们都有一个最小的网络结构,完整的模型是根据这些最小的模型进行叠加完成的。这些基础的API可以让你一层一层的构建模型。因此,你只需要很少的代码就可以来构建一个完整的复杂神经网络。

让我们来看看它是如何工作的。首先,你需要导入一些包。

代码语言:javascript
复制
from keras.models import Model

现在,你需要去指定输入数据,而不是在顺序模型中,在最后的 fit 函数中输入数据。这是序列模型和这些功能性的API之间最显著的区别之一。我们使用 input() 函数来申明一个 1*28*28 的张量。

代码语言:javascript
复制
from keras.layers import Input## First, define the vision modulesdigit_input = Input(shape=(1, 28, 28))

现在,让我们来利用API设计一个卷积层,我们需要指定要在在哪个层使用卷积网络,具体代码这样操作:

代码语言:javascript
复制
x = Conv2D(64, (3, 3))(digit_input)x = Conv2D(64, (3, 3))(x)x = MaxPooling2D((2, 2))(x)out = Flatten()(x)

最后,我们对于指定的输入和输出数据来构建一个模型。

代码语言:javascript
复制
vision_model = Model(digit_input, out)

当然,我们还需要指定损失函数,优化器等等。但这些和我们在序列模型中的操作一样,你可以使用 fit 函数和 compile 函数来进行操作。

接下来,让我们来构建一个vgg-16模型,这是一个很大很“老”的模型,但是由于它的简洁性,它是一个很好的学习模型。

6.1 使用Keras API开发VGG卷积神经网络

VGG:

VGG卷积神经网络是牛津大学在2014年提出来的模型。当这个模型被提出时,由于它的简洁性和实用性,马上成为了当时最流行的卷积神经网络模型。它在图像分类和目标检测任务中都表现出非常好的结果。在2014年的ILSVRC比赛中,VGG 在Top-5中取得了92.3%的正确率。 该模型有一些变种,其中最受欢迎的当然是 vgg-16,这是一个拥有16层的模型。你可以看到它需要维度是 224*224*3 的输入数据。

Vgg 16 architecture

让我们来写一个独立的函数来完整实现这个模型。

代码语言:javascript
复制
img_input = Input(shape=input_shape)# Block 1x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)# Block 2x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)# Block 3x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)# Block 4x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)# Block 5x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)x = Flatten(name='flatten')(x)x = Dense(4096, activation='relu', name='fc1')(x)x = Dense(4096, activation='relu', name='fc2')(x)x = Dense(classes, activation='softmax', name='predictions')(x)

我们可以将这个完整的模型,命名为 vgg16.py。

在这个例子中,我们来运行 imageNet 数据集中的某一些数据来进行测试。具体代码如下:

代码语言:javascript
复制
model = applications.VGG16(weights='imagenet')img = image.load_img('cat.jpeg', target_size=(224, 224))x = image.img_to_array(img)x = np.expand_dims(x, axis=0)x = preprocess_input(x)preds = model.predict(x)for results in decode_predictions(preds):    for result in results:        print('Probability %0.2f%% => [%s]' % (100*result[2], result[1]))

正如你在图中看到的,模型会对图片中的物体进行一个识别预测。

我们通过API构建了一个VGG模型,但是由于VGG是一个很简单的模型,所以并没有完全将API的能力开发出来。接下来,我们通过构建一个 SqueezeNet模型,来展示API的真正能力。

6.2 使用Keras API构建并运行SqueezeNet卷积神经网络

SequeezeNet 是一个非常了不起的网络架构,它的显著点不在于对正确性有多少的提高,而是减少了计算量。当SequeezeNet的正确性和AlexNet接近时,但是ImageNet上面的预训练模型的存储量小于5 MB,这对于在现实世界中使用CNN是非常有利的。SqueezeNet模型引入了一个 Fire模型,它由交替的 Squeeze 和 Expand 模块组成。

SqueezeNet fire module

现在,我们对 fire 模型进行多次复制,从而来构建完整的网络模型,具体如下:

为了去构建这个网络,我们将利用API的功能首先来构建一个单独的 fire 模块。

代码语言:javascript
复制
# Squeeze part of fire module with 1 * 1 convolutions, followed by Relux = Convolution2D(squeeze, (1, 1), padding='valid', name='fire2/squeeze1x1')(x)x = Activation('relu', name='fire2/relu_squeeze1x1')(x)#Expand part has two portions, left uses 1 * 1 convolutions and is called expand1x1 left = Convolution2D(expand, (1, 1), padding='valid', name='fire2/expand1x1')(x)left = Activation('relu', name='fire2/relu_expand1x1')(left)#Right part uses 3 * 3 convolutions and is called expand3x3, both of these are follow#ed by Relu layer, Note that both receive x as input as designed. right = Convolution2D(expand, (3, 3), padding='same', name='fire2/expand3x3')(x)right = Activation('relu', name='fire2/relu_expand3x3')(right)# Final output of Fire Module is concatenation of left and right. x = concatenate([left, right], axis=3, name='fire2/concat')

为了重用这些代码,我们可以将它们转换成一个函数:

代码语言:javascript
复制
sq1x1 = "squeeze1x1"exp1x1 = "expand1x1"exp3x3 = "expand3x3"relu = "relu_"WEIGHTS_PATH = "https://github.com/rcmalli/keras-squeezenet/releases/download/v1.0/squeezenet_weights_tf_dim_ordering_tf_kernels.h5"

模块化处理

代码语言:javascript
复制
sq1x1 = "squeeze1x1"exp1x1 = "expand1x1"exp3x3 = "expand3x3"relu = "relu_"def fire_module(x, fire_id, squeeze=16, expand=64):   s_id = 'fire' + str(fire_id) + '/'   x = Convolution2D(squeeze, (1, 1), padding='valid', name=s_id + sq1x1)(x)   x = Activation('relu', name=s_id + relu + sq1x1)(x)   left = Convolution2D(expand, (1, 1), padding='valid', name=s_id + exp1x1)(x)   left = Activation('relu', name=s_id + relu + exp1x1)(left)   right = Convolution2D(expand, (3, 3), padding='same', name=s_id + exp3x3)(x)   right = Activation('relu', name=s_id + relu + exp3x3)(right)   x = concatenate([left, right], axis=3, name=s_id + 'concat')return x

现在,我们可以利用我们构建好的单独的 fire 模块,来构建完整的模型。

代码语言:javascript
复制
x = Convolution2D(64, (3, 3), strides=(2, 2), padding='valid', name='conv1')(img_input)x = Activation('relu', name='relu_conv1')(x)x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool1')(x)x = fire_module(x, fire_id=2, squeeze=16, expand=64)x = fire_module(x, fire_id=3, squeeze=16, expand=64)x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool3')(x)x = fire_module(x, fire_id=4, squeeze=32, expand=128)x = fire_module(x, fire_id=5, squeeze=32, expand=128)x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool5')(x)x = fire_module(x, fire_id=6, squeeze=48, expand=192)x = fire_module(x, fire_id=7, squeeze=48, expand=192)x = fire_module(x, fire_id=8, squeeze=64, expand=256)x = fire_module(x, fire_id=9, squeeze=64, expand=256)x = Dropout(0.5, name='drop9')(x)x = Convolution2D(classes, (1, 1), padding='valid', name='conv10')(x)x = Activation('relu', name='relu_conv10')(x)x = GlobalAveragePooling2D()(x)out = Activation('softmax', name='loss')(x)model = Model(inputs, out, name='squeezenet')

完整的网络模型我们放置在 squeezenet.py 文件里。我们应该先下载 imageNet 预训练模型,然后在我们自己的数据集上面进行训练和测试。下面的代码就是实现了这个功能:

代码语言:javascript
复制
import numpy as npfrom keras_squeezenet import SqueezeNetfrom keras.applications.imagenet_utils import preprocess_input, decode_predictionsfrom keras.preprocessing import imagemodel = SqueezeNet()img = image.load_img('pexels-photo-280207.jpeg', target_size=(227, 227))x = image.img_to_array(img)x = np.expand_dims(x, axis=0)x = preprocess_input(x)preds = model.predict(x)all_results = decode_predictions(preds)for results in all_results:  for result in results:    print('Probability %0.2f%% => [%s]' % (100*result[2], result[1]))

对于相同的一幅图预测,我们可以得到如下的预测概率。

原文 https://www.jianshu.com/p/20585e3b6d02

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 目标检测和深度学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • batch
  • iterations
  • epochs
  • 1. 为什么选择Keras?
  • 2. 怎么安装Keras,并且把TensorFlow作为后端
    • a) 依赖安装
    • 3. Keras基础知识
    • 4. Keras Sequential models
    • 数据输入
      • 4.1 实际例子讲解线性回归问题
      • 5. 使用 Keras 保存和回复预训练的模型
        • HDF5 二进制格式
        • 6. Keras API
          • 6.1 使用Keras API开发VGG卷积神经网络
            • 6.2 使用Keras API构建并运行SqueezeNet卷积神经网络
            相关产品与服务
            数据保险箱
            数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档