我在tflearn中有一个lstm网络,它在给定前面单词上下文的情况下,按顺序预测下一个单词。这些单词作为特定大小词汇的索引输入到网络中,并以二进制类的形式输出,例如:
上下文:[45,243,11906,4,2,0,0,0,0]
标签:[0,0,0…….1,0,0,….0,0,0](人声长度)
然而,由于我在回归层中使用了“范畴交叉熵”目标函数,所以模型每次都会学习预测几乎相同的单词。
我想尝试基于word embeddings(word2vec)来评估损失,我已经为数据集生成了这个工具。因此,如果模型预测的是“你好”,而实际情况是“你好”,那么它的损失要比预测的“比萨饼”低得多。方案是计算两个嵌入向量之间的余弦,以获得单词之间的“相似性”。
我正在将此自定义丢失函数添加到tflearn安装中的objectives.py文件中,但在尝试将预测转换为嵌入向量时遇到了障碍。
tflearn/objectives.py:
vocab = np.loadtxt('/home/vocab.txt',dtype='str')
embedding_model = gensim.models.Word2Vec.load('/home/embedding')
def embedded_similarity(y_pred, y_true):
global vocab, embedding_model
with tf.name_scope("Similarity"):
#convert one-hot format to indices of max values (predictions)
pred_max = tf.argmax(y_pred,dimension=1)
true_max = tf.argmax(y_true,dimension=1)
#convert indices into embedded vectors
pred_vectors = tf.map_fn(lambda x: embedding_model[vocab[x]], pred_max)
true_vectors = tf.map_fn(lambda x: embedding_model[vocab[x]], true_max)
#calc dot product
dot_products = tf.reduce_sum(tf.mul(pred_vectors,true_vectors),axis=1)
#return inverse mean of dot products
return -1*(tf.reduce_mean(dot_products))
返回的错误为:
ValueError: Index out of range using input dim 0; input has only 0 dims for 'Similarity/map/while/strided_slice' (op: 'StridedSlice') with input shapes: [], [1], [1], [1].
这表示我不能使用张量来索引vocab(numpy数组)。但是,我不能使用eval()来获取张量的值,因为这不是在会话中运行的。因此,我需要一种方法来建立索引的一维张量到包含相应字向量的张量的转换,以便计算损失。
任何关于这个问题的帮助,或者其他评估我的模型的方法,都是非常感谢的。
最佳答案
我用tf.gather来解决这个问题。另外,我添加了根据算法分类的可信度进行缩放,以修复我遇到的无法计算渐变的错误。下面是代码:
objectives.py标题处的代码:
import numpy as np
import gensim
vocab = np.genfromtxt('/home/vocab.txt',dtype='str')
embedding_model = gensim.models.Word2Vec.load('/home/embedding')
i2v = []
for v in vocab:
i2v.append(embedding_model[v])
嵌入的相似性(y_pred,y_true):
global i2v
with tf.name_scope("Similarity"):
i2v_tensors = [ tf.cast(tf.constant(iv), tf.float32) for iv in i2v ]
i2v_tensorarray = tf.pack(i2v_tensors)
#convert one-hot to indices
pred_max = tf.cast(tf.argmax(y_pred,dimension=1), tf.int32)
true_max = tf.cast(tf.argmax(y_true,dimension=1), tf.int32)
#extract probabilities for scaling later
pred_iter = tf.concat(tf.constant(1),[y_pred,tf.pack([tf.cast(pred_max,tf.float32)],axis=1)])
confidence_scaler = 1 / tf.map_fn(lambda x: tf.gather(x, tf.cast(tf.gather(x,tf.constant(5002)),tf.int32)), pred_iter, tf.float32)
#convert indices into vectors (of type tensor)
pred_vectors = tf.map_fn(lambda x: tf.gather(i2v_tensorarray, x), pred_max, tf.float32)
true_vectors = tf.map_fn(lambda x: tf.gather(i2v_tensorarray, x), true_max, tf.float32)
#calc dot product
dot_products = tf.reduce_sum(tf.mul(pred_vectors,true_vectors),axis=1)
#divide by magnitudes
pred_magnitudes = tf.sqrt(tf.reduce_sum(tf.mul(pred_vectors,pred_vectors),axis=1))
true_magnitudes = tf.sqrt(tf.reduce_sum(tf.mul(true_vectors,true_vectors),axis=1))
cosines = dot_products / tf.mul(pred_magnitudes,true_magnitudes)
loss = -1*tf.cast(cosines, tf.float32) + 2 #min loss is 1, max is 3
scaled_loss = tf.multiply(loss, confidence_scaler)
# loss = -1*cosines + 1
# return inverse sum of dot products
return tf.reduce_mean(scaled_loss)
但是,我遇到了一个奇怪的虫子。当我尝试适应模型时,代码运行得非常好,直到它列出培训和验证示例的数量,如下所示:
---------------------------------
Training samples: 800
Validation samples: 200
然后输出只是冻结,而不是整个计算机。我无法控制代码,必须启动另一个终端。系统似乎也没有明显的减速,我试着将训练集大小和批次大小都减少到可笑的低数字,但没有结果。
我会将这个问题标记为已解决,因为我回答了我遇到的主要问题,但如果有人在遇到这种行为之前请评论。谢谢!
关于python - tflearn自定义损失函数用于余弦相似度,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41913121/