黑马程序员3天带你玩转Python深度学习TensorFlow框架学习笔记

文章目录

这是黑马程序员3天带你玩转Python深度学习TensorFlow框架学习笔记

视频链接:黑马程序员3天带你玩转Python深度学习TensorFlow框架

1、深度学习的介绍

1.1、深度学习与机器学习的区别

学习目标:知道深度学习与机器学习的区别
区别:深度学习没有特征提取
在这里插入图片描述

特征方面

  1. 机器学习的特征工程步骤是要靠手动完成的,而且需要大量领域专业知识
  2. 深度学习通常由多个层组成,它们通常将更简单的模型组合在一起,将数据从一层传递到另一层来构建更复杂的模型。通过训练大量数据自动得到模型,不需要人工特征提取环节

深度学习算法试图从数据中学习高级功能,这是深度学习的一个非常独特的部分。因此,减少了为每个问题开发新特征提取器的任务。适合用在难提取特征的图像、语音、自然语言处理领域

数据量和计算性能要求

机器学习需要的执行时间远少于深度学习,深度学习参数往往很庞大,需要通过大量数据的多次优化来训练参数

在这里插入图片描述

  1. 深度学习需要大量的训练数据集
  2. 训练深度神经网络需要大量的算力
  3. 可能要花费数天、甚至数周的时间,才能使用数百万张图像的数据集训练出一个深度网络。所以深度学习通常需要强大的GPU服务器来进行计算

算法代表

  1. 机器学习:朴素贝叶斯,决策树
  2. 深度学习:神经网络

1.2、深度学习的应用场景

  1. 图像识别:物体识别、场景识别、车型识别、人脸检测跟踪、人脸关键点定位、人脸身份认证
  2. 自然语言处理技术:机器翻译、文本识别、聊天对话
  3. 语音技术:语音识别

1.3、深度学习框架介绍

常见深度学习框架对比
在这里插入图片描述

  1. 最常用的框架当数TensorFlow和Pytorch,而 Caffe和Caffe2次之。
  2. PyTorch和 Torch更适用于学术研究(research) ; TensorFlow,Caffe,Caffe2更适用于工业界的生产环境部署(industrial production)
  3. Caffe适用于处理静态图像(static graph) ; Torch和PyTorch更适用于动态图像(dynamic graph) ; TensorFlow在两种情况下都很实用。
  4. Tensorflow和Caffe2可在移动端使用。

Tensorflow的安装

官网:https://www.tensorflow.org/

CPU版本
2 GPU版本:核芯数量多,更适合处理并行任务

pip install tensorflow==1.8 -i https://pypi.douban.com/simple

#对于 1.15 及更早版本,CPU 和 GPU 软件包是分开的:
pip install tensorflow==1.15      # CPU
pip install tensorflow-gpu==1.15  # GPU

CPU:核芯的数量少;
每一个核芯的速度更快,性能更强;更适用于处理连续性(sequential)任务。

GPU:核芯的数量多;
但是每一个核芯的处理速度较慢;更适用于并行(parallel)任务。

Tensorflow特点

  • 高度灵活(Deep Flexibility)
    • 它不仅可以用来做神经网络算法研究,也可以用来做普通的机器学习算法,甚至是只要把计算表示成数据流图,都可以用TensorFlow。
  • 语言多样(Language Options)
    • TensorFlow使用C++实现的,然后用Python封装。谷歌号召社区通过SwIG开发更多的语言接口来支持TensorFlow。
  • 设备支持
    • TensorFlow可以运行在各种硬件上,同时根据计算的需要,合理将运算分配到相应的设备,比如卷积就分配到GPU上,也允许在CPU和GPU上的计算分布,甚至支持使用gRPC进行水平扩展。
  • Tensorboard可视化
    • TensorBoard是TensorFlow的一组Web应用,用来监控TensorFlow运行过程,或可视化Computation Graph。TensorBoard目前支持5种可视化:标量(scalars) 、图片(images) 、音频(audio) 、直方图(histograms)和计算图(Computation Graph)。TensorBoard的Events Dashboard可以用来持续地监控运行时的关键指标,比如loss、学习速率(learning rate)或是验证集上的准确率(accuracy)

2、TensorFlow

2.1、初始TensorFlow

官网:https://www.tensorflow.org/

TensorFlow程序通常被组织成一个构件图阶段和一个执行图阶段。

  1. 在构建图阶段,数据与操作的执行步骤被描述为一个图
  2. 在执行图阶段,使用会话(调用系统资源)执行构建好的图中的操作
  • 图:这是TensorFlow将计算表示为指令之间的依赖关系的一种表示法,(数据+操作)
  • 会话:TensorFlow跨一个或多个本地或远程设备运行数据流图的机制
  • 张量(数据):TensorFlow中的基本数据对象
  • 节点(操作):提供图当中执行的操作W
import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 去警告

def tensorflow_demo1():
   """
   tensoflow的基本结构
   """
   # python版本
   a=2
   b=3
   c=a+b
   print('python版本的加法操作:\n',c)

   # tensorflow实现加法操作
   a_t=tf.constant(2) # 定义常量
   b_t=tf.constant(3)
   c_t=a_t+b_t
   print('tensorflow版本的加法操作:\n',c_t)

   # 开启会话
   with tf.Session() as sess:
      c_t_value=sess.run(c_t)
      print('开启会话的结果\n',c_t_value)


if __name__ == '__main__':
   tensorflow_demo1()
'''
python版本的加法操作:
 5
tensorflow版本的加法操作:
 Tensor("add:0", shape=(), dtype=int32)
开启会话的结果
 5
'''    

2.2、图

图包含了一组tf.Operation代表的计算单元对象和tf.Tensor代表的计算单元之间流动的数据

一个图一个命名空间,互不干扰影响

  1. 默认图
  2. 自定义图

通常tensorflow会默认帮我们创建一张图

查看默认图的两种方法:

  • 通过调用**tf.get_default_graph()**访问
  • 通过graph属性访问
def graph_demo():
   # tensorflow实现加法操作
   a_t = tf.constant(2)  # 定义常量
   b_t = tf.constant(3)
   c_t = a_t + b_t
   #查看默认图
   #方法1:调用方法
   defalut_g=tf.get_default_graph()
   print('默认图:',defalut_g)
   #方法2:调用属性
   print('a_t的图属性: ',a_t.graph)
   print('c_t的图属性: ',c_t.graph)
   # 开启会话
   with tf.Session() as sess:
      c_t_value = sess.run(c_t)
      print('sess的图属性:',sess.graph)
if __name__ == '__main__':
   graph_demo()
'''
默认图: <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
a_t的图属性:  <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
c_t的图属性:  <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
sess的图属性: <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
'''    

自定义图

  1. 通过tf.Graph() 自定义图
  2. 通过tf.Graph.as_default() 图上下文管理器 去定义张量和节点,图上下文管理器会自动将张量和节点绑定在图中
  3. 开启会话,需要传入自定义图
def create_graph():
   # 自定义图
   new_graph=tf.Graph()
   # 图上下文管理器定义数据和操作
   with new_graph.as_default():
      a_new = tf.constant(20)
      b_new = tf.constant(30)
      c_new = a_new + b_new
      print("c_new:", c_new)
      print("a_new的图属性:", a_new.graph)
      print("c_new的图属性:", c_new.graph)
   #开启会话,执行图,注意这里需要传入自定义图对象graph
   with tf.Session(graph = new_graph) as sess:
      c_new_value=sess.run(c_new)
      print('自定义图的运算结果:',c_new_value)
      print('sess的图属性:',sess.graph)


if __name__ == '__main__':
   create_graph()
'''
c_new: Tensor("add:0", shape=(), dtype=int32)
a_new的图属性: <tensorflow.python.framework.ops.Graph object at 0x000001D3439BF278>
c_new的图属性: <tensorflow.python.framework.ops.Graph object at 0x000001D3439BF278>
自定义图的运算结果: 50
sess的图属性: <tensorflow.python.framework.ops.Graph object at 0x000001D3439BF278>
'''

TensorBoard可视化工具

tensorflow可用于训练大规模深度神经网络所需的计算,使用该工具设计的计算往往复杂而深奥。为了更方便tensorflow程序的理解、调试与优化,tensorflow提供了TensorBoard可视化工具

实现程序可视化过程:

  1. 将图进行数据序列化,为events文件
  2. 打开终端,启动tensorBoard

1、将图进行数据序列化,为events文件

TensorBoard通过读取TensorFlow的事件文件来运行,故需要将图序列化为Summary对象

tf.summary.FileWriter(path, graph=sess.graph)

2、打开终端,启动tensorBoard

tensorboard --logdir=path

def graph_demo():
	# tensorflow实现加法操作
	a_t = tf.constant(2)  # 定义常量
	b_t = tf.constant(3)
	c_t = a_t + b_t
    # 开启会话
	with tf.Session() as sess:
		c_t_value = sess.run(c_t)
		print('sess的图属性:',sess.graph)

	# sess图序列化为summary对象
	# 参数一:输出sumary对象的路径,参数二:需要进行序列化的图
	tf.summary.FileWriter('./temp/summary',graph = sess.graph)
    
if __name__ == '__main__':
    graph_demo()

在这里插入图片描述

在终端输入,注意路径

tensorboard --logdir=‘./machine_learning/temp/summary’

在这里插入图片描述

点击http://MSI:6006 跳到tensorBoard页面

在这里插入图片描述

OP 操作对象 operation

类型 实例
标量运算 add,sub, mul, div,exp, log, greater, less,equal
向量运算 concat,slice,splot, constant,rank,shape, shuffle
矩阵运算 matmul, matrixinverse,matrixdateminant
带状态的运算 Variable, assgin, assginadd
神经网络组件 softmax,sigmoid,relu,convolution,max_pool
存储,恢复 Save,Restroe
队列及同步运算 Enqueue,Dequeue,MutexAcquire,MutexRelease
控制流 Merge,Switch, Enter,Leave,Nextlteration
操作函数 操作对象
tf.constant(Tensor对象) 输入Tensor对象-Const输出 Tensor对象
tf.add(Tensor对象1,Tensor对象2) 输入(Tensor对象1,Tensor对象2) ,add对象,输出 Tensor对象3

一个b操作对象(Operation)是TensorFlow图中的一个节点,可以接收0个或者多个输入Tensor对象,并且可以输出0个或者多个Tensor,Operation对象是通过op构造函数(如tf.matmul())创建的。

例如: c = tf.matmul(a, b)创建了一个Operation对象,类型为 MatMul类型,它将张量a, b作为输入,c作为输出,,并且输出数据,打印的时候也是打印的数据。其中tf.matmul)是函数,在执行matmul函数的过程中会通过MatMul类创建—个与之对应的对象

注意,打印出来的是张量值,可以理解成OP当中包含了这个值。并且每一个OP指令都对应一个唯一的名称,如上面的Const:0,这个在TensorBoard上面也可以显示

请注意,tf.Tensor对象以输出该张量的tf.Operation明确命名。张量名称的形式为“<OP_NAME>:< i >",其中:
. "<OP_NAME>"是生成该张量的指令的名称
. "< i >"是一个整数,它表示该张量在指令的输出中的索引

指令名称

一张图有对应自己的命名空间

tf.Graph对象为其包含的 tf.Operation对象定义的一个命名空间。TensorFlow 会自动为图中的每个指令选择一个唯一名称,用户也可以指定描述性名称,使程序阅读起来更轻松。我们可以以以下方式改写指令名称

  • 每个创建新的tf.Operation或返回新的tf.Tensor的 API函数可以接受可选的name参数。

例如,tf.constant(42.0, name=“answer”)创建了一个名为“answer"的新tf.Operation并返回一个名为“answer:0”的tf.Tensor。如果默认图已包含名为"answer"的指令,则TensorFlow 会在名称上附加“1"、“2”等字符,以便让名称具有唯一性。

  • 当修改好之后,我们在Tensorboard显示的名字也会被修改

2.3、会话

会话创建

  • **tf.Session:**用于完整的程序当中
  • tf.InteractiveSession:用于交互式上下文中的TensorFlow,例如shell

1 TensorFlow使用tf.Session类来表示客户端程序(通常为Python程序,但也提供了使用其他语言的类似接口)与C++运行时之间的连接

2 tf.Session对象使用分布式TensorFlow运行时提供对本地计算机中的设备和远程设备的访问权限。

快速查看张量的值,在会话中调用 对象.eval() 查看

在这里插入图片描述

会话上下文管理器

会话可能拥有的资源,如tf.Variable,tf.QueueBase和tf.ReaderBase。当这些资源不再需要时,释放这些资源非常重要。因此,需要调用tf.Session.close会话中的方法,或将会话用作上下文管理器。

tf.Session(target=‘’,graph=None,config=None)

  1. target:如果将此参数留空(默认设置),会话将仅使用本地计算机中的设备。可以指定grpc://网址,以便指定TensorFlow服务器的地址,这使得会话可以访问该服务器控制的计算机上的所有设备
  2. graph:默认情况下,新的tf.Session将绑定到当前的默认图
  3. config:此参数允许您指定一个tf.ConfigProto以便控制会话的行为。例如,ConfigProto协议用于打印设备使用信息
