发布时间:2024-01-08 08:30
这是黑马程序员3天带你玩转Python深度学习TensorFlow框架学习笔记
视频链接:黑马程序员3天带你玩转Python深度学习TensorFlow框架
学习目标:知道深度学习与机器学习的区别
区别:深度学习没有特征提取
特征方面
深度学习算法试图从数据中学习高级功能,这是深度学习的一个非常独特的部分。因此,减少了为每个问题开发新特征提取器的任务。适合用在难提取特征的图像、语音、自然语言处理领域
数据量和计算性能要求
机器学习需要的执行时间远少于深度学习,深度学习参数往往很庞大,需要通过大量数据的多次优化来训练参数
算法代表
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特点
官网:https://www.tensorflow.org/
TensorFlow程序通常被组织成一个构件图阶段和一个执行图阶段。
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
\'\'\'
图包含了一组tf.Operation代表的计算单元对象和tf.Tensor代表的计算单元之间流动的数据
一个图一个命名空间,互不干扰影响
通常tensorflow会默认帮我们创建一张图
查看默认图的两种方法:
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()
\'\'\'
默认图:
a_t的图属性:
c_t的图属性:
sess的图属性:
\'\'\'
自定义图
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的图属性:
c_new的图属性:
自定义图的运算结果: 50
sess的图属性:
\'\'\'
TensorBoard可视化工具
tensorflow可用于训练大规模深度神经网络所需的计算,使用该工具设计的计算往往复杂而深奥。为了更方便tensorflow程序的理解、调试与优化,tensorflow提供了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明确命名。张量名称的形式为“
. \"
. \"< i >\"是一个整数,它表示该张量在指令的输出中的索引
指令名称
一张图有对应自己的命名空间
tf.Graph对象为其包含的 tf.Operation对象定义的一个命名空间。TensorFlow 会自动为图中的每个指令选择一个唯一名称,用户也可以指定描述性名称,使程序阅读起来更轻松。我们可以以以下方式改写指令名称
例如,tf.constant(42.0, name=“answer”)创建了一个名为“answer\"的新tf.Operation并返回一个名为“answer:0”的tf.Tensor。如果默认图已包含名为\"answer\"的指令,则TensorFlow 会在名称上附加“1\"、“2”等字符,以便让名称具有唯一性。
会话创建
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)
# 开启会话上下文管理器(推荐)
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)
注: 使用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不存在的键。
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]
\'\'\'
TensorFlow的张量就是一个N维数组,类型为tf.Tensor。
标量:一个数字----0阶张量
向量:一维数组-----1阶张量
矩阵:二维数组------2阶张量
3阶张量
张量的类型
数据类型 | 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)
\'\'\'
创建固定值张量
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
1 类型改变
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的张量具有两种形状变换,动态形状和静态形状
静态形状:初始创建张量时的形状
什么情况下可以改变静态形状:
只有在形状还没有完全固定下来的情况下,如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
TensorFlow变量是表示程序处理的共享持久状态的最佳方法。变量通过tf.Variable类进行操作。
变量的特点:
tf.Variable(initia_value=None, trainable=True, collections=None, name=None)
注意:创建完变量后,需要进行变量初始化,且运行该初始化后,才能使用变量
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:
b:
c: Tensor(\"Add:0\", shape=(), dtype=int32)
a_value, 30
b_value, 50
c_value, 80
\'\'\'
tf.variable_scope()
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:
b:
c: Tensor(\"yourscore/Add:0\", shape=(), dtype=int32)
\'\'\'
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构建网络的核心模块,其中包含了添加各种层的函数,比如添加卷积层、池化层等。
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展示
回顾:根据数据建立回归模型,w1x1+w2x2+…+b = y,通过真实值与预测值之间建立误差,使用梯度下降优化得到损失最小对应的权重和偏置。最终确定模型的权重和偏置参数。最后可以用这些参数进行预测。
使用到的API
运算:
梯度下降优化:
tf.train.GradientDescentOptimizer(learning_rate)
梯度下降优化
learning_rate:学习率,一般为0~1之间比较小的值
method:
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
\'\'\'
学习率的设置、步数的设置与梯度爆炸
学习率越大,训练到较好结果的步数越小;学习率越小,训练到较好结果的步数越大。
但是学习过大会出现梯度爆炸现象。
如何解决梯度爆炸问题(深度神经网络当中更容易出现)
目的:在TensorBoard当中观察模型的参数、损失值等变量值的变化
1、收集变量
2、合并变量写入事件文件
创建事件文件 tf.summary.FileWriter(\'path, graph=sess.graph)
merged = tf.summary.merge_all() 合并变量
运行合并: summary = sess.run(merged),每次迭代都需运行
添加:FileWriter.add_summary(summary,i),i表示第几次的值
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()
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()
tf.train.Saver(var_list=None,max_to_keep=5)
步骤:
注意:
1、path,目录一定要提前创建
2、保存的是会话(里面是具体模型的参数)
3、保存模型的格式为 ckpt
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
\'\'\'
tf.app.flags(DEFINE),它支持应用从命令行接受参数,可以用来指定集群配置等。在tf.app.flags()下面有各种定义参数的类型
#定义一些常用的命令行参数
#训练步数
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\']
\'\'\'
shuffle 洗牌
第一阶段:构造文件名队列
第二阶段:读取与解码
第三阶段:批处理 (需要手动开启线程)
注意:这些操作需要启动运行这些队列操作的线程,以便我们在进行文件读取的过程中能够顺利进行入队出队操作
1、构造文件名队列
将需要读取的文件的文件名放入到文件名队列
tf.train.string_input_producer(string_tensor, shuffle=True)
2、读取与解码
从队列当中读取文件内容,并进行解码操作。
2.1、读取文件内容
阅读器默认每次只读取一个样本
具体来说:
文本文件默认一次读取一行,图片文件默认一次读取一张图片,二进制文件一次读取指定字节数(最好是一个样本的字节数),TFRecords默认一次读取一个example
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格式
解码阶段,默认所有的内容都解码成tf.uint8类型,如果之后需要转换成指定类型则可使用 tf.cast() 进行相应转换。
3 批处理
解码之后,可以直接获取默认的一个样本内容了,但如果想要获取多个样本,需要加入到新的队列进行批处理。
tf.train.batch(tensors, batch_size, num_threads = 1, capacity = 32,name=None)
读取指定大小(个数)的张量
tensors:可以是包含张量的列表,批处理的内容放到列表当中
batch_size:从队列中读取的批处理大小
num_threads:进入队列的线程数
capacity:整数,队列中元素的最大数量
return:tensors
tf.train.shuffle_batch() : 随机批量操作
以上用到的队列都是tf.train.QueueRunner对象。
每个QueueRunner都负责一个阶段,tf.train.start_queue_runners()函数会要求图中的每个QueueRunner启动它的运行队列操作的线程。(这些操作需要在会话中开启)
tf.train.start_queue_runners(sess=None, coord=None)
tf.train.Coordinator()
组成图片最基本单位是 像素
1、图片三要素
组成一张图片特征值是所有的像素值,有三个维度:图片长度、图片宽度、图片通道数
图片的通道数是什么?
描述一个像素点,如果是灰度图,那么只需要一个数值来描述它,就是单通道
如果一个像素点,有RGB三种颜色来描述它,及时三通道
灰度图:单通道,[长,宽,1]
彩色图片:三通道,[长,宽,3] 像素点为 长 X 宽 X 3
2、张量形状
在TensorFlow中如何用张量表示一张图片呢?
一张图片可以被表示成一个3D张量,即其形状为[height,width, channel],height就表示高,width表示宽,channel表示通道数。我们会经常遇到3D和4D的表示
为什么要缩放图片到统一大小?
在进行图像识别的时候,每个图片样本的特征数量要保持相同。所以需要将所有图片张量大小统一转换
缩小放大图片
tf.image**.resize_images**(images, size)
images:4-D形状[batch, height, width, channels]或3-D形状的张量[height, width, channels]的图片数据
size:1-D int32张量:new_height,new_width,图像的新尺寸
返回4-D格式或者3-D格式图片
存储:unit8(节省空间)
矩阵计算:float32(提高精度)
流程:
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;\\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
\'\'\'
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个字节
流程分析
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.]]
....]]]]
\'\'\'
TFRecords其实是一种二进制文件,虽然它不如其他格式好理解,但是它能更好的利用内存,更方便复制和移动,并且不需要单独的标签文件。即tfrecords 特征值和目标值是绑定在一起的
使用步骤:
文件格式 * . tfrecords
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
}
}
}
}
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]))}))
这种example结构很好地实现了数据和标签(训练的类别标签)或者其他属性数据存储在同一个文件中
example.SerializeToString() 将example 序列化到本地
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)
读取这种文件整个过程与其他文件一样,只不过需要有个解析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)
})
tfrecords文件读取步骤分析
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)
**人工神经网络(Artificial Neural Network,简写为ANN)也简称为神经网络(NN)。**是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功能的计算模型。经典的神经网络结构包含三个层次的神经网络。分别为输入层,输出层以及隐藏层。
其中每层的圆圈代表一个神经元,隐藏层和输出层的神经元有输入的数据计算后输出,输入层的神经元只是输入
神经网络的特点:
那么为什么设计这样的结构呢?首先从一个最基础的结构说起,神经元。以前也称之为感知机。神经元就是要模拟人的神经元结构。
一个神经元通常具有多个树突,主要用来接受传入信息;而轴突只有一条,轴突尾端有许多轴突末梢可以给其他多个神经元传递信息。轴突末梢跟其他神经元的树突产生连接,从而传递信号。这个连接的位置在生物学上叫做**\"突触”**。
感知机(PLA : Perceptron Learning Algorithm)
感知机就是模拟这样的大脑神经网络处理数据的过程。感知机模型如下图:
感知机是一种最基础的分类模型,类似于逻辑回归,不同的是,**感知机的激活函数用的是sign,而逻辑回归用的sigmoid。**感知机也具有连接的权重和偏置
神经网络解决多分类问题最常用的方法是设置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)
损失大小求平均
tf.reduce_mean(input_tensor)
计算张量的尺寸的元素平均值
交叉熵的优化:梯度下降
数据集介绍
文件说明:
网址: 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(\'mnist_data\', one_hot=True)
print(mnist.train.next_batch(1))
print(mnist.train.images[0]) # 查看特征值
print(mnist.train.labels[0]) # 目标值
mnist手写体识别网络层设计
我们采用只有一层,即最后一个输出层的神经网络,也称之为全连接(full connected) 层神经网络
全连接层计算:即构造权重和偏置
计算准确率:对One-hot概率 求平均值
全连接分析:
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
\'\'\'
输入层
隐藏层:卷积层、激活层、池化层、全连接层
输出层
神经网络(neural networks)的基本组成包括输入层、隐藏层、输出层。而卷积神经网络的特点在于隐藏层分为卷积层、激活层和池化层(pooling layer,又叫下采样层subsample)。
卷积神经网络的结构
卷积核又叫 filter、过滤器、模型参数、卷积单元
卷积神经网络中每层卷积层由若干卷积单元(卷积核)组成,每个卷积单元的参数都是通过反向传播算法最佳化得到的。
卷积运算的目的是特征提取,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征。
1、卷积核(Filter)的四大要素
卷积核个数
卷积核大小
卷积核步长
卷积核零填充大小
接下来我们通过计算案例讲解,假设图片是黑白图片(只有一个通道)
2、卷积核计算-大小
卷积核大小一般为 1 * 1 3 * 3 5 * 5
卷积核我们可以理解为一个观察的人,带着若干权重和一个偏置去观察,进行特征加权运算。
下图只有权重,少了偏置,一般情况下都要加上偏置!
通常的卷积核大小 1,3,5,是经过研究人员实验证明比较好的效果。这个人观察之后会得到一个运算结果,
那么这个人想观察所有这张图的像素怎么办?那就需要平移(即步长):
3、步长
需要去平移卷积核观察这张图片,需要的参数就是步长。
假设移动的步长为一个像素,那么最终这个人观察的结果以下图为例:
5x5的图片,3x3的卷积大小去一个步长运算得到3x3的大小观察结果
如果移动的步长为2那么结果是这样
5x5的图片,3x3的卷积大小,2个步长运算得到2x2的大小观察结果
4、卷积核个数
不同的卷积核带的权重和偏置都不一样,即随机初始化的参数
那么如果在某一层结构当中,不止是一个人观察,多个人(卷积核)一起去观察。那就得到多张观察结果。
也就是说,一个卷积核得到一个观察结果,多个卷积核就是多个观察结果
5、零填充大小
Filter观察窗口的大小和移动步长有时会导致超过图片像素宽度!
解决办法:
零填充就是在图片像素外围填充一圈值为0的像素。
6、计算输出大小
如果已知输入图片形状,卷积核数量,卷积核大小,以及移动步长,那么输出图片形状如何确定?
通过一个例子来理解上面的公式
计算案例:
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
随着神经网络的发展,大家发现原有的sigmoid等激活函数并不能达到好的效果,所以才去新的激活函数。
不同激活函数网站演示:http://playground.tensorflow.org
Relu函数
效果:
Relu激活函数API
为什么采用新的激活函数
Pooling层主要的作用是特征提取,通过去掉Feature Map中不重要的样本,进一步减少参数数量。即通过池化层尽可能保留图像的主要特征,不会影响图像模型的最终效果,减少模型的复杂度,避免过拟合现象。
Pooling的方法很多,通常采用最大池化
池化层计算: 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
全连接层计算:即构造权重和偏置
如全连接:
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
自己设计一个简单的卷积神经网络做图像识别。由于神经网络的黑盒子特性,如果想自己设计复杂网络通常还是比较困难的,可以使用一些现有的网络结构如之前的GoogleNet、vGG等等。
简单的网络结构
具体参数
经过每一层图片数据大小的变化需要确定,Mnist输入的每批次若干图片数据[None,784],如果要经过卷积计算,需要变成[None, 28, 28,1] , 28 x 28=784
卷积网络API: tf.nn.conv2d( input,filter, strides=,padding=)
第一层卷积大层
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,故输出宽高跟输入一致
激活层: 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,32]
第二层卷积大层
卷积层: 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,故输出宽高跟输入一致
激活层: Relu tf.nn.relu(features, name=None)
池化层: 大小2*2 步长2 ,默认padding=0 tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)
输出形状:[None,7,7,64]
全连接层
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
\'\'\'
网络的优化和改进
def weight__variables(shape ) :
w = tf.Variable(tf.random_normal(shape=shape,mean=0.0,stddev=0.1) # 调整平均值和标准差
return w
卷积神经网络结构在imagenet比赛对比
卷积网络其它用途
步骤分析
步骤分析
特征值目标值–模型
特征值:6000张图片-目标值―—对应
读取图片数据
解析CSV文件,建立文件名和标签值对应表格
将一个样本的特征值和目标值一一对应
建立卷积神经网络模型== 》得出y_predict
计算sigmoid交叉嫡损失
优化
计算准确率
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)