美文网首页
TensorFlow2 的层次结构

TensorFlow2 的层次结构

作者: 水之心 | 来源:发表于2020-09-09 15:17 被阅读0次

一般地,TensorFlow 可划分为 5 个不同的层次结构:即硬件层,内核层,低阶 API,中阶 API,高阶 API。

  • 最底层为硬件层,支持 CPU、GPU 或 TPU 加入计算资源池。
  • 第二层为 C++ 实现的内核,kernel 可以跨平台分布运行。
  • 第三层为 Python 实现的操作符,提供了封装 C++ 内核的低级 API 指令,主要包括各种张量操作算子、计算图、自动微分。如 tf.Variabletf.constanttf.functiontf.GradientTapetf.nn.softmax 等。如果把模型比作一个房子,那么第三层 API 就是【模型之砖】。
  • 第四层为 Python 实现的模型组件,对低级 API 进行了函数封装,主要包括各种模型层,损失函数,优化器,数据管道,特征列等等。 如tf.keras.layerstf.keras.lossestf.keras.metricstf.keras.optimizerstf.data.DataSettf.feature_column 等。如果把模型比作一个房子,那么第四层 API 就是【模型之墙】。
  • 第五层为 Python 实现的模型成品,一般为按照 OOP 方式封装的高级 API,主要为tf.keras.models 提供的模型的类接口。如果把模型比作一个房子,那么第五层 API 就是模型本身,即【模型之屋】。

为了更好的理解 TensorFLow 的层次结构,本文以线性回归模型为例介绍其使用。

为了方便打印时间分割线,定义:

import tensorflow as tf


