YOLO学習のためのファイル操作もろもろ

複数のファイルに連番をつける

Windowsの場合にはコマンドプロンプト(あるいはPower Shell)を使えばできる。
新たに勉強するのが面倒くさいのでRで行う。
(例としてPASという名前がついたtifファイルに連番をつける)

mypath <- getwd()
setwd(choose.dir())
files <- list.files()
PAS <- grep("PAS",files)
files <- files[PAS]

sink("rename.bat")
for (i in 1:length(files))
{
	cat("rename")
	cat(" ")
	cat(files[i])
	cat(" ")
	cat(paste("PAS",sprintf("%05d",i),".tif",sep=""))
	cat("\n")
}
sink()

shell.exec("rename.bat")
setwd(mypath)
#file.remove("rename.bat")

file.removeが早めに実行されてしまうとうまくいかない。

連番をつけたのちに何番かのファイルが欠損している場合、そのファイル名を知る

(例としてPAS00162.txtまで存在する場合)

for(i in 1:162)
{
	file <- paste("PAS",sprintf("%05d",i),".txt",sep="")
	if(!is.element(file,files)) print(i)
}

フォルダ内のjpgファイルのフルパスをテキストに書き出す

setwd("C:/Users/yuki/darknet/build/darknet/x64/data/obj/PAS/")

files <- list.files()
PAS <- grep("jpg",files)
files <- files[PAS]

sink("data.txt")
for(i in 1:length(files))
{
	cat(paste("C:/Users/yuki/darknet/build/darknet/x64/data/obj/PAS/",files[i],sep=""))
	cat("\n")
}
sink()

Bash on Ubuntu on Windowsでのファイル操作(ImageMagick使用)

  • tif → jpg
  • 画像縮小
mogrify -format jpg *.tif
mogrify -resize 600x *.jpg

pythonでの画像回転

import glob
import os
from PIL import Image

files = glob.glob('*.jpg')

for f in files:
    (dirname,filename)=os.path.split(f)

    file_plus = "./new/5+" + filename
    file_minus = "./new/5-" + filename
    img = Image.open(filename)
    img_plus = img.rotate(5)
    img_minus = img.rotate(-5)
    img_plus.save(file_plus)
    img_minus.save(file_minus)

Python素人がWindowsでmxnet-ssdを使うまでの長い長い道のり

DarknetのYOLOを試してみたらどうしてもSSDも試したくなった
そこで真剣にPythonに取り組もうと決めた
今後はRとPythonの両方を使っていく

環境

Pythonのインストール

pip install numpy-1.13.1+mkl-cp35-cp35m-win_amd64.whl
pip install scipy‑0.19.1‑cp35‑cp35m‑win_amd64.whl
  • matplotlibもインストール
pip install matplotlib

mxnetのインストール

下記を参考にさせて頂いた
yohira3.hatenablog.com
qiita.com

openCVをインストール

  • openCV3.3を選択してダウンロード
  • 解凍してパスを通す(C直下の場合には以下のパス)
C:\opencv\build\x64\vc14\bin
pip install opencv_python-3.3.0+contrib-cp35-cp35m-win_amd64.whl

mxnet-ssdをダウンロード

  • こちらから「Download ZIP」でごっそりダウンロードして解凍

github.com

  • 同じサイトの下の方から「ssd_resnet50_0712.zip」をダウンロード
  • 解凍してmodelフォルダに中身のみコピー(jsonファイルとparamsファイル)

いよいよ実行

python demo.py --cpu --images ./data/demo/000022.jpg

結果

このような図ができる
f:id:touch-sp:20170816171825p:plain

Rから実行

Rからバッチファイルを吐き出して、実行する。

setwd("C:/mxnet-ssd")
bat <- "python demo.py --cpu --images"
myfile <- file.choose()
bat_code <- paste(bat, myfile, sep = " ")
cat(bat_code, file = "ssd_exec.bat")
shell.exec("ssd_exec.bat")

WindowsでDarknetのYOLO-v2を試してみる

Deep learningの世界ではLinux+Pythonが主流。
自分のようにWindows+Rでやっているのはおそらくかなりの少数派。
物体検出をmxnet-ssdでやろうと思ったが今のところPythonを使わないといけない。
そこでDarknetのYOLOに興味をもった。

参考にさせて頂いたサイト

tadaoyamaoka.hatenablog.com

環境

手順

github.com
まずはサイト内のDownload Zipボタンからファイルをダウンロード。
こちらのサイトからVisual Studio 2015 Community(英語)のインストーラーもダウンロードできる。
Microsoft公式サイトからVisual Studio 2015をインストールしようとすると登録が必要)
OpenCV2.4.13をダウンロードして展開。
その後は上記の参考にさせて頂いたサイト通りにやれば問題なし。

Rから実行

まずはyolo.weightsをダウンロードしてくる。
Rからバッチファイルを吐き出して、実行する。

