RaspberryPiにOpenCV3.4+Tensorflow1.4+keras2.1をインストールする

RaspberryPiにOpenCV3.4+Tensorflow1.4+keras2.1をインストールする

以前のエントリーではRaspberryPiで新しめのtensorflowを使ってみようということでインストール設定を行いました。いろいろWarningが出ながらも動作できるようになり、あとはやるだけなんだよと思いつつ、腰はまだ上がりませんでした。

そんな時大垣のソフトピアで

www.softopia.or.jp

なるイベントが開催され参加することもできましたので、今回はPCではなくRaspberryPiでやってみようと思いました。PCではAnacondaでの設定だけど、RaspberryPiでは自分の設定したものでできるなあとタカをくくっていて、あとはOpenCVを入れれば実験できるなあとかなり軽く考えていました。

ただ、python3.5ではOpenCVの設定がなくあれー?(お手軽じゃないじゃんの意)って感じになり、仕方なくソースコードからOpenCVをインストールすることにました。

uepon.hatenadiary.com

茨の道に入ったような気がしますが、色々(2週間ほどビルド地獄だったw)あり、違う方法も含めて実験には成功できましたので、そのときのメモ。

OpenCVインストール放浪編【結論を求めるなら読む必要のない情報】

OpenCVをソースからインストールするということで以下のサイトを参考にしてインストールしてみました。

www.pyimagesearch.com

基本的な流れとしては

  1. ビルドに必要なパッケージのインストール
  2. OpenCVのソース関連の取得
  3. VirtualEnv環境のセッティング
  4. numpyのインストール
  5. ビルド
  6. ビルド後の設定

こんな感じになります。

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install build-essential cmake pkg-config
$ sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
$ sudo apt-get install libxvidcore-dev libx264-dev
$ sudo apt-get install libgtk2.0-dev
$ sudo apt-get install libatlas-base-dev gfortran
$ sudo apt-get install python2.7-dev python3-dev
$ wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.4.0.zip
$ wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.4.0.zip
$ unzip opencv.zip
$ unzip opencv_contrib.zip
$ wget https://bootstrap.pypa.io/get-pip.py
$ sudo python3 get-pip.py
$ sudo pip3 install virtualenv virtualenvwrapper
$ sudo rm -rf ~/.cache/pip
$ echo -e "\n# virtualenv and virtualenvwrapper" >> ~/.profile
$ echo "export WORKON_HOME=$HOME/.virtualenvs" >> ~/.profile
$ echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.profile
$ source ~/.profile
$ mkvirtualenv cv-python3 -p python3
$ workon cv-python3
$ pip install numpy  
$ cd opencv-3.4.0/
$ mkdir build
$ cd build/
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D INSTALL_PYTHON_EXAMPLES=ON -D OPENCV_EXTRA_MODULES_PATH=~/opencv/opencv_contrib-3.4.0/modules -D BUILD_EXAMPLES=ON ..
$ make clean
$ time make

ここまででビルドがされますが、とても時間がかかります。 参考サイトではmake -j4となっていますが、発熱やmakeする順序などによっては失敗する様です。自分は3回失敗したので-j2としてみましたが、それでもダメ。最終的にmakeのみにしています。(makeだけでは失敗したことはないです)実際かかる時間はこんな感じなので、寝る前にやりましょう。

real    283m10.666s
user    246m21.650s
sys     6m20.950s

ビルドが終了したらインストールを行います。

$ sudo make install
$ sudo ldconfig
$ ls -l /usr/local/lib/python3.5/site-packages/
$ cd /usr/local/lib/python3.5/site-packages/
$ sudo mv cv2.cpython-35m.so cv2.so
$ cd ~/.virtualenvs/cv-python3/lib/python3.5/site-packages/
$ ln -s /usr/local/lib/python3.5/site-packages/cv2.so cv2.so

これでインストール完了になりました。

あとは確認となるのですが…

$ workon cv-python3
(cv-python3)  $ python
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'3.4.0'
>>>

無事インストール成功です。ちゃんといっているのですが…

OpenCV以外のパッケージが消えていますw。前のエントリーで折角インストールしたTensorflowとkerasも消えてます。

(cv-python3)  $ pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
numpy (1.14.0)
pip (9.0.1)
setuptools (38.4.1)
wheel (0.30.0)

うわああああ

f:id:ueponx:20180211120348p:plain

この手順をいろいろと5回ほど実験したところ(w)VirtualEnv環境を設定したあたりでこの状況になるようです。この手順を外せば行けそうです。

ただ、なんとなくこれではつらみがあるので、再度ググって設定方法を見直したいと思います。

再度見直し

再度ネットをググってビルド済みのパッケージも含めて探してみました。

opencv3.4のインストールパッケージ

https://github.com/mt08xx/files/raw/master/opencv-rpi/libopencv3_3.4.0-20180115.1_armhf.deb

tensorflow1.4.1のインストールパッケージ

github.com

python2.7

https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.1/tensorflow-1.4.1-cp27-none-linux_armv7l.whl

python3.5

https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.1/tensorflow-1.4.1-cp35-none-linux_armv7l.whl

インストール作業へ

今回使用したRaspbianのバージョンはこちらになります。

  • 2017-11-29-raspbian-stretch.img

バージョン情報を確認すると…

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.1 (stretch)
Release:        9.1
Codename:       stretch

$ python --version
Python 2.7.13
$ python3 --version
Python 3.5.3

pythonが3.5.3になっているで前回のエントリーの設定では動作はするのですが、Warningが出るというものでした。

OpenCV3.4のインストール

以下のブログがありました。OpenCVの構築にほとんどの時間が割かれるのでこれは助かりました。

qiita.com

今から思えば、最初からこれを使えばよかったのではないのかと思います。

$ wget https://github.com/mt08xx/files/raw/master/opencv-rpi/libopencv3_3.4.0-20180115.1_armhf.deb
$ sudo apt install -y ./libopencv3_3.4.0-20180115.1_armhf.deb
$ sudo ldconfig

これでOpenCV3.4をインストールができました。この作業でPython2系もPython3系も使用可能になっています。

Tensorflow1.4.1のインストール

以下の作業ではTensorflowとともにkerasもインストールします。

TensorflowのWhlパッケージを作成されている方がいらっしゃいました。tensorflowのバージョンが1.4.1でかつpython3.5様なのも嬉しいところです。大概のパッケージがpython3.4なのが辛いです(minicondaにあわせているのかも?)

github.com

python2.7で使用する場合

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo pip install https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.1/tensorflow-1.4.1-cp27-none-linux_armv7l.whl
$ sudo apt-get install python-h5py
$ sudo pip install keras

これで完了です。REPL環境でチェックしてみます。

$ python
Python 2.7.13 (default, Jan 19 2017, 14:48:08)
[GCC 6.3.0 20170124] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import cv2
>>> import tensorflow
>>> import keras
Using TensorFlow backend.
>>> numpy.__version__
'1.12.1'
>>> cv2.__version__
'3.4.0'
>>> tensorflow.__version__
'1.4.1'
>>> keras.__version__
'2.1.3'
>>>

python3.5で使用する場合

$ pip3 install numpy==1.13
$ sudo apt-get install libblas-dev liblapack-dev python3-dev libatlas-base-dev gfortran python3-setuptools
$ sudo pip3 install https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.1/tensorflow-1.4.1-cp35-none-linux_armv7l.whl
$ sudo apt-get install python3-h5py
$ sudo pip3 install keras

