機械学習にアノテーションを活用して、商品検索の関連キーワード機能を作る

DataStrategyの齋藤(@pigooosuke)です。

ネットショップ作成サービス「BASE」は60万店舗のショップが利用しており、ショッピングアプリ「BASE」のユーザーは、新着商品、キーワード検索、関連商品、商品特集などを介して気になる商品を見つけることができます。今回、新機能として、検索ワードに関連するキーワードを表示することで、ユーザーの興味のありそうな商品にたどり着ける動線を機械学習を活用して実装しました。

DataStrategyチームは発足して間もなく、サービスドメインに適応した単語辞書がなかったので、新規で作成するところから始まりました。機械学習におけるデータセットのアノテーションについての知見が共有される機会が少ない印象もあり、折角なので今回私達が行ったデータ作りから実装までの流れをご紹介します。

概要

f:id:HifiroleLorum:20181016175341p:plain

今回、どんなキーワードも意味的に近ければ、サジェストしても良いとはせず、ホワイトリストに登録されたキーワードのみをサジェストし、サービス品質を保てることを最低条件としています。また、関連キーワードにはいくつか定義が存在しますが、今回は類義語をサジェストする関連キーワードの開発を行いました。

大まかな手順は以下となります。

  1. 「BASE」で過去検索されたキーワードのデータからキーワードのリストを取得
  2. 前処理として、不適切な検索キーワード、優先度が低いキーワードを一定のルールで削除
  3. 有用なキーワードに対して、アプリに表示可能な単語かをアノテーション
  4. チェックがOKだったキーワードを登録したMeCab辞書を活用し、商品のタイトル・紹介文を分かち書きに分解
  5. 商品情報(タイトル+説明文)に対してWord2vecを通し、類似度の高い単語を調査し、関連キーワードとして表示

f:id:HifiroleLorum:20181016175427p:plain

Word2vecについて

文字の通り、word(文字)をvector(ベクトル:n次元)で表現するために深層学習を行うモデルです。それぞれの単語はその周辺に出現する単語によって決められているという仮説に基づいて学習を行います。今回の記事のテーマではないので詳細は割愛します。

# 学習語彙での類似度の高い単語を出力
model.wv.most_similar(positive='ワンピース', topn=6)
> [('フレアワンピース', 0.8115994334220886),
>  ('ロングワンピース', 0.7681916952133179),
>  ('ミニワンピース', 0.7396647930145264),
>  ('aラインワンピース', 0.7346851825714111),
>  ('vネックワンピース', 0.7129236459732056),
>  ('レースワンピース',0.7060198783874512)]

アノテーション

実際にアノテーションを進めていく前に、きちんとルールを決めておくことがかなり重要です。 いくらルールを厳格に決めておいても、「このケースはOKで通してみたけれど、アノテーションを進めて全体感がつかめてくると、あれはNGのケースだった。」という手戻りは少なからず発生してしまいます。 ましてや、集団でアノテーションを実施する時の難易度はかなり高くなると感じています。 今回は、(幸いなことに?)アノテーション作業を一人で行ったので、可能な限りルールの統一が出来たと思います。

参考までに、今回設定したルールとしては下記の通りになります。 今回は、各キーワードについて3つのラベルをつけていきます。

NG単語ラベル

