写点什么

深度学习利器:TensorFlow 与深度卷积神经网络

2017 年 7 月 09 日

前言

图像识别技术越来越多地渗透到我们的日常生活中,人可以很快递判别图像类型,比如,很容易地识别一个图片是狮子还是其它动物,可以很容易地对人脸进行识别。但是对于机器来说,去识别一个图片是什么,是一个非常困难的问题。但在过去的几年中,图像识别技术取得了巨大的进展,在一些固定领域可以达到,甚至超越人类的识别精度,该技术称为深度卷积神经网络(Deep Convolutional Neural Network)。

目前,学术界主要通过 ImageNet 的 Benchmark 问题,去验证图像识别技术的发展程度,卷积神经网络模型包括:QuocNet, AlexNet, Inception (GoogLeNet), BN-Inception-v2,以及最新的 Inception-v3 模型。其中,AlexNet 的 top-5 的错误率为 15.3%;Inception(GoogLeNet)降到 6.67%;BN-Inception-v2 降到 4.9%;Inception-v3 降到 3.46%。

如果用户有业务图片数据,如何利用开源现有的模型进行训练呢?如何进行花图片识别,人物图片识别,车辆图片识别,医学图片识别呢?本文主要介绍 TensorFlow 开源模型 Cifar10,Inception V3,Vgg19 的主要架构和代码。如果用户需要对业务图片识别,可再已有模型的基础上持续改进,进行训练及调优,加速研发,满足业务需求。

卷积神经网络回顾

卷积神经网络是基于人工神经网络的深度机器学习方法,成功应用于图像识别领域。CNN 采用了局部连接和权值共享,保持了网络的深层结构,同时又减少了网络参数,使模型具有良好的泛化能力又较容易训练,CNN 的训练算法是梯度下降的错误反向传播(Back Propagate,BP)算法的一种变形。

卷积神经网络通常采用若干个卷积和子采样层的叠加结构作为特征抽取器。卷积层与子采样层不断将特征图缩小,但是特征图的数量往往增多。特征抽取器后面接一个分类器,分类器通常由一个多层感知机构成。在特征抽取器的末尾,我们将所有的特征图展开并排列成为一个向量,称为特征向量,该特征向量作为后层分类器的输入,如下图所示:

(点击放大图像)

卷积过程有三个二维矩阵参与,它们分别是两个特征图和一个卷积核:原图inputX、输出图outputY、卷积核kernelW。卷积过程可以理解为卷积核卷积核kernalW 覆盖在原图inputX 的一个局部的面上,kernalW 对应位置的权重乘于inputX 对应神经元的输出,对各项乘积求和并赋值到outputY 矩阵的对应位置。卷积核在inputX 图中从左向右,从上至下每次移动一个位置,完成整张inputX 的卷积过程,如下图所示:

(点击放大图像)

子采样有两种方式,一种是均值子采样,一种是最大值子采样,如下图所示:

(点击放大图像)

在最大值子采样中的卷积核中,只有一个值为1,其他值为0,保留最强输入值,卷积核在原图上的滑动步长为2,相当于把原图缩减到原来的1/4。均值子采样卷积核中的每个权重为0.25,保留的是输入图的均值数据。

卷积核的本质是神经元之间相互连接的权重,而且该权重被属于同一特征图的神经元所共享。在实际的网络训练过程中,输入神经元组成的特征图被切割成卷积核大小的小图。每个小图通过卷积核与后层特征图的一个神经元连接。一个特征图上的所有小图和后层特征图中某个神经元的连接使用的是相同的卷积核,也就是同特征图的神经元共享了连接权重。

TensorFlow API 构建卷积神经网络

在 TensorFlow 中,卷积神经网络(Convolutional neural networks,CNNs)主要包含三种类型的组件,主要 API 如下:

  • 卷积层(Convolutional Layer),构建一个 2 维卷积层,常用的参数有:
复制代码
conv = tf.layers.conv2d(
inputs=pool,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)

inputs 表示输入要的 Tensor,filters 表示卷积核的数量,kernel_size 表示卷积核的大小,padding 表示卷积的边界处理方式,有 valid 和 same 两种方式,valid 方式不会在原有输入的基础上添加新的像素,same 表示需要对 input 的边界数据进行填存,具体计算公式参见 https://www.tensorflow.org/api_docs/python/tf/nn/convolution

activation 表示要采用的激活函数。

  • 池化层(Pooling Layer,max_pooling2d 或 average_pooling2d),用于构建 2 维池化,常用的参数有:
