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などは発生せずにうまくロードできました。