2016年2月21日日曜日

AWSを使ってみる:Deep-learningのために

このところ、Deep-learningの勉強をしているんですが、サンプルでとにかく処理時間のかかるものがあります。
chainerやTensorFlowは64bit環境が前提(chainerはそうでもないんですが、そっちのほうが望ましい)なので、自宅のLinuxは32bitでアウト。そうなるとMac OSXになるのですが、ノートPCなので電源つなげっぱなしはバッテリーへのタメージから考えると避けたい。
自宅のLinuxを64bitにしてもいいんですが(古いPCですが、Core2なんで一応64bit OSはインストールできます)、せっかくなのでAWSを試してみます。

お試しなので、作れるインスタスは小さな"t2.micro"になります。(64bit redhatですが、メモリが1GBしかありません)それでも、まあchainerは動くだろうと、インストールを始めますが色々問題が出ました。

1.rootのパスワードは何?
まず、pipをインストールしようとしたらエラーがでました。まあ、この手のものはroot権限が必要ですから、sudoコマンドを使おうとすると、passwdを聞かれました。でも、AWSでEC2にインスタンスを作ったばかり、passwdは何?最初、AWSのアカウントのパスワードかと思いましたが、初期状態ではpasswdが設定されていないので、

$ su -
$ passwd

で、rootのパスワードを設定してやるものなんだそうです。

2.chainerのインストールができない(gccが必要)
さて、pipのインストールができたので、それでchainerをインストールしようとすると、エラーがでます。はじめは何が問題なのかわからなく、色々ぐぐってみました。でもどれも見当はずれ。よくよくエラーメッセージをみると、gccコンパイラがないと・・・
そうです、AWS EC2のインスタンスでは最低限のものしか入っていなくて(でもpythonは入っていた)、gccがなかったのです。

$ sudo yum install gcc
$ sudo yum isntall gcc-c++  ←これわかり難い
$ sudo yum install gcc-gfortran ←これも通常の名前と違うみたい
$ sudo yum install python-devel  ←これが一番悩んだ。pipで、Python.hがないと怒られた。

と、いろんな開発用パッケージをインストールしないといけません。AWS内ではyumリポジトリがAmazon専用のものが設けてあるのは知っていましたが、なんかパッケージ名が違うのか?ググったものと”微妙”にパッケージ名が違い困りました。(何かパッケージ名が微妙に違う気がしますが、これは自分が数年間RedHatから遠ざかり、Ubuntuを使い続けたからかもしれません)

3.virtualenv環境でchainerが動かない
これはまだ原因がわかりません。上記、各種パッケージのインストールをしたあと、virtualenv環境下でchainerをインストールしたのですが、なぜかnumpy等のパッケージが見つからないと怒られます。しかたなく、virtualenvの使用をあきらめるとうまくいくので、色々試行錯誤してるうちにどこかで間違ったかもしれません。

と、かなりとまどいました。とりあえず、今回はここで力つきました。AWSでDeep-learningを試してみるのは次にします。

2016年2月20日土曜日

TensorFlowで学習プログラム

TensorFlowで学習するプログラムを作ってみました。
一番単純な、2入力1出力です。(論理積を学習させます)
以前、chainerとかのサンプルも探しましたがどれも学習結果を使う所が見つかりませんでした。TensorFlowだとダイレクトにプログラムしないといけないので、その辺りは楽にできました。

とりあえず、サンプルです。


# -*- coding: utf-8 -*-

import tensorflow as tf
import numpy as np

# 入力データの定義 4行2列(データの定義方法がchainerとは違うようです)
# x_data = [
#   np.array([0., 0.]),
#   np.array([0., 1.]),
#   np.array([1., 0.]),
#   np.array([1., 1.])
# ]
x_data = np.array([
  [0., 0.],
  [0., 1.],
  [1., 0.],
  [1., 1.]
])

# 結果データの定義(4行1列)
# y_data = [
#   np.array([0.]),
#   np.array([0.]),
#   np.array([0.]),
#   np.array([1.])
# ]
y_data = np.array([
  [0.],
  [0.],
  [0.],
  [1.]
])


