關於TensorFlow 2.0,這裏有你想知道的一切

全文共8094字,預計學習時長30分鐘或更長python

圖片來源:pexels.com/@pixabaygit

TensorFlow是谷歌2015年開源的通用高性能計算庫。最初主要是爲構建神經網絡(NNs)提供高性能的API。然而,隨着時間的推移和機器學習(ML)社區的興起,TensorFlow已經發展爲一個完整的機器學習生態系統。程序員

TensorFlow自誕生以來變化巨大。TensorFlow 2.0目前處於測試階段,與TF1.x相比有了許多變化。下面是主要的幾個變化。github

1. 默認狀態的Eager Execution

首先,eager execution是運行TF代碼的默認方式。web

爲了在TF1.x中構建一個神經網絡,須要定義一個名爲圖形(Graph)的抽象數據結構。另外,若是試圖打印其中一個圖節點,將看不到指望值,卻能夠看到對圖節點的引用。實際上,要運行圖形,須要使用一個名爲會話(Session)的封裝。使用Session.run()法,能夠將Python數據傳給圖形,並對模型進行實際訓練。編程

TF 1.x代碼示例api

利用eager execution能夠進行改變。如今,TensorFlow代碼能夠像普通的Python代碼同樣運行。這意味着能夠迅速建立並評估操做。瀏覽器

Tensorflow 2.0代碼示例服務器

TensorFlow 2.0代碼看起來很像NumPy代碼。事實上,TensorFlow和NumPy的對象能夠很容易地切換。所以沒必要擔憂佔位符、會話、feed_dictionaties等問題。網絡

2. API清理

許多API,如tf.gans、tf.app、tf.contrib、tf.flags,會被清理或移動到單獨的存儲庫。

然而,最重要的清理之一涉及到咱們如何構建模型。TF1.x中有超過1或2種不一樣的構建/訓練ML模型的方法。

tf.slim,tf.layers,tf.contrib.layers,tf.keras都是能夠用來構建神經網絡的API。不包括TF1.x中的序列到API序列。大多數狀況下,每種狀況下要選擇哪種尚不明確。

儘管許多API性能良好,但彷佛並無收斂出一種通用的開發方式。此外,若是在其中一個API中訓練模型,那麼使用其餘API來再利用該代碼並不簡單。

在TF2.0中,tf.keras是推薦的高級API。

能夠看到,目前正試圖利用KerasAPI解決全部可能的用例。

3. 初學者API

與1.0版本相比,2.0版本中的初學者API變化不大。可是如今,Keras爲默認和推薦的高級API。總之,Keras指的是一組圖層,經過使用明確的標準來構建神經網絡。使用pip安裝TensorFlow時,通常會獲得完整的Keras API和一些附加功能。

