본문 바로가기
자연어처리(NLP) & CHAT GPT/NLP

[NLP] BERT+ Fine-tuning, KoBERT - 실습

by 11car28z 2023. 8. 23.

TPU 사용하기 위한 환경설정

참고 링크 : https://wikidocs.net/119990

 

18-01 코랩(Colab)에서 TPU 사용하기

지금까지는 GPU 사용만으로도 모델을 학습하는데 큰 무리가 없었지만, BERT의 경우 지금까지 사용한 모델보다 무거운 편입니다. 다시 말해 학습 속도가 상대적으로 느린 편입니다.…

wikidocs.net

 

# TPU 초기화
import tensorflow as tf
import os

resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='grpc://' + os.environ['COLAB_TPU_ADDR'])

tf.config.experimental_connect_to_cluster(resolver)
tf.tpu.experimental.initialize_tpu_system(resolver)



#TPU Strategy 셋팅
strategy = tf.distribute.TPUStrategy(resolver)

 

 

#딥 러닝 모델의 컴파일
def create_model():
  return tf.keras.Sequential( #Sequential객체 리턴
      [tf.keras.layers.Conv2D(256, 3, activation='relu', input_shape=(28, 28, 1)),
       tf.keras.layers.Conv2D(256, 3, activation='relu'),
       tf.keras.layers.Flatten(),
       tf.keras.layers.Dense(256, activation='relu'),
       tf.keras.layers.Dense(128, activation='relu'),
       tf.keras.layers.Dense(10)])# 10차원 구조로 예측된 결과 출력

 

 

with strategy.scope():#중요!!!!!!!!!!!
  model = create_model() #만들어진 모델 변수에 들어감
  model.compile(optimizer='adam',
                loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                metrics=['sparse_categorical_accuracy'])

 

 


BERT

transformers의 모델 클래스 불러오기(파인튜닝) ->분류기에 적절한 형태로 변형하기

 

BERT 사전 학습 모델 참고: https://github.com/google-research/bert

 

GitHub - google-research/bert: TensorFlow code and pre-trained models for BERT

TensorFlow code and pre-trained models for BERT. Contribute to google-research/bert development by creating an account on GitHub.

github.com

pip install transformers

 

import transformers
transformers.__version__

 

import pandas as pd
import numpy as np
import urllib.request
import os
from tqdm import tqdm
import tensorflow as tf
from transformers import BertTokenizer, TFBertModel

 

1.데이터 로드하기

#추가 학습 데이터 다운
#네이버 영화 감성 분류 데이
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt", filename="ratings_train.txt")
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt", filename="ratings_test.txt")



#데이터 프레임 형식으로 읽어오기
train_data = pd.read_table('ratings_train.txt')
test_data = pd.read_table('ratings_test.txt')



#데이터 확인
train_data

 

2.데이터 정제하기

train_data = train_data.dropna(how = 'any') # Null 값이 존재하는 행 제거
train_data = train_data.reset_index(drop=True)
print(train_data.isnull().values.any()) # Null 값이 존재하는지 확인

#False

test_data = test_data.dropna(how = 'any') # Null 값이 존재하는 행 제거
test_data = test_data.reset_index(drop=True)# 중간에 0인 값을 없애기 위해 reset_index
print(test_data.isnull().values.any()) # Null 값이 존재하는지 확인

#False

len(train_data)#149995

 

3.학습된 BERT 토크나이저 가져오기

#이미 학습된 모델을 가져오기, BertTokenizer은 이름
tokenizer = BertTokenizer.from_pretrained('bert-base-multilingual-cased')



#한국인이 만든 한국어 BERT : klue/bert-base
tokenizer_klue = BertTokenizer.from_pretrained('klue/bert-base')

 

4.정수 인코딩 하기

#인코딩된 토크나이저 결과 확인하기
print(tokenizer.encode("보는내내 그대로 들어맞는 예측 카리스마 없는 악역"))

#인코딩된 결과를 디코딩해서 원문 확인해보기
print(tokenizer.decode(tokenizer.encode("보는내내 그대로 들어맞는 예측 카리스마 없는 악역")))
#[CLS], [SEP] : 문장 시작과 끝

 

[101, 9356, 11018, 31605, 31605, 110589, 71568, 118913, 11018, 9576, 119281, 9786, 79940, 23811, 40364, 9520, 23160, 102]
[CLS] 보는내내 그대로 들어맞는 예측 카리스마 없는 악역 [SEP]

 

