TensorFlow 2.1指南:keras模式、渴望模式和圖形模式(附代碼)

2020-12-13 人工智慧研究院

我們是否使用了正確的工具?哪種框架最適合我的用例?這種方法可擴展嗎?我們是否考慮到可擴展性?如果你像我一樣是一個普通人,那麼可能已經體驗到有時會陷入應用程式開發的困境,以至於很難停下來,去思考一下我們是否採取了有效的方式。

在AI領域尤其如此。眾所周知,人工智慧是一個快速發展的領域。當天發表了新的研究。正在迅速開發的主要AI框架之間存在著巨大的鬥爭。發布了新的硬體體系結構,晶片和優化,以支持不斷增長的AI應用的部署。

什麼時候是停下來重新考慮的好時機?那只有你會知道。對我來說,這一刻已經到來了。我一直在使用Keras和Tensorflow的1.x(TF1)在工作和我的個人項目,因為我在這個領域開始。我完全喜歡Keras庫的高級方法和Tensorlfow的低級方法,這些方法可以讓我們在需要更多自定義時在後臺進行更改。

儘管我一直是Keras-Tensorflow兼容的忠實擁護者,但始終有一個非常具體的缺點:調試功能。如你所知,在Tensorflow中,存在這樣的範例:首先定義計算圖,然後進行編譯(或將其移至GPU),然後運行它。這種範例非常好,從技術上來講很有意義,但是,一旦在GPU中擁有了模型,幾乎就不可能對其進行調試。

這就是為什麼,自從TensorFlow 2.0以其Alpha版本發布以來已經過去了大約一年,我決定在TensorFlow 2.1與大家分享使用的體驗。

TensorFLow 2.1

事實上,我很難弄清楚應該如何使用這個新的TensorFlow版本,即著名的2.1穩定版本。TensorFlow 2編程與TensorFlow 1的不同之處在於面向對象編程與功能性編程的區別。

經過一些實驗後,我發現在TensorFlow 2.1中,有3種構建模型的方法:

Keras模式(tf.keras):基於圖形定義,並在以後運行圖形。渴望模式:基於定義執行的所有迭代定義圖的操作。圖形模式(tf.function):之前兩種方法的混合。讓我們來看看代碼。

Keras模式

import numpy as npimport tensorflow as tffrom tensorflow import kerasfrom tensorflow.keras.layers import Input, Dense, Flatten, Conv2Dfrom tensorflow.keras import Modelfrom tensorflow.keras.optimizers import Adamdef loss(y_true, y_pred): """Loss function""" return tf.square(y_true - y_pred)if __name__ == '__main__': # Learn to sum 20 nums, train and test datasets train_samples = tf.random.normal(shape=(10000, 20)) train_targets = tf.reduce_sum(train_samples, axis=-1) test_samples = tf.random.normal(shape=(100, 20)) test_targets = tf.reduce_sum(test_samples, axis=-1) # Model building with Keras functional API x = Input(shape=[20]) h = Dense(units=20, activation='relu')(x) h = Dense(units=10, activation='relu')(h) y = Dense(units=1)(h) model = Model(x,y) # Compiling model model.compile( optimizer=Adam(learning_rate=0.001), loss=loss, metrics=['mse']) # Training model.fit( x=train_samples, y=train_targets, batch_size=1, epochs=10, validation_data=(test_samples, test_targets), shuffle=True)

這是我們所有人都習慣的標準用法。僅使用具有自定義損失功能且具有平方誤差損失的普通Keras。該網絡是3個密集層的深層網絡。

# The networkx = Input(shape=[20])h = Dense(units=20, activation='relu')(x)h = Dense(units=10, activation='relu')(h)y = Dense(units=1)(h)

這裡的目的是教一個網絡,學習如何對20個元素的向量求和。因此,我們用的數據集為網絡提供數據[10000 x 20],因此10000個樣本每個都有20個特徵(要求和的元素)。

# Training samplestrain_samples = tf.random.normal(shape=(10000, 20))train_targets = tf.reduce_sum(train_samples, axis=-1)test_samples = tf.random.normal(shape=(100, 20))test_targets = tf.reduce_sum(test_samples, axis=-1)

我們可以運行該示例,然後得到通常看起來不錯的Keras輸出:

