* Pretrenowanie modeli System AlphaZero uczy się grając sam ze sobą — wystarczy 24 godziny, by system nauczył się grać w szachy lub go na nadludzkim poziomie. *Pytanie*: Dlaczego granie samemu ze sobą nie jest dobrym sposobem nauczenia się grania w szachy dla człowieka, a dla maszyny jest? Co jest odpowiednikiem grania samemu ze sobą w świecie przetwarzania tekstu? Tzn. *pretrenowanie* (/pretraining/) na dużym korpusie tekstu. (Tekst jest tani!) Jest kilka sposobów na pretrenowanie modelu, w każdym razie sprowadza się do odgadywania następnego bądź zamaskowanego słowa. W każdym razie zawsze stosujemy softmax (być może ze „sztuczkami” takimi jak negatywne próbkowanie albo hierarchiczny softamx) na pewnej *representecji kontekstowej*: $$\vec{p} = \operatorname{softmax}(f(\vec{c})).$$ Model jest karany używając funkcji log loss: $$-\log(p_j),$$ gdzie $w_j$ jest wyrazem, który pojawił się rzeczywiście w korpusie. ** Przewidywanie słowa (GPT-2) Jeden ze sposobów pretrenowania modelu to po prostu przewidywanie następnego słowa. Zainstalujmy najpierw bibliotekę transformers. #+BEGIN_SRC ipython :session mysession :exports both :results raw drawer ! pip install transformers #+END_SRC #+BEGIN_SRC ipython :session mysession :exports both :results raw drawer import torch from transformers import GPT2Tokenizer, GPT2LMHeadModel tokenizer = GPT2Tokenizer.from_pretrained('gpt2-large') model = GPT2LMHeadModel.from_pretrained('gpt2-large') text = "Warsaw is the capital city of" encoded_input = tokenizer(text, return_tensors='pt') output = model(**encoded_input) next_token_probs = torch.softmax(output[0][:, -1, :][0], dim=0) nb_of_tokens = next_token_probs.size()[0] _, top_k_indices = torch.topk(next_token_probs, 30, sorted=True) top_k_indices # words = tokenizer.convert_ids_to_tokens(top) # top_probs = [] # for ix in range(len(top)): # top_probs.append((words[ix], next_token_probs[top[ix]].item())) # top_probs #+END_SRC #+RESULTS: :results: # Out[8]: #+BEGIN_EXAMPLE [('Ġthe', 0.4415026307106018), ('ĠPoland', 0.236798495054245), ('ĠBelarus', 0.10114768147468567), ('ĠUkraine', 0.058283545076847076), ('Ġeastern', 0.020564062520861626), ('ĠEastern', 0.011137397028505802), ('ĠPolish', 0.010205904021859169), ('ĠWestern', 0.00833223108202219), ('Ġwestern', 0.006872199941426516), ('Ġa', 0.004939113277941942), ('ĠSlovakia', 0.003553805174306035), ('ĠLithuania', 0.003335304092615843), ('ĠRussia', 0.002872465644031763), ('Ġcentral', 0.002493523992598057), ('Ġmodern', 0.0022767107002437115), ('ĠCzech', 0.0022264323197305202), ('ĠPr', 0.002146221464499831), ('Ġformer', 0.0021054286044090986), ('Ġwhat', 0.0017435317859053612), ('ĠSlov', 0.0014634730760008097), ('ĠUkrainian', 0.0014347084797918797), ('ĠCentral', 0.0013676199596375227), ('ĠSouth', 0.0013484350638464093), ('Ġone', 0.001204205909743905), ('ĠNorthern', 0.0011802552035078406), ('ĠWest', 0.001175572513602674), ('ĠEast', 0.0011596156982704997), ('Ġsouthern', 0.0011580033460631967), ('Ġnorthern', 0.001110077602788806), ('Ġ"', 0.0010494199814274907)] #+END_EXAMPLE :end: Zalety tego podejścia: - prostota, - dobra podstawa do strojenia systemów generowania tekstu zwłaszcza „otwartego” (systemy dialogowe, generowanie (fake) newsów, streszczanie tekstu), ale niekoniecznie tłumaczenia maszynowego, - zaskakująca skuteczność przy uczeniu /few-shot/ i /zero-shot/. Wady: - asymetryczność, przetwarzanie tylko z lewej do prawej, preferencja dla lewego kontekstu, - mniejsza skuteczność przy dostrajaniu do zadań klasyfikacji i innych zadań niepolegających na prostym generowaniu. Przykłady modeli: GPT, GPT-2, GPT-3, DialoGPT. ** Maskowanie słów (BERT) Inną metodą jest maskowanie słów (/Masked Language Modeling/, /MLM/). W tym podejściu losowe wybrane zastępujemy losowe słowa specjalnym tokenem (~[MASK]~) i każemy modelowi odgadywać w ten sposób zamaskowane słowa (z uwzględnieniem również prawego kontekstu!). Móciąc ściśle, w jednym z pierwszych modeli tego typu (BERT) zastosowano schemat, w którym również niezamaskowane słowa są odgadywane (!): - wybieramy losowe 15% wyrazów do odgadnięcia - 80% z nich zastępujemy tokenem ~[MASK]~, - 10% zastępujemy innym losowym wyrazem, - 10% pozostawiamy bez zmian. #+BEGIN_SRC ipython :session mysession :exports both :results raw drawer from transformers import AutoModelWithLMHead, AutoTokenizer import torch tokenizer = AutoTokenizer.from_pretrained("xlm-roberta-large") model = AutoModelWithLMHead.from_pretrained("xlm-roberta-large") sequence = f'II wojna światowa zakończyła się w {tokenizer.mask_token} roku.' input_ids = tokenizer.encode(sequence, return_tensors="pt") mask_token_index = torch.where(input_ids == tokenizer.mask_token_id)[1] token_logits = model(input_ids)[0] mask_token_logits = token_logits[0, mask_token_index, :] mask_token_logits = torch.softmax(mask_token_logits, dim=1) top_10 = torch.topk(mask_token_logits, 10, dim=1) top_10_tokens = zip(top_10.indices[0].tolist(), top_10.values[0].tolist()) for token, score in top_10_tokens: print(sequence.replace(tokenizer.mask_token, tokenizer.decode([token])), f"(score: {score})") #+END_SRC #+RESULTS: :results: # Out[3]: :end: Przykłady: BERT, RoBERTa (również Polish RoBERTa). ** Podejście generatywne (koder-dekoder). System ma wygenerować odpowiedź na różne pytania (również odpowiadające zadaniu MLM), np.: - "translate English to German: That is good." => "Das ist gut." - "cola sentence: The course is jumping well." => "not acceptable" - "summarize: state authorities dispatched emergency crews tuesday to survey the damage after an onslaught of severe weather in mississippi..." => "six people hospitalized after a storm in attala county" - "Thank you for me to your party week." => for inviting last #+BEGIN_SRC ipython :session mysession :exports both :results raw drawer from transformers import T5Tokenizer, T5Config, T5ForConditionalGeneration T5_PATH = 't5-base' t5_tokenizer = T5Tokenizer.from_pretrained(T5_PATH) t5_config = T5Config.from_pretrained(T5_PATH) t5_mlm = T5ForConditionalGeneration.from_pretrained(T5_PATH, config=t5_config) slot = '' text = f'Warsaw is the {slot} of Poland.' encoded = t5_tokenizer.encode_plus(text, add_special_tokens=True, return_tensors='pt') input_ids = encoded['input_ids'] outputs = t5_mlm.generate(input_ids=input_ids, num_beams=200, num_return_sequences=5, max_length=5) _0_index = text.index(slot) _result_prefix = text[:_0_index] _result_suffix = text[_0_index+len(slot):] def _filter(output, end_token=''): _txt = t5_tokenizer.decode(output[2:], skip_special_tokens=False, clean_up_tokenization_spaces=False) if end_token in _txt: _end_token_index = _txt.index(end_token) return _result_prefix + _txt[:_end_token_index] + _result_suffix else: return _result_prefix + _txt + _result_suffix results = [_filter(out) for out in outputs] results #+END_SRC (Zob. https://arxiv.org/pdf/1910.10683.pdf) Przykład: T5, mT5