u-ryo's blog

various information for coding...

Author: U-ryo

Peeking an Encrypted Luks Lvm

| Comments

純粋に知的好奇心から、 とある暗号化diskをmountして中身を見てみたくなりまして。 targetはubuntuで、立ち上がる時にdisk復号化keyを入力して 立ち上がるような代物です。 それをddでcopyして(最後の方50GBくらいは何かI/Oエラーで copyがうまく行きませんでしたがそれはそもそもそうなのか、 直前にちょっと蹴っ躓いてコードに少し足が引っかかったせいなのか、 よくわかりません)、 copyした方に対してmountをかけるといきなりpassword聞かれて、 答えると難なくmount出来たもののそれはgrubとかkernelとか 置かれているboot領域。 root領域本体はsdb5の中。 いますぐ実践! Linux システム管理 / Vol.186 暗号化ファイルシステムを使ってみる ~ LUKS 編を参考に、 sudo apt install cryptsetupして、

1
2
$ sudo cryptsetup luksOpen /dev/sdb5 luks
Enter passphrase for /dev/sdb5: *******

とすると、/dev/mapper/luksが出来ます。 それをmountすればいいようなんですが、

1
2
$ sudo mount /dev/mapper/luks /tmp/luks/
mount: /tmp/luks: unknown filesystem type 'LVM2_member'.

と言われて出来ません。 HDDからのデータサルベージを参考に、

1
2
3
$ sudo vgscan
  Reading volume groups from cache.
  Found volume group "ubuntu-vg" using metadata type lvm2

確かに何かあるようです。 LVMの使い方を参考に、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sudo pvscan
  PV /dev/mapper/luks
  Total: 1 [<232.17 GiB] / in use: 0 [0   ] / in no VG: 1 [<232.17 GiB]
$ sudo pvdisplay -v
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  "/dev/mapper/luks" is a new physical volume of "<232.17 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/mapper/luks
  VG Name
  PV Size               <232.17 GiB
  Allocatable           NO
  PE Size               0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               w34D6Y-8iVC-zIWW-0WHB-ltuf-FADa-sPMT7k
1
2
$ sudo vgchange -ay
  2 logical volume(s) in volume group "ubuntu-vg" now active

これで、/dev/ubuntu-vg/が出来ます。

1
2
3
4
5
6
$ ls -alrt /dev/ubuntu-vg/
total 0
lrwxrwxrwx  1 root root    7  9月 19 04:44 root -> ../dm-1
drwxr-xr-x 22 root root 4760  9月 19 04:44 ..
lrwxrwxrwx  1 root root    7  9月 19 04:44 swap_1 -> ../dm-2
drwxr-xr-x  2 root root   80  9月 19 04:44 .

これをmountすればよいですね。

1
$ sudo mount /dev/ubuntu-vg/root /tmp/luks

unmount / detach

これを外すのに右往左往してしまいました。 sudo vgremove ubuntu-vgとかってやってしまいました。 これは、volume groupを消してしまう行為でした。 やってはいけません。

結局、外す時はこれでいいわけですね。

1
2
3
4
$ sudo umount /tmp/luks
$ sudo vgchange -an ubuntu-vg
  0 logical volume(s) in volume group "ubuntu-vg" now active
$ sudo cryptsetup luksClose luks

これで/dev/ubuntu-vg//dev/mapper/luksもなくなり、 deviceを外せます。

vgremoveしちゃったからもうダメかな、と思ったら、戻せるんですね。 CentOS / RHEL : How to restore/recover a deleted volume group in LVMを参考に、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ sudo vgcfgrestore --list ubuntu-vg

  File:         /etc/lvm/archive/ubuntu-vg_00000-434080001.vg
  Couldn't find device with uuid w34D6Y-8iVC-zIWW-0WHB-ltuf-FADa-sPMT7k.
  VG name:      ubuntu-vg
  Description:  Created *before* executing 'vgremove ubuntu-vg'
  Backup Time:  Tue Sep 18 21:04:48 2018


  File:         /etc/lvm/archive/ubuntu-vg_00001-841595159.vg
  VG name:      ubuntu-vg
  Description:  Created *before* executing 'vgcreate ubuntu-vg /dev/mapper/luks-1144f2c9-43f4-c433-66a7-81aa5e0f703a'
  Backup Time:  Wed Sep 19 04:31:30 2018


  File:         /etc/lvm/backup/ubuntu-vg
  VG name:      ubuntu-vg
  Description:  Created *after* executing 'vgcreate ubuntu-vg /dev/mapper/luks-1144f2c9-43f4-c433-66a7-81aa5e0f703a'
  Backup Time:  Wed Sep 19 04:31:30 2018

