人脸情绪识别模型

意义:通过卷积神经网络(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%
训练完成!
相关推荐
嘉行文1 分钟前
传统机器学习与深度学习的特点与选择
人工智能·深度学习·机器学习
咕泡科技2 分钟前
深度学习碾压机器学习?经典机器学习是否真的无用了?从LLM底层逻辑到工业落地全景解析
人工智能·深度学习·机器学习·llm·nlp
饼饼学习空间智能8 分钟前
机器人规模化部署平台怎么选?Fleet、VDA 5050、多机器人调度与运营闭环解析
大数据·深度学习·机器学习
HealthScience9 分钟前
彻底禁止 WSL 启动(可恢复)
深度学习
腾讯云大数据11 分钟前
腾讯云AI Native数据平台功能发布合集【9月】
人工智能·腾讯云
谢客诚科技17 分钟前
镀膜脆性薄片,不能接触镀膜面,脆性薄片搬运选伯努利还是边缘承靠式末端模组?
人工智能·机器人
我喜欢就喜欢18 分钟前
纳米 AI 搜索实战应用场景指南
人工智能
GlobalInfo23 分钟前
上新 | 全球及中国反无人机综合防御系统行业研究报告(2026版):市场现状、行业前景与占有率分析
人工智能·无人机
9i编程23 分钟前
6. 带 AI 从零搭低代码平台·踩坑实录:实测与大回归,实操又跑偏逐条清零
人工智能·openai·ai编程