ロボットを作る

子供のころ、映画「STARWARS」 を観てワクワクし、ガンプラにドキドキしていた。時間が経つのも忘れてしまう、そんな時間をもう一度、取り戻すために、Raspberry pi を使って、オヤジがロボット作りに挑戦する!

やり始めてみると、なかなか思い通りに行かない。時間の経つのも忘れて悪戦苦闘中。 「こんなちっちゃな Raspberry Pi で、こんなことができるんだ」を日々実感している今日この頃。

機械学習

気になっていた

O'Reillyの本
「ゼロから作るDeep Learning
―Pythonで学ぶディープラーニングの理論と実装」

を買ってみた。



レベル感が私にぴったりで、すごく丁寧にわかりやすく、タイトルどおり「ゼロから」説明されている。

まだ半分しか読んでないのだが、じっくり繰り返し読んでいきたい本である。

散々迷ったあげく、ファイルサイズの小さいデータでやり直した。
もともとは、11Gだったが、今回 46M のデータを利用。もちろんできた。

データは、
https://dumps.wikimedia.org/enwiki/latest/
から小さいデータを選んだ。とにかく RaspberryPi2 で出きることをやる。


$ python -m gensim.scripts.make_wiki enwiki-latest-pages-articles1.xml-p000000010p000010000.bz2 wiki_en_output 1000
2015-05-13 07:49:11,950 : INFO : running /usr/local/lib/python2.7/dist-packages/gensim/scripts/make_wiki.py enwiki-latest-pages-articles1.xml-p000000010p000010000.bz2 wiki_en_output 1000
2015-05-13 07:49:13,406 : INFO : adding document #0 to Dictionary(0 unique tokens: [])
2015-05-13 08:00:07,043 : INFO : finished iterating over Wikipedia corpus of 4680 documents with 13500677 positions (total 6280 articles, 13507365 positions before pruning articles shorter than 50 words)
2015-05-13 08:00:07,044 : INFO : built Dictionary(260454 unique tokens: [u'biennials', u'tripolitan', u'unsupportable', u'refreshable', u'nunnery']...) from 4680 documents (total 13500677 corpus positions)
2015-05-13 08:00:11,267 : INFO : discarding 240659 tokens: [(u'ability', 817), (u'able', 1252), (u'about', 2936), (u'abstention', 7), (u'abstentionism', 2), (u'according', 2057), (u'account', 890), (u'accounts', 486), (u'achieved', 648), (u'across', 1240)]...
2015-05-13 08:00:11,268 : INFO : keeping 19795 tokens which were in no less than 20 and no more than 468 (=10.0%) documents
2015-05-13 08:00:12,348 : INFO : resulting dictionary: Dictionary(19795 unique tokens: [u'writings', u'homomorphism', u'hordes', u'yellow', u'gag']...)
2015-05-13 08:00:12,564 : INFO : storing corpus in Matrix Market format to wiki_en_output_bow.mm
2015-05-13 08:00:12,566 : INFO : saving sparse matrix to wiki_en_output_bow.mm
2015-05-13 08:00:14,260 : INFO : PROGRESS: saving document #0
2015-05-13 08:12:06,707 : INFO : finished iterating over Wikipedia corpus of 4680 documents with 13500677 positions (total 6280 articles, 13507365 positions before pruning articles shorter than 50 words)
2015-05-13 08:12:06,709 : INFO : saved 4680x19795 matrix, density=1.896% (1756120/92640600)
2015-05-13 08:12:06,711 : INFO : saving MmCorpus index to wiki_en_output_bow.mm.index
2015-05-13 08:12:06,726 : INFO : saving dictionary mapping to wiki_en_output_wordids.txt.bz2
2015-05-13 08:12:11,686 : INFO : loaded corpus index from wiki_en_output_bow.mm.index
2015-05-13 08:12:11,687 : INFO : initializing corpus reader from wiki_en_output_bow.mm
2015-05-13 08:12:11,688 : INFO : accepted corpus with 4680 documents, 19795 features, 1756120 non-zero entries
2015-05-13 08:12:11,689 : INFO : collecting document frequencies
2015-05-13 08:12:11,753 : INFO : PROGRESS: processing document #0
2015-05-13 08:13:48,804 : INFO : calculating IDF weights for 4680 documents and 19794 features (1756120 matrix non-zeros)
2015-05-13 08:13:48,979 : INFO : storing corpus in Matrix Market format to wiki_en_output_tfidf.mm
2015-05-13 08:13:48,980 : INFO : saving sparse matrix to wiki_en_output_tfidf.mm
2015-05-13 08:13:49,063 : INFO : PROGRESS: saving document #0
2015-05-13 08:17:32,296 : INFO : saved 4680x19795 matrix, density=1.896% (1756120/92640600)
2015-05-13 08:17:32,297 : INFO : saving MmCorpus index to wiki_en_output_tfidf.mm.index
2015-05-13 08:17:32,309 : INFO : finished running make_wiki.py
$ ls -l
-rw-r--r-- 1 pi pi 11820881800  4月  7 07:06 enwiki-latest-pages-articles.xml.bz2
-rw-r--r-- 1 pi pi    46529467  5月 13 07:44 enwiki-latest-pages-articles1.xml-p000000010p000010000.bz2
-rw-r--r-- 1 pi pi    21416947  5月 13 08:12 wiki_en_output_bow.mm
-rw-r--r-- 1 pi pi       26176  5月 13 08:12 wiki_en_output_bow.mm.index
-rw-r--r-- 1 pi pi    46458890  5月 13 08:17 wiki_en_output_tfidf.mm
-rw-r--r-- 1 pi pi       27274  5月 13 08:17 wiki_en_output_tfidf.mm.index
-rw-r--r-- 1 pi pi      131400  5月 13 08:12 wiki_en_output_wordids.txt.bz2

