attacklm 0.6.3__tar.gz → 0.6.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.
Files changed (211) hide show
  1. {attacklm-0.6.3 → attacklm-0.6.4}/PKG-INFO +1 -1
  2. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/device_utils.py +57 -2
  3. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/train_template.py +126 -46
  4. attacklm-0.6.4/src/attacklm/__version__.py +1 -0
  5. attacklm-0.6.3/src/attacklm/__version__.py +0 -1
  6. {attacklm-0.6.3 → attacklm-0.6.4}/.github/workflows/release.yml +0 -0
  7. {attacklm-0.6.3 → attacklm-0.6.4}/.gitignore +0 -0
  8. {attacklm-0.6.3 → attacklm-0.6.4}/ATTRIBUTION.md +0 -0
  9. {attacklm-0.6.3 → attacklm-0.6.4}/CHANGELOG.md +0 -0
  10. {attacklm-0.6.3 → attacklm-0.6.4}/CONTRIBUTING.md +0 -0
  11. {attacklm-0.6.3 → attacklm-0.6.4}/EVALUATION.md +0 -0
  12. {attacklm-0.6.3 → attacklm-0.6.4}/LICENSE +0 -0
  13. {attacklm-0.6.3 → attacklm-0.6.4}/MANIFEST.in +0 -0
  14. {attacklm-0.6.3 → attacklm-0.6.4}/Makefile +0 -0
  15. {attacklm-0.6.3 → attacklm-0.6.4}/NOTICE +0 -0
  16. {attacklm-0.6.3 → attacklm-0.6.4}/QA_BEFORE_RELEASES.md +0 -0
  17. {attacklm-0.6.3 → attacklm-0.6.4}/README.md +0 -0
  18. {attacklm-0.6.3 → attacklm-0.6.4}/REPLAY_PLAN.md +0 -0
  19. {attacklm-0.6.3 → attacklm-0.6.4}/data/ATTRIBUTION.md +0 -0
  20. {attacklm-0.6.3 → attacklm-0.6.4}/data/LEGAL.md +0 -0
  21. {attacklm-0.6.3 → attacklm-0.6.4}/data/REMOVAL.md +0 -0
  22. {attacklm-0.6.3 → attacklm-0.6.4}/data/bench/questions.jsonl +0 -0
  23. {attacklm-0.6.3 → attacklm-0.6.4}/data/bench/speed_context.txt +0 -0
  24. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/ATTRIBUTION.md +0 -0
  25. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/GEMINI_RESEARCH_2026-06-11.md +0 -0
  26. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/acquisition_report.json +0 -0
  27. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/manifest.json +0 -0
  28. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/README.md +0 -0
  29. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/_index.json +0 -0
  30. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  31. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  32. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  33. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  34. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  35. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  36. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  37. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  38. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  39. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  40. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  41. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  42. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  43. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  44. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  45. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  46. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  47. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  48. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  49. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  50. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  51. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  52. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  53. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  54. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  55. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  56. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  57. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  58. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  59. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  60. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  61. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  62. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  63. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  64. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  65. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  66. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  67. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  68. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  69. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  70. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  71. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  72. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  73. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  74. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  75. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  76. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  77. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  78. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  79. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  80. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  81. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  82. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  83. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  84. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  85. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  86. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  87. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  88. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  89. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  90. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  91. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  92. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  93. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  94. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  95. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  96. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  97. {attacklm-0.6.3 → attacklm-0.6.4}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  98. {attacklm-0.6.3 → attacklm-0.6.4}/data/golden/prompts.jsonl +0 -0
  99. {attacklm-0.6.3 → attacklm-0.6.4}/data/reference/prompts.jsonl +0 -0
  100. {attacklm-0.6.3 → attacklm-0.6.4}/data/steering/prompts/opsec_aware.txt +0 -0
  101. {attacklm-0.6.3 → attacklm-0.6.4}/data/steering/prompts/opsec_unaware.txt +0 -0
  102. {attacklm-0.6.3 → attacklm-0.6.4}/data/steering/prompts/succinct.txt +0 -0
  103. {attacklm-0.6.3 → attacklm-0.6.4}/data/steering/prompts/verbose.txt +0 -0
  104. {attacklm-0.6.3 → attacklm-0.6.4}/experiments/README.md +0 -0
  105. {attacklm-0.6.3 → attacklm-0.6.4}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  106. {attacklm-0.6.3 → attacklm-0.6.4}/hf/.gitattributes +0 -0
  107. {attacklm-0.6.3 → attacklm-0.6.4}/hf/README.md +0 -0
  108. {attacklm-0.6.3 → attacklm-0.6.4}/hf/data/manifest.json +0 -0
  109. {attacklm-0.6.3 → attacklm-0.6.4}/hf/dataset_infos.json +0 -0
  110. {attacklm-0.6.3 → attacklm-0.6.4}/hf/scripts/build_hf_dataset.py +0 -0
  111. {attacklm-0.6.3 → attacklm-0.6.4}/hf/scripts/push_to_hf.py +0 -0
  112. {attacklm-0.6.3 → attacklm-0.6.4}/hpo_runs/.gitkeep +0 -0
  113. {attacklm-0.6.3 → attacklm-0.6.4}/hpo_runs/hpo_state.json +0 -0
  114. {attacklm-0.6.3 → attacklm-0.6.4}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  115. {attacklm-0.6.3 → attacklm-0.6.4}/logs/.gitkeep +0 -0
  116. {attacklm-0.6.3 → attacklm-0.6.4}/notes/BLUE_TEAM_DESIGN_v0.5.0.md +0 -0
  117. {attacklm-0.6.3 → attacklm-0.6.4}/notes/EVAL_DESIGN_v0.4.0.md +0 -0
  118. {attacklm-0.6.3 → attacklm-0.6.4}/notes/STEERING_REVIEW_v0.4.0.md +0 -0
  119. {attacklm-0.6.3 → attacklm-0.6.4}/pipeline.example.yaml +0 -0
  120. {attacklm-0.6.3 → attacklm-0.6.4}/presets/blue-team.json +0 -0
  121. {attacklm-0.6.3 → attacklm-0.6.4}/presets/purple-team.json +0 -0
  122. {attacklm-0.6.3 → attacklm-0.6.4}/presets/red-team.json +0 -0
  123. {attacklm-0.6.3 → attacklm-0.6.4}/pyproject.toml +0 -0
  124. {attacklm-0.6.3 → attacklm-0.6.4}/requirements.txt +0 -0
  125. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/_eval_loader.py +0 -0
  126. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_cloud_attack_dataset.py +0 -0
  127. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_ics_dataset.py +0 -0
  128. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_phishing_dataset.py +0 -0
  129. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_red_team_tactics.py +0 -0
  130. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_replay_general.py +0 -0
  131. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_supply_chain_dataset.py +0 -0
  132. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_web_attack_dataset.py +0 -0
  133. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/acquire_wireless_dataset.py +0 -0
  134. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/add_attribution.py +0 -0
  135. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/audit_dataset.py +0 -0
  136. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/augment_attribution.py +0 -0
  137. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/balance_buckets.py +0 -0
  138. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/bucket_loader.py +0 -0
  139. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/build.py +0 -0
  140. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/classify_unrouted_modules.py +0 -0
  141. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/clone_repos.sh +0 -0
  142. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/collect_reference.py +0 -0
  143. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/compare_scores.py +0 -0
  144. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/convert_to_gguf.py +0 -0
  145. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/dedupe_and_import_llm.py +0 -0
  146. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/demo.py +0 -0
  147. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/domain_bench.py +0 -0
  148. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/eval_retention.py +0 -0
  149. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  150. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  151. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_by_tactic.py +0 -0
  152. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  153. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_elastic_rules.py +0 -0
  154. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  155. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_mordor.py +0 -0
  156. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_nist_ir.py +0 -0
  157. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_rta_to_jsonl.py +0 -0
  158. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_sigma_defensive.py +0 -0
  159. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_splunk_content.py +0 -0
  160. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/extract_threathunter_playbook.py +0 -0
  161. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_dataset.py +0 -0
  162. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_dataset_deterministic.py +0 -0
  163. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_hybrid_dataset.py +0 -0
  164. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_metasploit_dataset.py +0 -0
  165. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_orchestrator.py +0 -0
  166. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_prompt_injection.py +0 -0
  167. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_source_layout.py +0 -0
  168. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/generate_synthetic_scarce.py +0 -0
  169. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/golden_vectors.py +0 -0
  170. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/hpo_runner.py +0 -0
  171. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/import_gguf.sh +0 -0
  172. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/import_to_lmstudio.sh +0 -0
  173. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/infer.py +0 -0
  174. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/init_pipeline.py +0 -0
  175. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/llm_generate_wrapper.py +0 -0
  176. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/merge_adapter.py +0 -0
  177. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/migrate_buckets_to_v021.py +0 -0
  178. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/migrate_v015_to_v020.py +0 -0
  179. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/mitre_tactic_lookup.py +0 -0
  180. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/parse_metasploit_to_jsonl.py +0 -0
  181. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/pipeline.py +0 -0
  182. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/rebuild_manifest.py +0 -0
  183. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/register_ollama.py +0 -0
  184. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/reorganize_buckets.py +0 -0
  185. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/replay_mixer.py +0 -0
  186. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/run_all_acquisitions.py +0 -0
  187. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/score_candidates.py +0 -0
  188. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/scrub_bpl_callback.py +0 -0
  189. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/setup_buckets.py +0 -0
  190. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/speed_bench.py +0 -0
  191. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/stamp_and_reorg.py +0 -0
  192. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/steering.py +0 -0
  193. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/train_all.py +0 -0
  194. {attacklm-0.6.3 → attacklm-0.6.4}/scripts/validate_per_category.py +0 -0
  195. {attacklm-0.6.3 → attacklm-0.6.4}/src/attacklm/__init__.py +0 -0
  196. {attacklm-0.6.3 → attacklm-0.6.4}/src/attacklm/_project_root.py +0 -0
  197. {attacklm-0.6.3 → attacklm-0.6.4}/src/attacklm/cli.py +0 -0
  198. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_balance_buckets.py +0 -0
  199. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_collect_reference.py +0 -0
  200. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_compare_scores.py +0 -0
  201. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_domain_bench.py +0 -0
  202. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_eval_loader.py +0 -0
  203. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_eval_retention.py +0 -0
  204. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_golden_vectors.py +0 -0
  205. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_init_pipeline.py +0 -0
  206. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_replay_mixer.py +0 -0
  207. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_score_candidates.py +0 -0
  208. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_speed_bench.py +0 -0
  209. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_steering.py +0 -0
  210. {attacklm-0.6.3 → attacklm-0.6.4}/tests/test_thinking_models.py +0 -0
  211. {attacklm-0.6.3 → attacklm-0.6.4}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attacklm
