这里面最重要的是keras模块
import tensorflow as tf
import matplotlib.pyplot as plt
# 定义正确的权重和偏置
TRUE_W = 3.0 #这权值里我们是要通过模型预测出权重
TRUE_b = 2.0 #这权值里我们是要通过模型预测出偏置
# 制作训练数据,添加一些噪声进去
NUM_EXAMPLES = 100
inputs = tf.random.normal(shape=[NUM_EXAMPLES]) #制作的数据集
noise = tf.random.normal(shape = [NUM_EXAMPLES])
outputs = inputs * TRUE_W + TRUE_b + noise #这是我的标签 输出数据:线性关系 + 噪声
plt.scatter(inputs, outputs, label='Original data')
plt.show()
#定义模型和损失函数
class Model(object):
def __init__(self): #初始化参数
self.W = tf.Variable(10.0) #初始值为 10.0
self.b = tf.Variable(-5.0)
#基于函数定义的模型
def __call__(self, inputs):
return self.W * inputs + self.b # 线性模型
#设计它的损失函数
def compute_loss(y_true, y_pred):
return tf.reduce_mean(tf.square(y_true-y_pred)) # 均方误差MSE
model = Model() # 初始化模型
def plot(epoch): # 定义可视化函数,传入epoch参数
plt.scatter(inputs, outputs, c='b') # 画散点图,传入inputs,outputs数据集,c是颜色为blue
plt.scatter(inputs, model(inputs), c='r') # 传入inputs, 预测的model(inputs),c是红色
plt.title("epoch %2d, loss = %s" %(epoch, str(compute_loss(outputs, model(inputs)).numpy())))
plt.legend() # 加上图例
plt.draw() # 打开交互模式工作,如果更改了数据或格式,则允许图表本身更改.
plt.ion() # 打开交互模式
plt.pause(1) # 暂停一秒
#plt.pause()会把它之前的所有绘图都绘制在对应坐标系中,而不仅仅是在当前坐标系中绘图;
#plt.pause(time)函数也能实现窗口绘图(不需要plt.show),但窗口只停留time时间便会自动关闭,然后再继续执行后面代码
plt.close()
# 使用梯度下降法训练模型
learning_rate=0.2 #设置损失函数的学习率
epoch=30 # 训练轮数,1个epoch是一整个数据集,bachsize是一次性送入网络中的样本数量,用总的数据集/bachsize=迭代数
for i in range(30): #进行for循环
with tf.GradientTape() as tape:
loss = compute_loss(outputs, model(inputs)) # 计算损失
dW, db = tape.gradient(loss, [model.W, model.b]) # 计算梯度
model.W.assign_sub(learning_rate * dW) # 更新权重
model.b.assign_sub(learning_rate * db) # 更新权重
print("=> epoch %2d: w_true= %.2f, w_pred= %.2f; b_true= %.2f, b_pred= %.2f, loss= %.2f" %(
epoch+1, TRUE_W, model.W.numpy(), TRUE_b, model.b.numpy(), loss.numpy()))
plot(epoch + 1)
即刻执行(Eager execution)是TensorFlow2.0的新特性,如同python解释器一样,执行即可获得计算结果,不需要手动建立图结构和会话,与python的兼容性更强, 为快速搭建和测试算法模型提供了便利
tensorflow2.0默认是Eager execution模式;
eager模式对numpy的支持很友好,具体如下:
numpy的操作可以接受Tensor作为参数;
Tensorflow的数学操作会将python对象和numpy的arrays转换成Tensor;
tf.Tensor.numpy方法返回numpy的ndarray.
可逐行动态控制流,逐行控制代码的运行;
一切皆函数,无须手动搭建tensorflow数据结构。
import tensorflow as tf# 导入TensorFlow
scalar_tf=tf.constant(3.14)#创建张量
m=tf.add(scalar_tf,scalar_tf)#执行操作
m
# <tf.Tensor: shape=(), dtype=float32, numpy=6.28000020980835>
# print(m)
# tf.Tensor(6.28, shape=(), dtype=float32)
# print(m.numpy())
# 6.28000020980835
默认情况下,Eager execution处于启用状态
可以用tf.executing_eargerly()查看Eager Execution当前的启动状态,返回True则是开启,False是关闭
可以用tf.compat.v1.enable_eager_execution()启动eager模式。
tf.compat.v1.executing_eagerly() # 查看状态 默认是开启的
# tf.compat.v1.disable_eager_execution() # 关闭
# tf.compat.v1.executing_eagerly() # 查看状态
# tf.compat.v1.enable_eager_execution() # 开启eager模式 必须在程序的最开始调用 重启内核
# tf.compat.v1.executing_eagerly() # 查看状态
图是TensorFlow最基本的结构,一切计算都是基于图结构运行的,图结构包含张量(Tensor)和操作(Operation)
TensorFlow1.x采用的是静态计算图,需要先创建计算图,然后再开启会话Session,显式执行计算图
在TensorFlow2.0中,采用的是动态计算图,即每使用一个算子后,该算子会被动态加入到默认计算图中即即执行,无需开启Session
使用动态计算图即Eager Excution的优势是方便程序调试。使用动态计算图的缺点是运行效率相对会低一些
因为使用动态图会有许多次Python进程和TensorFlow的C++进程之间的通信
而静态计算图构建完成之后几乎全部在TensorFlow内核上使用C++代码执行,效率更高
此外静态图会对计算步骤进行一定的优化,剪去与结果无关的计算步骤
如果需要在TensorFlow2.0中使用静态图,可以使用@tf.function装饰器将普通Python函数转换成对应的TensorFlow计算图构建代码
运行该函数就相当于在TensorFlow1.x中用Session执行代码
使用tf.function构建静态图的方式叫做 Autograph
计算图由节点(nodes)和线(edges)组成
节点表示操作符Operator,线表示计算间的依赖关系
实线表示有数据传递依赖,传递的数据即张量
虚线通常可以表示控制依赖,即执行先后顺序
静态计算则意味着程序在编译执行时将先生成神经网络的结构,然后再执行相应操作
从理论上讲,静态计算这样的机制允许编译器进行更大程度的优化,但是这也意味 着你所期望的程序与编译器实际执行之间存在着更多的代沟
这也意味着,代码中的错误将 更加难以发现(比如,如果计算图的结构出现问题,你可能只有在代码执行到相应操作的时 候才能发现它)
import tensorflow as tf
g = tf.compat.v1.Graph()
with g.as_default():
x = tf.compat.v1.placeholder(name='x', shape=[], dtype=tf.string)
y = tf.compat.v1.placeholder(name='y', shape=[], dtype=tf.string)
z = tf.strings.join([x,y],name = "join",separator = " ")
with tf.compat.v1.Session(graph = g) as sess:
# fetches的结果非常像一个函数的返回值,而feed_dict中的占位符相当于函数的参数序列。
result = sess.run(fetches = z,feed_dict = {x:"hello",y:"world"})
print(result)
动态计算意味着程序将按照我们编写命令的顺序进行执行
这种机制将使得调试更加容易,并且也使得我们将大脑中的想法转化为实际代码变得更加容易
# 动态计算图在每个算子处都进行构建,构建后立即执行
x = tf.constant("hello")
y = tf.constant("world")
z = tf.strings.join([x,y],separator=" ")
print(z.numpy())
tf.print(z)
TensorFlow 2.0主要使用的是动态计算图和Autograph
Autograph机制通过@tf.function装饰器,可以将动态图转换成静态计算图,达到兼顾执行效率和编码效率的目的
AutoGraph将Python控制流转换为TensorFlow表达式,允许用户在装饰有tf.function的函数中编写常规Python,例如while,if,break,continue和return,支持嵌套
这意味着可以在while和if语句的条件下使用Tensor表达式,或者在for循环中迭代Tensor
注意:有一些编码规范需要遵循
使用tf内部函数,避免直接使用python函数,因为无法嵌入进计算图;
避免定义 tf.Variable, 以为它是动态的,每次迭代都会更新;
不可以修改列表字典等数据结构。
import tensorflow as tf
import numpy as np
@tf.function(autograph=True)
def myadd(a,b):
for i in tf.range(3):
tf.print(i)
c = a+b
print("tracing")
return c
# 执行过程
# 第一步,创建一个静态计算图,跟踪执行一遍函数体中的Python代码,确定各个变量的Tensor类型,并根据执行顺序将算子添加到计算图中
# 在这个过程中,如果开启了autograph=True(默认开启),会将Python控制流转换成TensorFlow图内控制流
# 主要是将if语句转换成tf.cond算子表达,将while和for循环语句转换成tf.while_loop算子表达,并在必要的时候添加tf.control_dependencies指定执行顺序依赖关系
# 第二步,执行计算图
# 第一次调用
myadd(tf.constant("hello"),tf.constant("world"))
# 第二次调用函数,直接执行已创建的计算图,只进行第二步,执行计算图。因此打印结果中没有"tracing"。
myadd(tf.constant("hello"),tf.constant("world"))
# 由于输入参数的类型已经发生变化,已经创建的计算图不能够再次使用。需要重新创建新的计算图、执行计算图。
myadd(tf.constant(1),tf.constant(2))
# 输入参数的类型发生变化,已创建的计算图无法复用,需要重新创建
myadd("hello","world")
# print("tracing") 是在 Python 函数体中执行的,因此每次计算图创建时都会打印
# 所以先打印 tracing
# tf.print(i) 是在 TensorFlow 计算图中执行的,因此每次调用计算图时都会打印
# 再打印0 1 2