liblinear-ruby-swigを使って手書き数字を判別する1

今回は、liblinear-ruby-swigを使って手書き数字を判別する機械学習のプログラムを組んでいきたいと思います。
【liblinear-ruby-swigのインストール】
liblinear-ruby-swigを使うには以下のコマンドを実行して
sudo gem sources -a http://gems.github.com (you only have to do this once)
sudo gem install tomz-liblinear-ruby-swig
ソースコードの最初に
require 'rubygems'
require 'linear'
と宣言すれば大丈夫です。

【サンプルを動かす】
では早速作っていきましょう。
と言っても、一から書くのはなかなか至難の技・・・
そこであるサイトのコードを基にして、それを改良する形でソースコードを組んでいきます。
そのサイトはこちら
http://yshtak.tumblr.com/post/32271070401/ruby%E3%81%A7svm%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AAliblinear-ruby-swig
このサイトでは少し難しいですがliblinear-ruby-swigを使ったサンプルコードがあるのでこれを使います。(少し改良してあります)
libsvm.rb---------------

require "linear"

# types = [ 'L2R_LR', 'L2R_L2LOSS_SVC_DUAL', 'L2R_L2LOSS_SVC', 'L2R_L1LOSS_SVC_DUAL', 'MCSVM_CS', 'L1R_L2LOSS_SVC', 'L1R_LR' ] SVMの種類
# 0:L2_LR , 1:L2LOSS_SVM_DUAL , 2:L2LOSS_SVM , 3: L1L1LOSS_SVM_DUAL, 4: MCSVM_CS, ... 定義されている変数名

pa = LParameter.new
pa.solver_type = MCSVM_CS
pa.eps = 0.1
bias = 1
labels, samples = read_file("training_file")
sp = LProblem.new(labels,samples,bias)
model = LModel.new(sp,pa)

x = {1=>1,2=>0.1,3=>0.2,4=>0,5=>0} # テストしてみるデータ
model.predict(x)
puts x # どのラベルに分類されているかが出力される

model.save("sample01.model") # Modelファイルの保存
                                            • -

これを動かす際の注意点として、同じフォルダ内に「training_file」というファイルを作りそこに以下のような内容を記述しておいてください!(これがないと動きません。私はこれで3時間くらい止まってました・・・)

  1. 1 1:0.708333 2:1 3:1 4:-0.320755 5:-0.105023 6:-1 7:1 8:-0.419847 9:-1 10:-0.225806 12:1 13:-1
  • 1 1:0.583333 2:-1 3:0.333333 4:-0.603774 5:1 6:-1 7:1 8:0.358779 9:-1 10:-0.483871 12:-1 13:1
  1. 1 1:0.166667 2:1 3:-0.333333 4:-0.433962 5:-0.383562 6:-1 7:-1 8:0.0687023 9:-1 10:-0.903226 11:-1 12:-1 13:1
  • 1 1:0.458333 2:1 3:1 4:-0.358491 5:-0.374429 6:-1 7:-1 8:-0.480916 9:1 10:-0.935484 12:-0.333333 13:1
  • 1 1:0.875 2:-1 3:-0.333333 4:-0.509434 5:-0.347032 6:-1 7:1 8:-0.236641 9:1 10:-0.935484 11:-1 12:-0.333333 13:-1

動きましたか?とりあえず動いたなら成功です。
動かした結果このような出力が得れて
training_file: 5 samples loaded.
{1=>1, 2=>0.1, 3=>0.2, 4=>0, 5=>0}
かつ、フォルダ内にsample01.modelとかいうのが生成されたら大成功です。
次のステップに進みましょう。

【手書き数字のデータを取ってくる】
手書き数字に関する情報はこのサイトを参考にしました。
http://qiita.com/kenmatsu4/items/2d21466078917c200033
ここにあるコードはpythonですが、扱っているデータなどはcsvで問題なく扱えます。
ここに書いてあるように学習用のデータやテストデータなどはここにあります
https://www.kaggle.com/c/digit-recognizer/data
簡単な登録があります。(無料です)
ここの「train」の右側にある「.csv」をクリックしてダウンロードしましょう。
すごく時間がかかります。確か4万くらいデータがあるので。