このように出て来るので、 身に覚えのあるものを選んで、

1
2
$ sudo vgcfgrestore -f /etc/lvm/archive/ubuntu-vg_00000-434080001.vg ubuntu-vg
  Restored volume group ubuntu-vg

とするとVolume Groupが戻るんですね。すごいー。 助かりました。

あと、cryptsetuplvmが予め入っていると、 encrypted diskをUSBで繋げた時点でkeyを聞かれて、 luksOpenまで裏でやっちゃうんですね。 自分でluksOpenしようとして、

1
2
3
$ sudo cryptsetup luksOpen /dev/sdb5 luks2
Enter passphrase for /dev/sdb5: 
Cannot use device /dev/sdb5 which is in use (already mapped or mounted).

といわれて「?!」とか思ってしまいました。 この時点で/dev/mapper/luks-1144f2c9-43f4-c433-66a7-81aa5e0f703aが出来ています。

Viewing/Recording TV (Hiden No Tare)

| Comments

何を今更ですが、ここ15年、以下のようにTVを見たり録画したりしています。 3000円くらいで買ったUSB Video Capture Box(LiveView:絶版)を使い続けています。 画像と音声は別々だしsizeも320x240と凄く小さいんですけど、 1秒2MBとfile sizeもcompactだし細かい字は読めないものの話の筋は十分わかるので、 いっかなぁと。

1
2
3
4
5
echo 'ffmpeg -s 320x240 -r 12 -vd /dev/video -ad /dev/dsp -y -t 0:15:00 ~/avi/hanbun_aoi_146.avi &> /dev/null' |at 8:00

vlc --color -I dummy v4l:/dev/video:norm=ntsc:size=640x480:adev=/dev/dsp:audio=0:channel=0:fps=12 --sout "#transcode{vcodec=mp4v,acodec=mpga,vb=3000,ab=256,venc=ffmpeg{keyint=80,vt=800000},deinterlace}:std{access=http,mux=asf,url=0.0.0.0:8080}" --ttl 2

echo '(sleep 45;pkill -f ffmpeg) &> /dev/null'|at 7:59

vlcのこんなparameter、もう探し当てられません。 vlcのversionは古い(0.8.2)ので注意です。 上記USB Boxに適合するkernel drvierのため、Debian sarge限定です。 最後のは、朝ドラ始まる前まで安心してTVを見ていられるように、です。

ついでに、いつもsargeをinstallしている手順です。 自分用のメモです。

/etc/rc.local

1
2
3
4
5
6
7
8
9
#!/bin/sh
modprobe tda7313
modprobe saa7111-new
#insmod ~u-ryo/ov511-2.31/tuner.o
sleep 3
#v4lctl setchannel 1
#v4lctl setinput CVBS-0
v4lctl setinput S-Video-0
v4lctl volume 50000

kernel2.6ならtuner.oは出来ないので不要。

INSTALL Sarge

  1. unetbootinでUSB作成可
  2. boot直後、linux26を選択
  3. cdrom mountに失敗するのでmountは手で。mount /dev/disks/scsi/disk0/lun0/part0 /cdromとか何とか
  4. symlink張れないので、自分でrm /cdrom/dists/stable;cp -rp /cdrom/dists/sarge /cdrom/dists/stable
  5. source URLは、deb http://ftp.riken.jp/Linux/debian/debian-archive/debian sarge main contrib non-freeを自分でedit

/etc/apt/sources.list

backportを付加。

1
2
deb http://ftp.riken.jp/Linux/debian/debian-archive/debian sarge main contrib non-free
deb http://archive.debian.org/backports.org/ sarge-backports main contrib non-free
1
2
3
4
5
6
7
8
9
$ sudo apt-get install -t sarge-backports debhelper dh-make build-essential
$ sudo m-a a-i madwifi
$ sudo apt-get install alsa-tools ntp ntpdate ntp-server screen sudo ffmpeg vlc bzip2 wpasupplicant
$ sudo m-a a-i alsa
$ sudo m-a a-i thinkpad
$ sudo /sbin/modprobe thinkpad
$ sudo /sbin/modprobe thinkpadpm
$ sudo /sbin/modprobe rtcmosram
$ sudo /sbin/modprobe smapi

ffmpegsarge-backportsのに上げるとVideo4Linux2(V4L2)を入力に要求するようになるのでダメポ。

alsa

