2018年11月02日

Google ColabでDeep Learningのテスト その3

よく見ると記事数が500件突破していますね。よく続いているものです。今回は自分用のメモです。自前のデータセットを使う場合の方法が良くわからなかったので、適当に調べてやってみました。何か間違っている気がするので、ちゃんとしたやり方がわかるといいのですが。

まず、Google Driveの接続です。[1]の方法を1つのセルにまとめただけです。2回リンクのクリックとコードの代入が必要です。
    
    !pip install -U -q PyDrive
    !apt-get install -y -qq software-properties-common module-init-tools
    !add-apt-repository -y ppa:alessandro-strada/ppa 2>&1 > /dev/null
    !apt-get update -qq 2>&1 > /dev/null
    !apt-get -y install -qq google-drive-ocamlfuse fuse
    from pydrive.auth import GoogleAuth
    from pydrive.drive import GoogleDrive
    from google.colab import auth
    from oauth2client.client import GoogleCredentials
    from google.colab import auth
    auth.authenticate_user()
    from oauth2client.client import GoogleCredentials
    creds = GoogleCredentials.get_application_default()
    import getpass
    !google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret} < /dev/null 2>&1 | grep URL
    vcode = getpass.getpass()
    !echo {vcode} | google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret}
    !mkdir -p drive
    !google-drive-ocamlfuse drive
    
続いて、画像読込用にPILなどをimportします。imtoolsは実践コンピュータビジョンという本にあったimtools.py[2]というファイルを、Google Driveにdrive/path/to/libsというディレクトリを作ってそこに置きました。get_imlistという関数しか使っていなかったと思いますが…。
    
    import matplotlib.pyplot as plt
    from matplotlib.image import imread
    import tensorflow as tf
    import numpy as np
    from PIL import Image
    import os
    from pylab import *
    import sys
    sys.path.append('drive/path/to/libs')
    from imtools import *
    
続いて画像の読込みです。drive/image/inputというディレクトリを作って、そこに画像を置きました。このために月額380円プランに入って200GBに容量増やしました…。空の行列を作る→画像を読み込んで変換→appendで追加という処理を画像枚数分繰り返しています。この辺もっとスマートにできそうな気がするんですが、やり方がわからなかったのでC言語っぽいベタ処理です。また、毎回画像を読み込んで変換は時間がかかるので、numpyの行列に変換して保存しました。savez_compressedを使いましたが、圧縮しない方が読み書きの時間は早かったかなと思っています。
    
    folder = "drive/image/input"
    filelist = get_imlist(folder, '.png')
    imnbr = len(filelist) # 画像数を得る

    # 6000枚の画像を1000枚ずつ6個のファイルに分割して保存
    for div in range(0,6):
        # 空の行列を作成
        immatrix = np.empty((0, 512,512), np.float32)
        # 保存するファイル名
        matname = "drive/image/input/input512_%02d.npz" % div
        # 画像の開始番号
        startNo = 1000*div
        # 1000枚ずつ保存
        for num in range(startNo, startNo+1000):
            # 画像のファイル名はsrc00000.pngなど
            filename = "drive/image/input/src%05d.png" % num
            print(num, ", ", filename)
            # PILで画像を開いてfloat型に変換
            samp = array(Image.open(filename), dtype='f')
            # R(B?)だけ取り出し
            samp = samp[:,:,0]
            # リサイズするためにImageに戻す
            pilImg = Image.fromarray(np.float32(samp))
            gray = pilImg.resize((512,512), Image.BICUBIC)
            # arrayに戻す
            graymat = np.asarray(gray)
            # appendで追加
            immatrix = np.append(immatrix, np.array([graymat]), axis=0)

        print("immatrix.shape=", immatrix.shape)
        # npzファイルとして保存
        np.savez_compressed(matname, immatrix)
    
使うときはloadで開きます。savez_compressedは複数の行列をまとめて保存できるので、取り出す場合はキーを指定する必要があります。キーを指定していない場合、デフォルトで'arr_0'になるみたいです。
    
    # 入力画像の読込み
    src_mat = np.load('drive/image/input/input512_03.npz')
    src_mat = src_mat['arr_0']
    print('src_mat.shape=', src_mat.shape)
    
