Bag of ML Words

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

Lapack for Torch

ちょっとSVDが必要だったのでtorch.svdをしたら"LAPACKがないよ"と怒られました。

 

torchの線形代数ライブラリはLapackをラッパしているだけなので、そもそもコンパイル時にLapackがないとだめ。

 

ということでOpenBLASをインストールする。

 

git clone https://github.com/xianyi/OpenBLAS.git

cd OpenBLAS

make NO_AFFINITY=1 USE_OPENMP=1

sudo make install

 

これで/opt/OpenBLASにBLASが入ります。

 

あとはpathを通す。

export CMAKE_LIBRARY_PATH=/opt/OpenBLAS/include:/opt/OpenBLAS/lib:$CMAKE_LIBRARY_PATH 

 

このパスが正しく通っていればTorchの再コンパイルLapackが使えるようになっているはず。

 

2つのファイルの共通業を抽出するワンライナー

たびたび使うので。

 

 grep -x -i -f file1 file2

 

以下のQiita記事に書いてありました!

 

qiita.com

Installing CUDA9 + CuDNN7 + Torch on CentOS 7 (Japanese post + English post)

このポストの目的

下記の自著記事を基にして、CUDA8 + CuDNN5.1はinstallした計算機があります。

今度はこのマシンのCUDA, CuDNNを更新します。

 

dr-kayai.hatenablog.com

 

Purpose of this post: 

update the CUDA (8 --> 9) and CuDNN (5 -->7) on CentOS 7. 

 

作業開始!

CUDA, CuDNNのダウンロード

まずはnvidiaの公式ページよりCUDAのrpm(network install)とCuDNNのtgzを確保します。

Download the .rpm file of CUDA9 (network install) and .tgz file of CuDNN7. 

 

CUDA Toolkit Download | NVIDIA Developer

NVIDIA cuDNN | NVIDIA Developer

 

CUDA、CuDNNのインストール

特に何も考えずにrpmインストールです。

Simplu install CUDA from RPM

sudo rpm --install cuda-repo-rhel7-9.0.176-1.x86_64.rpm

sudo yum clean expire-cache

sudo yum install cuda

環境変数をアップデートします。sourceを忘れずに。

Update the environmental variables. Do not forget source-ing!

export PATH="/usr/local/cuda-9.0/bin:$PATH"
# THIS IS OBSOLETE export PATH="/usr/local/cuda-8.0/bin:$PATH"


export LD_LIBRARY_PATH="/usr/local/cuda-9.0/lib64:$LD_LIBRARY_PATH"

# THIS IS OBSOLETE export LD_LIBRARY_PATH="/usr/local/cuda-8.0/lib64:$LD_LIBRARY_PATH" 

 CuDNNについては、.tgzファイルを解凍して、出来上がるcudaディレクトリの中身を/usr/local/cudaディレクトリにコピーするだけです。

Copy the contents of the CuDNN .tgz file to /usr/local/cuda. 

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

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

 

TorchのRe-install

事前情報を得ていたので、以下の環境変数を設定。

Set the following varaible. 

export TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__"

 

Torchディレクトリからinstall. 躓いたら、./clean.shをしてからもう一度やってみましょう。

Install. If you failed, try ./clean.sh, then update all relevant packages and libraries. 

cd ~/torch

./install-deps

./update.sh

./clean.sh

export TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__"

./install.sh

<<After successful installation, do luarocks for torch packages>>

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への投稿は次の記事に続く(かもしれない)

小技:linuxでn行おきに何かしたいとき

awk使うマン!

 

# 3行おきに出力

cat file.txt | awk '(NR%3==0){print}'

 

# 10行おきに改行入れる

cat file.txt | awk '(NR%10==0){$0=$0"\n"}{print}'

 

 

qiita.com