備忘録 blog

Docker/Machine Learning/Linux

ownCloudのアプリを作る

tl;dr

ownCloudはphp製のオープンソースオンラインストレージであり、社内Dropboxのようなものとして使えるが、プラグインのような形でAppを自作・追加することができます。このAppはHookやCronジョブのほか、ownCloud内にアプリ用のページを実装することもできます。しかし日本語の資料が乏しく、マニュアルも十分に整備されていないので自分でソースコードを読みながら適宜、実装を書いていく必要があります。

App Development — ownCloud Developer Manual 9.0 documentation

以下ではownCloud9.0を対象に、アプリを作る上で気になったことや引っかかったことをメモしておきます。

アプリの作り方とデバッグ方法

アプリは、\apps内にフォルダを作って置けば良い。予めocdevというコマンドラインツールをダウンロードしておいて、\appsフォルダ内で

ocdev startapp OwnNotes

というコマンドを叩くことでディレクトリが自動で生成されます。ここで注意しなければならないのは、イニシャルキャピタルのキャメルケースでアプリ名を定めなければならないということです。実際に生成されるフォルダはすべて小文字になっているので注意。ここで決めるアプリ名が、そのまま名前空間になります。モジュール名は例えば\OCA\MyApp\Controller\PageController が /apps/myapp/controller/pagecontroller.php に対応しているように、ファイル名のスラッシュの向きが入れ替わってキャメルケースになります。

デバッグですが、php初心者の私はひたすらownCloudのログに出力するという方法をとっていました。\data\ownCloud.logless +Fして眺めていましたが、このログはそのままでは少しみずらいです。一方でWeb上の管理画面でログを見ることはできますが、そうすると今度は自分で更新しなきゃならないので痛し痒しです。

Hookが効かない

https://doc.owncloud.org/api/classes/OCP.Files.Node.html

Fileが書き込まれたときにHookして、callback関数で書き込まれたファイルのNodeを取得して、中身をあれこれするコードを書こうと思った時のための備忘録。

https://doc.owncloud.org/server/9.0/developer_manual/app/init.html

\OCP\Util::connectHook('OC_Filesystem', 'post_write', 'OCA\OwnNotes\Hooks\UserHooks', 'postWrite');

こうすると、ownnotes/hooks/userhooks.phpclass UserHooksのシングルトンメソッドとしてstatic public def postWrite($args)を定義すればよいのですが、この戻り値が曲者で、返ってくる値は

{
"run" => 1,
"path" => "\aaa.txt",
}

みたいな形になります。(実際にはphpのデータ構造です。var_export($node, true)みたいなコードを書くと、文字列型として出力されます。)

https://github.com/owncloud/core/blob/master/lib/private/Files/Node/HookConnector.php

このコードを読む限り、このpathをNodeにするにはHookConnectorgetNodeForPathを呼ばなければならないのですが、private methodなのでクラスのインスタンスを作らなければなりません。しかしコンストラクタには$rootと$viewが必要となって、厄介なのでやはり引数として[$node]自体が返ってくるようにしたいです。

https://doc.owncloud.org/server/9.0/developer_manual/app/hooks.html

というわけで、上のページを参考にしてhookを定めます。registerメソッド内でHookをlistenしておいてapp起動時にregisterを呼ぶようにしておけば、この時呼ばれるcallbackメソッドの引数はNodeになります。

ファイルの作成/更新ができない

Filesystem — ownCloud Developer Manual 9.0 documentation

    public function writeTxt($content) {
        // check if file exists and write to it if possible
        try {
            try {
                $file = $this->storage->get('/myfile.txt');
            } catch(\OCP\Files\NotFoundException $e) {
                $this->storage->touch('/myfile.txt');
                $file = $this->storage->get('/myfile.txt');
            }

            // the id can be accessed by $file->getId();
            $file->putContent($content);

        } catch(\OCP\Files\NotPermittedException $e) {
            // you have to create this exception by yourself ;)
            throw new StorageException('Cant write to file');
        }
   }

ドキュメントにあるコードそのままですが、\OCP\Files\NotPermittedExceptionが出てしまってファイルを書き込めません。

若者の生態を青春小説の系譜から探る

若者 は常に、良くも悪くも時代を象徴する存在であった。太陽族竹の子族、ヒッピー、アッシー君……といった時代を象徴する文化や言葉には、背後に若者の大きな力があった。しかしながら、一億総中流と呼ばれた日本人が多様化をする中で、人口に対する若者の占める割合が低下するだけでなく若者間での共通性が失われてきたのが現代の若者である。そう、もはや彼らを若者としてひとくくりに扱えるほどの共通性をもつ集団が存在しているわけではないのだ。

古市憲寿(2011)「絶望の国の幸福な若者たち」は、まさにそういった現代の若者をデータとインタビューの両面から切り取る資料集として非常に興味深い。

一方でかつての若者、特に学生はいったいどのように生きていたのだろうか。

しばしば語られることであるが、「大きな物語」の瓦解がもたらした影響は大きい。現代の若者は共通の文脈を失っている。かつてはほとんどの家庭が視ていたテレビ、そこで流される野球中継といったものは少なからず話題を生み出す役割を果たしていたはずだ。しかし今はそういった共通の中心軸となる話題もなく、個々人はより細分化された人間関係の中で過ごすようになっている。そういった現代の視点から過去を見渡したとき、いったいどのような変化がみられるのだろうか。

ここでは私が独断と偏見で選んだ学生を主人公とする小説を追いながら、それぞれの時代の学生事情を詳らかにしたい。また大澤真幸(2008)「不可能性の時代」に倣った時代区分を採用した。時代の先端をゆく若者であるからこそ、時代の空気に大きく影響を受けた生き方をしているのではないかと思う。昔に読んだ本ばかりなので記憶が曖昧であるし、そこまで深く掘り下げて考えたわけでもないし、かなり適当なことを言っている部分もあるが、それはそれとして最後まで読んでいただけたら幸いである。

不可能性の時代 (岩波新書)

