伪标记是一种简单的半监督学习方法

参考网址:https://datawhatnow.com/pseudo-labeling-semi-supervised-learning/

每一个机器学习项目的基础都是数据——这是你离不开的东西。在这篇文章中,我将展示一种称为伪标记的简单半监督学习方法,它可以利用未标记的数据提高您最喜欢的机器学习模型的性能。

伪标签

为了训练具有监督学习的机器学习模型,必须对数据进行标记。这是否意味着未标记的数据对于分类和回归等监督任务是无用的?当然不!除了将额外的数据用于分析目的之外,我们甚至可以用它来帮助用半监督学习来训练我们的模型——结合未标记和标记数据来进行模型训练。

其主要思想很简单。首先,在标记数据上训练模型,然后使用训练后的模型预测未标记数据上的标签,从而创建伪标签。此外,将标记数据和新伪标记数据合并到用于培训数据的新数据集中。
在这里插入图片描述
fast.ai MOOC (original paper)提到这个方法时,我受到了启发,开始尝试这个方法。虽然这个方法是在深度学习(在线算法)的背景下提到的,但是我在传统的机器学习模型上进行了尝试,并得到了一些改进。

数据预处理和探索

在比赛中,比如 Kaggle上的比赛,参赛者接收训练集(标记数据)和测试集(未标记数据)。这是测试伪标记的好地方。我们将使用的数据集来自the Mercedes-Benz Greener Manufacturing competition——目标是基于汽车的特性(回归)预测测试的持续时间。和往常一样,所有带有附加描述的代码都可以在这个notebook中找到。

import pandas as pd
# Load the data
train = pd.read_csv('input/train.csv')
test = pd.read_csv('input/test.csv')
print(train.shape, test.shape)
# (4209, 378) (4209, 377)

可以看出,训练数据集并不理想,数据点的数量较少(4209),特征较多(376)。为了改进数据集,我们应该减少特征的数量,并尽可能增加数据点的数量。我在前一篇博客文章中讨论了特性的重要性(特性减少),这个主题将被跳过,因为这篇博客文章的主要关注点是增加带有伪标记的数据点的数量。该数据集体积小,标记与未标记数据的比例为1:1,适合于伪标记。

下表显示了整个培训数据集的子集。特性X0-X8是分类变量,我们必须将它们转换成模型可用的形式——数值。
在这里插入图片描述
这是使用scikit-learn的LabelEncoder类完成的。

from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
features = train.columns[2:]
for column_name in features:
    label_encoder = LabelEncoder() 
    
    # Get the column values
    train_column_values = list(train[column_name].values)
    test_column_values = list(test[column_name].values)
    
    # Fit the label encoder
    label_encoder.fit(train_column_values + test_column_values)
    
    # Transform the feature
    train[column_name] = label_encoder.transform(train_column_values)
    test[column_name] = label_encoder.transform(test_column_values)

结果:
在这里插入图片描述
现在,数据已经为我们的机器学习模型准备好了。

使用Python和scikit-learn实现伪标记

让我们创建一个函数来创建由伪标记和标记数据组成的“增强训练集”。函数的参数包括模型、训练和测试集信息(数据和特性)以及参数sample_rate。Sample_rate允许我们控制将与真正的标记数据混合的伪标记数据的百分比。将sample_rate设置为0.0意味着模型将只使用真实的标记数据,而sample_rate 0.5意味着模型将使用所有真实的标记数据和一半的伪标记数据。无论哪种情况,模型都将使用所有真正标记的数据。

def create_augmented_train(X, y, model, test, features, target, sample_rate):
    '''
    Create and return the augmented_train set that consists
    of pseudo-labeled and labeled data.
    '''
    num_of_samples = int(len(test) * sample_rate)
    # Train the model and creat the pseudo-labeles
    model.fit(X, y)
    pseudo_labeles = model.predict(test[features])
    # Add the pseudo-labeles to the test set
    augmented_test = test.copy(deep=True)
    augmented_test[target] = pseudo_labeles
    # Take a subset of the test set with pseudo-labeles and append in onto
    # the training set
    sampled_test = augmented_test.sample(n=num_of_samples)
    temp_train = pd.concat([X, y], axis=1)
    augemented_train = pd.concat([sampled_test, temp_train])
    
    # Shuffle the augmented dataset and return it
    return shuffle(augemented_train)

