Translation
Transformers
Safetensors
llama
text-generation
multilingual
lora
astheraltranslate
text-generation-inference
Instructions to use SEE7/AstheralTranslate with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use SEE7/AstheralTranslate with Transformers:
# Use a pipeline as a high-level helper # Warning: Pipeline type "translation" is no longer supported in transformers v5. # You must load the model directly (see below) or downgrade to v4.x with: # pip install "transformers<5.0.0" from transformers import pipeline pipe = pipeline("translation", model="SEE7/AstheralTranslate")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("SEE7/AstheralTranslate") model = AutoModelForCausalLM.from_pretrained("SEE7/AstheralTranslate", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 6,656 Bytes
656ef99 caefe89 656ef99 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | import os,json,time,random,gc,hashlib
from pathlib import Path
import torch
from datasets import load_dataset
from transformers import AutoTokenizer,AutoModelForCausalLM,Trainer,TrainingArguments,set_seed
from peft import LoraConfig,get_peft_model
from huggingface_hub import HfApi,hf_hub_download
from sacrebleu.metrics import CHRF,BLEU
BASE='utter-project/EuroLLM-1.7B';REPO='SEE7/AstheralTranslate';DATA='Helsinki-NLP/opus-100'
api=HfApi();rev=api.model_info(BASE).sha;datarev=api.dataset_info(DATA).sha
out=Path('/tmp/translate');out.mkdir(exist_ok=True)
set_seed(42);rng=random.Random(42);start=time.monotonic()
langs={'de':'German','fr':'French','es':'Spanish','it':'Italian','pt':'Portuguese'}
tok=AutoTokenizer.from_pretrained(BASE,revision=rev);tok.pad_token=tok.eos_token;tok.padding_side='left'
def prompt(text,lang):return 'Translate from English to '+langs[lang]+'. Return only the translation.\nEnglish: '+text.strip()+'\n'+langs[lang]+':'
train=[];tests=[];seen=set()
for lang in langs:
conf='-'.join(sorted(['en',lang]))
ds=load_dataset(DATA,conf,split='train',revision=datarev)
ds=ds.shuffle(seed=42)
count=0
for row in ds:
x=row['translation'];a=x['en'].strip();b=x[lang].strip()
if not (8<=len(a)<=600 and 4<=len(b)<=700):continue
key=(lang,a,b)
if key in seen:continue
pre=tok(prompt(a,lang),add_special_tokens=True)['input_ids']
answer=tok(' '+b+tok.eos_token,add_special_tokens=False)['input_ids']
if len(pre)+len(answer)>256:continue
seen.add(key);train.append({'input_ids':pre+answer,'labels':[-100]*len(pre)+answer,'source':a,'target':b,'language':lang})
count+=1
if count==2000:break
print('DATA',lang,count,flush=True)
test=load_dataset(DATA,conf,split='test',revision=datarev)
for row in test:
x=row['translation'];a=x['en'].strip();b=x[lang].strip()
if 8<=len(a)<=300 and 4<=len(b)<=400 and (lang,a,b) not in seen:
tests.append({'source':a,'reference':b,'language':lang})
if sum(t['language']==lang for t in tests)==25:break
assert len(tests)==125
rng.shuffle(train)
(out/'training_manifest.json').write_text(json.dumps({'base':BASE,'revision':rev,'dataset':DATA,'dataset_revision':datarev,'examples':len(train),'per_language':2000,'seed':42,'sha256':hashlib.sha256(json.dumps(train,sort_keys=True).encode()).hexdigest()},indent=2))
model=AutoModelForCausalLM.from_pretrained(BASE,revision=rev,torch_dtype=torch.bfloat16,device_map={'':'cuda'},attn_implementation='sdpa').eval()
report={'base':BASE,'base_revision':rev,'dataset_revision':datarev,'parameters':sum(p.numel() for p in model.parameters()),'languages':langs,'hardware':torch.cuda.get_device_name(),'training_examples':len(train)}
@torch.inference_mode()
def evaluate(label):
rows=[]
for i,t in enumerate(tests):
x=tok(prompt(t['source'],t['language']),return_tensors='pt').to('cuda')
y=model.generate(**x,max_new_tokens=128,do_sample=False,pad_token_id=tok.pad_token_id,eos_token_id=tok.eos_token_id)
raw=tok.decode(y[0,x['input_ids'].shape[1]:],skip_special_tokens=True)
pred=raw.strip().split('\n')[0].strip()
rows.append({**t,'prediction':pred,'raw':raw,'generated_tokens':int(y.shape[1]-x['input_ids'].shape[1])})
if i%10==0:print('EVAL',label,i,flush=True)
scores={}
for lang in langs:
r=[r for r in rows if r['language']==lang];hyp=[r['prediction'] for r in r];refs=[[r['reference'] for r in r]]
scores[lang]={'chrf':CHRF().corpus_score(hyp,refs).score,'bleu':BLEU().corpus_score(hyp,refs).score,'n':len(r)}
(out/(label+'_outputs.json')).write_text(json.dumps(rows,ensure_ascii=False,indent=2))
print('SCORES',label,json.dumps(scores),flush=True)
return scores
report['base_scores']=evaluate('base')
model=get_peft_model(model,LoraConfig(r=32,lora_alpha=64,lora_dropout=0.05,target_modules=['q_proj','k_proj','v_proj','o_proj','gate_proj','up_proj','down_proj'],task_type='CAUSAL_LM'))
report['trainable_parameters']=sum(p.numel() for p in model.parameters() if p.requires_grad)
model.config.use_cache=False
def collate(rows):
length=max(len(r['input_ids']) for r in rows)
return {'input_ids':torch.tensor([[tok.pad_token_id]*(length-len(r['input_ids']))+r['input_ids'] for r in rows]),'labels':torch.tensor([[-100]*(length-len(r['labels']))+r['labels'] for r in rows]),'attention_mask':torch.tensor([[0]*(length-len(r['input_ids']))+[1]*len(r['input_ids']) for r in rows])}
args=TrainingArguments(output_dir='/tmp/checkpoints',max_steps=500,per_device_train_batch_size=4,gradient_accumulation_steps=4,learning_rate=1e-4,warmup_ratio=0.05,bf16=True,gradient_checkpointing=True,gradient_checkpointing_kwargs={'use_reentrant':False},save_strategy='no',logging_steps=20,report_to='none',remove_unused_columns=False,seed=42)
trainer=Trainer(model=model,args=args,train_dataset=train,data_collator=collate)
result=trainer.train();report['training']=result.metrics;report['optimizer_steps']=trainer.state.global_step
model.save_pretrained(out/'adapter');model.gradient_checkpointing_disable();model.config.use_cache=True;model.eval()
model=model.merge_and_unload(safe_merge=True);model.config.astheral_version='translate-1'
model.save_pretrained(out/'model',safe_serialization=True,max_shard_size='4GB');tok.save_pretrained(out/'model')
del trainer,model;gc.collect();torch.cuda.empty_cache()
model=AutoModelForCausalLM.from_pretrained(out/'model',torch_dtype=torch.bfloat16,device_map={'':'cuda'},attn_implementation='sdpa').eval()
report['finetuned_scores']=evaluate('finetuned')
report['mean_chrf_base']=sum(v['chrf'] for v in report['base_scores'].values())/5
report['mean_chrf_finetuned']=sum(v['chrf'] for v in report['finetuned_scores'].values())/5
report['improved']=report['mean_chrf_finetuned']>report['mean_chrf_base']
report['elapsed_seconds']=time.monotonic()-start
(out/'evaluation.json').write_text(json.dumps(report,indent=2))
(out/'train.py').write_text(Path(__file__).read_text())
api.upload_folder(repo_id=REPO,folder_path=str(out/'model'),commit_message='Publish actual merged AstheralTranslate weights after reload and translation evaluation')
api.upload_folder(repo_id=REPO,folder_path=str(out/'adapter'),path_in_repo='adapter',commit_message='Publish trained rank32 translation adapter')
api.upload_folder(repo_id=REPO,folder_path=str(out),allow_patterns=['*.json','*.py'],commit_message='Publish translation training provenance and before/after test outputs')
import urllib.request
license_path=str(out/'LICENSE')
Path(license_path).write_bytes(urllib.request.urlopen('https://www.apache.org/licenses/LICENSE-2.0.txt',timeout=20).read())
api.upload_file(repo_id=REPO,path_or_fileobj=license_path,path_in_repo='LICENSE')
print('TRANSLATE_COMPLETE',json.dumps(report),flush=True)
|