Skip to content
Open
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6b8ee39
Create _test_time.py
Jun 10, 2025
cd13eed
removed unnecessary clauses in TestTimeCriterion
Jun 11, 2025
d0ee0a3
added tests for TestTimeNet
Jun 12, 2025
32aec72
Corrected wrong attribute call
Jun 12, 2025
c23e8f2
fixed wrong dataloader in test
Jun 12, 2025
a3c0ced
remade tests, improved TestTimeNet
Jun 12, 2025
28ce3f3
Updated tests
Jun 12, 2025
e81a62e
added softmax_entropy, added foundation of Tent
Jun 13, 2025
4c76ba4
Updated Tent
Jun 16, 2025
aab0c09
added Tent, param freeze
Jun 24, 2025
44b2df9
Merge branch 'main' into mbarneche-tent
mbarneche Jun 24, 2025
616cc29
changed None to all to adapt all params
Jun 24, 2025
26840fd
Merge branch 'mbarneche-tent' of https://github.com/mbarneche/skada i…
Jun 24, 2025
b4c1841
Add shot loss
marionpavaux Jun 24, 2025
8bacda4
Merge branch 'mbarneche-tent' of https://github.com/mbarneche/skada i…
marionpavaux Jun 24, 2025
1f52a1b
Add reference for shot loss
marionpavaux Jun 24, 2025
bc37c6e
Implement SHOT model
FDerrida Jun 24, 2025
5a71c1d
Merge branch 'mbarneche-tent' of github.com:mbarneche/skada into mbar…
FDerrida Jun 24, 2025
6d34ed8
Add estimated labels
marionpavaux Jun 24, 2025
0c0dfae
Merge branch 'mbarneche-tent' of https://github.com/mbarneche/skada i…
marionpavaux Jun 24, 2025
1e501b8
Merge branch 'main' into mbarneche-tent
tgnassou Jun 25, 2025
7b17529
Add example for test time
marionpavaux Jun 25, 2025
62d86db
Add example for test time
marionpavaux Jun 25, 2025
d29d299
Add shot implementation and PseudoLabels class
FDerrida Jun 25, 2025
65c60d3
Merge branch 'mbarneche-tent' of github.com:mbarneche/skada into mbar…
FDerrida Jun 25, 2025
d103ef8
Adapt estimated labels to callbacks
marionpavaux Jun 25, 2025
96717f7
Merge branch 'main' into mbarneche-tent
tgnassou Sep 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions skada/deep/_test_time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Author : Maxence Barneche
#
# License: BSD-3-Clause

import torch

from skada.deep.base import DomainAwareNet


class TestTimeCriterion(torch.nn.Module):
def __init__(
self,
base_criterion,
adapt_criterion,
reg=1,
reduction="mean",
train_on_target=False,
mode="finetune",
):
super().__init__()
self.base_criterion = base_criterion
self.adapt_criterion = adapt_criterion
self.reg = reg
self.train_on_target = train_on_target
self.mode = mode

# Update the reduce parameter for both criteria if specified
if hasattr(self.base_criterion, "reduction"):
self.base_criterion.reduction = reduction

# TODO: implement losses between source and target
# that are sum of the losses of each sample
# if hasattr(self.adapt_criterion, 'reduction'):
# self.adapt_criterion.reduction = reduction

def forward(
self,
y_pred,
y_true,
):
"""
Parameters
----------
y_pred : tuple
This tuple comprises all the different data
needed to compute DA loss:
- y_pred : prediction of the source and target domains
- domain_pred : prediction of domain classifier if given
- features : features of the chosen layer
of source and target domains
- sample_domain : giving the domain of each samples
y_true :
The true labels. Available for source, masked for target.
"""
y_pred, domain_pred, features, sample_domain, sample_idx = y_pred

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should get only source or target so no need to separate here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, there is no need for all the if _thing_ is not None clauses. Is that correct?
Does this also mean that the train_on_target attribute has no use? Because using target data only depends on the mode now, right?

source_idx = sample_domain >= 0
y_pred_s = y_pred[source_idx]
y_pred_t = y_pred[~source_idx]

if domain_pred is not None:
domain_pred_s = domain_pred[source_idx]
domain_pred_t = domain_pred[~source_idx]
else:
domain_pred_s = None
domain_pred_t = None

if features is not None:
features_s = features[source_idx]
features_t = features[~source_idx]
else:
features_s = None
features_t = None

if sample_idx is not None:
sample_idx_s = sample_idx[source_idx]
sample_idx_t = sample_idx[~source_idx]
else:
sample_idx_s = None
sample_idx_t = None

if self.train_on_target:
Comment thread
tgnassou marked this conversation as resolved.
base_loss = self.base_criterion(y_pred_t, y_true[~source_idx])
else:
base_loss = self.base_criterion(y_pred_s, y_true[source_idx])

if self.mode == "finetune":
# In finetune mode, we only compute the base loss
return base_loss
elif self.mode == "adapt":
self.adapt_criterion(
y_s=y_true[source_idx],
y_pred_s=y_pred_s,
y_pred_t=y_pred_t,
domain_pred_s=domain_pred_s,
domain_pred_t=domain_pred_t,
features_s=features_s,
features_t=features_t,
sample_idx_s=sample_idx_s,
sample_idx_t=sample_idx_t,
)


class TestTimeNet(DomainAwareNet):
def __init__(self, module, criterion: "TestTimeCriterion", **kwargs):
super().__init__(module, criterion=criterion, **kwargs)

def fit_prepare(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not fan of fit_prepare but I don't have other chouchou for now

self, X, y=None, sample_domain=None, sample_weight=None, **fit_params
):
X = self._prepare_input(X, y, sample_domain, sample_weight)
X = X.select_source()
self.partial_fit(X, None, **fit_params)
return self

def fit_adapt(self, X, sample_domain=None, sample_weight=None, **fit_params):
if sample_domain is None:
sample_domain = -1
X = self._prepare_input(X, None, sample_domain, sample_weight)
X = X.select_target()
self.criterion.mode = "adapt"
self.partial_fit(X, None, **fit_params)
# here should be a partial fit call with criterion_adapt

def fit(self, X, y=None, sample_domain=None, sample_weight=None, **fit_params):
X = self._prepare_input(X, y, sample_domain, sample_weight)
self.fit_prepare(X, **fit_params)
self.fit_adapt(X, **fit_params)
return self