TensorFlow2卷积神经网络

简介

卷积神经网络广泛使用于计算机视觉领域,主要用于提取图片的特征图(feature map)。不同于数学中的卷积,这里的卷积指的是对矩阵的一种运算方式(本质上就是离散化的数学卷积),使用卷积核对图片矩阵进行操作,可以减少图片的位置信息,增加图片的通道信息,从而得到高层语义信息。

卷积操作

在提出卷积的运算方式之前必须清楚,为什么不使用全连接神经网络对图片处理,为什么使用卷积操作,为什么可以使用卷积。

  • 之所以不使用全连接神经网络是因为,全连接神经网络处理图片这类特征量很大的数据,即使是浅层神经网络,其参数量、数据量、梯度量都是极为庞大的,如此庞大的数据量是很难存储运算的(在过去很长一段时间内是不可能的)。而且,全连接神经网络在图片数据上的表现并不好。
  • 依据动物的局部感受野机制(每次观察只注意小部分区域),卷积神经网络诞生了。如果说全连接神经网络每次提取特征面向的是全局(每次全面观察,这是费力且没有必要的),卷积神经网络则是使用卷积核每次提取局部的特征(每次观察图片的一小部分,且观察方式不变),使用不同的卷积核就可以观察到各种特征信息。通过卷积神经网络代替全连接神经网络,网络的参数量大大减少了(卷积神经网络的参数只存在于卷积核中)。
  • 使用卷积核扫描区域并将卷积核对应位置的参数和扫描区域数值相乘求和得到特征值,扫描多个区域得到多个特征值组合的矩阵就是特征图(feature map)。需要注意的是,卷积操作是针对矩阵区域的,对多个通道的同区域会进行相应合并得到一个特征图(合并一般是分别对每个通道提取特征,然后特征值求和得到该区域的特征)。之所以使用卷积操作提取特征,这是由来已久的,在计算机视觉的历史上使用特定的滤波器处理图片是个常用手段,卷积很早就被提出了,不过那时候对于不同的任务人为设计不同的滤波器(卷积核),这里只是在深度学习的基础上沿用罢了(卷积核变为自动学习而不是人为设计)。

卷积神经网络

通过上述卷积操作,可以得到尺寸变小的高通道特征图,如使用16个3*3卷积核提取5*5图片特征(图片如第二节文末)会得到维度为[3, 3, 16]的特征图,很显然,图片的尺寸变小了。当然,区域维度的信息减少,位置维度的信息增加,这就是卷积神经网络提取特征的目的(这个过程表现为feature map长宽减小,channel增加,所以卷积神经网络的卷积核数目逐层增加或不变)。但是无法控制的变化是不必要的,这个尺寸变换的过程在深层网络中不容易明确,需要步步计算才能得到,为了解决这个麻烦,提出了Padding方法(填充方法)和Stride方法(步长方法)。

  • Padding是指在原图周围补上一圈全0的数值,使得变换后的矩阵尺寸不变。
  • 同时,为了调节特征图尺寸,控制stride也是不错的选择(一般的深度学习框架步长默认为1)。

卷积神经网络的体系逐渐发展,产生了固定的一些结构,如卷积层、池化层、上采样层等。这些固定的矩阵操作层在TensorFlow2中的keras模块中得到了封装。

  • 2D卷积的接口如下,指明卷积核数目,卷积核大小,步长,以及填充方式(same表示自动等尺寸,valid表示不进行padding)等即可。
  • 2D池化(下采样)接口如下,指明步长即可。根据给定的步长将该区域的所有值取最大或者平均。
  • 上采样是下采样的逆操作,有不同的方法,指明采用大小即可。

还有一个很关键的问题在卷积神经网络中,就是如何求出输出loss关于卷积核参数的梯度。这个计算并不复杂,根据链式法则可以知道最终Loss关于某层feature map的梯度为Loss关于O的梯度乘以O关于参数w的梯度,这个过程不复杂,TensorFlow是自动完成的。

经典网络