とりあえず今回はここで区切ります。

liblinear-ruby-swigを使って手書き数字を判別する2

今回も、前回に引き続きliblinear-ruby-swigを使って手書き数字を判別する機械学習のプログラムを組んでいきたいと思います。
【サンプルコードの改良】
サンプルコードには今回は関係ないものとかが多いので簡単に整理します。
libsvm.rb----------

require "linear"

# types = [ 'L2R_LR', 'L2R_L2LOSS_SVC_DUAL', 'L2R_L2LOSS_SVC', 'L2R_L1LOSS_SVC_DUAL', 'MCSVM_CS', 'L1R_L2LOSS_SVC', 'L1R_LR' ] SVMの種類
# 0:L2_LR , 1:L2LOSS_SVM_DUAL , 2:L2LOSS_SVM , 3: L1L1LOSS_SVM_DUAL, 4: MCSVM_CS, ... 定義されている変数名

pa = LParameter.new
pa.solver_type = MCSVM_CS
pa.eps = 0.1
bias = 1
labels, samples = read_file("training_file")
sp = LProblem.new(labels,samples,bias)
model = LModel.new(sp,pa)

x = {1=>1,2=>0.1,3=>0.2,4=>0,5=>0} # テストしてみるデータ
puts model.predict(x)
                                      • -

簡単ですけどこんな感じに整理しておきます。
みたらなんとなくわかると思いますが、
sp = LProblem.new(labels,samples,bias)
この部分に必要なデータを与えることがポイントになっています。

csvファイルの読み込み】
機械学習において重要なのがデータをいかにプログラムに組み込むかという点である。
今回の最終目標は
sp = LProblem.new(labels,samples,bias)
この部分に
label:正解の配列
samples:ピクセルデータの配列
を渡すことである。
そのためにそれにあった配列を作成する。
整理しておいてなんですが、先ほどのコードを全部コメントアウトします。
面倒な方は一旦消してもいいです。
そして以下のようなコードを書いていきます。
libsvm.rb----------

require "linear"
require "csv"

label = []
data = []
load_data = []
cnt = 0;
CSV.foreach("train.csv") do |row|
load_data.push(row)
cnt = cnt + 1
if cnt == 5
break
end

end
load_data.shift #先頭の一行を削除

load_data.each do |load|
label.push(load.shift.to_i)
data.push(load.map(&:to_i))
end
p label
p data
                                      • -

これで、csvファイルからlabel(正解の数字)とそれに関するデータ(ピクセル)をそれぞれ配列に入れることができます。
無理やりbreakさせてるのは、すべてやると4万個ロードしてなかなか動かないし、結果も見づらいからです。
to_iやmap(&:to_i)などは、もともとのcsvファイルの情報は全部文字列なので数値に変換する必要があるため行っています。

【実際のコーディング】
libsvm.rb----------

require "linear"
require "csv"
# types = [ 'L2R_LR', 'L2R_L2LOSS_SVC_DUAL', 'L2R_L2LOSS_SVC', 'L2R_L1LOSS_SVC_DUAL', 'MCSVM_CS', 'L1R_L2LOSS_SVC', 'L1R_LR' ] SVMの種類
# 0:L2_LR , 1:L2LOSS_SVM_DUAL , 2:L2LOSS_SVM , 3: L1L1LOSS_SVM_DUAL, 4: MCSVM_CS, ... 定義されている変数名
# 
def train_loop(limit)
label = []
data = []
load_data = []
cnt = 0;
CSV.foreach("train.csv") do |row|
load_data.push(row)
cnt = cnt + 1
if cnt == limit
break
end

end
load_data.shift #先頭の一行を削除

load_data.each do |load|
label.push(load.shift.to_i)
data.push(load.map(&:to_i))
end
test_method(label,data)
end