print(tokenizer_klue.encode("보는내내 그대로 들어맞는 예측 카리스마 없는 악역"))

#인코딩된 결과를 디코딩해서 원문 확인해보기
print(tokenizer_klue.decode(tokenizer_klue.encode("보는내내 그대로 들어맞는 예측 카리스마 없는 악역")))
#[CLS], [SEP] : 문장 시작과 끝

 

[2, 1160, 2259, 2369, 2369, 4311, 20657, 2259, 5501, 13132, 1415, 2259, 23713, 3]
[CLS] 보는내내 그대로 들어맞는 예측 카리스마 없는 악역 [SEP]

구글 토그나이저와 klue 토크나이저의 결과가 다름.

  • 구글 토그나이저: [101, 9356, 11018, 31605, 31605, 110589, 71568, 118913, 11018, 9576, 119281, 9786, 79940, 23811, 40364, 9520, 23160, 102]
  • klue 토크나이저: [2, 1160, 2259, 2369, 2369, 4311, 20657, 2259, 5501, 13132, 1415, 2259, 23713, 3]

klue는 특별토큰도 인코딩 결과로 나타난다.

 

for elem in tokenizer.encode("보는내내 그대로 들어맞는 예측 카리스마 없는 악역"):
  print(tokenizer.decode(elem))
#보는내내 -> 사전에 없는 단어라 분절되어 표현 : 보 / # # 는 / # # 내 / # # 내

 

[ C L S ]
보
# # 는
# # 내
# # 내
그 대 로
들 어
# # 맞
# # 는
예
# # 측
카
# # 리 스
# # 마
없 는
악
# # 역
[ S E P ]

 

tokenizer.decode(101) #'[ C L S ]'

tokenizer.decode(102) #'[ S E P ]'

tokenizer.cls_token_id #cls 토큰 번호 확인
#101

tokenizer.sep_token_id #sep 토큰 번호 확인
#102

tokenizer.pad_token_id #pad 토큰 번호 확인
#0

max_seq_len = 128

encoded_result = tokenizer.encode("전율을 일으키는 영화. 다시 보고싶은 영화", max_length=max_seq_len, pad_to_max_length=True)

encoded_result #cls / 본문 / sep / 0으로 패딩되어진 것들 - 길이 128만큼

 

5.세그먼트 임베딩

문장을 구분해야해서 서로 다른값 0(패딩) 또는 1(단어0)로 표

print([0]*max_seq_len)#길이가 128일 리스트에 요소값 0으로 채우기

 

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

 

tokenizer.encode("전율을 일으키는 영화. 다시 보고싶은 영화")
#실제 단어 토큰

 

[101,
 9665,
 119183,
 10622,
 9641,
 119185,
 66815,
 42428,
 119,
 25805,
 98199,
 119088,
 10892,
 42428,
 102]

 

#전체 문장에 대한 시퀀스의 길이
valid_num = len(tokenizer.encode("전율을 일으키는 영화. 다시 보고싶은 영화") )
#(128 - 15) 만큼 0(패딩)으로 채워져 있다.

 

어텐션 마스크 : 단어 토큰이 있는 위치는 1, 패딩 위치는 0

print(valid_num*[1]+(max_seq_len - valid_num)*[0])
#문자가 있는 개수만큼 1, 패딩 길이 만큼 0 출력

 

[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]

 