続きを読む



【追記 2015/5/12】
これは結果的に時間をロスした失敗のログ。RaspberryPi2 で、そのままやるのは無知なことだった。

後学のために、とりあえずログを残す。

---------

以下にインストールされた gensim の 
 /usr/local/lib/python2.7/dist-packages/gensim/scripts/make_wiki.py 
を使って、本のとおり以下のコマンドを実行する。
$ python -m gensim.scripts.make_wiki enwiki-latest-pages-articles.xml.bz2 wiki_en_output

生成されるのは3つのファイル。OUTPUT_PREFIX は、wiki_en_output。
---------
This actually creates three files:

* `OUTPUT_PREFIX_wordids.txt`: mapping between words and their integer ids
* `OUTPUT_PREFIX_bow.mm`: bag-of-words (word counts) representation, in
  Matrix Matrix format
* `OUTPUT_PREFIX_tfidf.mm`: TF-IDF representation
---------


超、悪戦苦闘の巻!
インデックス化できない。RaspberryPi2 / Raspbian 3.18(3.18.7-v7+ #755)

開始:2015-05-05 11:09:05,672
終了: zombie化? 5/6 10:40に強制終了。rebootして再スタート!

$ python -m gensim.scripts.make_wiki enwiki-latest-pages-articles.xml.bz2 wiki_en_output
2015-05-05 11:09:05,672 : INFO : running /usr/local/lib/python2.7/dist-packages/gensim/scripts/make_wiki.py enwiki-latest-pages-articles.xml.bz2 wiki_en_output
2015-05-05 11:09:06,955 : INFO : adding document #0 to Dictionary(0 unique tokens: [])
: 

5/6 08:30頃のログを見て、あれ? 今、10:30。。。こんなに間が空くか? top コマンドで確認。やっぱり動いてない。。。。がぁーーーーん。。。強制終了して、再スタート。



まただ。途中で止まってる。36時間動かしてたのに。。。。
開始:2015-05-06 10:46:58,613
終了: zombie化 05-07 22:30 ふたたび。。。

$ sudo python -m gensim.scripts.make_wiki enwiki-latest-pages-articles.xml.bz2 wiki_en_output
2015-05-06 10:46:58,613 : INFO : running /usr/local/lib/python2.7/dist-packages/gensim/scripts/make_wiki.py enwiki-latest-pages-articles.xml.bz2 wiki_en_output
2015-05-06 10:46:59,998 : INFO : adding document #0 to Dictionary(0 unique tokens: [])

 
2015-05-07 22:30:57,272 : INFO : resulting dictionary: Dictionary(2000000 unique tokens: [u'tripolitan', u'ftdna', u'fi\u0250', u'soestdijk', u'phintella']...)
2015-05-07 22:30:57,957 : INFO : adding document #2830000 to Dictionary(2000000 unique tokens: [u'tripolitan', u'ftdna', u'fi\u0250', u'soestdijk', u'phintella']...)


原因は?


続きを読む



20newsgroup をダウンロード

http://qwone.com/~jason/20Newsgroups/

20news-bydate.tar.gz
 
- 20 Newsgroups sorted by date; duplicates and some headers removed (18846 documents)


The second ("bydate") is sorted by date into training(60%) and test(40%) sets, does not include cross-posts (duplicates) and does not include newsgroup-identifying headers (Xref, Newsgroups, Path, Followup-To, Date).


このデータには、本にかかれている 379 や metadata は無い。metadata が無いと load_mlcompが使えないようだ。アカウント登録して mlcomp.org からデータ取得することも考えたが、このデータを活かしてすすめてみる。

生データは、train と test に分けて取得できたので、load_filesを使ってみる。
 
#dataset = sklearn.datasets.load_mlcomp("20news-18828", "train",
#                                        mlcomp_root=MLCOMP_DIR,
#                                       categories=groups)

dataset = sklearn.datasets.load_files("/home/pi/bmlswp/data/20news-bydate-train"
,categories=groups)



ここを直して、
 $ python rel_post_mlcomp_01.py 
を動かした。

 
 



第3章の目的:データだけからパターンを見つけ出す。
      課題:Q&Aサイト運営で、ユーザの「質問」と同じような過去の「質問」「回答」を提示する。

【おさらい】
 1.テキストデータを bag-of-word に変える。
  CountVectorizer を使って、単語の出現回数を数えて、ベクトル表記する。

 2.新しい文書と既存の文書を類似度を計算する。
  norm関数でユークリッド距離を測る。



この続き。正規化するところから。


(1)単語の出現回数ベクトルを正規化する。

dist_raw を dist_norm に変える。
----------------------
# norm 
def dist_raw(v1, v2):
    delta = v1 - v2
    return sp.linalg.norm(delta.toarray())

# norm version up
def dist_norm(v1, v2):
    v1_normalized = v1 / sp.linalg.norm(v1.toarray())
    v2_normalized = v2 / sp.linalg.norm(v2.toarray())
    delta = v1_normalized - v2_normalized
    return sp.linalg.norm(delta.toarray())
----------------------


(2)重要度の低い単語を取り除く:stop word

処理の対象外の単語(stop word)を考慮する。例に習って english を設定。予め用意されているのはこの englishのみ。他は list化するしかないようだ。

----------------------
#vectorizer = CountVectorizer(min_df=1)
vectorizer = CountVectorizer(min_df=1,stop_words='english')
----------------------


(3)語形の変化に対処する:stemming

ここからダウンロードしたrel_post_01.py を使う。
nltk.stem が import できないと言う。
$ python rel_post_01.py 
Traceback (most recent call last):
  File "rel_post_01.py", line 20, in <module>
    import nltk.stem
ImportError: No module named nltk.stem
 
本のとおり、nltk(自然言語処理用ライブラリ) を入れる。

 $ sudo pip install -U nltk
 

今度は、別のエラー。
$ python rel_post_01.py 
Traceback (most recent call last):
  File "rel_post_01.py", line 43, in <module>
    min_df=1, stop_words='english', charset_error='ignore')