Epoch 1/1010000/10000 [==============================] - 10s 1ms/sample - loss: 1.6754 - val_loss: 0.0481Epoch 2/1010000/10000 [==============================] - 10s 981us/sample - loss: 0.0227 - val_loss: 0.0116Epoch 3/1010000/10000 [==============================] - 10s 971us/sample - loss: 0.0101 - val_loss: 0.0070

以上是一個Keras玩具示例的訓練時間為每秒鐘10秒

看完這個過程後,可能會想知道一個問題:TensorFlow 2版本承諾將在所有功能上實現哪些功能?如果與Keras軟體包的集成意味著不必安裝其他軟體包,那麼優點是什麼?

急切模式

在這種模式下,所有張量操作都是交互的,你可以設置一個斷點並訪問任何中間張量變量。但是,這種靈活性要付出代價:需要更明確的代碼。讓我們來看看:

import numpy as npimport tensorflow as tffrom tqdm import tqdmfrom tensorflow import kerasfrom tensorflow.keras.layers import Input, Dense, Flatten, Conv2Dfrom tensorflow.keras import Modelfrom tensorflow.keras.optimizers import Adamdef loss_compute(y_true, y_pred): return tf.square(y_true - y_pred)if __name__ == '__main__': # Learn to sum 20 nums train_samples = tf.random.normal(shape=(10000, 20)) train_targets = tf.reduce_sum(train_samples, axis=-1) test_samples = tf.random.normal(shape=(100, 20)) test_targets = tf.reduce_sum(test_samples, axis=-1) # Model building: Keras functional API x = Input(shape=[20]) h = Dense(units=20, activation='relu')(x) h = Dense(units=10, activation='relu')(h) y = Dense(units=1)(h) model = Model(x,y) # Training loop epochs = 10 optimizer = tf.keras.optimizers.Adam(learning_rate=0.001) for epoch in range(epochs): # Fancy progress bar pbar = tqdm(range(len(train_samples))) # Metrics loss_metric = keras.metrics.Mean() # Batches iteration, batch_size = 1 for batch_id in pbar: # Getting sample target pair sample = train_samples[batch_id] target = train_targets[batch_id] # Adding batch dim since batch=1 sample = tf.expand_dims(sample, axis=0) target = tf.expand_dims(target, axis=0) # Forward pass: needs to be recorded by gradient tape with tf.GradientTape() as tape: target_pred = model(sample) loss = loss_compute(target, target_pred) # Backward pass: # compute gradients w.r.t. the loss # update trainable weights of the model gradients = tape.gradient(loss, model.trainable_weights) optimizer.apply_gradients(zip(gradients, model.trainable_weights)) # Tracking progress loss_metric(loss) pbar.set_description('Training Loss: %.3f' % loss_metric.result().numpy()) # At the end of the epoch test the model test_targets_pred = model(test_samples) test_loss = loss_compute(test_targets, test_targets_pred) test_loss_avg = tf.reduce_mean(test_loss) print('Validation Loss: %.3f' % test_loss_avg)

閱讀代碼後,第一件事可能是:很多代碼僅用於執行a model.compile和a model.fit。但另一方面,可以控制之前所有發生的事情。

所以現在情況變了。通過這種方法,可以從頭開始設計事物的工作方式。現在可以指定以下內容:

指標:按樣品,批次或任何其他自定義統計來測量結果。根據需要使用穩定的舊移動平均線或任何其他自定義指標。損失函數:可以在損失函數定義中獲得所有想要的技巧,而Keras不會因為其_standarize_user_data(link)報錯。漸變:可以訪問漸變,並定義前進和後退通道的細節。指標是使用新tf.keras.metrics API指定的。只需採用所需的指標,對其進行定義並按以下方式使用它:

# Getting metric instancedmetric = tf.keras.metrics.Mean() # Run your model to get the loss and update the metricloss = [...]metric(loss)# Print the metric print('Training Loss: %.3f' % metric.result().numpy())

損耗函數和梯度分別在前向和後向傳遞中計算。在這種方法中,前向通行證必須由記錄tf.GradientTape。在tf.GradientTape將跟蹤(或磁帶)的直傳這樣做可以在計算後向通行的梯度所有的張量操作。換句話說:為了向後運行,必須記住要前進的道路。

# Forward pass: needs to be recorded by gradient tapewith tf.GradientTape() as tape: y_pred = model(x) loss = loss_compute(y_true, y_pred)# Backward pass:gradients = tape.gradient(loss, model.trainable_weights)optimizer.apply_gradients(zip(gradients, model.trainable_weights))

