增量学习(Incremental Learning)

我们使用的算法模型中大都是批量学习(Batch Learning)模式,即:假设在训练之前所有训练样本一次都可以得到,学习这些样本之后,学习过程就终止了,不再学习新的知识。

在有些场景下,训练样本通常不可能一次全部得到,而是随着时间逐步得到的,并且样本反映的信息也可能随着时间产生了变化。如果新样本到达后要重新学习全部数据,需要消耗大量时间和空间,因此批量学习的算法不能满足这种需求。

这就像人在成长过程中,每天学习和接收新的事物,学习是逐步进行的,而且,对已经学习到的知识,人类一般是不会遗忘的。我们希望学习模型也能够不断地从新样本中学习新的知识,并且保存大部分以前已经学习到的知识,这就是增量学习。

增量学习主要有两方面的应用:

  1. 用于非常大的数据;
  2. 用于随着时间不断变化的数据。

1. partial_fit 和 fit

在 scikit-learn 中支持增量学习的算法模型(并不是所有的方法都支持增量学习)都通过 partial_fit 方法来实现增量运算。

模型的 partial_fit 和 fit 方法进行训练时有什么不同?

其实 fit 方法内部调用了 partial_fit 方法,不同的是直接调用 partial_fit 方法,其 max_iter 的值为 1,也就是说对于给定的样本只迭代一次。而 fit 方法的 max_iter 默认值是 1000,当然该值在创建模型的时候是可以自己指定,如下图所示:

左侧是 fit 函数中调用 _patial_fit 方法时传递的 max_iter=1000 ,右侧是 partial_fit 调用 _patial_fit 时候传递的 max_iter=1。

两者另外的不同是 fit 函数每次调用时,在 _partial_fit 调用前默认会将模型参数设置为 None,即:从零开始训练,而 patial_fit 则不会进行如此设置。如下图所示:

fit 方法将 coef、intercept 设置为 None

从这里可以看到如果要进行增量学习的话,调用 partial_fit 方法更适合。另外,从上面的截图代码中,看到 warm_start 属性,它似乎和模型参数有关?它的作用是什么?

warm_start 参数默认为 False,当它设置为 True 时,从上面代码可以看出,它会将以前训练得到的参数保留下来,而不是抹掉。也就是说,如果前面使用 fit 方法训练了一次,此时 设置 warm_start=True 并再使用 fit 方法进行第二次训练, 则模型就不会从零开始训练,而是在以前参数的基础上重新训练,这会加快模型的收敛。

上面的代码在 fit 函数中会出现,但是在 patial_fit 方法中是没有增加该逻辑的。也就是说,partial_fit 认为无论你之前训练参数是什么,我都在你的基础上进行增量训练。

2. 增量学习 API

下面列表中是 scikit-learn 中各个支持增量学习,不同任务的 API:

我们以 SGDRegressor 为例:

import math

from sklearn.linear_model import SGDRegressor
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
import numpy as np

import warnings
warnings.filterwarnings('ignore')

# 由于数据中可能存在黑人歧视,boston 数据将会在 1.2 版本移除
boston_data = load_boston()
x, y = boston_data.data, boston_data.target

# 数据集分割
x_train, x_test, y_train, y_test = \
    train_test_split(x, y, test_size=0.2, random_state=666)

# 全量训练
def test01():

    estimator = SGDRegressor(max_iter=1000, random_state=0)
    estimator.fit(x_train, y_train)
    score = estimator.score(x_test, y_test)
    print('全量训练:', score)


# 加载 mini batch 数据
def load_data(dataset, labels):

    batch_size = 2
    batch_num = math.ceil(len(labels) / 4)
    for index in range(batch_num):
        start = index * batch_size
        end = start + batch_size
        yield dataset[start: end], labels[start: end]

# 增量训练
def test02():

    global x_train, y_train

    x_train, x_incr, y_train, y_incr = \
        train_test_split(x_train, y_train, train_size=0.5, random_state=0)

    # 使用少量训练集进行训练
    estimator = SGDRegressor(max_iter=1000, random_state=0)
    estimator.fit(x_train, y_train)
    score = estimator.score(x_test, y_test)
    print('基础训练:', score)

    # 增量训练
    for data, label in load_data(x_incr, y_incr):
        estimator.partial_fit(data, label)

    score = estimator.score(x_test, y_test)
    print('增量训练:', score)


if __name__ == '__main__':
    test01()
    test02()

程序执行结果:

全量训练: -7.505174669422246e+26
基础训练: -1.0685014075494617e+27
增量训练: -1.3018409378020246e+26

这个结果并不重要,增量学习并不会保证效果一定比全量学习要好,我们需要选择在合适的场景来使用。

未经允许不得转载:一亩三分地 » 增量学习(Incremental Learning)
评论 (0)

8 + 7 =