# 开启会话上下文管理器(推荐)
with tf.Session() as sess:
	sess.run(sth)

# 传统的会话定义
sess=tf.Session()
sum_t=sess.run(c_t)
sess.close()

# 运行会话并打印设备信息
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True))

会话run()

run(fetches, feed_dict=None, options=None, run_metadata=None)

  • 通过使用sess.run()来运行operation
  • fetches:传入单一的operation,或者列表、元组(属于tensorflow的类型)
  • feed_dict:参数运行调用者覆盖图中张量的值,运行时赋值,与**tf.placeholder()**占位符搭配使用,则会检查值的形式是否与占位符兼容

注: 使用tf.operation.eval()也可以运行operation,但需要在会话中运行

# 创建图
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a + b

# 创建会话
sess = tf.Session()

# 计算C的值
print(sess.run(c))
print(c.eval(session=sess))

feed_dict()操作

请注意运行时候报的错误error:

RuntimeError:如果这Session是无效状态(例如已关闭)。

TypeError:如果fetches或者feed_dict键的类型不合适。

valueError:如果fetches或feed_dict键无效或引用Tensor不存在的键。

  • placeholder提供占位符,run时候通过feed_dict传参
def feed_dict_demo():
	# 当不确定值的时候,通过placeholder占位符解决
	a=tf.placeholder(tf.float32)
	b=tf.placeholder(tf.float32)
	c=tf.add(a,b)

	#开启会话,打印设备
	with tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)) as sess:
		c_value=sess.run([a,b,c],feed_dict={
    
    a:3.2,b:2.3})
		print('c_value: ',c_value)

if __name__ == '__main__':
	feed_dict_demo()
'''
Device mapping: no known devices.
Add: (Add): /job:localhost/replica:0/task:0/device:CPU:0
Placeholder_1: (Placeholder): /job:localhost/replica:0/task:0/device:CPU:0
Placeholder: (Placeholder): /job:localhost/replica:0/task:0/device:CPU:0
c_value:  [array(3.2, dtype=float32), array(2.3, dtype=float32), 5.5]
'''

2.4、张量

2.4.1、定义

TensorFlow的张量就是一个N维数组,类型为tf.Tensor。

标量:一个数字----0阶张量

向量:一维数组-----1阶张量

矩阵:二维数组------2阶张量

3阶张量

  • type:数据类型
  • 未指定类型时,默认类型:
    • 整型:tf.int32
    • 浮点型:tf.float32
  • shape:形状(阶)

张量的类型

数据类型 Python类型 描述
DT_FLOAT tf.float32 32位浮点数.
DT_DOUBLE tf.float64 64位浮点数.
DT_INT64 tf. int64 64位有符号整型.
DT_INT32 tf. int32 32位有符号整型.
DT_INT16 tf.int16 16位有符号整型.
DT_INT8 tf.int8 8位有符号整型.
DT_UINT8 tf.uint8 8位无符号整型.
DT_STRING tf.string 可变长度的字节数组.每一个张量元素都是一个字节数组.
DT_BOOL tf.bool 布尔型.
DT_COMPLEX64 tf.complex64 由两个32位浮点数组成的复数:实数和虚数.
DT_QINT32 tf.qint32 用于量化Ops的32位有符号整型.
DT_QINT8 tf.qint8 用于量化Ops的8位有符号整型.
DT_QUINT8 tf.quint8 用于最化Ops的8位无符号整型

张量的阶

数学实例 Python 例子
0 表量 (只有大小) s = 483
1 向量 (大小和方向) v = [1.1,2.2,3.3]
2 矩阵 (数据表) m = [[1,2,3],[4,5.6],[7,8,9]]
3 3阶张量 (数据立体) t = [[[2],[4],[6]],[[8],[10],[12]],[[14],[16],[18]]]
n n阶 (自己想想看)
def tensor_demo():
    """
    张量的演示
    """
    tensor1 = tf.constant(4.0)
    tensor2 = tf.constant([1,2,3,4])  # 未指定类型,默认类型
    linear_squares = tf.constant([[4],[9],[16],[25]],dtype=tf.int32)
    print("tensor1:", tensor1)
    print("tensor2:", tensor2)
    print("linear_square:", linear_squares)
    return None


if __name__ == "__main__":
    tensor_demo()
'''
tensor1: Tensor("Const:0", shape=(), dtype=float32)
tensor2: Tensor("Const_1:0", shape=(4,), dtype=int32)
linear_square: Tensor("Const_2:0", shape=(4, 1), dtype=int32)
'''

2.4.2、创建张量

创建固定值张量

tf.zeros(shape, dtype=tf.float32,name=None)

创建所有元素设置为零的张量。此操作返回一个dtype具有形状shape和所有元素设置为零的类型的张量。

tf.zeros_like(tensor,dtype=None, name=None)

给tensor定单张量(),此操作返回tensor与所有元素设置为零相同的类型和形状的张量。

tf.ones(shape, dtype=tf.float32, name=None)

创建一个所有元素设置为1的张量。此操作返回一个类型的张量,dtype形状shape和所有元素设置为1。

tf.ones_like(tensor, dtype=None, name=None)

给tensor定单张量(),此操作返回tensor与所有元素设置为1相同的类型和形状的张量。

tf.fill(dims, value, name=None)

创建一个填充了标量值的张量。此操作创建一个张量的形状dims并填充它value.

tf.constant(value, dtype=None,shape=None, name=‘Const’"

创建一个常数张量。

创建随机张量

一般我们经常使用的随机数函数Math.randoml()产生的是服从均匀分布的随机数,能够模拟等概率出现的情况,例如扔一个骰子,1到6点的概率应该相等,但现实生活中更多的随机现象是符合正态分布的,例如20岁成年人的体重分布等。

假如我们在制作一个游戏,要随机设定许许多多NPC的身高,如果还用Math.random),生成从140到220之间的数字,就会发现每个身高段的人数是一样多的,这是比较无趣的,这样的世界也与我们习惯不同,现实应该是特别高和特别矮的都很少,处于中间的人数最多,这就要求随机函数符合正态分布。

tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32,seed=None,name=None)

从截断的正态分布中输出随机值,和 tf.random_normal(0一样,但是所有数字都不超过两个标准差

tf.random_normal(shape, mean=0.0,stddev=1.0, dtype=tf.float32, seed=None, name=None)

从正态分布中输出随机值,由随机正态分布的数字组成的矩阵

其它特殊的创建张量的OP

  • tf.Variable

  • tf.placeholder

在这里插入图片描述

2.4.3、张量的变换

1 类型改变

  • tf.string_to_number(string_tensor, out_type=None, name=None)
  • tf.to_double(x, name=‘ToDouble’)
  • tf.to_float(x, name=‘ToFloat’)
  • tf.to_bfloat16(x, name=“ToBFloat16”)
  • tf.to_int32(x, name=‘Tolnt32’)
  • tf.to_int64(x, name=‘Tolnt64’)
  • tf.cast(x, dtype, name=None),通用类型转换
def cast_demo():
   a=tf.constant(4.0)
   b=tf.cast(a,dtype = tf.float64)
   print(a)
   print(b)

if __name__ == '__main__':
   cast_demo()
'''
Tensor("Const:0", shape=(), dtype=float32)
Tensor("Cast:0", shape=(), dtype=float64)
'''

2 形状改变
tensorflow的张量具有两种形状变换,动态形状静态形状

  1. tf.reshape(tensor,shape):动态创建新张量,当原形状固定的时候,动态改变张量的时候,张量的元素个数必须一致。如shape(2,3) 元素个数为6,则动态改变张量的时候,也要确保元素的个数为6
  2. tensor.set_shape(shape):改变静态形状

静态形状:初始创建张量时的形状

什么情况下可以改变静态形状:

只有在形状还没有完全固定下来的情况下,如shape(?,?);转换形状的时候,只能一维到一维,二维到二维,而不能跨维度改变形状,如 shape=[None, 10],前面无所谓变化,但后面一个必须要10

def shape_demo():
   a = tf.constant(4.0)
   b = tf.placeholder(dtype=tf.float32, shape=[None, 10])
   print('a:',a)
   print('b:',b)

   b.set_shape((2,10))
   print('修改b静态形状',b)
   c_dynamic=tf.reshape(b,shape = (10,2))
   # c_dynamic=tf.reshape(b,shape = (10,10)) 报错
   print('修改b动态形状',c_dynamic)

if __name__ == '__main__':
   shape_demo()
'''
a: Tensor("Const:0", shape=(), dtype=float32)
b: Tensor("Placeholder:0", shape=(?, 10), dtype=float32)
修改b静态形状 Tensor("Placeholder:0", shape=(2, 10), dtype=float32)
修改b动态形状 Tensor("Reshape:0", shape=(10, 2), dtype=float32)
'''

张量的数学运算,自己去查api

  • 算术运算符(如tf.add())
  • 基本数学函数
  • 矩阵运算(如tf.matmul())
  • reduce操作(如tf.reduce_sum()、tf.reduce_mean()
  • 序列索引操作

2.5、变量OP

TensorFlow变量是表示程序处理的共享持久状态的最佳方法。变量通过tf.Variable类进行操作。

变量的特点:

  • 存储持久化,如变量存储模型参数
  • 可修改值
  • 可指定被训练

2.5.1 创建变量

tf.Variable(initia_value=None, trainable=True, collections=None, name=None)

  1. initial_value:初始化的值
  2. trainable:是否被训练
  3. collections:新变量将添加到列出的图的集合中collections,默认为[GraphKeys.GLOBAL_VARIABLES],如果trainable是True变量也被添加到图形集合GraphKeys.TRAINABLE_VARIABLES

注意:创建完变量后,需要进行变量初始化,且运行该初始化后,才能使用变量

init = tf.global_variables_initializer()

sess.run(init)

def variable_demo():
	#创建变量
	a=tf.Variable(initial_value = 30)
	b=tf.Variable(initial_value = 50)
	c=tf.add(a,b)
	print('a:',a)
	print('b:',b)
	print('c:',c)
	# 变量初始化
	init=tf.global_variables_initializer()

	#开启会话
	with tf.Session() as sess:
		sess.run(init) # 运行初始化
		a_value,b_value,c_value=sess.run([a,b,c])
		print('a_value,',a_value)
		print('b_value,',b_value)
		print('c_value,',c_value)

if __name__ == '__main__':
	variable_demo()
'''
a: <tf.Variable 'Variable:0' shape=() dtype=int32_ref>
b: <tf.Variable 'Variable_1:0' shape=() dtype=int32_ref>
c: Tensor("Add:0", shape=(), dtype=int32)
a_value, 30
b_value, 50
c_value, 80
'''

2.5.2、修改变量的命名空间

tf.variable_scope()

  1. 会在OP变量的名字前面添加新的命名空间名
  2. 命名空间会使图的结构更加清晰
def scope_demo():
   with tf.variable_scope('myscore'):
      a = tf.Variable(initial_value = 30)
      b = tf.Variable(initial_value = 50)
   with tf.variable_scope('yourscore'):
      c = tf.add(a, b)
   print('a:', a)
   print('b:', b)
   print('c:', c)

if __name__ == '__main__':
   scope_demo()
'''
a: <tf.Variable 'myscore/Variable:0' shape=() dtype=int32_ref>
b: <tf.Variable 'myscore/Variable_1:0' shape=() dtype=int32_ref>
c: Tensor("yourscore/Add:0", shape=(), dtype=int32)
'''

2.6、高级API

2.6.1、其他基础API

1、tf.app
这个模块相当于为TensorFlow进行的脚本提供一个main函数入口,可以定义脚本运行的flags

2、tf.image
TensorFlow的图像处理操作。主要是一些颜色变换、变形和图像的编码和解码

3、tf.gfile
这个模块提供了一组文件操作函数

4、tf.summary
用来生成TensorBoard可用的统计日志,目前Summary主要提供了4种类型:
audio、image、histogram、scalar

5、tf.python_io
用来读写TFRecords文件

6、tf.train
这个模块提供了一些训练器,与tf.nn结合起来,实现一些网络的优化计算

7、tf.nn
这个模块提供了一些构建神经网络的底层函数。TensorFlow构建网络的核心模块,其中包含了添加各种层的函数,比如添加卷积层、池化层等。

2.6.2、高级API

1、tf.keras
Kears本来是一个独立的深度学习库,tensorflow将其学习过来,增加这部分模块在于快速构建模型

2、tf.layers
高级API,以便高级的概念层来定义一个模型。类似tf.kears

3、tf.contrib
tf.contrib.layers提供够将计算图中的网络层、正则化、摘要操作,是构建计算图的高级操作,但是tf.contrib包含不稳定和实验代码,有可能以后API会改变

4、tf.estimator
一个estimator相当于model + training + evaluate 的合体。在模块中,已经实现了几种简单的分类器和回归其,包括:Baseline,learning 和 DNN。这里的DNN的网络,只是全连接网络,没有提供卷积之类的

关于tensorflow的API展示

在这里插入图片描述

2.7、案例:实现线性回归

回顾:根据数据建立回归模型,w1x1+w2x2+…+b = y,通过真实值与预测值之间建立误差,使用梯度下降优化得到损失最小对应的权重和偏置。最终确定模型的权重和偏置参数。最后可以用这些参数进行预测。

  1. 构建线性回归模型
  2. 构造损失函数(均方误差)
  3. 优化损失(梯度下降)

使用到的API

运算:

  • 矩阵运算:tf.matmul(x,w)
  • 平方:tf.square(error)
  • 均方:tf.reduce_mean(error)

梯度下降优化:

tf.train.GradientDescentOptimizer(learning_rate)

  • 梯度下降优化

  • learning_rate:学习率,一般为0~1之间比较小的值

  • method:

    • minimize(loss) 最小化
  • return:梯度下降op

分析

1)准备真实数据:

tf.random_normal()

x:特征值,形状:(100,1),随机指定100个点,只有一个特征值
y_true:目标值,形状:(100,1)
y_true = 0.8x + 0.7 ,100个样本
即假设x和y之间的关系满足: y =kx + b, 最后求出k≈0.8,b=0.7 为正确的答案

即y_predict=x*weights+bias

2)构建模型

