人脸情绪识别模型

意义:通过卷积神经网络(CNN)自动识别图片中的人脸表情属于哪一类情绪

1. 模型的用途

  • 输入:一张人脸图片(RGB三通道,尺寸通常为48×48或类似)
  • 输出:7种情绪类别的概率分布
  • 情绪类别 (通常): 0. 愤怒 (Angry)
    1. 厌恶 (Disgust)
    2. 恐惧 (Fear)
    3. 开心 (Happy)
    4. 悲伤 (Sad)
    5. 惊讶 (Surprise)
    6. 中性 (Neutral)

2. 模型架构逻辑

输入: 3通道图像 (宽×高)

→ 卷积层1 (32个特征图) → 池化

→ 卷积层2 (64个特征图) → 池化

→ 卷积层3 (128个特征图) → 池化

→ 展平

→ 全连接层1 (100个神经元)

→ 全连接层2 (7个神经元 → 输出7种类别)

复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
class MoodCNN(nn.Module):
    def __init__(self, input_size=48, num_classes=7):
        super(MoodCNN,self).__init__()
         # 保存参数
        self.input_size = input_size
        self.num_classes = num_classes
         # 卷积层
        self.conv1 = nn.Conv2d(3, 32, stride=1, kernel_size=3, padding=1)  # 添加padding保持尺寸
        self.bn1 = nn.BatchNorm2d(32)
        self.conv2 = nn.Conv2d(32, 64, stride=1, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(64)
        self.conv3 = nn.Conv2d(64, 128, stride=1, kernel_size=3, padding=1)
        self.bn3 = nn.BatchNorm2d(128)
        # 池化层
        self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.dropout = nn.Dropout(0.5)
         # 计算全连接层输入维度
        # 输入48×48 → conv(48) → pool(24) → conv(24) → pool(12) → conv(12) → pool(6)
        conv_output_size = input_size // 8
        self.fc_input_size = 128 * 6 * 6
        # 全连接层
        self.fc1 = nn.Linear(self.fc_input_size, 256)
        self.fc2 = nn.Linear(256, num_classes)
    def forward(self,x):
        # 第一层:卷积+BN+ReLU+池化
        x = self.maxpool(F.relu(self.bn1(self.conv1(x))))  # 48→24
        
        # 第二层
        x = self.maxpool(F.relu(self.bn2(self.conv2(x))))  # 24→12
        
        # 第三层
        x = self.maxpool(F.relu(self.bn3(self.conv3(x))))  # 12→6
        
        # 展平
        x=x.view(-1,128*6*6)
        # 全连接层
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x
def test_model():
    """测试模型结构和维度"""
    # 创建模型
    model = MoodCNN(input_size=48)
    
    # 打印模型结构
    print("=" * 50)
    print("模型结构:")
    print(model)
    print("=" * 50)
    
    # 测试前向传播
    batch_size = 8
    test_input = torch.randn(batch_size, 3, 48, 48)
    
    # 前向传播
    output = model(test_input)
    print(f"输入尺寸: {test_input.shape}")
    print(f"输出尺寸: {output.shape}")
    
    # 验证输出维度
    assert output.shape == (batch_size, 7), f"输出维度错误: {output.shape}"
    
    # 统计参数
    total_params = sum(p.numel() for p in model.parameters())
    trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
    print(f"\n总参数量: {total_params:,}")
    print(f"可训练参数量: {trainable_params:,}")
    
    # 测试训练流程
    print("\n" + "=" * 50)
    print("测试训练循环...")
    
    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
    # 模拟一步训练
    labels = torch.randint(0, 7, (batch_size,))
    loss = criterion(output, labels)
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    print(f"训练损失: {loss.item():.4f}")
    print("训练测试通过!")
    print("=" * 50)
    
    return model
def inference_example():
    """推理示例"""
    model = MoodCNN()
    model.eval()  # 切换到评估模式
    
    # 模拟单张图像推理
    with torch.no_grad():
        single_image = torch.randn(1, 3, 48, 48)
        logits = model(single_image)
        probabilities = torch.softmax(logits, dim=1)
        predicted_class = torch.argmax(probabilities, dim=1)
        
        print(f"预测结果: 第{predicted_class.item()}类")
        print(f"各类概率: {probabilities.squeeze().tolist()}")
def train_example():
    """完整的训练示例"""
    # 创建模型
    model = MoodCNN()
    
    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
    
    # 模拟数据
    batch_size = 32
    train_data = torch.randn(1000, 3, 48, 48)
    train_labels = torch.randint(0, 7, (1000,))
    
    dataset = TensorDataset(train_data, train_labels)
    dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
    
    # 训练循环
    num_epochs = 5
    for epoch in range(num_epochs):
        running_loss = 0.0
        correct = 0
        total = 0
        
        for batch_idx, (inputs, targets) in enumerate(dataloader):
            # 前向传播
            outputs = model(inputs)
            loss = criterion(outputs, targets)
            
            # 反向传播
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            # 统计准确率
            _, predicted = torch.max(outputs, 1)
            total += targets.size(0)
            correct += (predicted == targets).sum().item()
            running_loss += loss.item()
            
        # 调整学习率
        scheduler.step()
        
        # 打印统计信息
        avg_loss = running_loss / len(dataloader)
        accuracy = 100 * correct / total
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {avg_loss:.4f}, Accuracy: {accuracy:.2f}%')
    
    return model
if __name__ == "__main__":
    print("1️⃣ 测试模型结构")
    model = test_model()
    
    print("\n2️⃣ 推理示例")
    inference_example()
    
    print("\n3️⃣ 完整训练示例")
    print("开始训练(使用模拟数据)...")
    trained_model = train_example()
    print("训练完成!")

测试结果:

复制代码
1️⃣ 测试模型结构
==================================================
模型结构:
MoodCNN(
  (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True)
  (conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True)
  (conv3): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (bn3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, bias=True, track_running_stats=True)
  (maxpool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (dropout): Dropout(p=0.5, inplace=False)
  (fc1): Linear(in_features=4608, out_features=256, bias=True)
  (fc2): Linear(in_features=256, out_features=7, bias=True)
)
==================================================
输入尺寸: torch.Size([8, 3, 48, 48])
输出尺寸: torch.Size([8, 7])

总参数量: 1,275,399
可训练参数量: 1,275,399

==================================================
测试训练循环...
训练损失: 2.0871
训练测试通过!
==================================================

2️⃣ 推理示例
预测结果: 第4类
各类概率: [0.15108568966388702, 0.13161693513393402, 0.1429980993270874, 0.13378497958183289, 0.15436622500419617, 0.14441630244255066, 0.14173167943954468]

3️⃣ 完整训练示例
开始训练(使用模拟数据)...
Epoch [1/5], Loss: 2.6241, Accuracy: 14.90%
Epoch [2/5], Loss: 1.9481, Accuracy: 13.00%
Epoch [3/5], Loss: 1.9470, Accuracy: 11.50%
Epoch [4/5], Loss: 1.9454, Accuracy: 14.50%
Epoch [5/5], Loss: 1.9449, Accuracy: 14.20%
训练完成!
相关推荐
thesky1234561 小时前
27届大模型岗面试准备(十四):多模态大模型 VLM——从视觉编码器到多模态推理的完整链路
人工智能·ai·大模型
一根数据线1 小时前
BIM建模效率低?试试和AI工具配合使用
人工智能·ai·3d建模·3d模型·bim·ai建模·造形家
怕浪猫2 小时前
2840亿参数只卖白菜价:DeepSeek V4 Flash 正式版上线,Agent 能力暴涨6倍
人工智能·算法
不爱记笔记2 小时前
多模态AI如何理解视频内容?从视觉、语音到语义的三层技术拆解
人工智能·自然语言处理·nlp·音视频·多模态
让学习成为一种生活方式2 小时前
苄基异喹啉生物碱糖基转移酶UGT74AN1晶体--Journal of Agricultural and Food Chemistry
人工智能·算法
犀利豆2 小时前
Claude code tools 研究系列(二)EnterPlanMode
人工智能·后端
sponge'2 小时前
《以场景为中心的无监督视频全景分割》论文框架讲解
人工智能·深度学习
陕西企来客2 小时前
2026年7月西安GEO优化哪家好?实战对比评估
人工智能·西安geo优化哪家好
LXT7122 小时前
2026职称申报冲刺期:ChatGPT、Claude、Kimi、雷小兔同题横评
人工智能·chatgpt
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章98-频域滤波
图像处理·人工智能·opencv·计算机视觉