U-Netもやってみたのですが、誤差が減らないので検討中です。

[1] Google Colaboratory内で画像やCSVファイルにアクセスするのが一苦労だった話
[2] Programming Computer Vision with Python



web拍手 by FC2
posted by シンドラー at 20:38 | Comment(0) | Machine Learning | このブログの読者になる | 更新情報をチェックする

2018年10月30日

Google ColabでDeep Learningのテスト その2

今日は画風変換を試してみました。[1]のサイトのコードをほぼそのまま使用させていただきました。Google Colabで画像ファイルを扱う場合、Google Driveにデータを置くと便利だと思いますので、[2]を参考にGoogle Driveへのアクセスの追加と、画像のパスだけ変更しました。

実行結果

スタイル画像
style_lic.jpg

グレースケール画像を入力画像にした場合
result_src.png

白飛びしているしうまくいっていないですね。

前回の出力画像を入力画像にした場合
result_test.png

それっぽくはなっていますが、顔の領域にも線が入って微妙ですね。パラメータを色々調整したり、参考サイトのリンクに改良法が色々あるので、それを試せばもう少しよくなるかもしれません。

[1] https://qiita.com/isboj/items/4e25f0bd0a2577d7b857
[2] https://qiita.com/yoshizaki_kkgk/items/bf01842d1a80c0f9e56c
web拍手 by FC2
posted by シンドラー at 21:58 | Comment(0) | Machine Learning | このブログの読者になる | 更新情報をチェックする

Google ColabでDeep Learningのテスト

AIが流行っているような、そろそろ幻滅期のような感じですが、Google Colab[1]が楽そうだったのと、そういえば昔LIC[2]を実装していたので、Deep LearningでLICっぽいことができるか試してみることにしました。

まずは教師画像の生成ということで、自前のコンバータにLICを実装しました。FBOで必要な情報をテクスチャに保存して、画像処理でやっているので1fpsぐらいしか出ていません。

実行結果

lic_test_002.png

あぴみくさんと[3]のモーションとMMDBridgeを使用させていただき、6055フレーム分の画像を出力しました。入力画像をグレースケール画像、教師画像をLIC計算後の画像で学習させてみます。

ネットワーク構成

今回はまずはテストということで、畳み込み層オンリーという簡単なネットワークにしてみました。プーリング層すら入れてないです。
  input_img = Input(shape=(512, 512, 1))
  x = Conv2D(16, (9, 9), padding='same')(input_img)
  x = Conv2D(16, (9, 9), padding='same')(x)
  x = BatchNormalization()(x)
  x = Activation('relu')(x)
  x = Conv2D(64, (9, 9), padding='same')(x)
  x = Conv2D(64, (9, 9), padding='same')(x)
  x = BatchNormalization()(x)
  x = Activation('relu')(x)
  x = Conv2D(64, (9, 9), padding='same')(x)
  x = Conv2D(64, (9, 9), padding='same')(x)
  x = BatchNormalization()(x)
  x = Activation('relu')(x)
  x = Conv2D(16, (9, 9), padding='same')(x)
  x = Conv2D(16, (9, 9), padding='same')(x)
  x = BatchNormalization()(x)
  x = Activation('relu')(x)
  x = Conv2D(3, (9, 9), padding='same')(x)
  x = Activation('relu')(x)
損失関数はMSEを使いました。平均なので結果がぼけてしまう気がしますね。
  model = Model(input_img, x)
  tpu_model = tf.contrib.tpu.keras_to_tpu_model(
    model,
      strategy=tf.contrib.tpu.TPUDistributionStrategy(
        tf.contrib.cluster_resolver.TPUClusterResolver(
         tpu='grpc://' + os.environ['COLAB_TPU_ADDR'])
    )
  )
  tpu_model.compile(
    optimizer=tf.keras.optimizers.Adam(lr=0.05),
     loss=tf.keras.losses.MSE,
    metrics=['mse']
  )
学習に800枚、検証に200枚使って、エポック数は100回ぐらいで、MSEが160ぐらいから下がらなくなりました。平均40の誤差ってかなり大きいですね。

実行結果

入力画像

出力画像

教師画像