這非常簡單,在前向傳遞中,可以運行預測,並通過計算損失來查看預測的效果。在後向過程中,可以通過計算梯度來檢查權重如何影響該損失,然後嘗試通過更新權重(在優化程序的幫助下)來最小化損失。還可以在代碼中注意到,在每個時期結束時,都會計算驗證損失(通過僅運行前向傳遞而不更新權重)來看看結果:

Epoch 1:Loss: 1.310: 100%|███████████| 10000/10000 [00:41<00:00, 239.70it/s]Epoch 2:Loss: 0.018: 100%|███████████| 10000/10000 [00:41<00:00, 240.21it/s]Epoch 3:Loss: 0.010: 100%|███████████| 10000/10000 [00:41<00:00, 239.28it/s]

在同一臺機器上,每個紀元花費41s,即4倍的時間增量……而這只是一個虛擬模型。能想像如何將其擴展到RetinaNet,YOLO或MaskRCNN等實際用例模型嗎?TensorFlow的好夥伴意識到了這一點,並實現了圖形模式。

圖形模式

圖形模式(來自AutoGraph或tf.function)是前兩種之間的混合模式。可以了解此處和此處的內容。但是發現這些指南有些混亂,所以用自己的話來解釋它。

如果Keras模式是要定義圖形並稍後在GPU中運行,而eager模式是要以交互方式執行每個步驟,則graph模式可以讓我們像在eager模式下一樣進行編碼,但是運行訓練的速度幾乎與處於Keras模式(是的,在GPU中)。

關於eager模式的唯一變化是在圖形模式下,將代碼分解為小函數,並使用注釋了這些函數@tf.function。讓我們看一下情況如何變化:

import numpy as npimport tensorflow as tffrom tqdm import tqdmfrom tensorflow import kerasfrom tensorflow.keras.layers import Input, Dense, Flatten, Conv2Dfrom tensorflow.keras import Modelfrom tensorflow.keras.optimizers import Adam@tf.functiondef loss_compute(y_true, y_pred): """Loss function""" return tf.square(y_true - y_pred)@tf.functiondef forward_pass(model, sample, target): # Needs to be recorded by gradient tape with tf.GradientTape() as tape: target_pred = model(sample) loss = loss_compute(target, target_pred) # compute gradients w.r.t. the loss # (I know this belongs to backward pass but...) gradients = tape.gradient(loss, model.trainable_weights) return loss, gradients@tf.functiondef backward_pass(model, gradients, optimizer): optimizer.apply_gradients(zip(gradients, model.trainable_weights))if __name__ == '__main__': # Learn to sum 20 nums train_samples = tf.random.normal(shape=(10000, 20)) train_targets = tf.reduce_sum(train_samples, axis=-1) test_samples = tf.random.normal(shape=(100, 20)) test_targets = tf.reduce_sum(test_samples, axis=-1) # Model Functional API x = Input(shape=[20]) h = Dense(units=20, activation='relu')(x) h = Dense(units=10, activation='relu')(h) y = Dense(units=1)(h) model = Model(x,y) # Training loop epochs = 10 optimizer = tf.keras.optimizers.Adam(learning_rate=0.001) for epoch in range(epochs): # Fancy progress bar pbar = tqdm(range(len(train_samples))) # Metrics loss_metric = keras.metrics.Mean() # Batches iteration, batch_size = 1 for batch_id in pbar: # Getting sample target pair sample = train_samples[batch_id] target = train_targets[batch_id] # Adding batch dim since batch=1 sample = tf.expand_dims(sample, axis=0) target = tf.expand_dims(target, axis=0) # This is computed in graph mode # Computing loss and gradients w.r.t the loss loss, gradients = forward_pass(model, sample, target) # Updaing model weights backward_pass(model, gradients, optimizer) # Tracking progress loss_metric(loss) pbar.set_description('Training Loss: %.3f' % loss_metric.result().numpy()) # At the end of the epoch test the model test_targets_pred = model(test_samples) test_loss = loss_compute(test_targets, test_targets_pred) test_loss_avg = tf.reduce_mean(test_loss) print('Validation Loss: %.3f' % test_loss_avg)

現在,將了解前向和後向傳遞計算如何重構為@tf.function裝飾器已注釋的2個函數。

