読者です 読者をやめる 読者になる 読者になる

Windows 上に Python 環境を構築して Tensorflow GPU + Keras で日本古典籍字形の文字認識を試すまで

tilfin.hatenablog.com

こちらの記事で書いたように Windows で Tensorflow を GPU で試してみました。この中で Python をオフィシャルのインストーラから入れて virtualenv で動作環境を作成したのですが、後々 matplotlib や OpenCV を入れようとしたところ Windows のために諸々嵌ることがあったので、より簡単に All-in-One 導入できる Anaconda から入れてみることにしました。

www.procrasist.com

またこちらの記事で見た Keras が、今後 Tensorflow で色々と試す上で非常分かりやすそうだったので、導入してみることにしました。

Anaconda で Python 3.5 をセットアップ

既にインストールしていた Python は「プログラムと機能」からアンインストールしておきました。

Download Anaconda Now! | Continuum から [Python 3.5 version 64-BIT INSTALLER] をダウンロードして実行します。インストール ウィザードで環境変数を通しておきます。(デフォルトのインストール場所ではなく D:\Anaconda35 に自分は入れました。)

Tensorflow + Keras をセットアップ

環境構築

ここから先は PowerShell で行います。

conda で work という名前の環境を作ります。

PS D:\> conda create -n work python=3.5 anaconda

…省略…

Extracting packages ...
[      COMPLETE      ]|##################################################| 100%
Linking packages ...
        1 個のファイルをコピーしました。##################               |  71%
[      COMPLETE      ]|##################################################| 100%
#
# To activate this environment, use:
# > activate work
#
# To deactivate this environment, use:
# > deactivate work
#
# * for power-users using bash, you must source
#

Tensorflow の導入

work 環境にして pip で tensorflow と tensorflow-gpu をインストールします。

PS D:\> activate work

PS D:\> pip install tensorflow
Collecting tensorflow
  Using cached tensorflow-0.12.1-cp35-cp35m-win_amd64.whl
Requirement already satisfied (use --upgrade to upgrade): wheel>=0.26 in d:\anaconda3\lib\site-packages (from tensorflow)
Collecting protobuf>=3.1.0 (from tensorflow)
  Using cached protobuf-3.1.0.post1-py2.py3-none-any.whl
Installing collected packages: protobuf, tensorflow
Successfully installed protobuf-3.1.0.post1 tensorflow-0.12.1

PS D:\> pip install tensorflow-gpu
Collecting tensorflow-gpu
  Using cached tensorflow_gpu-0.12.1-cp35-cp35m-win_amd64.whl
Installing collected packages: tensorflow-gpu
Successfully installed tensorflow-gpu-0.12.1

Keras をセットアップ

Keras Documentation は numpy, scipy, pyyaml OpenCV, HDF5, hdf5 に依存しています。この中で OpenCV は anaconda で入らないので別途インストール必要があります。

OpenCV 3.2 をインストール

hikuichi.hatenablog.com 単純に pip でインストールしても Windows では動かないので、こちらを参考にビルド済みパッケージを使って、OpenCV をインストールします。 http://www.lfd.uci.edu/~gohlke/pythonlibs/ から opencv_python‑3.2.0+contrib‑cp35‑cp35m‑win_amd64.whl をダウンロードして、 pip で絶対パスを指定してインストールします。

PS D:\> pip install D:\opencv_python-3.2.0+contrib-cp35-cp35m-win_amd64.whl
Processing d:\opencv_python-3.2.0+contrib-cp35-cp35m-win_amd64.whl
Installing collected packages: opencv-python
Successfully installed opencv-python-3.2.0+contrib

Keras をインストール

PS D:\> pip install keras
Collecting keras
  Downloading Keras-1.2.0.tar.gz (167kB)
    100% |################################| 174kB 911kB/s
Collecting theano (from keras)
  Downloading Theano-0.8.2.tar.gz (2.9MB)
    100% |################################| 2.9MB 471kB/s
Building wheels for collected packages: keras, theano
  Running setup.py bdist_wheel for keras ... done
  Stored in directory: C:\Users\someone\AppData\Local\pip\Cache\wheels\f8\2c\8e\ffffff128220b1acf6fcd5e692269c6e8d607