y_predict = tf.matmul(x, weights) + bias

3)构造损失函数(均方误差)

error = tf.reduce_mean(tf.square(y_predict - y_true))

4)优化损失:梯度下降优化器

optimizer = tf.train.GrandientDescentOptimizer(learning_rate=0.01).minimize(error)

def linear_regression():
	# 1、准备数据
	X=tf.random_normal(shape=[100,1]) # 特征值 100行1列
	y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

	# 2、构建模型
	# 采用变量定义模型参数
	weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 权重
	bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 偏置
	y_predict=tf.matmul(X,weigths)+bias # 预测值

	# 3、构建损失函数(均方误差)
	error=tf.reduce_mean(tf.square(y_predict-y_true))

	# 4、优化损失函数
	optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

	# 初始化变量
	init=tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		sess.run(init) # 运行初始化
		# 查看没有训练之前,初始化模型参数值
		print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

		# 开始训练模型,迭代100次
		for i in range(100):
			sess.run(optimizer)
			print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))


if __name__ == '__main__':
	linear_regression()
'''
训练前模型参数为:权重-2.152965, 偏置-1.636178, 损失值14.106889 
第1次训练前模型参数为:权重-2.086562, 偏置-1.589710, 损失值15.449847 
第2次训练前模型参数为:权重-2.022885, 偏置-1.536769, 损失值12.712150 
第3次训练前模型参数为:权重-1.953819, 偏置-1.488234, 损失值11.221785 
.....
第98次训练前模型参数为:权重0.379509, 偏置0.383643, 损失值0.302479 
第99次训练前模型参数为:权重0.386806, 偏置0.389533, 损失值0.247333 
第100次训练前模型参数为:权重0.396212, 偏置0.395469, 损失值0.296869 
'''

学习率的设置、步数的设置与梯度爆炸

学习率越大,训练到较好结果的步数越小;学习率越小,训练到较好结果的步数越大。

但是学习过大会出现梯度爆炸现象。

  1. 在极情况下,权重的值变得非常大,以至于溢出,导致 NaN值
  2. 如当线性回归的学习率设置为100时候,迭代100次的时候就出现权重和偏置为NaN

如何解决梯度爆炸问题(深度神经网络当中更容易出现)

  1. 重新设计网络
  2. 调整学习率
  3. 使用梯度截断(在训练过程中检查和限制梯度的大小)
  4. 使用激活函数

2.8、其他功能

2.8.1、增加变量显示

目的:在TensorBoard当中观察模型的参数、损失值等变量值的变化

1、收集变量

  • tf.summary.scalar(name=",tensor) 收集对于损失函数和准确率等单值变量,name为收集变量的名字,tensor为对象
  • tf.summary.histogram(name=‘’,tensor) 收集高维度的变量参数
  • tf.summary.image(name=",tensor) 收集输入的图片张量能显示图片

2、合并变量写入事件文件

  • 创建事件文件 tf.summary.FileWriter('path, graph=sess.graph)

  • merged = tf.summary.merge_all() 合并变量

  • 运行合并: summary = sess.run(merged),每次迭代都需运行

  • 添加:FileWriter.add_summary(summary,i),i表示第几次的值

  1. 创建事件文件
  2. 收集变量
  3. 合并变量
  4. 运行合并变量
  5. 将迭代后的变量写入到事件文件中
def linear_regression():
	# 1、准备数据
	X=tf.random_normal(shape=[100,1]) # 特征值 100行1列
	y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

	# 2、构建模型
	# 采用变量定义模型参数
	weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 权重
	bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 偏置
	y_predict=tf.matmul(X,weigths)+bias # 预测值

	# 3、构建损失函数(均方误差)
	error=tf.reduce_mean(tf.square(y_predict-y_true))

	# 4、优化损失函数
	optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

	# 初始化变量
	init=tf.global_variables_initializer()

	# 收集变量
	tf.summary.scalar('error',error)
	tf.summary.histogram('weights',weigths)
	tf.summary.histogram('bias',bias)

	# 合并变量
	merged=tf.summary.merge_all()

	# 开启会话
	with tf.Session() as sess:
		sess.run(init) # 运行初始化
		# 查看没有训练之前,初始化模型参数值
		print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

		# 创建事件文件
		file_writer=tf.summary.FileWriter('./temp/linear/',graph = sess.graph)
		# 运行合并变量操作
		summary=sess.run(merged)

		# 开始训练模型,迭代100次
		for i in range(100):
			sess.run(optimizer)
			print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))

			# 将每次迭代后的合并变量写入到事件文件中
			file_writer.add_summary(summary,i)

if __name__ == '__main__':
	linear_regression()

在Terminal输入 tensorboard --logdir=‘./temp/linear’
在这里插入图片描述

在这里插入图片描述

2.8.2、增加命名空间

tf.variable_scope(name=‘’)

使得代码结构更加信息,TensorBoard图结构更加清楚

def linear_regression():
   # 1、准备数据
   with tf.variable_scope('prepare_data'):
      X=tf.random_normal(shape=[100,1],name='feature') # 特征值 100行1列
      y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

   # 2、构建模型
   # 采用变量定义模型参数
   with tf.variable_scope('create_model'):
      weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name = 'Weights') # 权重
      bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name='Bias') # 偏置
      y_predict=tf.matmul(X,weigths)+bias # 预测值

   # 3、构建损失函数(均方误差)
   with tf.variable_scope('loss_function'):
      error=tf.reduce_mean(tf.square(y_predict-y_true))

   # 4、优化损失函数
   with tf.variable_scope('optimizer'):
      optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

   # 初始化变量
   init=tf.global_variables_initializer()

   # 收集变量
   tf.summary.scalar('error',error)
   tf.summary.histogram('weights',weigths)
   tf.summary.histogram('bias',bias)

   # 合并变量
   merged=tf.summary.merge_all()

   # 开启会话
   with tf.Session() as sess:
      sess.run(init) # 运行初始化
      # 查看没有训练之前,初始化模型参数值
      print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

      # 创建事件文件
      file_writer=tf.summary.FileWriter('./temp/linear/',graph = sess.graph)
      # 运行合并变量操作
      summary=sess.run(merged)

      # 开始训练模型,迭代100次
      for i in range(100):
         sess.run(optimizer)
         print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))

         # 将每次迭代后的合并变量写入到事件文件中
         file_writer.add_summary(summary,i)

if __name__ == '__main__':
   linear_regression()

在这里插入图片描述

2.8.3、模型的保存与加载

tf.train.Saver(var_list=None,max_to_keep=5)

  • 保存和加载模型(保存文件格式: checkpoint文件)
  • var_list:指定将要保存和还原的变量。它可以作为一个dict或一个列表传递
  • max_to_keep:指示要保留的最近检查点文件的最大数量。创建新文件时,会删除较旧的文件。如果无或0,则保留所有检查点文件。默认为5(即保留最新的5个检查点文件。)

步骤:

注意:

1、path,目录一定要提前创建

2、保存的是会话(里面是具体模型的参数)

3、保存模型的格式为 ckpt

  1. 实例化Saver
  2. 保存:saver.save(sess, path)
  3. 加载:saver.restore(sess, path)
def linear_regression():
   # 1、准备数据
   with tf.variable_scope('prepare_data'):
      X=tf.random_normal(shape=[100,1],name='feature') # 特征值 100行1列
      y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

   # 2、构建模型
   # 采用变量定义模型参数
   with tf.variable_scope('create_model'):
      weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name = 'Weights') # 权重
      bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name='Bias') # 偏置
      y_predict=tf.matmul(X,weigths)+bias # 预测值

   # 3、构建损失函数(均方误差)
   with tf.variable_scope('loss_function'):
      error=tf.reduce_mean(tf.square(y_predict-y_true))

   # 4、优化损失函数
   with tf.variable_scope('optimizer'):
      optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

   # 初始化变量
   init=tf.global_variables_initializer()

   # 收集变量
   tf.summary.scalar('error',error)
   tf.summary.histogram('weights',weigths)
   tf.summary.histogram('bias',bias)

   # 合并变量
   merged=tf.summary.merge_all()

   # 开启会话
   with tf.Session() as sess:
      sess.run(init) # 运行初始化
      # 查看没有训练之前,初始化模型参数值
      print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

      # 创建事件文件
      file_writer=tf.summary.FileWriter('./temp/linear/',graph = sess.graph)
      # 运行合并变量操作
      summary=sess.run(merged)

      # 实例化Saver
      saver=tf.train.Saver()

      # 开始训练模型,迭代100次
      # for i in range(100):
      #  sess.run(optimizer)
      #  print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))
      #
      #  # 将每次迭代后的合并变量写入到事件文件中
      #  file_writer.add_summary(summary,i)

         # 保存模型
         # if i%10==0:
         #  saver.save(sess,save_path = './temp/model/my_linear.ckpt')

         # 加载模型
      if os.path.exists('./temp/model/checkpoint'):
         saver.restore(sess, './temp/model/my_linear.ckpt')
         print('训练后模型参数为:权重%f, 偏置%f, 损失值%f ' % (weigths.eval(), bias.eval(), error.eval()))
        
if __name__ == '__main__':
	linear_regression()   
    
'''
训练前模型参数为:权重-1.358256, 偏置2.844705, 损失值6.984871 
训练后模型参数为:权重0.486487, 偏置0.413228, 损失值0.159787 
'''    

2.8.4、命令行参数设置

tf.app.flags(DEFINE),它支持应用从命令行接受参数,可以用来指定集群配置等。在tf.app.flags()下面有各种定义参数的类型

  • DEFINE_string(flag _name,default_value, docstring)
  • DEFINE_integer(flag_name, default_value, docstring)
  • DEFINE_boolean(flag_name, default_value, docstring)
  • DEFINE_float(flag_name, default_value, docstring)
  • tf.app.flags,在flags有一个FLAGS标志,它在程序中可以调用到我们前面具体定义的flag_name
  • 通过tf.app.run() 会自动启动 main(argv) 函数
#定义一些常用的命令行参数
#训练步数
tf.app.flags.DEFINE_integer("max_step",0,"训练模型的步数")
#定义模型的路径                            
tf.app.flags.DEFINE_string("model_dir", " ","模型保存的路径+模型名字")
#定义获取命令行参数
FLAGS = tf.app.flags.FLAGS                      

tf.app.flags(DEFINE) 使用

import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 去警告

# 1)定义命令行参数
tf.app.flags.DEFINE_integer("max_step", 100, "训练模型的步数")
tf.app.flags.DEFINE_string("model_dir", "Unknown", "模型保存的路径+模型的名字")
# 2)简化变量名
FLAGS = tf.app.flags.FLAGS

def command_demo():
    """
    命令行参数演示
    """
    print("max_step:", FLAGS.max_step)
    print("model_dir:", FLAGS.model_dir)

if __name__ == '__main__':
   command_demo()

'''
max_step: 100
model_dir: Unknown
'''

在这里插入图片描述

tf.app.run()使用

def main(argv):
   """
   这里是总文件,各种模块调用写在这里
   """
   print(argv)

if __name__ == '__main__':
   tf.app.run()
'''
['E:/RuanJian_2/PyCharm/PyCode/heima/junior/machine_learning/tensorflow_demo1.py']
'''

3、数据读取

3.1、文件读取流程

3.1.1、文件读取流程

在这里插入图片描述

shuffle 洗牌

第一阶段:构造文件名队列

第二阶段:读取与解码

第三阶段:批处理 (需要手动开启线程)

注意:这些操作需要启动运行这些队列操作的线程,以便我们在进行文件读取的过程中能够顺利进行入队出队操作

1、构造文件名队列
将需要读取的文件的文件名放入到文件名队列

tf.train.string_input_producer(string_tensor, shuffle=True)

  1. string_tensor:包含文件名+路径的1阶张量, 一般传入列表
  2. num_epochs:过几遍数据,默认无限过数据
  3. return:文件队列

2、读取与解码
从队列当中读取文件内容,并进行解码操作。

2.1、读取文件内容