def convert_examples_to_features(examples, labels, max_seq_len, tokenizer):#본문의 내용 / label /전체길이/ 토크나이저
    input_ids, attention_masks, token_type_ids, data_labels = [], [], [], []

    for example, label in tqdm(zip(examples, labels), total=len(examples)):
        # input_id는 워드 임베딩을 위한 문장의 정수 인코딩
        input_id = tokenizer.encode(example, max_length=max_seq_len, pad_to_max_length=True)
        # [2, 1000, 2000, ...500, 0, 0, ...0]


        padding_count = input_id.count(tokenizer.pad_token_id) #0의 개수를 count
        attention_mask = [1] * (max_seq_len - padding_count) + [0] * padding_count# attention_mask는 실제 단어가 위치하면 1, 패딩의 위치에는 0인 시퀀스.

        # token_type_id는 세그먼트 임베딩을 위한 것으로 이번 예제는 문장이 1개이므로 전부 0으로 통일.
        token_type_id = [0] * max_seq_len#토큰 타입을 전체 길이만큼 0으로

        assert len(input_id) == max_seq_len, "Error with input length {} vs {}".format(len(input_id), max_seq_len)#assert 중간에 에러 상황이면 대처
        assert len(attention_mask) == max_seq_len, "Error with attention mask length {} vs {}".format(len(attention_mask), max_seq_len)
        assert len(token_type_id) == max_seq_len, "Error with token type length {} vs {}".format(len(token_type_id), max_seq_len)

        #4개의 리스트 생성
        input_ids.append(input_id)
        attention_masks.append(attention_mask)
        token_type_ids.append(token_type_id)
        data_labels.append(label)

    #array로 바꾸기
    input_ids = np.array(input_ids, dtype=int)
    attention_masks = np.array(attention_masks, dtype=int)
    token_type_ids = np.array(token_type_ids, dtype=int)
    data_labels = np.asarray(data_labels, dtype=np.int32)

    return (input_ids, attention_masks, token_type_ids), data_labels #튜플->train_X, 변수->train_y 로 들어간다.

 

#기존의 사전 학습된 모델에 아래 데이터로 추가 학습시키기
train_X, train_y = convert_examples_to_features(train_data['document'], train_data['label'], max_seq_len=max_seq_len, tokenizer=tokenizer)

 

train_data['document'][0]
train_X[0][0]#단어 인코딩
train_X[1][0]#어텐션 마스크
train_X[2][0]#세그먼트 인코딩
train_y[0]#레이블

 

test_X, test_y = convert_examples_to_features(test_data['document'], test_data['label'], max_seq_len=max_seq_len, tokenizer=tokenizer)

BERT의 출력 구조 이해

#한국어 BERT 모델 로드
model=TFBertModel.from_pretrained("klue/bert-base", from_pt=True)

max_seq_len = 128

#입력 모양이 128차원이다, 단어 128개 들어갈 수 있음.
input_ids_layer = tf.keras.layers.Input(shape=(max_seq_len,), dtype=tf.int32)

#어텐션 마스크
attention_masks_layer = tf.keras.layers.Input(shape=(max_seq_len,), dtype=tf.int32)

#세그먼트
token_type_ids_layer = tf.keras.layers.Input(shape=(max_seq_len,), dtype=tf.int32)

#위 3개의 모델들을 리스트로 묶어 이미 학습된 모델에 전달
outputs = model([input_ids_layer, attention_masks_layer,token_type_ids_layer])

#outputs에는 2개의 출력이 존재

print(outputs[0])
#(None, 128, 768) : (배치크기, 128,768) #798차원 벡터가 128개 있다. 즉, 문장길이(128)만큼 출력이 된다.
#BERT를 이용한 다대다 문제 해결에 위의 구조를 사용 - outputs[0]을 사용
#다대다 문제 유형 : 객체명 인식(홍길동은 이번 카카오 코딩 테스트에 합격했다. / 사람: 홍길동, 회사: 카카오)

print(outputs[1])
#(None, 768): (배치크기,768)
#BERT를 이용한 다대일 문제 해결에 사용 - outputs[1]을 사용
#다대일 문제 유형 : 감성분류

BERT에 감성분류 데이터 학습시키기(Fine - tuning)

#클래스 호출시 생성자 작동

class TFBertForSequenceClassification(tf.keras.Model):
    def __init__(self, model_name):# 클래스 - 객체를 생성하는 시점에 무조건 호출됨(생성자 함수)
        super(TFBertForSequenceClassification, self).__init__() #모든 객체는 부모가 먼저 만들어져있어야함.
        self.bert = TFBertModel.from_pretrained(model_name, from_pt=True)
        self.classifier = tf.keras.layers.Dense(1,
                                                kernel_initializer=tf.keras.initializers.TruncatedNormal(0.02),
                                                activation='sigmoid',
                                                name='classifier')#출력이 1개 , 이중분류 / 시그모이드 함수 사용

    def call(self, inputs):
        input_ids, attention_mask, token_type_ids = inputs
        outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
        cls_token = outputs[1] #다대일 문제 유형( 만약 다대다 문제 유형이면 outputs[0] 참조)
        prediction = self.classifier(cls_token)
        return prediction

 

