人脸情绪识别模型

意义:通过卷积神经网络(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%
训练完成!
相关推荐
奕鼎竜瑆7 小时前
Solid 前端响应式开发从零到精通
前端·人工智能
YOLO数据集集合7 小时前
无人机桥梁损伤目标检测数据集 | 桥梁损伤 无人机巡检 结构健康监测 多类别检测9135期
人工智能·目标检测·无人机
动恰客流统计7 小时前
景区客流统计怎么做?兼顾管控与运营的实施方案解析
大数据·前端·人工智能
weixin_443883017 小时前
合规整改倒计时:高等级签名证书的应用场景
大数据·人工智能·法大大·法大大电子签·电子合同
魔猴疯猿7 小时前
从0到1用Python开发第一个智能体
人工智能·python·深度学习·神经网络·机器学习
天一生水water8 小时前
变分模态分解(VMD)的教程
人工智能
荆棘鸟智能8 小时前
林业遥感长势评估怎么做?从NDVI时序分析到LiDAR蓄积量回归
人工智能·算法·智慧林业
代码方舟8 小时前
数据科学风控实战:基于天远全能消金报告构建自动化信用评估网关
运维·人工智能·自动化
Yan-英杰8 小时前
2026年数据采集服务怎么选?4大主流平台(亮数据 Bright Data、Apify、ScrapingBee、Zyte)深度对比
人工智能·神经网络·microsoft·机器学习·ai开发工具