エッジはしっかり出ているみたいですが、中の線がつぶれている感じですね。画風変換とかU-Netとか使った方がうまくいきそうな気がするので、そちらも試してみたいですね。

[1] https://colab.research.google.com/
[2] http://sssiii.seesaa.net/article/393573439.html
[3] https://www.nicovideo.jp/watch/sm23692832


web拍手 by FC2
posted by シンドラー at 00:17 | Comment(0) | Machine Learning | このブログの読者になる | 更新情報をチェックする

2018年10月15日

VRMのテスト

Twitterを見ていたらOpen Asset Import Library[1]でVRM読込対応をされた方がいらっしゃった[2]ので、UE4のためみたいですがC++用として使わせていただきました。Assimpっていつの間にかglTFにも対応していたんですね。

AssimpでVRM読込みで詰まったのは、テクスチャ情報の取り出しでした。VRMは基本的に1つのファイルにまとまっているので、画像情報もVRMの中に埋め込まれています。Assimpでテクスチャ情報を見ると、mWidthがバイト数?でmHeightに0が入っていて、画像のサイズが取得できませんでした。説明を見るとpngやjpgなど圧縮されたデータの場合はこういう取り扱いになるみたいです。対応として、stb[3]を使うと展開やサイズの取得ができました[4]。
  unsigned char *image_data = nullptr;

  if (texture->mHeight == 0)
  {
    image_data = stbi_load_from_memory(
      reinterpret_cast<unsigned char*>(texture->pcData),
      texture->mWidth, &width, &height, &components_per_pixel, 0);
  }
実行結果

vrm_test_001.png

VRoid[5]のデフォルト設定を表示してみました。白髪なのはマテリアルデータなどを取得・反映していないからみたいです。

