カテゴリー別アーカイブ: ライブラリ

aws g2インスタンスでtensorflowをGPUサポートで動作させる

概要

機械学習をやる機会があり、巡り巡って こちら の word-rnn を tensorflow 上で動作させるものにめぐりあいました。

学習をするにあたって入力データがそれなりの量になってくると学習に時間がかかり、現実的な時間では終了しません。
そこで色々調べてみると tensorflow には GPUをサポートする機能があり、それによって処理の高速化が図れるようです。
GPUは通常名前のごとくグラフィック処理用の演算装置ですが、その演算処理が機械学習にも応用できるということですね。

今回はそれをaws環境で実行するべく、グラフィックボードを持つg2タイプのインスタンスで動かすことを目標としました。

先人たちの遺産について

一年くらい前から同じようなことをやろうとしていた人たちの記事が結構色々出てきます。
日本でのドキュメントもそこそこ出てきます、が初めから断言しておきますと、かなりの記事がもはや古くなりすぎていて参考になりません

このあたりの流れが非常に早く、現在では随分具合が異なるようです。

またこの記事も将来的に現実と乖離してくると思いますので、その点は十分注意してください。

インストールしてみる

色々参考にしたところ皆さん Ubuntu14.04 のAMIでやられていたので、自分もそれに倣うことにしました。
インスタンス起動後、まずは様々な記事でも導入されているように、必要なモジュールをインストールします。

$ sudo apt-get update
$ sudo apt-get upgrade -y
$ sudo apt-get install -y build-essential python-pip python-dev git python-numpy swig python-dev default-jdk zip zlib1g-dev ipython

二つ目のコマンドを実行するとGRUBローダーの設定を迫られたりしますが、自分の場合は何も選択せずに次に進み
次の選択肢では install package maintainers version を選択しました。

また参考記事の通りに実行していきます。

$ echo -e "blacklist nouveau\nblacklist lbm-nouveau\noptions nouveau modeset=0\nalias nouveau off\nalias lbm-nouveau off\n" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
$ echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
$ sudo update-initramfs -u
$ sudo reboot

ここで一旦再起動

$ sudo apt-get install -y linux-image-extra-virtual
$ sudo reboot
# Install latest Linux headers
$ sudo apt-get install -y linux-source linux-headers-<code>uname -r</code>

ここまで来たら tensorflowの公式ページ に従ってインストール作業を進めましょう。

以下は公式サイトの引用ですが、現在では Cubaのバージョンを8.0、cuDNNのバージョンを5をインストールすれば問題ないようです。

Download and install Cuda Toolkit
https://developer.nvidia.com/cuda-downloads
Install version 8.0 if using our binary releases.
Install the toolkit into e.g. /usr/local/cuda.
Download and install cuDNN
https://developer.nvidia.com/cudnn
Download cuDNN v5.

この2つのモジュールをインストールしたあとで 公式ページに則ってpip経由でインストール作業を行います。

自分の場合は python2系 を対象としたかったので下記のように実行しました。

$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.0rc0-cp27-none-linux_x86_64.whl
$ sudo pip install --upgrade $TF_BINARY_URL

アプリケーションコードを実行したところ下記のように正常にモジュールライブラリを実行できているようです。
(幾つか警告のようなものもありますが)
またGRID K520というg2インスタンスで搭載しているグラフィックボードの名前も確認できます。

I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally
I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:936] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties:
name: GRID K520

処理自体もCPUでの処理と比べて高速化できているようでしたので、これにてインストール作業を完了しました。

参考記事

http://qiita.com/h860a/items/294262d98e1223008252


PHPでYAMLファイルを取り扱う

概要

