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 个事件中的每一个)。我想使 true
与 predicted
形状相同:对于 60 个值中的每一个,都使大小为 462 的向量在事件编号位置上为 1,在其他位置上为 0。
所以我的问题:
- 如果在拟合模型之前我没有数据,如何更改度量中数组的形状?我得到的最大值是
K.gather(K.eye(462), tf.cast(number, tf.int32))
:该代码创建了单热数组,其中 1 在 number
位置。但是我不明白如何在不知道这个数组的情况下将它应用于数组。
- 也许有更简单的方法来解决这个问题?
我是 keras 和 NNs 的新手,所以我不确定所有步骤是否正确。如果您发现任何错误,请报告。
正如我之前测试的那样,除非其形状与模型的预测形状相同,否则使用 target_tensors
将不起作用。
所以,不能违反这个一般规则:
Your output data must have the same shape as your model's ouptut
这使得y_true
和y_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 的情况,但嵌入可以自由为任何元素中的任何值)。
我正在尝试为进程创建自动编码器。每个过程都是一系列事件,每个事件表示为 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 个事件中的每一个)。我想使 true
与 predicted
形状相同:对于 60 个值中的每一个,都使大小为 462 的向量在事件编号位置上为 1,在其他位置上为 0。
所以我的问题:
- 如果在拟合模型之前我没有数据,如何更改度量中数组的形状?我得到的最大值是
K.gather(K.eye(462), tf.cast(number, tf.int32))
:该代码创建了单热数组,其中 1 在number
位置。但是我不明白如何在不知道这个数组的情况下将它应用于数组。 - 也许有更简单的方法来解决这个问题?
我是 keras 和 NNs 的新手,所以我不确定所有步骤是否正确。如果您发现任何错误,请报告。
正如我之前测试的那样,除非其形状与模型的预测形状相同,否则使用 target_tensors
将不起作用。
所以,不能违反这个一般规则:
Your output data must have the same shape as your model's ouptut
这使得y_true
和y_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 的情况,但嵌入可以自由为任何元素中的任何值)。