bread-good111 commited on
Commit
4a85a47
·
verified ·
1 Parent(s): cae54c6

Upload folder using huggingface_hub

Browse files
Files changed (8) hide show
  1. README.md +111 -31
  2. config.json +34 -0
  3. detection_model.py +238 -0
  4. inference_example.py +91 -0
  5. model.pt +3 -0
  6. special_tokens_map.json +7 -0
  7. tokenizer_config.json +58 -0
  8. vocab.txt +0 -0
README.md CHANGED
@@ -1,46 +1,126 @@
1
- # LongEmotion 比赛核心文件
2
 
3
- ## 📁 件结构
4
 
5
- ### model/
6
- - `best_model.pt` - 训练好的BERT模型(验证准确率91.47%)
7
 
8
- ### test_data/
9
- - `test.jsonl` - 比赛试集(136个样本)
 
 
10
 
11
- ### scripts/
12
- - `run_inference_final.py` - 推理运行脚本
13
- - `inference_longemotion.py` - 推理核心逻辑
14
- - `convert_submission_format.py` - 格式转换脚本
15
- - `detection_model.py` - 模型定义
16
 
17
- ### submission/
18
- - `submission.jsonl` - 提交文件(格式: {"id": 0, "predicted_index": 24})
19
- - `Emotion_Detection_Result.jsonl` - 备份提交文件
 
 
 
 
20
 
21
- ### reports/
22
- - 项目进度报告和自查报告
23
 
24
- ## 🚀 使用方法
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- ### 运行推理
27
  ```bash
28
- # 从Detection文件夹内运行
29
- cd Detection
30
- python scripts/run_inference_final.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  ```
32
 
33
- ### 转换格式(可选)
 
34
  ```bash
35
- # 从Detection/scripts文件夹内运行
36
- cd Detection/scripts
37
- python convert_submission_format.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  ```
39
 
40
- ## 📊 模型性能
41
- - 验证准确率: 91.47%
42
- - 平均预测置信度: 89.27%
43
- - 推理时间: ~5-10分钟/136样本
 
 
 
 
44
 
45
- ## 📝 提交
46
- 提交文件: `submission/submission.jsonl`
 
1
+ # Emotion Detection Model - LongEmotion
2
 
3
+ 情感检测模型,基于BERT的中情感分类器
4
 
5
+ ## 📊 模型信息
 
6
 
7
+ - **基础模型**: bert-base-chinese
8
+ - **任务类型**: 6分类情感检
9
+ - **验证准确率**: 91.47%
10
+ - **框架**: PyTorch + Transformers
11
 
12
+ ## 🏷️ 情感类别
 
 
 
 
13
 
14
+ 模型可以识别以下6种情感:
15
+ - `sadness` (悲伤)
16
+ - `joy` (快乐)
17
+ - `love` (爱)
18
+ - `anger` (愤怒)
19
+ - `fear` (恐惧)
20
+ - `surprise` (惊讶)
21
 
22
+ ## 📁 文件说明
 
23
 
24
+ ```
25
+ detection_hug/
26
+ ├── model.pt # 模型权重文件
27
+ ├── config.json # 模型配置
28
+ ├── tokenizer_config.json # 分词器配置
29
+ ├── vocab.txt # 词表
30
+ ├── special_tokens_map.json # 特殊符号映射
31
+ ├── detection_model.py # 模型定义
32
+ ├── inference_example.py # 推理示例
33
+ └── README.md # 本文件
34
+ ```
35
+
36
+ ## 🚀 快速开始
37
+
38
+ ### 环境要求
39
 
 
40
  ```bash
41
+ pip install torch transformers
42
+ ```
43
+
44
+ ### 基本使用
45
+
46
+ ```python
47
+ import torch
48
+ from transformers import BertTokenizer
49
+ from detection_model import EmotionDetectionModel
50
+
51
+ # 1. 加载分词器
52
+ tokenizer = BertTokenizer.from_pretrained(".")
53
+
54
+ # 2. 加载模型
55
+ model = EmotionDetectionModel(
56
+ model_name="bert-base-chinese",
57
+ num_emotions=6
58
+ )
59
+ checkpoint = torch.load("model.pt", map_location="cpu")
60
+ model.load_state_dict(checkpoint)
61
+ model.eval()
62
+
63
+ # 3. 预测
64
+ text = "我今天很开心!"
65
+ encoding = tokenizer(text, return_tensors='pt', max_length=512, truncation=True, padding=True)
66
+ outputs = model(**encoding)
67
+ predicted_emotion = torch.argmax(outputs['logits'], dim=-1).item()
68
+
69
+ # 情感映射
70
+ emotions = ["sadness", "joy", "love", "anger", "fear", "surprise"]
71
+ print(f"预测情感: {emotions[predicted_emotion]}")
72
  ```
