본문 바로가기
주홍의 프로젝트/연습 프로젝트

Neural Network Embedding Recommendation System (kaggle) review

by orangecode 2022. 6. 23.
728x90
Neural Network Embedding Recommendation System

Neural Network Embedding Recommendation System

wikipedia에 있는 책의 정보와 위키피디아 내용의 다른 책들의 링크를 Embedding하여 Cosine Similarity로 유사한 책을 추천하는 추천시스템입니다.

 

Neural Network Embedding Recommendation System

Neural Network Embedding을 사용하여 책에 관한 모든 wikipedia article을 사용하는 책 추천 시스템을 만드는 것입니다.

추천 시스템은 유사한 wikipedia page로 연결되는 책들이 비슷하다는 생각을 바탕으로 만들어집니다.

 

신경망을 이용해 book, wikpedia links를 embedding하는 것을 학습하고, 추천시스템을 만들 수 있습니다.

 

 

Neural Network Embeddings

embedding = 이산형변수를 연속벡터로 나타내는 방법입니다.

 이산 변수(discrete variable) : 이산할 수 있는 변수(하나하나 셀 수 있는 변수)  ex) 아파트 층 수, 한 회사의 직원 수 등

   ↕

 연속 변수(continuous variable) : 변수의 각 값사이에 무수히 많은 다른 값이 존재하는 경우 ex) 사람의 키, 몸무게, 나이 등

 

 

 

Neural Network에서의 Embedding 의미

고차원의 벡터공간 저차원의 벡터로 만드는 것을 의미합니다.

원래 차원은 매우많은 범주형 변수들로 구성되어있는데, 학습방식을 통해 저차원으로 대응되게 됩니다.

임베딩 공간에서 서로 유사한 실체를 서로 가깝게 배치한다는 의미입니다.

 

Neural Network Embedding 목적

 1) Embedding 공간에서 nearest neighbor 찾기

 2) 저차원 시각화하기 

 3) ML의 지도학습(Supervised Learning)의 입력값으로 임베딩을 사용할 수 있습니다

 

 

Neural Network Embedding Recommendation System의 Embedding

해당 Neural Network는 책과 위키링크를 각각 50차원의 벡터에 매핑한 임베딩 두개의 병렬 임베딩을 사용합니다.

나머지 레이어는 두개의 임베딩을 내적곱(dot product)해서 최종적인 하나의 숫자로 만들어내는 레이어를 두었습니다.

그 임베딩들은 뉴럴네트워크의 가중치라고 불리는 것으로, 지도식 학습의 손실을 줄이는 방향으로 학습됩니다.

 

 

1. Data : All Book on Wikipedia

Data : 

 1) wikipedia book data : 30720,

 2) wikilinks : 42720

 

Data category 
Book title, information from 'infobos book' template, wikipedia links, externel links, the date of last edit, the number of characters in article

 

use data : Book title, Wikipadia

 

books = 37020개

Wikipedia = 311276개 -> 전처리 후 41758개

 

2. Data Cleadning

wiki links에 가장 많이 사용되는 links 10개 뽑아내기

 

책과 관련없는 wikilinks 제거하기

1) paperback(문고판), hardcover(양장본), hardback(=hardcover), e-book

2) wikiproject books, wikiproject novel wikiproject : 단순 책에대한 정보정리 글, article X

to_remove = ['hardcover', 'paperback', 'hardback', 'e-book', 'wikipedia:wikiproject books', 'wikipedia:wikiproject novels'] 

for t in to_remove:
    wikilinks.remove(t)
    _ = wikilink_counts.pop(t) # ????? #pop(t) t가 들어간 to_move의 카테고리들을 제거해라

 

5번 이상 사용된 wikilinks를 사용한다.

고유한 wikilinks 값이 너무 많아, 5번 이상 사용된 wikilinks로 제한합니다.

여러번 사용된 wikilink가 유사도 측정에 영향을 미치지 않을까 생각합니다.

 

1번(모든 고유 wikilinks 사용) = 297624개

2번 = 102,921개

3번 = 59,890개

4번 = 41764개

5번 = 31,907개

 

 

wikilinks to_index