TypeError: __init__() got an unexpected keyword argument 'charset_error'

ググる。StemmedTfidfVectorizer が、CountVectorizer、TfidfVectorizer を継承しているとして、scikit learnでの、この2つの関数のパラメータに charset_error が見当たらなかった。
charset_error を decode_error に変えると動いた。
 

第3章クラスタリング:関連のある文章を見つける

目の前にあるデータだけからパターンを見つける方法を学ぶ。本の例では、Q&Aサイトでユーザがした質問と同じような過去の質問を選ぶことを行う。

本章の前半はgitからダウンロードした中にないので、自分で手打ちする。それが普通か。

../data/toy に。01.txt〜05.txt の5つのテキストファイルを置いた。

$ cd ../data/toy
$ cat *
This is a toy post about machine learning. Actually, it contains not much interesting stuff.
Imaging databases can get huge.
Most imaging databases safe images permanently.
Imaging databases store images.
Imaging databases store images. Imaging databases store images. Imaging databases store images.



準備を整えて、以下を動かすと、、、

$ more ch03-1.py 
import os
import sys
import scipy as sp

DIR = r"../data/toy"
posts = [open(os.path.join(DIR, f)).read() for f in os.listdir(DIR)]
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(min_df=1)

print(vectorizer)




min_df はなに?って怒られる。

