tensorflow.keras中的模型中是否有类似于sklearn的MLPClassifier中的partial_fit函数?



我正在尝试创建一个击键生物识别程序,并使用基准击键生物特征数据集(https://www.cs.cmu.edu/~keyword/DSL StrongPasswordData.csv(。我的目标是首先根据可用用户数量训练模型,然后继续训练相同的模型,以便能够预测新用户。

data = pd.read_csv('keystroke.csv')
y = pd.get_dummies(data, columns=['subject']).loc[:, "subject_s002":]
X = data.loc[:, "H.period":"H.Return"]
for col in X.columns:
X[col] = (X[col] - X[col].mean()) / X[col].std()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = tf.keras.models.Sequential()
model.add(Dense(200, input_shape=(31,), activation='sigmoid'))
model.add(tf.keras.layers.Dropout(0.3))
model.add(Dense(51, activation='exponential', use_bias=True)) 
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

问题的出现是因为我必须指定输出层中的节点数量等于数据集中的标签数量。虽然我最初有51个用户,但我希望能够增加这些用户,并在同一型号上进行训练。但要做到这一点,我必须弹出当前的输出层,并用新的用户数量创建一个新的输出层。然后,我必须在整个数据集上重新训练模型,这在时间上是昂贵的。

我尝试使用sklearn的MLPC分类器做类似的事情——我将数据集分为25个和26个用户的单独集合,然后在前25个用户上使用partial_fit 500次,然后在其余26个用户上。但是,在我对其余26个用户使用partial_fit(我使用0.0001的初始学习率并将学习率设置为自适应(之后,前25个用户的得分正在降至0。

clf = MLPClassifier(activation='logistic', alpha=0, max_iter=900, solver='adam',
hidden_layer_sizes=(400,), learning_rate_init=0.00001, 
warm_start=True, shuffle=True, learning_rate='adaptive')
for i in range(500):
clf.partial_fit(X_train25, y_train25, classes=subjects)
score25 = clf.score(X_test25, y_test25) # 0.7995
for i in range(500):
clf.partial_fit(X_train26, y_train26)
score25 = clf.score(X_test25, y_test25) # 0.826
score26 = clf.score(X_test26, y_test26) # 0.0

所以我想知道是否可以在tensorflow.keras中做sklearn中的partial_fit?或者,在对其余26个用户使用partial_fit后,是否有办法保持sklearn模型中前25个用户的准确性?

一种实用的方法是使Y数据(以及最终的密集层(比当前的用户数量宽得多。如果你从51个用户开始,比如说你的Y数据中有100列,其中最后49个总是零。你的最终致密层也有100个单位。

如果你训练你的模型,你的模型永远不应该做出预测对于用户>51,因为没有Y数据具有这些标签。

然后,当用户52出现时,您只需开始填充列52并继续训练相同的模型。

这是一种方法,但我承认它并不优雅。在某个时刻,你会遇到限制和需要重新培训整个事情。

我将数据集划分为25个和26个用户的独立集合,然后在前25个用户上使用了partial_fit 500次,然后在其余26个用户。但前25名用户的得分正在下降到0在我为剩余的26个用户使用partial_fit之后

这是完全正常的。这个问题被称为灾难性遗忘。如果你尝试训练新课程而不提供旧课程的例子,这些课程就会被遗忘。为了将模型作为动态对象处理,能够在整个时间内获取新知识,您必须应用增量学习(IL(技术。

IL是关于学习一项新任务,只访问当前任务的一批数据(不是所有技术,而是大多数技术(。任务被定义为一组要学习的类,这些类被添加到已经训练过的类中。你想在学习一项新任务和保留之前的知识之间找到一种权衡。

有许多技术属于增量学习的名称。我认为最简单的方法之一是任务增量学习。

基本上,你可以一次训练一组n个班。每组称为一项任务。要训练一个新任务,必须向模型中添加一个特定于该任务的新头(输出层(。因此,每项任务都有其独特的头。要进行推理,只需将测试数据输入到模型中,并获得预测,您必须知道要查看的头部ID(或者不知道,但这更难(。

要进行任务的训练,您可以添加新的头,冻结所有其他头,使其不发生变化,并且通常会应用一个损失,这有助于最大限度地减少旧任务的准确性漂移。一种你可以看到的技术叫做不忘学习(LwF(,但实际上有很多技术可以帮助你。

使用LwF,您可以应用知识损失蒸馏(以了解更多信息(。为了添加一点代码,你的目标是这样的:

def k_dist_loss(logits, labels, T):
"""
Computes the knowledge distillation loss that constrain outputs for original tasks to be similar to the
original network. Logits are prediction logits (y_pred), labels, are the true labels (y_true), T a temperature.
"""
logits = tf.cast(logits, dtype='float32')
labels = tf.cast(labels, dtype='float32')
outputs = tf.nn.log_softmax(logits / T, axis=1)
labels = tf.nn.softmax(labels / T, axis=1)
outputs = tf.reduce_sum(outputs * labels, keepdims=False, axis=1)
outputs = -tf.reduce_mean(outputs, keepdims=False, axis=0)
return outputs  # knowledge distillation loss
def lwf_loss_f(labels, logits, heads_labels, T, lambda0):
"""
Computes a loss that is the sum of two components:
- 1 the loss for the last task head, currently in training, for example a ce loss
- 2 a loss to avoid forgetting old tasks, multiplied by the lambda0 value to preserve old outputs. 
The distillation loss component aims at minimizing the distance between outputs of the old model for old tasks and outputs of the new model for old tasks. 
This should preserve the accuracy on old tasks after the training of a new task using only new task data.
"""
ce = # obtain cross entropy or other loss for last layer added
distillation_loss = 0
for i in range(len(heads_labels)):
distillation_loss += k_dist_loss(labels=heads_labels[i], logits=logits[i], T=T)

loss = ce + lambda0 * distillation_loss
return loss
@tf.function
def train_step(x, y):
# Open a GradientTape to record the operations run
# during the forward pass, which enables auto-differentiation.
with tf.GradientTape() as tape:
logits = model(x, training=True)
# logits is an array of the logits of each task head
loss = lwf_loss_f(labels=y, logits=logits, heads_labels=heads_labels, T=T, lambda0=lambda0)
grads = tape.gradient(total_loss, model.trainable_weights)
optimizer.apply_gradients(zip(grads, model.trainable_weights))
return loss
# example train loop 
for epoch in range(epochs):
# Iterate over the batches of the dataset.
for batch in range(num_batch):
images = x_train[batch * batch_size: (batch + 1) * batch_size]
labels = y_train[batch * batch_size: (batch + 1) * batch_size]
heads_labels = prev_model(images, training=False)
loss = train_step(images, labels)

其中,prev_model是上一步骤中的模型(没有新头(。它用于将旧任务的知识转移到新模型中。在进行新的训练之前,请记住手动为新任务的模型添加一个新的输出层。

最新更新