alsaでないと声が割れる。 後から入れても有効にならないので、 sudo /sbin/modprobe -r i810_audio そうすると/dev/audioが無くなるので、sndを入れ直し。 for i in snd_mpu_401 snd_rawmidi snd_seq_device snd_intel8x0 snd_intel8x0m snd_ac97_codec snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd snd_page_alloc;do sudo /sbin/modprobe -r $i;done 再度sndmodprobe sudo /sbin/modprobe snd

for wpa_supplicant

cf. ThinkPad 535X Debian Sarge の 無線LANのまとめ

/etc/default/wpasupplicant

1
2
ENABLED=1
OPTIONS="-w -i ath0 -D madwifi -c /etc/wpa_supplicant.conf -dd"

/etc/wpa_supplicant.conf

1
2
3
4
5
6
7
8
9
10
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
eapol_version=1
ap_scan=1
fast_reauth=1

network={
        ssid="YOUR_SSID"
        psk="YOUR_PreSharedKey"
}
1
2
3
4
5
6
sudo apt-get install -t sarge-backports wpasupplicant
sudo mv /etc/init.d/wpasupplicant.dpkg-bak /etc/init.d/wpasupplicant
sudo mv /etc/default/wpasupplicant.dpkg-bak /etc/default/wpasupplicant
sudo mv /etc/wpa_supplicant.conf.dpkg-bak /etc/wpa_supplicant.conf
sudo ln -s /sbin/wpa_supplicant /usr/sbin/wpa_supplicant
sudo /usr/sbin/update-rc.d wpasupplicant defaults

/etc/network/interfaces

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

auto ath0
iface ath0 inet dhcp
  wpa-driver madwifi
  wpa-conf /etc/wpa_supplicant.conf
  wpa-scan-ssid 1
  wpa-proto RSN
  wpa-pairwise CCMP
  wpa-group CCMP
  wpa-key-mgmt WPA-PSK
  wpa-ssid Disney
  wpa-psk ru011415

wpa-driverwpa-confが無いとダメだった。

for mosh

色々試したがmoshはダメだった。諦めた。

Python Basic Web Server for Applying Keras Model

| Comments

VGG16をfine tuningしたmodelを簡単にapply(predict)するsystemが NotePC程度で動くことを証明したく、 PythonのBaseHTTPServerで1日でちゃちゃっと作りました。