不可能性の時代 (岩波新書)

ポスト学生紛争(理想の時代~虚構の時代Ⅰ)

赤頭巾ちゃん気をつけて (新潮文庫)

赤頭巾ちゃん気をつけて (新潮文庫)

ぼくらの七日間戦争 (角川文庫)

ぼくらの七日間戦争 (角川文庫)

この時代の有名な本は、学生運動という一時代が終わった虚脱感としらけの中で発生してきたといってもよい。ちょうど学生紛争以後に大学に入学した世代を「しらけ世代」と呼ぶように。

学生運動は、腐敗した大学上層部の粉砕を目論んだものが始まりではあったが、それが労使対立や新左翼運動と結びつき大規模なムーブメントとなった。しかしそれは過激化を招き、一般大衆の離反と先鋭化したメンバーによる浅間山荘事件を引き起こした。このように日本の革命はなしえなかったものの、而して大学解体じたいは成功した。大学全入時代の到来により大学生は量産されるようになったが、一方で彼らの全員が高い学習意欲を持っていたわけではない。その帰結として大学は以後、レジャーランド化の一途をたどるようになったのだ。

その中で、庄司薫(1969)「赤頭巾ちゃん気をつけて」は学生運動のあおりを受けて東大入試がなくなった年の浪人生が、人間との関わりを通して学問や人生について思索をめぐらし、その中で主人公が成長を遂げる成長譚である。

学生運動というある意味で悩める若者を吸収して有り余るエネルギーを議論と破壊に向けたはけ口がなくなったことで、若者は自律的に悩むことが求められるようになった混乱期の若者のあり方を等身大に描いているように感じる。そしてその悩みが若者で共有されたからこそ、多くの若者が当時この本を手に取り、芥川賞を受賞したのではないかと思う。身近なちっぽけなことからもっと規模の大きなことまでひっくるめて若者は悩んでいたのではないか、と感じさせる。少なくとも、人間関係や目先の就職だけに悩みが収斂していたとは思えない。

宗田理(1985)「ぼくらの七日間戦争」も同様のポスト学生運動期を描いた作品であったが、こちらはどちらかというと学生運動に対する回顧的、懐古的心情が強く、全共闘の亡霊を中学生の悪戯に仮託しているところが逆に、若い瑞々しい感性からの乖離を感じさせる。もちろん、読み物としては面白く、中学生が知恵を駆使して大人達の裏をかいていく姿はまさに痛快である。

ノルウェイの森 上 (講談社文庫)

ノルウェイの森 上 (講談社文庫)

ノルウェイの森 下 (講談社文庫)

ノルウェイの森 下 (講談社文庫)

一方で全く学生運動に関心を抱かない層もある。それが村上春樹(1987)「ノルウェイの森」だ。ここでの主人公(ワタナベ君)は学生運動を横目に見ながら、而して学生運動や学問というものにはまったく興味を持たず恋愛ゲームに興じ、過去の因縁にとらわれている。

村上春樹の場合、多くの作品で過去が重要なモチーフになっている。過去に囚われた主人公、過去の束縛から逃れられないヒロインなど、そういった登場人物を描く限り、将来を考えるためにはまず過去を解決しなければならないし、それが主題となってしまうのだから、彼らから前向きな悩みを見いだすのは難しいのかも知れない。だが一方で、過去の悩みはその時々の世相に左右される現在や将来の生活に比べて普遍的/時代に囚われないことが多く、それが彼の作品が長く人々を楽しませていることにつながっているのだろう。

バブル期(虚構の時代Ⅱ)

なんとなく、クリスタル (新潮文庫)

なんとなく、クリスタル (新潮文庫)

学生運動というある意味での理想を追い求める運動が破綻し、人々が虚構に溺れるようになったのが1970年代以後の「虚構の時代」とするならば、その頂点がバブル期であろう。 その中で田中康夫(1980)「なんとなく、クリスタル」はブランドという虚構に溺れながら、自律的な生活を送る恋人どうしの生活を端的な文章で表現する、バブル期を象徴する文学なのではないかと思う。

膨大な脚注は、それをシニカルな視点からメタ的に捉えている。そこではブランドが過剰なまでに記述される一方で、大学名については適度にぼやかされているところが、かえって学歴としての大学名が飾り立てたブランドよりも価値を有していると考えていることが暗黙裡に示唆される。彼らの生活の主体はもはや大学ではなく仕事であるにも関わらず、大学名にはやはり価値があるのだ。

田中康夫の小説は、どのような人生を送るかや将来を悩むということよりも「なんとなく」や「気分」で今を生きることを当然のようにとらえている。しかしそれは残念ながらバブル崩壊以後の現代には通用しない観念となってしまった。これが村上春樹と好対照を為している。彼らはどちらも若者を主人公に据えた小説を書き、時代の寵児となったわけだが、村上春樹の作品群はそれ以降の時代でも受容され、毎年ノーベル文学賞を取るのではないかと騒がれているが、作品自体が特定の年代/時代を扱うものが多いといえども、翻訳文体ともいわれるその文体じたいは時代に依存していないために、原典は日本語そのものが変革するまで読み続けられるだろう。一方、とうの田中康夫はそれ以降、批評家、そして政治家へ転向し、なんクリ自体はそれが古典小説と同様の扱いを受けるようになったことがそのことの何よりの証左だろう。

だがもう一作バブル期には面白い作品がある。それが杉元伶一(1991)の「就職戦線異状なし」だ。これは織田裕二主演の映画の方でしか観たことがないのだが、空前の(そして恐らく絶後の)売り手市場であったバブル期であって、就活はできるだけ良い会社に入るレースゲームのように捉えられていた中で、就活をしていくうちに段々、「本当に自分のやりたいこと」を見いだしていくというストーリーである。その中の一節で、「なりたいものではなく、なれるものを探し始めたら大人だ」という登場人物の台詞がある。それは正鵠を射ている。だがやりたいことをやる、なりたいものになろうとするのは若者の特権でもあるはずだ。それこそ当時よりも更に就活のあり方が画一化され、インターネットの普及により容易に大量に企業にエントリーできるようになった現代は企業とのマッチングはますます難しいものになっている一方で、経団連指針により就活期間は短くなっているという厳しい現実だが、その中でどう就活していくかということに対して作品の持つメッセージは色褪せていないはずだ。

