soup-cli 0.2.0__tar.gz → 0.2.2__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.
- {soup_cli-0.2.0 → soup_cli-0.2.2}/PKG-INFO +3 -3
- {soup_cli-0.2.0 → soup_cli-0.2.2}/README.md +2 -2
- soup_cli-0.2.2/TESTING_GUIDE.md +196 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/pyproject.toml +1 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/__init__.py +1 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/chat.py +2 -2
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/export.py +1 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/merge.py +2 -2
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/monitoring/callback.py +1 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/trainer/dpo.py +10 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/trainer/sft.py +10 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/utils/gpu.py +1 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_cli.py +2 -1
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_resume.py +2 -2
- {soup_cli-0.2.0 → soup_cli-0.2.2}/.claude/settings.json +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/.github/workflows/ci.yml +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/.github/workflows/publish.yml +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/.gitignore +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/CLAUDE.md +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/LICENSE +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup.png +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/__main__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/cli.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/data.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/eval.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/init.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/push.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/runs.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/commands/train.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/config/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/config/loader.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/config/schema.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/data/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/data/formats.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/data/loader.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/data/validator.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/experiment/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/experiment/tracker.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/monitoring/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/monitoring/display.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/trainer/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/utils/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/soup_cli/utils/constants.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/templates/chat.yaml +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/templates/code.yaml +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/templates/medical.yaml +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/__init__.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/conftest.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_callback.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_chat.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_config.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_data.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_data_tools.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_display.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_eval.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_export.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_formats.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_gpu.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_init.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_loader.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_merge.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_push.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_runs.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_smoke_train.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_tracker.py +0 -0
- {soup_cli-0.2.0 → soup_cli-0.2.2}/tests/test_validator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: soup-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Fine-tune LLMs in one command. No SSH, no config hell.
|
|
5
5
|
Project-URL: Homepage, https://github.com/MakazhanAlpamys/Soup
|
|
6
6
|
Project-URL: Repository, https://github.com/MakazhanAlpamys/Soup
|
|
@@ -67,7 +67,7 @@ Description-Content-Type: text/markdown
|
|
|
67
67
|
<a href="https://pypi.org/project/soup-cli/"><img src="https://img.shields.io/pypi/v/soup-cli?color=blue" alt="PyPI"></a>
|
|
68
68
|
<img src="https://img.shields.io/badge/python-3.9%2B-blue" alt="Python 3.9+">
|
|
69
69
|
<img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License">
|
|
70
|
-
<img src="https://img.shields.io/badge/tests-
|
|
70
|
+
<img src="https://img.shields.io/badge/tests-186%20passed-brightgreen" alt="Tests">
|
|
71
71
|
<a href="https://github.com/MakazhanAlpamys/Soup/actions"><img src="https://github.com/MakazhanAlpamys/Soup/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
72
72
|
</p>
|
|
73
73
|
|
|
@@ -418,7 +418,7 @@ pip install -e ".[dev]"
|
|
|
418
418
|
# Lint
|
|
419
419
|
ruff check soup_cli/ tests/
|
|
420
420
|
|
|
421
|
-
# Run unit tests (fast, no GPU needed —
|
|
421
|
+
# Run unit tests (fast, no GPU needed — 186 tests)
|
|
422
422
|
pytest tests/ -v
|
|
423
423
|
|
|
424
424
|
# Run smoke tests (downloads tiny model, runs real training)
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<a href="https://pypi.org/project/soup-cli/"><img src="https://img.shields.io/pypi/v/soup-cli?color=blue" alt="PyPI"></a>
|
|
22
22
|
<img src="https://img.shields.io/badge/python-3.9%2B-blue" alt="Python 3.9+">
|
|
23
23
|
<img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License">
|
|
24
|
-
<img src="https://img.shields.io/badge/tests-
|
|
24
|
+
<img src="https://img.shields.io/badge/tests-186%20passed-brightgreen" alt="Tests">
|
|
25
25
|
<a href="https://github.com/MakazhanAlpamys/Soup/actions"><img src="https://github.com/MakazhanAlpamys/Soup/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
26
26
|
</p>
|
|
27
27
|
|
|
@@ -372,7 +372,7 @@ pip install -e ".[dev]"
|
|
|
372
372
|
# Lint
|
|
373
373
|
ruff check soup_cli/ tests/
|
|
374
374
|
|
|
375
|
-
# Run unit tests (fast, no GPU needed —
|
|
375
|
+
# Run unit tests (fast, no GPU needed — 186 tests)
|
|
376
376
|
pytest tests/ -v
|
|
377
377
|
|
|
378
378
|
# Run smoke tests (downloads tiny model, runs real training)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Soup CLI — Quick Local Test Guide (Windows)
|
|
2
|
+
|
|
3
|
+
**Hardware:** RTX 3050 (4GB VRAM), i5
|
|
4
|
+
**Model:** `TinyLlama/TinyLlama-1.1B-Chat-v1.0` (~1.1B params, ~600MB in 4-bit)
|
|
5
|
+
**OS:** Windows (CMD/PowerShell)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 0. Install
|
|
10
|
+
|
|
11
|
+
```cmd
|
|
12
|
+
pip install soup-cli
|
|
13
|
+
pip install datasketch
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
> Unit tests (`pytest tests/`) only work from the repo clone (`pip install -e ".[dev]"`), not from pip install.
|
|
17
|
+
|
|
18
|
+
## 1. Version & Help
|
|
19
|
+
|
|
20
|
+
```cmd
|
|
21
|
+
soup version
|
|
22
|
+
soup --help
|
|
23
|
+
soup train --help
|
|
24
|
+
soup data --help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 2. Init Config from Templates
|
|
28
|
+
|
|
29
|
+
```cmd
|
|
30
|
+
soup init -t chat -o test_chat.yaml
|
|
31
|
+
soup init -t code -o test_code.yaml
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
> `soup init` without `-t` opens interactive wizard (requires terminal input).
|
|
35
|
+
|
|
36
|
+
## 3. Create Test Dataset
|
|
37
|
+
|
|
38
|
+
Create file `test_data.jsonl` with this content (copy-paste into any text editor, save as `test_data.jsonl`):
|
|
39
|
+
|
|
40
|
+
```jsonl
|
|
41
|
+
{"instruction": "What is Python?", "input": "", "output": "Python is a high-level programming language known for its simplicity."}
|
|
42
|
+
{"instruction": "Explain recursion", "input": "", "output": "Recursion is when a function calls itself to solve smaller subproblems."}
|
|
43
|
+
{"instruction": "What is a list?", "input": "", "output": "A list is an ordered, mutable collection of elements in Python."}
|
|
44
|
+
{"instruction": "What is a dictionary?", "input": "", "output": "A dictionary is a key-value data structure in Python."}
|
|
45
|
+
{"instruction": "What is OOP?", "input": "", "output": "OOP is a programming paradigm based on objects and classes."}
|
|
46
|
+
{"instruction": "What is an API?", "input": "", "output": "An API is an interface that allows software systems to communicate."}
|
|
47
|
+
{"instruction": "What is Git?", "input": "", "output": "Git is a distributed version control system for tracking code changes."}
|
|
48
|
+
{"instruction": "What is Docker?", "input": "", "output": "Docker is a platform for containerizing applications."}
|
|
49
|
+
{"instruction": "What is SQL?", "input": "", "output": "SQL is a language for managing and querying relational databases."}
|
|
50
|
+
{"instruction": "What is REST?", "input": "", "output": "REST is an architectural style for designing networked APIs using HTTP methods."}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or create it with Python one-liner:
|
|
54
|
+
|
|
55
|
+
```cmd
|
|
56
|
+
python -c "import json; data=[{'instruction':q,'input':'','output':a} for q,a in [('What is Python?','A high-level programming language.'),('Explain recursion','A function calling itself.'),('What is a list?','An ordered mutable collection.'),('What is OOP?','Programming with objects and classes.'),('What is Git?','A version control system.'),('What is Docker?','A containerization platform.'),('What is SQL?','A database query language.'),('What is REST?','An API architectural style.'),('What is an API?','An interface for software communication.'),('What is CSS?','A stylesheet language for web pages.')]]; f=open('test_data.jsonl','w'); [f.write(json.dumps(d)+'\n') for d in data]; f.close(); print('Created test_data.jsonl')"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 4. Data Tools
|
|
60
|
+
|
|
61
|
+
```cmd
|
|
62
|
+
soup data inspect test_data.jsonl
|
|
63
|
+
|
|
64
|
+
soup data validate test_data.jsonl --format alpaca
|
|
65
|
+
|
|
66
|
+
soup data stats test_data.jsonl
|
|
67
|
+
|
|
68
|
+
soup data convert test_data.jsonl --to sharegpt -o test_sharegpt.jsonl
|
|
69
|
+
|
|
70
|
+
soup data convert test_data.jsonl --to chatml -o test_chatml.jsonl
|
|
71
|
+
|
|
72
|
+
soup data inspect test_sharegpt.jsonl
|
|
73
|
+
|
|
74
|
+
soup data inspect test_chatml.jsonl
|
|
75
|
+
|
|
76
|
+
soup data merge test_data.jsonl test_sharegpt.jsonl -o test_merged.jsonl --shuffle
|
|
77
|
+
|
|
78
|
+
soup data dedup test_merged.jsonl -o test_deduped.jsonl --threshold 0.8
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 5. Create Config for Training
|
|
82
|
+
|
|
83
|
+
Create file `test_soup.yaml` (copy-paste into text editor):
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
base: TinyLlama/TinyLlama-1.1B-Chat-v1.0
|
|
87
|
+
|
|
88
|
+
data:
|
|
89
|
+
train: test_data.jsonl
|
|
90
|
+
format: alpaca
|
|
91
|
+
max_length: 256
|
|
92
|
+
|
|
93
|
+
training:
|
|
94
|
+
epochs: 2
|
|
95
|
+
lr: 2e-4
|
|
96
|
+
batch_size: 2
|
|
97
|
+
quantization: 4bit
|
|
98
|
+
logging_steps: 1
|
|
99
|
+
save_steps: 50
|
|
100
|
+
lora:
|
|
101
|
+
r: 8
|
|
102
|
+
alpha: 16
|
|
103
|
+
dropout: 0.05
|
|
104
|
+
|
|
105
|
+
output: ./test_output
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 6. Dry Run (validate without training)
|
|
109
|
+
|
|
110
|
+
```cmd
|
|
111
|
+
soup train -c test_soup.yaml --dry-run
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 7. Train
|
|
115
|
+
|
|
116
|
+
```cmd
|
|
117
|
+
soup train -c test_soup.yaml --name "local-test"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Training should take ~1-3 minutes on 3050 with this tiny dataset.
|
|
121
|
+
|
|
122
|
+
## 8. Experiment Tracking
|
|
123
|
+
|
|
124
|
+
```cmd
|
|
125
|
+
soup runs
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Copy the Run ID from the output, then:
|
|
129
|
+
|
|
130
|
+
```cmd
|
|
131
|
+
soup runs show RUN_ID_HERE
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Example: `soup runs show run_20260304_004948_983f284d`
|
|
135
|
+
|
|
136
|
+
## 9. Chat with Fine-Tuned Model
|
|
137
|
+
|
|
138
|
+
```cmd
|
|
139
|
+
soup chat -m ./test_output
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Type questions, then type `exit` to quit.
|
|
143
|
+
|
|
144
|
+
## 10. Merge LoRA
|
|
145
|
+
|
|
146
|
+
```cmd
|
|
147
|
+
soup merge -a ./test_output -o ./test_merged_model
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 11. Export to GGUF (optional, needs llama.cpp + cmake)
|
|
151
|
+
|
|
152
|
+
```cmd
|
|
153
|
+
soup export -m ./test_merged_model -q q4_k_m -o test_model.gguf
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 12. Eval (optional, slow)
|
|
157
|
+
|
|
158
|
+
```cmd
|
|
159
|
+
pip install lm-eval
|
|
160
|
+
soup eval -m ./test_output --benchmarks hellaswag --batch-size 4
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Cleanup (Windows)
|
|
166
|
+
|
|
167
|
+
```cmd
|
|
168
|
+
rmdir /s /q test_output test_merged_model
|
|
169
|
+
del test_data.jsonl test_sharegpt.jsonl test_chatml.jsonl test_merged.jsonl test_deduped.jsonl
|
|
170
|
+
del test_soup.yaml test_chat.yaml test_code.yaml test_model.gguf
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Or in PowerShell:
|
|
174
|
+
|
|
175
|
+
```powershell
|
|
176
|
+
Remove-Item -Recurse -Force test_output, test_merged_model -ErrorAction SilentlyContinue
|
|
177
|
+
Remove-Item test_data.jsonl, test_sharegpt.jsonl, test_chatml.jsonl, test_merged.jsonl, test_deduped.jsonl, test_soup.yaml, test_chat.yaml, test_code.yaml, test_model.gguf -ErrorAction SilentlyContinue
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Expected Results
|
|
181
|
+
|
|
182
|
+
| Step | Expected |
|
|
183
|
+
|------|----------|
|
|
184
|
+
| Version | `soup v0.2.1` |
|
|
185
|
+
| Init templates | Creates yaml files |
|
|
186
|
+
| Data inspect | Table with stats + sample rows |
|
|
187
|
+
| Data validate | "20/20 rows valid" |
|
|
188
|
+
| Data stats | Length distribution + histogram |
|
|
189
|
+
| Data convert | Creates sharegpt/chatml jsonl files |
|
|
190
|
+
| Data merge | Merges into single file |
|
|
191
|
+
| Data dedup | Removes near-duplicates |
|
|
192
|
+
| Dry run | "Config valid" or similar |
|
|
193
|
+
| Train | Loss decreasing, ~1-3 min |
|
|
194
|
+
| Runs | Shows run with metrics |
|
|
195
|
+
| Chat | Model responds (quality low with 10 samples — that's OK) |
|
|
196
|
+
| Merge | Creates full model in test_merged_model/ |
|
|
@@ -179,7 +179,7 @@ def _load_model(
|
|
|
179
179
|
base_model,
|
|
180
180
|
trust_remote_code=True,
|
|
181
181
|
device_map="auto",
|
|
182
|
-
|
|
182
|
+
dtype=torch.float16,
|
|
183
183
|
)
|
|
184
184
|
console.print(f"[dim]Loading LoRA adapter: {model_path}...[/]")
|
|
185
185
|
model_obj = PeftModel.from_pretrained(base, model_path)
|
|
@@ -189,7 +189,7 @@ def _load_model(
|
|
|
189
189
|
model_path,
|
|
190
190
|
trust_remote_code=True,
|
|
191
191
|
device_map="auto",
|
|
192
|
-
|
|
192
|
+
dtype=torch.float16,
|
|
193
193
|
)
|
|
194
194
|
|
|
195
195
|
model_obj.eval()
|
|
@@ -194,7 +194,7 @@ def _merge_adapter(adapter_path: str, base_model: str, output_dir: str):
|
|
|
194
194
|
console.print(f"[dim]Loading base model: {base_model}...[/]")
|
|
195
195
|
model = AutoModelForCausalLM.from_pretrained(
|
|
196
196
|
base_model,
|
|
197
|
-
|
|
197
|
+
dtype=torch.float16,
|
|
198
198
|
trust_remote_code=True,
|
|
199
199
|
device_map="cpu",
|
|
200
200
|
)
|
|
@@ -91,12 +91,12 @@ def merge(
|
|
|
91
91
|
"bfloat16": torch.bfloat16,
|
|
92
92
|
"float32": torch.float32,
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
model_dtype = dtype_map[dtype]
|
|
95
95
|
|
|
96
96
|
console.print(f"[dim]Loading base model: {base}...[/]")
|
|
97
97
|
model = AutoModelForCausalLM.from_pretrained(
|
|
98
98
|
base,
|
|
99
|
-
|
|
99
|
+
dtype=model_dtype,
|
|
100
100
|
trust_remote_code=True,
|
|
101
101
|
device_map="cpu",
|
|
102
102
|
)
|
|
@@ -47,7 +47,7 @@ class SoupTrainerCallback(TrainerCallback):
|
|
|
47
47
|
|
|
48
48
|
if torch.cuda.is_available():
|
|
49
49
|
used = torch.cuda.memory_allocated() / (1024**3)
|
|
50
|
-
total = torch.cuda.get_device_properties(0).
|
|
50
|
+
total = torch.cuda.get_device_properties(0).total_memory / (1024**3)
|
|
51
51
|
gpu_mem = f"{used:.1f}/{total:.1f} GB"
|
|
52
52
|
except Exception:
|
|
53
53
|
pass
|
|
@@ -127,6 +127,15 @@ class DPOTrainerWrapper:
|
|
|
127
127
|
output_dir = output_dir / cfg.experiment_name
|
|
128
128
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
129
129
|
|
|
130
|
+
# --- Calculate warmup steps from ratio ---
|
|
131
|
+
import math
|
|
132
|
+
|
|
133
|
+
total_steps = (
|
|
134
|
+
math.ceil(len(train_ds) / batch_size / tcfg.gradient_accumulation_steps)
|
|
135
|
+
* tcfg.epochs
|
|
136
|
+
)
|
|
137
|
+
warmup_steps = int(total_steps * tcfg.warmup_ratio)
|
|
138
|
+
|
|
130
139
|
# --- DPO config ---
|
|
131
140
|
dpo_config = DPOConfig(
|
|
132
141
|
output_dir=str(output_dir),
|
|
@@ -134,7 +143,7 @@ class DPOTrainerWrapper:
|
|
|
134
143
|
per_device_train_batch_size=batch_size,
|
|
135
144
|
gradient_accumulation_steps=tcfg.gradient_accumulation_steps,
|
|
136
145
|
learning_rate=tcfg.lr,
|
|
137
|
-
|
|
146
|
+
warmup_steps=warmup_steps,
|
|
138
147
|
weight_decay=tcfg.weight_decay,
|
|
139
148
|
max_grad_norm=tcfg.max_grad_norm,
|
|
140
149
|
optim=tcfg.optimizer,
|
|
@@ -137,6 +137,15 @@ class SFTTrainerWrapper:
|
|
|
137
137
|
output_dir = output_dir / cfg.experiment_name
|
|
138
138
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
139
139
|
|
|
140
|
+
# --- Calculate warmup steps from ratio ---
|
|
141
|
+
import math
|
|
142
|
+
|
|
143
|
+
total_steps = (
|
|
144
|
+
math.ceil(len(train_ds) / batch_size / tcfg.gradient_accumulation_steps)
|
|
145
|
+
* tcfg.epochs
|
|
146
|
+
)
|
|
147
|
+
warmup_steps = int(total_steps * tcfg.warmup_ratio)
|
|
148
|
+
|
|
140
149
|
# --- Training args ---
|
|
141
150
|
training_args = TrainingArguments(
|
|
142
151
|
output_dir=str(output_dir),
|
|
@@ -144,7 +153,7 @@ class SFTTrainerWrapper:
|
|
|
144
153
|
per_device_train_batch_size=batch_size,
|
|
145
154
|
gradient_accumulation_steps=tcfg.gradient_accumulation_steps,
|
|
146
155
|
learning_rate=tcfg.lr,
|
|
147
|
-
|
|
156
|
+
warmup_steps=warmup_steps,
|
|
148
157
|
weight_decay=tcfg.weight_decay,
|
|
149
158
|
max_grad_norm=tcfg.max_grad_norm,
|
|
150
159
|
optim=tcfg.optimizer,
|
|
@@ -25,7 +25,7 @@ def get_gpu_info() -> dict:
|
|
|
25
25
|
import torch
|
|
26
26
|
|
|
27
27
|
if torch.cuda.is_available():
|
|
28
|
-
total = torch.cuda.get_device_properties(0).
|
|
28
|
+
total = torch.cuda.get_device_properties(0).total_memory
|
|
29
29
|
total_gb = total / (1024**3)
|
|
30
30
|
return {
|
|
31
31
|
"memory_total": f"{total_gb:.1f} GB",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from typer.testing import CliRunner
|
|
4
4
|
|
|
5
|
+
from soup_cli import __version__
|
|
5
6
|
from soup_cli.cli import app
|
|
6
7
|
|
|
7
8
|
runner = CliRunner()
|
|
@@ -10,7 +11,7 @@ runner = CliRunner()
|
|
|
10
11
|
def test_version():
|
|
11
12
|
result = runner.invoke(app, ["version"])
|
|
12
13
|
assert result.exit_code == 0
|
|
13
|
-
assert
|
|
14
|
+
assert __version__ in result.output
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def test_help():
|
|
@@ -83,13 +83,13 @@ def test_resolve_checkpoint_auto_ignores_non_checkpoint_dirs(tmp_path: Path):
|
|
|
83
83
|
def test_train_resume_flag_in_help():
|
|
84
84
|
result = runner.invoke(app, ["train", "--help"])
|
|
85
85
|
assert result.exit_code == 0
|
|
86
|
-
assert "
|
|
86
|
+
assert "resume" in result.output.lower()
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
def test_train_wandb_flag_in_help():
|
|
90
90
|
result = runner.invoke(app, ["train", "--help"])
|
|
91
91
|
assert result.exit_code == 0
|
|
92
|
-
assert "
|
|
92
|
+
assert "wandb" in result.output.lower()
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
def test_train_resume_nonexistent_checkpoint(tmp_path: Path):
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|