# Wikilinks to Index
# book 데이터를 정수로 바꾸어주었듯이, Wikilinks도 정수로 바꿔준다
link_index = {link: idx for idx, link in enumerate(links)}
index_link = {idx: link for link, idx in link_index.items()}

link_index['ernest hemingway']
index_link[725]
link_index['renewable energy']
index_link[5100]
link_index['ismail merchant']
index_link[30100]
print(f'There are {len(link_index)} wikilinks that will be used.')

데이터가 깨끗하다고 확신이 들고 (title, wikilinks) paris가 주어지면, 위키링크(wikilink)가 책의 기사에 존재하는지 확인합니다.

3. Build a Training Set
의미있는 임베딩 학습을 위해, 신경망이 목표에 달성하도록 훈련해야합니다. 
 
Neural Network에 (title, wikilink)로 구성된 예제를 제공합니다.
 
 
책 페이지에 특정 위키링크가 있는지 알아보기 위한 학습을 통해,
네트워크는 콘텐츠 측면에서 유사한 책을 서로 가까이 두는 것을 학습하기를 원합니다
 
pairs = [] # pairs 빈 list 생성

# 각 책에대한 반복 수행
for book in books:
    # 각 책에대한 링크를 반복 수행
    # 720,000개의 예시 추가
    # 예시 각 title마다 link가 들어간 pairs만들기 (2, 616), (2, 2914) -> 77만개
    pairs.extend((book_index[book[0]], link_index[link.lower()]) for link in book[2] if link.lower() in links)

# 모델을 훈련시키기 위한 720,000개의 예시를 보여준다.
len(pairs), len(links), len(books)
pairs[5000]

# pairs 중복제거 
pairs_set = set(pairs)

pairs = (title, links)가 담긴 훈련용 720,000개의 예시를 추가해줍니다.

set()함수를 활용하여 pairs의 중복을 제거해줍니다.

 

 

4. 학습 sample 만들기

모델  훈련을 위해 추출할 수 있는 표본 720,000개(=True 값(title, wikilinks)가 일치하는 pairs와

(title, wikilinks)의 index들을 무작위로 선택해 True가 아닌지 확인한 뒤 False를 만들어 채웁니다.

 

batch_size는 n_positive, nagative_ratio를 이용해서 결정하고, n_positive에는 1을 부여하고, negative_ratio에 0 or 1을 부여한다. generator는 호출할 때마다 긍정 샘플과 부정 샘플의 새 배치를 생성합니다

 

 

# 데이터셋 positive, negative 생성기 만들기
# batch_size 정하기

import numpy as np
import random
random.seed(100)

def generate_batch(pairs, n_positive = 50, negative_ratio = 1.0, classification = False):
  # batch를 저장할 numpy 배열 준비하기
  batch_size = n_positive * (1 + negative_ratio) # 1 : positive가 할당받는 1 # + n_positive * (1 + negative_ratio) = n_positive + negative_ratio 
  batch = np.zeros((batch_size, 3)) # shape = batch_size * 3 -> next batch (book, link, batch)

  # 라벨 조정하기
  if classification:
    neg_label = 0
  else:
    neg_label = -1

  # 생성기 만들기
  while True:
    # 랜덤 positive 예시 선택
    for idx, (book_id, link_id) in enumerate(random.sample(pairs, n_positive)):
      batch[idx, :] = (book_id, link_id, 1)

    # idx = 1씩 증가
    idx += 1

    # batchsize가 찰때까지, negative examples 추가
    while idx < batch_size:

      # 랜덤선택
      random_book = random.randrange(len(books))
      random_link = random.randrange(len(links))

      # positive sample이 아니라는 걸 체크
      if (random_book, random_link) not in pairs_set:

        # 배치에 negative_index  추가하기 
        batch[idx, :] = (random_book, random_link, neg_label)
        idx += 1

      
    # Make sure to shuffle order
        np.random.shuffle(batch)
        yield {'book': batch[:, 0], 'link': batch[:, 1]}, batch[:, 2]

 

5. Embedding model

Embedding model 5 layers 
 1) input layer : book, link에 대한 병렬 입력 
 2) Embedding : book, link 병렬 50개 Embedding (None, 1, 50)
 3) Dot : 내적(Dot product)를 계산해 Embedding 합치기 (None, 1, 1)
 4) Reshape : Embedding shape를 단일 숫자로 형성 (None, 1)
 5) Dense : sigmoid activation을 이용한 출력