3
- Version: 0.6.3
3
+ Version: 0.6.4
4
4
  Summary: QLoRA-fine-tuned Qwen2.5-Coder for offensive/defensive security and AI red-teaming
5
5
  Project-URL: Homepage, https://github.com/Veedubin/AttackLM
6
6
  Project-URL: Repository, https://github.com/Veedubin/AttackLM
@@ -103,14 +103,16 @@ def setup_allocator_env() -> None:
103
103
  return
104
104
  os.environ.setdefault(
105
105
  "PYTORCH_CUDA_ALLOC_CONF",
106
- "expandable_segments:True,max_split_size_mb:128",
106
+ "expandable_segments:True,max_split_size_mb:512,"
107
+ "garbage_collection_threshold:0.8",
107
108
  )
108
109
  if is_rocm():
109
110
  # Older ROCm builds read PYTORCH_HIP_ALLOC_CONF instead.
110
111
  # Setting it is harmless on newer builds that ignore it.
111
112
  os.environ.setdefault(
112
113
  "PYTORCH_HIP_ALLOC_CONF",
113
- "expandable_segments:True,max_split_size_mb:128",
114
+ "expandable_segments:True,max_split_size_mb:512,"
115
+ "garbage_collection_threshold:0.8",
114
116
  )
115
117
 
