輕松學Pytorch-全卷積神經(jīng)網(wǎng)絡(luò)實現(xiàn)表情識別
重磅干貨,第一時間送達
轉(zhuǎn)載自:OpenCV學堂
我又又一周沒有更新這個系列文章了,但是我說過我會繼續(xù)堅持更新下去的,今天給大家更新了一篇如何使用殘差Block構(gòu)建全卷積神經(jīng)網(wǎng)絡(luò)實現(xiàn)圖像分類,對的,你沒有看錯就是基于全卷積神經(jīng)網(wǎng)絡(luò)實現(xiàn)人臉表情圖像的識別,其中數(shù)據(jù)集一部分來自CK+,更多的是我自己使用OpenVINO的表情識別模型來自動標注的,總數(shù)大致有5000張的表情圖像。
基于殘差Block,不過這個Block跟上一篇中不一樣地方是支持下采樣,它的代碼實現(xiàn)如下:
1class?ResidualBlock(torch.nn.Module):
2????def?__init__(self,?in_channels,?out_channels,?stride=1):
3????????"""
4????????Args:
5??????????in_channels?(int):??Number?of?input?channels.
6??????????out_channels?(int):?Number?of?output?channels.
7??????????stride?(int):???????Controls?the?stride.
8????????"""
9????????super(ResidualBlock,?self).__init__()
10
11????????self.skip?=?torch.nn.Sequential()
12
13????????if?stride?!=?1?or?in_channels?!=?out_channels:
14????????????self.skip?=?torch.nn.Sequential(
15????????????????torch.nn.Conv2d(in_channels=in_channels,?out_channels=out_channels,?kernel_size=1,?stride=stride,?bias=False),
16????????????????torch.nn.BatchNorm2d(out_channels))
17
18????????self.block?=?torch.nn.Sequential(
19????????????torch.nn.Conv2d(in_channels=in_channels,?out_channels=out_channels,?kernel_size=3,?padding=1,?stride=stride,?bias=False),
20????????????torch.nn.BatchNorm2d(out_channels),
21????????????torch.nn.ReLU(),
22????????????torch.nn.Conv2d(in_channels=out_channels,?out_channels=out_channels,?kernel_size=3,?padding=1,?stride=1,?bias=False),
23????????????torch.nn.BatchNorm2d(out_channels))
24
25????def?forward(self,?x):
26????????out?=?self.block(x)
27????????identity?=?self.skip(x)
28????????out?+=?identity
29????????out?=?F.relu(out)
30????????return?out其中stride參數(shù)為2的時候就會實現(xiàn)自動下采樣;為1的時候表示跟前面大小保持一致。
模型結(jié)構(gòu)中包括多個殘差Block,最終的輸出Nx8x1x1, 表示8種表情,然后通過softmax完成分類識別。模型的輸入:NCHW=Nx3x64x64。模型結(jié)構(gòu)參考了OpenVINO框架中的Caffe版本的表情識別模型。最終的模型實現(xiàn)代碼如下:
1class?EmotionsResNet(torch.nn.Module):
2????def?__init__(self):
3????????super(EmotionsResNet,?self).__init__()
4????????self.cnn_layers?=?torch.nn.Sequential(
5????????????#?卷積層?(64x64x3的圖像)
6????????????ResidualBlock(3,?32,?1),
7????????????ResidualBlock(32,?64,?2),
8????????????ResidualBlock(64,?64,?2),
9????????????ResidualBlock(64,?128,?2),
10????????????ResidualBlock(128,?128,?2),
11????????????ResidualBlock(128,?256,?2),
12????????????ResidualBlock(256,?256,?2),
13????????????ResidualBlock(256,?8,?1),
14????????)
15
16????def?forward(self,?x):
17????????#?stack?convolution?layers
18????????x?=?self.cnn_layers(x)
19
20????????#?Nx5x1x1
21????????B,?C,?H,?W?=?x.size()
22????????out?=?x.view(B,?-1)
23????????return?out基于交叉熵實現(xiàn)了模型訓練,訓練了15個epoch之后,保存模型。訓練的代碼如下:
1if?__name__?==?"__main__":
2????#?create?a?complete?CNN
3????model?=?EmotionsResNet()
4????print(model)
5
6????#?使用GPU
7????if?train_on_gpu:
8????????model.cuda()
9
10????ds?=?EmotionDataset("D:/facedb/emotion_dataset")
11????num_train_samples?=?ds.num_of_samples()
12????bs?=?16
13????dataloader?=?DataLoader(ds,?batch_size=bs,?shuffle=True)
14
15????#?訓練模型的次數(shù)
16????num_epochs?=?15
17????#?optimizer?=?torch.optim.SGD(model.parameters(),?lr=0.001)
18????optimizer?=?torch.optim.Adam(model.parameters(),?lr=1e-2)
19????model.train()
20
21????#?損失函數(shù)
22????mse_loss?=?torch.nn.MSELoss()
23????cross_loss?=?torch.nn.CrossEntropyLoss()
24????index?=?0
25????for?epoch?in??range(num_epochs):
26????????train_loss?=?0.0
27????????for?i_batch,?sample_batched?in?enumerate(dataloader):
28????????????images_batch,?emotion_batch?=?\
29????????????????sample_batched['image'],?sample_batched['emotion']
30????????????if?train_on_gpu:
31????????????????images_batch,?emotion_batch=?images_batch.cuda(),?emotion_batch.cuda()
32????????????optimizer.zero_grad()
33
34????????????#?forward?pass:?compute?predicted?outputs?by?passing?inputs?to?the?model
35????????????m_emotion_out_?=?model(images_batch)
36????????????emotion_batch?=?emotion_batch.long()
37
38????????????#?calculate?the?batch?loss
39????????????loss?=?cross_loss(m_emotion_out_,?emotion_batch)
40
41????????????#?backward?pass:?compute?gradient?of?the?loss?with?respect?to?model?parameters
42????????????loss.backward()
43
44????????????#?perform?a?single?optimization?step?(parameter?update)
45????????????optimizer.step()
46
47????????????#?update?training?loss
48????????????train_loss?+=?loss.item()
49????????????if?index?%?100?==?0:
50????????????????print('step:?{}?\tTraining?Loss:?{:.6f}?'.format(index,?loss.item()))
51????????????index?+=?1
52
53????????????#?計算平均損失
54????????train_loss?=?train_loss?/?num_train_samples
55
56????????#?顯示訓練集與驗證集的損失函數(shù)
57????????print('Epoch:?{}?\tTraining?Loss:?{:.6f}?'.format(epoch,?train_loss))
58
59????#?save?model
60????model.eval()
61????torch.save(model,?'face_emotions_model.pt')基于OpenCV人臉檢測得到的ROI區(qū)域,輸入到訓練好的人臉表情識別模型中,就可以預測人臉表情,完成實時人臉表情識別,演示代碼如下:
1cnn_model?=?torch.load("./face_emotions_model.pt")
2print(cnn_model)
3#?capture?=?cv.VideoCapture(0)
4capture?=?cv.VideoCapture("D:/images/video/example_dsh.mp4")
5
6#?load?tensorflow?model
7net?=?cv.dnn.readNetFromTensorflow(model_bin,?config=config_text)
8while?True:
9????ret,?frame?=?capture.read()
10????if?ret?is?not?True:
11????????break
12????frame?=?cv.flip(frame,?1)
13????h,?w,?c?=?frame.shape
14????blobImage?=?cv.dnn.blobFromImage(frame,?1.0,?(300,?300),?(104.0,?177.0,?123.0),?False,?False);
15????net.setInput(blobImage)
16????cvOut?=?net.forward()
17????#?繪制檢測矩形
18????for?detection?in?cvOut[0,0,:,:]:
19????????score?=?float(detection[2])
20????????if?score?>?0.5:
21????????????left?=?detection[3]*w
22????????????top?=?detection[4]*h
23????????????right?=?detection[5]*w
24????????????bottom?=?detection[6]*h
25
26????????????#?roi?and?detect?landmark
27????????????roi?=?frame[np.int32(top):np.int32(bottom),np.int32(left):np.int32(right),:]
28????????????rw?=?right?-?left
29????????????rh?=?bottom?-?top
30????????????img?=?cv.resize(roi,?(64,?64))
31????????????img?=?(np.float32(img)?/?255.0?-?0.5)?/?0.5
32????????????img?=?img.transpose((2,?0,?1))
33????????????x_input?=?torch.from_numpy(img).view(1,?3,?64,?64)
34????????????emotion_?=?cnn_model(x_input.cuda())
35????????????predict_?=?torch.max(emotion_,?1)[1].cpu().detach().numpy()[0]
36????????????emotion_txt?=?emotion_labels[predict_]
37????????????#?繪制
38????????????cv.putText(frame,?("%s"%(emotion_txt)),?(int(left),?int(top)-15),?cv.FONT_HERSHEY_SIMPLEX,?1,?(0,?0,?255),?2)
39????????????cv.rectangle(frame,?(int(left),?int(top)),?(int(right),?int(bottom)),?(255,?0,?0),?thickness=2)
40????????????c?=?cv.waitKey(10)
41????????????if?c?==?27:
42????????????????break
43????????????cv.imshow("face?detection?+?emotion",?frame)
44
45cv.waitKey(0)
46cv.destroyAllWindows()運行結(jié)果如下:

廢話就不多說了,還是希望大家支持,我繼續(xù)寫下去!
好消息!?
小白學視覺知識星球
開始面向外開放啦??????
下載1:OpenCV-Contrib擴展模塊中文版教程 在「小白學視覺」公眾號后臺回復:擴展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴展模塊教程中文版,涵蓋擴展模塊安裝、SFM算法、立體視覺、目標跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。 下載2:Python視覺實戰(zhàn)項目52講 在「小白學視覺」公眾號后臺回復:Python視覺實戰(zhàn)項目,即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學校計算機視覺。 下載3:OpenCV實戰(zhàn)項目20講 在「小白學視覺」公眾號后臺回復:OpenCV實戰(zhàn)項目20講,即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學習進階。 交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學影像、GAN、算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~

