Keras中RNN(LSTM/GRU)处理稀疏张量报错排查
问题
我正在用Python3构建医疗文本分类神经网络,计划采用LSTM层搭配Dense层实现。因数据集采用单词级独热编码后内存浪费严重,需使用稀疏张量表示数据。但构建模型时出现TypeError报错,提示无法将SparseTensor转换为Tensor。我尝试改用SimpleRNN、GRU层,或在LSTM前添加Dense层,均出现相同报错;使用密集张量的小规模模型可正常运行。
模型代码
import tensorflow as tf in_shape=(8, 4581, 2126) out_size=200 data= tf.sparse.SparseTensor(indices=[[0,0,0]],values=[1],dense_shape = in_shape) X_i = tf.keras.Input(shape= tf.shape(data)[1:], sparse=True) #shape=(None,) X = tf.keras.layers.LSTM(in_shape[-1])(X_i) X = tf.keras.layers.Dense(out_size)(X_i) X = tf.keras.layers.Activation('sigmoid')(X) model = tf.keras.Model(X_i, X)
参数说明
- 4581:测试文本的最大长度
- 2126:经过裁剪后的词汇表大小
- 8:使用密集张量且无内存问题时的样本数
报错信息
起始部分
TypeError Traceback (most recent call last) ~/Henv/lib/python3.6/site-packages/tensorflow/python/framework/tensor_util.py in make_tensor_proto(values, dtype, shape, verify_shape, allow_broadcast) 548 try: --> 549 str_values = [compat.as_bytes(x) for x in proto_values] 550 except TypeError: ~/Henv/lib/python3.6/site-packages/tensorflow/python/framework/tensor_util.py in <listcomp>(.0) 548 try: --> 549 str_values = [compat.as_bytes(x) for x in proto_values] 550 except TypeError:
结尾部分
TypeError: Failed to convert object of type <class 'tensorflow.python.framework.sparse_tensor.SparseTensor'> to Tensor. Contents: SparseTensor(indices=Tensor("inputs:0", shape=(None, 3), dtype=int64), values=Tensor("inputs_1:0", shape=(None,), dtype=float32), dense_shape=Tensor("inputs_2:0", shape=(3,), dtype=int64)). Consider casting elements to a supported type.
注:实际报错发生在LSTM层,但未在报错信息中显示。
解决方案
核心问题
TensorFlow的循环层(LSTM/GRU/SimpleRNN)以及普通Dense层不直接支持稀疏张量输入,它们只能处理密集张量,这是报错的根本原因。你尝试的几种改法都绕不开这个限制。另外原代码存在逻辑错误:LSTM层的输出被直接丢弃,后续Dense层错误地连接到输入张量X_i,完全没用到序列特征。
最优解决步骤
1. 替换独热编码为嵌入层(Embedding)
单词级独热编码本身内存效率极低,没必要用稀疏张量硬扛。tf.keras.layers.Embedding是NLP任务的标准方案,它能把整数形式的单词索引(比如每个单词对应0~2125的整数)转换成低维稠密向量,既省内存又能提升模型效果。
2. 调整模型结构
把稀疏独热输入换成整数索引输入,通过嵌入层转成稠密张量后,再接入LSTM和Dense层。修改后的示例代码:
import tensorflow as tf max_seq_len = 4581 vocab_size = 2126 out_size = 200 # 输入为整数索引,形状:(None, max_seq_len) X_i = tf.keras.Input(shape=(max_seq_len,)) # 嵌入层将索引转为稠密向量,输出形状(None, max_seq_len, 128) X = tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=128)(X_i) # LSTM层处理序列特征 X = tf.keras.layers.LSTM(128)(X) # 分类输出层(合并激活函数) X = tf.keras.layers.Dense(out_size, activation='sigmoid')(X) model = tf.keras.Model(X_i, X) model.summary()
特殊场景替代方案(不推荐)
若因特殊需求必须保留稀疏独热输入,可在循环层前手动将稀疏张量转为稠密张量,但这会失去内存优势:
import tensorflow as tf max_seq_len = 4581 vocab_size = 2126 out_size = 200 X_i = tf.keras.Input(shape=(max_seq_len, vocab_size), sparse=True) # 手动转换为稠密张量 X_dense = tf.keras.layers.Lambda(lambda x: tf.sparse.to_dense(x))(X_i) X = tf.keras.layers.LSTM(vocab_size)(X_dense) X = tf.keras.layers.Dense(out_size, activation='sigmoid')(X) model = tf.keras.Model(X_i, X)
内容的提问来源于stack exchange,提问作者Ide
相关产品推荐
相关产品推荐

