๊ฐ๊ด์ ๋ฌธ์ [[multiple-choice]]
[[open-in-colab]]
๊ฐ๊ด์ ๊ณผ์ ๋ ๋ฌธ๋งฅ๊ณผ ํจ๊ป ์ฌ๋ฌ ๊ฐ์ ํ๋ณด ๋ต๋ณ์ด ์ ๊ณต๋๊ณ ๋ชจ๋ธ์ด ์ ๋ต์ ์ ํํ๋๋ก ํ์ต๋๋ค๋ ์ ์ ์ ์ธํ๋ฉด ์ง์์๋ต๊ณผ ์ ์ฌํฉ๋๋ค.
์งํํ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ์ต๋๋ค:
- SWAG ๋ฐ์ดํฐ ์ธํธ์ 'regular' ๊ตฌ์ฑ์ผ๋ก BERT๋ฅผ ๋ฏธ์ธ ์กฐ์ ํ์ฌ ์ฌ๋ฌ ์ต์ ๊ณผ ์ผ๋ถ ์ปจํ ์คํธ๊ฐ ์ฃผ์ด์ก์ ๋ ๊ฐ์ฅ ์ ํฉํ ๋ต์ ์ ํํฉ๋๋ค.
- ์ถ๋ก ์ ๋ฏธ์ธ ์กฐ์ ๋ ๋ชจ๋ธ์ ์ฌ์ฉํฉ๋๋ค.
์์ํ๊ธฐ ์ ์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ชจ๋ ์ค์น๋์ด ์๋์ง ํ์ธํ์ธ์:
pip install transformers datasets evaluate
๋ชจ๋ธ์ ์ ๋ก๋ํ๊ณ ์ปค๋ฎค๋ํฐ์ ๊ณต์ ํ ์ ์๋๋ก ํ๊น ํ์ด์ค ๊ณ์ ์ ๋ก๊ทธ์ธํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ฉ์์ง๊ฐ ํ์๋๋ฉด ํ ํฐ์ ์ ๋ ฅํ์ฌ ๋ก๊ทธ์ธํฉ๋๋ค:
>>> from huggingface_hub import notebook_login
>>> notebook_login()
SWAG ๋ฐ์ดํฐ ์ธํธ ๊ฐ์ ธ์ค๊ธฐ[[load-swag-dataset]]
๋จผ์ ๐ค Datasets ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ SWAG ๋ฐ์ดํฐ์ ์ '์ผ๋ฐ' ๊ตฌ์ฑ์ ๊ฐ์ ธ์ต๋๋ค:
>>> from datasets import load_dataset
>>> swag = load_dataset("swag", "regular")
์ด์ ๋ฐ์ดํฐ๋ฅผ ์ดํด๋ด ๋๋ค:
>>> swag["train"][0]
{'ending0': 'passes by walking down the street playing their instruments.',
'ending1': 'has heard approaching them.',
'ending2': "arrives and they're outside dancing and asleep.",
'ending3': 'turns the lead singer watches the performance.',
'fold-ind': '3416',
'gold-source': 'gold',
'label': 0,
'sent1': 'Members of the procession walk down the street holding small horn brass instruments.',
'sent2': 'A drum line',
'startphrase': 'Members of the procession walk down the street holding small horn brass instruments. A drum line',
'video-id': 'anetv_jkn6uvmqwh4'}
์ฌ๊ธฐ์๋ ๋ง์ ํ๋๊ฐ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ์ค์ ๋ก๋ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค:
sent1๋ฐsent2: ์ด ํ๋๋ ๋ฌธ์ฅ์ด ์ด๋ป๊ฒ ์์๋๋์ง ๋ณด์ฌ์ฃผ๋ฉฐ, ์ด ๋ ํ๋๋ฅผ ํฉ์น๋ฉด์์ ๊ตฌ์ (startphrase)ํ๋๊ฐ ๋ฉ๋๋ค.์ข ๋ฃ ๊ตฌ์ (ending): ๋ฌธ์ฅ์ด ์ด๋ป๊ฒ ๋๋ ์ ์๋์ง์ ๋ํ ๊ฐ๋ฅํ ์ข ๋ฃ ๊ตฌ์ ๋ฅผ ์ ์ํ์ง๋ง ๊ทธ ์ค ํ๋๋ง ์ ๋ต์ ๋๋ค.๋ ์ด๋ธ(label): ์ฌ๋ฐ๋ฅธ ๋ฌธ์ฅ ์ข ๋ฃ ๊ตฌ์ ์ ์๋ณํฉ๋๋ค.
์ ์ฒ๋ฆฌ[[preprocess]]
๋ค์ ๋จ๊ณ๋ ๋ฌธ์ฅ์ ์์๊ณผ ๋ค ๊ฐ์ง ๊ฐ๋ฅํ ๊ตฌ์ ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด BERT ํ ํฌ๋์ด์ ๋ฅผ ๋ถ๋ฌ์ต๋๋ค:
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
์์ฑํ๋ ค๋ ์ ์ฒ๋ฆฌ ํจ์๋ ๋ค์๊ณผ ๊ฐ์์ผ ํฉ๋๋ค:
sent1ํ๋๋ฅผ ๋ค ๊ฐ ๋ณต์ฌํ ๋ค์ ๊ฐ๊ฐ์sent2์ ๊ฒฐํฉํ์ฌ ๋ฌธ์ฅ์ด ์์๋๋ ๋ฐฉ์์ ์ฌํํฉ๋๋ค.sent2๋ฅผ ๋ค ๊ฐ์ง ๊ฐ๋ฅํ ๋ฌธ์ฅ ๊ตฌ์ ๊ฐ๊ฐ๊ณผ ๊ฒฐํฉํฉ๋๋ค.- ์ด ๋ ๋ชฉ๋ก์ ํ ํฐํํ ์ ์๋๋ก ํํํ(flatten)ํ๊ณ , ๊ฐ ์์ ์ ํด๋นํ๋
input_ids,attention_mask๋ฐlabelsํ๋๋ฅผ ๊ฐ๋๋ก ๋ค์ฐจ์ํ(unflatten) ํฉ๋๋ค.
>>> ending_names = ["ending0", "ending1", "ending2", "ending3"]
>>> def preprocess_function(examples):
... first_sentences = [[context] * 4 for context in examples["sent1"]]
... question_headers = examples["sent2"]
... second_sentences = [
... [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers)
... ]
... first_sentences = sum(first_sentences, [])
... second_sentences = sum(second_sentences, [])
... tokenized_examples = tokenizer(first_sentences, second_sentences, truncation=True)
... return {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()}
์ ์ฒด ๋ฐ์ดํฐ ์งํฉ์ ์ ์ฒ๋ฆฌ ๊ธฐ๋ฅ์ ์ ์ฉํ๋ ค๋ฉด ๐ค Datasets [~datasets.Dataset.map] ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. batched=True๋ฅผ ์ค์ ํ์ฌ ๋ฐ์ดํฐ ์งํฉ์ ์ฌ๋ฌ ์์๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌํ๋ฉด map ํจ์์ ์๋๋ฅผ ๋์ผ ์ ์์ต๋๋ค:
tokenized_swag = swag.map(preprocess_function, batched=True)
[DataCollatorForMultipleChoice]๋ ๋ชจ๋ ๋ชจ๋ธ ์
๋ ฅ์ ํํํํ๊ณ ํจ๋ฉ์ ์ ์ฉํ๋ฉฐ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ฐจ์ํํฉ๋๋ค:
>>> from transformers import DataCollatorForMultipleChoice
>>> collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)
ํ๊ฐ ํ๊ธฐ[[evaluate]]
ํ๋ จ ์ค์ ๋ฉํธ๋ฆญ์ ํฌํจํ๋ฉด ๋ชจ๋ธ์ ์ฑ๋ฅ์ ํ๊ฐํ๋ ๋ฐ ๋์์ด ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ๐คEvaluate ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ๊ฐ ๋ฐฉ๋ฒ์ ๋น ๋ฅด๊ฒ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ด ์์ ์์๋ accuracy ์งํ๋ฅผ ๊ฐ์ ธ์ต๋๋ค(๐ค Evaluate ๋๋ฌ๋ณด๊ธฐ๋ฅผ ์ฐธ์กฐํ์ฌ ์งํ๋ฅผ ๊ฐ์ ธ์ค๊ณ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์ธํ ์์๋ณด์ธ์):
>>> import evaluate
>>> accuracy = evaluate.load("accuracy")
๊ทธ๋ฆฌ๊ณ ์์ธก๊ณผ ๋ ์ด๋ธ์ [~evaluate.EvaluationModule.compute]์ ์ ๋ฌํ์ฌ ์ ํ๋๋ฅผ ๊ณ์ฐํ๋ ํจ์๋ฅผ ๋ง๋ญ๋๋ค:
>>> import numpy as np
>>> def compute_metrics(eval_pred):
... predictions, labels = eval_pred
... predictions = np.argmax(predictions, axis=1)
... return accuracy.compute(predictions=predictions, references=labels)
์ด์ compute_metrics ํจ์๋ฅผ ์ฌ์ฉํ ์ค๋น๊ฐ ๋์์ผ๋ฉฐ, ํ๋ จ์ ์ค์ ํ ๋ ์ด ํจ์๋ก ๋์๊ฐ๊ฒ ๋ฉ๋๋ค.
ํ๋ จ ํ๊ธฐ[[train]]
[Trainer]๋ก ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํ๋ ๋ฐ ์ต์ํ์ง ์๋ค๋ฉด ๊ธฐ๋ณธ ํํ ๋ฆฌ์ผ ์ฌ๊ธฐ๋ฅผ ์ดํด๋ณด์ธ์!
์ด์ ๋ชจ๋ธ ํ๋ จ์ ์์ํ ์ค๋น๊ฐ ๋์์ต๋๋ค! [AutoModelForMultipleChoice]๋ก BERT๋ฅผ ๋ก๋ํฉ๋๋ค:
>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer
>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
์ด์ ์ธ ๋จ๊ณ๋ง ๋จ์์ต๋๋ค:
- ํ๋ จ ํ์ดํผํ๋ผ๋ฏธํฐ๋ฅผ [
TrainingArguments]์ ์ ์ํฉ๋๋ค. ์ ์ผํ ํ์ ๋งค๊ฐ๋ณ์๋ ๋ชจ๋ธ์ ์ ์ฅํ ์์น๋ฅผ ์ง์ ํ๋output_dir์ ๋๋ค.push_to_hub=True๋ฅผ ์ค์ ํ์ฌ ์ด ๋ชจ๋ธ์ ํ๋ธ์ ํธ์ํฉ๋๋ค(๋ชจ๋ธ์ ์ ๋ก๋ํ๋ ค๋ฉด ํ๊น ํ์ด์ค์ ๋ก๊ทธ์ธํด์ผ ํฉ๋๋ค). ๊ฐ ์ํญ์ด ๋๋ ๋๋ง๋ค [Trainer]๊ฐ ์ ํ๋๋ฅผ ํ๊ฐํ๊ณ ํ๋ จ ์ฒดํฌํฌ์ธํธ๋ฅผ ์ ์ฅํฉ๋๋ค. - ๋ชจ๋ธ, ๋ฐ์ดํฐ ์ธํธ, ํ ํฌ๋์ด์ , ๋ฐ์ดํฐ ์ฝ๋ ์ดํฐ,
compute_metricsํจ์์ ํจ๊ป ํ๋ จ ์ธ์๋ฅผ [Trainer]์ ์ ๋ฌํฉ๋๋ค. - [
~Trainer.train]์ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํฉ๋๋ค.
>>> training_args = TrainingArguments(
... output_dir="my_awesome_swag_model",
... eval_strategy="epoch",
... save_strategy="epoch",
... load_best_model_at_end=True,
... learning_rate=5e-5,
... per_device_train_batch_size=16,
... per_device_eval_batch_size=16,
... num_train_epochs=3,
... weight_decay=0.01,
... push_to_hub=True,
... )
>>> trainer = Trainer(
... model=model,
... args=training_args,
... train_dataset=tokenized_swag["train"],
... eval_dataset=tokenized_swag["validation"],
... processing_class=tokenizer,
... data_collator=collator,
... compute_metrics=compute_metrics,
... )
>>> trainer.train()
ํ๋ จ์ด ์๋ฃ๋๋ฉด ๋ชจ๋ ์ฌ๋์ด ๋ชจ๋ธ์ ์ฌ์ฉํ ์ ์๋๋ก [~transformers.Trainer.push_to_hub] ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ์ ํ๋ธ์ ๊ณต์ ํ์ธ์:
>>> trainer.push_to_hub()
๊ฐ๊ด์ ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋ณด๋ค ์ฌ์ธต์ ์ธ ์๋ ์๋ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์. PyTorch notebook ๋๋ TensorFlow notebook.
์ถ๋ก ํ๊ธฐ[[inference]]
์ด์ ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํ์ผ๋ ์ถ๋ก ์ ์ฌ์ฉํ ์ ์์ต๋๋ค!
ํ ์คํธ์ ๋ ๊ฐ์ ํ๋ณด ๋ต์์ ์์ฑํฉ๋๋ค:
>>> prompt = "France has a bread law, Le Dรฉcret Pain, with strict rules on what is allowed in a traditional baguette."
>>> candidate1 = "The law does not apply to croissants and brioche."
>>> candidate2 = "The law applies to baguettes."
๊ฐ ํ๋กฌํํธ์ ํ๋ณด ๋ต๋ณ ์์ ํ ํฐํํ์ฌ PyTorch ํ
์๋ฅผ ๋ฐํํฉ๋๋ค. ๋ํ labels์ ์์ฑํด์ผ ํฉ๋๋ค:
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_swag_model")
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="pt", padding=True)
>>> labels = torch.tensor(0).unsqueeze(0)
์
๋ ฅ๊ณผ ๋ ์ด๋ธ์ ๋ชจ๋ธ์ ์ ๋ฌํ๊ณ logits์ ๋ฐํํฉ๋๋ค:
>>> from transformers import AutoModelForMultipleChoice
>>> model = AutoModelForMultipleChoice.from_pretrained("my_awesome_swag_model")
>>> outputs = model(**{k: v.unsqueeze(0) for k, v in inputs.items()}, labels=labels)
>>> logits = outputs.logits
๊ฐ์ฅ ๋์ ํ๋ฅ ์ ๊ฐ์ง ํด๋์ค๋ฅผ ๊ฐ์ ธ์ต๋๋ค:
>>> predicted_class = logits.argmax().item()
>>> predicted_class
'0'