那麼,這裡到底發生了什麼?簡單。每當你用@tf.function裝飾器注釋函數時,都將與Keras一樣將這些操作「編譯」到GPU中。因此,通過注釋函數,可以告訴TensorFlow在GPU中的優化圖形中運行這些操作。

在幕後,真正發生的是該函數正在由AutoGraph解析tf.autograph。AutoGraph將獲取函數的輸入和輸出,並從中生成一個TensorFlow圖,這意味著它將解析操作以將輸入的輸出轉換為TensorFlow圖。生成的圖形將非常高效地運行到GPU中。

這就是為什麼它是一種混合模式的原因,因為除了用@tf.function裝飾器注釋的操作之外,所有操作都以交互方式運行。

這也意味著除了用修飾的函數中的變量和張量之外,將可以訪問所有變量和張量@tf.function,而其中的變量和張量只能訪問其輸入和輸出。這種方法建立了一種非常清晰的調試方式,可以在這種方式下以渴望的模式開始進行交互式開發,然後在模型準備就緒時,使用使其推向生產性能@tf.function。讓我們看看它的效果如何:

Epoch 1:Loss: 1.438: 100%|████████████| 10000/10000 [00:16<00:00, 612.3it/s]Epoch 2:Loss: 0.015: 100%|████████████| 10000/10000 [00:16<00:00, 615.0it/s]Epoch 3:Loss: 0.009: 72%|████████████| 7219/10000 [00:11<00:04, 635.1it/s]

驚人的16s/epoch。你可能會認為它不像Keras模式那樣快,但是,另一方面,你可以獲得所有調試功能和非常接近的性能。

在我看來,TensorFlow團隊在為開發人員提供更多靈活性而又不犧牲效率的前提下做出了出色的工作。

