Pretrained Model
- 대규모 데이터셋을 기반으로 학습된 모델로, 학습한 task에 대한 일반적인 지식을 갖고 있음
- GPT, PALM, Stable-Diffusion
전이학습
- 사전 학습된 모델 (pretrained model)의 지식을 다른 task에 활용하는 것
- 모델이 이미 학습한 일반적인 지식을 기반으로 더 빠르고 효과적이게 새로운 지식을 학습 가능
전이 학습 종류
- Fine-Tuning
- 전이 학습의 한 방법
- Pretrained model을 그대로 혹은 layers를 추가한 후 새로운 작업에 맞는 데이터로 모델을 추가로 더 훈련시키는 방법 - Domain Adaptation
- 전이 학습의 한 방법
- A 라는 도메인에서 학습한 모델을 B라는 도메인으로 전이하여 도메인 간의 차이를 극복하는 것이 목적 - Multi-task learning
: 하나의 모델을 사용하여 여러 개의 관련된 작업을 동시에 학습하면서 공통으로 사용되는 특징을 공유하는 학습 방식 - Zero-shot learning
: 기존에 학습되지 않은 새로운 클래스나 작업에 대해 예측을 수행하는 기술 (e.g. CLIP) - One/few-shot learning
: 하나 또는 몇 개의 훈련 예시를 기반으로 결과를 예측하는 학습 방식
전이 학습 전략
- 도메인이 비슷할 때, dataset 크기에 따른 전략
- 비교적 작을 때 : 마지막 classifier만 추가 학습 (나머지 freeze)
- 데이터셋의 크기가 비교적 작기 때문에, 기존의 학습한 일반적인 지식을 전달하는데 집중
- 비교적 클 때 : classifier 뿐만 아니라, 다른 일부 layers도 추가 학습
- 기존의 학습한 일반적인 지식을 유지하며, 몇 개의 layer만을 추가 학습시켜 specific한 새로운 데이터셋에 대한 지식을 학습 - 도메인이 매우 다를 때, dataset 크기에 따른 전략
- 꽤 클 때 : 꽤 많은 layers를 학습해야 함.
- 도메인이 매우 다를 때, pretrained model이 이미 가지고 있는 지식을 꽤 많이 수정해야 하기 때문 - Learning rate 전략
- Pretrained model의 일반적인 지식을 크게 업데이트 하지 않기 위해 작은 learning rate으로 학습
- 단, 마지막 FC Layer 만 업데이트 하는 경우 learning rate에 성능이 크게 영향을 받지 않음
Pretrained Model Community
- 필요성
- 최근 대규모 데이터셋을 사전 학습한 모델들이 발전
- 사전 학습된 대규모 모델을 쉽게 커스터마이징 (customizing) 해서 활용하고자 하는 수요 증대
- 이를 위한, pretrained model community 의 필요성 대두 - Timm for CV
- Timm (Pytorch Image Model)은 computer vision (CV) 분야에서 사용하는 사전 학습 모델 라이브러리
- 2021년 paper with codes 에서 가장 인기있는 라이브러리 선정
- 현재 모델은 사전 학습된 가중치가 있는 모델은 총 1,163개 제공 (2023.7월 기준)
- Official Site : https://github.com/huggingface/pytorch-image-models
- Timm 라이브러리 사용법
- timm.list_models() 로 제공되는 모델 리스트를 볼 수 있음
- timm.create_model(“model 이름”, pretrained = True) 로 사전 학습된 모델의 weight를 불러올 수 있음 - Hugging Face for NLP, CV
- 오픈 소스 라이브러리 및 여러 도구 (demo, dataset)를 지원하는 커뮤니티
- 초기엔 natural language processing (NLP) 위주였지만, 최근 computer vision, multi-modal, audio 등 다양한 분야의 pretrained 모델 라이브러리 제공
- 243,069 개의 모델과 46,033 개의 데이터셋 제공 (2023.07 기준)
- Official site : https://huggingface.co
- Hugging Face 사용법
- 다양한 라이브러리와 다양한 모델이 있어 사용하고자 하는 모델을 찾아야함 (Hugging Face Docs : https://huggingface.co/docs)
- 찾은 모델의 예시를 참고하여 pip로 설치 (e.g. pip install transformers)
timm을 활용한 pretrained model 사용법
- timm으로 pretrained model 불러오기
import timm # timm 라이브러리 불러오기
timm.list_models() # timm이 지원하는 모든 모델 리스트
timm.list_models('resnet*') # 쿼리를 통해 모델을 검색할 수 있음.
timm.list_models('resnet50', pretrained=True) # resnet 모델 중 pretrained weight 가 있는 모델 리스트
model = timm.create_model('resnet50', pretrained=True) # resnet50을 imagenet으로 pretrain한 모델 불러오기, 첫번째 모델로 불러옴.
model.default_cfg # resnet50 모델의 기본 정보
model # 모델의 아키텍쳐
model2 = timm.create_model('resnet50', pretrained = True, num_classes = 10) # 마지막 output class 개수 10개로 조정
model2 # num class 를 임의로 조정하면 fc layer 의 weight가 초기화됨
model3 = timm.create_model('resnet50', pretrained = True, num_classes = 10) # 비교를 위한 모델 생성
model2.fc.weight == model3.fc.weight # fc layer weight 비교 => fc layer의 weight는 초기화되는 것을 확인
model2.conv1.weight == model3.conv1.weight # fc layer 이전의 weight는 동일함
- timm을 활용한 전이 학습 실습
# 데이터 불러오기
cifar_transform = T.Compose([
T.ToTensor(), # 텐서 형식으로 변환
])
download_root = './CIFAR10_DATASET'
trainval_dataset = CIFAR10(download_root, transform=cifar_transform, train=True, download=True) # train dataset 다운로드
test_dataset = CIFAR10(download_root, transform=cifar_transform, train=False, download=True) # test dataset 다운로드
train_num, valid_num = int(len(trainval_dataset) * 0.8), int(len(trainval_dataset) * 0.2) # 8 : 2 = train : valid
print("Train dataset 개수 : ",train_num)
print("Validation dataset 개수 : ",valid_num)
train_dataset,val_dataset = torch.utils.data.random_split(trainval_dataset, [train_num, valid_num]) # train - valid set 나누기
BATCH_SIZE = 64 # 배치사이즈 설정
# 데이터로더 설정
train_dataloader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=False, num_workers = 8) # train dataloader 구성
val_dataloader = torch.utils.data.DataLoader(dataset=val_dataset,
batch_size=BATCH_SIZE,
shuffle=False,
drop_last=False, num_workers = 8) # valid dataloader 구성
test_dataloader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=BATCH_SIZE,
shuffle=False,
drop_last=False, num_workers = 8) # test dataloader 구성
- pretrained 된 모델로 추론하기
# pretrained model 불러오기 (resnet50 불러오기)
device = 'cuda:0' # gpu 설정
model = timm.create_model('resnet50', pretrained=True, num_classes = 10).to(device) # 10개의 클래스 예측
# 이미지 하나 추론하기
img, label = train_dataset[0]
img = img.unsqueeze(0) # 배치 추가
model.eval() # evaluation 상태로 만듦 (freeze)
preds = model(img.to(device)) # model inference, image 도 gpu에 올리기
pred_label = torch.argmax(preds).item() # 가장 큰 값의 index 반환
print(f'True Label : {label} \nPredict Label : {pred_label}')
- timm을 이용하여 fine tuning 하기
# training 코드, evaluation 코드, training_loop 코드
def training(model, dataloader, train_dataset, criterion, optimizer, device, epoch, num_epochs):
model.train() # 모델을 학습 모드로 설정
train_loss = 0.0
train_accuracy = 0
tbar = tqdm(dataloader)
for images, labels in tbar:
images = images.to(device)
labels = labels.to(device)
# 순전파
outputs = model(images)
loss = criterion(outputs, labels)
# 역전파 및 가중치 업데이트
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 손실과 정확도 계산
train_loss += loss.item()
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(outputs, 1)
train_accuracy += (predicted == labels).sum().item()
# tqdm의 진행바에 표시될 설명 텍스트를 설정
tbar.set_description(f"Epoch [{epoch+1}/{num_epochs}], Train Loss: {loss.item():.4f}")
# 에폭별 학습 결과 출력
train_loss = train_loss / len(dataloader)
train_accuracy = train_accuracy / len(train_dataset)
return model, train_loss, train_accuracy
def evaluation(model, dataloader, val_dataset, criterion, device, epoch, num_epochs):
model.eval() # 모델을 평가 모드로 설정
valid_loss = 0.0
valid_accuracy = 0
with torch.no_grad(): # model의 업데이트 막기
tbar = tqdm(dataloader)
for images, labels in tbar:
images = images.to(device)
labels = labels.to(device)
# 순전파
outputs = model(images)
loss = criterion(outputs, labels)
# 손실과 정확도 계산
valid_loss += loss.item()
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(outputs, 1)
valid_accuracy += (predicted == labels).sum().item()
# tqdm의 진행바에 표시될 설명 텍스트를 설정
tbar.set_description(f"Epoch [{epoch+1}/{num_epochs}], Valid Loss: {loss.item():.4f}")
valid_loss = valid_loss / len(dataloader)
valid_accuracy = valid_accuracy / len(val_dataset)
return model, valid_loss, valid_accuracy
def training_loop(model, train_dataloader, valid_dataloader, train_dataset, val_dataset, criterion, optimizer, device, num_epochs, patience, model_name):
best_valid_loss = float('inf') # 가장 좋은 validation loss를 저장
early_stop_counter = 0 # 카운터
valid_max_accuracy = -1
for epoch in range(num_epochs):
model, train_loss, train_accuracy = training(model, train_dataloader, train_dataset, criterion, optimizer, device, epoch, num_epochs)
model, valid_loss, valid_accuracy = evaluation(model, valid_dataloader, val_dataset, criterion, device, epoch, num_epochs)
if valid_accuracy > valid_max_accuracy:
valid_max_accuracy = valid_accuracy
# validation loss가 감소하면 모델 저장 및 카운터 리셋
if valid_loss < best_valid_loss:
best_valid_loss = valid_loss
torch.save(model.state_dict(), f"./model_{model_name}.pt")
early_stop_counter = 0
# validation loss가 증가하거나 같으면 카운터 증가
else:
early_stop_counter += 1
print(f"Epoch [{epoch + 1}/{num_epochs}], Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f} Valid Loss: {valid_loss:.4f}, Valid Accuracy: {valid_accuracy:.4f}")
# 조기 종료 카운터가 설정한 patience를 초과하면 학습 종료
if early_stop_counter >= patience:
print("Early stopping")
break
return model, valid_max_accuracy
# 모델 전체 fine tuning
num_epochs = 100
patience = 3
scores = dict()
model_name = 'exp1'
lr = 1e-3
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr = lr)
model, valid_max_accuracy = training_loop(model, train_dataloader, val_dataloader, train_dataset, val_dataset, criterion, optimizer, device, num_epochs, patience, model_name)
scores[model_name] = valid_max_accuracy
model.load_state_dict(torch.load("./model_exp1.pt")) # 모델 불러오기
model = model.to(device)
model.eval()
total_labels = []
total_preds = []
with torch.no_grad():
for images, labels in tqdm(test_dataloader):
images = images.to(device)
labels = labels
outputs = model(images)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(outputs.data, 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
full_model_tuning_acc = accuracy_score(total_labels, total_preds) # 정확도 계산
print("Full Fine tuning model accuracy : ",full_model_tuning_acc) # 전체 모델을 fine tuning 한 것이 점수
# 마지막 layer 만 fine tuning
num_epochs = 100
patience = 3
scores = dict()
model_name = 'exp2'
model = timm.create_model('resnet50', pretrained=True, num_classes= 10).to(device)
for para in model.parameters(): # 모든 layer freeze 하기
para.requires_grad = False
for para in model.fc.parameters(): # fc layer 만 학습하기
para.requires_grad = True
lr = 1e-3
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr = lr)
model, valid_max_accuracy = training_loop(model, train_dataloader, val_dataloader, train_dataset, val_dataset, criterion, optimizer, device, num_epochs, patience, model_name)
scores[model_name] = valid_max_accuracy
model.load_state_dict(torch.load("./model_exp2.pt")) # 모델 불러오기
model = model.to(device)
model.eval()
total_labels = []
total_preds = []
with torch.no_grad():
for images, labels in tqdm(test_dataloader):
images = images.to(device)
labels = labels
outputs = model(images)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(outputs.data, 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
fc_tuning_acc = accuracy_score(total_labels, total_preds) # 정확도 계산
print("Only FC Layer Fine tuning model accuracy : ",fc_tuning_acc) # 전체 layer를 fine tuning 한 것보다 점수가 낮음
# learning rate 에 따른 결과 비교
model3 = timm.create_model('resnet50', pretrained=True, num_classes= 10).to(device)
num_epochs = 100
patience = 3
scores = dict()
model_name = 'exp3'
lr = 1e-1 # learning rate 높게 설정
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model3.parameters(), lr = lr)
model, valid_max_accuracy = training_loop(model3, train_dataloader, val_dataloader, train_dataset, val_dataset, criterion, optimizer, device, num_epochs, patience, model_name)
scores[model_name] = valid_max_accuracy
model3.load_state_dict(torch.load("./model_exp3.pt")) # 모델 불러오기
model3 = model3.to(device)
model3.eval()
total_labels = []
total_preds = []
with torch.no_grad():
for images, labels in tqdm(test_dataloader):
images = images.to(device)
labels = labels
outputs = model3(images)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(outputs.data, 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
big_lr_acc = accuracy_score(total_labels, total_preds)
print("Large learning rate model accuracy : ",big_lr_acc)
# learning rate 에 따른 결과 비교
model4 = timm.create_model('resnet50', pretrained=True, num_classes= 10).to(device)
num_epochs = 100
patience = 3
scores = dict()
model_name = 'exp4'
lr = 1e-5 # 기존보다 더 작게 설정
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model4.parameters(), lr = lr)
model, valid_max_accuracy = training_loop(model4, train_dataloader, val_dataloader, train_dataset, val_dataset, criterion, optimizer, device, num_epochs, patience, model_name)
scores[model_name] = valid_max_accuracy
model4.load_state_dict(torch.load("./model_exp4.pt")) # 모델 불러오기
model4 = model4.to(device)
model4.eval()
total_labels = []
total_preds = []
with torch.no_grad():
for images, labels in tqdm(test_dataloader):
images = images.to(device)
labels = labels
outputs = model4(images)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(outputs.data, 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
small_lr_acc = accuracy_score(total_labels, total_preds)
print("Small learning rate model accuracy : ",small_lr_acc) # learning rate를 작게 설정했을 때가 더욱 정확도가 높음
Hugging Face를 통한 전이학습
- Hugging Face로 pretrained model 불러오기
from transformers import BertForSequenceClassification
BertForSequenceClassification.from_pretrained("bert-base-cased") # BERT로 분류기를 사용하는 모델 불러오기.
# data 불러오기
data = pd.read_csv('IMDB Dataset.csv')
print(data.shape)
data.head()
dic = {'positive':0, 'negative':1} # positive 면 0으로, negative면 1로 변환
data['sentiment'] = data['sentiment'].map(dic)
# data 8:1:1 로 나누기
train, test = train_test_split(data, test_size = .2, random_state = 42)
val, test = train_test_split(test, test_size = .5, random_state = 42)
print("Train 개수: ", len(train))
print("Validation 개수: ", len(val))
print("Test 개수: ", len(test))
train.reset_index(drop=True, inplace=True) # index 재정렬
val.reset_index(drop=True, inplace=True) # index 재정렬
test.reset_index(drop=True, inplace=True) # index 재정렬
- BERT를 훈련시키기 위한 모델 전처리
train['review'] = train['review'].apply(lambda x: f'[CLS] {x} [SEP]') # 문장의 앞뒤에 [CLS]와 [SEP] 삽입
val['review'] = val['review'].apply(lambda x: f'[CLS] {x} [SEP]') # 문장의 앞뒤에 [CLS]와 [SEP] 삽입
test['review'] = test['review'].apply(lambda x: f'[CLS] {x} [SEP]') # 문장의 앞뒤에 [CLS]와 [SEP] 삽입
train.head()
# 각 문장들만 추출
train_sentences = train['review'].values
val_sentences = val['review'].values
test_sentences = test['review'].values
# 정답값 추출
train_label = train['sentiment'].values
val_label = val['sentiment'].values
test_label = test['sentiment'].values
- HuggingFace Tokenizer
# BERT의 tokenizer로 문장을 토큰으로 분리
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-cased') # 기존에 학습된 BERT tokenizer 불러오기
tokenizer.tokenize(train_sentences[0])[:10] # BERT tokenizer 결과
train_tokenized_texts = list(map(lambda x: tokenizer.tokenize(x), train_sentences))
val_tokenized_texts = list(map(lambda x: tokenizer.tokenize(x), val_sentences))
test_tokenized_texts = list(map(lambda x: tokenizer.tokenize(x), test_sentences))
# 입력 토큰의 최대 시퀀스 길이
MAX_LEN = 128
# 토큰을 숫자 인덱스로 변환
train_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), train_tokenized_texts)) # convert_tokens_to_ids로 정수 형태로 변환해주기
val_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), val_tokenized_texts))
test_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), test_tokenized_texts))
# 입력 토큰의 최대 시퀀스 길이
MAX_LEN = 128
# 토큰을 숫자 인덱스로 변환
train_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), train_tokenized_texts)) # convert_tokens_to_ids로 정수 형태로 변환해주기
val_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), val_tokenized_texts))
test_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), test_tokenized_texts))
# 입력 토큰의 최대 시퀀스 길이
MAX_LEN = 128
# 토큰을 숫자 인덱스로 변환
train_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), train_tokenized_texts)) # convert_tokens_to_ids로 정수 형태로 변환해주기
val_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), val_tokenized_texts))
test_input_ids = list(map(lambda x: tokenizer.convert_tokens_to_ids(x), test_tokenized_texts))
train_input_ids[0]
- Mask 만들기
# 마스크 만들기
train_masks = train_input_ids > 0 # 패딩이 아닌 부분은 0보다 큰 값이 있으므로 flag를 통해서 마스크를 구성할 수 있습니다.
val_masks = val_input_ids > 0
test_masks = test_input_ids > 0
train_masks[0]
- Database 만들기
# 모두 tensor로 변환
train_inputs = torch.tensor(train_input_ids) # train set의 input token id들
train_labels = torch.tensor(train_label) # train set의 label들
train_masks = torch.tensor(train_masks) # train set의 mask
validation_inputs = torch.tensor(val_input_ids) # valid set의 input token id들
validation_labels = torch.tensor(val_label) # valid set의 label들
validation_masks = torch.tensor(val_masks) # valid set의 mask
test_inputs = torch.tensor(test_input_ids) # test set의 input token id들
test_labels = torch.tensor(test_label) # test set의 label들
test_masks = torch.tensor(test_masks) # test set의 mask
class EmotionData(torch.utils.data.Dataset): # custom 데이터셋 구성
def __init__(self, inputs, masks, labels):
self.inputs = inputs
self.masks = masks
self.labels = labels
def __len__(self):
return len(self.inputs)
def __getitem__(self,idx):
inputs_value = self.inputs[idx]
masks_value = self.masks[idx]
labels_value = self.labels[idx]
return inputs_value, masks_value, labels_value
train_dataset = EmotionData(train_inputs, train_masks, train_labels)
valid_dataset = EmotionData(validation_inputs, validation_masks, validation_labels)
test_dataset = EmotionData(test_inputs, test_masks, test_labels)
BATCH_SIZE = 32
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size = BATCH_SIZE, shuffle = True, drop_last = False, num_workers = 8)
valid_dataloader = torch.utils.data.DataLoader(valid_dataset, batch_size = BATCH_SIZE, shuffle = False, drop_last = False, num_workers = 8)
test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size = BATCH_SIZE, shuffle = False, drop_last = False, num_workers = 8)
- BERT 모델 불러오기
model = BertForSequenceClassification.from_pretrained("bert-base-cased").to(device) # pretrained bert 모델 불러오기
# training 코드, evaluation 코드, training_loop 코드
def training(model, dataloader, train_dataset, optimizer, device, epoch, num_epochs):
model.train() # 모델을 학습 모드로 설정
train_loss = 0.0
train_accuracy = 0
tbar = tqdm(dataloader)
for batch in tbar:
input_ = batch[0].to(device)
mask = batch[1].to(device)
labels = batch[2].to(device)
# 순전파
output = model(input_,
attention_mask= mask,
labels=labels)
loss = output['loss'] # 얘 확인
# 역전파 및 가중치 업데이트
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 손실과 정확도 계산
train_loss += loss.item()
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(output['logits'], 1)
train_accuracy += (predicted == labels).sum().item()
# tqdm의 진행바에 표시될 설명 텍스트를 설정
tbar.set_description(f"Epoch [{epoch+1}/{num_epochs}], Train Loss: {loss.item():.4f}")
# 에폭별 학습 결과 출력
train_loss = train_loss / len(dataloader)
train_accuracy = train_accuracy / len(train_dataset)
return model, train_loss, train_accuracy
def evaluation(model, dataloader, val_dataset, device, epoch, num_epochs):
model.eval() # 모델을 평가 모드로 설정
valid_accuracy = 0
with torch.no_grad(): # model의 업데이트 막기
tbar = tqdm(dataloader)
for batch in tbar:
input_ = batch[0].to(device)
mask = batch[1].to(device)
labels = batch[2].to(device)
# 순전파
output = model(input_,
attention_mask= mask,
labels=labels)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(output['logits'], 1)
valid_accuracy += (predicted == labels).sum().item()
# tqdm의 진행바에 표시될 설명 텍스트를 설정
tbar.set_description(f"Epoch [{epoch+1}/{num_epochs}]")
valid_accuracy = valid_accuracy / len(val_dataset)
return model, valid_accuracy
def training_loop(model, train_dataloader, valid_dataloader, train_dataset, val_dataset, optimizer, device, num_epochs, model_name):
best_valid_loss = float('inf') # 가장 좋은 validation loss를 저장
valid_max_accuracy = -1
for epoch in range(num_epochs):
model, train_loss, train_accuracy = training(model, train_dataloader, train_dataset, optimizer, device, epoch, num_epochs)
model, valid_accuracy = evaluation(model, valid_dataloader, val_dataset, device, epoch, num_epochs)
if valid_accuracy > valid_max_accuracy:
valid_max_accuracy = valid_accuracy
torch.save(model.state_dict(), f"./model_{model_name}.pt")
print(f"Epoch [{epoch + 1}/{num_epochs}], Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, Valid Accuracy: {valid_accuracy:.4f}")
return model, valid_max_accuracy
# 모델 전체 fine tuning
num_epochs = 2
model_name = 'bert1'
lr = 1e-5
optimizer = optim.Adam(model.parameters(), lr=lr)
model, valid_max_accuracy = training_loop(model, train_dataloader, valid_dataloader, train_dataset, valid_dataset, optimizer, device, num_epochs, model_name)
print('Valid max accuracy : ', valid_max_accuracy)
model.load_state_dict(torch.load("./model_bert1.pt")) # 모델 불러오기
model = model.to(device)
model.eval()
total_labels = []
total_preds = []
total_probs = []
with torch.no_grad():
for batch in tqdm(test_dataloader):
input_ = batch[0].to(device)
mask = batch[1].to(device)
labels = batch[2].to(device)
output = model(input_,
attention_mask= mask,
labels=labels)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(output['logits'], 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_probs.append(output['logits'].detach().cpu().numpy())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
total_probs = np.concatenate(total_probs, axis= 0)
acc = accuracy_score(total_labels, total_preds)
print("Full fine tuning model accuracy : ",acc)
model = BertForSequenceClassification.from_pretrained("bert-base-cased").to(device)
for para in model.parameters(): # 모든 layer freeze 하기
para.requires_grad = False
for name, param in model.named_parameters(): # fc layer 만 학습하기
if name in 'classifier.weight':
param.requires_grad = True
num_epochs = 2
model_name = 'bert2'
optimizer = optim.Adam(model.parameters(), lr=lr)
model, valid_max_accuracy = training_loop(model, train_dataloader, valid_dataloader, train_dataset, valid_dataset, optimizer, device, num_epochs, model_name)
print('Valid max accuracy : ', valid_max_accuracy)
model.load_state_dict(torch.load("./model_bert2.pt")) # 모델 불러오기
model = model.to(device)
model.eval()
total_labels = []
total_preds = []
total_probs = []
with torch.no_grad():
for batch in tqdm(test_dataloader):
input_ = batch[0].to(device)
mask = batch[1].to(device)
labels = batch[2].to(device)
output = model(input_,
attention_mask= mask,
labels=labels)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(output['logits'], 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_probs.append(output['logits'].detach().cpu().numpy())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
total_probs = np.concatenate(total_probs, axis= 0)
acc = accuracy_score(total_labels, total_preds)
print("Only FC layer tunning model accuracy : ", acc)
# learning rate 를 기존보다 높게 설정
model = BertForSequenceClassification.from_pretrained("bert-base-cased").to(device)
num_epochs = 2
model_name = 'bert3'
lr = 1e-4
optimizer = optim.Adam(model.parameters(), lr=lr)
model, valid_max_accuracy = training_loop(model, train_dataloader, valid_dataloader, train_dataset, valid_dataset, optimizer, device, num_epochs, model_name)
print('Valid max accuracy : ', valid_max_accuracy)
model.load_state_dict(torch.load("./model_bert3.pt")) # 모델 불러오기
model = model.to(device)
model.eval()
total_labels = []
total_preds = []
total_probs = []
with torch.no_grad():
for batch in tqdm(test_dataloader):
input_ = batch[0].to(device)
mask = batch[1].to(device)
labels = batch[2].to(device)
output = model(input_,
attention_mask= mask,
labels=labels)
# torch.max에서 dim 인자에 값을 추가할 경우, 해당 dimension에서 최댓값과 최댓값에 해당하는 인덱스를 반환
_, predicted = torch.max(output['logits'], 1)
total_preds.extend(predicted.detach().cpu().tolist())
total_labels.extend(labels.tolist())
total_probs.append(output['logits'].detach().cpu().numpy())
total_preds = np.array(total_preds)
total_labels = np.array(total_labels)
total_probs = np.concatenate(total_probs, axis= 0)
acc = accuracy_score(total_labels, total_preds)
print("Larger learning rate accuracy : ", acc)
'Study > 머신러닝' 카테고리의 다른 글
PyTorch Hydra (0) | 2024.12.17 |
---|---|
PyTorch Lightning (0) | 2024.12.17 |
딥러닝과 PyTorch (0) | 2024.12.17 |
텐서 조작, Tensor Manipulation(with PyTorch) (0) | 2024.12.16 |
Pytorch (0) | 2024.12.16 |