人間には、他の人が何を言っているのかを理解し、それに対して何を言うべきかという自然な能力がある。
この能力は、長年にわたって他の人々や社会と一貫して交流することによって培われる。
人間がどのように相互作用するかについて、言語は非常に重要な役割を担っている。
人間が相互作用のために使う言語を自然言語という。
自然言語にはさまざまなルールがある。
しかし、自然言語には、「柔軟性」と「進化」という共通点がある。
自然言語は非常に柔軟である。
例えば、あなたが車を運転しているときに、友人が次の3つのうちのどれかを言ったとしよう。
「車を止めろ」、「車を止めろ」、「止まれ」。
あなたはすぐに、彼があなたに車を止めるように頼んでいるのだと理解する。
これは、自然言語が非常に柔軟だからです。
一つのことを言うにも、複数の言い方があるのだ。
もう一つ重要なのは、自然言語が常に進化していることだ。
例えば、数年前には「Google it」という言葉はなかった。
これは、Googleの検索エンジンで何かを検索することを指す。
自然言語は常に進化を続けているのである。
一方、コンピュータ言語は厳密な文法に則っている。
コンピューターに「画面に何か印刷してくれ」と言えば、そのための特別なコマンドがある。
自然言語処理の課題は、コンピュータに人間の言葉を理解させ、人間に近い形で生成させることである。
これは非常に大きな課題であり、多くのハードルがあります。
ミシガン大学のこのビデオ講義は、なぜNLPが難しいのかについて非常に良い説明を含んでいます。
この記事では、PythonのGensimライブラリを使って、単語ベクトルの作成に使われるWord2Vecの単語埋め込み技術を実装します。
しかし、コーディングのセクションに飛ぶ前に、まず、よく使われる単語埋め込み技術を、その長所と短所とともに簡単におさらいしておきます。
ワードエンベッディングアプローチ
自然言語処理が難問である理由の一つは、コンピュータが人間と違って数字しか理解できないことである。
コンピュータが理解できるような数値で単語を表現しなければならない。
単語を数値で表現することを単語埋め込みという。
現在、いくつかのワードエンベッディングのアプローチが存在するが、いずれも一長一短がある。
ここでは、そのうちの3つを紹介する。
-
- 単語の袋
- TF-IDFスキーム
- Word2Vec
ーーバッグ・オブ・ワーズ
Bag of Wordsは、最も単純な単語埋め込み手法の一つです。
以下は、Bag of words approachを用いた単語埋め込み生成の手順である。
ここでは、Bag of words approachによって生成された単語埋め込みを例として見ていくことにする。
例えば、3つの文からなるコーパスがあるとする。
- S1 = 私は雨が好き
- S2 = 雨 雨は去っていく
- S3 = 私は離れている
上記の文をBag of Wordアプローチを使って対応する単語埋め込み表現に変換するためには、以下のステップを実行する必要がある。
- コーパスから固有語の辞書を作成する。上記のコーパスには、以下の固有単語がある。[I, love, rain, go, away, am] である。
- 文章を解析する。文中の各単語について、辞書にある単語の代わりに1を加え、辞書に存在しないその他の単語については0を加える。例えば、文S1(I love rain)の語袋表現は以下のようになる。[1, 1, 1, 0, 0, 0]. 同様に、S2とS3についても、それぞれ[0, 0, 2, 1, 1, 0]と[1, 0, 0, 0, 1, 1]という単語袋の表現になっています。
S2については、辞書の「rain」の代わりに「2」を追加していることに注目。
これは、S2には「rain」が2回含まれているからである。
バッグ・オブ・ワーズの長所と短所
Bag of Wordsアプローチには長所と短所がある。
Bag of wordsアプローチの主な利点は、良い結果を得るために非常に巨大な単語のコーパスを必要としないことである。
ここでは、3つの文からなる非常に基本的なBag of Wordモデルを構築しているのがわかる。
計算上、Bag of Wordモデルはそれほど複雑ではない。
Bag of Wordアプローチの大きな欠点は、数を表現するために空白の巨大なベクトル(スパース行列)を作成する必要があり、メモリとスペースを消費することである。
先ほどの例では、3つの文しかありませんでした。
しかし、どのベクトルにも3つのゼロがあるのがわかるだろう。
何千もの記事があるコーパスを想像してみよう。
このような場合、辞書に載っているユニークな単語の数は数千になることもある。
ある文書に10%の固有単語が含まれていたとしても、対応する埋め込みベクトルには90%のゼロが含まれることになります。
Bag of Wordのもう一つの大きな問題は、文脈情報を保持しないことである。
文中の単語の順番を気にしないのである。
例えば、「ボトルは車の中にある」と「車はボトルの中にある」という文は全く別の文であり、同じように扱われる。
単語間の関係を維持するためには、N-gramと呼ばれるBag of Wordアプローチの一種が有効である。
N-gramとは、連続したn個の単語の並びのことである。
例えば、”You are not happy “という文章は、”You are”, “are not”, “not happy “で2-gramとなる。
N-gramアプローチは単語間の関係を捉えることができるが、N-gramの数が多すぎると特徴セットのサイズが指数関数的に大きくなってしまう。
TF-IDFスキーム
TF-IDF方式はバッグワード法の一種で、埋め込みベクトルに0と1を加える代わりに、0と1に比べてより有用な情報を含む浮動小数点数を加える方式である。
TF-IDF方式の考え方は、ある文書での出現頻度が高く、他のすべての文書での出現頻度が低い単語は、分類上、より重要であるという事実である。
TF-IDFは、2つの値の積である。
用語頻度(TF)と逆文書頻度(IDF)の2つの値の積である。
項頻度とは、ある単語が文書中に出現する回数のことで、次のように計算できる。
Term frequence = (Number of Occurences of a word)/(Total words in the document)
例えば、前節の文S1、すなわち「I love rain」の場合、文中のすべての単語は一度だけ出現し、したがって頻度は1である。
逆にS2、すなわち「rain rain go away」の場合、rainの頻度は2であり、残りの単語は1である。
IDFとは、全文書数をその単語が存在する文書数で割った対数であり、以下のように計算できる。
IDF(word) = Log((Total number of documents)/(Number of documents containing the word))
例えば、”rain “という単語のIDF値は0.1760である。
文書総数は3であり、rainはそのうちの2つに出現するので、log(3/2)
は0.1760である。
一方、最初の文の単語 “love “を見ると、3つの文書のうちの1つに出現しているので、そのIDF値は log(3)
であり、0.4771となる。
TF-IDFの長所と短所
TF-IDFは単純なBag of Wordアプローチより改善され、一般的なNLPタスクでより良い結果が得られますが、全体的な長所と短所は変わりません。
TF-IDFは単純なbag of wordsの手法より改善され、一般的な自然言語処理タスクでより良い結果を得ることができますが、全体的な長所と短所は変わりません。
ワード2ベック
Tomas Mikolov 氏が開発した Word2Vec 埋め込みアプローチは、最先端と考えられています。
Word2Vecのアプローチは、ディープラーニングとニューラルネットワークベースの技術を使用して、N次元空間において意味的に類似したベクトルが互いに接近するように、単語を対応するベクトルに変換します(ここでNはベクトルの次元を意味します)。
Word2Vecは驚くような結果を返します。
Word2Vecの意味関係維持能力は、典型的な例として、”King “という単語のベクトルがあったとして、”King “から “Man “で表されるベクトルを取り除き、”Women “を加えた場合、”Queen “に近いベクトルを得ることができます。
この関係は、一般に次のように表される。
King - Man + Women = Queen
Word2Vecモデルには2つの種類がある。
スキップグラムモデルと連続単語袋モデル(CBOW)である。
スキップグラムモデルでは、文脈の単語は基本単語を使用して予測される。
例えば、”I love to dance in the rain “という文があった場合、”to “という単語を入力として、”love “と “dance “をスキップグラムモデルが予測する。
一方、CBOWモデルは、文脈上の単語「love」と「dance」を入力として与えると、「to」を予測する。
このモデルは、ディープニューラルネットワークを用いて、これらの関係を学習する。
Word2Vecの長所と短所
Word2VecはBag of WordやIF-IDFスキームと比較して、いくつかの利点がある。
Word2Vecは、文書中の異なる単語の意味を保持する。
文脈情報が失われることがない。
Word2Vecのもう一つの大きな利点は、埋め込みベクトルのサイズが非常に小さいことです。
埋め込みベクトルの各次元は、単語の1つの側面に関する情報を含んでいます。
Bag of wordsやTF-IDFのアプローチとは異なり、巨大なスパースベクトルは必要ないのです。
注:Word2Vecの動作の数学的詳細は、ニューラルネットワークとソフトマックス確率の説明を含みますが、この記事の範囲外です。
Gensim ライブラリを用いた Python による Word2Vec の開発
ここでは、PythonのGensimライブラリを用いてWord2Vecのモデルを実装します。
以下の手順に従ってください。
コーパスの作成
Word2Vecのモデルを作るには、コーパスが必要であることは前述した。
実際のアプリケーションでは、Word2Vecモデルは何十億ものドキュメントを使って作成される。
例えばGoogleのWord2Vecモデルは300万語の単語とフレーズを使って学習されます。
しかし、ここでは簡単のために、一つのWikipediaの記事からWord2Vecモデルを作成する。
我々のモデルはGoogleのモデルには及ばない。
しかし、Gensimライブラリを使ってどのようにWord2Vecモデルを実装するかを説明するには十分です。
Wikipediaの記事を要約する前に、記事を取得する必要があります。
そのために、いくつかのライブラリを使用します。
まず最初にダウンロードする必要があるのは、Webスクレイピングのための非常に便利なPythonユーティリティであるBeautiful Soup ライブラリです。
コマンドプロンプトで以下のコマンドを実行し、Beautiful Soupユーティリティをダウンロードします。
$ pip install beautifulsoup4
XMLやHTMLをパースするために必要なもう一つの重要なライブラリは、lxmlライブラリです。
コマンドプロンプトで以下のコマンドを実行し、lxmlをダウンロードしてください。
$ pip install lxml
今回スクレイピングするのは、Wikipediaの人工知能に関する記事です。
Wikipediaから記事をスクレイピングするPython Scriptを書いてみましょう。
import bs4 as bs
import urllib.request
import re
import nltk
scrapped_data = urllib.request.urlopen('https://en.wikipedia.org/wiki/Artificial_intelligence')
article = scrapped_data .read()
parsed_article = bs.BeautifulSoup(article,'lxml')
paragraphs = parsed_article.find_all('p')
article_text = ""
for p in paragraphs:
article_text += p.text
上のスクリプトでは、まず urllib
ライブラリの request
クラスの urlopen
メソッドを使用して Wikipedia の記事をダウンロードします。
次に、BeautifulSoup
クラスのオブジェクトを使って記事の内容を読み、パースします。
Wikipedia は記事の内容を p
タグ内に格納している。
BeautifulSoupオブジェクトの
find_all` 関数を使用して、記事の段落タグからすべてのコンテンツを取得します。
最後に、すべての段落を結合し、後で使用するためにスクレイピングした記事を article_text
変数に格納します。
前処理
この時点で、記事をインポートしました。
次のステップは、Word2Vecモデルのためのコンテンツの前処理を行うことです。
以下のスクリプトで前処理を行います。
# Cleaing the text
processed_article = article_text.lower()
processed_article = re.sub('[^a-zA-Z]', ' ', processed_article )
processed_article = re.sub(r's+', ' ', processed_article)
# Preparing the dataset
all_sentences = nltk.sent_tokenize(processed_article)
all_words = [nltk.word_tokenize(sent) for sent in all_sentences]
# Removing Stop Words
from nltk.corpus import stopwords
for i in range(len(all_words)):
all_words[i] = [w for w in all_words[i] if w not in stopwords.words('english')]
上のスクリプトでは、すべてのテキストを小文字に変換し、テキストから数字、特殊文字、余分なスペースをすべて削除しています。
前処理の後は、単語だけが残る。
Word2Vecモデルは単語の集合体に対して学習されます。
まず、記事を文章に変換する必要があります。
記事を文章に変換するために、nltk.sent_tokenize
ユーティリティを使用します。
文を単語に変換するために、nltk.word_tokenize
ユーティリティを使用します。
最後の前処理として、テキストからストップワードをすべて削除する。
スクリプトの実行が完了すると、all_words
オブジェクトに記事中の全単語のリストが格納されます。
このリストを用いて Gensim ライブラリで Word2Vec モデルを作成します。
Word2Vecモデルの作成
Gensim では、Word2Vec モデルを非常に簡単に作成することができます。
単語リストは gensim.models
パッケージの Word2Vec
クラスに渡されます。
ここで、min_count
パラメータに値を指定する必要があります。
min_count` に 2 を指定すると、コーパスに2回以上出現する単語のみをWord2Vecモデルに含めることができる。
以下のスクリプトはスクレイピングしたWikipediaの記事を用いてWord2Vecのモデルを作成する。
from gensim.models import Word2Vec
word2vec = Word2Vec(all_words, min_count=2)
コーパスに2回以上現れるユニークな単語の辞書を見るには、以下のスクリプトを実行する。
vocabulary = word2vec.wv.vocab
print(vocabulary)
上記のスクリプトを実行すると、2回以上出現するユニークな単語のリストが表示されます。
モデル解析
前節でWord2Vecのモデルを作成することに成功しました。
さて、次は作成したモデルを分析する番です。
単語のベクトル探し
Word2Vecモデルは、単語を対応するベクトルに変換することが分かっています。
では、どのようにすれば、特定の単語のベクトル表現を見ることができるかを見てみましょう。
v1 = word2vec.wv['artificial']
ベクトル v1
は “artificial” という単語のベクトル表現を持っている。
Gensim Word2Vec のデフォルトでは、100次元のベクトルが作成される。
これは、bag of words で生成されたものと比べると、かなり小さいベクトルである。
仮にBag of wordsの手法で記事を埋め込むと、最小出現頻度が2の単語が1206個あるので、それぞれのベクトルの長さは1206になります。
最小出現頻度を1にすると、Bag of wordsのベクトルの大きさはさらに大きくなります。
一方、Word2Vecによって生成されるベクトルは、語彙の大きさに影響されない。
類似語句の検索
先に、Word2Vecのアプローチでは、単語の文脈情報が失われないと述べた。
このことは、”intelligence “という単語に類似した単語をすべて見つけることで確認できる。
次のスクリプトを見てみよう。
sim_words = word2vec.wv.most_similar('intelligence')
変数 sim_words
をコンソールに出力すると、以下のように “intelligence” に最も近い単語が表示されます。
('ai', 0.7124934196472168)
('human', 0.6869025826454163)
('artificial', 0.6208730936050415)
('would', 0.583903431892395)
('many', 0.5610555410385132)
('also', 0.5557990670204163)
('learning', 0.554862380027771)
('search', 0.5522681474685669)
('language', 0.5408136248588562)
('include', 0.5248900055885315)
出力から、”intelligence “に類似した単語を類似度指数とともに見ることができます。
モデルによると、”ai “という単語が “intelligence “に最も似ている単語であり、これは実際に意味をなしています。
同様に、”intelligence “には “human “や “artificial “といった単語が混在していることが多いのです。
我々のモデルは、たった1つのWikipediaの記事を用いて、これらの関係をうまく捉えました。
さらに上を目指す – 手作りのEnd to Endプロジェクト
好奇心旺盛なあなたは、もっと先を目指したいと思っていませんか?ガイド付きプロジェクトのチェックをお勧めします。
「CNNとKerasのTransformerを使った画像キャプション作成」をご覧ください。
をご覧ください。
このガイド付きプロジェクトでは、画像を入力として受け取り、出力としてテキストキャプションを生成する画像キャプションモデルの構築方法を学びます。
このプロジェクトでは、次のことを学びます。
- テキストを前処理する
- 入力されたテキストを簡単にベクトル化する
-
tf.data
APIを使用し、パフォーマンスの高いデータセットを構築する。 - TensorFlow/Keras と KerasNLP – 最先端の NLP モデルを構築するための Keras への公式な水平方向の追加機能 – を使用してゼロから Transformers を構築する。
- あるネットワークの出力が別のネットワークにエンコードされるハイブリッドアーキテクチャの構築
画像キャプションをどのようにとらえるか?私たちはネットワークに説明を生成するように教えているので、ほとんどの人が生成的な深層学習の例だと考えています。
しかし、私はこれをニューラル機械翻訳の一例と見なしたいと思います。
つまり、画像の視覚的特徴を言葉に翻訳しているのです。
翻訳することで、単に新しい意味を生成するだけでなく、その画像の新しい表現を生成しているのです。
翻訳、ひいては生成と捉えることで、このタスクは別の観点から見ることができ、もう少し直感的に理解できるようになります。
問題を翻訳の問題としてとらえることで、どのアーキテクチャを使いたいかを考えることが容易になる。
エンコーダのみのトランスフォーマーは、エンコーダが意味のある表現をエンコードするため、テキストの理解(感情分析、分類など)に適している。
デコーダのみのモデルは、デコーダが意味のある表現を同じ意味を持つ別のシーケンスに推論することができるため、生成(GPT-3など)に最適である。
翻訳とは通常、エンコーダーとデコーダーのアーキテクチャによって行われ、エンコーダーは文(我々の場合は画像)の意味のある表現をエンコードし、デコーダーはこのシーケンスを我々にとってより解釈しやすい別の意味のある表現(文など)に変換することを学習するものである。
結論
In this article, we implemented a Word2Vec word embedding model with Python’s Gensim Library. We did this by scraping a Wikipedia article and built our Word2Vec model using the article as a corpus. We also briefly reviewed the most commonly used word embedding approaches along with their pros and cons as a comparison to Word2Vec.
I would suggest you to create a Word2Vec model of your own with the help of any text corpus and see if you can get better results compared to the bag of words approach.