Repository navigation
inference and validation performance fixes - #1077
maxwest-uw wants to merge 6 commits into
Conversation
DataProvider.resolve_data logged a duration for every item (including cache hits) and DataCache._do_insert logged one for every insert. Each is a SummaryWriter.add_scalar call, which made data loading the dominant cost of inference and validation (CIFAR-10 benchmark vs main: hyrax infer 2.67s -> 1.47s; validation over 3 epochs 3.76s -> 1.31s). The periodic cache count/size scalars (every 1000 inserts) are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
create_evaluator set eval mode but never disabled autograd, so every infer_batch built a graph and kept activations for a backward pass that never happens. Wrap the evaluator's run in torch.no_grad(), matching create_tester, create_validator and InferStreamSession. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Infer and Test read every item exactly once, so caching only cost time (insert + size accounting) and held the whole dataset in memory. Add DataCache.disable() and call it on the providers those verbs create. (CIFAR-10 benchmark vs main: hyrax infer 2.67s -> 2.27s.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_apply_configurations constructed a ConfigManager just to call the static merge_configs. Construction re-reads and re-parses the default TOML with tomlkit, reads any hyrax_config.toml in the cwd, and runs migrations, once per DataProvider with a dataset_config. (Benchmark: infer 2.67s -> 2.56s.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
validate_batch returned loss.item(), forcing a GPU->CPU sync on every batch, and only the last batch's value survived in validator.state.output, so the reported validation loss and best-checkpoint score were last-batch values. create_validator now accumulates each metric over the epoch and converts to float once. Built-in models with a standalone validate_batch return loss.detach(); models returning floats keep working. (Benchmark, nw=0: validation 3.76s -> 3.42s.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1077 +/- ##
==========================================
- Coverage 71.04% 70.98% -0.06%
==========================================
Files 92 92
Lines 9349 9362 +13
==========================================
+ Hits 6642 6646 +4
- Misses 2707 2716 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| # Note that `merge_configs` makes a copy of self.config, so the original | ||
| # config will not be modified. | ||
| return cm.merge_configs(base_config, tmp_config) | ||
| return ConfigManager.merge_configs(base_config, tmp_config) |
| if self._insert_count % self.logging_interval == 0 and self._insert_count != 0: | ||
| # Log cache growth periodically; logging on every insert is too slow for the data hot path. | ||
| if self._insert_count % self.logging_interval == 0: | ||
| prefix = self.__class__.__name__ |
There was a problem hiding this comment.
Reasonable and quick fix - I also wonder if it would be worth the effort to make a resource metric reporter that is disabled by default. Since model metrics and system metrics are logged via the same logger, it requires disentangling them, and might require instantiating multiple loggers in verb. Could be way more trouble than it's worth.
| if had_any_miss: | ||
| tensorboardx_logger.log_duration_ts(f"{prefix}/cache_miss_s", start_time) | ||
| else: | ||
| tensorboardx_logger.log_duration_ts(f"{prefix}/cache_hit_s", start_time) |
| decoded = self.forward(data) | ||
| loss = self.criterion(decoded, data) | ||
|
|
||
| return {"loss": loss.item()} |
There was a problem hiding this comment.
I'm unsure about this one. If it works and reduces run time - great.
I understand now, sorry about about the previous comment. This is a good find :)
| @validator.on(Events.ITERATION_COMPLETED) | ||
| def accumulate_metrics(validator): | ||
| for name, value in validator.state.output.items(): | ||
| value = value.detach() if isinstance(value, torch.Tensor) else value | ||
| metric_sums[name] = metric_sums.get(name, 0) + value | ||
| batch_count[0] += 1 |
There was a problem hiding this comment.
Do something similar for training and checkpointing?
There was a problem hiding this comment.
I tried this on the training engine and didn't see as much improvement, but there was improvement!
Change Description
Some performance boosts for validation and inference.
This is a subset of a longer list of problems that claude identified as issues (it also discovered a problem and fix that was on @drewoldag 's performance investigation branch already and applied that as well, listed as 0.)
Claude identified problems:
Solution Description
Code Quality