[1] http://www.assimp.org/
[2] https://github.com/ruyo/assimp
[3] https://github.com/nothings/stb
[4] https://github.com/assimp/assimp/issues/408
[5] https://vroid.pixiv.net/
web拍手 by FC2
posted by シンドラー at 01:44 | Comment(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする

2018年09月30日

Movidiusのテスト

油断すると月一更新が止まりそうになりますね。今回は購入してそのままにしていたMovidiusのテストです。IntelR Movidius™ Neural Compute Stick[1]は、Deep Learningの計算を加速するためのUSBスティックです。Raspberry Pi 3に刺すとSSD(Single Shot Multibox Detector)などがそれなりの速度で動くようになるみたいです。

今回はRaspberry Pi 3+Raspberry Pi用カメラの環境でインストール・実行までテストしてみました。変に色々入っていると失敗するので、OSをクリーンインストールしてから試した方が早いと思います。OSはRaspbianを入れました。

基本的には[2]のサイトを参考にさせていただきました。違う点としては、何となくNCSDK 2.05の方でmakeしました。githubもありますが、なぜか一時停止しているみたいですね[3]。

make examplesで例題もインストールされますが、ncappzoo[4]にもたくさんサンプルはあります。今回2.05をインストールしましたので、githubからcloneするときはバージョンに注意する必要があります。
  git clone -b ncsdk2 https://github.com/movidius/ncappzoo.git
後は[2]のサイトで参考にしている[5]のコードは、version 1.12用のようでしたので、2.05用に書き換えました。書き換え方法は元のサンプルと比較するのが簡単ですが、詳しい説明が[6]にあります。一番の違いはFIFO queuesというものが増えた?点みたいです。

変更点
  mvnc.EnumerateDevices() ⇒ mvnc.enumerate_devices()
  device.OpenDevice() ⇒ device.open()

  graphfile ⇒ graphFileBuff
  graph = device.AllocateGraph(graphfile) ⇒ graph = mvnc.Graph('graph')
    ⇒ fifoIn, fifoOut = graph.allocate_with_fifos(device, graphFileBuff)
  graph.LoadTensor(img.astype(numpy.float16), 'user object')
    ⇒ graph.queue_inference_with_fifo_elem(fifoIn, fifoOut, img, 'user object')
  output, userobj = graph.GetResult() ⇒ output, userobj = fifoOut.read_elem()

  graph.DeallocateGraph()
  device.CloseDevice()
    ↓
  fifoIn.destroy()
  fifoOut.destroy()
  graph.destroy()
  device.close()
使用した場合と使用しない場合とでは全然違いますね。OpenVINO[7]というものもあるみたいなので、こちらも少し試してみたいですね。

[1] https://software.intel.com/en-us/neural-compute-stick
[2] https://karaage.hatenadiary.jp/entry/2018/05/23/073000
[3] https://github.com/movidius/ncsdk
[4] https://github.com/movidius/ncappzoo
[5] https://gist.github.com/PonDad/bc185bdf81735dfd018bda6ce0b37fea
[6] https://movidius.github.io/ncsdk/ncapi/python_api_migration.html
[7] https://software.intel.com/en-us/openvino-toolkit

web拍手 by FC2
posted by シンドラー at 23:38 | Comment(0) | Machine Learning | このブログの読者になる | 更新情報をチェックする

2018年08月21日

Schemeの勉強 その2

プログラミング言語SCHEME本はまだちょっと難しい気がしたので、[1]のRacket本を購入してみました。chapter2までで数あてゲームの実装です。

#lang racket

(define lower 1)
(define upper 100)

(define (guess)
(quotient (+ lower upper) 2))

(define (smaller)
(set! upper (max lower (sub1 (guess))))
(guess))

(define (bigger)
(set! lower (min upper (add1 (guess))))
(guess))

(define (start n m)
(set! lower (min n m))
(set! upper (max n m))
(guess))
基本defineとset!を使って定義しています。add1, sub1が1足す、1引くで、quotientが割り算で現在の最小値と最大値を足して2で割っているようです。

実行結果

自分が考えた数値より小さければsmaller関数、大きければbigger関数を呼び出します。例えば、1〜100の間で56を思い浮かべた場合は下記のようになります。

> (start 1 100)
50
> (bigger)
75
> (smaller)
62
> (smaller)
56

[1] Realm of Racket

web拍手 by FC2
posted by シンドラー at 01:57 | Comment(0) | 関数プログラミング | このブログの読者になる | 更新情報をチェックする

2018年08月15日

Schemeの勉強

夏休みということでプログラミング言語Schemeを勉強してみることにしました[1]。Schemeは関数プログラミング言語のひとつで、多くの対話型プログラミング環境が提供されています。今回はDr.Racket[2]を使って動作確認などをすることにしました。

以下は[1]の第2章の内容のメモです。

define: 変数のバインド。トップレベル定義を行えばどこからでも参照可能
lambda: プロシージャの生成
load: ロード

単純式: 文字列、数値、シンボル、リストといった定数データ・オブジェクト
算術演算、前置記法
  (+ 1/2 1/2)
(- 1.5 1/2) ⇒ 1
(* 3 1/2) ⇒ 1.5
(/ 1.5 3/4) ⇒ 2.0
(* 2 (* 2 (* 2 (* 2 2)))) ⇒ 32
(/ (* 6/7 7/2) (- 4.5 1.5)) ⇒ 1.0
リスト
  (1 2 3 4 5)
("this" "is" "a" "list")
carとcdr: リストを切り離す2つの基本的なプロシージャ
car: リストの最初の要素を返す
cdr: リストの残りの部分を返す
それぞれの引数は空でないリスト
  (car '(a b c)) ⇒ a
(cdr '(a b c)) ⇒ (b c)
(cdr '(a)) ⇒ ()
(car (cdr '(a b c))) ⇒ b
(cdr (cdr '(a b c))) ⇒ (c)
(car '((a b) (c d))) ⇒ (a b)
(cdr '((a b) (c d))) ⇒ ((c d))
quote: プロシージャではないことを明示。シングルクォート(')でも指定可能
  '(/ (* 2 -1) 3)
cons: リストを生成する
2つの引数を与える。
  (cons 'a '()) ⇒ (a)
(cons 'a '(b c)) ⇒ (a b c)
(cons 'a (cons 'b (cons 'c '()))) ⇒ (a b c)
(cons '(a b) '(c d)) ⇒ ((a b) c d)
ちゃんとしたリストでなくてもcons可能。その際はドット対記法を使う
  (cons 'a 'b) ⇒ (a . b)
(cdr '(a . b)) ⇒ b
(const 'a '(b . c)) ⇒ (a b . c)
'(a . (b . (c . ()))) ⇒ (a b c)
list: 常に行儀のよいリストを生成する
  (list 'a 'b 'c) ⇒ (a b c)
(list 'a) ⇒ (a)
(list) ⇒ ()
let: letの本体として参照される式exprの並びに変数varと値valを対にしたリストを含めたもの
  (let ((x 2))
(+ x 3)) ⇒ 5
(let ((y 3))
(+ 2 y)) ⇒ 5
(let ((x 2) (y 3))
(+ x y)) ⇒ 5
バインド:letによって変数に値を保持すること
共通化することができる複数の部分式をまとめて扱いたい場合にも使用される
  (+ (* 4 4) (* 4 4)) ⇒ 32
(let ((a (* 4 4)))
(+ a a)) ⇒ 32
(let ((list1 '(a b c)) (list2 '(d e f)))
(cons (cons (car list1)
(car list2))
(cons (car (cdr list1))
(car (cdr list2))))) ⇒ ((a . d) b . e)
lambda: 引数として渡すことができるプロシージャを生成
もっとも一般的な操作例:
  ((lambda (x) (+ x x)) (* 3 4)) ⇒ 24
プロシージャを値として変数にバインド可能:
  (let ((double (lambda (x) (+ x x))))
(list (double (* 3 4))
(double (/ 99 11))
(double (- 2 7)))) ⇒ (24 18 -10)
defineを使ったトップレベル定義を行えばどこからでも参照可能
  (define double-any
(lambda (f x)
(f x x)))
トップレベル定義はletやlambdaで隠蔽される
  (define xyz '(x y z))
(let ((xyz '(z y x)))
xyz) ⇒ (z y x)
carとcdrを組み合わせたcadrやcdrとcdrを組み合わせたcddrといった省略形が用意されている。defineで定義すると:
  (define cadr
(lambda (x)
(car (cdr x))))
(define cddr
(lambda (x)
(cdr (cdr x))))
if: 条件式(if test consequent alternative)
帰結部consequentは条件testが真であった場合に評価される式
代替部alternativeは条件testが儀であった場合に評価される式
  (define abs
(lambda (n)
(if (< n 0)
(- 0 n)
n)))
述語: 引数に関する質問に対して#tか#fを返す
大半の述語は疑問符(?)で終わっている
  (null? '()) ⇒ #t
(eqv? #f #f) ⇒ #t
オブジェクトの型を調べる型述語
  pair?, symbol?, number?, string?
errorプロシージャ
  (define reciprocal
(lambda (n)
(if (and (number? n) (not (= n 0)))
(/ 1 n)
(error 'reciprocal "improper argument ~s" n))))
cond: 複数の条件と代替式を定義可能
  (define abs
(lambda (n)
(cond
((= n 0) 0)
((< n 0) (- 0 n))
(else n))))
簡単な再帰
  (define length
(lambda (ls)
(if (null? ls)
0
(+ (length (cdr ls)) 1))))
map: 「最初の引数をプロシージャとして扱い、それに対して2番目の引数であるリストの
       各要素を引き渡して適用し、出力のリストにマップしていくプロシージャ」
  (map abs '(1 -2 3 -4 5 -6)) ⇒ (1 2 3 4 5 6)
set!: 代入
カウンタ作成
  (define make-counter
(lambda ()
(let ((next 0))
(lambda ()
(let ((v next))
(set! next (+ next 1))
v)))))
スタック作成
  (define make-stack
(lambda ()
(let ((ls '()))
(lambda (msg . args)
(cond
((eqv? msg 'empty?) (null? ls))
((eqv? msg 'push!)
(set! ls (cons (car args) ls)))
((eqv? msg 'top) (car ls))
((eqv? msg 'pop!)
(set! ls (cdr ls)))
((eqv? msg 'print!) ls)
(else "oops"))))))
参考文献
[1] ケント ディヴィグ著、村上 雅章訳、”プログラミング言語SCHEME”、株式会社ピアソン・エデュケーション、2000
[2] http://racket-lang.org/




web拍手 by FC2
posted by シンドラー at 17:19 | Comment(0) | 関数プログラミング | このブログの読者になる | 更新情報をチェックする

2018年07月31日

pbrtのテスト

いつの間にか7月も終わりですね。それにしても毎日暑いです。今月まだ更新してなかったので無理やり更新します。今回は物理ベースレンダラの一つであるPBRTの動作確認です。

ビルド・インストール方法は、GitHubのページに書いてある通りです。依存関係のライブラリのダウンロードなどもまとめて行いたいので、git cloneで取ってきます。

1. Gitのインストール
2. Git Bashの起動
3. インストールしたいディレクトリに移動
4. pbrt-v3のダウンロード

$ git clone --recursive https://github.com/mmp/pbrt-v3/
$ cd pbrt-v3
$ git submodule update --init --recursive

5. サンプルシーンのダウンロード(8GB程度あるので時間がかかります)
http://pbrt.org/scenes-v3.html

$ cd ..
$ git clone git://git.pbrt.org/pbrt-v3-senes

6. cmake-guiの起動

Configure -> Visual Studio 15 2017 Win64

CMAKE_INSTALL_PREFIX: インストール先に変更
他デフォルト

Configure -> Generate -> Open Project

7. ビルド

ALL_BUILDのビルド
INSTALLをスタートアッププロジェクトに設定してビルド→インストール

以上でCMAKE_INSTALL_PREFIXに指定したディレクトリにpbrtがインストールされます。

実行結果

とりあえずサンプルシーンのpbrt-v3-scenes/simple/teapot-metal.pbrtをレンダリングしてみました。

$ pbrt.exe ../pbrt-v3-scenes/simple/teapot-metal.pbrt

大体10分ぐらいかかりました。

teapot-material.png

次回はobjをpbrtに変換するobj2pbrt.exe辺りを試してみたいと思います。LayerLab[2]とかMitsuba physically based renderer[3]とか色々関連プロジェクトもあるようですので、試すかもしれません。

[1] https://github.com/mmp/pbrt-v3
[2] https://github.com/wjakob/layerlab
[3] http://www.mitsuba-renderer.org/

web拍手 by FC2
posted by シンドラー at 22:26 | Comment(0) | Rendering | このブログの読者になる | 更新情報をチェックする

2018年06月11日

glTFのテスト その2

とりあえず読込みできるようになったので、前から作っているGUIに組み込んでみました。
テクスチャがおかしかった問題ですが、モデルによっては頂点カラーのみで、テクスチャ座標を持たないメッシュがあり、こちらで使っている中間データは頂点数=テクスチャ座標数で考えていたので、テクスチャ座標を持たないメッシュがあるとインデックスがずれてしまっていたのが原因でした。

実行結果

いくつかsketchfabのデータを表示してみましたが、大体は問題なさそうです。今回は[1]のデータを表示させていただきました。

glTF_test_002.png

[1] https://sketchfab.com/models/011dc1e272be4245bfe2f7e72503f6ab#
web拍手 by FC2
posted by シンドラー at 22:19 | Comment(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする

2018年05月31日

glTFのテスト

いつの間にか5月が終わりましたね。何となくglTF[1]対応をしてみようと思いました。
Khronos Group提唱ですので、OpenGLとの親和性が高そうですね。

今回は[2]のライブラリを使用させていただいて、とりあえずファイルを読み込んで.objに変換してみました。
nodeにmatrixやquaternion等の情報が親子関係で定義されていて、そこにmeshが関連付けられています。
meshにはmaterialやaccessorが関連付けられていて、bufferやimagesから各種データを取り出すことができます。
positionはオブジェクト座標ですので、nodeに記述されている位置姿勢を掛けていく行列操作も必要です。

実行結果

sketchfabというサイトではモデルを全てglTFで保存できるようになっているようで、今回は[3]のモデルをテストとして使用させていただきました。行列掛ける順番間違えたり結構苦労して、まだテクスチャ座標がおかしそうですが、とりあえずMeshLabで表示できたので、おおよその読み込みはできたと思います。

glTF_test_001.png

[1] 次世代の3Dデータフォーマット決定版 glTF 2.0 の概要図を日本語訳してみた
[2] Header only C++ tiny glTF 2.0 library
[3] sketchfab - Oculus Rift CV1
web拍手 by FC2
posted by シンドラー at 22:27 | Comment(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする