ページ

2015-05-30

waifu2xのAvisynthプラグインを作った

Windowsで動くC++版を書かれた方がいる(waifu2x-converter-cpp)という話を聞いて「Avisynthに乗せられるんじゃね?」ってことで、実際に乗せてみました。これで動画も変換できます。

いろいろ更新がありそうなので、ダウンロードリンクや使い方を書いたページを用意しました。詳しくはこちらを見てください。
http://waifu2x-avisynth.sunnyone.org/


ファイルに書き出さなくていいとか、モデルのローディングを初回しかしないとか、中の入出力部分の処理をちょいちょい変えたりしているので、各フレームの画像をコマンドで変換するより若干より速いかと思います。


現時点では、見ての通りびっくりする速度でした(Core i5-3570S。ページ書いたとき、Haswellのマシンだと勘違いしてましたがIvyでした)。特にがんばってはいないので、最適化する余地はたくさんあると思います。しかし、物理で殴ってでも欲しい人がいるかもしれないので、出してみました。

2015-05-17

「RustからPythonを呼び出す」資料と補足

Rust 1.0 Release記念祝賀LT会 お疲れ様でした。そして1.0.0リリースおめでとうございます。今回は、その祝賀会で「RustからPythonを呼び出す」という話をしたので、その補足エントリです(資料は最下部に配置)。

rust-cpythonの使い方

RustからPythonを呼び出すには、rust-cpython crate が使えます。使い方は、githubに書いてあるとおりですが、以下のような感じで簡単に使えます(恐らく非Windows/x64 or Windows/x86,x64なら:資料参照)(2015/5/27追記:下部追記参照)

$ cargo new newapp
$ cd newapp

(Cargo.tomlを編集)
[dependencies.cpython]
version = "*"

(src/main.rsを作成)
extern crate cpython;

use cpython::{PythonObject, Python};

fn main() {
    let gil_guard = Python::acquire_gil();
    let py = gil_guard.python();
    let sys = py.import("sys").unwrap();
    let version = sys.get("version").unwrap().extract::().unwrap();
    println!("Hello Python {}", version);
}

$ cargo run

作りたかったもの

なぜこのような話になったかというと、DLLを作成することで拡張できるアプリケーションがあるのですが、その拡張する内容自体、LLでちょいちょい変えていきたいので、LLとつなぐブリッジとなるDLLを作りたかった(作りたい)のです。Pythonなのは、アプリ埋め込みがしやすく、統計処理が得意なライブラリを持っているから。あと、coroutineが使いたいので、Python 3.4以降が使いたいです(ここはRustでもまだできていないところですが、python3-sysがあるので、どっか切り替えればなんとかなるんじゃないかと思っているところ)

考えた言語たち

Rustを使いたいからというよりも、Rustが向いているのではと思ったからです。以下、考えた言語たち。

C#

今回はWindowsの世界だとわかりきっているので、私的にはC#で書けると一番楽です。しかし、C#のDLLはmanaged (CLRで動作する) DLLなので、普通のC関数として呼び出すことはできません。一応、その向きのために「Unmanaged Exports」というのがあるようですが、コンパイルできませんでした。多分「Can't create unmanaged dll using C# and Robert Giesecke's Unmanaged Exports tool」という記事にある問題だと思うのですが、試してません。動いても動かすにはCLRがついてくるはずなので、フットプリントが大きくなり、単なるPythonブリッジにはちょっと大きいという点が気になります。

C

いろいろなもののベースになっているはずなので、Cに限った話ではないのですが、PythonのC APIは親切に提供されているので、Cで書くのも悪くないと思います。ないがしろになりがちそうなC拡張のドキュメントがしっかり書かれていて、和訳もあるという親切な環境です。悪くないといえば悪くないのですが、リソース管理系の話だとか、objectiveな操作が書きにくいとか、ヘッダファイルが別で冗長とか、いろいろあるので、他にベターなものがあれば避けたいなと。