73
 
74
+ ### 使用推理脚本
75
+
76
  ```bash
77
+ python inference_example.py
78
+ ```
79
+
80
+ ## 📈 模型性能
81
+
82
+ - **数据集**: dair-ai/emotion (中文情感数据)
83
+ - **验证准确率**: 91.47%
84
+ - **平均置信度**: 89.27%
85
+ - **最大序列长度**: 512 tokens
86
+
87
+ ## 🔧 技术细节
88
+
89
+ ### 模型架构
90
+
91
+ ```
92
+ EmotionDetectionModel
93
+ ├── BERT Encoder (bert-base-chinese)
94
+ │ └── 768-dim hidden states
95
+ ├── Dropout (p=0.1)
96
+ ├── Linear Layer (768 → 384)
97
+ ├── ReLU Activation
98
+ ├── Dropout (p=0.1)
99
+ └── Output Layer (384 → 6)
100
+ ```
101
+
102
+ ### 训练参数
103
+
104
+ - **优化器**: AdamW
105
+ - **学习率**: 2e-5
106
+ - **批次大小**: 16
107
+ - **最大长度**: 512
108
+
109
+ ## 📝 引用
110
+
111
+ 如果您使用此模型,请注明:
112
+ ```
113
+ LongEmotion Detection Model
114
+ - 基于 bert-base-chinese
115
+ - 训练于 dair-ai/emotion 数据集
116
  ```
117
 
118
+ ## 📧 联系方式
119
+
120
+ 如有问题,请通过项目仓库联系。
121
+
122
+ ---
123
+
124
+ **License**: 遵循 bert-base-chinese 的许可协议
125
+ **Created**: 2025
126
 
 
 