model= tf.keras.models.Sequential()
model.add(Flatten(input_shape=
(IMAGE_HEIGHT,IMAGE_WIDTH)))
model.add(Dense(units=32,activation='relu'))
model.add(Dropout(0.3))
model.add(Dense(units=32,activation='relu'))
model.add(Dense(units=10,activation='softmax')) 
#Configures the model for training.
#Define the model optimizer, the loss 
function and the accuracy metrics
model.compile(optimizer='adam',             
loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.summary()

初學者API稱爲序列化,通常會將神經網絡定義爲一組層。除了簡單性,它還有其餘優勢。請注意,模型是根據數據結構(一組層)來定義的。所以,因爲模型定義而產生錯誤的機率降至最低。

4. Keras-Tuner

Keras-tuner是一個對Keras模型進行超參數調整的專用庫。在撰寫本文時,該庫處於α以前的狀態,可是使用tf.keras和TensorFlow 2.0β能夠在Colab上很好地運行。

傳送門:https://github.com/keras-team/keras-tuner

這個概念很是簡單。首先,須要定義一個返回編譯後的Keras模型的建模函數。函數接受一個名爲hp的參數做爲輸入。經過使用hp,能夠定義一個候選值的範圍,對超參數值進行採樣。

下面創建了一個簡單的模型,並對3個超參數進行了優化。爲了查看隱藏單元,對預約義範圍之間的整數值進行採樣。爲了計算丟失率和學習率,在一些給定值之間隨機選擇。

defbuild_model(hp): 
# define the hyper parameter ranges for 
thelearning rate, dropout and hidden unit  
hp_units = hp.Range('units', min_value=32,max_value=128, step=32)  
hp_lr = hp.Choice('learning_rate',values=[1e-2, 1e-3, 1e-4])  
hp_dropout = hp.Choice('dropout',values=[0.1,0.2,0.3])  
 
# build a Sequential model  
model = keras.Sequential() 
model.add(Flatten(input_shape=(IMAGE_HEIGHT,IMAGE_WIDTH)))  
model.add(Dense(units=hp_units,activation='relu'))  
model.add(Dropout(hp_dropout))  
model.add(Dense(units=32, activation='relu'))  
model.add(layers.Dense(10,activation='softmax'))   
# compile and return the model model.compile(optimizer=keras.optimize
rs.Adam(hp_lr),      
loss='sparse_categorical_crossentropy',     
metrics=['accuracy'])  

return model 
#create a Random Search tunertuner= RandomSearch(    
build_model,    
objective='val_accuracy', # define themetric to be optimized over    
max_trials=3,    
executions_per_trial=1,    
directory='my_logs') 
# define the outputlog/checkpoints folder  
# start hyper-parameter optmization searchtuner.search(x_train,y_train,             
epochs=2,             
validation_data=(x_test, y_test))

而後建立一個調諧器對象。在這種狀況下,會實現隨機搜索策略。最後可使用search() 開始優化。它具備與 fit()相同的簽名。

最後,能夠檢查調諧器的結論,並選擇最佳模型。請注意,訓練日誌和模型檢查點都保存在目錄文件夾(my_logs)中。此外,最小化或最大化目標(驗證精度)的選擇是自動推斷的。

5. 高級API

當你看到這種類型的implementation時,要追溯到面向對象編程。這裏的模型是一個擴展tf.keras.Model的Python類。模型子類化是由Chainer提出的,與PyTorch如何定義模型有很大關聯。

經過模型子類化來定義類構造函數中的模型層。call()負責正推法的定義和執行。

class Model(tf.keras.Model):  
def__init__(self):    
# Define thelayers here    
super(Model,self).__init__()    
self.conv1 =Conv2D(filters=8, kernel_size=4, padding="same", 
strides=1,input_shape=(IMAGE_HEIGHT,IMAGE_WIDTH,IMAGE_DEPTH))    
self.conv2 =Conv2D(filters=16, kernel_size=4, padding="same", strides=1)    
self.pool =MaxPool2D(pool_size=2, strides=2, padding="same")    
self.flat =Flatten()    
elf.probs =Dense(units=N_CLASSES, activation='softmax', name="output")   
def call(self,x):   

# Define theforward pass    
net =self.conv1(x)    
net =self.pool(net)    
net =self.conv2(net)    
net =self.pool(net)    
net =self.flat(net)    
net =self.probs(net)    
return net   

defcompute_output_shape(self, input_shape):    
# You need tooverride this function if you want to use the subclassed model    
# as part of afunctional-style model.    
# Otherwise,this method is optional.    
shape =tf.TensorShape(input_shape).as_list()    
shape[-1] =self.num_classes    
returntf.TensorShape(shape)

子類化優勢不少:簡化模型檢查;(使用斷點調試)在給定的行中止並檢查模型的激活或邏輯。

然而,靈活性增長以後,隨之而來的是更多的漏洞。

模型子類化須要程序員更多的關注和了解。

總之,代碼的錯誤會更明顯(如模型佈線)。

6. 定義培訓迴路

