From 4fc27616851faa08397cff298efbffb98d8e4ff9 Mon Sep 17 00:00:00 2001 From: Yuanshuo Cui Date: Tue, 19 Mar 2024 22:16:45 -0700 Subject: [PATCH] Create TARGETS for captum/_utils (#1250) Summary: Create separate TARGETS files for different part of Captum project. Start with a relatively simple one: captum/_utils. Mostly TARGETS file change, with more exception to correct import, split test helper function to separate file etc. Differential Revision: D55091069 --- captum/_utils/av.py | 2 +- captum/_utils/models/__init__.py | 20 ------- tests/utils/evaluate_linear_model.py | 52 +++++++++++++++++++ .../linear_models/_test_linear_classifier.py | 10 ++-- tests/utils/test_linear_model.py | 52 ++----------------- 5 files changed, 61 insertions(+), 75 deletions(-) create mode 100644 tests/utils/evaluate_linear_model.py diff --git a/captum/_utils/av.py b/captum/_utils/av.py index c5ecc5325f..b26f0fb14e 100644 --- a/captum/_utils/av.py +++ b/captum/_utils/av.py @@ -8,7 +8,7 @@ import captum._utils.common as common import torch -from captum.attr import LayerActivation +from captum.attr._core.layer.layer_activation import LayerActivation from torch import Tensor from torch.nn import Module from torch.utils.data import DataLoader, Dataset diff --git a/captum/_utils/models/__init__.py b/captum/_utils/models/__init__.py index 5ebcee2e47..6c936bc955 100644 --- a/captum/_utils/models/__init__.py +++ b/captum/_utils/models/__init__.py @@ -1,25 +1,5 @@ -from captum._utils.models.linear_model import ( - LinearModel, - SGDLasso, - SGDLinearModel, - SGDLinearRegression, - SGDRidge, - SkLearnLasso, - SkLearnLinearModel, - SkLearnLinearRegression, - SkLearnRidge, -) from captum._utils.models.model import Model __all__ = [ "Model", - "LinearModel", - "SGDLinearModel", - "SGDLasso", - "SGDRidge", - "SGDLinearRegression", - "SkLearnLinearModel", - "SkLearnLasso", - "SkLearnRidge", - "SkLearnLinearRegression", ] diff --git a/tests/utils/evaluate_linear_model.py b/tests/utils/evaluate_linear_model.py new file mode 100644 index 0000000000..36dfeb8044 --- /dev/null +++ b/tests/utils/evaluate_linear_model.py @@ -0,0 +1,52 @@ +# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. +from typing import cast, Dict + +import torch +from torch import Tensor + + +def evaluate(test_data, classifier) -> Dict[str, Tensor]: + classifier.eval() + + l1_loss = 0.0 + l2_loss = 0.0 + n = 0 + l2_losses = [] + with torch.no_grad(): + for data in test_data: + if len(data) == 2: + x, y = data + w = None + else: + x, y, w = data + + out = classifier(x) + + y = y.view(x.shape[0], -1) + assert y.shape == out.shape + + if w is None: + l1_loss += (out - y).abs().sum(0).to(dtype=torch.float64) + l2_loss += ((out - y) ** 2).sum(0).to(dtype=torch.float64) + l2_losses.append(((out - y) ** 2).to(dtype=torch.float64)) + else: + l1_loss += ( + (w.view(-1, 1) * (out - y)).abs().sum(0).to(dtype=torch.float64) + ) + l2_loss += ( + (w.view(-1, 1) * ((out - y) ** 2)).sum(0).to(dtype=torch.float64) + ) + l2_losses.append( + (w.view(-1, 1) * ((out - y) ** 2)).to(dtype=torch.float64) + ) + + n += x.shape[0] + + l2_losses = torch.cat(l2_losses, dim=0) + assert n > 0 + + # just to double check + assert ((l2_losses.mean(0) - l2_loss / n).abs() <= 0.1).all() + + classifier.train() + return {"l1": cast(Tensor, l1_loss / n), "l2": cast(Tensor, l2_loss / n)} diff --git a/tests/utils/models/linear_models/_test_linear_classifier.py b/tests/utils/models/linear_models/_test_linear_classifier.py index 37e3a6f2de..3345a3525e 100644 --- a/tests/utils/models/linear_models/_test_linear_classifier.py +++ b/tests/utils/models/linear_models/_test_linear_classifier.py @@ -6,7 +6,7 @@ import numpy as np import sklearn.datasets as datasets import torch -from tests.utils.test_linear_model import _evaluate +from tests.utils.evaluate_linear_model import evaluate from torch.utils.data import DataLoader, TensorDataset @@ -80,11 +80,11 @@ def compare_to_sk_learn( alpha=alpha, ) - sklearn_stats.update(_evaluate(val_loader, sklearn_classifier)) - pytorch_stats.update(_evaluate(val_loader, pytorch_classifier)) + sklearn_stats.update(evaluate(val_loader, sklearn_classifier)) + pytorch_stats.update(evaluate(val_loader, pytorch_classifier)) - train_stats_pytorch = _evaluate(train_loader, pytorch_classifier) - train_stats_sklearn = _evaluate(train_loader, sklearn_classifier) + train_stats_pytorch = evaluate(train_loader, pytorch_classifier) + train_stats_sklearn = evaluate(train_loader, sklearn_classifier) o_pytorch = {"l2": train_stats_pytorch["l2"]} o_sklearn = {"l2": train_stats_sklearn["l2"]} diff --git a/tests/utils/test_linear_model.py b/tests/utils/test_linear_model.py index cc1bd23029..b3994af904 100644 --- a/tests/utils/test_linear_model.py +++ b/tests/utils/test_linear_model.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -from typing import cast, Dict, Optional, Union +from typing import Optional, Union import torch from captum._utils.models.linear_model.model import ( @@ -10,56 +10,10 @@ ) from tests.helpers import BaseTest from tests.helpers.basic import assertTensorAlmostEqual +from tests.utils.evaluate_linear_model import evaluate from torch import Tensor -def _evaluate(test_data, classifier) -> Dict[str, Tensor]: - classifier.eval() - - l1_loss = 0.0 - l2_loss = 0.0 - n = 0 - l2_losses = [] - with torch.no_grad(): - for data in test_data: - if len(data) == 2: - x, y = data - w = None - else: - x, y, w = data - - out = classifier(x) - - y = y.view(x.shape[0], -1) - assert y.shape == out.shape - - if w is None: - l1_loss += (out - y).abs().sum(0).to(dtype=torch.float64) - l2_loss += ((out - y) ** 2).sum(0).to(dtype=torch.float64) - l2_losses.append(((out - y) ** 2).to(dtype=torch.float64)) - else: - l1_loss += ( - (w.view(-1, 1) * (out - y)).abs().sum(0).to(dtype=torch.float64) - ) - l2_loss += ( - (w.view(-1, 1) * ((out - y) ** 2)).sum(0).to(dtype=torch.float64) - ) - l2_losses.append( - (w.view(-1, 1) * ((out - y) ** 2)).to(dtype=torch.float64) - ) - - n += x.shape[0] - - l2_losses = torch.cat(l2_losses, dim=0) - assert n > 0 - - # just to double check - assert ((l2_losses.mean(0) - l2_loss / n).abs() <= 0.1).all() - - classifier.train() - return {"l1": cast(Tensor, l1_loss / n), "l2": cast(Tensor, l2_loss / n)} - - class TestLinearModel(BaseTest): MAX_POINTS: int = 3 @@ -100,7 +54,7 @@ def train_and_compare( self.assertTrue(model.bias() is not None if bias else model.bias() is None) - l2_loss = _evaluate(train_loader, model)["l2"] + l2_loss = evaluate(train_loader, model)["l2"] if objective == "lasso": reg = model.representation().norm(p=1).view_as(l2_loss)