"너가 만든 거 유효하긴 해?", BERT, Random Forest 성능테스트 하기

2023. 8. 1. 09:54광고차단 머신러닝

728x90

 

 

동전에 이어 이번에는 나무...? Random Forest Model 은 뭘까

2023.06.28 - [산학협력프로젝트] - 산학협력 프로젝트, 광고 차단 오토로 돌리기 (졸업 하고 싶어요ㅠ) 산학협력 프로젝트, 광고 차단 오토로 돌리기 (졸업 하고 싶어요ㅠ) 1. 오늘의 주제 이번에 진

xpmxf4.tistory.com

저번 글을 읽고 오시면 좋습니다!


저난 글들은 주로 제가 이번 프로젝트를 진행하면서

선택한 기술들에 대한 이유와 근거에 대해 설명에 대한 글들이었습니다.

 

이번 글에서는 제가 사용한 BERT 와 Random Forest Model(이하 RF) 을

실제로 학습(Fine Tuning)시키고, 이를 가지고 실제로 성능 테스트를 해본 결과를 보겠습니다.

그전에 학습이라는 단어가 왜 Fine Tuning 이야? Training 아니야?

이번에 이 프로젝트로 논문을 쓰며 여러 자료를 찾던 와중 느낀 게

Fine Tuning(미세 조정), Training(학습) 은 영단어상 엄연히 다른 데 

내가 쓰는 단어는 주로 학습, 즉 Training 이였습니다.

 

이번 프로젝트를 진행하며 머신 러닝에 대해 일자무식이라

인터넷에 존재하는 글들을 찾다보니 이런 글을 찾았는데,

Fine Tuning vs 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 까지의 조합을 구하도록 했습니다.

모델 성능 평가

각 모델의 성능은 불일치율을 이용하여 평가하였습니다.

불일치율은 웹사이트의 실제 분류와 모델 이 예측한 분류가 일치하지 않는 비율을 나타냅니다!

 

이번 연구에서 개발한 앙상블 모델의 성능은 다음과 같습니다.

  1. RF - 4.807%
  2. BERT - 5.769%
  3. 가중평균(BERT+RF) - 4.7%

랜덤 포레스트와 BERT 모델을 각각 사용했을 때보다

앙상블 모델을 사용했을 때 더 좋은 성능을 보였습니다.

 

이 결과는 앙상블 학습이 여러 모델의 장점을 결합하여

더욱 정확한 예측을 수행할 수 있음을 보여줍니다!

결론

위 글에서 저에 대한 의심(?)해야 할 부분이 남아있습니다.

바로

 

과연 위 수치들은 의미가 있는 수치일까?

 

이에 대해 고민을 안 해보지 않았으나,

이 수치에 대해서는 단순히 개발자의 시선 뿐만이 아니라,

다양한 시각을 통한 의미 부여가 필요하다고 느꼈습니다.

 

그리고 여기까지는 BERT 를 통해 자연어 처리를 사용했지만,

https://xpmxf4.tistory.com/47

 

??? : 토크나이저...? 토큰...? 동전...?, 기술 선택의 이유와 근거 (2)

2023.07.24 - [산학협력프로젝트] - ??? : "하... 뭐 고르지?", 기술 선택의 이유와 근거 (1) ??? : "하... 뭐 고르지?", 기술 선택의 이유와 근거 (1) 뭐 먹을까요? 깔깔깔 산학협력 프로젝트, 광고 차단 오

xpmxf4.tistory.com

이전 글에서도 말했듯 BERT 의 개량형 모델들도 존재하기

같은 자료에 대해서 다른 모델로도 테스트 해볼 여지가 아직 남아있습니다...

아직 안 끝났다...

(실제로 뭔가가 더 남아있긴 하다...)

앞으로는 다른 모델을 통한 테스트,

그리고 추가적으로 기술 선택에 대한 이유가 보충이 필요하다고 생각하면

포스팅 하겠습니다!

참고

https://chrisalbon.com/Large+Language+Models/Fine-Tuning+Vs.+Training 

 

 

728x90