def test_method(label,data)
load_test_data = []
label_test = []
data_test = []
CSV.foreach("mini_test.csv") do |row|
load_test_data.push(row)
end
load_test_data.shift #先頭の一行を削除

load_test_data.each do |load|
label_test.push(load.shift.to_i)
data_test.push(load.map(&:to_i))
end

pa = LParameter.new
pa.solver_type = MCSVM_CS
pa.eps = 0.1
bias = 1
sp = LProblem.new(label,data,bias)
model = LModel.new(sp,pa)

index = 0.0
success = 0.0
data_test.each do |test|
# puts "#{model.predict(test)}:#{label_test[index]}"
if model.predict(test) == label_test[index]
success = success + 1
end
index = index + 1
end
puts "トータル#{index}正解#{success}正答率#{success/index*100}%"
end

num = [100,200,500,1000,5000]
5.times{|i|
puts "学習数#{num[i]}"
train_loop(num[i])
}
                                      • -

MacでRubyのLIBSVMを使いたいあなたへ

今回は、Rubyを使って機械学習で有名であるlibsvm(svm)を使うということをしたいを思います。

と言っても、unix系の環境でのやり方は意外とネットにあって、逆にMac環境でlibsvmをインストールする方法が書いていなかったので紹介します。

macLIBSVMを使いたいんだけどapt-getとか、yumとかのコマンドがないのでインストールができない・・・
そんな時に出会ったのがこのサイト
http://www.nal.ie.u-ryukyu.ac.jp/note/note_detail/1865/
なんとMacLIBSVMを使うという研究資料ではないか!
これを参考にインストールをしてみる。
まずは、説明されている通り
http://www.macports.org/install.php
このサイトの必要なものをインストール。今回、自分のバージョンはEl Capitanだったので「OS X El Capitan v10.11」をクリックしファイルを保存し実行する。
ターミナルを再起動後
sudo port install libsvm
を実行

簡単ですね。

git pull/pushできなくなってしまった人への参考資料

gitの勉強をしていると
うまくpushできなかった時の解決方法として
・git pull
・git fetch
の二種類がみつかるとおもいます。どちらを使うべきかと言うとはっきりは言えませんが、調べた限りではgit fetchを使って変更箇所を治すのがいいとされています。
と言っても、もうpullしてしまったという人もいると思うので、まずはpullの後の説明をします。
git pull
を行うと、競合(コンフリクト)が起きているファイルを「最新情報と変更部分」を加えた状態のものに書き換えてローカルレポジトリに反映させてくれます。
試しにそのファイルを開いてみましょう。
すると以下のようにHEADと何かで囲まれた部分があるとおもいます。(これはサンプルです)
sample.txt------------------
sample
text
itaya_user_a
<<<<<<< HEAD
sakura
test_a
=======
sakura_user_b
test
>>>>>>> 52658903394ee3d55c52192ac88e5b86d722dbd3
program
----------------------------
ここでは、リモートリポジトリでは
sakura
test_a
という部分が、ローカルリポジトリでは
sakura_user_b
test
となっているからpushできないよと言われてます。
そのため、この部分を必要に応じて変更します。
最終的にはこのようなこのような形にします。
sample.txt------------------
sample
text
itaya_user_a
sakura_user_b
test_a
>>>>>>> 52658903394ee3d55c52192ac88e5b86d722dbd3
program
----------------------------
そしたら、これをadd/commit/pushします。
すると問題なくpushできるとおもいます。

 

初めてgitを使って見る(Bitbucket編)Part2

前回に引き続きgitについてまとめます。
今回は複数人でソースコードの管理をするときにどのようにするのかというのをテーマにまとめていきます。

【仮想的にもう一つの作業場所を確保】
そのために、今回は仮想的にもう一人の作業場所を作成します。
今まで使っていたローカルリポジトリの他のどこかにフォルダを作成してください。
フォルダの作成は
・右クリック->新規フォルダ
・mkdir フォルダ名
のどちらでも構いません。

