【问题标题】:How to pass input dim from fit method to skorch wrapper?如何将输入 dim 从 fit 方法传递到 skorch 包装器?
【发布时间】:2020-02-17 00:14:52
【问题描述】:

我正在尝试将 PyTorch 功能整合到 scikit-learn 环境中(特别是 Pipelines 和 GridSearchCV),因此一直在研究 skorch。神经网络的标准文档示例看起来像

import torch.nn.functional as F
from torch import nn
from skorch import NeuralNetClassifier

class MyModule(nn.Module):
    def __init__(self, num_units=10, nonlin=F.relu):
        super(MyModule, self).__init__()

        self.dense0 = nn.Linear(20, num_units)
        self.nonlin = nonlin
        self.dropout = nn.Dropout(0.5)
        ...
        ...
        self.output = nn.Linear(10, 2)
    ...
    ...

您通过将输入和输出维度硬编码到构造函数中来显式传递它们。然而,scikit-learn 接口实际上并不是这样工作的,其中输入和输出维度由fit 方法派生,而不是显式传递给构造函数。作为一个实际的例子考虑

# copied from the documentation
net = NeuralNetClassifier(
    MyModule,
    max_epochs=10,
    lr=0.1,
    # Shuffle training data on each epoch
    iterator_train__shuffle=True,
)

# any general Pipeline interface
pipeline = Pipeline([
        ('transformation', AnyTransformer()),
        ('net', net)
        ])

gs = GridSearchCV(net, params, refit=False, cv=3, scoring='accuracy')
gs.fit(X, y)

除了转换器中没有任何地方必须指定输入和输出维度这一事实之外,在模型之前应用的转换器可能会改变训练集的维度(考虑降维和类似情况),因此在神经网络构造函数中对输入和输出进行硬编码是行不通的。

我是否误解了这应该如何工作或建议的解决方案是什么(我正在考虑将构造函数指定到 forward 方法中,您确实已经有 X 可供使用,但我不是确定这是好的做法)?

【问题讨论】:

    标签: python deep-learning pytorch skorch


    【解决方案1】:

    这是一个非常好的问题,恐怕有最佳实践答案,因为 PyTorch 通常以初始化和执行是单独步骤的方式编写,而这正是您 不 em> 在这种情况下想要。

    有几种方法都朝着同一个方向前进,即内省输入数据并在拟合之前重新初始化网络。我能想到的最简单的方法是编写一个回调,在训练开始时设置相应的参数:

    class InputShapeSetter(skorch.callbacks.Callback):
        def on_train_begin(self, net, X, y):
            net.set_params(module__input_dim=X.shape[-1])
    

    这会在训练开始期间设置一个模块参数,该参数将使用所述参数重新初始化 PyTorch 模块。此特定回调期望第一层的参数称为input_dim,但您可以根据需要更改此参数。

    一个完整的例子:

    import torch
    import skorch
    from sklearn.datasets import make_classification
    from sklearn.pipeline import Pipeline
    from sklearn.decomposition import PCA
    
    X, y = make_classification()
    X = X.astype('float32')
    
    class ClassifierModule(torch.nn.Module):
        def __init__(self, input_dim=80):
            super().__init__()
            self.l0 = torch.nn.Linear(input_dim, 10)
            self.l1 = torch.nn.Linear(10, 2)
    
        def forward(self, X):
            y = self.l0(X)
            y = self.l1(y)
            return torch.softmax(y, dim=-1)
    
    
    class InputShapeSetter(skorch.callbacks.Callback):
        def on_train_begin(self, net, X, y):
            net.set_params(module__input_dim=X.shape[-1])
    
    
    net = skorch.NeuralNetClassifier(
        ClassifierModule,
        callbacks=[InputShapeSetter()],
    )
    
    pipe = Pipeline([
        ('pca', PCA(n_components=10)),
        ('net', net),
    ])
    
    pipe.fit(X, y)
    print(pipe.predict(X))
    

    【讨论】:

    • 这很好,这是一个很好的解决方案,谢谢!但是,skorch 的进一步限制显然是回调仅在输入为np.ndarray(例如pd.DataFrame/serieslist)时才起作用。我想必须编写额外的回调来将对象转换为首选格式……但此时不妨从头开始编写一个全新的估算器 :)
    • 您可以轻松地将pd.DataFrame 传递为X,上面的示例也可以正常工作。如果您遇到问题,请随时提出新问题或打开新的 skorch 问题。
    • 我已经传递了一个数据帧,但我在管道中遇到异常(由于存在标头);同时我自己也在调查这个:)。
    • 好的!请注意,在传递数据框(或字典)时,列/条目作为命名参数传递给模块的 forward 方法,因此您需要相应地命名这些参数。
    猜你喜欢
    • 1970-01-01
    • 2020-02-21
    • 2021-12-23
    • 2020-05-11
    • 2018-06-10
    • 1970-01-01
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多