深度学习与图像处理理论基础与实践

1 深度学习概述

tips:后面实践部分,代码量偏大,若看着不舒服,可以看看文中写的思路,然后在下面这个链接直接下代码细看

链接:https://pan.baidu.com/s/1uixRdG-K5HGYD0gOxZ-86Q      提取码:a55o    最后也有二维码供保存 

1.1 深度学习发展的介绍

在机器学习中,我们主要处理的分类问题,回归问题的模型都属于浅层结构的简单学习,通常只包含1到3层的非线性特征转换层,例如一些典型的浅层结构:逻辑回归(LR)、支持向量机(SVM)和多层感知器(MLP)等。这些浅层模型对复杂函数的表示能力有限,无法提取到更高维度的特征。比如在图像、语音的处理上,机器学习就很难获得很好的表现。而深度学习可通过学习一种深层非线性网络结构,表征输入数据,实现复杂函数逼近,并展现了强大的从少数样本集中学习数据集本质特征的能力。

2006年,加拿大多伦多大学教授、机器学习领域泰斗——Geoffrey Hinton和他的学生Ruslan Salakhutdinov在顶尖学术刊物《科学》上发表了一篇文章,开启了深度学习在学术界和工业界的浪潮。自2006年以来,深度学习在学术界持续升温。斯坦福大学、纽约大学、加拿大蒙特利尔大学等成为研究深度学习的重镇。

1.2 深度学习的定义

通过前面对深度学习发展的介绍,这里我们给出Google在2013年10月对深度学习的定义,帮助读者更好的理解深度学习。

“深度学习是机器学习的一系列算法,它试图在多个层次中进行学习,每层对应于不同级别的抽象。它一般使用人工神经网络,学习到的统计模型中的不同层对应于不同级别的概念,高层概念取决于低层概念,而且同一低层的概念有助于确定多个高层概念。”

1.3 深度学习存在的问题

深度学习虽然具有强大的特征表达能力,但是依然存在以下问题。

①理论问题

统计学习方面的问题,我们不知道我们需要多少训练样本才能学习到足够好的深度模型。

计算方面的问题,我们需要多少计算资源才能通过训练得到更好的模型?理想的计算优化方法是什么?由于深度模型都是非凸函数,在这方面的理论研究极其困难。

②建模问题

在推进深度学习的学习理论和计算理论的同时,我们是否可以提出新的分层模型,使其不但具有传统深度模型所具有的强大表示能力,还具有其他的好处,比如更容易做理论分析。另外,针对具体应用问题,我们如何设计一个最适合的深度模型来解决问题?一个更有意思的问题是,是否存在可能建立一个通用的深度模型或深度模型的建模语言,作为统一的框架来处理语音、图像和语言?

③工程问题

如何获取大量的数据,更好的处理数据是各家企业需要解决的问题。如何在工程上利用大规模的并行计算平台来实现海量数据训练,是各家公司从事深度学习技术研发首先要解决的问题。

1.4 深度学习的前景

目前我们使用的Android手机中google的语音识别,百度识图,google的图片搜索,都已经使用到了深度学习技术。Facebook在去年名为DeepFace的项目中对人脸识别的准备率第一次接近人类肉眼(97.25% vs 97.5%)。大数据时代,结合深度学习的发展在未来对我们生活的影响无法估量。保守而言,很多目前人类从事的活动都将因为深度学习和相关技术的发展被机器取代,如自动汽车驾驶,无人飞机,以及更加职能的机器人等。深度学习的发展让我们第一次看到并接近人工智能的终极目标。

 

2 深度学习的分类

深度学习是基于机器学习延伸出来的一个的领域。因此深度学习的分类与机器学习的分类有着类似的分类方式。以下内容便是对深度学习的分类介绍。

2.1 有监督学习的深度学习网络结构

有监督学习是机器学习和深度学习中最常见的形式。举例来说,我们要建立一个系统,它能够对一个包含了一座房子、一辆汽车、一个人或一个宠物的图像进行分类。我们先收集大量的房子,汽车,人与宠物的图像的数据集,并对每个对象标上它的类别。在训练期间,机器会获取一副图片,然后产生一个输出,这个输出以向量形式的分数来表示,每个类别都有一个这样的向量。我们希望所需的类别在所有的类别中具有最高的得分,但是这在训练之前是不太可能发生的。通过计算一个目标函数可以获得输出分数和期望模式分数之间的误差(或距离)。然后机器会修改其内部可调参数,以减少这种误差。这些可调节的参数,通常被称为权值,它们是一些实数,可以被看作是一些“旋钮”,定义了机器的输入输出功能。在典型的深度学习系统中,有可能有数以百万计的样本和权值,和带有标签的样本,用来训练机器。为了正确地调整权值向量,该学习算法计算每个权值的梯度向量,表示了如果权值增加了一个很小的量,那么误差会增加或减少的量。权值向量然后在梯度矢量的相反方向上进行调整。我们的目标函数,所有训练样本的平均,可以被看作是一种在权值的高维空间上的多变地形。负的梯度矢量表示在该地形中下降方向最快,使其更接近于最小值,也就是平均输出误差低最低的地方。