アプリで表示するに耐えうる表現・ユーザーのUXを損なうことのない表現かをチェックしていきます。 OKとなった(ホワイトリストに登録された)キーワードのみアプリ上で表示されます。

  1. 基本的に最小商品単位になりうるものはOK
  2. 修飾語が3語以上つながっているものはNG(バックロゴ付き薄手コート:バック,ロゴ付き,薄手
  3. ブランド名が含まれているものは、社内ルール的にNG(ルイヴィトン,ディズニー
  4. 年号・数字・期間限定のキーワードが含まれているものはNG(例外で、季節感のあるものはOKとしているサマーサンダル,スプリングコート
  5. 色を表すものはNG(全色対応など、候補のノイズになる可能性が高いため)
  6. 口語表現がついているものはNG(ゆったり,もこもこ
  7. 単語単体で何を検索しているのか不明瞭なものはNG( ,クーポン,名刺

ゆらぎ表現ラベル

単語表現のゆらぎは検索エンジンにはつきものです。類似表現が出てきた時、両単語を表示することはせず、どちらかの単語のみを表示します。これをゆらぎ表現として別途登録して入出力制御に活用します。 例:Pコート,ピーコート,キャミソール,キャミなど。

  1. ゆらぎ表現は検索件数が多いものを正解とする
  2. 鞄でいう、〇〇バッグ,XXバックのように語尾が統一されないジャンルが存在するが、検索実績が多いキーワードを正解とする

カテゴリーラベル

これは個人の主観が大きく入るのと、全体のバランスを見つつゼロからラベルをつけていくので、大きく手戻りが発生する作業なかなか難しい作業です。こちらのラベルも出力制御に活用します。BASEで設定しているカテゴリーを参考にしつつ作業を進めました。

  1. 各単語について、何のカテゴリーなのかを手動でラベリング(コート,,
  2. カテゴリー階層は最大3階層まで

アノテーションデータはこのように構成されています f:id:HifiroleLorum:20181016175504p:plain

入出力の制御(アノテーションラベルの活用)

f:id:HifiroleLorum:20181016175514p:plain

Word2vecは学習に使用された語彙に対して、それぞれベクトルが設定されています。上図のようにアノテーションで属性が判明している単語もあれば、まだ調査していない未知語も入力として入ってくる可能性があります。未知語はシャットアウトすれば良いという判断もありますが、対応語を増やすため未知語でも入力を認めることにしました。ただ、Word2vecにより大量の文章を学習しており、未知語の関連語として何が出力されるのかブラックボックス化されてしまう懸念がありました。この不透明さを解消するために活用したのがこれまでアノテーションしてきたラベルです。

NGフィルタは、ホワイトリストに登録された単語のみを出力するように配置されています。ゆらぎ表現フィルタは、ホワイトリスト内の単語を片寄せするために配置されています。カテゴリーフィルタは、出力するカテゴリーを統一させ、出力ノイズを減らすために設置されています。カテゴリーフィルタは、特に未知語や学習が不十分な語彙に対して大きく影響を与えます。

下でカテゴリーフィルタ設定前後を比較しています。

# カテゴリー補正前
model.wv.most_similar(positive='ポット', topn=6)
>  [('ピッチャー',0.6643306016921997),
>   ('ティーポット',0.62236487865448),
>   ('ボウル',0.6212266087532043),
>   ('鉢',0.5690277814865112),
>   ('ティーカップ',0.5430924296379089),
>   ('花器',0.5429580211639404),

# カテゴリー補正後
model.wv.most_similar(positive='ポット', topn=6)
>  [('ピッチャー',0.6643306016921997),
>   ('ティーポット',0.62236487865448),
>   ('ボウル',0.6212266087532043),
>   ('ティーカップ',0.5430924296379089),
>   ('コーヒードリッパー',0.5426920056343079),
>   ('トレイ',0.5033057332038879),

花器といった、容器ではあるものの、キッチン周りにはふさわしくない園芸向けのキーワードの出現が抑制されるようになっています。結果、類似度の閾値制御だけでは弾くことが難しいケースもカテゴリーを設定することによって解決することができました。

まとめ

今回は、アノテーションを機械学習の制御に活用してみたという内容をお送りしました。機械学習の学習結果をそのまま信用して活用するのではなく、アノテーションの結果を活用することで品質向上を行うことができました。ただ、アノテーションを闇雲に行うのではなく、どう活用していくのか事前の課題設定をきちんと立てることも重要そうですね。

BASEでは一緒にネットショップ作成サービスを開発・改善するエンジニアを募集してます。 機械学習のチームでは、様々なデータや技術を使ってECならではの開発を続けています。 ご興味のある方はぜひ遊びにきてください!!

jobs.binc.jp