File size: 10,681 Bytes
0fa4cc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#!/usr/bin/env python3
"""
🎯 Tworzenie własnego modelu LLM - od fine-tuningu do publikacji
Przykład z Mistral 7B + własne dane
"""

import os
import json
from pathlib import Path
from datasets import Dataset
from transformers import (
    AutoModelForCausalLM, 
    AutoTokenizer, 
    TrainingArguments, 
    Trainer
)
from peft import LoraConfig, get_peft_model, TaskType
import torch

# === 1. PRZYGOTOWANIE DANYCH ===

def create_sample_dataset():
    """Tworzy przykładowy dataset do fine-tuningu"""
    
    # Przykładowe dane - zamień na swoje!
    sample_data = [
        {
            "instruction": "Jak nazywa się stolica Polski?",
            "input": "",
            "output": "Stolica Polski to Warszawa."
        },
        {
            "instruction": "Wyjaśnij czym jest sztuczna inteligencja",
            "input": "",
            "output": "Sztuczna inteligencja (AI) to dziedzina informatyki zajmująca się tworzeniem systemów zdolnych do wykonywania zadań wymagających inteligencji."
        },
        {
            "instruction": "Napisz krótką funkcję w Pythonie",
            "input": "funkcja do obliczania silni",
            "output": "```python\ndef factorial(n):\n    if n <= 1:\n        return 1\n    return n * factorial(n-1)\n```"
        },
        {
            "instruction": "Jak zoptymalizować kod Python?",
            "input": "",
            "output": "Główne sposoby optymalizacji kodu Python:\n1. Używaj wbudowanych funkcji\n2. Unikaj pętli, preferuj list comprehensions\n3. Używaj numpy dla operacji numerycznych\n4. Profiluj kod przed optymalizacją"
        },
        {
            "instruction": "Co to jest Docker?",
            "input": "",
            "output": "Docker to platforma konteneryzacji umożliwiająca pakowanie aplikacji wraz z zależnościami w lekkie, przenośne kontenery."
        }
    ]
    
    # Zapisz dataset
    os.makedirs("data", exist_ok=True)
    with open("data/training_data.json", "w", encoding="utf-8") as f:
        json.dump(sample_data, f, indent=2, ensure_ascii=False)
    
    print("✅ Sample dataset created in data/training_data.json")
    return sample_data

def format_training_data(examples):
    """Formatuje dane dla Mistral Instruct"""
    formatted_texts = []
    
    for example in examples:
        if example.get("input"):
            prompt = f"<s>[INST] {example['instruction']}\n{example['input']} [/INST] {example['output']}</s>"
        else:
            prompt = f"<s>[INST] {example['instruction']} [/INST] {example['output']}</s>"
        formatted_texts.append(prompt)
    
    return {"text": formatted_texts}

# === 2. FINE-TUNING Z LORA ===

def setup_model_and_tokenizer(model_name="mistralai/Mistral-7B-Instruct-v0.1"):
    """Ładuje model i tokenizer"""
    print(f"📥 Loading model: {model_name}")
    
    # Tokenizer
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    tokenizer.pad_token = tokenizer.eos_token
    tokenizer.padding_side = "right"
    
    # Model z quantization dla RTX 3050
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        torch_dtype=torch.float16,
        device_map="auto",
        load_in_4bit=True,  # 4-bit quantization
        trust_remote_code=True
    )
    
    return model, tokenizer

def setup_lora_config():
    """Konfiguracja LoRA dla efficient fine-tuning"""
    return LoraConfig(
        task_type=TaskType.CAUSAL_LM,
        inference_mode=False,
        r=16,  # LoRA rank
        lora_alpha=32,
        lora_dropout=0.1,
        target_modules=["q_proj", "k_proj", "v_proj", "o_proj"]  # Mistral attention modules
    )

def fine_tune_model():
    """Główna funkcja fine-tuningu"""
    
    # 1. Przygotuj dane
    print("🔄 Preparing training data...")
    sample_data = create_sample_dataset()
    
    # 2. Ładuj model
    model, tokenizer = setup_model_and_tokenizer()
    
    # 3. Setup LoRA
    lora_config = setup_lora_config()
    model = get_peft_model(model, lora_config)
    
    print(f"📊 Trainable parameters: {model.print_trainable_parameters()}")
    
    # 4. Przygotuj dataset
    dataset = Dataset.from_list(sample_data)
    formatted_dataset = dataset.map(
        lambda x: format_training_data([x]),
        remove_columns=dataset.column_names
    )
    
    # Tokenizacja
    def tokenize_function(examples):
        return tokenizer(
            examples["text"],
            truncation=True,
            padding="max_length",
            max_length=512,
            return_tensors="pt"
        )
    
    tokenized_dataset = formatted_dataset.map(tokenize_function, batched=True)
    
    # 5. Training arguments - optymalizowane dla RTX 3050
    training_args = TrainingArguments(
        output_dir="./results",
        num_train_epochs=3,
        per_device_train_batch_size=1,  # Mały batch size dla RTX 3050
        gradient_accumulation_steps=4,
        warmup_steps=10,
        learning_rate=2e-4,
        fp16=True,  # Mixed precision
        logging_steps=1,
        save_strategy="epoch",
        evaluation_strategy="no",
        dataloader_num_workers=0,  # Avoid multiprocessing issues
        remove_unused_columns=False,
    )
    
    # 6. Trainer
    trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=tokenized_dataset,
        tokenizer=tokenizer,
    )
    
    # 7. Train!
    print("🚀 Starting fine-tuning...")
    trainer.train()
    
    # 8. Save model
    model.save_pretrained("./fine_tuned_model")
    tokenizer.save_pretrained("./fine_tuned_model")
    
    print("✅ Fine-tuning completed! Model saved to ./fine_tuned_model")
    
    return model, tokenizer