在TF2.0中訓練模型的最簡便方法是使用 fit() 。fit()支持序列化模型和子類化模型。若是使用模型子類化,惟一須要調整的就是重寫compute_output_shape()分類方法。除此以外,應該可以將fit()與tf.data.Dataset 或標準NumPynd-arrays一塊兒輸入。

可是,若是想清楚地瞭解梯度或丟失的狀況,可使用梯度帶。這在研究中格外有效。

使用梯度帶,就能夠手動定義訓練過程的每一個步驟。可分別應用於訓練神經網絡的每一個基本步驟,如:

· 正推法

· 損失函數求值

· 逆推法

· 梯度降低法

能夠直觀地瞭解神經網絡是如何訓練的。也能夠直接輸出損失值w.r.t、模型權重或梯度向量自己來進行檢查。

梯度帶提供了更大的靈活性。可是,就像子類化與序列化同樣,靈活性越大,額外的成本越高。與fit()相比,須要手動定義一個訓練迴路。做爲一個天然結果,它使代碼的漏洞更加突出,而且更難調試。這是一個很好的折衷,和那些對開發新產品感興趣的研究人員相比,更適合代碼工程師(尋找標準化的代碼)。

另外,使用fit() 能夠簡便地設置TensorBoard。

7. 設置TensorBoard

使用 fit()能夠 簡便地設置TensorBoard的實例。它也適用於Jupyter/Colab notebook。

添加TensorBoard,做爲fit的回調函數。

fit()能夠用於序列化API和子類化API。

# Load theTensorBoard notebook extension%load_exttensorboard 
# create thetensorboard callbacktensorboard= TensorBoard
(log_dir='logs/{}'.format(time.time()), histogram_freq=1) 
# train themodelmodel.fit(x=x_train,  
        
y=y_train,          
epochs=2,          
validation_data=(x_test, y_test),          
callbacks=[tensorboard]) 
# launchTensorBoard%tensorboard--logdir logs

若是選擇使用模型子類化並本身編寫訓練迴路(使用分級帶),則還須要手動定義TensorBoard。包括使用 tf.summary.create_file_writer()建立摘要文件,並指定須要可視化的變量。

有許多回調函數可供使用,其中較爲有效的是:

· EarlyStopping:顧名思義,它創建了一個規則——當監控量中止增長時,就中止培訓。

· ReduceLROnPlateau:當測度中止增長時,下降學習速率。

· TerminateOnNaN:遇到NaN丟失時終止培訓。

· LambdaCallback:用於建立簡單的自定義聯機回調。

可在 TensorFlow 2.0 callbacks查看完整目錄。

傳送門:https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/callbacks

8. EagerCode的提取性能

若是選擇使用梯度帶進行模型訓練,性能會顯著降低。

執行TF代碼有助於理解,但性能不佳。爲了不這個問題,TF2.0引入了tf.function。

基本上,若是用tf.function修飾Python函數,TensorFlow會接收函數並將其轉換爲一個TF高性能抽象。

@tf.functiondeftrain_step(images, labels):   
with tf.GradientTape() as tape:    
# forward pass    
predictions = model(images)  
     
# compute the loss    
loss = cross_entropy(tf.one_hot(labels,N_CLASSES), predictions)   
# get the gradients w.r.t the model's weights  
gradients = tape.gradient(loss,model.trainable_variables)  
 
# perform a gradient descent step  
optimizer.apply_gradients(zip(gradients,model.trainable_variables))   
# accumulates the training loss and accuracy  train_loss(loss)  
train_accuracy(labels, predictions)

這意味着該函數將標記爲JIT編輯,以便TensorFlow將其做爲圖形運行。所以,能夠得到TF1.x(圖形)的性能優點,如節點修剪、內核融合等。

簡而言之,TF2.0旨在將代碼設計爲更小的函數。而後,可使用tf.function對所需的代碼進行標記以得到額外的性能。最適用於修飾表示最大計算瓶頸的函數。這些一般是訓練迴路或模型的正推。

