lora-easy 1.0__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.
lora_easy-1.0/PKG-INFO ADDED
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: lora-easy
3
+ Version: 1.0
4
+ Summary: A tiny OOP wrapper around PEFT for LoRA fine-tuning of causal LMs.
5
+ Author: Freakwill
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Freakwill/lora-easy
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: torch>=2.0
11
+ Requires-Dist: peft>=0.19
12
+ Requires-Dist: transformers>=4.45
13
+
14
+ # lora-easy
15
+
16
+ <p align="center">
17
+ <img src="assets/banner.svg" alt="lora-easy — LoRA fine-tuning" width="700">
18
+ </p>
19
+
20
+ <p align="center">
21
+ <img src="https://img.shields.io/badge/python-3.9%2B-blue" alt="python">
22
+ <img src="https://img.shields.io/badge/peft-0.19%2B-orange" alt="peft">
23
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="license">
24
+ </p>
25
+
26
+ A tiny, object-oriented wrapper around 🤗 **PEFT** for LoRA fine-tuning of causal
27
+ language models. One `LoraModel` class hides the `from_pretrained` boilerplate and
28
+ gives you `enable_lora` / `train` / `chat` / `save` in a few readable lines.
29
+
30
+ It is meant for **learning and small experiments** — a single file you can read
31
+ top to bottom — not a production training framework.
32
+
33
+ ## Key concepts
34
+
35
+ - **LoRA (Low-Rank Adaptation)** — instead of updating all of a model's weights,
36
+ LoRA freezes the base model and trains two small low-rank matrices (`A` and `B`)
37
+ injected into the attention layers. Typically **~0.1% of the parameters** are
38
+ trainable, so a checkpoint is a few MB instead of GB.
39
+ - **Base vs. adapter** — the large pretrained weights never change. The tiny
40
+ adapter carries the "new personality" you trained. `LoraModel` keeps both:
41
+ `self.base` (frozen) and `self.peft_model` (base + adapter). `enable_lora()` /
42
+ `disable_lora()` just switch which one `self.model` points at, so toggling never
43
+ loses your trained weights.
44
+ - **Chat template** — training and inference must format text the same way.
45
+ Training data is rendered with `add_generation_prompt=False` (the assistant reply
46
+ is already in the text); inference uses `add_generation_prompt=True` so the model
47
+ knows to start generating.
48
+ - **Label masking** — `labels` mirror `input_ids`, but padding positions are set to
49
+ `-100` so they are ignored in the loss.
50
+
51
+ ## Requirements
52
+
53
+ ```
54
+ torch>=2.0
55
+ peft>=0.19
56
+ transformers>=4.45
57
+ ```
58
+
59
+ Install:
60
+
61
+ ```bash
62
+ pip install -r requirements.txt
63
+ ```
64
+
65
+ Runs on CUDA, Apple Silicon (MPS), or CPU. The default device in `LoraModel` is
66
+ `"mps"` — change the `device=` argument for CUDA (`"cuda"`) or CPU (`"cpu"`).
67
+
68
+ ## Usage
69
+
70
+ ```python
71
+ import json
72
+ from lora_ez import LoraModel
73
+
74
+ # ShareGPT-format data: [{"messages": [{"role": "user", ...}, {"role": "assistant", ...}]}, ...]
75
+ data = json.loads(open("cat_chat.json").read())
76
+
77
+ m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct") # load base model + tokenizer
78
+
79
+ print(m.chat("过来让我抱一下。")) # before fine-tuning
80
+
81
+ m.enable_lora(r=8, alpha=16) # attach LoRA adapter
82
+ m.train(data, epochs=30) # fine-tune
83
+ m.save("./lora-cat") # save adapter (~2 MB)
84
+
85
+ print(m.chat("过来让我抱一下。")) # after fine-tuning
86
+ ```
87
+
88
+ Reload a saved adapter later:
89
+
90
+ ```python
91
+ m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct")
92
+ m.load("./lora-cat")
93
+ print(m.chat("过来让我抱一下。"))
94
+ ```
95
+
96
+ ### API
97
+
98
+ | Method | What it does |
99
+ |--------|--------------|
100
+ | `LoraModel(model_id, device="mps")` | Load base model + tokenizer |
101
+ | `enable_lora(r, alpha, dropout)` | Attach a LoRA adapter (reuses existing if present) |
102
+ | `disable_lora()` | Point back to the frozen base model |
103
+ | `train(conversations, epochs, lr)` | Fine-tune on ShareGPT-format data |
104
+ | `chat(prompt, max_tokens)` | Generate a reply through the chat template |
105
+ | `save(path)` / `load(path)` | Persist / restore the adapter |
106
+
107
+ ## Demo
108
+
109
+ The [`demo/`](demo/) folder trains `Qwen2.5-0.5B-Instruct` to talk like a sassy
110
+ house cat, using 15 short conversations ([`cat_chat.json`](demo/cat_chat.json)).
111
+
112
+ ```bash
113
+ cd demo
114
+ python3 lora-demo.py
115
+ ```
116
+
117
+ Sample result ([full log](demo/output.txt)):
118
+
119
+ ```
120
+ === BEFORE fine-tuning ===
121
+ input: 你觉得今天的晚饭吃什么好?
122
+ output: 很抱歉,我不能提供关于饮食的建议或推荐。作为人工智能助手……
123
+
124
+ === AFTER fine-tuning ===
125
+ input: 你觉得今天的晚饭吃什么好?
126
+ output: 你是在戏说我吧,今晚的晚饭是干粮。
127
+ ```
128
+
129
+ The trained adapter is saved under [`demo/lora-cat/`](demo/lora-cat/).
130
+
131
+ ## Links
132
+
133
+ - [🤗 PEFT documentation](https://huggingface.co/docs/peft)
134
+ - [LoRA paper (Hu et al., 2021)](https://arxiv.org/abs/2106.09685)
135
+ - [Qwen2.5 models](https://huggingface.co/Qwen)
136
+ - [Transformers Trainer](https://huggingface.co/docs/transformers/main_classes/trainer)
137
+
138
+ ## License
139
+
140
+ MIT
@@ -0,0 +1,127 @@
1
+ # lora-easy
2
+
3
+ <p align="center">
4
+ <img src="assets/banner.svg" alt="lora-easy — LoRA fine-tuning" width="700">
5
+ </p>
6
+
7
+ <p align="center">
8
+ <img src="https://img.shields.io/badge/python-3.9%2B-blue" alt="python">
9
+ <img src="https://img.shields.io/badge/peft-0.19%2B-orange" alt="peft">
10
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="license">
11
+ </p>
12
+
13
+ A tiny, object-oriented wrapper around 🤗 **PEFT** for LoRA fine-tuning of causal
14
+ language models. One `LoraModel` class hides the `from_pretrained` boilerplate and
15
+ gives you `enable_lora` / `train` / `chat` / `save` in a few readable lines.
16
+
17
+ It is meant for **learning and small experiments** — a single file you can read
18
+ top to bottom — not a production training framework.
19
+
20
+ ## Key concepts
21
+
22
+ - **LoRA (Low-Rank Adaptation)** — instead of updating all of a model's weights,
23
+ LoRA freezes the base model and trains two small low-rank matrices (`A` and `B`)
24
+ injected into the attention layers. Typically **~0.1% of the parameters** are
25
+ trainable, so a checkpoint is a few MB instead of GB.
26
+ - **Base vs. adapter** — the large pretrained weights never change. The tiny
27
+ adapter carries the "new personality" you trained. `LoraModel` keeps both:
28
+ `self.base` (frozen) and `self.peft_model` (base + adapter). `enable_lora()` /
29
+ `disable_lora()` just switch which one `self.model` points at, so toggling never
30
+ loses your trained weights.
31
+ - **Chat template** — training and inference must format text the same way.
32
+ Training data is rendered with `add_generation_prompt=False` (the assistant reply
33
+ is already in the text); inference uses `add_generation_prompt=True` so the model
34
+ knows to start generating.
35
+ - **Label masking** — `labels` mirror `input_ids`, but padding positions are set to
36
+ `-100` so they are ignored in the loss.
37
+
38
+ ## Requirements
39
+
40
+ ```
41
+ torch>=2.0
42
+ peft>=0.19
43
+ transformers>=4.45
44
+ ```
45
+
46
+ Install:
47
+
48
+ ```bash
49
+ pip install -r requirements.txt
50
+ ```
51
+
52
+ Runs on CUDA, Apple Silicon (MPS), or CPU. The default device in `LoraModel` is
53
+ `"mps"` — change the `device=` argument for CUDA (`"cuda"`) or CPU (`"cpu"`).
54
+
55
+ ## Usage
56
+
57
+ ```python
58
+ import json
59
+ from lora_ez import LoraModel
60
+
61
+ # ShareGPT-format data: [{"messages": [{"role": "user", ...}, {"role": "assistant", ...}]}, ...]
62
+ data = json.loads(open("cat_chat.json").read())
63
+
64
+ m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct") # load base model + tokenizer
65
+
66
+ print(m.chat("过来让我抱一下。")) # before fine-tuning
67
+
68
+ m.enable_lora(r=8, alpha=16) # attach LoRA adapter
69
+ m.train(data, epochs=30) # fine-tune
70
+ m.save("./lora-cat") # save adapter (~2 MB)
71
+
72
+ print(m.chat("过来让我抱一下。")) # after fine-tuning
73
+ ```
74
+
75
+ Reload a saved adapter later:
76
+
77
+ ```python
78
+ m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct")
79
+ m.load("./lora-cat")
80
+ print(m.chat("过来让我抱一下。"))
81
+ ```
82
+
83
+ ### API
84
+
85
+ | Method | What it does |
86
+ |--------|--------------|
87
+ | `LoraModel(model_id, device="mps")` | Load base model + tokenizer |
88
+ | `enable_lora(r, alpha, dropout)` | Attach a LoRA adapter (reuses existing if present) |
89
+ | `disable_lora()` | Point back to the frozen base model |
90
+ | `train(conversations, epochs, lr)` | Fine-tune on ShareGPT-format data |
91
+ | `chat(prompt, max_tokens)` | Generate a reply through the chat template |
92
+ | `save(path)` / `load(path)` | Persist / restore the adapter |
93
+
94
+ ## Demo
95
+
96
+ The [`demo/`](demo/) folder trains `Qwen2.5-0.5B-Instruct` to talk like a sassy
97
+ house cat, using 15 short conversations ([`cat_chat.json`](demo/cat_chat.json)).
98
+
99
+ ```bash
100
+ cd demo
101
+ python3 lora-demo.py
102
+ ```
103
+
104
+ Sample result ([full log](demo/output.txt)):
105
+
106
+ ```
107
+ === BEFORE fine-tuning ===
108
+ input: 你觉得今天的晚饭吃什么好?
109
+ output: 很抱歉,我不能提供关于饮食的建议或推荐。作为人工智能助手……
110
+
111
+ === AFTER fine-tuning ===
112
+ input: 你觉得今天的晚饭吃什么好?
113
+ output: 你是在戏说我吧,今晚的晚饭是干粮。
114
+ ```
115
+
116
+ The trained adapter is saved under [`demo/lora-cat/`](demo/lora-cat/).
117
+
118
+ ## Links
119
+
120
+ - [🤗 PEFT documentation](https://huggingface.co/docs/peft)
121
+ - [LoRA paper (Hu et al., 2021)](https://arxiv.org/abs/2106.09685)
122
+ - [Qwen2.5 models](https://huggingface.co/Qwen)
123
+ - [Transformers Trainer](https://huggingface.co/docs/transformers/main_classes/trainer)
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: lora-easy
3
+ Version: 1.0
4
+ Summary: A tiny OOP wrapper around PEFT for LoRA fine-tuning of causal LMs.
5
+ Author: Freakwill
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Freakwill/lora-easy
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: torch>=2.0
11
+ Requires-Dist: peft>=0.19
12
+ Requires-Dist: transformers>=4.45
13
+
14
+ # lora-easy
15
+
16
+ <p align="center">
17
+ <img src="assets/banner.svg" alt="lora-easy — LoRA fine-tuning" width="700">
18
+ </p>
19
+
20
+ <p align="center">
21
+ <img src="https://img.shields.io/badge/python-3.9%2B-blue" alt="python">
22
+ <img src="https://img.shields.io/badge/peft-0.19%2B-orange" alt="peft">
23
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="license">
24
+ </p>
25
+
26
+ A tiny, object-oriented wrapper around 🤗 **PEFT** for LoRA fine-tuning of causal
27
+ language models. One `LoraModel` class hides the `from_pretrained` boilerplate and
28
+ gives you `enable_lora` / `train` / `chat` / `save` in a few readable lines.
29
+
30
+ It is meant for **learning and small experiments** — a single file you can read
31
+ top to bottom — not a production training framework.
32
+
33
+ ## Key concepts
34
+
35
+ - **LoRA (Low-Rank Adaptation)** — instead of updating all of a model's weights,
36
+ LoRA freezes the base model and trains two small low-rank matrices (`A` and `B`)
37
+ injected into the attention layers. Typically **~0.1% of the parameters** are
38
+ trainable, so a checkpoint is a few MB instead of GB.
39
+ - **Base vs. adapter** — the large pretrained weights never change. The tiny
40
+ adapter carries the "new personality" you trained. `LoraModel` keeps both:
41
+ `self.base` (frozen) and `self.peft_model` (base + adapter). `enable_lora()` /
42
+ `disable_lora()` just switch which one `self.model` points at, so toggling never
43
+ loses your trained weights.
44
+ - **Chat template** — training and inference must format text the same way.
45
+ Training data is rendered with `add_generation_prompt=False` (the assistant reply
46
+ is already in the text); inference uses `add_generation_prompt=True` so the model
47
+ knows to start generating.
48
+ - **Label masking** — `labels` mirror `input_ids`, but padding positions are set to
49
+ `-100` so they are ignored in the loss.
50
+
51
+ ## Requirements
52
+
53
+ ```
54
+ torch>=2.0
55
+ peft>=0.19
56
+ transformers>=4.45
57
+ ```
58
+
59
+ Install:
60
+
61
+ ```bash
62
+ pip install -r requirements.txt
63
+ ```
64
+
65
+ Runs on CUDA, Apple Silicon (MPS), or CPU. The default device in `LoraModel` is
66
+ `"mps"` — change the `device=` argument for CUDA (`"cuda"`) or CPU (`"cpu"`).
67
+
68
+ ## Usage
69
+
70
+ ```python
71
+ import json
72
+ from lora_ez import LoraModel
73
+
74
+ # ShareGPT-format data: [{"messages": [{"role": "user", ...}, {"role": "assistant", ...}]}, ...]
75
+ data = json.loads(open("cat_chat.json").read())
76
+
77
+ m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct") # load base model + tokenizer
78
+
79
+ print(m.chat("过来让我抱一下。")) # before fine-tuning
80
+
81
+ m.enable_lora(r=8, alpha=16) # attach LoRA adapter
82
+ m.train(data, epochs=30) # fine-tune
83
+ m.save("./lora-cat") # save adapter (~2 MB)
84
+
85
+ print(m.chat("过来让我抱一下。")) # after fine-tuning
86
+ ```
87
+
88
+ Reload a saved adapter later:
89
+
90
+ ```python
91
+ m = LoraModel("Qwen/Qwen2.5-0.5B-Instruct")
92
+ m.load("./lora-cat")
93
+ print(m.chat("过来让我抱一下。"))
94
+ ```
95
+
96
+ ### API
97
+
98
+ | Method | What it does |
99
+ |--------|--------------|
100
+ | `LoraModel(model_id, device="mps")` | Load base model + tokenizer |
101
+ | `enable_lora(r, alpha, dropout)` | Attach a LoRA adapter (reuses existing if present) |
102
+ | `disable_lora()` | Point back to the frozen base model |
103
+ | `train(conversations, epochs, lr)` | Fine-tune on ShareGPT-format data |
104
+ | `chat(prompt, max_tokens)` | Generate a reply through the chat template |
105
+ | `save(path)` / `load(path)` | Persist / restore the adapter |
106
+
107
+ ## Demo
108
+
109
+ The [`demo/`](demo/) folder trains `Qwen2.5-0.5B-Instruct` to talk like a sassy
110
+ house cat, using 15 short conversations ([`cat_chat.json`](demo/cat_chat.json)).
111
+
112
+ ```bash
113
+ cd demo
114
+ python3 lora-demo.py
115
+ ```
116
+
117
+ Sample result ([full log](demo/output.txt)):
118
+
119
+ ```
120
+ === BEFORE fine-tuning ===
121
+ input: 你觉得今天的晚饭吃什么好?
122
+ output: 很抱歉,我不能提供关于饮食的建议或推荐。作为人工智能助手……
123
+
124
+ === AFTER fine-tuning ===
125
+ input: 你觉得今天的晚饭吃什么好?
126
+ output: 你是在戏说我吧,今晚的晚饭是干粮。
127
+ ```
128
+
129
+ The trained adapter is saved under [`demo/lora-cat/`](demo/lora-cat/).
130
+
131
+ ## Links
132
+
133
+ - [🤗 PEFT documentation](https://huggingface.co/docs/peft)
134
+ - [LoRA paper (Hu et al., 2021)](https://arxiv.org/abs/2106.09685)
135
+ - [Qwen2.5 models](https://huggingface.co/Qwen)
136
+ - [Transformers Trainer](https://huggingface.co/docs/transformers/main_classes/trainer)
137
+
138
+ ## License
139
+
140
+ MIT
@@ -0,0 +1,7 @@
1
+ README.md
2
+ pyproject.toml
3
+ lora_easy.egg-info/PKG-INFO
4
+ lora_easy.egg-info/SOURCES.txt
5
+ lora_easy.egg-info/dependency_links.txt
6
+ lora_easy.egg-info/requires.txt
7
+ lora_easy.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ torch>=2.0
2
+ peft>=0.19
3
+ transformers>=4.45
@@ -0,0 +1 @@
1
+ lora_ez
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "lora-easy"
7
+ version = "1.0"
8
+ description = "A tiny OOP wrapper around PEFT for LoRA fine-tuning of causal LMs."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Freakwill" }]
13
+ dependencies = [
14
+ "torch>=2.0",
15
+ "peft>=0.19",
16
+ "transformers>=4.45",
17
+ ]
18
+
19
+ [project.urls]
20
+ Homepage = "https://github.com/Freakwill/lora-easy"
21
+
22
+ [tool.setuptools]
23
+ py-modules = ["lora_ez"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+