生活随笔
收集整理的這篇文章主要介紹了
深度学习项目,使用python进行表情识别,pytorch应用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 前言
- 一、深度學習是什么?
- 二、數據的預處理
-
- 三、構建模型與訓練
-
- 四、實時識別
- 總結
前言
這個項目是以前課設用到的功能之一,參考了其他人的人的博客,自己做了一下整理
需要用到的庫有:opencv,pandas,pytorch,numpy,dlib
本項目基于深度學習
一、深度學習是什么?
深度學習(DL, Deep Learning)是機器學習(ML, Machine Learning)領域中一個新的研究方向,它被引入機器學習使其更接近于最初的目標——人工智能(AI, Artificial Intelligence)。
形象來說,深度學習就是構建一個類似于人類大腦的人工神經網絡,通過已有的數據不斷學習,最終使得每個神經元的參數趨于完美,使其能夠解決實際生活中的抽象問題。
二、數據的預處理
1.數據分類
我們所用到的數據都存放在train.csv文件里面,文件的結構如下:
其中,lable是單張圖片的標簽,不同的值對應不同的表情:
valueemotion
| 0 | angry |
| 1 | disgust |
| 2 | fear |
| 3 | happy |
| 4 | sad |
| 5 | surprise |
| 6 | neutral |
feature是單張圖片的字符串編碼,每一串編碼由28 * 28 = 784組字符串組成,每組字符串對應一個像素的灰度圖。
在預處理階段,我們需要將train.scv文件中的所有圖像提取出來,分為train_data和val_data,分別作為訓練集與驗證集,并存放到各自的文件夾。
同時,建立train_data.csv與val_data.csv存放文件名到該文件標簽的映射
2.代碼
"""
該文件將原數據‘train.csv’分離
圖片分離到train_data, val_data兩個文件夾中
并創建train_data_set.csv與val_data_set.csv來標注數據
"""
import pandas
as pd
import cv2
as cv
import numpy
as np
import os
def classify():"""將數據分為訓練集與數據集并儲存:return:"""path
= './train.csv'all_data
= pd
.read_csv
(path
)train_num
= int(all_data
.shape
[0] * 0.7)train_data
= all_data
.loc
[0: train_num
]val_data
= all_data
.loc
[train_num
:]print(train_data
)save_img_and_label
(train_data
, './train_data', './train_data_set.csv')save_img_and_label
(val_data
, './val_data', './val_data_set.csv')def save_img_and_label(data
: pd
.DataFrame
, img_save_path
, csv_save_path
):"""保存數據中的圖片并對其標注"""if not os
.path
.exists
(img_save_path
):os
.mkdir
(img_save_path
)img_name_list
= []img_label_list
= []for i
in range(len(data
)):img_name
= '{}.jpg'.format(i
)img_str
= data
[['feature']].values
[i
][0]img_label
= str(data
[['label']].values
[i
][0])img_list
= img_str
.split
(' ')img
= np
.array
(img_list
, dtype
=np
.int32
).reshape
((48, 48))cv
.imwrite
(img_save_path
+ '/' + img_name
, img
)img_name_list
.append
(img_name
)img_label_list
.append
(img_label
)save_data
= pd
.DataFrame
(img_label_list
, index
=img_name_list
)save_data
.to_csv
(csv_save_path
, header
=False)
classify
()
運行完成后結果如下
train_data里面的東西
train_data_set.csv里面的東西
三、構建模型與訓練
1.模型與代碼
使用的模型參考了如下A模型
代碼如下
文件名train_model.py
"""
訓練模型
"""
import torch
import torch
.utils
.data
as data
from torch
.utils
.data
.dataset
import T_co
import pandas
as pd
import numpy
as np
import cv2
as cv
import torch
.nn
as nn
from torch
import optim
class FaceDateset(data
.Dataset
):"""加載數據的類"""def __init__(self
, img_dir
, data_set_path
):self
.img_dir
= img_dirself
.label_path
= data_set_pathimg_names
= pd
.read_csv
(data_set_path
, header
=None, usecols
=[0])img_labels
= pd
.read_csv
(data_set_path
, header
=None, usecols
=[1])self
.img_names
= np
.array
(img_names
)[:, 0]self
.img_labels
= np
.array
(img_labels
)[:, 0]def __getitem__(self
, index
) -> T_co
:img_path
= self
.img_dir
+ '/' + self
.img_names
[index
]img
= cv
.imread
(img_path
)img
= cv
.cvtColor
(img
, cv
.COLOR_BGR2GRAY
)img
= cv
.equalizeHist
(img
)img
= img
.reshape
((1, 48, 48)) / 255.0img_torch
= torch
.from_numpy
(img
).type('torch.FloatTensor')label
= self
.img_labels
[index
]return img_torch
, label
def __len__(self
):return self
.img_names
.shape
[0]def gaussian_weights_init(m
):"""參數初始化,采用高斯分布"""classname
= m
.__class__
.__name__
if classname
.find
('Conv') != -1:m
.weight
.data
.normal_
(0.0, 0.04)def validate(model
, dataset
, batch_size
):"""驗證模型在驗證集上的正確率"""val_loader
= data
.DataLoader
(dataset
, batch_size
)result
, num
= 0.0, 0for images
, labels
in val_loader
:pred
= model
.forward
(images
)pred
= np
.argmax
(pred
.data
.numpy
(), axis
=1)labels
= labels
.data
.numpy
()result
+= np
.sum((pred
== labels
))num
+= len(images
)acc
= result
/ num
return acc
class FaceCNN(nn
.Module
):"""CNN神經網絡"""def __init__(self
):super().__init__
()self
.conv1
= nn
.Sequential
(nn
.Conv2d
(in_channels
=1, out_channels
=64, kernel_size
=3, stride
=1, padding
=1), nn
.BatchNorm2d
(num_features
=64), nn
.RReLU
(inplace
=True), nn
.MaxPool2d
(kernel_size
=2, stride
=2), )self
.conv2
= nn
.Sequential
(nn
.Conv2d
(in_channels
=64, out_channels
=128, kernel_size
=3, stride
=1, padding
=1),nn
.BatchNorm2d
(num_features
=128),nn
.RReLU
(inplace
=True),nn
.MaxPool2d
(kernel_size
=2, stride
=2),)self
.conv3
= nn
.Sequential
(nn
.Conv2d
(in_channels
=128, out_channels
=256, kernel_size
=3, stride
=1, padding
=1),nn
.BatchNorm2d
(num_features
=256),nn
.RReLU
(inplace
=True),nn
.MaxPool2d
(kernel_size
=2, stride
=2),)self
.conv1
.apply(gaussian_weights_init
)self
.conv2
.apply(gaussian_weights_init
)self
.conv3
.apply(gaussian_weights_init
)self
.fc
= nn
.Sequential
(nn
.Dropout
(p
=0.2),nn
.Linear
(in_features
=256 * 6 * 6, out_features
=4096),nn
.RReLU
(inplace
=True),nn
.Dropout
(p
=0.5),nn
.Linear
(in_features
=4096, out_features
=1024),nn
.RReLU
(inplace
=True),nn
.Linear
(in_features
=1024, out_features
=256),nn
.RReLU
(inplace
=True),nn
.Linear
(in_features
=256, out_features
=7),)def forward(self
, x
):"""前向傳播"""x
= self
.conv1
(x
)x
= self
.conv2
(x
)x
= self
.conv3
(x
)x
= x
.view
(x
.shape
[0], -1)y
= self
.fc
(x
)return y
def train(lr
=0.01, weight_decay
=0, batch_size
=128, epochs
=100):"""訓練模型"""train_data_set
= FaceDateset
('train_data', 'train_data_set.csv')val_data_set
= FaceDateset
('val_data', 'val_data_set.csv')train_loader
= data
.DataLoader
(train_data_set
, batch_size
)model
= FaceCNN
()loss_fun
= nn
.CrossEntropyLoss
()optimizer
= optim
.Adam
(model
.parameters
(), lr
=lr
, weight_decay
=weight_decay
)loss_log
= open('loss_log.txt', 'w')acc_log
= open('acc_log.txt', 'w')for epoch
in range(epochs
):print('第{}輪訓練開始'.format(epoch
))loss_rate
= 0model
.train
()for images
, labels
in train_loader
:optimizer
.zero_grad
()out_put
= model
.forward
(images
)loss_rate
= loss_fun
(out_put
, labels
)loss_rate
.backward
()optimizer
.step
()loss_log
.write
('{}\n'.format(loss_rate
.item
()))loss_log
.flush
()print('第{}輪損失值為:{}'.format(epoch
, loss_rate
.item
()))if epoch
% 5 == 0:acc
= validate
(model
, val_data_set
, batch_size
)print('第{}輪正確率為:{}'.format(epoch
, acc
))acc_log
.write
('{}, {}\n'.format(epoch
, acc
))acc_log
.flush
()torch
.save
(model
, './models/train_{}.pkl'.format(epoch
))loss_log
.close
()acc_log
.close
()if __name__
== '__main__':train
()
文件名show_log.py
"""
可視化結果
"""
import matplotlib
.pyplot
as plt
import numpy
as np
def cvt_file2np(log_file_path
):"""讀取log文件并轉化為np數組"""log
= np
.genfromtxt
(log_file_path
, delimiter
=',')if log
.ndim
!= 1:x
= np
.array
(log
[:, 0])y
= np
.array
(log
[:, 1])else:length
= log
.shape
[0]x
= np
.arange
(0, length
)y
= log
return [x
, y
]acc_data
= cvt_file2np
('acc_log.txt')
loss_data
= cvt_file2np
('loss_log.txt')
loss_data
[1] = loss_data
[1] + 0.0000001
loss_data
[1] = np
.log10
(loss_data
[1])plt
.subplot
(121)
plt
.plot
(acc_data
[0], acc_data
[1])
plt
.title
('acc')
plt
.xlabel
('epoch')
plt
.ylabel
('acc')plt
.subplot
(122)
plt
.plot
(loss_data
[0], loss_data
[1])
plt
.title
('log10(loss)')
plt
.xlabel
('iteration')
plt
.ylabel
('log10(loss)')
plt
.show
()
2.使用方法
首先運行train_model.py文件訓練模型,這里采用的是cup運算,非常花費時間。
運行完成后模型會保存到根目錄的models文件夾下,每訓練5個epoch保存一次。
訓練完成后,運行show_log.py將訓練結果可視化,例如:
不難看出,訓練到第35輪時正確率最高,之后數據發生了過擬合,正確率開始下降。
四、實時識別
使用opencv來打開攝像頭,實現對圖像中人臉的實時識別
(由于課設中不需要使用gui顯示圖像,所以設置了一個變量gui_open來控制是否顯示gui)
代碼如下:
文件名:my_face.py
"""
表情識別
"""
import cv2
as cv
import dlib
import numpy
as np
import torch
from train_model
import FaceCNN
from my_utils
import get_face_target
, labels
, soft_max
, cvt_R2N
import warnings
warnings
.filterwarnings
("ignore")class EmotionIdentify:"""用于表情識別的類"""def __init__(self
, gui_open
=False):self
.detector
= dlib
.get_frontal_face_detector
()self
.model
= FaceCNN
()self
.model
.load_state_dict
(torch
.load
('./models/train_35.pkl').state_dict
())self
.cap
= cv
.VideoCapture
(0)self
.cap
.set(3, 480)self
.img
= Noneself
.gui_open
= gui_open
def get_img_and_predict(self
):"""表情識別:return:(img, emotion)"""gray_img
, left_top
, right_bottom
, result
= None, None, None, Noneif self
.cap
.isOpened
():flag
, img
= self
.cap
.read
()self
.img
= imgimg_gray
= cv
.cvtColor
(img
, cv
.COLOR_RGB2GRAY
)faces
= self
.detector
(img_gray
, 0)if len(faces
) > 0:face
= faces
[0]left_top
= (face
.left
(), face
.top
())right_bottom
= (face
.right
(), face
.bottom
())gray_img
= cv
.cvtColor
(img
, cv
.COLOR_BGR2GRAY
)gray_img
= get_face_target
(gray_img
, face
)gray_img
= cv
.resize
(gray_img
, (48, 48))target_img
= gray_img
.reshape
((1, 1, 48, 48)) / 255.0img_torch
= torch
.from_numpy
(target_img
).type('torch.FloatTensor')result
= self
.model
(img_torch
).detach
().numpy
()result
= soft_max
(result
)if self
.gui_open
:self
.show
(gray_img
, left_top
, right_bottom
, result
)return self
.img
, result
raise Exception
('No camera')def show(self
, gray_img
, left_top
, right_bottom
, result
):"""顯示圖像"""show_img
= self
.img
if gray_img
is not None:cv
.imshow
('gray_img', gray_img
)color
= (255, 34, 78)cv
.rectangle
(show_img
, left_top
, right_bottom
, color
, 2)emotion
= labels
[np
.argmax
(result
)]cv
.putText
(show_img
, emotion
, left_top
, 0, 2, color
, 2)cv
.imshow
('cv', show_img
)cv
.waitKey
(20)def my_test():ed
= EmotionIdentify
(gui_open
=True)flag
= Truewhile flag
is not None:flag
= ed
.get_img_and_predict
()cv
.waitKey
(10)result
= flag
[1]print(cvt_R2N
(result
))if __name__
== '__main__':my_test
()
依賴工具my_utils.py
"""
使用的工具
"""
import numpy
as nplabels
= {0: 'angry', 1: 'disgust', 2: 'fear', 3: 'happy',4: 'sad', 5: 'surprise', 6: 'neutral'}def get_face_target(gray_img
: np
.ndarray
, face
):"""從gray_img中提取面部圖像:param gray_img::param face::return:"""img_size
= gray_img
.shapex1
, y1
, x2
, y2
= face
.left
(), face
.top
(), face
.right
(), face
.bottom
()def reset_point(point
, max_size
):"""重置點的位置:param point: 當前點的坐標:param max_size: 點在坐標軸的上的最大位置:return:"""if point
< 0:point
= 0if point
> max_size
:point
= max_size
- 1return pointx1
= reset_point
(x1
, img_size
[0])x2
= reset_point
(x2
, img_size
[0])y1
= reset_point
(y1
, img_size
[1])y2
= reset_point
(y2
, img_size
[1])return gray_img
[y1
:y2
, x1
:x2
]def soft_max(x
):"""classify"""exp_x
= np
.exp
(x
)sum_x
= np
.sum(exp_x
)y
= exp_x
/ sum_x
return y
def cvt_R2N(result
):"""將神經網絡預測的結果轉化為0-100的數值"""if result
is None:return 80cvt_M
= [70, 20, 60, 100, 10, 90, 80]cvt_M
= np
.array
(cvt_M
)level
= np
.sum(cvt_M
* result
)return level
結果如下:
注:cvt_R2N()函數該項目用不到
總結
該項目的項目樹如下
- data_classfy.py
- my_face.py
- my_utils.py
- show_log.py
- train.csv
- train_model.py
總結
以上是生活随笔為你收集整理的深度学习项目,使用python进行表情识别,pytorch应用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。