优达学城《DeepLearning》项目2:犬种分类器
在這個(gè)notebook中,你將邁出第一步,來開發(fā)可以作為移動(dòng)端或 Web應(yīng)用程序一部分的算法。在這個(gè)項(xiàng)目的最后,你的程序?qū)⒛軌虬延脩籼峁┑娜魏我粋€(gè)圖像作為輸入。如果可以從圖像中檢測到一只狗,它會(huì)輸出對(duì)狗品種的預(yù)測。如果圖像中是一個(gè)人臉,它會(huì)預(yù)測一個(gè)與其最相似的狗的種類。下面這張圖展示了完成項(xiàng)目后可能的輸出結(jié)果。
- Step 0: 導(dǎo)入數(shù)據(jù)集
- Step 1: 檢測人臉
- Step 2: 檢測狗狗
- Step 3: 從頭創(chuàng)建一個(gè)CNN來分類狗品種
- Step 4: 使用一個(gè)CNN來區(qū)分狗的品種(使用遷移學(xué)習(xí))
- Step 5: 完成你的算法
- Step 6: 測試你的算法
步驟 0: 導(dǎo)入數(shù)據(jù)集
下載狗數(shù)據(jù)集:dog dataset,放置在data文件夾內(nèi)并解壓。
下載人數(shù)據(jù)集:human dataset(一個(gè)人臉識(shí)別數(shù)據(jù)集),放置在data文件夾內(nèi)并解壓。
步驟1:檢測人臉
我們將使用 OpenCV 中的?Haar feature-based cascade classifiers?來檢測圖像中的人臉。OpenCV 提供了很多預(yù)訓(xùn)練的人臉檢測模型,它們以XML文件保存在?github。我們已經(jīng)下載了其中一個(gè)檢測模型,并且把它存儲(chǔ)在?haarcascades?的目錄中。
在如下代碼單元中,我們將演示如何使用這個(gè)檢測模型在樣本圖像中找到人臉。
寫一個(gè)人臉探測器
我們可以使用這個(gè)程序編寫一個(gè)函數(shù),如果在圖像中檢測到人臉,則返回True,否則返回False。這個(gè)函數(shù)名為face_detector,將圖像的文件路徑作為輸入,出現(xiàn)在下面的代碼塊中。
評(píng)估人臉檢測器
問題1:使用下面的代碼單元格來測試face_detector函數(shù)的性能。
- 在human_files的前100張圖片中有多大概率檢測到人臉?
- 在dog_files的前100張圖片中中有多大概率檢測到人臉?
步驟 2: 檢測狗狗
在這個(gè)部分中,我們使用預(yù)訓(xùn)練的 vgg16 模型去檢測圖像中的狗。
給定一個(gè)圖像,這個(gè)預(yù)先訓(xùn)練過的vgg16模型將為圖像中包含的對(duì)象返回一個(gè)預(yù)測(來自ImageNet中的1000個(gè)可能類別)。
用預(yù)先訓(xùn)練好的模型進(jìn)行預(yù)測
在下一個(gè)代碼單元格中,您將編寫一個(gè)函數(shù),它接受圖像的路徑作為輸入,并返回由預(yù)先訓(xùn)練的vgg -16模型預(yù)測的ImageNet類對(duì)應(yīng)的索引。輸出應(yīng)該始終是0到999之間的整數(shù)(含999)。
from PIL import Image
import torchvision.transforms as transforms# Set PIL to be tolerant of image files that are truncated.
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = Truedef VGG16_predict(img_path):'''Use pre-trained VGG-16 model to obtain index corresponding to predicted ImageNet class for image at specified pathArgs:img_path: path to an imageReturns:Index corresponding to VGG-16 model's prediction'''## TODO: Complete the function.## Load and pre-process an image from the given img_path## Return the *index* of the predicted class for that imagenormalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])transform = transforms.Compose([transforms.Resize((224,224)),transforms.CenterCrop(224),transforms.ToTensor(),normalize])image = Image.open(img_path)#print(image.size)image = transform(image)image.unsqueeze_(0)#print(image.size)if use_cuda:image = image.cuda()output = VGG16(image)if use_cuda:output = output.cuda()class_index = output.data.cpu().numpy().argmax() return class_index # predicted class index#print(dog_files[0])
VGG16_predict(dog_files[0])
結(jié)果:
252
寫一個(gè)狗狗探測器
在研究該?清單?的時(shí)候,你會(huì)注意到,狗類別對(duì)應(yīng)的序號(hào)為151-268。因此,在檢查預(yù)訓(xùn)練模型判斷圖像是否包含狗的時(shí)候,我們只需要檢查如上的?VGG16_predict 函數(shù)是否返回一個(gè)介于151和268之間(包含區(qū)間端點(diǎn))的值。
我們通過這些想法來完成下方的?dog_detector?函數(shù),如果從圖像中檢測到狗就返回?True,否則返回?False。
問題2:使用下面的代碼單元格來測試dog_detector函數(shù)的性能。
- 在human_files_short中有多少百分比檢測到狗?
- 在dog_files_short中有多少百分比檢測到狗?
你可以自由地探索其他預(yù)先訓(xùn)練網(wǎng)絡(luò)(如Inception-v3, ResNet-50等)。請(qǐng)使用下面的代碼單元來測試其他預(yù)先訓(xùn)練好的PyTorch模型。如果您決定執(zhí)行這個(gè)可選任務(wù),請(qǐng)報(bào)告human_files_short和dog_files_short的性能。
步驟 3: 從頭開始創(chuàng)建一個(gè)CNN來分類狗品種
現(xiàn)在我們已經(jīng)實(shí)現(xiàn)了一個(gè)函數(shù),能夠在圖像中識(shí)別人類及狗狗。但我們需要更進(jìn)一步的方法,來對(duì)狗的類別進(jìn)行識(shí)別。在這一步中,你需要實(shí)現(xiàn)一個(gè)卷積神經(jīng)網(wǎng)絡(luò)來對(duì)狗的品種進(jìn)行分類。你需要從頭實(shí)現(xiàn)你的卷積神經(jīng)網(wǎng)絡(luò)(在這一階段,你還不能使用遷移學(xué)習(xí)),并且你需要達(dá)到超過1%的測試集準(zhǔn)確率。在本項(xiàng)目的步驟五種,你還有機(jī)會(huì)使用遷移學(xué)習(xí)來實(shí)現(xiàn)一個(gè)準(zhǔn)確率大大提高的模型。
值得注意的是,對(duì)狗的圖像進(jìn)行分類是一項(xiàng)極具挑戰(zhàn)性的任務(wù)。因?yàn)榧幢闶且粋€(gè)正常人,也很難區(qū)分布列塔尼犬和威爾士史賓格犬。
不難發(fā)現(xiàn)其他的狗品種會(huì)有很小的類間差別(比如金毛尋回犬和美國水獵犬)。
同樣,拉布拉多犬(labradors)有黃色、棕色和黑色這三種。那么你設(shè)計(jì)的基于視覺的算法將不得不克服這種較高的類間差別,以達(dá)到能夠?qū)⑦@些不同顏色的同類狗分到同一個(gè)品種中。
我們也提到了隨機(jī)分類將得到一個(gè)非常低的結(jié)果:不考慮品種略有失衡的影響,隨機(jī)猜測到正確品種的概率是1/133,相對(duì)應(yīng)的準(zhǔn)確率是低于1%的。
請(qǐng)記住,在深度學(xué)習(xí)領(lǐng)域,實(shí)踐遠(yuǎn)遠(yuǎn)高于理論。大量嘗試不同的框架吧,相信你的直覺!當(dāng)然,玩得開心!
為Dog數(shù)據(jù)集指定數(shù)據(jù)加載器
問題3:描述您選擇的數(shù)據(jù)預(yù)處理過程。
- 你的代碼如何調(diào)整圖像的大小(裁剪,拉伸等)?輸入張量的大小是多少,為什么?
- 你決定擴(kuò)大數(shù)據(jù)集了嗎?如果有,如何(通過平移,翻轉(zhuǎn),旋轉(zhuǎn)等)?如果沒有,為什么?
指定損失函數(shù)和優(yōu)化器
訓(xùn)練和驗(yàn)證模型
# the following import is required for training to be robust to truncated images
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = Truedef train(n_epochs, loaders, model, optimizer, criterion, use_cuda, save_path):"""returns trained model"""# initialize tracker for minimum validation lossvalid_loss_min = np.Inf for epoch in range(1, n_epochs+1):# initialize variables to monitor training and validation losstrain_loss = 0.0valid_loss = 0.0#################### train the model ####################model.train()for batch_idx, (data, target) in enumerate(loaders['train']):# move to GPUif use_cuda:data, target = data.cuda(), target.cuda()## find the loss and update the model parameters accordingly## record the average training loss, using something like## train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data - train_loss))optimizer.zero_grad() ## find the loss and update the model parameters accordinglyoutput = model(data)loss = criterion(output, target)loss.backward()optimizer.step()## record the average training loss, using something like## train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data - train_loss))train_loss += ((1 / (batch_idx + 1)) * (loss.data - train_loss))# print training/validation statistics if (batch_idx+1) % 40 == 0:print('Epoch: {} \tBatch: {} \tTraining Loss: {:.6f}'.format(epoch, batch_idx + 1, train_loss))###################### # validate the model #######################model.eval()for batch_idx, (data, target) in enumerate(loaders['valid']):# move to GPUif use_cuda:data, target = data.cuda(), target.cuda()## update the average validation lossoutput = model(data)loss = criterion(output, target)valid_loss += ((1 / (batch_idx + 1)) * (loss.data - valid_loss))# print training/validation statistics if (batch_idx+1) % 40 == 0:print('Epoch: {} \tBatch: {} \tValidation Loss: {:.6f}'.format(epoch, batch_idx + 1, valid_loss))# print training/validation statistics print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(epoch, train_loss,valid_loss))## TODO: save the model if validation loss has decreasedif valid_loss <= valid_loss_min:print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...'.format(valid_loss_min,valid_loss))torch.save(model.state_dict(), save_path)valid_loss_min = valid_loss # return trained modelreturn modelepoch = 10# train the model
model_scratch = train(epoch, loaders_scratch, model_scratch, optimizer_scratch, criterion_scratch, use_cuda, 'model_scratch.pt')# load the model that got the best validation accuracy
model_scratch.load_state_dict(torch.load('model_scratch.pt'))
結(jié)果:
Epoch: 1 Batch: 40 Training Loss: 4.889728
Epoch: 1 Batch: 80 Training Loss: 4.887787
Epoch: 1 Batch: 120 Training Loss: 4.887685
Epoch: 1 Batch: 160 Training Loss: 4.885648
Epoch: 1 Batch: 200 Training Loss: 4.881847
Epoch: 1 Batch: 240 Training Loss: 4.873278
Epoch: 1 Batch: 280 Training Loss: 4.862270
Epoch: 1 Batch: 320 Training Loss: 4.854340
Epoch: 1 Batch: 40 Validation Loss: 4.712207
Epoch: 1 Training Loss: 4.851301 Validation Loss: 4.704982
Validation loss decreased (inf --> 4.704982). Saving model ...
Epoch: 2 Batch: 40 Training Loss: 4.730308
Epoch: 2 Batch: 80 Training Loss: 4.719476
Epoch: 2 Batch: 120 Training Loss: 4.701708
Epoch: 2 Batch: 160 Training Loss: 4.695746
Epoch: 2 Batch: 200 Training Loss: 4.692133
Epoch: 2 Batch: 240 Training Loss: 4.675904
Epoch: 2 Batch: 280 Training Loss: 4.663143
Epoch: 2 Batch: 320 Training Loss: 4.650386
Epoch: 2 Batch: 40 Validation Loss: 4.488307
Epoch: 2 Training Loss: 4.643542 Validation Loss: 4.494160
Validation loss decreased (4.704982 --> 4.494160). Saving model ...
Epoch: 3 Batch: 40 Training Loss: 4.474283
Epoch: 3 Batch: 80 Training Loss: 4.501595
Epoch: 3 Batch: 120 Training Loss: 4.477735
Epoch: 3 Batch: 160 Training Loss: 4.488136
Epoch: 3 Batch: 200 Training Loss: 4.490754
Epoch: 3 Batch: 240 Training Loss: 4.487989
Epoch: 3 Batch: 280 Training Loss: 4.490090
Epoch: 3 Batch: 320 Training Loss: 4.481546
Epoch: 3 Batch: 40 Validation Loss: 4.262285
Epoch: 3 Training Loss: 4.479444 Validation Loss: 4.275317
Validation loss decreased (4.494160 --> 4.275317). Saving model ...
Epoch: 4 Batch: 40 Training Loss: 4.402790
Epoch: 4 Batch: 80 Training Loss: 4.372338
Epoch: 4 Batch: 120 Training Loss: 4.365306
Epoch: 4 Batch: 160 Training Loss: 4.367325
Epoch: 4 Batch: 200 Training Loss: 4.374326
Epoch: 4 Batch: 240 Training Loss: 4.369847
Epoch: 4 Batch: 280 Training Loss: 4.365964
Epoch: 4 Batch: 320 Training Loss: 4.363493
Epoch: 4 Batch: 40 Validation Loss: 4.249445
Epoch: 4 Training Loss: 4.364571 Validation Loss: 4.248449
Validation loss decreased (4.275317 --> 4.248449). Saving model ...
Epoch: 5 Batch: 40 Training Loss: 4.229365
Epoch: 5 Batch: 80 Training Loss: 4.267400
Epoch: 5 Batch: 120 Training Loss: 4.269664
Epoch: 5 Batch: 160 Training Loss: 4.257591
Epoch: 5 Batch: 200 Training Loss: 4.261866
Epoch: 5 Batch: 240 Training Loss: 4.247512
Epoch: 5 Batch: 280 Training Loss: 4.239336
Epoch: 5 Batch: 320 Training Loss: 4.230827
Epoch: 5 Batch: 40 Validation Loss: 4.043582
Epoch: 5 Training Loss: 4.231559 Validation Loss: 4.039588
Validation loss decreased (4.248449 --> 4.039588). Saving model ...
Epoch: 6 Batch: 40 Training Loss: 4.180193
Epoch: 6 Batch: 80 Training Loss: 4.140314
Epoch: 6 Batch: 120 Training Loss: 4.153989
Epoch: 6 Batch: 160 Training Loss: 4.140887
Epoch: 6 Batch: 200 Training Loss: 4.151268
Epoch: 6 Batch: 240 Training Loss: 4.153749
Epoch: 6 Batch: 280 Training Loss: 4.153314
Epoch: 6 Batch: 320 Training Loss: 4.156451
Epoch: 6 Batch: 40 Validation Loss: 3.940857
Epoch: 6 Training Loss: 4.149529 Validation Loss: 3.945810
Validation loss decreased (4.039588 --> 3.945810). Saving model ...
Epoch: 7 Batch: 40 Training Loss: 4.060485
Epoch: 7 Batch: 80 Training Loss: 4.065772
Epoch: 7 Batch: 120 Training Loss: 4.056967
Epoch: 7 Batch: 160 Training Loss: 4.068470
Epoch: 7 Batch: 200 Training Loss: 4.076772
Epoch: 7 Batch: 240 Training Loss: 4.087616
Epoch: 7 Batch: 280 Training Loss: 4.074337
Epoch: 7 Batch: 320 Training Loss: 4.080192
Epoch: 7 Batch: 40 Validation Loss: 3.860693
Epoch: 7 Training Loss: 4.078263 Validation Loss: 3.884382
Validation loss decreased (3.945810 --> 3.884382). Saving model ...
Epoch: 8 Batch: 40 Training Loss: 3.960585
Epoch: 8 Batch: 80 Training Loss: 3.983979
Epoch: 8 Batch: 120 Training Loss: 3.965129
Epoch: 8 Batch: 160 Training Loss: 3.965021
Epoch: 8 Batch: 200 Training Loss: 3.965830
Epoch: 8 Batch: 240 Training Loss: 3.976013
Epoch: 8 Batch: 280 Training Loss: 3.975547
Epoch: 8 Batch: 320 Training Loss: 3.978744
Epoch: 8 Batch: 40 Validation Loss: 3.784086
Epoch: 8 Training Loss: 3.980776 Validation Loss: 3.779312
Validation loss decreased (3.884382 --> 3.779312). Saving model ...
Epoch: 9 Batch: 40 Training Loss: 3.917738
Epoch: 9 Batch: 80 Training Loss: 3.967938
Epoch: 9 Batch: 120 Training Loss: 3.934165
Epoch: 9 Batch: 160 Training Loss: 3.917138
Epoch: 9 Batch: 200 Training Loss: 3.910391
Epoch: 9 Batch: 240 Training Loss: 3.909857
Epoch: 9 Batch: 280 Training Loss: 3.907439
Epoch: 9 Batch: 320 Training Loss: 3.901893
Epoch: 9 Batch: 40 Validation Loss: 3.826410
Epoch: 9 Training Loss: 3.903304 Validation Loss: 3.824970
Epoch: 10 Batch: 40 Training Loss: 3.910845
Epoch: 10 Batch: 80 Training Loss: 3.910709
Epoch: 10 Batch: 120 Training Loss: 3.915924
Epoch: 10 Batch: 160 Training Loss: 3.900949
Epoch: 10 Batch: 200 Training Loss: 3.883792
Epoch: 10 Batch: 240 Training Loss: 3.882242
Epoch: 10 Batch: 280 Training Loss: 3.875963
Epoch: 10 Batch: 320 Training Loss: 3.858594
Epoch: 10 Batch: 40 Validation Loss: 3.638186
Epoch: 10 Training Loss: 3.861175 Validation Loss: 3.647465
Validation loss decreased (3.779312 --> 3.647465). Saving model ...
<All keys matched successfully>
測試模型
在狗圖片的測試數(shù)據(jù)集中試用你的模型。使用下面的代碼單元計(jì)算和打印測試loss和準(zhǔn)確性。確保您的測試精度大于10%。
步驟 4: 使用CNN遷移學(xué)習(xí)來區(qū)分狗的品種
使用 遷移學(xué)習(xí)(Transfer Learning)的方法,能幫助我們在不損失準(zhǔn)確率的情況下大大減少訓(xùn)練時(shí)間。在以下步驟中,你可以嘗試使用遷移學(xué)習(xí)來訓(xùn)練你自己的CNN。
模型架構(gòu)
指定損失函數(shù)和優(yōu)化器
訓(xùn)練和驗(yàn)證模型
# train the model
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = Truedef train(n_epochs, loaders, model, optimizer, criterion, use_cuda, save_path):"""returns trained model"""# initialize tracker for minimum validation lossvalid_loss_min = np.Inf for epoch in range(1, n_epochs+1):# initialize variables to monitor training and validation losstrain_loss = 0.0valid_loss = 0.0#################### train the model ####################model.train()for batch_idx, (data, target) in enumerate(loaders['train']):# move to GPUif use_cuda:data, target = data.cuda(), target.cuda()optimizer.zero_grad() ## find the loss and update the model parameters accordinglyoutput = model(data)loss = criterion(output, target)loss.backward()optimizer.step()## record the average training loss, using something like## train_loss = train_loss + ((1 / (batch_idx + 1)) * (loss.data - train_loss))train_loss += ((1 / (batch_idx + 1)) * (loss.data - train_loss))# print training/validation statistics if (batch_idx+1) % 40 == 0:print('Epoch: {} \tBatch: {} \tTraining Loss: {:.6f}'.format(epoch, batch_idx + 1, train_loss))###################### # validate the model #######################model.eval()for batch_idx, (data, target) in enumerate(loaders['valid']):# move to GPUif use_cuda:data, target = data.cuda(), target.cuda()## update the average validation lossoutput = model(data)loss = criterion(output, target)valid_loss += ((1 / (batch_idx + 1)) * (loss.data - valid_loss))# print training/validation statistics if (batch_idx+1) % 40 == 0:print('Epoch: {} \tBatch: {} \tValidation Loss: {:.6f}'.format(epoch, batch_idx + 1, valid_loss))# print training/validation statistics print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(epoch, train_loss,valid_loss))## TODO: save the model if validation loss has decreasedif valid_loss <= valid_loss_min:print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...'.format(valid_loss_min,valid_loss))torch.save(model.state_dict(), save_path)valid_loss_min = valid_loss # return trained modelreturn modeln_epochs = 2
model_transfer = train(n_epochs, loaders_transfer, model_transfer, optimizer_transfer, criterion_transfer, use_cuda, 'model_transfer.pt')# load the model that got the best validation accuracy (uncomment the line below)
model_transfer.load_state_dict(torch.load('model_transfer.pt'))
結(jié)果:
測試模型
用模型預(yù)測狗的品種
編寫一個(gè)函數(shù),以圖像路徑作為輸入,并返回您的模型預(yù)測的狗的品種
步驟 5: 完成你的算法
實(shí)現(xiàn)一個(gè)算法,它的輸入為圖像的路徑,它能夠區(qū)分圖像是否包含一個(gè)人、狗或兩者都不包含,然后:
- 如果從圖像中檢測到一只狗,返回被預(yù)測的品種。
- 如果從圖像中檢測到人,返回最相像的狗品種。
- 如果兩者都不能在圖像中檢測到,輸出錯(cuò)誤提示。
我們非常歡迎你來自己編寫檢測圖像中人類與狗的函數(shù),你可以隨意地使用上方完成的?face_detector?和?dog_detector?函數(shù)。你需要在步驟5使用你的CNN來預(yù)測狗品種。
下面提供了算法的示例輸出,但你可以自由地設(shè)計(jì)自己的模型!
步驟 6: 測試你的算法
在這個(gè)部分中,你將嘗試一下你的新算法!算法認(rèn)為你看起來像什么類型的狗?如果你有一只狗,它可以準(zhǔn)確地預(yù)測你的狗的品種嗎?如果你有一只貓,它會(huì)將你的貓誤判為一只狗嗎?
結(jié)果:
This is a human picture who looks like Norwich terrier
This is a human picture who looks like Curly-coated retriever
This is a human picture who looks like Curly-coated retriever
This is a dog picture and it's English cocker spaniel
This is a dog picture and it's Bloodhound
This is a dog picture and it's Lowchen
總結(jié)
以上是生活随笔為你收集整理的优达学城《DeepLearning》项目2:犬种分类器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI视频行为分析系统项目复盘——技术篇2
- 下一篇: AI视频行为分析系统项目复盘——技术篇3