ナード戦隊データマン

データサイエンスを用いて悪と戦うぞ

word2vecのオンライン学習

nonce2vec1とは、少数のデータを用いて訓練済みWord2vecに新語を加えるなどする手法です。ここでは、その使い方を見てみます。

概要

nonce2vecは3つのフェーズを取ります。

  1. 事前訓練済みWord2vec(skip-gram)の読み込み。
  2. 訓練対象文のボキャブラリー構築。
  3. パラメータを設定し、訓練対象文で対象語を訓練。

訓練対象文は、例えば訓練したい語の「語の定義」などを使います。要するに、新語を少数の定義文から更新する手法です。

インストール

pip install nonce2vec

実行例

from nonce2vec.models.nonce2vec import Nonce2Vec, Nonce2VecTrainables, Nonce2VecVocab
import MeCab
from pprint import pprint
import numpy as np
import copy

if __name__ == "__main__":
    #MODELS
    model = Nonce2Vec.load("word2vec.model")
    model.vocabulary = Nonce2VecVocab.load(model.vocabulary)
    model.trainables = Nonce2VecTrainables.load(model.trainables)
    tagger = MeCab.Tagger("-Owakati -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/")

    nonces = []
    sentences = []
    #INPUTS
    with open("10.test") as f:
        for line in f:
            tmp = line.split(":::")
            nonce = tmp[0]
            sentence = tagger.parse(tmp[1]).format(nonce).strip().split()
            nonces.append(nonce)
            sentences.append(sentence)

    #PARAMS
    alpha = 1
    sample = 10000
    neg = 3
    window = 15
    iter = 1
    lambda_den = 70
    sample_decay = 1.9
    window_decay = 5

    #PARAM SETTING
    def model_init(m, sentence, nonce, *ps):
        model.alpha=float(ps[0])
        model.sample=int(ps[1])
        model.sample_decay=float(ps[2])
        model.iter=int(ps[3])
        model.negative=int(ps[4])
        model.neg_labels = []
        if model.negative > 0:
            model.neg_labels = np.zeros(model.negative+1)
            model.neg_labels[0] = 1.
        model.vocabulary.nonce=nonce
        model.window=int(ps[5])
        model.window_decay=int(ps[6])
        model.lambda_den=float(ps[7])
        #model.min_count=int(1)
        print(sentence)
        model.build_vocab(sentences=[sentence], update=True)
        model.train([sentence], total_examples=model.corpus_count, epochs=model.iter)
        return model

    #DOIT
    import json
    out = {}
    for nonce, sentence in zip(nonces, sentences):
        model = model_init(model, sentence, nonce, *(alpha, sample, sample_decay, iter, neg, window, window_decay, lambda_den))
        tmp = model.most_similar(nonce, topn=30)
        out[nonce] = tmp
    with open("out.json","w") as f:
        f.write(json.dumps(out, indent=4, sort_keys=True, ensure_ascii=False))

実行例のデータ

11次元超重力理論:::{} とは、一般相対論を超対称化した理論、言い方を変えれば局所超対称性の理論である。量子化した際は、単なる一般相対論より紫外発散が弱くなるため、量子重力理論の文脈において1980年代初頭に精力的に研究された。超対称性のゲージ理論と考えることもできる。対応するゲージ場がグラヴィティーノである。
エンティティリンキング:::{} とは、自然言語処理において、テキスト内の表現を知識ベース内の識別子として認識するタスクである。
カバートアグレッション:::{} とは、評判を傷つけたり、関係を操作することで人に害を及ぼす行為である。
自己顕示バイアス:::{} とは、実験参加者が自分を良く見せようとすることによって生じるバイアスのこと。
INTJ:::{} とは、MBTIの診断結果の1つで、内向的・直感的・思考的・判断的な性格タイ
プのこと。
サイハテ村:::{} とは、熊本の宇土半島にあるエコビレッジ。
オブジェクト図:::{} とは、クラス図などで表現されたクラス構成や相互関係に対して、それをインスタンス化したレベルで表現したUMLの図。
レプティリアン:::{} とは、陰謀論の一つで、地球に隠れて生息するとされる宇宙人の一種。爬虫類に属する。
Metasploit:::{} とは、サイバーセキュリティのツールで、ペネトレーションテストを行うためのフレームワークである。
幾何学的ラングランズ予想:::{} とは、ラングランズプログラムを幾何学的に定式化しなおして、単に既約表現だけを考える以上のものを関連付けようとして生じたものである。単純な場合だと、代数曲線のエタール基本群の l-進表現を、その曲線上のベクトル束の
モジュライスタック上で定義された l-進層の導来圏の対象に関連付ける。

実行結果の一部

{
    "11次元超重力理論": [
        [
            "マイクロ磁気学",
            0.780556857585907
        ],
        [
            "ピカール・レフシェッツ",
            0.7795853614807129
        ],
        [
            "成りたつ",
            0.7746739387512207
        ],
        [
            "オイラー=ハイゼンベルク・ラグランジアン",
            0.7744903564453125
        ],
        [
            "散乱問題",
            0.7708392143249512
        ],
        .
        .
        .

おわりに

このように、少数のデータから、事前訓練済みWord2vecにはない語を学習することができました。

ただし、build_vocabでは、合計ベクトルを新語のベクトルとして採用しているため、新語同士が近くなってしまう問題があります。

補足: gensimのskip-gramモデル

skip-gramモデルを使うには、sg=1を指定します。

import logging
from gensim.models import word2vec
import multiprocessing

if __name__ == "__main__":
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    sentences = word2vec.Text8Corpus('./wiki_fixed.text8')
    model = word2vec.Word2Vec(sentences, size=200, workers=multiprocessing.cpu_count(), sg=1)
    model.save("word2vec.model")