“夢回童年,盡享美食“-- AI 識別童年美食
?昨晚終于把憋了很久的 ModelArts + Wechaty 實現(xiàn)有趣的美食圖片識別應(yīng)用跑通了。盡管結(jié)合 Wechaty 調(diào)用 AI 相關(guān)服務(wù)在多年以前就被千人實現(xiàn)過了,不過作為小白的我能夠借助一站式AI開發(fā)平臺 ModelArts 新手制作數(shù)據(jù)集、訓(xùn)練模型并部署,最終通過最好的微信開發(fā)庫 Wechaty 實現(xiàn)調(diào)用 AI 服務(wù)的聊天小助手,還是十分有趣的。當然,我也迫不及待地將我的實踐分享給大家,也希望能夠獲得各位大佬的指導(dǎo)!
?
數(shù)據(jù)集制作
我們從AI開發(fā)流程出發(fā),當我確定了我的目的是要結(jié)合 ModelArts + Wechaty 來實現(xiàn)童年美食識別,基本上我的技術(shù)選型也就確定了,鑒于我學(xué)藝不精,零基礎(chǔ)都能上手的一站式AI開發(fā)平臺ModelArts和四行代碼就能實現(xiàn)聊天機器人的微信開發(fā)庫 Wechaty,便成了我唯一的選擇。準備數(shù)據(jù)的階段,我有幸遇到了前輩貢獻的代碼,因此能夠快速從某度圖片獲取我想要的圖片,具體操作可以查看我的歷史文章《新手小白如何快速獲取數(shù)據(jù)集》。我用同樣的手法獲取到了菠蘿啤、大白兔奶糖、干脆面、果丹皮、漢堡橡皮糖、猴王丹、花生牛軋?zhí)恰⒔×殹⒕菩那煽肆Α⒖炯t薯、辣條、老冰棍、三色冰淇淋、沙琪瑪、跳跳糖、娃哈哈AD鈣、旺旺碎冰冰、旺仔牛奶、西瓜泡泡糖、仙貝、魚皮花生、玉米軟糖、真知棒、咪咪蝦條共24個分類,從7200張圖片中一張一張分揀,最終標注3543張,實現(xiàn)了一個暫時看上去想那么回事的數(shù)據(jù)集--《"兒童節(jié)特輯"--8090的童年美食》。
不過,目前從數(shù)據(jù)的標簽分布來看,不太合理,被標注最多的標簽數(shù)量多達268個,而被標注最少的標簽數(shù)量僅23個,兩者差了一個數(shù)量級,因此訓(xùn)練出來的模型大概率會跑偏。

在ModelArts上進行數(shù)據(jù)標注時,其實也是有一定技巧的。比如,我在本地獲取到了大量的圖片,通過 OBS 的命令行工具上傳到 OBS 桶中之后,由于此次標注是圖像分類,因此我在標注時可以通過圖片存放的 OBS 目錄來快速篩選出當前要分揀的標簽以及進行標注。目前ModelArts數(shù)據(jù)集處理時單頁最多可顯示60張圖片,這也給我對圖片進行精挑細選提供了強有力的支持。其次,在進行圖片挑選時,可以從最后一頁進行,每次刪除圖片時順帶把源文件也從 OBS 中移除,移除往前直至處理到第一頁。最后,又可以全選當前頁進行標注。整個數(shù)據(jù)集從數(shù)據(jù)獲取到數(shù)據(jù)處理再到數(shù)據(jù)集發(fā)布,花了不到2小時,個人感覺對新手小白已經(jīng)很友好了!

訓(xùn)練及評估模型
如果您對《"兒童節(jié)特輯"--8090的童年美食》數(shù)據(jù)集感興趣,可以在 AI Gallery 進行一鍵下載,既可以下載到 OBS 也也可直接下載到 ModelArts 數(shù)據(jù)集。