# 機械学習で最適化するWとbを設定する。Wは4行2列のテンソル。bは4行1列のテンソル。
W = tf.Variable(tf.random_uniform([4, 2], -1.0, 1.0))
b = tf.Variable(tf.zeros([4, 1]))
y = W * x_data + b

loss = tf.reduce_mean(tf.square(y_data - y))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)

# 学習を始める前にこのプログラムで使っている変数を全てリセットして空っぽにする
init = tf.initialize_all_variables()

# Launch the graph.(おきまりの文句)
sess = tf.Session()
sess.run(init)

# 学習を1000回行い、100回目ごとに画面に学習回数とWとbのその時点の値を表示する
for step in xrange(1001):
    sess.run(train)
    if step % 100 == 0:
        print step, sess.run(W), sess.run(b)

# 学習結果を確認
x_input = np.array([
  [0., 0.],
  [0., 1.],
  [1., 0.],
  [1., 1.]
])

y_res = tf.Variable(tf.zeros([4, 1]))
y_res = W * x_input + b
print sess.run(y_res)
# 4行1列の結果を期待しているのだが、4行2列になってしまう? 
# 学習が十分進めば、どちらの列も同じような結果になるからいいか。
print sess.run(b)

最後に、学習結果を確認しています。結果はこうなります。(一応、期待通りの結果になりました)
[[  0.00000000e+00   0.00000000e+00]
 [ -2.62142518e-23   1.62012971e-23]
 [  7.70256410e-23  -1.24630115e-22]
 [  9.99999881e-01   1.00000012e+00]]
[[  0.00000000e+00]
 [ -2.62142518e-23]
 [ -1.24630115e-22]
 [  6.69862151e-01]]
最後の、変数y_resとbの出力だけを貼り付けました。 どうしてもまだ理解できないのが、y_resの計算結果は4行1列になるはずなんですが、4行2列になってしまいます。(代入する直前でy_resを4行1列で定義しても上書きされてしまいます。bは4行2列でも、4行1列でも構わないようです)ただ結果をみると各行の値はどちらの列をとっても同じような値なのでよさそうです。 まだ深層学習の理論的な本を買って読み始めた所でよくわかっていませんが、TensrFlowの方がPrimitiveにプログラムしなければいけない分、直感的にわかります。(でもなんとなく、chainerの方がこの後進めていくのによさげな気もしますので、しばらく悩みます)

2016年1月31日日曜日

Mac OSX El Capitanの日本語入力について

MacのOSX、El Capitanにしてみました。(いつも通り、しばらく様子を見ていました。brewとかなんだかんだ入れているので、いきなりは怖いです)

こちらはWindowsほど劇的な変化はありませんでしたが、使い勝手で一番戸惑ったのが「日本語入力」です。デフォルトが自動変換になってました。Google日本語入力でもありましたが、強力な予測変換で、ユーザーが変換の意思を「スペースキー」を押さなくてもいいようにしてくれるんですが、自分的にはこれ大嫌いです。

OSが勝手に漢字変換を、意図しないタイミングでしてしまうのと、その瞬間どうしてもPCの動きが止まります。よどみなくタイピングしている最中に、意図しない漢字変換されてしまうとものすごいストレスを感じます。もうすぐに「自動変換」をオフしてしまいました。
MSとかApple、Googleはこの辺どう考えているんだろう?仕事でPC使っている人間には、どう考えても今の予測変換の実装はマイナスにしかなりません。(まだ、ガラケーやスマホの予測変換みたに、別領域に変換候補がでてきて、ユーザーが必要ならそれを選ぶ方式なら我慢できますが、入力しているカーソル部分で強制的に第一候補を表示してしまうのは困る。)変換候補を別領域に表示、選択はファンクションキーがいいと思うんだが、どうなんだろう?日本語意外の他の「非英語圏」のUIはどんな使い心地なのか気になります。

windows10について

自分のメインPC(Core2 Quad win7 64bit)を何時かwin10にしないといけないと思いながら、タイミングを計ってきました。他のPCは特に考えずに適当に更新をトライしてましたが、こいつだけは銀行のHP見たりするヤツなんで慎重です。
win10も発表から何度かUpdateがされ、金融機関から最初は出ていた更新を待ってくれという警告もなくなったので、そろそろ試してみるかとやってみました。