D

Win32 DLLs in Dという話も書いてあるし、これは結構ありかなと思っています。pydというPython bindingもあるみたいです。CPython 2.6+とあるので、2系しか考えてない気がしますが、Python 3系いけるかどうか。

ただ、GCがついてくるので、そのへん意識しないといけないですね。

Free Pascal (Object Pascal)

どこかでこれでDLLを書いてる例を見かけて、意外とありなのかなと思ったりしたりしました。Python4DelphiというPythonバインディングもあるようです。今からPascal覚えるのかーというところですね。

Rust

ここでRustを思い出して、よさそうだなと。#![create_type = "dylib"]と#[no_mangle]でDLLは作れそうだし、GCがないのでランタイムのオーバーヘッドも小さそうだし。そしてrust-cpythonを動かしてみたら、動いた ← 昼間ココ というわけです。

Pythonそのもの

呼び出そうと思っているのはPythonそのものなので、DLLがPythonで書けるとベターです。できないと思っていたのですが、Cythonを使うのはどうという話があり、こっちのほうがいいかも? ← 今ココ です。Pythonではないけど、専用のサポートがあるし、読む人もなじみやすそうですね。

とこんなかんじですが、他にもおすすめがあれば教えてください。

資料

ともあれ、資料はこちらになります。



. o O (もうちょっとうまいこと話せたらよかったのだけど、スタートがうまくしゃべれなかったせいでぐだぐだになってしまった...)

[2015/5/27 追記]
資料にあるLinux/x86でビルドできない罠ですが、Linux/x86対応をpull request出したらマージされたので、Linux/x86でもgitのmasterはビルドできるようになりました。Cargo.tomlもgitのほうを向ければビルドできるようになると思います。


2015-05-13

ScreenCaptureWrapper 0.0.2をリリース

動画キャプチャツールScreenCaptureWrapperですが、0.0.2をリリースしました

変更点は主に、範囲選択中にアスペクト比がわかるようにしたことです(ex. 16/9 = 1.77777777)


あと、さすがにHuffyuvは試しにくいと思ったので、デフォルト設定にwebmを足してみました。まぁ、0.0.2はほとんどRxで書いてみたかったからなんですけどね。

2015-05-11

boot2docker を Linux + KVM で使う

管理の都合上Docker用のVMの上でDockerコンテナを動かしたいなー、Dockerコンテナ動かすだけなら薄いやつがいいだろうからboot2dockerかなーと思ったのだけど、WindowsとMac OS Xで動かす例ばかりでLinuxで動かしている話を見かけない。使えないわけではなく、isoから入れれば使えそうなのでやってみた。なお今回の前提はKVMだけども、boot2dockerをカスタマイズしたいとなれば、Hyper-VやVirtualBoxでも設定の部分は参考になるかも。

手順の概要

概ねやりかたは以下の通り。
  • 永続化データ領域を確保・設定する。
  • virt-installでVMを作成する。
  • IPアドレスやSSHなどの設定をする。
  • リモート接続用の鍵を取り出して使う。

環境

ハイパーバイザ
Ubuntu 14.04 (libvirt/KVM設定済)
boot2docker
1.6.1
ここで試したのはUbuntuだけど、今回の例ではvirt-installが使えればだいたい一緒だと思う。

注意

boot2dockerはデフォルトではかなりinsecure (固定デフォルトパスワードあり・SSHパスワードログイン可) なので、信頼できないネットワーク、例えばインターネットに直接晒されるような環境で作業しないこと。

データ保存領域の設定

boot2dockerはOS部分となる揮発性の領域と、永続的なデータ保存領域(dockerイメージ格納領域を含む)で動作する。そのため、VMを立ち上げる前にデータ保存領域を事前に準備する。揮発性の部分の領域も用意してもいいのだが、今回はしないことにする。