def book_embedding_model(embedding_size=50, classification = False):

  # """Model to embed books and wikilinks using the functional API.
  #    \Trained to discern if a link is present in a article"""

    # 1차원 입력
    book = Input(name='book', shape=[1])
    link = Input(name='link', shape=[1])

    # 책 Embedding(None, 1, 50)
    # book Embeding (None, input, output)(book)
    # 30720 x 50 = 2,087,900 param(노드에 연결된 간선 수)
    book_embedding = Embedding(name = 'book_embedding',
                               input_dim = len(book_index), #book_index = 1
                               output_dim = embedding_size)(book)

    # link Embedding(None, 1, 50)
    # link Embeding (None, input, output)(link)
    # 41758 x 50 = 2,087,900 param(노드에 연결된 간선 수)
    link_embedding = Embedding(name = 'link_embedding',
                               input_dim = len(link_index),
                               output_dim = embedding_size)(link)

    

    # 내적으로 book&link embedding 1개의 Embedding으로 변형
    # merged = shape(None, 1, 1)
    # Dot(name, normalize(정규화), axes(샘플 간 내적계산))
    # Dot(normalize = True -> L2 Norm -> 내적 출력은 샘플간의 cosine 근접도 )
    merged = Dot(name = 'dot_product', normalize = True, axes=2)([book_embedding, link_embedding])

    # Reshape to be single Number(shape will be(None, 1))
    # Reshape_shape = 정수튜플/샘플/배치크기 포함하지 않음
    merged = Reshape(target_shape = [1])(merged)

    # if classifcation, add extra layers and loss function is binary crossentroy
    if classification:
        merged = Dense(1, activation = 'sigmoid')(merged)
        model = Model(inputs = [book, link], outputs = merged)
        model.compile(optimizer = 'Adam', loss = 'binary_crossentrypy', metrics = ['acccuracy'])

      # Otherwise loss function is mean squared error
    else:
      # model = tf.keras.Model(inputs=inputs, outputs=outputs)
        model = Model(inputs = [book, link], outputs = merged)
        model.compile(optimizer='adam', loss='mse')

    return model

# Instantitate model and show parameters
model = book_embedding_model()
model.summary()

 

test/validation set을 사용하지않는 이유

정확도 측정이 목표가 아닌 embedding model build가 목표이기에, 예측 작업은 임베딩을 위해 네트워크를 학습하는 수단일 뿐입니다.

학습이 끝나면 새로운 데이터에 대한 모델 테스트가 없으므로, validation set을 이용한 과적합을 방지할 필요가 없습니다. 최상의 임베딩 값을 확보하기 위해 모든 데이터를 학습에 사용합니다.

 

train model

n_positive = 1024

# negative_ratio = 2 인 이유는 2가 가장 잘 됨 = 제작자
gen = generate_batch(pairs, n_positive, negative_ratio=2)

# Train
# steps_per_epoch = 1epoch마다 사용할 batch_size를 정의함
# steps_per_epoch : 각 epoch에서 동일한 수의 pairs를 볼 수 있게 한다.
# verbose(상세정보) 보통 0, 자세히 1, 함축정보 2
model.fit_generator(gen, epochs = 15, steps_per_epoch = len(pairs) // n_positive, verbose=2)

# model 저장하기
model.save('first_attempt.h5')

 

 

 

시각화(visualizations)

사용 모델 : TSNE & UMAP

 

TSME(t-Stochastic Distributed Neighbors Embedding)

 

UMAP(Uniform Manifold Approximation and Projection)

 

차원축소

book = 37,020차원 -> 50개의 차원으로 embedding -> 2개 차원으로 embedding 

 

manifold

이미지를 구성하는 픽셀, 화소를 하나의 차원으로 간주하여, 고차원 공간에 한 점으로 이미지를 매핑시킬 수 있습니다. 맵핑시킨 그 점들의 집합을 잘 아우르는 전체 공간의 부분집합(subspace)이 존재할 수 있는데, 그것을 매니폴드(manifold)라고 합니다.

반응형

댓글