Skip to content

Commit 669be58

Browse files
author
ahsd-coder
committed
confidence
1 parent f088548 commit 669be58

7 files changed

Lines changed: 84 additions & 31 deletions

File tree

README.md

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# 训练模型
1+
# 一.训练模型
22

33
```commandline
44
python3 training_code/train_tfidf.py
55
python3 training_code/train_bert.py
66
```
77

8-
# 压测服务
8+
# 二.压测服务
99

1010
```commandline
1111
cd test/
@@ -15,7 +15,7 @@ ab -n 100 -c 100 -p data.json -T 'application/json' -H 'accept: application/json
1515
ab -n 100 -c 100 -p data.json -T 'application/json' -H 'accept: application/json' 'http://0.0.0.0:8000/v1/text-cls/bert'
1616
```
1717

18-
# 接口
18+
# 三.接口
1919

2020
```commandline
2121
curl -X 'POST' \
@@ -28,21 +28,48 @@ curl -X 'POST' \
2828
}'
2929
```
3030

31-
# 部署
31+
# 四.部署
3232

33-
## 只有后端时启动
33+
## (1)只有后端时启动
3434
```commandline
3535
fastapi run main.py
3636
```
37-
## 后端+前端启动
37+
## (2)后端+前端启动
3838
```commandline
3939
uvicorn main:app --host 0.0.0.0 --port 8000
4040
解释:Uvicorn是一个ASGI服务器,负责接收HTTP请求并转发给FastAPI应用处理。FastAPI本身只是一个框架,不负责网络监听;uvicorn才是真正"跑起来"的那个进程
4141
main:app → main是Python模块名,对应main.py文件;app是该模块里的变量,即main.py里的app = FastAPI()
4242
uvicorn会先 import main,然后拿到main.py里的FastAPI实例,开始监听请求
4343
```
4444

45-
# 推广
45+
# 五.推广
4646
```commandline
4747
可以重新找一个公开数据集(比如在魔搭社区的数据集),或直接标注一个文本分类数据集(推荐3个以上的类别个数),复现加载bert base 模型在新数据集上的微调过程。最终输入一个新的样本进行测试,验证分类效果是否准确。
4848
```
49+
50+
51+
# 六.意图识别方式
52+
```commandline
53+
本项目介绍了意图识别常用的三个方法:
54+
1.关键词匹配。写规则。好处是简单快,坏处是说法稍微变一下就抓不到了,并且容易误命中
55+
2.模型分类。用一个专门训练过的语言理解模型做分类(本项目有TFIDF/BERT)
56+
3.大模型判断:直接把用户输入喂给大语言模型,让它判断意图,不需要训练,但速度慢、成本高,适合长尾场景或刚起步阶段。
57+
58+
对于一个高频场景,通常的选择是:模型分类做主力,关键词规则兜底,大模型处理没见过的长尾说法。三个分开用,别指望一个方案全搞定。
59+
```
60+
61+
# 七.置信度
62+
```commandline
63+
置信度就是模型对自己判断结果的把握程度,范围0到1。1是完全确定,0是完全不知道
64+
┌────────────────────┬────────────────────┬────────────┐
65+
│ 路由 │ 置信度来源 │ 值范围 │
66+
├────────────────────┼────────────────────┼────────────┤
67+
│ /v1/text-cls/bert │ softmax 概率 │ 0 ~ 1 │
68+
├────────────────────┼────────────────────┼────────────┤
69+
│ /v1/text-cls/tfidf │ predict_proba 概率 │ 0 ~ 1 │
70+
├────────────────────┼────────────────────┼────────────┤
71+
│ /v1/text-cls/regex │ 固定值 │ 1.0 或 0.0 │
72+
├────────────────────┼────────────────────┼────────────┤
73+
│ /v1/text-cls/gpt │ 固定值 │ 1.0 │
74+
└────────────────────┴────────────────────┴────────────┘
75+
```

data_schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ class TextClassifyResponse(BaseModel):
2020
request_id: Optional[str] = Field(..., description="请求id")
2121
request_text: Union[str, List[str]] = Field(..., description="请求文本、字符串或列表")
2222
classify_result: Union[str, List[str]] = Field(..., description="分类结果")
23+
classify_confidence: Union[float, List[float], None] = Field(None, description="分类置信度")
2324
classify_time: float = Field(..., description="分类耗时")
2425
error_msg: str = Field(..., description="异常信息")

main.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,18 @@ def regex_classify(req: TextClassifyRequest) -> TextClassifyResponse:
3232
request_id=req.request_id,
3333
request_text=req.request_text,
3434
classify_result="",
35+
classify_confidence=None,
3536
classify_time=0,
3637
error_msg=""
3738
)
3839

