網站建設公司價seo營銷軟件
原文:What’s New in TensorFlow 2.0
協(xié)議:CC BY-NC-SA 4.0
譯者:飛龍
本文來自【ApacheCN 深度學習 譯文集】,采用譯后編輯(MTPE)流程來盡可能提升效率。
不要擔心自己的形象,只關心如何實現目標?!对瓌t》,生活原則 2.3.c
第 3 部分:TensorFlow 2.0 - 模型推斷和部署以及 AIY
如果您使用過 TensorFlow 1.x,則本部分將重點介紹遷移到 TensorFlow 2.0 所需的總體概念更改。 它還將教您使用 TensorFlow 可以進行的各種 AIY 項目。 最后,本節(jié)向您展示如何將 TensorFlow Lite 與跨多個平臺的低功耗設備一起使用。
本節(jié)包含以下章節(jié):
- 第 5 章,“模型推理管道 – 多平臺部署”
- 第 6 章,“AIY 項目和 TensorFlow Lite”
五、模型推理管道 - 多平臺部署
訓練完模型后您會怎么做? 用它? 如果答案是肯定的,那么您將如何使用它? 您正在尋找的答案是推理。 簡而言之,推理過程是確保機器學習模型可用于滿足實際用戶需求的基礎。 正式地說,推理是有效地計算經過訓練的機器學習模型以滿足用戶需求的過程。 可以在各種硬件類型上進行推斷,包括服務器以及最終用戶設備(例如電話和 Web 瀏覽器)。 根據用戶要求,它也可以在不同的操作系統(tǒng)上執(zhí)行。
前幾章重點介紹了如何…
技術要求
為了運行本章中給出的代碼摘錄,您將需要以下硬件和軟件:
- TensorFlow 2.0(TF 2.0)或更高版本(CPU 或 GPU 版本都足夠)
- Python 3.4+(當前,TensorFlow 支持的最高 Python 版本是 3.6)
- NumPy(如果不是由 TensorFlow 自動安裝)
- Docker(請參閱第 1 章和 “TensorFlow 2.0 入門”,有關如何安裝 Docker 的詳細信息)
curl
- 具有命令行界面的 Linux 計算機
本章中的每個 Python 代碼段均假定已安裝 TF 2.0,并且已將其導入到名稱空間中。 這意味著在執(zhí)行任何代碼塊之前,請先輸入以下行:
import tensorflow as tf
可在這個頁面中獲得本章的代碼文件。
機器學習工作流程 - 推理階段
機器學習應用的最常見子集之一遵循構建一次,并多次使用范式。 這種類型的應用涉及所謂的推理階段。 在推斷階段,開發(fā)人員必須專注于運行模型以滿足用戶需求。 滿足用戶需求可能涉及從用戶那里接受輸入并對其進行處理以返回適當的輸出。 下圖描述了典型的高級機器學習應用工作流程:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CvP0nnKr-1681704017943)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/whats-new-tf2/img/4dba2f20-e39c-4cce-98ba-9f2d018a4f3e.png)]
從上圖,我們可以看到推理過程如何適應整體情況。 在隨后的應用中…
從推理的角度理解模型
實現基于機器學習的應用的開發(fā)人員可以依靠的一件事是使生活變得輕松,無論所服務模型中的實際計算如何,向用戶提供模型的過程或多或少都是相同的。 這意味著,如果實現正確,工程師可能不必在每次數據科學家更新模型時都重新構建部署管道。 這可以通過利用抽象的力量來實現。 這里的一個關鍵抽象是模型存儲和加載的格式。 通過引入標準化格式,TF 2.0 使得在一個環(huán)境中訓練模型然后在各個平臺上使用它變得容易。 在 TF 2.0 中,執(zhí)行此操作的標準方法是通過SavedModel
格式。 這種標準化格式類似于軟件開發(fā)管道中的構建工件。 讀者可以將模型工件視為快照,可用于重新創(chuàng)建模型而無需訪問創(chuàng)建模型的實際代碼。
實際上,在推理時,模型被簡化為一個黑盒子,它具有一組預定義的輸入和輸出以及一個與底層模型進行交互的統(tǒng)一接口。 開發(fā)人員現在要做的就是建立在給定環(huán)境中實現和執(zhí)行黑匣子所需的基礎結構。 在以下各節(jié)中,我們將學習如何構建管道以服務于各種流行的軟件和硬件環(huán)境中的模型。
模型工件 – SavedModel 格式
SavedModel
格式是 TensorFlow 使用的默認模型序列化和反序列化格式。 用外行的術語來說,這可以理解為一個容器,它容納了在不訪問創(chuàng)建模型的原始代碼的情況下從頭開始重現模型的所有內容。 我們可以使用SavedModel
將訓練后的模型從訓練階段轉移到推理階段,甚至在訓練過程的不同部分之間轉移狀態(tài)。 簡而言之,可以說SavedModel
包含完整的 TensorFlow 程序以及模型權重和所描述的各種計算操作的描述。 使用 TF 2.0 的 Python API 時,現在可以導出某些本機…
了解核心數據流模型
在我們研究SavedModel
格式的細微差別之前,重要的是要首先了解 TensorFlow 模型的真正含義。 對于初學者,TensorFlow 實現數據流編程范例。 在這種范式下,程序被建模為在不同計算操作之間流動的數據的有向圖。 這意味著每個節(jié)點代表一個操作(或計算),邊代表數據。 輸入邊緣將代表該節(jié)點的輸入,而輸出邊緣將對應于計算節(jié)點產生的輸出。 為了說明這個想法,讓我們看一下tf.add()
操作的(粗略)數據流表示形式。 如下圖所示,輸入邊對應于 x 和 y 的輸入。 輸出邊緣z(x + y)
對應于節(jié)點的輸出,在這種特定情況下,該輸出恰好是輸入的總和:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-C9eLDsaC-1681704017944)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/whats-new-tf2/img/2e09fd48-ab43-4546-8eab-1df5c1dae380.png)]
使用數據流范例可以使 TensorFlow 在執(zhí)行用戶代碼時利用某些好處:
- 并行性:將模型表示為有向圖可以使 TensorFlow 識別哪些操作相互依賴,哪些不依賴。 這樣,可以并行執(zhí)行獨立的操作,從而加快基礎計算圖的執(zhí)行速度。
- 分布式執(zhí)行:并行性的一個相關好處是,并行執(zhí)行可以在同一臺物理計算機上執(zhí)行,也可以在另一臺物理計算機上完成。 TensorFlow 還負責這些節(jié)點之間的通信。
- 編譯:TensorFlow 的 XLA 編譯器旨在利用數據流圖中的信息,通過一系列優(yōu)化來生成更快的代碼。
- 可移植性:數據流圖是模型中代碼的語言無關表示形式。 這使得可以在 Python 中構建數據流圖并以較低級別的語言(例如 C 或 Java)將其還原以進行低延遲推理。
我們已經看到了如何使用數據流范例來表示一個簡單的操作。 實際的 TensorFlow 程序或模型將由許多這樣的簡單操作組成。 這意味著此類程序的數據流表示形式將由許多此類簡單表示形式組成,每個操作通常具有一個或多個節(jié)點。 SavedModel
格式可以理解為該基礎數據流圖的序列化。 這里有趣地提到了諸如 Keras 和 Estimators 之類的高級 API 的角色。 實際上,他們從用戶那里抽象出了該數據流圖的細節(jié),以至于用戶甚至不必考慮它。 它們?yōu)橛脩籼峁┝艘唤M高級操作,以供實現,然后將其轉換為 TensorFlow 可以執(zhí)行的數據流圖。 這意味著,最終,在 TensorFlow 中創(chuàng)建的任何模型,無論其創(chuàng)建方式如何,都將轉換為統(tǒng)一的計算圖。 這樣就可以使用一個統(tǒng)一的格式保存和加載所有模型。
tf.function API
正如我們在第 1 章中看到的那樣,第 2 章“TensorFlow 2.0 入門”, “Keras 默認集成和急切執(zhí)行”,默認情況下啟用急切執(zhí)行是 TF 2.0 中引入的主要更改之一。 第 1 章和 “TensorFlow 2.0 入門”還簡要提到了 TF 2.0 與 Python 編程語言更緊密地結合在一起。 此更改的核心是低級tf.function
API。 實際上,這是通過使用戶能夠從 Python 函數創(chuàng)建 TensorFlow 圖而將 TensorFlow 1.x 的功能與急切執(zhí)行的優(yōu)點相結合。 它既可以用作可調用函數,也可以用作裝飾器。 在本節(jié)中,我們將簡要介紹一下如何在每個人中使用它。
tf.autograph
函數
到目前為止,我們已經看到了如何從 Python 函數創(chuàng)建 TensorFlow 圖的代碼。 TF 2.0 將 Python-TensorFlow 耦合提升到了一個全新的水平。 新引入的 AutoGraph(tf.autograph
)函數使用戶可以使用本機 Python 語法編寫圖的代碼。
當前,此功能僅支持 Python 語法的有限子集。 這個頁面中提供了當前支持的語法元素的詳細列表。
這樣做的主要優(yōu)點是,它使開發(fā)人員可以編寫直觀的 Python 代碼來完成特定任務,然后自動將其轉換為高性能的 TensorFlow 圖代碼。 這意味著開發(fā)人員可以以直觀的 Python 形式描述基本的編程語言結構(例如循環(huán)和條件),而不是 TensorFlow 等效形式,并且具有可比的性能。
在 TF 2.0 中,調用tf.function
時會自動調用 AutoGraph。 用戶不需要單獨調用它。 tf.autograph
模塊包含低級模塊。 初學者或中級用戶幾乎不必直接使用它們,現在可以安全地忽略詳細信息。
讓我們看看執(zhí)行此操作的示例。 考慮一個計算給定張量中所有值之和的函數。 讓我們完全使用 Pythonic 語法實現它,然后使用tf.function
將其轉換為本地 TensorFlow 計算圖代碼:
@tf.function
def sum_of_cubes(numbers):_sum = 0for number in numbers:_sum += number ** 3return _sum
為了測試到目前為止已經編寫的代碼,讓我們創(chuàng)建一個介于 1 到 5 之間(包括兩端)的整數張量。 然后,將它們傳遞給我們的函數:
input_values = tf.constant([1, 2, 3, 4, 5])
result = sum_of_cubes(input_values)
print(type(result))
print(result)
這將導致以下輸出:
<class 'tensorflow.python.framework.ops.EagerTensor'>
tf.Tensor(225, shape=(), dtype=int32)
正如我們在提取的輸出中看到的那樣,我們已經編寫的純 Python 函數現在被轉換為 TensorFlow 圖。 函數現在返回張量而不是單個數字的事實證明了這一點。 輸出值與預期值相同。 有效地,我們已經證明了特定于 Python 的語法結構(例如for
循環(huán)和冪運算符)已成功轉換為 TensorFlow 圖的代碼。 這是tf.function
和 AutoGraph 的真正功能。 由于我們現在已經有效地將本機 Python 代碼轉換為 TensorFlow 計算圖,因此可以使用SavedModel
格式在環(huán)境之間共享此圖。
導出自己的 SavedModel 模型
如前所述,SavedModel
格式用于生成當前計算圖(數據流圖)的可再現表示。 此表示獨立于用于創(chuàng)建計算圖的特定代碼。 它也獨立于用于構造該圖的特定過程。 例如,SavedModel
格式沒有積極地區(qū)分使用本機 TensorFlow 操作,Keras 甚至tf.function
創(chuàng)建的計算圖。 盡管我們可以互換地將此計算圖稱為模型,但從技術上講,它也可以被認為是訓練有素的數學模型和圍繞它編寫的一些其他代碼的組合,以執(zhí)行支持…
使用tf.function
API
如前所述,tf.function
API 使我們能夠使用簡單的 Python 編寫 TensorFlow 圖和模型。 讓我們從構建一個簡單模型開始,該模型接受一個數字或一個數字列表并返回列表中值的平方。 然后,我們將由此創(chuàng)建的模型導出為SavedModel
格式。 這是本章以下大部分內容的重要步驟。 我們將幾乎在所有地方都使用SavedModel
工件。
首先,讓我們首先編寫一個簡單的 Python 函數來計算平方。 然后,我們可以從那里向后退:
def compute_square(number):return number ** 2
如我們所見,前面的 Python 方法接受一個數字作為輸入并返回其平方。 我們的最終目標是構建用于執(zhí)行此計算的 TensorFlow 圖。 利用我們從前面的部分中學到的知識,我們知道一種實現方法是使用tf.function
。 我們選擇使用tf.function
的裝飾器形式。 如果仔細觀察我們剛剛編寫的代碼段,您將意識到我們假設傳遞給number
變量的值是一個數值。 在現實世界中,情況未必一定如此。 為了解決這個問題,我們可以在裝飾器中指定此方法可以接受的值的類型。 這是通過在裝飾器中固定輸入簽名來完成的。 我們將其固定為包含 32 位浮點數的一維張量。 任何不符合此標準的輸入將被自動丟棄。 我們修改后的代碼片段(帶有實現錯誤檢查的功能)現在看起來像這樣:
@tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])
def compute_square(number):return number ** 2
到目前為止,我們已經成功實現了一個 TensorFlow 計算圖,該圖可以計算給定一維張量的平方。 現在唯一要做的就是以SavedModel
格式將此圖導出到磁盤。 您可能還記得,tf.saved_model
模塊中提供了用于SavedModel
的 API。 在閱讀該模塊的文檔時,我們發(fā)現save
方法可能會對我們有所幫助。 一個粗糙的邊緣是tf.saved_model.save
方法僅適用于Trackable
類型的對象,而我們所擁有的是tf.function()
對象(屬于Trackable
類型或其子類)。 為了克服這個問題,我們只需將代碼包裝在實現Trackable
接口的類中:
class Square(tf.Module):@tf.function(input_signature=[tf.TensorSpec(shape=None, dtype=tf.float32)])def compute_square(self, number):return number ** 2?
現在,我們將邏輯封裝在[H??TG0]方法支持的表示形式中。 最后,我們創(chuàng)建一個Square
類的對象(繼承自Trackable
)并將其傳遞給save
方法:
sos = Square()
tf.saved_model.save(sos, './square/1')
現在,您將看到模型已成功導出到./square/1
目錄。 可以通過列出前面目錄的內容來驗證。 打開終端并輸入以下內容:
cd <directory-containing-your-code>
ls -ax ./square/1
您將看到如下內容:
. .. assets saved_model.pb variables
在接下來的分析SavedModel
工件的部分中,我們將研究這些文件中的每個文件所包含的內容以及它們在保存模型的過程中所起的作用。
分析 SavedModel 工件
在本小節(jié)中,我們將詳細研究SavedModel
如何序列化和反序列化 TensorFlow 圖。 我們還將看看SavedModel
命令行界面,這是一個功能強大的工具,可以分析磁盤上SavedModel
的內容,甚至可以在本地運行SavedModel
!
SavedModel
格式本質上描述了一種在磁盤上存儲 TensorFlow 圖的方法。 在較低的級別上,其工作的一部分是編纂一種用于在文件中表示該圖的格式。 按照這種格式,每個圖都使用組成的底層函數及其狀態(tài)的組合表示。 用 TensorFlow 的話來說,這些組成函數用名稱標識,并稱為簽名或命名簽名。 這些…
SavedModel 命令行界面
SavedModel
命令行界面(CLI)是非常方便的工具,可用于分析各種SavedModel
實例并運行它們。 它在調試磁盤上的模型時非常有用,并且可以在不讀取,編寫或修改任何代碼的情況下使用。 在本節(jié)中,我們將簡要介紹如何安裝此工具,使用它分析圖的不同組件并運行計算圖。
該工具與 TensorFlow 二進制文件捆綁在一起。 如果您通過從源代碼構建 TensorFlow 來安裝它,則必須單獨安裝它。 有關安裝說明,請參見這里。
這里值得簡要討論的兩個命令是show
和run
。 前者可用于列出 MetaGraph 信息,而后者可用于通過命令行在一組輸入上執(zhí)行圖。 通過使用-h
參數運行工具,可以在每個步驟中獲取詳細說明:
saved_model_cli -h
可以通過在命令名稱后調用-h
參數來獲取特定命令的說明。 例如,如果您想要有關run
命令的詳細說明,請鍵入以下內容:
saved_model_cli run -h
為了親身體驗此工具,讓我們回到在tf.function
API 的較早部分中構建和訓練的模型。 您可能還記得,模型接受任何維數的張量,并返回包含原始元素平方的相同形狀的張量。 首先讓我們看一下模型中存在的元圖數量。 為此,請在“終端”窗口中鍵入以下內容:
saved_model_cli show --dir <path-to-model-dir>
對于我們計算平方的模型,您應該看到以下內容:
The given SavedModel contains the following tag-sets:
serve
如前所述,使用標記集來標識元圖。 在這里,我們可以看到只有一個名為serve
的標簽集。 我們可能還想看一下構成該元圖的組成函數。 要查看構成此標簽集的SignatureDefs
(有關詳細信息,請參閱 這里,您可以鍵入以下命令:
saved_model_cli show \--dir <path-to-model-dir> \--tag_set serve
對于我們計算平方的模型,您應該看到以下內容:
The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:
SignatureDef key: "__saved_model_init_op"
SignatureDef key: "serving_default"
現在,讓我們看看如何使用run
函數與直接使用命令行通過SavedModel
保存的 TensorFlow 計算圖進行交互,而無需編寫任何代碼。 從上一階段的輸出中可以看到,有兩個組件函數。 其中,我們選擇使用serving_default
SignatureDef。 現在,我們可以通過提供所需的輸入并獲得所需的結果,通過命令行運行它。 為此,我們需要將路徑傳遞給模型,標簽集,輸入值以及要運行的組件的名稱。 為了該測試的目的,我們要計算的張量由[1, 2 , 3]
給出。 確切的命令如下:
saved_model_cli run \--dir <path-to-model> \--tag_set serve \--input_exprs "number"="[1, 2, 3]" \--signature_def serving_default
以下是輸出:
Result for output key output_0:
[1\. 4\. 9.]
從上一階段的輸出中,我們可以觀察到以下內容:
- 輸出張量與輸入張量具有相同的形狀
- 輸出張量中的值對應于我們輸入張量中的值的平方
這些觀察結果都確認SavedModel
工作正常。
在隨后的部分中,我們將探討在各種硬件和軟件環(huán)境中服務于此模型的方法。
后端服務器上的推理
在當今世界,分布式系統(tǒng)無處不在。 從我們?yōu)g覽的網站到我們在手機上使用的應用范圍,當我們不使用分布式系統(tǒng)時幾乎沒有一天。 鑒于這種無所不在的性質,將這種范例用于構建機器學習系統(tǒng)顯然是一個選擇。 構建分布式系統(tǒng)的典型模式是在后端服務器上執(zhí)行資源密集型(和數據敏感型)計算,同時將較輕(且相對獨立)的計算任務推向用戶設備。 機器學習應用的很大一部分屬于資源密集型類別。 此外,機器學習模型是使用數據構建的。 在現實世界中的很大一部分…
TensorFlow 服務
TensorFlow 服務是 TensorFlow 擴展(TFX)平臺的組成部分。 顧名思義,它旨在用于服務于機器學習模型。 簡而言之,它是專為生產環(huán)境設計的高性能服務系統(tǒng)。 TensorFlow 服務的一個重要特征是它向下游用戶公開了一致的 API,而與所服務模型的實際內容無關。 這使得快速進行實驗和重新部署變得容易,而無需對其余軟件棧進行任何其他更改。 它附帶對 TensorFlow 模型的內置支持,并且可以擴展為服務于其他類型的模型。
在本節(jié)中,我們將詳細介紹 TensorFlow 服務。 從基本的安裝和設置開始,以下小節(jié)通過一系列動手示例描述如何設置服務器來為SavedModel
服務。 我們還將簡要介紹 TensorFlow 服務提供的一些關鍵 API。
設置 TensorFlow 服務
與 TensorFlow 平臺的大多數其他組件一樣,TensorFlow 服務也可以通過多種方式安裝。 這里推薦通過 Docker 鏡像使用它,因為它相對簡單。
如果容器鏡像對您不起作用,請在這個頁面上獲取其他安裝 TensorFlow 服務方法的摘要。
使用 Docker 設置 TensorFlow 服務涉及一個簡單的步驟。 但是,此步驟需要將 Docker 安裝在主機上。 有關設置 Docker 的說明,請參閱第 1 章, “TensorFlow 2.0 入門”或本章的“技術要求”部分。 您需要做的就是拉相關的 Docker 鏡像以…
設置并運行推理服務器
現在我們已經設置了 TensorFlow 服務,讓我們使用它來執(zhí)行一些實際任務。 我們可以看看如何設置后端服務器以服務于前面幾節(jié)中構建的SavedModel
格式。 我們可以使用上一節(jié)中下載的 Docker 鏡像來運行SavedModel
格式。 為此,我們需要做兩件事:
- 將本地主機上包含模型的位置綁定到容器內的目錄(
/models/<your-model_name>
) - 綁定網絡端口 TensorFlow 服務正在監(jiān)聽主機上的網絡端口
該命令的一般形式如下:
docker run -t --rm \-p <port-on-host>:8501 \-v <path-to-model-on-host>:/models/<model_name> \-e MODEL_NAME=<model_name> \tensorflow/serving&
現在,模型服務器應該在您的主機上<port-on-host>
中指定的端口上運行。
現在讓我們通過發(fā)送一些推斷數據來測試我們的模型。 我們可以通過 RESTful API 與模型進行交互。 我們應該將帶有輸入值的 HTTP POST
請求發(fā)送到服務器。 為此,請在“終端”窗口中鍵入以下命令:
curl -X POST \http://localhost:<port-on-host>/v1/models/square:predict \-H 'Content-Type: application/json' \-d '{"instances": [1.0, 2.0, 3.0, 4.0]}'
您應該看到以下輸出:
{"predictions": [1.0, 4.0, 9.0, 16.0]
}
現在我們已經看到了如何使用 TensorFlow 服務在后端服務器上提供SavedModel
。 可通過 gRPC 和 RESTful API 訪問此模型。 有關這些的詳細信息,請參見以下鏈接:
- https://www.tensorflow.org/tfx/serving/api_rest
- https://github.com/tensorflow/serving/blob/master/tensorflow_serving/apis/prediction_service.proto
請記住,每次調用docker run
時,主機上都會啟動一個新的 Docker 容器。 即使您已停止與該容器進行交互甚至關閉了“終端”窗口,該容器也可能會在后臺繼續(xù)刷新并運行。 這會導致大量的隱藏內存消耗。 需要有意識地停止容器。 為此,請執(zhí)行以下步驟:
找出剛啟動的容器的名稱或 ID。 在“終端”窗口中鍵入以下內容:
docker ps
如您在前面的命令的輸出中看到的,每個容器都有一個名稱和 ID。 這些中的任何一個都可以用來唯一地標識容器。 我們需要使用它來停止我們啟動的容器。 可以按照以下步驟進行:
docker stop <container-name>
您還可以使用以下內容:
docker stop <container-id>
現在,您可以放心,容器已停止并且沒有占用計算機的任何內存。
當 TensorFlow.js 與 Node.js 相遇時
TensorFlow.js 的引入使在 JavaScript 環(huán)境中運行 TensorFlow 模型成為可能。 您可能已經知道,Node.js 是一個跨平臺的運行時環(huán)境,可以在瀏覽器外部執(zhí)行 JavaScript 代碼。 這樣就可以使用 JavaScript 代碼編寫后端服務。 將 Node.js 與 TensorFlow.js 集成在一起,就可以從 JavaScript 環(huán)境在后端服務器上提供機器學習服務。 請參閱這個頁面上有關如何執(zhí)行此操作的文檔。
瀏覽器中的推斷
您可能還記得,在前面的部分中,我們簡要討論了分布式系統(tǒng)。 在那里,我們討論了主要在主機服務器上執(zhí)行基于機器學習的計算的場景。 在這里,我們將研究在瀏覽器中在用戶端執(zhí)行這些計算的場景。 這樣做的兩個重要優(yōu)點如下:
- 計算被推送到用戶端。 主機不必擔心為執(zhí)行計算而管理服務器。
- 將模型推送到用戶端意味著不必將用戶數據發(fā)送到主機。 對于使用敏感或私有用戶數據的應用來說,這是一個巨大的優(yōu)勢。 因此,瀏覽器中的推理成為對隱私至關重要的機器學習應用的絕佳選擇:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rhsf8SIv-1681704017944)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/whats-new-tf2/img/ed83cc9d-b1bb-4e26-b251-f69247244b1b.png)]
上圖中描述的工作流說明了從頭構建模型然后允許最終用戶在其 Web 瀏覽器中運行它的端到端管道。 我們看到該過程分為兩個主要階段:訓練和推理。 在訓練階段,數據科學家和其他機器學習從業(yè)者聚在一起,建立和訓練模型。 現在,該模型以SavedModel
格式導出。 但是,TensorFlow.js 尚不直接支持SavedModel
格式。 因此,有必要將模型轉換為 TensorFlow.js 支持的格式。
有關如何執(zhí)行轉換的詳細信息,請參見這里。
現在,通過任何其他 JavaScript 代碼,都可以通過 Web 服務器將轉換后的模型提供給用戶。 用戶為模型提供必要的輸入。 TensorFlow.js 模型在用戶瀏覽器中處理這些輸入并返回適當的輸出。
Detailed resources for getting started with TensorFlow.js are available at the following links:
- https://www.tensorflow.org/js/guide
- https://www.tensorflow.org/js/tutorials
- https://www.tensorflow.org/js/demos
移動和物聯網設備上的推理
在過去幾年中,智能手機的使用呈指數增長,并且以不減緩的方式持續(xù)增長。 其他物聯網設備在我們的日常生活中也變得越來越普遍。 使用率的這些上升趨勢對機器學習系統(tǒng)產生了有趣的影響。 與普通主機相比,這些平臺通常資源有限。 結果,需要其他優(yōu)化來在此類設備上進行推理。 TensorFlow 平臺支持構建機器學習和基于深度學習的應用,這些應用可以在不同類型的邊緣設備(例如手機和其他 IoT 設備)上運行。 實現此目的的主要工具是…
總結
在本章中,我們詳細介紹了推理階段。 首先,通過對端到端機器學習工作流的外觀有了基本了解,我們了解了每個階段涉及的主要步驟。 我們還了解了將模型從訓練階段轉移到推理階段時所起作用的不同抽象。 詳細了解SavedModel
格式和基礎數據流模型,我們了解了可用于構建和導出模型的不同選項。 我們還了解了tf.function
和tf.autograph
等出色功能,使我們能夠使用本地 Python 代碼構建 TensorFlow 圖。 在本章的后半部分,我們學習了如何構建推理管道,以便在后端服務器,Web 瀏覽器甚至邊緣設備等不同環(huán)境中運行 TensorFlow 模型。
在下一章中,我們將了解有關 AIY 項目和 TensorFlow Lite 的更多信息。
六、AIY 項目和 TensorFlow Lite
本章詳細介紹如何在低功耗嵌入式系統(tǒng)(例如邊緣設備,移動系統(tǒng)(例如 Android,iOS 和 Raspberry Pi),Edge TPU 和 NVIDIA Jetson Nano 上部署經過訓練的 TensorFlow 2.0(TF2.0)模型。 本章還介紹了自己動手工具包的訓練和部署模型,例如 Google 自己做人工智能(AIY)工具包。 本章涵蓋的其他主題是如何將經過訓練的 TensorFlow(TF)模型轉換為 TensorFlow Lite(TFLite)模型,他們之間的主要區(qū)別,以及兩者的優(yōu)勢。
本章與前幾章略有不同,從某種意義上說,它只是對 TF2.0 的更廣泛關注的介紹。 也就是說,硬件領域…
TFLite 簡介
TFLite 是一組工具,可幫助開發(fā)人員在二進制大小較小且延遲較低的設備上運行 TF 模型。 TFLite 由兩個主要組件組成:TFLite 解釋器(tf.lite.Interpreter
)和 TFLite 轉換器(tf.lite.TFLiteConverter
)。 TFLite 解釋器實際上是在低功耗設備(例如手機,嵌入式 Linux 設備和微控制器)上運行 TFLite 模型的。 另一方面,TFLite 轉換器在可用于訓練 TF 模型的強大設備上運行,并將訓練后的 TF 模型轉換為解釋器的有效形式。
TFLite 旨在簡化在設備上執(zhí)行機器學習的過程,而無需通過網絡連接發(fā)送任何數據。 這樣可以改善延遲時間(因為沒有通過網絡傳輸數據),提高了隱私性(因為沒有數據會離開設備)和脫機功能(因為不需要互聯網連接就可以在任何地方發(fā)送數據)。
TFLite 的一些關鍵功能包括針對設備的經過優(yōu)化的優(yōu)化解釋器(它支持在二進制大小較小的設備上優(yōu)化的一組核心操作),針對多種語言(例如 Swift,C,C++,Java 和 Python 的 API),預訓練的模型和教程(新手可以在低功耗設備上輕松部署機器學習模型)。 TFLite 旨在通過硬件加速以及預融合的激活和偏差進行高效和優(yōu)化。
TFLite 的基本開發(fā)工作流程是選擇模型,轉換模型,將其部署到所需的設備并優(yōu)化模型。 該模型可以是任何東西,從tf.keras
自定義訓練模型到從 TF 本身獲取的預訓練模型。
TFLite 入門
使用 TFLite 的第一步是選擇要轉換和使用的模型。 這包括使用預訓練的模型,定制訓練的模型或微調的模型。 TFLite 團隊提供了一組預訓練和預轉換的模型,可以解決各種機器學習問題。 這些包括圖像分類,對象檢測,智能回復,姿勢估計和分割。 使用經過微調的模型或經過定制訓練的模型需要另一步驟,將它們轉換為 TFLite 格式。
TFLite 旨在在設備上高效地執(zhí)行模型,而這種效率的某些內在原因來自用于存儲模型的特殊格式。 TF 模型必須先轉換為這種格式,然后才能使用…
在移動設備上運行 TFLite
在本節(jié)中,我們將介紹如何在兩種主要的移動操作系統(tǒng)(Android 和 iOS)上運行 TFLite。
Android 上的 TFLite
在 Android 上使用 TFLite 就像在 Android Studio 的build.gradle
文件中的dependencies
字段中添加 TFLite 并將其導入 Android Studio 一樣容易:
dependencies { implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly'}import org.tensorflow.lite.Interpreter;
一旦完成,下一步就是創(chuàng)建解釋器的實例并加載模型。 可以使用 GitHub 上 TFLite 示例中的getModelPath
函數getModelPath
和loadModelFile
加載轉換后的 TFLite 文件來實現。 現在,要運行模型,只需使用解釋器類的.run
方法并為其提供所需的輸入數據,如本例所示:
tflite.run(inp,out);
inp
參數是輸入數據,它將…
iOS 上的 TFLite
在 iOS 上使用 TFLite 的過程與此類似,其中包括安裝 TFLite 解釋器,加載模型并運行它。 再次按照“TFLite 入門”部分中的步驟操作,以創(chuàng)建和轉換機器學習模型以在智能手機上使用。 我們將使用以下步驟在 iOS 上實現 TFLite:
- 通過將 TFLite 添加到項目的
root
目錄中的pod
文件中來安裝它:
use_frameworks!
pod 'TensorFlowLiteSwift'
通過運行pod install
來安裝包,這將安裝pod
文件中包括的所有包,包括新添加的TFLite
包。 安裝后,可以通過在swift
文件頂部附近添加import TensorFlowLite
來導入包。
- 要運行
interpreter
,首先為張量分配內存:
let outputTensor: Tensor
do {try interpreter.allocateTensors()let inputTensor = try interpreter.input(at: 0)
- 然后,從圖像緩沖區(qū)中刪除
alpha
組件以獲取rgbData
變量:
guard let rgbData = rgbDataFromBuffer(thumbnailPixelBuffer,byteCount: batchSize * inputWidth * inputHeight * inputChannels,isModelQuantized: inputTensor.dataType == .uInt8) else {print("Failed to convert the image buffer to RGB data.")return}
- 接下來,將
rgbData
變量復制到Tensor
輸入模型中:
try interpreter.copy(rgbData, toInputAt: 0)
- 通過調用
interpreter
函數運行推理:
try interpreter.invoke()
- 獲取
outputTensor
函數以處理推理結果:
outputTensor = try interpreter.output(at: 0)
} catch let error {print("Failed to invoke the interpreter with error: \(error.localizedDescription)")return
}
然后可以處理結果并將其顯示在應用中。
在低功率機器上運行 TFLite
TFLite 能夠在低功耗和低二進制計算機上運行的能力使其在嵌入式 Linux 計算機上運行時非常強大。 TFLite 可以在許多流行的嵌入式 Linux 機器以及 Coral Dev Board 上運行。 在本節(jié)中,我們將介紹在三個設備上 TFLite 的構建,編譯和運行。 涵蓋的第一個設備是帶有 Edge TPU 處理器的 Coral Dev Board,第二個設備是 NVIDIA Jetson Nano,最后一個是 Raspberry Pi。 NVIDIA Jetson Nano 是 NVIDIA 的小型而強大的計算機,可在圖像分類,目標檢測,分割和語音等應用中并行運行多個神經網絡。
在 Edge TPU 處理器上運行 TFLite
Edge TPU 是一種小型處理器,能夠執(zhí)行深度前饋網絡,例如卷積神經網絡。 但是,它僅支持量化的 TFLite 模型。 量化是一種優(yōu)化技術,可將所有 32 位浮點數轉換為最接近的 8 位定點數。 這使模型更小,更快,盡管精度和準確率有所降低。
TF 支持兩種類型的量化。 第一種量化方式是訓練后量化。 通過將模型優(yōu)化屬性設置為帶有tf.lite.Optimize.OPTIMIZE_FOR_SIZE
的列表,可以在將 TF 模型轉換為 TFLite 模型時完成此操作。 這導致權重被轉換為 8 位精度,從而將延遲增加了多達 3 倍。 網絡中其他更多計算密集型操作將轉換為具有定點操作但具有浮點內存的混合操作。
另一種量化類型是量化感知訓練,它使用偽造的量化節(jié)點來模擬前向和后向模型中量化的效果; 該量化是直接估計。 這是 Edge TPU 支持的唯一量化,并允許在其上運行 TFLite 模型。
Edge TPU 有兩種可用方式:
- Coral 開發(fā)板,其中包含 TPU 以及預安裝的所有必需軟件和 API
- Edge TPU USB 擴展器,可在所需計算機上添加另一個處理器
USB 加速器與任何具有運行 Debian 的 USB 端口的 Linux 計算機兼容。 要設置 USB 加速器,請從這里下載.tar
文件,然后解壓縮并運行install.sh
。
這里要注意的一點是,在安裝過程中,安裝程序將要求啟用最大工作頻率,這將大大加快推理時間,但也會使 TPU 摸起來很燙。
下圖顯示了將 TF 模型轉換為 Edge TPU 模型并在其上運行的過程:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lCTiwxkG-1681704017945)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/whats-new-tf2/img/ee7dff88-2f0b-4a1a-86b9-966f0c8ce1d7.png)]
但是,Edge TPU 有兩個約束。 如前所述,必須使用量化感知訓練對Tensor
參數進行量化。 張量大小必須恒定(這樣就不能有動態(tài)大小); 模型參數必須恒定; 張量必須是一維,二維或三維張量,或者是三個最里面的大小大于 3 維的張量,并且只能包含 Edge TPU 支持的那些操作。 如果不滿足這些要求,那么將僅編譯某些模型。 模型圖中發(fā)生不支持的操作的第一點是編譯器將圖分為兩部分:一部分包含 Edge TPU 可以計算的所有操作,另一部分包含它不能計算的操作,這些部分將運行在 CPU 上:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-W4OjpxEr-1681704017945)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/whats-new-tf2/img/aedc0f8e-e06f-4917-ad0a-41abe07ad00b.png)]
一旦 TFLite 模型已編譯并準備好運行,就可以使用 Edge TPU 運行時和 API 庫執(zhí)行該模型。 Edge TPU API 具有三個用于推理的關鍵 API:
ClassificationEngine
API,執(zhí)行圖像分類。 要使用它,請通過指定模型來創(chuàng)建實例,然后將圖像傳遞到該實例的ClassifyWithImage()
方法,該方法返回標簽和分數列表。DetectionEngine
API,用于執(zhí)行對象檢測。 與先前的 API 一樣,通過指定模型文件來創(chuàng)建實例,然后運行DetectWithImage()
方法,該方法返回檢測候選對象的列表,每個候選對象包含一個標簽,一個得分和該對象的坐標。- 最終的關鍵 API 是允許壓印的 API:一種遷移學習算法,可以進行模型重新訓練而無需反向傳播,并且可以在 Edge TPU 上運行。 要運行此 API,必須遵循三個步驟:
- 首先,確定嵌入張量,它是最后一個分類層的輸入張量。
- 然后,切斷最后一個分類層。
- 最后,完成嵌入提取器。
Edge TPU 的性能遠遠優(yōu)于許多最強大的 CPU。 當在帶或不帶 USB 加速器的 IntelXeon?3.60 GHz 處理器上測試模型時,單個 Edge TPU 能夠以每秒 2 瓦的功率每秒執(zhí)行 4 萬億次操作; 嵌入式 1.5 GHz CPU; 和珊瑚開發(fā)委員會。 在運行 DeepLab 網絡時,英特爾至強花費了 301 毫秒,帶加速器的英特爾至強花費了 35 毫秒,嵌入式 CPU 花費了 1,210 毫秒,而珊瑚開發(fā)板花費了 156 毫秒。 顯然,Edge TPU 對模型的延遲具有重大影響。
在 NVIDIA Jetson Nano 上運行 TF
NVIDIA Jetson Nano 是另一種嵌入式設備,可為機器學習應用提供強大的計算能力。 Jetson Nano 的前提與 Edge TPU 不同,因為 Jetson Nano 是一款小型而功能強大的 GPU 計算機。 Jetson Nano 可以像配置用于深度學習的任何機器一樣使用,并且可以輕松安裝 GPU 版本的 TF。 也不需要安裝 CUDA 和 cuDNN,因為它已預先安裝在系統(tǒng)上。
比較 TFLite 和 TF
如前所述,TFLite 模型與普通 TF 模型有很大不同。 TFLite 模型更快,更小且計算量更少。 這種區(qū)別來自 TFLite 模型的特殊存儲和解釋方式。
速度的首次提高來自模型存儲的基本格式。.tflite
模型文件以FlatBuffer
格式存儲,其中包含模型的簡化形式和二進制形式。 FlatBuffer
是適用于多種流行語言的高效跨平臺序列化庫,由 Google 創(chuàng)建,用于游戲開發(fā)和其他對性能至關重要的應用。 FlatBuffer
格式在有效序列化模型數據并提供對這些數據的快速訪問,同時保持較小的二進制大小方面起著至關重要的作用。 由于大量的數字數據,這對于模型存儲很有用,這通常會在讀取操作中產生很多延遲。 通過使用FlatBuffers
,TFLite 可以繞過許多傳統(tǒng)的文件解析和非解析操作,這在計算上非常昂貴。
TFLite 模型優(yōu)化也一直延伸到設備上的硬件。 這是因為,由于電話處理器和嵌入式 CPU 的限制,必須以超高效標準使用所有處理器。 在 Android 上運行 TFLite 時,可訪問 Android 神經??網絡 API,該接口可訪問 Android 中的硬件加速推理操作,并且已接口,以利用有利的硬件加速來使用所使用的設備。 TFLite 還可以在電話和其他設備中使用內置的 GPU,從而使具有過多可并行化操作和量化敏感精度的模型的速度提高了近 7 倍。
如前所述,量化是另一種非常有影響力的優(yōu)化技術。 量化被視為 TF 中的一種壓縮技術。 神經網絡中的權重和激活趨向于具有分布在相對較小范圍內的三個值,因此可以有效地使用量化來壓縮這些值。 由于神經網絡往往對權重噪聲具有魯棒性,因此量化和舍入加到參數上的噪聲對模型的整體準確率影響很小。 量化模型的好處在于,它可以有效地表示任意范圍的范圍,它們的線性擴展使乘法簡單明了,而量化權重具有對稱范圍,可以實現下游硬件優(yōu)化,而 32 位浮點數則無法實現。
如下圖所示,將模型從 TF 轉換為量化的 TFLite 模型會大大減少模型的推理時間和延遲:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hPM7g7vJ-1681704017945)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/whats-new-tf2/img/6b0e98ac-64e7-4b03-ad69-abbde7fee70d.png)]
AIY
Google 為語音和視覺應用發(fā)布了自己的制造商套件,稱為 AIY。 這些套件隨附了所有必需的零件和組件,以及在線易于理解的教程。 AIY 當前提供兩種套件-語音套件和視覺套件。
語音套件
語音工具包提供了構建自然語言處理器并將其連接到 Google Assistant 或 Cloud Speech-to-Text 服務的功能。 該套件隨附 Raspberry Pi Zero,以及定制設計的語音引擎蓋和用于音頻功能的揚聲器。 該套件還隨附可插入 Pi 的 SD 卡,以及用于許多最常見應用的大量演示,示例和摘要。 它還帶有一個在設備上運行 Google Assistant 并將其轉變?yōu)橹悄芗揖釉O備的應用。
要開始使用語音工具包,請按照這個頁面上的說明構建設備。 該設備設計合理,易于組裝和設置。 要設置設備,可以使用計算機或手機。 該套件的設置非常簡單,可以通過安全外殼(SSH)或 HDMI 連接來完成。 完成后,可以運行許多演示來進一步了解和探索該工具包,例如前面提到的 Google Assistant 應用。
語音工具包可以完成的一些事情包括創(chuàng)建自定義語音用戶界面和使用助手控制 IoT 設備。
可以使用套件中demo
文件夾中包含的 Google Cloud 語音轉文本 API 和 AIY API 在語音工具包上創(chuàng)建自定義語音用戶界面。 該 API 增加了使用 Cloud Speech API,語音轉文本以及控制 Vision Bonnet 上的 GPIO 引腳的功能。
要使用語音工具包和助手來控制 IoT 設備,您可以使用幾種強大的技術。 都使用了用于物聯網項目的 Wi-Fi 開發(fā)套件 Particle Photon 和用于創(chuàng)建對話界面的DialogFlow
。 語音套件中包含的演示提供了打開和關閉連接到 Photon 的 LED 的代碼。
視覺套件
視覺套件提供了構建智能相機的功能,該相機可以使用機器學習來查看和識別對象,甚至可以在其上運行自定義 TF 模型。 與語音工具包一樣,該工具包還附帶 Raspberry Pi Zero,定制設計的 Vision Bonnet,壓電蜂鳴器和 Raspberry Pi Camera V2。 該套件隨附一個預先存儲有 AIY 系統(tǒng)圖像的 SD 卡,其中包括針對多種計算機視覺應用的演示,例如圖像分類,物體檢測,人臉檢測,食物分類和自動拍照。
和以前一樣,可以按照這里。 該設備有一個簡單的…
總結
TFLite 是 TF2.0 的一項功能,它采用 TF 模型并對其進行壓縮和優(yōu)化,以在嵌入式 Linux 設備或低功耗和低二進制設備上運行。 可以通過三種方式將 TF 模型轉換為 TFLite 模型:從已保存的模型,tf.keras
模型或具體函數。 轉換模型后,將創(chuàng)建一個.tflite
文件,然后可以將其傳輸到所需的設備并使用 TFLite 解釋器運行。 該模型經過優(yōu)化以使用硬件加速,并以FlatBuffer
格式存儲,以提高讀取速度。 可以將其他優(yōu)化技術應用于該模型,例如量化,以最小的精度權衡將 32 位浮點數轉換為 8 位定點數。 可以在 TFLite 上運行的某些設備是 Edge TPU,NVIDIA Jetson Nano 和 Raspberry Pi。 Google 還提供了兩個工具包,可為用戶提供創(chuàng)建與視覺和語音相關的機器學習應用所需的硬件。
在下一章中,我們將學習如何從 TF1.x 遷移到 TF2.0。
第 4 部分:TensorFlow 2.0 - 遷移,總結
本書的本部分將以高級方式總結 TensorFlow 2.0(TF 2.0)的使用,以及與以前版本相比 TF 2.0 的兼容性差異。 如果您使用過 TensorFlow 1.x(TF 1.x),則本書的這一部分將重點介紹如何遷移到 TF 2.0。 盡管有一個將 TF 1.x 代碼轉換為 TF 2.0 的遷移 API,但它只是進行語法到語法的轉換。 本部分還將深入指導您完成從語義上將 TF 1.x 代碼轉換為 TF 2.0 所需的代碼級更改。
本節(jié)包含以下章節(jié):
- 第 7 章“從 TensorFlow 1.x 遷移到 2.0”
七、從 TensorFlow 1.x 遷移到 2.0
本章將介紹如何將 TensorFlow 1.x(TF 1.x)代碼轉換為 TensorFlow 2.0(TF 2.0) 代碼有兩種方式。 第一種方法是使用更新腳本,該腳本會更改大多數 TF 1.x 代碼,以便可以在 TF 2.0 中運行。 但是,這僅將所有tf.x
API 調用轉換為tf.compat.v1.x
格式。 另一種方法是,考慮到對庫所做的核心更改,將 TF 1.x 代碼轉換為慣用的 TF2.0 代碼。 我們將討論 TF 1.x 和 TF 2.0 之間的概念差異,它們之間的兼容性標準以及我們在語法和語義上進行遷移的方式。 我們還將展示從 TF 1.x 到 TF 2.0 的語法和語義遷移的幾個示例,我們將通過它們提供參考和將來的信息。
本章將涵蓋以下主題:
- TF 2.0 的主要變化
- 適用于 TF 2.0 的推薦技術
- 使代碼 TF 2.0 原生
- 常見問題
- TF 2.0 的未來
TF 2.0 的主要變化
從 TF 1.x 遷移到 TF 2.0 時,您將遇到的主要變化涉及 API 清理。
TF 2.0 中的許多 API 都已被刪除或移動。 主要更改包括刪除tf.app
,tf.flags
和tf.logging
,以支持其他 Python 模塊,例如absl-py
和內置的日志記錄系統(tǒng)。
TF 2.0 在代碼方面所做的最大更改之一就是急切執(zhí)行。 TF 1.x 要求用戶使用tf.*
調用來手工拼接抽象語法樹,以構建計算圖,該圖將與session.run()
一起運行。 這意味著 TF 2.0 代碼逐行運行,因此不再需要tf.control_dependancies()
。
TF 1.x 中的session.run()
調用與…非常相似。
適用于 TF 2.0 的推薦技術
第一條建議涉及在 TF 2.0 中處理常規(guī)代碼工作流。 TF 1.x 中常見的工作流程是使用瀑布策略,其中所有計算都布置在默認圖上。 然后,使用session.run()
運行選定的張量。 在 TF 2.0 中,應將代碼重構為較小的函數,這些函數將在需要時調用。 這些函數可以是普通的 Python 函數,但如果在另一個以tf.function
注解的函數中調用它們,則仍可以在圖模式下運行。 這意味著tf.function
僅應用于注解高級計算,例如模型的前向傳遞或單個訓練步驟。
以前,模型和訓練循環(huán)所需的所有計算都將預先確定并編寫,并使用session.run()
執(zhí)行。 這使得 TF 1.x 代碼對于大多數編碼人員來說很難遵循,因為模型的流程可能與圖的編碼方式完全不同,因為該圖是在最后運行的。 急切執(zhí)行和tf.function
專門用于簡化 TensorFlow 代碼動態(tài)過程,并使其他開發(fā)人員更容易理解預編寫的代碼。
管理和跟蹤變量是 TF 1.x 中另一個復雜的過程。 使用了許多方法來控制和訪問這些變量,這為線性代碼增加了更多的維度。 TF 2.0 更加強調使用tf.keras
層和tf.estimator
模型來管理模型中的變量。
這與手動滾動神經網絡層和手動創(chuàng)建變量形成對比。 在以下示例中,必須跟蹤權重和偏差變量,其形狀的定義應遠離模型的創(chuàng)建。 這使得難以更改模型并使模型適應不同的架構和數據集:
def dense(x, W, b):return tf.nn.sigmoid(tf.matmul(x, W) + b)@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):x = dense(x, w0, b0)x = dense(x, w1, b1)x = dense(x, w2, b2)...
此代碼的tf.keras
實現非常簡單明了,并確保開發(fā)人員不必擔心變量和變量名的組織和管理。 它還可以輕松訪問模型中的可訓練變量:
layers = [tf.keras.layers.Dense(hidden_size, activation=tf.nn.sigmoid) for _ in range(n)]
perceptron = tf.keras.Sequential(layers)# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]
tf.keras
模型還繼承了tf.train.Checkpointable
模型的方法,并與tf.function
集成在一起,因此可以將它們直接保存到檢查點并導出到SavedModels
。
以下是遷移學習實現的示例,并顯示tf.keras
如何使收集相關值的子集,計算其梯度以及基于梯度對其進行調整變得容易:
trunk = tf.keras.Sequential([...])
head1 = tf.keras.Sequential([...])
head2 = tf.keras.Sequential([...])path1 = tf.keras.Sequential([trunk, head1])
path2 = tf.keras.Sequential([trunk, head2])# Train on primary dataset
for x, y in main_dataset:with tf.GradientTape() as tape:prediction = path1(x)loss = loss_fn_head1(prediction, y)# Simultaneously optimize trunk and head1 weights.gradients = tape.gradient(loss, path1.trainable_variables)optimizer.apply_gradients(zip(gradients, path1.trainable_variables))# Fine-tune second head, reusing the trunk
for x, y in small_dataset:with tf.GradientTape() as tape:prediction = path2(x)loss = loss_fn_head2(prediction, y)# Only optimize head2 weights, not trunk weightsgradients = tape.gradient(loss, head2.trainable_variables)optimizer.apply_gradients(zip(gradients, head2.trainable_variables))# You can publish just the trunk computation for other people to reuse.
tf.saved_model.save(trunk, output_path)
所有尚未存儲在內存中的數據集都應使用tf.dataset
進行存儲和流傳輸。 數據集在 TF 2.0 中是可迭代的,因此在急切的執(zhí)行模式下,它們可以像任何其他 Python 可迭代的一樣使用,例如列表和元組。 您還可以通過使用tf.function
包裝數據集迭代來利用數據集異步預取和流傳輸功能,該迭代將 Python 交互轉換為與 AutoGraph 等效的圖操作。 正如我們在本書前面所提到的,AutoGraph 采用默認的 Python 流并將其轉換為基于圖的代碼。 例如,諸如if...else
塊之類的控制流將轉換為tf.condition
語句。 以下代碼塊向您展示了如何使用for
塊訓練模型:
@tf.function
def train(model, dataset, optimizer):for x, y in dataset:with tf.GradientTape() as tape:prediction = model(x)loss = loss_fn(prediction, y)gradients = tape.gradient(loss, model.trainable_variables)optimizer.apply_gradients(zip(gradients, model.trainable_variables))
但是,如果您正在使用 Keras 的model.fit
,則不必擔心。 要使用model.fit
在數據集上訓練模型,只需將數據集傳遞給方法。 它將處理其他所有事項:
model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)
使代碼 TF 2.0 原生
使 TF 1.x 代碼與 TF 2.0 代碼兼容的最簡單方法是運行系統(tǒng)上安裝的更新腳本以及 TF 2.0 安裝。 更新腳本使用tf.compat.v1
模塊。
為了向 TF 1.x 編寫的代碼提供向后兼容性,在 TF 2.0 中引入了tf.compat.v1
模塊。 tf.compat.v1
模塊替換了所有 TF 1.x 符號,例如tf.foo
和tf.compat.v1.foo
。 此模塊允許轉換為 TF 1.x 編寫的大多數代碼,以便可以在 TF 2.0 中運行。
作為簡化此過程的一種方式,TensorFlow 提供了tf_upgrade_v2
工具,該工具有助于盡可能簡化轉換。 該工具已預裝…
轉換 TF 1.x 模型
第一步是將所有tf.Session.run()
調用替換為 Python 函數。 這意味著將tf.placeholder
和feed_dict
轉換為函數參數。 這些成為函數的返回值。 此更改意味著與 TF 1.x 不同,可以使用標準的 Python 工具(例如pdb
)來逐步調試該功能。 構建函數后,可以添加tf.function
注解以在圖模式下運行該函數,以及 TF 1.x 中等效的tf.Session.run
調用的效率。
使用tf.layers
API 創(chuàng)建的 TF 1.x 模型可以相對容易地轉換為 TF 2.0。 tf.layers
模塊用于包含依賴于tf.variable_scope
定義和重用變量的層函數。
以下代碼塊是使用tf.layers
API 編寫的 TF 1.x 中小型卷積神經網絡的實現:
def model(x, training, scope='model'):with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu,kernel_regularizer=tf.contrib.layers.l2_regularizer(0.04))x = tf.layers.max_pooling2d(x, (2, 2), 1)x = tf.layers.flatten(x)x = tf.layers.dropout(x, 0.1, training=training)x = tf.layers.dense(x, 64, activation=tf.nn.relu)x = tf.layers.batch_normalization(x, training=training)x = tf.layers.dense(x, 10, activation=tf.nn.softmax)return xtrain_out = model(train_data, training=True)
test_out = model(test_data, training=False)
將模型轉換為 TF 2.0 的最簡單方法是使用tf.keras.Sequential
,因為該模型由線性層組成。 從tf.layers
到tf.keras.layers
有一對一的轉換,但有一些區(qū)別。 在 TF 2.0 代碼中,訓練參數不再傳遞給每個層,因為模型會自動處理該參數。
這是 TF 2.0 中的代碼:
model = tf.keras.Sequential([tf.keras.layers.Conv2D(32, 3, activation='relu',kernel_regularizer=tf.keras.regularizers.l2(0.04),input_shape=(28, 28, 1)),tf.keras.layers.MaxPooling2D(),tf.keras.layers.Flatten(),tf.keras.layers.Dropout(0.1),tf.keras.layers.Dense(64, activation='relu'),tf.keras.layers.BatchNormalization(),tf.keras.layers.Dense(10, activation='softmax')
])train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))train_out = model(train_data)test_out = model(test_data, training=False)
如我們所見,tf.variable_scope
沒有用于組織為模型創(chuàng)建的變量。 在 TF 1.x 中,該范圍將用于從模型中恢復變量。 在 TF 2.0 中,可以使用model.trainable_variables
列出模型變量。
盡管從tf.layers
到tf.keras.layers
的轉換相對簡單,但是由于代碼流的差異,轉換變得更加復雜。
TF 1.x 中的低級 API 的一些示例包括使用變量作用域來控制重用,使用tf.get_variable
創(chuàng)建變量,使用tf.placeholder
和session.run
定期訪問集合以及手動初始化變量。 由于引入了系統(tǒng)范圍內的急切執(zhí)行,這些技術和策略中的許多現在已過時,因此以低級 API 編寫的代碼比以高級 API 編寫的代碼(例如tf.keras
和tf.layers
)需要更大的更改。 。
以下是使用 TF 1.x 的低級 API 編寫的一些代碼的示例:
in_a = tf.placeholder(dtype=tf.float32, shape=(2))
in_b = tf.placeholder(dtype=tf.float32, shape=(2))def forward(x):with tf.variable_scope("matmul", reuse=tf.AUTO_REUSE):W = tf.get_variable("W", initializer=tf.ones(shape=(2,2)),regularizer=tf.contrib.layers.l2_regularizer(0.04))b = tf.get_variable("b", initializer=tf.zeros(shape=(2)))return W * x + bout_a = forward(in_a)
out_b = forward(in_b)reg_loss = tf.losses.get_regularization_loss(scope="matmul")with tf.Session() as sess:sess.run(tf.global_variables_initializer())outs = sess.run([out_a, out_b, reg_loss],feed_dict={in_a: [1, 0], in_b: [0, 1]})
可以通過將前向函數更改為用tf.function
注解的函數進行基于圖的計算,刪除session.run
函數和變量范圍并添加簡單的函數調用來轉換此代碼。 將不會在W
變量上全局調用正則化; 相反,它將被手動調用,而無需引用全局集合:
W = tf.Variable(tf.ones(shape=(2,2)), name="W")
b = tf.Variable(tf.zeros(shape=(2)), name="b")@tf.function
def forward(x):return W * x + bout_a = forward([1,0])
out_b = forward([0,1])regularizer = tf.keras.regularizers.l2(0.04)
reg_loss = regularizer(W)
正如我們所看到的,TF 2.0 代碼比以前的 TF 1.x 代碼更加 Python 化和簡潔。
使用tf.placeholder
的好處之一是可以控制圖輸入的形狀,如果輸入與預定形狀不匹配,則會返回錯誤。 在 TF 2.0 中,仍然可以通過使用 Python 內置的assert
命令來完成此操作。 這可以用來斷言該函數的輸入自變量的形狀與輸入自變量所期望的形狀匹配。
現有的 TF 1.x 代碼通常同時包含較低級別的 TF 1.x 變量和具有較高級別tf.layers
的操作。 這意味著上述示例都不足以轉換 TF 1.x 代碼,并且需要tf.keras
編程的更復雜形式,稱為模型或層子類。
以下是在 TF 1.x 中使用tf.get_variable
和tf.layers
編寫的原始代碼:
def model(x, training, scope='model'):with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):W = tf.get_variable("W", dtype=tf.float32,initializer=tf.ones(shape=x.shape),regularizer=tf.contrib.layers.l2_regularizer(0.04),trainable=True)if training:x = x + Welse:x = x + W * 0.5x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu)x = tf.layers.max_pooling2d(x, (2, 2), 1)x = tf.layers.flatten(x)return xtrain_out = model(train_data, training=True)
test_out = model(test_data, training=False)
通過將所有低層操作和變量包裝在自定義創(chuàng)建的 Keras 層中,可以轉換此代碼。 這可以通過創(chuàng)建一個從tf.keras.layers.Layer
類繼承的類來完成:
# Create a custom layer for part of the model
class CustomLayer(tf.keras.layers.Layer):def __init__(self, *args, **kwargs):super(CustomLayer, self).__init__(*args, **kwargs)def build(self, input_shape):self.w = self.add_weight(shape=input_shape[1:],dtype=tf.float32,initializer=tf.keras.initializers.ones(),regularizer=tf.keras.regularizers.l2(0.02),trainable=True)# Call method will sometimes get used in graph mode,# training will get turned into a tensor@tf.functiondef call(self, inputs, training=None):if training:return inputs + self.welse:return inputs + self.w * 0.5
前面的代碼創(chuàng)建了一個名為CustomLayer
的類,該類繼承了tf.keras.layers.Layer
類的屬性。 此技術允許在tf.keras
模型內部使用任何類型的低級代碼,而不管它是使用Sequential
API 還是functional
API 的模型。 此類中有兩種方法:
build()
:此方法修改繼承的類的默認生成方法。 在這種方法中,應該創(chuàng)建模型所需的所有變量。 盡管可以在模型的the __init__()
方法中完成此操作,但建議使用build()
,以便在正確的最佳時間構建變量。 可以使用self.add_weight
函數完成此操作,以使 Keras 跟蹤變量和正則化損失。call()
:在輸入張量上調用模型時,將運行此方法。 此方法通常采用兩個參數:inputs
和training
。 盡管inputs
參數是不言自明的,但training
參數可能不會一直使用,但是對于在該層中使用批量規(guī)范化和丟棄的情況而言是必不可少的。 該功能由tf.function
裝飾器注解,以實現簽名,基于圖的優(yōu)點以及自動控件的依賴關系。
寫入此自定義層后,即可在tf.keras
模塊中的任何位置使用它。 對于此轉換,將使用Sequential
API:
train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))# Build the model including the custom layer
model = tf.keras.Sequential([CustomLayer(input_shape=(28, 28, 1)),tf.keras.layers.Conv2D(32, 3, activation='relu'),tf.keras.layers.MaxPooling2D(),tf.keras.layers.Flatten(),
])train_out = model(train_data, training=True)
test_out = model(test_data, training=False)
升級訓練循環(huán)
將 TF 1.x 代碼轉換為慣用的 TF 2.0 代碼的第二步是升級訓練管道。 TF 1.x 訓練管道涉及對優(yōu)化器,損失和預測的多個tf.Session.run()
調用。 這樣的訓練循環(huán)還涉及樣板代碼,該樣板代碼被編寫為將訓練結果記錄到控制臺以方便監(jiān)督。
在 TF 2.0 中,可以使用三種類型的訓練循環(huán)。 這些循環(huán)中的每一個都有不同的優(yōu)點和缺點,并且難度,API 級別和復雜性各不相同。 它們如下:
- 第一種訓練循環(huán)是
tf.keras.Model.fit()
。 這是一個內置的訓練循環(huán),可處理訓練的所有方面,并為各種 Keras 提供統(tǒng)一的接口…
轉換時要注意的其他事項
從 TF 1.x 遷移到 TF 2.0 時,還需要進行其他幾個主要轉換。 比起我們先前描述的對話,要困難得多的對話是將以 TF-Slim 編寫的代碼轉換為 TF 2.0。
由于 TF-Slim 打包在tf.contrib.layers
庫下,因此即使在兼容性模塊中,它也無法在 TF 2.0 中使用。 這意味著要將 TF-Slim 代碼轉換為 TF 2.0 格式,通常需要更改整個代碼動態(tài)。
這包括從代碼中刪除參數范圍,因為所有參數在 TF 2.0 中都應明確。 normalizer_fn
和activation_fn
函數應分為各自的層。 請注意,TF-Slim 層的參數名稱和默認值與tf.keras
層不同。
將 TF-Slim 模型轉換為 TF 2.0 的最簡單方法是將其轉換為 TF 1.x 中的tf.layers
API,然后將其轉換為tf.keras.layers
。
另一個需要注意的轉換細節(jié)是,在 TF 2.0 中,所有指標都是具有三種主要方法的對象:update_state()
(添加新的觀察值),result()
(獲取指標的當前結果)和reset_states()
( 清除所有觀察結果。
度量對象也是可調用的,并且在新觀察值上調用時,它們會累加值并返回最新結果。
以下示例向我們展示了如何在自定義訓練循環(huán)中使用指標:
- 創(chuàng)建度量標準對象,該度量標準對象在每次調用時都會累積度量標準數據:
loss_metric = tf.keras.metrics.Mean(name='train_loss')
accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')@tf.function
def train_step(inputs, labels):with tf.GradientTape() as tape:predictions = model(inputs, training=True)regularization_loss = tf.math.add_n(model.losses)pred_loss = loss_fn(labels, predictions)total_loss = pred_loss + regularization_lossgradients = tape.gradient(total_loss, model.trainable_variables)optimizer.apply_gradients(zip(gradients, model.trainable_variables))
- 更新指標:
loss_metric.update_state(total_loss)accuracy_metric.update_state(labels, predictions)for epoch in range(NUM_EPOCHS):
- 重置指標:
loss_metric.reset_states()accuracy_metric.reset_states()for inputs, labels in train_data:train_step(inputs, labels)
- 獲取度量結果:
mean_loss = loss_metric.result()
mean_accuracy = accuracy_metric.result()print('Epoch: ', epoch)
print(' loss: {:.3f}'.format(mean_loss))
print(' accuracy: {:.3f}'.format(mean_accuracy))
常見問題
在本節(jié)中,將解決有關從 TF 1.x 遷移到 TF 2.0 的一些常見問題。
用 TF 2.0 編寫的代碼的速度是否與基于圖的 TF 1.x 代碼相同?
是的,使用tf.function
或tf.keras
在 TF 2.0 中編寫的代碼將具有與 TF 1.x 相同的速度和最優(yōu)性。 正如我們在本章前面提到的那樣,使用tf.function
注解主要功能允許模型以圖模式運行,并且該功能中的所有計算和邏輯都將編譯為一個計算圖。 使用tf.keras
定義和訓練 TensorFlow 模型也是如此。 使用model.fit
方法還將在圖模式下訓練模型,并具有所有優(yōu)點和優(yōu)化功能,這些優(yōu)點和優(yōu)點包括:
TF 2.0 的未來
TF 2.0 目前處于 beta 版本,因此仍在開發(fā)中。 即將出現的一些關鍵功能包括對包的修改,例如 TensorBoard,TensorFlow Lite,TensorFlow.js,用于 TensorFlow 的 Swift 和 TensorFlow Extended,以及對基本 API 的微小更改。 TensorBoard 將看到增強功能,例如改進的超參數調優(yōu)功能,引入托管功能以使共享儀表板變得容易,并使插件能夠使用不同的前端技術,例如 ReactJS。 TensorFlow Lite 將擴大支持的操作范圍,將 TF 2.0 模型更輕松地轉換為 TFLite,并擴展對 Edge TPU 和 AIY 板的支持。 TensorFlow.js 和用于 TensorFlow 的 Swift 都將看到速度和性能方面的改進,并且很快將包含一組豐富的示例和帶有端到端教程的入門指南。 TF Extended 即將與 TF 2.0 基本 API 完全集成,并將包括完全協(xié)調的端到端工作流程和訓練函數。
TF 2.0 基本 API 將包括針對任務的更多預制估計器,例如增強樹,隨機森林,最近鄰搜索和 k 均值聚類。 tf.distribute.Strategy
模型將擴展其對 Keras 子模型,TPU 和多節(jié)點訓練的支持,以在多個處理器上實現更優(yōu)化和更快的訓練。
當前正在開發(fā)的另一個主要附加功能是tf-agents
模塊。 該模塊將核心強化學習算法實現為智能體,該算法定義了與環(huán)境進行交互的策略并從集體經驗中訓練了該策略。 TF-agents
與 OpenAI Gym 框架一起實現,并抽象了許多用于開發(fā)的關鍵強化學習算法。 該模塊當前處于預發(fā)布狀態(tài),但將于今年晚些時候發(fā)布。
可看的更多資源
可以在 TensorFlow Beta 網站上找到教程和許多其他資源,其中包含有關創(chuàng)建和訓練機器學習模型的關鍵因素的信息。 該頁面還為該領域的許多重要技術提供了許多有用的端到端教程。
可以在網站上找到 TF 2.0 的官方文檔,以及該模塊中每個 API 的詳細文檔。 該站點還具有指向其他 TensorFlow 模塊和功能的鏈接。
TensorFlow Medium 博客還提供有關 TensorFlow 庫和服務狀態(tài)的許多更新,并且源源不斷的有用新聞和…
總結
本章介紹了兩種將 TF 1.x 代碼轉換為 TF 2.0 代碼的方法。 第一種方法是使用隨附的升級腳本,該腳本會將所有 API 調用從tf.x
更改為tf.compat.v1.x
。 這允許 TF 1.x 代碼在 TF 2.0 中運行,但不會從 TF 2.0 中帶來的升級中受益。 第二種方法是將 TF 1.x 更改為慣用的 TF 2.0 代碼,這涉及兩個步驟。 第一步是將所有模型創(chuàng)建代碼更改為 TF 2.0 代碼,這涉及使用對函數的sess.run
調用,以及將占位符和字典饋入函數的參數來更改張量。 使用tf.layers
API 創(chuàng)建的模型與tf.keras.layers
具有一對一的比較。 第二步是通過使用tf.keras.Model.fit
或帶有tf.GradientTape
的自定義訓練循環(huán)來升級訓練管道。
TF 2.0 改變了 TensorFlow 代碼的編寫和組織方式。 TF 2.0 中的一些主要更改是對主模塊中 API 的重組和清理。 這包括刪除tf.contrib
模塊。 其他更改包括增加了代碼范圍內的急切執(zhí)行,以簡化調試和使用范圍。 由于急切執(zhí)行,因此在 TF 2.0 中創(chuàng)建的變量的行為類似于普通的 Python 變量。 這意味著用于處理全局變量的 TF 1.x API 已過時,因此已在 TF 2.0 中刪除。 這使我們到書的結尾!