机器学习实战——python + pytorch实现面部表情识别

简介

最近刚好学习了pytorch,于是想写写项目,而这个项目的最开始是使用kerasTensorFlow,我在这篇blog中使用pytorch

项目原文链接 Emojify - Create your own emoji with Deep Learning

数据集与代码

下面是百度网盘分享的数据集(FER2013,在data文件夹中)和代码(moduel.py为神经网络模型,model.ipynb用于训练并保存模型, main.py使用创建窗口,利用模型进行表情识别),emojis文件夹是显示映射后的表情的图片

分享链接

当然原项目链接也有数据集及代码链接(keras版本)

简单解释代码

model.ipynb

使用jupyter notebook打开

1. 加载数据集
  • train_path与test_path需要安装自己数据集路径设置(如果不知道工作路径,可以使用绝对路径)

  • transforms_train的第2,3行用于加强数据

  • transforms.RandomHorizontaiFlip()效果如下:

# 下载数据集并加载数据
train_path = "./data/train"
test_path = "./data/test"
transforms_train = transforms.Compose([
    transforms.Grayscale(),#使用ImageFolder默认扩展为三通道,重新变回去就行
    transforms.RandomHorizontalFlip(),#随机水平翻转
    transforms.ColorJitter(brightness=0.5, contrast=0.5),#随机调整亮度和对比度
    transforms.ToTensor()
])
transforms_test = transforms.Compose([
    transforms.Grayscale(),
    transforms.ToTensor()
])

data_train = torchvision.datasets.ImageFolder(root=train_path,transform=transforms_train)
data_test = torchvision.datasets.ImageFolder(root=test_path,transform=transforms_test)

dataload_train = DataLoader(data_train, batch_size=BATCH_SZIE, shuffle=True)
dataload_test = DataLoader(data_test, batch_size=BATCH_SZIE, shuffle=True)

 

2. 网络模型

下面代码中将展示每个阶段的数据的形状

(1, 48, 48):1代表是单通道因为是灰度图片,(48,48)代表图片的大小

nn.Softmax(dim = 1)需要设置参数dim,否则会有warning,dim=1表示按列计算概率,dim = 0代表按行计算(错误的),你可以通过计算出来结果打印查看是否正确。

在jupyter notebook可以查看打印结果

# 测试模型
module_test_data = torch.ones(6, 1, 48, 48)
output = face_recognition_module(module_test_data)
output

 

# 构建模型
class t716(nn.Module): 
    def __init__(self): 
        super().__init__()
        self.module = Sequential(
            # 输入:(1, 48, 48)
            Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1),
            # 输出:(32, 46, 46)
            nn.ReLU(True),
            Conv2d(32, 64, 3),
            # 输入:(64, 44, 44)
            nn.ReLU(), 
            MaxPool2d(2), 
            # 输出:(64, 22, 22)
            Dropout(0.25), 
            
            Conv2d(64, 128, 3), 
            # (128, 20, 20)
            nn.ReLU(),
            MaxPool2d(2), 
            # (128, 10, 10)
            Conv2d(128, 128, 3), 
            # (128, 8, 8)
            nn.ReLU(), 
            MaxPool2d(2), 
            # (128, 4, 4)
            Dropout(0.25), 

            Flatten(),
            # (128 * 4 * 4)
            Linear(2048, 1024), 
            nn.ReLU(), 
            Dropout(0.5), 
            Linear(1024, 7), 
            # dim = 1表示按列计算softmax(这里列为类别)
            nn.Softmax(dim=1)
        )
    def forward(self, data): 
        y = self.module(data)
        return y

3. 模型训练

我设置的部分尝试是这样的

 

# 设置常数
BATCH_SZIE = 6
LR = 0.0001		# 学习率
EPOCH = 50		# 学习轮数

 由于使用的是cpu训练,在这个参数设计写,一共训练了大概20个小时。(如果有独显,可以使用gpu训练)

 

main.py中的一写设置

main.py主要是利用cv2tkinter,实现一个GUI界面,利用模型进行识别,不讲解代码,但是有一些设置需要解释及本人遇到的问题需要解释。

结果展示:

红色框是logo.png加载的位置。

 