阅读器默认每次只读取一个样本

具体来说:

文本文件默认一次读取一行,图片文件默认一次读取一张图片,二进制文件一次读取指定字节数(最好是一个样本的字节数),TFRecords默认一次读取一个example

  1. tf.TextLineReader: 读取文本
    • 阅读文本文件逗号分隔值(CSV)格式,默认按行读取
    • return:读取器实例
  2. tf.WholeFileReader: 用于读取图片文件
    • return:读取器实例
  3. tf.FixedLengthRecordReader(record_bytes) : 读取二进制文件
    • 要读取每个记录是固定数量字节的二进制文件
    • orecord_bytes:整型,指定每次读取(一个样本)的字节数
    • return:读取器实例

1、它们有共同的读取方法: read(file_queue),并且都会返回一个Tensors元组(key文件名字,value默认的内容(一个样本))

2、由于默认只会读取一个样本,所以如果想要进行批处理,需要使用tf.train.batch或tf.train.shuffle_batch进行批处理操作,便于之后指定每批次多个样本的训练。

即file_queue=tf.train.strng_input_produce(string_tensor, shuffle=True)

key,value=读取器.read(file_queue)

key: 文件名

value: 一个样本

2.2、内容解码

读取不同类型的文件,也应该对读取到的不同类型的内容进行相对应的解码操作,解码成统一的Tensor格式

  1. tf.decode_csv(): 解码文本文件内容·
  2. tf.image.decode_jpeg(contents即样本)
    • 将JPEG编码的图像解码为uint8张量
    • return :uint8张量,3-D形状[height, width, channels].
  3. tf.image.decode_png(contents即样本)
    • 将PNG编码的图像解码为uint8张量
    • return: 张量类型,3-D形状[height, width, channels]
  4. tf.decode_raw()︰解码二进制文件内容
    • 与tf.FixedLengthRecordReader搭配使用,二进制读取为uint8类型

解码阶段,默认所有的内容都解码成tf.uint8类型,如果之后需要转换成指定类型则可使用 tf.cast() 进行相应转换。

3 批处理

解码之后,可以直接获取默认的一个样本内容了,但如果想要获取多个样本,需要加入到新的队列进行批处理。

  1. tf.train.batch(tensors, batch_size, num_threads = 1, capacity = 32,name=None)

    • 读取指定大小(个数)的张量

    • tensors:可以是包含张量的列表,批处理的内容放到列表当中

    • batch_size:从队列中读取的批处理大小

    • num_threads:进入队列的线程数

    • capacity:整数,队列中元素的最大数量

    • return:tensors

  2. tf.train.shuffle_batch() : 随机批量操作

3.1.2、线程操作

以上用到的队列都是tf.train.QueueRunner对象。

每个QueueRunner都负责一个阶段,tf.train.start_queue_runners()函数会要求图中的每个QueueRunner启动它的运行队列操作的线程。(这些操作需要在会话中开启)

tf.train.start_queue_runners(sess=None, coord=None)

  • 收集图中所有的队列线程,默认同时启动线程
  • sess:所在的会话
  • coord:线程协调器
  • return:返回所有线程

tf.train.Coordinator()

  • 线程协调器,对线程进行管理和协调
  • request_stop():请求停止
  • should_stop():询问是否结束
  • join(threads=None, stop_grace_period_secs=120):回收线程
  • return:线程协调器实例

3.2、图片读取

3.2.1、图像基本知识

组成图片最基本单位是 像素

1、图片三要素
组成一张图片特征值是所有的像素值,有三个维度:图片长度、图片宽度、图片通道数

图片的通道数是什么?

描述一个像素点,如果是灰度图,那么只需要一个数值来描述它,就是单通道

如果一个像素点,有RGB三种颜色来描述它,及时三通道

灰度图:单通道,[长,宽,1]

彩色图片:三通道,[长,宽,3] 像素点为 长 X 宽 X 3

在这里插入图片描述

2、张量形状

在TensorFlow中如何用张量表示一张图片呢?

一张图片可以被表示成一个3D张量,即其形状为[height,width, channel],height就表示高,width表示宽,channel表示通道数。我们会经常遇到3D和4D的表示

  1. 单个图片:[height, width, channel] 3D张量
  2. 多个图片:[batch,height,width, channel],batch表示一个批次的张量数量 4D张量

3.2.2、图片特征值处理

为什么要缩放图片到统一大小?

在进行图像识别的时候,每个图片样本的特征数量要保持相同。所以需要将所有图片张量大小统一转换

缩小放大图片

tf.image**.resize_images**(images, size)

  1. images:4-D形状[batch, height, width, channels]或3-D形状的张量[height, width, channels]的图片数据

  2. size:1-D int32张量:new_height,new_width,图像的新尺寸

  3. 返回4-D格式或者3-D格式图片

    存储:unit8(节省空间)
    矩阵计算:float32(提高精度)

3.2.3、案例:狗图片读取

流程:
1)构造文件名队列
2)读取与解码,使样本的形状和类型统一
3)批处理,一次性处理多张图片

def picture_read(file_list):
	#1、构建文件名队列
	file_queue=tf.train.string_input_producer(file_list)

	#2、文件读取与解码
	reader=tf.WholeFileReader() # 图片的读取器
	# key是文件名,value是一张图片的原始编码形式
	key,value=reader.read(file_queue) # 图片的读取
	print("key:", key)
	print("value:", value)

	# 解码阶段
	image=tf.image.decode_jpeg(value) # 解码jepg格式
	print('image:',image)

	# 图片形状,类型修改
	image_resize=tf.image.resize_images(image,[200,200]) # 统一行列为200
	print('image_resize:',image_resize)

	# 静态形状修改
	image_resize.set_shape(shape = [200,200,3]) # 能用静态形状就用静态,不行再用动态

	# 3、批处理(一次性处理多张图片) 这里1个线程处理100张图片
	image_batch=tf.train.batch([image_resize],batch_size = 100,num_threads = 1,capacity = 100)
	print("image_batch:", image_batch)

	# 开启会话
	with tf.Session() as sess:
		# 创建线程协调员
		coord=tf.train.Coordinator()
		# 开启线程
		threads=tf.train.start_queue_runners(sess=sess,coord = coord)
		key_new, value_new, image_new, image_resize_new, image_batch_new = sess.run([key, value, image, image_resize, image_batch])
		print("key_new:", key_new)
		print("value_new:", value_new)
		print("image_new:", image_new)
		print("image_resize_new:", image_resize_new)
		print("image_batch_new:", image_batch_new)

		# 回收线程,如果不回收,会一直占用系统资源
		coord.request_stop() # 停止线程
		coord.join(threads)  # 回收线程

	pass


if __name__ == '__main__':
	file_name=os.listdir('./data/image/dog')
	# 构造路径 + 文件名的列表
	file_list=[os.path.join('./data/image/dog',file) for file in file_name]
	print(file_name)
	print(file_list)
	picture_read(file_list)
    
'''
['dog.1.jpg', 'dog.10.jpg', 'dog.100.jpg', 'dog.11.jpg', 'dog.12.jpg', 'dog.13.jpg', 'dog.14.jpg', 'dog.15.jpg', ....., 'dog.99.jpg']
['./data/image/dog\\dog.1.jpg', './data/image/dog\\dog.10.jpg', './data/image/dog\\dog.100.jpg', './data/image/dog\\dog.11.jpg', './data/image/dog\\dog.12.jpg', './data/image/dog\\dog.13.jpg', './data/image/dog\\dog.14.jpg', './data/image/dog\\dog.15.jpg',...., './data/image/dog\\dog.99.jpg']
key: Tensor("ReaderReadV2:0", shape=(), dtype=string)
value: Tensor("ReaderReadV2:1", shape=(), dtype=string)
image: Tensor("DecodeJpeg:0", shape=(?, ?, ?), dtype=uint8)
image_resize: Tensor("resize_images/Squeeze:0", shape=(200, 200, ?), dtype=float32)
image_batch: Tensor("batch:0", shape=(100, 200, 200, 3), dtype=float32)
key_new: b'./data/image/dog\\dog.50.jpg'
value_new: b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\n\x07\x07\x08\x07\x06\n\x08\x08\x08\x0b\n\n\x0b\x0e\x18\x10\x0e\r\r\x0e\x1d\x15\x16\x11\x18#\x1f%$"\x1f"!&+7/&)4)!"0A149;>>>%.DIC<H7=>;\xff\xdb\x00C\x01\n\x0b\x0b\x0e\r\x0e\x1c\x10\x10\x1c;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\xff\xc0\x00\x11\x08\x00\xc7\x00\x9d\x03\x01"\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05\x12!1A\x06\x13Qa\x07"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17\x18\x19\x1a%&\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02w\x00\x01\x02\x03\x11\x04\x05!1\x06\x12AQ\x07aq\x13"2\x81\x08\x14B\x91\xa1\xb1\xc1\t#3R\xf0\x15br\xd1\n\x16$4\xe1%\xf1\x17\x18\x19\x1a&\'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00?'
image_new: [[[ 62  78  67]
  [ 42  58  47]
  [ 69  85  74]
  ...
  [193 223 225]
  [194 221 230]
  [149 172 188]]

 [[ 55  71  60]
  [ 46  62  51]
  [ 56  72  61]

  ...
  [231 231 231]
  [231 231 231]
  [231 231 231]]]
image_resize_new: [[[ 62.        78.        67.      ]
  [ 46.3       62.3       51.3     ]
  [ 57.39      73.39      62.39    ]
  ...
  [231.       231.       231.      ]
  [231.       231.       231.      ]
  [231.       231.       231.      ]]]
  
image_batch_new: [[[[  0.          0.          0.       ]
   [  0.          0.          0.       ]
   [  0.          0.          0.       ]
   ...
  [[125.09195   128.09195   137.09195  ]
   [171.11003   174.03503   183.26003  ]
   [129.0711    131.0711    143.2211   ]
   ...
   [ 15.224976   15.224976   15.224976 ]
   [ 12.149994   12.149994   12.149994 ]
   [ 11.         11.         11.       ]]]

   [ 77.06506    45.09503    13.125    ]
   [ 74.14496    43.14496    15.1449585]
   [ 78.745026   47.745026   18.745026 ]]]]

Process finished with exit code 0

'''    

3.3、二进制数据

3.3.1、CIFAR10二进制数据集介绍

CIFAR10数据集官网: https://www.cs.toronto.edu/~kriz/cifar.html

数据集分为五个训练批次和一个测试批次,每个批次有 10000 张图像。测试批次恰好包含来自每个类别的 1000 个随机选择的图像。训练批次包含随机顺序的剩余图像,但一些训练批次可能包含来自一个类的图像多于另一个。在它们之间,训练批次恰好包含来自每个类别的 5000 张图像

在这里插入图片描述

二进制版本数据文件

二进制版本包含文件data_batch_1.bin,data_batch_2.bin,…,data_batch_5.bin以及test_batch.bin

cifar10 的特征值是 image(3072Bytes) 目标值是 label 0-9 (1Bytes)

这些文件中的每一个格式如下,数据中每个样本包含了特征值和目标值:

<1×标签><3072×像素>

<1×标签><3072×像素>
第一个字节是第一个图像的标签,它是一个0-9范围内的数字。接下来的3072个字节是图像像素的值。前1024个字节是红色通道值,下1024个绿色,最后1024个蓝色。值以行优先顺序存储,因此前32个字节是图像第一行的红色通道值。每个文件都包含10000个这样的3073字节的“行"图像,但没有任何分隔行的限制。因此每个文件应该完全是30730000字节长。
即一个样本的形式为: 1+1024r+1024g+1024b=3073个字节

3.3.2、CIFAR10二进制数据读取

流程分析

1、构建文件名队列

file_queue=tf.train.string_input_producer(file_list)

2、读取与解码

reader=tf.FixedLengthRecordReader(3073)

key,value=reader.read(file_queue)

decoded=tf.decoded_raw(value,tf.uint8)

对tensor对象进行切片 label

一个样本image(3072字节=1024r+1024g+1024b)

[[r[32,32]],[g[32,32]],[b[32,32]]] 32x32=1024

shape=(3,32,32) = (channels,height,width)

故需要转换为TensorFlow的图像表示(height,width,channels)

tf.transpose(image,[a,b,c])

如 image_new=tf.transpose(image,[1,2,0]) 参数二是将image的原来索引位置,换成现在对应的索引。

即image_new 0,1,2的位置的值,对应image 1,2,0位置的值

3、批处理

tf.train.batch(tensors, batch_size, num_threads = 1, capacity = 32,name=None)

NHWC与NCHW

在读取设置图片形状的时候有两种格式:

设置为“NHWC"时,排列顺序为 [batch, height, width,channels];

设置为“NCHW"时,排列顺序为[batch, channels, height, width]。

其中N表示这批图像有几张,H表示图像在竖直方向有多少像素,W表示水平方向像素数,C表示通道数。

Tensorflow默认的[height, width, channel]

