实战之实现卷积神经网络的实例讲解,学习笔记TF027

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 < num_iter:
 image_batch,label_batch = sess.run([images_test,labels_test])
 predictions = sess.run([top_k_op],feed_dict={image_holder: image_batch,
             label_holder:label_batch})
 true_count += np.sum(predictions)
 step += 1
#最后,将准确率的评测结果计算并输出。
precision = true_count / total_sample_count
print('precision @ 1 = %.3f' % precision)

3、执行结果

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

4、模型分析

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

五、小结

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

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

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

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

实战之实现卷积神经网络的实例讲解,tensorflow实例讲解
本文根据最近学习TensorFlow书籍网络文章的情况,特将一些学习心得做了总结…

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

卷积神经网络(Convolutional Neural
Network,CNN),可以解决图像识别、时间序列信息问题。深度学习之前,借助SIFT、HoG等算法提取特征,集合SVM等机器学习算法识别图像。

一、相关性概念

SIFT,缩放、平移、旋转、视角转变、亮度调整畸变的一定程度内,具有不变性。有局限性,ImageNet
ILSVRC比赛最好结果错误率在26%以上,常年难以突破。

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

卷积神经网络提取特征效果更好,分类训练时自动提取最有效特征。卷积神经网络CNN,降低图像数据预处理要求,避免复杂特征工程。CNN使用图像原始像素输入,对缩放、平移、旋转畸变具有不变性,强泛化性。CNN卷积权值共享结构,大幅减少神经网络参数量,防止过拟合,降低神经网络模型复杂度。延时神经网络TDNN,时间权值共享,降低学习时间序列信号复杂度。

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

感受野(Receptive
Field),每个视觉神经元只会处理一小块区域视觉图像。神经认知机(Neocognitron),两类神经元,抽取特征S-cells对应主流卷积神经网络卷积核滤波操作,抗形变C-cells对应激活函数、最大池化(Max-Pooling)操作。LeCun
LeNet
CNN首个成功多层训练网络结构。卷积神经网络利用空间结构关系减少学习参数量,提高反向传播算法训练效率。

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

第一个卷积层,接受图像像素级输入,每个卷积操作只处理一小块图像。卷积变化后传到后面网络。每一层卷积(滤波器),提取数据最有效特征。提取图像最基础特征,组合抽像更高阶特征。

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

一般卷积神经网络多个卷积层构成。每个卷积层,图像多个不同卷积核滤波,加偏置(bias),提取局部特征,每个卷积核映射一个新2D图像,卷积核滤波输出结果,非线性激活函数处理(ReLU),激活函数结果池化操作(降采样),最大池化,保留最显著特征,提升模型畸变容忍能力。可以加LRN(Local
Response Normalization 局部响应归一化层),Batch Normalizations。

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

卷积核权值共享,卷积层多个不同卷积核,卷积核对应滤波后映射新图像,同一新图像每个像素来自完全相同卷积核。降低模型复杂度,减轻过拟合,降低计算量。

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

图像空间有组织结构,每个像素点与空间周围像素点有紧密联系,与太遥远像素点少联系,即感受野。每个感受野只接受一小块区域信号。小块区域内像素互相关联,每个神经元不需要接收全部像素点信息,只接收局部像素点输入,再将所有神经元收到局部信息综合起来得到全局信息。将全连接模型改为局部连接,从隐含层每个隐含节点和全部像素相连,改为每个隐含节点连接局部像素节点。

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

局部连接方式卷积操作,默认每个隐含节点参数完全一样。不再担心隐含节点数量和图片大小,参数量只跟卷积核大小有关。权值共享。一个卷积核只能提取一种卷积核滤波结果,只能提取一种图片特征。每个卷积核滤波图像是一类特征映射,一个Feature
Map。一般,第一个卷积层100个卷积核已经充足。

2、池化层

卷积,不管图片尺寸,训练权值只与卷积核大小、数量有关,可以用非常少参数量处理任意大小图片。每个卷积层提取特征,在后面层抽象组合更高阶特征,多层抽象卷积网络表达能力强,效率高。隐含节点数量没有下降,隐含节点数量只跟卷积步长有关。隐含节点数量=输入像素数量/(步长X步长)。

3、卷积核尺寸

卷积神经网络,局部连接(Local Connection)、权值共享(Weight
Sharing)、池化层(Pooling)降采样(Down-Sampling)。局部连接、权值共享降低参数量,训练复杂度下降,减轻过拟合。权值共享,卷积网络平移容忍性。池化层降低输出参数量,模型轻度形变容忍性,提高泛化能力。训练中自动完成特征提取抽象,同时模式分类,降低图像识别难度。

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

LeNet5 始于1994年,深层卷积神经网络。Yann
LeCun。可训练参数卷积层,用少量参数在图像多个位置提取相似特征。如果图像独立像素直接作输入,利用不到图像很强的空间相关性。每个卷积层包含卷积、池化、非线性激活函数。卷积提取空间特征。降采样(Subsample)平均池化层(Average
Pooling)。双曲正切(Tanh)或S型(Sigmoid)激活函数。MLP最后分类器。层间稀疏连接减少计算复杂度。

4.1、优点

State-of-the-art。LeNet5奠定现代卷积神经网络基石。LeNet5,输入图像,三个卷积层,一个全连接层,一个高斯连接层。第一个卷积层C1有6个卷积核,卷积核尺寸为5×5,共(5×5+1)x6=156个参数。1个bias。2×2平均池化层S2降采样。Sigmoid激活函数非线性处理。第二个卷积层C3,卷积核尺寸5×5,16个卷积核,16个Feature
Map。第二个池化层S4,2×2降采样。第三个卷积层C5,120个卷积核,卷积大小5×5,输入5×5,构成全连接,可以算全连接层。F6全连接层,84个隐含节点,激活函数Sigmoid。最后一层,欧式径向基函数(Euclidean
Radial Basis Function)单元组成,输出最后分类结果。

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

参考资料:
《TensorFlow实战》

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

欢迎付费咨询(150元每小时),我的微信:qingxingfengzi

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

(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 < num_iter:
 image_batch,label_batch = sess.run([images_test,labels_test])
 predictions = sess.run([top_k_op],feed_dict={image_holder: image_batch,
             label_holder:label_batch})
 true_count += np.sum(predictions)
 step += 1
#最后,将准确率的评测结果计算并输出。
precision = true_count / total_sample_count
print('precision @ 1 = %.3f' % precision)

3、执行结果

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

4、模型分析

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

五、小结

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

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

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

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

您可能感兴趣的文章:

  • 使用tensorflow实现AlexNet
  • Tensorflow卷积神经网络实例进阶
  • Tensorflow卷积神经网络实例
  • TensorFlow实现卷积神经网络
  • tensorflow实现简单的卷积神经网络
  • TensorFlow实现简单卷积神经网络
  • tensorflow学习笔记之mnist的卷积神经网络实例
  • TensorFlow深度学习之卷积神经网络CNN
  • TensorFlow实现卷积神经网络CNN
  • Tensorflow实现卷积神经网络用于人脸关键点识别
  • Tensorflow实现AlexNet卷积神经网络及运算时间评测