116
118
 
@@ -149,6 +151,59 @@ def gpu_mem_info_bytes() -> Tuple[int, int]:
149
151
  return 0, 0
150
152
 
151
153
 
154
+ def gpu_mem_allocated_bytes() -> int:
155
+ """Bytes currently allocated to tensors (excludes cached pool).
156
+
157
+ This is the number that matters for OOM risk — it counts only
158
+ tensors that are actually in use, not blocks the caching allocator
159
+ is holding for reuse. Compare with gpu_mem_reserved_bytes() to
160
+ see how much is cached vs. active.
161
+ """
162
+ if is_cuda():
163
+ return torch.cuda.memory_allocated()
164
+ return 0
165
+
166
+
167
+ def gpu_mem_reserved_bytes() -> int:
168
+ """Bytes reserved from the CUDA driver (allocated + cached pool)."""
169
+ if is_cuda():
170
+ return torch.cuda.memory_reserved()
171
+ return 0
172
+
173
+
174
+ def gpu_mem_cached_bytes() -> int:
175
+ """Bytes in the allocator cache (reserved - allocated).
176
+
177
+ This is what empty_cache() can release back to the driver.
178
+ """
179
+ if is_cuda():
180
+ return torch.cuda.memory_reserved() - torch.cuda.memory_allocated()
181
+ return 0
182
+
183
+
184
+ def gpu_fragmentation_report() -> dict:
185
+ """Return detailed allocator stats for diagnosing fragmentation.
186
+
187
+ Key metrics:
188
+ inactive_split_bytes — memory that is free but can't be used
189
+ because it's split across segment boundaries (fragmentation).
190
+ num_alloc_retries — how many times the allocator had to flush
191
+ the cache and retry. >0 means fragmentation is hurting.
192
+ """
193
+ if not is_cuda():
194
+ return {}
195
+ stats = torch.cuda.memory_stats()
196
+ return {
197
+ "allocated_mb": stats.get("allocated_bytes.all.current", 0) / (1024**2),
198
+ "reserved_mb": stats.get("reserved_bytes.all.current", 0) / (1024**2),
199
+ "active_mb": stats.get("active_bytes.all.current", 0) / (1024**2),
200
+ "inactive_split_mb": stats.get("inactive_split_bytes.all.current", 0)
201
+ / (1024**2),
202
+ "num_alloc_retries": stats.get("num_alloc_retries", 0),
203
+ "num_ooms": stats.get("num_ooms", 0),
204
+ }
205
+
206
+
152
207
  # ---------------------------------------------------------------------------
