当我们使用Keras训练深度神经网络时,我们通常需要监控训练期间的损失(loss)以及其对权重的导数值。这是因为我们可以通过观察损失对权重的导数来了解网络训练的状况,从而确定网络是否收敛、训练是否存在梯度消失或梯度爆炸等问题。本文将详细介绍如何使用Keras打印loss对权重的导数方式,包括以下步骤:
步骤1:定义模型
我们首先需要定义一个Keras模型,可以使用任何已有的模型或者自行构建一个模型,例如,我们可以定义一个简单的多层感知机(MLP)模型:
from keras.layers import Dense, Flatten
from keras.models import Sequential
model = Sequential([
Flatten(input_shape=(28, 28, 1)),
Dense(128, activation='relu'),
Dense(10, activation='softmax')
])
model.compile(loss='categorical_crossentropy', optimizer='adam')
该模型包含一个Flatten层,将输入的28x28的图像展平为一个一维数组,然后接两个全连接层。模型输出为一个10维向量,表示图像属于10个类别的概率。在这里,模型使用categorical_crossentropy作为损失函数,Adam优化器进行权重更新。
步骤2:定义回调函数
接下来,我们需要定义一个回调函数,用于在模型训练期间监控损失(loss)以及导数值。回调函数是Keras提供的一种机制,可以让我们在模型训练期间执行一些自定义的操作。
我们可以定义一个Callback类,重写on_epoch_end()方法,该方法会在每个epoch结束时被调用。在该方法中,我们可以使用model.optimizer中已经定义好的优化器,计算损失函数对权重的导数,然后打印出来,例如:
from keras.callbacks import Callback
class LossAndGradsLogger(Callback):
def on_epoch_end(self, epoch, logs=None):
weights = self.model.trainable_weights # 从模型中获取权重
loss = logs['loss'] # 当前epoch的损失
# 计算损失对权重的导数
grads = self.model.optimizer.get_gradients(loss, weights)
# 打印损失和导数值
for weight, grad in zip(weights, grads):
print(weight.name, grad.numpy())
该回调函数会在每个epoch结束时打印出每个权重的导数和当前的损失值。
步骤3:模型训练
最后,我们可以使用定义好的模型和回调函数进行模型训练,例如:
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(-1, 28, 28, 1) / 255.0
x_test = x_test.reshape(-1, 28, 28, 1) / 255.0
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
model.fit(x_train, y_train, batch_size=128, epochs=10, callbacks=[LossAndGradsLogger()])
在训练过程中,该模型会输出每个权重的导数和当前损失值。
示例1
以VGG-16模型为例:
from keras.applications.vgg16 import VGG16
from keras.callbacks import Callback
from keras.layers import Input, Flatten, Dense
from keras.models import Model
from keras.optimizers import Adam
CLASS_NUM = 5
IMG_SIZE = 224
def build_model():
input_tensor = Input(shape=(IMG_SIZE, IMG_SIZE, 3))
base_model = VGG16(include_top=False, weights="imagenet", input_tensor=input_tensor)
x = Flatten()(base_model.output)
x = Dense(1024, activation='relu')(x)
predictions = Dense(CLASS_NUM, activation='softmax')(x)
model = Model(inputs=input_tensor, outputs=predictions)
return model
class LossAndGradients(Callback):
def __init__(self, model, base_loss_func):
super(LossAndGradients, self).__init__()
self.model = model
self.base_loss_func = base_loss_func
def on_epoch_end(self, epoch, logs=None):
weights = self.model.trainable_weights
loss = self.base_loss_func(self.model.targets, self.model.outputs)
grads = self.model.optimizer.get_gradients(loss, weights)
for weight, grad in zip(weights, grads):
print("Weight: {}\nGradient:{}\n".format(weight.name,grad))
model = build_model()
model.compile(loss="categorical_crossentropy", optimizer=Adam(lr=1e-4, decay=1e-6), metrics=["accuracy"])
keep_history=model.fit(train_generator,
epochs=1,
steps_per_epoch=train_steps,
validation_steps=val_steps,
validation_data=val_generator,
callbacks=[LossAndGradients(model=model, base_loss_func=model.loss)])
示例2
以LSTM为例:
from keras.models import Sequential
from keras.layers import LSTM
seq = Sequential()
seq.add(LSTM(32, input_shape=(10,1),return_sequences=True))
seq.add(LSTM(32, input_shape=(10,1)))
seq.compile(optimizer='rmsprop', loss='mse')
class LossHistory(keras.callbacks.Callback):
def on_train_begin(self, logs={}):
self.losses = []
def on_batch_end(self, batch, logs={}):
self.losses.append(logs.get('loss'))
history = LossHistory()
X = np.random.randn(1000, 10,1)
Y = np.random.rand(1000)
seq.fit(X, Y, batch_size=128, epochs=5, callbacks=[history])
print(history.losses)
以上两个示例都展示了使用Keras计算loss对权重的导数的方法和使用回调函数打印loss和导数值的方法。其中示例1使用了VGG-16模型,而示例2使用了LSTM模型,这说明了该方法可以适用于不同类型的模型。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:keras打印loss对权重的导数方式 - Python技术站