๊ฐ๊ด์ ๋ฌธ์ [[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()
Keras๋ก ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํ๋ ๋ฐ ์ต์ํ์ง ์๋ค๋ฉด ๊ธฐ๋ณธ ํํ ๋ฆฌ์ผ ์ฌ๊ธฐ๋ฅผ ์ดํด๋ณด์๊ธฐ ๋ฐ๋๋๋ค!
TensorFlow์์ ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํ๋ ค๋ฉด ์ต์ ํ ํจ์, ํ์ต๋ฅ ์ค์ผ์ฅด ๋ฐ ๋ช ๊ฐ์ง ํ์ต ํ์ดํผํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํ๋ ๊ฒ๋ถํฐ ์์ํ์ธ์:>>> from transformers import create_optimizer
>>> batch_size = 16
>>> num_train_epochs = 2
>>> total_train_steps = (len(tokenized_swag["train"]) // batch_size) * num_train_epochs
>>> optimizer, schedule = create_optimizer(init_lr=5e-5, num_warmup_steps=0, num_train_steps=total_train_steps)
๊ทธ๋ฆฌ๊ณ [TFAutoModelForMultipleChoice]๋ก BERT๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค:
>>> from transformers import TFAutoModelForMultipleChoice
>>> model = TFAutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
[~transformers.TFPreTrainedModel.prepare_tf_dataset]์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ์ธํธ๋ฅผ tf.data.Dataset ํ์์ผ๋ก ๋ณํํฉ๋๋ค:
>>> data_collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)
>>> tf_train_set = model.prepare_tf_dataset(
... tokenized_swag["train"],
... shuffle=True,
... batch_size=batch_size,
... collate_fn=data_collator,
... )
>>> tf_validation_set = model.prepare_tf_dataset(
... tokenized_swag["validation"],
... shuffle=False,
... batch_size=batch_size,
... collate_fn=data_collator,
... )
compile์ ์ฌ์ฉํ์ฌ ํ๋ จ ๋ชจ๋ธ์ ๊ตฌ์ฑํฉ๋๋ค:
>>> model.compile(optimizer=optimizer)
ํ๋ จ์ ์์ํ๊ธฐ ์ ์ ์ค์ ํด์ผ ํ ๋ง์ง๋ง ๋ ๊ฐ์ง๋ ์์ธก์ ์ ํ๋๋ฅผ ๊ณ์ฐํ๊ณ ๋ชจ๋ธ์ ํ๋ธ๋ก ํธ์ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค. ์ด ๋ ๊ฐ์ง ์์ ์ ๋ชจ๋ Keras ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ์ํํ ์ ์์ต๋๋ค.
compute_metricsํจ์๋ฅผ [~transformers.KerasMetricCallback]์ ์ ๋ฌํ์ธ์:
>>> from transformers.keras_callbacks import KerasMetricCallback
>>> metric_callback = KerasMetricCallback(metric_fn=compute_metrics, eval_dataset=tf_validation_set)
๋ชจ๋ธ๊ณผ ํ ํฌ๋์ด์ ๋ฅผ ์
๋ก๋ํ ์์น๋ฅผ [~transformers.PushToHubCallback]์์ ์ง์ ํ์ธ์:
>>> from transformers.keras_callbacks import PushToHubCallback
>>> push_to_hub_callback = PushToHubCallback(
... output_dir="my_awesome_model",
... tokenizer=tokenizer,
... )
๊ทธ๋ฆฌ๊ณ ์ฝ๋ฐฑ์ ํจ๊ป ๋ฌถ์ต๋๋ค:
>>> callbacks = [metric_callback, push_to_hub_callback]
์ด์ ๋ชจ๋ธ ํ๋ จ์ ์์ํฉ๋๋ค! ํ๋ จ ๋ฐ ๊ฒ์ฆ ๋ฐ์ดํฐ ์ธํธ, ์ํญ ์, ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ fit์ ํธ์ถํ๊ณ ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํฉ๋๋ค:
>>> model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=2, callbacks=callbacks)
ํ๋ จ์ด ์๋ฃ๋๋ฉด ๋ชจ๋ธ์ด ์๋์ผ๋ก ํ๋ธ์ ์ ๋ก๋๋์ด ๋๊ตฌ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค!
๊ฐ๊ด์ ๋ชจ๋ธ์ ๋ฏธ์ธ ์กฐ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๋ณด๋ค ์ฌ์ธต์ ์ธ ์๋ ์๋ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์. 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'
๊ฐ ํ๋กฌํํธ์ ํ๋ณด ๋ต์ ์์ ํ ํฐํํ์ฌ ํ
์ํ๋ก ํ
์๋ฅผ ๋ฐํํฉ๋๋ค:
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_swag_model")
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="tf", padding=True)
๋ชจ๋ธ์ ์
๋ ฅ์ ์ ๋ฌํ๊ณ logits๋ฅผ ๋ฐํํฉ๋๋ค:
>>> from transformers import TFAutoModelForMultipleChoice
>>> model = TFAutoModelForMultipleChoice.from_pretrained("my_awesome_swag_model")
>>> inputs = {k: tf.expand_dims(v, 0) for k, v in inputs.items()}
>>> outputs = model(inputs)
>>> logits = outputs.logits
๊ฐ์ฅ ๋์ ํ๋ฅ ์ ๊ฐ์ง ํด๋์ค๋ฅผ ๊ฐ์ ธ์ต๋๋ค:
>>> predicted_class = int(tf.math.argmax(logits, axis=-1)[0])
>>> predicted_class
'0'