热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

TensorFlow实战之实现卷积神经网络的实例讲解

下面小编就为大家分享一篇TensorFlow实战之实现卷积神经网络的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

本文根据最近学习TensorFlow书籍网络文章的情况,特将一些学习心得做了总结,详情如下.如有不当之处,请各位大拿多多指点,在此谢过。

一、相关性概念

1、卷积神经网络(ConvolutionNeural Network,CNN)

19世纪60年代科学家最早提出感受野(ReceptiveField)。当时通过对猫视觉皮层细胞研究,科学家发现每一个视觉神经元只会处理一小块区域的视觉图像,即感受野。20世纪80年代,日本科学家提出神经认知机(Neocognitron)的概念,被视为卷积神经网络最初的实现原型。神经认知机中包含两类神经元:S-cells和C-cells。S-cells用来抽取特征,对应我们现在主流卷积神经网络中的卷积核滤波操作;C-cells用来抗形变,对应现在的激活函数、最大池化(Max-Pooling)等操作。

一般情况下,卷积神经网络由多个卷积层构成,每个卷积层通常会进行如下操作:

(1) 图像通过多个不同的卷积核的滤波,并加偏置(bias),提取出局部特征,每一个卷积核会映射出一个新的2D图像。

(2) 将前面卷积核的滤波处理结果,进行非线性的激活函数处理。目前最常见的是使用ReLU函数,之前Sigmoid函数应用较多。

(3)多激活函数处理的结果再进行池化操作(即降采样,例如:将4*4的图片降为1*1的图片),一般会使用最大池化,保留最显著特征,并提升模型畸变容忍能力。

这几个步骤就构成了最常见的卷积层,也可以再加上一个LRN(LocalResponse Normalization,局部响应归一化层)层,现在非常流行的Trick还有BatchNormalization等。

2、池化层

3、卷积核尺寸

4、神经网络算法相关特性

4.1、优点

(1)可以高效提取特征。

当我们面对一个分类任务时,传统的机器学习算法,一般要首先明确feature和label,然后拿数据取“喂”训练模型并保存,最后测试模型的准确性。这就需要我们确定好特征,当特征数目很少就无法精确进行分类而引起欠拟合;当特征数目很多,又会在分类过程中太过于看重某个特征引起分类错误,产生过拟合。而神经网络则不需要做大量的特征工程,可以直接把数据“灌”进去而让其自身训练,自我“修正”,即可达到预期效果。   (2)数据格式更加简易

利用传统的机器学习解决分类问题时,数据不能直接“灌”进去的,需要对数据进行一些处理,譬如量纲的归一化,格式的转化等等,然而在神经网络里却不需要额外对数据做过多的处理。

(3) 参数数目的少量性

同样在面对一个分类问题时,利用传统机器学习SVM来做的话,需要涉及核函数,惩罚因子,松弛变量等等参数,而这些不同的参数组合会对模型效果产生不一样的影响,想要迅速而又准确的得到最适合模型的参数,需要对相关理论知识有深入研究,但对于一个基本的三层神经网络来说(输入-隐含-输出),只需要初始化时给每一个神经元上随机的赋予一个权重w和偏置项b,在训练过程中,这两个参数就会不断的修正,调整到最优质,使模型的误差最小。所以从这个角度来看,我们的工作效率会更佳。 4.2、缺点

如果我们加深我网络层,每一个网络层都增加神经元数量,则参数的个数将是M*N(m为网络层数,N为每层神经元个数),这样一来参数很多,引起模型复杂化,就更加不好调参,进而会更加容易导致过拟合。另外,从神经网络的反向传播的过程来看,梯度在反向传播时,不断的迭代会导致梯度越来越小,引起梯度趋近于0(梯度消失),梯度消失就使得权值无法更新,这个神经元的存在就毫无意义,很难导致收敛。尤其是在图像领域,直接使用最基本的神经网络,是不合理的。