@tf.function
def printbar():
    today_ts = tf.timestamp()%(24*60*60)

    hour = tf.cast(today_ts//3600+8,tf.int32)%tf.constant(24)
    minite = tf.cast((today_ts%3600)//60,tf.int32)
    second = tf.cast(tf.floor(today_ts%60),tf.int32)

    def timeformat(m):
        if tf.strings.length(tf.strings.format("{}",m))==1:
            return(tf.strings.format("0{}",m))
        else:
            return(tf.strings.format("{}",m))

    timestring = tf.strings.join([timeformat(hour),timeformat(minite),
                timeformat(second)],separator = ":")
    tf.print("=========="*8+timestring)

1 线性回归模型

准备数据:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import tensorflow as tf

# 样本数量
n = 400

# 生成测试用数据集
X = tf.random.uniform([n, 2], minval=-10, maxval=10)
w0 = tf.constant([[2.0], [-3.0]])
b0 = tf.constant([[3.0]])
# @ 表示矩阵乘法
Y = X@w0 + b0 + tf.random.normal([n, 1], mean=0.0, stddev=2.0)  # 增加正态扰动

数据可视化:

%matplotlib inline
%config InlineBackend.figure_format = 'svg'

plt.figure(figsize=(12, 5))
ax1 = plt.subplot(121)
ax1.scatter(X[:, 0], Y[:, 0], c="b")
plt.xlabel("x1")
plt.ylabel("y", rotation=0)

ax2 = plt.subplot(122)
ax2.scatter(X[:, 1], Y[:, 0], c="g")
plt.xlabel("x2")
plt.ylabel("y", rotation=0)
plt.show()

1.1 低阶 API

低阶 API 主要包括张量操作,计算图和自动微分。

构建数据管道迭代器:

def data_iter(features, labels, batch_size=8):
    num_examples = len(features)
    indices = tf.range(num_examples)
    # 样本的读取顺序是随机的
    indices = tf.random.shuffle(indices)
    for i in range(0, num_examples, batch_size):
        indexs = indices[i: min(i + batch_size, num_examples)]
        yield tf.gather(features, indexs), tf.gather(labels, indexs)

测试数据管道效果:

batch_size = 8
(features,labels) = next(data_iter(X,Y,batch_size))
print(features)
print(labels)

输出:

tf.Tensor(
[[-0.2952814   6.653778  ]
 [ 6.9571      6.6220016 ]
 [-1.6679573   7.8447266 ]
 [-3.378389    0.7508259 ]
 [ 4.210842   -5.0142646 ]
 [-8.36364    -1.1773891 ]
 [-1.1047125   8.272064  ]
 [ 6.578846    0.59856415]], shape=(8, 2), dtype=float32)
tf.Tensor(
[[-19.67135  ]
 [ -3.0043507]
 [-21.989437 ]
 [ -4.338471 ]
 [ 26.106647 ]
 [ -8.700451 ]
 [-21.60449  ]
 [ 13.954208 ]], shape=(8, 1), dtype=float32)

定义模型:

# 定义模型
class LinearRegression:
    def __init__(self, w0, b0):
        self.w = tf.Variable(tf.random.normal(w0.shape))
        self.b = tf.Variable(tf.zeros_like(b0, dtype=tf.float32))
    # 正向传播

    def __call__(self, x):
        return x@self.w + self.b

    # 损失函数
    def loss_func(self, y_true, y_pred):
        return tf.reduce_mean((y_true - y_pred)**2/2)

model = LinearRegression(w0, b0)

训练模型:

# 定义模型
class LinearRegression:
    def __init__(self, w0, b0):
        self.w = tf.Variable(tf.random.normal(w0.shape))
        self.b = tf.Variable(tf.zeros_like(b0, dtype=tf.float32))

    def __call__(self, x):
        '''正向传播'''
        return x@self.w + self.b

    def loss_func(self, y_true, y_pred):
        '''损失函数'''
        return tf.reduce_mean((y_true - y_pred)**2/2)

    def train_step(self, features, labels):
        '''使用动态图调试'''
        with tf.GradientTape() as tape:
            predictions = self(features)
            loss = self.loss_func(labels, predictions)
        # 反向传播求梯度
        dloss_dw, dloss_db = tape.gradient(loss, [self.w, self.b])
        # 梯度下降法更新参数
        self.w.assign(self.w - 0.001*dloss_dw)
        self.b.assign(self.b - 0.001*dloss_db)
        return loss

    def train_model(self, epochs, X, Y, batch_size=10):
        for epoch in tf.range(1, epochs+1):
            for features, labels in data_iter(X, Y, batch_size):
                loss = self.train_step(features, labels)

            if epoch % 50 == 0:
                printbar()
                tf.print("epoch =", epoch, "loss = ", loss)
                tf.print("w =", self.w)
                tf.print("b =", self.b)


model = LinearRegression(w0, b0)

测试 train_step 效果:

batch_size = 10
features, labels = next(data_iter(X, Y, batch_size))
model.train_step(features, labels)

输出:

<tf.Tensor: shape=(), dtype=float32, numpy=28.589752>

开始训练:

model.train_model(200, X, Y, batch_size=10)

输出:

================================================================================14:37:01
epoch = 50 loss =  1.60174155
w = [[1.98152947]
 [-2.97623014]]
b = [[2.5552578]]
================================================================================14:37:03
epoch = 100 loss =  1.31020141
w = [[1.98884952]
 [-2.97311592]]
b = [[2.89677]]
================================================================================14:37:05
epoch = 150 loss =  1.57372892
w = [[1.98234701]
 [-2.96258068]]
b = [[2.94358778]]
================================================================================14:37:08
epoch = 200 loss =  2.14014482
w = [[1.98429]
 [-2.97808719]]
b = [[2.95075393]]

使用 autograph 机制转换成静态图进行加速:

class LinearRegressionAuto(LinearRegression):
    def __init__(self, w0, b0):
        super().__init__(w0, b0)
    
    @tf.function
    def train_step(self, features, labels):
        '''使用动态图调试'''
        return super().train_step(features, labels)

model = LinearRegressionAuto(w0, b0)
model.train_model(200, X, Y, batch_size=10)

输出:

================================================================================15:05:17
epoch = 50 loss =  1.97919536
w = [[1.99299932]
 [-2.99473619]]
b = [[2.64054227]]
================================================================================15:05:17
epoch = 100 loss =  4.11912918
w = [[1.99222016]
 [-2.99668217]]
b = [[2.99661422]]
================================================================================15:05:18
epoch = 150 loss =  1.16163898
w = [[1.99017787]
 [-3.0003643]]
b = [[3.0453]]
================================================================================15:05:19
epoch = 200 loss =  1.7077049
w = [[1.98725438]
 [-2.99538016]]
b = [[3.05199695]]

结果可视化:

def plot_model(X, Y, w, b):
    %matplotlib inline
    %config InlineBackend.figure_format = 'svg'

    plt.figure(figsize = (12,5))
    ax1 = plt.subplot(121)
    ax1.scatter(X[:,0],Y[:,0], c = "b",label = "samples")
    ax1.plot(X[:,0],w[0]*X[:,0]+b[0],"-r",linewidth = 5.0,label = "model")
    ax1.legend()
    plt.xlabel("x1")
    plt.ylabel("y",rotation = 0)

    ax2 = plt.subplot(122)
    ax2.scatter(X[:,1],Y[:,0], c = "g",label = "samples")
    ax2.plot(X[:,1],w[1]*X[:,1]+b[0],"-r",linewidth = 5.0,label = "model")
    ax2.legend()
    plt.xlabel("x2")
    plt.ylabel("y",rotation = 0)
    plt.show()

plot_model(X, Y, model.w, model.b)

结果:

1.2 中阶 API

TensorFlow 的中阶 API 主要包括各种模型层,损失函数,优化器,数据管道,特征列等。

构建输入数据管道:

from tensorflow.keras import models, layers, losses, metrics, optimizers

ds = tf.data.Dataset.from_tensor_slices((X, Y)).shuffle(buffer_size=100)
ds = ds.batch(10).prefetch(tf.data.experimental.AUTOTUNE)

定义模型:

model = layers.Dense(units = 1) 
model.build(input_shape = (2,)) # 用 build 方法创建 variables
model.loss_func = losses.mean_squared_error
model.optimizer = optimizers.SGD(learning_rate=0.001)

训练模型:

# 使用autograph机制转换成静态图加速

@tf.function
def train_step(model, features, labels):
    with tf.GradientTape() as tape:
        predictions = model(features)
        loss = model.loss_func(tf.reshape(labels, [-1]), tf.reshape(predictions, [-1]))
    grads = tape.gradient(loss,model.variables)
    model.optimizer.apply_gradients(zip(grads,model.variables))
    return loss

# 测试train_step效果
features,labels = next(ds.as_numpy_iterator())
train_step(model,features,labels)

输出:

<tf.Tensor: shape=(), dtype=float32, numpy=398.73175>
def train_model(model,epochs):
    for epoch in tf.range(1,epochs+1):
        loss = tf.constant(0.0)
        for features, labels in ds:
            loss = train_step(model,features,labels)
        if epoch%50==0:
            printbar()
            tf.print("epoch =",epoch,"loss = ",loss)
            tf.print("w =",model.variables[0])
            tf.print("b =",model.variables[1])
train_model(model,epochs = 200)

输出:

================================================================================15:07:10
epoch = 50 loss =  5.2171731
w = [[1.98394287]
 [-3.00856614]]
b = [2.99515676]
================================================================================15:07:10
epoch = 100 loss =  3.77920151
w = [[1.96747339]
 [-3.00186872]]
b = [3.04988098]
================================================================================15:07:11
epoch = 150 loss =  3.95153427
w = [[1.97758]
 [-2.99289441]]
b = [3.05139828]
================================================================================15:07:12
epoch = 200 loss =  2.17782164
w = [[1.97943664]
 [-2.98815298]]
b = [3.04926324]

结果可视化

plot_model(X, Y, *model.variables)

显示:

1.3 高阶 API

TensorFlow 的高阶 API 主要为 tf.keras.models 提供的模型的类接口。使用 Keras 接口有以下 3 种方式构建模型:

  1. 使用 Sequential 按层顺序构建模型
  2. 使用函数式 API 构建任意结构模型
  3. 继承 Model 基类构建自定义模型

此范例我们使用 Sequential 按层顺序构建模型,并使用内置 model.fit 方法训练模型【面向新手】。

import numpy as np 
import pandas as pd
from matplotlib import pyplot as plt 
import tensorflow as tf
from tensorflow.keras import models, layers, losses, metrics, optimizers

tf.keras.backend.clear_session()

model = models.Sequential()
model.add(layers.Dense(1, input_shape =(2,)))
model.summary()

输出:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 1)                 3         
=================================================================
Total params: 3
Trainable params: 3
Non-trainable params: 0
_________________________________________________________________

训练模型:

### 使用fit方法进行训练

model.compile(optimizer="adam",loss="mse",metrics=["mae"])
model.fit(X,Y,batch_size = 10,epochs = 200)  

tf.print("w = ",model.layers[0].kernel)
tf.print("b = ",model.layers[0].bias)

输出:

...
Epoch 193/200
400/400 [==============================] - 0s 75us/sample - loss: 3.9782 - mae: 1.5815
Epoch 194/200
400/400 [==============================] - 0s 73us/sample - loss: 3.9782 - mae: 1.5817
Epoch 195/200
400/400 [==============================] - 0s 77us/sample - loss: 3.9768 - mae: 1.5810
Epoch 196/200
400/400 [==============================] - 0s 75us/sample - loss: 3.9757 - mae: 1.5815
Epoch 197/200
400/400 [==============================] - 0s 75us/sample - loss: 3.9739 - mae: 1.5807
Epoch 198/200
400/400 [==============================] - 0s 77us/sample - loss: 3.9746 - mae: 1.5813
Epoch 199/200
400/400 [==============================] - 0s 80us/sample - loss: 3.9753 - mae: 1.5809
Epoch 200/200
400/400 [==============================] - 0s 80us/sample - loss: 3.9731 - mae: 1.5814
w =  [[1.98939872]
 [-2.99610186]]
b =  [2.98485875]

结果可视化:

相关文章

网友评论

      本文标题:TensorFlow2 的层次结构

      本文链接:https://www.haomeiwen.com/subject/ofgsektx.html