class Cifar(object):

	def __init__(self):
		# 初始化操作
		self.height=32
		self.width=32
		self.channels=3

		# 字节数
		self.image_bytes=self.height*self.width*self.channels # 图片像素数
		self.label_bytes=1 # 标签数
		self.all_bytes=self.label_bytes+self.image_bytes # 总字节数

	def read_and_decode(self,file_list):
		# 1、构造文件名队列
		file_queue=tf.train.string_input_producer(file_list)

		# 2、读取与解码
		# 读取阶段
		reader=tf.FixedLengthRecordReader(self.all_bytes)
		# key 文件名,value一个样本
		key,value=reader.read(file_queue)
		print('key: ',key)
		print('value: ',value)

		# 解码阶段
		decode=tf.decode_raw(value,tf.uint8)
		print('decode: ',decode)
		# 将目标值和特征值切片分开,即标签和通道分开。tf.slice(data,起始位置,个数)
		label=tf.slice(decode,[0],[self.label_bytes])
		image=tf.slice(decode,[self.label_bytes],[self.image_bytes])
		print('label: ',label)
		print('image: ',image)
		# 调整图片形状
		image_reshaped=tf.reshape(image,shape = [self.channels,self.height,self.width])
		print('image_reshaped: ',image_reshaped)

		# 转置,转成tf图片的表示格式 height,width,channels
		image_transposed=tf.transpose(image_reshaped,[1,2,0])
		print('image_transposed: ',image_transposed)

		# 跳转图像类型,uint8转为float32,调高精度
		image_cast=tf.cast(image_transposed,tf.float32)

		# 3、批处理
		label_batch,image_batch=tf.train.batch([label,image_cast],batch_size = 100,num_threads = 1,capacity = 100)
		print('label_batch: ',label_batch)
		print('image_batch: ',image_batch)

		# 开启会话
		with tf.Session() as sess:
			print('------------------开启会话------------------')
			# 开启线程
			coord=tf.train.Coordinator() # 协调器
			threads=tf.train.start_queue_runners(sess=sess,coord = coord)

key_new,value_new,decode_new,label_new,image_new,image_reshaped_new,image_transposed_new,label_batch_new,image_batch_new=sess.run([key,value,decode,label,image,image_reshaped,image_transposed,label_batch,image_batch])
			print('key_new: ',key_new)
			print('value_new: ',value_new)
			print('decode_new',decode_new)
			print('label_new',label_new)
			print('image_new',image_new)
			print('image_reshaped_new\n',image_reshaped_new)
			print('image_transposed_new\n',image_transposed_new)
			print('label_batch_new\n',label_batch_new)
			print('image_batch_new\n',image_batch_new)

			# 回收线程
			coord.request_stop()
			coord.join(threads)
		return None

if __name__ == '__main__':
	file_name=os.listdir('./data/cifar-10-batches-bin')
	# 构造路径 + 文件名的列表
	file_list=[os.path.join('./data/cifar-10-batches-bin',file) for file in file_name if file[-3:]=='bin']
	print('file_llist: ',file_list)
	#实例化Cifar类
	cifar=Cifar()
	cifar.read_and_decode(file_list)
    
'''
file_llist:  ['./data/cifar-10-batches-bin\\data_batch_1.bin', './data/cifar-10-batches-bin\\data_batch_2.bin', './data/cifar-10-batches-bin\\data_batch_3.bin', './data/cifar-10-batches-bin\\data_batch_4.bin', './data/cifar-10-batches-bin\\data_batch_5.bin', './data/cifar-10-batches-bin\\test_batch.bin']
key:  Tensor("ReaderReadV2:0", shape=(), dtype=string)
value:  Tensor("ReaderReadV2:1", shape=(), dtype=string)
decode:  Tensor("DecodeRaw:0", shape=(?,), dtype=uint8)
label:  Tensor("Slice:0", shape=(1,), dtype=uint8)
image:  Tensor("Slice_1:0", shape=(3072,), dtype=uint8)
image_reshaped:  Tensor("Reshape:0", shape=(3, 32, 32), dtype=uint8)
image_transposed:  Tensor("transpose:0", shape=(32, 32, 3), dtype=uint8)
label_batch:  Tensor("batch:0", shape=(100, 1), dtype=uint8)
image_batch:  Tensor("batch:1", shape=(100, 32, 32, 3), dtype=float32)
------------------开启会话------------------
key_new:  b'./data/cifar-10-batches-bin\\data_batch_1.bin:0'
value_new:  b'\x06;+2Dbw\x8b\x91\x95\x95\x83}\x8e\x90\x89\x81\x89\x86|\x8b\x8b\x85\x88\x8b\x98\xa3\xa8\x9f\x9e\x9e\x98\x94\x10\x00\x123Xx\x80\x7f~tjeiqmpwmi}\x7fz\x83|y\x83\x84\x85\x85{wz\x19\x101Sn\x81\x82yqppji\x80|\x82\x7fzsx\x82\x83\x8b\x7f~\x7f\x82\x8e\x82vxm!&Wjsuriky}mq\x92\x85\x7fvu\x7fz\x84\x89\x][SME7;:A;.9h\x8cTH'
decode_new [  6  59  43 ... 140  84  72]
label_new [6]
image_new [ 59  43  50 ... 140  84  72]
image_reshaped_new
 [[[ 59  43  50 ... 158 152 148]
  [ 16   0  18 ... 123 119 122]
  [ 25  16  49 ... 118 120 109]
  ...
  [ 96  34  26 ...  70   7  20]
  [ 96  42  30 ...  94  34  34]
  [116  94  87 ... 140  84  72]]]
image_transposed_new
 [[[ 59  62  63]
  [ 43  46  45]
  [ 50  48  43]
  ...
  [216 184 140]
  [151 118  84]
  [123  92  72]]]
  
label_batch_new
[[6]
 [0]
 [2]
 [7]
 [2]
 ....
 [2]
 [8]]
image_batch_new 
[[[[ 29.  43.  10.]
   [ 22.  36.   4.]
   [ 25.  37.  16.]
   ...
   [197. 219. 137.]
   [198. 219. 137.]
   [199. 222. 140.]] 
   ....]]]]
  
'''  

3.4、tfrecords读取

3.4.1、什么是TFRecords文件

TFRecords其实是一种二进制文件,虽然它不如其他格式好理解,但是它能更好的利用内存,更方便复制和移动,并且不需要单独的标签文件。即tfrecords 特征值和目标值是绑定在一起的
使用步骤:

  1. 获取数据
  2. 将数据填入到Example协议内存块(protocol buffer)
  3. 将协议内存块序列化为字符串,并且通过tf.python_io.TFRecordwriter写入到TFRecords文件。

文件格式 * . tfrecords

3.4.2、Example结构解析

Example:
    features {
    
    
        feature{
    
    
            key: "iamge"
            value:{
    
    
                bytes_list {
    
    
                    value: '\x06;+2Dbw\x8b\x91\x95\x95\x83}\x8e\x90\x89\x81\x89\x86|\x8b\x8b'
            	}
       	 }
    }
    
     feature{
    
    
            key: "label"
            value:{
    
    
                int64_list {
    
    
                    value: 9
            	}
       	 }
    }
}    

   
  1. tf.train.Example协议内存块(protocol buffer)(协议内存块包含了字段Features)
  2. Features包含了一个Feature字段
  3. Feature中包含要写入的数据、并指明数据类型。
    • 这是一个样本的结构,批数据需要循环存入这样的结构。 即一个example就是一个样本

example = tf.train.Example(features=tf.train.Features(feature={

“image” : tf.train.Feature(bytes_list=tf.train.BytesList(value=[Bytes])),
“label” : tf.train.Feature(int64_list=tf.train.Int64List(value=[Value]))

}))

  • tf.train.Example(features=None)
    • 写入tfrecords文件
    • features: tf.train.Features类型的特征实例
    • return: example格式协议块
  • tf.train.Features(feature=None)
    • 构建每个样本的信息键值对
    • feature:字典数据,key为要保存的名字
    • value为tf.train.Feature实例
    • return: Features类型
  • tf.train.Feature(options)
    • options:
      • bytes_list=tf.train. BytesList(value=[Bytes])
      • int64_list=tf.trai.Int64List(value=[Value])
    • 支持存入的类型如下
    • tf.train.Int64List(value=[Value]) 整型
    • tf.train.BytesList(value=[Bytes]) 字节
    • tf.train.FloatList(value=[value]) 浮点型

这种example结构很好地实现了数据和标签(训练的类别标签)或者其他属性数据存储在同一个文件中

example.SerializeToString() 将example 序列化到本地

3.4.1、tfrecords文件存储

  1. 构造存储实例,tf.python_io.TFRecordWriter(path)
    • 写入tfrecords文件
    • path: TFRecords文件的路径
    • return:写文件
      • method方法
        • write(record):向文件中写入一个example
        • close():关闭文件写入器
  2. 循环将数据填入到Example协议内存块(protocol buffer)
class Cifar(object):

   def __init__(self):
      # 初始化操作
      self.height=32
      self.width=32
      self.channels=3

      # 字节数
      self.image_bytes=self.height*self.width*self.channels # 图片像素数
      self.label_bytes=1 # 标签数
      self.all_bytes=self.label_bytes+self.image_bytes # 总字节数

   def read_and_decode(self,file_list):
      # 1、构造文件名队列
      file_queue=tf.train.string_input_producer(file_list)

      # 2、读取与解码
      # 读取阶段
      reader=tf.FixedLengthRecordReader(self.all_bytes)
      # key 文件名,value一个样本
      key,value=reader.read(file_queue)

      # 解码阶段
      decode=tf.decode_raw(value,tf.uint8)
      # 将目标值和特征值切片分开,即标签和通道分开。tf.slice(data,起始位置,个数)
      label=tf.slice(decode,[0],[self.label_bytes])
      image=tf.slice(decode,[self.label_bytes],[self.image_bytes])
      # 调整图片形状
      image_reshaped=tf.reshape(image,shape = [self.channels,self.height,self.width])
      # 转置,转成tf图片的表示格式 height,width,channels
      image_transposed=tf.transpose(image_reshaped,[1,2,0])
      # 跳转图像类型,uint8转为float32
      image_cast=tf.cast(image_transposed,tf.float32)
      
        # 3、批处理
      label_batch,image_batch=tf.train.batch([label,image_cast],batch_size = 100,num_threads = 1,capacity = 100)

      # 开启会话
      with tf.Session() as sess:
         print('------------------开启会话------------------')
         # 开启线程
         coord=tf.train.Coordinator() # 协调器
         threads=tf.train.start_queue_runners(sess=sess,coord = coord)
         label_batch_new,image_batch_new=sess.run([label_batch,image_batch])
         # 回收线程
         coord.request_stop()
         coord.join(threads)
      return label_batch_new,image_batch_new

   def write_to_tfrecords(self,label_batch,image_batch):
      # 将样本的特征值和目标值写入tfrecords文件
      with tf.python_io.TFRecordWriter('./temp/cifar10/cifar10.tfrecords') as tfWriter:
         # 循环构造example对象,并序列化写入文件
         for i in range(label_batch.size):
            image=image_batch[i].tostring() # 序列化
            label=label_batch[i][0] # [i][0]取出一维数组的值
            example = tf.train.Example(features = tf.train.Features(feature = {
    
    
               "image": tf.train.Feature(bytes_list = tf.train.BytesList(value=[image])),
               "label": tf.train.Feature(int64_list = tf.train.Int64List(value=[label]))
            }))
            # 将序列化后的example写入到cifar10.tfrecords文件中
            tfWriter.write(example.SerializeToString())
            
if __name__ == '__main__':
	file_name=os.listdir('./data/cifar-10-batches-bin')
	# 构造路径 + 文件名的列表
	file_list=[os.path.join('./data/cifar-10-batches-bin',file) for file in file_name if file[-3:]=='bin']
	print('file_llist: ',file_list)
	#实例化Cifar类
	cifar=Cifar()
	label_batch,image_batch=cifar.read_and_decode(file_list)
	cifar.write_to_tfrecords(label_batch,image_batch)            

3.4.2、tfrecords文件读取

读取这种文件整个过程与其他文件一样,只不过需要有个解析Example的步骤。从TFRecords文件中读取数据,可以使用tf.TFRecordReader的 tf.parse_single_example解析器。这个操作可以将Example协议内存块(protocol buffer)解析为张量。

#多了解析example的一个步骤
feature = tf.parse_single_example( values,features={
    
    
"image" : tf.FixedLenFeature([], tf.string),
"label" : tf.FixedLenFeature([], tf.int64)
})
  • tf.parse_single_example(serialized, features=None, name=None)
    • 解析一个单一的Example原型
    • serialized:标量字符串Tensor,一个序列化的Example
    • features: dict字典数据,键为读取的名字,值为FixedLenFeature
    • return:一个键值对组成的字典,键为读取的名字
  • tf.FixedLenFeature(shape, dtype)
    • shape:输入数据的形状,一般不指定,为空列表
    • dtype:输入数据类型,与存储进文件的类型要一致。
    • 类型只能是float32, int64, string(对应bytes类型)