常见的有监督深度学习网络结构有cnn(卷积神经网络)、rnn(循环神经网络),接下来对这两种网络进行介绍。

  • CNN(Convolutional Neural Network卷积神经网络)

CNN是图像处理上最常用的一种深度网络结构,它结构图如图:

                                                                图 2.1

从图2.1中可以看出cnn主要包括四个部分:卷积层、激励层、池化层和全连接层,这四个部分构建了cnn的基本网络结构。接下来讲讲这几个层的内涵。

卷积层,何为卷积操作?对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘再求和)的操作就是所谓的『卷积』操作,也是卷积神经网络的名字来源。卷积层通过卷积运算的作用是可用来获取图像的特征,通过堆叠这些模块,用不同的卷积核来获取更高阶的特征,堆叠起来的深度结构中,卷积核的权重参数是共享的,使得深度结构能获取更高维特征,但是参数量不会大幅增多。

激励层,在图15.2.1中没有显式的指明激励层,激励层通常用在卷积运算之后,选择一个合适的激励函数(如sigmoid、ReLU等激励函数)来对卷积运算的结果进行处理。激活函数的作用是把“激活的神经元的特征”通过函数把特征保留并映射出来(保留特征,去除一些数据中是的冗余),解决网络结构的非线性问题。

池化层,对数据进行下采样(数据压缩),可以避免过拟合,减少数据特征、数据计算量等操作。池化层一般有两种方式:Max pooling(常用,多用)和 Averarg pooling。

全连接层,这一层的连接即为神经网络结构中神经元在每一层之间的连接。全连接层在整个卷积神经网络中起到“分类器”的作用。如果说卷积层、池化层和激活函数层等操作是将原始数据映射到隐层特征空间的话,全连接层则起到将学到的“分布式特征表示”映射到样本标记空间的作用。通过这一层之后可接自定义的一层结构用来做分类或者回归问题。

CNN在计算机视觉上取得了长足的进步,通过深度网络结构获取到更多高维度图像的特征用来处理图像,并且通过卷积运算使得参数得以控制。近几年CNN在计算机视觉取得了广泛的应用。

  • RNN(Recurrent Neural Networks 循环神经网络)

RNNs在众多自然语言处理(Natural Language Processing, NLP)中取得了巨大成功以及广泛应用。RNNs的目的使用来处理序列数据。在传统的神经网络模型中,是从输入层到隐含层再到输出层,层与层之间是全连接的,每层之间的节点是无连接的。但是这种普通的神经网络对于很多问题却无能无力。例如,你要预测句子的下一个单词是什么,一般需要用到前面的单词,因为一个句子中前后单词并不是独立的。RNNs之所以称为循环神经网路,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅包括输入层的输出还包括上一时刻隐藏层的输出。理论上,RNNs能够对任何长度的序列数据进行处理。但是在实践中,为了降低复杂性往往假设当前的状态只与前面的几个状态相关,图2.1-2便是一个典型的RNNs:

                                                                    图 2.1-2

图2.1-2将循环神经网络进行展开成一个全神经网络。例如,对一个包含5个单词的语句,那么展开的网络便是一个五层的神经网络,每一层代表一个单词。对于该网络的计算过程如下:

  • xt表示第t,t=1,2,3...步(step)的输入。比如,x1为第二个词的one-hot向量(根据图15.2.1-2,x0为第一个词); 
    在使用计算机对自然语言进行处理,需要将自然语言处理成为机器能够识别的符号,加上在机器学习过程中,需要将其进行数值化。而词是自然语言理解与处理的基础,因此需要对词进行数值化,词向量便是一种可行又有效的方法。何为词向量,即使用一个指定长度的实数向量v来表示一个词。有一种种最简单的表示方法,就是使用One-hot vector表示单词,即根据单词的数量|V|生成一个|V| * 1的向量,当某一位为一的时候其他位都为零,然后这个向量就代表一个单词。
  • st为隐藏层的第t步的状态,它是网络的记忆单元。 st根据当前输入层的输出与上一步隐藏层的状态进行计算。st=f(Uxt+Wst−1),其中f一般是非线性的激活函数,如tanhReLU,在计算s0时,即第一个单词的隐藏层状态,需要用到s−1,但是其并不存在,在实现中一般置为0向量;
  • ot是第t步的输出,如下一个单词的向量表示,ot=softmax(Vst). 
    需要注意的是:

