83TensorFlow 2 模型部署方法實(shí)踐--使用 TensorFlow.js 部署模型

使用 TensorFlow.js 部署模型

TensorFlow.js 介紹

TensorFlow.js 是一個 JavaScript 庫宋渔,用于在瀏覽器或 Node.js 訓(xùn)練和部署機(jī)器學(xué)習(xí)模型少态。TensorFlow.js 的優(yōu)點(diǎn)有:
不用安裝驅(qū)動器和軟件,通過鏈接即可分享程序递递。
網(wǎng)頁應(yīng)用客税,交互性強(qiáng)。
有訪問 GPS,Camera揖闸,Microphone,Accelerator料身,Gyroscope 等傳感器的標(biāo)準(zhǔn) API汤纸。
安全性,因?yàn)閿?shù)據(jù)都保存在客戶端芹血。

本節(jié)實(shí)驗(yàn)將學(xué)習(xí) TensorFlow.js 基本語法贮泞,并部署 MobileNetV2 圖像識別的應(yīng)用。

在 JavaScript 項(xiàng)目中獲取 TensorFlow.js 的主要方法有兩種:
通過腳本標(biāo)簽導(dǎo)入:<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"> </script>幔烛。
使用 NPM 安裝 TensorFlow.js:npm install @tensorflow/tfj啃擦。

在本節(jié)實(shí)驗(yàn)中我們主要使用通過腳本標(biāo)簽導(dǎo)入的方法。
在桌面下創(chuàng)建 HTML 文件 demo.html饿悬,我們將在此文件中介紹 TensorFlow.js 的核心概念令蛉。

張量

TensorFlow.js 的數(shù)據(jù)單元是張量(Tensor):一組數(shù)值存儲于一維或者多維數(shù)組里。一個張量的實(shí)例有 shape 的屬性用于構(gòu)造多維數(shù)組狡恬。其中最主要的 Tensor 的構(gòu)造函數(shù)是 tf.tensor 珠叔,同時為了方便書寫,還有 tf.tensor2d弟劲,tf.tensor3d祷安,tf.scalar,tf.zeros 等函數(shù)兔乞,這樣也會增強(qiáng)代碼的可讀性汇鞭。

<html>
  <head>
    <!-- 導(dǎo)入 TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"></script>

    <!-- 在下方實(shí)現(xiàn) TensorFlow.js 的代碼 -->
    <script>
      const shape = [2, 3]; // 先定義張量的形狀
      const a = tf.tensor([1, 2, 3, 4, 5, 6], shape); //使用 tf.tensor 定義一個 2 * 3 的張量
      a.print(); //在瀏覽器的控制臺中打印結(jié)果
      // 輸出為:[[1, 2, 3],
      //         [4, 5, 6]]
      const b = tf.tensor2d([
        [6, 5, 4],
        [3, 2, 1],
      ]); //使用 tf.tensor2d 定義一個 2 * 3 的張量
      b.print();
      // 輸出為:[[6, 5, 4],
      //         [3, 2, 1]]
      const c = tf.scalar(3.5); // 使用 tf.scalar 定義常數(shù)
      c.print();
      // 輸出為:3.5
      const d = tf.zeros([2, 2]); // 使用 tf.zeros 定義一個 2 * 2凉唐, 值全為 0 的張量
      d.print();
      // 輸出為:[[0, 0],
      //         [0, 0]]
    </script>
  </head>
</html>

以 Chrome 瀏覽器為例:選擇 demo.html 文件,右鍵霍骄,選擇 Open With台囱,選擇使用 Preview 打開。在界面任意位置點(diǎn)擊右鍵腕巡,選擇檢查打開控制臺玄坦,點(diǎn)擊上邊欄的 Console,就可以看到程序的輸出了绘沉。

運(yùn)算

使用張量去存儲數(shù)據(jù)煎楣,那么運(yùn)算(Operation)允許你去利用這些數(shù)據(jù)。TensorFlow.js 提供了一整套適用于線性代數(shù)和機(jī)器學(xué)習(xí)的操作函數(shù)车伞。

<html>
  <head>
    <!-- 導(dǎo)入 TensorFlow.js -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"></script>

    <!-- 在下方實(shí)現(xiàn) TensorFlow.js 的代碼 -->
    <script>
      const shape = [2, 3]; // 先定義張量的形狀
      const a = tf.tensor([1, 2, 3, 4, 5, 6], shape); //使用 tf.tensor 定義一個 2 * 3 的張量
      a.print(); //在瀏覽器的控制臺中打印結(jié)果
      // 輸出為:[[1, 2, 3],
      //           [4, 5, 6]]
      const b = tf.tensor2d([
        [6, 5, 4],
        [3, 2, 1],
      ]); //使用 tf.tensor2d 定義一個 2 * 3 的張量
      b.print();
      // 輸出為:[[6, 5, 4],
      //           [3, 2, 1]]
      const c = tf.scalar(2.0); // 使用 tf.scalar 定義常數(shù)
      c.print();
      // 輸出為:2
      const a_plus_b = a.add(b); // 進(jìn)行 a + b 的運(yùn)算
      a_plus_b.print();
      // 輸出為:[[7, 7, 7],
      //          [7, 7, 7]]
      const reshape = a_plus_b.reshape([3, 2]); // 修改張量的形狀
      reshape.print();
      // 輸出為:[[7, 7],
      //          [7, 7],
      //          [7, 7]]

      //同時 TensorFlow.js 也支持鏈?zhǔn)綄懛ǎ?      const a_sub_div_c = a.sub(c).div(c); // 進(jìn)行 (a - c) / c 的運(yùn)算
      a_sub_div_c.print();
      // 輸出為:[[-0.5, 0, 0.5],
      //          [1, 1.5, 2]]
    </script>
  </head>
</html>

同樣择懂,選擇 demo.html 文件,右鍵另玖,選擇 Open With困曙,選擇使用 Preview 打開。在界面任意位置點(diǎn)擊右鍵谦去,選擇檢查打開控制臺慷丽,點(diǎn)擊上邊欄的 Console,就可以看到程序的輸出了鳄哭。
下面是視頻演示:
https://labfile.oss.aliyuncs.com/courses/1435/4-1.mp4

模型轉(zhuǎn)換

環(huán)境配置
使用一個 Web 服務(wù)器為模型文件提供服務(wù)時要糊,需要將服務(wù)器配置為允許跨源資源共享(CORS), 以允許在 JavaScript 中提取文件。
進(jìn)入之前實(shí)驗(yàn)所新建的虛擬環(huán)境(如果沒有虛擬環(huán)境則需要先執(zhí)行 virtualenv -p /usr/bin/python3.6 pyenv 進(jìn)行安裝)妆丘,安裝 TensorFlow.js 用于模型轉(zhuǎn)換锄俄,安裝 Flask-CORS 用于跨源資源共享。

$ . pyenv/bin/activate
$ pip install tensorflowjs==1.4.0 flask_cors==3.0.8

下載預(yù)訓(xùn)練模型勺拣,并將其放于 ~/.keras/models 目錄下奶赠,如果實(shí)驗(yàn)了上節(jié)實(shí)驗(yàn)的保存環(huán)境,則可以跳過此步驟药有。

$ wget https://labfile.oss.aliyuncs.com/courses/1435/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224.h5
$ mkdir -p ~/.keras/models
$ cp mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224.h5 ~/.keras/models

轉(zhuǎn)換 Keras 模型

在桌面創(chuàng)建文件腳本 convert.py毅戈,將 Keras 模型轉(zhuǎn)換為 TensorFlow.js 需要的格式。

import tensorflowjs as tfjs
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2
# 初始化 Keras 的 MobileNet 模型愤惰,并導(dǎo)入 ImageNet 權(quán)重
model = MobileNetV2(weights='imagenet')
# 進(jìn)行轉(zhuǎn)換苇经,將轉(zhuǎn)換后的模型保存在 model 文件夾下
tfjs.converters.save_keras_model(model, 'model/')

在終端輸入 python convert.py 執(zhí)行轉(zhuǎn)換程序。

開啟 CORS

