包与模块¶

这里面最重要的是keras模块

  1. api-keras:可以看到里面有我们最需要的一些模块
  2. activations :可以 看到最常用的一些激活函数
  3. applications :可以看到里面放了进几年最常用的模型
  4. datasets:可以看到里面放了最常用的数据集
    • layers:需要用到的一些基础操作 :Dense,Conv1D,Conv2D等
    • loss:用到的损失函数:BinaryCrossentropy,MAE等
    • metrics: 用到的最常用的评估函数。AUC,Accuracy等
    • optimizers:最常用的优化器。Adadelta,Adam,SGD
    • regularizers:最常用的正则化:L1,L2

框架模型¶

In [ ]:
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()
In [ ]:
#定义模型和损失函数
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()
In [ ]:
# 使用梯度下降法训练模型
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¶

即刻执行(Eager execution)是TensorFlow2.0的新特性,如同python解释器一样,执行即可获得计算结果,不需要手动建立图结构和会话,与python的兼容性更强, 为快速搭建和测试算法模型提供了便利

  1. tensorflow2.0默认是Eager execution模式;

  2. eager模式对numpy的支持很友好,具体如下:

  • numpy的操作可以接受Tensor作为参数;

  • Tensorflow的数学操作会将python对象和numpy的arrays转换成Tensor;

  • tf.Tensor.numpy方法返回numpy的ndarray.

  1. 可逐行动态控制流,逐行控制代码的运行;

  2. 一切皆函数,无须手动搭建tensorflow数据结构。

即刻输出¶

In [ ]:
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模式。

In [ ]:
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,线表示计算间的依赖关系
实线表示有数据传递依赖,传递的数据即张量
虚线通常可以表示控制依赖,即执行先后顺序

静态计算图:¶

静态计算则意味着程序在编译执行时将先生成神经网络的结构,然后再执行相应操作
从理论上讲,静态计算这样的机制允许编译器进行更大程度的优化,但是这也意味 着你所期望的程序与编译器实际执行之间存在着更多的代沟
这也意味着,代码中的错误将 更加难以发现(比如,如果计算图的结构出现问题,你可能只有在代码执行到相应操作的时 候才能发现它)

In [ ]:
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)

动态计算图:¶

动态计算意味着程序将按照我们编写命令的顺序进行执行
这种机制将使得调试更加容易,并且也使得我们将大脑中的想法转化为实际代码变得更加容易

In [ ]:
# 动态计算图在每个算子处都进行构建,构建后立即执行
 
x = tf.constant("hello")
y = tf.constant("world")
z = tf.strings.join([x,y],separator=" ")

print(z.numpy())
tf.print(z)

AutoGraph¶

TensorFlow 2.0主要使用的是动态计算图和Autograph
Autograph机制通过@tf.function装饰器,可以将动态图转换成静态计算图,达到兼顾执行效率和编码效率的目的
AutoGraph将Python控制流转换为TensorFlow表达式,允许用户在装饰有tf.function的函数中编写常规Python,例如while,if,break,continue和return,支持嵌套
这意味着可以在while和if语句的条件下使用Tensor表达式,或者在for循环中迭代Tensor

注意:有一些编码规范需要遵循

  1. 使用tf内部函数,避免直接使用python函数,因为无法嵌入进计算图;

  2. 避免定义 tf.Variable, 以为它是动态的,每次迭代都会更新;

  3. 不可以修改列表字典等数据结构。

In [ ]:
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