153
208
  # Attention implementation picker
154
209
  # ---------------------------------------------------------------------------
@@ -67,6 +67,10 @@ from device_utils import ( # noqa: E402 (import after sys.path tweak)
67
67
  empty_cache_and_sync,
68
68
  gpu_mem_info,
69
69
  gpu_mem_info_bytes,
70
+ gpu_mem_allocated_bytes,
71
+ gpu_mem_reserved_bytes,
72
+ gpu_mem_cached_bytes,
73
+ gpu_fragmentation_report,
70
74
  suggest_attn_implementation,
71
75
  print_hardware_banner,
72
76
  )
@@ -1317,7 +1321,7 @@ def detect_assistant_loss_support(tokenizer, dataset_sample: dict) -> dict:
1317
1321
  return result
1318
1322
 
1319
1323
 
1320
- def _stochastic_round_projections(optimizer):
1324
+ def _stochastic_round_projections(optimizer, buffers=None):
1321
1325
  """Re-quantize projection matrices with stochastic rounding.
1322
1326
 
1323
1327
  Stochastic rounding preserves gradient information that would be
@@ -1327,6 +1331,10 @@ def _stochastic_round_projections(optimizer):
1327
1331
 
1328
1332
  This is called after every optimizer step to maintain INT4 precision
1329
1333
  while preventing quantization drift.
1334
+
1335
+ If ``buffers`` is provided (a dict of pre-allocated tensors), reuses
1336
+ those instead of allocating new temporaries. This eliminates ~168
1337
+ temporary allocations per step for a 24-layer model.
1330
1338
  """
1331
1339
  import torch
1332
1340
 
@@ -1338,16 +1346,30 @@ def _stochastic_round_projections(optimizer):
1338
1346
  continue
1339
1347
  scale = group["proj_scale"]
1340
1348
  with torch.no_grad():
