眾所周知,前端相關(guān)的業(yè)務(wù)相當(dāng)于整個業(yè)務(wù)的用戶體驗前哨站。
除了在性能優(yōu)化、動畫等傳統(tǒng)的體驗上做努力,我們又如何在:目標(biāo)(手勢、肢體)識別、語音識別分析、無障礙、語音分析、增強現(xiàn)實、情緒識別、畫像細(xì)分等等,基于人工智能的交互體驗上,盡自己的一份力呢?
本文分為 第三方接口、重頭訓(xùn)練一個模型、使用成熟模型、再次訓(xùn)練 4個部分來展開前端應(yīng)用人工智能的方法。
希望可以拋轉(zhuǎn)引玉,給大家?guī)硪恍┧伎?。如果能對實際工作帶來幫助,那就更好不過了。
下面開始正文:
使用第三方接口就跟普通的業(yè)務(wù)沒太大區(qū)別,都是 【用戶輸入數(shù)據(jù) ->請求接口->解析接口內(nèi)容】,難點主要在于把解析后的數(shù)據(jù)玩出花樣。
比如之前刷爆朋友圈的你畫我猜,就是先讓用戶在canvas上畫出圖形后,把圖形上傳到自己的服務(wù)器,然后做出相應(yīng)的預(yù)測,你畫我猜類似版本體驗:https://quickdraw.withgoogle.com/。
但是google并沒有開放類似的使用接口,tensorflow的團隊也明確表示不打算做類似的服務(wù)(我所理解的,tensorflow的愿景現(xiàn)階段是盡可能的降低AI的使用門檻)。所以我收集了一些國內(nèi)比較專業(yè)的AI服務(wù)商,并且嘗試總結(jié)了他們的能力區(qū)別(只代表我本人的主觀判斷,如有錯誤請聯(lián)系我改正):
平臺 | 圖像處理 | 語音 | 文本處理 | 視頻 |
優(yōu)圖、ai開放平臺 | ★★★★ | ★★★★ | ★★★★ | - |
百度大腦 | ★★★★ | ★★★★ | ★★★ | ★★ |
face++ | ★★★★★ | - | - | - |
科大訊飛 | - | ★★★★★ | - | - |
雖然第三方門檻非常低、預(yù)測結(jié)果也基本上非??煽浚强啥ㄖ瞥潭鹊?、不適合在前端對視頻做實時預(yù)測、收費(如果要采購敏感的外部供應(yīng)商可能需要流程報備?)等等缺陷。
如果你覺得有些缺陷不能接受,跟我一起來看下第二種解決方案:重頭訓(xùn)練一個新的模型。
二:重頭訓(xùn)練一個新的模型
重頭訓(xùn)練一個模型需要大量的專業(yè)知識,但是這并不影響我開始這部分的介紹 :p,我會以一個簡單的例子開始,你可以測試一下你是否有興趣深入下去。
大家請看這個例子:
x = [-1.0,0.0,1.0,2.0,3.0,4.0
]
y = [-3.0,-1.0,1.0,3.0,5.0,7.0
],
請用一點時間推導(dǎo)一下X和Y的關(guān)系公式:
3...
2...
1...
相信大家經(jīng)過試錯和思考已經(jīng)找到答案了:【y=2x-1】。
這個就是神經(jīng)網(wǎng)絡(luò)的原理(我所理解的大白話):設(shè)計好神經(jīng)網(wǎng)絡(luò)之后,輸入的數(shù)據(jù)根據(jù)正確答案,經(jīng)過某些次數(shù)的訓(xùn)練(試錯)之后,擬合到一個最終的值(參數(shù))。把值(參數(shù))保存下來,以方便其他類似場景使用。
那么落地到tensorflow代碼中又是怎樣的呢?我們又如何設(shè)計這個神經(jīng)網(wǎng)絡(luò)呢?請看代碼(代碼基于tensorflow 1.9.0):
#加載模塊依賴import tensorflow as tfimport numpy as npfrom tensorflow import keras#添加一層神經(jīng)網(wǎng)絡(luò),輸入的參數(shù)是一維向量model = keras.Sequential([keras.layers.Dense(units=1,input_shape=[1])])#為模型添加sgd優(yōu)化器 損失函數(shù)為均方誤差model.compile(optimizer='sgd',loss='mse')#輸入的數(shù)據(jù)及正確的數(shù)據(jù)xs = np.array([-1.0,0.0,1.0,2.0,3.0,4.0],dtype=float)ys = np.array([-3.0,-1.0,1.0,3.0,5.0,7.0],dtype=float)#訓(xùn)練模型50輪model.fit(xs,ys,epochs=500)#輸出模型詳細(xì)信息model.summary()#保存模型model.save('model1.h5')#預(yù)測某個數(shù)字的結(jié)果print(model.predict([654615]))
[[1307159.4]]
接下來,在模型調(diào)試成功之后,把keras模型轉(zhuǎn)為tfjs可以使用的模型就可以在網(wǎng)頁中預(yù)測了(在第4部分有講到具體操作方法)。
如果你是一個沒有接觸tensorflow的同學(xué),看完這段代碼應(yīng)該大概率懵逼了,沒錯,我也是懵逼的。
而這只是一個非常簡單的只有一個全連接層的入門例子(人都可以短時間推導(dǎo)出來),但是人工智能往往需要做特別復(fù)雜的預(yù)測,比如票房預(yù)測、無人機飛行控制,人類手動計算各項輸入幾乎沒辦法完成。那網(wǎng)絡(luò)的設(shè)計將比這個復(fù)雜的多。(手動狗頭)
初了完美的網(wǎng)絡(luò)設(shè)計以外,如果你還希望預(yù)測的準(zhǔn)確率高一些,很完善的數(shù)據(jù)集也是必不可少的。比如之前提到的快速涂鴉的例子,僅"飛機"一個分類的數(shù)據(jù)集就有高達(dá)13萬張圖片數(shù)據(jù)(https://quickdraw.withgoogle.com/data/airplane)。
所以重頭訓(xùn)練一個新的模型,是一個學(xué)習(xí)周期很長、成本相當(dāng)高的方案。如果希望短時間內(nèi)用AI賦能你的業(yè)務(wù),最好先看下其他三種方案有沒有適合你的需求,或者問下AI部門的同事,他們有沒有興趣和你一起干。
如果你對此很有興趣想要深入學(xué)習(xí)下去,推薦你看吳恩達(dá)的最新課程(開始的例子也是出自這個課程):https://www.coursera.org/specializations/tensorflow-in-practice (旁聽免費)
除了很多限制的使用第三方接口和門檻很高的重頭訓(xùn)練以外,我們還可以選擇使用成熟的模型,tensorflow已經(jīng)有js版本了,并且已經(jīng)有成熟的開源模型和類庫(前端開源的相關(guān)應(yīng)用幾乎全是基于tfjs的)。
但是幾乎每個例子的demo為了展示能力,都預(yù)置了參數(shù)調(diào)整和復(fù)雜的交互邏輯,代碼晦澀難懂(至少我是這么認(rèn)為的)。
我把社區(qū)中開源的前端AI能力,又重新用直白的語言寫了一遍,每個DEMO下有原項目地址鏈接,有興趣應(yīng)用的可以研究更精確的參數(shù)。
為了照顧沒有攝像頭的用戶,我為每個例子都寫了上傳圖像的版本。
也為了保持demo的單獨性和便于理解,沒有抽離公用模塊,基本開箱即用:
抽取圖像上的特征應(yīng)用到其他圖片
可識別的分類:雛菊、蒲公英、玫瑰、向日葵、郁金香
支持?jǐn)z像頭
識別人臉、情緒、年齡
識別人體手部
支持?jǐn)z像頭
可識別的分類:https://github.com/tensorflow/tfjs-models/blob/master/mobilenet/src/imagenet_classes.ts
支持?jǐn)z像頭
可識別的目標(biāo):https://github.com/tensorflow/tfjs-models/blob/master/coco-ssd/src/classes.ts
支持?jǐn)z像頭
可識別人體輪廓
支持?jǐn)z像頭
可同時識別多個人體輪廓
支持?jǐn)z像頭
識別人體關(guān)鍵點
除了在瀏覽器中支持以外,tfjs官方也推出了支持小程序的插件:https://mp.weixin.qq.com/wxopen/pluginbasicprofile?action=intro&appid=wx6afed118d9e81df9&token=612578398&lang=zh_CN。有興趣的同學(xué)可以學(xué)習(xí)公司同事 @xiaoxiwang 出品的TFJS小程序的視頻教程。
成熟模型帶來了免費、視頻實時預(yù)測等等優(yōu)點,同時也帶來了無法定制識別自己的分類等缺點。
接下來是最后一種方法:再次訓(xùn)練
有的時候你的需求,需要的AI能力僅僅只需要識別一個標(biāo)志物體或者目標(biāo)的坐標(biāo),比如某個LOGO、某幅畫。那么可以在前人的訓(xùn)練好的模型基礎(chǔ)上再次訓(xùn)練。
在沒有強大數(shù)據(jù)集和AI團隊支持的情況下,使用前人訓(xùn)練好的參數(shù)和模型設(shè)計基礎(chǔ)上,再次訓(xùn)練不失為一種不錯的選擇。(這種方法也稱為遷移學(xué)習(xí))
下面以高度封裝的tensorflow-for-poets-2為例,介紹
訓(xùn)練圖片分類的詳細(xì)步驟(只需7步):
1. clone 預(yù)訓(xùn)練源代碼
git clone https://github.com/googlecodelabs/tensorflow-for-poets-2cd tensorflow-for-poets-2
2. 下載測試數(shù)據(jù)集 (解壓到 tensorflow-for-poets-2/tf_files
)
http://download.tensorflow.org/example_images/flower_photos.tgz
3. 開始訓(xùn)練 基于tensorflow 1.15.x環(huán)境
python -m scripts.retrain ^--bottleneck_dir=tf_files/bottlenecks ^--how_many_training_steps=2000 ^--model_dir=tf_files/models/ ^--summaries_dir=tf_files/training_summaries/mobilenet_0.50_224 ^--output_graph=tf_files/retrained_graph.pb ^--output_labels=tf_files/retrained_labels.txt ^--architecture=mobilenet_0.50_224 ^--image_dir=tf_files/flower_photos
mac下命令連接符是 \,win下是 ^
4. 開始訓(xùn)練 基于tensorflow 1.15.x環(huán)境
python -m scripts.label_image --graph=tf_files/retrained_graph.pb --image=xxx
#正常情況下會有類似輸出:daisy (score = 0.xxxx)sunflowers (score = 0.xxxx)
5. 優(yōu)化PB文件
python scripts/quantize_graph.py ^--input=tf_files/retrained_graph.pb ^--output=tf_files/quantized_graph.pb ^--output_node_names=final_result ^--mode=weights_rounded
6. 優(yōu)化PB文件 基于tensorflow.js 1.15.x環(huán)境
tensorflowjs_converter ^--input_format=tf_frozen_model ^--output_node_names=final_result ^tf_files/quantized_graph.pb ^tf_files/web
7. 轉(zhuǎn)成PB文件到j(luò)son文件
git clone git@github.com:tensorflow/tfjs.gitcd tfjs/tfjs-converteryarncross-env ts-node tools/pb2json_converter.ts ^/絕對路徑/tensorflow-for-poets-2/tf_files/web/ ^/絕對路徑/tensorflow-for-poets-2/tf_files/web_model/ ^
到這里,全部步驟已經(jīng)完成了。我也使用剛才的tfjs-converter轉(zhuǎn)換之后的
model.json寫了一個示例: https://allan5.com/FE-AI/flower.html
和使用成熟模型最大的不同是,需要自己處理傳遞給模型的圖像參數(shù)。
//初始輸入信息const image = tf.browser.fromPixels(pic);//把初始化為224x224的大小const resized_image =tf.image.resizeBilinear(image, [224,224]).toFloat();//把向量轉(zhuǎn)換為0~1的數(shù)值const offset = tf.scalar(255.0);const normalized = tf.scalar(1.0).sub(resized_image.div(offset));//把輸入的數(shù)據(jù)轉(zhuǎn)換為[0,224,224,3]的標(biāo)準(zhǔn)格式const batchedImage = normalized.expandDims(0);const result = await model.predict(batchedImage).data();//根據(jù)評分排序結(jié)果let text = label.map((label, index) => ({ label, score: result[index] })).sort((a,b)=>b.score - a.score)
因為篇幅的關(guān)系,就不仔細(xì)拆解目標(biāo)識別(帶物體具體的坐標(biāo)信息的預(yù)測)的訓(xùn)練步驟了,如果有興趣,可以試著看下面這個項目:
到這里,有同學(xué)可能要問:為什么你一個小前端要選擇python而不是熟悉的nodejs或者瀏覽器中的js來訓(xùn)練模型呢?
在我看來語言只是一種實現(xiàn)需求的手段,而前端跟其他職位只是面對的業(yè)務(wù)需求不同,選擇的語言不同而已。畢竟大道至簡,語言相通。
而現(xiàn)階段如果要深入機器學(xué)習(xí),python有自己得天獨厚的優(yōu)勢,比如社區(qū)豐富、有大規(guī)模訓(xùn)練的解決方案、圖像處理和數(shù)學(xué)計算等nodejs或js不能替代的模塊。所以本文中的一些示例用了python語言。
不過tf.js現(xiàn)在也在飛速發(fā)展,tensorflow官方除了開源社區(qū),也投入了數(shù)個全職人力開發(fā)。相信不久的將來,tf.js除了適合前端應(yīng)用以外,對訓(xùn)練、部署這些周邊支撐也會有高效的解決方案!
但是這些都是客觀原因,如何用現(xiàn)在的技術(shù)和自己本身的領(lǐng)域結(jié)合,做出更多花樣,才是前端同胞們需要一直思考的地方。