3940
# logger.info(f"{req.request_id} {req.request_text}") # 打印请求
4041
try:
41-
response.classify_result = model_for_regex(req.request_text)
42+
response.classify_result, response.classify_confidence = model_for_regex(req.request_text)
4243
response.error_msg = "ok"
4344
except Exception as err:
4445
response.classify_result = ""
46+
response.classify_confidence = None
4547
response.error_msg = traceback.format_exc() # traceback.format_exec()可将异常调用结果返回
4648

4749
response.classify_time = round(time.time() - start_time, 3)
@@ -60,16 +62,18 @@ def tfidf_classify(req: TextClassifyRequest) -> TextClassifyResponse:
6062
request_id=req.request_id,
6163
request_text=req.request_text,
6264
classify_result="",
65+
classify_confidence=None,
6366
classify_time=0,
6467
error_msg=""
6568
)
6669
# logger.info(f"Get requst: {req.json()}")
6770

6871
try:
69-
response.classify_result = model_for_tfidf(req.request_text)
72+
response.classify_result, response.classify_confidence = model_for_tfidf(req.request_text)
7073
response.error_msg = "ok"
7174
except Exception as err:
7275
response.classify_result = ""
76+
response.classify_confidence = None
7377
response.error_msg = traceback.format_exc()
7478

7579
response.classify_time = round(time.time() - start_time, 3)
@@ -89,16 +93,18 @@ def bert_classify(req: TextClassifyRequest) -> TextClassifyResponse:
8993
request_id=req.request_id,
9094
request_text=req.request_text,
9195
classify_result="",
96+
classify_confidence=None,
9297
classify_time=0,
9398
error_msg=""
9499
)
95100
# info 日志
96101
try:
97-
response.classify_result = model_for_bert(req.request_text)
102+
response.classify_result, response.classify_confidence = model_for_bert(req.request_text)
98103
response.error_msg = "ok"
99104
except Exception as err:
100105
# error 日志
101106
response.classify_result = ""
107+
response.classify_confidence = None
102108
response.error_msg = traceback.format_exc()
103109

104110
response.classify_time = round(time.time() - start_time, 3)
@@ -117,15 +123,17 @@ def gpt_classify(req: TextClassifyRequest) -> TextClassifyResponse:
117123
request_id=req.request_id,
118124
request_text=req.request_text,
119125
classify_result="",
126+
classify_confidence=None,
120127
classify_time=0,
121128
error_msg=""
122129
)
123130

124131
try:
125-
response.classify_result = model_for_gpt(req.request_text)
132+
response.classify_result, response.classify_confidence = model_for_gpt(req.request_text)
126133
response.error_msg = "ok"
127134
except Exception as err:
128135
response.classify_result = ""
136+
response.classify_confidence = None
129137
response.error_msg = traceback.format_exc()
130138

131139
response.classify_time = round(time.time() - start_time, 3)

model/bert.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Union, List
1+
from typing import Union, List, Tuple
22

33
import numpy as np
44
import pandas as pd
@@ -32,8 +32,8 @@ def __len__(self):
3232
return len(self.labels)
3333

3434

35-
def model_for_bert(request_text: Union[str, List[str]]) -> Union[str, List[str]]:
36-
classify_result: Union[str, List[str]] = None
35+
def model_for_bert(request_text: Union[str, List[str]]) -> Tuple[List[str], List[float]]:
36+
classify_result: List[str] = None
3737

3838
if isinstance(request_text, str):
3939
request_text = [request_text]
@@ -50,6 +50,7 @@ def model_for_bert(request_text: Union[str, List[str]]) -> Union[str, List[str]]
5050

5151
model.eval()
5252
pred = []
53+
confidence = []
5354
for batch in test_dataloader:
5455
with torch.no_grad(): # 关闭梯度计算,节省显存,加速推理
5556
input_ids = batch['input_ids'].to(device)
@@ -58,10 +59,12 @@ def model_for_bert(request_text: Union[str, List[str]]) -> Union[str, List[str]]
5859
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
5960
logits = outputs[1]
6061
logits = logits.detach().cpu().numpy()
61-
pred += list(np.argmax(logits, axis=1).flatten()) # +=是为多batch准备的,保持代码通用性,不管几条数据都能处理
62+
probs = np.exp(logits) / np.exp(logits).sum(axis=1, keepdims=True) # softmax
63+
pred += list(np.argmax(probs, axis=1).flatten())
64+
confidence += list(np.max(probs, axis=1).flatten())
6265

6366
classify_result = [CATEGORY_NAME[x] for x in pred]
64-
return classify_result
67+
return classify_result, confidence
6568

