aitech-eks-pub/wyk/14_pretrenowanie.org
2021-06-14 08:23:02 +02:00

5.3 KiB

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.

! pip install transformers
  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
  [('Ġ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)]

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.
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})")

Przykłady: BERT, RoBERTa (również Polish RoBERTa).