KATOエンジニヤリング開発日誌

「アウトプット無きエンジニアにインプットもチャンスも無い」の精神で書いています

WEB+DB PRESS Vol.100の人工知能の記事 - 自然言語処理 -

2017年8月に発売された「WEB+DB PRESS Vol.100」の人工知能の記事を読みました。

WEB+DB PRESS Vol.100

WEB+DB PRESS Vol.100

  • 作者: 河原一哉,白土慧,菊田洸,西鳥羽二郎,柄沢聡太郎,大谷勇毅,新井啓太,HANADA Yoshihito,増田謙一,池上達也,木下祐実,藤原大,長野雅広,樫田光,縣俊貴,大川徳之,栗林健太郎,小飼弾,庄司嘉織,鈴木勇介,高橋征義,田中哲,徳永拓之,中嶋謙互,中島拓,西尾泰和,西田圭介,羽生章洋,藤本真樹,外村和仁,まつもとゆきひろ,松本亮介,ミック,三宅陽一郎,森田創,山本陽平,吉羽龍太郎,牧大輔,石垣憲一,平原正裕,ひげぽん,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/08/24
  • メディア: 大型本
  • この商品を含むブログ (1件) を見る

先日も同じような内容の記事をSoftware Designで読んだので復習にもなりました。

www.kato-eng.info

第1章 人工知能とはどんな技術なのか

人工知能はコンピュータ上で人間のような知能を実現させようという技術で、新しい技術だと思われがちだがコンピュータの発達とともに注目されたり下火になったりを繰り返してきた歴史のある技術である。

人間のような知能とは次のようなものがある。

  • 言語系
    • 翻訳
    • 対話
    • 文の生成
  • 推論系
    • 囲碁や将棋などの対局
    • 広告の最適化
  • 認識系
    • 画像認識
    • 顔認識
    • 音声認識
  • 行動系
    • 車の自動運転
    • ロボットの自動制御

人工知能の種類

  • 出来ることでの分類
    • 弱い人工知能
      • 人間の能力の代わりを一部できる人工知能のこと。
      • 今実現されている人工知能はこの弱い人工知能のことである。
    • 強い人工知能
      • 人間の知能に迫るような能力や、人間の仕事をこなせるほどの能力を持っている人工知能。
  • 出来ることの範囲での分類
    • 特化型人工知能
      • 特定の領域に特化した人工知能。
      • 今実現されている人工知能はこの特価型人工知能のことである。
    • 汎用人工知能
      • 人間の知能で実現できる範囲すべてを対象にした人工知能のこと。

今ある人工知能は「弱い特化型人工知能」だが、深層学習を使った人工知能は強い人工知能や汎用人工知能を実現することができるかもしれないと期待されている。

第2章 自然言語処理

Dockerコンテナの準備

事前にDockerをインストールする。私はMacを使用しているのでDocker For Macを公式サイトからダウンロードしてインストールした。

Docker For Mac | Docker

Dockerの準備ができた後、技術評論社のサポートページからDockerイメージをダウンロードする。

サポートページ:WEB+DB PRESS Vol.100:|gihyo.jp … 技術評論社

「作って学ぶ人工知能」のソースコードを上記URLから取得し、zip解凍後に適当なディレクトリに格納する。

WDB100-toku1-AI $ pwd
[格納したディレクトリ]/WDB100-toku1-AI
WDB100-toku1-AI $ docker build -t webdb100 ./docker
Sending build context to Docker daemon  4.096kB
Step 1/7 : FROM centos:7
... 中略 ...
Successfully built 23535d952d11
Successfully tagged webdb100:latest
WDB100-toku1-AI $ docker run -it -v `pwd`:/webdb100 webdb100:latest
(python3.6) [root@d8b1c523c864 /]# 

Dockerコンテナを停止するにはexitコマンドを使用する。停止してもコンテナは残るのでdocker startコマンドでコンテナを再開し、docker attachコマンドでコンテナにログインできる。コンテナを削除する場合はdocker rmで削除できる。