①你可以认为隐藏层状态st是网络的记忆单元. st包含了前面所有步的隐藏层状态。而输出层的输出ot只与当前步的st有关,在实践中,为了降低网络的复杂度,往往st只包含前面若干步而不是所有步的隐藏层状态;

②在传统神经网络中,每一个网络层的参数是不共享的。而在RNNs中,每输入一步,每一层各自都共享参数U,V,W。其反应者RNNs中的每一步都在做相同的事,只是输入不同,因此大大地降低了网络中需要学习的参数。

③上图中每一步都会有输出,但是每一步都要有输出并不是必须的。比如,我们需要预测一条语句所表达的情绪,我们仅仅需要关系最后一个单词输入后的输出,而不需要知道每个单词输入后的输出。同理,每步都需要输入也不是必须的。RNNs的关键之处在于隐藏层,隐藏层能够捕捉序列的信息。

RNNs在自然语言处理中有很多成功的应用,比如在机器翻译、语音识别、图像描述等方面都表现出不错的效果。

2.2 无监督学习的深度学习网络结构

无监督的学习方法,这种方法可以创建一些网络层来检测特征而不使用带标签的数据,这些网络层可以用来重构或者对特征检测器的活动进行建模。通过预训练过程,深度网络的权值可以被初始化为有意思的值。然后一个输出层被添加到该网络的顶部,并且使用标准的反向传播算法进行微调。这个工作对手写体数字的识别以及行人预测任务产生了显著的效果,尤其是带标签的数据非常少的时候。接下来介绍两种无监督的网络结构模型。

受限玻尔兹曼机(Restricted Boltzmann Machine,简称RBM)是由Hinton和Sejnowski于1986年提出的一种生成式随机神经网络(generative stochastic neural network),该网络由一些可见单元(visible unit,对应可见变量,亦即数据样本)和一些隐藏单元(hidden unit,对应隐藏变量)构成,可见变量和隐藏变量都是二元变量,亦即其状态取{0,1}。整个网络是一个二部图,只有可见单元和隐藏单元之间才会存在边,可见单元之间以及隐藏单元之间都不会有边连接,如图2.2-1:

                                                                  图 2.2-1

图2.2-1所示的RBM含有12个可见单元(构成一个向量v)和3个隐藏单元(构成一个向量h),W是一个12*3的矩阵,表示可见单元和隐藏单元之间的边的权重。

RBM的权重的学习算法:

  • 取一个样本数据,把可见变量的状态设置为这个样本数据。随机初始化W。
  • 根据式子-9的第一个公式来更新隐藏变量的状态,亦即hj以P(hj=1|v)的概率设置为状态1,否则为0。然后对于每个边vihj,计算Pdata(vihj)=vi*hj(注意,vi和hj的状态都是取{0,1})。
  • 根据h的状态和式子-9的第二个公式来重构v1,并且根据v1和式子-9的第一个公式来求得h1,计算Pmodel(v1ih1j)=v1i*h1j。
  • 更新边vihj的权重Wij为Wij=Wij+L*(Pdata(vihj)=Pmodel(v1ih1j))。
  • 取下一个数据样本,重复1-4的步骤。
  • 以上过程迭代K次。

对应上述权重学习方法,可参考图2.2-2进行理解:

                                                                     图 2.2-2

RBF是一种非监督学习的网络结构,它的用处在于降低维度, 分类, 回归, 特征学习。

 

深度信念网络由 Geoffrey Hinton 在 2006 年提出。它是一种生成模型,通过训练其神经元间的权重,我们可以让整个神经网络按照最大概率来生成训练数据。多个Restricted Boltzmann Machines堆叠而成。DBN的网络结构如图2.2-3:

                                                                   图 2.2-3

DBN训练过程: 

1) 首先充分训练第一个 RBM; 

2) 固定第一个 RBM 的权重和偏移量,然后使用其隐性神经元的状态,作为第二个 RBM 的输入向量; 

3) 充分训练第二个 RBM 后,将第二个 RBM 堆叠在第一个 RBM 的上方; 