失われた20年(不可能性の時代)

大澤は1995年以降を「不可能性の時代」と呼んだ。この時代を「現実への逃避」という言葉で象徴したが、それは大澤の言葉を借りるならば「第三者の審級」の衰退と軌を一にしていたといえよう。世俗化による信仰の衰退に加え、ソ連崩壊による共産主義への幻滅が進み、日本ではバブル崩壊で成長神話も崩れた。それはつまり「大きな物語」の崩壊であった。それ以後人々は多様性の名のもとにお互いを許容し、尊重しあうことが求められた。

それと同時にセキュリティ化が進んだ。これの意味するところはジジェクの言うところのカフェインレス・コーヒーやノンアルコールビールのような無害な危険であり、主張なきデモであり、その究極系が美少女ゲームのような、恋愛や生身の身体性といった現実の面倒な手続きなしにセックスを体験することのできるバーチャル・リアリティである。科学の発展は、様々な危険から危険を取り除くことに成功した。しかしその手法はときに、現実と精神を仲立ちする中間媒体を設けることがしばしばあり、結果として久しく我々は、身体性を欠いたアンバランスな生活を送っている。

一方で変化する現実を受け入れられない人々が「大きな物語」を求めたが、その手法は極めて肉体的、身体的なものであった。その行き着く先がテロルや暴力であり、そういった破壊的な行為による原理への回帰を求めた。その帰結が9.11であり、その後の一連のテロとの戦いであり、例えば秋葉原連続通り魔事件もその発露ではないかと考えられる。

まさに現実が消毒されるのと対照的に失われた身体の感覚を取り戻さんとして暴力、自傷行為に走る人々が増えているのは、高度なセキュリティ化が生み出した矛盾といって差し支えないだろう。

将来が不安であるがゆえに若者は今が幸福だと考える。これは古市の見方だが、私は実際に今の日本の若者は「なんとなく」生きることはできず、そのかりそめの幸福を刹那的に享受するか、さもなくばその不安に押しつぶされながらひたすらにペシミスティックに(あるいは絶望して)生きるか、そのどちらかに収斂しているのではないかとみている。

参考ページ

なんとなく、クリスタル

http://d.hatena.ne.jp/SuzuTamaki/20080522/1211421607d.hatena.ne.jp

Wantedly SyncのGithub連携を試してみる

Wantedlyがリリースしている社内向けグループチャットツールSyncに、github連携できる機能がついたので早速試してみました。 github連携を有効にすると、プルリクなどを通知してくれるようになります。

方法

  • Syncにアクセスします。

Sync

  • 左下の歯車のマークをクリックし、外部サービス連携を押します。

f:id:sharply:20160514204330p:plain

f:id:sharply:20160514204454p:plain

  • Authorizeします。

f:id:sharply:20160514204907p:plain

f:id:sharply:20160516092632j:plain

これで設定終了です。

  • 試しにプルリクを立ててみる

f:id:sharply:20160516092644j:plain

プルリクの通知が届いていますね。確かに連携は成功です。

今回はWeb版で試してみましたが、普段はLinux環境で過ごしているので、SyncのクライアントアプリもLinuxのバイナリで提供してくれると嬉しいですね。(需要はなさそうですが...)

サイボウズ、ChatWork、Skype、Slack、チャットワークと様々なチャットツールを今まで使ってきましたが、Sync自体はslackとか違って非エンジニアの方でも便利に使えるし、他のチャットツールと違ってエンジニアに近い方も便利に使える多機能なチャットツールだと思います。

余談

誰なんだ!

f:id:sharply:20160514205418p:plain

ディープラーニングをKerasというフレームワーク上で行う

はじめに

機械学習、特にディープラーニングが近頃(といってもだいぶ前の話になりますが)盛んになっています。CaffeやChainerといったフレームワークもありますが、特にGoogleがTensorflowでtensorboardと呼ばれる簡単に使える可視化基盤を提供して有名になったのを機に、Tensorflowで機械学習を始めてみたという方も少なくないと思います。

しかしTensorflowは低レイヤーな行列演算、ベクトル演算を記述するには適していますが、機械学習モデルの記述という面では書きにくいことも確かで、何かが動いていることは確かめられたけれど自分で何かをするには敷居が高かったです。例えば、Tensorflowでsoftmax層を定義するには、以下のコードを書く必要があります。

 # softmax, i.e. softmax(WX + b)
  with tf.variable_scope('softmax_linear') as scope:
    weights = _variable_with_weight_decay('weights', [192, NUM_CLASSES],
                                          stddev=1/192.0, wd=0.0)
    biases = _variable_on_cpu('biases', [NUM_CLASSES],
                              tf.constant_initializer(0.0))
    softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name)
_activation_summary(softmax_linear)

https://github.com/tensorflow/tensorflow/blob/r0.7/tensorflow/models/image/cifar10/cifar10.pyから引用)

もちろん機械学習の研究をする場合や、細かくモデルを定義してチューニングをゴリゴリしたい場合には、これぐらい表現力が高い方がよいかもしれません。しかし数学が苦手だったり、趣味レベルで少し触ってみたいだけだったり、短い時間である程度の成果を上げたかったりする人にとっては、下のようにモデルに追加する層を列挙する形で書けると便利ですよね。

model.add(Activation('softmax'))

ここでKeras(Keras Documentation)というフレームワークを導入します。これは簡単な記法で(短いコードで)機械学習のモデルを書き下せる上、すぐに類似した問題に応用可能なsampleがついています。またバックエンドにTheanoの他Tensorflowを適用できるため、Tensorflowとほとんど変わらない速度で、しかも簡易な記法で記述したモデルを試すことが可能です。ここではKerasを用いてCNNで簡単なカラー画像の分類モデルを組み立て、学習させ、実際に予測をするサービスを作ろうとする上のtipsをメモしておきます。先に断っておきますが、私は機械学習の専門家でも、またそれを専門に学んでいるわけでもないため、ディープラーニングに対する記述には正しくない点も多く含まれていることをご了承下さい。