config.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "bert-emotion-detection",
3
+ "base_model": "bert-base-chinese",
4
+ "architecture": "EmotionDetectionModel",
5
+ "task": "emotion-classification",
6
+ "num_emotions": 6,
7
+ "emotion_labels": {
8
+ "0": "sadness",
9
+ "1": "joy",
10
+ "2": "love",
11
+ "3": "anger",
12
+ "4": "fear",
13
+ "5": "surprise"
14
+ },
15
+ "model_params": {
16
+ "hidden_size": 768,
17
+ "dropout": 0.1,
18
+ "classifier_architecture": "two-layer-mlp",
19
+ "intermediate_size": 384
20
+ },
21
+ "training_info": {
22
+ "dataset": "dair-ai/emotion",
23
+ "max_length": 512,
24
+ "validation_accuracy": 0.9147,
25
+ "framework": "pytorch"
26
+ },
27
+ "inference": {
28
+ "max_length": 512,
29
+ "batch_size": 16,
30
+ "device": "cuda or cpu"
31
+ },
32
+ "version": "1.0",
33
+ "created_by": "LongEmotion Detection Task"
34
+ }
detection_model.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 情感检测模型
3
+ Emotion Detection Task
4
+ 多标签分类任务
5
+ """
6
+ import torch
7
+ import torch.nn as nn
8
+ from transformers import (
9
+ BertModel,
10
+ BertTokenizer,
11
+ AutoModel,
12
+ AutoTokenizer
13
+ )
14
+ from typing import Dict, List, Optional
15
+
16
+
17
+ class EmotionDetectionModel(nn.Module):
18
+ """情感检测模型(多标签分类)"""
19
+
20
+ def __init__(
21
+ self,
22
+ model_name: str = "bert-base-chinese",
23
+ num_emotions: int = 7,
24
+ dropout: float = 0.1
25
+ ):
26
+ """
27
+ 初始化检测模型
28
+
29
+ Args:
30
+ model_name: 预训练模型名称
31
+ num_emotions: 情感类别数量
32
+ dropout: Dropout 比率
33
+ """
34
+ super().__init__()
35
+
36
+ self.bert = AutoModel.from_pretrained(model_name)
37
+ hidden_size = self.bert.config.hidden_size
38
+
39
+ # 多标签分类头
40
+ self.classifier = nn.Sequential(
41
+ nn.Dropout(dropout),
42
+ nn.Linear(hidden_size, hidden_size // 2),
43
+ nn.ReLU(),
44
+ nn.Dropout(dropout),
45
+ nn.Linear(hidden_size // 2, num_emotions)
46
+ )
47
+
48
+ self.num_emotions = num_emotions
49
+
50
+ def forward(
51
+ self,
52
+ input_ids: torch.Tensor,
53
+ attention_mask: torch.Tensor,
54
+ labels: Optional[torch.Tensor] = None
55
+ ):
56
+ """
57
+ 前向传播
58
+
59
+ Args:
60
+ input_ids: 输入ID
61
+ attention_mask: 注意力掩码
62
+ labels: 标签(多标签,形状为 [batch_size, num_emotions])
63
+
64
+ Returns:
65
+ 模型输出
66
+ """
67
+ outputs = self.bert(
68
+ input_ids=input_ids,
69
+ attention_mask=attention_mask
70
+ )
71
+
72
+ # 使用 [CLS] token 的表示
73
+ pooled_output = outputs.last_hidden_state[:, 0, :]
74
+
75
+ # 分类
76
+ logits = self.classifier(pooled_output)
77
+
78
+ loss = None
79
+ if labels is not None:
80
+ # 使用 BCE Loss 进行多标签分类
81
+ loss_fct = nn.BCEWithLogitsLoss()
82
+ loss = loss_fct(logits, labels.float())
83
+
84
+ return {
85
+ 'loss': loss,
86
+ 'logits': logits
87
+ }
88
+
89
+
90
+ class EmotionDetectionModelWrapper:
91
+ """情感检测模型封装器"""
92
+
93
+ def __init__(
94
+ self,
95
+ model_name: str = "bert-base-chinese",
96
+ num_emotions: int = 7,
97
+ max_length: int = 512,
98
+ device: str = "cuda" if torch.cuda.is_available() else "cpu",
99
+ threshold: float = 0.5
100
+ ):
101
+ """
102
+ 初始化
103
+
104
+ Args:
105
+ model_name: 预训练模型名称
106
+ num_emotions: 情感类别数量
107
+ max_length: 最大序列长度
108
+ device: 设备
109
+ threshold: 分类阈值
110
+ """
111
+ self.model_name = model_name
112
+ self.num_emotions = num_emotions
113
+ self.max_length = max_length
114
+ self.device = device
115
+ self.threshold = threshold
116
+
117
+ # 加载分词器
118
+ self.tokenizer = AutoTokenizer.from_pretrained(model_name)
119
+
120
+ # 加载模型
121
+ self.model = EmotionDetectionModel(
122
+ model_name=model_name,
123
+ num_emotions=num_emotions
124
+ ).to(device)
125
+
126
+ # 情感标签名称
127
+ self.emotion_names = [
128
+ "happiness",
129
+ "sadness",
130
+ "anger",
131
+ "fear",
132
+ "surprise",
133
+ "disgust",
134
+ "neutral"
135
+ ]
136
+
137
+ def preprocess(self, texts: List[str]) -> Dict[str, torch.Tensor]:
138
+ """预处理文本"""
139
+ encoding = self.tokenizer(
140
+ texts,
141
+ padding=True,
142
+ truncation=True,
143
+ max_length=self.max_length,
144
+ return_tensors="pt"
145
+ )
146
+
147
+ return {k: v.to(self.device) for k, v in encoding.items()}
148
+
149
+ def predict(self, texts: List[str]) -> List[Dict[str, any]]:
150
+ """
151
+ 批量预测
152
+
153
+ Args:
154
+ texts: 文本列表
155
+
156
+ Returns:
157
+ 预测结果列表
158
+ """
159
+ self.model.eval()
160
+
161
+ inputs = self.preprocess(texts)
162
+
163
+ with torch.no_grad():
164
+ outputs = self.model(**inputs)
165
+ logits = outputs['logits']
166
+ probabilities = torch.sigmoid(logits) # 多标签使用 sigmoid
167
+
168
+ results = []
169
+ for i, probs in enumerate(probabilities):
170
+ # 获取超过阈值的情感
171
+ detected_emotions = []
172
+ emotion_scores = {}
173
+
174
+ for j, prob in enumerate(probs):
175
+ emotion_scores[self.emotion_names[j]] = float(prob)
176
+ if prob >= self.threshold:
177
+ detected_emotions.append({
178
+ 'emotion': self.emotion_names[j],
179
+ 'score': float(prob)
180
+ })
181
+
182
+ results.append({
183
+ 'text': texts[i],
184
+ 'emotions': detected_emotions,
185
+ 'all_scores': emotion_scores
186
+ })
187
+
188
+ return results
189
+
190
+ def save(self, save_path: str):
191
+ """保存模型"""
192
+ import os
193
+ os.makedirs(save_path, exist_ok=True)
194
+
195
+ # 保存模型权重
196
+ torch.save(self.model.state_dict(), f"{save_path}/model.pt")
197
+
198
+ # 保存分词器
199
+ self.tokenizer.save_pretrained(save_path)
200
+
201
+ # 保存配置
202
+ import json
203
+ config = {
204
+ 'model_name': self.model_name,
205
+ 'num_emotions': self.num_emotions,
206
+ 'max_length': self.max_length,
207
+ 'threshold': self.threshold
208
+ }
209
+ with open(f"{save_path}/config.json", 'w') as f:
210
+ json.dump(config, f, indent=2)
211
+
212
+ print(f"检测模型已保存到 {save_path}")
213
+
214
+ @classmethod
215
+ def load(cls, model_path: str, device: str = "cuda"):
216
+ """加载模型"""
217
+ import json
218
+
219
+ # 加载配置
220
+ with open(f"{model_path}/config.json", 'r') as f:
221
+ config = json.load(f)
222
+
223
+ instance = cls(
224
+ model_name=config['model_name'],
225
+ num_emotions=config['num_emotions'],
226
+ max_length=config['max_length'],
227
+ device=device,
228
+ threshold=config.get('threshold', 0.5)
229
+ )
230
+
231
+ # 加载权重
232
+ instance.model.load_state_dict(
233
+ torch.load(f"{model_path}/model.pt", map_location=device)
234
+ )
235
+
236
+ print(f"检测模型已从 {model_path} 加载")
237
+ return instance
238
+
inference_example.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 情感检测推理示例
3
+ 使用detection_hug模型进行情感分类
4
+ """
5
+ import torch
6
+ from transformers import BertTokenizer
7
+ from detection_model import EmotionDetectionModel
8
+
9
+ def load_model(model_path="model.pt", device="cpu"):
10
+ """加载模型"""
11
+ print(f"加载模型: {model_path}")
12
+
13
+ # 加载分词器
14
+ tokenizer = BertTokenizer.from_pretrained(".")
15
+
16
+ # 创建模型
17
+ model = EmotionDetectionModel(
18
+ model_name="bert-base-chinese",
19
+ num_emotions=6,
20
+ dropout=0.1
21
+ )
22
+
23
+ # 加载权重
24
+ checkpoint = torch.load(model_path, map_location=device)
25
+ if isinstance(checkpoint, dict) and 'model_state_dict' in checkpoint:
26
+ model.load_state_dict(checkpoint['model_state_dict'])
27
+ else:
28
+ model.load_state_dict(checkpoint)
29
+
30
+ model = model.to(device)
31
+ model.eval()
32
+
33
+ print("✅ 模型加载成功")
34
+ return model, tokenizer
35
+
36
+ def predict(text, model, tokenizer, device="cpu"):
37
+ """预测单个文本的情感"""
38
+ # 情感标签
39
+ EMOTIONS = ["sadness", "joy", "love", "anger", "fear", "surprise"]
40
+
41
+ # 编码
42
+ encoding = tokenizer(
43
+ text,
44
+ padding='max_length',
45
+ truncation=True,
46
+ max_length=512,
47
+ return_tensors='pt'
48
+ )
49
+
50
+ input_ids = encoding['input_ids'].to(device)
51
+ attention_mask = encoding['attention_mask'].to(device)
52
+
53
+ # 推理
54
+ with torch.no_grad():
55
+ outputs = model(input_ids=input_ids, attention_mask=attention_mask)
56
+ logits = outputs['logits']
57
+ probabilities = torch.softmax(logits, dim=-1)
58
+ predicted_id = torch.argmax(probabilities, dim=-1).item()
59
+ confidence = probabilities[0, predicted_id].item()
60
+
61
+ return {
62
+ 'emotion': EMOTIONS[predicted_id],
63
+ 'confidence': confidence,
64
+ 'all_probabilities': {
65
+ EMOTIONS[i]: float(probabilities[0, i])
66
+ for i in range(len(EMOTIONS))
67
+ }
68
+ }
69
+
70
+ if __name__ == "__main__":
71
+ # 示例
72
+ device = "cuda" if torch.cuda.is_available() else "cpu"
73
+ model, tokenizer = load_model(device=device)
74
+
75
+ # 测试文本
76
+ test_texts = [
77
+ "我今天很开心!",
78
+ "这让我感到非常难过。",
79
+ "我爱你。"
80
+ ]
81
+
82
+ print("\n" + "="*60)
83
+ print("情感检测结果")
84
+ print("="*60)
85
+
86
+ for text in test_texts:
87
+ result = predict(text, model, tokenizer, device)
88
+ print(f"\n文本: {text}")
89
+ print(f"情感: {result['emotion']}")
90
+ print(f"置信度: {result['confidence']:.4f}")
91
+
model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:674ba0c78ee1e82d0e7e301184f359cc93067bc3d3c2c660589289c65f64087a
3
+ size 1227512245
special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
tokenizer_config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_basic_tokenize": true,
47
+ "do_lower_case": false,
48
+ "extra_special_tokens": {},
49
+ "mask_token": "[MASK]",
50
+ "model_max_length": 512,
51
+ "never_split": null,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "strip_accents": null,
55
+ "tokenize_chinese_chars": true,
56
+ "tokenizer_class": "BertTokenizer",
57
+ "unk_token": "[UNK]"
58
+ }
vocab.txt ADDED
The diff for this file is too large to render. See raw diff