此外,我们还需要一种拟合方法——一种训练模型的方法——它将采用增强训练集并使用它训练模型。这是另一个函数,我们之前写的那个函数已经有很多参数了。这是一个很好的机会,可以创建一个类来增强内聚性,使代码更干净,并将方法放入该类中。我们将创建的类将被称为PseudoLabeler。它将使用一个scikit-learn模型,并使用增强训练集对其进行训练。scikit-learn允许我们创建自己的回归函数,但我们必须遵循它们的库标准。

from sklearn.utils import shuffle
from sklearn.base import BaseEstimator, RegressorMixin
class PseudoLabeler(BaseEstimator, RegressorMixin):
    
    def __init__(self, model, test, features, target, sample_rate=0.2, seed=42):
        self.sample_rate = sample_rate
        self.seed = seed
        self.model = model
        self.model.seed = seed
        
        self.test = test
        self.features = features
        self.target = target
        
    def get_params(self, deep=True):
        return {
            "sample_rate": self.sample_rate,
            "seed": self.seed,
            "model": self.model,
            "test": self.test,
            "features": self.features,
            "target": self.target
        }
    def set_params(self, **parameters):
        for parameter, value in parameters.items():
            setattr(self, parameter, value)
        return self
        
    def fit(self, X, y):
        if self.sample_rate > 0.0:
            augemented_train = self.__create_augmented_train(X, y)
            self.model.fit(
                augemented_train[self.features],
                augemented_train[self.target]
            )
        else:
            self.model.fit(X, y)
        
        return self
    def __create_augmented_train(self, X, y):
        num_of_samples = int(len(test) * self.sample_rate)
        
        # Train the model and creat the pseudo-labels
        self.model.fit(X, y)
        pseudo_labels = self.model.predict(self.test[self.features])
        
        # Add the pseudo-labels to the test set
        augmented_test = test.copy(deep=True)
        augmented_test[self.target] = pseudo_labels
        
        # Take a subset of the test set with pseudo-labels and append in onto
        # the training set
        sampled_test = augmented_test.sample(n=num_of_samples)
        temp_train = pd.concat([X, y], axis=1)
        augemented_train = pd.concat([sampled_test, temp_train])
        return shuffle(augemented_train)
        
    def predict(self, X):
        return self.model.predict(X)
    
    def get_model_name(self):
        return self.model.__class__.__name__

除了“fit”和“_create_augmented_train”方法之外,scikit-learn还需要几个更小的方法来使用这个类作为回归器(您可以在官方文档中阅读关于这个主题的更多信息)。现在我们已经创建了用于伪标记的scikit-learn类,让我们来看一个例子。

target = 'y'
# Preprocess the data
X_train, X_test = train[features], test[features]
y_train = train[target]
# Create the PseudoLabeler with XGBRegressor as the base regressor
model = PseudoLabeler(
    XGBRegressor(nthread=1),
    test,
    features,
    target
)
# Train the model and use it to predict
model.fit(X_train, y_train)
model.predict(X_train)

在本例中,pseudolabeler类使用XGBRegressor对伪标记进行回归。“sample_rate”的默认参数是0.2,这意味着伪标记程序将使用未标记数据集的20%。

结果

To test out the PseudoLabeler, I used XGBoost (when the competition was live I was getting the best results with XGBoost). To evaluate the model, we compare the raw XGBoost against the pseudo-labeled XGBoost. Using eight-fold cross-validation (on 4k data points, each fold got a small dataset – around 500 data points). The evaluation metric is R2-score, the official metric of the competition.

伪随机变量具有略高的均值得分和较低的偏差,这使得它(略)优于原始模型。我在笔记本上做了更详细的分析,你可以在这里看到。性能提升可能看起来很低,但请记住这是一个Kaggle竞赛,分数的每一次提高都可能让你在排行榜上的排名更高。这里介绍的复杂性不是太大(~70 LOC),但是在这个例子中,问题和模型非常简单,在尝试将其用于更复杂的问题或领域时,请记住这一点。

结论

伪标记允许我们在训练机器学习模型时使用未标记的数据。这听起来像一个强大的技术,是的,它通常会提高我们模型的性能。但是,很难进行调优并使其正常工作,即使在工作时,也只能稍微提高性能。在Kaggle这样的比赛中,我相信这个技巧是有用的,因为,通常,即使是分数的轻微增加也能在排行榜上给你一个提升。尽管如此,在将其用于生产环境之前,我还是会三思而后行,因为它似乎会引入额外的复杂性,而不会显著提高性能,而这可能不是您想要的。

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值