diff --git a/README.md b/README.md
index 3f14d5509e1f946bc3456d19b2a9416949faefc2..991dcab918725606d955eafff7e2ec0266a99667 100644
--- a/README.md
+++ b/README.md
@@ -64,10 +64,10 @@ A similar tagger called `20230129` has been proposed to moderate this issue.
 This tagger shares the same characteristics as `20230111` and differs in three important aspects:
 
 * the number of training epochs was brought from 1,000 to 10,000 to let the original features be largely forgotten,
-* the training stage involved more data: 1,200,235 time segments were used instead of 100,000; these data were unbalanced and training was performed with the newly introduced balancing strategy `auto` (see https://gitlab.pasteur.fr/nyx/larvatagger.jl/-/issues/92),
+* the training stage involved more data: 1,200,235 time segments were used instead of 100,000; these data were unbalanced and training was performed with class weighting as per the newly introduced balancing strategy `auto` (see https://gitlab.pasteur.fr/nyx/larvatagger.jl/-/issues/92),
 * pretraining and training data were drawn from t15 only (as opposed to previous taggers that were pretrained and trained with data from t15 and t5).
 
-Note the last difference was not meant to improve performance, at all. The `20230129` was trained this way to study its performance on t5, and was kept as is after it showed better performance on t5 data, compared to previous taggers trained with t5 data in addition to t15 data.
+Note the last difference was not meant to improve performance. The `20230129` was trained this way to study its performance on t5, and was kept as is after it showed better properties (less temporal leakage, fewer hunches and rolls except on stimulus onset) on t5 data.
 
 ## Usage
 
diff --git a/pyproject.toml b/pyproject.toml
index e9961fb106e3acaed7745c6a5611beafe090efcf..6277e00da4d8a931ec390674f533d2d06df5da62 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "MaggotUBA-adapter"
-version = "0.10"
+version = "0.11.0"
 description = "Interface between MaggotUBA and the Nyx tagging UI"
 authors = ["François Laurent"]
 license = "MIT"
diff --git a/src/maggotuba/models/modules.py b/src/maggotuba/models/modules.py
index 9d197a3885a6719b3003ce793b84e5d0e4fa4a2f..78ec42e4bf03ba2b5d7859f1b41b8f3a5d7d2ae5 100644
--- a/src/maggotuba/models/modules.py
+++ b/src/maggotuba/models/modules.py
@@ -313,7 +313,8 @@ class DeepLinear(nn.Module):
 
 class MaggotClassifier(MaggotModule):
     def __init__(self, path, behavior_labels=[], n_latent_features=None,
-            n_layers=1, cfgfile=None, ptfile="trained_classifier.pt"):
+            n_layers=1, n_iterations=None, cfgfile=None,
+            ptfile="trained_classifier.pt"):
         super().__init__(path, cfgfile, ptfile)
         try: # try load config file, if any
             self.config
@@ -329,6 +330,16 @@ class MaggotClassifier(MaggotModule):
                 weight_init="xavier",
                 loss="cross-entropy",
                 optimizer="adam")
+            if n_iterations is not None:
+                if isinstance(n_iterations, str):
+                    n_iterations = map(int, n_iterations.split(','))
+                if isinstance(n_iterations, int):
+                    n_pretraining_iter = n_iterations // 2
+                    n_finetuning_iter = n_iterations // 2
+                else:
+                    n_pretraining_iter, n_finetuning_iter = n_iterations
+                self.config['pretraining_iter'] = n_pretraining_iter
+                self.config['finetuning_iter'] = n_finetuning_iter
 
     @classmethod
     def load_model(cls, config, path):
@@ -365,13 +376,22 @@ class MaggotClassifier(MaggotModule):
     def n_layers(self):
         return self.config["clf_depth"] + 1
 
+    @property
+    def n_pretraining_iter(self):
+        return self.config.get('pretraining_iter', None)
+
+    @property
+    def n_finetuning_iter(self):
+        return self.config.get('finetuning_iter', None)
+
 class SupervisedMaggot(nn.Module):