モデルをどう構築するか

従来の機械学習や統計、例えばSVMや回帰分析では、特徴量は自分で抽出しなければなりませんでした。しかしディープラーニングでは、その特徴量抽出は隠れ層の重みの学習に置き換えられるので、適切な学習データを用意することで特徴量自体の検出を機械に委ねることが可能になりました。従って必要となるのはどういったモデルを作るかということと、どう入力画像を扱うか、さらに言えば解きたい問題をどのように機械学習の枠組みに落とし込むかという3つになるでしょう。

Tensorflowよりモデルの構築は容易になったとはいえ、私のような初学者はいったいどのようにモデルを構築すればいいのか検討もつきませんが、画像を扱うにはいくつかの方法があって、MNISTとよばれるグレースケールの手書き数字認識では(MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges)多層パーセプトロンと畳み込みニューラルネットワークのサンプルがありました。kerasのexamplesフォルダにあるmnist_cnn.pymnist_mlp.pyを比べると分かりますが、CNNではモデルの中に

model.add(Convolution2D(nb_filters, nb_conv, nb_conv,
                        border_mode='valid',
                        input_shape=(1, img_rows, img_cols)))
model.add(Activation('relu'))
model.add(Convolution2D(nb_filters, nb_conv, nb_conv))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(nb_pool, nb_pool)))
model.add(Dropout(0.25))

このような畳み込み層(CNNのCは畳み込み:Convolutionalのcです)が入力と多層パーセプトロンの間に組み込まれています。それぞれの意味としてはConvolution2Dでが画像にフィルタを掛けて特徴量を抽出し、Max Pooling層が最大の値をサンプリングすることで、その値の位置感度を下げます。そして最後のDropout層によって出力をここでは4分の1にして過学習を防いでいるといった感じでしょうか。またノードからの出力の総和を計算する際、reluと呼ばれる活性化関数が用いられていますが、これはmax(0, x)で定義される関数で、負の入力に対しては0を返しますが、正の入力に対しては線形の出力が返されます。これによってある程度疎な行列が得られるので行列演算にも都合がよく隠れ層でよく使われる一方で、最終的な出力を得る際には表現力が貧弱だということもあり、softmax関数が使っているようです。

実際にサンプルのコメントにもあるように精度はCNNの方が高いですし、Cifar10(CIFAR-10 and CIFAR-100 datasets)とよばれるカラー画像6万枚の10分類のサンプルコードはCNN版しかありません。TensorflowでもCNNによる実装がチュートリアルにあったはずです。恐らくこのようなフルカラーの画像を扱う上では、計算コストはかかりますが畳み込み層を入れたほうがよいのでしょう。更にCNNのよいところは、全層結合のモデルで画像認識させる際に必要となる初期化処理(自己符号化器などを用いて、前もって適当な重みをそれぞれのノードにかけておかなければならない)をせずに学習させることができるところにもあります。

Kerasではこういった一直線のSequentialなモデルは、層を列挙していくだけで簡単に記述することができます。CNNを用いることとした上で、サンプルのモデルを使って数字をいろいろ変えてみてチューニングするといったことをしました。より高度なモデルを作るとしたら、論文を読むとか、強い人のものを参考にするという方法もあります。

github.com

例えばこのように公開されているKaggleで用いられたNeural Network Configurationsを参考にして層を増やすといったことは考えられます。ただ一方で、モデルを複雑にしたところでそもそも学習させる画像データが少ない場合、計算時間ばかりかかって満足できる結果を得ることにはつながりませんでした。

入力の扱い

機械学習に食わせるためには、入力を区間[0,1]のn次元配列(テンソル?)にする必要があります。例えば文章であれば文を単語に分けて、同じ単語に対して一意の数字を割り振ったベクトルとして表現できます。デジタル画像では、BMP形式だとわかりやすいですが1ピクセルに対してグレースケールであれば1つの値、カラー画像であればRGBの3つの値で表現することがすでにできているので、それをそのまま入力とすることを考えます。(ただし0〜1の範囲に落とし込むため、255で割る必要があります。逆に255で2回割ってしまうと全く予測結果がおかしなことになるので注意)

Kerasの例をみると、MNISTのようなグレースケールのものは1枚の画像は縦☓横の2次元配列で表されて、それ自体が1つの配列にすべて格納されている形で学習データを構成するので実質は3次元配列が入力全体となります。cifar10ではカラー画像なので1枚の画像は縦x横xRGBの3次元配列で表されて、それを1つの配列に全部格納するので実質4次元配列が入力の形となります。

分類結果は5値分類であれば0,1,2,3,4のように表現されますが、ここではバイナリ配列として扱う([1,0,0,0,0],[0,1,0,0,0],...のように)必要があります。これは関数が用意されているのでそのまま使います。

Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)

ではcifar10の場合に入力配列をどう生成するかということですが、Tensorflowではバイナリファイルから読み込むスタイルでした。このバイナリファイルの構造は簡単で1行に1画像であり、最初の1バイトが分類値で、次にRGB値が1024バイトごと入っているものでしたが、KerasではPythonのcPickle化されたものを入力として使っていました。サンプルコードをそのまま流用するためには画像をcPickleに落とし込まなければならないのですが、好きな画像群からダンプする場合は下の記事のコードのインスタンス変数名を少し変更することでカラー画像の読み込みを作ることができました。

qiita.com

私はこの時に、上下位置を少しずつずらした画像を作って学習効率の増強に努めました。KerasにもImageDataGeneratorというのがあって画像を適切に加工してくれるようなのですが、私が試した時はデータ数が少ないためもあったのか、うまくいきませんでした。(何度学習させてもlossが減らない、学習中に明らかにおかしいlossの変動がみられるなど)