一行目のnumpyのバージョンを1.13をしています。3.5系ではtensorflowをimportするとWarningが発生します。

Warningは

>>> import tensorflow
RuntimeError: module compiled against API version 0xb but this version of numpy is 0xa

こんな感じで表示されます。インストール後にpipでバージョンアップしても問題は無いようです。

ただ、バージョンアップをすればいいと思って、以下のようにnumpyを2018.02.10現在以下のようにアップグレートすると

$ pip install --upgrade numpy 

インストールが終わると1.14がインストールされ、tensorflowのimport時にWarningが発生するので、この設定は必須になります。

ではREPL環境でバージョンの確認を行ってみます。

$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import cv2
>>> import tensorflow
>>> import keras
Using TensorFlow backend.
>>> numpy.__version__
'1.13.0'
>>> cv2.__version__
'3.4.0'
>>> tensorflow.__version__
'1.4.1'
>>> keras.__version__
'2.1.3'
>>>

前回のエントリーではなんとなくWarningもでていましたが、今回のインストール方法では全く問題はなく、すんなり完了できたと思います。

サンプルの実行

OpenCVのテスト

f:id:ueponx:20180212091005p:plain

画像は表示されるのですが以下のようなWarningがでます。

** (image:1479): WARNING **: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files

org.a11y.BusのWarningは解決手段があまりないようでしたので動くので良しとしました。

Tensorflowのテスト

TensorflowのHello worldの実行になります。

【ソース】

import tensorflow as tf
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

hello = tf.constant('Hello, Tensorflow')
sess = tf.Session()

print(sess.run(hello))

【実行結果】

b'Hello, Tensorflow'

OpenCV&Tensorflow&kerasのサンプル

【07tf.py】

from keras.models import Sequential
from keras.layers import Activation, Dense, Dropout
from keras.utils.np_utils import to_categorical
from keras.optimizers import Adagrad
from keras.optimizers import Adam
import numpy as np
from PIL import Image
import os

image_list = []
label_list = []

# トレーニングデータを読み込む
for dir in os.listdir("data/train"):

    traindir = "data/train/" + dir
    if os.path.isdir(traindir) == False:
        continue

    label = 0              # 正解ラベル

    if dir == "apple":
        label = 0          # りんごの場合は、0
    elif dir == "orange":
        label = 1          # オレンジの場合は、1

    for file in os.listdir(traindir):
        if file != ".DS_Store":

            label_list.append(label)            # 正解ラベルを配列に入れる

            filepath = traindir + "/" + file  # ファイルパス

            resized_img = Image.open(filepath).resize((25, 25))                                                    # 画像を25x25にリサイズする
            image = np.array(resized_img)                                                                       # 25x25の2次元配列にする→[[R,G,B], [R,G,B]...]
            image = image.transpose(2, 0, 1)                                                                 # 配列を次元を変換する→[[R,R,R,...], [G,G,G,...], [B,B,B,...]]
            image = image.reshape(1, image.shape[0] * image.shape[1] * image.shape[2]).astype("float32")[0]     # 1次元配列に変換→[R,R,R,...,G,G,G,...,B,B,B]
            image_list.append(image / 255.)                                                            # 0.0〜1.0までの値にして配列に入れる

image_list = np.array(image_list)       # 画像リストをnumpy配列に変換

Y = to_categorical(label_list)          # 正解ラベルを配列にする(0→[1,0], 1→[0,1])

# 層を構築
model = Sequential()
# 入力層
model.add(Dense(200, input_dim=1875))
model.add(Activation("relu"))
model.add(Dropout(0.2))

# 隠れ層
model.add(Dense(200))
model.add(Activation("relu"))
model.add(Dropout(0.2))

# 出力層
model.add(Dense(2))
model.add(Activation("softmax"))

# オプティマイザにAdamを使用
opt = Adam(lr=0.001)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
# nb_epoch: 学習回数
# batch_size: 1度に処理する分量(GPUモードの際は、メモリ制限がある場合がある)
model.fit(image_list, Y, nb_epoch=1500, batch_size=100, validation_split=0.1)
# model.fit(image_list, Y, nb_epoch=10, batch_size=100, validation_split=0.1)

total = 0.
ok_count = 0.

for dir in os.listdir("data/test"):
    
    testdir = "data/test/" + dir
    if os.path.isdir(testdir) == False:
        continue

    label = 0

    if dir == "apple":
        label = 0          # りんごの場合は、0
    elif dir == "orange":
        label = 1          # オレンジの場合は、1

    for file in os.listdir(testdir):
        if file != ".DS_Store":
            label_list.append(label)
            filepath = testdir + "/" + file

            resized_img = Image.open(filepath).resize((25, 25))    
            image = np.array(resized_img)
            image = image.transpose(2, 0, 1)
            image = image.reshape(1, image.shape[0] * image.shape[1] * image.shape[2]).astype("float32")[0]

            # 予測する
            print(filepath)
            result = model.predict_classes(np.array([image / 255.]))
            print("label:", label, "result:", result[0])

            total += 1.

            if label == result[0]:
                ok_count += 1.

print(ok_count / total * 100, "%")

【実行結果】

