Module hummingbird.ml.operator_converters.skl_linear
Expand source code
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import torch
import numpy as np
from onnxconverter_common.registration import register_converter
from ._base_operator import BaseOperator
"""
Converters for scikit-learn linear models: LinearRegression, LogisticRegression, LinearSVC, SGDClassifier, LogisticRegressionCV
"""
class SklearnLinearModel(BaseOperator, torch.nn.Module):
def __init__(self, coefficients, intercepts, device, classes=[0], multi_class=None, is_linear_regression=False):
super(SklearnLinearModel, self).__init__()
self.coefficients = torch.nn.Parameter(torch.from_numpy(coefficients), requires_grad=False)
self.intercepts = torch.nn.Parameter(torch.from_numpy(intercepts), requires_grad=False)
self.classes = torch.nn.Parameter(torch.IntTensor(classes), requires_grad=False)
self.multi_class = multi_class
self.regression = is_linear_regression
self.perform_class_select = False
if min(classes) != 0 or max(classes) != len(classes) - 1:
self.perform_class_select = True
self.binary_classification = False
if len(classes) == 2:
self.binary_classification = True
def forward(self, x):
output = torch.addmm(self.intercepts, x, self.coefficients)
if self.multi_class == "multinomial":
output = torch.softmax(output, dim=1)
elif self.regression:
return output
else:
output = torch.sigmoid(output)
if not self.binary_classification:
output /= torch.sum(output, dim=1, keepdim=True)
if self.binary_classification:
output = torch.cat([1 - output, output], dim=1)
if self.perform_class_select:
return torch.index_select(self.classes, 0, torch.argmax(output, dim=1)), output
else:
return torch.argmax(output, dim=1), output
def convert_sklearn_linear_model(operator, device, extra_config):
"""
Converter for `sklearn.svm.LinearSVC`, `sklearn.linear_model.LogisticRegression`,
`sklearn.linear_model.SGDClassifier`, and `sklearn.linear_model.LogisticRegressionCV`
Args:
operator: An operator wrapping a `sklearn.svm.LinearSVC`, `sklearn.linear_model.LogisticRegression`,
`sklearn.linear_model.SGDClassifier`, or `sklearn.linear_model.LogisticRegressionCV` model
device: String defining the type of device the converted operator should be run on
extra_config: Extra configuration used to select the best conversion strategy
Returns:
A PyTorch model
"""
classes = [0] if not hasattr(operator.raw_operator, "classes_") else operator.raw_operator.classes_
if not all([type(x) in [int, np.int32, np.int64] for x in classes]):
raise RuntimeError(
"Hummingbird currently supports only integer labels for class labels. Please file an issue at https://github.com/microsoft/hummingbird."
)
coefficients = operator.raw_operator.coef_.transpose().astype("float32")
intercepts = operator.raw_operator.intercept_.reshape(1, -1).astype("float32")
multi_class = None
if hasattr(operator.raw_operator, "multi_class"):
if operator.raw_operator.multi_class == "ovr" or operator.raw_operator.solver in ["warn", "liblinear"]:
multi_class = "ovr"
else:
multi_class = "multinomial"
return SklearnLinearModel(coefficients, intercepts, device, classes=classes, multi_class=multi_class)
def convert_sklearn_linear_regression_model(operator, device, extra_config):
"""
Converter for `sklearn.linear_model.LinearRegression`
Args:
operator: An operator wrapping a `sklearn.linear_model.LinearRegression` model
device: String defining the type of device the converted operator should be run on
extra_config: Extra configuration used to select the best conversion strategy
Returns:
A PyTorch model
"""
coefficients = operator.raw_operator.coef_.transpose().reshape(-1, 1).astype("float32")
intercepts = operator.raw_operator.intercept_.reshape(1, -1).astype("float32")
return SklearnLinearModel(coefficients, intercepts, device, is_linear_regression=True)
register_converter("SklearnLinearRegression", convert_sklearn_linear_regression_model)
register_converter("SklearnLogisticRegression", convert_sklearn_linear_model)
register_converter("SklearnLinearSVC", convert_sklearn_linear_model)
register_converter("SklearnSGDClassifier", convert_sklearn_linear_model)
register_converter("SklearnLogisticRegressionCV", convert_sklearn_linear_model)
Functions
def convert_sklearn_linear_model(operator, device, extra_config)
-
Converter for
sklearn.svm.LinearSVC
,sklearn.linear_model.LogisticRegression
,sklearn.linear_model.SGDClassifier
, andsklearn.linear_model.LogisticRegressionCV
Args
operator
- An operator wrapping a
sklearn.svm.LinearSVC
,sklearn.linear_model.LogisticRegression
,sklearn.linear_model.SGDClassifier
, orsklearn.linear_model.LogisticRegressionCV
model device
- String defining the type of device the converted operator should be run on
extra_config
- Extra configuration used to select the best conversion strategy
Returns
A PyTorch model
Expand source code
def convert_sklearn_linear_model(operator, device, extra_config): """ Converter for `sklearn.svm.LinearSVC`, `sklearn.linear_model.LogisticRegression`, `sklearn.linear_model.SGDClassifier`, and `sklearn.linear_model.LogisticRegressionCV` Args: operator: An operator wrapping a `sklearn.svm.LinearSVC`, `sklearn.linear_model.LogisticRegression`, `sklearn.linear_model.SGDClassifier`, or `sklearn.linear_model.LogisticRegressionCV` model device: String defining the type of device the converted operator should be run on extra_config: Extra configuration used to select the best conversion strategy Returns: A PyTorch model """ classes = [0] if not hasattr(operator.raw_operator, "classes_") else operator.raw_operator.classes_ if not all([type(x) in [int, np.int32, np.int64] for x in classes]): raise RuntimeError( "Hummingbird currently supports only integer labels for class labels. Please file an issue at https://github.com/microsoft/hummingbird." ) coefficients = operator.raw_operator.coef_.transpose().astype("float32") intercepts = operator.raw_operator.intercept_.reshape(1, -1).astype("float32") multi_class = None if hasattr(operator.raw_operator, "multi_class"): if operator.raw_operator.multi_class == "ovr" or operator.raw_operator.solver in ["warn", "liblinear"]: multi_class = "ovr" else: multi_class = "multinomial" return SklearnLinearModel(coefficients, intercepts, device, classes=classes, multi_class=multi_class)
def convert_sklearn_linear_regression_model(operator, device, extra_config)
-
Converter for
sklearn.linear_model.LinearRegression
Args
operator
- An operator wrapping a
sklearn.linear_model.LinearRegression
model device
- String defining the type of device the converted operator should be run on
extra_config
- Extra configuration used to select the best conversion strategy
Returns
A PyTorch model
Expand source code
def convert_sklearn_linear_regression_model(operator, device, extra_config): """ Converter for `sklearn.linear_model.LinearRegression` Args: operator: An operator wrapping a `sklearn.linear_model.LinearRegression` model device: String defining the type of device the converted operator should be run on extra_config: Extra configuration used to select the best conversion strategy Returns: A PyTorch model """ coefficients = operator.raw_operator.coef_.transpose().reshape(-1, 1).astype("float32") intercepts = operator.raw_operator.intercept_.reshape(1, -1).astype("float32") return SklearnLinearModel(coefficients, intercepts, device, is_linear_regression=True)
Classes
class SklearnLinearModel (coefficients, intercepts, device, classes=[0], multi_class=None, is_linear_regression=False)
-
Abstract class defining the basic structure for operator implementations in Hummingbird.
Expand source code
class SklearnLinearModel(BaseOperator, torch.nn.Module): def __init__(self, coefficients, intercepts, device, classes=[0], multi_class=None, is_linear_regression=False): super(SklearnLinearModel, self).__init__() self.coefficients = torch.nn.Parameter(torch.from_numpy(coefficients), requires_grad=False) self.intercepts = torch.nn.Parameter(torch.from_numpy(intercepts), requires_grad=False) self.classes = torch.nn.Parameter(torch.IntTensor(classes), requires_grad=False) self.multi_class = multi_class self.regression = is_linear_regression self.perform_class_select = False if min(classes) != 0 or max(classes) != len(classes) - 1: self.perform_class_select = True self.binary_classification = False if len(classes) == 2: self.binary_classification = True def forward(self, x): output = torch.addmm(self.intercepts, x, self.coefficients) if self.multi_class == "multinomial": output = torch.softmax(output, dim=1) elif self.regression: return output else: output = torch.sigmoid(output) if not self.binary_classification: output /= torch.sum(output, dim=1, keepdim=True) if self.binary_classification: output = torch.cat([1 - output, output], dim=1) if self.perform_class_select: return torch.index_select(self.classes, 0, torch.argmax(output, dim=1)), output else: return torch.argmax(output, dim=1), output
Ancestors
- hummingbird.ml.operator_converters._base_operator.BaseOperator
- abc.ABC
- torch.nn.modules.module.Module
Methods
def forward(self, x)
-
Defines the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Module
instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.Expand source code
def forward(self, x): output = torch.addmm(self.intercepts, x, self.coefficients) if self.multi_class == "multinomial": output = torch.softmax(output, dim=1) elif self.regression: return output else: output = torch.sigmoid(output) if not self.binary_classification: output /= torch.sum(output, dim=1, keepdim=True) if self.binary_classification: output = torch.cat([1 - output, output], dim=1) if self.perform_class_select: return torch.index_select(self.classes, 0, torch.argmax(output, dim=1)), output else: return torch.argmax(output, dim=1), output