BertでECサイトの商品類似度を計算する


概要

商品の説明文とタイトルをBertを使ってベクトル化して、商品間の類似性を表現できるかテストする。

準備

以下colab環境で実装します。

アカウント認証

from google.colab import auth
auth.authenticate_user()

tensorflowのバージョンの変更

今回使用するソースコードに合わせてcolabにインストールされているtensorflowのバージョンを変更します。

#tensorflowを1x系に戻します
!pip uninstall -y tensorflow
!pip install tensorflow==1.15.0

入力データとBertのソースコードを用意

#必要なファイルを用意する
#こちらの記事を元にjumanppを使用できるようにコードを修正 https://dev.classmethod.jp/articles/bert-text-embedding/
!gsutil cp -r gs://${your_gcs_path}/bert ./
#日本語wikiで学習したモデルを取得 http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT%E6%97%A5%E6%9C%AC%E8%AA%9EPretrained%E3%83%A2%E3%83%87%E3%83%AB#k1aa6ee3
!gsutil cp -r gs://${your_gcs_path}/Japanese_L-12_H-768_A-12_E-30_BPE ./
#入力データを用意 (今回はamazonの電子書籍のタイトル+商品説明文)
!gsutil cp -r gs://${your_gcs_path}/inputdata ./

JUMAN++をインストール


# 以下を参照してjumanppをインストールする
#https://github.com/ku-nlp/jumanpp
!wget https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz
!sudo apt install cmake
!tar xJvf jumanpp-2.0.0-rc3.tar.xz
%cd jumanpp-2.0.0-rc3/
!mkdir bld
%cd bld
!cmake ..
!sudo make install

環境変数を設定

%env MODEL=Japanese_L-12_H-768_A-12_E-30_BPE
%env OUTPUT=output
%env INPUT=inputdata

出力ディレクトリを作成

%cd ../
!mkdir output

Bertで商品をベクトル化

# item.txt : 商品タイトル + 商品説明
!python ./bert/extract_features.py  --input_file=${INPUT}/item.txt  --output_file=${OUTPUT}/output.jsonl  --vocab_file=${MODEL}/vocab.txt  --bert_config_file=${MODEL}/bert_config.json  --init_checkpoint=${MODEL}/bert_model.ckpt  --do_lower_case False  --layers -2

商品間の距離行列を作成

Bertの出力結果からベクトル情報を取得

import json
import numpy as np
import pandas as pd

# 参照するレイヤーを指定する
TARGET_LAYER = -2

# 参照するトークンを指定する
SENTENCE_EMBEDDING_TOKEN = '[CLS]'

file ="./output/output.jsonl"

with open(file, 'r') as f:
    output_jsons = f.readlines()

embedding_list = []
for output_json in output_jsons:
    output = json.loads(output_json)
    for feature in output['features']:
        if feature['token'] != SENTENCE_EMBEDDING_TOKEN: continue
        for layer in feature['layers']:
            if layer['index'] != TARGET_LAYER: continue
            embedding_list.append(layer['values'])

np.savetxt('output.tsv', embedding_list, delimiter='\t')

商品タイトル + 商品ベクトルの行列を作成

#商品のベクトル
output = pd.read_csv("output.tsv", sep='\t',header=None)
#商品のタイトル
title = pd.read_csv("inputdata/title.txt", sep='\t',header=None, names=["title"])
#商品タイトルとベクトルを結合
res = pd.concat([title, output], axis=1)
# データを確認
res.head(3)

商品間の距離を計算

from scipy.spatial import distance
# ベクトルの作成
M = [a for a in res.iloc[:,2:769].values] 
# 総当たりに類似度を計算(こちらを参照https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html#scipy.spatial.distance.cdist)
dist_M = distance.cdist(M, M, metric='cosine')

商品間の距離行列を作成

dist_matrix = pd.DataFrame(dist_M,columns=res['title'],index=res['title'])

ヒートマップで可視化

pythonで日本語の描画が難しそうだったのでスプレッドシートで作成しました。
専門書か漫画かなど大まかなジャンルには別れているようです。
日本語wikiで学習されたモデルを使っていて、商品データでモデルの学習をしていないため、十分にデータを集めて学習を行うことでより精度は上がりそうです。