创建keras回调以在训练期间保存每个批次的模型预测和目标 [英] Create keras callback to save model predictions and targets for each batch during training
问题描述
我正在Keras(tensorflow后端)中构建一个简单的顺序模型.在培训期间,我想检查各个培训批次和模型预测.因此,我试图创建一个自定义Callback
,以保存每个训练批次的模型预测和目标.但是,该模型不是使用当前批次进行预测,而是使用整个训练数据.
I am building a simple Sequential model in Keras (tensorflow backend). During training I want to inspect the individual training batches and model predictions. Therefore, I am trying to create a custom Callback
that saves the model predictions and targets for each training batch. However, the model is not using the current batch for prediction, but the entire training data.
如何仅将当前的培训批次移交给Callback
?
How can I hand over only the current training batch to the Callback
?
又如何访问Callback
保存在self.predhis和self.targets中的批次和目标?
And how can I access the batches and targets that the Callback
saves in self.predhis and self.targets?
我当前的版本如下:
callback_list = [prediction_history((self.x_train, self.y_train))]
self.model.fit(self.x_train, self.y_train, batch_size=self.batch_size, epochs=self.n_epochs, validation_data=(self.x_val, self.y_val), callbacks=callback_list)
class prediction_history(keras.callbacks.Callback):
def __init__(self, train_data):
self.train_data = train_data
self.predhis = []
self.targets = []
def on_batch_end(self, epoch, logs={}):
x_train, y_train = self.train_data
self.targets.append(y_train)
prediction = self.model.predict(x_train)
self.predhis.append(prediction)
tf.logging.info("Prediction shape: {}".format(prediction.shape))
tf.logging.info("Targets shape: {}".format(y_train.shape))
推荐答案
注意:此答案已过时,仅适用于TF1.检查@bers的答案,以获取在TF2上测试过的解决方案.
NOTE: this answer is outdated and only works with TF1. Check @bers's answer for a solution tested on TF2.
模型编译后,y_true
的占位符张量在model.targets
中,而y_pred
的占位符张量在model.outputs
中.
After model compilation, the placeholder tensor for y_true
is in model.targets
and y_pred
is in model.outputs
.
要在每个批次中保存这些占位符的值,您可以:
To save the values of these placeholders at each batch, you can:
- 首先将这些张量的值复制到变量中.
- 在
on_batch_end
中评估这些变量,并存储结果数组.
- First copy the values of these tensors into variables.
- Evaluate these variables in
on_batch_end
, and store the resulting arrays.
现在涉及到第1步,因为您必须在训练功能model.train_function
上添加tf.assign
op.使用当前的Keras API,可以在构造训练函数时为K.function()
提供一个fetches
参数来实现.
Now step 1 is a bit involved because you'll have to add an tf.assign
op to the training function model.train_function
. Using current Keras API, this can be done by providing a fetches
argument to K.function()
when the training function is constructed.
在model._make_train_function()
中有一行:
self.train_function = K.function(inputs,
[self.total_loss] + self.metrics_tensors,
updates=updates,
name='train_function',
**self._function_kwargs)
包含tf.assign
ops的fetches
参数可以通过model._function_kwargs
提供(仅在Keras 2.1.0之后的 可用).
The fetches
argument containing the tf.assign
ops can be provided via model._function_kwargs
(only works after Keras 2.1.0).
例如:
from keras.layers import Dense
from keras.models import Sequential
from keras.callbacks import Callback
from keras import backend as K
import tensorflow as tf
import numpy as np
class CollectOutputAndTarget(Callback):
def __init__(self):
super(CollectOutputAndTarget, self).__init__()
self.targets = [] # collect y_true batches
self.outputs = [] # collect y_pred batches
# the shape of these 2 variables will change according to batch shape
# to handle the "last batch", specify `validate_shape=False`
self.var_y_true = tf.Variable(0., validate_shape=False)
self.var_y_pred = tf.Variable(0., validate_shape=False)
def on_batch_end(self, batch, logs=None):
# evaluate the variables and save them into lists
self.targets.append(K.eval(self.var_y_true))
self.outputs.append(K.eval(self.var_y_pred))
# build a simple model
# have to compile first for model.targets and model.outputs to be prepared
model = Sequential([Dense(5, input_shape=(10,))])
model.compile(loss='mse', optimizer='adam')
# initialize the variables and the `tf.assign` ops
cbk = CollectOutputAndTarget()
fetches = [tf.assign(cbk.var_y_true, model.targets[0], validate_shape=False),
tf.assign(cbk.var_y_pred, model.outputs[0], validate_shape=False)]
model._function_kwargs = {'fetches': fetches} # use `model._function_kwargs` if using `Model` instead of `Sequential`
# fit the model and check results
X = np.random.rand(10, 10)
Y = np.random.rand(10, 5)
model.fit(X, Y, batch_size=8, callbacks=[cbk])
除非可以将样品数量除以批次大小,否则最终批次的大小将与其他批次不同.因此,在这种情况下不能使用K.variable()
和K.update()
.您必须改为使用tf.Variable(..., validate_shape=False)
和tf.assign(..., validate_shape=False)
.
Unless the number of samples can be divided by the batch size, the final batch will have a different size than other batches. So K.variable()
and K.update()
can't be used in this case. You'll have to use tf.Variable(..., validate_shape=False)
and tf.assign(..., validate_shape=False)
instead.
要验证保存的数组的正确性,可以在training.py
中添加一行以打印出经过改组的索引数组:
To verify the correctness of the saved arrays, you can add one line in training.py
to print out the shuffled index array:
if shuffle == 'batch':
index_array = _batch_shuffle(index_array, batch_size)
elif shuffle:
np.random.shuffle(index_array)
print('Index array:', repr(index_array)) # Add this line
batches = _make_batches(num_train_samples, batch_size)
改组后的索引数组应打印出来:
The shuffled index array should be printed out during fitting:
Epoch 1/1
Index array: array([8, 9, 3, 5, 4, 7, 1, 0, 6, 2])
10/10 [==============================] - 0s 23ms/step - loss: 0.5670
您可以检查cbk.targets
是否与Y[index_array]
相同:
And you can check if cbk.targets
is the same as Y[index_array]
:
index_array = np.array([8, 9, 3, 5, 4, 7, 1, 0, 6, 2])
print(Y[index_array])
[[ 0.75325592 0.64857277 0.1926653 0.7642865 0.38901153]
[ 0.77567689 0.13573623 0.4902501 0.42897559 0.55825652]
[ 0.33760938 0.68195038 0.12303088 0.83509441 0.20991668]
[ 0.98367778 0.61325065 0.28973401 0.28734073 0.93399794]
[ 0.26097574 0.88219054 0.87951941 0.64887846 0.41996446]
[ 0.97794604 0.91307569 0.93816428 0.2125808 0.94381495]
[ 0.74813435 0.08036688 0.38094272 0.83178364 0.16713736]
[ 0.52609421 0.39218962 0.21022047 0.58569125 0.08012982]
[ 0.61276627 0.20679494 0.24124858 0.01262245 0.0994412 ]
[ 0.6026137 0.25620512 0.7398164 0.52558182 0.09955769]]
print(cbk.targets)
[array([[ 0.7532559 , 0.64857274, 0.19266529, 0.76428652, 0.38901153],
[ 0.77567691, 0.13573623, 0.49025011, 0.42897558, 0.55825651],
[ 0.33760938, 0.68195039, 0.12303089, 0.83509439, 0.20991668],
[ 0.9836778 , 0.61325067, 0.28973401, 0.28734073, 0.93399793],
[ 0.26097575, 0.88219053, 0.8795194 , 0.64887846, 0.41996446],
[ 0.97794604, 0.91307569, 0.93816429, 0.2125808 , 0.94381493],
[ 0.74813437, 0.08036689, 0.38094273, 0.83178365, 0.16713737],
[ 0.5260942 , 0.39218962, 0.21022047, 0.58569127, 0.08012982]], dtype=float32),
array([[ 0.61276627, 0.20679495, 0.24124858, 0.01262245, 0.0994412 ],
[ 0.60261369, 0.25620511, 0.73981643, 0.52558184, 0.09955769]], dtype=float32)]
如您所见,cbk.targets
中有两个批次(一个完整批次"的大小为8,最后一个批次的大小为2),并且行顺序与Y[index_array]
相同.
As you can see, there are two batches in cbk.targets
(one "full batch" of size 8 and the final batch of size 2), and the row order is the same as Y[index_array]
.
这篇关于创建keras回调以在训练期间保存每个批次的模型预测和目标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!