二、卷积神经网络基本原理

1、基本阐述

现在有一图像,其尺寸大小是1000像素*1000像素且设定为黑白图像,也就是只有一个颜色通道,则一张图片就要100万个像素点,输入数据维度也是100万维。如果连接的现在隐含层大小也是同样大小(100万个隐含节点),最后将产生100万*100万即一亿万个连接。仅仅一个全连接(FullConnected Layer),就有一万亿连接的权重需要去训练,目前看,显然是不划算不现实。

通过局部连接(LocalConnect)方法优化解决:由于每一个感受野只接受一小块区域的信号,且这一小块区域内的像素是互相关联的,每一个神经元不需要接收全部像素点的信息,只需要接收局部的像素点作为输入,而后将所有这些神经元收到的局部信息综合起来,就可以得到全局信息。假设局部感受野大小是10*10,即每个隐含节点只与10*10个像素点相连,现在只需要10*100万即1亿个连接。

现在隐含层每一个节点都与10*10的像素相连,即每一个隐含层节点都拥有100个参数。假设我们的局部连接方式是卷积操作,即默认每一个隐含节点的参数都完全一样,这样参数从1亿降为100。不管图像大小是多大,一律都是这个10*10=100个参数,即卷积核尺寸,显然卷积核对缩小参数数量贡献非常大、意义非凡。因此,此时,我们不需要再担心有多少隐含节点或者图片多大,参数量只跟卷积核的大小有关,即所谓的权值共享。

总结:卷积神经网络要素是局部连接(LocalConnection)、权值共享(WeightSharing)和池化层(Pooling)中的降采样(Down-Sampling)。其中,局部连接和权值共享降低了参数量,训练复杂度被大大下降、过拟合被减轻。同时,权值共享还赋予了卷积网络对平移的容忍性,而池化层降采样则进一步降低了输出参数量,并赋予模型对轻度形变的容忍性,提供了模型的泛化能力。

2、LeNet5

1994年,大名鼎鼎的LeNet5诞生,作为最早的深层卷积神经网络之一,推动了深度学习的发展。自1998年开始,在多次成功迭代之后,由Yann LeCun完成的开拓性成果被命名为LeNet5。LeCun认为,可训练参数的卷积层是一种利用少量参数在图像的多个位置上提取相似特征的有效方式,这和直接把每个像素作为多层神经网络的输入不一样。像素不应该被使用在输入层,因为图像具有很强的空间相关性,而使用图像中独立的像素直接作为输入则利用不到这些相关性。笔者认为,这些内容比较重要。

在当时,LeNet5的特性如下:

(1)每个卷积层包含三个部分:卷积、池化和非线性激活函数;

(2)使用卷积提取空间特征;

(3)降采样(Subsample)的平均池化层(AveragePooling);

(4)双曲正切(Tanh)或S型(Sigmoid)的激活函数;

(5)MLP作为最后的分类器;

(6)层与层之间的稀疏性连接减少计算复杂度。

三、TensorFlow 实现简单的卷积网络

1、简要说明

这里使用的数据集依然是MNIST,使用两个卷积层加一个全连接层构建一个简单但非常有代表性的卷积神经网络,预计准确率约为99.2%左右。

2、实现过程

#载入MNIST数据集,创建默认的Interactive Session。
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
sess = tf.InteractiveSession()
 
#定义初始化函数,以便重复使用创建权重、偏置、卷积层、池化层。
def weight_variable(shape):
 initial = tf.truncated_normal(shape, stddev=0.1)
 return tf.Variable(initial)
 
def bias_variable(shape):
 initial = tf.constant(0.1, shape=shape)
 return tf.Variable(initial)
 
def conv2d(x, W):
 return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
 
def max_pool_2x2(x):
 return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
      strides=[1, 2, 2, 1], padding='SAME') 
 