在桌面創(chuàng)建文件腳本 cors.py羊苟,CORS 功能將在此文件中實(shí)現(xiàn)。其中感憾,我們初始化 CORS蜡励,以允許對所有路由上的所有域進(jìn)行 CORS令花。

from flask import Flask
from flask_cors import CORS

# 創(chuàng)建 Flask 實(shí)例
app = Flask(__name__,
            static_url_path='/model',
            static_folder='model')

# 初始化 CORS,以允許對所有路由上的所有域進(jìn)行 CORS
cors = CORS(app)

# 注冊路由
@app.route("/")
def hello():
    return "Hello Shiyanlou!"

# 開啟服務(wù)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port='8080', debug=True)

在這個應(yīng)用中凉倚,我們把 URL 路徑 /model 映射到了文件目錄 model(相對于本文件)兼都,外界通過 {host}/model 就能訪問到 model 內(nèi)的文件。
在終端輸入 python cors.py 開啟 CORS 服務(wù)稽寒。
此時點(diǎn)擊 Web 服務(wù)扮碧,在瀏覽器地址欄里顯示的 URL 就是 host 的地址,在這里域名部分 c8ce7fff3a04-service 每個人都不同杏糙,需要實(shí)際運(yùn)行中進(jìn)行替換慎王。

image.png

這樣我們就可以通過訪問 https://c8ce7fff3a04-service.simplelab.cn/model 來訪問文件。

使用 TensorFlow.js 進(jìn)行預(yù)測

導(dǎo)入模型
在 TensorFlow.js 中導(dǎo)入模型的方法如下宏侍,即通過提供 model.json 文件的 URL 將模型加載到 TensorFlow.js 中赖淤。

const model = await tf.loadLayersModel('http://***/model.json');

在上述語句中關(guān)鍵詞 await 的意思是等待,即需要等到模型加載完成后再執(zhí)行后面的語句谅河。同時 await 只能在 async 函數(shù)中使用咱旱,不能在常規(guī)函數(shù)中使用,不能工作在頂級作用域绷耍。
在桌面創(chuàng)建文件腳本 tfjs.html吐限,在此文件中將實(shí)現(xiàn) TensorFlow.js 的全部功能。

<html>
  <!-- 導(dǎo)入 TensorFlow.js -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.2.8/dist/tf.min.js"></script>
  <!-- 在下方實(shí)現(xiàn) TensorFlow.js 的代碼 -->
  <script>
    // 首先定義 model
    let model;
    // 定義異步函數(shù) demo褂始,在這個函數(shù)中執(zhí)行所有處理
    const demo = async () => {
      // 載入模型诸典,記得將域名替換為自己的
      model = await tf.loadLayersModel(
        'https://c8ce7fff3a04-service.simplelab.cn/model/model.json'
      );
      // 定義一個 1 * 224 * 224 * 3 的全 0 張量,用于測試模型是否可用
      const batched = tf.zeros([1, 224, 224, 3]);
      // 打印模型的預(yù)測結(jié)果
      console.log(model.predict(batched).data());
    };
    // 運(yùn)行 demo 函數(shù)
    demo();
  </script>
</html>

對結(jié)果進(jìn)行預(yù)覽
以 Chrome 瀏覽器為例:選擇 tfjs.html 文件病袄,右鍵搂赋,選擇 Open With,選擇使用 Preview 打開益缠。在界面任意位置點(diǎn)擊右鍵脑奠,選擇檢查打開控制臺,點(diǎn)擊上邊欄的 console 就可以看到模型輸出了幅慌。
https://labfile.oss.aliyuncs.com/courses/1435/4-2.mp4

導(dǎo)入圖片

接下來我們導(dǎo)入之前實(shí)驗(yàn)中使用的圖片進(jìn)行預(yù)測宋欺,為方便操作,我們直接通過終端下載圖片和 ImageNet 對應(yīng)的類別標(biāo)簽胰伍。
新開一個終端窗口齿诞,在此終端中下載文件。

$ wget https://labfile.oss.aliyuncs.com/courses/1435/image.jpg
$ wget https://labfile.oss.aliyuncs.com/courses/1435/imagenet_classes.js

