在Keras Sequential模型中使用Doc2Vec句向量做情感分析的报错解决
问题分析与解决方案
错误根源
你遇到的InvalidArgumentError本质是输入层和输入数据完全不匹配:
- Keras的
Embedding层是用来把非负整数索引(比如词在字典中的ID)转换成向量的,它要求输入必须是≥0的整数。但你喂给它的是Doc2Vec生成的浮点数向量(甚至包含负数,比如错误里的-19),这完全不符合Embedding层的输入规则,所以才会抛出“索引不在有效范围”的错误。 - 另外,你的Doc2Vec训练代码也有逻辑问题:把token直接拼接成字符串保存,
TaggedLineDocument会把每行当成一个单“词”的文档,这样训练出来的Doc2Vec向量根本没有语义价值,等于白训了。
分步骤修复方案
1. 先修复Doc2Vec的训练逻辑
Doc2Vec需要的是每个文档的token列表,而不是拼接后的字符串,正确的训练代码应该是这样:
from gensim.models.doc2vec import Doc2Vec, TaggedDocument # 假设x是已经分词后的句子列表,比如x = [["i", "love", "this", "film"], ["it", "sucks", "badly"], ...] tagged_docs = [TaggedDocument(words=tokens, tags=[str(idx)]) for idx, tokens in enumerate(x)] # 调整Doc2Vec参数:alpha和min_alpha的合理范围是0.025到0.0001,vector_size用128维比5维更能捕捉语义 d2v_model = Doc2Vec( tagged_docs, dm=0, # DBOW模式 window=5, vector_size=128, epochs=100, workers=32, dbow_words=1, alpha=0.025, min_alpha=0.0001 )
2. 生成有效的句向量
用修复后的模型生成每个句子的向量,确保输入是token列表:
import numpy as np # 生成(样本数, 向量维度)的2D数组 doc_vectors = np.array([d2v_model.infer_vector(tokens) for tokens in x])
3. 修改Keras模型,移除错误的Embedding层
既然我们已经有了预训练好的句向量,就不需要再用Embedding层做索引映射。根据你的需求,分两种情况调整模型:
情况A:继续使用LSTM层
LSTM要求输入是3D张量(样本数, 时间步长, 特征数),所以需要把2D的句向量reshape成3D:
from keras.models import Sequential from keras.layers import LSTM, Dense, Dropout model = Sequential() # input_shape=(时间步长, 特征数),这里把每个向量维度当作一个时间步,特征数为1 model.add(LSTM(200, dropout=0.2, recurrent_dropout=0.2, input_shape=(doc_vectors.shape[1], 1))) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy']) # 把2D向量reshape成3D doc_vectors_3d = doc_vectors.reshape(doc_vectors.shape[0], doc_vectors.shape[1], 1) # 开始训练 model.fit(doc_vectors_3d, y, batch_size=32, epochs=8, verbose=1)
情况B:用全连接层替代LSTM(更高效)
句向量本身已经是语义压缩后的表示,直接用全连接层就能完成分类,不需要LSTM:
model = Sequential() model.add(Dense(256, activation='relu', input_shape=(doc_vectors.shape[1],))) model.add(Dropout(0.2)) model.add(Dense(128, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy']) # 直接用2D的句向量输入即可 model.fit(doc_vectors, y, batch_size=32, epochs=8, verbose=1)
内容的提问来源于stack exchange,提问作者Ritesh Gawai
相关产品推荐
相关产品推荐

