深度學(xué)習(xí)框架TensorFlow2初步入門學(xué)習(xí)

TensorFlow2入門學(xué)習(xí)

TensorFlow 2 新增變化特性

TensorFlow 2 安裝

2019 年初,TensorFlow 官方推出了 2.0 預(yù)覽版本,也意味著 TensorFlow 即將從 1.x 過度到 2.x 時代。


image-20210129102658788.png

根據(jù) TensorFlow 官方介紹內(nèi)容 顯示,2.0 版本將專注于簡潔性和易用性的改善,主要升級方向包括:

  • 使用 Keras 和 Eager Execution 輕松構(gòu)建模型。
  • 在任意平臺上實現(xiàn)穩(wěn)健的生產(chǎn)環(huán)境模型部署。
  • 為研究提供強大的實驗工具。
  • 通過清理廢棄的 API 和減少重復(fù)來簡化 API。

接下來,加載 TensorFlow 并查看版本號,看是否已經(jīng)為 2.x。

In [ ]:

import tensorflow as tf

tf.__version__
在這里插入圖片描述

Eager Execution

TensorFlow 2 帶來的最大改變之一是將 1.x 的 Graph Execution(圖與會話機制)更改為 Eager Execution(動態(tài)圖機制)。在 1.x 版本中,低級別 TensorFlow API 首先需要定義數(shù)據(jù)流圖,然后再創(chuàng)建 TensorFlow 會話,這一點在 2.0 中被完全舍棄。

TensorFlow 2 中的 Eager Execution 是一種命令式編程環(huán)境,可立即評估操作,無需構(gòu)建圖:操作會返回具體的值,而不是構(gòu)建以后再運行的計算圖。實際上,Eager Execution 在 1.x 的后期版本中也存在,但需要單獨執(zhí)行 tf.enable_eager_execution() 進行手動啟用。不過,2.0 版本的 TensorFlow 默認采用了 Eager Execution,無法關(guān)閉并回到 1.x 的 Graph Execution 模式中。

下面,我們來演示 Eager Execution 帶來的變化。

1.x 版本中,如果我們新建一個張量 tf.Variable([[1, 2], [3, 4]]) 并執(zhí)行輸出,那么只能看到這個張量的形狀和屬性,并不能直接輸出其數(shù)值。結(jié)果如下:

<tf.Variable 'Variable:0' shape=(2, 2) dtype=int32_ref>

如今,Eager Execution 模式下則可以直接輸出張量的數(shù)值了,并以 NumPy 數(shù)組方式呈現(xiàn)。

c = tf.Variable([[1, 2], [3, 4]])
c
在這里插入圖片描述

你還可以直接通過 .numpy() 輸出張量的 NumPy 數(shù)組。Eager Execution 適合與 NumPy 一起使用。NumPy 操作接受 tf.Tensor 參數(shù)。TensorFlow 數(shù)學(xué)運算將 Python 對象和 NumPy 數(shù)組轉(zhuǎn)換為 tf.Tensor 對象。tf.Tensor.numpy 方法返回對象的值作為 NumPy ndarray。

c.numpy()

Eager Execution 帶來的好處是不再需要手動管理圖和會話。例如,現(xiàn)在使用示例張量進行數(shù)學(xué)計算,可以像 Python 一樣直接相加。

c + c  # 加法計算

而在 1.x 版本中,我們需要初始化全局變量 → 建立會話 → 執(zhí)行計算,最終才能打印出張量的運算結(jié)果。

init_op = tf.global_variables_initializer()  # 初始化全局變量
with tf.Session() as sess:  # 啟動會話
    sess.run(init_op)
    print(sess.run(c + c))  # 執(zhí)行計算

Eager Execution 帶來的好處顯而易見,其進一步降低了 TensorFlow 的入門門檻。之前,因為圖與會話的模式,讓很多人在入門時都很納悶。除此之外,得益于自動微分的使用,在 Eager Execution 期間,可以使用 tf.GradientTape 這類跟蹤操作以便稍后計算梯度。

