Tensorflow 创建keras回调以在培训期间保存每个批次的模型预测和目标
我正在Keras(tensorflow后端)中构建一个简单的序列模型。在培训期间,我想检查各个培训批次和模型预测。因此,我试图创建一个自定义的Tensorflow 创建keras回调以在培训期间保存每个批次的模型预测和目标,tensorflow,callback,keras,Tensorflow,Callback,Keras,我正在Keras(tensorflow后端)中构建一个简单的序列模型。在培训期间,我想检查各个培训批次和模型预测。因此,我试图创建一个自定义的回调,它保存每个训练批的模型预测和目标。但是,该模型不是使用当前批次进行预测,而是使用整个训练数据 如何仅将当前培训批交给回调 如何访问回调保存在self.prethis和self.targets中的批和目标 我目前的版本如下: callback\u list=[prediction\u history((self.x\u train,self.y\u t
回调
,它保存每个训练批的模型预测和目标。但是,该模型不是使用当前批次进行预测,而是使用整个训练数据
如何仅将当前培训批交给回调
如何访问回调
保存在self.prethis和self.targets中的批和目标
我目前的版本如下:
callback\u list=[prediction\u history((self.x\u train,self.y\u 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)
类历史(keras.callbacks.Callback):
定义初始(自身、列车数据):
self.train\u data=列车数据
self.prethis=[]
self.targets=[]
批处理结束时的def(self、epoch、logs={}):
x\u列车,y\u列车=自列车数据
self.targets.append(y_列)
预测=自我模型预测(x_列车)
self.prethis.append(预测)
tf.logging.info(“预测形状:{}”.format(预测形状))
tf.logging.info(“目标形状:{}”.format(y_train.shape))
注意:此答案已过时,仅适用于TF1。检查@bers以获取在TF2上测试的解决方案
模型编译后,
y\u true
的占位符张量位于模型中。targets
和y\u pred
位于模型中。输出
要在每个批次保存这些占位符的值,可以:
中计算这些变量,并存储结果数组
tf。将op分配给培训功能model.train\u功能。使用当前的Keras API,可以通过在构造训练函数时向K.function()
提供获取
参数来实现
在模型中.\u make\u train\u function()
中有一行:
self.train\u功能=K功能(输入,
[self.total_loss]+self.metrics_张量,
更新=更新,
name='train\u函数',
**自身功能(kwargs)
获取包含tf.assign
操作的参数可以通过模型提供。_function\u kwargs
(仅在Keras 2.1.0之后有效)
例如:
来自keras.layers
从keras.models导入顺序
从keras.callbacks导入回调
从keras导入后端为K
导入tensorflow作为tf
将numpy作为np导入
类CollectOutputTarget(回调):
定义初始化(自):
超级(CollectOutputTarget,self)。\uuuu init\uuuuu()
self.targets=[]收集y#个真实批次
self.outputs=[]#收集y#u pred批
#这两个变量的形状将根据批次形状而变化
#要处理“最后一批”,请指定'validate\u shape=False`
self.var_y_true=tf.Variable(0.,validate_shape=False)
self.var_y_pred=tf.Variable(0.,validate_shape=False)
批处理端上的def(自身、批处理、日志=无):
#计算变量并将其保存到列表中
self.targets.append(K.eval(self.var\u y\u true))
self.outputs.append(K.eval(self.var_y_pred))
#建立一个简单的模型
#必须首先编译要准备的模型目标和模型输出
模型=顺序([密集(5,输入_形状=(10,)]))
compile(loss='mse',optimizer='adam')
#初始化变量和`tf.assign`ops
cbk=收集输出目标()
fetches=[tf.assign(cbk.var\u y\u true,model.targets[0],validate\u shape=False),
tf.assign(cbk.var\u y\u pred,model.outputs[0],validate\u shape=False)]
模型._function_kwargs={'fetches':fetches}使用'model._function_kwargs`如果使用'model'而不是'Sequential'`
#拟合模型并检查结果
X=np.random.rand(10,10)
Y=np.rand.rand(10,5)
model.fit(X,Y,批处理大小=8,回调=[cbk])
除非样本数量可以除以批次大小,否则最终批次的大小将不同于其他批次。因此,在这种情况下不能使用K.variable()
和K.update()
。您必须使用tf.Variable(…,validate\u shape=False)
和tf.assign(…,validate\u shape=False)
要验证保存的数组的正确性,可以在training.py
中添加一行以打印无序索引数组:
if shuffle==“batch”:
索引数组=\批量\洗牌(索引数组,批量大小)
elif shuffle:
np.random.shuffle(索引数组)
打印('索引数组:',repr(索引数组))#添加此行
批次=\制造\批次(数量\序列\样本,批次\大小)
在装配过程中,应打印出无序索引数组:
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中有两个批次(一个“完整批次”大小为8,最后一个批次大小为2),行顺序与Y[index\u array]
更新:请参阅TF>=2.2
@Yu-Yang的解决方案的一个问题是它依赖于模型。_function\u kwargs
,这不能保证工作,因为它不是API的一部分。特别是,在具有急切执行的TF2中,会话KWARG似乎根本不被接受,或者由于急切模式而抢先运行
因此,下面是我在tensorflow==2.1.0
上测试的解决方案。诀窍是替换fetches"""Demonstrate access to Keras symbolic tensors in a (tf.)keras.Callback."""
import numpy as np
import tensorflow as tf
use_tf_keras = True
if use_tf_keras:
from tensorflow import keras
from tensorflow.keras import backend as K
tf.config.experimental_run_functions_eagerly(False)
compile_kwargs = {"run_eagerly": False, "experimental_run_tf_function": False}
else:
import keras
from keras import backend as K
compile_kwargs = {}
in_shape = (2,)
out_shape = (1,)
batch_size = 3
n_samples = 7
class CollectKerasSymbolicTensorsCallback(keras.callbacks.Callback):
"""Collect Keras symbolic tensors."""
def __init__(self):
"""Initialize intermediate variables for batches and lists."""
super().__init__()
# Collect batches here
self.inputs = []
self.targets = []
self.outputs = []
# # For a pure Keras solution, we need to know the shapes beforehand;
# # in particular, batch_size must divide n_samples:
# self.input = K.variable(np.empty((batch_size, *in_shape)))
# self.target = K.variable(np.empty((batch_size, *out_shape)))
# self.output = K.variable(np.empty((batch_size, *out_shape)))
# If the shape of these variables will change (e.g., last batch), initialize
# arbitrarily and specify `shape=tf.TensorShape(None)`:
self.input = tf.Variable(0.0, shape=tf.TensorShape(None))
self.target = tf.Variable(0.0, shape=tf.TensorShape(None))
self.output = tf.Variable(0.0, shape=tf.TensorShape(None))
def on_batch_end(self, batch, logs=None):
"""Evaluate the variables and save them into lists."""
self.inputs.append(K.eval(self.input))
self.targets.append(K.eval(self.target))
self.outputs.append(K.eval(self.output))
def on_train_end(self, logs=None):
"""Print all variables."""
print("Inputs: ", *self.inputs)
print("Targets: ", *self.targets)
print("Outputs: ", *self.outputs)
@tf.function
def assign_keras_symbolic_tensors_metric(_foo, _bar):
"""
Return the assignment operations as a metric to have them evaluated by Keras.
This replaces `fetches` from the TF1/non-eager-execution solution.
"""
# Collect assignments as list of (dest, src)
assignments = (
(callback.input, model.inputs[0]),
(callback.target, model._targets[0] if use_tf_keras else model.targets[0]),
(callback.output, model.outputs[0]),
)
for (dest, src) in assignments:
dest.assign(src)
return 0
callback = CollectKerasSymbolicTensorsCallback()
metrics = [assign_keras_symbolic_tensors_metric]
# Example model
model = keras.Sequential([keras.layers.Dense(out_shape[0], input_shape=in_shape)])
model.compile(loss="mse", optimizer="adam", metrics=metrics, **compile_kwargs)
# Example data
X = np.random.rand(n_samples, *in_shape)
Y = np.random.rand(n_samples, *out_shape)
model.fit(X, Y, batch_size=batch_size, callbacks=[callback])
print("X: ", X)
print("Y: ", Y)