1341
- # Dequantize current INT4 for the forward pass
1342
- proj.copy_(group["proj_int4"].to(proj.dtype) * scale)
1343
- # Stochastic rounding: re-quantize with probability-based rounding
1344
- fp = proj / scale
1345
- floor_val = fp.floor()
1346
- frac = fp - floor_val
1347
- # Random rounding: round up with probability = fractional part
1348
- rand = torch.rand_like(frac)
1349
- rounded = floor_val + (rand < frac).to(fp.dtype)
1350
- group["proj_int4"] = rounded.clamp(-7, 7).to(torch.int8)
1349
+ if buffers is not None:
1350
+ # --- Pre-allocated path: zero temporary allocations ---
1351
+ b = buffers
1352
+ b["dequant"].copy_(group["proj_int4"].to(proj.dtype) * scale)
1353
+ proj.copy_(b["dequant"])
1354
+ torch.div(proj, scale, out=b["fp"])
1355
+ torch.floor(b["fp"], out=b["floor"])
1356
+ torch.sub(b["fp"], b["floor"], out=b["frac"])
1357
+ b["rand"].uniform_() # in-place random, no allocation
1358
+ # lt returns bool; convert to float for addition
1359
+ torch.lt(b["rand"], b["frac"], out=b["rounded_bool"])
1360
+ b["rounded"].copy_(b["rounded_bool"].to(proj.dtype))
1361
+ b["rounded"].add_(b["floor"])
1362
+ b["rounded"].clamp_(-7, 7)
1363
+ group["proj_int4"] = b["rounded"].to(torch.int8)
1364
+ else:
1365
+ # --- Fallback: allocates temporaries (legacy path) ---
1366
+ proj.copy_(group["proj_int4"].to(proj.dtype) * scale)
1367
+ fp = proj / scale
1368
+ floor_val = fp.floor()
1369
+ frac = fp - floor_val
1370
+ rand = torch.rand_like(frac)
1371
+ rounded = floor_val + (rand < frac).to(fp.dtype)
1372
+ group["proj_int4"] = rounded.clamp(-7, 7).to(torch.int8)
1351
1373
 
1352
1374
 
1353
1375
  def main() -> None:
@@ -2913,22 +2935,30 @@ def main() -> None:
2913
2935
  return control
2914
2936
 
2915
2937
  class GCEpochCallback(TrainerCallback):
2916
- """Run gc.collect() + empty_cache() after every eval to defragment VRAM.
2938
+ """Aggressive VRAM management: periodic clears + emergency threshold.
2939
+
2940
+ PyTorch's CUDA caching allocator holds freed blocks in a pool for
2941
+ reuse. ``mem_get_info()`` (the driver-level query) counts those
2942
+ cached blocks as "used", so the old 256MB threshold fired on cache
2943
+ bloat, not genuine OOM risk.
2917
2944
 
