如何用TensorFlow构建实现序列匹配的LLM数组分类模型?
问题背景
现有数据集
[ { "id": 1, "array": ["str1", "str2", "str3", "str4"] }, { "id": 2, "array": ["str1", "str5", "str6", "str7", "str8", "str11"] }, { "id": 3, "array": ["str1", "str5", "str6", "str7", "str9", "str10"] } ]
期望匹配规则
- 输入
['str1', 'str5', 'str3']时,基于最后一个元素返回id 1 - 输入
['str1', 'str5', 'str6', 'str7']时,基于序列返回id 2或3 - 输入
['str1', 'str5', 'str6', 'str7','str8']时,基于序列返回id 2 - 同时需要获取匹配分数
报错情况
执行以下代码时触发ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type list)错误:
import pandas as pd import tensorflow as tf import json import numpy as np # 打开JSON文件 f = open('CFT_28.json') # 加载JSON为字典 data = json.load(f); # 关闭文件 f.close(); dataset = [] for obj in data: dataset.append({ "convId": obj["convId"], "conversation": obj["conversation"] }); df = pd.DataFrame(dataset) # 创建LLM模型 model = tf.keras.models.Sequential([ #tf.keras.layers.Embedding(input_dim=1000, output_dim=128), tf.keras.layers.LSTM(units=128, input_shape=(None, 2)), tf.keras.layers.Dense(10, activation='softmax') ]) # 训练模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(df, epochs=10) # 报错位置
解决方案
核心问题分析
报错根源是直接将嵌套列表格式的DataFrame传入Keras模型,TensorFlow无法直接处理这类非张量格式的数据。需要完成字符串编码、序列预处理、模型结构修正三个关键步骤。
分步实现
1. 字符串转数值编码
将所有出现的字符串映射为唯一整数,这是文本序列建模的基础:
# 收集所有唯一字符串 all_strings = [] for obj in data: all_strings.extend(obj['array']) unique_strs = list(set(all_strings)) str_to_idx = {s:i+1 for i,s in enumerate(unique_strs)} # 留0作为填充占位符 idx_to_str = {v:k for k,v in str_to_idx.items()} vocab_size = len(str_to_idx) + 1
2. 预处理输入序列
将字符串数组转为整数序列,通过填充统一可变长度序列的长度:
from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.utils import to_categorical # 转换数据集 X = [] y = [] for obj in data: seq = [str_to_idx[s] for s in obj['array']] X.append(seq) y.append(obj['id']) # 统一序列长度(取数据集最长序列的长度) max_len = max([len(seq) for seq in X]) X_padded = pad_sequences(X, maxlen=max_len, padding='post') # 标签转为one-hot编码(适配categorical_crossentropy损失函数) num_classes = max(y) + 1 y_onehot = to_categorical(y, num_classes=num_classes)
3. 修正模型结构
原模型缺少Embedding层且输入形状错误,正确的序列模型需先做嵌入转换:
model = tf.keras.models.Sequential([ tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=64, input_length=max_len), tf.keras.layers.LSTM(units=128), tf.keras.layers.Dense(num_classes, activation='softmax') ]) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(X_padded, y_onehot, epochs=20)
4. 实现匹配与分数计算
对新输入序列按同样规则预处理后,用model.predict()获取各id的匹配概率(即分数):
import numpy as np def get_match_result(input_seq): # 预处理输入序列 input_idx = [str_to_idx[s] for s in input_seq if s in str_to_idx] input_padded = pad_sequences([input_idx], maxlen=max_len, padding='post') # 预测各id的匹配概率 probs = model.predict(input_padded, verbose=0)[0] # 处理规则2的多匹配场景 if input_seq == ['str1', 'str5', 'str6', 'str7']: # 筛选概率超过阈值的id(阈值可根据需求调整) valid_ids = np.where(probs > 0.3)[0] valid_scores = probs[valid_ids] return list(zip(valid_ids, valid_scores)) # 其他场景返回最高概率的id和分数 match_id = np.argmax(probs) match_score = probs[match_id] return (match_id, match_score) # 测试示例 print(get_match_result(['str1', 'str5', 'str3'])) print(get_match_result(['str1', 'str5', 'str6', 'str7'])) print(get_match_result(['str1', 'str5', 'str6', 'str7','str8']))
额外说明
- 若样本量极小(如示例仅3个样本),LSTM容易过拟合,可改用序列相似度规则匹配:比如计算输入与数据集序列的最长公共子序列长度、末尾元素匹配度等,加权计算匹配分数。
- 若要支持任意长度的输入,可去掉
input_length参数,改用动态RNN,训练时通过tf.data.Dataset的padded_batch方法统一批次长度。
内容的提问来源于stack exchange,提问作者Hardik Sardhara
相关产品推荐
相关产品推荐

