訂閱
糾錯
加入自媒體

如何在一天內(nèi)構(gòu)建和部署機(jī)器學(xué)習(xí)web應(yīng)用程序?

本文我將帶領(lǐng)大家構(gòu)建一個Web應(yīng)用程序以對榴蓮進(jìn)行分類,在這里(https://durian-classifier.herokuapp.com/) 可以查看相關(guān)信息。

如果你不知道榴蓮是什么,那我向你說明一下。它是一種質(zhì)地乳脂狀、氣味刺鼻(見下圖)和外表刺眼的水果(在新加坡我們稱之為水果之王),這意味著刺鼻的氣味讓人要么討厭它,要么絕對喜歡它(很明顯,我屬于后者)。如果你覺得它聞起來很香,那么它的味道可能會更好。問題陳述是的,這個項(xiàng)目的動力源于我對榴蓮的熱愛。你一定想知道,我們到底在分類什么?你會發(fā)現(xiàn),榴蓮有很多種,它們的味道、質(zhì)地和顏色各不相同。對于此項(xiàng)目,我們將對四種不同類型的榴蓮進(jìn)行分類,即:貓山王金鳳凰D24紅蝦下表總結(jié)了這些榴蓮的不同之處:

榴蓮的品種還有很多,但我認(rèn)為這些榴蓮的細(xì)微差別可能會讓我們的模型難以學(xué)習(xí)。數(shù)據(jù)收集每個項(xiàng)目都從數(shù)據(jù)收集開始。由于我們將部署的模型用于個人和教育目的,因此我們將從google獲取圖像,如果你將圖片用于其他用途,請檢查版權(quán)。我們將使用此API(https://github.com/ultralytics/google-images-download) 來獲取圖像。只需按照repo上的說明安裝軟件包。在說明的第3步中,我們將針對特定的用例運(yùn)行此命令(將路徑替換為chromedriver):python3 bing_scraper.py --url 'https://www.bing.com/images/search?q=mao+shan+wang' --limit 100 --download --chromedriver <path_to_chromedriver>在這里,我們將下載的圖片數(shù)量限制在100張,因?yàn)闆]有多少具體的“貓山王”圖片。我們重復(fù)以上步驟三次,用其他品種的榴蓮進(jìn)行搜索。請注意,由于我們在API中修改了搜索URL,查詢中的空格將替換為“+”(即mao+shan+wang,red+prawn+durian等)。當(dāng)然,你可以對任何要分類的圖像執(zhí)行此步驟。數(shù)據(jù)清理在我們的用例中,由于沒有公開的榴蓮圖像,因此下載的許多圖像可能與正確的榴蓮品種不符(例如,在搜索“ mao shan wang”時可能會找到通用的“未標(biāo)記”榴蓮) )。

因此,我需要手動檢查所有下載的圖像,以確保圖片的質(zhì)量,畢竟擁有高質(zhì)量(即正確標(biāo)記)的數(shù)據(jù)勝過大數(shù)量的數(shù)據(jù),對吧?此步驟確實(shí)需要一些領(lǐng)域知識,并且可能會花費(fèi)一些時間。(但是,數(shù)據(jù)清理是機(jī)器學(xué)習(xí)管道中的基本步驟,反映了數(shù)據(jù)科學(xué)家和AI工程師的實(shí)際情況。)清除數(shù)據(jù)后,剩下55張 D24、39張金鳳,59張貓山王和68張紅蝦圖像。訓(xùn)練榴蓮分類器我選擇使用TensorFlow框架,我相信大多數(shù)實(shí)踐者都已經(jīng)熟練使用了(當(dāng)然,可以隨意使用Pytorch)。

由于我們只有很少的圖像,我們無疑必須使用一個預(yù)先訓(xùn)練好的模型,并在我們的數(shù)據(jù)集上對其進(jìn)行微調(diào)。首先,確保你有下面的文件夾結(jié)構(gòu),這是之后使用 flow_from_directory 所必需的。train|-- d24|-- golden-phoenix|-- mao-shan-wang|-- red-prawnvalid|-- d24|-- golden-phoenix|-- mao-shan-wang|-- red-prawn讓我們開始構(gòu)建分類器!# Import relevant libraries we will be usingimport numpy as np
from tensorflow.keras.initializers import glorot_uniformfrom tensorflow.keras.regularizers import l2from tensorflow.keras.preprocessing.image import ImageDataGeneratorfrom tensorflow.keras.a(chǎn)pplications import Xceptionfrom tensorflow.keras.layers import (    Flatten,    Dense,    AveragePooling2D,    Dropout)from tensorflow.keras.optimizers import SGDfrom tensorflow.keras.preprocessing import imagefrom tensorflow.keras import Modelfrom tensorflow.keras.preprocessing.image import img_to_arrayfrom tensorflow.keras.callbacks import (    EarlyStopping,    ModelCheckpoint,    LearningRateScheduler)如上所示,我們將使用的基本模型是Xception,讓我們實(shí)例化它并添加一些全連接層。因?yàn)槲覀冇泻芏鄨D像,所以我們將使用較小的批處理大小8。我們還需要警惕我們的小型數(shù)據(jù)集過度擬合。SHAPE = 224BATCH_SIZE = 8
model = Xception(    input_shape=(SHAPE, SHAPE, 3),    include_top=False,    weights='imagenet')
x = model.outputx = AveragePooling2D(pool_size=(2, 2))(x)x = Dense(32, activation='relu')(x)x = Dropout(0.1)(x)x = Flatten()(x)x = Dense(4, activation='softmax',          kernel_regularizer=l2(.0005))(x)
model = Model(inputs=model.inputs, outputs=x)
opt = SGD(lr=0.0001, momentum=.9)model.compile(loss='categorical_crossentropy',              optimizer=opt,              metrics=['accuracy'])在此之后,讓我們使用TensorFlow的ImageDataGenerator及其flow_from_directory創(chuàng)建圖像生成器對象。由于我們沒有足夠的訓(xùn)練圖像,圖像增強(qiáng)比以往任何時候都更重要。train_datagen = ImageDataGenerator(    rescale=1./255,    rotation_range=15,    width_shift_range=0.1,    height_shift_range=0.1,    horizontal_flip=True)
valid_datagen = ImageDataGenerator(    rescale=1./255,    rotation_range=0,    width_shift_range=0.0,    height_shift_range=0.0,    horizontal_flip=False)
train_generator = train_datagen.flow_from_directory(    'train/',    target_size=(SHAPE, SHAPE),    shuffle=True,    batch_size=BATCH_SIZE,    class_mode='categorical',)
valid_generator = valid_datagen.flow_from_directory(    'valid/',    target_size=(SHAPE, SHAPE),    shuffle=True,    batch_size=BATCH_SIZE,    class_mode='categorical',)
>>> Found 178 images belonging to 4 classes.>>> Found 42 images belonging to 4 classes.讓我們在.fit()即我們的模型之前定義一些回調(diào)函數(shù)。earlystop = EarlyStopping(monitor='val_loss',                          patience=4,                          verbose=1)
checkpoint = ModelCheckpoint(    "model-weights/xception_checkpoint.h5",    monitor="val_loss",    mode="min",    save_best_only=True,    verbose=1)我們的模型終于開始訓(xùn)練了!history = model.fit_generator(    train_generator,    epochs=30,    callbacks=[earlystop, checkpoint],    validation_data=valid_generator)
# Save our model for inferencemodel.save("model-weights/xception.h5")

不幸的是,由于我們擁有的圖像數(shù)量有限,我們的模型在驗(yàn)證集上無法獲得非常好的準(zhǔn)確性,但是,模型微調(diào)并不是本文的重點(diǎn),因此我們不會對此進(jìn)行過多介紹。選擇我們的Web框架在這個項(xiàng)目中,我選擇使用streamlit(https://www.streamlit.io/) ,因?yàn)樗梢詫?shí)現(xiàn)機(jī)器學(xué)習(xí)應(yīng)用程序的超快速可視化,并且科可以方便地用Python編寫。建立好這些之后,剩下要做的就是部署它。首先,導(dǎo)入所需的庫并指定模型權(quán)重的路徑,同樣由于我們使用了flow_from_directory ,TensorFlow按字母順序分配類編號,因此,D24將為0類,依此類推。import numpy as np
from PIL import Imagefrom tensorflow.keras.models import load_modelfrom tensorflow.keras.preprocessing.image import img_to_arrayfrom tensorflow.keras.preprocessing import imageimport streamlit as st
PATH = "model-weights/"WEIGHTS = "xception.h5"CLASS_DICT = {    0: 'D24',    1: 'JIN FENG',    2: 'MAO SHAN WANG',    3: 'RED PRAWN'}

接下來,我們創(chuàng)建一個函數(shù),將上傳的圖像轉(zhuǎn)換為模型要使用的格式。我們使用PIL中的Image類,因?yàn)樯蟼鞯膱D像是BytesIO格式的。def load_img(input_image, shape):    img = Image.open(input_image).convert('RGB')    img = img.resize((shape, shape))    img = image.img_to_array(img)    return np.reshape(img, [1, shape, shape, 3])/255Streamlit的工作方式是,用戶指定參數(shù)的每一次更改,腳本都會從上到下重新運(yùn)行(因此它是交互式的UI),因此它以st.cache形式提供了一個緩存裝飾器來緩存加載的對象。緩存通常用于數(shù)據(jù)加載步驟或任何需要長時間計(jì)算/處理的步驟。

請記住,我們使用allow_output_variation=True參數(shù),因?yàn)槟J(rèn)情況下這是False,如果輸出對象以任何方式發(fā)生了變化,則應(yīng)用程序?qū)⒈恢匦录虞d。在我們的例子中,模型對象將在每次預(yù)測中發(fā)生變化,因此我們將    allow_output_variation的參數(shù)設(shè)置為True。我們之所以要緩存我們的模型是因?yàn)槲覀儾幌M看斡脩暨x擇不同的圖像時都加載它(即只加載一次模型)。@st.cache(allow_output_mutation=True)def load_own_model(weights):    return load_model(weights)最后,我們只需要向UI添加一些代碼即可:if __name__ == "__main__":    result = st.empty()    uploaded_img = st.file_uploader(label='upload your image:')    if uploaded_img:        st.image(uploaded_img, caption="your sexy durian pic",                 width=350)        result.info("please wait for your results")        model = load_own_model(PATH + WEIGHTS)        pred_img = load_img(uploaded_img, 224)        pred = CLASS_DICT[np.a(chǎn)rgmax(model.predict(pred_img))]        result.success("The breed of durian is " + pred)我們用Python創(chuàng)建的web應(yīng)用程序不需要太多的代碼行。你可以確保它(假設(shè)它會被調(diào)用應(yīng)用程序副本)可以通過在命令行中輸入以下命令在本地運(yùn)行:streamlit run app.py將我們的模型部署到Heroku就我個人而言,部署不是我最喜歡的部分,但是,如果web應(yīng)用程序不在web上,那它還有什么意義呢?我們開始吧。你可以通過多種方式為web應(yīng)用程序提供服務(wù),也可以使用許多云服務(wù)提供商來托管它。在這種情況下,我選擇使用Heroku主要是因?yàn)槲乙郧皼]有嘗試過。

什么是Heroku?

Heroku是一個云平臺即服務(wù)(PaaS),支持多種編程語言,允許開發(fā)人員完全在云中構(gòu)建、運(yùn)行和操作應(yīng)用程序。下面這篇文章解釋得很清楚。文章鏈接:https://devcenter.heroku.com/articles/how-h(huán)eroku-works在Heroku部署為了部署應(yīng)用程序,我們總是需要某種版本控制,以確保我們的應(yīng)用程序運(yùn)行在一個不同的服務(wù)器上,而不是在本地計(jì)算機(jī)上。為此,許多人使用Docker容器,指定所需的可運(yùn)行應(yīng)用程序和包。

使用Heroku進(jìn)行部署類似于同時使用Docker容器和web托管服務(wù),但是,它使用Git作為部署應(yīng)用程序的主要手段。我們不需要將所有必需的文件打包到Docker容器中,而是創(chuàng)建一個用于版本控制的git存儲庫,然后我們可以使用熟悉的git push,但是要用到heroku遠(yuǎn)程。Heroku隨后使用了相同的容器技術(shù),以dyno的形式進(jìn)行。每個應(yīng)用程序都放在一個dyno(或容器)中,每個應(yīng)用程序都消耗“dyno hours”。每個Heroku帳戶都有一些可用的空閑小時數(shù),消耗的小時數(shù)取決于應(yīng)用程序的活動/流量。

