关于深度学习:深入了解-TabNet-架构详解和分类代码实现

46次阅读

共计 6426 个字符,预计需要花费 17 分钟才能阅读完成。

Google 公布的 TabNet 是一种针对于表格数据的神经网络,它通过相似于加性模型的程序注意力机制(sequential attention mechanism)实现了 instance-wise 的特征选择,还通过 encoder-decoder 框架实现了自监督学习。

表格数据是日常中用到的最多的数据类型。例如信用卡的欺诈检测:咱们提取交易、身份、产品和网络属性(并将它们放入一个大的特色表中,不同的机器学习模型能够轻松地应用这些特色进行训练和推理。基于决策树的模型(例如随机森林或 XGBoost)是解决表格数据的首选算法,因为它们的性能、可解释性、训练速度和鲁棒性都是目前最好的。

然而神经网络在许多畛域被认为是最先进的,并且在具备起码特色工程的大型数据集上体现特地好。咱们的许多客户都有大量交易量,深度学习是进步模型在欺诈检测方面性能的潜在路径。

在这篇文章中,咱们将深入研究称为 TabNet (Arik & Pfister (2019)) 的神经网络架构,该架构旨在可解释并与表格数据很好地配合应用。在解释了它背地的要害构建块和想法之后,您将理解如何在 TensorFlow 中实现它以及如何将其利用于欺诈检测数据集,如果你应用 Pytorch 也不必放心,TabNet 有各种深度学习框架的实现。

TabNet

TabNet 应用 Sequential Attention 的思维模拟决策树的行为。简略地说,能够将其视为一个多步神经网络,在每一步利用两个要害操作:

  • Attentive Transformer 抉择最重要的特色在下一步解决
  • 通过 Feature Transformer 将特色解决成更有用的示意

模型最初应用 Feature Transformer 的输入稍后用于预测。TabNet 同时应用 Attentive 和 Feature Transformers,可能模仿基于树的模型的决策过程。例如以下的成人人口普查支出数据集的预测,模型可能抉择和解决对手头工作最有用的特色,从而进步可解释性和学习能力。

Attentive 和 Feature Transformer 的要害构建块是所谓的 Feature Blocks,所以让咱们先来摸索一下。

Feature Block 特色块

Feature Block 由程序利用的全连贯(FC)或密集层和批量归一化(BN)组成。此外,对于 Feature Transformer,输入通过 GLU 激活层传递。

GLU(与 sigmoid 门相同)的次要性能是容许暗藏单元更深刻地流传到模型中并避免梯度爆炸或隐没。

def glu(x, n_units=None):
    """Generalized linear unit nonlinear activation."""
    return x[:, :n_units] * tf.nn.sigmoid(x[:, n_units:])

原论文在训练过程中应用了 Ghost Batch Normalisation 来进步收敛速度。如果你感兴趣,你能够搜寻下相干的介绍,但在本文中咱们将应用默认的 BN 层。

class FeatureBlock(tf.keras.Model):
    """Implementation of a FL->BN->GLU block"""
    def __init__(
        self,
        feature_dim,
        apply_glu = True,
        bn_momentum = 0.9,
        fc = None,
        epsilon = 1e-5,
    ):
        super(FeatureBlock, self).__init__()
        self.apply_gpu = apply_glu
        self.feature_dim = feature_dim
        units = feature_dim * 2 if apply_glu else feature_dim # desired dimension gets multiplied by 2
                                                              # because GLU activation halves it

        self.fc = tf.keras.layers.Dense(units, use_bias=False) if fc is None else fc # shared layers can get re-used
        self.bn = tf.keras.layers.BatchNormalization(momentum=bn_momentum, epsilon=epsilon)

    def call(self, x, training = None):
        x = self.fc(x) # inputs passes through the FC layer
        x = self.bn(x, training=training) # FC layer output gets passed through the BN
        if self.apply_gpu: 
            return glu(x, self.feature_dim) # GLU activation applied to BN output
        return x

Feature Transformer

Feature Transformer (FT) 是按程序利用的特色块的汇合。在论文中,一个 FeatureTransformer 由两个共享块(即跨步重用权重)和两个依赖于步的块组成。共享权重缩小了模型中的参数数量并提供更好的泛化。

上面将介绍如何应用上一节中的 Feature Block 来构建 Feature Transformer。

class FeatureTransformer(tf.keras.Model):
    def __init__(
        self,
        feature_dim,
        fcs = [],
        n_total = 4,
        n_shared = 2,
        bn_momentum = 0.9,
    ):
        super(FeatureTransformer, self).__init__()
        self.n_total, self.n_shared = n_total, n_shared

        kwrgs = {
            "feature_dim": feature_dim,
            "bn_momentum": bn_momentum,
        }

        # build blocks
        self.blocks = []
        for n in range(n_total):
            # some shared blocks
            if fcs and n < len(fcs):
                self.blocks.append(FeatureBlock(**kwrgs, fc=fcs[n])) # Building shared blocks by providing FC layers
            # build new blocks
            else:
                self.blocks.append(FeatureBlock(**kwrgs)) # Step dependent blocks without the shared FC layers

    def call(self, x, training = None):
        # input passes through the first block
        x = self.blocks[0](x, training=training) 
        # for the remaining blocks
        for n in range(1, self.n_total):
            # output from previous block gets multiplied by sqrt(0.5) and output of this block gets added
            x = x * tf.sqrt(0.5) + self.blocks[n](x, training=training) 
        return x

    @property
    def shared_fcs(self):
        return [self.blocks[i].fc for i in range(self.n_shared)]

Attentive Transformer

Attentive Transformer (AT) 负责每一步的特征选择。特征选择是通过利用 sparsemax 激活(而不是 GLU)来实现的并同时思考到先验的比例。先验比例容许咱们管制模型抉择一个特色的频率,并由它在后面的步骤中应用的频率管制(稍后会具体介绍)。

前一步的 Transformer 提供前一步特色的比例信息,相当于告知了前一个步骤中应用了哪些个性。与 Feature Transformer 相似 Attentive Transformer 能够作为 TensorFlow 模型集成到更大的架构中。

class AttentiveTransformer(tf.keras.Model):
    def __init__(self, feature_dim):
        super(AttentiveTransformer, self).__init__()
        self.block = FeatureBlock(
            feature_dim,
            apply_glu=False, # sparsemax instead of glu
        )

    def call(self, x, prior_scales, training=None):
        # Pass input trhough a FC-BN block
        x = self.block(x, training=training)
        # Pass the output through sparsemax activation
        return sparsemax(x * prior_scales)

因为 Feature 和 Transformer 块可能会变得十分依赖参数,TabNet 应用了一些机制来管制复杂性并避免过拟合。

正则化

前一步特色比例计算

先验比例(P)容许咱们管制模型抉择特色的频率。应用先前的 Attentive Transformer 激活和松弛因子 (γ) 参数计算先验尺度 (P)。这是论文中提出的公式。

这个等式显示了先验比例(P)是如何更新的。从直观上来说,如果在后面的步骤中应用了一个特色,那么模型会更加关注剩下的特色,以缩小过拟合。

例如,当 γ=1 时,具备较大激活(例如 0.9)的特色将具备较小的先验尺度(1-0.9=0.1)。较小的先验比例确保不会在以后步骤中抉择该特色。

稠密正则化

由超参数 λ 缩放的激活熵会被增加到整体模型损失中,通过这种形式对于损失进行稠密正则化能够使注意力掩码变得更稠密。

def sparse_loss(at_mask):
    loss = tf.reduce_mean(tf.reduce_sum(tf.multiply(-at_mask, tf.math.log(at_mask + 1e-15)),
                      axis=1)
    )
    
    return loss

not_sparse_mask = np.array([[0.4, 0.5, 0.05, 0.05],
                      [0.2, 0.2, 0.5, 0.1]])

sparse_mask = np.array([[0.0, 0.0, 0.7, 0.3],
                      [0.0, 0.0, 1, 0.0]])

print('Loss for non-sparse attention mask:', sparse_loss(not_sparse_mask).numpy())
print('Loss for sparse attention mask:', sparse_loss(sparse_mask).numpy())

# Loss for non-sparse attention mask: 1.1166351874690217
# Loss for sparse attention mask: 0.3054321510274452

TabNet 的所有组件都曾经介绍实现了,接下来让咱们理解如何应用这些组件来构建 TabNet 模型。

TabNet 架构

把它们放在一起,TabNet 的次要思维是按程序利用 Feature 和 Attentive Transformers 组件,这样模型能够模拟决策树的生成过程。Attentive Transformer 执行特征选择,而 Feature Transformer 执行容许模型学习数据中简单模式的转换。能够在上面看到一个图表,该图表总结了 2 步 TabNet 模型的数据流。

首先通过 Feature Transformer 传递初始输出特色以取得初始特色示意。这个 Feature Transformer 的输入会被用作 Attentive Transformer 的输出,Attentive Transformer 抉择一个特色子集传递到下一步。这会有一个超参数来设定反复此步骤的次数。

模型通过应用每个决策步骤的 Feature Transformer 输入来生成最终预测。此外,在每一步注意力的掩码,以理解哪些特色被用于进行预测。这些掩码可用于取得部分特色重要性以及全局重要性。

以上就是 TabNet 的残缺架构,上面让咱们看看如何在 Kaggle 的欺诈检测示例数据集上训练这个模型。

应用 TabNet 进行欺诈检测

上面应用的数据集和代码都能够在咱们最初提供的连贯中找到。

数据

训练数据集十分大,有大概 590k 条数据,每条数据蕴含 420 个特色。执行的预处理是十分根底的,因为这不是本文的指标:

  • 删除非信息列
  • 缺失值填充
  • 编码分类变量
  • 基于工夫的训练 / 验证拆分

超参数调优

TabNet(与任何神经网络一样)对超参数十分敏感,因而调整对于取得一个好的模型至关重要。以下是咱们发现对模型性能影响最大的变量(和倡议范畴):

  1. 特色维度 / 输入维度:从 32 到 512(咱们通常将这些参数设置为相等的数值,因为论文也是这么倡议的)
  2. 步数:从 2(简略模型)到 9(非常复杂的模型),就是咱们在架构中说的那个超参数
  3. 松弛因子:从 1(强制仅在 第 1 步应用特色)到 3(放松限度)
  4. 稠密系数:从 0(无正则化)到 0.1(强正则化)

文末提供的代码中还给出了一个简略的 HP 调整示例。

训练和评估

训练 TabNet 与其余模型相似,能够通过试验学习速率调度和衰减来进一步提高性能。

# Params after 1 hour of tuning
tabnet = TabNet(num_features = train_X_transformed.shape[1],
                output_dim = 128,
                feature_dim = 128,
                n_step = 2, 
                relaxation_factor= 2.2,
                sparsity_coefficient=2.37e-07,
                n_shared = 2,
                bn_momentum = 0.9245)

# Early stopping based on validation loss    
cbs = [tf.keras.callbacks.EarlyStopping(monitor="val_loss", patience=30, restore_best_weights=True)]

# Optimiser 
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01, clipnorm=10)

# Second loss in None because we also output the importances
loss = [tf.keras.losses.CategoricalCrossentropy(from_logits=False), None]

# Compile the model
tabnet.compile(optimizer,
               loss=loss)

# Train the model
tabnet.fit(train_ds, 
           epochs=1000, 
           validation_data=val_ds,
           callbacks=cbs,
           verbose=1,
           class_weight={
             0:1,
             1: 10
           })

通常应用 ROC 和 PR AUC 分数来评估模型 (因为指标是不均衡的),所以这里是这个模型的验证集上的指标。

Test ROC AUC 0.8505
Test PR AUC 0.464

后果还能够,然而其实不太好,不过咱们本文的目标并不是取得名次,咱们的目标是如何构建和训练 TabNet 模型。

总结

本文介绍了 TabNet 的架构,以及它如何应用 Attentive 和 Feature Transformers 进行预测。TabNet 还有很多咱们没有波及的内容(例如注意力掩码和自监督的预训练),所以如果想进一步摸索这个模型,请再深刻浏览上面的这些资源:

本文作者:Anton Rubert

正文完
 0