そして、作ったフォルダをgitのローカルレポジトリにしましょう。
今回は、前回のようにgit initのようなことはせずに、今あるリモートリポジトリからコピーする形で作成します。
Bitbucketのページの左側にある「アクション」の下にあるクローンをクリックしてください。
すると以下のようなコマンドが出てくると思います。それをコピーして貼り付けてください。
git clone https://ユーザ名@bitbucket.org/ユーザ名/リモートリポジトリ名.git
これで、リモートリポジトリを基にした作業場所がローカルに作成されます。
この時点でリモートとローカルはリンクもしているので大丈夫です。
おそらく先ほど作ったフォルダの中にリモートレポジトリと同じ名前のフォルダがあると思うのでcdコマンドで移動しておきましょう。

※これからの作業では、ターミナルは一つではなく2つ起動しておいて、「cdコマンド」でそれぞれのディレクトリに移動しておきましょう。

【複数人でプッシュすることで生じる「競合」】

複数人でソースコードを管理する際にどのような問題が起きてしまうのか、簡単に体験してみましょう。
これから解説するにあたって、
・最初にadd/commit/pushした方のフォルダで作業してる人をA
・先ほどリモートレポジトリから作ったフォルダで作業してる人をB
として解説します。
では、まずAさんの方で1つファイルの内容を書き換えてみましょう。
その後add/commit/pushをしてみましょう。
問題なくpushできたはずです。問題はここからです。
次にBさんの方で先ほどと同じ名前のファイルの内容を書き換えてみましょう。
その後、add/commit/pushをしてみましょう。
うまくいかなかったと思います。

To https://ユーザ名@bitbucket.org/ユーザ名/git_1107.git

! [rejected]        master -> master (fetch first)

error: failed to push some refs to 'https://ユーザ名@bitbucket.org/ユーザ名/git_1107.git'

hint: Updates were rejected because the remote contains work that you do

hint: not have locally. This is usually caused by another repository pushing

hint: to the same ref. You may want to first integrate the remote changes

hint: (e.g., 'git pull ...') before pushing again.

hint: See the 'Note about fast-forwards' in 'git push --help' for details.


これが「競合」です。
もしかしたら「なんでこんなことが起こるの!!」「さっとプッシュさせろ!」と思った方もいるかもしれません。
でも考えてみてください、これでBさんの変更がリモートレポジトリの方に登録されてしまうとAさんの変更がなかったことになってしまいます。
それを防ぐためにこの競合ということが起きます。

【競合を解決するための機能「ブランチ」】
では、どのようにすればこのうまくいくのでしょうか。
そこで出てくるブランチというものです。
ブランチとは日本語で「枝」を意味しています。競合を避けるためにはまず作業員それぞれが枝を持ち、それを結合させることで1つのファイルにするというイメージを持っていただけるといいです。
<ブランチの作成>
ここからはA/B同時に作業を進めていきます。
まずAさんの方でtest_aというブランチを作成します。ブランチの作成には
git branch test_a
というコマンドを実行すれば大丈夫です。

次にBさんの方でtest_bというブランチを作成します。
git branch test_b
これでお互いが作業するためのブランチが完成しました。
<ブランチの切り替え>
ブランチは作成しただけでも使っていることにはなりません。作業する前にブランチの切り替えを行わなければなりません。
ブランチの切り替えには
git checkout ブランチ名
というコマンドを実行します。
そのため
Aさんは
git checkout test_a
Bさんは
git checkout test_b
というコマンドを実行してブランチの切り替えをしましょう。
<ブランチの結合>
ブランチの結合(マージ)これが一番よくわかりませんでした。
gitのマージをするにはまず、マージしたい方(今回の場合はmasterにtest_aをマージしたいのでmaster)に切り替えます
git checkout master
そして、ブランチのマージを行います。
git merge test_a
としてみると
でも、これだけではローカル環境のブランチが結合しただけなので、リモートリポジトリには何の変化もありません。
そこで、次にもう一度commit/pushを行います。
git commit 'ファイル名' -m 'コメント'
git push origin master
すると何かしら怒られると思います。
そしたら
git pull
というコマンドを実行します。
すると、コメントの入力が要求されます。
そこにコメントを入力すれば、リモートリポジトリの方も更新されます。
これをBでも行えば大丈夫です。