$ python ch03-1.py 
Traceback (most recent call last):
  File "ch03-1.py", line 8, in <module>
    vectorizer = CountVectorizer(min_df=1.0)
TypeError: __init__() got an unexpected keyword argument 'min_df'
$


ググってみると、どうも sklearnの version が低いせいかも。

$ python
Python 2.7.3 (default, Mar 18 2014, 05:13:23) 
[GCC 4.6.3] on linux2
>>> import sklearn
>>> sklearn.__version__
'0.11'
>>> 
 

versionを上げてみる。

$ sudo pip install -U scikit-learn

$ python
Python 2.7.3 (default, Mar 18 2014, 05:13:23) 
[GCC 4.6.3] on linux2
>>> import sklearn
>>> sklearn.__version__
'0.16.1'
>>> 


$ python ch03-1.py 
CountVectorizer(analyzer=u'word', binary=False, decode_error=u'strict',
        dtype=<type 'numpy.int64'>, encoding=u'utf-8', input=u'content',
        lowercase=True, max_df=1.0, max_features=None, min_df=1,
        ngram_range=(1, 1), preprocessor=None, stop_words=None,
        strip_accents=None, token_pattern=u'(?u)\\b\\w\\w+\\b',
        tokenizer=None, vocabulary=None)

確かに動いた。

新しい文書(new_post= "imaging databases")と 既存の文書(01.txt〜05.txt)のユークリッド距離を計算し、既存文書との類似度を計算する。


$ more ch03-1.py 
import os
import sys
import scipy as sp

DIR = r"../data/toy"
posts = [open(os.path.join(DIR, f)).read() for f in os.listdir(DIR)]
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(min_df=1)

x_train=vectorizer.fit_transform(posts)
num_samples, num_features=x_train.shape
print("#samples: %d, #features: %d" % (num_samples, num_features))

print("--------------------------------------------\n")
print(vectorizer.get_feature_names())
print("--------------------------------------------\n")

new_post = "imaging databases"
new_post_vec=vectorizer.transform([new_post])

print(new_post)
print(new_post_vec)
print(new_post_vec.toarray())

print("--------------------------------------------\n")

# norm 
def dist_raw(v1, v2):
    delta = v1 - v2
    return sp.linalg.norm(delta.toarray())


#
best_dist = sys.maxsize
best_i = None

for i in range(0, num_samples):
    post = posts[i]
    if post == new_post:
        continue
    post_vec = x_train.getrow(i)
    d = dist_raw(post_vec, new_post_vec)

    print("=== Post %i with dist=%.2f: %s" % (i, d, post))
    print(x_train.getrow(i).toarray())

    if d < best_dist:
        best_dist = d
        best_i = i

print("*** Best post is %i with dist=%.2f" % (best_i, best_dist))

$

実行すると。

$ python ch03-1.py 
#samples: 5, #features: 24
--------------------------------------------

[u'about', u'actually', u'can', u'contains', u'databases', u'get', u'huge', u'images', u'imaging', u'interesting', u'is', u'it', u'learning', u'machine', u'most', u'much', u'not', u'permanently', u'post', u'safe', u'store', u'stuff', u'this', u'toy']
--------------------------------------------

imaging databases
  (0, 4) 1
  (0, 8) 1
