kakao buffarを用いた推奨システムの実装


1.水牛の紹介

buffaloは、Kako Techが開示したオープンソース推薦システムライブラリである.
  • 水牛公式文書(リンク)
  • buffalo github( リンク )
  • 水牛庫内では4種類の推奨アルゴリズムを実現した.
    1. ALS(Alternating Least Squares)
    2. Bayesian Personalized Ranking Matrix Factorization
    3. Word2Vec
    4. CoFactors

    2. library & data install


    buffalo library install


    ライブラリをインストールしようとすると、多くのエラーが発生しました.まず、Windowsにインストールされていないため、linuxを使用してブファロが要求したn 2ライブラリをインストールすることをお勧めします.
  • 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++
    運転後、水牛を取り付け直せばいいです.
    **Compute 30に関連するエラーが発生した場合、水牛の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に分け、推奨リストを実際のmovie点数と比較し、異なるアルゴリズムの性能を比較することができます.