In [1]:

w = tf.Variable([[1.0]])  # 新建張量

with tf.GradientTape() as tape:  # 追蹤梯度
    loss = w * w

grad = tape.gradient(loss, w)  # 計算梯度
grad
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-1e9ac7891209> in <module>
----> 1 w = tf.Variable([[1.0]])  # 新建張量
      2 
      3 with tf.GradientTape() as tape:  # 追蹤梯度
      4     loss = w * w
      5 

NameError: name 'tf' is not defined
`tf.GradientTape` 會像磁帶一樣記錄下計算圖中的梯度信息,然后使用 `.gradient` 即可回溯計算出任意梯度,這對于使用 TensorFlow 低階 API 構(gòu)建神經(jīng)網(wǎng)絡(luò)時更新參數(shù)非常重要。
在這里插入圖片描述

Markdown Code

`tf.GradientTape` 會像磁帶一樣記錄下計算圖中的梯度信息,然后使用 `.gradient` 即可回溯計算出任意梯度,這對于使用 TensorFlow 低階 API 構(gòu)建神經(jīng)網(wǎng)絡(luò)時更新參數(shù)非常重要。

Eager Execution 的好處很多,但帶來的問題也是很明顯的,尤其是對于已經(jīng)熟練使用 TensorFlow 的工程師而言簡直是噩夢。

如今,TensorFlow 的默認執(zhí)行模式為 Eager Execution,這就意味著之前基于 Graph Execution 構(gòu)建的代碼將完全無法使用,因為 2.0 中已經(jīng)沒有了相應(yīng)的 API。例如,先前構(gòu)建神經(jīng)網(wǎng)絡(luò)計算圖時,都習(xí)慣于使用 tf.placeholder 占位符張量,等最終執(zhí)行時再傳入數(shù)據(jù)。Eager Execution 模式下,tf.placeholder 已無存在必要,所以此 API 已被移除。

所以,隨著 TensorFlow 2 默認引入 Eager Execution 機制,也就意味著原 1.x 低階 API 構(gòu)建圖的方法后續(xù)已無法使用。

TensorFlow Keras

TensorFlow 1.x 中,我們可以通過 tf.layers 高階層封裝開快速搭建神經(jīng)網(wǎng)絡(luò)。如果,2.0 已完全移除了 tf.layers 模塊,轉(zhuǎn)而引入了 tf.keras。

如果你熟悉 Keras 的使用,那么 tf.keras 用起來就得心應(yīng)手了,因為其基本和單獨發(fā)行版本一致,子模塊結(jié)構(gòu)也幾乎完全一樣。除此之外,原 tf.contrib 也已經(jīng)在 2.0 版本中被移除。

TensorFlow2實現(xiàn)線性回歸

低階 API 實現(xiàn)

低階 API 實現(xiàn),實際上就是利用 Eager Execution 機制來完成。實驗首先初始化一組隨機數(shù)據(jù)樣本,并添加噪聲,然后將其可視化出來。

低階 API 實現(xiàn),實際上就是利用 Eager Execution 機制來完成。實驗首先初始化一組隨機數(shù)據(jù)樣本,并添加噪聲,然后將其可視化出來。
import matplotlib.pyplot as plt
import tensorflow as tf
%matplotlib inline

TRUE_W = 3.0
TRUE_b = 2.0
NUM_SAMPLES = 100

# 初始化隨機數(shù)據(jù)
X = tf.random.normal(shape=[NUM_SAMPLES, 1]).numpy()
noise = tf.random.normal(shape=[NUM_SAMPLES, 1]).numpy()
y = X * TRUE_W + TRUE_b + noise  # 添加噪聲

plt.scatter(X, y)
在這里插入圖片描述

接下來,我們定義一元線性回歸模型。

f??,??,??)=?????+??f(w,b,x)=w?x+b

