최근에 진행했던 미니프로젝트에서 맡았던 task입니다. 요약된 리뷰 데이터를 임베딩한 뒤, 사용자별 feature로 사용할 수 있도록 만드는 task입니다.
Embedding
vectorizer를 적용하여 자연어를 수학적으로 바꾸는 것입니다. 저희 프로젝트의 목표는 리뷰 데이터의 요약 및 임베딩을 통해 추천시스템의 성능을 개선하는 것이었습니다. TFIDF를 사용하는 경우 별도의 처리없이 사용자별 feature로 사용할 수 있습니다. 다만 TF-IDF는 sparse한 데이터를 만들기 때문에 추천시스템 성능을 개선하는 데에는 충분하지 않다고 생각했습니다. 저희가 추가로 진행한 것과 같이, word2vec이나 다른 LM 모델의 last hidden state로 임베딩을 하는 경우 사용자의 feature로 사용하기 위해 별도의 처리 과정이 필요합니다.
오늘 포스팅에서는 word2vec과 kobart의 임베딩 차원을 변경하는 방법에 대해 작성해보겠습니다.
Word2Vec
sentences 파라미터에 토큰화된 값을 input으로 넣어줍니다. 이때, input은 데이터프레임이 아니라 2차원 리스트 형태로 되어 있어야 합니다.
model1 = Word2Vec(sentences=text, vector_size = 100, window = 5, workers = 6, sg = 0, seed = 42)
model1.wv.vectors
model.wv.vectors 는 word2vec을 이용해 얻은 임베딩값을 확인하기 위한 코드입니다.
def get_features(words, model, num_features):
# 출력 벡터 초기화
feature_vector = np.zeros((num_features), dtype=np.float32)
num_words = 0
# 어휘사전 준비
index2word_set = set(model.wv.index_to_key)
for w in words:
if w in index2word_set:
num_words +=1
# 사전에 해당하는 단어에 대해 단어 벡터를 더함
feature_vector = np.add(feature_vector, model.wv[w])
# 문장의 단어 수만큼 나누어 단어 벡터의 평균값을 문장 벡터로 함
feature_vector = np.divide(feature_vector, num_words)
return feature_vector
def get_dataset(reviews, model, num_features):
dataset = list()
for s in reviews:
dataset.append(get_features(s, model, num_features))
reviewFeatureVecs = np.stack(dataset)
return reviewFeatureVecs
문장 벡터를 구하기 위해 단어 벡터의 평균값을 사용했습니다. 사용자 정의 함수를 적용하기 위해서는 아래와 같이 코드를 실행하면 됩니다. 리뷰가 없는 사용자의 경우, 벡터값을 0으로 채우기 위해 fillna 코드를 추가했습니다.
lexrank_word2vec = pd.DataFrame(get_dataset(lexrank_list, model1, 100)).fillna(0)
lexrank_word2vec.index = lexrank['리뷰자']
매핑 시 꼬이는 일이 없도록 리뷰자 key를 index로 설정했습니다.
KoBART : torch 환경
from kobart_transformers import get_kobart_model, get_kobart_tokenizer
kobart_tokenizer = get_kobart_tokenizer()
model = get_kobart_model()
kobart의 last hidden state를 embedding으로 사용하기 위해 토크나이저와 모델을 불러왔습니다.
def get_embedding(txt, num = 768):
embeddings = []
tokens = kobart_tokenizer.tokenize(txt)
input_ids = kobart_tokenizer.convert_tokens_to_ids(tokens)
input_ids = torch.tensor([input_ids])
try:
with torch.no_grad():
lhs = model(input_ids)[0].mean(dim=1) #평균 이용
except IndexError: #리뷰가 없는 경우 0으로 채워진 array 생성
lhs = np.zeros(num)
embeddings.append(lhs.tolist())
return embeddings[0]
토크나이징부터 임베딩, 단어 벡터 평균을 이용하는 코드를 전부 하나의 사용자 정의 함수로 구현합니다. 사용자 정의 함수를 구현하기 위해서는 아래 코드를 실행하면 됩니다.
columns = [f"embedding_{i}" for i in range(768)]
df = pd.DataFrame(columns=columns)
for i,j in enumerate(lexrank['lexrank']):
df.loc[i] = get_embedding(j)[0]
if i % 100 == True:
print(i, "완료")
df.index = lexrank['리뷰자']
word2vec과 달리 2차원 리스트를 준비할 필요가 없습니다. lexrank 컬럼에는 요약문이 그대로 담겨 있습니다. word2vec과 마찬가지로 매핑 시 꼬이는 일이 없도록 리뷰자 key를 index로 설정했습니다.
결과
저희가 사용한 모델은 GNN으로, link prediction과 link regression을 진행하여 성능을 비교했습니다. link prediction에서는 리뷰 데이터를 추가 시 성능이 개선되지 않았고, link regression에서는 리뷰 데이터 추가 시 성능이 개선되었습니다. 추가적으로 link prediction에서는 리뷰 데이터의 임베딩 차원이 클수록 성능이 저하되는 현상이 나타났습니다.
임베딩 방식 중에서 word2vec, kobart, tf-idf 순으로 성능이 좋았습니다. word2vec이 dense한 데이터를 생성할 수 있기 때문에 임베딩 방식 중 가장 성능이 좋았던 게 아닐까 싶습니다.
Github에서 보기
GitHub - Sennysideup/Project
Contribute to Sennysideup/Project development by creating an account on GitHub.
github.com
reference
- ChatGPT
- https://yseon99.tistory.com/96
'Data > ML & DL' 카테고리의 다른 글
[Colab] 추천시스템 recommenders 라이브러리 성능 평가 (1) | 2024.01.28 |
---|---|
[Colab] recommenders 라이브러리 BPR 추천시스템 구현 (0) | 2024.01.25 |
[Colab] recommenders 라이브러리 ALS 추천시스템 구현 (1) | 2024.01.22 |
[Colab] 추천시스템 implicit 라이브러리 성능 평가 (0) | 2024.01.19 |
[Pytorch] 토크나이저에 vocab 추가하기 (0) | 2023.06.18 |