(python3.6) [root@d8b1c523c864 /]# exit
WDB100-toku1-AI $ 
WDB100-toku1-AI $ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
d8b1c523c864        webdb100:latest     "/bin/bash"              16 minutes ago      Exited (0) 5 minutes ago                       hardcore_lewin
WDB100-toku1-AI $docker start d8b1c523c864
WDB100-toku1-AI $docker attach d8b1c523c864
(python3.6) [root@d8b1c523c864 /]#

文書の準備

自然言語処理の解析で使用する文書を用意する。一般的にこの文書はそのままでは使用できず、クリーニングや正規化が必要となる。

文書のクリーニング

メタデータなど不要なものを削除してテキスト自体を取り出す。文書データがXMLやJSONのようなフォーマットであればスクリプトを書くことで必要な部分を簡単に取り出すことができる。文書データがExcelの場合はCSVファイル等に変換してから処理を行う。その際に元データと変換したファイルの文字コードには注意が必要である。
取り出した文書データが小規模であれば1つの文書を1つのファイルに保存したり、全ての文書を1つのファイルに保存しても問題にならないが、大規模な文書データの場合はファイル管理やストレージ管理の観点や後続処理の容易さから分散型アーキテクチャを用いることも選択肢の一つになる。

ノイズの除去

文書のクリーニングで取り出したテキストデータから自然言語処理で必要な部分だけを残す作業が「ノイズの除去」である。この段階ではHTMLファイルからタグを除去したりMarkdown記法の記号を取り除いたりする。この時にノイズを除去する前の元データは消さないようにする。後々になってタグで囲まれたテキストが重要なことがわかっても、ノイズ除去後ではそれがどこにあったかを知る術はない。解析手法を決定し運用フェーズに乗るまでは取得した段階の元データは残しておく。

辞書の利用

自然言語処理における辞書とは単語とその品詞などの情報を一覧にしたものである。日本語の辞書で一般的に使われている辞書は次のようなものがある。

  • 一般的な単語辞書
    • IPA辞書、JUMAN辞書、UniDic
    • 一般的な日本語の辞書でそれぞれ品詞体系や単語単位の区切り方が異なる。
  • 新語辞書
    • NEologd
    • 日々増え続ける固有名詞を収録する辞書。
  • 中古和文辞書・近大文語辞書
    • 古典・古文を解析できるようにした辞書。
  • 独自の辞書を作成
    • 解析対象の文書によっては独自に辞書を作成する場合がある。

文字列の正規化

文書に使用されている単語の表記が統一されていないこと場合、同じはずの単語を別のものとして扱ってしまったり、意図しない解析結果になることがある。このような問題を解決するために「正規化」という作業が必要になる。具体的には次のよう事を行う。

  • 全角英数字を半角に統一
    • 例:「Windows」を「Windows」に変換し統一する
  • 半角カタカナを全角に統一
    • 例:「カタカナ」を「カタカナ」に変換し統一する
  • 似た文字種の統一
    • 例:ハイフンマイナス(U+002D)に似た文字のノンブレーキングハイフン(U+2011)やフィギュアダッシュ(U+2012)をハイフンマイナス(U;002D)に変換し統一する
  • 不必要なスペースの削除
    • 全角スペースを半角スペースに置換
    • スペースが連続している場合は1つのスペースに置換
    • ひらがなや感じの間に含まれるスペースの削除

形態素解析

形態素とは文において意味を持つ最小の単位で、文章を構成要素に分解し文書の意味を理解できるようにするのが形態素解析である。英語の文章は基本的に空白やピリオド等の記号で区切ることができるが、日本語の文は区切りを決定すること自体が難しい問題となっている。

# 英語の場合はスペースやピリオドで句切ればよい
I | bought | a | book | .

# 日本語の場合は複数の区切り方が発生する場合がある
外国 | 人 | 参政 | 権
外国 | 人参 | 政権

MeCabを使った形態素解析

形態素解析の代表的なツールとしてMeCabがある。

(python3.6) [root@d8b1c523c864 webdb100]# mecab
私は本を買った
私 名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
本 名詞,一般,*,*,*,*,本,ホン,ホン
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
買っ  動詞,自立,*,*,五段・ワ行促音便,連用タ接続,買う,カッ,カッ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
EOS