這里我們構(gòu)建自定義模型類,并使用 TensorFlow 提供的 tf.Variable 隨機初始化參數(shù) ??w 和截距項b。

class Model(object):
    def __init__(self):
        self.W = tf.Variable(tf.random.uniform([1]))  # 隨機初始化參數(shù)
        self.b = tf.Variable(tf.random.uniform([1]))

    def __call__(self, x):
        return self.W * x + self.b  # w*x + b

對于隨機初始化的 ??w 和 ??b,我們可以將其擬合直線繪制到樣本散點圖中。

model = Model()  # 實例化模型

plt.scatter(X, y)
plt.plot(X, model(X), c='r')
在這里插入圖片描述

可以明顯看出,直線并沒有很好地擬合樣本。當然,由于是隨機初始化,也有極小概率一開始擬合效果非常好,那么重新執(zhí)行一次上面的單元格另外隨機初始化一組數(shù)據(jù)即可。

然后,我們定義線性回歸使用到的損失函數(shù)。這里使用線性回歸問題中常用的平方損失函數(shù)。對于線性回歸問題中與數(shù)學(xué)相關(guān)的知識點,本次實驗不再推動和講解。

Loss(??,??,??,??)=∑??=1??(??(??,??,????)?????)2Loss(w,b,x,y)=∑i=1N(f(w,b,xi)?yi)2

根據(jù)公式實現(xiàn)損失計算函數(shù)。

In [ ]:

def loss_fn(model, x, y):
    y_ = model(x)
    return tf.reduce_mean(tf.square(y_ - y))

接下來,就可以開始迭代過程了,這也是最關(guān)鍵的一步。使用迭代方法求解線性回歸的問題中,我們首先需要計算參數(shù)的梯度,然后使用梯度下降法來更新參數(shù)。

?? ??←?????????loss(??,??)???←?????????loss(??,??)???w←w?lr??loss(w,b)?w b←b?lr??loss(w,b)?b

公式中,????lr 指代學(xué)習(xí)率。

TensorFlow 2 中的 Eager Execution 提供了 tf.GradientTape 用于追蹤梯度。所以,下面我們就實現(xiàn)梯度下降法的迭代更新過程。

In [ ]:

EPOCHS = 10
LEARNING_RATE = 0.1

for epoch in range(EPOCHS):  # 迭代次數(shù)
    with tf.GradientTape() as tape:  # 追蹤梯度
        loss = loss_fn(model, X, y)  # 計算損失
    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 [{}/{}], loss [{:.3f}], W/b [{:.3f}/{:.3f}]'.format(epoch, EPOCHS, loss,
                                                                     float(model.W.numpy()),
                                                                     float(model.b.numpy())))

上面的代碼中,我們初始化 tf.GradientTape() 以追蹤梯度,然后使用 tape.gradient 方法就可以計算梯度了。值得注意的是,tape.gradient() 第二個參數(shù)支持以列表形式傳入多個參數(shù)同時計算梯度。緊接著,使用 .assign_sub 即可完成公式中的減法操作用以更新梯度。

在這里插入圖片描述

最終,我們繪制參數(shù)學(xué)習(xí)完成之后,模型的擬合結(jié)果。

In [ ]:

plt.scatter(X, y)
plt.plot(X, model(X), c='r')

如無意外,你將得到一個比隨機參數(shù)好很多的擬合直線。

在這里插入圖片描述

提示:由于是隨機初始化參數(shù),如果迭代后擬合效果仍然不好,一般是迭代次數(shù)太少的原因。你可以重復(fù)執(zhí)行上面的迭代單元格多次,增加參數(shù)更新迭代次數(shù),即可改善擬合效果。此提示對后面的內(nèi)容同樣有效。

高階 API 實現(xiàn)

TensorFlow 2 中提供了大量的高階 API 幫助我們快速構(gòu)建所需模型,接下來,我們使用一些新的 API 來完成線性回歸模型的構(gòu)建。這里還是沿用上面提供的示例數(shù)據(jù)。