[[0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
--------------------------------------------

=== Post 0 with dist=4.00: This is a toy post about machine learning. Actually, it contains not much interesting stuff.

[[1 1 0 1 0 0 0 0 0 1 1 1 1 1 0 1 1 0 1 0 0 1 1 1]]
=== Post 1 with dist=1.73: Imaging databases can get huge.

[[0 0 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
=== Post 2 with dist=2.00: Most imaging databases safe images permanently.

[[0 0 0 0 1 0 0 1 1 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0]]
=== Post 3 with dist=5.10: Imaging databases store images. Imaging databases store images. Imaging databases store images.

[[0 0 0 0 3 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0]]
=== Post 4 with dist=1.41: Imaging databases store images.

[[0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]]
*** Best post is 4 with dist=1.41

で、Post 3 と Post 4 で同じ単語が3回繰り返されているときの評価(dist)をもうちょっといけてる感じにかえるために、次に正規化する。


ここまでやってきて、本に載っているプログラムや出力結果の値は、いまいち信用できないようだ。
その点を踏まえて、しっかり自分の頭で理解していかないといけない。その意味で良い教科書だ。

 


この本の続き。クラス分類(classification)


初めにサンプルデータを使って、データを可視化してみる。

figure1.py を実行すると 本の図 2-1 にあるグラフが生成される。
本の pythonコマンドと figure1.py のコマンドとは若干異なるが、本質は同じなので
気にせず進める。



次に、「2.3 より複雑なデータセットとクラス分類」で、

小麦データセット(seeds data set)を

http://archive.ics.uci.edu/ml/

から落としてきた。ファイル名を seeds.tsv にして、../data/ ディレクトリに置いた。

以下のエラーがでた。


$ python seeds_threshold.py 
Traceback (most recent call last):
  File "seeds_threshold.py", line 12, in <module>
    features, labels = load_dataset('seeds')
  File "/home/pi/bmlswp/ch02/load.py", line 27, in load_dataset
    data.append([float(tk) for tk in tokens[:-1]])
ValueError: could not convert string to float: 
$  

これは、seed.tsv ファイルが nan を含んでいると見えるらしい。
seed.tsv ファイルを見ると、単に tab がずれている箇所がいくつかあった。これを修正したら動いた。


git からダウンロードした ch02 のサンプルプログラムの中身を見ながら、本を読み進めていく。


気になっていた O'REILLY 「実践 機械学習システム」をやっと買った。




これからちょっとずつ読み進めていこう。
まずは「第1章 Pythonではじめる機械学習」 から。

この本は、Pythonのライブラリである Numpy、Scipyを用い、scikit-learn で機械学習を学びます。 

準備として、


ソースコードを利用

この ch01 配下の .py をダウンロードして使う。

 ch01/
  data/
    web_traffic.tsv 
  gen_webstats.py
  analyze_webstats.py
  performance_test.py 


現状(2015/4/27時点)、このweb_traffic.tsv は、
1.5.1 データを読み込む で紹介されている不適切な値 nan は含んでいない。

サンプルプログラムの .py ファイル内の __file__ は、実際の環境に合わせて編集するべきものと、勝手に思い込んでいたが、実際には .py を実行するディレクトリに data フォルダを作ってやれば、そのまま実行できた。


analyze_webstats.py の実行中に、polyfitで warning が出たが、とりあえず実行は終わり png ファイルも生成された。

>>> f100 = sp.poly1d(sp.polyfit(x, y, 100))
/usr/lib/pymodules/python2.7/numpy/lib/polynomial.py:560: RankWarning: Polyfit may be poorly conditioned
  warnings.warn(msg, RankWarning)
>>> 

SciPyの numpy.polyfit

に、この原因について、
High-order polynomials may oscillate wildly:
と書かれている。

境目となるのは、コマンドラインから確認すると、

>>> f33 = sp.poly1d(sp.polyfit(xp, y, 33))
>>> f34 = sp.poly1d(sp.polyfit(xp, y, 34))
>>> f35 = sp.poly1d(sp.polyfit(xp, y, 35))
/usr/lib/pymodules/python2.7/numpy/lib/polynomial.py:560: RankWarning: Polyfit may be poorly conditioned
  warnings.warn(msg, RankWarning)
>>> 

であった。analyze_webstats.py の f100 の 100 を 30 に下げて、.py を実行。 あれ? 変わらず。
30 をさらに下げていくと、結局、後半の polyfit は 10 でも引っかかるようだ。


で、肝心の最適なモデルを決めることについて、本では 次数 2 のモデルが誤差が最小となっているが、analyze_webstats.py を実行する毎に変化する。次数 1 のときもあれば、次数 10 のときもある。

あれ? なんか変だな。

とりあえず、ひと通り進めてから考えよう。第1章でコケてるわけにはいかない。
 

↑このページのトップヘ