Coding-With-Bashir commited on
Commit
251c567
·
verified ·
1 Parent(s): 75a2f4b

Upload .\src\training\trainer.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. .//src//training//trainer.py +230 -0
.//src//training//trainer.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Training pipeline for BwengeAi."""
2
+
3
+ import logging
4
+ import os
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ import torch
9
+ from datasets import load_dataset
10
+ from transformers import (
11
+ AutoModelForCausalLM,
12
+ AutoTokenizer,
13
+ DataCollatorForLanguageModeling,
14
+ TrainingArguments,
15
+ )
16
+ from trl import SFTTrainer
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class BwengeTrainer:
22
+ """Training manager for BwengeAi."""
23
+
24
+ def __init__(self, config: dict[str, Any]):
25
+ self.config = config
26
+ self.training_config = config.get("training", {})
27
+ self.output_dir = Path(self.training_config.get("output_dir", "outputs"))
28
+ self.output_dir.mkdir(parents=True, exist_ok=True)
29
+
30
+ def prepare_dataset(
31
+ self,
32
+ data_path: str,
33
+ tokenizer: AutoTokenizer,
34
+ max_length: int = 2048,
35
+ ) -> Any:
36
+ """Prepare dataset for training."""
37
+ logger.info(f"Loading dataset from {data_path}")
38
+
39
+ dataset = load_dataset("json", data_files=data_path, split="train")
40
+
41
+ def tokenize_function(examples):
42
+ return tokenizer(
43
+ examples["text"],
44
+ truncation=True,
45
+ max_length=max_length,
46
+ padding="max_length",
47
+ )
48
+
49
+ tokenized_dataset = dataset.map(
50
+ tokenize_function,
51
+ batched=True,
52
+ remove_columns=dataset.column_names,
53
+ )
54
+
55
+ logger.info(f"Dataset prepared: {len(tokenized_dataset)} samples")
56
+ return tokenized_dataset
57
+
58
+ def prepare_instruction_dataset(
59
+ self,
60
+ data_path: str,
61
+ tokenizer: AutoTokenizer,
62
+ max_length: int = 2048,
63
+ ) -> Any:
64
+ """Prepare instruction-following dataset."""
65
+ logger.info(f"Loading instruction dataset from {data_path}")
66
+
67
+ dataset = load_dataset("json", data_files=data_path, split="train")
68
+
69
+ def format_instruction(examples):
70
+ texts = []
71
+ for i in range(len(examples["instruction"])):
72
+ instruction = examples["instruction"][i]
73
+ input_text = examples.get("input", [""] * len(examples["instruction"]))[i]
74
+ output = examples["output"][i]
75
+
76
+ if input_text:
77
+ text = f"### Instruction:\n{instruction}\n\n### Input:\n{input_text}\n\n### Response:\n{output}"
78
+ else:
79
+ text = f"### Instruction:\n{instruction}\n\n### Response:\n{output}"
80
+
81
+ texts.append(text)
82
+
83
+ return {"text": texts}
84
+
85
+ formatted_dataset = dataset.map(
86
+ format_instruction,
87
+ batched=True,
88
+ remove_columns=dataset.column_names,
89
+ )
90
+
91
+ def tokenize_function(examples):
92
+ return tokenizer(
93
+ examples["text"],
94
+ truncation=True,
95
+ max_length=max_length,
96
+ padding="max_length",
97
+ )
98
+
99
+ tokenized_dataset = formatted_dataset.map(
100
+ tokenize_function,
101
+ batched=True,
102
+ remove_columns=formatted_dataset.column_names,
103
+ )
104
+
105
+ logger.info(f"Instruction dataset prepared: {len(tokenized_dataset)} samples")
106
+ return tokenized_dataset
107
+
108
+ def train(
109
+ self,
110
+ model: AutoModelForCausalLM,
111
+ tokenizer: AutoTokenizer,
112
+ dataset: Any,
113
+ lora: bool = False,
114
+ ) -> None:
115
+ """Train the model."""
116
+ training_args = TrainingArguments(
117
+ output_dir=str(self.output_dir),
118
+ num_train_epochs=self.training_config.get("num_epochs", 3),
119
+ per_device_train_batch_size=self.training_config.get("batch_size", 8),
120
+ gradient_accumulation_steps=self.training_config.get("gradient_accumulation_steps", 4),
121
+ learning_rate=self.training_config.get("learning_rate", 2e-5),
122
+ weight_decay=self.training_config.get("weight_decay", 0.01),
123
+ warmup_steps=self.training_config.get("warmup_steps", 500),
124
+ max_grad_norm=self.training_config.get("max_grad_norm", 1.0),
125
+ fp16=self.training_config.get("fp16", False) and torch.cuda.is_available(),
126
+ logging_steps=self.training_config.get("logging_steps", 10),
127
+ save_steps=self.training_config.get("save_steps", 500),
128
+ save_total_limit=self.training_config.get("save_total_limit", 3),
129
+ report_to="none",
130
+ seed=self.training_config.get("seed", 42),
131
+ dataloader_num_workers=0,
132
+ remove_unused_columns=False,
133
+ )
134
+
135
+ if lora:
136
+ trainer = SFTTrainer(
137
+ model=model,
138
+ train_dataset=dataset,
139
+ args=training_args,
140
+ tokenizer=tokenizer,
141
+ max_seq_length=self.config.get("model", {}).get("max_length", 2048),
142
+ )
143
+ else:
144
+ data_collator = DataCollatorForLanguageModeling(
145
+ tokenizer=tokenizer,
146
+ mlm=False,
147
+ )
148
+
149
+ trainer = SFTTrainer(
150
+ model=model,
151
+ train_dataset=dataset,
152
+ args=training_args,
153
+ tokenizer=tokenizer,
154
+ data_collator=data_collator,
155
+ max_seq_length=self.config.get("model", {}).get("max_length", 2048),
156
+ )
157
+
158
+ logger.info("Starting training...")
159
+ trainer.train()
160
+
161
+ trainer.save_model(str(self.output_dir / "final"))
162
+ tokenizer.save_pretrained(str(self.output_dir / "final"))
163
+
164
+ logger.info(f"Training complete. Model saved to {self.output_dir / 'final'}")
165
+
166
+ def train_from_config(
167
+ self,
168
+ model: AutoModelForCausalLM,
169
+ tokenizer: AutoTokenizer,
170
+ data_path: str,
171
+ lora: bool = False,
172
+ ) -> None:
173
+ """Train using configuration."""
174
+ logger.info(f"Loading dataset from {data_path}")
175
+ dataset = load_dataset("json", data_files=data_path, split="train")
176
+
177
+ has_text = "text" in dataset.column_names
178
+ has_instruction = "instruction" in dataset.column_names
179
+
180
+ if has_instruction and not has_text:
181
+ def format_instruction(examples):
182
+ texts = []
183
+ for i in range(len(examples["instruction"])):
184
+ instruction = examples["instruction"][i]
185
+ input_text = examples.get("input", [""] * len(examples["instruction"]))[i]
186
+ output = examples["output"][i]
187
+ if input_text:
188
+ text = f"### Instruction:\n{instruction}\n\n### Input:\n{input_text}\n\n### Response:\n{output}"
189
+ else:
190
+ text = f"### Instruction:\n{instruction}\n\n### Response:\n{output}"
191
+ texts.append(text)
192
+ return {"text": texts}
193
+
194
+ dataset = dataset.map(format_instruction, batched=True, remove_columns=dataset.column_names)
195
+
196
+ max_seq_length = self.config.get("model", {}).get("max_length", 2048)
197
+
198
+ training_args = TrainingArguments(
199
+ output_dir=str(self.output_dir),
200
+ num_train_epochs=self.training_config.get("num_epochs", 3),
201
+ per_device_train_batch_size=self.training_config.get("batch_size", 8),
202
+ gradient_accumulation_steps=self.training_config.get("gradient_accumulation_steps", 4),
203
+ learning_rate=self.training_config.get("learning_rate", 2e-5),
204
+ weight_decay=self.training_config.get("weight_decay", 0.01),
205
+ warmup_steps=self.training_config.get("warmup_steps", 500),
206
+ max_grad_norm=self.training_config.get("max_grad_norm", 1.0),
207
+ fp16=self.training_config.get("fp16", False) and torch.cuda.is_available(),
208
+ logging_steps=self.training_config.get("logging_steps", 10),
209
+ save_steps=self.training_config.get("save_steps", 500),
210
+ save_total_limit=self.training_config.get("save_total_limit", 3),
211
+ report_to="none",
212
+ seed=self.training_config.get("seed", 42),
213
+ dataloader_num_workers=0,
214
+ remove_unused_columns=False,
215
+ )
216
+
217
+ trainer = SFTTrainer(
218
+ model=model,
219
+ train_dataset=dataset,
220
+ args=training_args,
221
+ processing_class=tokenizer,
222
+ )
223
+
224
+ logger.info("Starting training...")
225
+ trainer.train()
226
+
227
+ trainer.save_model(str(self.output_dir / "final"))
228
+ tokenizer.save_pretrained(str(self.output_dir / "final"))
229
+
230
+ logger.info(f"Training complete. Model saved to {self.output_dir / 'final'}")