注意,用tf.function修飾函數時,會失去eager execution的一些優點。也就是說,沒法在該代碼段中設置斷點或使用print()。

9. 保存和修復模型

TF1.x對於如何保存/加載通過培訓的模型以用於生產缺少一致的標準。TF2.0試圖經過定義單個API來解決這個問題。

TF2.0保存模型的方法很少,而是對一個稱爲SavedModel的抽象進行標準化。

這裏無需多言。若是使用tf.keras.模型建立序列化模型或擴展類,則類將從tf.train.Checkpoints繼承。所以,能夠將模型序列化爲SavedModel對象。

# serialize your model to a SavedModel object
# It includes the entire graph, all variables 
andweightsmodel.save('/tmp/model', save_format='tf') 
# load your saved 

modelmodel = tf.keras.
models.load_
model('/tmp/model')

SavedModel與Tensorflow生態系統結合到一塊兒。換句話說,可以將其分配到許多不一樣的設備,包括移動電話、邊緣設備和服務器。

10. 轉換至TF-Lite

若是要將SavedModel分配到Raspberry Pi、Edge TPU或手機等嵌入式設備,請使用TF Lite轉換器。

請注意,在2.0版本中中,TFLite轉換器不支持凍結的GraphDef(一般在TF1.x中生成)。若是要將凍結的GraphDefs轉換爲在TF2.0中運行,可使用tf.compat.v1.TFLite轉換器。

在分配到嵌入式設備以前,通常會進行訓練後量化。要使用TFLite轉換器執行此操做,請將優化標誌設置爲「OPTIMIZE_FOR_SIZE」。這將把模型的權重從浮點量化到8位精度。可在不下降模型精度的狀況下減少模型尺寸並改善延遲。

# create a TF Lite converter
converter 
=tf.lite.TFLiteConverter.from_keras_mode
l(model) 

# performs model quantization to reduce 
the size of themodel and improve latency

converter.optimizations 
=[tf.lite.Optimize.OPTIMIZE_FOR_SIZE] 
tflite_model = converter.convert()

請注意,這是一個實驗性標誌,可能會發生更改。

11. 轉換至TensorFlow.js

如要關閉,可使用相同的SavedModel對象並將其轉換爲TensorFlow.js格式。而後可以使用JavaScript進行加載,並在瀏覽器上運行模型。

!tensorflowjs_converter\    
--input_format=tf_saved_model \    
--saved_model_tags=serve \    
--output_format=tfjs_graph_model \    
/tmp/model \    
/tmp/web_model

首先,須要經過pip安裝TensorFlow.js。而後使用tensorflowjs_converter腳本獲取訓練模型並轉換爲Javascript兼容的代碼。最後,可進行加載並用Javascript進行推斷。

還能夠在瀏覽器上使用Tesnorflow.js來訓練模型。

結語

最後來介紹2.0版本的其餘功能。首先,向序列化模型或子類化模型添加更多層是很是簡單的。儘管TF覆蓋了Conv2D、TransposeConv2D等層,但總會出現不可用的狀況。對於論文再現或研究來講尤其如此。

好消息是,能夠開發自定義層。經過遵循相同的Keras API,能夠建立一個類並將其擴展到tf.keras.Layer。實際上,能夠按照很是類似的模式建立自定義激活函數、正則化層或測度。

資源傳送門:https://www.tensorflow.org/tutorials/eager/custom_layers

此外,還能夠將現有的TensorFlow 1.x代碼轉換爲TF2.0。爲此,TF團隊建立了tf_upgrade_v2。

此腳本不將TF1.x代碼轉換爲2.0慣用代碼。它基本上將tf.compat.v1模塊用於更更名稱空間的函數。另外,若是舊代碼使用tf.contrib,將沒法進行轉換。可能須要使用其餘庫或缺失函數的新TF2.0版本。

留言 點贊 發個朋友圈

咱們一塊兒分享AI學習與發展的乾貨

相關文章
相關標籤/搜索