setwd("D:/Download/darknet-master/darknet-master/build/darknet/x64")
bat <- "darknet detector test ./data/coco.data yolo.cfg yolo.weights"
myfile <- file.choose()
bat_code <- paste(bat, myfile, sep = " ")
cat(bat_code, file = "yolo_exec.bat")
shell.exec("yolo_exec.bat")

RでMXNet(9)

vgg16モデルを使ったfinetune
Kaggleの「Dogs vs. Cats」をやってみる

学習データ、テストデータの準備

  • 学習データは犬の写真2000枚、猫の写真2000枚
  • テストデータは犬の写真1250枚、猫の写真1250枚
library(EBImage)

#jpeg画像を配列に変換
x_train <- array(0, c(224, 224, 3, 4000))

path <- "G:/cat/"
setwd(path)
files_cat <- list.files()

for (i in 1:2000) {
    img <- readImage(files_cat[i])
    resize <- resize(img, w = 224, h = 224)
    x_train[,,, i] <- resize@.Data
}

path <- "G:/dog"
setwd(path)
files_dog <- list.files()

for (i in 1:2000) {
    img <- readImage(files_dog[i])
    resize <- resize(img, w = 224, h = 224)
    x_train[,,, 2000 + i] <- resize@.Data
}

x_train <- x_train * 255

#入力は「RGB」(Kerasなどでは「BGR」である)
x_train[,, 1,] <- x_train[,, 1,] - 123.68
x_train[,, 2,] <- x_train[,, 2,] - 116.779
x_train[,, 3,] <- x_train[,, 3,] - 103.939


#答え(Cat:0,Dog:1)
t_train <- c(rep(0, 2000), rep(1, 2000))
library(EBImage)

#jpeg画像を配列に変換
x_test <- array(0, c(224, 224, 3, 2500))

path <- "G:/cat_test/"
setwd(path)
files_cat <- list.files()

for (i in 1:1250) {
    img <- readImage(files_cat[i])
    resize <- resize(img, w = 224, h = 224)
    x_test[,,, i] <- resize@.Data
}

path <- "G:/dog_test"
setwd(path)
files_dog <- list.files()

for (i in 1:1250) {
    img <- readImage(files_dog[i])
    resize <- resize(img, w = 224, h = 224)
    x_test[,,, 1250 + i] <- resize@.Data
}

x_test <- x_test * 255

#入力は「RGB」(Kerasなどでは「BGR」である)
x_test[,, 1,] <- x_test[,, 1,] - 123.68
x_test[,, 2,] <- x_test[,, 2,] - 116.779
x_test[,, 3,] <- x_test[,, 3,] - 103.939


#答え(Cat:0,Dog:1)
t_test <- c(rep(0, 1250), rep(1, 1250))

畳み込み層のみ計算

  • 今回は畳み込み層を固定して、全結合層のみ変更する
vgg16 <- mx.model.load("vgg16", 0)

all_layers <- vgg16$symbol$get.internals()
pool5 <- all_layers[[match("pool5_output", all_layers$outputs)]]

new.params <- vgg16$arg.params

new.params$fc6_weight <- NULL
new.params$fc6_bias <- NULL

new.params$fc7_weight <- NULL
new.params$fc7_bias <- NULL

new.params$fc8_weight <- NULL
new.params$fc8_bias <- NULL

new.model <- list(symbol = pool5, arg.params = new.params, aux.params = list())
class(new.model) <- "MXFeedForwardModel"

pred <- predict(new.model, x_train, ctx = mx.gpu())

新規に学習

rand <- sample(4000, 4000)
x_train <- pred[,,, rand]
t_train <- t_train[rand]

rm(rand)

mydata <- mx.symbol.Variable("data")

flat <- mx.symbol.flatten(data = mydata)

fc1 <- mx.symbol.FullyConnected(data = flat, name="new_fc1",num_hidden = 200)
act1 <- mx.symbol.Activation(data = fc1, act_type = "relu")

fc2 <- mx.symbol.FullyConnected(data = act1, name="new_fc2",num_hidden = 200)
act2 <- mx.symbol.Activation(data = fc2, act_type = "relu")

fc3 <- mx.symbol.FullyConnected(data = act2, name="new_fc3",num_hidden = 2)

softmax <- mx.symbol.SoftmaxOutput(data = fc3)

mx.set.seed(1)

model <- mx.model.FeedForward.create(
    softmax, X = x_train,
    y = t_train,
    ctx = mx.cpu(),
    num.round = 5,
    array.batch.size = 10,
    learning.rate = 0.001, momentum = 0.9,
    eval.metric = mx.metric.accuracy,
    initializer = mx.init.normal(0.002),
    array.layout = "auto")

ニューモデルの作成

vgg16 <- mx.model.load("vgg16", 0)

all_layers <- vgg16$symbol$get.internals()
pool5 <- all_layers[[match("pool5_output", all_layers$outputs)]]