# TPU 작동을 위한 코드 TPU 작동을 위한 코드
resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='grpc://' + os.environ['COLAB_TPU_ADDR'])
tf.config.experimental_connect_to_cluster(resolver)
tf.tpu.experimental.initialize_tpu_system(resolver)
strategy = tf.distribute.experimental.TPUStrategy(resolver)

 

# 기존 BERT 모델에 감성분류 모델 데이터 추가 학습(Fine - tuning)
with strategy.scope():
  model = TFBertForSequenceClassification("bert-base-multilingual-cased")#클래스 호출
  optimizer = tf.keras.optimizers.Adam(learning_rate=5e-5)
  loss = tf.keras.losses.BinaryCrossentropy()
  model.compile(optimizer=optimizer, loss=loss, metrics = ['accuracy'])

model.fit(train_X, train_y, epochs=2, batch_size=64, validation_split=0.2) #2에폭만 돌지만 성능이 좋다 - 사전 학습 모델을 사용했기때문

 

results=model.evaluate(test_X, test_y, batch_size=1024) #test_X로 실행한 분류결과와 정답인 test_y 비교

 

결과: 입력해서 긍정인지 부정인지 출력

 

 def sentiment_predict(new_sentence):
  #긍정인지 부정인지 분류하는 함수

  #인코딩 + 패딩: 최대길이 지정, 단어 제외 나머지를 0으로 패딩
  input_id = tokenizer.encode(new_sentence, max_length=max_seq_len, pad_to_max_length=True)
  padding_count = input_id.count(tokenizer.pad_token_id)

  #어텐션 마스크
  attention_mask = [1] * (max_seq_len - padding_count) + [0] * padding_count
  token_type_id = [0] * max_seq_len

  #어레이로 바꿔주기
  input_ids = np.array([input_id])
  attention_masks = np.array([attention_mask])
  token_type_ids = np.array([token_type_id])

  #모델에 적용해보기
  encoded_input = [input_ids, attention_masks, token_type_ids]
  score = model.predict(encoded_input)[0][0]

  print(score)

  if(score > 0.5):
    print("{:.2f}% 확률로 긍정 리뷰입니다.\n".format(score * 100))
  else:
    print("{:.2f}% 확률로 부정 리뷰입니다.\n".format((1 - score) * 100))


  #인코딩

  #패

 

print(sentiment_predict("아 정말 개짜증 재미 없어"))
#개짜증이라는 것이 부정인지 판단하는 과정: 워드 피스 토크나이저를 사용
print(sentiment_predict("이딴게 영화라고..."))
print(sentiment_predict("개꿀잼 왕추천"))


KoBert:KoNLI문제 해결

참고 링크: https://github.com/kakaobrain/kor-nlu-datasets

 

GitHub - kakaobrain/kor-nlu-datasets: KorNLI and KorSTS: New Benchmark Datasets for Korean Natural Language Understanding

KorNLI and KorSTS: New Benchmark Datasets for Korean Natural Language Understanding - GitHub - kakaobrain/kor-nlu-datasets: KorNLI and KorSTS: New Benchmark Datasets for Korean Natural Language Und...

github.com

import os
import pandas as pd
import numpy as np
from tqdm import tqdm
import urllib.request
from sklearn import preprocessing
import tensorflow as tf
from transformers import BertTokenizer, TFBertModel
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
#EarlyStopping: 모델 조기 중단
#ModelCheckpoint: 가장 좋았을때의 모델을 저장


# 훈련 데이터 다운로드
urllib.request.urlretrieve("https://raw.githubusercontent.com/kakaobrain/KorNLUDatasets/master/KorNLI/multinli.train.ko.tsv", filename="multinli.train.ko.tsv")
urllib.request.urlretrieve("https://raw.githubusercontent.com/kakaobrain/KorNLUDatasets/master/KorNLI/snli_1.0_train.ko.tsv", filename="snli_1.0_train.ko.tsv")


#검증 데이터 다운로드
urllib.request.urlretrieve("https://raw.githubusercontent.com/kakaobrain/KorNLUDatasets/master/KorNLI/xnli.dev.ko.tsv", filename="xnli.dev.ko.tsv")


#테스트 데이터 다운로드
urllib.request.urlretrieve("https://raw.githubusercontent.com/kakaobrain/KorNLUDatasets/master/KorNLI/xnli.test.ko.tsv", filename="xnli.test.ko.tsv")


