参考网址:https://blog.csdn.net/xiang_freedom/article/details/81448062
《TensorFlow:实战Google深度学习框架(第二版)》笔记【1-6章】
第一章:深度学习简介
1.人工和深度学习的不同
既然人工的方式无法很好地抽取实体中的特征,那么是否有自动的方式呢?深度学习解决的核心问题之一就是自动的将简单地特征组合成更加复杂的特征,并使用这些组合特征解决问题。
2. 深度学习的发展历程
第一个阶段:模仿大脑的学习机理
感知机模型可以根据样例数据学习特征权重。
不足:感知机无法解决线性不可分问题,且计算能力不足以训练多层神经网络
第二个阶段:分布式知识表达和反向传播算法
分布式知识表达大大加强了模型的表达能力,让神经网络从宽度的方向走向了深度的方向。
反向传播算法大幅降低了训练神经网络所需要的时间。
不足:计算资源不足以训练深层神经网络;数据量无法满足训练需要。
第三个阶段:云计算、GPU和海量数据
解决了计算力和数据的问题,深度学习迎来高潮。
3 深度学习的应用
1计算机视觉:分类,识别,无人驾驶,图像搜索等
2语音识别:siri,同声传译等
3自然语言处理:语言模型、机器翻译、词性标注、实体识别、情感分析等
核心技术:单词向量word embedding
4人机博弈:AlphaGo系列
4深度学习工具
第二章: TensorFlow环境搭建
依赖包 和 安装方式
2.1. 依赖的工具包
Protocol Buffer的作用是将结构化的数据序列化,并从序列化之后的数据流中还原出原来的结构化数据。
与XML、Json等其他工具相比:
1序列化为二进制流,而不是字符串
2 XML、Json格式信息包含在数据流中,Protocol Buffer需要先定义数据的格式
3 Protocol Buffer数据流比XML小3-10倍,解析时间快20-100倍
结构化数据:
Protocol Buffer数据格式示例:
Protocol Buffer数据格式一般保存在.proto文件中。
TensorFlow中的数据基本都是通过Protocol Buffer来组织的
Bazel
Bazel是从Google开源的自动化构建工具,相比传统的makefile,Ant或者Maven,Bazel在速度、可伸缩性、灵活性以及对不同程序语言和平台的支持上都要更加出色。Tensorflow本身以及Google给出的很多官方样例都是通过Bazel来编译的。
WORKSPACE文件:定义了对外部资源的依赖关系
BUILD文件:找到需要编译的目标
在编译出来的结果中,bazel-bin目录下存放了编译产生的二进制文件以及运行该二进制文件所需要的所有依赖关系。
2.2Tensorflow安装方式
1.Docker:可移植性最强,但对GPU支持有限,且对本地开发环境的支持不够友好
2.Pip:最方便,但无法修改Tensorflow本身
3.源码:最灵活,但比较繁琐,一般只有修改tensorflow护着需要支持特殊GPU才会被用到
第三章:tensorflow入门
介绍Tensorflow的计算模型、数据模型和运行模型,以了解Tensorflow的工作原理
1.Tensorflow计算模型:计算图
计算图是Tensorflow中最基本的一个概念,Tensorflow中的所有计算都被被转化为计算图上的节点。
Tensorflow是一个通过计算图的形式来描述计算的编程系统。Tensor即张量,Flow指计算图。
Tensorflow中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算
tf自动维护一个默认的计算图,如果没有特意指定,tf会将定义的计算自动转化为默认计算图上的节点。
除了默认的计算图,也可以用tf.Graph生成新的计算图,不同计算图的张量和运算不会共享。
计算图可以通过tf.Graph.device函数指定运行计算的设备。
有效的整理tf程序中的资源也是计算图的一个重要功能。可以通过集合来管理不同类别的资源。tf通过tf.add_to_collection将资源加入一个或多个集合中,然后通过tf.get_collection获取一个集合里面的所有资源。这里的资源可以是张量、变量或者运行tf程序所需要的队列资源等。tf自动管理了一些最常用的集合:
2. Tensorflow数据模型:张量
张量是tf管理数据的形式。
tf所有的数据都通过张量的形式来表示,张量可以简单理解为多维数组。但张量在tf的实现并不是直接采用数组的形式,它只是对tf中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。
执行上面的代码,并不会得到加法的结果,而是对结果的一个引用。
tf的计算都可以通过计算图的模型来建立,而计算图上的每一个节点代表了一个计算,计算的结果保存在张量之中。张量对应了计算图上节点代表的计算结果。
一个张量主要保存三个属性:名字(name),维度(shape)和类型(type)。
张量的命名形式可以是“node:src_output"。其中node为节点的名称,src_output表示来自节点的第几个输出。
维度是张量一个很重要的属性,围绕张量的维度tf给出了很多有用的运算。
每个张量都有一个唯一的类型,tf会对参与运算的所有张量进行类型检查,当发现类型不匹配会报错。如
报错:
如果将a指定为实数类型”a=tf.constant([1,2],name=“a”,dtype=tf.float32)",就不会报错了。不指定类型,tf会给出默认的类型,容易导致类型不匹配问题。tf支持14中不同的类型,主要包括实数(tf.float32,tf.float64)、整数(tf.int8,tf.int16,tf.int64,tf.uinit8)、布尔型(tf.bool)和复数(tf.complex64/tf.conplex128)。
3. Tensorflow运行模型:会话
计算图和张量分别组织运算和数据,而会话(session)用来执行定义好的运算。会话拥有并管理tf程序运行时的所有资源,当所有计算完成之后需要关闭会话帮助系统回收资源,否则可能出现资源泄露的问题。tf中使用会话的模式一般有两种。
使用这种模式需要明确调用Session.close关闭会话并释放资源。当程序因为异常而退出时,关闭函数可能不会执行导致资源泄露。
通过Python上下文管理器机制,退出时自动释放所有资源。
会话和计算图有类似的机制,但tf不会自动生成默认的会话,而是需要手动指定。默认的会话被指定之后可以通过tf.Tensor.eval函数来计算一个张量的取值。
或者
在交互式环境(比如Python脚本或者Jupyter的编辑器)下,通过设置默认会话的方式来获取张量的取值更加方便。所以tf提供了一种直接构建默认会话的函数tf.InteractiveSession。
无论使用哪种方法都可以通过ConfigProto Protocol Buffer来配置需要生成的会话
通过ConfigProto可以配置类似并行的线程数、GPU分配策略,运算超时时间等参数。在这些参数中,最常使用的有两个。
1 allow_soft_placement:默认值为False。设为True时,可以在以下情况发生时,把GPU的运算放到CPU上。
1 运算无法在GPU上执行
2 没有GPU资源(比如指定在第二个GPU,但只有一个GPU)
3 运算输入包含对CPU结果的引用
2 log_device_placement:True时日志中会记录每个节点被安排在了哪个设备上以方便调试。在生产环境设为False可以减少日志量。
4 Tensorflow实现神经网络
Tensorflow游乐场是一个通过网页浏览器就可以训练的简单神经网络并实现了可视化训练的工具
使用这个工具可以看到神经网络解决分类问题主要分为以下步骤:
1. 提取问题中实体的特征向量作为神经网络的输入。
2. 定义神经网络的结构,并定义如何从输入得到输出
3. 通过训练数据来调整神经网络中参数的取值
4. 使用训练好的神经网络预测未知的数据
4.1前向传播算法简介
解神经元(也称为节点)的结构
一个节点有多个输入和一个输出,最简单的节点的输出就是对所有输入的加权和,不同输入的权重就是节点的参数。而神经网络的优化过程就是优化节点中参数的值的过程(反向传播算法)。下面给出了一个简单的判断零件是否合格的三层全连接神经网络(全连接神经网络是指相邻两层之间所有节点之间都有连接)。
计算神经网络的前向传播结果需要三部分信息。
神经网络的输入:从实体中提取的特征向量。上图中的零件长度x1和零件质量x2。
神经网络的连接结构:神经网络由节点组成,神经网络的结构就是不同节点之间输入输出的连接关系。
神经元的参数:用W表示神经元的参数。W的上标表明神经网络的层数,下标表明连接节点的编号。如W1,2(1)表示连接x1和a12节点的权重。
有了输入、结构和参数,就可以通过前向传播算法计算神经网络的输出,如图。
其中a11的计算过程
输出y的计算过程
前向传播算法可以表示为矩阵乘法,将输入x1,x2表示为1x2的矩阵x=[x1,x2],W(1)表示为2x3的矩阵
这样通过矩阵乘法就可以得到隐藏层三个节点的向量取值:
类似的输出层:
tf中矩阵乘法的实现非常简单。
4.2通过Tensorflow训练神经网络模型_反向传播的实现方式
在神经网络优化算法中,最常用的方法是反向传播算法,本小节主要介绍训练神经网络的整体流程以及Tensorflow对于这个流程的支持。
使用tf实现反向传播算法的第一步是表达一个batch的数据。之前的例子中曾使用常量表达过一个样本,但如果每次迭代都使用一个常量,那么计算图中的常量节点会非常多且利用率很低。为了避免这个问题,tf提供了placeholder机制用于提供输入数据。placeholder相当于定义了一个位置,这个位置中的数据在程序运行时再指定。定义placeholder时,需要指定类型,但是不一定需要维度,因为可以根据提供的数据推导出来。
第四章:深层神经网络
介绍深度学习的概念、损失函数、反向传播算法、tf实现反向传播的过程以及神经网络优化中常见的问题。
1. 激活函数实现非线性化(正向优化)
如果将前面提到的加权和节点后通过一个非线性函数,那么神经网络模型就是非线性的了。这个非线性函数就是激活函数。
新的结构中加入了偏置项(输出永远为1的节点)和非线性变换。
激活函数的图像都不是一条直线:
新的神经网络结构图:
输出层计算公式
目前tf提供7中不同的非线性激活函数,比如tf.nn.relu,tf.sigmoid和tf.tanh。tf也支持使用自定义的激活函数。以下代码展示了tf实现上图中的前向传播算法:
实例1:多层网络解决异或运算
神经网络发展史上,一个重要的问题就是异或问题。感知机模型的提出从数学上完成了对神经网络的建模,感知机可以简单的理解为单层的神经网络,其网络结构就是图4-5。然而感知机被证明无法解决异或运算(如果两个输入的符号相同输出0,否则输出1):
加入隐藏层后,异或问题可以很好地解决。
而且,隐藏层的四个节点中,每个节点都有一个角是黑的。这个节点代表了从输入特征中抽取的更高维的特征,比如第一个节点大致代表两个输入的逻辑与操作的结果。深度神经网络的组合特征提取的功能,对于解决不易提取特征向量的问题(图片识别、语音识别等)有很大帮助。
2. 损失函数定义
神经网络模型的效果以及优化的目标是通过损失函数来定义的,本节讲解适用于分类和回归问题的经典损失函数、自定义损失函数。
经典损失函数
分类问题:交叉熵函数
通过神经网络解决多分类问题最常用的方法是设置n个输出节点,n是分类的个数。理想情况下,如果一个样本属于类别k,那么这个类别对应的输出节点为1,其他节点为0,比如[0,1,0,0,0,0]。怎么判断一个输出向量和期望的向量有多接近呢?交叉熵(cross entropy)是常用的评判方法之一。交叉熵刻画了两个概率分布之间的距离,它是分类问题中使用比较多的损失函数。
给定两个概率分布p和q,通过q来表示p的交叉熵为
交叉熵刻画的是两个概率分布的距离,然而神经网络的输出不一定是一个概率分布(任意事件发生的概率都在0和1之间,且概率总和为1)。Softmax回归是一个常用的将前向传播结果变成概率分布的方法。
Softmax回归本身可以作为一个学习算法来优化分类结果,但在tf中,Softmax回归的参数被去掉了,只作为一个额外的处理层,将输出变成一个概率分布。
交叉熵值越小,两个概率分布越接近。之前已经用tf实现过交叉熵的计算:
因为交叉熵一般与Softmax回归一起使用,tf提供了tf.nn.softmax_cross_entropy_with_logits函数:
其中y代表输出值,y_代表标准答案。
如果分类只有一个正确答案,还可以使用tf.nn.sparse_softmax_cross_entropy_with_logits函数加速计算过程。
回归问题:均方误差函数
回归问题需要预测的不是一个实现定义好的类别,而是一个任意实数,比如房价、销量等。解决回归问题的神经网络一般只有一个输出节点,最常用的损失函数是均方误差(MSE)
自定义损失函数
为了让神经网络优化的结果更加接近实际问题,我们需要自定义损失函数。
比如商品销量问题,如果预测值较大(大于真实销量),商家损失生产商品的成本。如果预测值较小,损失商品的利润。因为一般成本和利润不相同,使用均方误差不能够很好地最大化利润。比如成本是1元,利润是10元,那么模型应该偏向预测值较大。下面的公式给出了预测值多于或少于真实值时有不同系数的损失函数,通过这个损失函数,模型可能最大化收益。
3神经网络优化算法
本节介绍如何通过反向传播算法和梯度下降算法调整神经网络中参数的取值。梯度下降算法主要用于优化单个参数的取值,而反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法。反向传播算法是训练神经网络的核心算法,可以根据定义好的损失函数优化参数的取值,从而使模型在训练数据集上的损失函数达到一个较小值。神经网络模型参数的优化过程直接决定了模型的质量。
4反向优化
1学习率的设置
tf提供了一种灵活的学习率设置方法——指数衰减法,tf.train.exponential_decay。先使用较大的学习率快速得到一个比较优的解,随着迭代的继续逐步减少学习率,使得模型在训练后期更加稳定。
2过拟合问题
正则化的思想是在损失函数中加入刻画模型复杂程度的指标,一般来说模型复杂度只由权重w决定,和偏置b无关。常用的刻画模型复杂度的函数R(w)有两种,L1正则
和L2正则
L1正则化会让参数变得更稀疏,而L2正则不会。其次,L1正则的计算公式不可导,L2正则可导。因为优化时需要计算损失函数的偏导数,所以对L2正则损失函数的优化要更加简洁。优化L1正则更加复杂,而且优化方法也有很多种。也可以将L1和L2一起使用
tf实现带L2正则的损失函数定义
3滑动平均模型
滑动平均模型是可以让模型在测试数据上更鲁棒的方法。tf提供了tf.train.ExponentialMovingAverage来实现滑动平均模型。初始化ExponentialMovingAverage时,需要提供一个衰减率(decay)。ExponentialMovingAverage对每一个变量都会维护一个影子变量(shadow variable),影子变量的初始值就是相应变量的值,而每次运行变量更新时,影子变量的值都会更新为:
decay决定了模型更新的速度,decay越大模型越趋于稳定。实际应用中,decay一般设成非常接近1的数(比如0.999或0.9999)。为了模型在训练前期可以更新的更快,ExponentialMovingAverage还提供了num_updates来动态设置decay的大小:
第五章MNIST数字识别问题
Tensorflow模型持久化
持久化即保存训练好的模型,并可以从文件中还原
加载模型并直接得到结果:
持久化原理及数据格式
实例2 MNIST数字识别
本章前面已经给出了一个完整的tf程序解决MNIST问题,然而这个程序的可扩展性并不好。比如,前向传播需要传入所有变量,可读性很差;没有持久化训练好的模型,且需要每隔一段时间保存一次模型训练的中间结果(防止程序退出导致结果丢失)。
结合前面介绍的变量管理和持久化机制,本节介绍一个tf训练神经网络模型的最佳实践。将训练和测试分为两个独立的程序,每一个组件更加灵活。训练神经网络的程序可以持续输出训练好的模型,而测试程序可以每隔一段时间检验最新模型的正确率。将前向传播的过程抽离成一个单独的库函数,方便且保持训练和测试使用的前向传播方法是一致的。
重构之后的代码分为三个程序,mnist_inference.py定义了前向传播的过程以及神经网络中的参数。mnist_train.py定义了神经网络的训练过程。mnist_eval.py定义了测试过程。
mnist_inference.py
mnist_train.py
运行程序得到结果:
新的训练代码中,不再将训练和测试跑在一起。训练过程中,没1000轮输出一次损失函数的大小评估训练的效果。每1000轮保存一次训练好的模型,这样可以通过一个单独的测试程序,更加方便的在滑动平均模型上做测试。
mnist_eval.py
测试程序每10秒运行一次,每次运行都是读取最新保存的模型,并在验证集上计算正确率。运行程序得到结果如下,注意因为训练程序不一定每10秒输出一个新模型,所以有些模型可能被测试多次。一般解决真实问题时,不会这么频繁地运行评测程序。
第六章 图像识别与卷积神经网络
卷积神经网络(CNN)的应用非常广泛,在自然语言处理、医药发现、灾难气候发现甚至围棋人工智能程序中都有应用。本章主要通过卷积神经网络在图像识别上的应用讲解卷积神经网络的基本原理以及如何使用Tensorflow实现。内容包括图像识别领域解决的问题以及经典数据集、卷积神经网络的主体架构、tf实现两个经典的CNN模型以及实现CNN的迁移学习。
卷积神经网络架构图:
一个卷积神经网络主要由以下5中结构组成:
输入层:在处理图像的CNN中,它一般代表了一张图片的像素矩阵,比如32323。从输入层开始,CNN通过不同的神经网络结构将上一层的三维矩阵转化为下一层的三维矩阵,直到最后的全连接层。
卷积层:卷积层中每一个节点的输入只是上一层神经网络的一小块,这小块常用的大小是33,55等。CNN将每一小块进行深入地分析从而得到抽象程度更高的特征。一般来说,通过卷积层处理过的节点矩阵会变得更深。
池化层:池化层不会改变三维矩阵的额深度,但是可以缩小矩阵的大小。可以认为是将一张高分辨率图片转化为分辨率较低的图片。可以进一步减少参数的数量。
全连接层:经过几轮卷积层和池化层的处理之后,可以认为图像中的信息已经被抽象成了信息含量更高的特征。在特征提取之后,仍然需要全连接层来完成分类任务。
Softmax层:用于得到不同种类的概率分布。
卷积层
过滤器可以将当前层神经网络上的一个子节点矩阵转化为下一层神经网络上的一个单位节点矩阵。单位节点矩阵指的是一个长和宽都是1,深度不限的节点矩阵。
卷积层结构的前向传播过程就是通过一个过滤器从神经网络当前层的左上角移动到右下角,并且在移动中计算每一个对应的单位矩阵得到的。
左上角的格子计算过程为:
池化层
和卷积层类似,池化层前向传播的过程也是通过移动一个类似过滤器的结构完成的。过滤器中的计算不是节点的加权和,而是最大值或者平均值运算,分别称为 max pooling和average pooling。同时,池化层的过滤器也需要人工设定过滤器的尺寸、padding方式以及步长等,且这些设置的意义相同。和卷积层移动方式不同的是,池化层的过滤器只影响一个深度上的节点,所以除了在长和宽方向上移动,还需要在深度这个方向上移动。如图所示:
Inception-v3模型:前面提到了一个卷积层可以使用边长为1、3或5的过滤器,如何在这些边长中选呢。Inception同时使用所有不同尺寸的过滤器,然后将得到的输出矩阵拼接起来。
迁移学习:可以保留训练好的Inception-v3模型中所有卷积层的参数,只是替换最后一层全连接层。最后这一层全连接层之前的网络层称之为瓶颈层(bottleneck)。有理由认为瓶颈层输出的节点向量可以被作为任何图像的一个更加精简且表达能力更强的特征向量。于是,在新数据集上,可以直接利用这个训练好的模型进行特征提取,再将这个特征向量作为输入来训练一个新的单层全连接神经网络处理新的分类问题。
实例3迁移学习实现
首先下载数据集
解压之后的文件夹包含5个子文件夹,每个子文件夹的名称为一种花的名称。
下载Google提供的Inception-v3模型
运行之后的结果:
实例整理:OpenCV 人脸识别 C++实例代码
https://www.cnblogs.com/mahatmasmile/p/5556314.html
https://blog.csdn.net/liuph_/article/details/51941705
实例整理:机器人随着人脸转动案例
https://blog.csdn.net/yangtze_1006/article/details/51606603
roslaunch carebot_bringup carebot_bringup.launch
roslaunch astra_launch astra.launch
roslaunch rbx1_vision my_face_tracker2.launch
roslaunch rbx1_apps my_object_tracker2.launch
face_tracker2.launch object_tracker2.launch 如果没找到节点信息,需要改一下节点名称