fc6 <- mx.symbol.FullyConnected(data = pool5, name = "fc6", num_hidden = 200)
act6 <- mx.symbol.Activation(data = fc6, act_type = "relu")

fc7 <- mx.symbol.FullyConnected(data = act6, name = "fc7", num_hidden = 200)
act7 <- mx.symbol.Activation(data = fc7, act_type = "relu")

fc8 <- mx.symbol.FullyConnected(data = act7, name = "fc8", num_hidden = 2)

softmax <- mx.symbol.SoftmaxOutput(data = fc8)

new.params <- vgg16$arg.params

new.params$fc6_weight <- model$arg.params$new_fc1_weight
new.params$fc6_bias <- model$arg.params$new_fc1_bias

new.params$fc7_weight <- model$arg.params$new_fc2_weight
new.params$fc7_bias <- model$arg.params$new_fc2_bias

new.params$fc8_weight <- model$arg.params$new_fc3_weight
new.params$fc8_bias <- model$arg.params$new_fc3_bias

new.model <- list(symbol = softmax, arg.params = new.params, aux.params = list())
class(new.model) <- "MXFeedForwardModel"

テストデータを用いた評価

pred <- apply(predict(new.model, x_test, ctx = mx.gpu()), 2, which.max) - 1
sum(pred == t_test) / 2500

結果

[1] 0.9852

WindowsのRからGPU版MXNetを使う

環境

手順

  • Visual C++ 2015 Build Toolsをインストー
    • CUDA Toolkit 8.0をインストールするためにはVisual Studio 2015が必要と書かれているが実はこれだけインストールしていれば問題なし。
  • CUDA Toolkit 8.0をインストー
  • cuDNN 5.1をダウンロード
    • cuDNN 6.0というのもあるがこちらは試していないのでうまくいくかどうかは不明。
    • ダウンロード後に解凍するとcudnn-8.0-windows10-x64-v5.1\cudaの中に「bin」「include」「lib」フォルダが存在する。
    • C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0\内に、cudnn-8.0-windows10-x64-v5.1\cuda内の「bin」「include」「lib」を上書きする。
  • Rから以下を実行
cran <- getOption("repos")
cran["dmlc"] <- "https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/GPU"
options(repos = cran)
install.packages("mxnet")

2017年7月17日現在、上記で問題なさそう。

RでMXNet(8)

速報

Githubをなんとなくのぞいてみたら、

400 mx.model.FeedForward.create <- 
401 function(symbol, X, y=NULL, ctx=NULL, begin.round=1, 
402          num.round=10, optimizer="sgd", 
403          initializer=mx.init.uniform(0.01), 
404          eval.data=NULL, eval.metric=NULL, 
405          epoch.end.callback=NULL, batch.end.callback=NULL, 
406          array.batch.size=128, array.layout="auto", 
407          kvstore = "local", verbose = TRUE, 
408          arg.params = NULL, aux.params = NULL, fixed.param = NULL, 
409          ...) { 

なんと、mx.model.FeedForward.createのパラメータにfixed.paramが追加された。
きっとこれはfine-tuneをするためのものに違いない。
Python使いにはModule APIというのがあるがRからは使えなかった。
Rを使うことに限界を感じ始めていたところにこの発見。やっぱりRで頑張ろう!!

RでMXNet(7)

Windows10 64bit
Microsoft R Open 3.4.0

ネットワークモデルを変更する方法

  • Fine-tuneをするにあたって大事
  • いつの日かGPU搭載パソコンが手に入ることを夢見て簡単なモデルで練習(泣)
  • 数年前に手に入れたノートパソコン(Intel第3世代 Ivy Bridge搭載)で頑張ってます(笑)

f:id:touch-sp:20170701004222p:plain

  • 「model」という名前のモデルであり訓練済みのパラメータを持っているものとする
  • relu1以降を変更
#layerの書き換え
all_layers <- model$symbol$get.internals()
relu1 <- all_layers[[match("relu1_output",all_layers$outputs)]]
fc2 <- mx.symbol.FullyConnected(data=relu1,num_hidden=100,name="fc2")
fc3 <- mx.symbol.FullyConnected(data=fc2,num_hidden=10,name="fc3")
softmax <- mx.symbol.SoftmaxOutput(fc3, name = "sm")
#パラメータの書き換え
new.params <- model$arg.params
new.params$fc2_weight <- mx.rnorm(c(100,100),0,0.01)
new.params$fc2_bias <- mx.nd.zeros(100)
new.params$fc3_weight <- mx.rnorm(c(100,10),0,0.01)
new.params$fc3_bias <- mx.nd.zeros(10)
#モデルの作成
#そのまま訓練を始めるならmx.model.FeedForward.createを使っても良い
new.model <- list(symbol=softmax,arg.params=new.params,aux.params=list())
class(new.model) <- "MXFeedForwardModel"
#モデルの図示
graph.viz(new.model$symbol,direction="LR")

f:id:touch-sp:20170701011306p:plain