Keras:模型的正确性和自定义指标的问题

Keras: correctness of model and issues with custom metric

我正在尝试为进程创建自动编码器。每个过程都是一系列事件,每个事件表示为 0 到 461 之间的数字(重要的是,数字接近的事件不相似,数字是随机给出的)。每个进程的长度为 60,进程总数为 n。所以我的输入数据是数组 (n, 60).

首先,我创建了嵌入层以将事件数字转换为单热表示:

BLOCK_LEN = 60
EVENTS_CNT = 462

input = Input(shape=(BLOCK_LEN,))
embedded = Embedding(input_dim=EVENTS_CNT+1, input_length=BLOCK_LEN, output_dim=200)(input)
emb_model = Model(input, embedded)
emb_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 60)                0         
_________________________________________________________________
embedding_1 (Embedding)      (None, 60, 200)           92600     
=================================================================
Total params: 92,600
Trainable params: 92,600
Non-trainable params: 0
_________________________________________________________________
None

其次,我创建了主要的 Seq2Seq 模型(使用 that library):

seq_model = Seq2Seq(batch_input_shape=(None, BLOCK_LEN, 200), hidden_dim=200, output_length=BLOCK_LEN, output_dim=EVENTS_CNT)

生成的模型:

model = Sequential()
model.add(emb_model)
model.add(seq_model)
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
model_1 (Model)              (None, 60, 200)           92600     
_________________________________________________________________
model_12 (Model)             (None, 60, 462)           1077124   
=================================================================
Total params: 1,169,724
Trainable params: 1,169,724
Non-trainable params: 0
_________________________________________________________________

我也有自己的准确度指标(因为库的准确度不适合我的数据):

def symbol_acc(y_true, y_pred):
    isEqual = K.cast(K.equal(y_true, y_pred), K.floatx())
    return K.mean(isEqual)

并编译:

model.compile(loss=tf.losses.sparse_softmax_cross_entropy,optimizer='adam', target_tensors=[tf.placeholder(tf.int32, [None, 60])], metrics=[symbol_acc])

为什么编译看起来像这样:起初模型多了一层model.add(TimeDistributed(Dense(EVENTS_CNT, activation='softmax'))),编译是model.compile(loss=custom_categorical_crossentropy, optimizer='rmsprop', metrics=[symbol_acc])。但是这样的模型产生了一个错误"ValueError: Error when checking target: expected time_distributed_2 to have 3 dimensions, but got array with shape (2714, 60)"。现在各种造型都合适

但现在我有新的问题(我故事的关键时刻):公制 symbol_acc 中的形状不同:

Shapes (symbol_acc): (?, 60) (?, ?, 462)

因此 true 数组的形状为 (?, 60),预测为 - (?, ?, 462)true 60 values中的每个值是0到461之间的数字(代表事件的真实数量)并且predicted 60 ones中的每个值是大小为462的向量,每个数字的概率分布为0到 461(对于 462 个事件中的每一个)(对于 462 个事件中的每一个)。我想使 truepredicted 形状相同:对于 60 个值中的每一个,都使大小为 462 的向量在事件编号位置上为 1,在其他位置上为 0。

所以我的问题:

  1. 如果在拟合模型之前我没有数据,如何更改度量中数组的形状?我得到的最大值是 K.gather(K.eye(462), tf.cast(number, tf.int32)):该代码创建了单热数组,其中 1 在 number 位置。但是我不明白如何在不知道这个数组的情况下将它应用于数组。
  2. 也许有更简单的方法来解决这个问题?

我是 keras 和 NNs 的新手,所以我不确定所有步骤是否正确。如果您发现任何错误,请报告。

正如我之前测试的那样,除非其形状与模型的预测形状相同,否则使用 target_tensors 将不起作用。

所以,不能违反这个一般规则:

Your output data must have the same shape as your model's ouptut

这使得y_truey_pred肯定具有相同的形状。

您需要使用 to_categorical().

使输出数据适应模型的形状
from keras.utils import to_categorical
one_hot_X = to_categorical(X_train,462)

有了它,您只需正常训练您的模型,而无需在损失和准确性方面创建变通方法:

model.fit(X_train, one_hot_X,...)

如果这样做 运行 遇到内存问题,您可以考虑创建一个生成器,它只会为每个批次转换部分数据:

def batch_generator(batch_size):
    
    while True: #keras generators must be infinite

        #you may want to manually shuffle X_train here

        for i in range(len(X_train)//batch_size): #make sure len is a multiple of batch_size
            
            x = X_train[i*batch_size:(i+1)*batch_size]
            y = to_categorical(x,462)

            yield (x,y)

训练:

model.fit_generator(batch_generator(size),....)

修正你在这个案例中的准确性

既然我们更了解你在做什么,你的准确性应该使用 K.argmax 来获得准确的结果(而不是考虑 462 个选项,而它应该是 1,正确与否)

(我的旧答案是错误的,因为我忘记了 y_true 是准确的,但 y_pred 是近似值)。

def symbol_acc(y_true, y_pred):
    y_true = K.argmax(y_true) #this gets the class as an integer (comparable to X_train)
    y_pred = K.argmax(y_pred) #transforming (any,60,462) into (any,60)

    isEqual = K.cast(K.equal(y_true, y_pred), K.floatx())
    return K.mean(isEqual)

稍作更正:

嵌入不会创建“单热”表示,它们只会创建多特征表示。 (one hot 严格适用于向量中只有一个元素为 1 的情况,但嵌入可以自由为任何元素中的任何值)。