tfrecords文件读取步骤分析

  1. 构造文件名队列
  2. 读取与解码
    1. 读取
    2. 解析example
    3. 解码
  3. 批处理
  4. 开启会话
	def write_to_tfrecords(self,label_batch,image_batch):
		# 将样本的特征值和目标值写入tfrecords文件
		with tf.python_io.TFRecordWriter('./temp/cifar10/cifar10.tfrecords') as tfWriter:
			# 循环构造example对象,并序列化写入文件
			for i in range(label_batch.size):
				image=image_batch[i].tostring() # 序列化
				label=label_batch[i][0] # [i][0]取出一维数组的值
				example = tf.train.Example(features = tf.train.Features(feature = {
    
    
					"image": tf.train.Feature(bytes_list = tf.train.BytesList(value=[image])),
					"label": tf.train.Feature(int64_list = tf.train.Int64List(value=[label]))
				}))
				# 将序列化后的example写入到cifar10.tfrecords文件中
				tfWriter.write(example.SerializeToString())

	def read_tfrecords(self,file_name):
		# 1、构造文件名队列
		file_queue=tf.train.string_input_producer([file_name])
		# 2、读取与解码
		tfReader=tf.TFRecordReader() # TFRecord读取器
		key,value=tfReader.read(file_queue)
		# 解析example
		feature=tf.parse_single_example(value,features = {
    
    
			"image":tf.FixedLenFeature([],tf.string),
			"label":tf.FixedLenFeature([],tf.int64)
		})
		image=feature["image"]
		label=feature["label"]
		print('read_tf_image:\n',image)
		print('read_tf_label:\n',label)

		# 解码
		image_decoded=tf.decode_raw(image,tf.uint8)
		print('image_decoded\n',image_decoded)
		# 图像形状调整,动态调整,调整为tf支持的格式
		image_reshaped=tf.reshape(image_decoded,[self.height,self.width,self.channels])
		print('image_reshaped\n',image_reshaped)

		# 3、批处理
		image_batch,label_batch=tf.train.batch([image_reshaped,label],batch_size = 100,num_threads = 1,capacity = 100)
		print('image_batch\n',image_batch)
		print('label_batch\n',label_batch)

		# 4、开启会话
		with tf.Session() as sess:
			# 开启线程
			# 协调器
			coord=tf.train.Coordinator()
			threads=tf.train.start_queue_runners(sess=sess,coord = coord)

			image_new,label_new,image_decoded_new,image_reshaped_new,image_batch_new,label_batch_new=sess.run([image,label,image_decoded,image_reshaped,image_batch,label_batch])
			print('image_new\n',image_new)
			print('label_new\n',label_new)
			print('image_decoded_new\n',image_decoded_new)
			print('image_reshaped_new\n',image_reshaped_new)
			print('image_batch_new\n',image_batch_new)
			print('label_batch_new\n',label_batch_new)

			# 线程回收
			coord.request_stop()
			coord.join(threads)

		return None
    
if __name__ == '__main__':
	path='./temp/cifar10/cifar10.tfrecords'
	cifar.read_tfrecords(path)

3.5、神经网络基础

3.5.1、定义

**人工神经网络(Artificial Neural Network,简写为ANN)也简称为神经网络(NN)。**是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功能的计算模型。经典的神经网络结构包含三个层次的神经网络。分别为输入层,输出层以及隐藏层。

在这里插入图片描述

其中每层的圆圈代表一个神经元,隐藏层和输出层的神经元有输入的数据计算后输出,输入层的神经元只是输入

神经网络的特点:

  • 每个连接都有个权值
  • 同一层神经元之间没有连接
  • 最后的输出结构对应的层也称之为全连接层

那么为什么设计这样的结构呢?首先从一个最基础的结构说起,神经元。以前也称之为感知机。神经元就是要模拟人的神经元结构。

在这里插入图片描述

一个神经元通常具有多个树突,主要用来接受传入信息;而轴突只有一条,轴突尾端有许多轴突末梢可以给其他多个神经元传递信息。轴突末梢跟其他神经元的树突产生连接,从而传递信号。这个连接的位置在生物学上叫做**"突触”**。

感知机(PLA : Perceptron Learning Algorithm)

感知机就是模拟这样的大脑神经网络处理数据的过程。感知机模型如下图:

在这里插入图片描述

感知机是一种最基础的分类模型,类似于逻辑回归,不同的是,**感知机的激活函数用的是sign,而逻辑回归用的sigmoid。**感知机也具有连接的权重和偏置

在这里插入图片描述

3.5.2、神经网络原理

在这里插入图片描述

神经网络解决多分类问题最常用的方法是设置n个输出节点,其中n为类别的个数。

任意事件发生的概率都在0和1之间,且总有某一个事件发生(概率的和为1)。如果将分类问题中“一个样例属于某一个类别”看成一个概率事件,那么训练数据的正确答案就符合一个概率分布。如何将神经网络前向传播得到的结果也变成概率分布呢? Softmax回归就是一个非常常用的方法。

softmax回归

softmax回归将神经网络输出转换成概率结果

在这里插入图片描述

softmax公式的理解

# 假设输出结果为:2.3,4.1,5.6
# softmax的计算输出结果为:
y1_p = e^2.3/(e^2.3+e^4.1+e^5.6)
y1_p = e^4.1/(e^2.3+e^4.1+e^5.6)
y1_p = e^5.6/( e^2.3+e^4.1+e^5.6)

这样子就把神经网络的输出也变成了一个概率输出

在这里插入图片描述

交叉熵损失函数: 衡量神经网络预测的概率和真实结果的概率之间的距离

交叉熵适合用于一个样本对应一个目标值

在这里插入图片描述

为了能够衡量距离,目标值需要进行one-hot编码,能与概率值――对应,如下图

在这里插入图片描述

计算

-[0log(0.10)+0log(0.05)+0log(0.15)+0log(0.10)+0log(0.05)+0log(0.20)+1log(0.10)…]

上述的结果为-1log(0.10),那么为了减少这一个样本的损失。神经网络应该怎么做?

答:提高对应目标值为1的位置输出概率大小。

损失大小

神经网络最后的损失为平均每个样本的损失大小。

即对所有样本的损失求和取其平均值

softmax、交叉熵损失API

tf.nn.softmax_cross_entropy_with_logits(labels=None, logits=None, name=None)

  • abels:标签值(真实值)
  • logits:样本加权之后的值
  • return:返回损失值列表

损失大小求平均

tf.reduce_mean(input_tensor)

计算张量的尺寸的元素平均值

交叉熵的优化:梯度下降

3.5.3、案例:minst手写数字识别

数据集介绍

在这里插入图片描述

文件说明:

  • train-images-idx3-ubyte.gz: training set images(9912422 bytes)
  • train-labels-idx1-ubyte.gz: training set labels (28881 bytes)
  • t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)
  • t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)

网址: http://yann.lecun.com/exdb/mnist

特征值

Mnist数据集可以从官网下载,网址: http://yann.lecun.com/exdb/mnist/下载下来的数据集被分成两部分:55000行的训练数据集(mnist.train)和10000行的测试数据集 (mnist.test)。每一个MNIST数据单元有两部分组成:一张包含手写数字的图片和一个对应的标签。我们把这些图片设为"xs",把这些标签设为"ys”。训练数据集和测试数据集都包含xs和ys,比如训练数据集的图片是mnist.train.images,训练数据集的标签是mnist.train.labels。

在这里插入图片描述

我们可以知道图片是黑白图片,每一张图片包含28像素X28像素。我们把这个数组展开成一个向量,长度是28x28 = 784。因此,在MNIST训练数据集中,mnist.trajn.images是一个形状为[60000,784]的张量。
在这里插入图片描述

目标值

MNIST中的每个图像都具有相应的标签,目标值:0到9之间的数字表示图像中绘制的数字。用的是one-hot编码
nn[0,0,0,1,0,0,0,0,0,0] mnist.train.labels [55000,10]

在这里插入图片描述

minst数据获取API

TensorFlow框架自带了获取这个数据集的接口,所以不需要自行读取。

  • from tensorflow.examples.tutorials.mnist import input_data
  • mnist = input_data.read_data_sets(path, one_hot=True)
    • mnist.train.next_batch(100)(提供批量获取功能)
    • mnist.train.images、labels
    • mnist.test.images、labels
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('mnist_data', one_hot=True)
print(mnist.train.next_batch(1))
print(mnist.train.images[0])  # 查看特征值
print(mnist.train.labels[0])  # 目标值

mnist手写体识别网络层设计

我们采用只有一层,即最后一个输出层的神经网络,也称之为全连接(full connected) 层神经网络

在这里插入图片描述

全连接层计算:即构造权重和偏置

  1. tf.matmul(a, b, name=None)+bias
    • return:全连接结果,供交叉损失运算
  2. tf.train.GradientDescentOptimizer(learning_rate) :梯度下降(优化交叉熵)
    • learning_rate:学习率
    • method: minimize(loss):最小优化损失

计算准确率:对One-hot概率 求平均值

  1. equal_list = tf.equal(tf.argmax(y_predict,1), tf.argmax(y_label,1) # 1按列,比对预测值和真实值,如果相同置1
  2. accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))

全连接分析:

y=w1x1+w2x2+…+b

y_predict[None,10]=X[None,784]*weights[784,10]+bias[10]

error=tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=y_predict)

def full_connection():
	# 用全连接对手写数字进行识别
	# 1、准备数据
	mnist=input_data.read_data_sets("./data/mnist_data",one_hot = True)
	#  用占位符定义真实数据
	X=tf.placeholder(dtype = tf.float32,shape = [None,784]) # 特征值
	y_true=tf.placeholder(dtype = tf.float32,shape = [None,10]) # 真实值

	# 2、构建模型 - 全连接
	# y_predict[None,10]=X[None,784]*weights[784,10]+bias[10]
	weights=tf.Variable(initial_value = tf.random_normal(shape = [784,10],stddev = 0.01))
	bias=tf.Variable(initial_value = tf.random_normal(shape = [10],stddev = 0.1))
	y_predict=tf.matmul(X,weights)+bias

	# 3、构造损失函数
	loss_list=tf.nn.softmax_cross_entropy_with_logits(logits = y_predict,labels = y_true)
	loss=tf.reduce_mean(loss_list)

	# 4、优化损失(梯度下降)
	optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)

	# 5、计算准确率 tf.argmax()计算最大值所在列数
	bool_list=tf.equal(tf.argmax(y_predict,axis = 1),tf.argmax(y_true,axis = 1))
	accuracy=tf.reduce_mean(tf.cast(bool_list,tf.float32))
	# 初始化变量
	init = tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		# 初始化变量
		sess.run(init)

		# 开始训练
		for i in range(100):
			# 获取真实值
			image, label = mnist.train.next_batch(100)
			# 因为optimizer返回的是None 所以用_,来接
			_, loss_value, accuracy_value = sess.run([optimizer, loss, accuracy], feed_dict = {
    
    X: image, y_true: label})

			print("第%d次的损失为%f,准确率为%f" % (i + 1, loss_value, accuracy_value))

	return None

if __name__ == '__main__':
    # 如果你报numpy.ufunc size changed错误,尝试更新一下Numpy的版本
    # pip install numpy==1.16.0
	full_connection()
    
'''
第1次的损失为2.292725,准确率为0.160000
第2次的损失为2.331739,准确率为0.020000
…………………………
第100次的损失为1.510217,准确率为0.730000
'''    

4、卷积神经网络

4.1、卷积神经网络简介

4.1.1、卷积神经网络与传统多层神经网络对比

  1. **传统意义上的多层神经网络是只有输入层、隐藏层、输出层。**其中隐藏层的层数根据需要而定,没有明确的理论推导来说明到底多少层合适
  2. 卷积神经网络(Convolutional Neural Networks, CNN),在原来多层神经网络的基础上,加入了更加有效的特征学习部分,具体操作就是在原来的全连接层前面加入了卷积层、激活层和池化层。卷积神经网络出现,使得神经网络层数得以加深,“深度”学习由此而来。
  3. 通常所说的深度学习,一般指的是这些CNN等新的结构以及一些新的方法(比如新的激活函数Relu等),解决了传统多层神经网络的一些难以解决的问题

输入层
隐藏层:卷积层、激活层、池化层、全连接层
输出层

4.1.2、卷积神经网络发展历史

在这里插入图片描述

  1. 网络结构加深
  2. 增强卷积模块功能
  3. 从分类任务到检测任务
  4. 增加新的功能单元

4.1.3、卷积网络ImageNet比赛错误率

  • lmageNet可以说是计算机视觉研究人员进行大规模物体识别和检测时,最先想到的视觉大数据来源,最初由斯坦福大学李飞飞等人在CVPR 2009的一篇论文中推出,并坡用于替代 PASCAL数据集(后者在数据规模和多样性上都不如lmageNet)和LabelMe数据集(在标准化上不如 ImageNet) 。
  • lmageNet不但是计算机视觉发展的重要推动者,也是这一波深度学习热潮的关键驱动力之一。
  • 截至2016年,ImageNet中含有超过1500万由人手工注释的图片网址,也就是带标签的图片,标签说明了图片中的内容,超过2.2万个类别。

在这里插入图片描述

4.2、卷积神经网络原理