最初に感じたのが、とにかく時間がかかること!まあ、OSのメインバージョンの更新なんだから、当たり前なんですが問題は更新後です。
自宅のPCで、EPSONのノートPC(Win7)がWin10に更新できませんでしたが(最後に問題が発生しました。HDDのパーティションの切り方が特殊なようです)、プリンタ・スキャナのドライバが最初は対応してくれず、ドライバの再登録などして何とか使えるようになりました。
後、更新後しばらくは「無茶苦茶遅い!」と感じました。Win10にしたら快適になると聞いていたんですが、「ダメじゃん」という感じ。調べてみると、暫くの間は「自動メンテナンス」で調整をする時間が必要なようです。数時間から1日くらいPCの電源入れっぱなしにして、MSとデータ交換しないといけないようです。

また、安定しても基本認証にMSとインターネットで通信しまくる仕様のようで、パフォーマンスモニタとか見てると、いつもネットワーク通信しています。そうそう、PCへのログイン・アカウントがそれまでのから、強制的にMSのアカウントに切り替えられてしまいました。(設定の途中で、MSのアカウント入力をさせる箇所があり、そこで入力してしまったせいでしょう)これではネットワークがない状況だとどうなるんだろう、という感じです。(最初から、ネットワークなしの状況で設定してればいいんでしょうが、一旦ネットワークがある状況で設定してしまうと、その後はタイムアウト待ちをするしかない?)

前回のWin8がひどい出来だったので、ほとんどWin7の操作に戻った感じですが、全体的に「常時オンライン」が前提のOSになってしまったようです。これはこれで、鬱陶しい!反応が鈍くなるんですよ。しかし、セキュリティの事を考えたらWin10に更新せざるをえません。付き合い方を考えるしかありませんね。

後、困ったのがウイルス対策ソフトのDefenderです。Google Drive等からファイルをDLすると自動的にスキャンしているようなんですが、時間が10~20秒くらいかかり、その間ファイル名の変更ができません。(Defenderがファイルをつかんでいるから)ちょっとこれにはまいりました。何とかなりませんかね。(時間がかかりすぎ。もしかしてパターンチェックか、データをMSに送っているのか?)

2016年1月6日水曜日

python:virtualenvメモ

ここのところchainer, TensorFlowとpythonを使ってみることが多かったのですが、他の方はよく

$ virtualenv

というコマンドを使って、そこに環境を構築していました。名前からすると「何らか」の仮想環境を構築するものなのでしょう。ちょっと調べてみると、python専用のライブラリを「試しで」作るときに、メインの環境にダメージを与えないようにするものでした。要は、VMwareやDocker(こっちの方が間隔的に近い)の様な仮想環境ですが、python限定なのが特別です。(ただ、試しにやってみたら、頑張れば、その中でのみ連携して動くJavaやc++のライブラリ、プログラムも入れれそうな感じです。ただ、Javaやc++のライブラリが特別な別のパッケージを要求していると、かなり大変そう。)

1.インストール
pipコマンドが使えるようになっているなら簡単です。

$ pip install virtualenv

これだけです。(中身は10行くらいのpythonスクリプトです)

2.仮想環境の構築
以下のコマンドだけです。

$ virtualenv testenv

これで、testenv/というディレクトリが作成され、配下に以下のディレクトリが作られます。

bin/ include/ lib/ local/

ここに当該OS環境におけるpython環境がコピーされてきます。(後で追加したpackage等は入っていません。使いたい場合はここで再構築です。)

3.仮想環境の実行
この環境でpythonのあるpackageを試してみたくなったら、以下の手順になります。

$ cd testenv
$ source bin/activate

この"activate"は先ほどコピーされたbin/以下に入っており、これを実行することにより、pythonバイナリ、ライブラリはtestenv/以下のものを参照するようになります。(プロンプトにtestenvの文字が追加され、仮想環境下で動いていることがわかります)
つまり、この環境下で"pip"コマンドでインストールすると、testenv/以下にインストールされることになり、本体OSのpythonには影響を与えません。

4.仮想環境の終了
以下のコマンドです。

$ deactivate