やりかたとしては、qemu-imgで領域を確保し、partedでパーティションを切り、mkfs.ext4でファイルシステムを作成する。このとき、"boot2docker-data"というラベルを設定することがポイント。boot2dockerはこのラベルを見てマウントしに来る。

コマンドライン例は、以下の通り。2Gと書いてみたけど、dockerコンテナのデータが全て来るので、適切なサイズに設定する。
# qemu-img create -f raw /home/images/boot2docker-data.img 2G
# chmod 600 boot2docker-data.img

# losetup -f
/dev/loop0
# losetup /dev/loop0 boot2docker-data.img
# parted --script /dev/loop0 'mklabel msdos'
# parted --script /dev/loop0 'mkpart primary 0% 100%'
# mkfs.ext4 -L boot2docker-data /dev/loop0p1 
# losetup -d /dev/loop0

mkpartで、0の代わりに0%とすると、アラインメントをよしなにしてくれる(警告はなくなるが意味はあるか?)。コマンドが短いのでpartedを使っただけで、fdiskでもいいし、再起動回数が増えるけどもboot2dockerが上がってきた後fdiskを使うとlosetupはしなくていい。

なお、LVMを使うなら、qemu-imgの代わりに、lvcreateでこんな感じ。
# lvcreate -L 8G -n boot2docker-data vg0

virt-installでVM作成

まず、boot2dockerのisoをどこかにダウンロードする。ずっと使うのでうっかり消さなそうな場所に。ここでは、/home/images/boot2docker.isoにダウンロードしてきたのを想定する。

そして、libvirtでVMを作成する。libvirtのXMLを自前で生成する例を見かけたけども、virt-installがやってくれるので、virt-installで作る。

例としては、こんな感じ。
# virt-install --name=boot2dockertest --ram=1024 --vcpus=1 \
   --os-type=linux --os-variant=virtio26 \
   --disk path=/home/images/boot2docker-data.img \
   --network bridge:br0 \
   --livecd --cdrom=/home/images/boot2docker.iso 
この--livecdをつけないと、初回だけCDがある状態になって、2回目の起動以降起動できなくなる。

さまざまな設定

これでboot2dockerが立ち上がってくる。virsh console VM名(ここではboot2dockertest)とすれば、コンソールに接続でき、dockerなどとユーザー名を入れればログインできる。poweroffコマンドでシャットダウン。

このように、/var/lib/{boot2docker,docker}が/mnt/vda1に向いていれば、データ領域の準備もOK。
docker@boot2docker:~$ df
Filesystem                Size      Used Available Use% Mounted on
rootfs                  445.5M     87.5M    358.0M  20% /
tmpfs                   445.5M     87.5M    358.0M  20% /
tmpfs                   247.5M         0    247.5M   0% /dev/shm
/dev/vda1                 1.9G     18.0M      1.8G   1% /mnt/vda1
cgroup                  247.5M         0    247.5M   0% /sys/fs/cgroup
/dev/vda1                 1.9G     18.0M      1.8G   1% /mnt/vda1/var/lib/docker/aufs
docker@boot2docker:~$ ls -al /var/lib
total 0
drwxrwxr-x    3 root     staff          100 May  9 15:26 ./
drwxrwxr-x    8 root     staff          180 May  9 15:26 ../
lrwxrwxrwx    1 root     root            29 May  9 15:26 boot2docker -> /mnt/vda1/var/lib/boot2docker/
lrwxrwxrwx    1 root     root            24 May  9 15:26 docker -> /mnt/vda1/var/lib/docker/
drwxr-xr-x    4 root     root           160 May  9 15:26 nfs/

ここから、いろいろと設定していく。

hostnameの設定

/var/lib/boot2docker/etc/hostname を変更する。データ保存領域にあるので、書き換えればOK.
$ sudo vi /var/lib/boot2docker/etc/hostname 

sshd_configの設定

