MarulAI commited on
Commit
71b3a83
·
verified ·
1 Parent(s): 011601f

Upload 11 files

Browse files
LICENSE.md ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Yedikule Model Lisansı
2
+
3
+ Sürüm 2.0
4
+
5
+ Telif hakkı sahibi: **Ahmet Karakuş** (Marul AI)
6
+
7
+ ## Kısaca
8
+
9
+ Modeli özgürce kullanabilir, üzerine kendi modelinizi eğitebilir ve paylaşabilirsiniz. Üç şartla: ticari kullanım için izin alın, Yedikule'ye atıf yapın, türev modelinizin adında Yedikule geçsin.
10
+
11
+ ## 1. Kapsam
12
+
13
+ Bu lisans Yedikule modelinin şu bileşenlerini kapsar:
14
+
15
+ - Model ağırlıkları ve bunlardan türetilen her biçim (GGUF, ONNX, nicelenmiş sürümler, ince ayar sonucu ağırlıklar, birleştirilmiş modeller)
16
+ - Tokenizer ve sözlüğü
17
+ - Model mimarisi kodu (`model.py`, `config.py`)
18
+ - Yapılandırma dosyaları ve dokümantasyon
19
+
20
+ Bunların tamamı bundan sonra "Model" olarak anılır. Model üzerindeki fikri mülkiyet hakları Ahmet Karakuş'a aittir.
21
+
22
+ ## 2. İzin verilen kullanım
23
+
24
+ Aşağıdakiler için ayrıca izin almanıza gerek yoktur. Hepsi ticari olmayan kullanımla sınırlıdır ve 3. bölümdeki şartlara tabidir.
25
+
26
+ **2.1 Kullanım.** Modeli kendi cihazınızda veya sunucunuzda çalıştırabilirsiniz.
27
+
28
+ **2.2 Eğitim ve araştırma.** Ders, atölye, tez, akademik araştırma ve ölçüt çalışmalarında kullanabilirsiniz.
29
+
30
+ **2.3 Yeniden eğitim ve türev model.** Model üzerinde ince ayar (fine-tuning) yapabilir, sürekli eğitimle geliştirebilir, LoRA veya benzeri adaptör ekleyebilir, damıtabilir, başka modellerle birleştirebilirsiniz. Ortaya çıkan modeli yayımlayabilirsiniz.
31
+
32
+ **2.4 Biçim dönüştürme.** Modeli GGUF, ONNX ve benzeri biçimlere çevirebilir, niceleyebilir (Q4, Q8 ve diğerleri) ve bu dosyaları paylaşabilirsiniz.
33
+
34
+ **2.5 Yeniden dağıtım.** Modeli olduğu gibi veya değiştirilmiş halde başka platformlarda yayımlayabilirsiniz.
35
+
36
+ ## 3. Şartlar
37
+
38
+ İzin verilen kullanımların tamamı aşağıdaki şartlara bağlıdır.
39
+
40
+ **3.1 Atıf.** Modeli kullandığınız veya ondan türettiğiniz her yerde Yedikule'ye ve geliştiricisine atıf yapmalısınız. Yayımladığınız model kartında, dokümantasyonda veya akademik yayında şu bilgi bulunmalıdır:
41
+
42
+ ```
43
+ Bu çalışma Yedikule modeline dayanmaktadır.
44
+ Yedikule, 202M parametreli Türkçe dil modeli.
45
+ Ahmet Karakuş, Marul AI, 2026.
46
+ ```
47
+
48
+ **3.2 İsim.** Yedikule'den türettiğiniz bir modeli yayımlarsanız, modelin adında **Yedikule** geçmelidir. Örnek: `Yedikule-Tip`, `Yedikule-Kod`, `Firma-Yedikule-Asistan`. Modelin Yedikule'den türediğini gizleyemez, kendi sıfırdan eğitiminiz gibi sunamazsınız.
49
+
50
+ **3.3 Türevler de bu lisansa tabidir.** Bu modelden türetilen her çalışma (ince ayar, sürekli eğitim, adaptör, damıtma, birleştirme, niceleme, biçim dönüşümü ve benzeri) bu lisansın kapsamındadır ve aynı koşullara bağlıdır. Türev modelinizi dağıtırken bu lisans dosyasını da birlikte vermeniz zorunludur. Türev modelinize daha gevşek bir lisans veremez, kendi lisansınızla yeniden lisanslayamazsınız. Bu yükümlülük türevin türevi için de sürer.
51
+
52
+ **3.4 Telif bilgisinin korunması.** Telif hakkı beyanını ve geliştirici bilgisini kaldıramaz veya değiştiremezsiniz.
53
+
54
+ ## 4. Ticari kullanım
55
+
56
+ Ticari kullanım, telif hakkı sahibinin yazılı izni olmadan yasaktır. Ticari kullanım şunları kapsar:
57
+
58
+ - Modeli doğrudan veya dolaylı gelir getiren bir ürüne veya hizmete gömmek
59
+ - API olarak ücretli sunmak, abonelik veya reklam geliri elde etmek
60
+ - Kurum içi ticari süreçlerde çalıştırmak
61
+ - Modelden türetilmiş bir modeli ticari amaçla kullanmak veya satmak
62
+ - Danışmanlık hizmetinde kullanmak
63
+
64
+ Ticari kullanım için telif hakkı sahibinden izin alın. Talebinizi şu adrese gönderin:
65
+
66
+ **marulai.resmi@gmail.com**
67
+
68
+ Talepler ayrıca değerlendirilir ve yazılı sözleşmeye bağlanır. Bu, modelden türetilmiş modellerin ticari kullanımı için de geçerlidir; türev modeli siz eğitmiş olsanız bile ticari kullanım izne bağlıdır.
69
+
70
+ Akademik araştırma, kişisel projeler, öğrenme ve açık kaynak topluluk çalışmaları ticari kullanım sayılmaz.
71
+
72
+ ## 5. Eğitim verisi
73
+
74
+ Bu model iki aşamada eğitildi. Ön eğitim corpus'u kısmen `uonlp/CulturaX` Türkçe alt kümesinden, kısmen telif hakkı sahibinin kendi web taramasından derlendi; CulturaX'in koşulları `mC4` ve `OSCAR` kümelerini takip eder ve her ikisi de Common Crawl üzerinden üretilmiştir.
75
+
76
+ Talimat ayarı aşamasında telif hakkı sahibinin hazırladığı `MarulAI/Marul-SFT-TR` veri seti kullanıldı. Bu veri seti Apache 2.0 lisansıyla ayrıca yayımlanmıştır.
77
+
78
+ Kaynak veri kümelerinin lisansları bu lisanstan bağımsız olarak yürürlüktedir. Modeli ticari amaçla kullanmak isteyen taraf, telif hakkı sahibinden izin almanın yanında ön eğitim verisinin kaynak koşullarının (mC4, OSCAR ve Common Crawl) kendi kullanım biçimine uygunluğunu da ayrıca değerlendirmelidir. Telif hakkı sahibinin verdiği ticari izin, kaynak veri koşullarından doğan yükümlülükleri ortadan kaldırmaz.
79
+
80
+ ## 6. Yasaklar
81
+
82
+ **6.1** İzinsiz ticari kullanım.
83
+
84
+ **6.2** Modeli veya türevini, Yedikule kaynaklı olduğunu gizleyerek sunmak.
85
+
86
+ **6.3** Telif hakkı beyanını, lisans dosyasını veya geliştirici bilgisini kaldırmak.
87
+
88
+ **6.4** Modeli yasa dışı içerik üretmek, kişileri hedef almak, yanıltıcı bilgi yaymak veya zarar verecek biçimde kullanmak.
89
+
90
+ ## 7. Garanti reddi
91
+
92
+ Model olduğu gibi sunulur. Telif hakkı sahibi, Modelin belirli bir amaca uygunluğu, kesintisiz çalışması veya ürettiği bilginin doğruluğu konusunda garanti vermez.
93
+
94
+ Model istatistiksel bir dil modelidir; yanlış, eksik veya yanıltıcı bilgi üretebilir. Tıbbi, hukuki, finansal veya güvenlik açısından kritik kararlarda tek başına kullanılmamalıdır. Çıktıların doğrulanması kullanıcının sorumluluğundadır.
95
+
96
+ ## 8. Sorumluluğun sınırlandırılması
97
+
98
+ Telif hakkı sahibi, Modelin kullanımından doğan doğrudan veya dolaylı hiçbir zarardan sorumlu tutulamaz. Modeli kullanan taraf, kullanımdan doğacak tüm hukuki ve mali sorumluluğu kabul eder.
99
+
100
+ ## 9. Lisansın feshi
101
+
102
+ Bu lisansın şartlarını ihlal etmeniz durumunda kullanım izniniz kendiliğinden sona erer. İhlali öğrendikten sonra otuz gün içinde düzeltirseniz izniniz geri kazanılır. Fesih, ihlal nedeniyle doğan hukuki sorumluluğu ortadan kaldırmaz.
103
+
104
+ ## 10. Uygulanacak hukuk
105
+
106
+ Bu lisans Türkiye Cumhuriyeti hukukuna tabidir. Uyuşmazlıklarda İstanbul mahkemeleri ve icra daireleri yetkilidir.
107
+
108
+ ## 11. İletişim
109
+
110
+ Ticari lisans, izin talepleri ve ihlal bildirimleri için:
111
+
112
+ Ahmet Karakuş, Marul AI
113
+ marulai.resmi@gmail.com
114
+
115
+ ---
116
+
117
+ ## English summary
118
+
119
+ This is a non-binding summary. The Turkish text above is the governing license.
120
+
121
+ Copyright Ahmet Karakuş (Marul AI).
122
+
123
+ **You may**, without asking: run the model, use it for education and research, fine-tune it, distill it, merge it, quantize it, convert it to other formats, and publish the result. All of this is limited to non-commercial use.
124
+
125
+ **You must**: give attribution to Yedikule and its developer; include the name **Yedikule** in the name of any derivative model you publish; ship this license with the model or any derivative; keep the copyright notice intact. Any derivative work remains subject to this same license and cannot be relicensed under different terms.
126
+
127
+ **You may not**, without written permission: use the model or any derivative commercially; present the model as your own work or hide that it derives from Yedikule; remove the license or copyright notice; or use it for illegal, harmful or deceptive purposes.
128
+
129
+ Provided as is, without warranty. Contact the copyright holder for commercial licensing: Ahmet Karakuş, Marul AI, marulai.resmi@gmail.com
README.md ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ license_name: yedikule-model-lisansi-v2
4
+ license_link: LICENSE.md
5
+ base_model: MarulAI/Yedikule-202M-Base
6
+ datasets:
7
+ - MarulAI/Marul-SFT-TR
8
+ language:
9
+ - tr
10
+ pipeline_tag: text-generation
11
+ tags:
12
+ - turkish
13
+ - turkce
14
+ - marul-ai
15
+ - yedikule
16
+ - instruct
17
+ - conversational
18
+ - reasoning
19
+ - tool-calling
20
+ ---
21
+
22
+ # Yedikule 1.4
23
+
24
+ Yedikule 1.4, Marul AI'ın Türkçe için sıfırdan eğittiği 202 milyon parametreli dil modelinin en yeni talimat ayarlı sürümüdür. Cevap vermeden önce kısa bir düşünme yapar, sistem mesajındaki kurallara uyar, kendisine verilen araçları açıklamalarına bakarak seçip çağırır ve çok turlu sohbetlerde bağlamı korur.
25
+
26
+ Bu sürüm, tamamen yeni ve bu model için hazırlanmış [Marul-SFT-TR](https://huggingface.co/datasets/MarulAI/Marul-SFT-TR) veri setiyle eğitildi. Önceki sürüme göre en büyük ilerleme düşünme, talimat takibi ve araç kullanımındadır: model artık eğitimde hiç görmediği araçlarla da çalışabiliyor. Ölçütlerde de yedi testin ortalamasında önceki sürümün ve temel modelin önüne geçti; okuduğunu anlamada ve zor fen sorularında açık farkla en iyi sonucu verdi. Üstelik modelin Türkçe dil bilgisi ve genel metin anlama yeteneği eksiksiz korundu.
27
+
28
+ | | |
29
+ |---|---|
30
+ | Geliştirici | Ahmet Karakuş, Marul AI |
31
+ | Model türü | Decoder-only Transformer, talimat ayarlı |
32
+ | Dil | Türkçe |
33
+ | Parametre | 202.1M |
34
+ | Bağlam | 2048 token |
35
+ | Ağırlık biçimi | bf16, safetensors |
36
+ | Temel model | [Yedikule 202M Base](https://huggingface.co/MarulAI/Yedikule-202M-Base) |
37
+ | Eğitim verisi | [Marul-SFT-TR](https://huggingface.co/datasets/MarulAI/Marul-SFT-TR) |
38
+ | Lisans | Yedikule Model Lisansı 2.0 |
39
+ | Sürüm | 1.4 (Ekim 2026) |
40
+
41
+ GGUF sürümü llama.cpp, Ollama ve LM Studio ile doğrudan çalışır: [MarulAI/Yedikule-1.4-GGUF](https://huggingface.co/MarulAI/Yedikule-1.4-GGUF). Depoda ana modelle bit düzeyinde aynı BF16 dosyasının yanında, bu model için ölçülerek hazırlanmış Q8_0, Q6_K, Q5_K_M ve Q4_K_M sürümleri de vardır; en küçüğü 140 MB'tır.
42
+
43
+ ## Öne çıkanlar
44
+
45
+ - **Düşünerek cevap verme.** Her cevaptan önce kullanıcının ne istediğini ve nasıl cevap vereceğini kısaca planlar. Düşünme ayrı bir bölümdür; arayüzde gizlenebilir.
46
+ - **Araç çağırma.** Araç tanımları sistem turunda verilir. Model doğru aracı adına değil açıklamasına bakarak seçer, parametreleri kullanıcının söylediklerinden çıkarır, gerektiğinde art arda veya aynı anda birden fazla araç çağırır ve sonucu doğal bir dille aktarır. Araç gerekmeyen sorularda araç çağırmaz.
47
+ - **Esnek sistem mesajı.** Tek bir sabit sistem mesajına bağlı değildir. Persona, kural, biçim ve uzunluk kısıtlarını, kurumsal asistan senaryolarını ve sohbet ortasında değişen talimatları izler.
48
+ - **Çok turlu sohbet.** Önceki turlarda söylenenleri hatırlar, kullanıcı fikir değiştirdiğinde ya da yeni bir kısıt eklediğinde cevabını buna göre günceller.
49
+ - **Doğal Türkçe.** Resmî yazan kullanıcıyı da, Türkçe karakter kullanmadan, yazım hatasıyla ya da argoyla yazanı da anlar; her zaman açık ve düzgün bir Türkçeyle cevap verir.
50
+
51
+ ## Örnek
52
+
53
+ Aşağıdaki çıktılar, bu kartın Kullanım bölümündeki kodla ve önerilen üretim ayarlarıyla üretildi.
54
+
55
+ ```
56
+ Kullanıcı : Fotosentezi kısaca anlatır mısın?
57
+ Düşünme : Kullanıcı fotosentezi tek cümleyle istiyor. Işığa bağlı tepkimeler ve Calvin döngüsü olarak
58
+ iki adımı, kısa ve net vermeliyim.
59
+ Yedikule : Fotosentez, bitkilerin güneş ışığını kullanarak besin üretmesi sürecidir.
60
+ ```
61
+
62
+ Araç çağırma (sistem turunda `hava_durumu` aracı tanımlı):
63
+
64
+ ```
65
+ Kullanıcı : Yarın İzmir'de hava nasıl olacak?
66
+ Araç çağrısı : {"name":"hava_durumu","arguments":{"sehir":"İzmir"}}
67
+ Araç sonucu : {"sehir":"İzmir","durum":"parçalı bulutlu","en_yuksek":27,"en_dusuk":19}
68
+ Düşünme : Sonuç yarın İzmir'de parçalı bulutlu, en yüksek 27, en düşük 19 derece. Kullanıcıya bunu
69
+ sade biçimde aktarmalıyım; sonuçta olmayan bilgi eklemeden.
70
+ Yedikule : Yarın İzmir'de hava parçalı bulutlu olacak. En yüksek 27, en düşük 19 derece.
71
+ ```
72
+
73
+ ## Değerlendirme
74
+
75
+ Bütün modeller aynı kodla, aynı veriyle ve aynı koşullarda ölçüldü. Çoktan seçmeli görevlerde her seçeneğin bağlama göre olasılığı hesaplanır ve en olası seçenek modelin cevabı sayılır (0-shot, lm-evaluation-harness yöntemi). Üretim yapılmadığı için sonuçlar örnekleme ayarlarından bağımsızdır ve birebir tekrarlanabilir.
76
+
77
+ | Ölçüt | Rastgele | Yedikule 202M Base | Yedikule 202M Instruct | Yedikule 1.4 |
78
+ |---|---:|---:|---:|---:|
79
+ | Belebele, okuduğunu anlama | 25,0 | 28,8 | 29,1 | **31,1** |
80
+ | XCOPA, neden sonuç çıkarımı | 50,0 | 60,2 | **60,6** | 59,2 |
81
+ | TurkishMMLU, lise düzeyi bilgi | 20,0 | **23,0** | 20,6 | 21,7 |
82
+ | ARC-TR kolay, fen soruları | 25,0 | 37,3 | **39,8** | 38,8 |
83
+ | ARC-TR zor, fen soruları | 25,0 | 24,1 | 26,5 | **28,5** |
84
+ | HellaSwag-TR, sağduyu | 25,0 | 35,0 | **35,4** | **35,4** |
85
+ | TurBLiMP, dil bilgisi | 50,0 | 92,8 | **93,1** | 92,6 |
86
+ | **Ortalama** | | 43,0 | 43,6 | **43,9** |
87
+
88
+ Belebele, TurkishMMLU, ARC ve HellaSwag'de uzunluğa göre normalleştirilmiş doğruluk (acc_norm), XCOPA ve TurBLiMP'te doğruluk (acc) verilmiştir. Yedikule 202M Instruct, bir önceki talimat ayarlı sürümdür.
89
+
90
+ Yedikule 1.4 yedi ölçütün ortalamasında üç modelin en yükseğidir. En belirgin ilerleme okuduğunu anlamada (Belebele: temel modele göre 2,3, önceki sürüme göre 2,0 puan) ve zor fen sorularındadır (ARC zor: temel modele göre 4,4, önceki sürüme göre 2,0 puan); her ikisi de modelin metni okuyup soruya göre akıl yürütmesini gerektirir. Dil bilgisi (TurBLiMP yüzde 92,6) ve sağduyu (HellaSwag) korunmuştur: talimat ayarı modele yeni beceriler kazandırırken Türkçesine zarar vermemiştir. XCOPA, TurkishMMLU ve ARC kolaydaki farklar ölçüm belirsizliği sınırındadır. Bu tür bilgi ölçütlerinin sonucunu esas olarak ön eğitim belirler; 202 milyon parametrelik bir modelin geniş dünya bilgisi isteyen TurkishMMLU gibi ölçütlerde rastgele düzeye yakın kalması beklenen bir durumdur.
91
+
92
+ Talimat ayarının asıl kazancı bu ölçütlerin ölçmediği yerdedir: düşünme, talimat takibi ve araç kullanımı. Aşağıdaki sonuçlar, Marul-SFT-TR'nin eğitimde hiç kullanılmayan doğrulama sohbetlerinde, modelin ilk cevabı en olası tokenler seçilerek üretilip ölçüldü.
93
+
94
+ | Araç kullanımı | Sonuç |
95
+ |---|---:|
96
+ | Araç gereken durumlarda geçerli bir çağrı üretme (282 sohbet) | yüzde 89,7 |
97
+ | Doğru aracı seçme | yüzde 75,9 |
98
+ | Zorunlu parametreleri eksiksiz doldurma | yüzde 87,9 |
99
+ | Eğitimde hiç görülmemiş araç adlarında doğru aracı seçme (30 sohbet) | yüzde 73,3 |
100
+ | Araç gerekmeyen durumlarda araç çağırmama (159 sohbet) | yüzde 73,0 |
101
+
102
+ Önceki sürüm yalnızca eğitimde gördüğü 15 araçla güvenilir biçimde çalışabiliyordu. Yedikule 1.4 ise araçları adlarından değil açıklamalarından tanımayı öğrendi; eğitimde hiç görmediği araçlarla da çalışabiliyor.
103
+
104
+ Ölçütler: [Belebele](https://huggingface.co/datasets/facebook/belebele) (tur_Latn, okuduğunu anlama), [XCOPA](https://huggingface.co/datasets/cambridgeltl/xcopa) (tr, neden sonuç çıkarımı), [TurkishMMLU](https://huggingface.co/datasets/AYueksel/TurkishMMLU) (lise düzeyi bilgi), [ARC-TR](https://huggingface.co/datasets/malhajar/arc-tr) (fen soruları, kolay ve zor), [HellaSwag-TR](https://huggingface.co/datasets/malhajar/hellaswag_tr-v0.2) (sağduyu ile cümle tamamlama), [TurBLiMP](https://huggingface.co/datasets/juletxara/turblimp) (Türkçe dil bilgisi, 16 olguda 15.980 cümle çifti).
105
+
106
+ ## Eğitim verisi: Marul-SFT-TR
107
+
108
+ Yedikule 1.4'ün sohbet yeteneklerinin kaynağı, bu model için baştan Türkçe olarak tasarlanan [Marul-SFT-TR](https://huggingface.co/datasets/MarulAI/Marul-SFT-TR) veri setidir. Çeviri değildir; Türk kültürü, günlük hayat, kurumlar ve konuşma alışkanlıkları gözetilerek hazırlandı.
109
+
110
+ | | |
111
+ |---|---|
112
+ | Sohbet | 99.847 |
113
+ | Kategori ve görev türü | 18 kategori, 244 görev türü |
114
+ | Çok turlu sohbet | yüzde 85,7 |
115
+ | Farklı sistem mesajı | 55.208 |
116
+ | Araç tanımı içeren sohbet | 16.724 (9.571 farklı araç adı) |
117
+ | Araç çağrısı | 24.510 (ardışık ve paralel çağrılar dahil) |
118
+ | Düşünme metni olan asistan cevabı | yüzde 100 |
119
+
120
+ Her sohbet ayrıntılı bir tariften üretildi: görev türü, kategori, sistem mesajı, kullanıcı profili ve yazım tarzı, hedef uzunluk, tur sayısı ve araç görevlerinde o senaryoya özel araç tanımları. Ardından çok katmanlı bir kalite kontrolünden geçti: biçim, dil ve araç çağrısı kontrolleri, birbirine benzeyen sohbetlerin ayıklanması ve her sohbetin bağımsız bir hakem model tarafından olgusal doğruluk, hesap doğruluğu, talimata uyum, araç kullanımı ve Türkçenin doğallığı açısından tek tek incelenmesi. 231.718 üretim denemesinin yalnızca yaklaşık yüzde 43'ü bütün kontrolleri geçti. Veri setinin kendisi Apache 2.0 lisansıyla ayrıca yayımlanmıştır.
121
+
122
+ ## Eğitim
123
+
124
+ Model, [Yedikule 202M Base](https://huggingface.co/MarulAI/Yedikule-202M-Base) ağırlıklarından başlatılarak Marul-SFT-TR ile tam parametre ince ayarla eğitildi.
125
+
126
+ | | |
127
+ |---|---|
128
+ | Eğitim / doğrulama | 97.261 / 2.586 sohbet |
129
+ | Epoch | 2 (2.353 optimizer adımı) |
130
+ | Optimizer | AdamW, tepe öğrenme hızı 1,5e-4, kosinüs azalma |
131
+ | Kayıp | yalnızca asistan turları: düşünme, cevap, araç çağrısı ve `<\|im_end\|>` |
132
+ | Doğrulama kaybı | 3,577'den 1,672'ye |
133
+ | Biçim tokeni isabeti | yüzde 95 |
134
+
135
+ Talimat ayarı sırasında modelin genel Türkçe bilgisini kaybetmemesi için eğitime bir miktar düz Türkçe metin karıştırıldı. Eğitimden sonra, eğitimde hiç görülmeyen genel web metinlerinde ölçülen perplexity değişimi yalnızca yüzde 1,2 oldu; model yeni beceriler kazanırken dil bilgisini korudu.
136
+
137
+ ## Sohbet şablonu
138
+
139
+ Şablon eğitimde görülen biçimin birebir aynısıdır.
140
+
141
+ ```
142
+ <|bos|><|im_start|><|system|>
143
+ {sistem mesajı}<|im_end|>
144
+ <|im_start|><|user|>
145
+ {kullanıcı mesajı}<|im_end|>
146
+ <|im_start|><|assistant|>
147
+ <think>{düşünme}</think>
148
+ {cevap}<|im_end|>
149
+ ```
150
+
151
+ Standart ChatML değildir: rol adları düz metin değil, ayrı özel tokenlerdir. Sistem turu isteğe bağlıdır.
152
+
153
+ | Kimlik | Token | Anlamı |
154
+ |---:|---|---|
155
+ | 3 | `<\|bos\|>` | dizinin başı |
156
+ | 4 | `<\|im_start\|>` | tur başlangıcı |
157
+ | 5 | `<\|im_end\|>` | tur sonu, üretim burada durur |
158
+ | 6, 7, 8 | `<\|system\|>`, `<\|user\|>`, `<\|assistant\|>` | roller |
159
+ | 9 | `<think>` | düşünme başlangıcı |
160
+ | 10 | `</think>` | düşünme sonu |
161
+ | 11 | `<tool_call>` | araç çağrısı başlangıcı |
162
+ | 12 | `</tool_call>` | araç çağrısı sonu |
163
+ | 13 | `<\|tool\|>` | araç sonucu rolü |
164
+ | 14 | `<tools>` | araç tanımları başlangıcı |
165
+ | 15 | `</tools>` | araç tanımları sonu |
166
+
167
+ Token adları ve kimlikleri GGUF dosyasında da aynıdır. Taban modelin tokenizer'ında 9-15 kimlikleri `<|reserved_0|>` ile `<|reserved_6|>` arasındaki adlarla durur. Kimlikler aynı olduğu için iki tokenizer metni aynı token dizisine çevirir: talimat verisinin tamamında (99.847 sohbet, 83,4 milyon token) ve düz Türkçe metinde sonuç birebir aynıdır. Taban modelden ince ayar yaparken bu tokenizer'ı doğrudan kullanabilirsiniz.
168
+
169
+ Üretimi `<|im_end|>` (5) tokeninde durdurun. İstemi her zaman `<|im_start|><|assistant|>\n` ile bitirin; model cevabına kendiliğinden düşünme bloğuyla başlar. Çok turlu sohbetlerde önceki asistan turlarını düşünmeleriyle birlikte geçmişe ekleyin; model eğitimde bu biçimi gördü. Aynı bilgiler `chat_format.json` dosyasında da bulunur.
170
+
171
+ ### Araç çağırma biçimi
172
+
173
+ Araç tanımları sistem turunun sonuna, her biri tek satırlık ve boşluksuz bir JSON olarak eklenir:
174
+
175
+ ```
176
+ <|im_start|><|system|>
177
+ {sistem mesajı}
178
+
179
+ <tools>
180
+ {"name":"hava_durumu","description":"Bir şehrin hava tahminini getirir.","parameters":{"sehir":{"type":"string","description":"Şehir adı"},"gun":{"type":"integer","description":"Kaç gün sonrası (0 = bugün, 1 = yarın)"}},"required":["sehir"]}
181
+ </tools><|im_end|>
182
+ ```
183
+
184
+ `parameters` alanı yalnızca özellikleri içerir; zorunlu alanlar `required` listesinde verilir, liste boşsa yazılmaz. Model bir araç çağırmak istediğinde cevabının sonuna şunu yazar:
185
+
186
+ ```
187
+ <tool_call>{"name":"hava_durumu","arguments":{"sehir":"İzmir","gun":1}}</tool_call><|im_end|>
188
+ ```
189
+
190
+ Aracı çalıştırıp sonucunu ayrı bir turda verin, ardından modelden devam etmesini isteyin:
191
+
192
+ ```
193
+ <|im_start|><|tool|>
194
+ {"sehir":"İzmir","durum":"parçalı bulutlu","en_yuksek":27,"en_dusuk":19}<|im_end|>
195
+ <|im_start|><|assistant|>
196
+ ```
197
+
198
+ Bir turda birden fazla çağrı art arda yazılabilir; sonuçlar çağrılarla aynı sırada, her biri ayrı bir araç turunda verilir.
199
+
200
+ ## Kullanım
201
+
202
+ ```bash
203
+ pip install torch tokenizers safetensors
204
+ ```
205
+
206
+ Dosyaları indirdiğiniz klasörde çalıştırın; `model.py` ve `config.py` modelin kendi mimari dosyalarıdır.
207
+
208
+ ```python
209
+ import json
210
+ import re
211
+
212
+ import torch
213
+ from safetensors.torch import load_file
214
+ from tokenizers import Tokenizer
215
+
216
+ from config import ModelConfig
217
+ from model import MarulLLM
218
+
219
+ cfg = ModelConfig.load("model_config.json")
220
+ model = MarulLLM(cfg)
221
+ model.load_state_dict({k: v.float() for k, v in load_file("model.safetensors").items()})
222
+ device = "cuda" if torch.cuda.is_available() else "cpu"
223
+ model.eval().to(device)
224
+ tok = Tokenizer.from_file("tokenizer.json")
225
+
226
+ THINK, THINK_END = "<think>", "</think>"
227
+ CALL, CALL_END = "<tool_call>", "</tool_call>"
228
+ TOOL, TOOLS, TOOLS_END = "<|tool|>", "<tools>", "</tools>"
229
+
230
+
231
+ def compact(obj):
232
+ return json.dumps(obj, ensure_ascii=False, separators=(",", ":"))
233
+
234
+
235
+ def tool_line(tool):
236
+ """OpenAI biçimindeki araç tanımını modelin eğitimde gördüğü tek satırlık biçime çevirir."""
237
+ f = tool.get("function", tool)
238
+ p = f.get("parameters") or {}
239
+ d = {"name": f["name"], "description": f.get("description", ""), "parameters": p.get("properties", {})}
240
+ if p.get("required"):
241
+ d["required"] = p["required"]
242
+ return compact(d)
243
+
244
+
245
+ def build_prompt(messages, tools=None):
246
+ system = None
247
+ if messages and messages[0]["role"] == "system":
248
+ system, messages = messages[0]["content"].strip(), messages[1:]
249
+ parts = [system] if system else []
250
+ if tools:
251
+ parts.append(TOOLS + "\n" + "\n".join(tool_line(t) for t in tools) + "\n" + TOOLS_END)
252
+ s = "<|bos|>"
253
+ if parts:
254
+ s += "<|im_start|><|system|>\n" + "\n\n".join(parts) + "<|im_end|>\n"
255
+ for m in messages:
256
+ if m["role"] == "assistant":
257
+ calls = "".join(CALL + compact({"name": c["name"], "arguments": c["arguments"]}) + CALL_END
258
+ for c in m.get("tool_calls", []))
259
+ s += ("<|im_start|><|assistant|>\n" + THINK + m.get("reasoning", "").strip() + THINK_END + "\n"
260
+ + m.get("content", "").strip() + calls + "<|im_end|>\n")
261
+ elif m["role"] == "tool":
262
+ s += "<|im_start|>" + TOOL + "\n" + m["content"].strip() + "<|im_end|>\n"
263
+ else:
264
+ s += "<|im_start|><|user|>\n" + m["content"].strip() + "<|im_end|>\n"
265
+ return s + "<|im_start|><|assistant|>\n"
266
+
267
+
268
+ def chat(messages, tools=None, max_new_tokens=600):
269
+ ids = tok.encode(build_prompt(messages, tools), add_special_tokens=False).ids
270
+ out = model.generate(torch.tensor([ids], device=device), max_new_tokens=max_new_tokens,
271
+ temperature=0.4, top_k=50, top_p=0.9, min_p=0.05,
272
+ repetition_penalty=1.12, no_repeat_ngram_size=0, eos_token_id=5)
273
+ text = tok.decode(out[0, len(ids):].tolist(), skip_special_tokens=False).split("<|im_end|>")[0]
274
+ reasoning, _, rest = text.partition(THINK_END)
275
+ calls = [json.loads(c) for c in re.findall(re.escape(CALL) + "(.*?)" + re.escape(CALL_END), rest, re.S)]
276
+ content = re.sub(re.escape(CALL) + ".*?" + re.escape(CALL_END), "", rest, flags=re.S).strip()
277
+ return {"role": "assistant", "reasoning": reasoning.replace(THINK, "").strip(), "content": content,
278
+ "tool_calls": calls}
279
+
280
+
281
+ torch.manual_seed(0)
282
+ messages = [
283
+ {"role": "system", "content": "Adın Yedikule. Marul AI tarafından Türkçe için geliştirilmiş bir yapay zeka "
284
+ "asistanısın. Kullanıcılara yardım ederken açık, doğru ve nazik ol."},
285
+ {"role": "user", "content": "Fotosentezi kısaca anlatır mısın?"},
286
+ ]
287
+ reply = chat(messages)
288
+ print(reply["reasoning"]) # düşünme
289
+ print(reply["content"]) # cevap
290
+
291
+ # Araç çağırma
292
+ tools = [{"type": "function", "function": {
293
+ "name": "hava_durumu",
294
+ "description": "Bir şehrin hava tahminini getirir.",
295
+ "parameters": {"type": "object",
296
+ "properties": {"sehir": {"type": "string", "description": "Şehir adı"},
297
+ "gun": {"type": "integer", "description": "Kaç gün sonrası (0 = bugün, 1 = yarın)"}},
298
+ "required": ["sehir"]}}}]
299
+ messages = [{"role": "user", "content": "Yarın İzmir'de hava nasıl olacak?"}]
300
+ reply = chat(messages, tools)
301
+ print(reply["tool_calls"])
302
+
303
+ result = {"sehir": "İzmir", "durum": "parçalı bulutlu", "en_yuksek": 27, "en_dusuk": 19}
304
+ messages += [reply, {"role": "tool", "content": compact(result)}]
305
+ print(chat(messages, tools)["content"])
306
+ ```
307
+
308
+ `build_prompt` eğitimdeki sohbet biçimini birebir üretir; `chat` cevabı düşünme, metin ve araç çağrıları olarak ayırır. Araç sonucunu `{"role": "tool", ...}` mesajıyla geçmişe ekleyip `chat`'i yeniden çağırdığınızda model sonucu kullanarak cevabını yazar. `model.generate` önbelleksiz çalışır; daha hızlı ve hafif kullanım için [GGUF sürümünü](https://huggingface.co/MarulAI/Yedikule-1.4-GGUF) llama.cpp veya Ollama ile çalıştırabilirsiniz.
309
+
310
+ ## Önerilen üretim ayarları
311
+
312
+ Önerilen değerler `generation_config.json` dosyasındadır:
313
+
314
+ | Ayar | Değer |
315
+ |---|---|
316
+ | temperature | 0,4 |
317
+ | top_k | 50 |
318
+ | top_p | 0,9 |
319
+ | min_p | 0,05 |
320
+ | repetition_penalty | 1,12 |
321
+ | no_repeat_ngram_size | 0 |
322
+ | max_new_tokens | 1024 |
323
+
324
+ Bu değerler; şablon metinler (e-posta, dilekçe, liste gibi), genel sorular ve araç çağırma görevlerinden oluşan bir ölçümle, altı farklı ayar karşılaştırılarak seçildi. Önceki sürümün ayarlarına (temperature 0,3, repetition_penalty 1,08) göre tekrar döngüsüne girme oranı yüzde 6,2'den yüzde 2,5'e indi; araç çağırma doğruluğu korundu.
325
+
326
+ Daha olgusal ve tutarlı cevaplar için sıcaklığı 0,3'e indirebilir, daha yaratıcı metinler için 0,6'ya kadar çıkarabilirsiniz. Tekrar cezasını 1,15'in üzerine çıkarmayın: Türkçe ekleri bozmaya başlar ve gereksiz araç çağrılarını artırır. `no_repeat_ngram_size` kapalı kalmalıdır; açık olduğunda model araç adlarını ve JSON yapılarını istemden kopyalayamaz.
327
+
328
+ ## Sistem mesajı
329
+
330
+ Model 55 binden fazla farklı sistem mesajıyla eğitildi; kendi sistem mesajınızı rahatlıkla yazabilirsiniz. Genel bir asistan için şu metin iyi bir başlangıçtır:
331
+
332
+ ```
333
+ Adın Yedikule. Marul AI tarafından Türkçe için geliştirilmiş bir yapay zeka asistanısın. Kullanıcılara yardım ederken açık, doğru ve nazik ol.
334
+ ```
335
+
336
+ Sistem mesajı vermeden de kullanılabilir; eğitim sohbetlerinin yaklaşık beşte biri sistem mesajı içermiyordu.
337
+
338
+ ## Mimari
339
+
340
+ - 24 katman, 768 gizli boyut, 2304 ara boyut
341
+ - Grouped Query Attention: 12 sorgu başlığı, 4 anahtar/değer başlığı, başlık boyutu 64
342
+ - Pre-norm RMSNorm, RoPE (theta 10000), SwiGLU
343
+ - Başlık boyutunda QK-Norm, RoPE'den önce uygulanır
344
+ - Bağlı giriş ve çıkış gömmeleri, hiçbir katmanda bias yok
345
+ - Tokenizer: Türkçe için eğitilmiş 48 bin tokenlik Byte-Level BPE
346
+
347
+ Mimari `model.py` içinde tanımlıdır; torch dışında bağımlılığı yoktur.
348
+
349
+ ## Sınırlar
350
+
351
+ Yedikule 1.4 202 milyon parametrelik küç��k bir modeldir. Günlük sohbet, açıklama, özetleme, metin düzeltme, yazım ve araçlarla çalışma gibi işlerde iyi sonuç verir; geniş dünya bilgisi isteyen sorularda ve çok adımlı aritmetikte hata yapabilir. Hesap gerektiren işlerde ona bir hesap makinesi aracı vermek doğruluğu belirgin biçimde artırır. Çok kurallı ve uzun sistem mesajlarındaki her ayrıntıyı (örneğin bir fiyat listesinin tamamını) her zaman doğru kullanamayabilir; kritik bilgileri kısa ve açık yazın. Bilgisi 2026 yılına kadardır ve internete erişimi yoktur.
352
+
353
+ Model yanlış veya eksik bilgi üretebilir. Ürettiği bilgiyi doğrulamadan kullanmayın; tıbbi, hukuki, finansal veya güvenlik açısından kritik kararlarda tek başına kullanmayın.
354
+
355
+ ## Dosyalar
356
+
357
+ | Dosya | İçerik |
358
+ |---|---|
359
+ | `model.safetensors` | bf16 ağırlıklar, 404 MB |
360
+ | `model.py` | model mimarisi |
361
+ | `config.py` | `ModelConfig` veri sınıfı |
362
+ | `model_config.json` | mimari parametreleri |
363
+ | `tokenizer.json` | 48 bin tokenlik Byte-Level BPE |
364
+ | `tokenizer_config.json` | tokenizer meta bilgisi |
365
+ | `tokenizer_info.json` | özel tokenler ve tokenizasyon örnekleri |
366
+ | `chat_format.json` | sohbet şablonu ve özel tokenlerin anlamları |
367
+ | `generation_config.json` | önerilen üretim ayarları |
368
+ | `LICENSE.md` | lisans tam metni |
369
+
370
+ ## Lisans
371
+
372
+ Yedikule Model Lisansı 2.0. Telif hakkı sahibi Ahmet Karakuş (Marul AI). Bağlayıcı metin `LICENSE.md` dosyasındadır.
373
+
374
+ İzin almadan yapabilecekleriniz: modeli çalıştırmak, eğitim ve araştırmada kullanmak, üzerine ince ayar yapmak, damıtmak, birleştirmek, nicelemek, başka biçimlere çevirmek ve sonucu yayımlamak. Hepsi ticari olmayan kullanımla sınırlıdır.
375
+
376
+ Uymanız gerekenler: Yedikule'ye atıf yapmak, türev modelinizin adında **Yedikule** geçirmek, lisansı model ile birlikte dağıtmak ve telif bilgisini korumak.
377
+
378
+ **Türevler de bu lisansa tabidir.** Modelden türettiğiniz her çalışma aynı koşullara bağlı kalır; kendi lisansınızla yeniden lisanslayamazsınız. Türev modeli siz eğitmiş olsanız bile ticari kullanımı izne bağlıdır.
379
+
380
+ Ticari kullanım yazılı izne bağlıdır. Ticari lisans ve izin talepleri: **marulai.resmi@gmail.com** (Ahmet Karakuş, Marul AI)
381
+
382
+ ## Atıf
383
+
384
+ ```
385
+ Bu çalışma Yedikule modeline dayanmaktadır.
386
+ Yedikule, 202M parametreli Türkçe dil modeli.
387
+ Ahmet Karakuş, Marul AI, 2026.
388
+ https://huggingface.co/MarulAI/Yedikule-1.4
389
+ ```
390
+
391
+ Eğitim verisi:
392
+
393
+ ```
394
+ Marul-SFT-TR, Ahmet Karakuş (Marul AI), 2026.
395
+ https://huggingface.co/datasets/MarulAI/Marul-SFT-TR
396
+ ```
chat_format.json ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "aciklama": "Yedikule 1.4 sohbet biçimi. Kimlikler ve adlar tokenizer.json ve GGUF dosyasıyla aynıdır. 9-15 kimlikli tokenler taban modelin (Yedikule-202M-Base) tokenizer'ında <|reserved_0|> ile <|reserved_6|> arasındaki adlarla durur; kimlikler aynıdır.",
3
+ "ozel_tokenler": {
4
+ "<|endoftext|>": {
5
+ "kimlik": 0,
6
+ "anlam": "metin sonu"
7
+ },
8
+ "<|pad|>": {
9
+ "kimlik": 1,
10
+ "anlam": "dolgu"
11
+ },
12
+ "<|unk|>": {
13
+ "kimlik": 2,
14
+ "anlam": "bilinmeyen"
15
+ },
16
+ "<|bos|>": {
17
+ "kimlik": 3,
18
+ "anlam": "dizinin başı, her istemin ilk tokeni"
19
+ },
20
+ "<|im_start|>": {
21
+ "kimlik": 4,
22
+ "anlam": "tur başlangıcı"
23
+ },
24
+ "<|im_end|>": {
25
+ "kimlik": 5,
26
+ "anlam": "tur sonu, üretim burada durdurulur"
27
+ },
28
+ "<|system|>": {
29
+ "kimlik": 6,
30
+ "anlam": "sistem rolü"
31
+ },
32
+ "<|user|>": {
33
+ "kimlik": 7,
34
+ "anlam": "kullanıcı rolü"
35
+ },
36
+ "<|assistant|>": {
37
+ "kimlik": 8,
38
+ "anlam": "asistan rolü"
39
+ },
40
+ "<think>": {
41
+ "kimlik": 9,
42
+ "anlam": "düşünme başlangıcı"
43
+ },
44
+ "</think>": {
45
+ "kimlik": 10,
46
+ "anlam": "düşünme sonu"
47
+ },
48
+ "<tool_call>": {
49
+ "kimlik": 11,
50
+ "anlam": "araç çağrısı başlangıcı"
51
+ },
52
+ "</tool_call>": {
53
+ "kimlik": 12,
54
+ "anlam": "araç çağrısı sonu"
55
+ },
56
+ "<|tool|>": {
57
+ "kimlik": 13,
58
+ "anlam": "araç sonucu rolü"
59
+ },
60
+ "<tools>": {
61
+ "kimlik": 14,
62
+ "anlam": "araç tanımları başlangıcı"
63
+ },
64
+ "</tools>": {
65
+ "kimlik": 15,
66
+ "anlam": "araç tanımları sonu"
67
+ }
68
+ },
69
+ "sablon": {
70
+ "sistem": "<|im_start|><|system|>\n{sistem mesajı}\n\n<tools>\n{araç tanımı, satır başına bir}\n</tools><|im_end|>\n",
71
+ "kullanici": "<|im_start|><|user|>\n{mesaj}<|im_end|>\n",
72
+ "asistan": "<|im_start|><|assistant|>\n<think>{düşünme}</think>\n{cevap}<tool_call>{araç çağrısı JSON}</tool_call><|im_end|>\n",
73
+ "arac_sonucu": "<|im_start|><|tool|>\n{araç sonucu}<|im_end|>\n",
74
+ "uretim_istemi": "<|im_start|><|assistant|>\n"
75
+ },
76
+ "kurallar": [
77
+ "İstem <|bos|> ile başlar.",
78
+ "Sistem turu isteğe bağlıdır. Araç verilmişse ve sistem mesajı yoksa, sistem turu yalnızca araç tanımlarını içerir.",
79
+ "Araç tanımı tek satırlık, boşluksuz JSON'dur: {\"name\":...,\"description\":...,\"parameters\":{özellikler},\"required\":[...]}. required boşsa yazılmaz.",
80
+ "Araç çağrısı boşluksuz JSON'dur: {\"name\":...,\"arguments\":{...}}. Bir turda birden fazla çağrı art arda yazılabilir.",
81
+ "Asistan her turda önce düşünür. Çok turlu sohbetlerde önceki asistan turlarının düşünmelerini de geçmişe ekleyin.",
82
+ "Üretimi <|im_end|> (5) tokeninde durdurun."
83
+ ],
84
+ "stop_token_id": 5,
85
+ "prompt_suffix": "<|im_start|><|assistant|>\n",
86
+ "prompt_suffix_ids": [
87
+ 4,
88
+ 8,
89
+ 214
90
+ ]
91
+ }
config.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ import json
6
+
7
+
8
+ @dataclass
9
+ class ModelConfig:
10
+ vocab_size: int = 48000
11
+ max_seq_len: int = 2048
12
+
13
+ hidden_size: int = 768
14
+ intermediate_size: int = 2304
15
+ num_layers: int = 24
16
+ num_heads: int = 12
17
+ num_kv_heads: int = 4
18
+
19
+ rope_theta: float = 10_000.0
20
+
21
+ rms_norm_eps: float = 1.0e-5
22
+ qk_norm: bool = True
23
+
24
+ initializer_range: float = 0.02
25
+
26
+ eos_token_id: int = 0
27
+ pad_token_id: int = 1
28
+ bos_token_id: int = 3
29
+
30
+ tie_word_embeddings: bool = True
31
+
32
+ z_loss_coef: float = 1.0e-4
33
+ attn_dropout: float = 0.0
34
+ resid_dropout: float = 0.0
35
+
36
+ @property
37
+ def head_dim(self) -> int:
38
+ assert self.hidden_size % self.num_heads == 0
39
+ return self.hidden_size // self.num_heads
40
+
41
+ @property
42
+ def kv_groups(self) -> int:
43
+ assert self.num_heads % self.num_kv_heads == 0
44
+ return self.num_heads // self.num_kv_heads
45
+
46
+ @classmethod
47
+ def load(cls, path: str | Path) -> "ModelConfig":
48
+ d = json.loads(Path(path).read_text(encoding="utf-8"))
49
+ valid = {f for f in cls.__dataclass_fields__}
50
+ return cls(**{k: v for k, v in d.items() if k in valid})
generation_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 3,
3
+ "eos_token_id": 5,
4
+ "pad_token_id": 1,
5
+ "do_sample": true,
6
+ "temperature": 0.4,
7
+ "top_k": 50,
8
+ "top_p": 0.9,
9
+ "min_p": 0.05,
10
+ "repetition_penalty": 1.12,
11
+ "no_repeat_ngram_size": 0,
12
+ "max_new_tokens": 1024
13
+ }
model.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from torch import Tensor
9
+
10
+ from config import ModelConfig
11
+
12
+
13
+ class RMSNorm(nn.Module):
14
+ def __init__(self, dim: int, eps: float = 1.0e-5):
15
+ super().__init__()
16
+ self.weight = nn.Parameter(torch.ones(dim))
17
+ self.eps = eps
18
+
19
+ def forward(self, x: Tensor) -> Tensor:
20
+ dtype = x.dtype
21
+ x32 = x.float()
22
+ rms = x32.pow(2).mean(dim=-1, keepdim=True).add_(self.eps).rsqrt_()
23
+ out = (x32 * rms).to(dtype)
24
+ return out * self.weight.to(dtype)
25
+
26
+
27
+ class RotaryEmbedding(nn.Module):
28
+ def __init__(self, head_dim: int, max_seq_len: int, theta: float = 10_000.0):
29
+ super().__init__()
30
+ self.head_dim = head_dim
31
+ self.max_seq_len = max_seq_len
32
+ self.theta = theta
33
+ self._cached_len: int = 0
34
+ self._cos_cache: Optional[Tensor] = None
35
+ self._sin_cache: Optional[Tensor] = None
36
+
37
+ def _build_cache(self, seq_len: int, device, dtype):
38
+ inv_freq = 1.0 / (
39
+ self.theta ** (torch.arange(0, self.head_dim, 2, dtype=torch.float32, device=device) / self.head_dim)
40
+ )
41
+ t = torch.arange(seq_len, dtype=torch.float32, device=device)
42
+ freqs = torch.outer(t, inv_freq)
43
+ emb = torch.cat([freqs, freqs], dim=-1)
44
+ self._cos_cache = emb.cos().to(dtype)
45
+ self._sin_cache = emb.sin().to(dtype)
46
+ self._cached_len = seq_len
47
+
48
+ def forward(self, seq_len: int, device, dtype) -> tuple[Tensor, Tensor]:
49
+ if (
50
+ self._cos_cache is None
51
+ or seq_len > self._cached_len
52
+ or self._cos_cache.device != device
53
+ or self._cos_cache.dtype != dtype
54
+ ):
55
+ self._build_cache(max(seq_len, self.max_seq_len), device, dtype)
56
+ return self._cos_cache[:seq_len], self._sin_cache[:seq_len]
57
+
58
+
59
+ def _rotate_half(x: Tensor) -> Tensor:
60
+ x1, x2 = x.chunk(2, dim=-1)
61
+ return torch.cat([-x2, x1], dim=-1)
62
+
63
+
64
+ def apply_rope(q: Tensor, k: Tensor, cos: Tensor, sin: Tensor) -> tuple[Tensor, Tensor]:
65
+ cos = cos.unsqueeze(0).unsqueeze(0)
66
+ sin = sin.unsqueeze(0).unsqueeze(0)
67
+ q_rot = (q * cos) + (_rotate_half(q) * sin)
68
+ k_rot = (k * cos) + (_rotate_half(k) * sin)
69
+ return q_rot, k_rot
70
+
71
+
72
+ class Attention(nn.Module):
73
+ def __init__(self, cfg: ModelConfig, layer_idx: int):
74
+ super().__init__()
75
+ self.cfg = cfg
76
+ self.layer_idx = layer_idx
77
+ self.num_heads = cfg.num_heads
78
+ self.num_kv_heads = cfg.num_kv_heads
79
+ self.head_dim = cfg.head_dim
80
+ self.kv_groups = cfg.kv_groups
81
+ self.scale = self.head_dim ** -0.5
82
+
83
+ h, hd = cfg.hidden_size, self.head_dim
84
+ self.q_proj = nn.Linear(h, self.num_heads * hd, bias=False)
85
+ self.k_proj = nn.Linear(h, self.num_kv_heads * hd, bias=False)
86
+ self.v_proj = nn.Linear(h, self.num_kv_heads * hd, bias=False)
87
+ self.o_proj = nn.Linear(self.num_heads * hd, h, bias=False)
88
+
89
+ if cfg.qk_norm:
90
+ self.q_norm = RMSNorm(hd, eps=cfg.rms_norm_eps)
91
+ self.k_norm = RMSNorm(hd, eps=cfg.rms_norm_eps)
92
+ else:
93
+ self.q_norm = nn.Identity()
94
+ self.k_norm = nn.Identity()
95
+
96
+ self.attn_dropout = cfg.attn_dropout
97
+
98
+ def forward(self, x: Tensor, cos: Tensor, sin: Tensor) -> Tensor:
99
+ B, S, _ = x.shape
100
+ q = self.q_proj(x).view(B, S, self.num_heads, self.head_dim)
101
+ k = self.k_proj(x).view(B, S, self.num_kv_heads, self.head_dim)
102
+ v = self.v_proj(x).view(B, S, self.num_kv_heads, self.head_dim)
103
+
104
+ q = self.q_norm(q)
105
+ k = self.k_norm(k)
106
+
107
+ q = q.transpose(1, 2)
108
+ k = k.transpose(1, 2)
109
+ v = v.transpose(1, 2)
110
+
111
+ q, k = apply_rope(q, k, cos, sin)
112
+
113
+ if self.kv_groups > 1:
114
+ k = k.repeat_interleave(self.kv_groups, dim=1)
115
+ v = v.repeat_interleave(self.kv_groups, dim=1)
116
+
117
+ out = F.scaled_dot_product_attention(
118
+ q, k, v,
119
+ attn_mask=None,
120
+ dropout_p=self.attn_dropout if self.training else 0.0,
121
+ is_causal=True,
122
+ )
123
+ out = out.transpose(1, 2).contiguous().view(B, S, self.num_heads * self.head_dim)
124
+ return self.o_proj(out)
125
+
126
+
127
+ class SwiGLU(nn.Module):
128
+ def __init__(self, cfg: ModelConfig):
129
+ super().__init__()
130
+ h, i = cfg.hidden_size, cfg.intermediate_size
131
+ self.gate_proj = nn.Linear(h, i, bias=False)
132
+ self.up_proj = nn.Linear(h, i, bias=False)
133
+ self.down_proj = nn.Linear(i, h, bias=False)
134
+
135
+ def forward(self, x: Tensor) -> Tensor:
136
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
137
+
138
+
139
+ class Block(nn.Module):
140
+ def __init__(self, cfg: ModelConfig, layer_idx: int):
141
+ super().__init__()
142
+ self.input_norm = RMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
143
+ self.attn = Attention(cfg, layer_idx)
144
+ self.post_attn_norm = RMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
145
+ self.mlp = SwiGLU(cfg)
146
+ self.resid_drop = nn.Dropout(cfg.resid_dropout) if cfg.resid_dropout > 0 else nn.Identity()
147
+
148
+ def forward(self, x: Tensor, cos: Tensor, sin: Tensor) -> Tensor:
149
+ x = x + self.resid_drop(self.attn(self.input_norm(x), cos, sin))
150
+ x = x + self.resid_drop(self.mlp(self.post_attn_norm(x)))
151
+ return x
152
+
153
+
154
+ class MarulLLM(nn.Module):
155
+ def __init__(self, cfg: ModelConfig):
156
+ super().__init__()
157
+ self.cfg = cfg
158
+
159
+ self.embed_tokens = nn.Embedding(cfg.vocab_size, cfg.hidden_size)
160
+ self.rotary = RotaryEmbedding(cfg.head_dim, cfg.max_seq_len, cfg.rope_theta)
161
+ self.layers = nn.ModuleList(Block(cfg, i) for i in range(cfg.num_layers))
162
+ self.final_norm = RMSNorm(cfg.hidden_size, cfg.rms_norm_eps)
163
+
164
+ if cfg.tie_word_embeddings:
165
+ self.lm_head = None
166
+ else:
167
+ self.lm_head = nn.Linear(cfg.hidden_size, cfg.vocab_size, bias=False)
168
+
169
+ self.apply(self._init_weights)
170
+ self._scale_residual_inits()
171
+
172
+ self.num_params = sum(p.numel() for p in self.parameters())
173
+ self.num_params_trainable = sum(p.numel() for p in self.parameters() if p.requires_grad)
174
+ embed_params = cfg.vocab_size * cfg.hidden_size
175
+ self.num_params_non_embed = self.num_params - embed_params
176
+
177
+ def _init_weights(self, module: nn.Module) -> None:
178
+ std = self.cfg.initializer_range
179
+ if isinstance(module, nn.Linear):
180
+ nn.init.normal_(module.weight, mean=0.0, std=std)
181
+ if module.bias is not None:
182
+ nn.init.zeros_(module.bias)
183
+ elif isinstance(module, nn.Embedding):
184
+ nn.init.normal_(module.weight, mean=0.0, std=std)
185
+
186
+ def _scale_residual_inits(self) -> None:
187
+ scale = (2 * self.cfg.num_layers) ** -0.5
188
+ with torch.no_grad():
189
+ for block in self.layers:
190
+ block.attn.o_proj.weight.mul_(scale)
191
+ block.mlp.down_proj.weight.mul_(scale)
192
+
193
+ def forward(
194
+ self,
195
+ input_ids: Tensor,
196
+ targets: Optional[Tensor] = None,
197
+ return_logits: bool = True,
198
+ ) -> tuple[Optional[Tensor], Optional[Tensor]]:
199
+ B, S = input_ids.shape
200
+ assert S <= self.cfg.max_seq_len, (
201
+ f"dizi uzunluğu {S}, modelin bağlam sınırı {self.cfg.max_seq_len}")
202
+
203
+ x = self.embed_tokens(input_ids)
204
+ cos, sin = self.rotary(S, x.device, x.dtype)
205
+
206
+ for block in self.layers:
207
+ x = block(x, cos, sin)
208
+ x = self.final_norm(x)
209
+
210
+ if self.cfg.tie_word_embeddings:
211
+ logits = F.linear(x, self.embed_tokens.weight)
212
+ else:
213
+ logits = self.lm_head(x)
214
+
215
+ loss: Optional[Tensor] = None
216
+ if targets is not None:
217
+ flat_logits = logits.view(-1, logits.size(-1))
218
+ flat_targets = targets.view(-1)
219
+ ce = F.cross_entropy(
220
+ flat_logits, flat_targets, ignore_index=-100, reduction="mean"
221
+ )
222
+ loss = ce
223
+ if self.cfg.z_loss_coef > 0:
224
+ mask = flat_targets != -100
225
+ lse = torch.logsumexp(flat_logits, dim=-1)
226
+ if mask.any():
227
+ z = (lse[mask].float().pow(2)).mean()
228
+ loss = loss + self.cfg.z_loss_coef * z
229
+
230
+ if not return_logits and targets is not None:
231
+ logits = None
232
+ return logits, loss
233
+
234
+ @torch.no_grad()
235
+ def generate(
236
+ self,
237
+ input_ids: Tensor,
238
+ max_new_tokens: int = 128,
239
+ temperature: float = 0.6,
240
+ top_k: int = 40,
241
+ top_p: float = 0.88,
242
+ repetition_penalty: float = 1.20,
243
+ no_repeat_ngram_size: int = 4,
244
+ min_p: float = 0.05,
245
+ eos_token_id: Optional[int] = None,
246
+ ) -> Tensor:
247
+ self.eval()
248
+ eos = eos_token_id if eos_token_id is not None else self.cfg.eos_token_id
249
+ out = input_ids.clone()
250
+ device = out.device
251
+
252
+ for _ in range(max_new_tokens):
253
+ ctx = out[:, -self.cfg.max_seq_len:]
254
+ logits, _ = self.forward(ctx)
255
+ logits = logits[:, -1, :].float()
256
+
257
+ if repetition_penalty is not None and repetition_penalty != 1.0:
258
+ for b in range(out.size(0)):
259
+ seen = torch.unique(out[b])
260
+ vals = logits[b, seen]
261
+ logits[b, seen] = torch.where(
262
+ vals > 0, vals / repetition_penalty, vals * repetition_penalty
263
+ )
264
+
265
+ if no_repeat_ngram_size and no_repeat_ngram_size > 0:
266
+ n = no_repeat_ngram_size
267
+ if out.size(1) >= n - 1:
268
+ for b in range(out.size(0)):
269
+ seq = out[b].tolist()
270
+ ngrams: dict = {}
271
+ for i in range(len(seq) - n + 1):
272
+ prefix = tuple(seq[i : i + n - 1])
273
+ ngrams.setdefault(prefix, set()).add(seq[i + n - 1])
274
+ curr = tuple(seq[-(n - 1):])
275
+ if curr in ngrams:
276
+ banned = torch.tensor(list(ngrams[curr]), device=device, dtype=torch.long)
277
+ logits[b, banned] = float("-inf")
278
+
279
+ if temperature is not None and temperature != 1.0:
280
+ logits = logits / max(temperature, 1.0e-6)
281
+
282
+ if top_k is not None and top_k > 0:
283
+ v, _ = torch.topk(logits, k=min(top_k, logits.size(-1)))
284
+ logits[logits < v[:, -1:]] = float("-inf")
285
+
286
+ if min_p is not None and min_p > 0.0:
287
+ probs_tmp = F.softmax(logits, dim=-1)
288
+ max_probs, _ = probs_tmp.max(dim=-1, keepdim=True)
289
+ logits = logits.masked_fill(probs_tmp < (max_probs * min_p), float("-inf"))
290
+
291
+ if top_p is not None and 0.0 < top_p < 1.0:
292
+ sorted_logits, sorted_idx = torch.sort(logits, descending=True, dim=-1)
293
+ probs = F.softmax(sorted_logits, dim=-1)
294
+ cumprobs = probs.cumsum(dim=-1)
295
+ mask = cumprobs > top_p
296
+ mask[..., 1:] = mask[..., :-1].clone()
297
+ mask[..., 0] = False
298
+ sorted_logits = sorted_logits.masked_fill(mask, float("-inf"))
299
+ logits = torch.full_like(logits, float("-inf")).scatter(-1, sorted_idx, sorted_logits)
300
+
301
+ probs = F.softmax(logits, dim=-1)
302
+ next_token = torch.multinomial(probs, num_samples=1)
303
+ out = torch.cat([out, next_token], dim=1)
304
+
305
+ if eos is not None and (next_token == eos).all():
306
+ break
307
+ return out
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6adb029e2780130dc227eb49a443f8cddde5c593636c922e8bb2c7aa880605ae
3
+ size 404137888
model_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "vocab_size": 48000,
3
+ "max_seq_len": 2048,
4
+ "hidden_size": 768,
5
+ "intermediate_size": 2304,
6
+ "num_layers": 24,
7
+ "num_heads": 12,
8
+ "num_kv_heads": 4,
9
+ "rope_theta": 10000.0,
10
+ "rms_norm_eps": 1e-05,
11
+ "qk_norm": true,
12
+ "tie_word_embeddings": true,
13
+ "bos_token_id": 3,
14
+ "eos_token_id": 5,
15
+ "pad_token_id": 1
16
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|bos|>",
4
+ "eos_token": "<|endoftext|>",
5
+ "extra_special_tokens": [
6
+ "<|im_start|>",
7
+ "<|im_end|>",
8
+ "<|system|>",
9
+ "<|user|>",
10
+ "<|assistant|>"
11
+ ],
12
+ "model_max_length": 2048,
13
+ "pad_token": "<|pad|>",
14
+ "tokenizer_class": "TokenizersBackend",
15
+ "unk_token": "<|unk|>"
16
+ }
tokenizer_info.json ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tur": "Byte-Level BPE",
3
+ "sozluk_boyutu": 48000,
4
+ "dil": "tr",
5
+ "kucuk_harfe_cevirir_mi": false,
6
+ "normalizasyon": "NFC",
7
+ "on_bolumleyici": "ByteLevel(add_prefix_space=False, use_regex=True)",
8
+ "cozucu": "ByteLevel",
9
+ "son_islemci": "ByteLevel(trim_offsets=False)",
10
+ "ozel_tokenler": {
11
+ "<|endoftext|>": 0,
12
+ "<|pad|>": 1,
13
+ "<|unk|>": 2,
14
+ "<|bos|>": 3,
15
+ "<|im_start|>": 4,
16
+ "<|im_end|>": 5,
17
+ "<|system|>": 6,
18
+ "<|user|>": 7,
19
+ "<|assistant|>": 8,
20
+ "<think>": 9,
21
+ "</think>": 10,
22
+ "<tool_call>": 11,
23
+ "</tool_call>": 12,
24
+ "<|tool|>": 13,
25
+ "<tools>": 14,
26
+ "</tools>": 15
27
+ },
28
+ "ornekler": [
29
+ {
30
+ "metin": "Türkiye'nin başkenti Ankara'dır.",
31
+ "token_sayisi": 8,
32
+ "parcalar": ["Türkiye", "'", "nin", " başkenti", " Ankara", "'d", "ır", "."]
33
+ },
34
+ {
35
+ "metin": "İstanbul'da yaşıyorum, çalışıyorum, eğleniyorum.",
36
+ "token_sayisi": 10,
37
+ "parcalar": ["İstanbul", "'d", "a", " yaşıyorum", ",", " çalışıyorum", ",", " eğlen", "iyorum", "."]
38
+ },
39
+ {
40
+ "metin": "Evlerimizdeydiniz galiba.",
41
+ "token_sayisi": 6,
42
+ "parcalar": ["Ev", "lerimizde", "y", "diniz", " galiba", "."]
43
+ },
44
+ {
45
+ "metin": "15 Temmuz 2026 tarihinde saat 09.30'da toplantımız var.",
46
+ "token_sayisi": 15,
47
+ "parcalar": ["15", " Temmuz", " 20", "26", " tarihinde", " saat", " 09", ".", "30", "'d", "a", " toplant", "ımız", " var", "."]
48
+ },
49
+ {
50
+ "metin": "Yapay zeka modelleri Türkçenin sondan eklemeli yapısıyla başa çıkmalı.",
51
+ "token_sayisi": 14,
52
+ "parcalar": ["Yapay", " zeka", " modelleri", " Türkç", "enin", " son", "dan", " eklem", "eli", " yapısıyla", " başa", " çık", "malı", "."]
53
+ },
54
+ {
55
+ "metin": "Muvaffakiyetsizleştiricileştiremeyebileceklerimizdenmişsinizcesine.",
56
+ "token_sayisi": 17,
57
+ "parcalar": ["M", "uv", "af", "fak", "iyet", "siz", "leştir", "ic", "ileştir", "em", "ey", "ebilecek", "lerimizden", "miş", "siniz", "cesine", "."]
58
+ }
59
+ ]
60
+ }