TensorFlow基础操作+手写回归+模型的保存于加载
深度学习介绍
什么是深度学习?
- 先把这四个字拆解成两个词,“深度”和“学习”,然后在逐一说明。
- 学习
- “学习”是我们从小就接触的词,每天听着好好学习,天天向上的教诲。小时候的学习就是上课,做题,最终通过考试验证了学习的效果。抽象的说,学习就是认知的过程,从未知到已知的探索和思考。比如从最早的学习,1+1=2,想想我们是怎么学习的?伸出一只手指,再伸出一只手指,数一数,两只手指那就是2。
- 学习就是从未知到已知的探索和思考。这里提前再定义一个概念,输入和输出,输入就是已知的信息,输出就是最终获得的认知的结果。这里的1和加号+,就是输入,而得到的计算结果2就是输出。所以,任何的从已经有的信息,无论是通过计算,判断,推理而后得到一个认知的过程都可以称为“学习”。
- 那么为什么有的人学习能力好,成绩高,但有的人成绩就没那么好呢。这经常的被解释为学习方法,思考过程,经验不同而导致的差异,可以统一归为“学习策略”,好的学习策略会更快更准确的得到认知的结果,而不好的学习策略可能会花费更多的时间或者获得错误的结论。那么在计算机的学习中,有没有一个比较好的学习策略呢?
- 神经网络:
- 现实世界中很多的问题都可以归为分类或者回归的问题。而研究此类问题,学术界研究出来一种叫做“神经网络”的学习策略。
- 这个词听起来,就知道和人脑有着一些关系。在人脑中负责活动的基本单元是“神经元”,它以细胞体为主体,由许多向周围延伸的不规则树枝状纤维构成的神经细胞,我们把神经元的结构想象成一棵枯树的枝干就可以了。人脑中含有上百亿个神经元,而这些神经元互相连接成一个更庞大的结构,就称为“神经网络”。学术界试图模仿人脑的“神经网络“建立一个类似的学习策略,也取名为”神经网络“。下图就是一个神经网络的大致结构
-
-
- 从x1,x2,x3输入到输出的过程,这里又定义了一个层次的概念,譬如上图就包括四层,包含最左边的输入层,和最右边的输出层,如果这是一道选择题的话,那么题目就是输入层,而ABCD的选择结果就是输出层,如上图的L1和L4分别是输入层和输出层。而选择题解题的过程是不写出来的,这个解题过程我们叫做”隐藏层“,这里L2和L3就是隐藏层,题目越难,给出的解题条件的信息可能是越多的,而解题所需要的过程就越复杂的,也就可能需要更多的”隐藏层“来计算最终的结果。
-
- 深度
- 最终要来解释什么是深度学习的”深度“了,就是从”输入层“到”输出层“所经历层次的数目,即”隐藏层“的层数,层数越多,网络的深度也越深。所以越是复杂的选择问题,越需要深度和层次越多。当然,除了层数多外,每层”神经元“,也就是如上图,橙色小圆圈的数目也要多。例如,AlphaGo的策略网络是13层。每一层的神经元数量为192个。
总结一句话,深度学习就是用多层次的分析和计算手段,得到结果的一种方法
深度学习代表性的应用
- 图像识别(图像理解)
- 给机器一张图片让机器可以理解图片的内容
- 人脸识别
- 验证码识别
- 给机器一张图片让机器可以理解图片的内容
- 语音识别
- 自然语言处理NLP
- 理解人类的语言
- 情感分析
- 智能对话
- 图像识别和NLP的结合:
- 理解人类的语言
- 机器自主(无人驾驶)
机器学习和深度学习的区别
- 算法方面:
- 机器学习的算法主要是处理回归和分类的相关问题
- 深度学习算法主要是处理较为复杂的相关事物的处理,比如NLP,图像识别,语音识别等等
- 应用领域方面:
- 在NLP,图像识别,语音识别等领域中使用机器学习处理效果不好,甚至有时候还不如人工的识别,但是深度学习可以达到很好的效果。且深度学习已经被应用到了计算机的视觉、语音识别、NLP、音频识别于生物信息学等领域并获取了极好的结果。
- 总结:机器学习和深度学习主要的区别就是算法和效率的不同。
- 深度学习框架:
- TensorFlow
- Caffe
- Torch
- ...
- TensorFlow在众多框架中的受关注度和使用人数是最多的一个框架,因此我们主要对其进行学习!
TensorFlow
- 认识TensorFlow(中文社区:http://www.tensorfly.cn/)
- 谷歌大脑的产物,谷歌大脑最初是由吴恩达带领的。
- 在谷歌内部很多产品中都应用了TensorFlow,比如AlphaGo,Gmail,谷歌地图等等。
- 于2015年11月开源问世,17年2月发布了1.0版本
- 最新版本2.0,但是建议使用1.0版本,较为稳定
- TensorFlow的特点:
- 真正的可移植性
- 引入各种计算设备的支持,包括CPU,GPU,以及能够很好的运行在各种系统的移动端
- 多语言支持
- 支持C++,python,R语言等
- 高度的灵活性和效率
- 边学习边体验
- 支持
- 由谷歌提供支持,谷歌希望其可以成为机器学习研究和开发人员通用的语言。
- 真正的可移植性
环境安装
- cpu和gpu的区别
- CPU,在电脑中起着控制计算机运行的作用,是电脑的中央处理器。
- GPU是一个附属型的处理器,主要处理计算机中与图形计算有关的工作,并将数据更好地呈现在显示器中。
- 总结:使用GPU的数据处理要比CUP效率更快
- TensorFlow可以选择性的安装基于CPU的和GPU的。目前windows的GPU对TensorFlow的包容性不是特别好,会有效部分的bug,因此课上我们使用cpu版本。
- 在cpu版本和gpu版本的代码编写几乎一致,如果想把cpu编程gpu需要要添加一行代码即可!
- 安装教程:
- pip install -U --ignore-installed wrapt enum34 simplejson netaddr
- pip install --upgrade setuptools
- pip install tensorflow==1.14.0
Tensorflow进阶
-
使用 TensorFlow, 你必须明白 TensorFlow:
- 图:TensorFlow 是一个编程系统(一个编程语言),使用图 (graph) 来表示一个计算任务或者计算单元.
- 计算任务:实现一个加法器,那任意值的加法运算就是一个计算任务
- 会话Session:图必须要在会话中进行执行
- tensor(张量:数组,阶:维度):就是numpy中的nd.array(数组),只不过从新起了一个名字而已!因此tensor一种数据类型。每个 Tensor 是一个类型化的数组. 或者是op的返回值,就是TensorFlow中的数据。tensor也可以被称为张量,那么张量的阶就是数组的维度。
- 节点op(operation):图表示TensorFlow的计算任务,而一个计算任务的具体实现操作就是op。一个op需要使用0个或者多个Tensor来执行计算且会产生0个会多个Tensor,简单点来说TensorFlow的API定义的函数都是op。
- 图:TensorFlow 是一个编程系统(一个编程语言),使用图 (graph) 来表示一个计算任务或者计算单元.
-
综述:
- 图描述了tensorflow计算的过程。为了进行计算, 图必须在会话里被启动.会话将图的op分发到诸如 CPU 或 GPU 之类的设备上, 图同时提供执行op的方法. 这些方法执行后, 将产生的 tensor 返回。
- 实现一个加法运算
- add(a,b)
定义a,b俩个tensor(张量)
import tensorflow as tf tf.__version__ # '1.14.0' # 定义a,b俩个tensor(张量) a = tf.constant(1.0) b = tf.constant(2.0) print(a,b) Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
调用add的函数(op)实现两数相加
# 调用add的函数(op)实现两数相加 import tensorflow as tf a = tf.constant(3) b = tf.constant(4) # 定义了一个op sum = tf.add(a,b) print(sum) Tensor("Add:0", shape=(), dtype=int32)
在会话中启动图
# 在会话中启动图 import tensorflow as tf # 定义a,b两个tensor(张量) a = tf.constant(3) b = tf.constant(4) # 定义了一个op图,图对应一系列操作 sum = tf.add(a,b) # 开启一个绘画,在绘画中执行图 with tf.Session() as sess: print(sess.run(sum)) # 7
获取图
- tf.get_default_graph()
- op,session,tensor的graph属性
# 在会话中启动图 import tensorflow as tf # 定义a,b两个tensor(张量) a = tf.constant(3) b = tf.constant(4) # 定义了一个op图,图对应一系列操作 sum = tf.add(a,b) # 开启一个绘画,在绘画中执行图 with tf.Session() as sess: print(sess.run(sum)) # 7 print(tf.get_default_graph()) # 返回当前的图 print(sum.graph) # 返回当前的图 print(a.graph) # 返回当前的图 print(b.graph) # 返回当前的图 print(sess.graph) # 返回当前的图 7 <tensorflow.python.framework.ops.Graph object at 0xb376c7048> <tensorflow.python.framework.ops.Graph object at 0xb376c7048> <tensorflow.python.framework.ops.Graph object at 0xb376c7048> <tensorflow.python.framework.ops.Graph object at 0xb376c7048>
创建新图(创建一个单独的计算任务单元)
- tf.Graph():新图对应的操作必须作用在上下文中!
- 上下文写法:with g.as_default()
import tensorflow as tf g = tf.Graph() # 创建一个新图 with g.as_default(): d = tf.constant([1,2,3]) c = tf.constant([4,5,6]) sum_ = tf.add(c,d) print(d.graph) a = tf.constant(3) b = tf.constant(4) sum = tf.add(a,b) with tf.Session() as sess: # 这里如果不采取操作,用的还是默认图 print(sess.run(sum)) print(sess.graph) <tensorflow.python.framework.ops.Graph object at 0x0000021AA4A13B00> 7 <tensorflow.python.framework.ops.Graph object at 0x0000021AA49347F0>
会话Session
- 会话就是运行图的一个资源类,运行的是默认的图,当然也可以单独运行指定的图
- 会话的资源包含如下资源,会话结束后需要关闭对应的资源,因此需要在上下文资源管理器中使用会话
- tf.Variable
- tf.QueueBase
- tf.ReaderBase
- TensorFlow可以分为前端系统和后端系统
- 前端系统:定义图的结构(定义张量tensor,定义op等)
- 后端系统:运行图
- 会话的作用:
- 运行图的结构
- 分配计算资源
- 掌握资源:会话只可以运行其对应图中的资源
- Session(graph=g)指定图
g = tf.Graph() # 创建一个新图 with g.as_default(): d = tf.constant([1,2,3]) c = tf.constant([4,5,6]) sum_ = tf.add(c,d) print(d.graph) a = tf.constant(3) b = tf.constant(4) sum = tf.add(a,b) with tf.Session(graph=g) as sess: # 参数指定新图 print(sess.run(sum_)) print(sess.graph) <tensorflow.python.framework.ops.Graph object at 0x0000021AA4BAA240> [5 7 9] <tensorflow.python.framework.ops.Graph object at 0x0000021AA4BAA240>
重载运算符
- session只可以运行op或者tensor,不可以运行其他类型的数据,但是如果一个tensor或者op使用某一个运算符和其他类型数据相加,则返回的为op或者tensor类型
a = tf.constant(3) b = 4 sum = a + b print(sum) Tensor("add_8:0", shape=(), dtype=int32)
run方法
- s.run(fetches, feed_dict=None,graph)
- fetches:就是运行的op和tensor,例如run(sum)也可以run([a,b,sum])
- feed_dict:程序在执行的时候,不确定输入数据是什么,提前使用placeholder占个位
- 给session提供实时运行的数据
# 应用场景:训练模型的时候,样本数量不固定,那么如何运行样本数据呢? import tensorflow as ts # 创建了一个op,placeholder为占位对象,现在占据了一个n行三列的位置 feature = ts.placeholder(dtype=tf.float32,shape=(None,3))# None为任意行数 with tf.Session() as s: print(s.run(feature,feed_dict={feature:[[1,2,3],[4,5,6],[4,5,6]]})) [[1. 2. 3.] [4. 5. 6.] [4. 5. 6.]]
张量相关的api
- 自动生成张量:
- tf.zeros(shape=(3,2))
- tf.ones()
- tf.random_normal(shape,mean,stddev)
- mean:平均值
- 方差
- 改变类型:
- tf.cast(x,dtype)
arr = tf.zeros(shape = (4,5)) rand_arr = tf.random_normal(shape=(3,4),mean=2,stddev=2) print(rand_arr) Tensor("random_normal_5:0", shape=(3, 4), dtype=float32)
变量
- 概念:变量也是一种op,是一种特殊的张量,能够进行持久化存储(普通张量不行),变量的值为张量。
- API:tf.Variable(initial_value,name,trainable,)
- initial_value变量接收的值(张量)
- 在手写线性回归时讲解
- 必须进行变量的显示的初始化,返回一个初始化变量的op:
- init_op = tf.global_variables_initializer()
import tensorflow as tf # 变量使用步骤 # 1.实例化变量对象,给它赋一个默认的输入值 # 2.对变量进行显示化的展示 # 3.通过绘画,对显示化的变量进行展示,才能够使用定义好的变量 # 1.实例化变量对象,给它赋一个默认的输入值 a = tf.constant([1,2,3,4,5]) var = tf.Variable(initial_value=a) # 2.对变量进行显示化的展示 # 显示的初始化 init_op = tf.global_variables_initializer() with tf.Session() as s: # 3.通过绘画,对显示化的变量进行展示,才能够使用定义好的变量 s.run(init_op) print(s.run(var)) print(a.eval()) # 相当于s.run(a) [1 2 3 4 5] [1 2 3 4 5]
线性回归原理回顾
- 找寻目标值和特征值之间存在的关系,求出w和b即可。
- y = (x1w1 + x2w2...+xn*wn)+b
- 损失函数(均方误差):表示真实值和预测值之间的误差
- 使用梯度下降将损失函数的误差值最小即可
实现流程
- 准备最简单的特征值和目标值
- y = 0.8*x+1.5,然后我们需要让手写的线性回归求出w(0.8)和b(1.5)
- 建立模型
- 随机初始化一个w和b
- 因为模型一开始也不知道w和b应该是什么,只能随机初始化一个,然后随着梯度下降逐步迭代更新w和b
- 然后求出预测值:y_pred = wx+b
- 随机初始化一个w和b
- 求出损失函数(误差)的结果
- 均方误差:y是真实值y'是预测值
- ((y1-y1')^2+(y2-y2')^2+...+(yn-yn')^2)/n
- 均方误差:y是真实值y'是预测值
- 使用梯度下降降低损失(梯度下降不需要手动实现,TensorFlow中有对应的API,只需要指定学习率即可)
- TensorFlow运算的API
- 矩阵运算:tf.matmul(a,b)
- 平方:tf.square(x)
- 均值:tf.reduce_mean()
- 梯度下降API
- 类:tf.train.GradientDescentOptimizer(learning_rate)
- learning_rate:需要手动指定学习率
- 类:tf.train.GradientDescentOptimizer(learning_rate)
注意:
- 线性回归是一个迭代算法,那么意味着在每次梯度下降的过程中y=wx+b中的w和b是在不停的变化的逐步在优化这两个值。因此记住,w和b是需要不断变化的在梯度下降的过程中!
- 结论:
- 在TensorFlow中随机初始化的w和b只可以用变量定义不可以用张量,因为,变量可以自身变化,而张量不行!
- 或者说模型的参数只可以用变量定义不可以用张量定义!!!
- tf.Variable(initial_value=None,trainable=True)
- trainable=True表示的含义就是在训练的过程中变量的值可以跟随训练而实时变化!!!
import tensorflow as tf # 第一步:准备数据 # tf.random_normal 返回一个指定形状的张量 x = tf.random_normal(shape=(100,1),mean=1.5,stddev=0.75) # 特征数据 y_true = tf.matmul(x,[[0.8]])+1.5 # 标签数据 w=0.8,b=1.5 # 第二步:建立模型,随机初始化一个w和b weight = tf.Variable(tf.random_normal(shape=(1,1),mean=1.2,stddev=0.5)) b = tf.Variable(2.5) # 预测结果 y_pred = tf.matmul(x,weight)+b # 第三步:损失函数就是均方误差 loss = tf.reduce_mean(tf.square(y_true - y_pred)) # 第四步.梯度下降优化损失 train_op = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss) # 定义的变量进行显示初始化 init_op = tf.global_variables_initializer() with tf.Session() as s: s.run(init_op) # 先运行变量的初始化操作 print('随机初始化的w=%f,b=%f'%(weight.eval(),s.run(b))) for i in range(1,401):# 固定迭代的次数 s.run(train_op) if i%20 == 0: print('第%d次优化后的w=%f,b=%f'%(i,weight.eval(),b.eval())) 随机初始化的w=0.816529,b=2.500000 第20次优化后的w=0.572955,b=1.896295 第40次优化后的w=0.680251,b=1.720152 第60次优化后的w=0.734756,b=1.615458 第80次优化后的w=0.764612,b=1.561906 第100次优化后的w=0.780714,b=1.533197 第120次优化后的w=0.789753,b=1.517574 第140次优化后的w=0.794484,b=1.509686 第160次优化后的w=0.797118,b=1.505182 第180次优化后的w=0.798350,b=1.502849 第200次优化后的w=0.799147,b=1.501556 第220次优化后的w=0.799511,b=1.500829 第240次优化后的w=0.799743,b=1.500452 第260次优化后的w=0.799859,b=1.500251 第280次优化后的w=0.799925,b=1.500136 第300次优化后的w=0.799960,b=1.500069 第320次优化后的w=0.799978,b=1.500037 第340次优化后的w=0.799988,b=1.500021 第360次优化后的w=0.799994,b=1.500011 第380次优化后的w=0.799996,b=1.500006 第400次优化后的w=0.799998,b=1.500003
模型保存与加载
代码报错(NotFindError),问题在于模型加载的路径或者在代码头部加上tf.reset_default_graph()
- 保存的其实就是w和b
- 定义saver的op
- saver = tf.train.Saver()
- 在会话中运行保存函数:
- saver.save(session,'path')
- path:表示保存模型的路径,携带模型的名称(任意名称)
- saver.save(session,'path')
- 在会话运行时加载模型:
- if os.path.exists('./xxx/checkpoint'):
- saver.restore(session,'path')
- if os.path.exists('./xxx/checkpoint'):
- 模型的加载
import os tf.reset_default_graph() # 如果加载保存好的模型时出现notfinderror就加上该行代码 # 第一步:准备数据 x = tf.random_normal(shape=(100,1),mean=1.5,stddev=0.75) # 特征数据 y_true = tf.matmul(x,[[0.8]])+1.5 # 标签数据 w=0.8,b=1.5 # 第二步:建立模型,随机初始化一个w和b weight = tf.Variable(tf.random_normal(shape=(1,1),mean=1.2,stddev=0.5),name='w') b = tf.Variable(2.5,name='b') # 预测结果 y_pred = tf.matmul(x,weight)+b # 第三步:损失函数就出均方误差 loss = tf.reduce_mean(tf.square(y_true-y_pred)) # 第四步.梯度下降优化损失 train_op = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss) # 定义的变量进行初始化 init_op = tf.global_variables_initializer() # 保存模型的op saver = tf.train.Saver() with tf.Session() as s: s.run(init_op) # 先运行变量的初始化操作 if os.path.exists('./imgs/checkpoint'):# 加载模型 print('模型已经加载读取完毕') saver.restore(s,'./imgs/model') w = s.run('w:0') b = s.run('b:0') print(w,b) # 就是从保存好的模型文件中读取出来的两个值 else: # 保存模型 print('随机初始化的w=%f,b=%f'%(weight.eval(),s.run(b))) for i in range(1,401):# 固定迭代的次数 s.run(train_op) if i%20 == 0: print('第%d次优化后的w=%f,b=%f'%(i,weight.eval(),b.eval())) saver.save(s,'./imgs/model')