44c15fd160c2c
  Running setup.py bdist_wheel for theano ... done
  Stored in directory: C:\Users\someone\AppData\Local\pip\Cache\wheels\96\2b\3d\ffffff24a7171a4afb7144d1e944a7be643b4
48b23a35b9937
Successfully built keras theano
Installing collected packages: theano, keras
Successfully installed keras-1.2.0 theano-0.8.2

Matplotlib, OpenCV, Keras を試す

Matplotlib を試す

REPL からシグモイド関数をグラフ描画して表示します。

PS D:\> python
Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul  5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> import matplotlib.pylab as plt
>>> def sigmoid(x):
...   return 1 / (1 + np.exp(-x))
...
>>> x = np.arange(-5.0, 5.0, 0.1)
>>> y = sigmoid(x)
>>> plt.plot(x, y)
SetProcessDpiAwareness(2) failed: COM error 0xffffffff80070005  (Unknown error 0x0ffffffff80070005), using 2
[<matplotlib.lines.Line2D object at 0x000002370B81EA20>]
>>> plt.ylim(-0.1,1.1)
(-0.1, 1.1)
>>> plt.show()
>>>
>>> ^Z

f:id:tilfin:20170108213321p:plain

OpenCV を試す

REPL から画像ファイルを開いて表示してみます。

PS D:\> python
Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul  5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.imread('pic.jpg')
>>> img = cv2.imread('./pic.jpg')
>>> cv2.imshow('win1', img)
>>> cv2.waitKey(0)
13
>>>
>>> cv2.destroyWindow('win1')
>>> ^Z

f:id:tilfin:20170108213343p:plain

cv2.waitKey(0) の後、ウィンドウに対して Enter を入力すると表示されます。

日本古典籍字形の文字認識で Keras を試す

www.procrasist.com Keras を実際に試してみます。こちらの記事を参考に日本古典籍字形の文字認識を試してみました。

書名一覧 | 日本古典籍字形データセット の「機械学習による文字認識」から サンプルコード(TAR+GZ 24.57 MB) をダウンロードします。 D:\pmjt_sample_20161116 に展開しました。

PS D:\pmjt_sample_20161116> python .\run.py
Using TensorFlow backend.
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cublas64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cudnn64_5.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cufft64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library nvcuda.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library curand64_80.dll locally
X_train shape: (19909, 28, 28, 1)
19909 train samples
3514 test samples
Train on 19909 samples, validate on 3514 samples
Epoch 1/12
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] Found device 0 with properties:
name: GeForce GTX 960
major: 5 minor: 2 memoryClockRate (GHz) 1.253
pciBusID 0000:01:00.0
Total memory: 2.00GiB
Free memory: 1.64GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] DMA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 960, pci bus id: 0000:01:00.0)
19909/19909 [==============================] - 5s - loss: 1.4426 - acc: 0.5135 - val_loss: 0.7607 - val_acc: 0.7803
Epoch 2/12
19909/19909 [==============================] - 3s - loss: 0.7044 - acc: 0.7817 - val_loss: 0.4843 - val_acc: 0.8677
Epoch 3/12
19909/19909 [==============================] - 3s - loss: 0.5310 - acc: 0.8401 - val_loss: 0.3561 - val_acc: 0.8973
Epoch 4/12
19909/19909 [==============================] - 2s - loss: 0.4451 - acc: 0.8646 - val_loss: 0.3038 - val_acc: 0.9124
Epoch 5/12
19909/19909 [==============================] - 2s - loss: 0.3969 - acc: 0.8815 - val_loss: 0.2888 - val_acc: 0.9121
Epoch 6/12
19909/19909 [==============================] - 2s - loss: 0.3606 - acc: 0.8928 - val_loss: 0.2586 - val_acc: 0.9266
Epoch 7/12
19909/19909 [==============================] - 2s - loss: 0.3389 - acc: 0.9012 - val_loss: 0.2390 - val_acc: 0.9306
Epoch 8/12
19909/19909 [==============================] - 2s - loss: 0.3208 - acc: 0.9065 - val_loss: 0.2283 - val_acc: 0.9308
Epoch 9/12
19909/19909 [==============================] - 2s - loss: 0.2999 - acc: 0.9116 - val_loss: 0.2147 - val_acc: 0.9351
Epoch 10/12
19909/19909 [==============================] - 2s - loss: 0.2819 - acc: 0.9176 - val_loss: 0.2038 - val_acc: 0.9397
Epoch 11/12
19909/19909 [==============================] - 2s - loss: 0.2677 - acc: 0.9181 - val_loss: 0.1995 - val_acc: 0.9394
Epoch 12/12
19909/19909 [==============================] - 2s - loss: 0.2605 - acc: 0.9219 - val_loss: 0.1968 - val_acc: 0.9405
Test score: 0.196767529901
Test accuracy: 0.940523619806

