全文共8094字,預計學習時長30分鐘或更長python
圖片來源:pexels.com/@pixabaygit
TensorFlow是谷歌2015年開源的通用高性能計算庫。最初主要是爲構建神經網絡(NNs)提供高性能的API。然而,隨着時間的推移和機器學習(ML)社區的興起,TensorFlow已經發展爲一個完整的機器學習生態系統。程序員
TensorFlow自誕生以來變化巨大。TensorFlow 2.0目前處於測試階段,與TF1.x相比有了許多變化。下面是主要的幾個變化。github
首先,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等問題。網絡
許多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解決全部可能的用例。
與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稱爲序列化,通常會將神經網絡定義爲一組層。除了簡單性,它還有其餘優勢。請注意,模型是根據數據結構(一組層)來定義的。所以,因爲模型定義而產生錯誤的機率降至最低。
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)中。此外,最小化或最大化目標(驗證精度)的選擇是自動推斷的。
當你看到這種類型的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)
子類化優勢不少:簡化模型檢查;(使用斷點調試)在給定的行中止並檢查模型的激活或邏輯。
然而,靈活性增長以後,隨之而來的是更多的漏洞。
模型子類化須要程序員更多的關注和了解。
總之,代碼的錯誤會更明顯(如模型佈線)。
在TF2.0中訓練模型的最簡便方法是使用 fit() 。fit()支持序列化模型和子類化模型。若是使用模型子類化,惟一須要調整的就是重寫compute_output_shape()分類方法。除此以外,應該可以將fit()與tf.data.Dataset 或標準NumPynd-arrays一塊兒輸入。
可是,若是想清楚地瞭解梯度或丟失的狀況,可使用梯度帶。這在研究中格外有效。
使用梯度帶,就能夠手動定義訓練過程的每一個步驟。可分別應用於訓練神經網絡的每一個基本步驟,如:
· 正推法
· 損失函數求值
· 逆推法
· 梯度降低法
能夠直觀地瞭解神經網絡是如何訓練的。也能夠直接輸出損失值w.r.t、模型權重或梯度向量自己來進行檢查。
梯度帶提供了更大的靈活性。可是,就像子類化與序列化同樣,靈活性越大,額外的成本越高。與fit()相比,須要手動定義一個訓練迴路。做爲一個天然結果,它使代碼的漏洞更加突出,而且更難調試。這是一個很好的折衷,和那些對開發新產品感興趣的研究人員相比,更適合代碼工程師(尋找標準化的代碼)。
另外,使用fit() 能夠簡便地設置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
若是選擇使用梯度帶進行模型訓練,性能會顯著降低。
執行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()。
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生態系統結合到一塊兒。換句話說,可以將其分配到許多不一樣的設備,包括移動電話、邊緣設備和服務器。
若是要將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()
請注意,這是一個實驗性標誌,可能會發生更改。
如要關閉,可使用相同的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學習與發展的乾貨