Bag of ML Words

ML = Machine Learning, Music Love, and Miscellaneous things in daily Livings

OpenNMT-py "raise lengths array has to be sorted in decreasing order"

まだクローズしていないバグを踏んでちょっと時間をとられたので情報共有です*1

 

OpenNMT-py, 正確にはtorchtext-0.20の修正のせいで、いま、最新のOpenNMT-pyをgitダウンロードで使うと、train.pyやtranslate.pyが表題エラーの通りに死ぬ事象が起きています。

github.com

 

フィックスの方法としては、torchtextのバージョンを下げるのが一番簡単なのですが、今後pytorch, openNMTはtorchtext-0.20の方針でいくので、このworkaroundはあまりアレです。

 

10/30追記

下記の修正で訓練(train.py)は動くのですが、どうやらtranslate.py(翻訳側)はだめなようです。なので、現段階はtorchtext-0.1.1にダウングレードしてください・・・

 

 

 

で、私の修正方法ですが、

  1. torchtextをpythonシステムからアンインストール
  2. pipで改めて最新版のtorchtextをインストール
  3. 上記リンクの中ほど、@JianyuZhan さんがベタ書きしているパッチの内容を OpenNMT-py/onmt/IO.py, OpenNMT-py/train.py, OpenNMT-py/translate.pyにそれぞれ適用する

の3段階でした。

*1:NMTやっていて、しかもpytorchという奇特な方にしか役立ちませんが・・・

slack webhookでログをslackに自動投げ込み

webhookなる仕組みを使って、slackにcurlで直接メッセージを投げ込むことができるらしい。これ使えば、入力フォームから誤訳文対が報告されるたびにslackに投げてみることができるっぽい?

 

api.slack.com

 

とりあえずslackの公式APIページを見ると使い方が一番わかりやすい。

 curlでPOSTするために、メッセージ取ってきて、JSON形式にしてあげればよろしい。

あとはメッセージを取得する方法(最新のログファイルを監視して追いかける)と、それをJSONにフォーマットする部分ですね。

 

ログ監視パート

ログ監視、tailfとgrepで頑張るのも良いですが、logmonっていうのもあるみたい。

service コマンドで動かせるっていうのはわかりやすくていいですね。

 

qiita.com

 

我々の例だと、

/var/www/html/log.txt に全部書き出されるはずなので、これを監視して、何か入ってきたらechoなりで標準出力に吐き出されるようにすればいいのかな?

(logmonをインストールしてから) /etc/logmon/logmon.conf

 

# Monitor for messages
:/var/www/html/log.txt
(,)  # commaは絶対あるので
echo -n "<%%%%>" >> /var/log/logmon-enja.log

 

# sudo service logmon check

# sudo service logmon restart

 

 よし。

 

 

slack webhookパート

これとは別にslack webhookをやる。

送るものとかを整形することを考えると、何らかのstdin入力を受け取って、

各行ごとに処理、jsonに整形、curlでPOST、というスクリプトを書くのがいいかなぁ。

 

qiita.com

swfz.hatenablog.com

 

このあたりにしたがって順番にやってみる。

 

単純POST by curl

slackのアプリのあちこちをいじるとincoming webhookを設定するところにいくので、送りたいchannelを指定してwebhook urlを取得する。

これをcurlでPOSTする。curlの例文はwebhook URLを取得したら下に書いてあります。優しさ。

f:id:Dr_KayAi:20170713124647p:plain

curl -X POST --data-urlencode 'payload={"channel": "送るチャンネル名", "username": "goyakubot", "text": "This is a webhook test", "icon_eomji": ":ghost:"}' https://hooks.slack.com/services/XXXXXXXXXXXX

 

おお、とどいた!これだけでうれしい!

f:id:Dr_KayAi:20170713124906p:plain

 

スクリプト経由にする

慣れたpythonにstdinでファイルとかcatして、見た目お化粧したい。

jsonとrequestsモジュールを使えば簡単簡単。

 

python3でも日本語処理が必要になるのね。。。

 

(slack_webhook_post.py)

 

# -*- coding: utf-8 -*-
#
# given the stdin INPUT (tab-separted), break in line, send.

import json
import requests

def _main():

# Set the webhook_url to the one provided by Slack when you create the webhook at https://my.slack.com/services/new/incoming-webhook/
webhook_url = "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXXXX"
slack_data = {
"channel": "送るチャンネル名",
"username": "goyakubot",
"text": "This is a webhook test from パイソンだよ",
"icon_eomji": ":ghost:"
}