# === 3. KONWERSJA DO GGUF ===

def convert_to_gguf():
    """Konwertuje model do formatu GGUF dla Ollama"""
    
    print("🔄 Converting to GGUF format...")
    
    # Ten skrypt wymaga llama.cpp
    conversion_script = """
#!/bin/bash

# Pobierz llama.cpp jeśli nie masz
if [ ! -d "llama.cpp" ]; then
    git clone https://github.com/ggerganov/llama.cpp.git
    cd llama.cpp
    make -j
    cd ..
fi

# Konwertuj model
python llama.cpp/convert.py ./fine_tuned_model --outtype f16 --outfile my_custom_model.gguf

echo "✅ GGUF conversion completed: my_custom_model.gguf"
"""
    
    with open("convert_to_gguf.sh", "w") as f:
        f.write(conversion_script)
    
    os.chmod("convert_to_gguf.sh", 0o755)
    
    print("📝 Created convert_to_gguf.sh script")
    print("Run: ./convert_to_gguf.sh")

# === 4. TWORZENIE MODELFILE DLA OLLAMA ===

def create_ollama_modelfile():
    """Tworzy Modelfile dla Ollama"""
    
    modelfile_content = '''FROM ./my_custom_model.gguf

# Model metadata
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER top_k 40
PARAMETER num_ctx 2048

# System prompt
SYSTEM "Jesteś pomocnym asystentem AI stworzonym specjalnie dla polskich użytkowników.\nOdpowiadasz w języku polskim, jesteś precyzyjny i pomocny.\nSpecjalizujesz się w programowaniu, technologii i sztucznej inteligencji."

# Chat template dla Mistral
TEMPLATE "<s>[INST] {{ if .System }}{{ .System }}{{ end }}{{ .Prompt }} [/INST] {{ .Response }}</s>"

# Metadata
PARAMETER num_predict 256
PARAMETER stop "<s>"
PARAMETER stop "[INST]"
PARAMETER stop "[/INST]"
'''
    
    with open("Modelfile", "w", encoding="utf-8") as f:
        f.write(modelfile_content)
    print("✅ Utworzono Modelfile dla Ollama")
    print("✅ Created Modelfile for Ollama")

# === 5. PUBLIKACJA MODELU ===

def create_model_in_ollama():
    """Tworzy model w Ollama"""
    
    ollama_commands = """
# 1. Utwórz model w Ollama
ollama create wronai -f Modelfile

# 2. Test modelu
ollama run wronai "Cześć! Kim jesteś?"

# 3. Push do Ollama Library (wymaga konta)
ollama push wronai

# 4. Alternatywnie - export do pliku
ollama save wronai wronai-model.tar
"""
    
    with open("ollama_commands.sh", "w") as f:
        f.write(ollama_commands)
    
    print("✅ Created ollama_commands.sh")

# === 6. PUBLIKACJA NA HUGGING FACE ===

def create_hf_publish_script():
    """Skrypt do publikacji na Hugging Face"""
    
    hf_script = '''#!/usr/bin/env python3
"""
Publikacja modelu na Hugging Face Hub
"""

from huggingface_hub import HfApi, create_repo
import os

def publish_to_hf():
    # Konfiguracja
    model_name = "your-username/my-custom-mistral-7b"
    
    # Login (wymagany HF token)
    # huggingface-cli login
    
    # Utwórz repo
    api = HfApi()
    
    try:
        create_repo(
            repo_id=model_name,
            repo_type="model",
            private=False  # Ustaw True dla prywatnego
        )
        print(f"✅ Repository created: {model_name}")
    except Exception as e:
        print(f"Repository may already exist: {e}")
    
    # Upload plików
    api.upload_folder(
        folder_path="./fine_tuned_model",
        repo_id=model_name,
        commit_message="Initial model upload"
    )
    
    # Upload GGUF (jeśli istnieje)
    if os.path.exists("my_custom_model.gguf"):
        api.upload_file(
            path_or_fileobj="my_custom_model.gguf",
            path_in_repo="my_custom_model.gguf",
            repo_id=model_name,
            commit_message="Add GGUF version"
        )
    
    print(f"🎉 Model published: https://huggingface.co/{model_name}")

if __name__ == "__main__":
    publish_to_hf()
'''
    
    with open("publish_to_hf.py", "w") as f:
        f.write(hf_script)
    
    print("✅ Created publish_to_hf.py")

# === GŁÓWNA FUNKCJA ===

def main():
    """Pełny pipeline tworzenia własnego modelu"""
    
    print("🎯 Custom LLM Creation Pipeline")
    print("===============================")
    
    choice = input("""
Wybierz opcję:
1. Stwórz sample dataset
2. Fine-tune model (wymaga GPU)
3. Konwertuj do GGUF
4. Utwórz Modelfile dla Ollama
5. Przygotuj skrypty publikacji
6. Pełny pipeline (1-5)

Wybór (1-6): """).strip()
    
    if choice == "1":
        create_sample_dataset()
    elif choice == "2":
        fine_tune_model()
    elif choice == "3":
        convert_to_gguf()
    elif choice == "4":
        create_ollama_modelfile()
    elif choice == "5":
        create_hf_publish_script()
    elif choice == "6":
        print("🚀 Running full pipeline...")
        create_sample_dataset()
        
        if input("Continue with fine-tuning? (y/N): ").lower() == 'y':
            fine_tune_model()
            convert_to_gguf()
        
        create_ollama_modelfile()
        create_model_in_ollama()
        create_hf_publish_script()
        
        print("✅ Full pipeline completed!")
    else:
        print("Invalid choice")

if __name__ == "__main__":
    main()