在80年代后期,SVM几乎统治了机器学习世界,深度学习的发展受阻,直到2012年AlexNet的突破性表现,深度卷积神经网络在计算机视觉的发展才如火如荼起来,先后出现了VGGNet、GoogLeNet、ResNet、DenseNet等,总体的发展趋势围绕Google和微软产生了两种,越来越宽或者越来越深。由于这些网络的提出解析都需要大量篇幅介绍,这里只提一下突破性的成就,设计自己的应用网络时可以借鉴这些突破点。

  • AlexNet

    • 由Hinton主导(深度学习三驾马车之一)相比较于之前的LeNet结构类似,不过提出了Max pooling、Relu激活函数、Dropout正则化,并且第一次使用GPU加速训练。
    • 不过,AlexNet由于当时显卡限制,手工进行网络的双卡切分,如今的显卡以及深度框架会帮助完成这些。
  • VGGNet
    • 由牛津大学VGG组提出,主要贡献是采用多层小卷积核代替大卷积核计算量减少且效果更好。计算量较大。
  • GoogLeNet
    • 由Google设计,主要贡献为使用1*1调整通道数目,对同一层使用多种卷积核以获得不同感受野得到不同信息,使得网络更宽。
  • ResNet
    • 华人学者何凯明于微软亚洲研究院提出残差模块,解决了过深网络难以训练(主要是梯度弥散)的情况。这是深层卷积神经网络发展的基础,也是计算机视觉近几年最突破的成就之一。
  • DenseNet
    • 每一层都与前面所有层连接,连接极为密集,信息量很大的网络设计,基于ResNet设计。

Cifar100与VGG13实战

VGGNet在卷积神经网络的历史上地位举足轻重,其做出了很多新的尝试并产生很多贡献。具体的介绍可以查看我关于VGGNet的博文。这里通过构建VGG13网络对Cifar100进行分类实战。具体Pipeline流程为加载数据集、构建网络、训练网络、测试网络。VGGNet是很简单粗暴的容易理解的卷积神经网络之一,它的设计思路也是按照卷积神经网络的基本设计思想。

VGGNet的具体网络配置如下表。

具体的Python代码下面给出。

