bergson 2.2.2__tar.gz → 2.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bergson-2.2.2 → bergson-2.2.4}/PKG-INFO +5 -5
- {bergson-2.2.2 → bergson-2.2.4}/README.md +4 -4
- {bergson-2.2.2 → bergson-2.2.4}/bergson/__init__.py +1 -1
- {bergson-2.2.2 → bergson-2.2.4}/bergson/build.py +10 -2
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/shampoo.py +8 -7
- {bergson-2.2.2 → bergson-2.2.4}/bergson/process_autocorrelation.py +41 -30
- bergson-2.2.4/bergson/utils/batch_size.py +260 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/worker_utils.py +4 -6
- {bergson-2.2.2 → bergson-2.2.4}/bergson.egg-info/PKG-INFO +5 -5
- {bergson-2.2.2 → bergson-2.2.4}/bergson.egg-info/SOURCES.txt +2 -0
- {bergson-2.2.2 → bergson-2.2.4}/pyproject.toml +4 -1
- bergson-2.2.4/tests/test_auto_batch_size.py +90 -0
- bergson-2.2.4/tests/test_process_autocorrelation.py +62 -0
- bergson-2.2.2/bergson/utils/batch_size.py +0 -309
- {bergson-2.2.2 → bergson-2.2.4}/LICENSE +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/__main__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/approx_unrolling/adam_preconditioner.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/approx_unrolling/approx_unrolling_math.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/approx_unrolling/pipeline.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/approx_unrolling/precompute_checkpoints.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/approx_unrolling/segment_aggregation.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/approx_unrolling/train_cfg_io.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/builder.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/cli/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/cli/commands.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/cli/trackstar.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/cli/trak.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collection.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collector/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collector/collector.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collector/dist_autocorrelation_gradient_collector.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collector/gradient_collectors.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collector/in_memory_collector.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/collector/projection_matrix.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/config/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/config/config.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/config/config_io.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/config/validation.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/data.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/diagnose.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/distributed.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/format.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/gradients.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/apply_hessian.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/astra.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/autocorrelation.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/eigenvectors.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/hessian_approximations.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/inversion.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/kfac.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/pipeline.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/preconditioner.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/sharded_computation.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/hessians/tkfac.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/huggingface.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/cli.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/config.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/data_stream.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/dtensor_patch.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/fsdp.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/grad_accum.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/metasmoothness.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/optim.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/rtl_tqdm.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/score_plot.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/shard_load.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/swap.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/magic/trainer.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/moe.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/process_grads.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/query/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/query/attributor.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/query/faiss_index.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/query/query_index.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/recall/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/recall/facts.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/recall/generate.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/recall/recall.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/score/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/score/candidates.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/score/output_influence.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/score/score.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/score/score_writer.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/score/scorer.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/__init__.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/csv_writer.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/gradcheck.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/load_from_optimizer.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/logger.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/logging.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/math.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/peft.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/step_state.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/trainer_export.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/utils/utils.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson/validate.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson.egg-info/dependency_links.txt +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson.egg-info/entry_points.txt +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson.egg-info/requires.txt +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/bergson.egg-info/top_level.txt +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/setup.cfg +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_adam_state_loading.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_advantages.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_approx_unrolling_checkpoint_parse.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_attention_head_normalizers.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_attribute_tokens.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_attributor.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_bank_loss_cache.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_banked_model_loading.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_batch_size_invariance.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_build.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_builder.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_candidates.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_ckpt_avg_query_grads.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_cli.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_compute_lambda.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_config_runner.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_contrast.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_data.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_ddp.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_diagnose.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_distributed_batch_budget.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_distributed_cap.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_distributed_failure.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_distributed_magic.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_epoch_shuffle.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_faiss_ann_cpu_load.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_force_math_sdp.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_format.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_global_kfac.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_global_projection.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_grad_clipping.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_gradcheck.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_gradients.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_hessian.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_launch_devices.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_log_fn.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_logit_scale.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_magic.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_metasmoothness.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_moe.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_multi_query_validate.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_multinode.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_muon.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_normalizer.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_outer_product_gradients.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_output_influence.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_padding.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_per_query_magic.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_per_token_lds.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_pretokenized.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_projection_inner_products.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_projection_matrix.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_projection_settings.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_query_batching_invariance.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_query_loss_padding.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_query_set_config.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_recall.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_reduce.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_save_mode_final.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_score.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_score_plot.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_score_writer_dist.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_shard_load.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_source_fisher_normalization.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_source_optimizer_variants.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_source_resume_polarity.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_source_trainer_integration.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_step_matrix.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_step_state.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_tokenize.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_trainer_callback.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_trak.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_truncation.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_validate_filter.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_validate_routing.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_validation_config.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_wandb_logging.py +0 -0
- {bergson-2.2.2 → bergson-2.2.4}/tests/test_weighted_ce.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bergson
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.4
|
|
4
4
|
Summary: Tracing the memory of neural nets with data attribution
|
|
5
5
|
License: MIT License
|
|
6
6
|
Keywords: interpretability,explainable-ai
|
|
@@ -91,16 +91,16 @@ Indicative performance of data attribution methods in the finetuning regime - se
|
|
|
91
91
|
| Method | QLD | LDS | Per-token QLD |
|
|
92
92
|
|:---|:---:|:---:|:---:|
|
|
93
93
|
| MAGIC | 0.100 [0.090, 0.112] | 0.931 [0.925, 0.936] | 1.375 [1.348, 1.403] |
|
|
94
|
-
|
|
|
94
|
+
| EKFAC + ASTRA | 0.074 [0.063, 0.087] | 0.643 [0.624, 0.660] | 1.082 [1.047, 1.116] |
|
|
95
95
|
| Eigenvalue-corrected Shampoo | 0.071 [0.060, 0.082] | 0.517 [0.491, 0.539] | 0.922 [0.887, 0.957] |
|
|
96
96
|
| SOURCE (Adam, EK-FAC) | 0.071 [0.060, 0.084] | 0.473 [0.446, 0.498] | 0.908 [0.877, 0.942] |
|
|
97
|
-
|
|
|
97
|
+
| EKFAC | 0.070 [0.058, 0.082] | 0.454 [0.426, 0.479] | 0.863 [0.833, 0.894] |
|
|
98
98
|
| BM25 | 0.062 [0.048, 0.076] | 0.220 [0.185, 0.252] | 0.677 [0.650, 0.704] |
|
|
99
|
+
| Activation similarity (activation covariance preconditioner) | 0.055 [0.043, 0.069] | 0.157 [0.120, 0.192] | 0.073 [0.056, 0.092] |
|
|
99
100
|
| Semantic search ([Qwen3 8B](https://huggingface.co/Qwen/Qwen3-Embedding-8B)) | 0.049 [0.038, 0.061] | 0.132 [0.093, 0.169] | 0.008 [0.006, 0.010] |
|
|
100
|
-
| TrackStar (no optimizer
|
|
101
|
+
| TrackStar (no optimizer) | 0.045 [0.036, 0.055] | 0.276 [0.252, 0.299] | 0.492 [0.467, 0.517] |
|
|
101
102
|
| TRAK (8-model ensemble) | 0.032 [0.024, 0.040] | 0.138 [0.111, 0.165] | 0.119 [0.112, 0.125] |
|
|
102
103
|
| Gradient cosine similarity | 0.021 [0.016, 0.027] | 0.156 [0.131, 0.181] | 0.217 [0.206, 0.229] |
|
|
103
|
-
| Activation similarity | 0.000 [-0.000, 0.001] | 0.110 [0.070, 0.149] | 0.028 [0.018, 0.039] |
|
|
104
104
|
|
|
105
105
|
Results with 95% confidence intervals for GPT-2 finetuned on 4 epochs of the WikiText corpus. Held-out loss dropped from 3.545 to 3.111 over training.
|
|
106
106
|
|
|
@@ -30,16 +30,16 @@ Indicative performance of data attribution methods in the finetuning regime - se
|
|
|
30
30
|
| Method | QLD | LDS | Per-token QLD |
|
|
31
31
|
|:---|:---:|:---:|:---:|
|
|
32
32
|
| MAGIC | 0.100 [0.090, 0.112] | 0.931 [0.925, 0.936] | 1.375 [1.348, 1.403] |
|
|
33
|
-
|
|
|
33
|
+
| EKFAC + ASTRA | 0.074 [0.063, 0.087] | 0.643 [0.624, 0.660] | 1.082 [1.047, 1.116] |
|
|
34
34
|
| Eigenvalue-corrected Shampoo | 0.071 [0.060, 0.082] | 0.517 [0.491, 0.539] | 0.922 [0.887, 0.957] |
|
|
35
35
|
| SOURCE (Adam, EK-FAC) | 0.071 [0.060, 0.084] | 0.473 [0.446, 0.498] | 0.908 [0.877, 0.942] |
|
|
36
|
-
|
|
|
36
|
+
| EKFAC | 0.070 [0.058, 0.082] | 0.454 [0.426, 0.479] | 0.863 [0.833, 0.894] |
|
|
37
37
|
| BM25 | 0.062 [0.048, 0.076] | 0.220 [0.185, 0.252] | 0.677 [0.650, 0.704] |
|
|
38
|
+
| Activation similarity (activation covariance preconditioner) | 0.055 [0.043, 0.069] | 0.157 [0.120, 0.192] | 0.073 [0.056, 0.092] |
|
|
38
39
|
| Semantic search ([Qwen3 8B](https://huggingface.co/Qwen/Qwen3-Embedding-8B)) | 0.049 [0.038, 0.061] | 0.132 [0.093, 0.169] | 0.008 [0.006, 0.010] |
|
|
39
|
-
| TrackStar (no optimizer
|
|
40
|
+
| TrackStar (no optimizer) | 0.045 [0.036, 0.055] | 0.276 [0.252, 0.299] | 0.492 [0.467, 0.517] |
|
|
40
41
|
| TRAK (8-model ensemble) | 0.032 [0.024, 0.040] | 0.138 [0.111, 0.165] | 0.119 [0.112, 0.125] |
|
|
41
42
|
| Gradient cosine similarity | 0.021 [0.016, 0.027] | 0.156 [0.131, 0.181] | 0.217 [0.206, 0.229] |
|
|
42
|
-
| Activation similarity | 0.000 [-0.000, 0.001] | 0.110 [0.070, 0.149] | 0.028 [0.018, 0.039] |
|
|
43
43
|
|
|
44
44
|
Results with 95% confidence intervals for GPT-2 finetuned on 4 epochs of the WikiText corpus. Held-out loss dropped from 3.545 to 3.111 over training.
|
|
45
45
|
|
|
@@ -84,12 +84,20 @@ def build_worker(
|
|
|
84
84
|
model, target_modules = setup_model_and_peft(index_cfg)
|
|
85
85
|
processor = create_processor(model, index_cfg, target_modules)
|
|
86
86
|
|
|
87
|
-
maybe_auto_batch_size(index_cfg, model, ds, processor, target_modules, rank)
|
|
88
|
-
|
|
89
87
|
attention_cfgs = {
|
|
90
88
|
module: index_cfg.attention for module in index_cfg.split_attention_modules
|
|
91
89
|
}
|
|
92
90
|
|
|
91
|
+
maybe_auto_batch_size(
|
|
92
|
+
index_cfg,
|
|
93
|
+
model,
|
|
94
|
+
ds,
|
|
95
|
+
processor,
|
|
96
|
+
target_modules,
|
|
97
|
+
attention_cfgs,
|
|
98
|
+
preprocess_cfg,
|
|
99
|
+
)
|
|
100
|
+
|
|
93
101
|
kwargs = {
|
|
94
102
|
"model": model,
|
|
95
103
|
"data": ds,
|
|
@@ -15,14 +15,15 @@ from bergson.utils.utils import assert_type
|
|
|
15
15
|
@dataclass(kw_only=True)
|
|
16
16
|
class ShampooCollector(HookCollectorBase):
|
|
17
17
|
"""
|
|
18
|
-
Collects activation and gradient covariances for
|
|
18
|
+
Collects activation and gradient covariances for Shampoo.
|
|
19
19
|
|
|
20
20
|
Computes:
|
|
21
|
-
A_shampoo = sum over batches of Grad @ Grad
|
|
22
|
-
S_shampoo = sum over batches of Grad
|
|
21
|
+
A_shampoo = sum over batches of (Grad.T @ Grad) / trace for activations
|
|
22
|
+
S_shampoo = sum over batches of (Grad @ Grad.T) for gradients
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
where Grad = G.T @ X is the batch gradient [O, I], X is input activations
|
|
25
|
+
[N*S, I], G is output gradients [N*S, O], and trace is the trace of the
|
|
26
|
+
summed activation factor.
|
|
26
27
|
"""
|
|
27
28
|
|
|
28
29
|
dtype: torch.dtype
|
|
@@ -42,7 +43,7 @@ class ShampooCollector(HookCollectorBase):
|
|
|
42
43
|
)
|
|
43
44
|
|
|
44
45
|
def forward_hook(self, module: nn.Module, a: Tensor) -> None:
|
|
45
|
-
"""
|
|
46
|
+
"""Store the input activations for the backward hook."""
|
|
46
47
|
|
|
47
48
|
mask = self.collection_mask(module)
|
|
48
49
|
assert mask is not None, "Collection mask not set for forward hook."
|
|
@@ -60,7 +61,7 @@ class ShampooCollector(HookCollectorBase):
|
|
|
60
61
|
module._inputs = a_bi
|
|
61
62
|
|
|
62
63
|
def backward_hook(self, module: nn.Module, g: Tensor) -> None:
|
|
63
|
-
"""
|
|
64
|
+
"""Accumulate gradient and activation covariances, A.T @ A and G.T @ G."""
|
|
64
65
|
name = assert_type(str, module._name)
|
|
65
66
|
S_shampoo_po = self.S_shampoo_dict[name]
|
|
66
67
|
A_shampoo_ki = self.A_shampoo_dict[name]
|
|
@@ -4,6 +4,14 @@ import torch.distributed as dist
|
|
|
4
4
|
from bergson.gradients import GradientProcessor
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
def _eigh(prec: torch.Tensor, device, dtype) -> tuple[torch.Tensor, torch.Tensor]:
|
|
8
|
+
eigvals, eigvecs = torch.linalg.eigh(prec.to(dtype=torch.float64, device=device))
|
|
9
|
+
return (
|
|
10
|
+
eigvals.to(dtype=dtype).contiguous().cpu(),
|
|
11
|
+
eigvecs.to(dtype=dtype).contiguous().cpu(),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
7
15
|
def process_autocorrelation_matrices(
|
|
8
16
|
processor: GradientProcessor,
|
|
9
17
|
hessians: dict[str, torch.Tensor],
|
|
@@ -20,9 +28,11 @@ def process_autocorrelation_matrices(
|
|
|
20
28
|
count when ``attribute_tokens`` produced per-token rows — so the
|
|
21
29
|
normalized matrix is the second moment over whichever unit the rows
|
|
22
30
|
represent.
|
|
23
|
-
"""
|
|
24
|
-
hessians_eigen = {}
|
|
25
31
|
|
|
32
|
+
A rank may hold a partial Gram over its own rows for every module, or the
|
|
33
|
+
full Gram for the modules it owns. Each module's Gram is summed onto one
|
|
34
|
+
of the ranks that hold it, which eigendecomposes the total.
|
|
35
|
+
"""
|
|
26
36
|
device = next(iter(hessians.values())).device
|
|
27
37
|
dtype = next(iter(hessians.values())).dtype
|
|
28
38
|
|
|
@@ -32,57 +42,58 @@ def process_autocorrelation_matrices(
|
|
|
32
42
|
for name, prec in hessians.items():
|
|
33
43
|
hessians[name] = (prec / num_rows).cpu()
|
|
34
44
|
|
|
35
|
-
if rank == 0:
|
|
36
|
-
print("Computing hessian eigen decompositions...")
|
|
37
|
-
|
|
38
|
-
for name in hessians.keys():
|
|
39
|
-
prec = hessians[name].to(dtype=torch.float64, device=device)
|
|
40
|
-
eigvals, eigvecs = torch.linalg.eigh(prec)
|
|
41
|
-
hessians_eigen[name] = (
|
|
42
|
-
eigvals.to(dtype=dtype).contiguous().cpu(),
|
|
43
|
-
eigvecs.to(dtype=dtype).contiguous().cpu(),
|
|
44
|
-
)
|
|
45
|
-
|
|
46
45
|
if not dist.is_initialized():
|
|
46
|
+
if rank == 0:
|
|
47
|
+
print("Computing hessian eigen decompositions...")
|
|
47
48
|
processor.hessians = hessians
|
|
48
|
-
processor.hessians_eigen =
|
|
49
|
+
processor.hessians_eigen = {
|
|
50
|
+
name: _eigh(prec, device, dtype) for name, prec in hessians.items()
|
|
51
|
+
}
|
|
49
52
|
return
|
|
50
53
|
|
|
51
54
|
if rank == 0:
|
|
52
|
-
print("
|
|
55
|
+
print("Reducing hessians and computing eigen decompositions...")
|
|
53
56
|
|
|
54
57
|
cpu_group: dist.ProcessGroup = dist.new_group(backend="gloo") # type: ignore[assignment]
|
|
55
|
-
|
|
56
|
-
for
|
|
58
|
+
world_size = dist.get_world_size()
|
|
59
|
+
held: list[list[str]] = [[] for _ in range(world_size)]
|
|
60
|
+
dist.all_gather_object(held, sorted(hessians), group=cpu_group)
|
|
61
|
+
|
|
62
|
+
totals, hessians_eigen = {}, {}
|
|
63
|
+
for i, (name, grad_size) in enumerate(grad_sizes.items()):
|
|
64
|
+
holders = [r for r in range(world_size) if name in held[r]] or [0]
|
|
65
|
+
owner = holders[i % len(holders)]
|
|
57
66
|
if name in hessians:
|
|
58
|
-
local_prec = hessians
|
|
59
|
-
del hessians[name]
|
|
67
|
+
local_prec = hessians.pop(name)
|
|
60
68
|
else:
|
|
61
69
|
local_prec = torch.zeros([grad_size, grad_size], dtype=dtype, device="cpu")
|
|
62
70
|
|
|
63
|
-
dist.reduce(local_prec, dst=
|
|
71
|
+
dist.reduce(local_prec, dst=owner, op=dist.ReduceOp.SUM, group=cpu_group)
|
|
64
72
|
|
|
65
|
-
if rank ==
|
|
66
|
-
|
|
73
|
+
if rank == owner:
|
|
74
|
+
totals[name] = local_prec
|
|
75
|
+
hessians_eigen[name] = _eigh(local_prec, device, dtype)
|
|
67
76
|
|
|
68
77
|
if rank == 0:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
print("Gathering eigen decompositions...")
|
|
78
|
+
print("Gathering hessians and eigen decompositions...")
|
|
72
79
|
|
|
73
80
|
for name, grad_size in grad_sizes.items():
|
|
74
81
|
prec_size = torch.Size([grad_size, grad_size])
|
|
75
|
-
|
|
82
|
+
prec = totals.pop(name, None)
|
|
83
|
+
if name in hessians_eigen:
|
|
84
|
+
eigval, eigvec = hessians_eigen[name]
|
|
85
|
+
else:
|
|
86
|
+
prec = torch.zeros(prec_size, dtype=dtype)
|
|
76
87
|
eigval = torch.zeros(prec_size[0], dtype=dtype)
|
|
77
88
|
eigvec = torch.zeros(prec_size, dtype=dtype)
|
|
78
|
-
else:
|
|
79
|
-
eigval, eigvec = hessians_eigen[name]
|
|
80
89
|
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
for t in (prec, eigval, eigvec):
|
|
91
|
+
dist.reduce(t, dst=0, op=dist.ReduceOp.SUM, group=cpu_group)
|
|
83
92
|
|
|
84
93
|
if rank == 0:
|
|
94
|
+
hessians[name] = prec
|
|
85
95
|
hessians_eigen[name] = (eigval, eigvec)
|
|
86
96
|
|
|
87
97
|
if rank == 0:
|
|
98
|
+
processor.hessians = hessians
|
|
88
99
|
processor.hessians_eigen = hessians_eigen
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import gc
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import torch
|
|
10
|
+
import torch.distributed as dist
|
|
11
|
+
from datasets import Dataset
|
|
12
|
+
from peft import PeftModel
|
|
13
|
+
from transformers import AutoTokenizer, PreTrainedModel
|
|
14
|
+
|
|
15
|
+
from bergson.collector.collector import fwd_bwd_factory
|
|
16
|
+
from bergson.collector.gradient_collectors import GradientCollector
|
|
17
|
+
from bergson.config.config import AttentionConfig, IndexConfig, PreprocessConfig
|
|
18
|
+
from bergson.data import _allocate_batches_world, pad_and_tensor
|
|
19
|
+
from bergson.gradients import GradientProcessor
|
|
20
|
+
from bergson.utils.worker_utils import max_tokens_for_model
|
|
21
|
+
|
|
22
|
+
CACHE_PATH = Path(".cache") / "batch_size_cache.jsonl"
|
|
23
|
+
|
|
24
|
+
PROBE_MEMORY_FRACTION = 0.9
|
|
25
|
+
"""Share of device memory the probe batches may use, leaving the rest for the
|
|
26
|
+
fragmentation a full run builds up."""
|
|
27
|
+
|
|
28
|
+
UNKEYED_FIELDS = {
|
|
29
|
+
"run_path",
|
|
30
|
+
"overwrite",
|
|
31
|
+
"token_batch_size",
|
|
32
|
+
"auto_batch_size",
|
|
33
|
+
"distributed",
|
|
34
|
+
"debug",
|
|
35
|
+
"profile",
|
|
36
|
+
}
|
|
37
|
+
"""IndexConfig fields that leave a run's memory unchanged."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def maybe_auto_batch_size(
|
|
41
|
+
cfg: IndexConfig,
|
|
42
|
+
model: PreTrainedModel | PeftModel,
|
|
43
|
+
ds: Dataset,
|
|
44
|
+
processor: GradientProcessor,
|
|
45
|
+
target_modules: set[str] | None,
|
|
46
|
+
attention_cfgs: dict[str, AttentionConfig],
|
|
47
|
+
preprocess_cfg: PreprocessConfig,
|
|
48
|
+
) -> None:
|
|
49
|
+
"""Set ``cfg.token_batch_size`` to the largest budget whose batches fit, if
|
|
50
|
+
``cfg.auto_batch_size``.
|
|
51
|
+
|
|
52
|
+
Every rank probes the same batches and the ranks agree on each result, so
|
|
53
|
+
sharded models and multi-node runs search together.
|
|
54
|
+
"""
|
|
55
|
+
if not cfg.auto_batch_size:
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
lengths = [int(n) for n in ds["length"][:]]
|
|
59
|
+
key = _cache_key(cfg, preprocess_cfg, lengths)
|
|
60
|
+
rank = dist.get_rank() if dist.is_initialized() else 0
|
|
61
|
+
|
|
62
|
+
found = [_check_cache(CACHE_PATH, key) if rank == 0 else None]
|
|
63
|
+
if dist.is_initialized():
|
|
64
|
+
dist.broadcast_object_list(found, src=0)
|
|
65
|
+
if found[0] is not None:
|
|
66
|
+
cfg.token_batch_size = found[0]
|
|
67
|
+
print(f"Loaded token_batch_size from cache: {found[0]}")
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
tokenizer = AutoTokenizer.from_pretrained(cfg.tokenizer or cfg.model)
|
|
71
|
+
max_len = max_tokens_for_model(tokenizer, cfg.model, cfg.revision)
|
|
72
|
+
collector = GradientCollector(
|
|
73
|
+
model=model.base_model, # type: ignore
|
|
74
|
+
cfg=cfg,
|
|
75
|
+
processor=processor,
|
|
76
|
+
target_modules=target_modules,
|
|
77
|
+
data=ds,
|
|
78
|
+
preprocess_cfg=preprocess_cfg,
|
|
79
|
+
attention_cfgs=attention_cfgs,
|
|
80
|
+
filter_modules=cfg.filter_modules,
|
|
81
|
+
)
|
|
82
|
+
try:
|
|
83
|
+
cfg.token_batch_size = determine_batch_size(
|
|
84
|
+
cfg, model, ds, collector, lengths, max_len
|
|
85
|
+
)
|
|
86
|
+
finally:
|
|
87
|
+
del collector
|
|
88
|
+
_clear_cache()
|
|
89
|
+
|
|
90
|
+
if rank == 0:
|
|
91
|
+
_append_to_cache(CACHE_PATH, key, cfg.token_batch_size)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def determine_batch_size(
|
|
95
|
+
cfg: IndexConfig,
|
|
96
|
+
model: PreTrainedModel | PeftModel,
|
|
97
|
+
ds: Dataset,
|
|
98
|
+
collector: GradientCollector,
|
|
99
|
+
lengths: list[int],
|
|
100
|
+
max_len: int,
|
|
101
|
+
) -> int:
|
|
102
|
+
"""Find the largest token budget whose batches fit, doubling from the
|
|
103
|
+
longest document and then bisecting."""
|
|
104
|
+
# Documents longer than the budget can't be batched, and a budget past
|
|
105
|
+
# the context length is rejected when the data is tokenized
|
|
106
|
+
lo = max(lengths)
|
|
107
|
+
limit = max(lo, min(max_len, sum(lengths)))
|
|
108
|
+
print(f"Determining token_batch_size in [{lo}, {limit}]...")
|
|
109
|
+
if not _fits(cfg, model, ds, collector, lengths, lo):
|
|
110
|
+
raise RuntimeError(
|
|
111
|
+
f"token_batch_size={lo}, the longest document, does not fit in memory."
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
hi = None
|
|
115
|
+
while lo < limit:
|
|
116
|
+
candidate = min(2 * lo, limit)
|
|
117
|
+
if not _fits(cfg, model, ds, collector, lengths, candidate):
|
|
118
|
+
hi = candidate
|
|
119
|
+
break
|
|
120
|
+
lo = candidate
|
|
121
|
+
|
|
122
|
+
# lo fits and hi, when set, does not
|
|
123
|
+
while hi is not None and hi - lo > max(256, lo // 16):
|
|
124
|
+
mid = (lo + hi) // 2
|
|
125
|
+
if _fits(cfg, model, ds, collector, lengths, mid):
|
|
126
|
+
lo = mid
|
|
127
|
+
else:
|
|
128
|
+
hi = mid
|
|
129
|
+
|
|
130
|
+
print(f"Optimal token_batch_size: {lo}")
|
|
131
|
+
return lo
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def probe_batches(
|
|
135
|
+
lengths: list[int], N: int, world_size: int, max_batch_size: int | None
|
|
136
|
+
) -> list[list[int]]:
|
|
137
|
+
"""The batches of budget ``N`` with the most padded tokens, the most
|
|
138
|
+
documents and the most attention entries, over every rank's batches."""
|
|
139
|
+
batches = [
|
|
140
|
+
b
|
|
141
|
+
for rank in _allocate_batches_world(
|
|
142
|
+
lengths, N, world_size, max_batch_size=max_batch_size
|
|
143
|
+
)
|
|
144
|
+
for b in rank
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
def shape(b):
|
|
148
|
+
return len(b), max(lengths[i] for i in b)
|
|
149
|
+
|
|
150
|
+
keys = (
|
|
151
|
+
lambda b: shape(b)[0] * shape(b)[1],
|
|
152
|
+
lambda b: shape(b)[0],
|
|
153
|
+
lambda b: shape(b)[0] * shape(b)[1] ** 2,
|
|
154
|
+
)
|
|
155
|
+
return [max(batches, key=key) for key in keys]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _fits(
|
|
159
|
+
cfg: IndexConfig,
|
|
160
|
+
model: PreTrainedModel | PeftModel,
|
|
161
|
+
ds: Dataset,
|
|
162
|
+
collector: GradientCollector,
|
|
163
|
+
lengths: list[int],
|
|
164
|
+
N: int,
|
|
165
|
+
) -> bool:
|
|
166
|
+
"""Whether every rank runs the probe batches of budget ``N`` in memory."""
|
|
167
|
+
world_size = dist.get_world_size() if dist.is_initialized() else 1
|
|
168
|
+
device = torch.device(model.device) # type: ignore[attr-defined]
|
|
169
|
+
fwd_bwd = fwd_bwd_factory(cfg)
|
|
170
|
+
|
|
171
|
+
print(f" Testing {N}...", end=" ", flush=True)
|
|
172
|
+
fits = True
|
|
173
|
+
_clear_cache()
|
|
174
|
+
if device.type == "cuda":
|
|
175
|
+
torch.cuda.set_per_process_memory_fraction(PROBE_MEMORY_FRACTION, device)
|
|
176
|
+
try:
|
|
177
|
+
for indices in probe_batches(lengths, N, world_size, cfg.max_batch_size):
|
|
178
|
+
batch = ds[indices]
|
|
179
|
+
x, y, _, collection_mask = pad_and_tensor(
|
|
180
|
+
batch["input_ids"],
|
|
181
|
+
labels=batch.get("labels"),
|
|
182
|
+
device=device,
|
|
183
|
+
sync_max_len=False,
|
|
184
|
+
)
|
|
185
|
+
with collector.with_batch(collection_mask):
|
|
186
|
+
losses = fwd_bwd(model, x, y, batch)
|
|
187
|
+
collector.process_batch(indices, losses=losses)
|
|
188
|
+
except torch.cuda.OutOfMemoryError:
|
|
189
|
+
fits = False
|
|
190
|
+
finally:
|
|
191
|
+
collector.mod_grads.clear()
|
|
192
|
+
model.zero_grad(set_to_none=True)
|
|
193
|
+
if device.type == "cuda":
|
|
194
|
+
torch.cuda.set_per_process_memory_fraction(1.0, device)
|
|
195
|
+
_clear_cache()
|
|
196
|
+
|
|
197
|
+
if dist.is_initialized():
|
|
198
|
+
flag = torch.tensor(int(fits), device=device)
|
|
199
|
+
dist.all_reduce(flag, op=dist.ReduceOp.MIN)
|
|
200
|
+
fits = bool(flag.item())
|
|
201
|
+
print("fits" if fits else "OOM")
|
|
202
|
+
return fits
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _clear_cache() -> None:
|
|
206
|
+
"""Aggressively clear memory."""
|
|
207
|
+
gc.collect()
|
|
208
|
+
if torch.cuda.is_available():
|
|
209
|
+
torch.cuda.empty_cache()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _cache_key(
|
|
213
|
+
cfg: IndexConfig, preprocess_cfg: PreprocessConfig, lengths: list[int]
|
|
214
|
+
) -> dict[str, Any]:
|
|
215
|
+
"""Everything a run's memory depends on: its configs, the document lengths,
|
|
216
|
+
the device and the number of ranks."""
|
|
217
|
+
index = {
|
|
218
|
+
k: v for k, v in dataclasses.asdict(cfg).items() if k not in UNKEYED_FIELDS
|
|
219
|
+
}
|
|
220
|
+
gpu_name, gpu_mem = "cpu", 0
|
|
221
|
+
if torch.cuda.is_available():
|
|
222
|
+
gpu_name = torch.cuda.get_device_name(0)
|
|
223
|
+
gpu_mem = torch.cuda.get_device_properties(0).total_memory
|
|
224
|
+
configs = json.dumps(
|
|
225
|
+
[index, dataclasses.asdict(preprocess_cfg)], sort_keys=True, default=str
|
|
226
|
+
)
|
|
227
|
+
return {
|
|
228
|
+
"configs": hashlib.sha256(configs.encode()).hexdigest(),
|
|
229
|
+
"lengths": hashlib.sha256(np.asarray(lengths, np.int64).tobytes()).hexdigest(),
|
|
230
|
+
"world_size": dist.get_world_size() if dist.is_initialized() else 1,
|
|
231
|
+
"gpu_name": gpu_name,
|
|
232
|
+
"gpu_memory": gpu_mem,
|
|
233
|
+
"torch": torch.__version__,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _check_cache(cache_file: Path, key: dict[str, Any]) -> int | None:
|
|
238
|
+
"""The batch size cached under ``key``, the latest if there are several."""
|
|
239
|
+
if not cache_file.exists():
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
found = None
|
|
243
|
+
with open(cache_file) as f:
|
|
244
|
+
for line in f:
|
|
245
|
+
try:
|
|
246
|
+
row = json.loads(line)
|
|
247
|
+
except json.JSONDecodeError:
|
|
248
|
+
continue
|
|
249
|
+
if row.get("key") == key:
|
|
250
|
+
found = row.get("token_batch_size")
|
|
251
|
+
return found
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _append_to_cache(cache_file: Path, key: dict[str, Any], batch_size: int) -> None:
|
|
255
|
+
"""Append a new row to the JSONL cache file."""
|
|
256
|
+
cache_file.parent.mkdir(parents=True, exist_ok=True)
|
|
257
|
+
with open(cache_file, "a") as f:
|
|
258
|
+
f.write(json.dumps({"key": key, "token_batch_size": batch_size}) + "\n")
|
|
259
|
+
|
|
260
|
+
print(f"Cached batch size {batch_size} to {cache_file}")
|
|
@@ -217,13 +217,11 @@ def setup_model_and_peft(
|
|
|
217
217
|
model_kwargs.update(simple_parse_kwargs_string(cfg.model_kwargs))
|
|
218
218
|
|
|
219
219
|
if meta_init:
|
|
220
|
-
config = AutoConfig.from_pretrained(
|
|
220
|
+
config = AutoConfig.from_pretrained(
|
|
221
|
+
base_model_path, revision=cfg.revision, **model_kwargs
|
|
222
|
+
)
|
|
221
223
|
with torch.device("meta"):
|
|
222
|
-
model = AutoModelForCausalLM.from_config(
|
|
223
|
-
config,
|
|
224
|
-
dtype=dtype,
|
|
225
|
-
**model_kwargs,
|
|
226
|
-
)
|
|
224
|
+
model = AutoModelForCausalLM.from_config(config, dtype=dtype)
|
|
227
225
|
else:
|
|
228
226
|
model = AutoModelForCausalLM.from_pretrained(
|
|
229
227
|
base_model_path,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bergson
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.4
|
|
4
4
|
Summary: Tracing the memory of neural nets with data attribution
|
|
5
5
|
License: MIT License
|
|
6
6
|
Keywords: interpretability,explainable-ai
|
|
@@ -91,16 +91,16 @@ Indicative performance of data attribution methods in the finetuning regime - se
|
|
|
91
91
|
| Method | QLD | LDS | Per-token QLD |
|
|
92
92
|
|:---|:---:|:---:|:---:|
|
|
93
93
|
| MAGIC | 0.100 [0.090, 0.112] | 0.931 [0.925, 0.936] | 1.375 [1.348, 1.403] |
|
|
94
|
-
|
|
|
94
|
+
| EKFAC + ASTRA | 0.074 [0.063, 0.087] | 0.643 [0.624, 0.660] | 1.082 [1.047, 1.116] |
|
|
95
95
|
| Eigenvalue-corrected Shampoo | 0.071 [0.060, 0.082] | 0.517 [0.491, 0.539] | 0.922 [0.887, 0.957] |
|
|
96
96
|
| SOURCE (Adam, EK-FAC) | 0.071 [0.060, 0.084] | 0.473 [0.446, 0.498] | 0.908 [0.877, 0.942] |
|
|
97
|
-
|
|
|
97
|
+
| EKFAC | 0.070 [0.058, 0.082] | 0.454 [0.426, 0.479] | 0.863 [0.833, 0.894] |
|
|
98
98
|
| BM25 | 0.062 [0.048, 0.076] | 0.220 [0.185, 0.252] | 0.677 [0.650, 0.704] |
|
|
99
|
+
| Activation similarity (activation covariance preconditioner) | 0.055 [0.043, 0.069] | 0.157 [0.120, 0.192] | 0.073 [0.056, 0.092] |
|
|
99
100
|
| Semantic search ([Qwen3 8B](https://huggingface.co/Qwen/Qwen3-Embedding-8B)) | 0.049 [0.038, 0.061] | 0.132 [0.093, 0.169] | 0.008 [0.006, 0.010] |
|
|
100
|
-
| TrackStar (no optimizer
|
|
101
|
+
| TrackStar (no optimizer) | 0.045 [0.036, 0.055] | 0.276 [0.252, 0.299] | 0.492 [0.467, 0.517] |
|
|
101
102
|
| TRAK (8-model ensemble) | 0.032 [0.024, 0.040] | 0.138 [0.111, 0.165] | 0.119 [0.112, 0.125] |
|
|
102
103
|
| Gradient cosine similarity | 0.021 [0.016, 0.027] | 0.156 [0.131, 0.181] | 0.217 [0.206, 0.229] |
|
|
103
|
-
| Activation similarity | 0.000 [-0.000, 0.001] | 0.110 [0.070, 0.149] | 0.028 [0.018, 0.039] |
|
|
104
104
|
|
|
105
105
|
Results with 95% confidence intervals for GPT-2 finetuned on 4 epochs of the WikiText corpus. Held-out loss dropped from 3.545 to 3.111 over training.
|
|
106
106
|
|
|
@@ -101,6 +101,7 @@ tests/test_approx_unrolling_checkpoint_parse.py
|
|
|
101
101
|
tests/test_attention_head_normalizers.py
|
|
102
102
|
tests/test_attribute_tokens.py
|
|
103
103
|
tests/test_attributor.py
|
|
104
|
+
tests/test_auto_batch_size.py
|
|
104
105
|
tests/test_bank_loss_cache.py
|
|
105
106
|
tests/test_banked_model_loading.py
|
|
106
107
|
tests/test_batch_size_invariance.py
|
|
@@ -145,6 +146,7 @@ tests/test_padding.py
|
|
|
145
146
|
tests/test_per_query_magic.py
|
|
146
147
|
tests/test_per_token_lds.py
|
|
147
148
|
tests/test_pretokenized.py
|
|
149
|
+
tests/test_process_autocorrelation.py
|
|
148
150
|
tests/test_projection_inner_products.py
|
|
149
151
|
tests/test_projection_matrix.py
|
|
150
152
|
tests/test_projection_settings.py
|
|
@@ -37,7 +37,7 @@ dependencies = [
|
|
|
37
37
|
"bitsandbytes",
|
|
38
38
|
"huggingface-hub>=1.13.0",
|
|
39
39
|
]
|
|
40
|
-
version = "2.2.
|
|
40
|
+
version = "2.2.4"
|
|
41
41
|
[project.optional-dependencies]
|
|
42
42
|
dev = [
|
|
43
43
|
"pre-commit",
|
|
@@ -93,6 +93,9 @@ reportPrivateImportUsage = false
|
|
|
93
93
|
[tool.setuptools.packages.find]
|
|
94
94
|
include = ["bergson*"]
|
|
95
95
|
|
|
96
|
+
[tool.uv.pip]
|
|
97
|
+
torch-backend = "auto"
|
|
98
|
+
|
|
96
99
|
[tool.black]
|
|
97
100
|
target-version = ["py310", "py311", "py312"]
|
|
98
101
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from dataclasses import replace
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import torch
|
|
7
|
+
|
|
8
|
+
from bergson.config import IndexConfig, PreprocessConfig
|
|
9
|
+
from bergson.data import _allocate_batches_world
|
|
10
|
+
from bergson.utils.batch_size import _cache_key, probe_batches
|
|
11
|
+
|
|
12
|
+
from .cli_command import bergson_cmd, bergson_env
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_probe_batches_cover_every_rank():
|
|
16
|
+
lengths = [512] * 4 + [8] * 300 + [100] * 40
|
|
17
|
+
world_size = 4
|
|
18
|
+
probes = probe_batches(lengths, 1024, world_size, None)
|
|
19
|
+
batches = [
|
|
20
|
+
b for rank in _allocate_batches_world(lengths, 1024, world_size) for b in rank
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
def docs(b):
|
|
24
|
+
return len(b)
|
|
25
|
+
|
|
26
|
+
def padded(b):
|
|
27
|
+
return len(b) * max(lengths[i] for i in b)
|
|
28
|
+
|
|
29
|
+
assert padded(probes[0]) == max(padded(b) for b in batches)
|
|
30
|
+
assert docs(probes[1]) == max(docs(b) for b in batches)
|
|
31
|
+
# The many-short-documents batch, which a probe of full-length rows misses
|
|
32
|
+
assert docs(probes[1]) == 1024 // 8
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_cache_key_tracks_memory():
|
|
36
|
+
cfg = IndexConfig(run_path="a", model="EleutherAI/pythia-14m")
|
|
37
|
+
pre = PreprocessConfig()
|
|
38
|
+
lengths = [10, 20, 30]
|
|
39
|
+
key = _cache_key(cfg, pre, lengths)
|
|
40
|
+
|
|
41
|
+
assert _cache_key(replace(cfg, run_path="b", overwrite=True), pre, lengths) == key
|
|
42
|
+
assert _cache_key(replace(cfg, token_batch_size=4096), pre, lengths) == key
|
|
43
|
+
for changed in (
|
|
44
|
+
replace(cfg, attribute_tokens=True),
|
|
45
|
+
replace(cfg, include_bias=True),
|
|
46
|
+
replace(cfg, filter_modules="*.mlp.*"),
|
|
47
|
+
replace(cfg, loss_fn="kl"),
|
|
48
|
+
replace(cfg, max_batch_size=4),
|
|
49
|
+
):
|
|
50
|
+
assert _cache_key(changed, pre, lengths) != key
|
|
51
|
+
assert _cache_key(cfg, replace(pre, aggregation="mean"), lengths) != key
|
|
52
|
+
assert _cache_key(cfg, pre, [10, 20, 31]) != key
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available")
|
|
56
|
+
@pytest.mark.parametrize("extra", [[], ["--attribute_tokens"]])
|
|
57
|
+
def test_auto_batch_size_build(tmp_path: Path, extra: list[str]):
|
|
58
|
+
def build(run: str):
|
|
59
|
+
return subprocess.run(
|
|
60
|
+
bergson_cmd(
|
|
61
|
+
"build",
|
|
62
|
+
run,
|
|
63
|
+
"--model",
|
|
64
|
+
"EleutherAI/pythia-14m",
|
|
65
|
+
"--dataset",
|
|
66
|
+
"NeelNanda/pile-10k",
|
|
67
|
+
"--split",
|
|
68
|
+
"train[:100]",
|
|
69
|
+
"--truncation",
|
|
70
|
+
"--projection_dim",
|
|
71
|
+
"16",
|
|
72
|
+
"--token_batch_size",
|
|
73
|
+
"512",
|
|
74
|
+
"--auto_batch_size",
|
|
75
|
+
*extra,
|
|
76
|
+
),
|
|
77
|
+
cwd=tmp_path,
|
|
78
|
+
env=bergson_env(),
|
|
79
|
+
capture_output=True,
|
|
80
|
+
text=True,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
first = build("first")
|
|
84
|
+
assert first.returncode == 0, first.stderr
|
|
85
|
+
assert "Optimal token_batch_size" in first.stdout
|
|
86
|
+
assert (tmp_path / "first" / "gradients.bin").exists()
|
|
87
|
+
|
|
88
|
+
second = build("second")
|
|
89
|
+
assert second.returncode == 0, second.stderr
|
|
90
|
+
assert "Loaded token_batch_size from cache" in second.stdout
|