Coding-With-Bashir commited on
Commit
111c92f
·
verified ·
1 Parent(s): 9f33f44

Upload .\src\models\bwenge_model.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. .//src//models//bwenge_model.py +157 -0
.//src//models//bwenge_model.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """BwengeAi model architecture."""
2
+
3
+ import logging
4
+ from typing import Any
5
+
6
+ import torch
7
+ import torch.nn as nn
8
+ from transformers import (
9
+ AutoModelForCausalLM,
10
+ AutoTokenizer,
11
+ BitsAndBytesConfig,
12
+ PreTrainedModel,
13
+ )
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class BwengeModel:
19
+ """Manager for BwengeAi model."""
20
+
21
+ def __init__(self, config: dict[str, Any]):
22
+ self.config = config
23
+ self.model_config = config.get("model", {})
24
+ self.tokenizer = None
25
+ self.model = None
26
+
27
+ def load_base_model(
28
+ self,
29
+ model_name: str | None = None,
30
+ use_quantization: bool = False,
31
+ device_map: str | None = None,
32
+ ) -> tuple[PreTrainedModel, AutoTokenizer]:
33
+ """Load a base model for fine-tuning."""
34
+ if model_name is None:
35
+ model_name = self.model_config.get("base_model", "meta-llama/Llama-3.2-1B")
36
+
37
+ logger.info(f"Loading base model: {model_name}")
38
+
39
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
40
+ if tokenizer.pad_token is None:
41
+ tokenizer.pad_token = tokenizer.eos_token
42
+
43
+ use_cuda = torch.cuda.is_available()
44
+
45
+ if device_map is None:
46
+ device_map = "auto" if use_cuda else None
47
+
48
+ model_kwargs: dict[str, Any] = {
49
+ "trust_remote_code": True,
50
+ }
51
+
52
+ if use_quantization:
53
+ bnb_config = BitsAndBytesConfig(
54
+ load_in_4bit=True,
55
+ bnb_4bit_quant_type="nf4",
56
+ bnb_4bit_compute_dtype=torch.float16,
57
+ bnb_4bit_use_double_quant=True,
58
+ )
59
+ model_kwargs["quantization_config"] = bnb_config
60
+ model_kwargs["device_map"] = "auto"
61
+ elif use_cuda:
62
+ model_kwargs["dtype"] = torch.float16
63
+ model_kwargs["device_map"] = "auto"
64
+ else:
65
+ model_kwargs["dtype"] = torch.float32
66
+ model_kwargs["device_map"] = None
67
+ model_kwargs["low_cpu_mem_usage"] = True
68
+
69
+ model = AutoModelForCausalLM.from_pretrained(model_name, **model_kwargs)
70
+
71
+ self.tokenizer = tokenizer
72
+ self.model = model
73
+
74
+ logger.info(f"Model loaded: {model.num_parameters():,} parameters")
75
+ return model, tokenizer
76
+
77
+ def setup_lora(self, model: PreTrainedModel) -> PreTrainedModel:
78
+ """Set up LoRA for parameter-efficient fine-tuning."""
79
+ from peft import LoraConfig, get_peft_model, TaskType
80
+
81
+ lora_config = self.model_config.get("finetune", {}).get("lora", {})
82
+
83
+ config = LoraConfig(
84
+ task_type=TaskType.CAUSAL_LM,
85
+ r=lora_config.get("r", 16),
86
+ lora_alpha=lora_config.get("lora_alpha", 32),
87
+ lora_dropout=lora_config.get("lora_dropout", 0.05),
88
+ target_modules=lora_config.get("target_modules", [
89
+ "q_proj", "k_proj", "v_proj", "o_proj",
90
+ "gate_proj", "up_proj", "down_proj",
91
+ ]),
92
+ bias="none",
93
+ )
94
+
95
+ model = get_peft_model(model, config)
96
+
97
+ trainable, total = model.get_nb_trainable_parameters()
98
+ logger.info(f"LoRA applied: {trainable:,} trainable / {total:,} total ({100 * trainable / total:.2f}%)")
99
+
100
+ return model
101
+
102
+ def save_model(self, output_dir: str) -> None:
103
+ """Save the model and tokenizer."""
104
+ if self.model is None or self.tokenizer is None:
105
+ logger.error("No model loaded to save")
106
+ return
107
+
108
+ logger.info(f"Saving model to {output_dir}")
109
+ self.model.save_pretrained(output_dir)
110
+ self.tokenizer.save_pretrained(output_dir)
111
+ logger.info("Model saved successfully")
112
+
113
+ def load_saved_model(self, model_dir: str) -> tuple[PreTrainedModel, AutoTokenizer]:
114
+ """Load a previously saved model."""
115
+ logger.info(f"Loading saved model from {model_dir}")
116
+
117
+ tokenizer = AutoTokenizer.from_pretrained(model_dir)
118
+ model = AutoModelForCausalLM.from_pretrained(
119
+ model_dir,
120
+ torch_dtype=torch.float16,
121
+ device_map="auto",
122
+ )
123
+
124
+ self.tokenizer = tokenizer
125
+ self.model = model
126
+
127
+ return model, tokenizer
128
+
129
+ def generate(
130
+ self,
131
+ prompt: str,
132
+ max_new_tokens: int = 256,
133
+ temperature: float = 0.7,
134
+ top_p: float = 0.9,
135
+ top_k: int = 50,
136
+ ) -> str:
137
+ """Generate text from a prompt."""
138
+ if self.model is None or self.tokenizer is None:
139
+ logger.error("No model loaded for generation")
140
+ return ""
141
+
142
+ inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
143
+
144
+ with torch.no_grad():
145
+ outputs = self.model.generate(
146
+ **inputs,
147
+ max_new_tokens=max_new_tokens,
148
+ temperature=temperature,
149
+ top_p=top_p,
150
+ top_k=top_k,
151
+ do_sample=True,
152
+ pad_token_id=self.tokenizer.eos_token_id,
153
+ )
154
+
155
+ generated = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
156
+
157
+ return generated[len(prompt):]