#在设计卷积神经网络结构之前,定义输入的placeholder,x是特征,y_是真实Label。
#由于卷积神经网络会使用到空间结构信息,所以,需要将1D的输入向量转为2D图片结构,即从1*784的形式转换为原始的28*28结构。
#因为只有一个颜色通道,所以最终尺寸为[-1,28,28,1],其中‘-1'代表样本数量不固定,'1'代表颜色通道数量。
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
x_image = tf.reshape(x, [-1,28,28,1])
#定义第一个卷积层。
#先使用前面函数进行初始化,包括weights和bias。其中[5,5,1,32]代表卷积核尺寸为5**5,1个颜色通道,32个不同的卷积核。
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
#定义第二个卷积层。
#基本与第一个卷积层一样,只是其中的卷积核数量变成64.
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
 
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
#为了减轻过拟合,使用一个Dropout层,其用法是通过一个placeholder传入keep_prob比率来控制。
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
 
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_cOnv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
#定义损失函数cross_entropy,这里选择Adam优化器。
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#继续定义评测准确率操作。
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
 
#开始训练过程。
tf.global_variables_initializer().run()
for i in range(20000):
 batch = mnist.train.next_batch(50)
 if i%100 == 0:
 train_accuracy = accuracy.eval(feed_dict={
  x:batch[0], y_: batch[1], keep_prob: 1.0})
 print("step %d, training accuracy %g"%(i, train_accuracy))
 train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
#全部训练完毕,在最终的测试集上进行全面测试,得到整体的分类准确率。
print("test accuracy %g"%accuracy.eval(feed_dict={
 x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

3、执行结果

Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
step 0, training accuracy 0.1
step 100, training accuracy 0.82
step 200, training accuracy 0.9
step 300, training accuracy 0.9
step 400, training accuracy 0.96
step 500, training accuracy 0.9
step 600, training accuracy 0.94
step 700, training accuracy 0.96
step 800, training accuracy 0.94
step 900, training accuracy 0.98
.  .  .  .  .
 
step 19600, training accuracy 1
step 19700, training accuracy 1
step 19800, training accuracy 1
step 19900, training accuracy 1
test accuracy 0.9929

4、模型分析

CNN模型的最终准确率约为99.2%,基本上可以满足对手写数字识别准确率的初步要求。相比于之前的MLP2%的错误率,CNN下降了60%左右。这里的性能提升主要在于更佳的网络设计,也就是卷积网络对图像特征的提取和抽象能力。依靠卷积核的权值共享,CNN的参数数量没有爆炸,降低计算量的同时也减去了过拟合,所以,整个模型的性能会有较大的提升。

四、TensorFlow实现进阶的卷积网络

1、基本介绍

这里使用CIFAR-10数据集,包含60,000张32*32的彩色图像,其中训练集50,000张,测试10,000张,一共标注为10类,分别为airplane、automobile、bird、cat、deer、dog、frog、horse、shhip、truck,,每一类图片6000张,其中没有任何重叠情况发生,例如:automobile 只包括小型汽车,truck只包括卡车,不会出现一张图片展现两类物体的现象。

2、实现过程

#载入数据
import cifar10,cifar10_input
import tensorflow as tf
import numpy as np
import time
 
max_steps = 3000 #训练轮数
batch_size = 128
data_dir = '/tmp/cifar10_data/cifar-10-batches-bin'#下载数据默认路径。
 
 
def variable_with_weight_loss(shape, stddev, wl):
 var = tf.Variable(tf.truncated_normal(shape, stddev=stddev))
 if wl is not None:
  weight_loss = tf.multiply(tf.nn.l2_loss(var), wl, name='weight_loss')
  tf.add_to_collection('losses', weight_loss)
 return var
 
#计算CNN的损失。
def loss(logits, labels):
 
 labels = tf.cast(labels, tf.int64)
 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
  logits=logits, labels=labels, name='cross_entropy_per_example')
 cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
 tf.add_to_collection('losses', cross_entropy_mean)
 
 return tf.add_n(tf.get_collection('losses'), name='total_loss') 
 
cifar10.maybe_download_and_extract()
 
images_train, labels_train = cifar10_input.distorted_inputs(data_dir=data_dir,
               batch_size=batch_size)
 
images_test, labels_test = cifar10_input.inputs(eval_data=True,
            data_dir=data_dir,
            batch_size=batch_size)            
 
image_holder = tf.placeholder(tf.float32, [batch_size, 24, 24, 3])
label_holder = tf.placeholder(tf.int32, [batch_size])
 
#创建第一个卷积层。
weight1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=5e-2, wl=0.0)
kernel1 = tf.nn.conv2d(image_holder, weight1, [1, 1, 1, 1], padding='SAME')
bias1 = tf.Variable(tf.constant(0.0, shape=[64]))
conv1 = tf.nn.relu(tf.nn.bias_add(kernel1, bias1))
pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
      padding='SAME')
norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75)
 
#创建第二个卷积层。
weight2 = variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=5e-2, wl=0.0)
kernel2 = tf.nn.conv2d(norm1, weight2, [1, 1, 1, 1], padding='SAME')
bias2 = tf.Variable(tf.constant(0.1, shape=[64]))
conv2 = tf.nn.relu(tf.nn.bias_add(kernel2, bias2))
norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75)
pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
      padding='SAME')
#使用一个全连接层,先把第二个卷积层的输出结果flatten,将每个样本都变成一维向量。
reshape = tf.reshape(pool2, [batch_size, -1])
dim = reshape.get_shape()[1].value
weight3 = variable_with_weight_loss(shape=[dim, 384], stddev=0.04, wl=0.004)
bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)
#下面这个使用的全连接层,其隐含节点数下降了一半。
weight4 = variable_with_weight_loss(shape=[384, 192], stddev=0.04, wl=0.004)
bias4 = tf.Variable(tf.constant(0.1, shape=[192]))          
local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)
 
weight5 = variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, wl=0.0)
bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
logits = tf.add(tf.matmul(local4, weight5), bias5)
loss = loss(logits, label_holder)
train_op = tf.train.AdamOptimizer(1e-3).minimize(loss) #0.72
top_k_op = tf.nn.in_top_k(logits, label_holder, 1)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
tf.train.start_queue_runners()
#正式开始训练。
for step in range(max_steps):
 start_time = time.time()
 image_batch,label_batch = sess.run([images_train,labels_train])
 _, loss_value = sess.run([train_op, loss],feed_dict={image_holder: image_batch,
               label_holder:label_batch})
 duration = time.time() - start_time
 if step % 10 == 0:
  examples_per_sec = batch_size / duration
  sec_per_batch = float(duration)
  
  format_str = ('step %d, loss = %.2f (%.1f examples/sec; %.3f sec/batch)')
  print(format_str % (step, loss_value, examples_per_sec, sec_per_batch))
  
#评测模型在测试集上的准确率。
num_examples = 10000
import math
num_iter = int(math.ceil(num_examples / batch_size))
true_count = 0 
total_sample_count = num_iter * batch_size
step = 0
while step 

3、执行结果

由于笔者试了几次CIFAR-10模块,最后一步失败,所以没能正确显示,后续找机会再试试,但以笔者的初步判断,在CIFAR-10安装成功的情况下,执行结果应该是没问题的。感兴趣的朋友可以再看看,这里就不贴出相关结果了,望各位网友理解。

4、模型分析

在CIFAR-10数据集上,通过一个短时间小迭代次数的训练,可以达到约73%的准确率,后续若增加max_steps,期望准确率会逐渐增加。若max_steps比较大的化,建议使用学习速率衰减(decay)的SGD来进行训练,其训练过程中准确率的峰值会较高,约86%,因为这其中的L2正则和LRN层的使用均提升了模型准确率和模型的泛化性能。

五、小结