问题1

show_vid()函数中的cascade_path为自己下载的文件haarcascade_frontalface_default.xml的路径,你可以根据下面下载链接下载,随便存储在某个文件夹。

下载链接

问题2

show_void()的lmain.after(300, show_vid)与show_vid2的lmain2.after(300, show_vid2)的第一个参数如果填的比较小,那么窗口会打不开,太大打开的窗口延迟比较高,由于没有学过opencv,所以也不知道是为什么?

问题3

main函数中加载的logo.png可以自己随便设置一张。

源码

训练与保存模型部分

 

# 导入相关库
import numpy as np
import torch
import torchvision
import matplotlib.pyplot as plt 
import torch.nn as nn
from torch.nn import Conv2d, Sequential, MaxPool2d, Flatten, Linear, Dropout, Softmax
from torchvision import transforms, datasets
from torch.utils.data import DataLoader

# 设置常数
BATCH_SZIE = 6
LR = 0.0001
EPOCH = 50

# 下载数据集并加载数据
train_path = "./data/train"
test_path = "./data/test"
transforms_train = transforms.Compose([
    transforms.Grayscale(),#使用ImageFolder默认扩展为三通道,重新变回去就行
    transforms.RandomHorizontalFlip(),#随机翻转
    transforms.ColorJitter(brightness=0.5, contrast=0.5),#随机调整亮度和对比度
    transforms.ToTensor()
])
transforms_test = transforms.Compose([
    transforms.Grayscale(),
    transforms.ToTensor()
])

data_train = torchvision.datasets.ImageFolder(root=train_path,transform=transforms_train)
data_test = torchvision.datasets.ImageFolder(root=test_path,transform=transforms_test)

dataload_train = DataLoader(data_train, batch_size=BATCH_SZIE, shuffle=True)
dataload_test = DataLoader(data_test, batch_size=BATCH_SZIE, shuffle=True)

# 查看一下数据集
for data in dataload_train: 
    image, target = data
    break
print(f"图片形状: {image.shape}")
print(f"类别:{data_train.classes}\n取出的为: {target}")
# imshow()对于灰度图片只支持两个维度(m, n),因而需要reshape 
for i in range(1, 7): 
    plt.subplot(4, 4, i) 
    newimage = image[i - 1].reshape((48, 48))
    plt.imshow(newimage, cmap='grey')
    plt.axis('off')
plt.show()

# 构建模型
class t716(nn.Module): 
    def __init__(self): 
        super().__init__()
        self.module = Sequential(
            # 输入:(1, 48, 48)
            Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1),
            # 输出:(32, 46, 46)
            nn.ReLU(True),
            Conv2d(32, 64, 3),
            # 输入:(64, 44, 44)
            nn.ReLU(), 
            MaxPool2d(2), 
            # 输出:(64, 22, 22)
            Dropout(0.25), 
            
            Conv2d(64, 128, 3), 
            # (128, 20, 20)
            nn.ReLU(),
            MaxPool2d(2), 
            # (128, 10, 10)
            Conv2d(128, 128, 3), 
            # (128, 8, 8)
            nn.ReLU(), 
            MaxPool2d(2), 
            # (128, 4, 4)
            Dropout(0.25), 

            Flatten(),
            # (128 * 4 * 4)
            Linear(2048, 1024), 
            nn.ReLU(), 
            Dropout(0.5), 
            Linear(1024, 7), 
            # dim = 1表示按列计算softmax(这里列为类别)
            nn.Softmax(dim=1)
        )
    def forward(self, data): 
        y = self.module(data)
        return y
    
# 创建模型
face_recognition_module = t716()
loss = nn.CrossEntropyLoss()
optim = torch.optim.Adam(face_recognition_module.parameters(), lr=LR)


# 测试模型
module_test_data = torch.ones(6, 1, 48, 48)
output = face_recognition_module(module_test_data)
output

# 训练模型
face_recognition_module.train()
iterator = 0
for epoch in range(EPOCH): 
    print(f'-------第{epoch}轮训练-------')
    for data in dataload_train: 
        iterator += 1
        images, target = data
        output = face_recognition_module(images)
        loss_output = loss(output, target)
        optim.zero_grad()
        loss_output.backward() 
        optim.step()
        if iterator % 500 == 0: 
            print(f"第{iterator}次的损失为: {loss_output}")
            
    
