如何让 AI Agent Harness Engineering 具备情绪理解与人机交互能力
如何让 AI Agent Harness Engineering 具备情绪理解与人机交互能力
一、 引言
钩子:当AI遇到"情绪"这个难题
你是否有过这样的经历:在与智能客服对话时,无论你多么焦急或沮丧,它总是用一成不变的语气回复"请您稍等"或"感谢您的理解";或者你使用的AI助手完全无法察觉你已经疲惫不堪,依然在滔滔不绝地提供信息?这些场景暴露了当前AI系统的一个核心局限性:它们缺乏对人类情绪的理解能力,也无法据此调整交互方式。
在电影《她》(Her)中,主人公西奥多与操作系统OS1萨曼莎发展出一段特殊的感情。萨曼莎不仅能够理解西奥多的情绪变化,还能以共情的方式回应,甚至展现出自己的"个性"。虽然这只是科幻电影中的场景,但它描绘了我们对未来人机交互的憧憬:AI系统不仅是工具,更是能够理解、共情并与人类建立情感连接的伙伴。
定义问题/阐述背景:为什么情绪理解对AI Agent至关重要
在当今技术发展的浪潮中,AI Agent(智能代理)正从实验室走向现实应用,从简单的问答助手演变为能够执行复杂任务的自主系统。Gartner预测,到2025年,超过50%的知识工作者将使用AI Agent作为日常工作的一部分。然而,随着AI Agent越来越多地融入我们的生活和工作,一个关键问题日益凸显:如何让这些智能系统更好地理解人类用户,并与之进行自然、流畅、富有情感的交互?
传统的AI系统主要关注任务完成的效率和准确性,往往忽略了交互过程中的情感维度。但人类沟通中,情绪信息占据了重要位置——研究表明,在面对面交流中,情绪传达占总信息量的55%(通过肢体语言)和38%(通过语调),而言语内容仅占7%。这意味着,如果AI Agent无法理解和回应人类的情绪,它将错失大部分沟通信息,导致交互体验生硬、低效甚至令人沮丧。
情绪理解与人机交互能力的缺失,已经成为制约AI Agent进一步发展和普及的瓶颈。无论是客户服务、教育辅导、医疗陪护还是个人助手,能够感知、理解和适应用户情绪的AI Agent,都将提供更优质的服务体验,建立更牢固的用户信任。
亮明观点/文章目标:构建有"温度"的AI Agent
本文将带你深入探索如何通过Harness Engineering(控制工程)的方法论,为AI Agent赋予情绪理解与人机交互能力。我们不仅会讨论理论基础,还将通过实战案例,展示从设计到实现的全过程。
具体来说,本文将涵盖以下内容:
- 核心概念解析:什么是情绪AI、情感计算、人机交互,以及它们如何与AI Agent结合;
- 技术栈详解:实现情绪理解需要哪些技术,从信号处理到机器学习模型;
- 系统构建指南:如何设计并实现一个具备情绪理解能力的AI Agent架构;
- 实战演练:通过Python代码示例,展示如何集成情绪识别功能到AI Agent中;
- 最佳实践与挑战:探讨在实际应用中可能遇到的问题及解决方案;
- 未来展望:情绪理解AI的发展趋势和前沿研究方向。
读完本文,你将不仅理解情绪AI的理论基础,还能掌握构建具备情绪理解能力AI Agent的实用技能。让我们一起踏上这场构建有"温度"的AI系统的旅程!
二、 基础知识/背景铺垫
在深入探讨如何为AI Agent赋予情绪理解能力之前,我们需要先建立一些基础概念。这一节将介绍情绪AI、AI Agent、人机交互等核心概念,并梳理它们之间的关系。
核心概念定义
1. 情绪AI (Emotional AI) 与 情感计算 (Affective Computing)
情绪AI,有时也被称为情感AI,是人工智能的一个分支,专注于赋予机器识别、理解、处理和模拟人类情绪的能力。这个领域的研究可以追溯到1995年,MIT媒体实验室的罗莎琳德·皮卡德(Rosalind Picard)教授提出了"情感计算"(Affective Computing)的概念,将其定义为"与情绪相关的、由情绪引发的或有意影响情绪的计算"。
情绪AI的研究范围广泛,包括:
- 情绪识别:从各种输入信号(如面部表情、语音、文本、生理信号)中检测和分类人类情绪;
- 情绪理解:解释情绪产生的原因和可能的后果;
- 情绪表达:让机器以自然的方式表达情绪(如通过语音语调、文字语气或虚拟角色表情);
- 情绪响应:根据检测到的情绪调整系统行为和交互策略。
从心理学角度,情绪可以按照不同模型进行分类。最常用的两种模型是:
类别模型(Categorical Model):将情绪分为几种基本类别,如保罗·艾克曼(Paul Ekman)提出的6种基本情绪:
- 快乐(Happiness)
- 悲伤(Sadness)
- 愤怒(Anger)
- 恐惧(Fear)
- 惊讶(Surprise)
- 厌恶(Disgust)
维度模型(Dimensional Model):将情绪映射到一个或多个连续维度上,最常用的是罗素(Russell)的效价-唤醒度模型:
- 效价(Valence):从消极到积极的连续体;
- 唤醒度(Arousal):从平静到兴奋的连续体。
这两种模型各有优势,类别模型直观易懂,维度模型则能更细致地捕捉情绪的细微差别。在实际应用中,往往会根据具体需求选择合适的模型,甚至将两者结合使用。
2. AI Agent (智能代理)
AI Agent是指能够感知环境、做出决策并采取行动以实现特定目标的自主系统。这个概念源于人工智能和计算机科学领域,近年来随着大语言模型(LLM)的发展而受到广泛关注。
一个典型的AI Agent通常包含以下核心组件:
- 感知模块(Perception):接收和处理来自环境的输入(如文本、语音、图像等);
- 推理/决策模块(Reasoning/Decision Making):处理感知信息,根据目标和知识做出决策;
- 行动模块(Action):执行决策,对环境产生影响;
- 记忆模块(Memory):存储历史信息、知识和经验;
- 目标/价值模块(Goals/Values):定义Agent的目标和行为准则。
根据不同的应用场景和功能,AI Agent可以分为多种类型:
- 反应式Agent(Reactive Agents):简单的刺激-响应系统,不使用内部记忆;
- 基于模型的Agent(Model-based Agents):维护环境的内部模型,用于决策;
- 目标导向的Agent(Goal-based Agents):具有明确目标,规划行动以实现目标;
- 效用驱动的Agent(Utility-based Agents):不仅考虑目标,还考虑实现目标的质量或效用;
- 学习型Agent(Learning Agents):能够从经验中学习,不断改进性能。
将情绪理解能力赋予AI Agent,本质上是在感知、推理和行动模块中增加情绪维度,使Agent能够:
- 感知用户的情绪状态;
- 理解情绪对交互和任务的影响;
- 根据情绪调整其响应和行为策略。
3. 人机交互 (Human-Computer Interaction, HCI)
人机交互是研究人与计算机之间交互的设计、评估和实现的学科。它关注如何使计算机系统更易于使用、更高效、更令人满意。
传统的HCI研究主要关注可用性(Usability),即系统是否容易学习、使用效率如何、是否容易出错等。但随着技术的发展,尤其是AI的普及,HCI的研究范围也在扩展,越来越关注体验(User Experience, UX)和情感维度。
**情感化设计(Emotional Design)**是由唐纳德·诺曼(Donald Norman)提出的概念,强调产品不仅要功能强大,还要能引发用户的积极情绪。诺曼将情感化设计分为三个层次:
- 本能层(Visceral):外观带来的直接情感反应;
- 行为层(Behavioral):使用过程中的体验和感受;
- 反思层(Reflective):使用后对产品的思考和评价。
将情绪理解引入人机交互,正是在这三个层次上增强用户体验:
- 本能层:通过情感化的界面和交互设计引发积极的第一印象;
- 行为层:通过实时感知用户情绪调整交互方式,提供更流畅的体验;
- 反思层:通过长期的情感互动,建立用户与系统之间的情感连接。
相关工具/技术概览
为AI Agent赋予情绪理解能力,需要整合多种技术和工具。以下是一些关键技术领域的概览:
1. 情绪识别技术
情绪识别是情绪AI的基础,根据输入信号的不同,可以分为多种类型:
-
面部表情识别:通过分析面部图像或视频识别人类情绪。
- 传统方法:特征提取(如HOG、SIFT)+ 分类器(如SVM、随机森林);
- 深度学习方法:CNN(如VGG、ResNet、FaceNet)、视频模型(如3D CNN、ConvLSTM);
- 工具/库:OpenFace、Face++、Microsoft Azure Face API、Amazon Rekognition。
-
语音情绪识别:通过分析语音信号(如语调、节奏、音量)识别情绪。
- 特征:韵律特征(基频、能量、语速)、音质特征(共振峰、谐波噪声比)、频谱特征(MFCC);
- 模型:传统统计模型(如GMM、HMM)、深度学习模型(如CNN、RNN、Transformer);
- 工具/库:OpenSMILE、Librosa、Google Speech-to-Text (附带情感分析)。
-
文本情绪分析:通过分析文本内容识别作者的情绪或态度。
- 方法:基于词典的方法、传统机器学习(如NB、SVM)、深度学习(如TextCNN、LSTM、BERT);
- 粒度:文档级、句子级、方面级;
- 工具/库:NLTK、TextBlob、VADER、spaCy、Hugging Face Transformers。
-
生理信号情绪识别:通过分析生理信号(如心电图ECG、脑电图EEG、皮肤电反应GSR)识别情绪。
- 优势:不易伪装,更接近真实情绪;
- 挑战:需要特殊设备,普及性较差;
- 应用场景:医疗、研究、特殊行业(如飞行员训练)。
在实际应用中,往往会采用多模态融合的方法,结合多种信号源进行情绪识别,以提高准确性和鲁棒性。
2. 大语言模型与AI Agent框架
近年来,大语言模型(LLMs)的突破性发展为AI Agent提供了强大的基础。这些模型不仅具有强大的语言理解和生成能力,还展现出一定的推理和规划能力。
-
主流大语言模型:
- GPT系列(OpenAI):GPT-3.5、GPT-4等;
- Claude系列(Anthropic);
- PaLM/LaMDA系列(Google);
- Llama系列(Meta);
- 文心一言(百度)、通义千问(阿里巴巴)、星火(科大讯飞)等国内模型。
-
AI Agent开发框架:
- LangChain:用于构建由语言模型驱动的应用程序的框架;
- AutoGPT:一个实验性的开源尝试,旨在使GPT-4完全自主;
- BabyAGI:受AutoGPT启发的简化版本;
- Semantic Kernel(微软):将最新的LLM技术与传统编程语言集成;
- Hugging Face Transformers/Agents:提供预训练模型和工具。
这些框架为构建AI Agent提供了基础,但大多数默认不包含情绪理解能力。本文的重点之一就是探讨如何在这些框架基础上增加情绪理解模块。
3. 人机交互设计工具
为AI Agent设计良好的人机交互界面,需要专业的设计工具和方法:
- UI/UX设计工具:Figma、Sketch、Adobe XD、Axure;
- 原型设计与用户测试:InVision、Principle、Framer、UserTesting;
- 对话式界面设计:Dialogflow、Microsoft Bot Framework、Rasa;
- 虚拟角色/数字人:Unity、Unreal Engine、MetaHuman、D-ID。
概念之间的关系
为了更清晰地理解这些核心概念之间的关系,我们可以从不同维度进行分析。
概念核心属性维度对比
| 概念 | 核心目标 | 输入 | 输出 | 关键技术 | 应用场景 |
|---|---|---|---|---|---|
| 情绪AI | 理解和处理人类情绪 | 多模态信号(面部/语音/文本/生理) | 情绪标签/维度值/情绪响应 | 深度学习、信号处理、心理学 | 客户服务、医疗、教育、娱乐 |
| AI Agent | 自主完成特定目标 | 环境感知 | 决策/行动 | LLM、规划、推理、记忆 | 个人助手、客服、自动化工具 |
| 人机交互 | 优化人与计算机的交互体验 | 用户行为/反馈 | 交互界面/策略 | UI/UX设计、用户研究、认知科学 | 软件应用、智能设备、服务系统 |
ER实体关系图
交互关系图
本章小结
在这一章中,我们介绍了构建具备情绪理解与人机交互能力的AI Agent所需的基础概念。我们定义了情绪AI、AI Agent和人机交互这三个核心概念,探讨了它们各自的关键技术和应用场景,并通过表格和图表清晰地展示了它们之间的关系。
情绪AI为我们提供了识别和理解人类情绪的技术手段,AI Agent为我们提供了自主决策和行动的框架,而人机交互则指导我们如何设计自然、有效的交互方式。将这三者结合,我们就能构建出不仅能完成任务,还能理解用户情绪、提供人性化交互体验的AI系统。
有了这些基础概念,我们现在可以深入探讨如何通过Harness Engineering的方法,将情绪理解能力集成到AI Agent中。
三、 核心内容/实战演练
在这一节中,我们将深入探讨如何实际构建一个具备情绪理解与人机交互能力的AI Agent。我们将从系统架构设计开始,然后逐步实现各个核心组件,最后通过一个完整的示例项目展示整个流程。
系统架构设计
要构建一个具备情绪理解能力的AI Agent,我们需要设计一个模块化、可扩展的架构。以下是一个参考架构,它将情绪理解无缝集成到AI Agent的核心功能中。
这个架构分为四个主要层次:
- 用户交互层:负责与用户进行直接交互,接收用户输入(文本、语音、图像)并呈现系统输出。
- 情绪感知层:从各种输入信号中提取情绪信息,并通过多模态融合得到更准确的情绪理解。
- AI Agent核心层:是系统的大脑,负责理解用户意图、规划行动、执行任务,并生成情绪感知的响应。
- 知识库层:存储领域知识、情绪知识和用户画像,为AI Agent的决策提供支持。
接下来,我们将逐步实现这个架构中的关键组件。
环境准备与安装
在开始编写代码之前,我们需要准备开发环境并安装必要的库和工具。以下是我们将使用的主要技术栈:
- 编程语言:Python 3.8+
- 大语言模型:OpenAI GPT-3.5/4(或兼容的开源模型如Llama 2)
- 文本情绪分析:Hugging Face Transformers
- 语音处理:OpenAI Whisper(ASR)、ElevenLabs或Microsoft TTS
- 面部表情识别:OpenCV + 预训练模型
- AI Agent框架:LangChain
- 其他工具:FastAPI(API服务)、Streamlit(UI)
让我们创建一个项目目录并安装必要的依赖:
mkdir emotion-aware-agent
cd emotion-aware-agent
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
创建 requirements.txt 文件:
openai>=1.0.0
langchain>=0.1.0
transformers>=4.35.0
torch>=2.1.0
torchaudio>=2.1.0
torchvision>=0.16.0
opencv-python>=4.8.0
streamlit>=1.28.0
fastapi>=0.104.0
uvicorn>=0.24.0
python-multipart>=0.0.6
python-dotenv>=1.0.0
pydantic>=2.5.0
numpy>=1.26.0
pandas>=2.1.0
matplotlib>=3.8.0
seaborn>=0.13.0
whisper-openai>=20231117
安装依赖:
pip install -r requirements.txt
创建 .env 文件来存储API密钥:
OPENAI_API_KEY=your_openai_api_key_here
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here # 可选
核心组件实现
现在,我们将逐步实现系统架构中的核心组件。我们将从基础的情绪识别模块开始,然后构建AI Agent的核心功能。
1. 文本情绪分析模块
首先,让我们实现一个文本情绪分析模块。我们将使用Hugging Face的Transformers库,加载一个预训练的情绪分类模型。
创建 emotion_analyzer.py 文件:
import os
from typing import List, Dict, Tuple, Optional
import numpy as np
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
pipeline
)
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
class TextEmotionAnalyzer:
"""文本情绪分析器"""
def __init__(self, model_name: str = "bhadresh-savani/bert-base-uncased-emotion"):
"""
初始化文本情绪分析器
Args:
model_name: 预训练模型名称
"""
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSequenceClassification.from_pretrained(model_name)
# 创建情绪分析pipeline
self.emotion_classifier = pipeline(
"text-classification",
model=self.model,
tokenizer=self.tokenizer,
return_all_scores=True
)
# 定义情绪类别(根据模型可能有所不同)
self.emotion_categories = [
"sadness", "joy", "love", "anger", "fear", "surprise"
]
# 情绪到维度的映射( valence, arousal )
self.emotion_to_dimensions = {
"sadness": (-0.8, -0.4),
"joy": (0.9, 0.7),
"love": (0.8, 0.5),
"anger": (-0.6, 0.8),
"fear": (-0.7, 0.6),
"surprise": (0.2, 0.9)
}
def analyze_emotion(self, text: str) -> Dict:
"""
分析文本的情绪
Args:
text: 输入文本
Returns:
包含情绪分析结果的字典
"""
results = self.emotion_classifier(text)[0]
# 转换为更易读的格式
emotions = {item["label"]: item["score"] for item in results}
# 找出主导情绪
dominant_emotion = max(emotions, key=emotions.get)
dominant_score = emotions[dominant_emotion]
# 计算维度值
valence, arousal = self._calculate_dimensions(emotions)
return {
"text": text,
"emotions": emotions,
"dominant_emotion": dominant_emotion,
"dominant_score": dominant_score,
"valence": valence,
"arousal": arousal
}
def _calculate_dimensions(self, emotions: Dict[str, float]) -> Tuple[float, float]:
"""
根据类别情绪计算维度值
Args:
emotions: 情绪类别到分数的映射
Returns:
(valence, arousal) 元组
"""
valence = 0.0
arousal = 0.0
total_weight = 0.0
for emotion, score in emotions.items():
if emotion in self.emotion_to_dimensions:
v, a = self.emotion_to_dimensions[emotion]
valence += v * score
arousal += a * score
total_weight += score
if total_weight > 0:
valence /= total_weight
arousal /= total_weight
return valence, arousal
def batch_analyze(self, texts: List[str]) -> List[Dict]:
"""
批量分析文本情绪
Args:
texts: 文本列表
Returns:
情绪分析结果列表
"""
return [self.analyze_emotion(text) for text in texts]
# 示例用法
if __name__ == "__main__":
analyzer = TextEmotionAnalyzer()
sample_texts = [
"我今天真的很开心,收到了梦寐以求的礼物!",
"我对这件事感到非常失望,完全没有达到预期。",
"这种情况让我感到很焦虑,不知道该怎么办才好。",
"听到这个消息我很惊讶,但同时也有点担心。"
]
results = analyzer.batch_analyze(sample_texts)
for result in results:
print(f"\n文本: {result['text']}")
print(f"主导情绪: {result['dominant_emotion']} ({result['dominant_score']:.2f})")
print(f"维度值: 效价={result['valence']:.2f}, 唤醒度={result['arousal']:.2f}")
print("所有情绪分数:")
for emotion, score in result['emotions'].items():
print(f" {emotion}: {score:.2f}")
这个模块实现了基本的文本情绪分析功能,它可以:
- 对输入文本进行情绪分类
- 输出各个情绪类别的分数
- 计算效价-唤醒度维度值
- 支持批量处理
2. 语音处理与情绪识别模块
接下来,我们将实现语音处理模块,包括语音转文本(ASR)和语音情绪识别。我们将使用OpenAI的Whisper进行ASR,然后使用一个预训练模型进行语音情绪识别。
创建 voice_processor.py 文件:
import os
import io
import numpy as np
from typing import Dict, Tuple, Optional
import torch
import torchaudio
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
Wav2Vec2Processor,
Wav2Vec2ForSequenceClassification
)
import whisper
from dotenv import load_dotenv
load_dotenv()
class VoiceProcessor:
"""语音处理器,包含ASR和语音情绪识别"""
def __init__(self,
whisper_model: str = "base",
speech_emotion_model: str = "audeering/wav2vec2-large-robust-12-ft-emotion-msp-dim"):
"""
初始化语音处理器
Args:
whisper_model: Whisper模型大小
speech_emotion_model: 语音情绪识别模型
"""
# 加载Whisper模型用于ASR
print(f"加载Whisper模型: {whisper_model}")
self.asr_model = whisper.load_model(whisper_model)
# 加载语音情绪识别模型
print(f"加载语音情绪识别模型: {speech_emotion_model}")
self.processor = Wav2Vec2Processor.from_pretrained(speech_emotion_model)
self.speech_emotion_model = Wav2Vec2ForSequenceClassification.from_pretrained(speech_emotion_model)
# 定义情绪维度(根据所选模型可能有所不同)
self.emotion_dimensions = ["valence", "arousal", "dominance"]
def transcribe_audio(self, audio_path: str) -> Dict:
"""
转录音频文件为文本
Args:
audio_path: 音频文件路径
Returns:
包含转录文本和元数据的字典
"""
result = self.asr_model.transcribe(audio_path)
return {
"text": result["text"],
"language": result.get("language", "unknown"),
"segments": result.get("segments", [])
}
def analyze_speech_emotion(self, audio_path: str) -> Dict:
"""
分析语音中的情绪
Args:
audio_path: 音频文件路径
Returns:
包含情绪分析结果的字典
"""
# 加载音频
waveform, sample_rate = torchaudio.load(audio_path)
# 重采样到16kHz(模型要求)
if sample_rate != 16000:
resampler = torchaudio.transforms.Resample(sample_rate, 16000)
waveform = resampler(waveform)
# 处理音频
inputs = self.processor(
waveform.squeeze().numpy(),
sampling_rate=16000,
return_tensors="pt",
padding=True
)
# 推理
with torch.no_grad():
outputs = self.speech_emotion_model(**inputs)
# 获取logits并转换为numpy
logits = outputs.logits.cpu().numpy()[0]
# 构建结果
result = {}
for i, dim in enumerate(self.emotion_dimensions):
result[dim] = float(logits[i])
# 计算主导情绪类别(基于维度值)
result["dominant_emotion"] = self._dimensions_to_emotion(result["valence"], result["arousal"])
return result
def _dimensions_to_emotion(self, valence: float, arousal: float) -> str:
"""
将维度值映射到情绪类别
Args:
valence: 效价
arousal: 唤醒度
Returns:
情绪类别
"""
# 简单的启发式规则
if valence > 0.5 and arousal > 0.5:
return "joy"
elif valence > 0.5 and arousal <= 0.5:
return "calm"
elif valence <= 0.5 and arousal > 0.5:
return "anger" if valence < -0.3 else "surprise"
elif valence <= -0.5 and arousal <= 0.5:
return "sadness"
else:
return "neutral"
def process_voice(self, audio_path: str) -> Dict:
"""
完整处理音频:转录+情绪分析
Args:
audio_path: 音频文件路径
Returns:
包含所有处理结果的字典
"""
# 转录
transcription = self.transcribe_audio(audio_path)
# 分析语音情绪
speech_emotion = self.analyze_speech_emotion(audio_path)
# 合并结果
return {
"transcription": transcription,
"speech_emotion": speech_emotion
}
# 示例用法
if __name__ == "__main__":
# 注意:实际使用时需要准备一个音频文件
# 这里仅作为示例代码展示,运行时需要提供真实的音频文件路径
print("语音处理器示例")
print("=" * 50)
# 初始化处理器
processor = VoiceProcessor(whisper_model="tiny") # 使用tiny模型加快示例速度
# 注释掉实际处理部分,因为需要音频文件
"""
# 处理音频
result = processor.process_voice("path/to/your/audio.wav")
# 打印结果
print(f"转录文本: {result['transcription']['text']}")
print(f"检测语言: {result['transcription']['language']}")
print(f"语音情绪分析:")
print(f" 效价 (Valence): {result['speech_emotion']['valence']:.2f}")
print(f" 唤醒度 (Arousal): {result['speech_emotion']['arousal']:.2f}")
print(f" 主导情绪: {result['speech_emotion']['dominant_emotion']}")
"""
print("请提供音频文件以运行完整示例")
这个模块提供了语音处理功能,包括语音转文本和语音情绪识别。需要注意的是,实际使用时需要准备音频文件。
3. 面部表情识别模块
接下来,我们将实现面部表情识别模块。这个模块将使用OpenCV捕获或加载图像,并使用预训练的深度学习模型识别面部表情。
创建 face_emotion.py 文件:
import os
import cv2
import numpy as np
from typing import Dict, List, Tuple, Optional
from pathlib import Path
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
from dotenv import load_dotenv
load_dotenv()
# 简单的CNN模型用于面部表情识别(实际应用中可以使用更先进的预训练模型)
class SimpleEmotionCNN(nn.Module):
"""简单的面部表情识别CNN模型"""
def __init__(self, num_classes: int = 7):
super(SimpleEmotionCNN, self).__init__()
# 卷积层
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
# 池化层
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
# 全连接层
self.fc1 = nn.Linear(128 * 6 * 6, 512)
self.fc2 = nn.Linear(512, num_classes)
# dropout层
self.dropout = nn.Dropout(0.5)
def forward(self, x):
# 卷积层1
x = self.conv1(x)
x = F.relu(x)
x = self.pool(x) # 输出: 32 x 24 x 24
# 卷积层2
x = self.conv2(x)
x = F.relu(x)
x = self.pool(x) # 输出: 64 x 12 x 12
# 卷积层3
x = self.conv3(x)
x = F.relu(x)
x = self.pool(x) # 输出: 128 x 6 x 6
# 展平
x = x.view(-1, 128 * 6 * 6)
# 全连接层1
x = self.fc1(x)
x = F.relu(x)
x = self.dropout(x)
# 全连接层2
x = self.fc2(x)
return x
class FaceEmotionAnalyzer:
"""面部表情分析器"""
def __init__(self, model_path: Optional[str] = None):
"""
初始化面部表情分析器
Args:
model_path: 预训练模型路径(可选)
"""
# 加载人脸检测器(使用OpenCV的Haar级联分类器)
self.face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
# 定义情绪类别
self.emotion_categories = [
"angry", "disgust", "fear", "happy", "sad", "surprise", "neutral"
]
# 情绪到维度的映射
self.emotion_to_dimensions = {
"angry": (-0.6, 0.8),
"disgust": (-0.7, 0.3),
"fear": (-0.7, 0.7),
"happy": (0.9, 0.7),
"sad": (-0.8, -0.4),
"surprise": (0.2, 0.9),
"neutral": (0.0, 0.0)
}
# 初始化模型
self.model = SimpleEmotionCNN(num_classes=len(self.emotion_categories))
# 如果提供了模型路径,则加载预训练权重
if model_path and os.path.exists(model_path):
self.model.load_state_dict(torch.load(model_path, map_location='cpu'))
print(f"加载预训练模型: {model_path}")
else:
print("警告: 未加载预训练模型,将使用随机初始化的权重")
print("提示: 请在实际应用中使用在FER-2013等数据集上预训练的模型")
self.model.eval()
# 定义图像预处理
self.transform = transforms.Compose([
transforms.ToPILImage(),
transforms.Grayscale(),
transforms.Resize((48, 48)),
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
def detect_faces(self, image: np.ndarray) -> List[Tuple[int, int, int, int]]:
"""
在图像中检测人脸
Args:
image: 输入图像(BGR格式)
Returns:
人脸边界框列表 [(x, y, w, h), ...]
"""
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = self.face_cascade.detectMultiScale(
gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)
)
return faces
def analyze_face_emotion(self, face_img: np.ndarray) -> Dict:
"""
分析单个人脸图像的情绪
Args:
face_img: 人脸图像(BGR格式)
Returns:
情绪分析结果
"""
# 预处理图像
input_tensor = self.transform(face_img).unsqueeze(0)
# 推理
with torch.no_grad():
outputs = self.model(input_tensor)
probabilities = F.softmax(outputs, dim=1).numpy()[0]
# 构建结果
emotions = {self.emotion_categories[i]: float(probabilities[i])
for i in range(len(self.emotion_categories))}
# 找出主导情绪
dominant_idx = np.argmax(probabilities)
dominant_emotion = self.emotion_categories[dominant_idx]
dominant_score = float(probabilities[dominant_idx])
# 计算维度值
valence, arousal = self._calculate_dimensions(emotions)
return {
"emotions": emotions,
"dominant_emotion": dominant_emotion,
"dominant_score": dominant_score,
"valence": valence,
"arousal": arousal
}
def _calculate_dimensions(self, emotions: Dict[str, float]) -> Tuple[float, float]:
"""
根据类别情绪计算维度值
Args:
emotions: 情绪类别到分数的映射
Returns:
(valence, arousal) 元组
"""
valence = 0.0
arousal = 0.0
total_weight = 0.0
for emotion, score in emotions.items():
if emotion in self.emotion_to_dimensions:
v, a = self.emotion_to_dimensions[emotion]
valence += v * score
arousal += a * score
total_weight += score
if total_weight > 0:
valence /= total_weight
arousal /= total_weight
return valence, arousal
def analyze_image(self, image: np.ndarray) -> List[Dict]:
"""
分析图像中的所有人脸情绪
Args:
image: 输入图像(BGR格式)
Returns:
每个人脸的分析结果列表
"""
faces = self.detect_faces(image)
results = []
for (x, y, w, h) in faces:
# 提取人脸
face_img = image[y:y+h, x:x+w]
# 分析情绪
emotion_result = self.analyze_face_emotion(face_img)
# 添加边界框信息
emotion_result["face_box"] = {"x": int(x), "y": int(y), "w": int(w), "h": int(h)}
results.append(emotion_result)
return results
def visualize_results(self, image: np.ndarray, results: List[Dict]) -> np.ndarray:
"""
在图像上可视化情绪分析结果
Args:
image: 原始图像
results: 分析结果
Returns:
可视化后的图像
"""
vis_img = image.copy()
for result in results:
if "face_box" in result:
box = result["face_box"]
x, y, w, h = box["x"], box["y"], box["w"], box["h"]
# 绘制边界框
cv2.rectangle(vis_img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 准备文本
emotion = result["dominant_emotion"]
score = result["dominant_score"]
text = f"{emotion}: {score:.2f}"
# 绘制文本背景
text_size, _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
cv2.rectangle(vis_img, (x, y - text_size[1] - 10),
(x + text_size[0], y), (0, 255, 0), -1)
# 绘制文本
cv2.putText(vis_img, text, (x, y - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
return vis_img
# 示例用法
if __name__ == "__main__":
print("面部表情分析器示例")
print("=" * 50)
# 初始化分析器
analyzer = FaceEmotionAnalyzer()
# 注释掉实际处理部分,因为需要图像文件或摄像头
"""
# 从文件加载图像
image = cv2.imread("path/to/your/image.jpg")
if image is not None:
# 分析图像
results = analyzer.analyze_image(image)
if results:
print(f"检测到 {len(results)} 个人脸")
for i, result in enumerate(results):
print(f"\n人脸 {i+1}:")
print(f"主导情绪: {result['dominant_emotion']} ({result['dominant_score']:.2f})")
print(f"维度值: 效价={result['valence']:.2f}, 唤醒度={result['arousal']:.2f}")
# 可视化结果
vis_img = analyzer.visualize_results(image, results)
# 显示结果(如果有图形界面)
# cv2.imshow("Emotion Analysis", vis_img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 或者保存结果
cv2.imwrite("emotion_analysis_result.jpg", vis_img)
print("结果已保存到 emotion_analysis_result.jpg")
else:
print("未检测到人脸")
else:
print("无法加载图像,请检查路径")
# 摄像头实时分析示例
print("\n尝试启动摄像头进行实时分析...")
cap = cv2.VideoCapture(0)
if cap.isOpened():
print("按 'q' 键退出")
while True:
ret, frame = cap.read()
if not ret:
break
# 分析帧
results = analyzer.
更多推荐

所有评论(0)