如何将 fit 方法的输入暗淡传递给 skorch 包装器?
How to pass input dim from fit method to skorch wrapper?
我正在尝试将 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
可用于适合已经,但我不确定这是不是好做法)?
这是一个很好的问题,恐怕对此有最佳实践答案,因为 PyTorch 通常以初始化和执行是分开的步骤的方式编写,这正是您 不要't 在这种情况下想要。
有几种前进的方式都是朝着同一个方向前进的,即内省输入数据并在拟合之前重新初始化网络。我能想到的最简单的方法是写一个回调,在训练开始时设置相应的参数:
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))
我正在尝试将 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
可用于适合已经,但我不确定这是不是好做法)?
这是一个很好的问题,恐怕对此有最佳实践答案,因为 PyTorch 通常以初始化和执行是分开的步骤的方式编写,这正是您 不要't 在这种情况下想要。
有几种前进的方式都是朝着同一个方向前进的,即内省输入数据并在拟合之前重新初始化网络。我能想到的最简单的方法是写一个回调,在训练开始时设置相应的参数:
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))