パスワードログインできないように設定する。こちらも書き換えればOK.
$ sudo vi /var/lib/boot2docker/ssh/sshd_config
(以下を変更/追記)
PasswordAuthentication no 

ssh 公開鍵の配置

ssh ログインできるよう、公開鍵を配置する。作業用ユーザである「docker」のホームディレクトリは永続化されないので、boot2dockerの「/var/lib/boot2docker/userdata.tarを置いておくとホームディレクトリに展開される」という機能を利用して、SSH鍵を配置することにする。

公開鍵の取り方はなんでもいいが、ここではgithub.com/{username}.keysにアクセスするとそのユーザの公開鍵が得られるという方法で鍵を取ってみる例を載せる。

$ cd /var/lib/boot2docker
$ sudo mkdir userdata
$ sudo chown docker userdata
$ cd userdata
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ curl -o authorized_keys https://github.com/{username}.keys
$ cd /var/lib/boot2docker/userdata
$ tar cf ../userdata.tar .

起動時スクリプトの設定(IPアドレス他の設定)

デフォルトでは、dhcpでIPアドレスをもらうだけなので、固定IPアドレスにしたいときは、設定が必要になる。boot2dockerの「起動時に/var/lib/boot2docker/bootsync.shとbootlocal.shが呼び出される」という機能を利用して、スクリプトにIPアドレス他を設定するコマンドをいれておくことにする。bootsync.shは/etc/rc.d/dockerが起動される前、bootlocal.shは後に動くので、先に動くbootsync.shに設定する。

例は以下の通り。boot2dockerのVMのIPアドレスは192.168.1.100と仮定する。
$ sudo vi /var/lib/boot2docker/bootsync.sh
(以下を記述)
#!/bin/sh
/etc/init.d/services/dhcp stop
ip addr flush eth0
ip addr add 192.168.1.100/24 dev eth0
ip route add default via 192.168.1.254
echo "nameserver 192.168.1.254" >> /etc/resolv.conf

$ sudo chmod 755 /var/lib/boot2docker/bootsync.sh

リモート接続用の鍵の再生成

初回起動時に/var/lib/boot2docker/tls/にリモート接続用の鍵が生成されて、必要なものが~/.dockerにコピーされているが、IPアドレスが含まれているので、再生成する。生成の方法は/etc/rc.d/dockerに書いてあるが、簡単にするため、いったん消して再起動時に作らせてしまうことにする。
$ sudo rm -rf /var/lib/boot2docker/tls

あとは、rebootで再起動して設定が反映されていることを確認する。

リモート接続用の鍵の取り出し

このままboot2dockerのVMでdockerコマンドを叩いても使えるが、作業用のPCからdockerコマンドで接続できるようにすると便利。先ほど生成させたキーを、作業用のPCにscpでもらってくる。

$ mkdir -p ~/.boot2docker/certs/boot2dockertest
$ scp 'docker@192.168.1.100:~/.docker/*.pem' ~/.boot2docker/certs/boot2dockertest

あとは、ここに接続するための環境変数を設定するスクリプトを用意して、dot sourceして使えばOK。
$ vi ~/bin/use-boot2dockertest
export DOCKER_CERT_PATH=~/.boot2docker/certs/boot2dockertest
export DOCKER_TLS_VERIFY=1
export DOCKER_HOST=tcp://192.168.1.100:2376
$ . ~/bin/use-boot2dockertest

これで一通りの設定が終了。例えばこんな風に動かして、VM上でdocker psすると、boot2docker VMで動いていることがわかる。dockerのバージョンが合ってないとつながらなかったりするので注意。
$ boot2docker run ubuntu:14.04 -i -t /bin/bash

今後の展開

もう少しスクリプト化することもできるのだろうけど、それはDocker Machineの仕事だよねと思ってやめた。Docker Machineがlibvirtに対応すれば、ほとんどの作業を一通りやってくれるはずなので期待して続報を待とう。