といっても「PythonのBaseHTTPServer」なんて触るの初めてです。 bradmontgomery/dummy-web-server.pyを参考にしました。 なるほど、classを定義して、BaseHTTPRequestHandlerを引数にして、 do_GETdo_POSTを書くわけですね。 routingは自分でやれと。面倒なのでmethodで分けました。 このsystem自体をone fileで済ませたかったので、 GETindex.htmlを返したいと思い、 そのためにはhere documentを書きたいな、 と思ったので、 Pythonのヒアドキュメントを参考に、 あぁ、普通に'''(single quote 3つ)でいいのね、とわかりました。 single quoteでも中で変数展開されるんですね。へー。 PythonでJSONを受けて処理をするを参考に、 POST時のparameter(=request body)の受け取り方を。 HTTP Request HeaderのContent-Lengthintとして記憶し、 self.rfile.read()でそのbyte分読んで、 decode()でstringにすると。 parameterizedされるわけではなく、bodyがまるっと読まれるので、 parameterで分けるのは自分でやれということですね。

あと、base64として来た文字列をdecodeしてImage化するには、 先頭のimage/jpeg;base64,を除去し(replace())て純粋にBase64文字列だけにし、 base64.b64decode(content)したものをio.BytesIO()し、 それをImage.open()すると。

predict()したものは2次元配列になっているので、 0番目のargmax()したものが答えの添字、なのですね。

ともあれ、このpython predict server script 1つと keras model fileの2 filesだけでサクッと動くものを、 githubに置きました。

DeepLearning for Java DL4J

| Comments

会社はケチな(本気でMLやる気はない)のでマシンもGPUもなく、 やむなくGoogle Colaboratory上でkerasでVGG16 with ImageNetをfine tuningしたmodelを、 GPUのないNotePCでpredictしようとしました。 NotePCはDisk/Memory容量が小さいためpythonも本気では入れてないので、 Groovy+DeepLearning4Jで何とかならないかなー、 とあがきました。 単純にGrapeでの指定だけだと失敗するんです。

1
2
3
4
5
6
7
8
9
$ groovy dl4j.groovy
Caught: java.lang.NoClassDefFoundError: org/bytedeco/javacpp/hdf5$Group
java.lang.NoClassDefFoundError: org/bytedeco/javacpp/hdf5$Group
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder.modelHdf5Filename(KerasModelBuilder.java:226)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport.importKerasSequentialModelAndWeights(KerasModelImport.java:194)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport$importKerasSequentialModelAndWeights.call(Unknown Source)
        at dl4j.run(dl4j.groovy:17)
Caused by: java.lang.ClassNotFoundException: org.bytedeco.javacpp.hdf5$Group
        ... 4 more

これは、何も指定しないと~/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-windows-x86_64.jarが落ちてきて、Windows用native libraryで動こうとするからっぽい?んですね。 なので、hdf5-1.10.2-1.4.2-linux-x86_64.jarを落としてきて、-cpで明示的に指定しないとダメでした。

1
2
3
4
5
6
7
8
9
10
$ groovy -cp ~/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-linux-x86_64.jar dl4j.groovy
[main] INFO org.deeplearning4j.nn.modelimport.keras.Hdf5Archive - Unexpected end-of-input: was expecting closing quote for a string value at [Source: {"config": {"name": "model_1", "input_layers": ......, "name; line: 1, column: 20001]
Caught: org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException: Model class name must be Sequential (found Model). For more information, see http://deeplearning4j.org/model-import-keras.
org.deeplearning4j.nn.modelimport.keras.exceptions.InvalidKerasConfigurationException: Model class name must be Sequential (found Model). For more information, see http://deeplearning4j.org/model-import-keras.
        at org.deeplearning4j.nn.modelimport.keras.KerasSequentialModel.<init>(KerasSequentialModel.java:94)
        at org.deeplearning4j.nn.modelimport.keras.KerasSequentialModel.<init>(KerasSequentialModel.java:61)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder.buildSequential(KerasModelBuilder.java:320)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport.importKerasSequentialModelAndWeights(KerasModelImport.java:195)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport$importKerasSequentialModelAndWeights.call(Unknown Source)
        at dl4j.run(dl4j.groovy:18)

VGG16はSequential Modelじゃないからダメでした。 ...ってこれ、importKerasSequentialModelAndWeightsでやってるからですよね。 そりゃそうですか。importKerasModelAndWeightsに変えて試してみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ groovy -cp ~/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-linux-x86_64.jar dl4j.groovy
[main] INFO org.deeplearning4j.nn.modelimport.keras.Hdf5Archive - Unexpected end-of-input: was expecting closing quote for a string value at [Source: {"config": {"name": "model_1", ......, "name; line: 1, column: 20001]
Caught: java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
        at org.deeplearning4j.nn.conf.dropout.Dropout.initializeHelper(Dropout.java:107)
        at org.deeplearning4j.nn.conf.dropout.Dropout.<init>(Dropout.java:100)
        at org.deeplearning4j.nn.conf.dropout.Dropout.<init>(Dropout.java:80)
        at org.deeplearning4j.nn.conf.layers.Layer$Builder.dropOut(Layer.java:257)
        at org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolution2D.<init>(KerasConvolution2D.java:101)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getKerasLayerFromConfig(KerasLayerUtils.java:226)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.prepareLayers(KerasModel.java:220)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:166)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:98)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder.buildModel(KerasModelBuilder.java:305)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport.importKerasModelAndWeights(KerasModelImport.java:144)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport$importKerasModelAndWeights.call(Unknown Source)
        at dl4j.run(dl4j.groovy:18)
Caused by: java.lang.RuntimeException: org.nd4j.linalg.factory.Nd4jBackend$NoAvailableBackendException: Please ensure that you have an nd4j backend on your classpath. Please see: http://nd4j.org/getstarted.html
        at org.nd4j.linalg.factory.Nd4j.initContext(Nd4j.java:5449)
        at org.nd4j.linalg.factory.Nd4j.<clinit>(Nd4j.java:213)
        ... 13 more
Caused by: org.nd4j.linalg.factory.Nd4jBackend$NoAvailableBackendException: Please ensure that you have an nd4j backend on your classpath. Please see: http://nd4j.org/getstarted.html
        at org.nd4j.linalg.factory.Nd4jBackend.load(Nd4jBackend.java:213)
        at org.nd4j.linalg.factory.Nd4j.initContext(Nd4j.java:5446)
        ... 14 more

何でしょう。今度はNd4jのようなので、同じように~/.groovy/grapes/org.nd4j/nd4j-native/jars/nd4j-native-1.0.0-beta2-linux-x86_64.jarを落としてきて入れて明示的に指定して試してみても同じだったので、色々試行錯誤の結果、Grapeで指定するのはnd4j-native-platformではなくnd4j-nativeの方だった、ということで一歩進みました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ groovy -cp ~/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native/jars/nd4j-native-1.0.0-beta2-linux-x86_64.jar dl4j.groovy
[main] INFO org.deeplearning4j.nn.modelimport.keras.Hdf5Archive - Unexpected end-of-input: was expecting closing quote for a string value at [Source: {"config": {"name": "model_1", ......, "name; line: 1, column: 20001]
[main] INFO org.nd4j.linalg.factory.Nd4jBackend - Loaded [CpuBackend] backend
[main] INFO org.nd4j.nativeblas.NativeOpsHolder - Number of threads used for NativeOps: 2
Caught: java.lang.UnsatisfiedLinkError: no jniopenblas_nolapack in java.library.path
java.lang.UnsatisfiedLinkError: no jniopenblas_nolapack in java.library.path
        at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1225)
        at org.bytedeco.javacpp.Loader.load(Loader.java:983)
        at org.bytedeco.javacpp.Loader.load(Loader.java:882)
        at org.bytedeco.javacpp.openblas_nolapack.<clinit>(openblas_nolapack.java:10)
        at org.bytedeco.javacpp.Loader.load(Loader.java:941)
        at org.bytedeco.javacpp.Loader.load(Loader.java:898)
        at org.bytedeco.javacpp.presets.openblas_nolapack.blas_set_num_threads(openblas_nolapack.java:189)
        at org.nd4j.linalg.cpu.nativecpu.blas.CpuBlas.setMaxThreads(CpuBlas.java:136)
        at org.nd4j.nativeblas.Nd4jBlas.<init>(Nd4jBlas.java:52)
        at org.nd4j.linalg.cpu.nativecpu.blas.CpuBlas.<init>(CpuBlas.java:31)
        at org.nd4j.linalg.cpu.nativecpu.CpuNDArrayFactory.createBlas(CpuNDArrayFactory.java:91)
        at org.nd4j.linalg.factory.BaseNDArrayFactory.blas(BaseNDArrayFactory.java:72)
        at org.nd4j.linalg.cpu.nativecpu.ops.NativeOpExecutioner.getEnvironmentInformation(NativeOpExecutioner.java:1236)
        at org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner.printEnvironmentInformation(DefaultOpExecutioner.java:649)
        at org.nd4j.linalg.factory.Nd4j.initWithBackend(Nd4j.java:5575)
        at org.nd4j.linalg.factory.Nd4j.initContext(Nd4j.java:5447)
        at org.nd4j.linalg.factory.Nd4j.<clinit>(Nd4j.java:213)
        at org.deeplearning4j.nn.conf.dropout.Dropout.initializeHelper(Dropout.java:107)
        at org.deeplearning4j.nn.conf.dropout.Dropout.<init>(Dropout.java:100)
        at org.deeplearning4j.nn.conf.dropout.Dropout.<init>(Dropout.java:80)
        at org.deeplearning4j.nn.conf.layers.Layer$Builder.dropOut(Layer.java:257)
        at org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolution2D.<init>(KerasConvolution2D.java:101)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasLayerUtils.getKerasLayerFromConfig(KerasLayerUtils.java:226)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.prepareLayers(KerasModel.java:220)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:166)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:98)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder.buildModel(KerasModelBuilder.java:305)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport.importKerasModelAndWeights(KerasModelImport.java:144)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport$importKerasModelAndWeights.call(Unknown Source)
        at dl4j.run(dl4j.groovy:19)
Caused by: java.lang.UnsatisfiedLinkError: no openblas_nolapack in java.library.path
        at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1225)
        at org.bytedeco.javacpp.Loader.load(Loader.java:968)
        ... 28 more

openblasがない? sudo apt install libopenblas-base libopenblas-devしても変わりません。 うーん。 色々探すと、libopenblas_nolapack.so.0: cannot open shared object file: No such file or directory #6132という記事があり、 「nd4j-backends」から「mkl-dnn」をexcludeしろ、とあります。 えー! nd4j-backendsはpomだけでjarないんですけど。 org.bytedeco.javacpp-presets:mkl-dnnを見てみると、 windowsのjarmkl-dnn-0.15-1.4.2-windows-x86_64.jarが落ちてきていました。 それならっていうんで、linux-x86 64版を持ってきて-cpで指定します。 ついでに、org.bytedeco.javacpp-presets:openblasというのもあって こっちにもwindows-x86 64版のjarだったので、これについてもlinux-x86 64版を 持ってきてClassPathに入れます。 するとどうでしょう、漸く動き出しました。 けれども、ヌルポで落ちます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ groovy -cp ~/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native/jars/nd4j-native-1.0.0-beta2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/mkl-dnn/jars/mkl-dnn-0.15-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/openblas/jars/openblas-0.3.0-1.4.2-linux-x86_64.jar dl4j.groovy
[main] INFO org.deeplearning4j.nn.modelimport.keras.Hdf5Archive - Unexpected end-of-input: was expecting closing quote for a string value at [Source: {"config": {"name": "model_1",......, "name; line: 1, column: 20001]
[main] INFO org.nd4j.linalg.factory.Nd4jBackend - Loaded [CpuBackend] backend
[main] INFO org.nd4j.nativeblas.NativeOpsHolder - Number of threads used for NativeOps: 2
[main] INFO org.nd4j.nativeblas.Nd4jBlas - Number of threads used for BLAS: 2
[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Backend used: [CPU]; OS: [Linux]
[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Cores: [4]; Memory: [4.3GB];
[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Blas vendor: [MKL]
{config={lr=9.999999747378752E-5, decay=0.0, momentum=0.8999999761581421, nesterov=false}, class_name=SGD}
Caught: java.lang.NullPointerException
java.lang.NullPointerException
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasOptimizerUtils.mapOptimizer(KerasOptimizerUtils.java:119)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.importTrainingConfiguration(KerasModel.java:253)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:173)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:98)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder.buildModel(KerasModelBuilder.java:305)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport.importKerasModelAndWeights(KerasModelImport.java:144)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport$importKerasModelAndWeights.call(Unknown Source)
        at dl4j.run(dl4j.groovy:19)

これ、119行目って、KerasOptimizerUtils.javaこの修正の前のこれですね。

1
119: double momentum = (double) optimizerParameters.get("epsilon");

epsilonじゃねーよmomentumだよー今は。 ここは8.17.2018にtry-catchで囲まれて、現在のversionには反映されてないので、 うー、commentしました。 でもまー、keras変わっちゃうと、DL4Jがついていくのも大変なのかもですね。 けどこれで現状、kerasのmodelのimportは、 optimizerにSGDを使ったものについては全滅です。 実に下らない理由(=parameter nameの間違い)で。

あまりにも悔しいので、Java Bytecode Editor: JByteModを使ってbytecodeを書き換えてみました(正確にはCol-E/RecafJBE - Java Bytecode Editorと3つ試してみて、JByteModだけでうまく書き換えられました)。 deeplearning4j-modelimport-1.0.0-beta2.jarをjarごと読み込めて、 org.deeplearning4j.nn.modelimport.keras.utils.KerasOptimizerUtilsに 降りていって、 EditorのDecompilerで見事にsource codeが出て来ます。 こちらで変えたくなりますが、ここはview onlyの模様。 EditorのCodeで見られるbytecodeならいじれるので、 line 119近辺のldc String "epsilon"に当たりをつけ、 それをmomentumに変えて保存すると... うまく行きました!→次のエラーに進みました。orz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[main] INFO org.nd4j.linalg.factory.Nd4jBackend - Loaded [CpuBackend] backend
[main] INFO org.nd4j.nativeblas.NativeOpsHolder - Number of threads used for NativeOps: 2
[main] INFO org.nd4j.nativeblas.Nd4jBlas - Number of threads used for BLAS: 2
[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Backend used: [CPU]; OS: [Linux]
[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Cores: [4]; Memory: [4.3GB];
[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Blas vendor: [MKL]
{config={lr=9.999999747378752E-5, decay=0.0, momentum=0.8999999761581421, nesterov=false}, class_name=SGD}
Caught: org.deeplearning4j.exception.DL4JInvalidConfigException: Invalid configuration for layer (idx=-1, name=block2_conv1, type=ConvolutionLayer) for width dimension:  Invalid input configuration for kernel width. Require 0 < kW <= inWidth + 2*padW; got (kW=3, inWidth=1, padW=0)
Input type = InputTypeConvolutional(h=112,w=1,c=64), kernel = [3, 3], strides = [1, 1], padding = [0, 0], layer size (output channels) = 128, convolution mode = Same
org.deeplearning4j.exception.DL4JInvalidConfigException: Invalid configuration for layer (idx=-1, name=block2_conv1, type=ConvolutionLayer) for width dimension:  Invalid input configuration for kernel width. Require 0 < kW <= inWidth + 2*padW; got (kW=3, inWidth=1, padW=0)
Input type = InputTypeConvolutional(h=112,w=1,c=64), kernel = [3, 3], strides = [1, 1], padding = [0, 0], layer size (output channels) = 128, convolution mode = Same
        at org.deeplearning4j.nn.conf.layers.InputTypeUtil.getOutputTypeCnnLayers(InputTypeUtil.java:349)
        at org.deeplearning4j.nn.conf.layers.ConvolutionLayer.getOutputType(ConvolutionLayer.java:181)
        at org.deeplearning4j.nn.modelimport.keras.layers.convolutional.KerasConvolution2D.getOutputType(KerasConvolution2D.java:150)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.inferOutputTypes(KerasModel.java:306)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:181)
        at org.deeplearning4j.nn.modelimport.keras.KerasModel.<init>(KerasModel.java:98)
        at org.deeplearning4j.nn.modelimport.keras.utils.KerasModelBuilder.buildModel(KerasModelBuilder.java:305)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport.importKerasModelAndWeights(KerasModelImport.java:144)
        at org.deeplearning4j.nn.modelimport.keras.KerasModelImport$importKerasModelAndWeights.call(Unknown Source)
        at tt.run(tt.groovy:19)

Require 0 < kW <= inWidth + 2*padW; got (kW=3, inWidth=1, padW=0)ということからすると、多分keras modelの方のblock2_conv1padWが1でないとダメ? 何をどうすればいいんでしょう?

心が折れそうになりましたが、もう少し頑張ってみます。

まずVGG16のblock2_conv1のpadding(padWって恐らくこれでしょう?)は"same"のようです(VGG16をkerasで実装した)。 実際、途中のlogでは下のように"padding": "same"とあります。

1
{"name": "block2_conv1", "config": {"kernel_regularizer": null, "activation": "relu", "dilation_rate": [1, 1], "name": "block2_conv1", "data_format": "channels_last", "kernel_size": [3, 3], "bias_constraint": null, "filters": 128, "kernel_initializer": {"config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}, "class_name": "VarianceScaling"}, "use_bias": true, "kernel_constraint": null, "activity_regularizer": null, "trainable": false, "padding": "same", ...

色々見ると、VGG16ではpadding=[1,1]みたいです(事前学習済み VGG-16 畳み込みニューラル ネットワーク) (Build VGG16 from scratch : part II) (Reading the VGG Network Paper and Implementing It From Scratch with Keras)。 "same"が0と解釈された?? いやいや、DL4Jのsourceを見ると、"same"はきちんと扱っているようです。 あー、SAMEってこういう意味だったんですね(【Python】 KerasのConv2Dの引数paddingについて)。 今回のExceptionは、具体的には deeplearning4j/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/layers/InputTypeUtil.javaの以下で出ていることがわかりました。

1
2
3
4
5
6
if (kW <= 0 || kW > inWidth + 2 * padW) {
    throw new DL4JInvalidConfigException(getConfigErrorCommonLine(layerIdx, layerName, layerClass, false)
                    + " Invalid input configuration for kernel width. Require 0 < kW <= inWidth + 2*padW; got (kW="
                    + kW + ", inWidth=" + inWidth + ", padW=" + padW + ")\n" + getConfigErrorCommonLastLine(
                                    inputType, kernelSize, stride, padding, outputDepth, convolutionMode));
}

padWって何?

1
2
int padH = (padding == null ? 0 : padding[0]); //May be null for ConvolutionMode.Same
int padW = (padding == null ? 0 : padding[1]);

paddinggetOutputTypeCnnLayersの引数です。 その元はdeeplearning4j/deeplearning4j/deeplearning4j-nn/src/main/java/org/deeplearning4j/nn/conf/layers/ConvolutionLayer.javaの↓から来ていて、

1
2
3
4
5
6
7
8
9
10
@Override
public InputType getOutputType(int layerIndex, InputType inputType) {
    if (inputType == null || inputType.getType() != InputType.Type.CNN) {
        throw new IllegalStateException("Invalid input for Convolution layer (layer name=\"" + getLayerName()
                + "\"): Expected CNN input, got " + inputType);
    }

    return InputTypeUtil.getOutputTypeCnnLayers(inputType, kernelSize, stride, padding, dilation,
            convolutionMode, nOut, layerIndex, getLayerName(), ConvolutionLayer.class);
}

このpaddingはconstructorから来ていて。

1
this.padding = builder.padding;

builderはinner classでそのpaddingは外から来ているか 又はdefaultならnew int[]{0, 0}と。 うーーー。 似ているissueもありましたが、input shapeの明示的指定では解決しなかったので、 もうissue上げました。

試すのは、Groovyだと↓で済むんですけど、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat dl4j.groovy
@Grab('org.deeplearning4j:deeplearning4j-core:1.0.0-beta2')
@Grab('org.deeplearning4j:deeplearning4j-modelimport:1.0.0-beta2')
@Grab('org.nd4j:nd4j-native:1.0.0-beta2')
@Grab('org.slf4j:slf4j-simple')
@Grab('org.bytedeco.javacpp-presets:hdf5:1.10.2-1.4.2')
@Grab('org.bytedeco:javacpp:1.4.2')

import org.deeplearning4j.nn.modelimport.keras.KerasModelImport

// model = KerasModelImport.importKerasModelAndWeights('my_model.hdf5', [224, 224, 3] as int[], false)
model = KerasModelImport.importKerasModelAndWeights('my_model.hdf5')

$ groovy -cp ~/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native/jars/nd4j-native-1.0.0-beta2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/mkl-dnn/jars/mkl-dnn-0.15-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/openblas/jars/openblas-0.3.2-1.4.2-linux-x86_64.jar dl4j.groovy

本家のissueで聞くからには、 Groovyだからダメなんじゃないの? とか言われそうだったので、 Javaにしました。 classpathの指定が大変でした。 不要なjarも入っているかもです。

1
2
3
4
5
6
7
8
9
10
11
$ cat DL4J.java
class DL4J {
    public static void main(String... args) throws Exception {
        org.deeplearning4j.nn.modelimport.keras.KerasModelImport
            .importKerasModelAndWeights("my_model.hdf5",
                                        new int[]{224, 224, 3}, false);
            // .importKerasModelAndWeights("my_model.hdf5"); // failed too
    }
}
$ javac -cp ~/.groovy/grapes/org.deeplearning4j/deeplearning4j-modelimport/jars/deeplearning4j-modelimport-1.0.0-beta2.jar:/usr/share/java/slf4j-simple.jar:/home/u-ryo/.groovy/grapes/org.deeplearning4j/deeplearning4j-nn/jars/deeplearning4j-nn-1.0.0-beta2.jar DL4J.java
$ java -cp ~/.groovy/grapes/org.deeplearning4j/deeplearning4j-modelimport/jars/deeplearning4j-modelimport-1.0.0-beta2.jar:/usr/share/java/slf4j-simple.jar:/home/u-ryo/.groovy/grapes/org.deeplearning4j/deeplearning4j-nn/jars/deeplearning4j-nn-1.0.0-beta2.jar:/usr/share/java/slf4j-api.jar:.:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2.jar:/home/u-ryo/.groovy/grapes/org.bytedeco/javacpp/jars/javacpp-1.4.2.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-jackson/jars/nd4j-jackson-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/jackson/jars/jackson-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-common/jars/nd4j-common-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-api/jars/nd4j-api-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-context/jars/nd4j-context-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-buffer/jars/nd4j-buffer-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native/jars/nd4j-native-1.0.0-beta2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native-platform/jars/nd4j-native-platform-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native/jars/nd4j-native-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.nd4j/nd4j-native-api/jars/nd4j-native-api-1.0.0-beta2.jar:/home/u-ryo/.groovy/grapes/org.apache.commons/commons-math3/jars/commons-math3-3.5.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/openblas/jars/openblas-0.3.0-1.4.2-linux-x86_64.jar:/home/u-ryo/.groovy/grapes/org.bytedeco/javacpp/jars/javacpp-1.4.2.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/hdf5/jars/hdf5-1.10.2-1.4.2.jar:/home/u-ryo/.groovy/grapes/org.bytedeco.javacpp-presets/openblas/jars/openblas-0.3.0-1.4.2.jar DL4J

Battle Against Fool

| Comments

いゃぁ、びっくりしました。 今日会社でいきなり会議に招集されたんですけど、 その内容が、今後AI外観検査案件で使うPCの標準specを決めます、というもの。 そもそも外観検査、出来るかどうか、とかどういう撮像でどういうalgorithmで、 とかじゃなくて、えー、まずはそんなところから入るんだー、と驚きです。 営業とかマネージャーとか、技術全くわかんない(わかろうともしない)人達って、 そういうこと考えてるんですね。 確かに、そういうところなら彼らでも議論が出来る、から?

丁度、頭に来てもアホとは戦うな!をちょっと立ち読みしたので、 もう受け流すことにしました。

「そうですよねー、Nさん目の付け所が違いますねー」

『目の付け所が違う』のは確かでしょう。 真面目に議論しちゃうと、精神衛生上よくない気がしました。 しかしこの本、カスタマーレビューでは結構叩かれてますね。 尤もだと思います。

ちょっぴりアホと戦ってしまいました。 やっぱりまだまだですねーぼくも。

社内用語集

  • 勉強させている → 放置プレイ
  • マネジメント → 「どう? 出来た?」/日程調整
  • PM → Project Messenger
  • 高コミュ力 → イエスマン
  • ワンストップ・トータルコーディネート → 客からの中間搾取(=BPへの丸投げ)
  • 客先常駐・SES → 偽装派遣
  • BP派遣 → 多重派遣