response = requests.post(
webhook_url, data=json.dumps(slack_data, ensure_ascii=False).encode("utf-8"),
headers={'Content-Type': 'application/json'}
)
if response.status_code != 200:
raise ValueError(
'Request to slack returned an error %s, the response is:\n%s'
% (response.status_code, response.text)
)

# end main

_main()

 

 

f:id:Dr_KayAi:20170713131745p:plain

 

やったぜ。

あとはtext部分を通常のpythonと同様にinput()から受け取った内容でparseすればよいね!

 

結合パート

 logmon.confのecho部分を、メッセージゲット --> Pythonにパイプ、これでいいはず

echo -n "<%%%%>" >> /var/log/logmon-enja.log

--->

echo -n "<%%%%>" | /full/path/to/python /full/path/to/slack_webhook_post.py

 

できたー!!

f:id:Dr_KayAi:20170713134915p:plain

 

 とおもったらechoからのメッセージに日本語が入るとだめ。なぜ・・・

 

http://qiita.com/FGtatsuro/items/f45c349e06d6df95839b#%E3%82%82%E3%81%86unicodeencodeerror%E3%82%82%E6%81%90%E3%81%8F%E3%81%AA%E3%81%84

に回答がありました。つまり、locale環境変数が効かないということです。

echo -n "<%%%%>" | /full/path/to/python /full/path/to/slack_webhook_post.py

-->

echo -n "<%%%%>" | PYTHONIOENCODING=utf-8:surrogateescape /full/path/to/python /full/path/to/slack_webhook_post.py 

 で解決!!

Webサーバー構築(Apache+PHP) の練習

ちょっとお仕事で

AWS上のインスタンスを用いて

*既定の入力フォーマットでいろいろな人から入力を集めて

*入力結果を保存して

AWS S3やslack botに入力結果の保存内容を投げる

ということがしたくなったので、webサーバを構築してみる

 

AWSインスタンス

まずサーバとなるインスタンスを立てる。

IPv4パブリックIPを与えること

*セキュリティグループで会社内ネットワークのIPからHTTPアクセスを許可する

だけ忘れずに設定する。後者は後でも追加可能。

仮にパブリックIPが12.345.6.78だとする

Apache

まず基本であろうApache(httpd)でウェブサーバサービスを立てる

sudo yum install httpd

sudo service httpd start

これでひとまずAWSインスタンス上でhttpdサービスがスタートした。

これだけで、会社内ネットワーク上のマシンから、ブラウザで

12.345.6.78

と入力すると、apache server testページが出てくる。やったね!

 

特別portの指定

/etc/httpd/conf/httpd.conf内のListen項目に

Listen 8080

を追加してからhttpdをrestartすると、

12.345.6.78:8080

でも行けるようになるね。使うライブラリとか、排他的な制御とかそういうときにport番号指定したりするときはこうする?

 

自前html!

httpd.confを見ると

DocumentRoot "/var/www/html"

となっています。ので、http://12.345.6.78はこのパスを実際には見ることになります。

日本語コーデックの確認も兼ねて、

centossrv.com

を参考にさせていただいて、簡単htmlを置きましょう。

sudo emacs /var/www/html/sample.html

 

[sample.html] 

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
<title>テスト</title>
</head>
<body>
テスト
</body>
</html>

これで

12.345.6.78:8080/sample.html

にアクセスします。

「テスト」とだけ表示されるページができたら成功ですね!

 

入力フォームつくるー

まずはテキストボックスしかないページを作るぞー

 

htmlで入力したデータをサーバ側に送信する方法 その1

5.1 HTMLフォームを使ったデータの入力とWebサーバ側での受信

こういうページを参考にしますよー

 

今回の目標

翻訳の失敗例を集めたい!ので

*ユーザさんに「翻訳クエリ」と「失敗した翻訳結果」を入力してもらう

*ボタンを押すと2つがまとめて保存なり送信される

という機能がほしいですね。

 

ページの要素として

*テキストボックスが2つ

*送信するボタン

の2つが必要です。これはhtml内の<form>タグを作って、その中に

テキストボックス2つとボタン1つを配置して完了します。

<form action="collection.php" method="POST" enctype="multipart/form-data">

<table>
<tr>
<td>
<textarea name="input" rows="3" cols="100" placeholder="翻訳に失敗した入力文章をここに入れてください(500文字以内)。" maxlength="500"\
class="form-control"></textarea>
</td>
<td>
<textarea name="output" rows="3" cols="100" placeholder="失敗した翻訳結果をここに入力してください(500文字以内)。" maxlength="500" cl\
ass="form-control"></textarea>
</td>
</tr>
</table>

