我正在使用Keras(Theano后端)构建一个基于chacter的rnn模型。需要注意的一件事是,我不想使用预构建的损失函数。相反,我想计算某些数据点的损失。这就是我的意思。
矢量训练集及其标签如下所示:X_train = np.array([[0,1,2,3,4]])y_train = np.array([[1,2,3,4,5]])
但是出于某种原因,我用 0 替换了y_train中的第一个 k 元素。因此,例如,新y_train是
y_train = np.array([[0,0,3,4,5]])
我将前两个元素设置为 0 的原因是我不希望在计算损失时包含它们。换句话说,我想计算 X_train[2:] 和 y_train[2:] 之间的损失。
这是我的尝试。
import numpy as np
np.random.seed(0) # for reproducibility
from keras.preprocessing import sequence
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Embedding
from keras.layers import LSTM
from keras.layers.wrappers import TimeDistributed
X_train = np.array([[0,1,2,3,4]])
y_train = np.array([[0,0,3,4,5]])
y_3d = np.zeros((y_train.shape[0], y_train.shape[1], 6))
for i in range(y_train.shape[0]):
for j in range(y_train.shape[1]):
y_3d[i, j, y_train[i,j]] = 1
model = Sequential()
model.add(Embedding(6, 5, input_length=5, dropout=0.2))
model.add(LSTM(5, input_shape=(5, 12), return_sequences=True) )
model.add(TimeDistributed(Dense(6))) #output classes =6
model.add(Activation('softmax'))
from keras import backend as K
import theano.tensor as T
def custom_objective(y_true,y_pred):
# Find the last index of minimum value in y_true, axis=-1
# For example, y_train = np.array([[0,0,3,4,5]]) in my example, and
# I'd like to calculate the loss only between X_train[3:] and y_train[3:] because the values
# in y_train[:3] (i.e.0) are dummies. The following is pseudo code if y_true is 1-d numpy array, which is not true.
def rindex(y_true):
for i in range(len(y_true), -1, -1):
if y_true(i) == 0:
return i
starting_point = rindex(y_true)
return K.categorical_crossentropy(y_pred[starting_point:], y_true[starting_point:])
model.compile(loss=custom_objective,
optimizer='adam',
metrics=['accuracy'])
model.fit(X_train, y_t, batch_size=batch_size, nb_epoch=1)
从小错误(例如第 35 行中的错误偏执和最后一行中的错误变量名称)来看,您的代码有两个问题。
首先,您定义的模型将返回每个时间步的类的概率分布矩阵(由于 softmax 激活)。但在custom_objective
中,您将输出视为向量。您已经正确地将y_train
转换为上面的矩阵。
因此,您首先必须获得实际的预测,最简单的情况是分配具有最高概率的类,即:
y_pred = y_pred.argmax(axis=2)
y_true = y_true.argmax(axis=2) # this reconstructs y_train resp. a subset thereof
第二个问题是你把这些当作实变量(numpy数组)。但是,y_true
和y_pred
是符号张量。您收到的错误清楚地说明了由此产生的问题之一:
TypeError: object of type 'TensorVariable' has no len()
TensorVariable
没有长度,因为在插入实际值之前根本不知道!这也使得以你实现它的方式进行迭代是不可能的。顺便说一下,在迭代真实向量的情况下,你可能希望像这样向后迭代:range(len(y_true)-1, -1, -1)
不要越界,甚至for val in y_true[::-1]
为了实现你想要的,你需要将相应的变量视为它们,并使用为张量提供的方法。
此计算的中心是查找最小值的argmin
函数。默认情况下,这将返回此最小值的第一次出现。由于你想找到这个最小值的最后一次出现,我们需要将其应用于反向张量,并将其计算回原始向量的索引。
starting_point = y_true.shape[0] - y_true[::-1].argmin() - 1
可能有一个更简单的解决方案来解决您的问题,因为看起来您正在尝试实现诸如屏蔽之类的东西。您可能需要查看嵌入层的mask_zero=True
标志。不过,这将适用于输入端。