4.2.1、卷积神经网络三个结构

神经网络(neural networks)的基本组成包括输入层、隐藏层、输出层。而卷积神经网络的特点在于隐藏层分为卷积层、激活层和池化层(pooling layer,又叫下采样层subsample)。

  1. 卷积层: 通过在原始图像上平移来提取特征
  2. 激活层: 增加非线性分割能力
  3. 池化层(下采样层): 减少学习的参数,降低网络的复杂度(最大池化和平均池化)
  4. **全连接层:**实现分类效果
  5. **输出层:**进行损失计算并输出分类结果

卷积神经网络的结构

在这里插入图片描述

  • CONV: 卷积层
  • RELU: 激活层
  • POOL: 池化层
  • FC(Full Connection): 全连接层

4.2.2、卷积层(Convolutional Layer)

卷积核又叫 filter、过滤器、模型参数、卷积单元

卷积神经网络中每层卷积层由若干卷积单元(卷积核)组成,每个卷积单元的参数都是通过反向传播算法最佳化得到的。

卷积运算的目的是特征提取,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征。

1、卷积核(Filter)的四大要素

  1. 卷积核个数

  2. 卷积核大小

  3. 卷积核步长

  4. 卷积核零填充大小

接下来我们通过计算案例讲解,假设图片是黑白图片(只有一个通道)

2、卷积核计算-大小

卷积核大小一般为 1 * 1 3 * 3 5 * 5

卷积核我们可以理解为一个观察的人,带着若干权重和一个偏置去观察,进行特征加权运算。

下图只有权重,少了偏置,一般情况下都要加上偏置!

在这里插入图片描述

通常的卷积核大小 1,3,5,是经过研究人员实验证明比较好的效果。这个人观察之后会得到一个运算结果,
那么这个人想观察所有这张图的像素怎么办?那就需要平移(即步长):

在这里插入图片描述

3、步长

需要去平移卷积核观察这张图片,需要的参数就是步长

假设移动的步长为一个像素,那么最终这个人观察的结果以下图为例:

5x5的图片,3x3的卷积大小去一个步长运算得到3x3的大小观察结果

在这里插入图片描述

如果移动的步长为2那么结果是这样

5x5的图片,3x3的卷积大小,2个步长运算得到2x2的大小观察结果

在这里插入图片描述

4、卷积核个数

不同的卷积核带的权重和偏置都不一样,即随机初始化的参数

那么如果在某一层结构当中,不止是一个人观察,多个人(卷积核)一起去观察。那就得到多张观察结果。

也就是说,一个卷积核得到一个观察结果,多个卷积核就是多个观察结果

5、零填充大小

Filter观察窗口的大小和移动步长有时会导致超过图片像素宽度!

解决办法:

  1. 不要超出图像宽度的观察结果
  2. 零填充

零填充就是在图片像素外围填充一圈值为0的像素。

在这里插入图片描述

6、计算输出大小

如果已知输入图片形状,卷积核数量,卷积核大小,以及移动步长,那么输出图片形状如何确定?

  1. 输入体积大小H1* W1 * D1
  2. 四个超参数︰
    1. Filter数量K
    2. Filter大小F
    3. 步长S
    4. 零填充大小P
  3. 输出体积大小H2 * W2* D2
    1. H2=(H1- F+2P)/S+1 ((高-过滤器大小+2零填充)/步长+1)
    2. W2= (W1- F+2P)/S+1
    3. D2=k

通过一个例子来理解上面的公式

计算案例:

1、假设已知的条件:输入图像32 * 32 * 1 , 50个Filter,大小为5 * 5,移动步长为1,零填充大小为1。请求出输出大小?
H2= (H1 -F +2P)/S + 1 =(32 - 5+2 * 1)/1 + 1 = 30

w2=(W1-F+2P)/S + 1 =(32 -5+2 * 1)/1 + 1 = 30

D2= K= 50(D2等于过滤器的数量K)
所以输出大小为[30,30,50]

2、假设已知的条件∶输入图像32 * 32 * 1 ,50个Filter,大小为3*3,移动步长为1,未知零填充。输出大小32 * 32,求零填充大小?
H2= (H1 -F +2P)/S + 1 = (32 - 3+2 * P)/1 +1 = 32

w2=(W1 -F+2P)/S+ 1 =(32-3+2 * P)/1 +1 = 32

故P=1

所以零填充大小为:1*1

7、多通道图片如何观察

如果是一张彩色图片,那么就有三种表分别为R,G,B。原本每个人需要带一个3x3或者其他大小的卷积核,现在需要带3张3x3的权重和一个偏置,总共就27个权重。最终每个人还是得出一张结果:

在这里插入图片描述

8、卷积网络API

  1. tf.nn.conv2d(input, filter, strides=, padding=, name=None)
    • 计算给定4-D input和filter张量的2维卷积
    • input:给定的输入张量,具有[batch,heigth,width,channel],类型一定为 float32,64
    • filter:指定过滤器的权重数量,[filter_height, filter_width, in_channels,out_channels]
    • strides: strides = [1, stride,stride,1],步长。 例如,如果步长为1,则strides=[1,1,1,1]
    • padding: “SAME"“,“VALID”,具体解释见下面。
  2. Tensorflow的零填充方式有两种方式,SAME和VALID
    • SAME︰越过边缘取样,取样的面积和输入图像的像素宽度一致。公式:ceil(H/S)
      • H为输入的图片的高或者宽,S为步长
      • 无论过滤器的大小是多少,零填充的数量由API自动计算。
    • VALID:不越过边缘取样,取样的面积小于输入人的图像的像素宽度。不填充。
    • 一般填same , valid如果越过边缘的话,观察结果直接丢弃掉
  3. 在Tensorflow当中,卷积API设置"SAME”之后,如果步长为1,输出高宽与输入大小一样(重要)

4.2.3、激活函数

随着神经网络的发展,大家发现原有的sigmoid等激活函数并不能达到好的效果,所以才去新的激活函数。

  • Relu
  • Tanh
  • sigmoid

不同激活函数网站演示:http://playground.tensorflow.org

Relu函数

在这里插入图片描述

效果:

在这里插入图片描述

Relu激活函数API

  • tf.nn.relu(features, name=None)
    • features: 卷积后加上偏置的结果
    • return: 激活函数的计算结果

为什么采用新的激活函数

  1. Relu优点
    • 有效解决梯度消失问题
    • 计算速度非常快,只需要判断输入是否大于0。SGD(批梯度下降)的求解速度速度远快于sigmoid和tanh
  2. sigmoid缺点
    • 采用sigmoid等函数,计算量相对大,而采用Relu 激活函数,整个过程的计算量节省很多。在深层网络中,sigmoid函数反向传播时,很容易就会出现梯度消失的情况

4.2.4、池化层(Polling)

Pooling层主要的作用是特征提取,通过去掉Feature Map中不重要的样本,进一步减少参数数量。即通过池化层尽可能保留图像的主要特征,不会影响图像模型的最终效果,减少模型的复杂度,避免过拟合现象。

Pooling的方法很多,通常采用最大池化

  1. max_polling:取池化窗口的最大值
  2. avg_polling:取池化窗口的平均值

在这里插入图片描述

池化层计算: H2=(H1- F+2P)/S+1 ((高-过滤器大小+2零填充)/步长+1)

池化层也有窗口的大小以及移动步长,那么之后的输出大小怎么计算? 计算公式同卷积计算公式一样

计算:224x224x64,窗口为2,步长为2 输出结果?

H2 =(224 -2+ 2 * 0)/2 +1 = 112
w2 =(224- 2+ 2 * 0)/2 +1 =112

通常池化层采用2x2大小、步长为2窗口,零填充为默认P=0

例子2:

输入图片大小为200×200,依次经过一层卷积(kernel size 5×5,padding 1,stride 2) ,
pooling (kernel size 3×3,padding 0,stride 1),又一层卷积(kernel size 3×3,padding 1,stride 1)之后,

输出特征图大小为:
A.95
B.96
C.97
D.98
E.99
F.100

答案:C

h2=99 w2=99 d2=5 h3=97 d3=3 h4=97 d4=3

注:卷积层向下取整,池化层向上取整

池化层API

  • tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)
    • 输入上执行最大池数
    • value: 4-D Tensor形状[batch, height,width, channels]
    • channel:并不是原始图片的通道数,而是多少filter观察
    • ksize:池化窗口大小,[1,ksize, ksize,1]
    • strides:步长大小,[1,strides,strides,1]
    • padding:“SAME”",“VALID”,使用的填充算法的类型,默认使用 “SAME”

4.2.5、全连接层

全连接层计算:即构造权重和偏置

  1. tf.matmul(a, b, name=None)+bias
    • return:全连接结果,供交叉损失运算
  2. tf.train.GradientDescentOptimizer(learning_rate) :梯度下降(优化交叉熵)
    • learning_rate:学习率
    • method: minimize(loss):最小优化损失

如全连接:

y=w1x1+w2x2+…+b

y_predict[None,10]=X[None,784]*weights[784,10]+bias[10]

weights=tf.Variable(initial_value = tf.random_normal(shape = [784,10],stddev = 0.01))
bias=tf.Variable(initial_value = tf.random_normal(shape = [10],stddev = 0.1))
y_predict=tf.matmul(X,weights)+bias

4.2.6、卷积神经网络总结

在这里插入图片描述

4.3、案例:CNN-Mnist手写数字识别

4.3.1、网络层设计

自己设计一个简单的卷积神经网络做图像识别。由于神经网络的黑盒子特性,如果想自己设计复杂网络通常还是比较困难的,可以使用一些现有的网络结构如之前的GoogleNet、vGG等等。

简单的网络结构

在这里插入图片描述

具体参数

  1. 第一层
    • 卷积:32个filter、大小5 * 5、strides=1、padding=“SAME”。
    • padding=same 指输出图像和输入一样,故宽高都跟原来的值一样
    • 激活:Relu
    • 池化:大小2x2、strides2
  2. 第二层
    • 卷积:64个filter、大小5 * 5、strides=1、padding=“SAME”
    • 激活:Relu
    • 池化:大小2x2、strides2
  3. 全连接层

经过每一层图片数据大小的变化需要确定,Mnist输入的每批次若干图片数据[None,784],如果要经过卷积计算,需要变成[None, 28, 28,1] , 28 x 28=784

卷积网络API: tf.nn.conv2d( input,filter, strides=,padding=)

  1. 第一层卷积大层

    • c

    • 32个filter 大小F:5 * 5 步长S:1 padding=“SAME”

    • padding=same 指输出图像和输入一样,故宽高都跟原来的值一样

    • 输入图片形状 [betch, heigth,width, channel] ,要求:类型为float32,64

    • input:输入图像[None,28,28,1]

      filter:

      变量initial_value=random_normal(shape=[F,F,channels,K])

      ​ weights = tf.Variable(initial_value=tf.random_normal(shape=[5,5,1,32]))

      ​ bias = tf.Variable(initial_value=tf.random_normal(shape=[32]))

      strides: 步长1

      ​ [1,1,1,1]

      padding: "SAME”
      SAME”︰越过边缘取样

      “VALID”":不越过边缘取样

    • 输出形状:因为是padding=same,故输出宽高跟输入一致

      • [None,28,28,32]
    • 激活层: Relu tf.nn.relu(features, name=None)

    • 池化层: 大小2*2 步长2 ,默认padding=0 tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)

      • 输入形状:[None,28,28,32]
    • 输出形状:[None,14,14,32]

  2. 第二层卷积大层

    • 卷积层: tf.nn.conv2d( input,filter, strides=,padding=)

    • 64个filter 大小5 * 5 步长:1 padding=“SAME”

    • 输入现状: [None,14,14,32]

    • filter:

      变量initial_value=random_normal(shape=[F,F,channels,K])

      ​ weights = tf.Variable(initial_value=tf.random_normal(shape=[5,5,32,64]))

      ​ bias = tf.Variable(initial_value=tf.random_normal(shape=[64]))

      strides: 步长1

      ​ [1,1,1,1]

      padding: "SAME”
      SAME”︰越过边缘取样

      “VALID”":不越过边缘取样

    • 输出形状:因为是padding=same,故输出宽高跟输入一致

      • [None,14,14,64]
    • 激活层: Relu tf.nn.relu(features, name=None)

    • 池化层: 大小2*2 步长2 ,默认padding=0 tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)

      • 输入形状:[None,14,14,64]
    • 输出形状:[None,7,7,64]

  3. 全连接层

    • tf.reshape()
    • [None,7,7,64]-----转换为二阶矩阵-> pool2 = [None,7 * 7 * 64]
    • 最终的目标值形式[None,10]=[None,7 * 7 * 64] * [7 * 7 * 64 ,10](权重)
    • y_predict = tf.matmul(pool2,weights) + bias

CNN-Minst卷积神经网络简单案例:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

def create_weights(shape):
	# 定义权重和偏置  stddev 标准差
	return tf.Variable(initial_value = tf.random_normal(shape = shape,stddev = 0.01))