#데이터 프레임으로 데이터들 읽기
train_snli = pd.read_csv("snli_1.0_train.ko.tsv", sep='\t', quoting=3)# quoting=3 - 인용부호 제거
train_xnli = pd.read_csv("multinli.train.ko.tsv", sep='\t', quoting=3)
val_data = pd.read_csv("xnli.dev.ko.tsv", sep='\t', quoting=3)
test_data = pd.read_csv("xnli.test.ko.tsv", sep='\t', quoting=3)

train_snli.head()

 

#train_snli에 train_xnli를 추가하기
train_data = train_snli.append(train_xnli)

train_data.shape #(942854, 3)

train_data = train_data.sample(frac=1)#frac=1 - 100% 데이터를 섞어라

train_data.head()

 

 

def drop_na_and_duplciates(df):
  df = df.dropna()#nan값 제거
  df = df.drop_duplicates()#중복행제거
  df = df.reset_index(drop=True)#번호 1번부터 다시 주도록
  return df

 

# 결측값 및 중복 샘플 제거
train_data = drop_na_and_duplciates(train_data)
val_data = drop_na_and_duplciates(val_data)
test_data = drop_na_and_duplciates(test_data)

print('훈련용 샘플 개수 :',len(train_data))
print('검증용 샘플 개수 :',len(val_data))
print('테스트용 샘플 개수 :',len(test_data))

#훈련용 샘플 개수 : 941814
#검증용 샘플 개수 : 2490
#테스트용 샘플 개수 : 5010

 

#학습된 모델 불러오기
tokenizer = BertTokenizer.from_pretrained("klue/bert-base")

 

sent1 = train_data['sentence1'].iloc[0]
sent2 = train_data['sentence2'].iloc[0]
print(sent1)
print(sent2)

 

간판을 들고 있는 녹색 옷을 입은 남자가 금발 여자를 껴안는다.
남자는 빨간 옷을 입고 갈색 여자를 껴안는다.

 

#encode_plus함
encoding_result = tokenizer.encode_plus(sent1, sent2, max_length=max_seq_len, pad_to_max_length=True)
#2개의 문장으로 비교해야해서
#token_type_ids - 0나오고 두번째문장에 1이나오고 마지막 0은 패딩 문자인코딩이다.

 

encoding_result

 

def convert_examples_to_features(sent_list1, sent_list2, max_seq_len, tokenizer):#달라진 부분:examples ->
    input_ids, attention_masks, token_type_ids = [], [], []
    for sent1, sent2 in tqdm(zip(sent_list1, sent_list2), total=len(sent_list1)):
        encoding_result = tokenizer.encode_plus(sent1, sent2, max_length=max_seq_len, pad_to_max_length=True)#달라진 부분: 인코드와 관련된 3개가 다 들어가잇음.
        input_ids.append(encoding_result['input_ids'])
        attention_masks.append(encoding_result['attention_mask'])
        token_type_ids.append(encoding_result['token_type_ids'])
    input_ids = np.array(input_ids, dtype=int)
    attention_masks = np.array(attention_masks, dtype=int)
    token_type_ids = np.array(token_type_ids, dtype=int)
    return (input_ids, attention_masks, token_type_ids)

 

#X_train인코딩
X_train = convert_examples_to_features(train_data['sentence1'], train_data['sentence2'], max_seq_len=max_seq_len, tokenizer=tokenizer)

 

#저장된 것을 출력해보기
# 최대 길이: 128
input_id = X_train[0][0]
attention_mask = X_train[1][0]
token_type_id = X_train[2][0]

 

 

print('단어에 대한 정수 인코딩 :',input_id)
#한문장: 2  8366  2069   882  2088  1513  2259  6119  1451  2069  1511  2073 3997  2116 21459  3883  2138 15322  2259  2062    18
#두번째 문장: 3997  2259   8013  1451  2069  1511  2088 14008  3883  2138 15322  2259  2062    18
print('어텐션 마스크 :',attention_mask)
print('세그먼트 인코딩 :',token_type_id)
print('각 인코딩의 길이 :', len(input_id))
print('정수 인코딩 복원 :',tokenizer.decode(input_id))

 

#X_val인코딩
X_val = convert_examples_to_features(val_data['sentence1'], val_data['sentence2'], max_seq_len=max_seq_len, tokenizer=tokenizer)

 