如果你的應(yīng)用程序不需要大量流量,那么免費(fèi)套餐應(yīng)已足夠了。另外值得注意的是,當(dāng)Heroku接收到應(yīng)用程序源時,它會啟動應(yīng)用程序的構(gòu)建(例如在requirements.txt創(chuàng)建必要的資產(chǎn)等),被組裝成一個slug。術(shù)語解釋:slug是源代碼、獲取的依賴項(xiàng)、語言運(yùn)行時和編譯生成的系統(tǒng)輸出的捆綁包—為執(zhí)行做準(zhǔn)備。要在Heroku上部署,我們需要以下文件:(1)setup.sh創(chuàng)建必要的目錄并將一些信息(例如端口號)寫入.toml文件mkdir -p ~/.streamlit/
echo "[server]headless = trueport = $PORTenableCORS = false\n" > ~/.streamlit/config.toml(2) Procfile類似于Dockerfile,包含我們要執(zhí)行的指令。我們將首先在setup.sh中執(zhí)行一些bash命令,然后執(zhí)行streamlit run app.py命令。web: sh setup.sh && streamlit run app.py(3) requirements.txt包含應(yīng)用程序所需的所有包依賴項(xiàng)。請注意,這些是我正在使用的版本。你可以通過終端中的conda list或使用pip freeze > requirements.txt獲取環(huán)境當(dāng)前使用的軟件包的詳盡列表。numpy==1.18.1spacy==2.2.4pandas==1.0.1Pillow==7.1.2streamlit==0.61.0tensorflow-cpu==2.2.0我們的文件夾目錄應(yīng)如下所示:app.pyProcfileREADME.mdrequirements.txtsetup.shmodel-weights|-- xception.h5如果你以前從未創(chuàng)建過Github存儲庫,請按照以下一些簡單步驟進(jìn)行操作:創(chuàng)建一個新的存儲庫<repo_name>