多分・・・

初めてgitを使って見る(Bitbucket編)Part1

今回は、初めてgitを扱うことになったので最初の設定するところからまとめていきたいと思います。

【gitの概要】

gitの細かな概要や、用途などについては

サルでもわかるGit入門 〜バージョン管理を使いこなそう〜 | どこでもプロジェクト管理バックログ

このサイトにて学習しました。

簡単に言うと、リモートリポジトリ(ネット上の場所)とローカルリポジトリ(実機端末)をリンクさせることでソースコードを管理するのがgitとなっています。

これを使うことで複数人のソースコード管理ができるようになったりします。


【gitの初期設定〜ローカルリポジトリ設定〜】

今回は、Macにて設定を行ったのでそちらについてまとめます。

まず、gitで管理したいコードが入っているフォルダに移動します。

移動には「cdコマンド」を利用します。

そして、そのフォルダ内に移動したらgitの初期設定である

git init

というコマンドを入力します。

これで、現在いるフォルダが最初に説明したローカルリポジトリになります。


【gitの初期設定〜リモートリポジトリ設定〜】

今回は、Bitbucketというサービスを使ってリモートリポジトリの設定を行います。

Bitbucketのアカウント登録を済ませたら上の方にある「リポジトリ」タブから「リポジトリの作成」を選択し適当な名前をつけて「リポジトリの作成」をクリックします。

これでリモートリポジトリが完成です。


【gitの初期設定〜リモートリポジトリとローカルリポジトリのリンク〜】

そしたら、次に実機に作ったローカルリポジトリと、ネット上に作ったリモートリポジトリをリンクさせます。

まず、Bitbucketの「概要」というところをクリックします。すると

コマンドライン」->「私はゼロからスタートします。」というところがあるのでそこをクリックします。すると、幾つかのコマンドが出てくると思います。最初の3行はもう行ったので最後の1行をコピーしてターミナルに入力しましょう。一応コマンドを載せておきます。

git remote add origin https://ユーザ名@bitbucket.org/ユーザ名/リモートリポジトリ名.git

これでリモートリポジトリとローカルリポジトリのリンクは終了です。


【gitの基本機能〜add/commit/push〜】

リンクが終了したところで、リモートリポジトリにローカルリポジトリソースコードを送る方法をまとめます。その手順は「add/commit/push」の3つに分かれます。

<add>

ソースコードを送るにはまず、

git add 'ファイル名'

と入力して送るファイルを指定します。

ここには正規表現も使える為、全部のファイルを送信したい場合は

git add *

と入力すればOKです。

<commit>

次に送信するときに必要なコメントの挿入をcommitで行います。commitを行うには

git commit

と入力してEnterを押して、コメントを入力すればOKです。

<push>

最後にコメント付きのファイルを送信します。ファイルの送信にはpushを行います。pushを行うには

git push origin master

と入力すればOKです。

 

試しに、ちゃんとリモートリポジトリに反映されているか確認してみましょう。

確認するには、Bitbucketの左側にある「NAVIGATION」の「ソース」というところをクリックすれば、ちゃんとリモートリポジトリにも登録されていることが確認できると思います。

エンジニアなら知っておきたいUNIX時間

UNIX時間とは

協定世界時 (UTC) での1970年1月1日真夜中(午前0時0分0秒)の時刻からの形式的な経過秒数 (wikipediaより引用)

 のことである。

 

UNIX時間の何が優れているかというと、経過秒数で表されているため何分後、何時間後、何日後の計算が簡単にできるというところです。

例えば二日後といった場合、UNIX時間に

二日(60*60*24*2)=172800

を加えれば良い。

日時では、くり上がりや繰り下がりなどが扱いにくいですが、これを使えばその辺の問題が解消されます。