任务1:模型融合

【介绍】

你们研发小组已经完成了一个音乐热度预测模型的训练。在上线之前,一般需要对模型的泛化能力进行测试。模型融合可能会比单个模型有更好的泛化能力。在本任务中,你们要对多个训练好的回归模型完成模型融合,结合多个回归模型的预测结果,以生成最终的预测结果。

【目标】

model1.pkl、model2.pkl、model3.pkl 是本任务提供的基于 sklearn 训练的回归模型。

请按要求编写以下函数代码。

predictY 函数

函数功能

加载提供的 model1.pkl、model2.pkl、model3.pkl,分别对给定的测试数据进行预测。

基于指定权重对三个模型的预测结果进行加权平均,得到模型融合后的预测结果。其中 model1.pkl、model2.pkl、model3.pkl 分别对应的权重为 0.3, 0.1, 0.6。

参数

test_data,字典,key 表示特征名,value 表示特征值。

返回值

output_ensemble,浮点型数值,表示模型融合后的预测结果。

请在模块三文件夹下1.py文件中 #TODO处补充函数代码,确保实现以下目标:

① 正确输出模型推理结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pickle

def predictY(test_data):
# 加载模型
with open("model1.pkl", "rb") as f:
model1 = pickle.load(f)
with open("model2.pkl", "rb") as f:
model2 = pickle.load(f)
with open("model3.pkl", "rb") as f:
model3 = pickle.load(f)

# 对测试数据进行预测
pred1 = model1.predict([[test_data['feature1'], test_data['feature2'], test_data['feature3']]])[0]
pred2 = model2.predict([[test_data['feature1'], test_data['feature2'], test_data['feature3']]])[0]
pred3 = model3.predict([[test_data['feature1'], test_data['feature2'], test_data['feature3']]])[0]

# 模型融合
output_ensemble = 0.3 * pred1 + 0.1 * pred2 + 0.6 * pred3

return output_ensemble

# 测试数据
test_data = {'feature1': 0.5, 'feature2': 0.3, 'feature3': 0.8}
result = predictY(test_data)
print(result)

任务2:模型转换

【介绍】

在前面的任务中,我们搭建并训练完成了文本分析模型。在实际应用中,还需要将训练后的模型转换为其他格式,以支持不同的推理引擎。ONNX(Open Neural Network Exchange)提供了一个开放的源模型格式,支持多种深度学习框架之间的模型转换。本任务要求你们研发小组将提供的基于 PyTorch 的文本分类模型转换为 ONNX 格式,并实现一个使用 ONNX 模型进行推理的简单应用。model.pt是本任务提供的 PyTorch 模型权重文件。

【目标】

请按要求编写以下函数代码。

convert 函数

函数功能

将本任务提供的 pt 模型文件转换为 ONNX 格式。

ONNX 模型文件保存在模块三文件夹下,命名为 text_classifier.onnx。

inference 函数

函数功能

读取 ONNX 模型文件。

使用 ONNX 模型进行推理。

返回推理结果。

参数

model_path,字符串类型,ONNX 模型文件的绝对路径。

input,整数列表类型,为待预测样本,示例如:[101, 304, 993, 1008,102]。

返回值

result,浮点数列表类型,为 ONNX 文件推理结果,示例如:[[0.53419, 0.44313]]。

请在模块三文件夹下2.py文件中 #TODO 处补充函数代码,并执行 main() 函数,确保能够实现以下目标:

① 正确转换模型文件。

② 正确输出推理结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import torch
import torch.onnx
import onnx

# 转换模型为ONNX格式
def convert(model_path):
# 加载PyTorch模型
model = torch.load(model_path)

# 设置模型为评估模式
model.eval()

# 创建一个模拟输入
dummy_input = torch.LongTensor([101, 304, 993, 1008, 102]).unsqueeze(0)

# 使用torch.onnx导出模型
torch.onnx.export(model, dummy_input, "text_classifier.onnx", verbose=True)