2918
- Also monitors VRAM after every optimizer step and triggers an
2919
- emergency cache clear if free memory drops below 2GB — this
2920
- catches the case where peak transient allocations during a
2921
- forward pass push us close to the ceiling.
2945
+ This callback now uses ``memory_allocated()`` (tensors actually in
2946
+ use) for the emergency threshold, and clears the cache *periodically*
2947
+ (every 50 steps) to prevent the pool from growing large enough to
2948
+ trigger spurious emergencies.
2949
+
2950
+ Also monitors fragmentation (inactive_split_bytes) and allocation
2951
+ retries — if the allocator is struggling to find contiguous blocks,
2952
+ we log a warning.
2922
2953
  """
2923
2954
 
2924
- # OOM fix #10: VRAM threshold for emergency cache clear
2925
- # (in bytes). If free VRAM drops below this after an optimizer
2926
- # step, force a gc.collect + empty_cache. 256MB is the "we're
2927
- # about to OOM" threshold — below this, PyTorch can't allocate
2928
- # a single large tensor. GaLore's per-layer hooks free gradients
2929
- # after each layer's backward pass, so peak memory is much lower
2930
- # than QLoRA and we rarely need to clear.
2931
- EMERGENCY_CLEAR_THRESHOLD_BYTES = 256 * (1024**2)
2955
+ # Fraction of total VRAM that triggers an emergency clear.
2956
+ # 0.92 = 14.3GB on a 15.6GB card, leaving ~1.3GB for transients.
2957
+ EMERGENCY_ALLOCATED_FRACTION = 0.92
2958
+
2959
+ # Clear the cache every N optimizer steps to prevent pool bloat.
2960
+ # Cost: ~1-2ms per clear, negligible vs. step time (~350ms).
2961
+ PERIODIC_CLEAR_EVERY_N_STEPS = 50
2932
2962
 
2933
2963
  def on_evaluate(self, args, state, control, **kwargs):
2934
2964
  import gc
@@ -2937,36 +2967,53 @@ def main() -> None:
2937
2967
  if is_cuda():
2938
2968
  empty_cache_and_sync()
2939
2969
  free_gb, total_gb = gpu_mem_info()
2970
+ allocated_gb = gpu_mem_allocated_bytes() / (1024**3)
2971
+ cached_gb = gpu_mem_cached_bytes() / (1024**3)
2940
2972
  print(
2941
2973
  f"\r\n [GCEpochCallback] Post-eval VRAM: "
2942
- f"{free_gb:.2f}GB free / {total_gb:.2f}GB total"
2974
+ f"{free_gb:.2f}GB free / {total_gb:.2f}GB total "
2975
+ f"(alloc {allocated_gb:.1f}GB, cached {cached_gb:.1f}GB)"
2943
2976
  )
2944
2977
  return control
2945
2978
 
2946
2979
  def on_optimizer_step(self, args, state, control, **kwargs):
2947
- """Emergency VRAM clear when free memory gets dangerously low.
2980
+ """Periodic cache clear + emergency threshold check.
2948
2981
 
2949
- Fires after every optimizer step (per `on_optimizer_step`
2950
- callback event). We DO NOT unconditionally clear cache here
2951
- (that would cost 5-10% throughput). Instead, we only clear
2952
- if free VRAM is below the emergency threshold.
2982
+ Periodic clears prevent the cached pool from growing large
2983
+ enough to trigger the emergency threshold. The emergency
2984
+ check uses ``memory_allocated()`` (tensors in use), not
2985
+ ``mem_get_info()`` (which includes the cached pool).
2953
2986
  """
2954
2987
  if not is_cuda():
2955
2988
  return control
2956
- free_bytes, _total_bytes = gpu_mem_info_bytes()
2957
- if free_bytes < self.EMERGENCY_CLEAR_THRESHOLD_BYTES:
2989
+
2990
+ # --- Periodic clear: prevent cache bloat ---
2991
+ if state.global_step % self.PERIODIC_CLEAR_EVERY_N_STEPS == 0:
2958
2992
  import gc
2959
2993
 
2960
2994
  gc.collect()
2961
2995
  torch.cuda.empty_cache()
2962
- # Don't sync here — that defeats the purpose of the
2963
- # threshold check. The next forward pass will sync
2964
- # implicitly if it needs to.
2965
- free_gb = free_bytes / (1024**3)
2996
+
2997
+ # --- Emergency check: actual OOM risk ---
2998
+ allocated = gpu_mem_allocated_bytes()
2999
+ total = torch.cuda.get_device_properties(0).total_memory
3000
+ if allocated / total > self.EMERGENCY_ALLOCATED_FRACTION:
3001
+ import gc
3002
+
3003
+ gc.collect()
3004
+ torch.cuda.empty_cache()
3005
+ cached_mb = gpu_mem_cached_bytes() / (1024**2)
3006
+ frag = gpu_fragmentation_report()
2966
3007
  print(
2967
- f"\r\n [GCEpochCallback] Step {state.global_step} emergency "
2968
- f"cache clear: {free_gb:.2f}GB free"
3008
+ f"\r\n [GCEpochCallback] Step {state.global_step} "
3009
+ f"EMERGENCY: alloc {allocated / (1024**3):.1f}GB "
3010
+ f"(>{self.EMERGENCY_ALLOCATED_FRACTION:.0%} of "
3011
+ f"{total / (1024**3):.1f}GB), "
3012
+ f"cached {cached_mb:.0f}MB freed, "
3013
+ f"frag {frag.get('inactive_split_mb', 0):.0f}MB, "
3014
+ f"retries {frag.get('num_alloc_retries', 0)}"
2969
3015
  )
