如何在一天內(nèi)構(gòu)建和部署機(jī)器學(xué)習(xí)web應(yīng)用程序?
本文我將帶領(lǐng)大家構(gòu)建一個(gè)Web應(yīng)用程序以對榴蓮進(jìn)行分類,在這里(https://durian-classifier.herokuapp.com/) 可以查看相關(guān)信息。
如果你不知道榴蓮是什么,那我向你說明一下。它是一種質(zhì)地乳脂狀、氣味刺鼻(見下圖)和外表刺眼的水果(在新加坡我們稱之為水果之王),這意味著刺鼻的氣味讓人要么討厭它,要么絕對喜歡它(很明顯,我屬于后者)。如果你覺得它聞起來很香,那么它的味道可能會(huì)更好。問題陳述是的,這個(gè)項(xiàng)目的動(dòng)力源于我對榴蓮的熱愛。你一定想知道,我們到底在分類什么?你會(huì)發(fā)現(xiàn),榴蓮有很多種,它們的味道、質(zhì)地和顏色各不相同。對于此項(xiàng)目,我們將對四種不同類型的榴蓮進(jìn)行分類,即:貓山王金鳳凰D24紅蝦下表總結(jié)了這些榴蓮的不同之處:
榴蓮的品種還有很多,但我認(rèn)為這些榴蓮的細(xì)微差別可能會(huì)讓我們的模型難以學(xué)習(xí)。數(shù)據(jù)收集每個(gè)項(xiàng)目都從數(shù)據(jù)收集開始。由于我們將部署的模型用于個(gè)人和教育目的,因此我們將從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”時(shí)可能會(huì)找到通用的“未標(biāo)記”榴蓮) )。
因此,我需要手動(dòng)檢查所有下載的圖像,以確保圖片的質(zhì)量,畢竟擁有高質(zhì)量(即正確標(biāo)記)的數(shù)據(jù)勝過大數(shù)量的數(shù)據(jù),對吧?此步驟確實(shí)需要一些領(lǐng)域知識,并且可能會(huì)花費(fèi)一些時(shí)間。(但是,數(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)。
由于我們只有很少的圖像,我們無疑必須使用一個(gè)預(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)比以往任何時(shí)候都更重要。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),因此我們不會(huì)對此進(jìn)行過多介紹。選擇我們的Web框架在這個(gè)項(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)建一個(gè)函數(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ù)的每一次更改,腳本都會(huì)從上到下重新運(yùn)行(因此它是交互式的UI),因此它以st.cache形式提供了一個(gè)緩存裝飾器來緩存加載的對象。緩存通常用于數(shù)據(jù)加載步驟或任何需要長時(shí)間計(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擇不同的圖像時(shí)都加載它(即只加載一次模型)。@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è)它會(huì)被調(diào)用應(yīng)用程序副本)可以通過在命令行中輸入以下命令在本地運(yùn)行:streamlit run app.py將我們的模型部署到Heroku就我個(gè)人而言,部署不是我最喜歡的部分,但是,如果web應(yīng)用程序不在web上,那它還有什么意義呢?我們開始吧。你可以通過多種方式為web應(yīng)用程序提供服務(wù),也可以使用許多云服務(wù)提供商來托管它。在這種情況下,我選擇使用Heroku主要是因?yàn)槲乙郧皼]有嘗試過。
什么是Heroku?
Heroku是一個(gè)云平臺即服務(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)行在一個(gè)不同的服務(wù)器上,而不是在本地計(jì)算機(jī)上。為此,許多人使用Docker容器,指定所需的可運(yùn)行應(yīng)用程序和包。
使用Heroku進(jìn)行部署類似于同時(shí)使用Docker容器和web托管服務(wù),但是,它使用Git作為部署應(yīng)用程序的主要手段。我們不需要將所有必需的文件打包到Docker容器中,而是創(chuàng)建一個(gè)用于版本控制的git存儲(chǔ)庫,然后我們可以使用熟悉的git push,但是要用到heroku遠(yuǎn)程。Heroku隨后使用了相同的容器技術(shù),以dyno的形式進(jìn)行。每個(gè)應(yīng)用程序都放在一個(gè)dyno(或容器)中,每個(gè)應(yīng)用程序都消耗“dyno hours”。每個(gè)Heroku帳戶都有一些可用的空閑小時(shí)數(shù),消耗的小時(shí)數(shù)取決于應(yīng)用程序的活動(dòng)/流量。
如果你的應(yīng)用程序不需要大量流量,那么免費(fèi)套餐應(yīng)已足夠了。另外值得注意的是,當(dāng)Heroku接收到應(yīng)用程序源時(shí),它會(huì)啟動(dòng)應(yīng)用程序的構(gòu)建(例如在requirements.txt創(chuàng)建必要的資產(chǎn)等),被組裝成一個(gè)slug。術(shù)語解釋:slug是源代碼、獲取的依賴項(xiàng)、語言運(yùn)行時(shí)和編譯生成的系統(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存儲(chǔ)庫,請按照以下一些簡單步驟進(jìn)行操作:創(chuàng)建一個(gè)新的存儲(chǔ)庫<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)建一個(gè)Heroku帳戶并進(jìn)行驗(yàn)證
(2)在此處(https://devcenter.heroku.com/articles/heroku-cli) 安裝Heroku CLI
(3)通過終端登錄到你的Heroku帳戶。將打開一個(gè)瀏覽器窗口,供你進(jìn)行身份驗(yàn)證。heroku login
(4)創(chuàng)建一個(gè)Heroku應(yīng)用heroku create <project-name>完成此步驟后,你將能夠在終端中看到指向你的項(xiàng)目的鏈接。
(5)將git repo推送到Heroku遙控器。在我們的github存儲(chǔ)庫的同一目錄中,運(yùn)行以下命令:git push heroku master我們完成了!構(gòu)建完成后,你應(yīng)該能夠在上面的鏈接中看到部署的應(yīng)用程序!
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個(gè)字
最新活動(dòng)更多
-
即日-10.29立即報(bào)名>> 2024德州儀器嵌入式技術(shù)創(chuàng)新發(fā)展研討會(huì)
-
10月31日立即下載>> 【限時(shí)免費(fèi)下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報(bào)名>>> 【在線會(huì)議】多物理場仿真助跑新能源汽車
-
11月14日立即報(bào)名>> 2024工程師系列—工業(yè)電子技術(shù)在線會(huì)議
-
12月19日立即報(bào)名>> 【線下會(huì)議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
-
即日-12.26火熱報(bào)名中>> OFweek2024中國智造CIO在線峰會(huì)
推薦專題
- 1 Intel宣布40年來最重大轉(zhuǎn)型:年底前裁員15000人、拋掉2/3房產(chǎn)
- 2 因美封殺TikTok,字節(jié)股價(jià)骨折!估值僅Meta1/5
- 3 宏山激光重磅發(fā)布行業(yè)解決方案,助力智能制造產(chǎn)業(yè)新飛躍
- 4 國產(chǎn)AI芯片公司破產(chǎn)!白菜價(jià)拍賣
- 5 具身智能火了,但規(guī)模落地還需時(shí)間
- 6 國產(chǎn)英偉達(dá)們,抓緊沖刺A股
- 7 三次錯(cuò)失風(fēng)口!OpenAI前員工殺回AI編程賽道,老東家捧金相助
- 8 英特爾賦能智慧醫(yī)療,共創(chuàng)數(shù)字化未來
- 9 英偉達(dá)的麻煩在后頭?
- 10 將“網(wǎng)紅”變成“商品”,AI“爆改”實(shí)力拉滿
- 高級軟件工程師 廣東省/深圳市
- 自動(dòng)化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市