TensorFlow in JavaScript(Huan) ========================================================== **Atwood’s Law** “Any application that can be written in JavaScript, will eventually be written in JavaScript.” -- Jeff Atwood, Founder of StackOverflow.com “JavaScript now works.” -- Paul Graham, YC Founder TensorFlow.js 簡介 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. figure:: /_static/image/javascript/tensorflow-js.png :width: 60% :align: center TensorFlow.js 是 TensorFlow 的 JavaScript 版本,支持 GPU 硬體加速,可以執行在 Node.js 或瀏覽器環境中。不但支援完全基於 JavaScript 從頭開發、訓練和部署模型,也可以用來運行已有的 Python 版 TensorFlow 模型,或者基於現有的模型進行繼續訓練。 .. figure:: /_static/image/javascript/architecture.png :width: 60% :align: center TensorFlow.js 支援 GPU 硬體加速。在 Node.js 環境中,如果有 CUDA 環境支援,或者在瀏覽器環境中,有 WebGL 環境支援,那麼 TensorFlow.js 可以使用硬體進行加速。 .. admonition:: 微信小程式 微信小程式也提供了官方套件,封裝了TensorFlow.js 函式庫,利用小程式WebGL API 給第三方程式呼叫時提供 GPU 加速。 本章,我們將基於 TensorFlow.js 1.0,向大家簡單地介紹如何基於 ES6 的 JavaScript 進行 TensorFlow.js 的開發,然後提供兩個例子,並基於例子進行詳細的講解和介紹,最終實現使用純 JavaScript 進行 TensorFlow 模型的開發、訓練和部署。 .. admonition:: 章節程式碼位置 本章中提到的 JavaScript 版 TensorFlow 的相關程式碼,使用說明,和訓練好的模型文件及參數,都可以在作者的 GitHub 上找到。地址: https://github.com/huan/tensorflow-handbook-javascript 瀏覽器中使用 TensorFlow.js 的優勢 -------------------------------------------- .. figure:: /_static/image/javascript/chrome-ml.png :width: 60% :align: center TensorFlow.js 可以讓我們直接在瀏覽器中載入 TensorFlow,讓用戶立即透過自己的 CPU/GPU 資源進行我們所需要的機器學習運算,更靈活地進行 AI 應用的開發。 瀏覽器中進行機器學習,相對比與伺服器端來講,將擁有以下四大優勢: * 不需要安裝軟體或驅動程式(打開瀏覽器即可使用); * 可以透過瀏覽器進行更加方便的人機互動; * 可以透過手機瀏覽器,呼叫手機硬體的各種感測器(如:GPS、電子羅盤、加速度傳感器、相機等); * 用戶的資料不需要上傳到伺服器,在本機端即可完成所需操作。 透過這些優勢,TensorFlow.js 將給開發者帶來極高的靈活性。比如在 Google Creative Lab 在 2018 年 7 月發布的 Move Mirror 裡,我們可以在手機上打開瀏覽器,通過手機攝像頭檢測影片中用戶的身體動作姿勢,然後透過對圖片資料庫中類似身體動作姿勢的檢索,給用戶顯示一個最能夠和他當前動作相似的照片。在 Move Mirror 的執行過程中,資料沒有上傳到伺服器,所有的運算都是在手機本體,基於手機的 CPU/GPU 完成的,而這項技術,將使 Servreless 與 AI 應用結合起來成為可能。 .. figure:: /_static/image/javascript/move-mirror.jpg :width: 60% :align: center - Move Mirror 網址:https://experiments.withgoogle.com/move-mirror - Move Mirror 所使用的 PoseNet 網址:https://github.com/tensorflow/tfjs-models/tree/master/posenet TensorFlow.js 環境配置 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 在瀏覽器中使用 TensorFlow.js -------------------------------------------- 在瀏覽器中載入 TensorFlow.js ,最方便的方法是在 HTML 中直接引用 TensorFlow.js 發布的 NPM 包中已經打包安裝好的 JavaScript 程式碼。 .. literalinclude:: /_static/code/zh/deployment/javascript/regression.html :lines: 1-3 在 Node.js 中使用 TensorFlow.js -------------------------------------------- 伺服器端使用 JavaScript ,首先需要按照 `NodeJS.org `_ 官網的說明,完成安裝最新版本的 Node.js 。 然後,完成以下四個步驟即可完成配置: 1. 確認 Node.js 版本(v10 或更新的版本):: $ node --verion v10.5.0 $ npm --version 6.4.1 2. 建立 TensorFlow.js 項目目錄:: $ mkdir tfjs $ cd tfjs 3. 安裝 TensorFlow.js:: # 初始化項目管理文件 package.json $ npm init -y # 安裝 tfjs 函式庫,純 JavaScript 版本 $ npm install @tensorflow/tfjs # 安裝 tfjs-node 函式庫,C Binding 版本 $ npm install @tensorflow/tfjs-node # 安裝 tfjs-node-gpu 函式庫,支援 CUDA GPU 加速 $ npm install @tensorflow/tfjs-node-gpu 4. 確認 Node.js 和 TensorFlow.js 工作正常:: $ node > require('@tensorflow/tfjs').version { 'tfjs-core': '1.3.1', 'tfjs-data': '1.3.1', 'tfjs-layers': '1.3.1', 'tfjs-converter': '1.3.1', tfjs: '1.3.1' } > 如果你看到了上面的 ``tfjs-core``, ``tfjs-data``, ``tfjs-layers`` 和 ``tfjs-converter`` 的輸出資訊,那麼就說明環境配置沒有問題了。 然後,在 JavaScript 程式中,通過以下指令,即可導入 TensorFlow.js: .. code-block:: javascript import * as tf from '@tensorflow/tfjs' console.log(tf.version.tfjs) // Output: 1.3.1 .. admonition:: 使用 `import` 載入 JavaScript 模組 ``import`` 是 JavaScript ES6 版本新開始擁有的新特性。粗略可以認為等同於 ``require``。例如:``import * as tf from '@tensorflow/tfjs'`` 和 ``const tf = require('@tensorflow/tfjs')`` 對上面的範例程式碼是相同的。希望了解更多的讀者,可以訪問 `MDN 文件 `_ 。 在微信小程式中使用 TensorFlow.js -------------------------------------------- TensorFlow.js 微信小程式套件封裝了 TensorFlow.js 函式庫,用於提供給第三方程式呼叫。 在使用套件前,首先要在程式管理後台的“設置-第三方服務-套件管理”中添加套件。開發者可登入程式管理後台,通過 appid _wx6afed118d9e81df9_ 查找套件並添加。本套件無需申請,添加後可直接使用。 例子可以看 TFJS Mobilenet: `物體辨識程式 `_ `TensorFlow.js 微信小程式官方文件位置 `_ .. admonition:: TensorFlow.js 微信小程式教學 為了推動微信小程式中人工智能應用的發展,Google 專門為微信小程式打造了最新 TensorFlow.js 套件,並聯合 Google 認證機器學習專家、微信、騰訊課堂 NEXT 學院,聯合推出了“NEXT學院:TensorFlow.js 遇到程式” 課程,幫助程式開發者帶來更加易於上手和流暢的 TensorFlow.js 開發體驗。 上述課程主要介紹了如何將 TensorFlow.js 套件嵌入到微信小程式中,並基於其進行開發。課程中以一個姿態檢測的模型 PoseNet 作為範例,介紹了 TensorFlow.js 套件導入到微信小程式開發工具中,在項目開發中的配置,功能呼叫,載入模型等方法應用;此外,還介紹了在 Python 環境下訓練好的模型如何轉換並載入到程式中。 本章作者也參與了課程製作,課程中的案例簡單有趣易上手,通過學習,可以快速熟悉 TensorFlow.js 在程式中的開發和應用.有興趣的讀者可以前往 NEXT 學院,進行後續深度學習。 課程地址:https://ke.qq.com/course/428263 TensorFlow.js 模型部署 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 在瀏覽器中加載 Python 模型 -------------------------------------------- 一般 TensorFlow 的模型,會被存儲為 SavedModel 格式。這也是 Google 目前推薦的模型保存最佳方式。SavedModel 格式可以通過 tensorflowjs-converter 轉換器轉換為可以直接被 TensorFlow.js 載入的格式,在 JavaScript 語言中進行使用。 1. 安裝 ``tensorflowjs_converter`` :: $ pip install tensorflowjs ``tensorflowjs_converter`` 的使用細節,可以透過 ``--help`` 參數查看程式指令:: $ tensorflowjs_converter --help 2. 以下我們以 MobilenetV1 為例,看一下如何對模型文件進行轉換操作,並將可以被 TensorFlow.js 載入的模型文件,存放到 ``/mobilenet/tfjs_model`` 目錄下。 轉換 SavedModel:將 ``/mobilenet/saved_model`` 轉換到 ``/mobilenet/tfjs_model`` :: tensorflowjs_converter \ --input_format=tf_saved_model \ --output_node_names='MobilenetV1/Predictions/Reshape_1' \ --saved_model_tags=serve \ /mobilenet/saved_model \ /mobilenet/tfjs_model 轉換完成的模型,保存成兩類文件: - ``model.json``:模型架構 - ``group1-shard*of*``:模型參數 舉例來說,我們對 MobileNet v2 轉換出來的文件,如下: /mobilenet/tfjs_model/model.json /mobilenet/tfjs_model/group1-shard1of5 ... /mobilenet/tfjs_model/group1-shard5of5 3. 為了加載轉換完成的模型文件,我們需要安裝 ``tfjs-converter`` 和 ``@tensorflow/tfjs`` 套件:: $ npm install @tensorflow/tfjs 4. 然後,我們就可以透過 JavaScript 來載入 TensorFlow 模型了! .. code-block:: javascript import * as tf from '@tensorflow/tfjs' const MODEL_URL = '/mobilenet/tfjs_model/model.json' const model = await tf.loadGraphModel(MODEL_URL) const cat = document.getElementById('cat') model.execute(tf.browser.fromPixels(cat)) .. admonition:: 轉換 TFHub 模型 將 TFHub 模型 ``https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/1`` 轉換到 ``/mobilenet/tfjs_model``:: tensorflowjs_converter \\ --input_format=tf_hub \\ 'https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/1' \\ /mobilenet/tfjs_model 在 Node.js 中執行原生 SavedModel 模型 -------------------------------------------- 除了透過轉換工具 tfjs-converter 將 TensorFlow SavedModel、TFHub 模型或 Keras 模型轉換為 JavaScript 瀏覽器相容格式之外,如果我們在 Node.js 環境中執行,那麼還可以使用 TensorFlow C++ 的接口,直接執行原生的 SavedModel 模型。 在 TensorFlow.js 中執行原生的 SavedModel 模型非常簡單。我們只需要把預訓練的 TensorFlow 模型存為 SavedModel 格式,並透過 ``@tensorflow/tfjs-node`` 或 ``tfjs-node-gpu`` 包將模型載入到 Node.js 進行推論即可,無需使用轉換工具 ``tfjs-converter``。 預訓練的 TensorFlow SavedModel 可以透過一行程式碼在 JavaScript 中載入模型並用於推論: .. code-block:: javascript const model = await tf.node.loadSavedModel(path) const output = model.predict(input) 也可以將多個輸入以陣列或圖的形式提供給模型: .. code-block:: javascript const model1 = await tf.node.loadSavedModel(path1, [tag], signatureKey) const outputArray = model1.predict([inputTensor1, inputTensor2]) const model2 = await tf.node.loadSavedModel(path2, [tag], signatureKey) const outputMap = model2.predict({input1: inputTensor1, input2:inputTensor2}) 此功能需要 ``@tensorflow/tfjs-node`` 版本為 1.3.2 或更高,同時支持 CPU 和 GPU。它支援在 TensorFlow Python 1.x 和 2.0 版本中訓練和匯出的 TensorFlow SavedModel。這項功能帶來的好處除了無需進行任何轉換,原生執行 TensorFlow SavedModel 表示你可以在模型中使用 TensorFlow.js 尚未支援的運算子。這要透過將 SavedModel 作為 TensorFlow 會話載入到 C++ 中進行綁定得以實現。 使用 TensorFlow.js 模型資料庫 -------------------------------------------- TensorFlow.js 提供了一系列預訓練好的模型,方便大家快速的給自己的程式,加入人工智慧的能力。 模型庫 GitHub 網址:https://github.com/tensorflow/tfjs-models,其中模型分類包括圖像辨識、語音辨識、人體姿態辨識、物體辨識、文字分類等。 由於這些 API 預設模型文件都儲存在谷歌雲上,在程式內使用模型 API 時要提供 modelUrl 的參數,可以指向谷歌的伺服器。 谷歌雲的base url是 https://cloud.google.com/storage。以 posenet 模型為例: - 谷歌雲網址是:**https://storage.googleapis.com/tfjs-models/savedmodel/posenet/mobilenet/float/050/model-stride16.json 在瀏覽器中使用 MobileNet 進行攝像頭物體辨識 -------------------------------------------- 這裡我們透過一個簡單的 HTML 頁面,來呼叫 TensorFlow.js 和與訓練好的 MobileNet ,在用戶的瀏覽器中,通過攝像頭來辨識圖像中的物體是什麼。 1. 我們建立一個 HTML 文件,在表頭資訊中,通過將 NPM 模組轉換為線上可以引用的免費服務 ``unpkg.com``,來載入 ``@tensorflow/tfjs`` 和 ``@tensorflow-models/mobilenet`` 兩個 TFJS 模塊: .. literalinclude:: /_static/code/zh/deployment/javascript/mobilenet.html :lines: 3-6 2. 我們宣告三個 HTML 元素:用來顯示視頻的 ``