# 模型测试
face_recognition_module.eval()
total_right = 0
with torch.no_grad(): 
    for data in dataload_test: 
        images, targets = data 
        output = face_recognition_module(images)
        right = (output.argmax(1) == targets).sum()
        total_right += right
accuracy = total_right / len(data_test)
print(accuracy)

# 保存模型
torch.save(face_recognition_module.state_dict(), './modules/face_recognition_module_716.pth')

 GUI的代码

# 导入相关的库
import cv2
import torch
import numpy as np
import tkinter as tk
import time
from tkinter import *
from PIL import Image, ImageTk
from moduel import t716


# 加载模型
par = torch.load('./modules/face_recognition_module_716.pth')
face_recognition_module = t716()
face_recognition_module.load_state_dict(par)
print(face_recognition_module)


cv2.ocl.setUseOpenCL(False)    # CPU训练
emotion_dict = {0: "Angry", 1: "Disgusted", 2: "Fearful", 3: "Happy", 4: "Neutral", 5: "Sad", 6: "Surprised"}
emoji_dist={0:"./emojis/angry.png",1:"./emojis/disgusted.png",2:"./emojis/fearful.png",3:"./emojis/happy.png",
            4:"./emojis/neutral.png",5:"./emojis/sad.png",6:"./emojis/surpriced.png"}
global last_frame1                                    
last_frame1 = np.zeros((480, 640, 3), dtype=np.uint8)
global cap1
show_text=[0]