Ubuntu に OpenCV をインストールして Python で画像から顔をクロップするまで

以前に Tensorflow のセットアップをして、付属するサンプルを試すところまでして終わっていましたが、 実際に何か試してみないとということで、よくある顔判別をやるためにデータを用意する仕組みを作ろうとしてます。

Python 3 と OpenCV 3 を使って画像から顔検出してそれを正方形でクロップして同一サイズにするというスクリプトを作ります。

セットアップ

ほぼ下記のサイトの通りやったところうまくいきました。 www.pyimagesearch.com 以前にcudaのライブラリを VirtualBox 上の仮想環境にに入れていたせいでコンパイルエラーになりましたが、 それも下記のオプションを指定して進められました。 codeyarns.com

スクリプト

Python はほとんど書いたことないのですが、色々と調べてなんとかそれらしいものができました。

import cv2
import sys
import os


class FaceCropper(object):
    CASCADE_PATH = "data/haarcascades/haarcascade_frontalface_default.xml"

    def __init__(self):
        self.face_cascade = cv2.CascadeClassifier(self.CASCADE_PATH)

    def generate(self, image_path, show_result):
        img = cv2.imread(image_path)
        if (img is None):
            print("Can't open image file")
            return 0

        #img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = self.face_cascade.detectMultiScale(img, 1.1, 3, minSize=(100, 100))
        if (faces is None):
            print('Failed to detect face')
            return 0

        if (show_result):
            for (x, y, w, h) in faces:
                cv2.rectangle(img, (x,y), (x+w, y+h), (255,0,0), 2)
            cv2.imshow('img', img)
            cv2.waitKey(0)
            cv2.destroyAllWindows()

        facecnt = len(faces)
        print("Detected faces: %d" % facecnt)
        i = 0
        #height, width = img.shape[:2]

        for (x, y, w, h) in faces:
            r = max(w, h) / 2
            centerx = x + w / 2
            centery = y + h / 2
            nx = int(centerx - r)
            ny = int(centery - r)
            nr = int(r * 2)

            faceimg = img[ny:ny+nr, nx:nx+nr]
            lastimg = cv2.resize(faceimg, (32, 32))
            i += 1
            cv2.imwrite("image%d.jpg" % i, lastimg)


if __name__ == '__main__':
    args = sys.argv
    argc = len(args)

    if (argc != 2):
        print('Usage: %s [image file]' % args[0])
        quit()

    detecter = FaceCropper()
    detecter.generate(args[1], True)

CASCADE_PATH は OpenCV に付属している顔検出の XML 定義のファイルパスを指定します。 顔検出は face_cascade.detectMultiScale の部分で最低の検出サイズを 100x100 として、scaleFactor=1.1, minNeighbors=3 を色々試行して良さそうな値としました。 また下記のサイトを参考にさせてもらいました。 物体検出(detectMultiScale)をパラメータを変えて試してみる(minNeighbors編) | Workpiles

スクリプトJPEGファイルパスを指定すると、サイズ 32x32 の imageナンバー.jpg というファイルが検出された数だけ保存されます。 generateメソッドの第2引数を True にすると検出状態をウィンドウで表示します。

実装例によっては一旦グレースケールに変換しているものを見ましたが(上記ではコメントアウトしてます)、手元の画像で試した限り結果に差はなさそうでした。データセットとしてDeep Learningに用いることまで考慮するとモノクロの方が情報削減にはなりそうですが。