卷积网络最后的几个全连接层的作用是输出分类结果,前面的卷积层主要做特征提取工作,直到最后的全连接层才开始对特征进行组合分配,并进行分类。

卷积层一般需要和一个池化层连接,二者组合是做图像识别时的一个标准组件。卷积层的训练相对于全连接层更复杂,训练全连接层基本是进行一个些矩阵乘法运算,而目前卷积层的训练基本上依赖于cuDNN实现,其中的算法也相对复杂,甚至会涉及到傅里叶变换。

参考资料 主要参考资料《TensorFlow实战》(黄文坚 唐源 著)(电子工业出版社)。

以上这篇TensorFlow 实战之实现卷积神经网络的实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


推荐阅读
  • TensorFlow入门上
    前置准备在阅读本文之前,请确定你已经了解了神经网络的基本结构以及前向传播、后向传播的基本原理,如果尚未了解,可以查看下文。神经网络初探​chrer.com也可以直接在我博客阅读Te ... [详细]
  • 「爆干7天7夜」入门AI人工智能学习路线一条龙,真的不能再透彻了
    前言应广大粉丝要求,今天迪迦来和大家讲解一下如何去入门人工智能,也算是迪迦对自己学习人工智能这么多年的一个总结吧,本条学习路线并不会那么 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 【论文】ICLR 2020 九篇满分论文!!!
    点击上方,选择星标或置顶,每天给你送干货!阅读大概需要11分钟跟随小博主,每天进步一丢丢来自:深度学习技术前沿 ... [详细]
  • 干货 | 携程AI推理性能的自动化优化实践
    作者简介携程度假AI研发团队致力于为携程旅游事业部提供丰富的AI技术产品,其中性能优化组为AI模型提供全方位的优化方案,提升推理性能降低成本࿰ ... [详细]
  • 2018年GitHub上最流行50大Python开源项目(上),Go语言社区,Golang程序员人脉社 ... [详细]
  • 开源真香 离线识别率高 Python 人脸识别系统
    本文主要介绍关于python,人工智能,计算机视觉的知识点,对【开源真香离线识别率高Python人脸识别系统】和【】有兴趣的朋友可以看下由【000X000】投稿的技术文章,希望该技术和经验能帮到 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文介绍了在Python张量流中使用make_merged_spec()方法合并设备规格对象的方法和语法,以及参数和返回值的说明,并提供了一个示例代码。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • 建立分类感知器二元模型对样本数据进行分类
    本文介绍了建立分类感知器二元模型对样本数据进行分类的方法。通过建立线性模型,使用最小二乘、Logistic回归等方法进行建模,考虑到可能性的大小等因素。通过极大似然估计求得分类器的参数,使用牛顿-拉菲森迭代方法求解方程组。同时介绍了梯度上升算法和牛顿迭代的收敛速度比较。最后给出了公式法和logistic regression的实现示例。 ... [详细]
  • 2017亚马逊人工智能奖公布:他们的AI有什么不同?
    事实上,在我们周围,“人工智能”让一切都变得更“智能”极具讽刺意味。随着人类与机器智能之间的界限变得模糊,我们的世界正在变成一个机器 ... [详细]
  • Two Sigma人均22万英镑~
    近期原创文章: ... [详细]
  • 分享篇:第十届“泰迪杯”数据挖掘挑战赛农田害虫图像识别(特等奖)一
    1.1赛题背景昆虫的种类浩如烟海,农田常见的昆虫是人工生态系统的重要组成部分。分辨益虫和害虫,保留益虫,消灭害虫,对于减轻害 ... [详细]
  • 基于深度学习的遥感应用
    文章目录深度学习的发展过程深度学习在遥感中的应用基于深度学习的遥感样例库建设基于深度学习的遥感影像目标及场景检索基于深度学习的建筑物提取基于深度学习的密集建筑物自动检测基于深度学习 ... [详细]
author-avatar
ZZ张朝_288
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有