<p>
<button type="submit" class="btn btn-primary btn-lg"> 報告するマン!! </button>
</p>
</form>

 

アクション機能として

*ボタンを押すと2つのテキストボックスの内容を取得する

*確認用に受け取った2つの内容を表示する

が必要です。

機能部分はPHPで書くのが簡単っぽい?ので、phpのファイルを作成して処理させます。

フォームからの入力 | PHP Labo

 

まずPHPを動かすようにします(これに気づかず2時間溶けた)

sudo yum install php

 

sudo emacs /etc/httpd/conf/httpd.conf

AddType application/x-httpd-php .php  と追記

 を追加。

で、collection.phpをhtmlと同じ場所において、

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>sample</title>
</head>
<body>
<table border="1">
<p>
<p>
<tr>
<td>翻訳クエリ</td><td><?php echo htmlspecialchars($_POST["query"], ENT_QUOTES); ?></td>
</tr>
<tr>
<td>誤訳結果</td><td><?php echo htmlspecialchars($_POST["translated"] , ENT_QUOTES); ?></td>
</tr>
</table>
</body>
</html>

これで、報告すると報告結果がブラウザにでるようになります.

 

入力された内容を保存したいー

 これでpostでデータの受け渡しはできるようになったけども、このままだと送信のたびにページが切り替わってしまう。

そこで*送信結果の表示の裏で、ファイルに送信結果を書きだす

これができるようになりたい。

 

これで行けた。

【PHP】フォームから送信された情報をファイルに保存する方法

# collection.php

 

# 上記の</table>と</body>の間に以下を挿入します

<!-- sent to the file-->
<?php
if ( isset($_POST["query"]) && ($_POST["query"] != "") ) {

$query = $_POST["query"];
if( get_magic_quotes_gpc() ) { $query = stripslashes("$query"); } // Escaping quotes
$query = htmlspecialchars ($query); // prohibit HTML tags
print "query=$query \n ";

if ( isset($_POST["translated"]) ) {
$translated = $_POST["translated"];
if( get_magic_quotes_gpc() ) { $translated = stripslashes("$translated"); } // Escaping quotes
$translated = htmlspecialchars ($translated); // prohibit HTML tags
print "translated=$translated \n ";
}

$time = date("Y/n/j G:i"); //日時の取得
$write = $time . ", " . $query . ",". $translated . "/";
$log = fopen ("log.txt","a"); // open with write mode
flock ($log, LOCK_EX); // lock the output file
fputs ($log,$write); // file write
flock ($log, LOCK_UN); // unlock the output file
fclose ($log); // close
}
?>

<p>
<h3>Above content is sent to the file. thanks.</h3>
<p>

 

これで、/var/www/html/log.txtに書き込まれるはずです。

 

・・・できませんでした

SE linux!!

/var/www/htmlは通常rootのものなので、apacheさんなどには書き込めません。

そこで

Apache - Apacheのドキュメントルートのパーミッションと所有権に関して(2111)|teratail

などを参考にしてパーミッションを変えます。

groupadd apache

usermod -a -G apache apache
usermod -a -G apache centos

chown root:apache /var/www/html/ 
 
chmod 2775 /var/www/html/ -R 

 

これでも書けないので、SE Linuxを疑います。

ApacheでSELinuxが原因で403 Forbiddenエラー - カタカタブログ

 

sudo setenforce 0 # SElinux一時停止

 これで・・・書き込める!やっぱSE linuxのせいだった!

 

画面切り替えたくない!

ひとまず入力フォームの入力内容を書きだせるようになったけど、

今は送信のたびに画面が変わるのでたくさん書いてもらうには面倒。

そこで、

*送信してもページが切り替わらないで、「送信したよ!」とだけ表示が増える

*つづけて送信できる

 としたい。

 

簡単には、sample.phpの中で直接php処理を全部書いてしまえばよい。

具体的にはsample.phpの中の次の文を書き換えて・・・

<form action="collection.php" method="POST" enctype="multipart/form-data"> 

-->

<form action="sample.php" method="POST" enctype="multipart/form-data"> 

 にして、collection.phpの中の実際にphp処理する部分をそのままsample.phpの中に書けばOK.

 

AWSやSlackへの投稿は次の記事に続く(かもしれない)

読みました:年収は「住むところ」で決まる ─ 雇用とイノベーションの都市経済学

shoeihidoさんの

sla.hatenablog.com

に触発されて、「年収は「住むところ」で決まる-─-雇用とイノベーションの都市経済学」

を買って読んでみました。

結論:かなり面白かったです。読む価値あります。

すらさんありがとう!良い本に出合いました!

 

