デジタル・デザイン・ラボラトリーな日々

アラフィフプログラマーが数学と物理を基礎からやり直す

TensorFlowコトハジメ Automatic Colorization(白黒画像の自動彩色)

はじめに

静岡Developers勉強会では、今年の勉強会のテーマとして「人工知能ハンズオン」を2016/4/23に開催しました。
その際に「Automatic Colorization(白黒画像の自動彩色)」については、間に合わずに事前に試すことが出来なかった為、勉強会当日は紹介のみに留まってしまいました。
GW期間があって試すことができましたので、その顛末を記事を書いてみました。なお、実行する場合にはメモリ不足から解消しないと2度手間になりますので注意してください。

Automatic Colorizationとは

白黒写真や動画をディープ・ラーニングを用いて自動でカラーに変換するRyan Dahlさんによるプロジェクトです。ちなみにライアン・ダール(Ryan Dahl)さんは、Node.jsの創始者でもあります。 自動彩色については他にもバークレーのコンピュータ科学者 Richard Zhangさん他、幾つかのプロジェクトがあります。

日本での取り組み

早稲田大学にて、飯塚 里志さん、シモセラ エドガーさん、石川博さんが白黒写真の自動色付けを行っています。
参照: ディープネットワークを用いた大域特徴と局所特徴の学習による白黒写真の自動色付け-早稲田大学

eiji_kさんのTwitterによれば

試した方がいます。プログラム言語はLuaを使用しているようです。
参照: Automatic Colorization of Grayscale Images を試すメモ

トレーニング有り版

下記サイトを公開しているPavel Gonchar氏のcolornetでは、白黒写真の自動色付けのトレーニング用も含まれています。
GitHub - pavelgonchar/colornet: Neural Network to colorize grayscale images

これを使ったeiji_kさんのTwitterによれば

導入方法

VirtualBoxUbuntu 14.04.2 LTSのPython数値計算環境「Anaconda」にて試したところ、「Segmentation fault (コアダンプ)」エラーとなって動作しなかった為、Dockerを使用することにしました。Dockerを使うことで少ないメモリで実行できるようです。
今回のDockerイメージは、TensorFlow公式サイト版で説明していきます。 yaju3d.hatenablog.jp

2016/07/13追記 Segmentation faultの回避方法 qiita.com

環境

  • Windows 10 Home 64bit(Intel(R) Core(TM) i7-4700MQ CPU 2.40GHz メモリ 8.00GB)
  • DockerToolbox 1.10.3 → 1.11.1
  • VirtualBox 5.0.16 → 5.0.20

Dockerイメージ(TensorFlow公式サイト版)

TensorflowのサイトにあるDockerイメージにはscikit-imageがデフォルトでインストールされていないため、Jupyter NotebookのTerminalにて下記コマンドでインストールする必要があります。インストールには10分程かかります。

pip install scikit-image
 ︙
Successfully installed dask-0.9.0 networkx-1.11 scikit-image-0.12.3 toolz-0.7.4   

※Docker stop等でコンテナが破棄されると初期化されるため、毎回インストールする必要があります。

学習済みモデルファイルの取得

学習済みモデルのファイルが「colorize-20160110.tgz.torrent 492M」というトレントファイル(.torrent)として配布されています。
"BitTorrent(ビットトレント)"とは、大容量のファイルを高速に配信する為のP2Pソフトウェアです。
ダウンロードするには専用のソフトが必要になり、私はBitComet 日本語公認サイトから辿った先の「BitComet 1.40」を使いました。

世の中にはトレントファイルではなくtgzファイルのまま公開している方がいるので、そちらからダウンロード(colorize-20160108.tgz)するのが楽かと思います。
トレント版が20160110なので20160108と2日早いのが気になります。

解凍すると下記3つのファイルが展開されます。

  • colorize.tfmodel (学習済みモデル)
  • forward.py (自動彩色実行ファイル Python 2.7)
  • shark.jpg (サンプルの白黒のサメ画像 224x224)
フォルダ共有による方法(追記:2016/05/19)

DockerとWindowsのフォルダ共有方法 with tensorflowのサイトを参考にしたらフォルダ共有が出来ました。この方法ならDockerコンテナにコピーする必要がないのでいいですね。

colorize-20160110フォルダをC:\Users(ユーザー名)の配下にします。
ダウンロードフォルダのままでも問題なかったです。

$ docker run -d -m 4g -p 8888:8888 -p 6006:6006 -v /c/Users/(ユーザー名)/Downloads\colorize-20160110:/notebooks b.gcr.io/tensorflow/tensorflow