基于數(shù)據(jù)集,在 ModelArts 平臺上除了可以自行開發(fā)算法并訓(xùn)練模型,也可以使用 AI Gallery 的訂閱算法或者直接使用 ModelArts 的自動學(xué)習來訓(xùn)練模型。這里為了更簡便的操作,本大獅就直接使用簡單粗暴的自動學(xué)習來實現(xiàn),主要想看到當前的數(shù)據(jù)集能訓(xùn)練出怎么樣的結(jié)果(PS:其實主要是免費,「請把免費打在評論區(qū)」),您期待嗎?

在創(chuàng)建完自動學(xué)習的任務(wù)運行9分鐘之后,我 Get 到了一個模型,從訓(xùn)練結(jié)果來看還是非常理想的,不過究竟是騾子是馬,還得看最終部署之后的效果。

表中是各個標簽所對應(yīng)的參考值,其中F1值是模型精確率和召回率的加權(quán)調(diào)和平均,用于評價模型的好壞,當F1值較高時說明模型效果較好;精確度指的是被模型預(yù)測為某個分類的所有樣本中,模型正確預(yù)測的樣本比率,反映模型對負樣本的區(qū)分能力;召回率指的是被用戶標注為某個分類的所有樣本中,模型正確預(yù)測為該分類的樣本比率,反映模型對正樣本的識別能力。
| 標簽名 | F1值 | 精確率 | 召回率 |
|---|---|---|---|
| 三色冰淇淋 | 0.933 | 0.875 | 1.000 |
| 仙貝 | 0.985 | 1.000 | 0.971 |
| 健力寶 | 0.957 | 1.000 | 0.917 |
| 咪咪蝦條 | 0.990 | 0.980 | 1.000 |
| 大白兔奶糖 | 0.986 | 0.972 | 1.000 |
| 娃哈哈AD鈣 | 0.977 | 0.955 | 1.000 |
| 干脆面 | 0.944 | 0.919 | 0.971 |
| 旺仔牛奶 | 0.971 | 0.971 | 0.971 |
| 旺旺碎冰冰 | 1.000 | 1.000 | 1.000 |
| 果丹皮 | 0.968 | 1.000 | 0.938 |
| 漢堡橡皮糖 | 0.971 | 1.000 | 0.943 |
| 沙琪瑪 | 1.000 | 1.000 | 1.000 |
| 烤紅薯 | 0.990 | 1.000 | 0.981 |
| 猴王丹 | 1.000 | 1.000 | 1.000 |
| 玉米軟糖 | 0.977 | 0.956 | 1.000 |
| 真知棒 | 1.000 | 1.000 | 1.000 |
| 老冰棍 | 1.000 | 1.000 | 1.000 |
| 花生牛軋?zhí)?/td> | 0.947 | 0.973 | 0.923 |
| 菠蘿啤 | 0.987 | 1.000 | 0.974 |
| 西瓜泡泡糖 | 0.957 | 0.917 | 1.000 |
| 跳跳糖 | 0.933 | 1.000 | 0.875 |
| 辣條 | 0.969 | 0.969 | 0.969 |
| 酒心巧克力 | 1.000 | 1.000 | 1.000 |
| 魚皮花生 | 0.978 | 0.957 | 1.000 |
部署模型
目前 ModelArts 支持一個免費的部署服務(wù)實例,因為我之前的實踐已經(jīng)占用了名額,因此當我再次在自動學(xué)習中部署模型時會提示以下圖中的報錯,從而我只能去到「部署在線--在線服務(wù)」手動新建一個服務(wù)實例。

在部署模型的時候,我們可以根據(jù)自身的需求添加一些個性化設(shè)置或者其他功能,比如數(shù)據(jù)采集、難例篩選等等。

看到服務(wù)部署成功之后,我已經(jīng)迫不及待地想先調(diào)試一下,隨便找了一張「跳跳糖」的圖片,讓 AI 識別一下,哎呀還不錯哦,感覺比我想象中的要好。ModelArts 的開發(fā)部分就告一段落,接著我們按照在線服務(wù)的調(diào)試指南進行與 Wechaty 的聯(lián)合開發(fā),“Talk is cheap. Show me the code.”
此時,我們獲得的信息:AI 服務(wù)的在線地址以及file形式的輸入?yún)?shù)images。
Wechaty 開發(fā)