接下來骂租,我們在 tfjs.html 文件中導(dǎo)入圖片祷杈,并進(jìn)行預(yù)測,輸出結(jié)果渗饮。

<html>
  <!-- 創(chuàng)建圖片元素但汞,設(shè)置 id 屬性為 image宿刮,以供 js 讀取調(diào)用 -->
  <img src="image.jpg" id="image" width="224" height="224" />
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.2.8/dist/tf.min.js"></script>
  <!-- 創(chuàng)建一個標(biāo)題元素,用于顯示預(yù)測結(jié)果 -->
  <h5 id="output">正在預(yù)測...</h5>
  <script type="module">
    // 從 imagenet_classes.js 中獲取標(biāo)簽列表
    import { IMAGENET_CLASSES } from './imagenet_classes.js';
    let model;
    const demo = async () => {
      // 載入模型私蕾,記得將域名替換為自己的
      model = await tf.loadLayersModel(
        'https://c8ce7fff3a04-service.simplelab.cn/model/model.json'
      );
      // 通過 getElementById 獲取圖片元素
      const imageElement = document.getElementById('image');
      // 將圖片元素轉(zhuǎn)換為 float 格式
      const img = tf.browser.fromPixels(imageElement).toFloat();
      // 將圖片像素每個位置減去 127.5 再除以 127.5 以歸一化到 [-1, 1] 之間
      const offset = tf.scalar(127.5);
      const normalized = img.sub(offset).div(offset);
      // 將歸一化后的圖片 reshape 到模型需要的輸入形狀
      const batched = normalized.reshape([1, 224, 224, 3]);
      // 進(jìn)行預(yù)測
      const pred = model.predict(batched);
      // 獲取預(yù)測結(jié)果最大值所在索引
      const index = await tf.argMax(pred, 1).data();
      // 從 IMAGENET_CLASSES 獲取所對應(yīng)的標(biāo)簽
      const label = IMAGENET_CLASSES[index];
      // 將標(biāo)簽輸出到 h5 元素中顯示
      document.getElementById('output').innerHTML = label;
    };
    // 運(yùn)行 demo 函數(shù)
    demo();
  </script>
</html>

對結(jié)果進(jìn)行預(yù)覽
選擇 tfjs.html 文件僵缺,右鍵,選擇 Open With踩叭,選擇使用 Preview 打開磕潮。
https://labfile.oss.aliyuncs.com/courses/1435/4-3.mp4

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市容贝,隨后出現(xiàn)的幾起案子自脯,更是在濱河造成了極大的恐慌,老刑警劉巖嗤疯,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冤今,死亡現(xiàn)場離奇詭異,居然都是意外死亡茂缚,警方通過查閱死者的電腦和手機(jī)戏罢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脚囊,“玉大人龟糕,你說我怎么就攤上這事』谠牛” “怎么了讲岁?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衬以。 經(jīng)常有香客問我缓艳,道長,這世上最難降的妖魔是什么看峻? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任阶淘,我火速辦了婚禮,結(jié)果婚禮上互妓,老公的妹妹穿的比我還像新娘溪窒。我一直安慰自己,他們只是感情好冯勉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布澈蚌。 她就那樣靜靜地躺著,像睡著了一般灼狰。 火紅的嫁衣襯著肌膚如雪宛瞄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天交胚,我揣著相機(jī)與錄音份汗,去河邊找鬼伐厌。 笑死,一個胖子當(dāng)著我的面吹牛裸影,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播军熏,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼轩猩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了荡澎?” 一聲冷哼從身側(cè)響起均践,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摩幔,沒想到半個月后彤委,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡或衡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年焦影,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片封断。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡斯辰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坡疼,到底是詐尸還是另有隱情彬呻,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布柄瑰,位于F島的核電站闸氮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏教沾。R本人自食惡果不足惜蒲跨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望详囤。 院中可真熱鬧财骨,春花似錦、人聲如沸藏姐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羔杨。三九已至捌臊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兜材,已是汗流浹背理澎。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工逞力, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糠爬。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓寇荧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親执隧。 傳聞我的和親對象是個殘疾皇子揩抡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容