本章將對(duì)TensorFlow的基本概念做簡(jiǎn)介表鳍,每節(jié)會(huì)對(duì)一個(gè)大概念做一個(gè)概論--你可以在每節(jié)末尾找到更詳細(xì)的鏈接地址秤茅。
TensorFlow是機(jī)器學(xué)習(xí)的一個(gè)端對(duì)端平臺(tái),支持以下操作:
- 多維數(shù)組的數(shù)字計(jì)算
- GPU和分布式運(yùn)算
- 自動(dòng)微分
- 模型構(gòu)建、訓(xùn)練和導(dǎo)出
- 以及其他
Tensors
TensorFlow的運(yùn)算是基于多維數(shù)組或張量帆吻,這些運(yùn)算對(duì)象在TensorFlow中被標(biāo)識(shí)為tf.Tensor對(duì)象普泡。下面的代碼描述了一個(gè)二維張量:
import tensorflow as tf
x = tf.constant([[1., 2., 3. ], [4., 5., 6. ]])
print(x)
print(x.shape)
print(x.dtype)
運(yùn)行結(jié)果為:
tf.Tensor(
[[1. 2. 3.]
[4. 5. 6.]], shape=(2, 3), dtype=float32)
(2, 3)
<dtype: 'float32'>
對(duì)于Tensor來(lái)說(shuō)播掷,這里有兩個(gè)相當(dāng)重要的概念shape和dtype:
- Tensor.shape: 表示獲取張量在各個(gè)維度的大小。
- Tensor.dtype: 表示張量中所有元素的類型撼班。
TensorFlow在實(shí)現(xiàn)了基于張量的標(biāo)準(zhǔn)數(shù)字操作符的同時(shí)也實(shí)現(xiàn)了機(jī)器學(xué)習(xí)中常用的專用的運(yùn)算符歧匈。如:
x + x
結(jié)果為:
tf.Tensor(
[[ 2. 4. 6.]
[ 8. 10. 12.]], shape=(2, 3), dtype=float32)
5 * x
結(jié)果為:
tf.Tensor(
[[ 5. 10. 15.]
[20. 25. 30.]], shape=(2, 3), dtype=float32)
x @ tf.transpose(x)
結(jié)果為:
tf.Tensor(
[[14. 32.]
[32. 77.]], shape=(2, 2), dtype=float32)
tf.concat([x, x, x], axis=0)
結(jié)果為:
tf.Tensor(
[[1. 2. 3.]
[4. 5. 6.]
[1. 2. 3.]
[4. 5. 6.]
[1. 2. 3.]
[4. 5. 6.]], shape=(6, 3), dtype=float32)
tf.concat([x, x, x], axis=1)
結(jié)果為:
tf.Tensor(
[[1. 2. 3. 1. 2. 3. 1. 2. 3.]
[4. 5. 6. 4. 5. 6. 4. 5. 6.]], shape=(2, 9), dtype=float32)
tf.nn.softmax(x, axis=1)
結(jié)果為:
tf.Tensor(
[[0.09003057 0.24472848 0.66524094]
[0.09003057 0.24472848 0.66524094]], shape=(2, 3), dtype=float32)
tf.reduce_sum(x)
結(jié)果為:
tf.Tensor(21.0, shape=(), dtype=float32)
在CPU上執(zhí)行大規(guī)模計(jì)算時(shí),效率并不高砰嘁。在進(jìn)行配置之后件炉,TensorFlow可以運(yùn)行在如GPU之類的硬件之上執(zhí)行運(yùn)行操作勘究,效率很高。
if tf.config.list_physical_devices('GPU'):
print("TensorFlow **IS** using the GPU")
else:
print("TensorFlow **IS NOT** using the GPU")
結(jié)果為:
TensorFlow **IS NOT** using the GPU
更多細(xì)節(jié)參考Tensor Guide
變量
tf.Tensor類型是不可變類型斟冕,當(dāng)需要保存如模型參數(shù)之類的變量時(shí)口糕,可以使用tf.Variable類型
var = tf.Variable([0.0, 0.0, 0.0])
var.assign([1, 2, 3])
<tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>
var.assign_add([1, 1, 1])
<tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([2., 3., 4.], dtype=float32)>
更多細(xì)節(jié)參閱Variables guide
自動(dòng)微分
梯度下降法及相關(guān)算法是現(xiàn)代機(jī)器學(xué)習(xí)的重要基礎(chǔ)。
TensorFlow實(shí)現(xiàn)了基于微積分學(xué)的自動(dòng)微分磕蛇,可以幫助你自動(dòng)計(jì)算梯度景描。通常你會(huì)使用這個(gè)功能來(lái)計(jì)算模型的loss關(guān)于其參數(shù)的梯度。
import tensorflow as tf
x = tf.Variable(1.0)
def f(x):
y = x ** 2 + 2 * x -5
return y
f(x)
結(jié)果為:
tf.Tensor(-2.0, shape=(), dtype=float32)
在x=1.0孤里,y=f(x) = -2伏伯,其導(dǎo)數(shù)為y' = 2 * x + 2 = 4。TensorFlow可以自動(dòng)計(jì)算出導(dǎo)數(shù)
with tf.GradientTape() as tape:
y = f(x)
g_x = tape.gradient(y, x)
g_x
運(yùn)行結(jié)果為:
tf.Tensor(4.0, shape=(), dtype=float32)
這是一個(gè)對(duì)簡(jiǎn)單標(biāo)量x求導(dǎo)數(shù)的例子捌袜。TensorFlow可以對(duì)任意數(shù)量的張量同時(shí)計(jì)算梯度说搅。
參考自動(dòng)微分獲得更多的詳情。
圖和tf.function
TensorFlow可以讓你像使用其他python庫(kù)一樣交互式地使用TensorFlow虏等,TensorFlow還提供了一些工具:
- 性能優(yōu)化:加速訓(xùn)練和推算過(guò)程
- 導(dǎo)出:在訓(xùn)練結(jié)束之后保存模型
這需要你使用tf.function讓TensorFlow代碼與Python代碼分離弄唧。
@tf.function
def my_func(x):
print('Tracing')
return tf.reduce_sum(x)
x = tf.constant([1, 2, 3])
print(my_func(x))
結(jié)果為:
Tracing
tf.Tensor(6, shape=(), dtype=int32)
在接下來(lái)的調(diào)用中,TensorFlow只會(huì)運(yùn)行優(yōu)化過(guò)的圖代碼霍衫,跳過(guò)非TensorFlow代碼候引。下面的代碼中my_func不會(huì)打印“Tracing”字符,因?yàn)閜rint是一個(gè)純python代碼敦跌,不是TensorFlow的函數(shù)澄干。
x = tf.constant([10, 9, 8])
my_func(x)
結(jié)果為:
tf.Tensor(27, shape=(), dtype=int32)
一個(gè)圖方法會(huì)為不同的入?yún)㈩愋?shape and dtype)創(chuàng)建不同的實(shí)例,即下面的代碼會(huì)生成一個(gè)新的圖柠傍。
x = tf.constant([10.0, 9.1, 8.2], dtype=tf.float32)
my_func(x)
這種圖快照提供了兩個(gè)優(yōu)點(diǎn):
- 很多情況下圖快照可以提供顯著的計(jì)算加速效果
- 你可以使用tf.saved_model導(dǎo)出圖麸俘,并將其運(yùn)行在其他系統(tǒng)上(如服務(wù)器和移動(dòng)設(shè)備),而無(wú)需Python環(huán)境惧笛。
Modules, Layers 和models
tf.Module是用于管理tf.Variables對(duì)象以及基于這些對(duì)象的tf.function對(duì)象的類从媚。tf.Module類是實(shí)現(xiàn)如下兩個(gè)重要功能特性的必要條件:
- 使用tf.train.CheckPoint實(shí)現(xiàn)變量保存的功能,可以快速保存在訓(xùn)練過(guò)程中的模型狀態(tài)
- 使用tf.saved_model來(lái)導(dǎo)入導(dǎo)出tf.Variable的值和tf.function的圖患整,這使得你可以脫離Python環(huán)境而在任意的設(shè)備上運(yùn)行你的模型拜效。
下面是一個(gè)簡(jiǎn)單卻又完整的tf.Module導(dǎo)出過(guò)程:
import tensorflow as tf
class MyModule(tf.Module):
def __init__(self, value):
self.weight = tf.Variable(value)
@tf.function
def multiply(self, x):
return x * self.weight
mod = MyModule(3)
mod.multiply(tf.constant([1, 2, 3]))
save_path = './saved'
tf.saved_model.save(mod, save_path)
reload = tf.saved_model.load(save_path)
print(reload.multiply(tf.constant([1, 2, 3])))
保存結(jié)果SavedModel獨(dú)立于創(chuàng)建時(shí)的代碼。你可以重新載入SavedModel至Python各谚、其他支持TensorFlow的編程語(yǔ)言或TensorFlow Serving紧憾。你也可以將其運(yùn)行在 TensorFlow Lite 或 TensorFlow JS上
基于tf.Module的tf.keras.layers.Layer和tf.keras.Model類提供了更多的功能和便捷的方法用于編譯、訓(xùn)練和保存模型嘲碧,這些將在下一節(jié)提及稻励。
更多細(xì)節(jié)請(qǐng)參考Intro to modules
Training Loops
下面,我們將上述的所有概念綜合使用起來(lái)建立一個(gè)模型,并且從頭開(kāi)始進(jìn)行訓(xùn)練望抽。
首先我們創(chuàng)建一下測(cè)試數(shù)據(jù)加矛,使用二次曲線產(chǎn)生一些數(shù)據(jù)點(diǎn)。
import tensorflow as tf
import matplotlib
from matplotlib import pyplot as plt
matplotlib.rcParams['figure.figsize'] = [9, 6]
x = tf.linspace(-2, 2, 201)
x = tf.cast(x, tf.float32)
def f(x):
y = x ** 2 + 2 * x - 5
return y
y = f(x) + tf.random.normal(shape=[201])
plt.plot(x.numpy(), y.numpy(), '.', label='Data')
plt.plot(x, f(x), label='Ground truth')
plt.legend()
plt.show()
然后煤篙,創(chuàng)建一個(gè)模型
class Model(tf.keras.Model):
def __init__(self, units):
super(Model, self).__init__()
self.dense1 = tf.keras.layers.Dense(units=units,
activation=tf.nn.relu,
kernel_initializer=tf.random.normal,
bias_initializer=tf.random.normal)
self.dense2 = tf.keras.layers.Dense(1)
def call(self, x, training=True):
x = x[:, tf.newaxis]
x = self.dense1(x)
x = self.dense2(x)
return tf.squeeze(x, axis=1)
model = Model(64)
plt.plot(x.numpy(), y.numpy(), '.', label='Data')
plt.plot(x, f(x), label='Ground truth')
plt.plot(x, model(x), label='Untrained predictions')
plt.title('Before training')
plt.legend()
plt.show()
編寫代碼進(jìn)入訓(xùn)練階段斟览。由于tf.keras已經(jīng)集成了大多數(shù)常用的訓(xùn)練工具,因此直接調(diào)用keras自帶的功能即可辑奈。為此苛茂,你需要使用Model.compile和Model.fit方法來(lái)實(shí)現(xiàn)訓(xùn)練過(guò)程。
model.compile(loss=tf.keras.losses.MSE, optimizer=tf.keras.optimizers.SGD(learning_rate=0.01))
history = model.fit(x, y, epochs=100, batch_size=32, verbose=0)
model.save("./my_model")
將訓(xùn)練過(guò)程中的loss打印出來(lái):
plt.plot(history.history['loss'])
plt.xlabel('Epoch')
plt.ylim([0, max(plt.ylim())])
plt.ylabel('Loss [Mean Squared Error]')
plt.title('Keras training progress')
plt.show()
更多詳情請(qǐng)參考 Basic training loops 與 Keras guide