この後は「実行」まで読み飛ばしても構いません。試行段階の経緯も書いているため、参考程度にお読みください。

Dockerイメージ(mokemokechickenさん版)

mokemokechickenさんのDockerファイルにはscikit-imageが含まれており、その他にもGraphvizなどもあるので今後いろいろやりたい場合には便利です。

githubサイトから「Download ZIP」ボタンで「jupyter-tensorflow-master.zip」をダウンロードし、解凍してダウンロードフォルダに展開しました。

DockerファイルからDockerイメージを作成します。

$ docker build -t tensorenv /c/Users/(ユーザー名)/Downloads/jupyter-tensorflow-master

VirtualBoxの設定にある共有フォルダは「c/Users」になっています。"c/"は英小文字なので注意してください。

qiita.com

以前は出来たのですが、直近(2016/05/15)では下記エラーが出ました。

E: Unable to locate package graphviz-dev
E: Unable to locate package graphviz
E: Package 'pkg-config' has no installation candidate
E: Unable to locate package libgdal-dev

DockerFileのRUN apt-getの直後に「update && apt-get」を付けるといいでしょう。

RUN apt-get install -y graphviz-dev graphviz pkg-config
RUN apt-get install -y libgdal-dev
↓
RUN apt-get update && apt-get install -y graphviz-dev graphviz pkg-config
RUN apt-get update && apt-get install -y libgdal-dev

後述するメモリ制限値の"-m"オプションを付けて実行します。"-d"オプションはコンテナをバックグラウンドで動かします。

$ docker run -d -m 4g -p 8888:8888 -p 6006:6006 tensorenv

学習済みモデルファイルのコンテナへのコピー

$ docker ps
#コンテナ名(NAME)を取得 例 loving_minsky

$ docker cp /c/Users/(ユーザー名)/Downloads/colorize-20160110/colorize.tfmodel loving_minsky:/home/jovyan/work

Docker内へのファイルアップロード

Jupyter NotebookにはUpload機能があるのですが、アップロードできるサイズが25MByteまでとなっています。そのため、colorize.tfmodelファイルは529MByteと巨大なため、別方法でアップロードする必要があります。 f:id:Yaju3D:20160514134901p:plain

docker cpコマンドによる方法

docker run している場合、Control-Cで停止してください。

$ docker cp [コピー元ファイル] [CONTAINER ID or NAME]:[コピー先ファイル]

今回、colorize-20160110はダウンロードフォルダに展開しました。
VirtualBoxの設定にある共有フォルダは「c/Users」になっています。"c/"は英小文字なので注意してください。
※ホストからコンテナへのコピーにdocker execコマンドを使った方法があるのですが、Docker 1.8からホストからコンテナへのコピーも docker cp コマンドでサポートされたため、修正しました。

$ docker ps
#コンテナ名(NAME)を取得 例 cranky_murdock

$ docker cp /c/Users/(ユーザー名)/Downloads/colorize-20160110/colorize.tfmodel cranky_murdock:/notebooks

$ docker start cranky_murdock

qiita.com

curlコマンドによる方法

docker execコマンドを使わない方法として、Jupyter NotebookのTerminalにて下記コマンドを入力します。これによりnotebooksフォルダ配下にcolorize-20160108フォルダが出来ます。

# curl -SL https://s3.amazonaws.com/tinyclouds-storage/colorize-20160108.tgz | tar -xzC /notebooks                                                                     
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                                                               
                                 Dload  Upload   Total   Spent    Left  Speed                                                                                 
100  491M  100  491M    0     0  8714k      0  0:00:57  0:00:57 --:--:-- 9284k                                                                             

※この方法を使用した場合、ソースリストのファイル指定時に"colorize-20160108\colorize.tfmodel"としてフォルダを指定する必要があります。

実行

Jupyter Notebookにて下記ソースコードを実行します。 f:id:Yaju3D:20160514140332p:plain

import tensorflow as tf
import skimage.transform
from skimage.io import imsave, imread

def load_image(path):
    img = imread(path)
    # crop image from center
    short_edge = min(img.shape[:2])
    yy = int((img.shape[0] - short_edge) / 2)
    xx = int((img.shape[1] - short_edge) / 2)
    crop_img = img[yy : yy + short_edge, xx : xx + short_edge]
    # resize to 224, 224
    img = skimage.transform.resize(crop_img, (224, 224))
    # desaturate image
    return (img[:,:,0] + img[:,:,1] + img[:,:,2]) / 3.0

