Bi-LSTM+CRF模型训练报错:NumPy数组转Tensor失败(不支持list类型)
问题修复方案
核心报错原因
报错ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type list)的根源:
- 处理后的
Name列是变长序列列表,而CompanyId、TableTypeCode是one-hot编码后的数值型列,两者无法直接合并成模型可接收的张量 - 原模型结构错误,未考虑多输入(文本序列+数值特征)的适配逻辑,也未按需求集成CRF层
完整修复代码
import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences from keras.utils import to_categorical from keras.layers import Input, Embedding, LSTM, Dense, Bidirectional, Concatenate from keras.models import Model import tensorflow_addons as tfa # 加载数据 df = pd.read_excel("data.xlsx") X = df[['CompanyId', 'Name', 'TableTypeCode']] y = df['BlockName'] # 1. 预处理文本特征(Name) X['Name'] = X['Name'].astype(str) tokenizer = Tokenizer() tokenizer.fit_on_texts(X['Name']) # 先拟合所有文本,再生成序列 name_sequences = tokenizer.texts_to_sequences(X['Name']) # 对序列做padding,统一长度(取最长序列或自定义固定长度) max_seq_len = max([len(seq) for seq in name_sequences]) name_padded = pad_sequences(name_sequences, maxlen=max_seq_len, padding='post', truncating='post') # 2. 预处理数值/类别特征(CompanyId、TableTypeCode) # One-hot编码 cat_features = pd.get_dummies(X[['CompanyId', 'TableTypeCode']]) # 转换为numpy数组 cat_np = cat_features.values # 3. 处理标签 encoder = LabelEncoder() y_encoded = encoder.fit_transform(y) y_categorical = to_categorical(y_encoded) n_classes = len(encoder.classes_) # 4. 划分训练测试集 X_name_train, X_name_test, X_cat_train, X_cat_test, y_train, y_test = train_test_split( name_padded, cat_np, y_categorical, test_size=0.2, random_state=42 ) # 5. 构建多输入Bi-LSTM+CRF模型 # 文本输入分支 text_input = Input(shape=(max_seq_len,), name='text_input') embedding = Embedding(input_dim=len(tokenizer.word_index)+1, output_dim=128)(text_input) bilstm = Bidirectional(LSTM(units=128, return_sequences=False))(embedding) # 数值特征输入分支 cat_input = Input(shape=(cat_features.shape[1],), name='cat_input') cat_dense = Dense(64, activation='relu')(cat_input) # 拼接两个分支的输出 concat = Concatenate()([bilstm, cat_dense]) dense = Dense(64, activation='relu')(concat) # 加入CRF层 crf = tfa.layers.CRF(n_classes, activation='softmax') output = crf(dense) model = Model(inputs=[text_input, cat_input], outputs=output) # CRF层使用专属损失函数 model.compile(optimizer='adam', loss=crf.loss, metrics=[crf.accuracy]) # 训练模型 model.fit( [X_name_train, X_cat_train], y_train, validation_data=([X_name_test, X_cat_test], y_test), epochs=10, batch_size=32 )
关键修复点说明
- 文本特征标准化:通过
pad_sequences将变长的Name序列统一为固定长度,彻底解决列表类型无法转换为张量的核心问题 - 多输入模型设计:将文本序列和数值类别特征拆分为两个独立输入分支,分别处理后再拼接输出,适配多模态数据的输入需求
- CRF层正确集成:使用
tfa.layers.CRF替代原有的Dense+softmax,同时配套使用CRF自带的损失函数与评估指标,符合序列标注任务的特性 - 预处理流程修正:先调用
tokenizer.fit_on_texts拟合全部文本数据,再转换为序列,确保编码规则的一致性
内容的提问来源于stack exchange,提问作者Harshit
相关产品推荐
相关产品推荐