复制代码
tf.layers.max_pooling2d(
inputs=conv,
pool_size=[2, 2],
strides=2)

inputs 表示要被池化的输入 Tensor,pool_size 表示池化窗口大小,strides 表示进行池化操作的步长。

  • 全链接层(Dense Layer,dense),主要对特性向量执行分类操作。执行全链接操作前,需要对池化后的特性向量,执行展开操作,转换成 [batch_size, features] 的形式,如下所示: tf.reshape(pool, [-1, 7 * 7 * 64]),-1 表示 BatchSize,

    全链接层主要参数如下所示:

复制代码
tf.layers.dense(inputs=pool2_flat,
units=1024,
activation=tf.nn.relu)

inputs 表示输入层,units 表示输出层的 tensor 的形状为 [batchsize, units],activation 表示要采用的激化函数。

使用 TensorFlow API 构建卷积神经网络的示例代码,如下所示:

复制代码
# 输入层
# 改变输入数据维度为 4-D tensor: [batch_size, width, height, channels]
# 图像数据为 28x28 像素大小, 并且为单通道
input_layer = tf.reshape(features, [-1, 28, 28, 1])
# 卷积层 1
# 卷积核大小为 5x5,卷积核数量为 32, 激活方法使用 RELU
# 输入 Tensor 维度: [batch_size, 28, 28, 1]
# 输出 Tensor 维度: [batch_size, 28, 28, 32]
conv1 = tf.layers.conv2d(
inputs=input_layer,
filters=32,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
# 池化层 1
# 采用 2x2 维度的最大化池化操作,步长为 2
# 输入 Tensor 维度: [batch_size, 28, 28, 32]
# 输出 Tenso 维度: [batch_size, 14, 14, 32]
pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
#卷积层 2
#卷积核大小为 5x5,卷积核数量为 64, 激活方法使用 RELU.
#输入 Tensor 维度: [batch_size, 14, 14, 32]
#输出 Tensor 维度: [batch_size, 14, 14, 64]
conv2 = tf.layers.conv2d(
inputs=pool1,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
#池化层 2
#采用 2x2 维度的最大化池化操作,步长为 2
#输入 Tensor 维度: [batch_size, 14, 14, 64]
#输出 Tensor 维度: [batch_size, 7, 7, 64]
pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
# 展开并列池化层输出 Tensor 为一个向量
#输入 Tensor 维度: [batch_size, 7, 7, 64]
#输出 Tensor 维度: [batch_size, 7 * 7 * 64]
pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])
# 全链接层
# 该全链接层具有 1024 神经元
#输入 Tensor 维度: [batch_size, 7 * 7 * 64]
#输出 Tensor 维度: [batch_size, 1024]
dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
#对全链接层的数据加入 dropout 操作,防止过拟合
#40% 的数据会被 dropout,
dropout = tf.layers.dropout(
inputs=dense, rate=0.4, training=mode == learn.ModeKeys.TRAIN)
# Logits 层,对 dropout 层的输出 Tensor,执行分类操作
#输入 Tensor 维度: [batch_size, 1024]
#输出 Tensor 维度: [batch_size, 10]
logits = tf.layers.dense(inputs=dropout, units=10)

TensorFlow Cifar10 模型

CIFAR-10, http://www.cs.toronto.edu/~kriz/cifar.html ,是图片识别的 benchmark 问题,主要对 RGB 为 32*32 的图像进行 10 分类,类别包括:airplane, automobile, bird, cat, deer, dog, frog, horse, ship, and truck。其中包括 50000 张训练图片,10000 张测试图片。

(点击放大图像)

TensorFlow Cifar10, https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10 ,模型包含 1,068,298 个参数,单个图片的推导包含 19.5M 个乘法 / 加法运算。该模型在 GPU 上运行几个小时后,测试精确度会达到 86%。模型特性主要包括:

  • 核心数学组件:卷积操作,RELU 激活算子,池化操作,局部响应归一化操作。
  • 可视化展示:展示训练过程的 loss 值,梯度,以及参数分布情况等。
  • 滑动平均:使用参数的滑动平均值执行评估操作。
  • 预处理队列:通过队列对训练数据进行预处理,用于减少读取数据的延迟,加快数据的预处理。

