OpenCVをソースからビルドするとhaarlike分類器(顔認識などに使われているやつ)の学習ツールが手に入るんだけど、たくさんのマシンでたくさん学習させているとそれぞれの進行状況をチェックするのが面倒になってくる。
でも、入力した画像ファイルが壊れていると学習が強制終了してしまったり、データがばらつきすぎてて収束しなくてあきらめて終了されたりするので、プロセスが死んでいたらパラメータを直してすぐやり直しをさせたい。学習中は予断を許さない状況が続く。
なので、進行状況を監視してtwitterアカウントshokai_logにpostするbotを作った。
5分間隔でopencv-haartrainingの作業ディレクトリとプロセスが生きているかをチェックする。
学習stageが進む毎に適当に通知し、プロセスが強制終了していた場合は激しくreplyしてくれる。これで安心して寝れる。OpenCV1.0/2.0両方対応。
一見何言ってるのかわかりにくいpostもあるが、「ドドドド」だったらstage4が終わったという意味。
辞書はコード内にある。
第2引数にopencv-haartrainingの-dataオプションで渡した「結果の書き出し先ディレクトリ名」を指定する。第3引数は無しでもいいが、twitter投稿の末尾にメモを付けられる。複数のマシンで実行していてどれの進行状況かわからなくなる時は、マシンの名前を入れておけばいい。
ruby tweet-haartraining.rb /Users/sho/path/to/training/dir/ "Macbook黒"
tweet-haartraining.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rubygems'
require 'twitter'
# setting
USER = 'your-account'
PASS = 'your-password'
INTERVAL = 300 # sleep sec
YOU = 'shokai' # 時々replyしてくる nilでreplyなし
NOPOST = false # debug用
def post(message)
return if !message
message = "@#{YOU} #{message}" if rand(3)<1 if !(message =~ /@#{YOU}/) && rand(2)<1
puts message + "\t" + Time.now.to_s
return if NOPOST
httpAuth = Twitter::HTTPAuth.new(USER, PASS)
tw = Twitter::Base.new(httpAuth)
tw.update(message)
end
if ARGV.size < 1
puts '結果が出力されるディレクトリへのパスが必要です。メモも付けられます(オプション)'
puts 'e.g. ruby tweet-haartraining.rb /path/to/haar/training/dir/ "研究室の学習用パソコン"'
exit 1
end
puts path = ARGV.shift
memo = ARGV.shift || ""
dir_path = path
if path =~ /\/$/
dir_path = path
xml_path = path[0...path.size-1]+'.xml'
else
dir_path = path+'/'
xml_path = path+'.xml'
end
if stage_p = Dir.glob(dir_path+'*').delete_if{|i| File::ftype(i) != 'directory'}.map{|i| i.split(/\//).last.to_i}.max
post "ステージ#{stage_p}から開始" + " " + memo
else
messages = ["開始。",
"はじめ",
"起床",
"おきた",
"start",
"スタートしました",
"hello world",
"hello work",
"はじめますわっ",
"スタンバイレディ セタップ"]
post messages[rand(messages.size)] + " " + memo
end
while true do
sleep INTERVAL
stage = Dir.glob(dir_path+'*').delete_if{|i| File::ftype(i) != 'directory'}.map{|i| i.split(/\//).last.to_i}.max
if File.exists? xml_path
messages = ["全行程完了(ステージ#{stage})。お疲れ様でした。",
"全部オワタ(#{stage})",
"修了しました",
"寝る。#{stage}時に起きる。",
"終わったので、#{stage}時に帰ります",
"全段階完了しました。データを回収し、電源を落としてください(#{xml_path.split(/\//).last})",
"全ステージ完了しました(#{xml_path.split(/\//).last})",
"ⓢⓤⓨⓐⓡⓘ"]
post "@#{YOU} " + messages[rand(messages.size)] + " " + memo
exit 0
end
if nil == `ps aux | grep opencv-haartraining`.split(/[\r\n]/).delete_if{|m|m=~/grep opencv-haartraining/}.first
messages = ["#{stage}段階目まで来たけど異常終了したかも",
"落ちてる",
"ERROR! haartraining is not working. please restart \(^o^)/",
"異常終了",
"異常です",
"動いてないっぽい・・・",
"死んだかも",
"だめっぽい・・",
"おい、異常終了してるぞ",
"冒 険 の 書 (#{stage}) は 消 え ま し た",
"おお、死んでしまうとは情けない",
"\(^o^)/"*stage,
"ピッコロの気が消えた",
"なん・・だと・・",
"#{stage}面でピチュった"]
post "@#{YOU} " + messages[rand(messages.size)] + " " + memo
sleep INTERVAL*2
next
end
next if stage == stage_p or stage == nil
stage_p = stage
messages = ["#{stage}段階目まで進みました",
"バリバリです(stage#{stage})",
"ばっちりですわっ",
"------ここまで読んだ(#{stage})------",
"がんばってます(#{stage})",
"stage #{stage}",
"ステージ#{stage}なう",
"now finished stage#{stage}.",
"よし!ステージ#{stage}まで終わった!!!",
"うわ"+"あ"*stage,
"ド"*stage,
"ゴ"*stage,
"ゴ"+"ー"*stage,
"もりもり",
"ふむふむなるほど"+"・"*stage,
"頭が"*stage+"おかしくなりそうだ",
"もういや",
"無理"*stage,
"ズザ"+"ー"*stage,
"帰りたい",
"まだ#{stage}段階目だ",
"もうstage#{stage}まで終わった。超はやい",
"もうstage#{stage}まで終わった",
"stage#{stage}まで終わった",
"stage#{stage}まで終わったし",
"ククク・・遂に#{stage}界までまで昇ってきたか・・・",
"ⓢⓤⓨⓐ"*stage]
post messages[rand(messages.size)] + " " + memo
end