3016
+
2970
3017
  return control
2971
3018
 
2972
3019
  class LiveProgressCallback(TrainerCallback):
@@ -3054,14 +3101,20 @@ def main() -> None:
3054
3101
  except (TypeError, ValueError):
3055
3102
  loss_val = 0.0
3056
3103
 
3057
- # --- VRAM (used/total) ---
3104
+ # --- VRAM (allocated + cached / total) ---
3058
3105
  vram_str = ""
3059
3106
  if is_cuda():
3060
3107
  try:
3061
- free_b, total_b = gpu_mem_info_bytes()
3062
- used_gb = (total_b - free_b) / (1024**3)
3063
- total_gb = total_b / (1024**3)
3064
- vram_str = f"VRAM USED {used_gb:.1f}/{total_gb:.1f} GB"
3108
+ allocated_gb = gpu_mem_allocated_bytes() / (1024**3)
3109
+ cached_gb = gpu_mem_cached_bytes() / (1024**3)
3110
+ total_gb = torch.cuda.get_device_properties(0).total_memory / (
3111
+ 1024**3
3112
+ )
3113
+ vram_str = (
3114
+ f"VRAM alloc {allocated_gb:.1f} "
3115
+ f"cache {cached_gb:.1f} "
3116
+ f"/{total_gb:.1f} GB"
3117
+ )
3065
3118
  except Exception:
3066
3119
  pass
3067
3120
 
@@ -3451,9 +3504,33 @@ def main() -> None:
3451
3504
  # Q-GaLore: quantize projection matrices to INT4
3452
3505
  if _use_qgalore:
3453
3506
  self._quantize_projections()
3507
+ # Pre-allocate reusable buffers for stochastic
3508
+ # rounding. Without this, every optimizer step
3509
+ # creates 7 temporary tensors per layer (168
3510
+ # allocs/step for 24 layers), each of which
3511
+ # leaves a cached block in the allocator pool.
3512
+ self._sr_buffers: dict[str, dict] = {}
3513
+ for prefix, opt in self._galore_optimizers.items():
3514
+ for group in opt.param_groups:
3515
+ proj = group.get("projection_matrix")
3516
+ if proj is None or proj.numel() == 0:
3517
+ continue
3518
+ self._sr_buffers[prefix] = {
3519
+ "dequant": torch.empty_like(proj),
3520
+ "fp": torch.empty_like(proj),
3521
+ "floor": torch.empty_like(proj),
3522
+ "frac": torch.empty_like(proj),
3523
+ "rand": torch.empty_like(proj),
3524
+ "rounded_bool": torch.empty(
3525
+ proj.shape,
3526
+ dtype=torch.bool,
3527
+ device=proj.device,
3528
+ ),
3529
+ "rounded": torch.empty_like(proj),
3530
+ }
3454
3531
 
3455
3532
  # Register per-layer hooks
3456
- def _make_hook(opt):
3533
+ def _make_hook(opt, prefix=""):
3457
3534
  def hook(p):
3458
3535
  if p.grad is None:
3459
3536
  return
@@ -3461,14 +3538,17 @@ def main() -> None:
3461
3538
  opt.zero_grad()
3462
3539
  # Q-GaLore: stochastic rounding after step
3463
3540
  if _use_qgalore:
3464
- _stochastic_round_projections(opt)
3541
+ bufs = self._sr_buffers.get(prefix)
3542
+ _stochastic_round_projections(opt, bufs)
3465
3543
 
3466
3544
  return hook
3467
3545
 
3468
3546
  for prefix, opt in self._galore_optimizers.items():
3469
3547
  for group in opt.param_groups:
3470
3548
  for p in group["params"]:
3471
- p.register_post_accumulate_grad_hook(_make_hook(opt))
3549
+ p.register_post_accumulate_grad_hook(
3550
+ _make_hook(opt, prefix)
3551
+ )
3472
3552
 
3473
3553
  def _quantize_projections(self):
3474
3554
  """Quantize GaLore projection matrices to INT4.
@@ -0,0 +1 @@
1
+ __version__ = "0.6.4"
@@ -1 +0,0 @@
1
- __version__ = "0.6.3"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes