elevne's Study Note

Huggingface 공부 - (2-2: Huggingface 코드 사용해보기) 본문

Machine Learning/NLP

Huggingface 공부 - (2-2: Huggingface 코드 사용해보기)

elevne 2022. 12. 15. 22:46

본격적으로 Model을 Train 돌리기 전, Model에 Sequence를 입력하였을 때 어떠한 Output이 나오게되는지 확인해보았다. 아래와 같은 코드를 작성한다.

 

 

 

text = "This is a text for test"
inputs = tokenizer(text, return_tensors="pt")

print(inputs["input_ids"])
print("Input Tensor Size:", inputs["input_ids"].size())

 

 

result

 

 

 

이전에 확인해보았듯이, 우선 Sequence는 tokenizer에 들어가게 될 것이고 이는 하나의 tensor data로 바뀌게된다. inputs를 print 하여 확인해보면 아래와 같은 모습을 띈다.

 

 

 

result

 

 

 

아래와 같은 코드를 작성하여 불러온 model에 Sequence를 넣고, 마지막 은닉상태를  추출해볼 수 있다.

 

 

 

inputs = {k:v.to(device) for k,v in inputs.items()}
with torch.no_grad():
  outputs = model(**inputs)
print(outputs)

 

 

result

 

 

last_hidden_state

 

 

 

위와 같이 torch.no_grad() Context Manager을 사용하면 Gradient 자동 계산이 비활성화되어 계산에 필요한 메모리 양이 줄어든다고 한다. outputs 결과 값에 .last_hidden_state를 사용하여 마지막 은닉상태의 결과값만 가져올 수 있고, 해당 은닉상태의 size 값을 확인해볼 수 있었다.

 

 

 

이제 훈련을 위해 cmopute_metrics 함수를 작성한다. 이는 Epoch이 끝날 때마다 사용될 Metrics라고 생각하면 되겠다.

 

 

 

from sklearn.metrics import accuracy_score, f1_score

def compute_metrics(pred):
  labels = pred.label_ids
  preds = pred.predictions.argmax(-1)
  f1 = f1_score(labels, preds, average="weighted")
  acc = accuracy_score(labels, preds)
  return {"accuracy":acc, "f1":f1}

 

 

 

 

Sckit Learn에서 accuracy, f1 score 함수를 가져와서 사용하였다. 

 

 

 

이전에 사용해본 AutoModel Class 대신에 AutoModelForSequenceClassification 클래스를 사용하였다. 이 모델은 사전훈련된 모델 출력위에 베이스모델(이 경우에는 DistilBERT)과 함께 쉽게 훈련할 수 있는 분류 헤드가 있다는 점에서 다르다고 한다. 분류 헤드의 출력크기를 정해죽 위해 num_labels 값을 지정해줄 수 있는 것이다. (밑의 코드를 실행하면 모델 일부가 랜덤하게 초기화된다는 경고가 뜨게 되는데, 이는 분류 헤드가 아직 훈련되지 않았기 때문에 뜨는 것이다.)

 

 

 

from transformers import AutoModelForSequenceClassification

num_labels = 6
model = (AutoModelForSequenceClassification.from_pretrained(model_ckpt, num_labels=num_labels).to(device))

 

 

 

transformers에서는 TrainigArguments 라는 Class를 제공한다. 이는 Trainer Class에 필요한 인자들을 미리 넣어두어 사용할 수 있는 Class이다. 

 

 

 

from transformers import Trainer, TrainingArguments

batch_size = 32
logging_steps = len(emotions_encoded["train"])
model_name = "{}-finetuned-emotion".format(model_ckpt)
training_args = TrainingArguments(output_dir="./", num_train_epochs=1, learning_rate=2e-5, per_device_train_batch_size=batch_size, per_device_eval_batch_size=batch_size, save_strategy="epoch",
                                  weight_decay=0.01, evaluation_strategy="epoch", disable_tqdm=False, logging_steps=logging_steps, push_to_hub=False, load_best_model_at_end=True, log_level="error")

 

 

 

위 training_args를 활용하여 Trainer을 만들어준다.

 

 

 

from transformers import TrainingArguments

trainer = Trainer(model=model,
                  args=training_args,
                  compute_metrics=compute_metrics,
                  train_dataset=emotions_encoded["train"],
                  eval_dataset=emotions_encoded["validation"],
                  tokenizer=tokenizer)

trainer.train()

 

 

train

 

 

 

Epoch이 끝나며 지정한 Metric에 대한 값들이 출력되는 것을 확인할 수 있다. 또한, 사전훈련 모델을 만들어 사용하였기에 Epoch 한 번만으로도 F1 socre 0.9라는 매우 높은 값이 나오는 것을 확인할 수 있었다.

 

 

 

학습시킨 모델을 아래와 같은 코드로 Validation set에 대해서도 시험해보고, 결과값을 확인해볼 수 있다.

 

 

 

pred_output = trainer.predict(emotions_encoded["validation"])
pred_output.metrics