tf.keras 模塊下提供的 tf.keras.layers.Dense 全連接層(線性層)實際上就是一個線性計算過程。所以,模型的定義部分我們就可以直接實例化一個全連接層即可。

In [ ]:

model = tf.keras.layers.Dense(units=1)  # 實例化線性層
model

其中,units 為輸出空間維度。此時,參數(shù)已經(jīng)被初始化了,所以我們可以繪制出擬合直線。

In [ ]:

plt.scatter(X, y)
plt.plot(X, model(X), c='r')

結(jié)果顯示:

在這里插入圖片描述

你可以使用 model.variables 打印出模型初始化的隨機參數(shù)。

In [ ]:

model.variables

[圖片上傳失敗...(image-ce7380-1642220407496)]

接下來就可以直接構(gòu)建模型迭代過程了。

這里同樣使用 tf.GradientTape() 來追蹤梯度,我們簡化損失計算和更新的過程。首先,損失可以使用現(xiàn)有 API tf.keras.losses.mean_squared_error 計算,最終使用 tf.reduce_sum 求得全部樣本的平均損失。

In [ ]:

EPOCHS = 10
LEARNING_RATE = 0.002
for epoch in range(EPOCHS):  # 迭代次數(shù)
    with tf.GradientTape() as tape:  # 追蹤梯度
        y_ = model(X)
        loss = tf.reduce_sum(tf.keras.losses.mean_squared_error(y, y_))  # 計算損失

    grads = tape.gradient(loss, model.variables)  # 計算梯度
    optimizer = tf.keras.optimizers.SGD(LEARNING_RATE)  # 隨機梯度下降
    optimizer.apply_gradients(zip(grads, model.variables))  # 更新梯度

    print('Epoch [{}/{}], loss [{:.3f}]'.format(epoch, EPOCHS, loss))

其次,使用 model.variables 即可讀取可參數(shù)的列表,無需像上面那樣手動傳入。這里不再按公式手動更新梯度,而是使用現(xiàn)有的隨機梯度下降函數(shù) tf.keras.optimizers.SGD,然后使用 apply_gradients 即可更新梯度。

在這里插入圖片描述

最終,同樣將迭代完成的參數(shù)繪制擬合直線到原圖中。

In [ ]:

plt.scatter(X, y)
plt.plot(X, model(X), c='r')
在這里插入圖片描述

如果擬合效果不好,請參考上文提示。

Keras 方式實現(xiàn)

上面的高階 API 實現(xiàn)過程實際上還不夠精簡,我們可以完全使用 TensorFlow Keras API 來實現(xiàn)線性回歸。

我們這里使用 Keras 提供的 Sequential 序貫?zāi)P徒Y(jié)構(gòu)。和上面的例子相似,向其中添加一個線性層。不同的地方在于,Keras 序貫?zāi)P偷谝粚訛榫€性層時,規(guī)定需指定輸入維度,這里為 input_dim=1。

In [ ]:

model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units=1, input_dim=1))
model.summary()  # 查看模型結(jié)構(gòu)
在這里插入圖片描述

接下來,直接使用 .compile 編譯模型,指定損失函數(shù)為 MSE 平方損失,優(yōu)化器選擇 SGD 隨機梯度下降。然后,就可以使用 .fit 傳入數(shù)據(jù)開始迭代了。

In [ ]:

model.compile(optimizer='sgd', loss='mse')
model.fit(X, y, steps_per_epoch=100)
image-20210608213207812.png

steps_per_epoch 只的是在默認小批量為 32 的條件下,傳入相應(yīng)次數(shù)的小批量樣本。最終繪制出迭代完成的擬合圖像。

In [ ]:

plt.scatter(X, y)
plt.plot(X, model(X), c='r')
在這里插入圖片描述

如果擬合效果不好,請參考上文提示。

如上所示,完全使用 Keras 高階 API 實際上只需要 4 行核心代碼即可完成。相比于最開始的低階 API 簡化了很多。