-    def __init__(self, cfgfilepath, behaviors=[], n_layers=1):
+    def __init__(self, cfgfilepath, behaviors=[], n_layers=1, n_epochs=None):
         super().__init__()
         if behaviors: # the model is only pre-trained
             self.encoder = PretrainedMaggotEncoder(cfgfilepath)
             self.clf = MaggotClassifier(self.encoder.path / "clf_config.json",
-                    behaviors, self.encoder.config["dim_latent"], n_layers)
+                    behaviors, self.encoder.config["dim_latent"], n_layers,
+                    n_epochs)
         else: # the model has been retrained
             self.clf = MaggotClassifier(cfgfilepath)
             self.encoder = MaggotEncoder(self.clf.config["autoencoder_config"],
@@ -398,15 +418,35 @@ class SupervisedMaggot(nn.Module):
         self.encoder.to(device)
         self.clf.to(device)
 
+    @property
+    def n_pretraining_iter(self):
+        n = self.clf.n_pretraining_iter
+        if n is None:
+            enc = self.encoder
+            n = enc.config['optim_iter']
+            if enc.was_pretrained():
+                n = n // 2
+        return n
+
+    @property
+    def n_finetuning_iter(self):
+        n = self.clf.n_finetuning_iter
+        if n is None:
+            enc = self.encoder
+            n = enc.config['optim_iter']
+            if enc.was_pretrained():
+                n = n // 2
+        return n
+
 class MultiscaleSupervisedMaggot(nn.Module):
-    def __init__(self, cfgfilepath, behaviors=[], n_layers=1):
+    def __init__(self, cfgfilepath, behaviors=[], n_layers=1, n_iterations=None):
         super().__init__()
         if behaviors: # the model is only pre-trained
             self.encoders = MaggotEncoders(cfgfilepath, cls=PretrainedMaggotEncoder)
             path = next(iter(self.encoders)).path.parent
             n_latent_features = sum(enc.config["dim_latent"] for enc in self.encoders)
             self.clf = MaggotClassifier(path / "clf_config.json",
-                    behaviors, n_latent_features, n_layers)
+                    behaviors, n_latent_features, n_layers, n_iterations)
         else: # the model has been retrained
             self.clf = MaggotClassifier(cfgfilepath)
             self.encoders = MaggotEncoders(self.clf.config["autoencoder_config"],
@@ -426,6 +466,26 @@ class MultiscaleSupervisedMaggot(nn.Module):
         self.clf.model # force parameter loading or initialization
         return super().parameters(self)
 
+    @property
+    def n_pretraining_iter(self):
+        n = self.clf.n_pretraining_iter
+        if n is None:
+            any_enc = self.encoders[0]
+            n = any_enc.config['optim_iter']
+            if any_enc.was_pretrained():
+                n = n // 2
+        return n
+
+    @property
+    def n_finetuning_iter(self):
+        n = self.clf.n_finetuning_iter
+        if n is None:
+            any_enc = self.encoders[0]
+            n = any_enc.config['optim_iter']
+            if any_enc.was_pretrained():
+                n = n // 2
+        return n
+
 """
 Bagging for `SupervisedMaggot`.
 
@@ -436,9 +496,10 @@ Bags of taggers are stored so that the models directory only contains
 subdirectories, each subdirectory specifying an individual tagger.
 """
 class MaggotBag(nn.Module):
-    def __init__(self, paths, behaviors=[], n_layers=1, cls=SupervisedMaggot):
+    def __init__(self, paths, behaviors=[], n_layers=1, n_iterations=None,
+                 cls=SupervisedMaggot):
         super().__init__()
-        self.maggots = [cls(path, behaviors, n_layers) for path in paths]
+        self.maggots = [cls(path, behaviors, n_layers, n_iterations) for path in paths]
         self._lead_maggot = None
 
     def forward(self, x):
diff --git a/src/maggotuba/models/train_model.py b/src/maggotuba/models/train_model.py
index f9562c524a0de3cd72eed5a1817090286b346e9a..18d2fdf0b64efc8f3dc4f2cf69801da0978a990c 100644
--- a/src/maggotuba/models/train_model.py
+++ b/src/maggotuba/models/train_model.py
@@ -6,7 +6,7 @@ import json
 import glob
 
 def train_model(backend, layers=1, pretrained_model_instance="default",
-                subsets=(1, 0, 0), rng_seed=None, balancing_strategy='maggotuba', **kwargs):
+                subsets=(1, 0, 0), rng_seed=None, iterations=1000, **kwargs):
     # make_dataset generated or moved the larva_dataset file into data/interim/{instance}/
     #larva_dataset_file = backend.list_interim_files("larva_dataset_*.hdf5") # recursive
     larva_dataset_file = glob.glob(str(backend.interim_data_dir() / "larva_dataset_*.hdf5")) # not recursive (faster)