また入力画像として、あまり関連性のない画像を分類問題として与えるとうまくいかないことが多かったです。例えば画像がアニメキャラのものか実在する人間のものかを二値分類するのはそれなりに精度がよかったのですが、あるアニメの登場人物と別のアニメの登場人物をそれぞれ集合として与えた時、登場人物1人につき1枚ずつの写真が大量にあったとしても、うまくいきませんでした。

予測するには

Tensorflowではセッションに対してrunを呼ぶとき、学習データと分類値を入れれば学習になるし、feed_dict=にテストデータを与えれば分類が受け取れるということのようだったのですが、Kerasではpredictという専用の関数があります。これに学習データを投げると、配列で受け取ることができます。またpredict_classesを呼ぶと、分類結果のラベルだけを表示してくれます。

学習させた後のモデルを最後にこんな感じのコードを追加すると、architecture.jsonにはモデル構造がJSON形式で、weights.h5にはそれぞれのノードの重みが保存されます。

model_json = model.to_json()
open('architecture.json', 'w').write(model_json)
model.save_weights('weights.h5', overwrite=True)

予測させたいときには

def load_model(model_def_fname, model_weight_fname):
   model = model_from_json(open(model_def_fname).read())
   model.load_weights(model_weight_fname)

こんな感じで呼べるので、これを再びコンパイルしたものを使ってpredictすると、1回の学習データをもとにさまざまなデータに対して予測をすることが簡単にできます。

ところでこれはpythonというかnumpyのtipsなのですが、多値分類は結果の値が指数表現になることがあります。こうなってしまったとき小数点以下の値が見にくいときは、

import numpy as np

np.set_printoptions(suppress=True) # 小数表現にする
np.set_printoptions(precision=3) # 小数点以下3桁まで表示させるようにする

と書くとprintしたときにわかりやすくなるでしょう。

サービス化する

Kerasを使った予測サービスをWeb上で展開しようというとき、金があればいくらでも方法はあるのですが、個人レベルで且つ無料で済ませたい(且つアクセスを期待しない)場合はどうするかという問題があって、検討した結果を記述します。

ここでやりたいのは学習済みのarchitecture.jsonweights.h5を置き、解析用のコードとwebサーバーを立てておいて、そこに入力のベクトルをPOSTすると予測結果を返すものを作るということです。TensorflowはPythonなので、Webサーバーは同じくPythonのFlaskとかで記述すると書きやすいです。

heroku

