forked from filipg/aitech-eks-pub
156 lines
5.3 KiB
Org Mode
156 lines
5.3 KiB
Org Mode
|
* 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("distilroberta-base")
|
||
|
model = AutoModelWithLMHead.from_pretrained("distilroberta-base")
|
||
|
|
||
|
sequence = f"Hugging Face is a French company based in {tokenizer.mask_token}"
|
||
|
|
||
|
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_5 = torch.topk(mask_token_logits, 5, dim=1)
|
||
|
top_5_tokens = zip(top_5.indices[0].tolist(), top_5.values[0].tolist())
|
||
|
|
||
|
for token, score in top_5_tokens:
|
||
|
print(sequence.replace(tokenizer.mask_token, tokenizer.decode([token])), f"(score: {score})")
|
||
|
#+END_SRC
|
||
|
|
||
|
|
||
|
Przykłady: BERT, RoBERTa (również Polish RoBERTa).
|