我正在阅读 Daniel Nouri 关于使用 CNN 进行面部识别的教程,我遇到了一些我不明白的代码。Daniel 正在定义一个在网络训练期间每次迭代结束时调用的类,这将决定训练是否应该提前停止:
class EarlyStopping(object):
def __init__(self, patience=100):
self.patience = patience
self.best_valid = np.inf
self.best_valid_epoch = 0
self.best_weights = None
def __call__(self, nn, train_history):
current_valid = train_history[-1]['valid_loss']
current_epoch = train_history[-1]['epoch']
if current_valid < self.best_valid:
self.best_valid = current_valid
self.best_valid_epoch = current_epoch
self.best_weights = nn.get_all_params_values()
elif self.best_valid_epoch + self.patience < current_epoch:
print("Early stopping.")
print("Best valid loss was {:.6f} at epoch {}.".format(
self.best_valid, self.best_valid_epoch))
nn.load_params_from(self.best_weights)
raise StopIteration()
这是有道理的,但是代码中的实际实现如下所示:
net8 = NeuralNet(
# ...
on_epoch_finished=[
AdjustVariable('update_learning_rate', start=0.03, stop=0.0001),
AdjustVariable('update_momentum', start=0.9, stop=0.999),
EarlyStopping(patience=200),
],
# ...
)
显然,Daniel 将类作为函数调用。但是,我不明白他是如何在没有显示的参数的情况下调用它的__call__(args)
。这就是在 nolearn 的源代码中实现的方式吗?我对网络如何知道如何使用nn
以及train_history
没有将它们传递给函数感到困惑。