keras-deeplab-v3-plusで人だけとってみる

github.com

Semantic Segmentationで人をとってきたいのでこのアーキテクチャを使って人と背景を分ける。

準備

# 仮想環境の準備
$ conda create -n keras-deeplab-v3-plus
$ source activate keras-deeplab-v3-plus

# モジュールインストール
$ conda install tqdm
$ conda install numpy
$ conda install keras

# 重みダウンロード
$ python extract_weights.py 
$ python load_weights.py 

Jupyterを使って画像を出力

ここからは自分用にカスタマイズしていく。 多クラス分類だが、人だけとれれば良い。

デフォルトで入っているimage1.jpgを使う。

import model
import cv2

img = cv2.imread('./imgs/image1.jpg')
img = cv2.resize(img, (512, 512)) # imgは0〜255の値をとる

model_dlv3 = model.Deeplabv3()

predicted = model_dlv3.predict(img[np.newaxis, ...])
print(predicted.shape) 
# (1, 512, 512, 21)

21クラス分類だが、どれが人なのか。
閾値がどうなっているのか知りたい。

が、プログラム内に無さげ。
「semantic segmentation 21 class names」でぐぐる

一番上にぽいのが出てくる。 github.com 0が背景で、15が人と仮定する。

追記
というかmodels.pydef Deeplabv3(weights='pascal_voc', ...という行もあるのでこれで合っていると思われる。

person_score = predicted[0, :, : ,15]
back_score = predicted[0, :, :, 0]

mask = (person_score > back_score).astype("uint8") * 255
cv2.imwrite("test.jpg", mask)

出力してみると真っ黒。

考えられる原因

  1. OpenCVはBGRだがこれはRGBを使っている
  2. 0〜255ではなく-1〜1などで処理している

追記
入力画像の大きさが小さすぎた&人が横になっていたのが原因でした(横になっていた際の出力例、RGBに変換した画像は下の方にあります)

入力の際の前処理

ところで、これはモデルとしてMobileNetv2を使用していた。
画像の前処理はどうやってるんだろう?
Kerasがmobilenetv2を提供していて、ResNetなどもpreprocess_input的な関数は提供している(らしい)。
ということで調べてみる。

こういう当たりが付けられるの強い。
といってもここらへん全部友人がやってくれた。圧倒的人任せ。

「mobilenetv2 preprocess keras」でぐぐると以下のサイトが見つかる。 github.com

preprocess_inputというのがあるのでそれを使ってみよう。

import cv2
import numpy as np

import model

from keras.applications.mobilenetv2 import preprocess_input

img = preprocess_input(cv2.imread('./imgs/image1.jpg')) ## ここでエラー
img = cv2.resize(img, (512, 512))

エラー発生

TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind''

参考: TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind'' #8635

最終的にはこんな感じに。

import cv2
import numpy as np

import model

from keras.applications.mobilenetv2 import preprocess_input

img = preprocess_input(cv2.imread('./imgs/test.jpg').astype("float"))
img = cv2.resize(img, (512, 512))

img.max() # 0.9921875
model_dlv3 = model.Deeplabv3()

predicted = model_dlv3.predict(img[np.newaxis, ...])

person_score = predicted[0, :, : ,15]
back_score = predicted[0, :, :, 0]

mask = (person_score > back_score).astype("uint8") * 255
cv2.imwrite("test.jpg", mask)

出力結果

背景はデフォルトで黒、あとは人だけ取り出してみた。 上手いこととれた! f:id:saneeeatsu:20180820183446p:plain

因みにこの人を横にすると人だと認識しない。 f:id:saneeeatsu:20180820183428p:plain

BGR→RGBにしてみる

OpenCVではデフォルトでBGRで扱うが、もしこのアーキテクチャではRGBで扱っていて、更に人を肌の色などで認識している場合、精度が異なってくる。
ってことで試す。

と言っても1行追加するだけだけど。

img = preprocess_input(cv2.imread('./imgs/R0_L0_ono_001360.jpg').astype("float"))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 追加行
img = cv2.resize(img, (512, 512))

元画像を載せていないのでよくわからないと思うが、本来白色になってほしいところ(スカートの白色の部分)が白色にきちんとなっているしRGBの方が良さげではある。 f:id:saneeeatsu:20180820184540p:plain

シェルでは使えているPythonモジュールをJupyterNotebookで実行すると「ImportError: No module named module_name」が出てくる

問題点

はじめてPytorchを使った際に以下のようなエラーが。

ImportError: No module named torch

pip installする

$ pip install torch
Requirement already satisfied: torch in /home/ubuntu/miniconda3/lib/python3.6/site-packages (0.4.1)

既にインストールされてる。
シェルでも問題なく使える

$ python 
Python 3.6.5 |Anaconda, Inc.| (default, Apr 29 2018, 16:14:56) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch
>>> 

はて…?

現状

現在はvenvで作った環境にいる。

$ conda create -n pytorch-segmentation-detection
$ source activate pytorch-segmentation-detection

(pytorch-segmentation-detection) ubuntu@ip-172-31-5-82:~/Code/pytorch-segmentation-detection$ 

が、Jupyter上で見るとこの「pytorch-segmentation-detection」というカーネルが存在しない。 f:id:saneeeatsu:20180820140843p:plain

解決策

そこで、ipykernelをインストールする。

$ conda install ipykernel
$ ipython kernel install --user --name pytorch-segmentation-detection --display-name pytorch-segmentation-detection

出てきた! f:id:saneeeatsu:20180820141009p:plain

参考

実行したファイルの残り時間をターミナルに表示する

機械学習のプログラムを書き始めると、大きいファイルを扱う機会が増えた。 そこでターミナルに残り時間を表示させたいと思ったので、 h5ファイルを作成する関数を例にしてメモっておく。

def create_h5(h5_fpath, image_fpaths, better_model, num):
    start_time = datetime.now() # 現在時刻取得
    print('============================')
    print("Start: " + str(start_time))
    print("Num  : " + str(num)) # 読み込む画像の枚数
    
    with h5py.File(h5_fpath, "w") as f:
        for i, image_fpath in enumerate(image_fpaths):
            # ここでファイルを読み込んでh5ファイルを作成する処理を行っていることとする
            
            # 100枚毎に残り時間を表示させる
            if i % 100 == 0 and i != 0:
                elapsed_time = datetime.now() - start_time  # 経過時間
                ave_time = elapsed_time/i                   # 現在における1つあたりの平均処理時間を算出
                remain_time = (ave_time*num) - elapsed_time # 「平均*画像枚数」で全体的なかかる時間を計算し、経過時間を引く
                print(str(i)+": "+str(remain_time)+" left")

実際の出力はこんな感じ。

4200: 0:00:57.961352 left
4300: 0:00:50.587814 left
4400: 0:00:43.323896 left
4500: 0:00:35.996341 left
4600: 0:00:28.692517 left
4700: 0:00:21.979801 left
4800: 0:00:14.650676 left
4900: 0:00:07.381439 left

JupyterNotebookでファイルがリロードされない

リロードさせる方法

1. importlib.reload

import load_weights
import model
importlib.reload(load_weights)
importlib.reload(model)

2. autoreload 2

以下をJupyterNotebookに貼り付ける。

% load_ext autoreload # 外部のモジュールautoreloadをロード
% autoreload 2 # 実行する度にインポートしたモジュールをリロードする。

参考

Kerasで「AttributeError: 'NoneType' object has no attribute HOGEHOGE」

エラー

Kerasで重みを読み込む時に以下のエラー。

model_50 = model_50.load_weights('/host/weights/weights.013-7.248.hdf5')

# AttributeError: 'NoneType' object has no attribute 'load_weights'

NoneType。。。

print(type(model_50))

# <class 'NoneType'>

解決策

代入はしなくて以下のようにするだけでmodel_50には代入される。

model_50.load_weights('/host/weights/weights.013-7.248.hdf5')

うん。大丈夫。

print(type(model_50))

# <class 'keras.engine.training.Model'>

Kerasで「ImportError: Could not import PIL.Image. The use of `array_to_img` requires PIL.」とPILのエラーが出る

エラー

ローカルではこのエラー見たことなかったんだけど、サーバ側で実行したらPILに関するエラーが。 Kerasで以下のようにimportしてるのにだめなのか…。

from keras.preprocessing.image import (
    ImageDataGenerator,
    load_img,
    img_to_array,
    array_to_img
)

解決策

condaでインストール。

$ conda install Pillow

もう一度実行したら… なんで!!OpenCVインストールしてなかったっけなぁ…。

ImportError: numpy.core.multiarray failed to import
Traceback (most recent call last):
  File "datagen.py", line 4, in <module>
    import cv2
ImportError: numpy.core.multiarray failed to import

以下コマンドでインストール。

$ conda install -c conda-forge opencv

おしまい。

参考

AWSインスタンスをもらった時にやったこと

AWSインスタンスを割り当てられて、諸々の設定はやってあるので、それ以降自分用にやったことをメモっておく。

miniconda

Miniconda — Conda 上のサイトからインストール。

$  wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh

byobu

$ sudo apt-get install byobu

zsh

$ sudo apt-get install zsh
$ /bin/zsh --version
$ which zsh

$ sudo vi /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/zsh    # この行を追加

# chshコマンドを利用してログインシェルを変更
$ chsh -s /usr/local/bin/zsh # whichの出力

以下参考。 saneeeatsu.hatenablog.com

公開鍵をGithub/Gitlabに登録

$ ssh-keygen
$ cat .ssh/id_rsa.pub 

コピーする際に使うMacpbcopyは、Ubuntuではxselに当たる。 以下参考。 saneeeatsu.hatenablog.com

マウント

$ ssh username@hogehoge.dip.jp -p 10022
$ exit

$ mkdir ~/mount_host
$ sudo apt-get install sshfs
$ sshfs username@hogehoge.dip.jp:/host ~/spacely_host -o IdentityFile=/home/ubuntu/.ssh/id_rsa -p 10022
fuse: bad mount point `/home/ubuntu/spacely_host': Transport endpoint is not connected

# エラー解決
$ fusermount -u ~/mount_host

参考 - Transport endpoint is not connected - Stackoverflow - sshfs - transport endpoint is not connected - Stackexchange