책 리뷰/101가지 문제로 배우는 딥러닝 허깅페이스 트랜스포머
02장. DistilBERT 파인튜닝 및 평가 (문제8~11)
조조링
2024. 11. 24. 02:48
728x90
반응형
문제8. 데이터세트 클래스 생성
Torch.utils.data.Dataset을 상속하는 IMDbFDataset이라는 클래스를 작성하세요. 그리고 문제 7의 IMDB 데이터세트에서 생성한 학습, 검증, 테스트 데이터세트를 입력해서 이 클래스를 인스턴스화합니다. 클래스 및 인스턴스화 개념은 문제2를 참고하세요.
상속이란?
클래스를 생성할 때 다른 클래스의 기능을 가져다 쓰는 것을 상속이라고 합니다. 예를 들어 20층 건물을 지을 때, 타 고층 빌딩의 설계도를 참고하면 도움이 됩니다. 엘리베이터 기능, 공조 기능, 지진 설계 등을 빌려와 쓸 수 있다면 시간과 노력이 절감됩니다. 즉, 객체 A를 짓는 설계도 클래스의 기능을 물려받아 객체 B를 짓는 설계도 클래스에서 그대로 사용한다는 개념이 바로 상속입니다.
Dataset 클래스를 상속하는 IDMbDataset 클래스를 정의해보자. __init__은 인스턴스화에 쓰이는 생성자이다.
생성자는 클래스로 객체를 생성할 때 자동으로 호출되는 메서드로, 객체를 미리 설정한 값으로 초기화합니다. 생성자 역시 클래스 내 메서드이므로 항상 자신을 가리키는 매개변수 self를 포함합니다.
import torch
# Dataset 클래스를 상속하는 IMDBDataset 클래스를 정의
class IMDbDataset(torch.utils.data.Dataset):
# 생성자 __init__()
# 자신을 가르키는 매개변수 self 포함
# 변수를 저장하기 위해 self.변수명을 사용
def __init__(self, encodings, labels):
self.encodings = encodings
self.labels = labels
# 자신을 가르키는 매개변수 self 포함
def __getitem__(self, idx):
# self.encoding에 담긴 키(key)와 키값(value)을 items()로 추출
# 이 값을 key와 val 변수에 담아 새로운 키(key)와 키값(torch.tensor(val[idx]))를 갖는 딕셔너리 생성
# 딕셔너리는 {"key1:value1", "key2:value2", ,,,} 형태를 지닌 파이썬 데이터 구조
# val[idx]에 담긴 데이터를 torch.tensor()를 통해 파이토치 텐서로 변환
item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
# self.lables[idx]에 담긴 데이터를 torch.tensor()를 통해 파이토치 텐서 변환
item['labels'] = torch.tensor(self.labels[idx])
return item
# 자신을 가르키는 매개변수 self 포함
def __len__(self):
return len(self.labels)
train_dataset = IMDbDataset(train_encodings, train_labels)
val_dataset = IMDbDataset(val_encodings, val_labels)
test_dataset = IMDbDataset(test_encodings, test_labels)
- __getitem__()은 대괄호 [] 안에 표기된 인덱스와 결합된 객체를 얻어 오는 파이썬 메서드이다.
- 메서드는 클래스 내에 포함되어 있는 함수이다.
- 얻어 온 결과물을 torch.tensor() 처리를 거친 레이블 값을 출력한다.
- __len()__는 객체를 입력하면 len() 값인 입력 데이터의 개수를 출력하는 파이썬 메서드이다.
- 위 코드의 각 데이터세트 train_dataset, val_dataset, test_dataset은 반복 가능(iterable)타입이다.
# train_dataset 확인
for i in train_dataset:
print(i)
break
# {'input_ids': tensor([ 101, 4937, 11350, 2038, 2048, 1000, 7592, 14433, 1000, 1011,
# 2828, 18401, 2015, 28866, 2075, 2006, 1037, 13576, 4440, 2083,
# 1996, 25115, 1010, 2073, 2505, 2064, 4148, 1010, 1998, 2515,
# 1012, 2023, 2568, 1011, 4440, 4691, 4004, 2460, 3594, 2053,
# 13764, 8649, 1010, 4942, 21532, 2773, 22163, 2612, 1012, 2045,
# 2003, 2053, 2126, 1997, 7851, 2023, 17183, 14088, 9476, 3272,
# 2000, 2425, 2017, 2000, 2156, 2009, 2005, 4426, 1012, 1998,
# 2191, 2469, 2053, 2028, 2104, 2184, 2003, 1999, 1996, 2282,
# 1012, 4487, 6491, 6633, 5677, 3672, 1998, 2064, 3490, 10264,
# 2964, 1998, 18186, 1998, 9576, 2854, 1998, 5573, 2331, 1998,
# 2655, 3560, 27770, 2005, 2500, 2024, 2691, 6991, 1012, 7481,
# 1012, 3383, 1996, 2087, 13432, 3746, 2003, 2008, 1997, 2019,
# 10777, 3605, 1997, 2300, 2008, 1996, 8934, 7368, 9880, 2083,
# 1998, 1999, 1010, 1998, 2036, 4536, 1012, 2021, 2066, 8134,
# 2673, 2842, 1999, 2023, 2143, 1010, 2008, 10021, 1010, 27263,
# 17933, 4226, 25347, 2574, 3310, 2000, 1037, 9202, 2203, 1012,
# 102, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0]), 'attention_mask': tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0]), 'labels': tensor(1)}
- 결과를 보면 키로 input_ids, attention_mask, labels의 값이 딕셔너리 타입으로 반환되었고, 이 값은 torch.tensor 타입이다.
- input_ids: 단어 ID이고, 숫자로 작성되며 0부터 시작한다.
- attention_mask: 패딩 위치를 나타낸다. 실제 입력 토큰과 패딩 토큰을 구분하기 위해 사용된다.
- labels: 인코딩된 torch.tensor의 레이블 값이다.
문제9. 사전학습 모델 불러오기
DistilBertForSequenceClassification 클래스를 사용해서 사전학습 모델을 불러오세요.
- from_pretrained를 사용해서 distilbert-base-uncased 모델을 불러온다.
from transformers import DistilBertForSequenceClassification
# distilbert 모델 불러오기
model = DistilBertForSequenceClassification.from_pretrained("distilbert-base-uncased")
model
# DistilBertForSequenceClassification(
# (distilbert): DistilBertModel(
# (embeddings): Embeddings(
# (word_embeddings): Embedding(30522, 768, padding_idx=0)
# (position_embeddings): Embedding(512, 768)
# (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
# (dropout): Dropout(p=0.1, inplace=False)
# )
# (transformer): Transformer(
# (layer): ModuleList(
# (0-5): 6 x TransformerBlock(
# (attention): DistilBertSdpaAttention(
# (dropout): Dropout(p=0.1, inplace=False)
# (q_lin): Linear(in_features=768, out_features=768, bias=True)
# (k_lin): Linear(in_features=768, out_features=768, bias=True)
# (v_lin): Linear(in_features=768, out_features=768, bias=True)
# (out_lin): Linear(in_features=768, out_features=768, bias=True)
# )
# (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
# (ffn): FFN(
# (dropout): Dropout(p=0.1, inplace=False)
# (lin1): Linear(in_features=768, out_features=3072, bias=True)
# (lin2): Linear(in_features=3072, out_features=768, bias=True)
# (activation): GELUActivation()
# )
# (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
# )
# )
# )
# )
# (pre_classifier): Linear(in_features=768, out_features=768, bias=True)
# (classifier): Linear(in_features=768, out_features=2, bias=True)
# (dropout): Dropout(p=0.2, inplace=False)
# )
문제10. TrainingArguments 설정
TrainArguments 클래스를 호출해서, 파인튜닝에 사용하기 위한 하이퍼파라미터를 정의하세요
- 대표적인 하이퍼파라미터들의 값을 다음과 같이 설정합니다.
- 학습 에포크: 8
- 학습 시 미니 배치 사이즈: 16
- 평가 시 미니 배치 사이즈: 64
- 최적화 함수: Adam
- 특정 스텝을 넘기면 학습률을 증가시키기 위해 웜업 스텝을 500으로 설정
- 딥러닝 모델에서 신경망층을 많이 배치할수록 과적합 발생 경향이 있는데 가중치 감소는 이를 상쇄하기 위해 도입된 장치
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir='./results', # 출력 디렉토리 경로
num_train_epochs=8, # 학습 에포크 수
per_device_train_batch_size=16, # 학습시 (디바이스 별) 미니 배치 수
per_device_eval_batch_size=64, # 평가시 (디바이스 별) 미니 배치 수
warmup_steps=500, # 학습률 스케줄링용 웜업 스텝 수
weight_decay=0.01, # 가중치 감쇄 강도
logging_dir='./logs', # 로그 디렉토리 경로
logging_steps=10,
)
문제11. GPU로 전송
문제9에서 불러온 사전학습 모델을 코랩의 GPU 디바이스로 전달합니다.
- torch.tensors 타입의 데이터는 model.to(device) 메서드를 통해 GPU로 전달된다.
import torch
# GPU 사용이 가능한 경우 텐서 타입 데이터를 GPU로 전달
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
728x90
반응형