
導 論 :Hello 各位小伙伴,今天給大家帶來零基礎入門深度學習第一個小專案—情緒識別,本訂閱號作為科普類的公眾號,目的就是科普人工智能,無論什么專業只需要掌握了高中數學基礎與簡單編程就能入門人工智能,好了,接下來開始我們今天的第一個小專案—計算機視覺之情緒檢測,
本小專案是非常經典的,會了這個專案也就掌握了卷積神經網路的使用,之后自己舉一反三也就會人臉口罩識別、性別識別、動物識別、手寫數字識別、手寫字母識別、車牌識別等等各種圖片的識別,所以本期第一個小專案是非常重要的,后期還會給大家介紹生成對抗網路、時間序列網路、強化學習等各種有趣的專案,
本期需要預先掌握的知識有Python程式設計、Pytorch深度學習框架基礎,電腦需要安裝Python3.6/3.7、pytorch,電腦有NVIDIA顯卡最好,沒有的話也可以使用CPU進行訓練,
目前的流行的人工智能實作基本上都是基于深度學習的模型,往往是模型越大(引數就越多)其能力越大,例如自然語言處理領域的GPT-3模型多達1750億個引數,這類超大模型只可遠觀不可褻玩焉,甚至我們把訓練好的GPT-3(350多G)下載下來也無法運行,這類模型往往功能非常強大,例如可以作詞作詩、翻譯、對對聯等等,但是這些大模型也同樣經不起圖靈測驗(人類和它互動很容易發現它就是機器人),有興趣的同學可以去試玩百度的文心大模型(https://wenxin .baidu.com/wenxin/ernie-vilg),該模型引數超過2000億,如下面圖1是通過詩句機器自動作畫的應用,

其實實作一些功能并不需要如此龐大的神經網路,一些具體的問題其實只需要很小的網路就可以完成,什么是人工神經網路?這里讀者需要知道神經網路的概念,其實神經網路就是一個能夠擬合任何函式的一個函式,神經網路就是一個function,那么我們需要做的就是通過訓練集找到能夠識別情緒圖片的神經網路引數,目前如果對神經網路及其優化還不了解的小伙伴可以將神經網路理解為一個魔法盒,我們只需要告訴盒子哪些圖片是悲傷的,哪些圖片是快樂的,哪些圖片是驚訝的,哪些圖片是憤怒的就可以,這些圖片我們稱之為訓練集,當網路模型學完訓練集后就基本知道快樂、悲傷等的表情大概具有什么樣的特征,之后我們給一張網路模型從未見過的情緒圖片給它,它依然可以做到準確識別,如果想具體了解理論的小伙伴可以等我后期出關于理論部分的介紹后再閱讀,
情緒檢測
情緒檢測或表情分類在深度學習領域中有著廣泛的研究,使用電腦攝像頭和一些簡單的代碼我們就可以對情緒進行實時分類, 需要預先掌握的知識:
? Python基礎
? OpenCV基礎
? 卷積神經網路(CNN)
? pytorch基礎
訓練集: 本文共使用28000張人臉情緒圖片作為訓練樣本,類別分為憤怒、害怕、高興、正常、悲傷、驚訝6個類,
測驗集: 本文共使用3500張人臉情緒圖片作為測驗樣本,用來測驗神經網路模型的效果,
該資料集屬于公開資料集,約3w張分好類的人臉灰度圖,其資料類別分布不均衡,所以對于某些類別的預測不準確,資料集公眾號回復:emotion_data 即可下載


定義網路模型
本文使用卷積神經網路,代碼如下:
# 定義卷積神經網路,這里使用5層的神經網路
import torch
import torch.nn as nn
class CNN5(nn.Module):
def __init__(self):
super(CNN5, self).__init__()
self.conv1 = nn.Conv2d(1, 64, kernel_size=(3, 3),padding=1)
self.relu = nn.ReLU()
self.maxpool1 = nn.MaxPool2d(kernel_size=(2, 2) )
self.conv2 = nn.Conv2d(64, 256, kernel_size=(3, 3))
self.maxpool2 = nn.MaxPool2d(kernel_size=(2, 2) )
self.fc1 = nn.Linear(256*7*7, 4096)
self.fc2 = nn.Linear(4096, 1024)
self.fc3 = nn.Linear(1024, 6)
def forward(self, img):
output = self.conv1(img)
output = self.relu(output)
output = self.maxpool1(output)
output = self.conv2(output)
output = self.relu(output)
output = self.maxpool2(output)
feature = output.view(-1, 256*7*7)
output = self.fc1(feature)
output = self.relu(output)
output = self.fc2(output)
output = self.relu(output)
output = self.fc3(output)
return output
讀取資料集
定義好了卷積網路接著需要讀取檔案夾中的訓練資料集,并進行資料增強、歸一化等操作,代碼如下:
def get_emotion_data(args):
#args引數封裝,理解為引數字典
train_loader = torch.utils.data.DataLoader(
datasets.ImageFolder(args.data_root+'train',
transform=transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Grayscale(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=args.batch_size, shuffle=True, num_workers=2)
test_loader = torch.utils.data.DataLoader(
datasets..ImageFolder(args.data_root+'validation',
transform=transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Grayscale(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=args.batch_size, shuffle=True, num_workers=2)
return train_loader , test_loader
訓練方法
def my_train(args, model, device, train_loader, optimizer, epoch):
model.train()
for idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.cross_entropy(output, target)
loss.backward()
optimizer.step()
if (idx+1) % 20 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, idx * len(data), len(train_loader.dataset),
100. * idx / len(train_loader), loss.item()))
測驗方法
def my_test(args, model, device, test_loader, cur_epoch):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.cross_entropy(output, target, reduction='sum').item() # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nEpoch {} Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.4f}%)'.format(
cur_epoch, test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
return correct/len(test_loader.dataset)
main方法
if __name__ == '__main__':
#封裝引數
parser = argparse.ArgumentParser()
parser.add_argument('--data_root', type=str, default='Q:\cache\emotion\\')
parser.add_argument('--batch_size', type=int, default=128, metavar='N',
help='input batch size for training (default: 64)')
parser.add_argument('--lr', type=float, default=0.1, metavar='LR',
help='learning rate (default: 0.1)')
parser.add_argument('--weight_decay', type=float, default=5e-4)
parser.add_argument('--epochs',type=int,default=30)
parser.add_argument('--momentum', type=float, default=0.9, metavar='M',
help='SGD momentum (default: 0.9)')
args = parser.parse_args()
device = "cuda" if torch.cuda.is_available() else "cpu"
print('運行在{}上...'.format(device))
#實體化模型
model = LeNet5().to(device)
#定義優化器
optimizer = optim.SGD(model.parameters(), lr=args.lr, weight_decay=args.weight_decay, momentum=args.momentum)
#加載資料
train_loader,test_loader = get_emotion_data(args)
best_acc=0
for epoch in range(1, args.epochs + 1):
my_train(args, model, device, train_loader, optimizer, epoch)
acc = my_test(args, model, device, test_loader, epoch)
if acc>best_acc:
best_acc = acc
torch.save(model.state_dict(),"models/emotion.ckpt")
print("Best Acc=%.6f"%best_acc)
本文默認運行30個epoch,最后保存準確率最高為52.8%的模型,完整代碼關注本公眾號回復:"情緒檢測代碼"即可獲得完整原始碼,這個準確率其實一言難盡,目前使用ResNet網路來訓練準確率也只有60%左右,因為這個資料集的自身分類誤差就很大,加之資料類別不均衡等原因導致識別難度大,這依舊是具有挑戰性的研究,在CVPR、Kaggle等比賽中,人臉情緒識別依舊很火熱,本文作為入門實驗在這里不做深入探究,
使用表情檢測模型
當我們訓練完識別模型后我們可以用來檢測視頻中的人物表情或者攝像頭拍攝到的人物表情,這里基于OpenCV來實作,其實我們用來訓練的是人臉,所以首先我們需要檢測出人臉,我們當然可以訓練一個神經網路用來檢測人臉,但是本期介紹主要介紹圖片分類,所以檢測人臉我們直接呼叫OpenCV的模型,OpenCV自帶的人臉檢測表現的非常糟糕,有興趣的小伙伴有手就行可以輕松訓練人臉檢測的網路輕輕松松超越OpenCV自帶的模型,該部分代碼獲取公眾號回復"情緒檢測"即可獲取!
公眾號:矩陣科學

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/416166.html
標籤:AI
上一篇:pandas資料預處理(欄位篩選、query函式進行資料篩選、缺失值洗掉)、seaborn使用Catplot函式可視化基本箱圖(Boxplot with Seaborn Catplot)
