2023. 8. 1. 09:54ㆍ광고차단 머신러닝
저번 글을 읽고 오시면 좋습니다!
저난 글들은 주로 제가 이번 프로젝트를 진행하면서
선택한 기술들에 대한 이유와 근거에 대해 설명에 대한 글들이었습니다.
이번 글에서는 제가 사용한 BERT 와 Random Forest Model(이하 RF) 을
실제로 학습(Fine Tuning)시키고, 이를 가지고 실제로 성능 테스트를 해본 결과를 보겠습니다.
그전에 학습이라는 단어가 왜 Fine Tuning 이야? Training 아니야?
이번에 이 프로젝트로 논문을 쓰며 여러 자료를 찾던 와중 느낀 게
Fine Tuning(미세 조정), Training(학습) 은 영단어상 엄연히 다른 데
내가 쓰는 단어는 주로 학습, 즉 Training 이였습니다.
이번 프로젝트를 진행하며 머신 러닝에 대해 일자무식이라
인터넷에 존재하는 글들을 찾다보니 이런 글을 찾았는데,
즉, Fine Tuning 과 Training 은 엄연히 다른 의미라는 것이였습니다...
위 글을 정리해보자면 다음과 같다.
학습(Training)은 기본적으로 모델에 대한 지식을 구축하는 과정입니다.
이 단계에서, 모델은 방대한 양의 데이터를 통해 다양한 패턴, 관계, 사실들을 학습합니다.
이렇게 학습된 정보는 모델의 "장기기억"에 해당하고 기본적인 지식과 이해를 형성하는 데 크게 기여하게 된다.
미세조정(Fine Tuning)은 학습된 모델에 특정 작업이나 스타일을 가르치는 과정입니다.
이는 모델의 "단기기억"에 비유할 수 있습니다.
미세조정은 특정 작업에 대해 모델을 최적화하며, 특정 작업에 대한 성능을 향상시키는 데 중점을 둡니다.
말하자면 이번 프로젝트에서 작업들은 pre-trained,
즉, 미리 trained 학습된 모델들을 가지고
'광고 사이트 검열' 이라는 작업을 하기 위한 fine-tuning 이라고 말할 수 있다!
BERT, RF 학습 코드
서론이 길었으니 바로 BERT, RF 학습 코드로 가보겠습니다!
이번 프로젝트는 Python 3.7과 PyTorch 1.9.0 환경에서 수행하였습니다.
Random Forest Model 튜닝
RF 모델은 sklearn 패키지의 RandomForestClassifier 를 사용하였습니다.
HTML 의 태그들을 피처로 사용하였으며, 이를 TfidVectorizer 를 이용해 벡터화하고
이렇게 생성된 피처들을 RF 모델에 적용하여 학습 하였습니다.
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.ensemble import RandomForestClassifier
# HTML 태그를 파싱하여 계층적 구조를 반영한 피처 생성
parsed_html_features = []
for html in html_data:
soup = BeautifulSoup(html, 'html.parser')
tag_features = []
for tag in soup.descendants:
if tag.name is not None:
tag_features.append(tag.name)
parsed_html_features.append(' '.join(tag_features))
# 피처 벡터화
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(parsed_html_features)
# 랜덤 포레스트 모델 학습
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, Y_train)
BERT Model 튜닝
BERT 모델 학습에는 Hugging Face 의 Transformers 라이브러리를 사용하였습니다.
이 라이브러리를 사용하여 BERT 모델의 구조를 정의하고 웹사이트의 내용을 토큰화하였습니다
그 후 토큰화된 웹사이트의 내용과 해당 웹사이트의 라벨을 모델에 적용하여 학습하였습니다.
# BERT 모델
model = BertForSequenceClassification.from_pretrained('bert-base-multilingual-cased', num_labels=2)
model = model.to(device)
# 옵티마이저
optimizer = AdamW(model.parameters(), lr=1e-5)
# 학습
model.train()
for epoch in range(5):
for batch in dataloader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['label'].to(device)
outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
loss.backward()
optimizer.step()
optimizer.zero_grad()
print(f'Epoch {epoch + 1}, Loss {loss.item()}')
# 학습된 모델 저장
torch.save(model.state_dict(), 'models/bert_ver3.pt')
모델 예측
모델이 학습되면, 각 모델을 사용하여 웹사이트 분류를 예측할 수 있습니다.
각 모델은 다음과 같이 동작합니다
Random Forest Model Prediction
HTML 태그를 파싱하여 계층적 구조를 반영한 피처를 생성하고,
이 피처들을 벡터화하여, 랜덤 포레스트 모델에 적용하여 분류를 예측하였습니다.
# 피처 벡터화
X = vectorizer.transform(parsed_html_features)
# 예측 수행
df['Infer_Label_RF'] = rf.predict(X)
# 레이블과 예측 레이블이 다른 행 찾기
mismatch_rows = df[df['Label'] != df['Infer_Label_RF']]
BERT Model Prediction
웹사이트의 내용을 토큰화하고, BERT 모델에 적용하여 분류를 예측하였습니다.
class MyDataset(Dataset):
def __init__(self, sentences, tokenizer):
self.sentences = sentences
self.tokenizer = tokenizer
def __len__(self):
return len(self.sentences)
def __getitem__(self, idx):
sentence = self.sentences[idx]
encoding = self.tokenizer.encode_plus(
sentence,
add_special_tokens=True,
truncation=True,
padding='max_length',
max_length=512,
return_tensors='pt'
)
return {
'input_ids': encoding['input_ids'].flatten(),
'attention_mask': encoding['attention_mask'].flatten()
}
# 데이터셋 생성
dataset = MyDataset(df['Natural_Language'].values, tokenizer)
# 추론 및 결과 기록
df['Infer_Label_BERT'] = None
problematic_rows = [] // 처리가 불가능한 경우, 배열에 담고 나서 따로 콘솔창에 출력
for i, row in df.iterrows():
try:
inputs = tokenizer(row['Natural_Language'], return_tensors='pt', padding='longest', truncation=True)
inputs = {key: inputs[key].to(device) for key in inputs}
outputs = model(**inputs)
_, predicted = torch.max(outputs.logits, 1)
df.loc[i, 'Infer_Label_BERT'] = predicted.item()
except Exception as e:
problematic_rows.append(i)
결과 평가
앙상블 모델 예측
하나의 모델만 사용하는 것보다,
두 가지 모델을 조합하면 더 좋지 않을까 생각해
두 모델을 합친 앙상블 학습을 진행했습니다.
앙상블 학습은 각 모델의 예측 확률을 가중 평균하여 최종 예측을 수행하였고,
가중치는 BERT 모델과 랜덤 포레스트 모델의 예측이 불일치하는 비율이 최소가 되도록 설정하였습니다!
best_mismatch_rate = 100 # 가장 안 좋은 가능한 불일치율로 초기화합니다
best_weights = (0, 0) # 더미 가중치로 초기화합니다
# 가능한 모든 가중치 조합에 대해 반복합니다
for bert_weight in range(1, 1001):
rf_weight = 1001 - bert_weight
bert_weight /= 1000
rf_weight /= 1000
# 확률의 가중 평균을 계산합니다
df['Infer_Prob'] = bert_weight * df['Infer_Prob_BERT'] + rf_weight * df['Infer_Prob_RF']
# 가중 평균 확률에 기반하여 최종 라벨을 결정합니다
df['Infer_Label'] = df['Infer_Prob'].apply(lambda x: 1 if x > 0.5 else 0)
# 불일치율을 계산합니다
mismatch_rows = df[df['Label'] != df['Infer_Label']]
mismatch_rate = len(mismatch_rows) / (len(df) - error_count) * 100
# 이 가중치 조합이 더 나은 (낮은) 불일치율을 가져오면, 최적의 불일치율과 가중치를 업데이트합니다
if mismatch_rate < best_mismatch_rate:
best_mismatch_rate = mismatch_rate
best_weights = (bert_weight, rf_weight)
# 불일치율이 같으면, 가중치를 출력합니다
elif mismatch_rate == best_mismatch_rate:
print(f"BERT 가중치: {bert_weight}, RF 가중치: {rf_weight}, 불일치율: {mismatch_rate}%")
# 최적의 가중치와 그에 해당하는 불일치율을 출력합니다
print(f"최적의 가중치 --> BERT: {best_weights[0]}, RF: {best_weights[1]}, 불일치율: {best_mismatch_rate}%")
수학적으로 최적의 가중치 조합해를 구하는 방법이 있을 까
생각을 해봤지만 생각이 나지 않았습니다.
그래서 for문 이중 중첩을 통해
각각의 가중치를 0.001~ 1.000 까지의 조합을 구하도록 했습니다.
모델 성능 평가
각 모델의 성능은 불일치율을 이용하여 평가하였습니다.
불일치율은 웹사이트의 실제 분류와 모델 이 예측한 분류가 일치하지 않는 비율을 나타냅니다!
이번 연구에서 개발한 앙상블 모델의 성능은 다음과 같습니다.
- RF - 4.807%
- BERT - 5.769%
- 가중평균(BERT+RF) - 4.7%
랜덤 포레스트와 BERT 모델을 각각 사용했을 때보다
앙상블 모델을 사용했을 때 더 좋은 성능을 보였습니다.
이 결과는 앙상블 학습이 여러 모델의 장점을 결합하여
더욱 정확한 예측을 수행할 수 있음을 보여줍니다!
결론
위 글에서 저에 대한 의심(?)해야 할 부분이 남아있습니다.
바로
과연 위 수치들은 의미가 있는 수치일까?
이에 대해 고민을 안 해보지 않았으나,
이 수치에 대해서는 단순히 개발자의 시선 뿐만이 아니라,
다양한 시각을 통한 의미 부여가 필요하다고 느꼈습니다.
그리고 여기까지는 BERT 를 통해 자연어 처리를 사용했지만,
이전 글에서도 말했듯 BERT 의 개량형 모델들도 존재하기
같은 자료에 대해서 다른 모델로도 테스트 해볼 여지가 아직 남아있습니다...
(실제로 뭔가가 더 남아있긴 하다...)
앞으로는 다른 모델을 통한 테스트,
그리고 추가적으로 기술 선택에 대한 이유가 보충이 필요하다고 생각하면
포스팅 하겠습니다!
참고
https://chrisalbon.com/Large+Language+Models/Fine-Tuning+Vs.+Training
'광고차단 머신러닝' 카테고리의 다른 글
어디서부터 이게 잘못된 걸까..., 기계 학습 시 데이터셋 양의 중요성 (0) | 2023.08.03 |
---|---|
BERT 로는 노오력이 부족하다, RoBERTa 로 성능 개선 시도했는 데 결과물이...? (0) | 2023.08.03 |
동전에 이어 이번에는 나무...? Random Forest Model 은 뭘까 (0) | 2023.07.31 |
??? : 토크나이저...? 토큰...? 동전...?, 기술 선택의 이유와 근거 (2) (0) | 2023.07.27 |
??? : "하... 뭐 고르지?", 기술 선택의 이유와 근거 (1) (0) | 2023.07.24 |