6669
'''
6770
以用户输入 request_text = "放个游戏视频看看" 为例,逐行追踪:

model/prompt.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Union, List
1+
from typing import Union, List, Tuple
22

33
import openai
44
import pandas as pd
@@ -36,8 +36,8 @@
3636

3737

3838

39-
def model_for_gpt(request_text: Union[str, List[str]]) -> List[str]:
40-
classify_result: Union[str, List[str]] = []
39+
def model_for_gpt(request_text: Union[str, List[str]]) -> Tuple[List[str], List[float]]:
40+
classify_result: List[str] = []
4141

4242
if isinstance(request_text, str):
4343
tfidf_feat = tfidf.transform([request_text]) # 一个文本
@@ -72,7 +72,8 @@ def model_for_gpt(request_text: Union[str, List[str]]) -> List[str]:
7272

7373
classify_result.append(response.choices[0].message.content)
7474

75-
return classify_result
75+
classify_confidence = [1.0] * len(classify_result)
76+
return classify_result, classify_confidence
7677

7778

7879
# 算法算法项目测试

model/regex_rule.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from typing import Union, List
2+
from typing import Union, List, Tuple
33

44
from config import REGEX_RULE
55

@@ -8,27 +8,34 @@
88
REGEX_RULE_COMPILED[category] = re.compile("|".join(REGEX_RULE[category]))
99

1010

11-
def model_for_regex(request_text: Union[str, List[str]]) -> Union[str, List[str]]:
12-
classify_result: Union[str, List[str]] = []
11+
def model_for_regex(request_text: Union[str, List[str]]) -> Tuple[List[str], List[float]]:
12+
classify_result: List[str] = []
13+
classify_confidence: List[float] = []
1314

1415
if isinstance(request_text, str):
1516
for category in REGEX_RULE_COMPILED.keys():
1617
if REGEX_RULE_COMPILED[category].findall(request_text):
1718
classify_result.append(category)
19+
classify_confidence.append(1.0)
1820
if not classify_result:
1921
classify_result.append("Other")
22+
classify_confidence.append(0.0)
2023
elif isinstance(request_text, list):
2124
classify_result = []
25+
classify_confidence = []
2226
for text in request_text:
2327
is_classified = False
2428
for category in REGEX_RULE_COMPILED.keys():
25-
if REGEX_RULE_COMPILED[category].findall(request_text):
29+
if REGEX_RULE_COMPILED[category].findall(text):
2630
classify_result.append(category)
31+
classify_confidence.append(1.0)
2732
is_classified = True
33+
break
2834

2935
if not is_classified:
3036
classify_result.append("Other")
37+
classify_confidence.append(0.0)
3138
else:
3239
raise Exception("格式不支持")
3340

34-
return classify_result
41+
return classify_result, classify_confidence

model/tfidf_ml.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from typing import Union, List
1+
from typing import Union, List, Tuple
22

33
import jieba
4+
import numpy as np
45
import pandas as pd
56
from joblib import load
67
from config import TFIDF_MODEL_PKL_PATH
@@ -12,20 +13,25 @@
1213
cn_stopwords = pd.read_csv('http://mirror.coggle.club/stopwords/baidu_stopwords.txt', header=None)[0].values
1314

1415

15-
def model_for_tfidf(request_text: Union[str, List[str]]) -> Union[str, List[str]]:
16-
classify_result: Union[str, List[str]] = None
16+
def model_for_tfidf(request_text: Union[str, List[str]]) -> Tuple[List[str], List[float]]:
17+
classify_result: List[str] = None
18+
classify_confidence: List[float] = None
1719

1820
if isinstance(request_text, str):
1921
query_words = " ".join([x for x in jieba.lcut(request_text) if x not in cn_stopwords])
20-
classify_result = list(model.predict(tfidf.transform([query_words])))
22+
proba = model.predict_proba(tfidf.transform([query_words]))
23+
classify_result = list(model.classes_[np.argmax(proba, axis=1)])
24+
classify_confidence = list(np.max(proba, axis=1).flatten())
2125
elif isinstance(request_text, list):
2226
query_words = []
2327
for text in request_text:
2428
query_words.append(
2529
" ".join([x for x in jieba.lcut(text) if x not in cn_stopwords])
2630
)
27-
classify_result = list(model.predict(tfidf.transform(query_words)))
31+
proba = model.predict_proba(tfidf.transform(query_words))
32+
classify_result = list(model.classes_[np.argmax(proba, axis=1)])
33+
classify_confidence = list(np.max(proba, axis=1).flatten())
2834
else:
2935
raise Exception("格式不支持")
3036

31-
return classify_result
37+
return classify_result, classify_confidence

0 commit comments

Comments
 (0)