TensorFlow 1.x 實現(xiàn)

為了與 TensorFlow 2 線性回歸實現(xiàn)過程進行對比。最終,我們給出 TensorFlow 1.x 線性回歸實現(xiàn)代碼。這里,我們需要實驗 TensorFlow 2 中 tensorflow.compat.v1 模塊下提供的兼容性代碼。

In [ ]:

import tensorflow.compat.v1 as tf

tf.disable_v2_behavior() # 關(guān)閉 Eager Execution 特性
在這里插入圖片描述

接下來,就可以使用 TensorFlow 1.x 中提供的圖與會話方式來實現(xiàn)線性回歸過程了。

In [ ]:

X_train = tf.placeholder(tf.float32)  # 定義占位符張量
y_train = tf.placeholder(tf.float32)
W = tf.Variable(tf.random.normal([1]))  # 初始化參數(shù)
b = tf.Variable(tf.random.normal([1]))

LEARNING_RATE = 0.001  # 學(xué)習(xí)率

y_train_ = W*X_train + b  # 線性函數(shù)
loss = tf.reduce_mean(tf.square(y_train_ - y_train))  # 平方損失函數(shù)
optimizer = tf.train.GradientDescentOptimizer(
    LEARNING_RATE).minimize(loss)  # 梯度下降優(yōu)化損失函數(shù)

EPOCHS = 1000  # 迭代次數(shù)
with tf.Session() as sess: # 啟動會話
    tf.global_variables_initializer().run()  # 初始化全局變量
    for epoch in range(EPOCHS):  # 迭代優(yōu)化
        sess.run(optimizer, feed_dict={X_train:X, y_train:y})
    final_weight = sess.run(W)  # 最終參數(shù)
    final_bias = sess.run(b)

print(final_weight, final_bias)
在這里插入圖片描述

最后,我們依據(jù)迭代更新的參數(shù),將擬合直線繪制到原圖中。

In [ ]:

preds = final_weight * X + final_bias  # 計算預(yù)測值
plt.scatter(X, y)
plt.plot(X, preds, c='r')
在這里插入圖片描述

實驗總結(jié)

本次實驗中,我們利用 TensorFlow 2 提供的 Eager Execution 實現(xiàn)了線性回歸的經(jīng)典過程。同時,利用 TensorFlow Keras 高階 API 簡化了實現(xiàn)步驟。實驗的最后,使用 TensorFlow 1.x API 進行了對比示例,希望你能夠準確把握 TensorFlow 2 和 1.0 之間的區(qū)別。

TensorFlow2構(gòu)建前饋神經(jīng)網(wǎng)絡(luò)

低階 API 構(gòu)建

學(xué)習(xí)完線性回歸中的低階 API 實現(xiàn)方法,那么使用 TensorFlow 2 低階 API 構(gòu)建神經(jīng)網(wǎng)絡(luò)實際上就比較簡單了。這里,我們先加載一組數(shù)據(jù),DIGITS 數(shù)據(jù)集是 scikit-learn 提供的簡單手寫字符識別數(shù)據(jù)集。

我們讀取數(shù)據(jù)集并進行簡單切分,這里對字符標簽進行了獨熱編碼方便后面計算損失值。

In [1]:

import numpy as np
import tensorflow as tf
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

digits = load_digits()
digits_y = np.eye(10)[digits.target.reshape(-1)]  # 標簽獨熱編碼
X_train, X_test, y_train, y_test = train_test_split(digits.data, digits_y,
                                                    test_size=0.2, random_state=1)

X_train.shape, X_test.shape, y_train.shape, y_test.shape

Out[1]:

((1437, 64), (360, 64), (1437, 10), (360, 10))

下面,使用 TensorFlow 2 低階 API 構(gòu)建一個包含 1 個隱含層的簡單神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)。神經(jīng)網(wǎng)絡(luò)的輸入是單個手寫字符樣本的向量長度 64,隱含層輸入為 30,最終的輸出層為 10。

