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

时间:2018-05-14 22:00:54

标签: python tensorflow neural-network keras metrics

我正在尝试为进程创建自动编码器。每个过程都是一系列事件,每个事件代表从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
_________________________________________________________________

此外,我有自己的准确度指标(因为lib的准确度并不适合我的数据):

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:期望time_distributed_2具有3个维度,但是得到了具有形状的数组(2714,60)"。现在所有形状都适合。

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

  

形状(symbol_acc):(?,60)(?,?,462)

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

所以我的问题:

  1. 如果在拟合模型之前没有数据,如何在度量中更改数组的形状?我得到的Maxumum是K.gather(K.eye(462), tf.cast(number, tf.int32)):该代码创建一个在number位置有1的热门数组。但我不明白如何在不知道这个数组的情况下将它应用于数组。
  2. 也许有更简单的方法来解决这个问题?
  3. 我是keras和NN的新手,因此我不确定所有步骤是否正确。如果您发现任何错误,请报告。

1 个答案:

答案 0 :(得分:2)

正如我之前测试的那样,使用target_tensors除非其形状与模型预测的形状相同,否则无法使用y_true

因此,不能违反这条一般规则:

  

您的输出数据必须与您的型号“ouptut”具有相同的形状

这使得y_predfrom keras.utils import to_categorical one_hot_X = to_categorical(X_train,462) 肯定具有相同的形状。

您需要的是使用to_categorical()将输出数据调整为模型的形状。

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

确定此案例的准确性

现在我们已经更清楚地知道您正在做什么,您的准确性应该使用y_true来获得准确的结果(而不是考虑462选项,而它应该是1,正确与否)

(我的回答是错误的,因为我忘了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) 是近似的。

{{1}}

只是一个小小的修正:

嵌入不会创造出一个热门的"表示,他们只是创建一个多特征表示。 (一个热点严格地说是向量中只有一个元素是一个的情况,但嵌入对任何元素中的任何值都是自由的)。