Heim > Artikel > Technologie-Peripheriegeräte > Wie führt man mit scikit-learn eine Hyperparameter-Rastersuche nach einem PyTorch-Modell durch?
scikit-learn ist die beste Bibliothek für maschinelles Lernen in Python, und PyTorch bietet uns praktische Operationen zum Erstellen von Modellen. Können ihre Vorteile integriert werden? In diesem Artikel erfahren Sie, wie Sie die Rastersuchfunktion in scikit-learn verwenden, um die Hyperparameter eines PyTorch-Deep-Learning-Modells zu optimieren:
To One Eine der einfachsten Möglichkeiten, PyTorch-Modelle für die Verwendung in Scikit-Learn verfügbar zu machen, ist die Verwendung des Skorch-Pakets. Dieses Paket stellt eine scikit-learn-kompatible API für PyTorch-Modelle bereit. In Skorch gibt es NeuralNetClassifier zur Klassifizierung neuronaler Netze und NeuralNetRegressor zur Regression neuronaler Netze.
pip install skorch
Um diese Wrapper zu verwenden, müssen Sie Ihr PyTorch-Modell mit nn.Module als Klasse definieren und dann beim Erstellen der NeuralNetClassifier-Klasse den Namen der Klasse an den Modulparameter übergeben. Beispiel: Der Konstruktor der
class MyClassifier(nn.Module): def __init__(self): super().__init__() ... def forward(self, x): ... return x # create the skorch wrapper model = NeuralNetClassifier( module=MyClassifier )
NeuralNetClassifier-Klasse kann die Parameter abrufen, die an den model.fit()-Aufruf (die Methode zum Aufrufen der Trainingsschleife in Scikit-Learn-Modellen) übergeben werden, wie z. B. die Anzahl der Epochen und die Stapelgröße. Zum Beispiel:
model = NeuralNetClassifier( module=MyClassifier, max_epochs=150, batch_size=10 )
Der Konstruktor der NeuralNetClassifier-Klasse kann auch neue Parameter akzeptieren. Diese Parameter können an den Konstruktor Ihrer Modellklasse übergeben werden. Voraussetzung ist, dass davor module__ (zwei Unterstriche) hinzugefügt werden. Diese neuen Parameter können im Konstruktor Standardwerte haben, sie werden jedoch überschrieben, wenn der Wrapper das Modell instanziiert. Zum Beispiel:
import torch.nn as nn from skorch import NeuralNetClassifier class SonarClassifier(nn.Module): def __init__(self, n_layers=3): super().__init__() self.layers = [] self.acts = [] for i in range(n_layers): self.layers.append(nn.Linear(60, 60)) self.acts.append(nn.ReLU()) self.add_module(f"layer{i}", self.layers[-1]) self.add_module(f"act{i}", self.acts[-1]) self.output = nn.Linear(60, 1) def forward(self, x): for layer, act in zip(self.layers, self.acts): x = act(layer(x)) x = self.output(x) return x model = NeuralNetClassifier( module=SonarClassifier, max_epochs=150, batch_size=10, module__n_layers=2 )
Wir können die Ergebnisse überprüfen, indem wir ein Modell initialisieren und drucken:
print(model.initialize()) #结果如下: <class 'skorch.classifier.NeuralNetClassifier'>[initialized]( module_=SonarClassifier( (layer0): Linear(in_features=60, out_features=60, bias=True) (act0): ReLU() (layer1): Linear(in_features=60, out_features=60, bias=True) (act1): ReLU() (output): Linear(in_features=60, out_features=1, bias=True) ), )
Rastersuche ist eine Technik zur Optimierung von Modellhyperparametern. Es erschöpft einfach alle Kombinationen von Hyperparametern und findet diejenige, die die beste Punktzahl liefert. In scikit-learn stellt die GridSearchCV-Klasse diese Technik bereit. Beim Erstellen dieser Klasse muss im Parameter param_grid ein Wörterbuch mit Hyperparametern bereitgestellt werden. Dies ist eine Karte mit Modellparameternamen und Wertearrays zum Ausprobieren.
Precision wird standardmäßig als Score für die Optimierung verwendet, es können jedoch auch andere Scores im Score-Parameter des GridSearchCV-Konstruktors angegeben werden. GridSearchCV erstellt für jede auszuwertende Parameterkombination ein Modell. Und verwenden Sie die standardmäßige dreifache Kreuzvalidierung, die über Parameter festgelegt werden kann.
Hier ist ein Beispiel für die Definition einer einfachen Rastersuche:
param_grid = { 'epochs': [10,20,30] } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, Y)
Wenn Sie den Parameter n_jobs im GridSearchCV-Konstruktor auf -1 setzen, bedeutet dies, dass alle Kerne auf der Maschine verwendet werden. Andernfalls wird der Grid-Suchprozess nur in einem einzelnen Thread ausgeführt, was bei Multi-Core-CPUs langsamer ist.
Nach der Ausführung können Sie auf die Ergebnisse der Rastersuche im Ergebnisobjekt zugreifen, das von grid.fit() zurückgegeben wird. best_score liefert den besten Wert, der während der Optimierung beobachtet wurde, und best_params_ beschreibt die Kombination von Parametern, die die besten Ergebnisse erzielt hat.
Unsere Beispiele werden alle anhand eines kleinen Standarddatensatzes für maschinelles Lernen demonstriert, bei dem es sich um einen Datensatz zur Klassifizierung des Diabetes-Ausbruchs handelt. Dies ist ein kleiner Datensatz und alle numerischen Attribute sind einfach zu handhaben.
Im ersten einfachen Beispiel stellen wir vor, wie Sie die Batch-Größe und die Anzahl der bei der Anpassung des Netzwerks verwendeten Epochen optimieren.
Wir werden einfach verschiedene Batchgrößen von 10 bis 100 auswerten, die Codeauflistung lautet wie folgt:
import random import numpy as np import torch import torch.nn as nn import torch.optim as optim from skorch import NeuralNetClassifier from sklearn.model_selection import GridSearchCV # load the dataset, split into input (X) and output (y) variables dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') X = dataset[:,0:8] y = dataset[:,8] X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1) # PyTorch classifier class PimaClassifier(nn.Module): def __init__(self): super().__init__() self.layer = nn.Linear(8, 12) self.act = nn.ReLU() self.output = nn.Linear(12, 1) self.prob = nn.Sigmoid() def forward(self, x): x = self.act(self.layer(x)) x = self.prob(self.output(x)) return x # create model with skorch model = NeuralNetClassifier( PimaClassifier, criterinotallow=nn.BCELoss, optimizer=optim.Adam, verbose=False ) # define the grid search parameters param_grid = { 'batch_size': [10, 20, 40, 60, 80, 100], 'max_epochs': [10, 50, 100] } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, y) # summarize results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
Die Ergebnisse sind wie folgt:
Best: 0.714844 using {'batch_size': 10, 'max_epochs': 100} 0.665365 (0.020505) with: {'batch_size': 10, 'max_epochs': 10} 0.588542 (0.168055) with: {'batch_size': 10, 'max_epochs': 50} 0.714844 (0.032369) with: {'batch_size': 10, 'max_epochs': 100} 0.671875 (0.022326) with: {'batch_size': 20, 'max_epochs': 10} 0.696615 (0.008027) with: {'batch_size': 20, 'max_epochs': 50} 0.714844 (0.019918) with: {'batch_size': 20, 'max_epochs': 100} 0.666667 (0.009744) with: {'batch_size': 40, 'max_epochs': 10} 0.687500 (0.033603) with: {'batch_size': 40, 'max_epochs': 50} 0.707031 (0.024910) with: {'batch_size': 40, 'max_epochs': 100} 0.667969 (0.014616) with: {'batch_size': 60, 'max_epochs': 10} 0.694010 (0.036966) with: {'batch_size': 60, 'max_epochs': 50} 0.694010 (0.042473) with: {'batch_size': 60, 'max_epochs': 100} 0.670573 (0.023939) with: {'batch_size': 80, 'max_epochs': 10} 0.674479 (0.020752) with: {'batch_size': 80, 'max_epochs': 50} 0.703125 (0.026107) with: {'batch_size': 80, 'max_epochs': 100} 0.680990 (0.014382) with: {'batch_size': 100, 'max_epochs': 10} 0.670573 (0.013279) with: {'batch_size': 100, 'max_epochs': 50} 0.687500 (0.017758) with: {'batch_size': 100, 'max_epochs': 100}
Sie können sehen, dass „batch_size“: 10, „max_epochs“: 100 ungefähr erreicht 71 % Beste Ergebnisse für Genauigkeit.
Sehen wir uns an, wie Sie den Optimierer anpassen. Wir wissen, dass es viele Optimierer gibt, aus denen Sie wählen können, wie z. B. SDG, Adam usw., also wie wählen Sie aus?
Der vollständige Code lautet wie folgt:
import numpy as np import torch import torch.nn as nn import torch.optim as optim from skorch import NeuralNetClassifier from sklearn.model_selection import GridSearchCV # load the dataset, split into input (X) and output (y) variables dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') X = dataset[:,0:8] y = dataset[:,8] X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1) # PyTorch classifier class PimaClassifier(nn.Module): def __init__(self): super().__init__() self.layer = nn.Linear(8, 12) self.act = nn.ReLU() self.output = nn.Linear(12, 1) self.prob = nn.Sigmoid() def forward(self, x): x = self.act(self.layer(x)) x = self.prob(self.output(x)) return x # create model with skorch model = NeuralNetClassifier( PimaClassifier, criterinotallow=nn.BCELoss, max_epochs=100, batch_size=10, verbose=False ) # define the grid search parameters param_grid = { 'optimizer': [optim.SGD, optim.RMSprop, optim.Adagrad, optim.Adadelta, optim.Adam, optim.Adamax, optim.NAdam], } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, y) # summarize results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
Die Ausgabe lautet wie folgt:
Best: 0.721354 using {'optimizer': <class 'torch.optim.adamax.Adamax'>} 0.674479 (0.036828) with: {'optimizer': <class 'torch.optim.sgd.SGD'>} 0.700521 (0.043303) with: {'optimizer': <class 'torch.optim.rmsprop.RMSprop'>} 0.682292 (0.027126) with: {'optimizer': <class 'torch.optim.adagrad.Adagrad'>} 0.572917 (0.051560) with: {'optimizer': <class 'torch.optim.adadelta.Adadelta'>} 0.714844 (0.030758) with: {'optimizer': <class 'torch.optim.adam.Adam'>} 0.721354 (0.019225) with: {'optimizer': <class 'torch.optim.adamax.Adamax'>} 0.709635 (0.024360) with: {'optimizer': <class 'torch.optim.nadam.NAdam'>}
Es ist ersichtlich, dass der Adamax-Optimierungsalgorithmus mit einer Genauigkeit von etwa 72 % der beste für unser Modell und unseren Datensatz ist.
Obwohl der Lernratenplan in Pytorch es uns ermöglicht, die Lernrate je nach Runde dynamisch anzupassen, werden wir als Beispiel die Lernrate und die Parameter der Lernrate als Parameter demonstrieren Rastersuche. In PyTorch werden Lernrate und Dynamik wie folgt festgelegt:
optimizer = optim.SGD(lr=0.001, momentum=0.9)
Verwenden Sie im Skorch-Paket das Präfix Optimizer__, um die Parameter an den Optimierer weiterzuleiten.
import numpy as np import torch import torch.nn as nn import torch.optim as optim from skorch import NeuralNetClassifier from sklearn.model_selection import GridSearchCV # load the dataset, split into input (X) and output (y) variables dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') X = dataset[:,0:8] y = dataset[:,8] X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1) # PyTorch classifier class PimaClassifier(nn.Module): def __init__(self): super().__init__() self.layer = nn.Linear(8, 12) self.act = nn.ReLU() self.output = nn.Linear(12, 1) self.prob = nn.Sigmoid() def forward(self, x): x = self.act(self.layer(x)) x = self.prob(self.output(x)) return x # create model with skorch model = NeuralNetClassifier( PimaClassifier, criterinotallow=nn.BCELoss, optimizer=optim.SGD, max_epochs=100, batch_size=10, verbose=False ) # define the grid search parameters param_grid = { 'optimizer__lr': [0.001, 0.01, 0.1, 0.2, 0.3], 'optimizer__momentum': [0.0, 0.2, 0.4, 0.6, 0.8, 0.9], } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, y) # summarize results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
Die Ergebnisse sind wie folgt:
Best: 0.682292 using {'optimizer__lr': 0.001, 'optimizer__momentum': 0.9} 0.648438 (0.016877) with: {'optimizer__lr': 0.001, 'optimizer__momentum': 0.0} 0.671875 (0.017758) with: {'optimizer__lr': 0.001, 'optimizer__momentum': 0.2} 0.674479 (0.022402) with: {'optimizer__lr': 0.001, 'optimizer__momentum': 0.4} 0.677083 (0.011201) with: {'optimizer__lr': 0.001, 'optimizer__momentum': 0.6} 0.679688 (0.027621) with: {'optimizer__lr': 0.001, 'optimizer__momentum': 0.8} 0.682292 (0.026557) with: {'optimizer__lr': 0.001, 'optimizer__momentum': 0.9} 0.671875 (0.019918) with: {'optimizer__lr': 0.01, 'optimizer__momentum': 0.0} 0.648438 (0.024910) with: {'optimizer__lr': 0.01, 'optimizer__momentum': 0.2} 0.546875 (0.143454) with: {'optimizer__lr': 0.01, 'optimizer__momentum': 0.4} 0.567708 (0.153668) with: {'optimizer__lr': 0.01, 'optimizer__momentum': 0.6} 0.552083 (0.141790) with: {'optimizer__lr': 0.01, 'optimizer__momentum': 0.8} 0.451823 (0.144561) with: {'optimizer__lr': 0.01, 'optimizer__momentum': 0.9} 0.348958 (0.001841) with: {'optimizer__lr': 0.1, 'optimizer__momentum': 0.0} 0.450521 (0.142719) with: {'optimizer__lr': 0.1, 'optimizer__momentum': 0.2} 0.450521 (0.142719) with: {'optimizer__lr': 0.1, 'optimizer__momentum': 0.4} 0.450521 (0.142719) with: {'optimizer__lr': 0.1, 'optimizer__momentum': 0.6} 0.348958 (0.001841) with: {'optimizer__lr': 0.1, 'optimizer__momentum': 0.8} 0.348958 (0.001841) with: {'optimizer__lr': 0.1, 'optimizer__momentum': 0.9} 0.444010 (0.136265) with: {'optimizer__lr': 0.2, 'optimizer__momentum': 0.0} 0.450521 (0.142719) with: {'optimizer__lr': 0.2, 'optimizer__momentum': 0.2} 0.348958 (0.001841) with: {'optimizer__lr': 0.2, 'optimizer__momentum': 0.4} 0.552083 (0.141790) with: {'optimizer__lr': 0.2, 'optimizer__momentum': 0.6} 0.549479 (0.142719) with: {'optimizer__lr': 0.2, 'optimizer__momentum': 0.8} 0.651042 (0.001841) with: {'optimizer__lr': 0.2, 'optimizer__momentum': 0.9} 0.552083 (0.141790) with: {'optimizer__lr': 0.3, 'optimizer__momentum': 0.0} 0.348958 (0.001841) with: {'optimizer__lr': 0.3, 'optimizer__momentum': 0.2} 0.450521 (0.142719) with: {'optimizer__lr': 0.3, 'optimizer__momentum': 0.4} 0.552083 (0.141790) with: {'optimizer__lr': 0.3, 'optimizer__momentum': 0.6} 0.450521 (0.142719) with: {'optimizer__lr': 0.3, 'optimizer__momentum': 0.8} 0.450521 (0.142719) with: {'optimizer__lr': 0.3, 'optimizer__momentum': 0.9}
Für SGD wurden die besten Ergebnisse mit einer Lernrate von 0,001 und einem Impuls von 0,9 erzielt, mit einer Genauigkeit von etwa 68 %.
Die Aktivierungsfunktion steuert die Nichtlinearität eines einzelnen Neurons. Wir werden die Evaluierung einiger der in PyTorch verfügbaren Aktivierungsfunktionen demonstrieren.
import numpy as np import torch import torch.nn as nn import torch.nn.init as init import torch.optim as optim from skorch import NeuralNetClassifier from sklearn.model_selection import GridSearchCV # load the dataset, split into input (X) and output (y) variables dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') X = dataset[:,0:8] y = dataset[:,8] X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1) # PyTorch classifier class PimaClassifier(nn.Module): def __init__(self, activatinotallow=nn.ReLU): super().__init__() self.layer = nn.Linear(8, 12) self.act = activation() self.output = nn.Linear(12, 1) self.prob = nn.Sigmoid() # manually init weights init.kaiming_uniform_(self.layer.weight) init.kaiming_uniform_(self.output.weight) def forward(self, x): x = self.act(self.layer(x)) x = self.prob(self.output(x)) return x # create model with skorch model = NeuralNetClassifier( PimaClassifier, criterinotallow=nn.BCELoss, optimizer=optim.Adamax, max_epochs=100, batch_size=10, verbose=False ) # define the grid search parameters param_grid = { 'module__activation': [nn.Identity, nn.ReLU, nn.ELU, nn.ReLU6, nn.GELU, nn.Softplus, nn.Softsign, nn.Tanh, nn.Sigmoid, nn.Hardsigmoid] } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, y) # summarize results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
Die Ergebnisse sind wie folgt:
Best: 0.699219 using {'module__activation': <class 'torch.nn.modules.activation.ReLU'>} 0.687500 (0.025315) with: {'module__activation': <class 'torch.nn.modules.linear.Identity'>} 0.699219 (0.011049) with: {'module__activation': <class 'torch.nn.modules.activation.ReLU'>} 0.674479 (0.035849) with: {'module__activation': <class 'torch.nn.modules.activation.ELU'>} 0.621094 (0.063549) with: {'module__activation': <class 'torch.nn.modules.activation.ReLU6'>} 0.674479 (0.017566) with: {'module__activation': <class 'torch.nn.modules.activation.GELU'>} 0.558594 (0.149189) with: {'module__activation': <class 'torch.nn.modules.activation.Softplus'>} 0.675781 (0.014616) with: {'module__activation': <class 'torch.nn.modules.activation.Softsign'>} 0.619792 (0.018688) with: {'module__activation': <class 'torch.nn.modules.activation.Tanh'>} 0.643229 (0.019225) with: {'module__activation': <class 'torch.nn.modules.activation.Sigmoid'>} 0.636719 (0.022326) with: {'module__activation': <class 'torch.nn.modules.activation.Hardsigmoid'>}
Die ReLU-Aktivierungsfunktion erzielte die besten Ergebnisse mit einer Genauigkeit von etwa 70 %.
在本例中,我们将尝试在0.0到0.9之间的dropout百分比(1.0没有意义)和在0到5之间的MaxNorm权重约束值。
import numpy as np import torch import torch.nn as nn import torch.nn.init as init import torch.optim as optim from skorch import NeuralNetClassifier from sklearn.model_selection import GridSearchCV # load the dataset, split into input (X) and output (y) variables dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') X = dataset[:,0:8] y = dataset[:,8] X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1) # PyTorch classifier class PimaClassifier(nn.Module): def __init__(self, dropout_rate=0.5, weight_cnotallow=1.0): super().__init__() self.layer = nn.Linear(8, 12) self.act = nn.ReLU() self.dropout = nn.Dropout(dropout_rate) self.output = nn.Linear(12, 1) self.prob = nn.Sigmoid() self.weight_constraint = weight_constraint # manually init weights init.kaiming_uniform_(self.layer.weight) init.kaiming_uniform_(self.output.weight) def forward(self, x): # maxnorm weight before actual forward pass with torch.no_grad(): norm = self.layer.weight.norm(2, dim=0, keepdim=True).clamp(min=self.weight_constraint / 2) desired = torch.clamp(norm, max=self.weight_constraint) self.layer.weight *= (desired / norm) # actual forward pass x = self.act(self.layer(x)) x = self.dropout(x) x = self.prob(self.output(x)) return x # create model with skorch model = NeuralNetClassifier( PimaClassifier, criterinotallow=nn.BCELoss, optimizer=optim.Adamax, max_epochs=100, batch_size=10, verbose=False ) # define the grid search parameters param_grid = { 'module__weight_constraint': [1.0, 2.0, 3.0, 4.0, 5.0], 'module__dropout_rate': [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, y) # summarize results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
结果如下:
Best: 0.701823 using {'module__dropout_rate': 0.1, 'module__weight_constraint': 2.0} 0.669271 (0.015073) with: {'module__dropout_rate': 0.0, 'module__weight_constraint': 1.0} 0.692708 (0.035132) with: {'module__dropout_rate': 0.0, 'module__weight_constraint': 2.0} 0.589844 (0.170180) with: {'module__dropout_rate': 0.0, 'module__weight_constraint': 3.0} 0.561198 (0.151131) with: {'module__dropout_rate': 0.0, 'module__weight_constraint': 4.0} 0.688802 (0.021710) with: {'module__dropout_rate': 0.0, 'module__weight_constraint': 5.0} 0.697917 (0.009744) with: {'module__dropout_rate': 0.1, 'module__weight_constraint': 1.0} 0.701823 (0.016367) with: {'module__dropout_rate': 0.1, 'module__weight_constraint': 2.0} 0.694010 (0.010253) with: {'module__dropout_rate': 0.1, 'module__weight_constraint': 3.0} 0.686198 (0.025976) with: {'module__dropout_rate': 0.1, 'module__weight_constraint': 4.0} 0.679688 (0.026107) with: {'module__dropout_rate': 0.1, 'module__weight_constraint': 5.0} 0.701823 (0.029635) with: {'module__dropout_rate': 0.2, 'module__weight_constraint': 1.0} 0.682292 (0.014731) with: {'module__dropout_rate': 0.2, 'module__weight_constraint': 2.0} 0.701823 (0.009744) with: {'module__dropout_rate': 0.2, 'module__weight_constraint': 3.0} 0.701823 (0.026557) with: {'module__dropout_rate': 0.2, 'module__weight_constraint': 4.0} 0.687500 (0.015947) with: {'module__dropout_rate': 0.2, 'module__weight_constraint': 5.0} 0.686198 (0.006639) with: {'module__dropout_rate': 0.3, 'module__weight_constraint': 1.0} 0.656250 (0.006379) with: {'module__dropout_rate': 0.3, 'module__weight_constraint': 2.0} 0.565104 (0.155608) with: {'module__dropout_rate': 0.3, 'module__weight_constraint': 3.0} 0.700521 (0.028940) with: {'module__dropout_rate': 0.3, 'module__weight_constraint': 4.0} 0.669271 (0.012890) with: {'module__dropout_rate': 0.3, 'module__weight_constraint': 5.0} 0.661458 (0.018688) with: {'module__dropout_rate': 0.4, 'module__weight_constraint': 1.0} 0.669271 (0.017566) with: {'module__dropout_rate': 0.4, 'module__weight_constraint': 2.0} 0.652344 (0.006379) with: {'module__dropout_rate': 0.4, 'module__weight_constraint': 3.0} 0.680990 (0.037783) with: {'module__dropout_rate': 0.4, 'module__weight_constraint': 4.0} 0.692708 (0.042112) with: {'module__dropout_rate': 0.4, 'module__weight_constraint': 5.0} 0.666667 (0.006639) with: {'module__dropout_rate': 0.5, 'module__weight_constraint': 1.0} 0.652344 (0.011500) with: {'module__dropout_rate': 0.5, 'module__weight_constraint': 2.0} 0.662760 (0.007366) with: {'module__dropout_rate': 0.5, 'module__weight_constraint': 3.0} 0.558594 (0.146610) with: {'module__dropout_rate': 0.5, 'module__weight_constraint': 4.0} 0.552083 (0.141826) with: {'module__dropout_rate': 0.5, 'module__weight_constraint': 5.0} 0.548177 (0.141826) with: {'module__dropout_rate': 0.6, 'module__weight_constraint': 1.0} 0.653646 (0.013279) with: {'module__dropout_rate': 0.6, 'module__weight_constraint': 2.0} 0.661458 (0.008027) with: {'module__dropout_rate': 0.6, 'module__weight_constraint': 3.0} 0.553385 (0.142719) with: {'module__dropout_rate': 0.6, 'module__weight_constraint': 4.0} 0.669271 (0.035132) with: {'module__dropout_rate': 0.6, 'module__weight_constraint': 5.0} 0.662760 (0.015733) with: {'module__dropout_rate': 0.7, 'module__weight_constraint': 1.0} 0.636719 (0.024910) with: {'module__dropout_rate': 0.7, 'module__weight_constraint': 2.0} 0.550781 (0.146818) with: {'module__dropout_rate': 0.7, 'module__weight_constraint': 3.0} 0.537760 (0.140094) with: {'module__dropout_rate': 0.7, 'module__weight_constraint': 4.0} 0.542969 (0.138144) with: {'module__dropout_rate': 0.7, 'module__weight_constraint': 5.0} 0.565104 (0.148654) with: {'module__dropout_rate': 0.8, 'module__weight_constraint': 1.0} 0.657552 (0.008027) with: {'module__dropout_rate': 0.8, 'module__weight_constraint': 2.0} 0.428385 (0.111418) with: {'module__dropout_rate': 0.8, 'module__weight_constraint': 3.0} 0.549479 (0.142719) with: {'module__dropout_rate': 0.8, 'module__weight_constraint': 4.0} 0.648438 (0.005524) with: {'module__dropout_rate': 0.8, 'module__weight_constraint': 5.0} 0.540365 (0.136861) with: {'module__dropout_rate': 0.9, 'module__weight_constraint': 1.0} 0.605469 (0.053083) with: {'module__dropout_rate': 0.9, 'module__weight_constraint': 2.0} 0.553385 (0.139948) with: {'module__dropout_rate': 0.9, 'module__weight_constraint': 3.0} 0.549479 (0.142719) with: {'module__dropout_rate': 0.9, 'module__weight_constraint': 4.0} 0.595052 (0.075566) with: {'module__dropout_rate': 0.9, 'module__weight_constraint': 5.0}
可以看到,10%的Dropout和2.0的权重约束获得了70%的最佳精度。
单层神经元的数量是一个需要调优的重要参数。一般来说,一层神经元的数量控制着网络的表示能力,至少在拓扑的这一点上是这样。
理论上来说:由于通用逼近定理,一个足够大的单层网络可以近似任何其他神经网络。
在本例中,将尝试从1到30的值,步骤为5。一个更大的网络需要更多的训练,至少批大小和epoch的数量应该与神经元的数量一起优化。
import numpy as np import torch import torch.nn as nn import torch.nn.init as init import torch.optim as optim from skorch import NeuralNetClassifier from sklearn.model_selection import GridSearchCV # load the dataset, split into input (X) and output (y) variables dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') X = dataset[:,0:8] y = dataset[:,8] X = torch.tensor(X, dtype=torch.float32) y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1) class PimaClassifier(nn.Module): def __init__(self, n_neurnotallow=12): super().__init__() self.layer = nn.Linear(8, n_neurons) self.act = nn.ReLU() self.dropout = nn.Dropout(0.1) self.output = nn.Linear(n_neurons, 1) self.prob = nn.Sigmoid() self.weight_constraint = 2.0 # manually init weights init.kaiming_uniform_(self.layer.weight) init.kaiming_uniform_(self.output.weight) def forward(self, x): # maxnorm weight before actual forward pass with torch.no_grad(): norm = self.layer.weight.norm(2, dim=0, keepdim=True).clamp(min=self.weight_constraint / 2) desired = torch.clamp(norm, max=self.weight_constraint) self.layer.weight *= (desired / norm) # actual forward pass x = self.act(self.layer(x)) x = self.dropout(x) x = self.prob(self.output(x)) return x # create model with skorch model = NeuralNetClassifier( PimaClassifier, criterinotallow=nn.BCELoss, optimizer=optim.Adamax, max_epochs=100, batch_size=10, verbose=False ) # define the grid search parameters param_grid = { 'module__n_neurons': [1, 5, 10, 15, 20, 25, 30] } grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3) grid_result = grid.fit(X, y) # summarize results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
结果如下:
Best: 0.708333 using {'module__n_neurons': 30} 0.654948 (0.003683) with: {'module__n_neurons': 1} 0.666667 (0.023073) with: {'module__n_neurons': 5} 0.694010 (0.014382) with: {'module__n_neurons': 10} 0.682292 (0.014382) with: {'module__n_neurons': 15} 0.707031 (0.028705) with: {'module__n_neurons': 20} 0.703125 (0.030758) with: {'module__n_neurons': 25} 0.708333 (0.015733) with: {'module__n_neurons': 30}
你可以看到,在隐藏层中有30个神经元的网络获得了最好的结果,准确率约为71%。
Das obige ist der detaillierte Inhalt vonWie führt man mit scikit-learn eine Hyperparameter-Rastersuche nach einem PyTorch-Modell durch?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!