TensorFlow が正式に Windows サポートして GPU が使えたので試してみた

Google から正式に Tensorflow が Windows 対応して GPU が使えるとのアナウンスがありました。
https://developers.googleblog.com/2016/11/tensorflow-0-12-adds-support-for-windows.html

セットアップ環境

この環境で TensorFlow を試しみたいと思います。なるべくDドライブにセットアップするようにしています。

CUDA と cuDNN をインストール

CUDA Toolkit 8.0

https://developer.nvidia.com/cuda-downloads

  • Operating System: Windows
  • Architecture: x86_64
  • Version: 10
  • Installer Type: exe (network)

普通にインストーラを実行しました。

cuDNN v5.1

開発者アカウントを登録して利用規約に同意してダウンロードしました。

https://developer.nvidia.com/rdp/cudnn-download cuDNN v5.1 Library for Windows 10 を落として zip 内の cuda フォルダ内を C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0 にコピー展開します。

Python 3.5 のセットアップ

Windows の場合 Anaconda を使った方が後々楽なのでこちらを奨めます。 (2017/01/08 追記)
http://tilfin.hatenablog.com/entry/2017/01/08/220556 内に記載してます。

普通にトップページからダウンロードすると 32bit 版なので、https://www.python.org/downloads/windows/ から Download Windows x86-64 executable installer をダウンロードしてインストールします。 ※ なお、 D:\Python35 にインストールしました。

3.5系は環境変数の追加や pip も同時に入れてくれました。 PowerShell から一応 pip のアップグレードもしました。

virtualenv をインストール

実行環境用の作業フォルダを作れるモジュールを入れます。

PS D:\> pip install --upgrade virtualenv
Collecting virtualenv
  Downloading virtualenv-15.1.0-py2.py3-none-any.whl (1.8MB)
    100% |################################| 1.8MB 646kB/s
Installing collected packages: virtualenv
Successfully installed virtualenv-15.1.0

TensorFlow のパッケージをインストール

PowerShell から pip で tensorflow と tensorflow-gpu を入れます。 https://pypi.python.org/pypi/tensorflow

tensorflow

PS D:\> pip install tensorflow
Processing y:\tensorflow-0.12.0rc0-cp35-cp35m-win_amd64.whl
Collecting six>=1.10.0 (from tensorflow==0.12.0rc0)
  Using cached six-1.10.0-py2.py3-none-any.whl
Collecting protobuf==3.1.0 (from tensorflow==0.12.0rc0)
  Downloading protobuf-3.1.0-py2.py3-none-any.whl (339kB)
    100% |################################| 348kB 2.2MB/s
Collecting wheel>=0.26 (from tensorflow==0.12.0rc0)
  Using cached wheel-0.29.0-py2.py3-none-any.whl
Collecting numpy>=1.11.0 (from tensorflow==0.12.0rc0)
  Downloading numpy-1.11.2-cp35-none-win_amd64.whl (7.6MB)
    100% |################################| 7.6MB 179kB/s
Requirement already satisfied (use --upgrade to upgrade): setuptools in d:\python35\lib\site-packages (from protobuf==3
1.0->tensorflow==0.12.0rc0)
Installing collected packages: six, protobuf, wheel, numpy, tensorflow
Successfully installed numpy-1.11.2 protobuf-3.1.0 six-1.10.0 tensorflow-0.12.0rc0 wheel-0.29.0

tensorflow-gpu

PS D:\> pip install tensorflow-gpu
Collecting tensorflow-gpu
  Downloading tensorflow_gpu-0.12.0rc0-cp35-cp35m-win_amd64.whl (32.5MB)
    100% |################################| 32.5MB 40kB/s
Requirement already satisfied: wheel>=0.26 in d:\python35\lib\site-packages (from tensorflow-gpu)
Requirement already satisfied: numpy>=1.11.0 in d:\python35\lib\site-packages (from tensorflow-gpu)
Requirement already satisfied: six>=1.10.0 in d:\python35\lib\site-packages (from tensorflow-gpu)
Requirement already satisfied: protobuf==3.1.0 in d:\python35\lib\site-packages (from tensorflow-gpu)
Requirement already satisfied: setuptools in d:\python35\lib\site-packages (from protobuf==3.1.0->tensorflow-gpu)
Installing collected packages: tensorflow-gpu
Successfully installed tensorflow-gpu-0.12.0rc0