# 使用ONNX模型进行推理
def inference(model_path, input):
# 加载ONNX模型
model = onnx.load(model_path)

# 准备输入数据
input_data = torch.LongTensor(input).unsqueeze(0)

# 使用ONNX模型进行推理
ort_session = onnxruntime.InferenceSession(model_path)
ort_inputs = {ort_session.get_inputs()[0].name: input_data.numpy()}
ort_outs = ort_session.run(None, ort_inputs)

return ort_outs

def main():
# 转换模型
convert("model.pt")

# 进行推理
result = inference("text_classifier.onnx", [101, 304, 993, 1008, 102])
print(result)

if __name__ == '__main__':
main()

任务3:模型部署

【介绍】

为了充分挖掘新媒体平台上积累的用户文本数据中的命名实体信息并为其他应用提供服务,我们需要将该模型部署到线上环境。一般来说,在自然语言处理应用的开发中,我们会使用 Web 框架(如 Flask)部署模型,并为外部提供 API 接口以支持在线预测。在本任务中,你们研发小组将接手一个部分完成的 Flask 项目。该项目已经包括了命名实体识别(NER)模型的载入、运行以及接收 tokenize 后的数据的代码。考生的核心任务是将模型的整数向量输出转换为一个结构化的实体标注列表,并通过 Flask API 返回这个列表。此步骤不仅实现了自动化的实体识别,更使得新媒体平台可以实时、高效地获取文本中的实体信息,为后续的数据分析和运营决策提供有力支撑。ner.pt是本任务提供的 PyTorch 模型权重文件。

【目标】

请按要求编写以下函数代码。

process函数

函数功能

将本任务提供的请求数据使用提供的模型进行推理。

将推理结果转换为结构化的实体标注列表。

对于不合理的序列,如单字实体 [‘O’, ‘B-LOC’, ‘O’] 和以 I- 起始的实体 [‘O’, ‘I-LOC’, ‘I-LOC’],将其作为非实体序列处理。

实体标注列表为一个嵌套字典列表,其中列表中每个元素及其说明见下表。

请在模块三文件夹下3.py文件中 #TODO 处补充函数代码,并运行代码块,确保能够实现以下目标:

① 正确地使用模型进行推理。

② 返回正确的结构化结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import torch
import torch.nn.functional as F
from torch import nn
from flask import Flask, request, jsonify

# 定义模型结构
class NERModel(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(NERModel, self).__init__()
self.embedding = nn.Embedding(input_dim, hidden_dim)
self.lstm = nn.LSTM(hidden_dim, hidden_dim)
self.fc = nn.Linear(hidden_dim, output_dim)

def forward(self, x):
embedded = self.embedding(x)
output, _ = self.lstm(embedded)
output = self.fc(output)
return output

# 加载模型权重
def load_model(model_path):
model = NERModel(input_dim=1000, hidden_dim=128, output_dim=5) # 这里根据实际情况设置input_dim和output_dim
model.load_state_dict(torch.load(model_path))
model.eval()
return model

# 处理请求数据
def process(model, input_data):
with torch.no_grad():
output = model(input_data)
output = F.softmax(output, dim=-1)
pred_labels = output.argmax(dim=-1).tolist()[0]

# 转换预测结果为实体标注列表
entities = []
entity = {}
for idx, label in enumerate(pred_labels):
if label == 0: # O
if entity:
entities.append(entity)
entity = {}
elif label == 1: # B-PER
if entity:
entities.append(entity)
entity = {}
entity['start'] = idx
entity['end'] = idx
entity['label'] = 'PER'
elif label == 2: # I-PER
if 'start' in entity:
entity['end'] = idx
# 添加其他实体类型的处理

if entity:
entities.append(entity)

return entities

# Flask API
app = Flask(__name__)
model = load_model("ner.pt")

@app.route('/predict', methods=['POST'])
def predict():
data = request.get_json()
input_data = torch.LongTensor(data['input']).unsqueeze(0)
entities = process(model, input_data)
return jsonify(entities)

if __name__ == '__main__':
app.run(debug=True)