在這里插入圖片描述

特別地,我們對隱含層進行 RELU 激活,輸出層不激活。輸出層的單樣本長度為 10,這樣正好就和上方獨熱編碼后的值對應(yīng)上了。

In [ ]:

class Model(object):
    def __init__(self):
        self.W1 = tf.Variable(tf.random.normal([64, 30]))  # 隨機初始化張量參數(shù)
        self.b1 = tf.Variable(tf.random.normal([30]))

        self.W2 = tf.Variable(tf.random.normal([30, 10]))
        self.b2 = tf.Variable(tf.random.normal([10]))

    def __call__(self, x):
        x = tf.cast(x, tf.float32)  # 轉(zhuǎn)換輸入數(shù)據(jù)類型
        # 線性計算 + RELU 激活
        fc1 = tf.nn.relu(tf.add(tf.matmul(x, self.W1), self.b1))
        fc2 = tf.add(tf.matmul(fc1, self.W2), self.b2)
        return fc2

下面,我們開始構(gòu)建損失函數(shù)。損失函數(shù)使用 TensorFlow 提供的 tf.nn.softmax_cross_entropy_with_logits,這是一個自帶 Softmax 的交叉熵損失函數(shù)。最終通過 reduce_mean 求得全局平均損失。

In [ ]:

def loss_fn(model, x, y):
    preds = model(x)
    return tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=y))

于此同時,為了方便查看分類準確度,我們需要手動構(gòu)建一個準確度評估函數(shù)。tf.argmax 可以將 Softmax 結(jié)果轉(zhuǎn)換為對應(yīng)的字符值。然后使用 tf.equal 比對各樣本的結(jié)果是否正確,最終使用 reduce_mean 求得全部樣本的分類準確度。

In [ ]:

def accuracy_fn(logits, labels):
    preds = tf.argmax(logits, axis=1)  # 取值最大的索引,正好對應(yīng)字符標簽
    labels = tf.argmax(labels, axis=1)
    return tf.reduce_mean(tf.cast(tf.equal(preds, labels), tf.float32))

下面開始構(gòu)建最關(guān)鍵的訓(xùn)練迭代過程。實際上,這部分和構(gòu)建線性回歸非常相似,我們的目的是對神經(jīng)網(wǎng)絡(luò)參數(shù)進行迭代優(yōu)化。

In [ ]:

EPOCHS = 100  # 迭代此時
LEARNING_RATE = 0.02  # 學(xué)習(xí)率
model = Model()  # 模型
for epoch in range(EPOCHS):
    with tf.GradientTape() as tape:  # 追蹤梯度
        loss = loss_fn(model, X_train, y_train)

    trainable_variables = [model.W1, model.b1, model.W2, model.b2]  # 需優(yōu)化參數(shù)列表
    grads = tape.gradient(loss, trainable_variables)  # 計算梯度

    optimizer = tf.optimizers.Adam(learning_rate=LEARNING_RATE)  # 優(yōu)化器
    optimizer.apply_gradients(zip(grads, trainable_variables))  # 更新梯度
    accuracy = accuracy_fn(model(X_test), y_test)  # 計算準確度

    # 輸出各項指標
    if (epoch + 1) % 10 == 0:
        print('Epoch [{}/{}], Train loss: {:.3f}, Test accuracy: {:.3f}'
              .format(epoch+1, EPOCHS, loss, accuracy))
在這里插入圖片描述

Keras 高階 API 實現(xiàn)

線性回歸的實驗中,我們使用了 Sequential 序貫?zāi)P?,實際上 Keras 中更容易理解的是函數(shù)式模型。函數(shù)式模型最直觀的地方在于可以看清楚輸入和輸出。

函數(shù)式模型

例如,下面我們開始定義函數(shù)式模型。首先是 Input 層,這在序貫?zāi)P椭惺菦]有的。然后我們將 inputs 傳入 Dense 層,最終再輸出。

In [ ]:

# 函數(shù)式模型
inputs = tf.keras.Input(shape=(64,))
x = tf.keras.layers.Dense(30, activation='relu')(inputs)
outputs = tf.keras.layers.Dense(10, activation='softmax')(x)

# 指定輸入和輸出
model = tf.keras.Model(inputs=inputs, outputs=outputs)
model.summary()  # 查看模型結(jié)構(gòu)
在這里插入圖片描述

值得注意的是,函數(shù)式模型中需要使用 tf.keras.Model 來最終確定輸入和輸出。

下面,可以開始編譯和訓(xùn)練模型。這里使用 tf.optimizers.Adam 作為優(yōu)化器,tf.losses.categorical_crossentropy 多分類交叉熵作為損失函數(shù)。與 tf.nn.softmax_cross_entropy_with_logits 不同的是,tf.losses.categorical_crossentropy 是從 Keras 中演化而來的,其去掉了 Softmax 的過程。而這個過程被我們直接加入到模型的構(gòu)建中。你可以看到,上面的 model 輸出層使用了 softmax 激活。

In [ ]:

# 編譯模型
model.compile(optimizer=tf.optimizers.Adam(),
              loss=tf.losses.categorical_crossentropy, metrics=['accuracy'])
# 訓(xùn)練和評估
model.fit(X_train, y_train, batch_size=64, epochs=10,
          validation_data=(X_test, y_test))
在這里插入圖片描述

Keras 的訓(xùn)練過程可以采用小批量迭代,直接指定 batch_size 即可。validation_data 可以傳入測試數(shù)據(jù)得到準確度評估結(jié)果,非常方便。

序貫?zāi)P?/h4>

當然,上方的函數(shù)式模型也可以被寫為序貫?zāi)P?。下面,我們就使用序貫?zāi)P瓦M行實現(xiàn)。

In [ ]:

model = tf.keras.Sequential()  # 建立序貫?zāi)P?model.add(tf.keras.layers.Dense(units=30, input_dim=64, activation='relu'))  # 隱含層 
model.add(tf.keras.layers.Dense(units=10, activation='softmax'))  # 輸出層
model.summary()  # 查看模型結(jié)構(gòu)
在這里插入圖片描述

此時,我們使用參數(shù)簡寫來替代函數(shù)式模型中復(fù)雜的寫法。

In [ ]:

model.compile(optimizer='adam', loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(X_train, y_train, batch_size=64, epochs=10,
          validation_data=(X_test, y_test))
在這里插入圖片描述

自由度更高的模型

TensorFlow 2 中還支持另外一種更為靈活的 Keras 定義模型方法,這種方法和 PyTorch 中繼承 torch.nn.Module 來定義模型的思路非常相似。我們可以繼承 tf.keras.Model 來構(gòu)建模型。這種模型的定義方法自由度更高,我們可以添加更多的中間組件,相對靈活。

In [ ]:

class Model(tf.keras.Model):
    def __init__(self):
        super(Model, self).__init__()
        self.dense_1 = tf.keras.layers.Dense(30, activation='relu')  # 初始化
        self.dense_2 = tf.keras.layers.Dense(10, activation='softmax')

    def call(self, inputs):
        x = self.dense_1(inputs)  # 前向傳播過程
        return self.dense_2(x)

接下來的過程和上面相似,實例化模型然后訓(xùn)練并評估。

In [ ]:

model = Model()  # 實例化模型
model.compile(optimizer='adam', loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(X_train, y_train, batch_size=64, epochs=10,
          validation_data=(X_test, y_test))
在這里插入圖片描述
在這里插入圖片描述

實驗總結(jié)

本次實驗中,我們實驗中 TensorFlow 2 構(gòu)建了簡單的前饋神經(jīng)網(wǎng)絡(luò),并完全手寫字符識別分類。特別地,一定要掌握 Eager Execution 的實現(xiàn)過程,而對于 TensorFlow Keras 的使用也應(yīng)用有充分的理解。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容