bread-good111 commited on
Commit
23c8921
·
verified ·
1 Parent(s): 6901179

Delete scripts/detection_model.py

Browse files
Files changed (1) hide show
  1. scripts/detection_model.py +0 -238
scripts/detection_model.py DELETED
@@ -1,238 +0,0 @@
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
-