復(fù)制紅色框中的URL

在終端上,運(yùn)行以下命令:# Clone the repository into our local machinegit clone <repo URL in step 2>
# Enter the directory we just clonedcd <repo_name>將之前創(chuàng)建的文件復(fù)制到此文件夾中,然后在終端中運(yùn)行以下命令:# Add all the files we just copied over to be committedgit add .
# Commit the files, along with a commit messagegit commit -m "deploy app"
# Push to master branch on our github repogit push origin master我們就快到了!這是最后的步驟。

(1)創(chuàng)建一個Heroku帳戶并進(jìn)行驗(yàn)證

(2)在此處(https://devcenter.heroku.com/articles/heroku-cli) 安裝Heroku CLI

(3)通過終端登錄到你的Heroku帳戶。將打開一個瀏覽器窗口,供你進(jìn)行身份驗(yàn)證。heroku login

(4)創(chuàng)建一個Heroku應(yīng)用heroku create <project-name>完成此步驟后,你將能夠在終端中看到指向你的項(xiàng)目的鏈接。

(5)將git repo推送到Heroku遙控器。在我們的github存儲庫的同一目錄中,運(yùn)行以下命令:git push heroku master我們完成了!構(gòu)建完成后,你應(yīng)該能夠在上面的鏈接中看到部署的應(yīng)用程序!

圖片標(biāo)題

聲明: 本文由入駐維科號的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場。如有侵權(quán)或其他問題,請聯(lián)系舉報(bào)。

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無評論

暫無評論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯
x
*文字標(biāo)題:
*糾錯內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號