実行開始

virtualenv で D:\tensorflow に作業フォルダを作ります。

PS D:\> virtualenv --system-site-packages D:\tensorflow
Using base prefix 'd:\\python35'
New python executable in D:\tensorflow\Scripts\python.exe
Installing setuptools, pip, wheel...done.

学習解析サンプルを用意する

適当なところで git clone --recurse-submodules https://github.com/tensorflow/tensorflow します。自分は普段 VirtualBoxLinux を動かしていて SMB でファイル共有するのでそちらでクローンしました。 tensorflow/tensorflow/modelsD:\tensorflow\models となるようにコピーします。

MNIST を試す

手書き数字の解析プログラムを試してみます。

PS D:\> cd tensorflow\tensorflow\models\image\mnist
PS D:\tensorflow\models\image\mnist> python convolutional.py
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfu
lly opened CUDA library cublas64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfu
lly opened CUDA library cudnn64_5.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfu
lly opened CUDA library cufft64_80.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfu
lly opened CUDA library nvcuda.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfu
lly opened CUDA library curand64_80.dll locally
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting data\train-images-idx3-ubyte.gz
Extracting data\train-labels-idx1-ubyte.gz
Extracting data\t10k-images-idx3-ubyte.gz
Extracting data\t10k-labels-idx1-ubyte.gz
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] F
ound device 0 with properties:
name: GeForce GTX 960
major: 5 minor: 2 memoryClockRate (GHz) 1.253
pciBusID 0000:01:00.0
Total memory: 2.00GiB
Free memory: 1.64GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] D
MA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0
:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] C
reating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 960, pci bus id: 0000:01:00.0)
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:586] C
ould not identify NUMA node of /job:localhost/replica:0/task:0/gpu:0, defaulting to 0.  Your kernel may not have been bu
ilt with NUMA support.
Initialized!
Step 0 (epoch 0.00), 50.9 ms
Minibatch loss: 8.334, learning rate: 0.010000
Minibatch error: 85.9%
Validation error: 84.6%
Step 100 (epoch 0.12), 12.1 ms
Minibatch loss: 3.226, learning rate: 0.010000
Minibatch error: 4.7%
Validation error: 7.3%
Step 200 (epoch 0.23), 12.0 ms
Minibatch loss: 3.404, learning rate: 0.010000
Minibatch error: 10.9%
(省略)
Minibatch loss: 1.609, learning rate: 0.006302
Minibatch error: 0.0%
Validation error: 1.0%
Test error: 0.8%

割と早く終わったので GPU が効いているのでしょう。上手く動いたことは確認できましたが、わかりやすい ImageNet を次に試します。

ImageNet を試す

画像を解析して何の画かを当てる ImageNet です。

PS D:> cd \tensorflow\models\imagenet

まず準備です。 python .\classify_image.py を実行します。

PS D:\tensorflow\models\image\imagenet> python .\classify_image.py
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cublas64_8
0.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cudnn64_5.
dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cufft64_80
.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library nvcuda.dll
 locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library curand64_8
0.dll locally
>> Downloading inception-2015-12-05.tgz 100.0%
Successfully downloaded inception-2015-12-05.tgz 88931400 bytes.
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] Found device 0 with properties:
name: GeForce GTX 960
major: 5 minor: 2 memoryClockRate (GHz) 1.253
pciBusID 0000:01:00.0
Total memory: 2.00GiB
Free memory: 1.64GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] DMA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] Creating TensorFlow device (/gpu:0)
 -> (device: 0, name: GeForce GTX 960, pci bus id: 0000:01:00.0)
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:586] Could not identify NUMA node of /jo
b:localhost/replica:0/task:0/gpu:0, defaulting to 0.  Your kernel may not have been built with NUMA support.
W c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_def_util.cc:332] Op BatchNormWithGlobalNormalization is depr
ecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization().
W c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\bfc_allocator.cc:217] Ran out of memory trying to allocate
 1.91GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca (score = 0.89233)
