본문 바로가기
필기 노트/Huggingface Transformers

[Huggingface] Datasets / Preprocessing / Training / Evaluating

by misconstructed 2021. 7. 18.
728x90

출처 : https://www.youtube.com/watch?v=_BZearw7f0w&list=PLo2EIpI_JMQvbh6diTDl2TwbAyu8QWdpx&ab_channel=HuggingFace 


Dataset / Preprocessing

load_dataset() 을 통해서 Huggingface에서 제공하는 데이터셋을 불러와서 사용할 수 있다. load_dataset() 을 통해서 불러온 데이터셋은 DatasetDict 클래스로 제공된다. (그냥 dictionary라고 생각하면 된다.) split 에 따라서 "train", "validation", "test" 등으로 구분되어 있어서 해당 split의 이름으로 데이터셋에 접근할 수 있다. 

raw_dataset = load_dataset('...')
# train dataset
# 5개 출력
raw_dataset['train'][:5]
# 데이터셋의 추가적인 정보 출력
raw_dataset['train'].features

이렇게 불러온 데이터를 모델의 입력으로 제공하기 위해서는 tokenizer를 이용해서 string을 token id로 변환해야 한다.

# 불러온 데이터를 tokenizer를 통해서 token id로 변환하는 함수
def tokenize_function(example):
	return tokenizer(example['sentence1'], 
    		    example['sentence2'], 
                    padding='max_length', 
                    truncation=True, 
                    max_legnth=128)

# tokenized된 결과들은 remove_columns(), rename_columns(), with_format() 등의 함수로 전처리
tokenized = raw_dataset.map(tokenize_function, batch=True)

위 코드와 같이 max_length로 입력 최대 길이를 지정하면, 모든 데이터에 대해서 padding을 입력 최대 길에 대해서 추가하기 때문에, 입력 문장이 짧아질수록 padding token이 더 많이 추가되는 현상이 발생하고, 이는 추가적인 computation을 발생시킨다. 이를 해결하기 위해서 batch 단위로 padding을 할 수 있다. 이렇게 하면, 동일한 batch 내에서 가장 긴 문장의 길이에 맞게 padding을 주고, (max_length만큼 줬을 때 보다 훨씬 적은 padding token을 추가하게 된다.) 이는 CPU/GPU에서의 연산량을 감소시키는 효과가 있다. 하지만, TPU와 같은 환경에서는 더 느려질 수 있다는 점을 주의해야 한다. (TPU에서는 fixed batch size를 사용하도록 한다.) 이렇게 batch 내에서 가장 긴 문장의 길이에 맞게 padding을 하는 dynamic padding 기법은 DataCollectorWithPadding을 사용해서 정의할 수 있고, Dataloader에서 collate_fn의 파라미터로 넘겨주면, Dataloader에서 데이터를 제공할 때 dynamic padding이 적용된 상태로 제공된다. 

GLUE benchmark를 보면 COLA, SST-2 등의 task는 하나의 문장을 처리하는 task이고 MRPC, STS-B, QQP, MNLI, QNLI, RTE, WNLI 등의 task는 두 개의 문장(sentence-pair)을 처리하는 Task로 구성되어 있다. 두 개의 문장을 처리해야 하는 경우, 그냥 단순하게 tokenizer에 2개의 문장을 입력으로 넣어주면 된다.

tokenizer("... sentence 1 ...", "... sentence 2 ...")

이렇게 2개의 문장을 입력으로 넣어주면 결과로는 input_ids, token_type_ids, attention_mask 등이 출력으로 나오는데, 2개의 문장을 사용했기 때문에 두 문장을 구분해줄 필요가 있다. 이러한 역할을 token_type_ids 에서 하는데, 첫 번째 문장에 해당하는 token들의 인덱스에는 0을, 두 번째 문장에 해당하는 token들의 인덱스에는 1을 지정해서, 모델로 하여금 지금 처리하는 token이 몇 번째 문장에 해당하는지 알 수 있게 한다. Special token을 보면, 첫 번째 문장의 앞에 [SEP] token, 뒤에는 [SEP] token이 들어가게 되고 (이 두 token들의 token_type_ids 는 0으로 지정된다.), 두 번째 문장의 제일 뒤에는 [SEP] token이 들어가게 된다. (해당 token의 token_type_ids는 1로 지정된다.)

TrainerAPI

Trainer class에 학습에 필요한 hyperparemter를 제공하면 자동으로 해당 설정에 맞게 학습을 진행할 수 있다. 이 때, hyperparameter는 TrainingArguments 라는 클래스에 명시적으로 정의할 수 있다.

# Trainer 정의 예시
trainer = Trainer(model,
                  training_args,
                  # 학습 데이터
                  train_dataset=...,
                  # evaluation 데이터 
                  eval_dataset=...,
                  data_collector=...,
                  tokenizer=...)

이렇게 trainer를 정의했다면, trainer.train() 을 통해서 자동으로 학습이 가능하다.

trainer.predict() 를 통해서 예측도 할 수 있는데, 예시 코드는 다음과 같다. 

output = trainer.predict(EVAL_DATA)
# logit을 의미
predictions = output.predictions
label_ids = output.label_ids
metrics = output.metircs

# 사용하고 싶은 metric 불러오기
metric = load_metric('...')

preds = np.argmax(predictions, axis=1)
# 지정한 metric으로 결과 계산, dict 형태로 결과를 받아볼 수 있음.
metric.compute(predictions=preds, references=label_ids)

Training loop

1. training data 불러오기 : Dataloader (shuffle, batch_size, colalte_fn 등을 정의) 를 이용해서 Dataloader를 정의한다.

2. model : from_pretrained() 로 사전 학습된 모델을 불러오고, model.train()으로 학습 가능하도록 모드를 변경한다.

3. model(**batch) 를 통해서 loss를 구하고, gradient를 계산한다.

4. optimizer를 통해서 모델의 파라미터들을 업데이트 한다.

loss = output.loss
loss.backward()
optimizer.step()
optimizer.zero_grad()

Evaluate model

model.eval()

for batch in eval_loader:
	with torch.no_grad():
    	outputs = model(**batch)
    logits = outputs.logits
    predictions = np.argmax(logits, dim=1)
    metric.add_batch(prediction=predictions, references=batch['labels'])

metric.compute()

Accelerator

한 번도 사용해본 경험이 없다. 이번 기회에 좀 자세히 알아보고 사용해봐야겠다.

Accelerator() 를 사용하면, 데이터를 명시적으로 특정 device에 추가할 필요가 없어지고, 연산을 현재의 환경에 알맞게 최적화해서 학습이 가능하도록 한다고 한다고 한다. -

728x90

댓글