该模型的代码结构如下:

  • cifar10_input.py:负责加载训练数据。
  • cifar10.py:负责构建 cifar10 模型。
  • cifar10_train.py:负责在单设备(CPU/GPU)上进行训练。
  • cifar10_multi_gpu_train.py:负责在多 GPU 上进行训练。
  • cifar10_eval.py:负责对模型进行评估。

该模型的 Graph 结构如下:

(点击放大图像)

下图为Cifar10 的多GPU 模型架构,每个GPU 型号最好相同,具备足够的内存能运行整个Cifar10 模型。

(点击放大图像)

该架构会复制Cifar10 模型到每个GPU 上,每个GPU 上训练完一个Batch 的数据后,在CPU 端对梯度执行同步操作(求均值),更新训练参数,然后把模型参数发送给每个GPU,进行下一个Batch 数据的训练。

TensorFlow Inception V3 模型

Inception V3, http://arxiv.org/abs/1512.00567 ,模型包含 25 million 个模型参数,对单个图片的推导包含了 5 billion 的乘法 / 加法运算。top-1 的误差率降到了 21.2%,top-5 的误差率降到了 5.6%。该模型网络结构如下图所示:

(点击放大图像)

由于ImageNet 的训练数据比较大,下面主要介绍如何使用Flower 的数据进行训练,该数据集有5 种类别(daisy, dandelion, roses, sunflowers, tulips)的花,大概有几千张图片。

首先我们需要下载TensorFlow Inception V3 模型,如下所示:

git pull https://github.com/tensorflow/models

对花数据进行训练的代码结构,如下所示:

  • data/download_and_preprocess_flowers.sh: 下载花的数据,并转换为 TFRecord 格式。
  • slim/inception_model.py:inception V3 模型。
  • flowers_train.py:执行单机多 GPU 模型的训练。
  • flowers_eval.py:对训练的准确度进行评估。
复制代码
#进入 Inception V3 程序目录
cd models/inception
#设定 Flower 数据的存储路径
FLOWERS_DATA_DIR=/tmp/flowers-data/
#编译程序
bazel build //inception:download_and_preprocess_flowers
#执行下载和转换 TFRecord 操作
bazel-bin/inception/download_and_preprocess_flowers "${FLOWERS_DATA_DIR}"
转换好的训练数据包括:train-00000-of-00002,train-00001-of-00002
转换好的验证数据包括:validation-00000-of-00002,validation-00001-of-00002
基于训练好的 Inception V3 模型,继续训练花的数据:
#设定 Inception V3 模型下载路径
INCEPTION_MODEL_DIR=$HOME/inception-v3-model
mkdir -p ${INCEPTION_MODEL_DIR}
cd ${INCEPTION_MODEL_DIR}
#下载训练好的 Inception 模型
curl -O http://download.tensorflow.org/models/image/imagenet/inception-v3-2016-03-01.tar.gz
tar xzf inception-v3-2016-03-01.tar.gz
#编译程序
bazel build //inception:flowers_train
#设定要加载的模型路径
MODEL_PATH="${INCEPTION_MODEL_DIR}/inception-v3/model.ckpt-157585"
#设定训练数据路径
FLOWERS_DATA_DIR=/tmp/flowers-data/
#执行模型训练
bazel-bin/inception/flowers_train \
--train_dir="${TRAIN_DIR}" \
--data_dir="${FLOWERS_DATA_DIR}" \
--pretrained_model_checkpoint_path="${MODEL_PATH}" \
--fine_tune=True \
--initial_learning_rate=0.001 \
--input_queue_memory_factor=1

采用单 GPU,训练 1000 次迭代后,模型 loss 值降到 1.04,如下所示:

(点击放大图像)

TensorFlow Vgg19 模型

VGG 网络与 AlexNet 类似,也是一种 CNN,VGG 在 2014 年的 ILSVRC localization and classification 两个问题上分别取得了第一名和第二名。VGG 网络非常深,通常有 16-19 层,卷积核大小为 3 x 3,16 和 19 层的区别主要在于后面三个卷积部分卷积层的数量。可以看到 VGG 的前几层为卷积和 maxpool 的交替,后面紧跟三个全连接层,激活函数采用 Relu,训练采用了 dropout。VGG 中各模型配置如下, 其中 VGG19 的 top-1 的训练精度可达到 71.1%,top-5 的训练精度可达到 89.8%。模型结构示例如下:

(点击放大图像)

(点击放大图像)

TensorFlow Vgg19 的模型示例如下, https://github.com/tensorflow/models/blob/master/slim/nets/vgg.py