herokuは18時間までならタダで動かせるのでこれを使うのが一番王道だと思いますが、dockerコンテナを立てるにはクレジットカードが必要です。そうしない場合はKerasのバックエンドとなるTensorflow、Theanoをどちらもheroku上にインストールすることができませんでした。Theanoをrequirements.txtに記述してpush時にpipでインストールさせようとしても、まず最新バージョンが落とせない。それにビルドの途中で

 Problem occurred during compilation with the command line below:
 /usr/bin/g++ -shared -g -march=core-avx-i -mcx16 -msahf -mno-movbe -maes -mpclmul -mpopcnt -mno-abm -mno-lwp -mno-fma -mno-fma4 -mno-xop -mno-bmi -mno-bmi2 -mno-tbm -mavx -mno-avx2 -msse4.2 -msse4.1 -mno-lzcnt -mno-rtm -mno-hle -mrdrnd -mf16c -mfsgsbase -mno-rdseed -mno-prfchw -mno-adx -mfxsr -mxsave -mxsaveopt --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=25600 -mtune=core-avx-i -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION -m64 -fPIC -I/app/.heroku/python/lib/python2.7/site-packages/numpy/core/include -I/app/.heroku/python/include/python2.7 -I/app/.heroku/python/lib/python2.7/site-packages/theano/gof -fvisibility=hidden -o /app/.theano/compiledir_Linux-3.13--generic-x86_64-with-debian-jessie-sid-x86_64-2.7.7-64/lazylinker_ext/lazylinker_ext.so /app/.theano/compiledir_Linux-3.13--generic-x86_64-with-debian-jessie-sid-x86_64-2.7.7-64/lazylinker_ext/mod.cpp -L/app/.heroku/python/lib -lpython2.7
 /usr/bin/ld: /app/.heroku/python/lib/libpython2.7.a(abstract.o): relocation R_X86_64_32S against `_Py_NotImplementedStruct' can not be used when making a shared object; recompile with -fPIC
 /app/.heroku/python/lib/libpython2.7.a: error adding symbols: Bad value
 collect2: error: ld returned 1 exit status

というエラーメッセージが出て駄目でした。Tensorflowは下のページを見る限り動かなさそうでしたし、herokuを予測サーバーに使うのは断念しました。

d.hatena.ne.jp

Openshift Online

これもしばしば無料でWebサーバー立てる際に使うのですが、今回は試していないです。

Arukas.io

arukas.io

さくらインターネットが出しているDockerホスティングサービス。つい最近公開されましたが、Dockerイメージを今の所制約なしにホスティングしてくれるのはかなりありがたいです。TheanoやTensoflowのインストールでこけるぐらいなら、全部入りのDockerイメージをアップロードしてしまうほうがはるかに楽で、Dockerfileにkeras + tensorflow + flaskを入れる設定を書いてDocker hubにアップロードし、それをArukas.ioにデプロイするというフローで拍子抜けするほど簡単に予測サーバーを立てることができました。メモリは512MBに設定していますが予測する分ならほとんど手元のマシンと変わらない速度で動いている感があります。

続き

Kerasを用いて様々な処理を施した所感は以下になります。

sharply.hatenablog.com

Refernces

Neural Networks using Keras on Rescale | Rescale

www.slideshare.net

github.com

IBMのx10チュートリアルをやる

tl;dr

IBMのx10言語という、並列計算に向いた言語がある。言語仕様の詳細は省くが、scalaライクにオブジェクト指向で書ける言語の割に、MPIほど面倒なことを書かなくてもネイティブなC/C++のコードを吐いてくれるので速度が出るというありがたい言語である。

このチュートリアルをやってみた時に戸惑ったことの備忘録。なお、バージョンアップによる記法の変動が割と大きいので注意されたし。以下の環境で動作を確認。

x10c++ version 2.5.4

x10-lang.org

なお、見るとわかるがver2.5のチュートリアルはなく、ver2.4のチュートリアルはAPGASと呼ばれるjava用のライブラリの説明しかないので、ver2.2のものを使うしかないので注意。

Sequential Monti Pi

(-1,-1),(1,1),(-1,1),(1,-1)で囲まれた空間にランダムに点を打ったとき、円周内に入った点の数から円周率を計算できるというもの。モンテカルロ法の亜種。

  • args:Rail[String]

argsの後のRailは引数不要になっているので、()を外そう。

The x10.lang.Rail class also provides a similar, high-performance implementation of a one dimensional array. The expectation should be that a Array_1 and a Rail should have very similar performance characteristics, although the Array_1 has an additional wrapper object and thus may have marginally lower performance in some situations.

Arrayクラスもあるのだが、一次元配列の場合はより高速なRailを使うのがよいかもしれない。

  • Place.MAX_PLACES is duplicated by Place.numPlaces()

MAX_PLACESで検索しても古いドキュメントしか出てこなくて途方に暮れてしまうのだが、Placeクラスのドキュメントを見るとnumPlaces()になっているらしい。

その他のtips

  • Mismatched input 'var' expecting {'--', '|', '-', '!', '!=', '%', '&', '&&', '(', '*', ',', '.', '/', ';', '?', '[', '^', '||', '~', '+', '++', '<', '<<', '>>', '>>>', '<=', '==', '>', '>=', '..', '->', '<:', ':>', '**', '!~', '<-', '-<', '>-', '<>', '><', 'as', 'haszero', 'instanceof', 'isref'}

このエラーを見かけたら;が欠落していることを疑ったほうが良い。CやC++と同様。

  • 配列の添字を()で表す

CやC++に慣れていると[]とついつい書いてしまうがエラーが出る。

  • 型のキャストをas Intのようにする。
val x:Long = 4 as Long;
val x:Long = 4L;

例えばLong型であれば数字リテラルの末尾にLをつけるだけでもよい。Byte型やらShort型やらchar型やら、型はやたらめったら出てくるので場合に応じた適切なものを用いるとよい。

  • staticをつけるとクラスに属するメソッドになる

これはC++JAVAと同じですが、rubyでいうところのシングルトンメソッド・特異メソッドになります。実際にはrubyのシングルトンメソッドは外から呼べるので、public staticに対応しているといえるでしょう。staticにするだけでは、クラスの内部からしか呼べません。

(x10)

class Node {
  public static def length(){
  }
}

(ruby)

class Node
  def self.length
    
  end
end
  • Pair型 Pair(T first, U second) 例えば関数の返り値をペアにできる。

Gentoo Linuxにxmonadを導入する

動機

Gentoo Linuxではコンパイルに時間がかかるので、大規模なデスクトップ環境を構築しようとするとすごい時間がかかる。 当方はGNOME派だが、恐らくGNOMEKDEを入れるのは骨が折れるだろう。コテコテのデスクトップ環境を構築するのもそれはそれで一興だが、今回は敢えて軽量な環境とするためにタイル型を導入してみたいと思う。

タイル型デスクトップ環境といえばawesomeも有名だが、ここではHaskellで設定ファイルが記述できるxmonadを導入することとした。

Emerge

# emerge xmonad xmonad-contrib xmobar

依存関係を確認すると、その場でコンパイルするのでghcが必要となり、これのコンパイルにものすごい時間がかかるので、先に入れておくとよい。xmonad-contribxmonadの設定ファイルを書く際に便利なアルゴリズムが同梱されているので導入しておきたい。また、ここではステータスバーとしてxmobarを入れることとした。

この他にもHaskellのcabalを使って導入する方法もあるが、せっかくPortageツリーに入っているのでemergeで入れることとした。

xmonadxmobarの相性について

xmonad上でアプリケーションを開きながらその上にxmobarを重ねる場合、設定ファイルにどう記述してもなぜか下に潜ってしまう問題が起きた。 これは0.12を使っていたからということらしい。gentooPortageツリーに入っていた安定版の0.11を使うと解決した。

Usage

modキーをAltに割り当てると他のキーバインドと重複して厄介なので、Windowsボタンに割り当てることとした。基本的な使い方は以下が詳しい。(但し以下ではGNOME共存させているが、今回はxmonad単体で実行している)

blog.blueblack.net

http://blog.drmn.jp/2013/04/haskell-xmonad.html

参考サイト

https://wiki.archlinuxjp.org/index.php/Xmonad

Gentoo Linuxでうどんワールドする

tl;dr

Gentoo LinuxPortageを使う際、

# emerge --uDNva @world

をしたときに大量に循環依存やエラーメッセージが出た場合の対処策。

まずはメッセージを読む

$ man emerge

emergeコマンドの説明(できれば英語版のようがよい)を読みながら、出力の意味を理解する。 USEフラグを立てろと言われた場合は、メッセージの通りに設定してもよいですが、私はflaggieを使って管理しています。 maskしろと言われた場合も同様。

例:app-emulation/dockerでaufsフラグを立てたい場合

$ sudo flaggie app-emulation/docker +aufs

それとnewsを読むと役に立つ情報が手にはいります。

$ eselect news read

循環参照じたいは、メッセージで表示されるパッケージに関わるUSEフラグを適当に-gtkとか-emacsとかしておいてからemergeして片方ずつ入れれば解決することが多いです。

ghcperlのコンフリクトを解決する

ghcperlといったプログラミング言語本体のパッケージの更新が関わってくると、バージョンの違いによって依存するライブラリがエラーを吐くことがあります。このときは関連するライブラリは入れずに、まずはghcperlだけを先に更新し、それからライブラリをツールを使って一括で更新する、ということでエラーメッセージを回避することができます。

@worldからやると関連のライブラリを更新しようとするためにエラーメッセージが出ることがあり、@systemをまず対象とするとエラーメッセージが出ないかもしれません。そうでない場合は個別にghcperlを選択し、更新をかけましょう。

その後しばしば@preserved-rebuildをしろというメッセージが出るので、実行しましょう。これによってパッケージの更新によって壊れた依存関係を解決してリビルドしてくれます。

emerge -1 @preserved-rebuild

ここで-1というフラグをつけることで、--oneshotつまり、ここで指定したパッケージは@worldに含まずに更新することができます。こうすることで、どうでもいいパッケージの更新を追尾せずにすむので、@worldの肥大化を防げます。

その後、perlであればperl-cleaner --all, pythonであればpython-updatorといったコマンドが用意されているので、その言語固有のパッケージの更新をかけることで、バージョンアップに伴う依存関係の再構築を行うことが可能です。

dispatch-confする

/etc/以下のファイルを、emergeによって推奨する設定に書き換えるとき、それらの作業は手動で行われなければなりません。 古い文献ではetc-updateしろと書いてある場合がありますが、dispatch-confのほうが良さそうです。

dispatch-conf の使い方 - WebOS Goodies

あとは最後に、不要となったパッケージを整理するだけです。

$ emerge --depclean

参考ページ

d.hatena.ne.jp

hanepjiv: Gentoo Linux / gentooのアップデート

Gentoo Linuxでtestingブランチを使わないことにする

tl;dr

AMD64環境のGentoo LinuxXmonadを入れるときに、一部のdev-haskellパッケージのUSEフラグで~amd64を追加するように指示された。

/etc/package/make.confACCEPT_KEYWORDS="~amd64"と指定してうどんワールド *1 してしまったせいで、次の日から大量の更新パッケージが降ってきてうどんワールドすると大変なことになった。

ACCEPT_KEYWORDSの指定を外すと、今度は大量のダウングレードとそれに伴う依存性破損が生じて大変なことになった。従って、現行のバージョンをできるだけ維持して、今後はstableブランチを使うようにしようとした。

~amd64とは

amd64環境ではstableでないパッケージをインストールする時に用いるフラグ。

これをつけないと、Firefoxは38が最新だし(現行は45)Dockerは1.7が入ってくるし、割と悲惨な目に遭うが、testing環境ではどんどん新しいパッケージが降ってくるのでコンパイルするだけでやたらと時間をとられる。

今回の問題はグローバルに~amd64をつけてしまったことにあり、最新のパッケージを使うぶんには良いのだが、毎日emergeに時間をとられるのが辛い場合は、stableなブランチに戻したくなる。

応急処置

暫定的に、ひたすらmaskをかけて「現行のバージョンより古いバージョンのパッケージをemerge」しないこととした。

<app-i18n/fcitx-anthy-0.2.2
<x11-misc/xfe-1.41
<sys-boot/os-prober-1.71
<media-fonts/jp-ipafonts-003.03
<x11-libs/libdrm-2.4.67
<app-portage/layman-2.3.0-r1
<x11-terms/rxvt-unicode-9.22
<x11-terms/xterm-324

このような形で、現行のバージョン未満の値のパッケージをmaskすれば、それらのパッケージがemergeされることはなくなるので、とりあえず今のバージョンが保たれる。さすがに全てのパッケージに対してこれを記述するのは大変なので、主立ったツールコンパイルに時間のかかるfirefoxghcなどを中心に指定した。

謎のvirtual/パッケージのせいで様々な依存関係が生じる

うどんワールドしたときの依存性をツリーで表示させたときに、例えばvirtual/dev-managersys-fs/static-devを要求しているが、sys-fs/static-devをemergeしようとすると怒られたとする。

このときは、virtual/dev-managerをemergeすると何が起こるか見てみることにする。/usr/portage/virutal/dev-manager/dev-manager-0.ebuildを開く。

# Copyright 1999-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

EAPI="2"

DESCRIPTION="Virtual for the device filesystem manager"
HOMEPAGE=""
SRC_URI=""

LICENSE=""
SLOT="0"
KEYWORDS="alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 s390 sh sparc x86 ~sparc-fbsd ~x86-fbsd"
IUSE=""

DEPEND=""
RDEPEND="|| (
        virtual/udev
        sys-apps/busybox[mdev]
        sys-fs/devfsd
        sys-fs/static-dev
        sys-freebsd/freebsd-sbin
    )"

ここで大事なのはRDEPENDのところで、||はorのことであるから、列挙されているパッケージのうち、どれか1つをインストールすればよいということである。

Gentooとは選択である。

今回は上から順に、ということでvirtual/udevをemergeしてみたところ、そのパッケージは既に入っているがstableブランチよりバージョンが新しいので、~amd64のフラグが足りないと言われた。それを付けると、今度は依存性解決がうまく行ってemergeできた。

参考ページ

d.hatena.ne.jp

ACCEPT_KEYWORDS - Gentoo Wiki

*1:sudo emerge -uDN @world

Gentoo Linuxをインストールする

パーティション設定

* sda2 128M part /boot ext2
* sda3 論理パーティション
    * sda5 8G swap
    * sda6 96.8G part / btrfs

メモリを2GBしか積んでいないので、コンパイル時にSwap領域を使うかと思って8GBぐらい確保しておいた。 btrfsが死なないことを祈る。

インストールの流れ

  • 予め他のlivecdでgpartedなどを使ってパーティションを切っておく。
  • Livecdで起動し、hddをマウントしてchrootする。(手元にあったArchbootを使ったが問題なし。)
  • sshdを立てて、ssh接続でインストールした。wikiをみながら作業するとよいと思う。
  • locale等の諸設定をして、カーネルの設定をしてカーネルmakeする。何度やってもよい。
  • grubの設定をして(重要)、再起動してhddから起動するようにBIOSを設定する。
  • 起動したらインストール自体は成功。うまくいっていない場合はchrootからやり直し。

はまったこと

  • ネットワークのドライバが入っていないために、有線LANにつながらない。
  • startxすると怒られる。RADEONのドライバを認識してくれない。
  • 何度もライブcdからchrootし直すはめになる。
  • コンパイル中は暇。

対策

カーネルの設定時に忘れずにネットワークカードを選択する。

lspci -k | grep driver

をlivecdでした際の結果と、gentoo内でした結果を比較して、足りないドライバーをカーネルコンパイルオプションで追加する。 カーネルビルトインではなくモジュールで追加するようにすると、動かすものを明示的に指定できるためうまくいくことがある。

d.hatena.ne.jp

RADEON系のグラボを使っている場合、xf86-video-atiを使うことになるが、その際はカーネルでbinファイルを指定しなければならない。

startxしたときのエラーメッセージに、Device(s) detected, but none match those in the config fileとかいう文が入っていたら、ドライバが正しく動いていないことがある。

fglrx - Gentoo Wiki

amdのドライバはプロプライエタリなもの(Fglrx)とオープンソースのものがあるが、上をみるとRADEONの古いバージョンだと新しいxorgを入れられないということがわかったので、オープンソースのドライバを選択することにした。

radeon - Gentoo Wiki

これを読んで、カーネルの設定で正しくradeon/<YOUR-MODEL>.binを指定しなければならない。ドライバが認識されると、コンソールの解像度が適切なものになる(はず)

何度でもchrootし直すはめになる

mkdir /mnt/gentoo 
mount /dev/sda6 /mnt/gentoo
mount /dev/sda2 /mnt/gentoo/boot
mount -t proc proc /mnt/gentoo/proc
mount --rbind /dev /mnt/gentoo/dev
mount --rbind /sys /mnt/gentoo/sys
chroot /mnt/gentoo /bin/bash

source /etc/profile

その都度livecdから入り直し、上のコマンドをコピペして対応した。

うどんワールドする

ソフトウェアの更新をする際に。

# emerge -uDN @world

これで依存関係と新しいUSEフラグを含めて、アプリケーションをすべて更新できる。俗に言う「うどんワールド」である。

参考ページ

http://syusui.tumblr.com/post/17262231474/gentoo-linux-インストール-メモ
syusui.tumblr.com

Gentoo Linuxをインストールする

ハンドブック:AMD64 - Gentoo Wiki

ビギナーズガイド - ArchWiki

なんだかんだarchwikiは頼りになる。

Dockerでサーバーを立てる(2)

それでは実際に、Docker-composeでRailsアプリを立てるところまでやってみたいと思う。

構成

今回のdocker-compose構成は以下である。

supervisordで1つのコンテナに全て立てるのはやはりdockerの原則に反していると思うので、原則として1プロセス1コンテナとした。 まずデータコンテナを置いて、そこにlogを取っておいて各コンテナをマウントするのはデータ永続化の手法としてしばしば用いられるらしい。 mysqldを立てていないのはsqlite3を使っているためである。sqlite3のファイル自体はデータコンテナに格納できていると思われる(?) やはりsqlは別コンテナに立てるべきだと思うので今後、改善したい。

unicornではなくpumaを使う

blog.willnet.in

リバプロとしてnginxを立てる以上、スロークライアントとの通信はリバプロが引き受けるためにunicornの弱点であるプロセスの専有は防げるらしいので、pumaをアプリケーションサーバーとする必要はないらしい。だが敢えてnginx+pumaで立ててみる。

yuuki.hatenablog.com

ちなみにこのエントリが、アプリケーションサーバーの機構についてまとめてあり参考になる。Unicornはマルチプロセス(prefork)型だが、Pumaはマルチスレッド型(スレッドプール)とマルチプロセス型のhybridだそうだ。但し、Rubinius or JRubyを使うことが推奨されている。今回はMRI上で動くアプリだが、TwitterAPIを叩くようなBlocking I/Oを呼ぶようなことはないので使っても大丈夫だろうという判断である。

実際のソケットの設定方法などはunicornを使ったパターンが多く、情報が少なく苦労したがこのあたりを調べた。

www.digitalocean.com

arakaji.hatenablog.com

Arch linuxによるnginxサーバーを立てる時の注意点

既存のnginxイメージを使ってもよいのだが、せめてこれぐらいはArch linuxで立てたいと思ってDockerfileを記述した。

RUN \
        pacman -Syu && \
        pacman -S nginx --noconfirm

ADD ./nginx.conf /etc/nginx/nginx.conf

VOLUME ["/etc/nginx/sites-enabled", "/etc/nginx/certs", "/etc/nginx/conf.d", "/var/log/nginx", "/var/www/html"]

WORKDIR /etc/nginx

EXPOSE 80

ENTRYPOINT /usr/sbin/nginx -g 'daemon off;'

この中で、

ADD ./nginx.conf /etc/nginx/nginx.conf

の部分が厄介で、Arch linuxのnginxでは/etc/nginx/nginx.confinclude /etc/nginx/conf.d/*.conf;という記述がないので、そのままでは/etc/nginx/conf.d/nginx.confなどに設定ファイルを記述したところで自動で読み込んではくれない。そこで、もとの/etc/nginx/nginx.confを手元のファイルで上書きする必要があるのだ。

結論:自分でDockerfileをフルスクラッチで書こうとするより、先駆者のものを参考にするのがよい。

github.com

実行

Dockerfile, docker-compose.ymlがアプリのルートディレクトリに置いてあって、Arch linuxによるnginxサーバーのイメージは予めbuildしてあることとする。

$ docker-compose up -d

これで、コンテナをcreateして実行してくれる。Dockeruiによる管理をしていれば、webui上で正常に動作しているかどうかを確認できる。

その後、dbのmigrationは実際に内部に入って行う必要がある。

$ docker exec -it app bash
# bundle exec rake db:migrate
$ docker-compose down

これでコンテナを消せるので、失敗したものはどんどん消していくとよいと思う。

参考ページ

qiita.com

qiita.com