先看看我們最終的呈現(xiàn)效果,也就是像微信機器人發(fā)送指定關(guān)鍵字之后再發(fā)送圖片,微信機器人就會調(diào)用 ModelArts 的在線服務(wù)來識別圖片并將結(jié)果返回給微信端。這里我們就需要用到 Wechaty 這個強大的微信開發(fā)庫。關(guān)于 Wechaty 的詳細情況,您可以訪問 Wechaty 的官網(wǎng)了解--https://wechaty.js.org/。從域名來看,這個開發(fā)庫應(yīng)該和 JavaScript 有關(guān),經(jīng)過翻閱文檔,我得知,新手使用 Wechaty 僅需四行代碼:
npm install qrcode-terminal --save
npm install wechaty
npm install wechaty-puppet-wechat --save // 這個依賴是關(guān)鍵
export WECHATY_PUPPET=wechaty-puppet-wechat // 這里也是關(guān)鍵,需要配置你使用的puppet
我們可以新建一個文件夾,執(zhí)行npm init初始化一個項目,然后執(zhí)行上述代碼,接著新建index.js,寫入:
const { Wechaty } = require('wechaty');
const name = 'wechat-puppet-wechat';
let bot = '';
bot = new Wechaty({
name, // generate xxxx.memory-card.json and save login data for the next login
});
// 二維碼生成
function onScan(qrcode, status) {
require('qrcode-terminal').generate(qrcode); // 在console端顯示二維碼
const qrcodeImageUrl = [
'https://wechaty.js.org/qrcode/',
encodeURIComponent(qrcode),
].join('');
console.log(qrcodeImageUrl);
}
// 登錄
async function onLogin(user) {
console.log(`貼心小助理${user}登錄了`);
// if (config.AUTOREPLY) {
// console.log(`已開啟機器人自動聊天模式`);
// }
// 登陸后創(chuàng)建定時任務(wù)
// await initDay();
}
//登出
function onLogout(user) {
console.log(`小助手${user} 已經(jīng)登出`);
}
bot.on('scan', onScan);
bot.on('login', onLogin);
bot.on('logout', onLogout);
bot
.start()
.then(() => console.log('開始登陸微信'))
.catch((e) => console.error(e));
基本上就完成了 Wechaty 部分的開發(fā),執(zhí)行node index.js就能在控制臺顯示一個二維碼,其實類似我們登錄桌面端的微信,接著我們主要需要解決的問題:
監(jiān)聽微信消息 -- 可以使用 bot.on('message')來實現(xiàn);對接 ModelArts -- 可以使用 token 鑒權(quán)方式訪問; 文件傳遞 -- 可以通過 form-data進行數(shù)據(jù)轉(zhuǎn)換。
基本代碼實現(xiàn)如下:
// 獲取Token
async function getToken() {
let token = ''
const data = {
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"domain": {
"name": config.IAMDomain
},
"name": config.IAMUser,
"password": config.IAMPassword
}
}
},
"scope": {
"project": {
"name": config.IAMProject
}
}
}
}
await axios.post(config.TokenURL, data).then(res => {
token = res.headers['x-subject-token']
}).catch(err => {
console.log(err)
token = ''
});
return token
}
// 識別美食
async function sendImage(fileName) {
let resp = {}
await getToken().then(async res => {
// console.log(res)
const form = new FormData();
form.append('images', fs.createReadStream(fileName));
console.log(form.getHeaders())
await axios.post(config.URL, form, { headers: Object.assign(form.getHeaders(), { "X-Auth-Token": res }) }).then(res => {
console.log(res.data)
resp = res.data
}).catch(err => {
console.log(err)
if (err.response && err.response.data) {
resp = err.response.data
}
})
}).catch(err => {
console.log(err)
resp = err.data
})
return resp
}
完整代碼參見:https://github.com/hu-qi/modelarts-wechaty
如需體驗可以添加我Hugi66并發(fā)送「food」, 也可以登錄 AI Gallery -- huaweicloud.ai聯(lián)系我,期待您的指導(dǎo)!