4) 重复以上三个步骤任意多次; 

5) 如果训练集中的数据有标签,那么在顶层的 RBM 训练时,这个 RBM 的显层中除了显性神经元,还需要有代表分类标签的神经元,一起进行训练: 

a) 假设顶层 RBM 的显层有 500 个显性神经元,训练数据的分类一共分成了 10 类; 

b) 那么顶层 RBM 的显层有 510 个显性神经元,对每一训练训练数据,相应的标签神经元被打开设为 1,而其他的则被关闭设为 0。

DBN的几点说明:

  1. 每层的神经元不与本层的其他神经元交流。
  2. 最后一层通常是classification layer (比如Softmax)。
  3. 除了第一层和最后一层,每层都有两个作用:对于前一层作为隐藏层,对于后一层作为输入层。

DBN多用在降低维度, 图像搜索(压缩), 数据压缩, 信息检索。

 

3 项目实战

在这里将分别介绍上述两种深度网络结构的示例,采用mnist手写数字数据集以及tensorflow框架进行实战,mnist数据可在官网这进行下载(http://yann.lecun.com/exdb/mnist/)。

3.1 使用RBM对mnist数据集进行生成

实例:RBM深度网络结构的实现

  • 首先我们用一个基类来存放受限玻尔兹曼机RBM的模型结构。创建一个模块命名为rbm.py用来构建RBM网络结构。
  1. from __future__ import print_function  
  2.   
  3. import tensorflow as tf  
  4. import numpy as np  
  5. import sys  
  6.   
  7. def tf_xavier_init(fan_in, fan_out, *, const=1.0, dtype=np.float32):  
  8.     ''''' 该函数对权重w参数进行初始化 '''  
  9.     k = const * np.sqrt(6.0 / (fan_in + fan_out))  
  10.     return tf.random_uniform((fan_in, fan_out), minval=-k, maxval=k, dtype=dtype)  
  11.   
  12.   
  13. class RBM:  
  14.     ''''' 用一个类来存放受限玻尔兹曼机RBM模型结构 '''  
  15.     def __init__(self,  
  16.                  n_visible,     # 可见变量数  
  17.                  n_hidden,      # 隐藏层数目  
  18.                  learning_rate=0.01,    # 学习速率  
  19.                  momentum=0.95,         # 动量参数  
  20.                  xavier_const=1.0,      # 初始化设置参数  
  21.                  err_function='mse',    # 损失函数选择参数  
  22.                  use_tqdm=False,    
  23.                  tqdm=None):  
  24.         if not 0.0 <= momentum <= 1.0:  
  25.             raise ValueError('momentum should be in range [0, 1]')  
  26.   
  27.         if err_function not in {'mse''cosine'}:  
  28.             raise ValueError('err_function should be either \'mse\' or \'cosine\'')  
  29.   
  30.         self._use_tqdm = use_tqdm  
  31.         self._tqdm = None  
  32.   
  33.         if use_tqdm or tqdm is not None:  
  34.             from tqdm import tqdm  
  35.             self._tqdm = tqdm  
  36.   
  37.         self.n_visible = n_visible  
  38.         self.n_hidden = n_hidden  
  39.         self.learning_rate = learning_rate  
  40.         self.momentum = momentum  
  41.   
  42.         self.x = tf.placeholder(tf.float32, [None, self.n_visible])  
  43.         self.y = tf.placeholder(tf.float32, [None, self.n_hidden])  
  44.   
  45.         self.w = tf.Variable(tf_xavier_init(self.n_visible, self.n_hidden, const=xavier_const), dtype=tf.float32)  
  46.         self.visible_bias = tf.Variable(tf.zeros([self.n_visible]), dtype=tf.float32)  
  47.         self.hidden_bias = tf.Variable(tf.zeros([self.n_hidden]), dtype=tf.float32)  
  48.   
  49.         self.delta_w = tf.Variable(tf.zeros([self.n_visible, self.n_hidden]), dtype=tf.float32)  
  50.         self.delta_visible_bias = tf.Variable(tf.zeros([self.n_visible]), dtype=tf.float32)  
  51.         self.delta_hidden_bias = tf.Variable(tf.zeros([self.n_hidden]), dtype=tf.float32)  
  52.   
  53.         self.update_weights = None  
  54.         self.update_deltas = None  
  55.         self.compute_hidden = None  
  56.         self.compute_visible = None  
  57.         self.compute_visible_from_hidden = None  
  58.   
  59.         self._initialize_vars()  
  60.   
  61.         assert self.update_weights is not None  
  62.         assert self.update_deltas is not None  
  63.         assert self.compute_hidden is not None  
  64.         assert self.compute_visible is not None  
  65.         assert self.compute_visible_from_hidden is not None  
  66.   
  67.         if err_function == 'cosine':  
  68.             x1_norm = tf.nn.l2_normalize(self.x, 1)  
  69.             x2_norm = tf.nn.l2_normalize(self.compute_visible, 1)  
  70.             cos_val = tf.reduce_mean(tf.reduce_sum(tf.mul(x1_norm, x2_norm), 1))  
  71.             self.compute_err = tf.acos(cos_val) / tf.constant(np.pi)  
  72.         else:  
  73.             self.compute_err = tf.reduce_mean(tf.square(self.x - self.compute_visible))  
  74.   
  75.         init = tf.global_variables_initializer()  
  76.         self.sess = tf.Session()  
  77.         self.sess.run(init)  
  78.   
  79.     def _initialize_vars(self):  
  80.         pass  
  81.   
  82.     def get_err(self, batch_x):  
  83.         return self.sess.run(self.compute_err, feed_dict={self.x: batch_x})  
  84.   
  85.     def reconstruct(self, batch_x):  
  86.         ''''' 
  87.         该函数根据训练参数返回可见层节点 
  88.         '''  
  89.         return self.sess.run(self.compute_visible, feed_dict={self.x: batch_x})  
  90.   
  91.     def partial_fit(self, batch_x):  
  92.         self.sess.run(self.update_weights + self.update_deltas, feed_dict={self.x: batch_x})  
  93.   
  94.     # 该方法对输入数据进行训练,学习  
  95.     def fit(self,  
  96.             data_x,  
  97.             n_epoches=10,  
  98.             batch_size=10,  
  99.             shuffle=True,  
  100.             verbose=True):  
  101.         assert n_epoches > 0  
  102.   
  103.         n_data = data_x.shape[0]  
  104.   
  105.         if batch_size > 0:  
  106.             n_batches = n_data // batch_size + (0 if n_data % batch_size == 0 else 1)  
  107.         else:  
  108.             n_batches = 1  
  109.   
  110.         if shuffle: #是否将数据打乱处理  
  111.             data_x_cpy = data_x.copy()  
  112.             inds = np.arange(n_data)  
  113.         else:  
  114.             data_x_cpy = data_x  
  115.   
  116.         errs = []  
  117.   
  118.         # 开始每一轮的训练  
  119.         for e in range(n_epoches):  
  120.             if verbose and not self._use_tqdm:  
  121.                 print('Epoch: {:d}'.format(e))  
  122.   
  123.             epoch_errs = np.zeros((n_batches,))  
  124.             epoch_errs_ptr = 0  
  125.   
  126.             if shuffle:  
  127.                 np.random.shuffle(inds)  
  128.                 data_x_cpy = data_x_cpy[inds]  
  129.   
  130.             r_batches = range(n_batches)  
  131.   
  132.             if verbose and self._use_tqdm:  
  133.                 r_batches = self._tqdm(r_batches, desc='Epoch: {:d}'.format(e), ascii=True, file=sys.stdout)  
  134.   
  135.             # 对每一个batch进行loss的计算,并更新参数  
  136.             for b in r_batches:  
  137.                 batch_x = data_x_cpy[b * batch_size:(b + 1) * batch_size]  
  138.                 self.partial_fit(batch_x) # 对参数进行更新  
  139.                 batch_err = self.get_err(batch_x)  
  140.                 epoch_errs[epoch_errs_ptr] = batch_err  
  141.                 epoch_errs_ptr += 1  
  142.   
  143.             # 对训练过程错误输出处理  
  144.             if verbose:  
  145.                 err_mean = epoch_errs.mean()  
  146.                 if self._use_tqdm:  
  147.                     self._tqdm.write('Train error: {:.4f}'.format(err_mean))  
  148.                     self._tqdm.write('')  
  149.                 else:  
  150.                     print('Train error: {:.4f}'.format(err_mean))  
  151.                     print('')  
  152.                 sys.stdout.flush()  
  153.   
  154.             errs = np.hstack([errs, epoch_errs])  
  155.   
  156.         return errs  
  • 在rbm.py的模块基础上创建一个伯努利-伯努利的RBM深度网络结构,这里同样用一个类来保存结构,并且该类继承于rbm类,根据不同的受限玻尔兹曼机的模型结构进行不一样的参数初始化,创建一个名为bbrbm.py的模块保存。
  1. import tensorflow as tf  
  2. from .rbm import RBM  
  3.   
  4. def sample_bernoulli(probs):  
  5.     return tf.nn.relu(tf.sign(probs - tf.random_uniform(tf.shape(probs))))  
  6.   
  7. class BBRBM(RBM):  
  8.     def __init__(self, *args, **kwargs):  
  9.         RBM.__init__(self, *args, **kwargs)  
  10.   
  11.     def _initialize_vars(self):  
  12.         ''''' 
  13.         对伯努利-伯努利受限玻尔兹曼机变量进行初始化 
  14.         '''  
  15.         hidden_p = tf.nn.sigmoid(tf.matmul(self.x, self.w) + self.hidden_bias)  
  16.         visible_recon_p = tf.nn.sigmoid(tf.matmul(sample_bernoulli(hidden_p), tf.transpose(self.w)) + self.visible_bias)  
  17.         hidden_recon_p = tf.nn.sigmoid(tf.matmul(visible_recon_p, self.w) + self.hidden_bias)  
  18.   
  19.         positive_grad = tf.matmul(tf.transpose(self.x), hidden_p)  
  20.         negative_grad = tf.matmul(tf.transpose(visible_recon_p), hidden_recon_p)  
  21.   
  22.         def f(x_old, x_new):  
  23.             ''''' 
  24.             函数f用来计算参数的变化量 
  25.             '''  
  26.             return self.momentum * x_old +\  
  27.                    self.learning_rate * x_new * (1 - self.momentum) / tf.to_float(tf.shape(x_new)[0])  
  28.   
  29.         # 计算参数的变化量  
  30.         delta_w_new = f(self.delta_w, positive_grad - negative_grad)  
  31.         delta_visible_bias_new = f(self.delta_visible_bias, tf.reduce_mean(self.x - visible_recon_p, 0))  
  32.         delta_hidden_bias_new = f(self.delta_hidden_bias, tf.reduce_mean(hidden_p - hidden_recon_p, 0))  
  33.   
  34.         # 对bbrbm模型参数进行初始化更新  
  35.         update_delta_w = self.delta_w.assign(delta_w_new)  
  36.         update_delta_visible_bias = self.delta_visible_bias.assign(delta_visible_bias_new)  
  37.         update_delta_hidden_bias = self.delta_hidden_bias.assign(delta_hidden_bias_new)  
  38.   
  39.         update_w = self.w.assign(self.w + delta_w_new)  
  40.         update_visible_bias = self.visible_bias.assign(self.visible_bias + delta_visible_bias_new)  
  41.         update_hidden_bias = self.hidden_bias.assign(self.hidden_bias + delta_hidden_bias_new)  
  42.   
  43.         # 将更新的参数添加到模型结构的参数中  
  44.         self.update_deltas = [update_delta_w, update_delta_visible_bias, update_delta_hidden_bias]  
  45.         self.update_weights = [update_w, update_visible_bias, update_hidden_bias]  
  46.   
  47.         self.compute_hidden = tf.nn.sigmoid(tf.matmul(self.x, self.w) + self.hidden_bias)  
  48.         self.compute_visible = tf.nn.sigmoid(tf.matmul(self.compute_hidden, tf.transpose(self.w)) + self.visible_bias)  
  49.         self.compute_visible_from_hidden = tf.nn.sigmoid(tf.matmul(self.y, tf.transpose(self.w)) + self.visible_bias)  

 

  • 创建主模块训练这个网络结构。

导入相应的包:

  1. import numpy as np  
  2. import matplotlib.pyplot as plt  
  3. from example_tfrbm import bbrbm  
  4. from tensorflow.examples.tutorials.mnist import input_data  

导入minist手写数据集:

  1. mnist = input_data.read_data_sets('/home/tony/dl_cv/dataset/mnist/', one_hot=True)  # 这里填写下载好的数据集地址
  2. mnist_images = mnist.train.images  

显示导入的数据:

  1. IMAGE = 1  
  2. def show_digit(x):  
  3.     plt.imshow(x.reshape((28, 28)), cmap=plt.cm.gray)  
  4.     plt.show()  
  5.   
  6. image = mnist_images[IMAGE]  
  7. show_digit(image)  

开始训练bbrbm模型:

  1. # 初始化模型  
  2. model = bbrbm.BBRBM(n_visible=784, n_hidden=64, learning_rate=0.01, momentum=0.95, use_tqdm=True)  
  3. # 训练模型,返回训练loss  
  4. errs = model.fit(mnist_images, n_epoches=30, batch_size=10)  

训练过程输出:

... ... ... ......................................

... ... ... ......................................

 

查看训练过程loss收敛图像:

  1. # 画出训练的loss图像  
  2. plt.plot(errs)  
  3. plt.show()  

收敛结果图像:

生成训练结果图像:

  1. # 根据训练输出的节点,用图像进行输出  
  2. image_rec = model.reconstruct(image.reshape(1,-1))  
  3. show_digit(image_rec)  

生成结果如图:

至此,整个模型训练完成,得到的图像与生成的图像相似度还比较满意。

3.2 深度卷积网络识别mnist手写数字

在没有使用深度网络结构,在mnist手写数字识别中,svm一直是表现最好的模型,直到2012年AlexNet深度卷积网络的出现,让mnist手写数字识别到了一个更高的准确度。到现在例如GoogLeNet、ResNet等深度网络结构不断地在提高识别度,有些甚至比人眼更精确。

  • AlexNet的实现讲解

创建一个文件名为AlexNet.py实现该网络结构。

  1. #coding=utf-8  
  2. from __future__ import print_function  
  3. from tensorflow.examples.tutorials.mnist import input_data  
  4. mnist = input_data.read_data_sets('/home/tony/dl_cv/dataset/mnist/', one_hot=True)  
  5. import tensorflow as tf  
  6. # 定义网络超参数  
  7. learning_rate = 0.001  
  8. training_iters = 200000  
  9. batch_size = 64  
  10. display_step = 20  
  11.   
  12. # 定义网络参数  
  13. n_input = 784 # 输入的维度  
  14. n_classes = 10 # 标签的维度  
  15. dropout = 0.8 # Dropout 的概率  
  16.   
  17. # 占位符输入  
  18. x = tf.placeholder(tf.float32, [None, n_input])  
  19. y = tf.placeholder(tf.float32, [None, n_classes])  
  20. keep_prob = tf.placeholder(tf.float32)  
  21.   
  22. # 卷积操作  
  23. def conv2d(name, l_input, w, b):  
  24.     return tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(l_input, w, strides=[1, 1, 1, 1], padding='SAME'),b), name=name)  
  25.   
  26. # 最大下采样操作  
  27. def max_pool(name, l_input, k):  
  28.     return tf.nn.max_pool(l_input, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME', name=name)  
  29.   
  30. # 归一化操作  
  31. def norm(name, l_input, lsize=4):  
  32.     return tf.nn.lrn(l_input, lsize, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=name)  
  33.   
  34. # 定义整个网络   
  35. def alex_net(_X, _weights, _biases, _dropout):  
  36.     # 向量转为矩阵  
  37.     _X = tf.reshape(_X, shape=[-1, 28, 28, 1])  
  38.   
  39.     # 卷积层  
  40.     conv1 = conv2d('conv1', _X, _weights['wc1'], _biases['bc1'])  
  41.     # 下采样层  
  42.     pool1 = max_pool('pool1', conv1, k=2)  
  43.     # 归一化层  
  44.     norm1 = norm('norm1', pool1, lsize=4)  
  45.     # Dropout  
  46.     norm1 = tf.nn.dropout(norm1, _dropout)  
  47.   
  48.     # 卷积  
  49.     conv2 = conv2d('conv2', norm1, _weights['wc2'], _biases['bc2'])  
  50.     # 下采样  
  51.     pool2 = max_pool('pool2', conv2, k=2)  
  52.     # 归一化  
  53.     norm2 = norm('norm2', pool2, lsize=4)  
  54.     # Dropout  
  55.     norm2 = tf.nn.dropout(norm2, _dropout)  
  56.   
  57.     # 卷积  
  58.     conv3 = conv2d('conv3', norm2, _weights['wc3'], _biases['bc3'])  
  59.     # 下采样  
  60.     pool3 = max_pool('pool3', conv3, k=2)  
  61.     # 归一化  
  62.     norm3 = norm('norm3', pool3, lsize=4)  
  63.     # Dropout  
  64.     norm3 = tf.nn.dropout(norm3, _dropout)  
  65.   
  66.     # 全连接层,先把特征图转为向量  
  67.     dense1 = tf.reshape(norm3, [-1, _weights['wd1'].get_shape().as_list()[0]])   
  68.     dense1 = tf.nn.relu(tf.matmul(dense1, _weights['wd1']) + _biases['bd1'], name='fc1')   
  69.     # 全连接层  
  70.     dense2 = tf.nn.relu(tf.matmul(dense1, _weights['wd2']) + _biases['bd2'], name='fc2')   
  71.   
  72.     # 网络输出层  
  73.     out = tf.matmul(dense2, _weights['out']) + _biases['out']  
  74.     return out  
  75.   
  76. # 存储所有的网络参数  
  77. weights = {  
  78.     'wc1': tf.Variable(tf.random_normal([3, 3, 1, 64])),  
  79.     'wc2': tf.Variable(tf.random_normal([3, 3, 64, 128])),  
  80.     'wc3': tf.Variable(tf.random_normal([3, 3, 128, 256])),  
  81.     'wd1': tf.Variable(tf.random_normal([4*4*256, 1024])),  
  82.     'wd2': tf.Variable(tf.random_normal([1024, 1024])),  
  83.     'out': tf.Variable(tf.random_normal([1024, 10]))  
  84. }  
  85. biases = {  
  86.     'bc1': tf.Variable(tf.random_normal([64])),  
  87.     'bc2': tf.Variable(tf.random_normal([128])),  
  88.     'bc3': tf.Variable(tf.random_normal([256])),  
  89.     'bd1': tf.Variable(tf.random_normal([1024])),  
  90.     'bd2': tf.Variable(tf.random_normal([1024])),  
  91.     'out': tf.Variable(tf.random_normal([n_classes]))  
  92. }  
  93.   
  94. # 构建模型  
  95. pred = alex_net(x, weights, biases, keep_prob)  
  96. # 定义损失函数和学习步骤  
  97. cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = pred, labels = y))  
  98. optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)  
  99. # 测试网络  
  100. correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))  
  101. accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))  
  102. # 初始化所有的共享变量  
  103. init = tf.initialize_all_variables()  
  104. # 开启一个训练  
  105. with tf.Session() as sess:  
  106.     sess.run(init)  
  107.     step = 1  
  108.     # Keep training until reach max iterations  
  109.     while step * batch_size < training_iters:  
  110.         batch_xs, batch_ys = mnist.train.next_batch(batch_size)  
  111.         # 获取批数据  
  112.         sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys, keep_prob: dropout})  
  113.         if step % display_step == 0:  
  114.             # 计算精度  
  115.             acc = sess.run(accuracy, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})  
  116.             # 计算损失值  
  117.             loss = sess.run(cost, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})  
  118.             print ("Iter " + str(step*batch_size) + ", Minibatch Loss= " + "{:.6f}".format(loss) + ", Training Accuracy = " + "{:.5f}".format(acc))  
  119.         step += 1  
  120.     print ("Optimization Finished!")  
  121.     # 计算测试精度  
  122.     print ("Testing Accuracy:", sess.run(accuracy, feed_dict={x: mnist.test.images[:256], y: mnist.test.labels[:256], keep_prob: 1.}))  
  • 实验运行结果

