TensorFlow2入門學(xué)習(xí)
TensorFlow 2 新增變化特性
TensorFlow 2 安裝
2019 年初,TensorFlow 官方推出了 2.0 預(yù)覽版本,也意味著 TensorFlow 即將從 1.x 過度到 2.x 時代。

根據(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)

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)用有充分的理解。