相關焦點

  • TensorFlow(Keras)中的正則化技術及其實現(附代碼)
    過度擬合:此問題涉及算法過於精確地預測在訓練過程中觀察和學習到的模式實例,從而預測向其呈現的模式的新實例。這可能導致機器學習算法無法準確地推廣到看不見的數據。如果訓練數據不能準確表示測試數據的分布,則可能會發生過度擬合。
  • TensorFlow 2.0正式版官宣!深度集成Keras
    查看分布式訓練指南了解更多:https://www.tensorflow.org/guide/distributed_trainingTensorFlow 2.0在GPU上提供了許多性能改進。如果你使用過TensorFlow 1.x,這裡有一個遷移到2.0的官方指南:https://www.tensorflow.org/guide/migrateTensorFlow 2.0也包括一個自動轉換腳本。
  • tensorflow2.4的重大改進
    一些重大改進涉及處理同級故障和許多錯誤修復。請查看有關使用Keras進行多工人培訓的詳細教程。介紹了對名為的新模塊的實驗支持,該模塊tf.experimental.numpy是用於編寫TF程序的NumPy兼容API。請參閱詳細指南以了解更多信息。以下是其他詳細信息。
  • 深度解讀TensorFlow,了解它的最新發展!
    Tensorboard是tensorflow內置的一個可視化工具,它通過將tensorflow程序輸出的日誌文件的信息可視化,使得tensorflow程序的理解、調試和優化更加簡單高效。Tensorboard的可視化依賴於tensorflow程序運行輸出的日誌文件,因而tensorboard和tensorflow程序在不同的進程中運行。
  • TensorFlow 1.9.0-rc0 升級 tf.keras 至 Keras 2.1.6 API
    TensorFlow 1.9.0-rc0 已發布。
  • Keras和TensorFlow究竟哪個會更好?
    雖然這不是最先進的模型,但它能比隨機猜測 (1/10) 要好得多。 相比起小型的神經網絡,我們模型的結果實際上是非常好的! 此外,正如我們在輸出圖6中所示,我們模型並不會發生過擬合現象。 ▌用 Tensorflow 和  tf.keras 訓練一個神經網絡模型
  • TensorFlow 2.0入門指南(上篇)
    連結:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/LIMITATIONS.md此外,要注意的一點是,經過AutoGraph轉換的新函數是可以eager模式下執行的,但是性能卻並不會比轉換前的高,你可以對比:
  • TensorFlow 2入門指南,初學者必備!
    2入門指南,初學者必備!Tensorflow v1難以使用和理解,因為它的Pythonic較少,但是隨著Keras發行的v2現在與Tensorflow.keras完全同步,它易於使用,易學且易於理解。廢話不多說,我們直接看看代碼。
  • 基於Tensorflow\keras銀行卡識別
    本文轉載自【微信公眾號:機器學習算法與Python精研 ,ID:AITop100】,經微信公眾號授權轉載,如需轉載原文作者聯繫來自:GitHub測試環境Ubuntu 18.04python 3.6.7numpy 1.16.4
  • 使用tensorflow和Keras的初級教程
    __version__)import pandas as pdimport numpy as npfrom sklearn.model_selection import train_test_splitimport tensorflow as tffrom sklearn import preprocessingfrom tensorflow.keras.models import Sequentialfrom
  • 詳解深度強化學習展現TensorFlow 2.0新特性(代碼)
    本文完整代碼資源連結:GitHub:https://github.com/inoryy/tensorflow2-deep-reinforcement-learning>>> import tensorflow as tf>>> print(tf.
  • 基於RTX2060構建TensorFlow-gpu(keras)學習平臺
    開始菜單運行anaconda navigator檢查是否安裝了notebook(默認有安裝)三、安裝tensorflow/keras在激活的環境中安裝:1. 如果機器上有gpu,則安裝gpu版本,沒有GPU就安裝cpu版。
  • Keras結合Keras後端搭建個性化神經網絡模型(不用原生Tensorflow)
    Keras是基於Tensorflow等底層張量處理庫的高級API庫。它幫我們實現了一系列經典的神經網絡層(全連接層、卷積層、循環層等),以及簡潔的迭代模型的接口,讓我們能在模型層面寫代碼,從而不用仔細考慮模型各層張量之間的數據流動。
  • Tensorflow 2.0的這些新設計,你適應好了嗎?
    而就在即將到來的2019年,Tensorflow 2.0將正式入場,給暗流湧動的框架之爭再燃一把火。如果說兩代Tensorflow有什麼根本不同,那應該就是Tensorflow 2.0更注重使用的低門檻,旨在讓每個人都能應用機器學習技術。考慮到它可能會成為機器學習框架的又一個重要裡程碑,本文會介紹1.x和2.x版本之間的所有(已知)差異,重點關注它們之間的思維模式變化和利弊關係。
  • 使用Tensorflow和Python對產品評論進行二進位分類(附代碼)
    任何其他筆記本電腦都可以正常工作,但需要安裝Tensorflow。我使用了TensorFlow 2.0。這是開發模型的分步指南:導入所有必需的軟體包。儘管您可以隨時導入軟體包。as pltimport matplotlib.image as mpimgfrom tensorflow.keras.preprocessing.text import Tokenizerfrom tensorflow.keras.preprocessing.sequence
  • TensorFlow 2.X,會是它走下神壇的開始嗎?
    他們實際上還是用 1.X 那一套方法寫的,只不過能兼容 TensorFlow 2.X。你會驚奇地發現,它們的 TensorFlow 導入都是這種風格:import tensorflow.compat.v1 as tfimport tensorflow.compat.v2 as tf其中,「compat」是 TF2.X 專門為兼容 TF 1.X 配置的模塊。
  • 用TensorFlow和Keras構建卷積神經網絡
    筆者已經編寫了一個如何使用TensorFlow的KerasAPI來訓練神經網絡的教程,著重介紹了自動編碼器:http://www.datastuff.tech/machine-learning/autoencoder-deep-learning-tensorflow-eager-api-keras/本文將嘗試三種不同的體系結構
  • 初學AI神經網絡應該選擇Keras或是Pytorch框架?
    keras是google的一個大佬開發的一個高度封裝的模型框架,已開源到github上。起初的計算後臺為Theano(和tensorflow差不多的一個框架),後來經過一系列的劇情,現在默認的計算後臺就為tensorflow了。
  • TensorFlow 2.4來了:上線對分布式訓練和混合精度的新功能支持
    優化器本次更新包括重構 tf.keras.optimizers.Optimizer 類,讓 model.fit 的用戶和自定義訓練循環的用戶能夠編寫可與任何優化器一起使用的訓練代碼。所有內置 tf.keras.optimizer.Optimizer 子類都可接受 gradient_transformers 和 gradient_aggregator 參數,輕鬆定義自定義梯度變換。
  • 機器學習:TensorFlow 2.0中的10個技巧
    1(a). 用於構建輸入管道的tf.data API從張量構建管道Batch和Shuffle壓縮兩個Datsets映射外部函數1(b). ImageDataGenerator這是tensorflow.keras API的最佳特性之一。