网络训练过程:

  1. Iter 1280, Minibatch Loss= 86770.125000, Training Accuracy = 0.35938  
  2. Iter 2560, Minibatch Loss= 64896.742188, Training Accuracy = 0.39062  
  3. Iter 3840, Minibatch Loss= 34028.277344, Training Accuracy = 0.50000  
  4. Iter 5120, Minibatch Loss= 30742.812500, Training Accuracy = 0.59375  
  5. .......................................................
  6. .......................................................
  7. .......................................................
  8. Iter 190720, Minibatch Loss= 896.383911, Training Accuracy = 0.96875  
  9. Iter 192000, Minibatch Loss= 2677.220215, Training Accuracy = 0.93750  
  10. Iter 193280, Minibatch Loss= 610.773926, Training Accuracy = 0.96875  
  11. Iter 194560, Minibatch Loss= 1569.147217, Training Accuracy = 0.95312  
  12. Iter 195840, Minibatch Loss= 40.134521, Training Accuracy = 0.98438  
  13. Iter 197120, Minibatch Loss= 2792.126953, Training Accuracy = 0.93750  
  14. Iter 198400, Minibatch Loss= 380.154297, Training Accuracy = 0.95312  
  15. Iter 199680, Minibatch Loss= 1328.015381, Training Accuracy = 0.93750  
  16. Optimization Finished!  
  17. Testing Accuracy: 0.972656 

从AlexNet训练中我们可以看到整个网络训练时,整体Loss是在不断下降的,学到更多数据的特征信息,到后面整个网络收敛,表现出不错的准确率。测试的结果高达97%以上。

练习:在ImageNet上下载猫狗等数据集,用InceptionV3、ResNet等训练模型进行识别。

代码链接:

  • 7
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值