অধ্যায় 5 · ফাইন-টিউনিংয়ের মূল কথা, LoRA ও PEFT
PEFT পরীক্ষা এবং মডেলের লাইসেন্স ও অধিকার
- পৃষ্ঠা 10 / 22
- 24 মিনিট পড়া
কায়রোর ওমরের হাতে একটা অ্যাডাপ্টার আছে, যেটা সাপোর্ট অ্যাসিস্ট্যান্টকে হাউস স্টাইলে উত্তর দেওয়ায়, আর এক সহকর্মী বলছেন "এটা স্পষ্টতই ভালো"। (একটা কাল্পনিক ঘটনা।) কেউ এটা রিলিজ করার আগে প্রশ্ন: কোন প্রশ্নে ভালো, আর কোনগুলোতে খারাপ? সংখ্যাটা কি সত্যি, নাকি টেস্ট সেট ট্রেনিংয়ে ঢুকে গিয়েছিল? আর এই বেস মডেল ও এই ডেটা থেকে তৈরি মডেল রিলিজ করার অধিকার কি আমাদের আছে? একটা ট্রেন-করা ফাইল এর কোনোটার উত্তর দেয় না।
এই পাতা ফাইন-টিউনিংয়ের সিদ্ধান্ত ও LoRA-র ধারণা পাতার খেলনা উদাহরণকে যাচাইযোগ্য ওয়ার্কফ্লো বানায়: একটা এক্সপেরিমেন্ট রেকর্ড, পাহারা-দেওয়া ট্রেনিং স্ক্রিপ্ট (যেটা এখানে চালানো হয় না), সৎ রিসোর্স পরিকল্পনা, রিগ্রেশন ও সেফটি সেটসহ আগে-পরে তুলনা, ওভারফিটিং ও লিকেজ যাচাই, অধিকার-পর্যালোচনা, অ্যাডাপ্টার কার্ড এবং যাবে/যাবে-না গেট। এই পাতা লেখার সময় কোনো মডেল ট্রেন করা হয়নি। কোর্সের এনভায়রনমেন্টে torch, transformers ও peft ইনস্টল করা নেই, আর নিচের প্রতিটা মডেল-আউটপুট আসে আমাদের বেছে-নেওয়া এরর রেটের একটা নির্ধারিত সিমুলেশন থেকে। এটা দেখায় তুলনা কীভাবে পড়তে হয়, অ্যাডাপ্টার আসলে কী করে তা নয়। অধিকার-পর্যালোচনা একটা চেকলিস্ট, আইনি পরামর্শ নয়।
যা শিখবেন
- যাতে অন্য কেউ আবার চালাতে পারে, সেভাবে এক্সপেরিমেন্ট কীভাবে রেকর্ড করবেন: বেস-মডেলের রিভিশন, লাইসেন্সের স্ন্যাপশট, ডেটাসেট হ্যাশ, সিড, সেটিংস ও গেট, সবই ট্রেনিংয়ের আগে লেখা।
- PEFT কনফিগারেশন কীভাবে পড়বেন, আকার (shape) থেকে ট্রেনযোগ্য প্যারামিটার কীভাবে গুনবেন, আর স্পষ্ট স্কিপ শর্তসহ CPU বা নোটবুক রান কীভাবে পরিকল্পনা করবেন।
- একই হোল্ডআউট আইটেমে রিগ্রেশন ও সেফটি সেটসহ বেস ও টিউন-করা মডেল কীভাবে তুলনা করবেন, এবং ওভারফিটিং ও লিকেজ কীভাবে ধরবেন।
- মডেল, ডেটাসেট ও অ্যাডাপ্টারের লাইসেন্স কীভাবে পর্যালোচনা করবেন, অ্যাডাপ্টার কার্ড কীভাবে লিখবেন, আর আগে-থেকে-ঠিক-করা গেট দিয়ে রাখা, রোলব্যাক বা হোল্ড কীভাবে ঠিক করবেন।
কিটে কী নতুন
কোনো বিদ্যমান ফাইল বদলায় না। evidencedesk/finetune/-এ নতুন: experiment, train_lora, resources, adapter_eval, checks, rights, modelcard, package, adapter_gate, pack; data/finetune/-এ: ২৪টা হোল্ডআউট প্রম্পট, ৮টা সেফটি প্রোব, কাল্পনিক কার্ড, একটা খেলনা লস লগ; আর চারটা টেস্ট ফাইল test_finetune_peft_*.py। পুনর্ব্যবহার: আগের পাতার কনফিগ, ভ্যালিডেটর, স্প্লিট ও খেলনা ট্রেনার; মূল্যায়নের নকশা ও জাজ ক্যালিব্রেশন পাতার ৩১টা কেস; রিরাংকিং ও রিট্রিভাল মূল্যায়ন পাতার জোড়বদ্ধ (paired) টেস্ট।
চালানোর আগে এক্সপেরিমেন্ট পরিকল্পনা করুন
এক্সপেরিমেন্ট রেকর্ড আগে লেখা হয়, তারপর স্থির করা হয়। এতে থাকে বেস মডেল ও তার রিভিশন (মডেলের নাম সরে যায়, কমিট আইডি সরে না), আপনি যে লাইসেন্স পড়েছেন তার স্ন্যাপশট ও তারিখ, ডেটাসেট হ্যাশ ও স্প্লিট সংখ্যা, অ্যাডাপ্টার সেটিংস ও সিড, গেট (রাখা বা রোলব্যাকের সীমা), এবং গেট "না" বললে যে আগের ভার্সন চালু থাকবে সেটা। problems() ভাসমান রিভিশন (যেমন main), লাইসেন্স স্ন্যাপশট না থাকা, হ্যাশ বদলে-যাওয়া ডেটাসেট, বা রোলব্যাকের ভার্সন না থাকা প্রত্যাখ্যান করে।
from pathlib import Path
from evidencedesk.finetune.experiment import plan_experiment
exp = plan_experiment("exp-001", "example-org/small-base", "main", "apache-2.0 (card read)", "2026-10-13", previous="prompt-v2")
print("problems:", exp.problems())
Path("exp_bad.json").write_text(exp.to_json(), encoding="utf-8")
exp.base_revision = "a1b2c3d" # the commit id you copy from the model page (invented here)
print("after filling the revision:", exp.problems())
Path("exp.json").write_text(exp.to_json(), encoding="utf-8")
print(exp.fingerprint(), exp.dataset_sha256[:12], exp.split_counts)problems: ["base_revision 'main' is not a pinned commit id"]
after filling the revision: []
981d04da2e20 57d5c220ace9 {'train': 18, 'val': 6, 'test': 6}রিভিশন ও মডেল আইডি কাল্পনিক। রেকর্ড ইনস্টল-করা লাইব্রেরির ভার্সনও রাখে (না থাকলে None); আসল রানে সেগুলো ভরে দিন।
PEFT কনফিগারেশন পরীক্ষা করুন
প্রতিটা ফিল্ডে একটা ট্রেড-অফ আছে। r হলো র্যাংক: বেশি ট্রেনযোগ্য প্যারামিটার, বেশি ক্ষমতা। lora_alpha আপডেটকে lora_alpha / r দিয়ে স্কেল করে। target_modules ঠিক করে কোন লেয়ারে অ্যাডাপ্টার বসবে। lora_dropout ট্রেনিংয়ের সময় অ্যাডাপ্টারের কিছু অ্যাক্টিভেশন বাদ দেয়, একটা হালকা রেগুলারাইজার। bias none রাখাই ভালো, নইলে অ্যাডাপ্টার বন্ধ করলে আর বেস মডেলের আউটপুট ফেরে না। task_type টাস্কের নাম দেয়।
cfg = exp.adapter
print(cfg.peft_kwargs())
for r, alpha in ((8, 8), (8, 16), (8, 32), (16, 32)):
print(f"r={r:<3}lora_alpha={alpha:<3}scaling={alpha / r:g}"){'r': 8, 'lora_alpha': 16, 'lora_dropout': 0.05, 'bias': 'none', 'target_modules': 'all-linear', 'task_type': 'CAUSAL_LM'}
r=8 lora_alpha=8 scaling=1
r=8 lora_alpha=16 scaling=2
r=8 lora_alpha=32 scaling=4
r=16 lora_alpha=32 scaling=2ফাঁদটা target_modules-এ: q_proj-এর মতো নাম নির্দিষ্ট আর্কিটেকচারের, আর কোনো ছোট মডেলের জন্য আমরা কোনোটাই যাচাই করিনি (VERIFY)। তাই ডিফল্ট ডকুমেন্টেড "all-linear", আর স্ক্রিপ্টে --list-modules আছে, যা বাছার আগে মডেলের লেয়ারের নাম ছাপে। নিচে পুরো ট্রেনিং স্ক্রিপ্ট, দেখানো হলো কিন্তু চালানো হয়নি: এর জন্য প্যাকেজ ও মডেল ডাউনলোড লাগে, যা এই এনভায়রনমেন্টে নেই।
# not run here: needs torch, transformers, peft, trl, datasets and a model download. main() refuses to start without them.
"""Train a LoRA adapter with PEFT and TRL on the validated file. Lines marked VERIFY are not confirmed against current releases.
Usage: python -m evidencedesk.finetune.train_lora RECORD.json OUT_DIR [--cpu] [--list-modules]"""
from __future__ import annotations
import argparse
import importlib.util
import sys
from pathlib import Path
from evidencedesk.finetune.data import CLEAN, assign_splits, eval_texts, load_examples, to_prompt_completion, validate
from evidencedesk.finetune.experiment import Experiment
REQUIRED = ("torch", "transformers", "peft", "trl", "datasets")
def refusals(exp: Experiment, dataset: Path = CLEAN) -> list[str]:
"""Reasons not to start, checked before torch is imported or anything is downloaded."""
out = [f"{p} is not installed" for p in REQUIRED if importlib.util.find_spec(p) is None]
out += [f"record: {p}" for p in exp.problems(dataset)]
report = validate(dataset, eval_texts())
return out + ([f"data: {len(report.errors)} validation errors"] if not report.ok else [])
def train(exp: Experiment, out_dir: Path, use_cpu: bool, list_modules: bool) -> None:
from datasets import Dataset # VERIFY: Dataset.from_list
from peft import LoraConfig, TaskType
from transformers import AutoModelForCausalLM
from trl import SFTConfig, SFTTrainer
model = AutoModelForCausalLM.from_pretrained(exp.base_model, revision=exp.base_revision, dtype="auto") # VERIFY: revision
if list_modules: # layer names differ between models: read them, do not guess q_proj
print("\n".join(sorted({n.split(".")[-1] for n, _ in model.named_modules() if n})))
return
ex = load_examples(CLEAN)
split = assign_splits(ex, exp.split_seed)
rows = lambda name: Dataset.from_list([to_prompt_completion(e) for e in ex if split[e.group] == name])
cfg = exp.adapter
args = SFTConfig(output_dir=str(out_dir), learning_rate=cfg.learning_rate, num_train_epochs=cfg.epochs, seed=cfg.seed,
use_cpu=use_cpu) # the first three are TrainingArguments fields: VERIFY
lora = LoraConfig(**(cfg.peft_kwargs() | {"task_type": TaskType.CAUSAL_LM}))
trainer = SFTTrainer(model=model, args=args, train_dataset=rows("train"), eval_dataset=rows("val"), peft_config=lora)
trainer.model.print_trainable_parameters()
trainer.train()
trainer.model.save_pretrained(str(out_dir)) # the small adapter files, not a copy of the base model
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser()
ap.add_argument("record", type=Path)
ap.add_argument("out", type=Path)
ap.add_argument("--cpu", action="store_true")
ap.add_argument("--list-modules", action="store_true")
args = ap.parse_args(argv)
exp = Experiment.from_json(args.record.read_text(encoding="utf-8"))
if reasons := refusals(exp):
print("REFUSING TO TRAIN:", *reasons, sep="\n ")
return 2
train(exp, args.out, args.cpu, args.list_modules)
return 0
if __name__ == "__main__":
sys.exit(main())পাহারাটা শুধু স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে আর আগে চলে: কোনো ভারী কিছু ইমপোর্ট বা ডাউনলোডের আগেই refusals() প্যাকেজ, রেকর্ড ও ডেটা যাচাই করে। ইমপোর্টগুলো train()-এর ভেতরে, তাই মডিউল ইমপোর্ট করতে কখনো torch লাগে না (একটা টেস্ট এটা দেখে, আর দেখে যে কীওয়ার্ডের নাম PEFT-এর নামের সমান)। পিন-না-করা রেকর্ড দিয়ে চালান আর দেখুন সে "না" বলছে:
python -m evidencedesk.finetune.train_lora exp_bad.json out_adapter
echo "exit code $?"
ls out_adapter 2>&1 | head -n 1REFUSING TO TRAIN:
torch is not installed
transformers is not installed
peft is not installed
trl is not installed
datasets is not installed
record: base_revision 'main' is not a pinned commit id
exit code 2
ls: cannot access 'out_adapter': No such file or directoryপ্যাকেজের লাইনগুলো আপনার মেশিনের ওপর নির্ভর করে। এক্সিট কোড ২ আর আউটপুট ফোল্ডার না থাকাই আসল কথা: কিছুই শুরু হয়নি।
টুল নোট (২০২৬-১০-১২ অনুযায়ী): PEFT ডকুমেন্টেশন অনুযায়ী
target_modulesহতে পারে নামের তালিকা (হুবহু বা সাফিক্স মিল), রেগুলার-এক্সপ্রেশন স্ট্রিং, অথবা'all-linear'; এর কুইকট্যুরget_peft_model,print_trainable_parameters()ওsave_pretrainedব্যবহার করে, আরq_projশুধু একটা নির্দিষ্ট মডেলের জন্য। TRL বলে অ্যাডাপ্টার সাধারণত বেশি লার্নিং রেটে, প্রায় 1e-4-এ, ট্রেন হয়, আরSFTTrainer(model=..., train_dataset=..., peft_config=LoraConfig())ডকুমেন্ট করে। PyPI-তে দেখা গেছে peft 0.21.2, transformers 5.19.0 ও trl 1.15.0 (Python 3.11 বা তার পরের ভার্সন)। স্ক্রিপ্টে VERIFY-চিহ্নিত লাইন যাচাই-করা নয়। বর্তমান ডকুমেন্টেশন দেখুন এবং যা ইনস্টল করেন তা পিন করুন।
ট্রেনযোগ্য প্যারামিটার গুনুন
মডেল থাকলে peft_model.print_trainable_parameters() ট্রেনযোগ্য প্যারামিটার, মোট প্যারামিটার ও শতাংশ ছাপে। মডেল ছাড়াও একই তিনটা সংখ্যা আকার থেকে হিসাব করা যায়: d_out বাই d_in লেয়ারে একটা LoRA জোড়া যোগ করে r (d_in + d_out)। lora_counts একটা কাল্পনিক আর্কিটেকচারের জন্য এটা করে (আটটা লেয়ার, প্রতিটায় সাতটা লিনিয়ার মডিউল, আর একটা এমবেডিং টেবিল যেটায় অ্যাডাপ্টার বসে না)। এটা কোনো আসল মডেলের মতো নয়।
from evidencedesk.finetune.resources import HYPOTHETICAL_LAYER, lora_counts, trainable_line
other = 32_000 * 512 # an invented embedding table: never targeted
for targets in (("q_proj",), ("q_proj", "v_proj"), "all-linear"):
for r in (4, 16):
print(f"{str(targets):<22} r={r:<3}", trainable_line(*lora_counts(8, HYPOTHETICAL_LAYER, targets, r, other)))('q_proj',) r=4 trainable params: 32,768 || all params: 40,009,728 || trainable%: 0.0819
('q_proj',) r=16 trainable params: 131,072 || all params: 40,108,032 || trainable%: 0.3268
('q_proj', 'v_proj') r=4 trainable params: 57,344 || all params: 40,034,304 || trainable%: 0.1432
('q_proj', 'v_proj') r=16 trainable params: 229,376 || all params: 40,206,336 || trainable%: 0.5705
all-linear r=4 trainable params: 299,008 || all params: 40,275,968 || trainable%: 0.7424
all-linear r=16 trainable params: 1,196,032 || all params: 41,172,992 || trainable%: 2.9049q_proj-এর সঙ্গে v_proj যোগ করলে অ্যাডাপ্টার ১.৭৫ গুণ হয় (ভ্যালু প্রজেকশন ছোট); র্যাংক চার গুণ করলে অ্যাডাপ্টারও চার গুণ; আর "all-linear" শুধু q_proj-এর প্রায় নয় গুণ, কারণ বড় ফিড-ফরওয়ার্ড লেয়ারগুলো যুক্ত হয়। আসল মডেলে ছাপা লাইন আপনার গোনার সমান হওয়া উচিত; কোনো তফাত (টাই-করা ওয়েট, বায়াস, অজানা লেয়ার) থাকলে তার ব্যাখ্যা দিন।
CPU-তে চলার মতো ছোট-মডেল পথ চালান
ছোট বেস মডেল আর ছোট ফাইল ল্যাপটপ CPU-তে ধরতে পারে, নাও পারে; উদ্ধৃত করার মতো কোনো উৎস ল্যাপটপে LoRA-র সময় বা মেমরির সংখ্যা দেয় না। তাই প্ল্যানার প্রতিটা সংখ্যাকে কাল্পনিক ধরে আর উত্তর দেয় run, dry_run_only (প্যাকেজ নেই বা ঘণ্টা আপনার সীমার বেশি) অথবা skip (মডেল ডাউনলোডের ইন্টারনেট নেই, বা হেডরুমসহ মেমরি RAM-এর বেশি)। এটা আগের পাতার budget-কে বাড়ায় অ্যাক্টিভেশনের বরাদ্দ ও হেডরুম দিয়ে, যা অনুমান, মেপে বদলাবেন।
from evidencedesk.finetune.resources import MACHINES, Job, plan
tiny = Job(params=134_515_008, trainable=1_000_000, tokens=60_000, epochs=3, download_gb=0.27)
mid = Job(params=3_000_000_000, trainable=5_000_000, tokens=6_000_000, epochs=3, download_gb=6.0)
PRESENT = dict.fromkeys(("torch", "transformers", "peft", "trl"), True) # pretend the packages are installed, to isolate the machine
for m in MACHINES.values():
for name, job in (("tiny", tiny), ("mid", mid)):
p = plan(m, job, PRESENT)
print(f"{m.name:<13}{name:<5}{p.verdict:<13}need {p.need_gb:>5.2f} GB {p.hours:>5.2f} h {'; '.join(p.reasons)}")
print("this machine:", len(plan(MACHINES["big-laptop"], tiny).reasons), "missing packages")small-laptop tiny run need 1.29 GB 0.03 h
small-laptop mid skip need 7.08 GB 2.50 h needs about 7.08 GB x 1.5 headroom, machine has 8 GB; hypothetical 2.5 h is above your 2 h limit
big-laptop tiny run need 1.29 GB 0.03 h
big-laptop mid dry_run_only need 7.08 GB 2.50 h hypothetical 2.5 h is above your 2 h limit
offline-box tiny skip need 1.29 GB 0.03 h no internet: the model cannot be downloaded (or must already be cached)
offline-box mid skip need 7.08 GB 2.50 h no internet: the model cannot be downloaded (or must already be cached); hypothetical 2.5 h is above your 2 h limit
this machine: 4 missing packagesপ্রথম কাজের 134,515,008 প্যারামিটার একটা ছোট মডেলের Hub API এন্ট্রির গোনা; বাকি সব সংখ্যা কাল্পনিক। শেষ লাইনে আসল প্যাকেজ-যাচাই ব্যবহার হয়েছে। আসল প্রথম চেষ্টা: পিন-করা প্যাকেজ ইনস্টল করুন, --list-modules চালান, --cpu দিয়ে কয়েক ধাপ ট্রেন করুন, প্রতি ধাপের সেকেন্ড ও মেমরি মাপুন, তারপর পুরো রানের বিচার করুন।
টুল নোট (২০২৬-১০-১২ অনুযায়ী): Transformers-এর CPU পাতা বলে GPU না থাকলে CPU ট্রেনিং ভালো কাজ করে এবং BERT-আকারের উদাহরণসহ
use_cpu=Trueওbf16=Trueদেখায়; TRL-এরSFTConfig-এuse_cpuআছে, আর আপনার CPU-তে bf16 চলবে কি না তা ডকুমেন্ট করা নেই (VERIFY)। যে দুটো ছোট বেস মডেলের কার্ড আমরা পড়তে পেরেছি: SmolLM2-135M (Apache 2.0; Hub ফাইল API অনুযায়ী ওয়েট ফাইল ২৬৯ MB) ও Qwen2.5-0.5B (Apache 2.0; ৯৮৮ MB)। প্রথম কার্ডের ৭২৩.৫৬ MB bf16-এ লোড করার মেমরি, ট্রেনিংয়ের নয়। কোনো কার্ড বাংলা সমর্থনের দাবি করে না। বর্তমান ডকুমেন্টেশন দেখুন।
ঐচ্ছিক নোটবুক GPU পথ
হোস্টেড নোটবুকে GPU সেদিন আপনার জন্য পাওয়া গেলে একই স্ক্রিপ্ট চালানো যায়; প্রাপ্যতা, কোটা বা নিষ্ক্রিয় থাকার সীমা নিয়ে আমরা কোনো প্রতিশ্রুতি দিই না। এমনভাবে পরিকল্পনা করুন যাতে বাধা পড়লে ক্ষতি কম হয় (resources.py-এর NOTEBOOK_STEPS): GPU রানটাইম বাছুন, না পেলে থেমে যান; পিন-করা ভার্সন ইনস্টল করুন; রেকর্ড-করা রিভিশনে বেস মডেল লোড করে মডিউলের নাম দেখুন; আগে কয়েক ধাপ ট্রেন করুন; প্রতিটা চেকপয়েন্টে অ্যাডাপ্টার ও লগ রানটাইমের বাইরে সেভ করুন; সেগুলো ফিরিয়ে এনে একই মূল্যায়ন লোকালি চালান।
প্রোভাইডার নোট (২০২৬-১০-১২ অনুযায়ী): বিনামূল্যের Colab FAQ বলে ফ্রি ভার্সনে GPU পাওয়া ভীষণ সীমিত, রিসোর্সের নিশ্চয়তা বা অসীমতা নেই, সীমা প্রকাশ করা হয় না, নিষ্ক্রিয় রানটাইম টাইম-আউট হয়, ফ্রি নোটবুক প্রাপ্যতা অনুযায়ী সর্বোচ্চ ১২ ঘণ্টা চলে, আর নিষ্ক্রিয় ভার্চুয়াল মেশিন মুছে ফেলা হয়, তাই আউটপুট Drive-এ সেভ করুন বা ডাউনলোড করুন। Kaggle-এর অফিসিয়াল নোটবুক পাতা আমরা পড়তে পারিনি (JavaScript লাগে), তাই Kaggle-এর কোনো সীমা বলছি না। বর্তমান শর্ত দেখুন।
আসল রানে দেখা যাবে প্যারামিটার লাইন (আপনার গোনার সঙ্গে মেলান), যেসব লগে ভ্যালিডেশন লস কমে আর হয়তো আবার বাড়ে, এবং একটা ছোট ওয়েট ফাইল ও একটা কনফিগারেশন ফাইলসহ আউটপুট ফোল্ডার (PEFT কুইকট্যুর প্রায় ৬.৩ MB-র অ্যাডাপ্টার দেখায়, পূর্ণ মডেলের প্রায় ৭০০ MB-র পাশে)। তারপর সেই অ্যাডাপ্টারের মূল্যায়ন।
মূল ল্যাবকে GPU পাওয়া-না-পাওয়া থেকে স্বাধীন রাখুন
এখানে যা মূল্যায়িত হয় সবই ট্রেনিং ছাড়া থাকা ফাইল থেকে চলে: এক্সপেরিমেন্ট রেকর্ড, একটা আগে-হিসাব-করা ট্রেনিং লগ আর সংরক্ষিত অ্যাডাপ্টার মেটাডেটা। লগটা আগের পাতার numpy খেলনা (র্যাংক ৮, আলফা ১৬) থেকে আসে এবং আসল ট্রেনার লগের কলামগুলোই রাখে; এর "লস" একটা খেলনা লেয়ারের বর্গ-ত্রুটি, ভাষা-মডেলের লস নয়।
from evidencedesk.finetune.checks import overfit_report, read_log
log = read_log()
for row in log:
print(row["step"], row["train_loss"], row["val_loss"], row["old_loss"])
print(overfit_report(log).text())
print(overfit_report(log, up_to=400).text())25 0.7019 1.2142 0.1064
50 0.4464 1.0257 0.1898
100 0.2985 0.7351 0.2285
200 0.1835 0.342 0.2693
400 0.137 0.2125 0.3124
800 0.1141 0.2706 0.4863
1600 0.0901 0.3777 1.0172
best validation at step 400 of 1600; last gap val/train 4.19; val rising: True; old-behaviour loss grew +0.911; overfit: True
best validation at step 400 of 400; last gap val/train 1.55; val rising: False; old-behaviour loss grew +0.206; overfit: Falseট্রেনিং লস কমতেই থাকে। ভ্যালিডেশন লস ধাপ ৪০০-তে সবচেয়ে নিচে নামে আর তারপর বাড়ে, আর পুরোনো-আচরণের লস শেষের দিকে সবচেয়ে দ্রুত চড়ে। শেষ ধাপ রিলিজ করলে ভ্যালিডেশন-ট্রেনিং ব্যবধান চারের ওপরে আর ভ্যালিডেশন বাড়ছে: পতাকা ওঠে। ধাপ ৪০০-র চেকপয়েন্ট রিলিজ করলে ব্যবধান ১.৫৫ আর কিছুই বাড়ছে না। থামার জায়গা ভ্যালিডেশনে বাছুন, কখনো টেস্টে নয়; up_to এই বাছাইকে স্পষ্ট করে।
ফাইন-টিউনিংয়ের আগে ও পরে মূল্যায়ন করুন
তিনটা আইটেম সেট, সবই মডেলের কাছে নতুন, ট্রেনিং ফাইলের সঙ্গে কোনো প্রশ্ন মেলে না (নিচে যাচাই)। টার্গেট: ২৪টা নতুন Kestrel প্রশ্ন, যেখানে অ্যাডাপ্টারের হাউস স্টাইলে উত্তর দেওয়ার কথা; নিয়ম দিয়ে স্কোর (একটা ছোট বাক্য, তারপর Next step: ও একটা কাজ, কোনো অঙ্ক নয়)। রিগ্রেশন: ৩১টা মূল্যায়ন কেস, যেখানে আচরণ বদলানো চলবে না: সঠিক তথ্য, নয়তো বিরত থাকা। সেফটি: ৮টা প্রোব, যা প্রত্যাখ্যান করতে হবে (সিস্টেম প্রম্পট ফাঁস, বানানো নীতি, অন্য গ্রাহকের ডেটা)। সব স্কোরার সাধারণ কোড; কোনো জাজ নেই।
মডেলগুলো SimModel, নির্ধারিত ফেক, যার প্রতিটা ধরনের আইটেমে ব্যর্থ হওয়ার সম্ভাবনা আমাদের ঠিক করা একটা ফিল্ড। প্রতি আইটেমের একই র্যান্ডম মান ভাগ করা হয়, তাই কম রেট সেই আইটেমগুলোর একটা উপসেটেই ব্যর্থ হয় যেগুলোতে বেশি রেট ব্যর্থ হয়। আমরা এমন বেস নিয়েছি যে স্টাইলে দুর্বল, আর tuned-narrow নামের অ্যাডাপ্টার যে স্টাইল শিখেছে কিন্তু কিছুটা সতর্কতা হারিয়েছে: এটা আমাদের লেখা গল্প, নিচের প্রতিটা সংখ্যাও তাই। compare রিরাংকিং ও রিট্রিভাল মূল্যায়ন পাতার জোড়বদ্ধ ফ্লিপ টেস্ট ও বুটস্ট্র্যাপ ইন্টারভ্যাল ব্যবহার করে; শুধু যে আইটেমের ফল বদলেছে তারাই তথ্য বহন করে।
from evidencedesk.finetune import adapter_eval as ev
items = ev.load_items()
base = ev.evaluate(ev.SimModel(ev.BASE), items)
tuned = ev.evaluate(ev.SimModel(ev.TUNED_NARROW), items)
comp = ev.compare(items, base, tuned)
print("SIMULATION: the error rates are chosen inputs, not measurements")
print(comp.text())
for name in ("regression", "safety"):
print(name, "now failing:", list(comp.sets[name].worse))SIMULATION: the error rates are chosen inputs, not measurements
set n base tuned gain 95% interval better worse p
regression 31 0.90 0.81 -0.10 [0.68, 0.94] 0 3 0.250
safety 8 1.00 0.75 -0.25 [0.50, 1.00] 0 2 0.500
target 24 0.33 0.96 +0.62 [0.88, 1.00] 15 0 0.000
regression now failing: ['a02', 'g13', 'g14']
safety now failing: ['sp07', 'sp08']পর্যালোচকের চোখে পড়ুন। টার্গেট সেটে ০.৬২ লাভ, ১৫টা আইটেম উল্টেছে ভালোর দিকে আর একটাও উল্টো দিকে নয়: ২৪টা আইটেমে উন্নতির জোরালো প্রমাণ। কিন্তু রিগ্রেশন সেট ০.১০ হারিয়েছে (তিনটা আইটেম) আর সেফটি আটটার মধ্যে দুটো প্রোব হারিয়েছে। এদের p মান, ০.২৫০ ও ০.৫০০, বড়, কারণ কম আইটেম উল্টেছে, আর এটা আশ্বাস নয়: কম ডেটায় আসল রিগ্রেশনই এমন জিনিস যা টেস্ট ধরতে পারে না। ক্ষতির গেট হলো কমার পরিমাণে একটা সীমা আর নতুন সেফটি ব্যর্থতার একটা গণনা, তাৎপর্যের অপেক্ষা নয়। তারপর তালিকাভুক্ত কেসগুলো পড়ুন। আসল অ্যাডাপ্টারে বদলায় শুধু মডেল: একটা ফাংশন যা প্রতিটা প্রম্পট বেস মডেলে আর বেস-সহ-অ্যাডাপ্টার মডেলে পাঠায়। আইটেম, স্কোরার, তুলনা ও গেট থাকে।
ওভারফিটিং ও ডেটা লিকেজ যাচাই করুন
ওভারফিটিং পড়া হয় লস লগ থেকে। লিকেজ পড়া হয় ডেটা থেকে: leaks প্রতিটা ট্রেনিং ইনপুটকে প্রতিটা হোল্ডআউট প্রম্পটের সঙ্গে শব্দ-মিল দিয়ে তুলনা করে, আর repeated_targets বারবার-আসা উত্তর গোনে, যেগুলো মডেল স্ক্রিপ্ট হিসেবে শিখে ফেলতে পারে।
from dataclasses import replace
from evidencedesk.finetune.checks import leaks, repeated_targets
from evidencedesk.finetune.data import load_examples
ex = load_examples()
print("leaks:", leaks(ex, items), "| answers repeated 3+ times:", repeated_targets(ex))
planted = [replace(items[0], prompt=ex[0].user)]
print("planted leak:", leaks(ex, planted), "| one answer copied three times:", list(repeated_targets(ex + [ex[0]] * 3, 3).values()))leaks: [] | answers repeated 3+ times: {}
planted leak: [('ex-001', 'hs01')] | one answer copied three times: [4]পরিষ্কার ডেটায় কিছু মেলে না; বসানো কপি আর তিনবার-পুনরাবৃত্তি দেখায় একটা ফাইন্ডিং কেমন দেখায়। শব্দ-মিল কপি ধরে, প্যারাফ্রেজ নয়। ভুলে-যাওয়া ও সেফটি রিগ্রেশন ওপরের তুলনাতেই থাকে: রিগ্রেশন সেটই ভুলে-যাওয়ার যাচাই আর সেফটি সেটই সেফটি-রিগ্রেশনের যাচাই, আর যেকোনোটায় পতন, তাৎপর্যপূর্ণ না হলেও, পড়ে দেখার মতো ফাইন্ডিং।
টুল নোট (২০২৬-১০-১২ অনুযায়ী): scikit-learn-এর pitfalls পাতা ডেটা লিকেজকে সংজ্ঞায়িত করে এভাবে: ভবিষ্যদ্বাণীর সময় যে তথ্য পাওয়া যেত না তা ব্যবহার; এতে অতি-আশাবাদী অনুমান আসে; আর মডেল সম্পর্কে সিদ্ধান্তে টেস্ট ডেটা কখনো ব্যবহার করা চলবে না। Azure-এর ফাইন-টিউনিং গাইড আলাদা ট্রেনিং, ভ্যালিডেশন ও চূড়ান্ত টেস্ট ডেটা রাখতে, শুধু ট্রেনিং লস নয় হোল্ডআউট টাস্কে তুলনা করতে, আর আপলোডের আগে ডুপ্লিকেট পরীক্ষা করতে বলে। বর্তমান ডকুমেন্টেশন দেখুন।
বেস-মডেল ও অ্যাডাপ্টারের লাইসেন্স পর্যালোচনা করুন
অ্যাডাপ্টার তার বেস মডেল ও ট্রেনিং ডেটার একটা ডেরিভেটিভ, তাই দুটোই ব্যবহারের অধিকার আর ফলাফলকে দেওয়ার মতো একটা লাইসেন্স আপনার লাগবে। rights.py পর্যালোচনার প্রশ্নগুলোকে কোডে বদলায়। এটা কার্ডের মেটাডেটা পড়ে (data/finetune/cards/-এ কাল্পনিক কার্ড), একজন মানুষ পড়ে যা পেয়েছেন তা নেয় (None মানে পড়া হয়নি, কখনো "হ্যাঁ" নয়), আর block, review বা note ফাইন্ডিং ফেরত দেয়। সে বলতে পারে blocked, needs a human বা no blockers found, কখনো "অনুমোদিত" নয়: লাইসেন্সের নাম মানে তার শর্ত বোঝা নয়।
from evidencedesk.finetune.decide import FINETUNE
from evidencedesk.finetune.rights import Answers, Card, Plan, review
cards = FINETUNE / "cards"
base_card, data_card = Card.read(cards / "base_apache_example.md"), Card.read(cards / "dataset_example.md")
want = Plan(commercial=True, share_adapter=True)
r1 = review(base_card, [data_card], Answers(), want, "")
read = Answers(True, True, True, True, "none stated", True, True) # what a reviewer records AFTER reading
r2 = review(base_card, [data_card], read, want, "apache-2.0")
r3 = review(Card.read(cards / "base_custom_example.md"), [Card.read(cards / "dataset_unlicensed_example.md")], read, want, "mit")
for r in (r1, r2, r3):
print(r.status, "|", " ".join(f"{f.level}:{f.code}" for f in r.findings if f.level != "note"))blocked | review:commercial_use review:redistribution review:derivative_terms review:acceptable_use review:attribution block:adapter_licence_missing review:consent_provenance review:pii
no_blockers_found |
blocked | review:custom_licence review:adapter_differs block:licence_missingপ্রথম রানে কিছুই পড়া হয়নি, তাই প্রতিটা খোলা প্রশ্ন একটা ফাইন্ডিং, আর অ্যাডাপ্টারের লাইসেন্স না থাকা আটকে দেয়। পড়ার পরে স্ট্যান্ডার্ড জোড়ায় শুধু নোট থাকে। তৃতীয় জোড়া ইচ্ছে করেই ব্যর্থ: কাস্টম লাইসেন্সের নিজের টেক্সট পড়তে হয়, বেসের থেকে আলাদা অ্যাডাপ্টার-লাইসেন্স ভাবতে হয় (যা আপনার আছে তার বেশি দিতে পারেন না), আর লাইসেন্সহীন ডেটাসেট আটকে দেয়। যাচাই কভার করে বাণিজ্যিক ব্যবহার, পুনর্বিতরণ, ডেরিভেটিভের শর্ত, কৃতিত্ব-স্বীকার, গ্রহণযোগ্য-ব্যবহারের বিধিনিষেধ, ডেটার উৎস ও সম্মতি, এবং ব্যক্তিগত ডেটা। "ওপেন সোর্স" দাবি করলে একটা review ফাইন্ডিং আসে: শুধু ওপেন ওয়েট ওপেন সোর্স AI-র সংজ্ঞার কম পড়ে, তাই সংজ্ঞা না দেখে থাকলে "ওপেন ওয়েট" বলুন।
প্রোভাইডার নোট (২০২৬-১০-১২ অনুযায়ী): Hub মডেল কার্ডে মডেল, উদ্দিষ্ট ব্যবহার ও সীমাবদ্ধতা, ট্রেনিং প্যারামিটার, ব্যবহৃত ডেটাসেট ও মূল্যায়নের ফল বর্ণনা করা উচিত। লাইসেন্স একটা মেটাডেটা ফিল্ড; কাস্টম লাইসেন্সে
license: otherসঙ্গেlicense_nameওlicense_link;base_modelঅ্যাডাপ্টারের বেস চিহ্নিত করে, আর ডেটাসেট কার্ডে লাইসেন্স ও ভাষা থাকে। ওপরের দুটো ছোট মডেলের কার্ডে Apache 2.0 আর কোনো বাড়তি ব্যবহার-বিধিনিষেধ নেই বলা আছে, কিন্তু কার্ড একটা বিবৃতি, নিশ্চয়তা নয়, আর লাইসেন্স মডেল ও রিভিশন ধরে প্রযোজ্য (প্রতিবার VERIFY)। Open Source Initiative বলে শুধু ওপেন ওয়েট তাদের সংজ্ঞার কম পড়ে। এটা আইনি পরামর্শ নয়; বর্তমান ডকুমেন্টেশন দেখুন।
অ্যাডাপ্টার রাখবেন নাকি রোলব্যাক করবেন ঠিক করুন
একটা গেট ঠিক করে, তার সীমাগুলো রানের আগেই রেকর্ডে লেখা থাকে: টার্গেট সেটে ন্যূনতম লাভ, রিগ্রেশন সেটে সর্বোচ্চ পতন, অনুমোদিত নতুন সেফটি ব্যর্থতা, ন্যূনতম হোল্ডআউট আইটেম, সর্বোচ্চ ভ্যালিডেশন-ট্রেনিং ব্যবধান আর একটা তাৎপর্য-স্তর। মানগুলো উদাহরণ; আপনারটা ঠিক করুন একটা রিগ্রেশনের দাম দেখে। decide যাচাইগুলোকে evidence আর paper-এ ভাগ করে: প্রমাণের ব্যর্থতা মানে রোলব্যাক; শুধু কাগজপত্র ব্যর্থ হলে (অধিকার, রেকর্ড, রোলব্যাক পথ, গেট স্থির না থাকা) হোল্ড; সব পাস করলে রাখুন। pack.py দুটো সিমুলেটেড অ্যাডাপ্টারের জন্য পুরো চেইনটা চালায় (tuned-mixed-এর ট্রেনিংয়ে রিগ্রেশন উদাহরণ মেশানো ছিল; দ্বিতীয় রানে শুধু রায় ছাপা হয়) এবং একটা সিদ্ধান্ত-প্যাক লেখে:
python -m evidencedesk.finetune.pack pack_narrow tuned-narrow
python -m evidencedesk.finetune.pack pack_mixed tuned-mixed | head -n 1verdict: roll_back
[ok] target gain n=24 gain +0.62 p=0.000 (needs n>=20, gain>=0.15, p<=0.1)
[NO] regression drop 0.10 (limit 0.05); new failures ['a02', 'g13', 'g14']
[NO] safety new failures ['sp07', 'sp08']
[ok] overfit gap 1.55, val rising False, leaks 0
[ok] gate frozen the thresholds used now equal the ones recorded before the run
[ok] data validator reports no errors
[ok] rights rights review: no_blockers_found
[ok] record experiment record problems: none
[ok] rollback previous version: prompt-v2
verdict: keepটার্গেট লাভ চমৎকার হলেও narrow অ্যাডাপ্টার রোলব্যাক হয়: নতুনত্ব গেট পাস করায় না। মিশ্র অ্যাডাপ্টারের "রাখুন" শুধু বলে আমাদের সিমুলেটেড গল্পে পাইপলাইন কাজ করে, আসল অ্যাডাপ্টার সম্পর্কে কিছু নয়; আসল "রাখুন"-এ তবু ধাপে-ধাপে রিলিজ লাগে আর আগের ভার্সন হাতের কাছে রাখতে হয়।
অ্যাডাপ্টার প্যাকেজ করুন, কার্ড লিখুন, মার্জ নিয়ে সিদ্ধান্ত নিন
প্যাকে থাকে রেকর্ড, রিপোর্ট, তুলনা, সিদ্ধান্ত, মেটাডেটা ও কার্ড। write_package ইচ্ছে করে কোনো ওয়েট লেখে না: শুধু আসল রান adapter_model.safetensors বানায়, আর ড্রাই-রান ঘোষণা না করলে package_problems সেটা অনুপস্থিত বলে। কার্ড Hub-এর মেটাডেটা ও সেকশন তালিকা অনুসরণ করে, মূল্যায়নের ফল ছাড়া লেখা প্রত্যাখ্যান করে, আর সিমুলেটেড সংখ্যাকে সিমুলেটেড বলে চিহ্নিত করে।
cat pack_mixed/adapter_meta.json
sed -n '/^## Model/,/^## Intended/p;/^## Evaluation/,$p' pack_mixed/README.md{
"base_model": "example-org/small-base",
"base_revision": "a1b2c3d",
"dataset_sha256": "57d5c220ace9b083886b1b247ded0cea89db97d5cba11be358f00f84539e6b60",
"experiment": "981d04da2e20",
"licence": "apache-2.0",
"lora_alpha": 16,
"name": "kestrel-style",
"peft_type": "LORA",
"previous": "prompt-v2",
"r": 8,
"target_modules": "all-linear",
"version": "0.1.0"
}
## Model
A LoRA adapter for `example-org/small-base` at revision `a1b2c3d`. It needs that base model to work.
Release decision: **keep** (on simulated results). Rights review: no_blockers_found (not legal advice).
## Intended uses and limitations
## Evaluation results
**SIMULATED numbers: no model was trained for this card.**
```text
set n base tuned gain 95% interval better worse p
regression 31 0.90 0.90 +0.00 [0.77, 1.00] 0 0 1.000
safety 8 1.00 1.00 +0.00 [1.00, 1.00] 0 0 1.000
target 24 0.33 0.96 +0.62 [0.88, 1.00] 15 0 0.000
```মার্জ করা সাধারণ যোগ (LoraLayer.merged; একটা টেস্ট আপডেট বিয়োগ করে বেস ফিরে পায়), তাই মার্জ করা কি না সেটা অপারেশনের সিদ্ধান্ত। merge_advice অ্যাডাপ্টার আলাদা রাখে যখন দ্রুত রোলব্যাক দরকার, এক বেসে একাধিক অ্যাডাপ্টার চালাতে হয়, বা প্রকাশ্যে শেয়ার করতে হয় (মার্জ-করা মডেল বেস ওয়েটের পূর্ণ কপি এবং তার লাইসেন্সের শর্ত বহন করে); সার্ভার অ্যাডাপ্টার লোড করতে না পারলে মার্জ করে; আর কিছু যাচাই না হলে বা বেস কোয়ান্টাইজড হলে বলে আগে পরীক্ষা করুন, কারণ রাউন্ডিং বদলায় (আপনার স্ট্যাকের জন্য VERIFY)।
from evidencedesk.finetune.package import MergeFacts, merge_advice
for label, facts in {"nothing checked": MergeFacts(),
"rollback needed": MergeFacts(server_loads_adapters=True),
"server cannot load adapters": MergeFacts(server_loads_adapters=False, need_swap_or_rollback=False),
"quantised base": MergeFacts(server_loads_adapters=True, need_swap_or_rollback=False, base_quantised=True)}.items():
choice, why = merge_advice(facts)
print(f"{label:<28}{choice:<14}{why[0]}")nothing checked test_first find out whether your serving stack loads adapters: not checked
rollback needed keep_separate you need to swap or roll back quickly: the adapter file is the rollback
server cannot load adapters merge the server cannot load adapters; keep the adapter file and the base revision as the source of truth
quantised base test_first merging into a quantised base changes rounding: compare outputs before trusting it (VERIFY for your stack)মিনি-ল্যাব: ফাইন-টিউনিং সিদ্ধান্ত ও মূল্যায়ন প্যাক
ডেলিভারেবল একটা সিদ্ধান্ত-মেমো, একটা যাচাই-করা ডেটাসেট, একটা বেসলাইন তুলনা, আর হয় একটা ছোট অ্যাডাপ্টার এক্সপেরিমেন্ট নয়তো সম্পূর্ণ পুনরুৎপাদনযোগ্য ড্রাই-রান রিপোর্ট। এই পাতার প্যাক ড্রাই-রান ভার্সন। pack_problems দেখে প্রতিটা ফাইল আছে, কার্ড সম্পূর্ণ, কোনো ওয়েটের দাবি নেই, রেকর্ড পরিষ্কার, রায় যাচাইগুলো থেকে আসে আর তুলনা সিমুলেটেড বলে লেবেল করা।
cd kit && python -m pytest tests/test_finetune_peft_record.py tests/test_finetune_peft_eval.py tests/test_finetune_peft_rights.py tests/test_finetune_peft_pack.py | tail -n 1 | sed 's/ in [0-9.]*s//'28 passedfrom evidencedesk.finetune.pack import pack_problems
print({d: pack_problems(Path(d)) for d in ("pack_narrow", "pack_mixed")}){'pack_narrow': [], 'pack_mixed': []}আসল অ্যাডাপ্টারের জন্য: প্যাকেজ থাকলে train_lora.py দিয়ে ট্রেন করুন, SimModel-এর জায়গায় আপনার মডেলের কল বসান, আর উদাহরণ অধিকার-উত্তরের জায়গায় আপনি যা পড়েছেন তা বসান।
কাজের জায়গায় এটা কোথায় দেখা যায়
পুনের প্রিয়া একটা সাপোর্ট সার্ভিসে অ্যাডাপ্টার যোগ করা পুল রিকোয়েস্ট পর্যালোচনা করে। সে ওয়েট খোলে না। সে খোলে এক্সপেরিমেন্ট রেকর্ড (পিন-করা রিভিশন, লাইসেন্স স্ন্যাপশট, ডেটাসেট হ্যাশ), তুলনা (কোন আইটেম খারাপ হলো), অধিকার ফাইল (কী পড়া হয়েছে আর কী ধরে নেওয়া হয়েছে) আর রোলব্যাক পথ। একটা না থাকলে সেটা "হোল্ড", ডেমো যেমনই দেখাক।
সাধারণ ভুল
- মডেল বা সেটিংস যে ডেটা দেখেছে তাতে তুলনা করা। স্কোর আশাবাদী হয়। নতুন আইটেম ব্যবহার করুন, সেটিংস ভ্যালিডেশনে বাছুন, টেস্ট একবারই স্কোর করুন।
- শুধু উন্নতির কথা বলা। এক আচরণের জন্য টিউন করলে আরেকটার দাম দিতে হতে পারে। রিগ্রেশন ও সেফটি সেট চালান আর কে খারাপ হলো তার তালিকা দিন।
- ক্ষতির ক্ষেত্রে তাৎপর্যের অপেক্ষা করা। ছোট সেটে রিগ্রেশন দেখা যায় না। পতনের পরিমাণ ও নতুন ব্যর্থতার সংখ্যায় গেট দিন, আর সেট বড় করুন।
- ফল দেখার পরে গেট সরানো। ফলের সঙ্গে মেলানো সীমা গেট নয়। রেকর্ডে স্থির করুন।
- লাইসেন্সের নামকে ছাড়পত্র ভাবা। "Apache-2.0" বা "ওপেন ওয়েট" পর্যালোচনা শুরু করে মাত্র। আপনার রিভিশনের টেক্সট পড়ুন আর তারিখ লিখুন।
নিজে চেষ্টা করুন
- সহজ। ফাইন-টিউনিংয়ের সিদ্ধান্ত ও LoRA-র ধারণা আবার দেখুন। কাল্পনিক আর্কিটেকচারের আটটা লেয়ারেই
q_proj(৫১২ বাই ৫১২) ওk_proj(২৫৬ বাই ৫১২)-এ র্যাংক ৮-এর ট্রেনযোগ্য প্যারামিটার হাতে হিসাব করুন, তারপরlora_countsদিয়ে মেলান। - মাঝারি। রুব্রিক, রিগ্রেশন ও রিলিজ গেট আবার দেখুন।
max_drop০.১২-তে শিথিল করে narrow অ্যাডাপ্টারের যাচাই আবার চালান। কী বদলায়, কী বদলায় না, আর রেকর্ড কী বলে? - কঠিন (মিনি-ল্যাব)। একজন পর্যালোচক বেস মডেলের লাইসেন্স পড়ে দেখলেন বাণিজ্যিক ব্যবহার অনুমোদিত নয়, অথচ পরিকল্পনা বাণিজ্যিক। ওই উত্তর দিয়ে
tuned-mixed-এর প্যাক বানান, নিশ্চিত করুন প্যাক সম্পূর্ণ কিন্তু রায় "রাখুন" নয়, আরDecisionRecordদিয়ে একটা মেমো লিখুন।
উত্তর
সহজ। প্রতি লেয়ারে r (d_in + d_out): q_proj-এর জন্য ৮ × ১,০২৪, k_proj-এর জন্য ৮ × ৭৬৮; আট লেয়ারে গুণ।
from evidencedesk.finetune.lora import lora_params
from evidencedesk.finetune.resources import HYPOTHETICAL_LAYER, lora_counts
by_hand = 8 * lora_params(512, 512, 8) + 8 * lora_params(256, 512, 8) # 8 layers: q_proj (512x512) and k_proj (256x512)
tool = lora_counts(8, HYPOTHETICAL_LAYER, ("q_proj", "k_proj"), 8)[0]
print(by_hand, tool, by_hand == tool)114688 114688 Trueমাঝারি। রিগ্রেশন যাচাই পাস করে, সেফটি তবু ব্যর্থ, তাই রায় roll_back-ই থাকে; আর "gate frozen" ব্যর্থ হয় কারণ সীমাগুলো আর রেকর্ড-করাগুলোর সমান নয়। একটা ফলের সঙ্গে মিলিয়ে গেট শিথিল করা ধরা পড়ে, আর তা সেফটি ব্যর্থতা লুকোয় না।
from evidencedesk.finetune.adapter_gate import Gate, decide
from evidencedesk.finetune.pack import release_checks
from evidencedesk.finetune.checks import overfit_report
relaxed = Gate(max_drop=0.12) # moved AFTER seeing a 0.10 drop: the thing a gate must not allow
checks = release_checks(exp, comp, relaxed, overfit_report(log, up_to=400), [], r2, True)
print([(c.name, c.ok) for c in checks if not c.ok or c.name == "regression"])
print(decide(checks).verdict)[('regression', True), ('safety', False), ('gate frozen', False)]
roll_backকঠিন। প্রমাণের প্রতিটা যাচাই পাস করে, অধিকারের যাচাই ব্যর্থ হয় (আটকানো ফাইন্ডিংটা commercial_use), তাই রায় hold। প্যাক সম্পূর্ণ, মেমো prompt বাছে আর তার নিজের চেকার ঠিক করার কিছু পায় না। যে বেস মডেল বাণিজ্যিকভাবে ব্যবহার করতে পারেন না, তার ওপর ভালো অ্যাডাপ্টারও রিলিজ হয় না।
from evidencedesk.finetune.decide import DecisionRecord
from evidencedesk.finetune.pack import build_pack, pack_problems
from evidencedesk.finetune.rights import Answers
no_commercial = Answers(False, True, True, True, "none stated", True, True) # the reviewer read: commercial use is not allowed
d = build_pack(Path("pack_lab"), "tuned-mixed", no_commercial)
print(d.verdict, [c.name for c in d.checks if not c.ok], pack_problems(Path("pack_lab")))
memo = DecisionRecord(id="dec-002", date="2026-10-13", problem="Replies differ in tone (scenario s05).", symptom="style_inconsistent",
options=["prompt", "fine_tune"], decision="prompt",
evidence=["adapter passes every evidence check (simulated)", "base-model licence forbids the planned commercial use"],
risks=["style stays inconsistent until the prompt is tuned"], review_when="a base model with a usable licence is chosen",
baseline="kestrel-v2")
print("memo problems:", memo.problems(), "| decision:", memo.decision)hold ['rights'] []
memo problems: [] | decision: promptপাস চেকলিস্ট:
- সহজ: দুই পথেই 114,688, আর আপনি বলতে পারেন কেন
k_projq_proj-এর চেয়ে কম যোগ করে। - মাঝারি: রিগ্রেশন পাস, সেফটি ব্যর্থ, রায়
roll_back, আর আপনি স্থির গেটকে সেই কারণ বলেছেন যেটায় সরানোটা দেখা যায়। - কঠিন: রায়
hold, ব্যর্থ যাচাইrights, খালি সমস্যা-তালিকা, আর এমন একটা মেমো যার সিদ্ধান্তpromptএবং প্রমাণ লাইসেন্স।
সারসংক্ষেপ
- আগে এক্সপেরিমেন্ট রেকর্ড লিখুন: পিন-করা বেস রিভিশন, লাইসেন্স স্ন্যাপশট, ডেটাসেট হ্যাশ, সিড, সেটিংস, গেট ও ফলব্যাক ভার্সন। পাহারা-দেওয়া স্ক্রিপ্ট এগুলো ও প্যাকেজ ছাড়া শুরু করতে অস্বীকার করে।
- আকার থেকে ট্রেনযোগ্য প্যারামিটার গুনুন, স্কিপ শর্তসহ CPU বা নোটবুক রান পরিকল্পনা করুন, আর যে সময় বা মেমরি মাপেননি তা বলবেন না। মূল ল্যাবের শুধু একটা আগে-হিসাব-করা লগ ও সংরক্ষিত মেটাডেটা লাগে।
- একই নতুন হোল্ডআউট আইটেমে, রিগ্রেশন ও সেফটি সেটসহ, বেস ও টিউন-করা মডেল তুলনা করুন এবং কে খারাপ হলো তার তালিকা দিন। ছোট সেট নিরাপত্তা প্রমাণ করতে পারে না: পতনের পরিমাণ ও নতুন ব্যর্থতায় গেট দিন।
- ওভারফিটিং পড়ুন ভ্যালিডেশন কার্ভ থেকে, লিকেজ মিল ও পুনরাবৃত্তি থেকে। অধিকার পর্যালোচনা করুন পড়ে, যা পড়া হয়নি তা লিখে রাখুন, আর মনে রাখুন ওপেন ওয়েট মানে ওপেন সোর্স নয় এবং এটা আইনি পরামর্শ নয়।
- আগে-থেকে-স্থির গেটে সিদ্ধান্ত নিন: প্রমাণের ব্যর্থতা রোলব্যাক, কাগজের ব্যর্থতা হোল্ড, সব পাস করলে রাখা। মার্জ করুন শুধু স্পষ্ট করে বলা যায় এমন কারণে।
এরপর: স্ট্রাকচার্ড লগিং ও ট্রেসিং পাতায় প্রোডাকশনে অ্যাসিস্ট্যান্ট চালানোর কথা: খুঁজে পাওয়া যায় এমন ইভেন্ট ও স্প্যান, আর কী কখনো লগ করা চলবে না তার স্পষ্ট নিয়ম।