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
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)라고 합니다.
'주홍의 프로젝트 > 연습 프로젝트' 카테고리의 다른 글
surprise 라이브러리 알고리즘 정리 (0) | 2022.07.04 |
---|---|
surprise 라이브러리 algorithm 정리 (0) | 2022.06.29 |
추천 시스템 정리 (0) | 2022.06.29 |
사용자기반 협업 필터링 추천시스템 - 애니메이션 추천시스템 (1) | 2022.06.22 |
netflix recommendation system - user collaborative filtering (1) | 2022.06.21 |
댓글