だいたいまとめると

1) 先進国で低付加価値の製造業が破壊(特に雇用が)されるのはもう避けられない。その代わりに、アイデアや斬新さ、世界を変えるようなイノベーションで駆動する産業が先進国の経済をドライブする。

2) イノベーション駆動の産業は人・組織のつながりでより加速するので、ひとところに企業や優秀な人材があつまる(イノベーションハブ)。集まることでよりハブは強くなるので、その集まった地域だけが急速に地位を向上していくし、イノベーションハブに引き寄せられる優秀企業はそこから抜け出ることがなくなる*1。 人の面でも、イノベーションハブの企業のビジネスは個々人の知的生産性の高さで勝負しているので、優秀な高給取りが集まってくる*2

3)イノベーション産業自体は少数精鋭の高給取りが主役なのでマスを支えることはできないが、イノベーションハブを支える地域経済(スーパーとかレストランとかお医者さんとかクリーニング屋さんとかその他もろもろ)を急速に潤すことができて、かつこの波及効果が製造業よりもずっと大きい。そのため、イノベーションハブでは「すべての知的階級と職層の」給料(と物価)が上昇する。

4) 一方、イノベーション産業から取り残された場所(「ラストベルト」)は相対的に経済的に沈んでいく。このながれをひっくり返すための処方箋はいまだ存在しないし、つまりイノベーションハブを狙って作ることは難しい。

5) 沈みゆく地域から脱出するのは、知的階層の上位に属する人たちがメイン。苦しい目にあう下位の人たちは、情報断絶による機会喪失や、経済的困窮により移住したくてもできないなどの理由でその場所に縛り付けられる。これは比較的引っ越しの多いアメリカでもそうなっている。

 

感想

・一時期、「フラット化する世界」が流行したわけですが、現実には格差は国単位どころか地域・都市単位で発生している状況ですね(東京vs地方)。しかしながら先進国の発展のためには格差を助長するイノベーションハブにますます栄えてもらってもっと税収を上げて国全体に還流させる必要があるという・・・

・アメリカの強さの一つとしてイノベーションハブが多数あること、があるのかなと。日本(東京)、韓国(ソウル)、フランス(パリ)、イギリス(ロンドン)などはハブが一つしかない(あるだけましですが)から、そこに一極集中する。ドイツは伝統的にいろいろ分散しているんですが、その代わりに圧倒的なハブがない。

・日本だと愛知・名古屋圏が「製造業(自動車)のイノベーションハブ」としての機能を維持していると思うのですが、これは何か例外な仕組みが回っているのでしょうか?それともトヨタ系列が痛みにたえているだけ?

・これを見た後に今回のアメリカ大統領選挙、そしてトランプ大統領の「アメリカというかラストベルトへの製造業回帰(と雇用創出)」を切実に必要とする支持層、まだハネムーン期間なのにすでに険悪な対応をとる東西海岸部とそこにベースを置くメディア、なんともなるほど感というか。*3

*1:そこにいないだけで競争が不利になるため。

*2:一方製造業は設備投資・マシンの高性能化で競争力がつくので高価になるのは機械。

*3:製造業回帰で今後永続的に先進国を駆動するのは難しいかもしれませんが、帰ってきてくれた工場が5年だけでも雇用を創出してくれれば次の大統領選挙でも票が集まりそうですね。票取り戦略としては一理ある

Installing CUDA8+CUDNN5.1+Torch on CentOS7 (Japanese/English mixed post)

ほぼ真っ白なCentOSだとあまり情報がないので、自分用のメモもかねて忘れないうちに。

I found there are few posts about CUDA8 + GPU-enabled Torch on 'vanilla' CentOS. Hope this post helps somebody... 

基本ライブラリ群のインストール (Installing very basics)

sudo yum install emacs nano wget git gcc make cmake openssl-devel bzip2-devel readline sqlite-devel hdf5-devel

他にも何かいるかも。

Maybe I forget some libraries...

python

 pipはget-pip.pyを持ってくる

Get PIP by get-pip.py :-)

wget https://bootstrap.pypa.io/get-pip.py

python get-pip.py

pyenvをgit clone

Cloning the pyenv. I do not use virtualenv so far (I do not fully understand the benefit of virtualenv)

git clone https://github.com/yyuu/pyenv.git ~/.pyenv
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile 

 

pythonは今後も考えて3系で進めます。

Use python 3.X based on my personal preference. 

pyenv install 3.5.0

pyenv shell 3.5.0

pip install numpy

pip install scipy

pip install matplotlib

pip install pandas

  