shark_gray = load_image("shark.jpg").reshape(1, 224, 224, 1)

with open("colorize.tfmodel", mode='rb') as f:
    fileContent = f.read()
graph_def = tf.GraphDef()
graph_def.ParseFromString(fileContent)
grayscale = tf.placeholder("float", [1, 224, 224, 1])
tf.import_graph_def(graph_def, input_map={ "grayscale": grayscale }, name='')

with tf.Session() as sess:
    inferred_rgb = sess.graph.get_tensor_by_name("inferred_rgb:0")
    inferred_batch = sess.run(inferred_rgb, feed_dict={ grayscale: shark_gray })
    imsave("shark-color.jpg", inferred_batch[0])
    print("saved shark-color.jpg")

メモリエラー

残念ながら実行すると「MemoryError」が出力されてしまいます。

/usr/local/lib/python2.7/dist-packages/google/protobuf/internal/python_message.pyc in SerializePartialToString(self)
   1072     out = BytesIO()
   1073     self._InternalSerialize(out.write)
-> 1074     return out.getvalue()
   1075   cls.SerializePartialToString = SerializePartialToString
   1076 

MemoryError: 

メモリを増やす

DockerToolboxで最初に作成されるdefaultマシンのメモリは1GByteとなっていますので、下記サイトを参考にVirtualBoxの設定にてdefaultマシンのメモリを増やします。
※ちなみにクラウドAWS EC2の無料で使えるt2.microはメモリが1GByteとなっているので動作出来そうもありません。

qiita.com
defaultの電源オフの状態で設定ボタンをクリックする
f:id:Yaju3D:20160514135543p:plain
1024MBから4096MBにメモリを変更 f:id:Yaju3D:20160514135556p:plain

docker runの"-m"オプションを付けてメモリ制限値を指定します(※割り当てではない)。単位には b,k,m,g があります。

$ docker run -m 4g -p 8888:8888 -p 6006:6006 b.gcr.io/tensorflow/tensorflow

dockerコンテナが破棄されると初期化した状態になるため、再度scikit-imageのインストールと学習済みモデルをセットしてください。

Jupyter NotebookのTerminalにて「free」コマンドを入力するとメモリサイズが表示されます。

# free                                                                                                                                                        
             total       used       free     shared    buffers     cached                                                                                     
Mem:       4045896    1188836    2857060     167164      40364     953316                                                                                     
-/+ buffers/cache:     195156    3850740                                                                                                                      
Swap:      1939036          0    1939036   

再実行

先ずはサンプルのshark.jpgをやってみました。変換は15秒程度です。
f:id:Yaju3D:20160105021604j:plain f:id:Yaju3D:20160514140945j:plain

鉛筆画を試す

Twitterユーザーの古谷振一さん(@shtt4881)の鉛筆画が白黒写真のようにしか見えないと話題になっておりました。
参照:きれいな写真だなー……って絵だとぉ!? 鉛筆で描かれた芸能人たちが目を疑う精巧さと美しさ
むむ、白黒画像なら自動彩色してみようと試してみました(サイズ 224x224 2値画像に変換してから試す)。ちょっと微妙ですかね。 連続してやるとメモリ不足になるので、毎回Shutodownしてメモリを解消しました。
f:id:Yaju3D:20160407003537p:plain

f:id:Yaju3D:20160514160825j:plain f:id:Yaju3D:20160514160838j:plain
f:id:Yaju3D:20160514160854j:plain f:id:Yaju3D:20160514160914j:plain
f:id:Yaju3D:20160514160931j:plain f:id:Yaju3D:20160514160947j:plain
f:id:Yaju3D:20160514161005j:plain f:id:Yaju3D:20160514161015j:plain

坂本龍馬を試す

顔写真だけだとつまらないので、坂本龍馬で検索した画像を試してみました。背景の草や板に色が付くようになっています。
f:id:Yaju3D:20160514162118j:plain f:id:Yaju3D:20160514162106j:plain

動画の変換

下記サイトにて動画のカラー化を行っています。
前後にffmpegでの処理を行って、Automatic Colorizationをフォルダ内の画像に対してループしているとのこと。 www.shun.bz

カラー化した画像ファイルをホストへコピー

docker cpコマンドでホストへファイルをコピーすることが出来ます。

$ docker ps
#コンテナ名(NAME)を取得 例 cranky_murdock

$ docker cp cranky_murdock:/notebooks/shark-color.jpg /c/Users/(ユーザー名)