indri, indris, Indri indri, Indri brevicaudatus (score = 0.00859)
lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens (score = 0.00264)
custard apple (score = 0.00141)
earthstar (score = 0.00107)

適当に M:\fuji.jpg に富士山の写真をおきました。 python .\classify_image.py --image_file M:\fuji.jpg で解析させます。

PS D:\tensorflow\models\image\imagenet> python .\classify_image.py --image_file M:\fuji.jpg
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cublas64_8
0.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cudnn64_5.
dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library cufft64_80
.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library nvcuda.dll
 locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\stream_executor\dso_loader.cc:128] successfully opened CUDA library curand64_8
0.dll locally
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:885] Found device 0 with properties:
name: GeForce GTX 960
major: 5 minor: 2 memoryClockRate (GHz) 1.253
pciBusID 0000:01:00.0
Total memory: 2.00GiB
Free memory: 1.64GiB
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:906] DMA: 0
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:916] 0:   Y
I c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:975] Creating TensorFlow device (/gpu:0)
 -> (device: 0, name: GeForce GTX 960, pci bus id: 0000:01:00.0)
E c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\gpu\gpu_device.cc:586] Could not identify NUMA node of /jo
b:localhost/replica:0/task:0/gpu:0, defaulting to 0.  Your kernel may not have been built with NUMA support.
W c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\framework\op_def_util.cc:332] Op BatchNormWithGlobalNormalization is depr
ecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization().
W c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\bfc_allocator.cc:217] Ran out of memory trying to allocate
 1.91GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
volcano (score = 0.91087)
fire screen, fireguard (score = 0.00192)
alp (score = 0.00162)
lakeside, lakeshore (score = 0.00130)
geyser (score = 0.00077)

volcano (score = 0.91087) 火山と認識されましたね。ちなみに写真は雪化粧してる富士山でした。

W c:\tf_jenkins\home\workspace\release-win\device\gpu\os\windows\tensorflow\core\common_runtime\bfc_allocator.cc:217] Ran out of memory trying to allocate
 1.91GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.

と警告が出ていたのでもっとメモリがあるといいのでしょう。

とりあえず特に嵌らずに動いたのでみなさんもお試しください。

AWS IAM Switch Roleのリストを増やすChrome Extensionを作った

AWS Chrome

AWS Management Console において、AWSアカウントから他のAWSアカウントにスイッチロールできますが、これの最近の履歴が5つまでしか表示されない。あくまでも最近使ったものという位置付けなんだと思います。

某仕事上、1つのアカウントから多数の他のアカウントに Switch Role にせざる得ないので専用の URL をブックマークしていました。しかし、これでも毎回補完された入力フォームが挟まれて怠い(このページ遷移が結構かかります)。

このような理由で、Switch Role の履歴(リスト)を拡張する Chrome Extension を作りました。Chrome Web Store で公開しているので簡単にインストールできます。

chrome.google.com

f:id:tilfin:20160809233207p:plain

特徴

  • Switch Role の履歴に設定に定義されたプロファイル(アカウント)の分が項目増えるリスト拡張される。
  • リストには <プロファイル名> | <AWSアカウントID>AWSアカウントID がわかりやすくなる。
  • 色指定ができる(固定色ではない)。
  • スイッチロール後に黒いヘッダーの下部に指定色のバーが表示されてより現在のプロファイルが識別しやすくなる。
  • Chrome Sync (端末間) で設定は共有されます。

設定