def create_model(x):
	# 构建卷积神经网络模型
	# 1、第一卷积大层
	with tf.variable_scope('conv1'):
		# 卷积层
		# 将x[None,784]进行形状上的修改  -1 会自动统计有多少张betch
		input_x=tf.reshape(x,shape = [-1,28,28,1])
		# 定义32个filter和偏置
		conv1_weights=create_weights(shape = [5,5,1,32])
		conv1_bias=create_weights(shape = [32])
		conv1_x=tf.nn.conv2d(input = input_x,filter = conv1_weights,strides = [1,1,1,1],padding="SAME")+conv1_bias

		# 激活层
		relu1_x=tf.nn.relu(conv1_x)

		# 池化层
		pool1_x=tf.nn.max_pool(value =relu1_x,ksize = [1,2,2,1],strides = [1,2,2,1],padding = "SAME")

	# 2、第一卷积大层
	with tf.variable_scope('conv2'):
		# 卷积层
		# 定义64个filter和偏置
		conv2_weights = create_weights(shape = [5, 5, 32, 64])
		conv2_bias = create_weights(shape = [64])
		conv2_x = tf.nn.conv2d(input = pool1_x, filter = conv2_weights, strides = [1, 1, 1, 1],padding = "SAME") + conv2_bias

		# 激活层
		relu2_x = tf.nn.relu(conv2_x)

		# 池化层
		pool2_x = tf.nn.max_pool(value = relu2_x, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = "SAME")

	# 全连接层
	with tf.variable_scope('full_connection'):
		# 改变形状,修改为二维数组类型
		x_fc=tf.reshape(pool2_x,shape = [-1,7*7*64])
		weights_fc=create_weights(shape = [7*7*64,10])
		bias_fc=create_weights(shape = [10])
		y_predict=tf.matmul(x_fc,weights_fc)+bias_fc
	return y_predict

def full_connection():
	# 用全连接对手写数字进行识别
	# 1、准备数据
	mnist=input_data.read_data_sets("./data/mnist_data",one_hot = True)
	#  用占位符定义真实数据
	X=tf.placeholder(dtype = tf.float32,shape = [None,784]) # 特征值
	y_true=tf.placeholder(dtype = tf.float32,shape = [None,10]) # 真实值
	# 2、构建模型 - 全连接
	y_predict=create_model(X)
	# 3、构造损失函数
	loss_list=tf.nn.softmax_cross_entropy_with_logits(logits = y_predict,labels = y_true)
	loss=tf.reduce_mean(loss_list)
	# 4、优化损失(梯度下降)
	optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss) # 默认0.01最多
	# 调优,修改学习率,优化器等
	# optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)
	# Adam优化器
	# optimizer=tf.train.AdamOptimizer(learning_rate = 0.01).minimize(loss)
	
	# 5、计算准确率 tf.argmax()计算最大值所在列数
	bool_list=tf.equal(tf.argmax(y_predict,axis = 1),tf.argmax(y_true,axis = 1))
	accuracy=tf.reduce_mean(tf.cast(bool_list,tf.float32))
	# 初始化变量
	init = tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		# 初始化变量
		sess.run(init)
		# 开始训练
		for i in range(300):
			# 获取真实值
			image, label = mnist.train.next_batch(100)
			# 因为optimizer返回的是None 所以用_,来接
			_, loss_value, accuracy_value = sess.run([optimizer, loss, accuracy], feed_dict = {
    
    X: image, y_true: label})
			print("第%d次的损失为%f,准确率为%f" % (i + 1, loss_value, accuracy_value))
	return None

# 准确率  比较输出的结果最大值与真实值最大值所在的位置
    # print(mnist.train.next_batch(1))
    # print(mnist.train.images[0])  # 查看特征值
    # print(mnist.train.labels[0])  # 目标值
    # one - hot  0 1 ...9
 
if __name__ == '__main__':
    # 如果你报numpy.ufunc size changed错误,尝试更新一下Numpy的版本
    # pip install numpy==1.16.0
	full_connection()
    
'''
第66次的损失为2.066249,准确率为0.200000
第67次的损失为1.938220,准确率为0.310000
第68次的损失为1.739915,准确率为0.450000
第69次的损失为1.615815,准确率为0.470000
'''    

网络的优化和改进

  1. 调整学习率、随机初始化的权重和偏置
  2. 调整优化器,优化损失函数
  3. 使用不同的激活函数
  4. 重新设计网络
  5. 使用梯度截断(在训练过程中检查和限制梯度的大小)
  6. 对于深度网络模型,添加batch normalization层或者droupout层
    1. batch normalization层 (批量标准化,让这层的网络输出的权重、偏置或者参数分布归一化,即分布在同样的规律内)
    2. droupout层 (使当前的神经元失效,减低模型的复杂度)
def weight__variables(shape ) :
	w = tf.Variable(tf.random_normal(shape=shape,mean=0.0,stddev=0.1)  # 调整平均值和标准差
	return w

卷积神经网络结构在imagenet比赛对比

在这里插入图片描述

卷积网络其它用途

  1. Yolo: GoogleNet+ bounding boxes
  2. SD: VGG + region proposalso
  3. Faster-RCNN: VGG, ResNet

4.4、案例:验证码图片识别

步骤分析

  1. 计算损失率
    1. 验证码图片(如NZPP)–》一个样本对应四个特征值。–》使用sigmoid交叉熵
    2. 手写数字图片识别((0~9之间的某一个数)–》一个样本对应一个特征值–》使用softmax交叉熵
    3. NZPP–》根据字母的顺序标记 [13,25,15,15] -->[4,26]
    4. –>[ [ 0, 0,0,0,0,o,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 ], [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0]]
  2. 数据集
    特征值 目标值怎么用
  3. 如何分类?
    1. 如何比较输出结果和真实值的正确性?如何衡量损失?
      手写数字识别案例
      softmax+交叉嫡
      [4,26] ->[4*26]
      sigmoid交叉嫡
      准确率如何计算?
      核心:对比真实值和预测值最大值所在位置手写
    2. 数字识别案例
      y_predict [None,10]
      tf.argmax(y_predict,axis=1)
      y_predict [None,4,26]
      tf.argmax(y_predict, axis=2/-1)
      [True,
      True,
      True,
      False] -> tf.reduce_all() -> False
  4. 流程分析
    1. 读取图片数据
      • filename ->标签值
    2. 解析csv文件,将标签值NZPP->[13,25,15,15]
    3. 将filename和标签值联系起来
    4. 构建卷积神经网络->y_predict
    5. 构造损失函数
    6. 优化损失
    7. 计算准确率
    8. 开启会话、开启线程

步骤分析

特征值目标值–模型

特征值:6000张图片-目标值―—对应

  1. 读取图片数据

    1. key, value = read(file_queue)key:文件名- labels.csv -目标值value:一个样本的内容
  2. 解析CSV文件,建立文件名和标签值对应表格

  3. 将一个样本的特征值和目标值一一对应

    1. 通过文件名查表(csv_data)
    2. 在这里插入图片描述
  4. 建立卷积神经网络模型== 》得出y_predict

  5. 计算sigmoid交叉嫡损失

  6. 优化

  7. 计算准确率

import tensorflow as tf
import pandas as pd
import numpy as np
import glob

# 1、读取图片数据
# key, value = read(file_queue)
# key: 文件名 - labels.csv - 目标值value:一个样本的内容
def read_pic():
	#1、构建文件名队列
	file_names=glob.glob('./data/GenPics/*.jpg')
	file_queue=tf.train.string_input_producer(file_names)
	#2、读取与解码
	reader=tf.WholeFileReader()
	filename,image=reader.read(file_queue)
	#解码阶段
	decoded_image=tf.image.decode_jpeg(image)
	#更新形状,将图片形状确定下来
	decoded_image.set_shape([20,80,3])
	#修改图片的类型
	cast_image=tf.cast(decoded_image,tf.float32)
	#3、批处理
	filename_batch,image_batch=tf.train.batch([filename,cast_image],batch_size = 100,num_threads = 1,capacity = 200)
	return filename_batch,image_batch

# 2、解析CSV文件,建立文件名和标签值对应表格
def parse_csv():
	# 读取文件
	csv_data=pd.read_csv('./data/GenPics/labels.csv',names = ['file_num','chars'],index_col = 'file_num')
	#根据字母生成对应数字
	# NZPP  [13,25,15,15]
	labels=[]
	for label in csv_data['chars']:
		letter=[]
		for word in label:
			# A在26字母中的序号为0 B为1
			letter.append(ord(word)-ord('A'))  # ord() 返回对应的ASCII数值
		labels.append(letter)

	csv_data['labels']=labels  # 更新labels列的内容

	return csv_data

# 3、将一个样本的特征值和目标值一一对应
# 通过文件名查表(csv_data)
def filename2label(filenames,csv_data):
	labels=[]

	for file_name in filenames:
		file_num="".join((list(filter(str.isdigit,str(file_name))))) # 获取csv的序号,从而找到目标值
		target_labels=csv_data.loc[int(file_num),'labels']  # 目标值
		labels.append(target_labels)
	return np.array(labels)

# 4、建立卷积神经网络模型 == 》得出y_predict
def create_weights(shape):
	# 定义权重和偏置  stddev 标准差
	return tf.Variable(initial_value = tf.random_normal(shape = shape,stddev = 0.01))

def create_model(x):
	# 构建卷积神经网络模型
	# x: [None,20,80,3]
	# 1、第一卷积大层
	with tf.variable_scope('conv1'):
		# 卷积层
		# 定义32个filter和偏置
		conv1_weights=create_weights(shape = [5,5,3,32])
		conv1_bias=create_weights(shape = [32])
		conv1_x=tf.nn.conv2d(input = x,filter = conv1_weights,strides = [1,1,1,1],padding="SAME")+conv1_bias
		# 激活层
		relu1_x=tf.nn.relu(conv1_x)
		# 池化层
		pool1_x=tf.nn.max_pool(value =relu1_x,ksize = [1,2,2,1],strides = [1,2,2,1],padding = "SAME")

	# 2、第一卷积大层
	with tf.variable_scope('conv2'):
		# 卷积层
		# 定义64个filter和偏置
		conv2_weights = create_weights(shape = [5, 5, 32, 64])
		conv2_bias = create_weights(shape = [64])
		conv2_x = tf.nn.conv2d(input = pool1_x, filter = conv2_weights, strides = [1, 1, 1, 1],padding = "SAME") + conv2_bias
		# 激活层
		relu2_x = tf.nn.relu(conv2_x)
		# 池化层
		pool2_x = tf.nn.max_pool(value = relu2_x, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = "SAME")

	# 全连接层
	with tf.variable_scope('full_connection'):
		# 改变形状,修改为二维数组类型
		# # 输入[None,10,40,32]-->[None,5,20,64]
		#[None, 5, 20, 64]-->[None, 5 * 20 * 64]
		#[None,5 * 20 * 64]*[5 * 20 * 64,4 * 26] = [None,4 * 26]
		x_fc=tf.reshape(pool2_x,shape = [-1,5*20*64])
		weights_fc=create_weights(shape = [5*20*64,4*26])
		bias_fc=create_weights(shape = [4*26])
		y_predict=tf.matmul(x_fc,weights_fc)+bias_fc
	return y_predict

if __name__ == '__main__':
	filename,image=read_pic()
	csv_data=parse_csv()

	# 1、准备数据
	x=tf.placeholder(tf.float32,shape = [None,20,80,3])
	y_true=tf.placeholder(tf.float32,shape = [None,4*26])
	# 2、构建模型
	y_predict=create_model(x)
	# 3、构建损失函数
	loss_list=tf.nn.sigmoid_cross_entropy_with_logits(labels = y_true,logits = y_predict)
	loss=tf.reduce_mean(loss_list)
	# 4、优化损失
	# optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(loss) # 梯度下降,最小化
	optimizer=tf.train.AdamOptimizer(learning_rate = 0.1).minimize(loss) # Adam优化器,最小化

	# 5、计算准确率
	equal_list=tf.reduce_all(tf.equal(tf.argmax(tf.reshape(y_predict,shape = [-1,4,26]),axis = 2),
									  tf.argmax(tf.reshape(y_true, shape = [-1, 4,26]), axis = 2)),axis=1)
	accuracy=tf.reduce_mean(tf.cast(equal_list,tf.float32))
	# 初始化变量
	init=tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		sess.run(init)
		# 开启线程
		coor=tf.train.Coordinator()
		threads=tf.train.start_queue_runners(sess = sess,coord = coor)
		for i in range(150):
			filename_value,image_value=sess.run([filename,image])
			labels=filename2label(filename_value,csv_data) # 将一个样本的特征值和目标值一一对应
			# 将目标值转换为one-hot编码
			labels_value=tf.reshape(tf.one_hot(labels,depth = 26),[-1,4*26]).eval()
			_,error,accuracy_value=sess.run([optimizer,loss,accuracy],feed_dict = {
    
    x:image_value,y_true:labels_value})
			print('第%d次训练损失为%f,准确率为%f'%(i+1,error,accuracy_value))

		# 回收线程
		coor.request_stop()
		coor.join(threads)

猜你喜欢

转载自blog.csdn.net/qq_44231797/article/details/125086565