def show_vid():      
    cascade_path = "D:/APP2/anaconda/anaconda/envs/pytorch/Lib/site-packages/cv2/data/haarcascade_frontalface_default.xml"
    cap1 = cv2.VideoCapture(0)
    if not cap1.isOpened():                            
        print("cant open the camera1")
    flag1, frame1 = cap1.read()
    # (500, 600, 3)
    frame1 = cv2.resize(frame1,(600,500))
    bounding_box = cv2.CascadeClassifier(cascade_path)
    gray_frame = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)    # 转变为灰度图片
    num_faces = bounding_box.detectMultiScale(gray_frame,scaleFactor=1.3, minNeighbors=5)
    for (x, y, w, h) in num_faces:
        cv2.rectangle(frame1, (x, y-50), (x+w, y+h+10), (255, 0, 0), 2)
        roi_gray_frame = gray_frame[y:y + h, x:x + w]
        cropped_img = np.expand_dims(np.expand_dims(cv2.resize(roi_gray_frame, (48, 48)), 0), 0)
        cropped_img = torch.tensor(cropped_img).to(torch.float32)
        
        with torch.no_grad():
            prediction = face_recognition_module(cropped_img)
        
        maxindex = int(np.argmax(prediction))
        cv2.putText(frame1, emotion_dict[maxindex], (x+20, y-60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)
        show_text[0]=maxindex
    
    if flag1 is None:
        print ("Major error!")
    elif flag1:
        global last_frame1
        global lmain
        last_frame1 = frame1.copy()
        pic = cv2.cvtColor(last_frame1, cv2.COLOR_BGR2RGB)     
        img = Image.fromarray(pic)
        imgtk = ImageTk.PhotoImage(image=img)
        lmain.imgtk = imgtk
        lmain.configure(image=imgtk)
        lmain.after(300, show_vid)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        exit()
    return


def show_vid2():
    global lmain2, lmain3
    frame2=cv2.imread(emoji_dist[show_text[0]])
    pic2=cv2.cvtColor(frame2,cv2.COLOR_BGR2RGB)
    img2=Image.fromarray(frame2)
    imgtk2=ImageTk.PhotoImage(image=img2)
    lmain2.imgtk2=imgtk2
    lmain3.configure(text=emotion_dict[show_text[0]],font=('arial',45,'bold'))
    
    lmain2.configure(image=imgtk2)
    lmain2.after(300, show_vid2)
    
if __name__ == '__main__':
    root=tk.Tk()   
    img = ImageTk.PhotoImage(Image.open("logo.png"))
    heading = Label(root,image=img,bg='black')
    heading.pack() 
    heading2=Label(root,text="Photo to Emoji",pady=20, font=('arial',45,'bold'),bg='black',fg='#CDCDCD')                                 
    heading2.pack()
    
    lmain = tk.Label(master=root,padx=50,bd=10)
    lmain2 = tk.Label(master=root,bd=10)
    lmain3=tk.Label(master=root,bd=10,fg="#CDCDCD",bg='black')
    #lmain.pack(side=LEFT)
    lmain.place(x=50,y=250)
    #lmain3.pack()
    lmain3.place(x=960,y=250)
    #lmain2.pack(side=RIGHT)
    lmain2.place(x=900,y=350)
    
    root.title("Photo To Emoji")            
    root.geometry("1400x900+100+10") 
    root['bg']='black'
    exitbutton = Button(root, text='Quit',fg="red",command=root.destroy,font=('arial',25,'bold'))
    exitbutton.pack(side = BOTTOM)
    show_vid()
    show_vid2()
    root.mainloop()

### 回答1: PythonPyTorch是用于语音识别的两个重要工具。Python是一种高级编程语言,具有易学易用、灵活多变、开源免费等优点,被广泛应用于人工智能、机器学习等领域。PyTorch是一个基于Python的科学计算库,主要用于深度学习和神经网络的构建和训练。在语音识别领域,PythonPyTorch可以结合使用,通过搭建深度学习模型实现语音识别任务。 ### 回答2: PythonPyTorch语音识别是一种基于深度学习和人工智能技术的语音识别方法,它能够将人类语音转换为文本数据。这种技术已经得到了广泛的应用,应用领域涵盖语音识别系统、自动翻译、智能交互等多个领域。 Python语言是一种简单易用、高效性能和广泛应用的编程语言。它的优点是语法简洁,可读性强,支持面向对象和函数式编程,同时还有完善的第三方库和工具支持。这使得Python成为了开发深度学习技术的首选语言之一。 PyTorch是Facebook推出的深度学习框架之一,它具有易于使用、灵活和可扩展性强等特点。PyTorch提供了一系列用于实现深度学习模型的API,并且支持自定义开发,这使得PyTorch成为了深度学习开发者的首选框架之一。 在语音识别方面,PythonPyTorch可以有效结合,通过PyTorch的API可以实现深度学习模型的开发,而Python的第三方库和工具可以对语音识别系统进行扩展和应用。 总的来说,PythonPyTorch结合的语音识别系统具有模型灵活、易于使用、丰富的应用场景等特点。因此,这种技术有望成为未来语音识别系统发展的一大趋势,将得到越来越广泛的应用。 ### 回答3: Python pytorch语音识别是一项基于深度学习算法的语音识别技术。在实现语音识别的过程中,pytorch是一个很好的选择,因为它提供了简单、灵活、可扩展的框架,且易于使用。 pytorch语音识别的基础是声音的数学表示,即将声音信号转化为数字信号。它是基于一种神经网络的深度学习算法,通过多次训练,在大量数据上进行权重调整,最终实现从声音信号到语音文本的转换。 在pytorch框架下,通常使用的语音识别模型是CTC、Attention和Transformer。其中,CTC模型是传统的深度学习模型,通过输出每个音素的概率,使用贝叶斯公式对音素序列进行解码;Attention模型是针对CTC模型的改进,更加关注每个时间步的输入,因此在语音识别中表现更加出色;而Transformer模型是一种新兴的模型,可以获得更好的性能和更短的训练时间。 此外,在pytorch语音识别中,常用的数据集是Librispeech、Common Voice、TED-LIUM和Aurora-4等。这些数据集提供了一系列简单到复杂的语音识别任务,可供研究者和开发人员进行模型优化和性能测试。 总的来说,Python pytorch语音识别是一项高效、准确、可扩展的语音识别技术,可以在多种应用场景中得到广泛应用,如电子助手、智能客服、语音翻译等。随着深度学习技术的不断发展和优化,相信pytorch语音识别模型将会在未来的语音识别领域中发挥越来越重要的作用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Febu4

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值