# 최대 길이: 128
input_id = X_val[0][0]
attention_mask = X_val[1][0]
token_type_id = X_val[2][0]
print('단어에 대한 정수 인코딩 :',input_id)
print('어텐션 마스크 :',attention_mask)
print('세그먼트 인코딩 :',token_type_id)
print('각 인코딩의 길이 :', len(input_id))
print('정수 인코딩 복원 :',tokenizer.decode(input_id))

 

#X_test인코딩
X_test = convert_examples_to_features(test_data['sentence1'], test_data['sentence2'], max_seq_len=max_seq_len, tokenizer=tokenizer)

 

train_label = train_data['gold_label'].tolist()
val_label = val_data['gold_label'].tolist()
test_label = test_data['gold_label'].tolist()

 

#문자로 들어가 있는 label을 숫자로 변형해주기
#문자를 카테고리화하는 방법
#pd.get_dummies(), LabelEncoder()

idx_encode = preprocessing.LabelEncoder()
idx_encode.fit(train_label)
y_train = idx_encode.transform(train_label) # 주어진 고유한 정수로 변환
y_val = idx_encode.transform(val_label) # 고유한 정수로 변환
y_test = idx_encode.transform(test_label) # 고유한 정수로 변환

 

y_train #array([0, 0, 0, ..., 2, 1, 2])

y_val #array([2, 0, 1, ..., 2, 0, 1])

y_test #array([0, 1, 2, ..., 2, 0, 1])

 

label_idx = dict(zip(list(idx_encode.classes_), idx_encode.transform(list(idx_encode.classes_))))

idx_label = {value: key for key, value in label_idx.items()}

print(label_idx) #{'contradiction': 0, 'entailment': 1, 'neutral': 2}
print(idx_label) #{0: 'contradiction', 1: 'entailment', 2: 'neutral'}

 

#클래스 중요!!!!!!!!!!!!!!
#두문장을 입력해서 문장사이의 관계 3종류 중 출력
class TFBertForSequenceClassification(tf.keras.Model):
    def __init__(self, model_name, num_labels):
        super(TFBertForSequenceClassification, self).__init__()
        self.bert = TFBertModel.from_pretrained(model_name, from_pt=True)
        self.classifier = tf.keras.layers.Dense(num_labels, #여기가 다름!!!!!!!!!!!!!!!!, 분류가 3종류로 나와야해서 출력 3개
                                                kernel_initializer=tf.keras.initializers.TruncatedNormal(0.02),
                                                activation='softmax',
                                                name='classifier')
    def call(self, inputs):
        input_ids, attention_mask, token_type_ids = inputs
        outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
        cls_token = outputs[1]
        prediction = self.classifier(cls_token)
        return prediction

 

# TPU 작동을 위한 코드 TPU 작동을 위한 코드
resolver = tf.distribute.cluster_resolver.TPUClusterResolver(tpu='grpc://' + os.environ['COLAB_TPU_ADDR'])
tf.config.experimental_connect_to_cluster(resolver)
tf.tpu.experimental.initialize_tpu_system(resolver)

 

strategy = tf.distribute.experimental.TPUStrategy(resolver)

with strategy.scope():
  model = TFBertForSequenceClassification("klue/bert-base", num_labels=3)#여기 중요!!!!!!!!!!!!num_labels=3 - 출력 종류가 3개다.
  optimizer = tf.keras.optimizers.Adam(learning_rate=5e-5)
  loss = tf.keras.losses.SparseCategoricalCrossentropy()
  model.compile(optimizer=optimizer, loss=loss, metrics = ['accuracy'])

 

early_stopping = EarlyStopping(
    monitor="val_accuracy",
    min_delta=0.001,
    patience=2)#두번 돌려보고 모델이 좋아지지않으 멈춰

model.fit(
    X_train, y_train, epochs=5, batch_size=32, validation_data = (X_val, y_val),
    callbacks = [early_stopping]
)

 

print("\n 테스트 정확도: %.4f" % (model.evaluate(X_test, y_test, batch_size=1024)[1]))

 

'자연어처리(NLP) & CHAT GPT > NLP' 카테고리의 다른 글

[NLP] GPT, KoGPT - 실습  (0) 2023.08.22
[NLP] Transformer, BERT - 실습  (0) 2023.08.10
[NLP] BERT  (0) 2023.08.09
[NLP] Seq2Seq - 실습  (0) 2023.08.08
[NLP] Seq2eq에서 BERT까지  (0) 2023.08.07