kakao buffalo로 추천시스템 구현하기

정예슬·2022년 1월 26일
0

recommender system

목록 보기
1/1

1. buffalo 소개


buffalo는 kakao Tech에서 공개한 오픈 소스 추천 시스템 라이브러리이다.

buffalo 라이브러리 내에는 4가지 추천 알고리즘이 구현되어 있다.

1. ALS(Alternating Least Squares)
2. Bayesian Personalized Ranking Matrix Factorization
3. Word2Vec
4. CoFactors

2. library & data install


buffalo library install


라이브러리를 설치하려고 할 때 많은 시행착오가 있었는데, 먼저 buffalo requirements의 n2 라이브러리가 windows에서는 설치가 안 돼서 linux로 설치하는 것을 권장한다.

  • n2 library install
$ git clone https://github.com/kakao/n2.git
$ cd n2
$ git submodule update --init
$ python setup.py install
  • buffalo library install
$ git clone -b master https://github.com/kakao/buffalo
$ cd buffalo
$ git submodule update --init
$ pip install -r requirements.txt
$ python setup.py install

서버에서 conda 가상환경을 여러 개 사용하고 있고, gcc 버전이 사용하는 cuda, cudnn 등의 버전과 맞지 않는다면, gcc 관련 에러가 발생한다.

해당 에러 발생 시에는 conda 가상환경에서 gcc version을 따로 설치해서 사용하면 된다.
나는 gcc 6.4.0을 설치했다. 다른 버전 설치방법은 검색해보면 나올 것이다.

$ conda install -c rgrout gcc_linux-64
$ conda install -c rgrout gxx_linux-64

설치를 한 후에는 해당 가상환경에서 conda gcc를 사용하도록 경로를 잡아줘야 하는데, 심볼릭 링크를 생성하여 가상환경 gcc 경로를 잡도록 만들면 된다.

$ cd /home/root/anaconda3/envs/ENV_NAME/bin	# 가상환경 bin 폴더로 이동
$ ln -s x86_64-conda-cos6-linux-gnu-gcc cc	# 심볼릭 링크 생성(cc,gcc,g++,c++) 
$ ln -s x86_64-conda-cos6-linux-gnu-gcc gcc
$ ln -s x86_64-conda-cos6-linux-gnu-g++ g++
$ ln -s x86_64-conda-cos6-linux-gnu-g++ c++

실행 후 buffalo를 재설치 하면 된다.

** 추가로 compute 30 관련 에러가 뜬다면 buffalo의 cuda_setup.py 파일에서,

post_args = ['-gencode=arch=compute_30,code=sm_30',
                 '-gencode=arch=compute_50,code=sm_50',
                 '-gencode=arch=compute_60,code=sm_60',
                 '-gencode=arch=compute_60,code=compute_60',
                 '--ptxas-options=-v', '-O2']

'-gencode=arch=compute_30,code=sm_30' 부분을 지운 후 설치를 다시 해보자.

data install


추천시스템 구현에 사용할 데이터는, 추천 시스템 성능 테스트로 많이 사용되는 movielens이다.
다음 다운로드 링크에서 ml-25.zip을 다운로드 받으면 된다. [링크]

해당 데이터의 압축을 해제하고, ratings.csv를 data directory에 넣는다.

3. ALS Sample Code


쥬피터 노트북에 소스코드를 차례로 입력하면서 실행해 보면 된다.

import pandas as pd
data = pd.read_csv('./data/ratings.csv')
data.head()

------------------------------------------------------

# dtype transform
data = data[['userId', 'movieId', 'rating']].astype(str)

------------------------------------------------------

# buffalo library import
from buffalo.algo.als import ALS, inited_CUALS
from buffalo.algo.options import ALSOption
import buffalo.data
from buffalo.misc import aux
from buffalo.data.mm import MatrixMarketOptions
import numpy as np
from scipy.io import mmwrite
from scipy.io import mmread
from scipy.sparse import csr_matrix
import scipy.sparse as sp

------------------------------------------------------

print(inited_CUALS) # True이면 gpu 학습 가능

------------------------------------------------------

# 유저 * 아이템 매트릭스 생성
def get_df_matrix_mappings(df, row_name, col_name):
    
    rid_to_idx = {}
    idx_to_rid = {}
    
    for (idx, rid) in enumerate(df[row_name].unique().tolist()):
        rid_to_idx[rid] = idx
        idx_to_rid[idx] = rid

    cid_to_idx = {}
    idx_to_cid = {}
    
    for (idx, cid) in enumerate(df[col_name].unique().tolist()):
        cid_to_idx[cid] = idx
        idx_to_cid[idx] = cid

    return rid_to_idx, idx_to_rid, cid_to_idx, idx_to_cid