@@ -14,18 +14,17 @@ def train_model(backend, layers=1, pretrained_model_instance="default",
     # subsets=(1, 0, 0) => all data are training data; no validation or test subsets
     dataset = LarvaDataset(larva_dataset_file[0], new_generator(rng_seed),
                            subsets=subsets, **kwargs)
-    dataset.weight_classes = isinstance(balancing_strategy, str) and (balancing_strategy.lower() == 'auto')
     labels = dataset.labels
     assert 0 < len(labels)
     labels = labels if isinstance(labels[0], str) else [s.decode() for s in labels]
     # copy and load the pretrained model into the model instance directory
     if isinstance(pretrained_model_instance, str):
         config_file = import_pretrained_model(backend, pretrained_model_instance)
-        model = make_trainer(config_file, labels, layers)
+        model = make_trainer(config_file, labels, layers, iterations)
     else:
         pretrained_model_instances = pretrained_model_instance
         config_files = import_pretrained_models(backend, pretrained_model_instances)
-        model = make_trainer(config_files, labels, layers)
+        model = make_trainer(config_files, labels, layers, iterations)
     # fine-tune the model
     model.train(dataset)
     # add post-prediction rule ABC -> AAC
diff --git a/src/maggotuba/models/trainers.py b/src/maggotuba/models/trainers.py
index 6852e40dbc23d9b8d3ff2155333c6315f4928e12..06010e0d7100a87c8aa8947c97fa2e4e77b1438d 100644
--- a/src/maggotuba/models/trainers.py
+++ b/src/maggotuba/models/trainers.py
@@ -20,9 +20,9 @@ Training the model instead relies on the readily-preprocessed data of a
 *larva_dataset hdf5* file.
 """
 class MaggotTrainer:
-    def __init__(self, cfgfilepath, behaviors=[], n_layers=1,
+    def __init__(self, cfgfilepath, behaviors=[], n_layers=1, n_iterations=None,
             average_body_length=1.0, device=device):
-        self.model = SupervisedMaggot(cfgfilepath, behaviors, n_layers)
+        self.model = SupervisedMaggot(cfgfilepath, behaviors, n_layers, n_iterations)
         self.average_body_length = average_body_length # usually set later
         self.device = device
 
@@ -166,14 +166,12 @@ class MaggotTrainer:
         model.train() # this only sets the model in training mode (enables gradients)
         model.to(self.device)
         criterion = nn.CrossEntropyLoss(**kwargs)
-        nsteps = self.config['optim_iter']
         grad_clip = self.config['grad_clip']
         # pre-train the classifier with static encoder weights
         if model.encoder.was_pretrained():
-            nsteps = nsteps // 2
             optimizer = torch.optim.Adam(model.clf.parameters())
             print("pre-training the classifier...")
-            for step in range(nsteps):
+            for step in range(self.model.n_pretraining_iter):
                 optimizer.zero_grad()
                 # TODO: add an option for renormalizing the input
                 data, expected = self.draw(dataset)
@@ -186,7 +184,7 @@ class MaggotTrainer:
         optimizer = torch.optim.Adam(model.parameters())
         print(("fine-tuning" if model.encoder.was_pretrained() else "training") + \
                " the encoder and classifier...")
-        for step in range(nsteps):
+        for step in range(self.model.n_finetuning_iter):
             optimizer.zero_grad()
             data, expected = self.draw(dataset)
             predicted = self.forward(data, train=True)
@@ -246,20 +244,19 @@ def new_generator(seed=None):
 
 
 class MultiscaleMaggotTrainer(MaggotTrainer):
-    def __init__(self, cfgfilepath, behaviors=[], n_layers=1,
+    def __init__(self, cfgfilepath, behaviors=[], n_layers=1, n_iterations=None,
             average_body_length=1.0, device=device):
-        self.model = MultiscaleSupervisedMaggot(cfgfilepath, behaviors, n_layers)
+        self.model = MultiscaleSupervisedMaggot(cfgfilepath, behaviors,
+                                                n_layers, n_iterations)
         self.average_body_length = average_body_length # usually set later
         self.device = device
         self._default_encoder_config = None
         # check consistency
-        ref_config = self.config
-        for attr in ["batch_size", "optim_iter"]:
-            # TODO: add pretraining_iter and finetuning_iter parameters in
-            #       clf_config to have a lever other than optim_iter, that
-            #       could consequently be ignored
-            for enc in self.model.encoders:
-                assert enc.config[attr] == ref_config[attr]
+        if n_iterations is None:
+            ref_config = self.config
+            for attr in ["batch_size", "optim_iter"]:
+                for enc in self.model.encoders:
+                    assert enc.config[attr] == ref_config[attr]
 
     @property
     def config(self):