Text Generation
Transformers
Safetensors
Turkish
qwen3
turkish
türkçe
continued-pretraining
turkish-llm
türkçe-dil-modeli
conversational
Eval Results (legacy)
text-generation-inference
Instructions to use ecloudtech/Erk-32B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ecloudtech/Erk-32B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="ecloudtech/Erk-32B") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("ecloudtech/Erk-32B") model = AutoModelForCausalLM.from_pretrained("ecloudtech/Erk-32B", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use ecloudtech/Erk-32B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "ecloudtech/Erk-32B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ecloudtech/Erk-32B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/ecloudtech/Erk-32B
- SGLang
How to use ecloudtech/Erk-32B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "ecloudtech/Erk-32B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ecloudtech/Erk-32B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "ecloudtech/Erk-32B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ecloudtech/Erk-32B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use ecloudtech/Erk-32B with Docker Model Runner:
docker model run hf.co/ecloudtech/Erk-32B
egitim/: v2 betikleri ve veri ozetleri
Browse files- egitim/dogal_egitim32.py +198 -0
egitim/dogal_egitim32.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""Dogal-CPT (32B surumu): Erk-32B'ye (birlesik-075) DOGAL Turkce metinle (FineWeb-2 tur_Latn, gorulmemis parcalar) tam-parametre devam egitimi.
|
| 3 |
+
|
| 4 |
+
NEDEN BU RECETE
|
| 5 |
+
Iki onceki recete (sozluk genisletme, sentetik kural-CPT) on-kayitli olcutleri gecemedi. Teshis: Erk'in
|
| 6 |
+
acigi istisna kovalarinda (unlu dusmesi, uyum kirici, ikizlesme, kisaltma, sayi) — bunlar SOZLUKSEL bilgi,
|
| 7 |
+
sablonla ogretilemez; dogal metinde dogal sikliklariyla gorulerek ogrenilir (2B Turkce-yerli modellerin yolu).
|
| 8 |
+
Sentetik veri tamami duzenli uyum ornegi oldugu icin uyum-kirici kovasini GERILETMISTI; dogal metinde bu
|
| 9 |
+
yanlilik yok.
|
| 10 |
+
Teknik duzeltme: onceki egitimler saf bf16 AdamW ile lr 1e-5 kullandi; bf16'da 1e-5'lik guncelleme cogu
|
| 11 |
+
agirlik icin yarim ulp'nin altinda kalir ve YUVARLANIR (agirlik_degisim.py teshisi). Burada fp32 ANA
|
| 12 |
+
AGIRLIK tutulur: ileri/geri bf16, optimizer fp32, her adimda bf16'ya kopyalanir.
|
| 13 |
+
|
| 14 |
+
VERI
|
| 15 |
+
dogal_metin.txt (dogal_secim.py: %70 rastgele paragraf + %30 kesme-isaretli-cekim yogun paragraf; kiyas
|
| 16 |
+
maddesi/sablonu/govde listesi/TDK sozlugu KULLANILMADI; sozluk-maddesi gorunumlu satirlar atildi).
|
| 17 |
+
Sohbet yetenegini korumak icin ~her 12 paragrafta bir SFT konusmasi (sft_clean_v2, sohbet sablonuyla).
|
| 18 |
+
|
| 19 |
+
ON-KAYITLI BASARI OLCUTLERI (sonuca bakilmadan yazildi; karar DEV kesitinde, cekirdek bir kez olculur)
|
| 20 |
+
A) TurkishMMLU, ayni betik, ayni 652 soru: dogal >= taban - 1,0 puan
|
| 21 |
+
B) DEV kesiti (2.000 cekirdek-disi madde, kova oranlari cekirdekle ayni): hucre-kumeli esli fark
|
| 22 |
+
anlamli pozitif VE >= +1,5 puan
|
| 23 |
+
C) DEV'de hicbir kovada anlamli gerileme yok
|
| 24 |
+
Ucu gecerse 3.6 cekirdegi BIR KEZ olculur ve tabloya o sayi girer; ayni recete 32B'ye uygulanir.
|
| 25 |
+
Gecmezse model yayimlanmaz, 32B'ye uygulanmaz. Kontrol noktasi secimi de yalniz DEV ile yapilir.
|
| 26 |
+
"""
|
| 27 |
+
import os, random, time, json, torch, torch.nn.functional as F
|
| 28 |
+
from torch.utils.data import DataLoader, Dataset
|
| 29 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 30 |
+
|
| 31 |
+
MODEL = os.environ.get("MODEL", "/ari/users/ytanis/erk32b-birlesik-075")
|
| 32 |
+
GENEL = os.environ.get("GENEL", "/ari/users/ytanis/dogal_metin.txt")
|
| 33 |
+
SFT = os.environ.get("SFT", "/ari/users/ytanis/erk/sft_clean_v2.jsonl")
|
| 34 |
+
CIK = os.environ.get("CIK", "/ari/users/ytanis/erk32b-dogal")
|
| 35 |
+
OPT = os.environ.get("OPT", "adafactor_sr") # adafactor_sr: fp32 ana agirlik YOK, bf16 parametre + KARARLI (stokastik) YUVARLAMA # 32B: Adam durumlari (256 GB) 4xA100'a sigmaz; Adafactor faktorlu durum, fp32 ana agirlik korunur
|
| 36 |
+
KAYDET = os.environ.get("KAYDET", "1") == "1"
|
| 37 |
+
UZUNLUK = int(os.environ.get("UZUNLUK", "1024"))
|
| 38 |
+
ADIM = int(os.environ.get("ADIM", "9000"))
|
| 39 |
+
YIGIN = int(os.environ.get("YIGIN", "2")); BIRIKIM = int(os.environ.get("BIRIKIM", "8"))
|
| 40 |
+
LR = float(os.environ.get("LR", "1e-5"))
|
| 41 |
+
SFT_HER = int(os.environ.get("SFT_HER", "12"))
|
| 42 |
+
SENTETIK = os.environ.get("SENTETIK", "") # tur 2: kural cumleleri (kisaltma/sayi/cati), kiyas govdeleri DISLANMIS
|
| 43 |
+
SENTETIK_ORAN = float(os.environ.get("SENTETIK_ORAN", "0.0"))
|
| 44 |
+
SURE_DK = float(os.environ.get("SURE_DK", "1560")); KAYIT_HER = int(os.environ.get("KAYIT_HER", "3000"))
|
| 45 |
+
yaz = lambda *a: print(*a, flush=True)
|
| 46 |
+
t_bas = time.time()
|
| 47 |
+
if not torch.cuda.is_available(): raise SystemExit("CUDA yok")
|
| 48 |
+
tok = AutoTokenizer.from_pretrained(MODEL)
|
| 49 |
+
model = AutoModelForCausalLM.from_pretrained(MODEL, dtype=torch.bfloat16, device_map="balanced")
|
| 50 |
+
model.gradient_checkpointing_enable(); model.config.use_cache = False
|
| 51 |
+
aygit = model.get_input_embeddings().weight.device
|
| 52 |
+
yaz("model yerlesimi:", sorted({str(p.device) for p in model.parameters()}))
|
| 53 |
+
|
| 54 |
+
class Karisim(Dataset):
|
| 55 |
+
def __init__(self, n_blok):
|
| 56 |
+
rng = random.Random(20260926)
|
| 57 |
+
sft_f = open(SFT, encoding="utf8"); self.blok, tampon, say, n_sft, n_sent = [], [], 0, 0, 0
|
| 58 |
+
sent = []
|
| 59 |
+
if SENTETIK:
|
| 60 |
+
sent = [l.strip() for l in open(SENTETIK, encoding="utf8", errors="ignore") if l.strip()]; rng.shuffle(sent)
|
| 61 |
+
with open(GENEL, encoding="utf8", errors="ignore") as f:
|
| 62 |
+
for satir in f:
|
| 63 |
+
say += 1
|
| 64 |
+
if sent and rng.random() < SENTETIK_ORAN:
|
| 65 |
+
# bir paragraf yerine 3-6 kural cumlesi (tek satir), dogal metnin arasina serpistirilir
|
| 66 |
+
k = rng.randint(3, 6); satir = " ".join(sent[n_sent % len(sent): n_sent % len(sent) + k]) + "\n"; n_sent += k
|
| 67 |
+
elif say % SFT_HER == 0:
|
| 68 |
+
ln = sft_f.readline()
|
| 69 |
+
if ln:
|
| 70 |
+
try:
|
| 71 |
+
msg = json.loads(ln)["messages"]
|
| 72 |
+
satir = tok.apply_chat_template(msg, tokenize=False) + "\n"; n_sft += 1
|
| 73 |
+
except Exception: pass
|
| 74 |
+
tampon += tok(satir, add_special_tokens=False).input_ids + [tok.eos_token_id]
|
| 75 |
+
while len(tampon) >= UZUNLUK + 1:
|
| 76 |
+
self.blok.append(tampon[:UZUNLUK + 1]); tampon = tampon[UZUNLUK:]
|
| 77 |
+
if len(self.blok) >= n_blok:
|
| 78 |
+
yaz("veri: %d blok · %d paragraf · %d SFT konusmasi · %d sentetik cumle" % (len(self.blok), say, n_sft, n_sent)); return
|
| 79 |
+
yaz("veri: %d blok (dosya bitti) · %d paragraf · %d SFT · %d sentetik" % (len(self.blok), say, n_sft, n_sent))
|
| 80 |
+
def __len__(self): return len(self.blok)
|
| 81 |
+
def __getitem__(self, i):
|
| 82 |
+
b = torch.tensor(self.blok[i]); return b[:-1], b[1:]
|
| 83 |
+
|
| 84 |
+
veri = Karisim(ADIM * YIGIN * BIRIKIM + 500)
|
| 85 |
+
dl = DataLoader(veri, batch_size=YIGIN, shuffle=True, num_workers=4, drop_last=True)
|
| 86 |
+
|
| 87 |
+
def ara_kayit(et):
|
| 88 |
+
y = CIK + "-" + et; os.makedirs(y, exist_ok=True)
|
| 89 |
+
model.save_pretrained(y, safe_serialization=True); tok.save_pretrained(y); yaz(" ara kayit:", y)
|
| 90 |
+
|
| 91 |
+
for p in model.parameters(): p.requires_grad = True
|
| 92 |
+
egitilen = [p for p in model.parameters()]
|
| 93 |
+
ANA = OPT != "adafactor_sr"
|
| 94 |
+
if ANA:
|
| 95 |
+
# fp32 ana agirliklar (ayni aygitta), optimizer bunlarin uzerinde
|
| 96 |
+
ana = [p.detach().to(torch.float32).clone() for p in egitilen]
|
| 97 |
+
for m in ana: m.requires_grad = True
|
| 98 |
+
else:
|
| 99 |
+
ana = egitilen
|
| 100 |
+
|
| 101 |
+
def sr_bf16(x32):
|
| 102 |
+
"""fp32 -> bf16 KARARLI yuvarlama: alt 16 bite rastgele ekle, sonra kes. Kucuk guncellemeler
|
| 103 |
+
ortalamada korunur (deterministik yuvarlama 1e-5'lik guncellemeyi cogu agirlikta yutar)."""
|
| 104 |
+
b = x32.view(torch.int32)
|
| 105 |
+
b = b + torch.randint(0, 1 << 16, b.shape, device=b.device, dtype=torch.int32)
|
| 106 |
+
return (b & -65536).view(torch.float32).to(torch.bfloat16)
|
| 107 |
+
|
| 108 |
+
if OPT == "adafactor_sr":
|
| 109 |
+
import math
|
| 110 |
+
from transformers.optimization import Adafactor
|
| 111 |
+
class AdafactorSR(Adafactor):
|
| 112 |
+
"""transformers 5.13 Adafactor.step ile birebir; tek fark: bf16 parametreye geri yazarken sr_bf16."""
|
| 113 |
+
@torch.no_grad()
|
| 114 |
+
def step(self, closure=None):
|
| 115 |
+
for group in self.param_groups:
|
| 116 |
+
for p in group["params"]:
|
| 117 |
+
if p.grad is None: continue
|
| 118 |
+
grad = p.grad.float() if p.grad.dtype in (torch.float16, torch.bfloat16) else p.grad
|
| 119 |
+
state = self.state[p]; grad_shape = grad.shape
|
| 120 |
+
factored, use_first_moment = self._get_options(group, grad_shape)
|
| 121 |
+
if len(state) == 0:
|
| 122 |
+
state["step"] = 0
|
| 123 |
+
if use_first_moment: state["exp_avg"] = torch.zeros_like(grad)
|
| 124 |
+
if factored:
|
| 125 |
+
state["exp_avg_sq_row"] = torch.zeros(grad_shape[:-1]).to(grad)
|
| 126 |
+
state["exp_avg_sq_col"] = torch.zeros(grad_shape[:-2] + grad_shape[-1:]).to(grad)
|
| 127 |
+
else: state["exp_avg_sq"] = torch.zeros_like(grad)
|
| 128 |
+
state["RMS"] = 0
|
| 129 |
+
p32 = p.float()
|
| 130 |
+
state["step"] += 1; state["RMS"] = self._rms(p32); lr = self._get_lr(group, state)
|
| 131 |
+
beta2t = 1.0 - math.pow(state["step"], group["decay_rate"])
|
| 132 |
+
update = (grad ** 2) + group["eps"][0]
|
| 133 |
+
if factored:
|
| 134 |
+
r, c = state["exp_avg_sq_row"], state["exp_avg_sq_col"]
|
| 135 |
+
r.mul_(beta2t).add_(update.mean(dim=-1), alpha=(1.0 - beta2t))
|
| 136 |
+
c.mul_(beta2t).add_(update.mean(dim=-2), alpha=(1.0 - beta2t))
|
| 137 |
+
update = self._approx_sq_grad(r, c); update.mul_(grad)
|
| 138 |
+
else:
|
| 139 |
+
v = state["exp_avg_sq"]; v.mul_(beta2t).add_(update, alpha=(1.0 - beta2t)); update = v.rsqrt().mul_(grad)
|
| 140 |
+
update.div_((self._rms(update) / group["clip_threshold"]).clamp_(min=1.0)); update.mul_(lr)
|
| 141 |
+
if use_first_moment:
|
| 142 |
+
e = state["exp_avg"]; e.mul_(group["beta1"]).add_(update, alpha=(1 - group["beta1"])); update = e
|
| 143 |
+
if group["weight_decay"] != 0: p32.add_(p32, alpha=(-group["weight_decay"] * lr))
|
| 144 |
+
p32.add_(-update)
|
| 145 |
+
p.copy_(sr_bf16(p32) if p.dtype == torch.bfloat16 else p32)
|
| 146 |
+
del p32, update
|
| 147 |
+
return None
|
| 148 |
+
opt = AdafactorSR(ana, lr=LR, scale_parameter=False, relative_step=False, warmup_init=False, weight_decay=0.01, beta1=None)
|
| 149 |
+
elif OPT == "adafactor":
|
| 150 |
+
from transformers.optimization import Adafactor
|
| 151 |
+
opt = Adafactor(ana, lr=LR, scale_parameter=False, relative_step=False, warmup_init=False, weight_decay=0.01, beta1=None)
|
| 152 |
+
else:
|
| 153 |
+
opt = torch.optim.AdamW(ana, lr=LR, weight_decay=0.01, foreach=False)
|
| 154 |
+
plan = torch.optim.lr_scheduler.OneCycleLR(opt, max_lr=LR, total_steps=ADIM, pct_start=0.05, cycle_momentum=(OPT not in ("adafactor", "adafactor_sr")))
|
| 155 |
+
yaz("=== DOGAL-CPT-32B · optimizer %s" % OPT)
|
| 156 |
+
yaz("=== DOGAL-CPT · %d adim · %d jeton/adim · lr %.1e · %s · %.2f B parametre"
|
| 157 |
+
% (ADIM, UZUNLUK * YIGIN * BIRIKIM, LR, "fp32 ana agirlik" if ANA else "bf16 + kararli yuvarlama", sum(p.numel() for p in egitilen) / 1e9))
|
| 158 |
+
try:
|
| 159 |
+
for g in range(torch.cuda.device_count()):
|
| 160 |
+
yaz(" kart %d: %.1f / %.1f GB" % (g, torch.cuda.memory_allocated(g) / 2**30, torch.cuda.get_device_properties(g).total_memory / 2**30))
|
| 161 |
+
except Exception as e: yaz(" (bellek raporu yok: %s)" % e)
|
| 162 |
+
|
| 163 |
+
model.train(); i = biriken = 0; t0 = time.time(); kayip = None; degisen_ilk = None
|
| 164 |
+
while i < ADIM:
|
| 165 |
+
for x, y in dl:
|
| 166 |
+
if i >= ADIM: break
|
| 167 |
+
lg = model(input_ids=x.to(aygit)).logits
|
| 168 |
+
kayip = F.cross_entropy(lg.float().view(-1, lg.size(-1)), y.to(lg.device).view(-1))
|
| 169 |
+
(kayip / BIRIKIM).backward(); biriken += 1
|
| 170 |
+
if biriken == BIRIKIM:
|
| 171 |
+
torch.nn.utils.clip_grad_norm_(egitilen, 1.0)
|
| 172 |
+
if ANA:
|
| 173 |
+
with torch.no_grad():
|
| 174 |
+
for m, p in zip(ana, egitilen):
|
| 175 |
+
m.grad = p.grad.to(torch.float32); p.grad = None
|
| 176 |
+
with torch.no_grad():
|
| 177 |
+
if i == 0: p0 = egitilen[len(egitilen)//2]; once = p0.detach().clone()
|
| 178 |
+
opt.step(); plan.step(); opt.zero_grad(set_to_none=True)
|
| 179 |
+
with torch.no_grad():
|
| 180 |
+
if ANA:
|
| 181 |
+
for m, p in zip(ana, egitilen): p.copy_(m.to(p.dtype))
|
| 182 |
+
if i == 0:
|
| 183 |
+
yaz(" ilk adimda bf16'da degisen agirlik orani (orta katman): %.4f" % (p0 != once).float().mean().item())
|
| 184 |
+
biriken = 0; i += 1
|
| 185 |
+
if i % 100 == 0:
|
| 186 |
+
yaz(" adim %5d/%d | kayip %.4f | %.1f dk | %.0f jeton/sn" % (i, ADIM, float(kayip), (time.time() - t0) / 60,
|
| 187 |
+
i * UZUNLUK * YIGIN * BIRIKIM / (time.time() - t0)))
|
| 188 |
+
if i % KAYIT_HER == 0 and KAYDET: ara_kayit("adim%d" % i)
|
| 189 |
+
if i == 3 or i % 500 == 0:
|
| 190 |
+
try: yaz(" bellek zirve:", " ".join("%d:%.0fGB" % (g, torch.cuda.max_memory_allocated(g)/2**30) for g in range(torch.cuda.device_count())))
|
| 191 |
+
except Exception: pass
|
| 192 |
+
if (time.time() - t_bas) / 60 > SURE_DK:
|
| 193 |
+
yaz(" !! sure butcesi doldu, %d. adimda kesiliyor" % i); i = ADIM; break
|
| 194 |
+
|
| 195 |
+
model.config.use_cache = True
|
| 196 |
+
if KAYDET:
|
| 197 |
+
os.makedirs(CIK, exist_ok=True); model.save_pretrained(CIK, safe_serialization=True); tok.save_pretrained(CIK)
|
| 198 |
+
yaz("yazildi: %s (%.1f dk)" % (CIK, (time.time() - t_bas) / 60))
|