TensorFlow与词嵌入报错:TypeError: unhashable type: 'numpy.ndarray'修复
解决RNN问答预测代码中的TypeError: unhashable type: 'numpy.ndarray'错误
先给你吃个定心丸:这个错误和unstack操作完全无关,问题出在你对TensorFlow中feed_dict的用法理解出现了偏差,咱们一步步来修复:
错误根源分析
你在sess.run()里写的feed_dict完全搞反了规则:
feed_dict的键必须是TensorFlow的占位符(placeholder)或者变量(Variable),而且必须是可哈希的类型;- 你现在把
tf.nn.embedding_lookup(W, x2)这种Tensor运算结果当成键,同时还把numpy数组y直接作为键——numpy数组是不可哈希的类型,这直接触发了TypeError。
另外,你还跳过了最基础的一步:没有定义输入数据的占位符,TensorFlow根本不知道该接收什么样的输入数据。
具体修复步骤
1. 先定义输入占位符
在graph初始化的最开头,先定义好输入序列x2和目标输出y的占位符,维度根据你的任务调整(比如输入是固定长度的问答序列,目标是单个词的索引):
tf.reset_default_graph() g = tf.Graph() with g.as_default(): # 先定义占位符!根据你的实际数据维度调整 sequence_length = 10 # 假设你的输入序列长度是10,改成你自己的数值 x2 = tf.placeholder(tf.int32, [None, sequence_length]) # 输入序列的词索引数组 y = tf.placeholder(tf.int32, [None]) # 目标输出的词索引(单个词) # 后面是你原来的embedding、RNN定义代码...
2. 修正feed_dict的写法
feed_dict的键是刚才定义的占位符,值是你生成的numpy数组(也就是np.array(list(vocab_processor.transform([s])))得到的结果),不需要在feed_dict里做embedding_lookup——因为你已经在graph里用tf.nn.embedding_lookup(W, x2)处理了输入:
# 假设你已经生成了x2_numpy和y_numpy这两个numpy数组 _,loss, pred_ = sess.run([optimizer, cost, pred], feed_dict = {x2: x2_numpy, y: y_numpy})
3. 修正损失函数的维度匹配
你的损失函数用了tf.nn.l2_loss(pred-y),但pred是embedding维度的Tensor,而y是词索引,需要先转成embedding向量才能计算损失:
# 在定义cost之前,先把y转成embedding向量 y_embedding = tf.nn.embedding_lookup(W, y) cost = tf.reduce_mean(tf.nn.l2_loss(pred - y_embedding))
4. 其他优化建议
- 你的
NHIDDEN()返回1,这个隐藏层维度太小了,实际任务里建议调大到128/256,不然模型根本学不到有效特征; - 确保
vocab_size、embedding_dim等参数和你的预训练词向量完全匹配,避免维度不兼容的问题。
修正后的完整核心代码片段
import tensorflow.contrib as ct def NHIDDEN(): return 128 # 调大隐藏层维度 tf.reset_default_graph() g = tf.Graph() with g.as_default(): # 定义输入占位符 sequence_length = 10 # 根据你的数据调整 x2 = tf.placeholder(tf.int32, [None, sequence_length]) y = tf.placeholder(tf.int32, [None]) # RNN输出层权重和偏置 weights = { 'out': tf.Variable(tf.random_normal([NHIDDEN(), embedding_dim])) } biases = { 'out': tf.Variable(tf.random_normal([embedding_dim])) } with tf.name_scope("embedding"): W = tf.Variable(tf.constant(0.0, shape=[vocab_size, embedding_dim]), trainable=False, name="W") embedding_placeholder = tf.placeholder(tf.float32, [vocab_size, embedding_dim]) embedding_init = W.assign(embedding_placeholder) preimage = tf.nn.embedding_lookup(W, x2) # 重塑输入并构建RNN x_unstack = tf.unstack(preimage, axis=1) # 明确指定axis,避免歧义 rnn_cell = ct.rnn.MultiRNNCell([ct.rnn.BasicLSTMCell(NHIDDEN()), ct.rnn.BasicLSTMCell(NHIDDEN())]) outputs, states = ct.rnn.static_rnn(rnn_cell, x_unstack, dtype=tf.float32) # 取最后一个输出做预测 pred = tf.matmul(outputs[-1], weights['out']) + biases['out'] # 修正损失函数 y_embedding = tf.nn.embedding_lookup(W, y) cost = tf.reduce_mean(tf.nn.l2_loss(pred - y_embedding)) optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost) step = 0 acc_total = 0 loss_total = 0 # 假设你已经加载了预训练词向量到embedding_vectors,生成了x2_numpy和y_numpy with tf.Session(graph = g) as sess: sess.run(tf.global_variables_initializer()) # 初始化预训练词向量 sess.run(embedding_init, feed_dict={embedding_placeholder: embedding_vectors}) while step < 100: # 改成你的训练迭代次数 _,loss, pred_ = sess.run([optimizer, cost, pred], feed_dict = {x2: x2_numpy, y: y_numpy}) loss_total += loss print("Step {}, Avg Loss = {:.6f}".format(step, loss_total/(step+1))) step += 1 print ("Finished Optimization")
内容的提问来源于stack exchange,提问作者johnsmith
相关产品推荐
相关产品推荐