复制代码
#卷积操作和池化操作
net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
net = slim.max_pool2d(net, [2, 2], scope='pool1')
net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2')
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.repeat(net, 4, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool3')
net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv4')
net = slim.max_pool2d(net, [2, 2], scope='pool4')
net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv5')
net = slim.max_pool2d(net, [2, 2], scope='pool5')
net = slim.conv2d(net, 4096, [7, 7], padding=fc_conv_padding, scope='fc6')
#dropout 操作,防止过拟合
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout6')
net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout7')
net = slim.conv2d(net, num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
scope='fc8')

总结

本文首先回顾了深度卷积神经网络的特征图、卷积核,池化操作,全链接层等基本概念。接着介绍了使用 TensorFlow API 构建卷积神经网络,主要包括卷积操作 API,池化操作 API 以及全链接操作 API。针对图片识别,讲解了 TensorFlow Benchmark 模型(Cifar10,Inception V3 及 Vgg19)的架构和代码。如果有用户需要对自己的业务图片进行识别,可再已有模型的基础上持续改进,进行训练及调优,加速研发。

参考文献

  1. http://www.tensorflow.org
  2. 深度学习利器: 分布式 TensorFlow 及实例分析
  3. 深度学习利器:TensorFlow 使用实战
  4. 深度学习利器:TensorFlow 系统架构与高性能程序设计

作者简介

武维:博士,现为 IBM Spectrum Computing 研发工程师。主要从事大数据,深度学习,云计算等领域的研发工作。

2017 年 7 月 09 日 17:4011704

评论

发布
暂无评论
发现更多内容

探寻融云多年领先的秘密:不断创新贴近开发者真实需求

DT极客

CentOS7使用Iptables做网络转发

wong

Centos 7 iptables

MacOS使用指南之我并不需要系统菜单栏

lmymirror

macos 高效工作 完美主义 操作系统 新手指南

我跑步的时候会想些什么

养牛致富带头人

跑步 运动 锻炼

人生就是一场说走就走的旅行

kimmking

Web3极客日报#137

谢锐 | Frozen

区块链 独立开发者 技术社区 Rebase Web3 Daily

高仿瑞幸小程序 06 layout布局

曾伟@喵先森

小程序 微信小程序 前端

面试官竟然一直和我聊线程的启动和终止

Simon郎

Java 大数据 后端 多线程

你还在这样使用MYSQL吗?

无箭的丘比特

MySQL 数据库 数据库规范 数据库设计

Mac 自带软件-聚焦搜索

Winann

macos Mac spotlight

TL如何在团队中培养出更多前端技术专家

贵重

前端 团队建设 技术管理

你觉得你是哪类人?

Janenesome

读书笔记 思考

放假了,你还会打开钉钉么?

无箭的丘比特

高效工作 团队管理 企业文化 个人成长 技术管理

深入理解MDL元数据锁

Simon

MySQL

OceanBase原理与实现分析

ElvinYang

Web3极客日报#136

谢锐 | Frozen

区块链 独立开发者 技术社区 Rebase Web3 Daily

回"疫"录(13):不信谣,不传谣

小天同学

疫情 回忆录 现实纪录 纪实 谣言

【Howe 学 JAVA】Java 类集框架2——Set 集合

Howe

Java 集合 set

Using R for everything: 方差分解(Variation partition)变量筛选与显著性标注

洗衣机用户不会用洗衣机

数据分析 R

C语言if分支结构

C语言技术网-码农有道

C语言 C语言if分支结构

如何扩大我们的英语词汇量

七镜花园-董一凡

学习

保险知识梳理

魁拔

保险 生活质量

前端开发的瓶颈与未来之路

keelii

node.js typescript ruby-on-rails 编程 前端

游戏夜读 | 游戏设计需要天赋?

game1night

自助设备系列——技术应用

孙苏勇

产品 行业资讯 智能设备

【Howe 学 JAVA】Java 类集框架2——集合输出

Howe

Java 集合 输出 类集

物联网资产整合架构

老任物联网杂谈

物联网架构

《Linux就该这么学》笔记(一)

编程随想曲

Linux

办公人员的 python 妙用——抽签结果提取

Sicolas Flamel

Python 远程办公

【Howe 学 JAVA】Java 类集框架1——List集合

Howe

Java List 集合

带你100% 地了解 Redis 6.0 的客户端缓存

程序员历小冰

redis 缓存 redis6.0.0

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

深度学习利器:TensorFlow与深度卷积神经网络-InfoQ