5.仮想環境の削除
お試しが終了して、必要なくなったらディレクトリ毎削除すればOKです。

$ rm -rf testenv/


と、非常にお手軽に色々なpythonのパッケージを試すことができます。


2015年12月30日水曜日

TOPPERSにトライ

自分は組み込み系のプログラムを作る仕事はほとんどしたことがないのですが、最近IoTが騒がれており、Raspberry Piもいじっているので小型のRTOS(リアルタイムOS)に興味がでてきました。
ただ、RTOSというのは通常特殊なメーカから販売されている高価なものしか使ってみたことがなく(しかも組み込み用途では使ったことありません)、オープンソースで手頃なものというとITRONになります。
TOPPERSというITRONの実装がかなり有名なようで、ぐぐると結構かかります。調べてみると、純粋なITRONの仕様から少し拡張されているようですが、活動が2015年現在でも活発に行われており、勉強用にLinux/Windows上でも動作できるエミュレータがついているとか。いきなりRaspberry Piにインストール、という前にちょっと勉強がてらLinux上で動かすのにトライしてみました。
(注:結論を先に述べておきますが、結局失敗しました。どうもLinux上のエミュレータの実装が、かなり古いLinux(おそらくkernel2.6系?)の時から更新されていないようで、今のUbuntu等のkernel3.x系で動かすのはかなり困難が伴うようです

1.TOPPERSのDL
TOPPERSのHP(http://www.toppers.jp/)に行ってみると、様々なバージョンがあるのにびっくりしました。各バージョンがどんな内容かひと通り読むだけで結構時間がかかりましたが、とりあえずスタンダードな以下をDLしてきました。

・TOPPERS/JSP-1.4.4.1

2.TOPPERSのビルド
以下のコマンドでLinuxエミュレータ上で動くものができるようです。(Linuxでは、sample1というプログラムが動くそうです)

$ ./configure -C linux
$ make depend
$ make

ところが当然ながら問題がでてきます。

(1)configureのperlスクリプトでエラーがでる。
configure:40lineで以下の行があります。

require "getopt.pl";

これ、perlのスクリプト起動時のオプションを拾ってくる機能拡張モジュールらしいんですが、現在では使われておらず、以下の様にするようです。

use Getopt::Std;
あと、Getoopt()→getopt()にする。

TOPPERSのMLの2012年にこの指摘があり、提案するとありましたがいまだに採用されていないようです。他の箇所にも同じような所がありましたが、修正してconfigureは通しました。

(2)make dependで、cfg/cfgがないと怒られる。
TOPレベルにcfg/というディレクトリがあるのですが、どうもここのビルドが実行されていないようです。make dependの段階でこれが必要ということは、configureの時点でアーキテクチャに応じてcfg/cfgがビルドされていることを期待しているんでしょうが、先の(1)の修正だけではまだ問題があったようです。
とりあえず手動でビルドして、cfg/cfgを作ります。
→これは、動かしたいTASKの登録をここでしておくので、先に設定をしてビルドしておくものだと判明。

(3)makeでエラー
さて、(2)までの修正でmake dependはパスしました。やっとビルドですが、以下の様なエラーがでてきました。

In file included from ../kernel/task.c:47:0:
../config/linux/cpu_context.h: In function ‘activate_context’:
../config/linux/cpu_context.h:74:35: error: ‘JB_PC’ undeclared (first use in this function)
     ((int *) &(tcb->tskctxb.env))[JB_PC] = (int) activate_r;
                                   ^
../config/linux/cpu_context.h:74:35: note: each undeclared identifier is reported only once for each function it appears in
../config/linux/cpu_context.h:75:35: error: ‘JB_SP’ undeclared (first use in this function)
     ((int *) &(tcb->tskctxb.env))[JB_SP] = (int)(((VB *) tcb->tinib->stk) +

何のことやらさっぱりですが、どうも自分の環境のライブラリには、"JB_PC", JB_SP"の定義がない、と怒られています。
そもそも、これらのdefineが何なのかぐぐってみると、cの関数で、setjmp()/longjmp()のための定義とのことでした。それらは本来以下の場所に定義されているようです。

/usr/include/setjmp.h
/usr/include/bits/setjmp.h

一つ目が2つ目をincludeしており、そこが肝心な部分なんですが、自分の環境(Ubuntu-14.04)ではそもそも2つ目のincludeが位置が違い、内容も大幅に変わっていて、JB_PC/JB_SPとかのdefineがありません。
bits/setjmp.hの定義場所が、CPUのアーキテクチャ毎のところになっていました。そもそも、このsetjmp()/longjmp()が何者なのかですが、c++等で例外処理にthrow→catchが使われていますが、cの時代にはこれが使われていたようです。つまり、ある関数を実行中(これが大事!)にエラーが発生したことを検知した場合、強制的に別のエラー処理用の関数にジャンプする関数だそうです。
かなりやばい系の関数ですが、当然その実装のためには様々なCPUのレジスタの退避とかしないと、エラー処理なんてできません。kernel2.x系の頃は、なんとかc言語だけで実装していたのを、kernel3.x系になったところでCPUアーキテクチャ別にしたようです。(性能とか、完全な動作を考えるとまともな考えですね。)
doc/linux.txtを見てみると、kernel2.2/glibc2.1の頃に作られた模様...、ちょっとこれはお手上げです。(・_・)


さてそうなるととりあえず自分ではお手上げの状態です。自分はc言語で、setjmp()/longjmp()を使ったことないので、既存のエミュレータをどう改修したらいいかわかりません。
自分のところにはまだ別の環境があるので、そちらで動かないか試してみます。


PS@20151231
自分の持っているVMPlayerの環境に、CentOS4と古いバージョンがありました。これで試してみると、

・(1)の問題は発生しません。やはりPerlの古い使い方のようです。
・makeで別の問題が発生しました。
 ../config/linux/tool_config.h:70: undefined reference to `software_term_hook'
ぐぐってみると、2007年に同じ問題にぶつかった人がMLに残していましたが、問題の箇所の関数はjsp-1.4.2のころは全部コメントアウトしてあったのが、jsp-1.4.3からコメントアウトが外されていて、エラーがでるようになったとのこと。別途、関数定義例があり、それを使ってビルド終了。

サンプルの、./jspが動くようになりました!ただコマンドをシリアルから入力することになっていますが、Linuxエミュレータ上で./jspプロセスのシリアルにどうやってつないだらいいのかわかりません。ttyで送ってみましたがダメでした。
まあ、とりあえず動かせる環境はできたんで、後はこれで勉強してみます。



2015年12月26日土曜日

gitによる開発に関して:特定部分を別branchで管理し、master等にコピーしたい

最近、悩んでいるのがgitの操作方法についてです。しかもやりたいことが少し特殊です。

・プログラムの開発をしているが、異なるbranchで開発しているもののうち、自分の担当している部分だけmasterに持ってきて(コピー)、全体の試験がしたい

通常ならば、branch間でmergeすればいいんですが、そうすると自分が使っているdevelop branchにある別のフォルダの内容がmasterと完全に別内容にしているため、それができない!
本来なら、リポジトリのディレクトリ設計の時に考慮しておくべきことなんですが、それに失敗した例です。ただ開発が最終局面にきていて、いまさらリポジトリの再設定をしてしまうと、これまでの各ファイルの改定履歴がリセットされてしまいます。(git等のバージョン管理システムではよくあることですが、ファイルのディレクトリの位置を変えただけでも、当該ファイルの履歴が消えてしまいます。せいぜい、当該ファイルが移動されたよ、というログが残る程度です。subversionは特別に履歴を引き継ぐオプションがあるようですが、特別扱いのようです。詳細は後の雑談で。)開発が結合試験に入っているため、ログが消えるのはかなり痛いです。

開発が終わってしまえば、ログが消えてもまだ我慢できますが、このフェーズではきついです。mergeできなくてもコピーだけでもできればいい・・・、最後はbranchを切り替えて、一旦別の場所にコピーしておいて、再度master branchに切り替え、(手動で)コピーしようかと考えました。色々とぐぐってみると、かなりトリッキーな技があるようですが、最終的に以下のコマンドで可能なことがわかりました。

$ git branch master
$ git checkout develop /home/hoge/git/repo/A/B
                    (branch名) (path名:フルパスで!)

これでdevelop branchのBディレクトリ以下のファイルがmaster branchのBディレクトリ以下にコピーされてきます。(master, developともrepo/以下のディレクトリ構造は基本的に同じはずですから、コピー元を規定するだけで問題ないはずです。万一、構造が変わっていたりすると・・・、ちょっと考えないと。)もちろん、modifyのstatusになりますので、commitとしとくなりしとかないといけません。(当然、ログには「developからコピーしたよ」等入れておきましょう)

注:上記checkoutではpath名をフルパスで規定しています。ぐぐったサンプルでは如何にもリポジトリのtopからのpath名と推測できるような書き方がしてあるものばかりでしたが、どうもフルパスが必要なようです。

具体的に例を示します。

1.gitリポジトリの作成

$ mkdir git/repo
$ cd git/repo
$ git init

2.リポジトリの中身を作る
今回は以下の様な階層を作ってみました。(詳細なコマンドは省略します)

A/ A.txt
     B/ B.txt
          D/ D.txt
     C/ C.txt

Aディレクトリのあるところに、".git"があります。各ディレクトリにあるテキストファイルには以下の様なテキストが入っています。(注:赤字の部分を別branchからコピーしてきます。ちなみに、B/とC/は同じA/以下の階層にいます。)

A.txtサンプルのテキスト
master branchのファイル

最初にファイル名を入れ、後はbranch名を入れてあります。(もちろん、この後commitしておきましょう)

3.develop branchの作成

$ git checkout -b develop

これで全く同じ内容でdevelop branchが作成され、develop branchに移動しました。

4.develop branch内のファイルの変更
次に、後にmaster brachの特定の部分(Bディレクトリ以下)にこのdevelop branchの内容をコピーするので、それがわかるようにファイルの中身を変更します。具体的には、以下の様にします。(これを、A, B, C, Dの4個のtxtファイルに行います)

A.txtサンプルのテキスト
develop branchのファイル

5.master branchへの移動、develop branchの一部をコピー

$ git checkout master
$ git checkout develop /home/hoge/git/repo/A/B

2回めのcheckoutはbranchを移動しません。単にdevelop branchのBディレクトリ以下をmaster branchにコピーしてくるだけです。これにより、B.txtと配下にいるD.txtがコピーされます。git statusをしてみると、この2つのファイルがmodifiedだといってきて、各ファイルの内容は以下の様になっています。

B.txtサンプルのテキスト
develop branchのファイル


これで自分のメインの開発はdevelop branchで行い、結合試験の必要に応じてmaster branchにコピーすることができます。


雑談:
今回、gitのことを色々調べていて思ったのが、こういうリポジトリ管理ではリポジトリ間でも「部分的な」コピーはどうやっても行えないということです。よく考えてみると、一つのリポジトリは一つの目的を持って作っているのであり、その一部だけを(履歴つきで)持ってくるのはかなり危ないことだと気づきました。そもそもその「履歴」(ログ)は別のリポジトリ(環境)で開発中のことが記録されているので、それを別のリポジトリで見ても何の意味もないか、逆に勘違いの元になる可能性があります。
同じように、一つのリポジトリ内でも、ファイルの移動を行うだけで「履歴」が消えてしまいますが、これはファイルの位置が変わるということは、当該ファイルの(開発)目的が変わる場合がほとんどで
、昔の履歴は害になることが多いはずです。
本来は、そんなことのないようにリポジトリを設計する段階できちんと決めておくべき(将来の可能性・拡張性を考えて)なのですが、世の中万能の人間ばかりではないので、filter-branch等駆使して、強引にログを書き換えてしまう参考例がいくつかありました。
ただ、最初から別リポジトリで開発を進め、途中から一つのリポジトリ管理下に置くようにすることは認められているようです。
後、調べている最中に"git-new-workdir"というツールの紹介がありました。このコマンドを使ってbranch間のコピー(共有?)を設定すると、どちらのbranchで操作を行っても、相手のbranchに反映される上に、履歴もつくのだとか。一瞬これこそ求めていたものだと思いましたが、よく考えたらこんなの使いはじめると「多用」しそうで危ないツールだと思いました。