MeCabで独自の辞書を使う

viコマンドでカレントディレクトリに「original_dic.csv」ファイルを作成する。

(python3.6) [root@d8b1c523c864 /]# vi original_dic.csv

original_dic.csvファイルの中身は下記の通り。

WEB+DB PRESS,,,10,名詞,固有名詞,一般,*,*,*,WEB+DB PRESS,ウェブディービープレス,ウェブディービープレス

original_dic.csvファイルを作成したら次のコマンドで辞書ファイルを作成する。

(python3.6) [root@d8b1c523c864 /]# /usr/local/libexec/mecab/mecab-dict-index -d /usr/local/lib/mecab/dic/ipadic -u original.dic -f utf-8 -t utf-8 original_dic.csv
reading original_dic.csv ... 1
emitting double-array: 100% |###########################################|

done!

作成した辞書ファイルを使用できるようにするためviコマンドで設定ファイルを開き、末尾に「useridc = /original_dic」と記述する。

(python3.6) [root@d8b1c523c864 /]# vi /usr/local/lib/mecab/dic/ipadic/dicrc

その後、MeCabを実行し、登録した辞書が利用されていることを確認する。

(python3.6) [root@d8b1c523c864 /]# mecab
WEB+DB PRESSという雑誌
WEB+DB PRESS    名詞,固有名詞,一般,*,*,*,WEB+DB PRESS,ウェブディービープレス,ウェブディービープレス
という   助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
雑誌  名詞,一般,*,*,*,*,雑誌,ザッシ,ザッシ
EOS

係り受け解析

係り受け解析とは語句と語句の修飾関係を解析するものである。「私は本を買った」という文章では「私は」と「本を」という語句が「買った」に係っている。「高い」という語句は「本」に係っている。修飾する語句と修飾される語句を解析することで文章の構造を把握できるようなる。

CaboChaを使った係り受け解析

係り受け解析を行うツールとしてCaboChaが有名。コンソール上でcabochaコマンドで実行し、文章を入力すると係り受け解析の結果をツリー型に出力してくれる。

(python3.6) [root@d8b1c523c864 /]# cabocha
等は花子が読んでいる本を次郎に渡した
      等は---------D
      花子が-D     |
    読んでいる-D   |
            本を---D
            次郎に-D
              渡した
EOS

前処理

解析を行う前に前処理を行うことで解析精度や解析速度の向上が図れる。前処理としては次のような作業がある。

表記揺れの対応

表記揺れとは「行き止まり」「行きどまり」「行止まり」のような同じ語を別の書き表し方で表記しているものを指す。表記揺れの対応については国立国語研究所が公開している表記統合辞書を利用するとよい。

同義語の対応

同義語とは「台所」「厨房」のような表記は異なるが意味が同じ語のことをいう。「国際連合」を「国連」と略したものも同義語にあたる。
同義語となる語を一つの表記にまとめることによって文字列検索でカバーできる語を広げたり複数の語を1つの語に統一して語彙数を減らすことで計算速度の改善を図ることができる。

ストップワードの除去

「こと」や「いる」のような一般的な単語が形態素解析の結果、出現することが多い。これらの単語は様々な文書で出現するため文書の特徴を表すのには不適切で解析の精度を下げる要因になりえる。このような解析にしようしたくない語をストップワードとよぶ。精度向上や処理の高速化のためにストップワードを除去することが多い。

文書の表現

文書と文書の関係性を調査する時など、1つ1つの文書を何かしらの形式に変換するときがある。

分かち書き表現

文書を単語に区切って表現した形式のこと。形態素解析の結果を用いて出現した順に単語を並べる。

文書のベクトル表現

