【導(dǎo)語(yǔ)】完成一個(gè)簡(jiǎn)單的端到端的機(jī)器學(xué)習(xí)模型需要幾步?在本文中,我們將從一個(gè)完整的工作流:下載數(shù)據(jù)→圖像分割與處理→建?!l(fā)布模型,教大家如何對(duì) 900 萬(wàn)張圖像進(jìn)行分類(lèi),分類(lèi)標(biāo)簽多達(dá) 600 個(gè)??墒侨绱她嫶蟮臄?shù)據(jù)集又是從何而來(lái)呢?上周,AI科技大本營(yíng)為大家介紹過(guò)一篇文章在過(guò)去十年間,涵蓋 CV、NLP 和語(yǔ)音等領(lǐng)域,有 68 款大規(guī)模數(shù)據(jù)集,本文所用的數(shù)據(jù)集也在其中,大家也可以以此為借鑒,學(xué)習(xí)如何利用好這些數(shù)據(jù)。
前言
如果您想構(gòu)建一個(gè)圖像分類(lèi)器,哪里可以得到訓(xùn)練數(shù)據(jù)呢?這里給大家推薦 Google Open Images,這個(gè)巨大的圖像庫(kù)包含超過(guò) 3000 萬(wàn)張圖像和 1500 萬(wàn)個(gè)邊框,高達(dá) 18tb 的圖像數(shù)據(jù)!并且,它比同級(jí)別的其他圖像庫(kù)更加開(kāi)放,像 ImageNet 就有權(quán)限要求。
但是,對(duì)單機(jī)開(kāi)發(fā)人員來(lái)說(shuō),在這么多的圖像數(shù)據(jù)中篩選過(guò)濾并不是一件易事,需要下載和處理多個(gè)元數(shù)據(jù)文件,還要回滾自己的存儲(chǔ)空間,也可以申請(qǐng)使用谷歌云服務(wù)。另一方面,實(shí)際中并沒(méi)有那么多定制的圖像訓(xùn)練集,實(shí)話(huà)講,創(chuàng)建、共享這么多的訓(xùn)練數(shù)據(jù)是一件頭疼的事情。
在今天的教程中,我們將教大家如何使用這些開(kāi)源圖像創(chuàng)建一個(gè)簡(jiǎn)單的端到端機(jī)器學(xué)習(xí)模型。
先來(lái)看看如何使用開(kāi)源圖像中自帶的 600 類(lèi)標(biāo)簽來(lái)創(chuàng)建自己的數(shù)據(jù)集。下面以類(lèi)別為“三明治”的照片為例,展示整個(gè)處理過(guò)程。
谷歌開(kāi)源圖像-三明治圖片
一、下載數(shù)據(jù)
首先需要下載相關(guān)數(shù)據(jù),然后才能使用。這是使用谷歌開(kāi)源圖像(或其他外部數(shù)據(jù)集)的第一步。而下載數(shù)據(jù)集需要編寫(xiě)相關(guān)腳本,沒(méi)有其他簡(jiǎn)單的方法,不過(guò)不用擔(dān)心,我寫(xiě)了一個(gè)Python腳本,大家可以直接用。思路:首先根據(jù)指定的關(guān)鍵字,在開(kāi)源數(shù)據(jù)集中搜索元數(shù)據(jù),找到對(duì)應(yīng)圖像的原始 url(在 Flickr 上),然后下載到本地,下面是實(shí)現(xiàn)的 Python 代碼:
1importsys 2importos 3importpandasaspd 4importrequests 5 6fromtqdmimporttqdm 7importratelim 8fromcheckpointsimportcheckpoints 9checkpoints.enable()101112defdownload(categories):13#Downloadthemetadata14kwargs={'header':None,'names':['LabelID','LabelName']}15orig_url="https://storage.googleapis.com/openimages/2018_04/class-descriptions-boxable.csv"16class_names=pd.read_csv(orig_url,**kwargs)17orig_url="https://storage.googleapis.com/openimages/2018_04/train/train-annotations-bbox.csv"18train_boxed=pd.read_csv(orig_url)19orig_url="https://storage.googleapis.com/openimages/2018_04/train/train-images-boxable-with-rotation.csv"20image_ids=pd.read_csv(orig_url)2122#GetcategoryIDsforthegivencategoriesandsub-selecttrain_boxedwiththem.23label_map=dict(class_names.set_index('LabelName').loc[categories,'LabelID']24.to_frame().reset_index().set_index('LabelID')['LabelName'])25label_values=set(label_map.keys())26relevant_training_images=train_boxed[train_boxed.LabelName.isin(label_values)]2728#Startfrompriorresultsiftheyexistandarespecified,otherwisestartfromscratch.29relevant_flickr_urls=(relevant_training_images.set_index('ImageID')30.join(image_ids.set_index('ImageID'))31.loc[:,'OriginalURL'])32relevant_flickr_img_metadata=(relevant_training_images.set_index('ImageID').loc[relevant_flickr_urls.index]33.pipe(lambdadf:df.assign(LabelValue=df.LabelName.map(lambdav:label_map[v]))))34remaining_todo=len(relevant_flickr_urls)ifcheckpoints.resultsisNoneelse35len(relevant_flickr_urls)-len(checkpoints.results)3637#Downloadtheimages38withtqdm(total=remaining_todo)asprogress_bar:39relevant_image_requests=relevant_flickr_urls.safe_map(lambdaurl:_download_image(url,progress_bar))40progress_bar.close()4142#Writetheimagestofiles,addingthemtothepackageaswegoalong.43ifnotos.path.isdir("temp/"):44os.mkdir("temp/")45for((_,r),(_,url),(_,meta))inzip(relevant_image_requests.iteritems(),relevant_flickr_urls.iteritems(),46relevant_flickr_img_metadata.iterrows()):47image_name=url.split("/")[-1]48image_label=meta['LabelValue']4950_write_image_file(r,image_name)515253@ratelim.patient(5,5)54def_download_image(url,pbar):55"""DownloadasingleimagefromaURL,rate-limitedtooncepersecond"""56r=requests.get(url)57r.raise_for_status()58pbar.update(1)59returnr606162def_write_image_file(r,image_name):63"""Writeanimagetoafile"""64filename=f"temp/{image_name}"65withopen(filename,"wb")asf:66f.write(r.content)676869if__name__=='__main__':70categories=sys.argv[1:]71download(categories)
該腳本可以下載原始圖像的子集,其中包含我們選擇的類(lèi)別的邊框信息:
1$gitclonehttps://github.com/quiltdata/open-images.git2$cdopen-images/3$condaenvcreate-fenvironment.yml4$sourceactivatequilt-open-images-dev5$cdsrc/openimager/6$pythonopenimager.py"Sandwiches""Hamburgers"
圖像類(lèi)別采用多級(jí)分層的方式。例如,類(lèi)別三明治和漢堡包還都屬于食物類(lèi)標(biāo)簽。我們可以使用 Vega 將其可視化為徑向樹(shù):
并不是開(kāi)源圖像中的所有類(lèi)別都有與之關(guān)聯(lián)的邊框數(shù)據(jù)。但這個(gè)腳本可以下載 600 類(lèi)標(biāo)簽中的任意子集,本文主要通過(guò)”漢堡包“和”三明治“兩個(gè)類(lèi)別展開(kāi)討論。
football,toy,bird,cat,vase,hairdryer,kangaroo,knife,briefcase,pencilcase,tennisball,nail,highheels,sushi,skyscraper,tree,truck,violin,wine,wheel,whale,pizzacutter,bread,helicopter,lemon,dog,elephant,shark,flower,furniture,airplane,spoon,bench,swan,peanut,camera,flute,helmet,pomegranate,crown…
二、圖像分割和處理
我們?cè)诒镜靥幚韴D像時(shí),可以使用 matplotlib 顯示這些圖片:
1importmatplotlib.pyplotasplt2frommatplotlib.imageimportimread3%matplotlibinline4importos5fig,axarr=plt.subplots(1,5,figsize=(24,4))6fori,imginenumerate(os.listdir('../data/images/')[:5]):7axarr[i].imshow(imread('../data/images/'+img))
可見(jiàn)這些圖像并不容易訓(xùn)練,也存在其他網(wǎng)站的源數(shù)據(jù)集所面臨的所有問(wèn)題。比如目標(biāo)類(lèi)中可能存在不同大小、不同方向和遮擋等問(wèn)題。有一次,我們甚至沒(méi)有成功下載到實(shí)際的圖像,只是得到一個(gè)占位符——我們想要的圖像已經(jīng)被刪除了!
我們下載得到了幾千張這樣的圖片之后就要利用邊界框信息將這些圖像分割成三明治,漢堡。下面給出一組包含邊框的圖像:
帶邊界框
此處省略了這部分代碼,它有點(diǎn)復(fù)雜。下面要做的就是重構(gòu)圖像元數(shù)據(jù),剪裁分割圖像;再提取匹配的圖像。在運(yùn)行上述代碼之后,本地會(huì)生成一個(gè) images_cropped 文件夾,其中包含所有分割后的圖像。
三、建模
完成了下載數(shù)據(jù),圖像分割和處理,就可以訓(xùn)練模型了。接下來(lái),我們對(duì)數(shù)據(jù)進(jìn)行卷積神經(jīng)網(wǎng)絡(luò)(CNN)訓(xùn)練。卷積神經(jīng)網(wǎng)絡(luò)利用圖像中的像素點(diǎn)逐步構(gòu)建出更高層次的特征。然后對(duì)圖像的這些不同特征進(jìn)行得分和加權(quán),最終生成分類(lèi)結(jié)果。這種分類(lèi)的方式很好的利用了局部特征。因?yàn)槿魏我粋€(gè)像素與附近像素的特征相似度幾乎都遠(yuǎn)遠(yuǎn)大于遠(yuǎn)處像素的相似度。
CNNs 還具有其他吸引之處,如噪聲容忍度和(一定程度上的)尺度不變性。這進(jìn)一步提高了算法的分類(lèi)性能。
接下來(lái)就要開(kāi)始訓(xùn)練一個(gè)非常簡(jiǎn)單的卷積神經(jīng)網(wǎng)絡(luò),看看它是如何訓(xùn)練出結(jié)果的。這里使用 Keras 來(lái)定義和訓(xùn)練模型。
1、首先把圖像放在一個(gè)特定的目錄下
1images_cropped/2sandwich/3some_image.jpg4some_other_image.jpg5...6hamburger/7yet_another_image.jpg8...
然后 Keras 調(diào)用這些文件夾,Keras會(huì)檢查輸入的文件夾,并確定是二分類(lèi)問(wèn)題,并創(chuàng)建“圖像生成器”。如以下代碼:
1fromkeras.preprocessing.imageimportImageDataGenerator 2 3train_datagen=ImageDataGenerator( 4rotation_range=40, 5width_shift_range=0.2, 6height_shift_range=0.2, 7rescale=1/255, 8shear_range=0.2, 9zoom_range=0.2,10horizontal_flip=True,11fill_mode='nearest'12)1314test_datagen=ImageDataGenerator(15rescale=1/25516)1718train_generator=train_datagen.flow_from_directory(19'../data/images_cropped/quilt/open_images/',20target_size=(128,128),21batch_size=16,22class_mode='binary'23)2425validation_generator=test_datagen.flow_from_directory(26'../data/images_cropped/quilt/open_images/',27target_size=(128,128),28batch_size=16,29class_mode='binary'30)
我們不只是返回圖像本身,而是要對(duì)圖像進(jìn)行二次采樣、傾斜和縮放等處理(通過(guò)train_datagen.flow_from_directory)。其實(shí),這就是實(shí)際應(yīng)用中的數(shù)據(jù)擴(kuò)充。數(shù)據(jù)擴(kuò)充為輸入數(shù)據(jù)集經(jīng)過(guò)圖像分類(lèi)后的裁剪或失真提供必要的補(bǔ)償,這有助于我們克服數(shù)據(jù)集小的問(wèn)題。我們可以在單張圖像上多次訓(xùn)練算法模型,每次用稍微不同的方法預(yù)處理圖像的一小部分。
2、定義了數(shù)據(jù)輸入后,接下來(lái)定義模型本身
1fromkeras.modelsimportSequential 2fromkeras.layersimportConv2D,MaxPooling2D 3fromkeras.layersimportActivation,Dropout,Flatten,Dense 4fromkeras.lossesimportbinary_crossentropy 5fromkeras.callbacksimportEarlyStopping 6fromkeras.optimizersimportRMSprop 7 8 9model=Sequential()10model.add(Conv2D(32,kernel_size=(3,3),input_shape=(128,128,3),activation='relu'))11model.add(MaxPooling2D(pool_size=(2,2)))1213model.add(Conv2D(32,(3,3),activation='relu'))14model.add(MaxPooling2D(pool_size=(2,2)))1516model.add(Conv2D(64,(3,3),activation='relu'))17model.add(MaxPooling2D(pool_size=(2,2)))1819model.add(Flatten())#thisconvertsour3Dfeaturemapsto1Dfeaturevectors20model.add(Dense(64,activation='relu'))21model.add(Dropout(0.5))22model.add(Dense(1))23model.add(Activation('sigmoid'))2425model.compile(loss=binary_crossentropy,26optimizer=RMSprop(lr=0.0005),#halfofthedefaultlr27metrics=['accuracy'])
這是一個(gè)簡(jiǎn)單的卷積神經(jīng)網(wǎng)絡(luò)模型。它只包含三個(gè)卷積層:輸出層之前的后處理層,強(qiáng)正則化層和 Relu 激活函數(shù)層。這些層因素共同作用以保證模型不會(huì)過(guò)擬合。這一點(diǎn)很重要,因?yàn)槲覀兊妮斎霐?shù)據(jù)集很小。
3、最后一步是訓(xùn)練模型
1importpathlib 2 3sample_size=len(list(pathlib.Path('../data/images_cropped/').rglob('./*'))) 4batch_size=16 5 6hist=model.fit_generator( 7train_generator, 8steps_per_epoch=sample_size//batch_size, 9epochs=50,10validation_data=validation_generator,11validation_steps=round(sample_size*0.2)//batch_size,12callbacks=[EarlyStopping(monitor='val_loss',min_delta=0,patience=4)]13)1415model.save("clf.h5")
epoch 步長(zhǎng)的選擇是由圖像樣本大小和批處理量決定的。然后對(duì)這些數(shù)據(jù)進(jìn)行 50 次訓(xùn)練。因?yàn)榛卣{(diào)函數(shù) EarlyStopping 訓(xùn)練可能會(huì)提前暫停。如果在前 4 個(gè) epoch 中沒(méi)有看到訓(xùn)練性能的改進(jìn),那么它會(huì)在 50 epoch 內(nèi)返回一個(gè)相對(duì)性能最好的模型。之所以選擇這么大的步長(zhǎng),是因?yàn)槟P万?yàn)證損失存在很大的可變性。
這個(gè)簡(jiǎn)單的訓(xùn)練方案產(chǎn)生的模型的準(zhǔn)確率約為75%。
precisionrecallf1-scoresupport00.900.590.71139910.640.920.751109microavg0.730.730.732508macroavg0.770.750.732508weightedavg0.780.730.732508
有趣的是,我們的模型在分類(lèi)漢堡包為第 0 類(lèi)時(shí)信心不足,而在分類(lèi)漢堡包為第 1 類(lèi)時(shí)信心十足。90% 被歸類(lèi)為漢堡包的圖片實(shí)際上是漢堡包,但是只分類(lèi)得到 59% 的漢堡。
另一方面,只有 64% 的三明治圖片是真正的三明治,但是分類(lèi)得到的是 92% 的三明治。這與 Francois Chollet 采用相似的模型,應(yīng)用到一個(gè)相似大小的經(jīng)典貓狗數(shù)據(jù)集中,所得到的結(jié)果為 80% 的準(zhǔn)確率基本是一致的。這種差異很可能是谷歌 Open Images V4 數(shù)據(jù)集中的遮擋和噪聲水平增加造成的。數(shù)據(jù)集還包括其他插圖和照片,使分類(lèi)更加困難。如果自己構(gòu)建模型時(shí),也可以先刪除這些。
使用遷移學(xué)習(xí)技術(shù)可以進(jìn)一步提高算法性能。要了解更多信息,可以查閱 Francois Chollet 的博客文章:Building powerful image classification models using very little data,使用少量數(shù)據(jù)集構(gòu)建圖像分類(lèi)模型
https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
四、模型發(fā)布
現(xiàn)在我們構(gòu)建好了一個(gè)定制的數(shù)據(jù)集和訓(xùn)練模型,非常高興可以與大家分享?;诖艘策M(jìn)行了一些總結(jié),機(jī)器學(xué)習(xí)項(xiàng)目應(yīng)該是模塊化的可復(fù)制的,體現(xiàn)在:
將模型因素分為數(shù)據(jù)、代碼和環(huán)境組件
數(shù)據(jù)版本控制模型定義和訓(xùn)練數(shù)據(jù)
代碼版本控制訓(xùn)練模型的代碼
環(huán)境版本控制用于訓(xùn)練模型的環(huán)境。比如環(huán)境可能是一個(gè)Docker文件,也可能在本地使用pip或conda
如果其他人要使用該模型,提供相應(yīng)的{數(shù)據(jù)、代碼、環(huán)境}元組即可
遵循這些原則,就可以通過(guò)幾行代碼,訓(xùn)練出需要的模型副本:
gitclonehttps://github.com/quiltdata/open-images.gitcondaenvcreate-fopen-images/environment.ymlsourceactivatequilt-open-images-devpython-c"importt4;t4.Package.install('quilt/open_images',dest='open-images/',registry='s3://quilt-example')"
結(jié)論
在本文中,我們演示了一個(gè)端到端的圖像分類(lèi)的機(jī)器學(xué)習(xí)實(shí)現(xiàn)方法。從下載/轉(zhuǎn)換數(shù)據(jù)集到訓(xùn)練模型的整個(gè)過(guò)程。最后以一種模塊化的、可復(fù)制的便于其他人重構(gòu)的方式發(fā)布出來(lái)。由于自定義數(shù)據(jù)集很難生成和發(fā)布,隨著時(shí)間的積累,形成了這些廣泛使用的示例數(shù)據(jù)集。并不是因?yàn)樗麄兒糜?,而是因?yàn)樗鼈兒芎?jiǎn)單。例如,谷歌最近發(fā)布的機(jī)器學(xué)習(xí)速成課程大量使用了加州住房數(shù)據(jù)集。這些數(shù)據(jù)有將近 20 年的歷史了!在此基礎(chǔ)上應(yīng)用新的數(shù)據(jù),使用現(xiàn)實(shí)生活的一些有趣的圖片,或許會(huì)變得比想象中更容易!
有關(guān)文中使用的數(shù)據(jù)、代碼、環(huán)境等信息,可通過(guò)下面的鏈接獲取更多:
https://storage.googleapis.com/openimages/web/index.html
https://github.com/quiltdata/open-images
https://alpha.quiltdata.com/b/quilt-example/tree/quilt/open_images/
https://blog.quiltdata.com/reproduce-a-machine-learning-model-build-in-four-lines-of-code-b4f0a5c5f8c8
原文鏈接:
https://medium.freecodecamp.org/how-to-classify-photos-in-600-classes-using-nine-million-open-images-65847da1a319
-
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4751瀏覽量
100443 -
圖像分類(lèi)
+關(guān)注
關(guān)注
0文章
90瀏覽量
11899 -
數(shù)據(jù)集
+關(guān)注
關(guān)注
4文章
1202瀏覽量
24623
原文標(biāo)題:輕松練:如何從900萬(wàn)張圖片中對(duì)600類(lèi)照片進(jìn)行分類(lèi)|技術(shù)頭條
文章出處:【微信號(hào):rgznai100,微信公眾號(hào):rgznai100】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論