허깅 페이스 BERT 및 ‘가중치 및 편향(W&B)를 통한 문장 분류
서론
이 튜토리얼에서는 Natural Language Processing 분야에서 최근 혁신적인 기술의 힘을 활용한 최고 수준의 문장 분류기를 만들어보겠습니다. NLP로의 전이 학습의 적용에 초점을 맞추도록 하겠습니다. 이를 활용해서 다양한 NLP작업에 최소한의 노력으로 최고 성능의 모델을 구축할 것입니다. 구글의 BERT는 연구자들이 특정 작업에 대한 미세조정을 최소화 하면서 다수의 벤치마크를 깨뜨릴 수 있었습니다. 그 결과, NLP 연구 재생산 및 실험에대한 접근 가능성이 높아졌습니다.
We'll use WandB's hyperparameter Sweeps later on. Here's a simple notebook to get you started with sweeps. 추후에 WandB의 초매개변수 스윕(hyperparameter Sweeps)를 사용하겠습니다. 여기를 클릭하시면 비우기(sweeps) 작업을 시작할 수 있는 간단한 노트를 확인하실 수 있습니다.
colab에서 BERT 미세조정 해보기→
COLA 데이터집합 로딩 및 토큰화
분할 및 로딩
데이터 집합 분할
데이터를 훈련 세트 및 시험 세트로 나눕니다. 90%는 교육에, 10%는 검증에 사용하도록 훈련 세트를 분할하세요.
from torch.utils.data import TensorDataset, random_split
# Combine the training inputs into a TensorDataset.
dataset = TensorDataset(input_ids, attention_masks, labels)
# Create a 90-10 train-validation split.
# Calculate the number of samples to include in each set.
train_size = int(0.9 * len(dataset))
val_size = len(dataset) - train_size
# Divide the dataset by randomly selecting samples.
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
데이터 집합 로딩
다음 단계에서는 다양한 초매개변수(hyper-parameter values) 값을 추측하셔야 합니다. 모든 매개변수의 값 조합을 훑어냄으로써 이러한 작업들을 자동화합니다. 현재 실행의 초매개변수 값은 wandb.config.parameter_name에 저장됩니다.
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler
import wandb
# WANDB PARAMETER
def ret_dataloader():
batch_size = wandb.config.batch_size
print('batch_size = ', batch_size)
train_dataloader = DataLoader(train_dataset,sampler = RandomSampler(train_datase t), batch_size = batch_size)
validation_dataloader = DataLoader( val_dataset, sampler = SequentialSampler(val_ dataset), batch_size = batch_size)
return train_dataloader,validation_dataloader
훈련용 모델 설정
초매개변수 스윕(sweep) 설정
모델 훈련에 앞서 아직 한 단계가 남았습니다.
초매개변수가 취할 수 있는 모든 값을 나열하는 구성 파일(configuration file)을 생성합니다.
다음, 각 조합의 성능을 로그, 비교, 시각화하기 위해 wandb 스윕 에이전트를 초기화합니다.
최대화할 메트릭은 훈련 반복 루프(training loop)에 로그할 val_accuracy 입니다.
BERT 논문에서 저자들은 전이 학습(transfer learning)수행할 수 있는 최고의 초매개변수 세트에 대해 서술하고 있으며, 우리는 초매개변수에 대해 동일한 값의 세트를 사용하고 있습니다.
import wandb
sweep_config = {
'method': 'random', #grid, random
'metric': {
'name': 'val_accuracy',
'goal': 'maximize'
},
'parameters': {
'learning_rate': {
'values': [ 5e-5, 3e-5, 2e-5]
},
'batch_size': {
'values': [16, 32]
},
'epochs':{
'values':[2, 3, 4]
}
}
}
sweep_id = wandb.sweep(sweep_config)
훈련 함수
import random
import numpy as np
def train():
wandb.init()
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
model = ret_model()
model.to(device)
train_dataloader,validation_dataloader = ret_dataloader()
optimizer = ret_optim(model)
scheduler = ret_scheduler(train_dataloader,optimizer)
training_stats = []
total_t0 = time.time()
epochs = wandb.config.epochs
for epoch_i in range(0, epochs):
print('======== Epoch {:} / {:} ========'.format(epoch_i + 1, epochs))
t0 = time.time()
total_train_loss = 0
model.train()
for step, batch in enumerate(train_dataloader):
if step % 40 == 0 and not step == 0:
elapsed = format_time(time.time() - t0)
print(' Batch {:>5,} of {:>5,}. Elapsed: {:}.'.format(step, len (train_dataloader), elapsed))
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
model.zero_grad()
loss, logits = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
#Log the train loss
wandb.log({'train_batch_loss':loss.item()})
total_train_loss += loss.item()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
scheduler.step()
avg_train_loss = total_train_loss / len(train_dataloader)
training_time = format_time(time.time() - t0)
#Log the Avg. train loss
wandb.log({'avg_train_loss':avg_train_loss})
print("")
print(" Average training loss: {0:.2f}".format(avg_train_loss))
print("Running Validation...")
t0 = time.time()
model.eval()
total_eval_accuracy = 0
total_eval_loss = 0
nb_eval_steps = 0
# Evaluate data for one epoch
for batch in validation_dataloader:
b_input_ids = batch[0].cuda()
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
with torch.no_grad():
(loss, logits) = model(b_input_ids,
token_type_ids=None,
attention_mask=b_input_mask,
labels=b_labels)
total_eval_loss += loss.item()
logits = logits.detach().cpu().numpy()
label_ids = b_labels.to('cpu').numpy()
total_eval_accuracy += flat_accuracy(logits, label_ids)
avg_val_accuracy = total_eval_accuracy / len(validation_dataloader)
print(" Accuracy: {0:.2f}".format(avg_val_accuracy))
avg_val_loss = total_eval_loss / len(validation_dataloader)
validation_time = format_time(time.time() - t0)
#Log the Avg. validation accuracy
wandb.log({'val_accuracy':avg_val_accuracy,'avg_val_loss':avg_val_loss})
print(" Validation Loss: {0:.2f}".format(avg_val_loss))
시각화
결론
이제, 여러분께서는 다양한 통계 시각화와 더불어 문장 분류 수행을 위한 초매개변수 값 세트에 대해 훈련된 최신 BERT 모델을 가지고 계십니다. 스윕 실행을 통해 최고의 초매개변수값을 확인하실 수 있습니다. 이 스윕 배치에서 달성한 최상의 검증 정확도는 약 84%입니다.
모델의 성능 향상여부를 확인하시기 위해서는, 보다 다양한 초매개변수 조합으로 스위프를 실행하시기를 바랍니다.