ブラウザの URL バー右に並ぶ拡張のアイコンをクリックして、ポップアップしたテキストエリアに CLIで同様の設定となる ~/aws/config ファイルと同様のフォーマットで定義して保存するだけです。色指定 (例.color = ffcc99) も CSS ライク(先頭 # なし)で指定できます。GitHubの README を詳しくは参照ください。

GitHub - tilfin/aws-extend-switch-roles: Extend your AWS IAM switching roles by Chrome extension

f:id:tilfin:20160809233023p:plain

GitLab CI から Google Cloud Pub/Sub 経由で自動デプロイ

GoogleCloud DevOps

自分用のちょっとしたWebサービスをさくら VPS環境に構築しています。こんなオレオレサービスでも Git リポジトリの master ブランチに push したら自動的にデプロイできるようにしたい。毎回 SSH して手動で更新はしたくない。

一般的な方法だと、どうしてもデプロイ先のサーバーにリクエストの受け先を用意する必要があります。概ね HTTP 経由で受けないといけないので、そこから派生するアクションの内容から鑑みても、セキュリティ的にグローバル空間に置かれたサーバでやりたくないものです。

そこで自前で Pub/Sub サービスを経由してやってみることにしました。Pub/Sub であれば懸念事項のアクセスを受け入れることなく、Subscriber も Pull 型で設置できます。

Google Cloud Console

まず Google Cloud Console - 認証情報サービスアカウントを作成しておきます。次に Google Cloud Console - Pub/Subトピックを作成します。そしてそのトピック対して用意したサービスアカウントにPub/Sub サブスクライバ―Pub/Sub パブリッシャーの権限を与えます。

自動デプロイの仕組みを作る

スクリプトは Node.js を使います。gcloud モジュールをグローバルで使えるようにしておきます。下記の package.json の定義とおり サブスクライバーとなる agent.js と通知をする publish.js をそれぞれ作ります。

package.json

{
  "name": "myapp",
  "scripts": {
    "agent": "NODE_PATH=`npm root -g` node agent.js",
    "publish": "NODE_PATH=`npm root -g` node publish.js"
  },
  "dependencies": {
    "gcloud": "^0.36.0"
  },
  "private": true
}

通知

GitLab CI から呼び出して Pub/Sub にデプロイメッセージを発行するスクリプトを作ります。

publish.js

gcloudオブジェクトからpubsubオブジェクトを取得して、トピック名からtopicオブジェクトを取得して、通知を行うというシンプルなものです。

'use strict';

const gcloud = require('gcloud')({
  keyFilename: 'サービスアカウントのキーJSONファイルパス',
  projectId: 'Google Cloud ConsoleのプロジェクトID'
});

const pubsub = gcloud.pubsub();
const topic = pubsub.topic('トピックID');

topic.publish({
  data: {
    command: 'deploy'
  }
}, function(err) {
  if (err) {
    console.error(err);
  } else {
    console.info('Published deploy message!');
  }
});

デプロイエージェント

トピックのサブスクライバーとしてメッセージを受信したら、Gitリポジトリから最新の内容を反映してデーモンを再起動するエージェントを作ります。

agent.js

topicオブジェクトを取得して、subscribe(購読)します。このとき1番目の引数が購読名になるため、ホスト名を使って複数のエージェントが存在する状態でもそれぞれに通知されるようにします。同じ名前にしてしまうと同一のサブスクライバーとみなされて、メッセージがいずれかのエージェントにしか飛びません。

'use strict';

const os = require('os');
const path = require('path');
const execFile = require('child_process').execFile;

const gcloud = require('gcloud')({
  keyFilename: 'サービスアカウントのキーJSONファイルパス',
  projectId: 'Google Cloud ConsoleのプロジェクトID'
});

function startDeploy() {
  const child = execFile('deploy.sh',
    (error, stdout, stderr) => {
      if (error) {
        throw error;
      }
      console.log(stderr);
      console.log(stdout);
    });
}

const pubsub = gcloud.pubsub();
const topic = pubsub.topic('トピックID');
const name = 'sub_' + os.hostname();

var opts = {
  autoAck: true, // メッセージを取得したことの承認を自動で行う
  reuseExisting: true, // 再購読時にエラーならないように再利用する
  interval: 60
};

topic.subscribe(name, opts, (err, subscription, apiResponse) => {
  if (err) {
    console.error(err);
    return;
  }

  console.info('Subscribed');

  subscription.on('message', (msg) => {
    const data = msg.data;
    const command = (data && data.command) || null;

    if (command === 'deploy') {
      console.info('Received deploy message id:%s', msg.id);

      try {
        startDeploy();
      } catch (ex) {
        console.error(ex);
      }
    } else {
      console.warn('Received unexpected message:');
      console.warn(msg);
    }
  });
});

注意事項として Pull 型サブスクライバーは接続の度に課金カウンタが上がるので、 interval はできるだけ長くした方が良いです。 メッセージが来たら下記のような deploy.sh スクリプトを用意してリポジトリを更新してサービスをリフレッシュします。

deploy.sh

#!/bin/bash
git fetch --all
git checkout --force origin/master

npm run deploy # サービスリフレッシュ
echo "Deployed"

GitLab CI からキック

下記の設定ファイルをリポジトリに設置するとデプロイステージで発行します。gcloudモジュールのインストールはそれなりの大きさで時間がかかるので、 https://hub.docker.com/r/tilfin/gitlab-deployer/ で公開している Docker で Node.js と gcloud を入れてあります。これコンテナを deploy タグ付きで CI Runner 登録しておく良いでしょう。

.gitlab-ci.yml

stages:
  - deploy

deploy_job:
  type: deploy
  script:
    - npm run publish
  tags:
    - deploy
  only:
    - master

動作確認

実行環境でも Node.js + gcloud をセットアップしておき npm run agent してサブスクライバーを起動しておきます。 GitLab のリポジトリの master に push すると Pub/Sub メッセージを経由してサブスクライバーがデプロイスクリプトを実行します。

TweetDeckライクなGitHubとBacklogのタイムラインビューワーを作ってみた

GitHub

GitHub のダッシュボードが絶望的に使いづらいので、タイトル通りタイムラインビューワーを作りました。

tilfin.github.io

GitHub のイベントダッシュボードは「誰が何をしたのか」はわかるのですが、結局情報が不足してるためにわざわざ詳細ページに飛ぶ必要があります。そこをどうにかしたかったのが開発理由です。また普段 Nulab さんの Backlog を使っているので、こちらのプロジェクト更新履歴も同じく表示できるようにしました。

f:id:tilfin:20160404212722j:plain:w400

サイトの [See a Demo] ボタンからデモとして、GitHub の Public イベントといくつかの有名リポジトリと組織のタイムラインの見られます。(これは非認証状態での API 利用なので社内からのアクセスですと IP アドレスのリミットでエラーになるかもしれません。)

両方とも API がクロスオリジンで呼び出せたので単純な静的ページアプリ(SPA)として作って Github Page で公開しました。そのため各 API のアクセストークンやタイムラインの情報は全てブラウザのローカルストレージに保存する仕様です。JSON でインポート・エクスポートできるのとレスポンシブデザインにしているため、PC で設定をエクスポートして、スマホでホーム画面登録してインポートすることも可能です。

以下は設定方法を説明しておきます。

設定方法

[Get Started Now] ボタンからタイムラインの編集画面に飛びます。追加するタイムラインのサービス毎に [GitHub], [Backlog] ボタンがあります。下記スクリーンショットはそれぞれの My Timeline を追加したものです。カラム幅と通知のオンオフが設定できます。

f:id:tilfin:20160404203915j:plain:w300

GitHub タイムラインの追加

f:id:tilfin:20160404203658j:plain:w300

まずアクセストークンを生成してください。 https://github.com/settings/tokens から [Generate new token] ボタンをクリックして、「Select scopes」から repo, admin:org/read:org, notifications を選択して、トークンを下記の最初の [Access Token] にセットします。

f:id:tilfin:20160404205535j:plain:h600

2番目は GitHub Enterprize を使っている場合は、ルート URL を入れます(この機能は自分自身が利用していないので未確認です)。GitHub.com の場合は空のままにして、[Activate] ボタンを押すと認証が通ると下部の組織タイムラインもしくはリポジトリ(例.microsoft, facebook/react)の指定、または GitHub 全体の Public タイムラインを追加できます。

Backlog タイムラインの追加

API Root URL」にお使いの Backlog サイトのルート URL をセットします。さらに Backlog サイトで個人設定ページを開いて、左のメニューの API から新しいAPIキーを発行をして、「API Token」にセットします。

f:id:tilfin:20160404203658j:plain:w300

[Load Project] ボタンをクリックして認証が通るとプロジェクト一覧がロードされるので、選択して追加します。