CUDA, CUDNNインストール (Installing CUDA toolkit and CuDNN)

CUDAインストール

事前に、DKMSというライブラリを手動で確保する. Nouveauドライバをblacklistしないといけないかもしれません。ランタイムレベルは変えなくてもいけました。

Install a library called DKMS manually. Maybe you need to disable 'nouveau' drivers by blacklisting. 

wget ftp://rpmfind.net/linux/epel/7/x86_64/d/dkms-2.3-1.20161202gitde1dca9.el7.noarch.rpm

sudo rpm -ivh dkms-2.3-1.20161202gitde1dca9.el7.noarch.rpm

 

NVIDIAからインストールパッケージ(network)をダウンロードします。

Download the CUDA toolkit from the NVIDIA homepage. 

sudo rpm -ivh cuda-repo-rhel7-8.0.44-1.x86_64.rpm

sudo yum clean all

sudo yum install cuda

 

path設定 

Setting the PATHs. 

echo 'export PATH="/usr/local/cuda-8.0/bin:$PATH"' >> ~/.bashrc

echo 'export LD_LIBRARY_PATH="/usr/local/cuda-8.0/lib64:$LD_LIBRARY_PATH"' >> ~/.bashrc

source ~/.bashrc 

 

CUDNNインストール

NVIDIAからユーザ登録してCUDNNのパッケージを確保。展開してコピーする。

You first need to register (for free) to utilize CuDNN. After that, get the tgz of the CuDNN. Extract and copy it to CUDA library directory. Easy. 

tar -xvzf cudnn-8.0-linux-x64-v5.1.tgz  

sudo cp -a cuda/lib64/* /usr/local/cuda/lib64/ 

sudo cp -a cuda/include/cudnn.h /usr/local/cuda/include/

 

Torch/Luaのインストール

あえてLUA (not LUAJIT)をインストール。

We install LUA, not LUAJIT. LUAJIT is memory-limited. 

git clone https://github.com/torch/distro.git ~/torch --recursive

cd torch/

bash install-deps   

TORCH_LUA_VERSION=LUA52 ./install.sh   

 

 

必要なモジュール群をインストール. 

Install modules by luarocks. Order matters. 

luarocks install image

luarocks install tds

luarock install cwrap

luarock install torch

luarock install optim

luarocks install nn

luarocks install nngraph

luarocks install cutorch

luarocks install cunn

luarocks install cudnn

luarocks install hdf5

luarocks install luautf8

luarocks install threads

luarocks install penlight

luarocks install bit32

 これでTorchでDeepぶん回せますね!

Now you are ready to rock with Deep NN on Torch!! 

C++学習記(5): boost mpi (+openmpi) on multiple CPUs (machines)

Boost MPIに複数コア分散計算のお仕事は終わったので、いよいよ複数マシンによる盛大な負荷分散をやろうと思う。

 

簡単じゃない?簡単じゃない

 

hostsを指定するファイルを作って

 # nodes_for_MPI.txt

host.1.xx.yyy cpu=4

host.2.xx.yyy cpu=2

 

 mpirun起動時に指定するのみ。簡単じゃない?

mpirun -np 6 --hostfile nodes_for_MPI.txt ./helloBoostMPI

 

ORTE was unable to reliably start one or more daemons.
This usually is caused by:
 

 はい死んだー。

 

sshで直接コマンド渡すとき~

FAQ: Running MPI jobs

のdiagnosisに従うと、まず2番目、ssh経由でコマンド渡すときのpath設定があってなかった。

ということで

ssh-env - ssh実行時に環境変数を設定/変更したい - spikelet days

に従って、/etc/ssh/sshd_configの修正と.ssh/environmentの作成。

pathとかはすべて一つにまとめて直書きする必要があります。

 

sudo service sshd restart

sshdをリスタートして・・。

 

mpirun -np 6 --hostfile nodes_for_MPI.txt ./helloBoostMPI

ORTE was unable to reliably start one or more daemons.
This usually is caused by:
 

まだできない。

 

ファイヤーウォール氏~

--mca plm_base_verbose 10 をオプションとしてつけると、TCP/IPコネクションの問題ぽい。ファイヤーウォールの設定ぽいな・・・。

sudo /etc/init.d/iptable. stop

mpirunをたたく側のマシンのiptableをカット。まあ、社内ファイヤーウォール内だから大丈夫でしょう。。。

 

mpirun --hostfile nodes_for_mpi.txt ./helloBoostMPI
My rank =1 of 6
My rank =4 of 6
My rank =0 of 6
My rank =5 of 6
My rank =2 of 6
My rank =3 of 6

やったねたえちゃん!