def df_to_matrix(df, row_name, col_name):
    
    rid_to_idx, idx_to_rid, cid_to_idx, idx_to_cid = get_df_matrix_mappings(df, row_name, col_name)

    def map_ids(row, mapper):
        return mapper[row]

    I = df[row_name].apply(map_ids, args=[rid_to_idx]).to_numpy()
    J = df[col_name].apply(map_ids, args=[cid_to_idx]).to_numpy()
    V = np.ones(I.shape[0])
    
    interactions = sp.coo_matrix((V, (I, J)), dtype=np.float64)
    interactions = interactions.tocsr()
    
    return interactions, rid_to_idx, idx_to_rid, cid_to_idx, idx_to_cid
 
------------------------------------------------------

# 행렬 매트릭스를 생성하여 파일로 저장
user_items, uid_to_idx, idx_to_uid, mid_to_idx, idx_to_mid = df_to_matrix(data, 'userId', 'movieId')
mmwrite(f'./train/main.mtx', user_items)  

------------------------------------------------------

# uid = user ID, iid = item ID
uid = list(idx_to_uid.values())
iid = list(idx_to_mid.values())

------------------------------------------------------

# uid, iid 값을 파일로 저장
with open(f"./train/uid", "w") as f:
    for val in uid:
        print(val, file=f)
f.close()

with open(f"./train/iid", "w") as f:
    for val in iid:
        print(val, file=f)
f.close()

------------------------------------------------------

# parameter Optimizer
# -- hyperopt 사용하여 최적 파라미터 서치
opt = ALSOption().get_default_option()
opt.num_workers = 6 # worker 수 조정
opt.num_iters = 20
opt.evaluation_period = 20
opt.evaluation_on_learning = True
opt.save_best = True
opt.accelerator = True # GPU option

# optimizer에 사용할 데이터 옵션(경로) 설정
data_opt = MatrixMarketOptions().get_default_option()
data_opt.input.main = './train/main.mtx'
data_opt.input.iid = './train/iid'
data_opt.input.uid = './train/uid'
data_opt.data.ath = './train/mm.h5py'
data_opt.data.validation.p = 0.1
data_opt.data.validation.max_samples = 5000

# optimizer search 범위 설정
opt.validation = aux.Option({'topk' : 10 })
opt.tensorboard = aux.Option({'root' : './train/als-validation', 'name' : 'als-new'})
opt.optimize = aux.Option({
   'loss': 'val_ndcg',
        'max_trials':100,
        'deployment': True,
        'start_with_default_parameters': False,
        'space': {
            'd': ['randint', ['d', 10, 128]],
            'reg_u': ['uniform', ['reg_u', 0.1, 1.0]],
            'reg_i': ['uniform', ['reg_i', 0.1, 1.0]],
            'alpha': ['randint', ['alpha', 1, 10]]
        } 
})

------------------------------------------------------

# 설정 옵션을 ALS 모델에 넣고 생성
als = ALS(opt, data_opt = data_opt)
als.initialize()

als.opt.model_path = './train/als-best-model.bin'
als.optimize() # parameter optimizing
als.get_optimization_data()

------------------------------------------------------

# 학습시킬 데이터 설정
data_opt = MatrixMarketOptions().get_default_option()
data_opt.input.main = f'./train/main.mtx'
data_opt.input.iid = f'./train/iid'
data_opt.input.uid = f'./train/uid'
data_opt.data.validation.p = 0.1
data_opt.data.validation.max_samples = 10000
data_opt.data.path = f'./train/mm.h5py'

data = buffalo.data.load(data_opt)
data.create()

------------------------------------------------------

del als
als_opt = ALS()
als_opt.load('./train/als-best-model.bin') # 최적화 opt 불러오기
als_opt.opt

------------------------------------------------------

# model train
model = ALS(als_opt.opt, data= data)
model.initialize()
model.train()

------------------------------------------------------

# Top 5 movie list for 'userId 1'
model.topk_recommendation('1',topk=5)

# Simmilar movie with 'movieId 4973'
model.most_similar('4973',topk=5)

------------------------------------------------------

마무리


샘플 실행 코드는 ALS만 있지만, 진행 방식은 유사하기 때문에 라이브러리만 다르게 임포트 해서 다른 알고리즘도 적용해 볼 수 있을 것이다.

날짜로 데이터를 스플릿해서 train set, test set으로 나눈 후 recommendation list를 실제 movie 점수와 비교해보면, 알고리즘 별 성능을 비교해 볼 수 있다.

profile
춘식이랑 함께하는 개발일지

0개의 댓글