"""
Author: Zhou Chen
Date: 2019/11/2
Desc: VGG13 for Cifar100
"""
import os
import tensorflow as tf
from tensorflow.keras import layers, optimizers, datasets, Sequential
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 忽略低级别警告conv_layers = [# block1layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),# block2layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),# block3layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),# block4layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),# block5layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same')]def preprocess(x, y):# [0~1]x = tf.cast(x, dtype=tf.float32) / 255.y = tf.cast(y, dtype=tf.int32)return x, y(x, y), (x_test, y_test) = datasets.cifar100.load_data()
y, y_test = tf.squeeze(y, axis=1), tf.squeeze(y_test, axis=1)
print(x.shape, y.shape, x_test.shape, y_test.shape)train_db = tf.data.Dataset.from_tensor_slices((x, y))
train_db = train_db.shuffle(1000).map(preprocess).batch(128)test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_db = test_db.map(preprocess).batch(64)sample = next(iter(train_db))
print('sample:', sample[0].shape, sample[1].shape,tf.reduce_min(sample[0]), tf.reduce_max(sample[0]))def main():# [b, 32, 32, 3] => [b, 1, 1, 512]conv_net = Sequential(conv_layers)fc_net = Sequential([layers.Dense(256, activation=tf.nn.relu),layers.Dense(128, activation=tf.nn.relu),layers.Dense(100, activation=None),])conv_net.build(input_shape=[None, 32, 32, 3])fc_net.build(input_shape=[None, 512])optimizer = optimizers.Adam(lr=1e-4)variables = conv_net.trainable_variables + fc_net.trainable_variables  # 拼接变量列表# trainingfor epoch in range(50):for step, (x, y) in enumerate(train_db):with tf.GradientTape() as tape:# [b, 32, 32, 3] => [b, 1, 1, 512]out = conv_net(x)out = tf.reshape(out, [-1, 512])# [b, 512] => [b, 100]logits = fc_net(out)y_onehot = tf.one_hot(y, depth=100)# compute lossloss = tf.losses.categorical_crossentropy(y_onehot, logits, from_logits=True)loss = tf.reduce_mean(loss)grads = tape.gradient(loss, variables)optimizer.apply_gradients(zip(grads, variables))if step % 100 == 0:print(epoch, step, 'loss:', float(loss))total_num = 0total_correct = 0for x, y in test_db:out = conv_net(x)out = tf.reshape(out, [-1, 512])logits = fc_net(out)prob = tf.nn.softmax(logits, axis=1)pred = tf.argmax(prob, axis=1)pred = tf.cast(pred, dtype=tf.int32)correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)correct = tf.reduce_sum(correct)total_num += x.shape[0]total_correct += int(correct)acc = total_correct / total_numprint(epoch, 'acc:', acc)if __name__ == '__main__':main()

Cifar100与ResNet18实战

尽管VGG曾今取得过瞩目的成就,然而过于庞大的计算量在今天如此深层的网络下已经有些不合适了,因此ResNet的提出解决了这个问题。这里通过ResNet18对Cifar100进行训练测试,对比其与VGGNet的效果。下面给出模型构建代码,训练代码类似之前,可以在文末的Github地址找到。

"""
Author: Zhou Chen
Date: 2019/11/2
Desc: ResNet实现
"""
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequentialclass BasicBlock(layers.Layer):def __init__(self, filter_num, stride=1):super(BasicBlock, self).__init__()self.conv1 = layers.Conv2D(filter_num, (3, 3), strides=stride, padding='same')self.bn1 = layers.BatchNormalization()self.relu = layers.Activation('relu')self.conv2 = layers.Conv2D(filter_num, (3, 3), strides=1, padding='same')self.bn2 = layers.BatchNormalization()if stride != 1:self.downsample = Sequential()self.downsample.add(layers.Conv2D(filter_num, (1, 1), strides=stride))else:self.downsample = lambda x: xdef call(self, inputs, training=None):# [b, h, w, c]out = self.conv1(inputs)out = self.bn1(out, training=training)out = self.relu(out)out = self.conv2(out)out = self.bn2(out, training=training)identity = self.downsample(inputs)output = layers.add([out, identity])output = tf.nn.relu(output)return outputclass ResNet(keras.Model):def __init__(self, layer_dims, num_classes=100):  # [2, 2, 2, 2]super(ResNet, self).__init__()self.stem = Sequential([layers.Conv2D(64, (3, 3), strides=(1, 1)),layers.BatchNormalization(),layers.Activation('relu'),layers.MaxPool2D(pool_size=(2, 2), strides=(1, 1), padding='same')])self.layer1 = self.build_resblock(64, layer_dims[0])self.layer2 = self.build_resblock(128, layer_dims[1], stride=2)self.layer3 = self.build_resblock(256, layer_dims[2], stride=2)self.layer4 = self.build_resblock(512, layer_dims[3], stride=2)# output: [b, 512, h, w],self.avgpool = layers.GlobalAveragePooling2D()self.fc = layers.Dense(num_classes)def call(self, inputs, training=None):x = self.stem(inputs, training=training)x = self.layer1(x, training=training)x = self.layer2(x, training=training)x = self.layer3(x, training=training)x = self.layer4(x, training=training)# [b, c]x = self.avgpool(x)# [b, 100]x = self.fc(x)return xdef build_resblock(self, filter_num, blocks, stride=1):res_blocks = Sequential()# may down sampleres_blocks.add(BasicBlock(filter_num, stride))for _ in range(1, blocks):res_blocks.add(BasicBlock(filter_num, stride=1))return res_blocksdef resnet18():return ResNet([2, 2, 2, 2])

补充说明

本文介绍了卷积神经网络相关内容以及在TensorFlow2中如何实现CNN模型。具体的代码同步至我的Github仓库欢迎star;博客同步至我的个人博客网站,欢迎查看其他文章。如有疏漏,欢迎指正。

TensorFlow2-卷积神经网络相关推荐

  1. Tensorflow2.x.x全卷积神经网络(CNN)

    Tensorflow2.x.x全卷积神经网络(CNN) 本章节主要使用Tensorflow2.x.x来搭建CNN神经网络. 全卷积神经网络原理 引用小伙伴的原理,作者个人理解为卷积层提取特征而已,每一 ...

  2. 卷积神经网络(CNN)详解及TensorFlow2代码实现

    卷积神经网络名字听着挺吓人,本文用通俗易懂的方式解释.人人都能看懂. 文章目录 卷积是什么 一.卷积神经网络介绍 卷积层--提取局部图片特征 扩充--padding,保持卷积后图片的长和宽保持不变 池 ...

  3. TensorFlow2.0 学习笔记(三):卷积神经网络(CNN)

    欢迎关注WX公众号:[程序员管小亮] 专栏--TensorFlow学习笔记 文章目录 欢迎关注WX公众号:[程序员管小亮] 专栏--TensorFlow学习笔记 一.神经网络的基本单位:神经元 二.卷 ...

  4. 【深度学习】利用tensorflow2.0卷积神经网络进行卫星图片分类实例操作详解

    本文的应用场景是对于卫星图片数据的分类,图片总共1400张,分为airplane和lake两类,也就是一个二分类的问题,所有的图片已经分别放置在2_class文件夹下的两个子文件夹中.下面将从这个实例 ...

  5. 基于Python tensorflow2.3实现的水果识别系统源码+模型+数据集,卷积神经网络的入门案例

    水果识别-基于tensorflow2.3实现 水果识别是卷积神经网络的入门案例,这里我将模型的训练.测试.保存以及使用整合在了一起,至于原理部分,大家可以参考知乎或者B站上的回答,在这里我就不赘述了 ...

  6. 深度学习-Tensorflow2.2-卷积神经网络{3}-卷积神经网络CNN基础-11

    CNN 简介 实现对图像的高准确率识别离不开一种叫做卷积神经网络的深度学习 技术. 卷积神经网络主要应用于计算机视觉相关任务,但它能处理的任务并 不局限于图像,其实语音识别也是可以使用卷积神经网络. ...

  7. 图卷积神经网络(GCN)理解与tensorflow2.0代码实现

    图(Graph),一般用 G=(V,E)G=(V,E)G=(V,E) 表示,这里的VVV是图中节点的集合,EEE 为边的集合,节点的个数用NNN表示.在一个图中,有三个比较重要的矩阵: 特征矩阵XXX ...

  8. TensorFlow2.0(九)--Keras实现基础卷积神经网络

    Keras实现基础卷积神经网络 1. 卷积神经网络基础 2. Keras实现卷积神经网络 2.1 导入相应的库 2.2 数据集的加载与处理 2.3 构建模型 2.4 模型的编译与训练 2.5 学习曲线 ...

  9. 曹健老师 TensorFlow2.1 —— 第五章 卷积神经网络

    第一章 第二章 第三章 第四章 本章目的:用图卷积神经网络实现离散数据的分类 ( 以图像分类为例 ) . 5.1 卷积计算过程 在实际项目中,输入神经网络的是具有更高分辨率的彩色图片,使得送入全连接网 ...

  10. 【神经网络】(6) 卷积神经网络(VGG16),案例:鸟类图片4分类

    各位同学好,今天和大家分享一下TensorFlow2.0中的VGG16卷积神经网络模型,案例:现在有四种鸟类的图片各200张,构建卷积神经网络,预测图片属于哪个分类. 1. 数据加载 将鸟类图片按类分 ...

最新文章

  1. apache和nginx的性能分析
  2. 存储过程编写经验和优化措施
  3. Silicon Labs收购业界RTOS厂商
  4. Oracle获取最近执行的SQL语句
  5. 计算机二级通app打不开,计算机二级通app
  6. hbase命令行演示
  7. java数据结构-Vector
  8. Xcode9学习笔记63 - 使用SystemSoundId播放简短声音(太长的无法播放)
  9. Hibernate中inverse属性与cascade属性
  10. html5input表单标签新属性
  11. rhel系统启动过程_Linux系统启动过程分析
  12. python创建时间序列_python时间序列按频率生成日期
  13. Daily scrum 10.12
  14. php hbase thrift,php通过thrift操作hbase
  15. 深度竞品分析:阿里旗下闲鱼与58旗下转转
  16. android 计步器acc,基于加速度的门限检测计步算法设计
  17. Faster R-CNN算法详细流程
  18. 【ValueError: data type <class ‘numpy.object_‘> not inexact】
  19. python----语句
  20. 【Dash搭建可视化网站】项目13:销售数据可视化大屏制作步骤详解

热门文章

  1. 多案分库分表带来的问题-跨库关联查询
  2. J.U.C 提供的阻塞队列
  3. LockSupport
  4. base64补等号规则说明
  5. 分布式文件系统研究-什么是分布式文件系统
  6. Bootstrap全局css样式_表单
  7. animate方法 jQuery中元素的创建 创建十个p标签 创建列表 动态创建列表
  8. 侍魂胧月传说显示服务器未开启,侍魂胧月传说为什么进不去 侍魂胧月传说进不去的原因...
  9. linux zip 开源工程,7-Zip 18.06 发布,开源数据压缩程序
  10. 对象的多态(核心、困难、重点)