文書の特徴をベクトルとして表現する形式のこと。文書中に単語がどのように分布しているかをベクトルとして表現する。これは似た文書には同じ単語が含まれているという考えから、似た文書を探す処理をおこなうときにこの表現を用いることが多い。
文書をベクトルで表す方法としては下記のようなものがある。

  • バイナリ表現
    • 文書中に単語が1つでも出現したら「1」を、出現しない場合には「0」とする表現。
  • カウント表現
    • 文書中の単語の出現数を重み付けとして利用する方法。
  • tf-idf表現
    • 文書中の単語の重要度をtf-idfという手法で計算し、その値で重み付けする方法。

一般的にはtf-idf表現がよく利用されるが文書数が非常に多い場合はtf-idfの計算に時間が掛かることがあり、その場合にはその他の表現方法を使うこともある。

次章以降で利用するデータの準備

第3章以降で使用するデータであるWikipediaの記事を取得する。

https://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2

※2.4GBあるので注意

取得したデータがローカル端末にあるので、Dockerで起動しているコンテナにコピーする。先ほど用意したDockerコンテナのディレクトリにファイルを移動させればよい。そうすればdockerコンテナ上でファイルが認識できるようになる。

その後ファイルをルートディレクトリに移動させbzip2コマンドで解凍する。

(python3.6) [root@d8b1c523c864 /]# mv webdb100/jawiki-latest-pages-articles.xml.bz2 /
(python3.6) [root@d8b1c523c864 /]# bzip2 -d jawiki-latest-pages-articles.xml.bz2
(python3.6) [root@d8b1c523c864 /]# head jawiki-latest-pages-articles.xml
<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="ja">
  <siteinfo>
    <sitename>Wikipedia</sitename>
    <dbname>jawiki</dbname>
    <base>https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8</base>
    <generator>MediaWiki 1.31.0-wmf.1</generator>
    <case>first-letter</case>
    <namespaces>
      <namespace key="-2" case="first-letter">メディア</namespace>
      <namespace key="-1" case="first-letter">特別</namespace>

このファイルから解析対象の文書として必要な部分だけを取り出す。Wikipediaに対して使えるWikiExtractorというツールを使用してノイズ除去を行う。

(python3.6) [root@d8b1c523c864 /]# git clone
(python3.6) [root@d8b1c523c864 /]# python 
... 中略 ...
INFO: Finished 3-process extraction of 1078159 articles in 3217.9s (335.0 art/s)
(python3.6) [root@d8b1c523c864 /]#

出力されたファイルをリネームする。

(python3.6) [root@d8b1c523c864 /]# mv extracted/AA

NEologdが推奨する正規化手法で正規化を行う。

(python3.6) [root@d8b1c523c864 /]# python webdb100/02/wikipedia_normalize.py wikipedia_extracted_data.txt
... 中略 ...
  23160000 /   23218230 lines (99.7 percent) done
  23180000 /   23218230 lines (99.8 percent) done
  23200000 /   23218230 lines (99.9 percent) done

内容語のみを取り出して分かち書き表現にする。この際ストップワードを省き単語の原型を用いる。辞書にはNEologdを使用する。

(python3.6) [root@d8b1c523c864 /]# python wikipedia_wakachi.py
100 documents done.
200 documents done.
300 documents done.
400 documents done.
... 省略 ...

wikipedia_wakatied_data.txtを確認すると、分かち書きされているのが確認できる。

(python3.6) [root@d8b1c523c864 /]# head -1 wikipedia_wakatied_data.txt
5   意味 記号 ラテン語 合字 フォント 表示 合字 容易 わかる 意味 使用 遡る 中葉 現代 至る 変遷 わかる 続く ラテン文字 アルファベット 時期 役割 果たす 文字 呼ぶ 数字 似る 記号 記号 現在 ゲール文字 使う 記号 ラテン語 まじる 英語 自身 表す くずれる 形 英語 言語 名称 多様 日常 手書き 場合 欧米 縦 引く 単純 使う 同様 プラス 輪 重ねる 無声歯茎側面摩擦音 示す 発音記号 の・ようなもの 使う プログラミング言語 多数 言語 演算子 用いる 例 変数 宣言 記号 直前 記述 参照 渡し 行う 系列 言語 文字列 連結 演算子 使用 返す 主 マイクロソフト 整数 表記 用いる 表現 使う 実体 参照