$ python3 07tf.py
Using TensorFlow backend.
/usr/local/lib/python3.5/dist-packages/keras/models.py:944: UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`.
  warnings.warn('The `nb_epoch` argument in `fit` '
Train on 35 samples, validate on 4 samples
Epoch 1/1500
35/35 [==============================] - 3s 93ms/step - loss: 0.9337 - acc: 0.5429 - val_loss: 0.0025 - val_acc: 1.0000
Epoch 2/1500
35/35 [==============================] - 0s 2ms/step - loss: 2.7587 - acc: 0.4571 - val_loss: 0.3437 - val_acc: 1.0000

(中略)

Epoch 1498/1500
35/35 [==============================] - 0s 2ms/step - loss: 8.9737e-06 - acc: 1.0000 - val_loss: 3.8743e-07 - val_acc: 1.0000
Epoch 1499/1500
35/35 [==============================] - 0s 2ms/step - loss: 3.3191e-05 - acc: 1.0000 - val_loss: 3.5763e-07 - val_acc: 1.0000
Epoch 1500/1500
35/35 [==============================] - 0s 2ms/step - loss: 6.7218e-06 - acc: 1.0000 - val_loss: 3.5763e-07 - val_acc: 1.0000
data/test/apple/1212043top.jpg
label: 0 result: 0
data/test/apple/81306024002554.jpg
label: 0 result: 0
data/test/apple/81306024002557.jpg
label: 0 result: 0
data/test/apple/1757f226647a6f1.jpg
label: 0 result: 0
data/test/orange/images (1).jpeg
label: 1 result: 1
data/test/orange/8242_1.jpg
label: 1 result: 1
data/test/orange/1152194_orange_isolated_on_white_background.jpg
label: 1 result: 1
data/test/orange/DKCcTzZXUAA0ckm.jpg
label: 1 result: 1
100.0 %
Exception ignored in: <bound method BaseSession.__del__ of <tensorflow.python.client.session.Session object at 0x6f3a1430>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 696, in __del__
TypeError: 'NoneType' object is not callable

若干のWarningとExceptionがでているんですが、概ね実行はできているっぽいようです。このサンプルの内容はりんごとオレンジを画像を学習して分類するというものです。

最初と最後にでているExceptionに関してはググってみると解決方法はあるようです。 Keras2系のバージョンによるものの模様です。

qiita.com

keras+tensorflowで終了処理でエラーが発生する | CodeLab技術ブログ

おわりに

前回はスッキリしない終わり方でしたが、今回はimport時のWarningなどは発生せずにうまくロードできました。

node.jsでPromiseを使って同期的に処理を行う

node.jsでPromiseを使って同期的に処理を行う

前回の補足的なエントリーです。

uepon.hatenadiary.com

以前のgoogle-home-notifierを使用した処理では以下のようなコードを書いてみました。 いちいちプログラムを起動するのも面倒だなと思ったので、常に入力を受け付けるような処理にしたいと思っていました。 ただ、キーボード入力と非同期実行のお陰で単純に書いても予想通りには動きません。(node.jsではこの部分が個人的には一番ハードルが高いと思う)

var googlehome = require('google-home-notifier');
var language = 'ja'; // if not set 'us' language will be used

googlehome.device('テスト', language);
googlehome.ip('xxx.xxx.xxx.xxx');  //IPアドレスは自分も持っているデバイスを調べて入力してください

var text = 'こんにちは';

if(process.argv.length == 3){
        text = process.argv[2];
}

try {
        googlehome.notify(text, function(notifyRes) {
                console.log(notifyRes);
        });
} catch(err) {
        console.log(err);
}

このコードではコマンド引数に与えた文字列を単純にgoogle-home-notifierモジュールのnotifierメソッドに渡しています。 この処理を無限ループにすることでいいはずなのですが、文字入力が完了する前に次の処理がおこなわれるので文字には空文字列が入り、 目的とは違った空振りのコードで動いてしまします。node.jsではI/O処理も非同期的に動作するため、時間のかかる処理では データが格納される前に次の処理が行われてしまいます。ネットワークからのデータ取得やファイルからの読み込み・書き込み、キーボード入力などが該当します。

そういう場合にはpromiseを使うようです。くっそ適当に言ってます。 C#みたいなasync/awaitの方が理解しやすいんですが、node.jsのasync/awaitは少し違っているみたいに思ったので、 今回はpromiseを理解することにしました。

const readlineSync = require('readline-sync');

var googlehome = require('google-home-notifier');
var language = 'ja';
googlehome.device('テスト', language);
googlehome.ip('xxx.xxx.xxx.xxx');

console.log('話させたい文字列を入力してください>');
process.stdin.setEncoding('utf-8');
process.stdin.on('data', function (data) {
        googleHomeNotify(data).then(()=> {
                return PromiseSleep(2000);
        }).then(() => {
                console.log('話させたい文字列を入力してください>');
        });
});

function googleHomeNotify(data) {
        return new Promise((resolve, reject) => {
                try {
                        googlehome.notify(data, function(notifyRes) {
                                console.log(notifyRes);
                        });
                } catch(err) {
                        console.log(err);
                }
                resolve();
        });
}

function PromiseSleep(time) {
        return new Promise((resolve, reject) => {
                setTimeout(() => {
                        resolve();
                }, time);
        });
}

基本的な流れとしては

  1. 常時入力待機(イベント)
  2. 入力が行われたらPromiseを生成して、その中でgoogle-home-notifierのnotifyメソッドに入力された文字列を引数に実行
  3. google-home-notifierのnotify処理を行っている間にwait処理を行う(setTimeoutメソッド)
  4. wait時間が過ぎたら次の文字列入力を促す表示を行う
  5. 入力待機状態に戻る

こんな感じです。process.stdin.on(...)の部分をwhileやforなどで無限ループにするとうまく動きません。Promiseと同期型のループ処理で散々悩みました…(単体では動くがループでは動かない)

もっと、多分良い書き方があるのかなと思いますが、こんな感じでかけました。もう少しスッキリかけるといいなあというところです。

関数の処理を見直して以下のように書き直してみました。

const readlineSync = require('readline-sync');

var googlehome = require('google-home-notifier');
var language = 'ja';
googlehome.device('テスト', language);
googlehome.ip('xxx.xxx.xxx.xxx');

console.log('話させたい文字列を入力してください>');
process.stdin.setEncoding('utf-8');
process.stdin.on('data', function (data) {
        googleHomeNotify(data).then(()=> {
                return PromiseSleep(2000);
        }).then(() => {
                console.log('話させたい文字列を入力してください>');
        });
});

function googleHomeNotify(data) {
        return new Promise((resolve, reject) => {
                try {
                        googlehome.notify(data, function(notifyRes) {
                                console.log(notifyRes);
                        });
                } catch(err) {
                        console.log(err);
                }
                resolve();
        });
}

function PromiseSleep(time) {
        return new Promise((resolve, reject) => {
                setTimeout(() => {
                        resolve();
                }, time);
        });
}

まとめ

いままでjavascriptの非同期的な部分は避けて通ってきましたが、やっと重い腰を上げられたかなと思います。

さらにPromiseとasync/awaitを使ってわかりやすくしてみました。 ネストが少し浅くなったのでわかりやすくなった気がします。

const readlineSync = require('readline-sync');

var googlehome = require('google-home-notifier');
var language = 'ja';
googlehome.device('テスト', language);
googlehome.ip('xxx.xxx.xxx.xxx');

console.log('話させたい文字列を入力してください>');
process.stdin.setEncoding('utf-8');
process.stdin.on('data', async function (data) {
        googleHomeNotify(data);
        await PromiseSleep(3000);
        console.log('話させたい文字列を入力してください>');
});

function googleHomeNotify(data) {
        try {
                googlehome.notify(data, function(notifyRes) {
                        console.log(notifyRes);
                });
        } catch(err) {
                console.log(err);
        }

function PromiseSleep(time) {
        return new Promise((resolve, reject) => {
                setTimeout(() => {
                        resolve();
                }, time);
        });
}

これで非同期的に動作する機能をわかりやすく記述することができたような気がしますね。

RaspberryPiでgoogle-home-notifierをインストールしてお好みの言葉を話してみる

RaspberryPiでgoogle-home-notifierをインストールしてお好みの言葉を話してみる

GoogleHomeMiniが年末に安売りになったので自分も購入し、天気やキッチンタイマーのようなものに使用していました。 とはいっても、3日ぐらいで飽きるので他の使い方がないのかなと思い、IFTTTからGoogleスプレッドシートへ記録なども行っていました。 IFTTTの連携は結構便利だなーとは思っているのですが言葉をいろいろ決めたりしないといけないので、制限がおおいなあというのが、 実際のところでした。そこで、RaspberryPiと連携し、話す言葉を変更できる連携に手をだしました。

このネタは2017年のアドベントカレンダーではさんざんやりつくされた感じはしたのですが、自分もその波に乗ってみました。 それでもつまずく自分…。今年もいろいろなトラップに引っかかる予感です。

今回紹介するgoogle-home-notifierは非常に簡単な呼び出しを行うだけで話すことができるのでとても便利です。 ただ、RaspberryPiのように常時起動の機器がないと実現ができないのは少しハードルはあるかなと思います。

githubを参考に

github.com

Node.jsの準備

google-home-notifierNode.jsのモジュールなので、新しめのNode.jsの設定をします。最近のバージョンは4.x系なので昔よりはマシになりましたが 最近のLTSあたりにしておくのが無難かなと思います。

過去のエントリーを参考にして設定します。

uepon.hatenadiary.com

やっててよかった備忘録。2018/01/08現在は以下のバージョンがLTSのようです。

$ node -v
v8.9.4

google-home-notifierのインストール

ググったのサイトをみていると

# 任意のフォルダに移動し
$ npm init
$ npm install google-home-notifier

こんな感じで問題ないようなことが書いてあるのですが。 Node.jsの初心者の私にはピンときていませんでした…。

あと、モジュールのインストールを行うとエラーが発生して、インストールが完了しませんでした。

公式のドキュメントにRaspberryPiの項目があるのでそれを見ると

Raspberry Pi
If you are running from Raspberry Pi make sure you have the following before nunning "npm install": Use the latest nodejs dist.

curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
sudo apt-get install nodejs

Also install these packages:

sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev

てな記載が。別途パッケージが必要なのね。(ちゃんとドキュメントを読みましょう) パッケージ名を確認するとavahiとかmdnsなライブラリが必要のようです。 (前半部分はNode.jsのインストールなので既に行っていることから省略でもも問題はありません)

インストールに必要な事前準備

以下でパッケージをインストールします。

【コマンド】

$ sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev

【ログ】

$ sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
libnss-mdns はすでに最新バージョン (0.10-8) です。
libnss-mdns は手動でインストールしたと設定されました。
以下の追加パッケージがインストールされます:
  libavahi-client-dev libavahi-common-dev libavahi-compat-libdnssd1
  libdbus-1-dev
以下のパッケージが新たにインストールされます:
  git-core libavahi-client-dev libavahi-common-dev
  libavahi-compat-libdnssd-dev libavahi-compat-libdnssd1 libdbus-1-dev
アップグレード: 0 個、新規インストール: 6 個、削除: 0 個、保留: 3 個。
424 kB のアーカイブを取得する必要があります。
この操作後に追加で 1,285 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://mirrordirector.raspbian.org/raspbian stretch/main armhf git-core all 1:2.11.0-3+deb9u2 [1,410 B]
取得:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-common-dev armhf 0.6.32-2 [62.6 kB]
取得:3 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libdbus-1-dev armhf 1.10.24-0+deb9u1 [200 kB]
取得:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-client-dev armhf 0.6.32-2 [56.5 kB]
取得:5 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-compat-libdnssd1 armhf 0.6.32-2 [44.0 kB]
取得:6 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-compat-libdnssd-dev armhf 0.6.32-2 [58.8 kB]
424 kB を 4秒 で取得しました (102 kB/s)
以前に未選択のパッケージ git-core を選択しています。
(データベースを読み込んでいます ... 現在 124934 個のファイルとディレクトリがインストールされています。)
.../0-git-core_1%3a2.11.0-3+deb9u2_all.deb を展開する準備をしています ...
git-core (1:2.11.0-3+deb9u2) を展開しています...
以前に未選択のパッケージ libavahi-common-dev:armhf を選択しています。
.../1-libavahi-common-dev_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-common-dev:armhf (0.6.32-2) を展開しています...
以前に未選択のパッケージ libdbus-1-dev:armhf を選択しています。
.../2-libdbus-1-dev_1.10.24-0+deb9u1_armhf.deb を展開する準備をしています ...
libdbus-1-dev:armhf (1.10.24-0+deb9u1) を展開しています...
以前に未選択のパッケージ libavahi-client-dev:armhf を選択しています。
.../3-libavahi-client-dev_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-client-dev:armhf (0.6.32-2) を展開しています...
以前に未選択のパッケージ libavahi-compat-libdnssd1:armhf を選択しています。
.../4-libavahi-compat-libdnssd1_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-compat-libdnssd1:armhf (0.6.32-2) を展開しています...
以前に未選択のパッケージ libavahi-compat-libdnssd-dev:armhf を選択しています。
.../5-libavahi-compat-libdnssd-dev_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-compat-libdnssd-dev:armhf (0.6.32-2) を展開しています...
libdbus-1-dev:armhf (1.10.24-0+deb9u1) を設定しています ...
libavahi-common-dev:armhf (0.6.32-2) を設定しています ...
libavahi-client-dev:armhf (0.6.32-2) を設定しています ...
libavahi-compat-libdnssd1:armhf (0.6.32-2) を設定しています ...
libc-bin (2.24-11+deb9u1) のトリガを処理しています ...
git-core (1:2.11.0-3+deb9u2) を設定しています ...
libavahi-compat-libdnssd-dev:armhf (0.6.32-2) を設定しています ...

google-home-notifierのインストール

google-home-notifierのインストールはnpmで行います。

今回作業するディレクトリはgooglehomeSampleとしました。適宜読み替えて作業をしてください。 任意のディレクトリとなっていますが、google-home-notifierというモジュール名と同じディレクトリ名にすると エラーになりますので気を付けてください。(自分はハマった

【コマンド】

$ mkdir googlehomeSample
$ cd googlehomeSample/
$ npm init
$ npm install google-home-notifier

公式ページではインストール前のnpm initについては言及がされていませんでしたが、事前にしておくと警告行が減ったので含めています。 npm initではパッケージバージョンの情報やライセンス情報の入力などを求められますが、そのままリターンしました。

【ログ】

$ mkdir googlehomeSample
$ cd googlehomeSample/

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (googlehomesample)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /home/pi/googlehomeSample/package.json:

{
  "name": "googlehomesample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes)

$ npm install google-home-notifier

> mdns@2.3.4 install /home/pi/googlehomeSample/node_modules/mdns
> node-gyp rebuild

make: ディレクトリ '/home/pi/googlehomeSample/node_modules/mdns/build' に入ります
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_sd.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_browse.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_enumerate_domains.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_get_addr_info.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_process_result.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_ref.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_ref_deallocate.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_ref_sock_fd.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_register.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_resolve.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_update_record.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/mdns_utils.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/network_interface.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/socket_watcher.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_ref.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_create.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_deallocate.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_set_value.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_get_length.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_buffer_to_object.o
  SOLINK_MODULE(target) Release/obj.target/dns_sd_bindings.node
  COPY Release/dns_sd_bindings.node
make: ディレクトリ '/home/pi/googlehomeSample/node_modules/mdns/build' から出ま す

> ngrok@2.2.24 postinstall /home/pi/googlehomeSample/node_modules/ngrok
> node ./postinstall.js

ngrok - downloading binary https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip
ngrok - downloading progress: 5084312/5084312
ngrok - binary downloaded to /home/pi/.ngrok/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1saW51eC1hcm0uemlw.zip
ngrok - unpacking binary
ngrok - binary unpacked to /home/pi/googlehomeSample/node_modules/ngrok/bin/ngrok
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN googlehomesample@1.0.0 No description
npm WARN googlehomesample@1.0.0 No repository field.

+ google-home-notifier@1.2.0
added 138 packages in 170.896s

これでインストールができました。途中でngrokなどもビルドしているようなので少し時間はかかっています。

サンプルを動かす

サンプルは以下のようになっていますが、コアの要素だけを抽出し簡単にしてみました。

【オリジナルのサンプル】 github.com

【機能を絞ったサンプル】

var googlehome = require('google-home-notifier');
var language = 'ja';

googlehome.device('テスト', language);
googlehome.ip('192.168.0.2');// IPアドレスは自分の環境のGoogleHomeの設定に合わせてください

var text = 'こんにちは';

try {
        googlehome.notify(text, function(notifyRes) {
                console.log(notifyRes);
        });
} catch(err) {
        console.log(err);
}

基本的にはgooglehomeの設定(言語設定、IP設定など)を行い、notifyメソッドを実行すると、 いったん音がなり、テキストの読み上げが行われます。

deviceメソッドの第一引数は適当でいいようなのですが、たぶん事前設定した名前にすればIP設定しなくてもいいのかなとなんとなく思いました。(未確認)

警告が表示されますが、特に問題はないようです。 (内容はavahi関連の警告で、今回のコードではIP直接のアクセスだから問題ないのかなと思います。)

【実行のようす】

$ node test.js
*** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node>
*** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node&f=DNSServiceRegister>
Device notified

これで無事音声が出力されました。読み上げた音声はたどたどしい抑揚です。

では固定の文字列ではなくコマンドライン引数にしていした文字列を読み上げるコードに変更してみます。

var googlehome = require('google-home-notifier');
var language = 'ja';

googlehome.device('テスト', language);
googlehome.ip('192.168.0.2');// IPアドレスは自分の環境のGoogleHomeの設定に合わせてください

var text = 'こんにちは';

if(process.argv.length == 3){
        text = process.argv[2];
}

try {
        googlehome.notify(text, function(notifyRes) {
                console.log(notifyRes);
        });
} catch(err) {
        console.log(err);
}

省略した場合は「こんにちは」と出力し、引数に指定した場合には「引数に指定した言葉」を話します。

おわりに

話す言葉の制限がかなりあったGoogleHomeではありますが、これでかなり自由度が高くなりました。

RaspberryPi+OpenJTalk+Bluetoothスピーカーなどの組み合わせを、RaspberryPi+google-home-notifier+GoogleHomeに変更することも可能かなと思います。 数字の読み上げなどがどうなるのかはまだテストしていませんが、それなりに動いてくれるのでは?と思ってはいます。

cronやアラームシステムとの組合わせ、WebAPIとの連携なども簡単にできそうなのでなかなか魅力的な感じです。

それにしても、いつになったらAmazon Echoの招待が来るのだろうか…

RaspberryPiに比較的新しいTensorFlowをインストールしてみる(Python2系、Python3系)

RaspberryPiに比較的新しいTensorFlowをインストールしてみる(Python2系、Python3系)

そろそろ、TensorFlowを入れなきゃと思いインストールしてみたのですが、ネットを調べただけで、なにもしていなかったので年末だということもあり設定をしてみました。

github.com

比較的新しいバージョンのインストールエントリーがあったので以下2つを参考にさせてもらいました。基本的に1からビルドするとかなり時間がかかるのですが、これにより時間を大幅に短縮できたのでとても助かりました。ただ、この情報もそのままだとうまくいかない(インストールが失敗する)ので、失敗の状況も含めていろいろ調べて修正してみました。参考になればと思います。

qiita.com

petewarden.com

個人的にはpython3にそろそろ移行していきたいところ(個人的な来年の目標はpython3系に移行することにしています) 手順のエントリーには、python2系、python3系の両方のやり方が書いてあったので、折角なので両方セットアップしてみます。

python2系(version2.7)の手順

TensorFlowのインストール

python開発系のパッケージをインストールしていきます。インストールのログが長いのでコマンドとログを分けました。

コマンド:失敗例

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl

【ログ】

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
Reading package lists... Done
Building dependency tree
Reading state information... Done
python-dev is already the newest version (2.7.13-2).
python-dev set to manually installed.
python-setuptools is already the newest version (33.1.1-1).
python-setuptools set to manually installed.
The following additional packages will be installed:
  gfortran-6 libatlas-dev libatlas3-base libgfortran-6-dev
Suggested packages:
  gfortran-doc gfortran-6-doc libgfortran3-dbg libcoarrays-dev libblas-doc
  liblapack-doc liblapack-doc-man
The following NEW packages will be installed:
  gfortran gfortran-6 libatlas-base-dev libatlas-dev libatlas3-base
  libblas-dev libgfortran-6-dev liblapack-dev
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 11.7 MB of archives.
After this operation, 56.2 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libgfortran-6-dev armhf 6.3.0-18+rpi1 [199 kB]
Get:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf gfortran-6 armhf 6.3.0-18+rpi1 [5,422 kB]
Get:3 http://mirrordirector.raspbian.org/raspbian stretch/main armhf gfortran armhf 4:6.3.0-4 [1,352 B]
Get:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libatlas3-base armhf 3.10.3-1+rpi1 [1,920 kB]
Get:5 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libblas-dev armhf 3.7.0-2 [114 kB]
Get:6 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libatlas-dev armhf 3.10.3-1+rpi1 [65.9 kB]
Get:7 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libatlas-base-dev armhf 3.10.3-1+rpi1 [2,528 kB]
Get:8 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf liblapack-dev armhf 3.7.0-2 [1,483 kB]
Fetched 11.7 MB in 8s (1,304 kB/s)
Selecting previously unselected package libgfortran-6-dev:armhf.
(Reading database ... 122979 files and directories currently installed.)
Preparing to unpack .../0-libgfortran-6-dev_6.3.0-18+rpi1_armhf.deb ...
Unpacking libgfortran-6-dev:armhf (6.3.0-18+rpi1) ...
Selecting previously unselected package gfortran-6.
Preparing to unpack .../1-gfortran-6_6.3.0-18+rpi1_armhf.deb ...
Unpacking gfortran-6 (6.3.0-18+rpi1) ...
Selecting previously unselected package gfortran.
Preparing to unpack .../2-gfortran_4%3a6.3.0-4_armhf.deb ...
Unpacking gfortran (4:6.3.0-4) ...
Selecting previously unselected package libatlas3-base.
Preparing to unpack .../3-libatlas3-base_3.10.3-1+rpi1_armhf.deb ...
Unpacking libatlas3-base (3.10.3-1+rpi1) ...
Selecting previously unselected package libblas-dev.
Preparing to unpack .../4-libblas-dev_3.7.0-2_armhf.deb ...
Unpacking libblas-dev (3.7.0-2) ...
Selecting previously unselected package libatlas-dev.
Preparing to unpack .../5-libatlas-dev_3.10.3-1+rpi1_armhf.deb ...
Unpacking libatlas-dev (3.10.3-1+rpi1) ...
Selecting previously unselected package libatlas-base-dev.
Preparing to unpack .../6-libatlas-base-dev_3.10.3-1+rpi1_armhf.deb ...
Unpacking libatlas-base-dev (3.10.3-1+rpi1) ...
Selecting previously unselected package liblapack-dev.
Preparing to unpack .../7-liblapack-dev_3.7.0-2_armhf.deb ...
Unpacking liblapack-dev (3.7.0-2) ...
Setting up libatlas3-base (3.10.3-1+rpi1) ...
update-alternatives: using /usr/lib/atlas-base/atlas/libblas.so.3 to provide /usr/lib/libblas.so.3 (libblas.so.3) in auto mode
update-alternatives: using /usr/lib/atlas-base/atlas/liblapack.so.3 to provide /usr/lib/liblapack.so.3 (liblapack.so.3) in auto mode
Setting up libgfortran-6-dev:armhf (6.3.0-18+rpi1) ...
Processing triggers for libc-bin (2.24-11+deb9u1) ...
Processing triggers for man-db (2.7.6.1-2) ...
Setting up gfortran-6 (6.3.0-18+rpi1) ...
Setting up gfortran (4:6.3.0-4) ...
update-alternatives: using /usr/bin/gfortran to provide /usr/bin/f95 (f95) in auto mode
update-alternatives: using /usr/bin/gfortran to provide /usr/bin/f77 (f77) in auto mode
Setting up libblas-dev (3.7.0-2) ...
update-alternatives: using /usr/lib/libblas/libblas.so to provide /usr/lib/libblas.so (libblas.so) in auto mode
Setting up libatlas-dev (3.10.3-1+rpi1) ...
Setting up liblapack-dev (3.7.0-2) ...
update-alternatives: using /usr/lib/lapack/liblapack.so to provide /usr/lib/liblapack.so (liblapack.so) in auto mode
Setting up libatlas-base-dev (3.10.3-1+rpi1) ...
update-alternatives: using /usr/lib/atlas-base/atlas/libblas.so to provide /usr/lib/libblas.so (libblas.so) in auto mode
update-alternatives: using /usr/lib/atlas-base/atlas/liblapack.so to provide /usr/lib/liblapack.so (liblapack.so) in auto mode

コマンドの1行目の必須パッケージのインストールはうまく行ったのですが、tensorflowの本体のインストールでは失敗してしまいます。 ブラウザでwhlファイルがあるURLを確認するとファイルのアクセスができない状態のようです。nightlyビルドってこんなものなの?かな。

$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl
Collecting tensorflow==1.3.0 from http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl
Exception:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/usr/lib/python2.7/dist-packages/pip/commands/install.py", line 353, in run
    wb.build(autobuilding=True)
  File "/usr/lib/python2.7/dist-packages/pip/wheel.py", line 749, in build
    self.requirement_set.prepare_files(self.finder)
  File "/usr/lib/python2.7/dist-packages/pip/req/req_set.py", line 380, in prepare_files
    ignore_dependencies=self.ignore_dependencies))
  File "/usr/lib/python2.7/dist-packages/pip/req/req_set.py", line 620, in _prepare_file
    session=self.session, hashes=hashes)
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 821, in unpack_url
    hashes=hashes
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 659, in unpack_http_url
    hashes)
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 855, in _download_http_url
    resp.raise_for_status()
  File "/usr/share/python-wheels/requests-2.12.4-py2.py3-none-any.whl/requests/models.py", line 893, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
HTTPError: 404 Client Error: Not Found for url: http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl

いろいろと考えてnightlyビルドなのでもしかしたら新しいURLに格納されているのかなと思い、サイトを調べてみました。

nightly-pi [Jenkins]

このページから最新のRaspberryPi用のnightlyビルドが取得できそうです。現在はtensorflowのバージョンは1.4になっていますので参考にしたサイトより更に最新のものになります。(わーい)2017.12.30現在のビルドは#140なのでそれを使用してインストールを行っています。URLを変更して以下の様にします。

【インストールコマンド変更】

$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl

【ログ】

$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl
Collecting tensorflow==1.4.0 from http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl
  Downloading http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl (56.3MB)
    100% |????????????????????????????????| 56.3MB 10.9MB/s
Collecting protobuf>=3.4.0 (from tensorflow==1.4.0)
  Downloading protobuf-3.5.1-py2.py3-none-any.whl (388kB)
    100% |????????????????????????????????| 389kB 550kB/s
Collecting absl-py>=0.1.6 (from tensorflow==1.4.0)
  Downloading absl-py-0.1.7.tar.gz (78kB)
    100% |????????????????????????????????| 81kB 1.6MB/s
Collecting tensorflow-tensorboard (from tensorflow==1.4.0)
  Downloading tensorflow_tensorboard-0.1.8-py2-none-any.whl (1.6MB)
    100% |????????????????????????????????| 1.6MB 154kB/s
Requirement already satisfied: six>=1.10.0 in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Requirement already satisfied: enum34>=1.1.6 in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Collecting backports.weakref>=1.0rc1 (from tensorflow==1.4.0)
  Downloading backports.weakref-1.0.post1-py2.py3-none-any.whl
Requirement already satisfied: wheel in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Collecting mock>=2.0.0 (from tensorflow==1.4.0)
  Downloading mock-2.0.0-py2.py3-none-any.whl (56kB)
    100% |????????????????????????????????| 61kB 1.8MB/s
Requirement already satisfied: setuptools in /usr/lib/python2.7/dist-packages (from protobuf>=3.4.0->tensorflow==1.4.0)
Collecting markdown>=2.6.8 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading Markdown-2.6.10.zip (414kB)
    100% |????????????????????????????????| 419kB 646kB/s
Requirement already satisfied: werkzeug>=0.11.10 in /usr/lib/python2.7/dist-packages (from tensorflow-tensorboard->tensorflow==1.4.0)
Collecting bleach==1.5.0 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading bleach-1.5.0-py2.py3-none-any.whl
Collecting html5lib==0.9999999 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading html5lib-0.9999999.tar.gz (889kB)
    100% |????????????????????????????????| 890kB 261kB/s
Collecting funcsigs>=1; python_version < "3.3" (from mock>=2.0.0->tensorflow==1.4.0)
  Downloading funcsigs-1.0.2-py2.py3-none-any.whl
Collecting pbr>=0.11 (from mock>=2.0.0->tensorflow==1.4.0)
  Downloading pbr-3.1.1-py2.py3-none-any.whl (99kB)
    100% |????????????????????????????????| 102kB 954kB/s
Building wheels for collected packages: absl-py, markdown, html5lib
  Running setup.py bdist_wheel for absl-py ... done
  Stored in directory: /root/.cache/pip/wheels/c4/71/71/7bd70f858f062d3f99990dcbc3f45b795bde057a42f971537f
  Running setup.py bdist_wheel for markdown ... done
  Stored in directory: /root/.cache/pip/wheels/1e/5a/55/a80b200d12e234d575ad68c1528593d1ce488720b65b24e48c
  Running setup.py bdist_wheel for html5lib ... done
  Stored in directory: /root/.cache/pip/wheels/6f/85/6c/56b8e1292c6214c4eb73b9dda50f53e8e977bf65989373c962
Successfully built absl-py markdown html5lib
Installing collected packages: protobuf, absl-py, markdown, html5lib, bleach, tensorflow-tensorboard, backports.weakref, funcsigs, pbr, mock, tensorflow
Successfully installed absl-py-0.1.7 backports.weakref-1.0.post1 bleach-1.5.0 funcsigs-1.0.2 html5lib-0.9999999 markdown-2.6.10 mock-2.0.0 pbr-3.1.1 protobuf-3.5.1 tensorflow-1.4.0 tensorflow-tensorboard-0.1.8

コマンド:成功例

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl

一般のパッケージに比べれば少し時間はかかりますが、そんな大した時間ではありません。これでインストールが完了しましたので対話型インターフェースで実行を行ってみます。

【実行テスト】

$ python
Python 2.7.13 (default, Nov 24 2017, 17:33:09)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
Hello, TensorFlow!
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a + b))
42
>>>

TensorFlowが無事にインストールされたようです。やりました!

Kerasもインストールする

Kerasは,Pythonで書かれた,TensorFlowまたはCNTK,Theano上で実行可能な高水準のニューラルネットワークライブラリです. Kerasは,迅速な実験を可能にすることに重点を置いて開発されました. アイデアから結果に到達するまでのリードタイムをできるだけ小さくすることが,良い研究をするための鍵になります.

Kerasのサイトは以下になります。

Keras Documentation

https://keras.io/ja/keras.io

Keras Documentation

Kerasのインストールに関しては比較的簡単です。あとは依存系のライブラリモジュールもインストールしておきます。

【コマンド】

$ sudo apt-get install python-h5py
$ sudo pip install keras

【ログ】

$ sudo apt-get install python-h5py
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  libaec0 libhdf5-100 libsz2
Suggested packages:
  python-h5py-doc
The following NEW packages will be installed:
  libaec0 libhdf5-100 libsz2 python-h5py
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,790 kB of archives.
After this operation, 7,210 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libaec0 armhf 0.3.2-1 [19.4 kB]
Get:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libsz2 armhf 0.3.2-1 [5,836 B]
Get:3 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libhdf5-100 armhf 1.10.0-patch1+docs-3 [1,203 kB]
Get:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf python-h5py armhf 2.7.0-1 [561 kB]
Fetched 1,790 kB in 3s (480 kB/s)
Selecting previously unselected package libaec0:armhf.
(Reading database ... 123241 files and directories currently installed.)
Preparing to unpack .../libaec0_0.3.2-1_armhf.deb ...
Unpacking libaec0:armhf (0.3.2-1) ...
Selecting previously unselected package libsz2:armhf.
Preparing to unpack .../libsz2_0.3.2-1_armhf.deb ...
Unpacking libsz2:armhf (0.3.2-1) ...
Selecting previously unselected package libhdf5-100:armhf.
Preparing to unpack .../libhdf5-100_1.10.0-patch1+docs-3_armhf.deb ...
Unpacking libhdf5-100:armhf (1.10.0-patch1+docs-3) ...
Selecting previously unselected package python-h5py.
Preparing to unpack .../python-h5py_2.7.0-1_armhf.deb ...
Unpacking python-h5py (2.7.0-1) ...
Setting up libaec0:armhf (0.3.2-1) ...
Processing triggers for libc-bin (2.24-11+deb9u1) ...
Setting up libsz2:armhf (0.3.2-1) ...
Setting up libhdf5-100:armhf (1.10.0-patch1+docs-3) ...
Setting up python-h5py (2.7.0-1) ...
Processing triggers for libc-bin (2.24-11+deb9u1) ...

$ sudo pip install keras
Collecting keras
  Using cached Keras-2.1.2-py2.py3-none-any.whl
Collecting pyyaml (from keras)
Requirement already satisfied: six>=1.9.0 in /usr/lib/python2.7/dist-packages (from keras)
Collecting scipy>=0.14 (from keras)
  Using cached scipy-1.0.0.tar.gz
Requirement already satisfied: numpy>=1.9.1 in /usr/lib/python2.7/dist-packages (from keras)
Building wheels for collected packages: scipy
  Running setup.py bdist_wheel for scipy ... done
  Stored in directory: /root/.cache/pip/wheels/b9/3e/bd/e9f0e1707c4be2bb1f671fd4246028d5d2e10cd70740ffd801
Successfully built scipy
Installing collected packages: pyyaml, scipy, keras
Successfully installed keras-2.1.2 pyyaml-3.12 scipy-1.0.0

これでインストールできました。(2時間弱かかりました)

python3系(version3.4またはversion3.5)の手順

pippip3と明示する必要があります。

TensorFlowのインストール

pythonの動作するバージョンに合わせる必要があります。 念のためRaspberryPiで動作するpython3系のバージョンを調べましょう。

比較的新しいRaspbianではPythonのバージョンは3.5.3のようです。

動作するpythonのバージョンがversion3.4の場合

すみませんが、こちらは動かせていませんが、whlファイルも存在するので多分うまく行きそうです。

【version3.4のコマンド】

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo pip3 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi-python3/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp34-none-any.whl

動作するpythonのバージョンがversion3.5の場合

作業自体は大きくは変化しないのですが、3.4用に作成されたwhlファイルを3.5用に名前だけ変更してインストールしています。そのため一度名前変更するためにcurlでローカルにダウンロードしてからpip3でインストールしています。また、python3用にパッケージ名も変更しています。(既にpython3-devpython3-setuptoolsインストールはされているので気にしなくてもいいかもしれません。)

【version3.5のコマンド】

$ sudo apt-get install libblas-dev liblapack-dev python3-dev libatlas-base-dev gfortran python3-setuptools
$ curl -O http://ci.tensorflow.org/view/Nightly/job/nightly-pi-python3/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp34-none-any.whl
$ mv tensorflow-1.4.0-cp34-none-any.whl tensorflow-1.4.0-cp35-none-any.whl
$ sudo pip3 install tensorflow-1.4.0-cp35-none-any.whl

【ログ】

$ sudo apt-get install libblas-dev liblapack-dev python3-dev libatlas-base-dev gfortran python3-setuptools
Reading package lists... Done
Building dependency tree
Reading state information... Done
gfortran is already the newest version (4:6.3.0-4).
libatlas-base-dev is already the newest version (3.10.3-1+rpi1).
libblas-dev is already the newest version (3.7.0-2).
liblapack-dev is already the newest version (3.7.0-2).
python3-dev is already the newest version (3.5.3-1).
python3-dev set to manually installed.
python3-setuptools is already the newest version (33.1.1-1).
python3-setuptools set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

$ curl -O http://ci.tensorflow.org/view/Nightly/job/nightly-pi-python3/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp34-none-any.whl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 53.6M  100 53.6M    0     0  2912k      0  0:00:18  0:00:18 --:--:-- 2966k
pi@raspberrypi:~/tensorflow $ mv tensorflow-1.4.0-cp34-none-any.whl tensorflow-1.4.0-cp35-none-any.whl
pi@raspberrypi:~/tensorflow $ ls
tensorflow-1.4.0-cp35-none-any.whl

$ sudo pip3 install tensorflow-1.4.0-cp35-none-any.whl
Processing ./tensorflow-1.4.0-cp35-none-any.whl
Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python3/dist-packages (from tensorflow==1.4.0)
Collecting absl-py>=0.1.6 (from tensorflow==1.4.0)
  Downloading https://www.piwheels.hostedpi.com/simple/absl-py/absl_py-0.1.7-py3-none-any.whl (93kB)
    100% |????????????????????????????????| 102kB 91kB/s
Collecting protobuf>=3.4.0 (from tensorflow==1.4.0)
  Using cached protobuf-3.5.1-py2.py3-none-any.whl
Requirement already satisfied: wheel>=0.26 in /usr/lib/python3/dist-packages (from tensorflow==1.4.0)
Collecting tensorflow-tensorboard (from tensorflow==1.4.0)
  Downloading tensorflow_tensorboard-0.1.8-py3-none-any.whl (1.6MB)
    100% |????????????????????????????????| 1.6MB 176kB/s
Requirement already satisfied: six>=1.10.0 in /usr/lib/python3/dist-packages (from tensorflow==1.4.0)
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from protobuf>=3.4.0->tensorflow==1.4.0)
Collecting bleach==1.5.0 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Using cached bleach-1.5.0-py2.py3-none-any.whl
Requirement already satisfied: werkzeug>=0.11.10 in /usr/lib/python3/dist-packages (from tensorflow-tensorboard->tensorflow==1.4.0)
Collecting markdown>=2.6.8 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading https://www.piwheels.hostedpi.com/simple/markdown/Markdown-2.6.10-py3-none-any.whl (77kB)
    100% |????????????????????????????????| 81kB 58kB/s
Collecting html5lib==0.9999999 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading https://www.piwheels.hostedpi.com/simple/html5lib/html5lib-0.9999999-py3-none-any.whl (111kB)
    100% |????????????????????????????????| 112kB 165kB/s
Installing collected packages: absl-py, protobuf, html5lib, bleach, markdown, tensorflow-tensorboard, tensorflow
Successfully installed absl-py-0.1.7 bleach-1.5.0 html5lib-0.9999999 markdown-2.6.10 protobuf-3.5.1 tensorflow-1.4.0 tensorflow-tensorboard-0.1.8

無事にインストールが終了した様です。では、こちらも対話型インターフェースでテストしてみます。 importしてみると…

$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: compiletime version 3.4 of module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.5
  return f(*args, **kwds)
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: builtins.type size changed, may indicate binary incompatibility. Expected 432, got 412
  return f(*args, **kwds)
>>>

げーッまたしてもエラーが発生しました。

ぐぐってみたら以下のエントリーが。

qiita.com

どうもこの問題は既知の問題のようです。インストールするときにもファイル名をpython3.5に合わせるために修正したことも関係しているのでしょう。一番最初リンクしたサイトにも以下の記述がありました。

If you’re running Python 3.5, you can use the same wheel but with a slight change to the file name, since that encodes the version. You will see a couple of warnings every time you import tensorflow, but it should work correctly.

but it should work correctly.の記載があるので今後のバージョンアップに期待したいところです。では、テストを続けてみます。

$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: compiletime version 3.4 of module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.5
  return f(*args, **kwds)
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: builtins.type size changed, may indicate binary incompatibility. Expected 432, got 412
  return f(*args, **kwds)
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
b'Hello, TensorFlow!'
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a + b))
42
>>>

いろいろメッセージは出ますが、動作には問題ないようです。ビルドさせられるのは厳しかったのでかなり助かった気分です。

Kerasもインストールする

【コマンド】

$ sudo apt-get install python3-h5py
$ sudo pip3 install keras

【ログ】

$ sudo apt-get install python3-h5py
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  python-h5py-doc
The following NEW packages will be installed:
  python3-h5py
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 558 kB of archives.
After this operation, 2,647 kB of additional disk space will be used.
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf python3-h5py armhf 2.7.0-1 [558 kB]
Fetched 558 kB in 1s (396 kB/s)
Selecting previously unselected package python3-h5py.
(Reading database ... 123353 files and directories currently installed.)
Preparing to unpack .../python3-h5py_2.7.0-1_armhf.deb ...
Unpacking python3-h5py (2.7.0-1) ...
Setting up python3-h5py (2.7.0-1) ...

$ sudo pip3 install keras
Collecting keras
  Using cached Keras-2.1.2-py2.py3-none-any.whl
Collecting pyyaml (from keras)
  Downloading https://www.piwheels.hostedpi.com/simple/pyyaml/PyYAML-3.12-cp35-cp35m-linux_armv7l.whl (43kB)
    100% |????????????????????????????????| 51kB 47kB/s
Requirement already satisfied: six>=1.9.0 in /usr/lib/python3/dist-packages (from keras)
Collecting scipy>=0.14 (from keras)
  Downloading https://www.piwheels.hostedpi.com/simple/scipy/scipy-1.0.0-cp35-cp35m-linux_armv7l.whl (35.1MB)
    100% |????????????????????????????????| 35.1MB 8.4kB/s
Requirement already satisfied: numpy>=1.9.1 in /usr/lib/python3/dist-packages (from keras)
Installing collected packages: pyyaml, scipy, keras
Successfully installed keras-2.1.2 pyyaml-3.12 scipy-1.0.0

こちらも無事にインストールができました。2系のインストールが終わっていたからかもしれませんが、すぐに完了しました。

おわりに

一応これでpython2系でもpython3系でもTensorFlow1.4のインストールができました。 あとは使うだけなんですよ。使うだけ…

RaspberryPiからWio Node経由でLEDStrip(LEDテープ)を光らせる

RaspberryPiからWio Node経由でLEDStrip(LEDテープ)を光らせる

前回のエントリーではRaspberryPiからWio Nodeに接続した温度センサーの値を取得しました。

uepon.hatenadiary.com

ようやく手元にLEDStrip(俗にいうLEDテープ)が届いたのでテストしてみました。今回はクリスマスセールでSeeedさんの商品がかなり安く購入できたのでそれに含まれていた LEDテープを使用しています。(Groveコネクタもついているのでそのまま使えます。)これでNagoyaハッカソンのネタは自宅でできるようになりました。

このLEDテープなんですが、セット商品にしかついていないのが残念なので単独販売されるといいなと思います。 まあ作ればいいんですけど、最近は老眼が酷くて手元がおぼつかないのです。

このあたりはセンサー類だけでもお得なので購入おすすめ(12/28現在:クリアランスセールでセットで$24とかないよ…でも同梱されてるWio Linkは使っちゃダメなんで注意)

www.seeedstudio.com

micro:bitのコネクター付のセットもいいかなと思います。(秋月ですし)

akizukidenshi.com

Wio Nodeに接続する

設定に関しては過去のエントリーを参照していただければと思います。接続操作は簡単で、OutputのカテゴリーにあるWS2812 LED Strip 60を選択し、コネクタにドロップします。画面したに赤くConfrom Farmwareと出るのでそれも忘れずに押してください。

f:id:ueponx:20171228182318p:plain

あとは画面左上のハンバーガーボタンを押してAPIの確認をします。

温度センサーの設定をそのままにしているので温度センサーのAPIに加えてLEDテープの設定が追加されています。 点灯・消灯のAPIはこのようになっています。

f:id:ueponx:20171228182903p:plain

この設定では最大60個のLEDまでコントロールできるのですが、今回接続したものは30個なのでパラメータとしては30、後はRGBの16進6桁表記( #0xは不要です)でパラメータを送信すればOKです。 消灯する場合には000000を指定すれば消灯します。

Curlでのアクセスは以下のようになります。

$ curl -k -X POST https://us.wio.seeed.io/v1/node/GroveLedWs2812D0/clear/30/aa00aa?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{"result": "ok"}

youtu.be

点灯・消灯以外にもスタートインデックスを指定して、RGBパターンを連続して記述して、一つ一つのLEDの色を変えるようなこともできます。 また、 rainbow flowと呼ばれる色を変化させながら点滅するモードもあります。

f:id:ueponx:20171228185654j:plain

RaspberryPiからアクセスしてみる

pythonからはこんな感じでアクセスできます。恒例のrequestsモジュールを使って、今回はPOSTメソッドでアクセスしています。 コマンドライン引数からパラメータをセットしています。joinを使ったほうがキレイにできると思いましたが、それは好みでということで。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import requests

argvs = sys.argv
argc = len(argvs)

length = '30'
britness = '0'
speed = '1'

if(argc > 1):
    length = argvs[1]
if(argc > 2):
    britness = argvs[2]
if(argc > 3):
    speed = argvs[3]

url = 'https://us.wio.seeed.io/v1/node/GroveLedWs2812D0/start_rainbow_flow/' + length + '/' + britness + '/' + speed

payload = {'access_token': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'}
r = requests.post(url, params=payload)
print(r.text)

youtu.be

一応、うまくいったようです。

終わりに

Nagoyaハッカソンで使ったもののメモとしてはこれで終わりかなと思います。 それにしても、本当に老眼ではんだ付けがきつくなった自分にとってはGroveサマサマといった感じです。

/* -----codeの行番号----- */