PHPでYAMLファイルを取り扱う方法について2つの方法を取り上げて解説したいと思います。
PHPでは純正のyamlライブラリが標準では無いため、別途用意する必要があります。

  • yaml拡張モジュール
  • yaml拡張モジュールとはlibyamlを用いた拡張モジュールになります。
    cで記述されているため高速に動作することが見込まれます。

  • Spyc
  • また完全にPHPのみを用いて記述されたyamlライブラリも存在し、そのうちの一つにSpycというも有名なのがあるのでこれも取り扱います。公式ページ
    特徴としては拡張モジュールはインストール作業が必要なのに対してSpycに関してはPHPのみで記述されているライブラリなので、複雑なインストール作業は不要です。
    1ファイルで構成されているのでリンク先からファイルをダウンロードし、Spyc.phpをrequireするだけで使用できる状態になります。非常にお手軽です。

    準備する

    それぞれの実装が使用できるように準備しましょう。

  • yaml拡張モジュール
  • 拡張モジュールはlibyamlおよびlibyaml-develを事前にインストールした状態でpeclコマンドを用いてインストールすることができます。
    rootになるまたはsudoコマンド経由で下記のようなコマンドを実行すれば完了です。

    [root@localhost ~]# yum install libyaml
    ...
    [root@localhost ~]# yum install libyaml-devel
    ...
    [root@localhost ~]# pecl install YAML
    ...
    
  • Spyc
  • 対してSpycは先にも述べましたがソースコードをダウンロードしてきて使用したい箇所でrequireするだけです。
    最近ではgithubでソースコードを管理されているようなので下記のようにcloneしてくれば十分だと思います。

    git clone https://github.com/mustangostang/spyc/
    

    検証してみる

    先にSpycで動かしてみましょう
    使用箇所でrequireします。するとグローバルでspyc_load_fileという関数が使用可能になります。
    これは引数としてファイルパスを与えることで、ファイルを読み込んでyaml形式でパースを行います。
    下記のような感じでOKです。

    <?php
    require_once (dirname(__FILE__) . '/Spyc.php');
    
    $obj = spyc_load_file('hoge.yaml');
    var_dump($obj);
    

    hoge.yamlは下記のように記述しておきましょう。

    - foo
    - bar
    

    すると出力結果は下記のようになります。

    array(2) {
      [0]=>
      string(3) "foo"
      [1]=>
      string(3) "bar"
    }
    

    動きましたね〜。

    対してyaml拡張モジュールではphp.iniにyaml.soライブラリをロードするように追記します。
    するとyaml_parse_fileという関数がグローバルで使用可能になります。
    こちらも同様に引数としてファイルパスを与えることで、ファイルを読み込んでパースを行います。

    $obj = yaml_parse_file('hoge.yaml');
    var_dump($obj);
    

    こちらも同様に、動きましたね。

    ただこの2つにはかなり挙動の違いがあるような箇所もあります。
    例えば入力ファイルの中身を下記のように編集したとしよう

    foo : bar
    bar
    

    この内容をパースすると

    Spycでは下記のようにパースされる。

    array(2) {
      'foo' =>
      string(3) "bar"
      [0] =>
      string(3) "bar"
    }
    

    たいしてyaml拡張モジュールではワーニングが表示され返り値としてはfalseがかえってきます。
    パースに失敗しているのです。

    PHP Warning:  yaml_parse_file(): scanning error encountered during parsing: could not find expected ':' (line 3, column 1), context while scanning a simple key (line 2, column 1) in /tmp/hoge.php on line 2
    bool(false)
    

    はたしてこれらは一体どちらが正しいのか。
    異なるフォーマットが与えられた時にちゃんとしてくれないのは困る。

    これに関していえるのはbarの扱いをどのように解釈しているのか、である。

    yaml1.1の仕様書を参考にしてみる。
    パラパラっと見た感じ、スカラ値のみで構成されるような場合は定義されていない。
    したがって結果として拡張モジュールでパースエラーが発生しているほうが安全であると言える。
    Spycではこれを意図的しているのかしていないのかは分からないが、純粋に配列の頭に付け加える(index:0)ことでパースを試みる。

    また別な例として下記の例もある。
    yamlではいくつかのメタ文字を定義していて
    例えば~はNULLを意味するしyはtrueを、nはfalseを意味する。などがあります。
    これらは型情報も一緒に解釈されるべきであります。

    実際に下記のようなyamlデータを用意して食わせてみましょう。

    null: ~
    true: true
    false: n
    string: '12345'
    

    Spycでの出力結果は下記のようになります。

    array(4) {
      'null' =>
      NULL
      'true' =>
      bool(true)
      'false' =>
      bool(false)
      'string' =>
      string(5) "12345"
    }
    

    yaml拡張モジュールでは下記のようになります。

    array(3) {
      [""]=>
      bool(false)
      [1]=>
      bool(true)
      ["string"]=>
      string(5) "12345"
    }
    

    驚いたことにyaml拡張モジュールでの出力結果は、はっきり言って構成を壊してしまっているといってもいいです。
    yaml界では一般的なのだろうか。

    対してSpycではメタ文字が使用されたとしてもキーとして使用されているうちは一意にstringとして解釈されるようです。
    拡張モジュールの方ではキーで使用される際もメタ文字として解釈され、結果わけのわからないことになっちゃってます。

    実際に用途として拡張モジュールのように解釈されてしまうと困ることのほうが困るような気がします。
    この辺りは逆にSpycのほうが直感に沿った解釈をしてくれているのかなと思います。

    好みのチョイスであるところもあるかもしれませんが、今回私はSpycの方をチョイスして実装の方を進めることにしました。
    今のところそこまで悪いところはなさそうです。
    (それに余談ですがインフラ都合もあって簡単にミドルモジュールをいじれるような状況でもないので)

    とりあえず、一点だけSpycで直して欲しいところがあったりして、spyc_load_fileファイルは読み込むyamlファイルパスを指定することでファイルを読み込めるのですが、引数に存在しないファイルを指定した際にもなんと普通に動いちゃいます

    たとえば下記のようなプログラムを実行すると

    <?php
    require_once (dirname(__FILE__) . '/Spyc.php');
    // aaaaは存在しないファイル
    $hoge = spyc_load_file('aaaa');
    var_dump($hoge);
    

    下記のように出力されます。

    array(1) {
      [0]=>
      string(4) "aaaa"
    }
    

    これまずくない??
    個人的には返り値がfalseになるとか例外投げるとかいろいろ設計はあると思うんですが。
    明らかに設計ミス?なにか意図があるのかと理解に苦しみます。

    と、、まあ今のところそんなこともあるのですが、また追加で問題などあれば追ってレポートしたいと思います。