トップ 追記

本 日 の h o g e

hogeとはワイルドカードのようなものです。日々起こった、さまざまなこと −すなわちワイルドカード− を取り上げて日記を書く、という意味で名付けたのかというとそうでもありません。適当に決めたらこんな理由が浮かんできました。

更新情報の取得には rdflirs を使ってもらえると嬉しいです.


05/28/2017 ふむ [長年日記]

tDiary 5330日目

[Py][小ネタ] lesync

exFAT なパーティションにディレクトリツリーを同期したいことがあるのだが,

  • 10 年以上前からデスクトップのファイルシステムが EUC-JP で,convert するのも面倒なので放置している
  • しかし exFAT はファイル名が UTF-8 じゃないと書き込みを拒否するくさい

といったようなことがあって,面倒臭いなあと思っていた.

ファイルの同期といえば rsync(1) 大先生なのだが,単に -a オプションを使うと chown(2) でエラーを吐くとかまあ色々あって,概ね下記のようなオプションを指定することになる.

# rsync -rpt --iconv eucjp,utf8 SRC DST

とはいえ覚えられないし打つのも面倒だし,alias するとか wrapper 書くとかすることになると思うのだが,どうせ rsync(1) ほど高機能/高性能なものを求めているわけでもなし,せっかくなのでフルスクラッチで書いてみた. それが lesync

とはいえどうせなら zero-copy でいっちょやってみるかと,データ本体を user space にメモリコピーすることはないようにした. その結果が下記.

$ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches'
$ time sudo lesync -S hoge /mnt/card/tmp/.
real    0m3.328s
user    0m0.467s
sys     0m0.347s

$ rm -rf /mnt/card/tmp/hoge
$ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches'
$ time sudo rsync -rpt --iconv eucjp,utf8 hoge /mnt/card/tmp/.
real    0m3.633s
user    0m1.296s
sys     0m0.304s

rsync(1) はデータを user space に持ってきてから kernel space に送る (read(2) したデータを write(2) する) という動作をするので,zero-copy にすることで user 時間に差が現れる. まあ,real は大差ないので大した意味はないけれど.

lesync はデフォルトでは差分をチェックせず cp -r のような動作をするので,更新されたファイルだけコピーしたい場合は上記のように -S オプションを指定する. 差分のチェックはデフォルトでサイズ,mtime,ファイル名の比較だけど,プラットフォームが Linux Kernel Crypto API をサポートしていれば md5 等のハッシュ値を比較することもできる. 例えば sha1 ハッシュ値を比較したい場合は下記のようにする.

$ sudo lesync -S -D sha1 hoge /mnt/card/tmp/.

hashlib を使わなかったのは,言わずもがな zero-copy を堅持するため. とはいえ如何に zero-copy と言えど,ハッシュ値の比較を使うとめちゃくちゃ遅くなるので,使いどころはあまりないのだけれど.

ちなみにハッシュ値を算出する部分は独立したモジュールに分けておいたので,下記のようにハッシュ値を求めることができる.

$ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches'
$ time python3 -m lehash -a sha1 data
440a94499f1862fab752280ab7c4470b7d859a69  data
real    0m4.592s
user    0m0.071s
sys     0m2.279s

$ sudo bash -c 'echo 1 > /proc/sys/vm/drop_caches'
$ time sha1sum data
440a94499f1862fab752280ab7c4470b7d859a69  data
real    0m4.393s
user    0m2.332s
sys     0m0.272s

zero-copy のため user 時間と sys 時間に差が生まれているのが見て取れるけど,こちらもまあ real は大差ないので大した意味はない.


05/20/2016 ふむ [長年日記]

tDiary 4957日目

[日記] ロマサガ 2

ついカッとなって PS Vita 版ロマサガ 2 を買ってしまったので,どうせなら 4000 年プレイでもするかーとちまちまプレイ.ようやく完走したので記録しておく.

1011年  第二皇子皇帝 ジェラール        術研究所建設
1505年  サイゴ族皇帝 ハールファグル    カンバーランドを帝国領にする
1756年  ホーリーオーダー皇帝 ピーター  アバロン帝国大学建設
2008年  人形皇帝 コッペリア            ヴィクトール運河奪回
2258年  ハンター皇帝 バイ              ヴィクトール運河にレオンブリッジ建設
3010年  イーリス皇帝 クラウディア      ボクオーンを倒し 地上戦艦を撃沈
3260年  ノーマッド皇帝 ベスマ          七英雄のリーダー ワグナスを浮遊城にて撃破
3510年  陰陽師皇帝 ドウマン            サイゴ族の子供を助け ダンターグ出現 これを撃破
3761年  海女皇帝 ナタリー              氷海においてスービエを撃破
4013年  最終皇帝                       アバロン新市街建設
4014年  最終皇帝                       封印の地にてクジンシーを再び撃破
4016年  最終皇帝                       サラマットを解放しロックブーケを撃破
4018年  最終皇帝                       さまよえる湖にてノエルを打倒
4019年  最終皇帝                       ラストダンジョンにてスービエを撃破
4019年  最終皇帝                       七英雄との戦いにピリオドを打つ!

陣形ロスが何よりイヤなので最終皇帝前に陣形持ちクラスを皇帝にすべく各所を制圧している. これにより 2 年のロスがあるはずなので,おそらく PS Vita 版の最大は 4021 年だろうか. ちなみにヒラガは 99 世,トーマは 80 世だった.

なお可哀想なスービエはいつも二度死ぬ.


01/06/2016 [長年日記]

tDiary 4822日目

[Gentoo] Gentoo (OpenRC) で DHCPv6 client

ふと気付くと,DHCPv6 ready な環境であるはずなのに,手元のマシンに IPv6 アドレスが (linklocal 以外) 付与されていなかった. 何か特殊な設定必要だったっけなーと思って色々調べてみるも,どうにも何だか要領を得ない記述しか見当たらない.

仕方がないので,面倒だけど netifrc を改造して DHCPv6 client ready にした. 改造と言ってもインストール済みファイルを手で書き換えてパッケージシステムを否定するような悪行には手を染めたくないので,epatch_user を使って対処した.

# mkdir -p /etc/portage/patches/net-misc/netifrc-0.2.2
# cd /etc/portage/patches/net-misc/netifrc-0.2.2
# wget http://www.atzm.org/depot/netifrc-0.2.2-dhclientv6.patch
# emerge net-misc/dhcp net-misc/netifrc

こんな感じで,DHCPv6 client ready な netifrc をインストールすることが出来る. ただし DHCPv6 client は optional としてあるので,例えば下記のように設定を追加する必要がある. なお手元のマシンでは IPv6 アドレスを付与したい I/F がブリッジだったので,I/F 名は br0 になっている.

modules_br0="dhclient dhclientv6"
config_br0=("dhcp" "dhcpv6")
dhcpv6_br0="nodns nontp accept_ra autoconf"

modules_br0 や config_br0 は見たまんまなので割愛するとして,dhcpv6_br0 について.

nodns, nontp:
これらは素の dhclient でも指定可能なオプションで,例えば nodns は,/etc/resolv.conf に手を付けてくれるなよ,という指示を行うもの. v4, v6 で /etc/resolv.conf 等の上書き合戦を行われるのは気持ちが悪いので,v6 の方では明示的に切っている. 気にしない人は別に指定せずとも良い.
accept_ra, autoconf:
何かよく分からんのだけど,どうも OpenRC が強制的にブリッジインタフェースの net.ipv6.conf.br0.accept_ra とか net.ipv6.conf.br0.autoconf とかを勝手に無効化してくれやがるので,これらを指定することで有効化できるようにした. 対象がブリッジでなければたぶん必要ない.

ちなみに config_br0 が array になっているので OpenRC に毎度怒られることになるのだけれど,だからと言って dhcp と dhcpv6 をスペース区切りの文字列で書いても機能してくれなかった. しかし怒られることに快感を覚える諸兄にはむしろご褒美だと思うので,もはや深くは考えていない.

とか何とか書いた矢先に

dhclientv6: Add DHCPv6 support via dhclient という commit を見つけた.

けど 2013 年の commit が stable になってないってどういうことなの...


12/15/2015 ふむ [長年日記]

tDiary 4800日目

[Py][OpenFlow] Trema day #8 で発表してきた

あまりにも放置しすぎているので,たまには何か書こうか... ということで.

ひょんなことからお声かけ頂いて,先日 Trema day #8 で発表してきた. ネタは OpenFlow 環境での L2 traceroute について. 資料は slideshare に置いておいた ので興味のある方はどうぞ. コードも oftroute, oftgui に公開しているので,virtualenv でも作って

$ pip install git+https://github.com/atzm/oftroute.git
$ pip install git+https://github.com/atzm/oftgui.git

とか何とかやればインストールできると思います. コマンドとか使い方は簡単にドキュメントに書いてあるけど,基本的にはコントローラを起動して mininet とかを繋いでやれば動作を見るくらいはできる. Ryu アプリとして書いてあるので,ライブラリ的に (?) 扱って他の Ryu アプリと連携して動くこともできるはず.

L2 の traceroute と言えば IEEE 802.1ag とか Ethernet OAM とかまあそんなキーワードで語られることが多いというかそれがスタンダードなので当然なんだけども,さてそれがそのまま OpenFlow 環境下で使えるかというと,必ずしもそうとは限らない.

例えば IEEE 802.1ag では OAM フレームを Ethertype 0x8902 でぶん投げることによってその機能を果たすわけだけれども,OpenFlow Switch がそれをそのまま吸い上げてしまうようなことをすると,制御対象外ネットワークから入ってくる OAM フレームまで吸い上げてしまうことになるので,場合によっては好ましくないこともある.

また OpenFlow 環境では,普通の IEEE 802.1D 的な Learning Switch と違って,主に L2,3,4 のフィールドを使って転送経路を自由に設定できてしまうので,例えば ARP は経路 A を通るけど,IPv4 は経路 B を通る,というようなネットワークを組めてしまう. こうなると,特定のフレームが通る経路だけでなく,「どういうフレームだったら」どういう経路を通るのか,ということを確認する術が欲しくなる.

スライドにも書いてある通り,この手の話についてはいくつも論文が発表されているようで,今さら何か目新しいネタというわけでもなさそうなのだけれど,(公開されてるものだけだけど) 読んでみると頭の弱い自分にはどうにも難しすぎる... ということで,自分でも分かる/作れるくらいに簡素化/最適化したやり方をひねり出してみたのでした.

あと 1 つ注意点. 一応 traceroute 実行時にフレーム転送時間が出るようになってるけども,現状これはとても信用ならない値なので無視した方が良い. というのも,Ryu の (というか Ryu が内部で使ってる tinyrpc の?) WebSocket ライブラリの都合で,client が ack を返さないと server はそこで block してしまうらしい. 要するに,client (oft-traceroute コマンドや oftgui Web 画面) が server (oft-controller とか) に ack を返すまでの時間が,転送時間に乗ってきてしまっているということ. これはどうしたもんかなぁ... と思いつつ,今に至る...

何はともあれ,関係者の皆様,参加の皆様,お疲れ様でした & ありがとうございました.


09/14/2014 うむ [長年日記]

tDiary 4343日目

[Py][小ネタ] 人工無脳 amazonas 実践編

さて昨日 この人工無脳の構造やアルゴリズム的なところを書いた わけだけれど,実際に,どんな文章を学習するとどんな文章を吐き出すのか,それを簡単に書いてみようと思う.

昨日,最後に「試したいことがあった」と書いたけれど,それは「歌詞の自動生成」. これは「歌詞とか詩的なものって文章の繋がりとか多少変でも気にならないというかむしろ多少変な方がそれっぽいんじゃね?」という変な思いつきから生まれたもの. よく Web 上では「J-POP の歌詞はワンパターンだ」と揶揄されているようだけれど,ワンパターンなら,文章の自動生成にはうってつけの題材でもあるはずだ.

ただし何か特定の用途向けにコードをチューニングするのはつまらないので,パラメタはチューニングするとしても,アルゴリズム自体を歌詞向けに特化させるようなことはしない. あくまでただのマルコフ連鎖型文章生成器で,どのような歌詞を吐き出せるのかを見てみたい.

なおテーマ自体は「歌詞 自動生成」とかでぐぐれば大量に出てくることなので,さして新しいことというわけではない.

動作環境を整える

インストールとかその辺は pip とか ebuild 書くとか setup.py 叩くとかで適当に. インストールすると amzweb (人工無脳 API サーバ),amzcons (簡易コンソール),amzirc (IRC Bot) という実行ファイルが作られるので,設定ファイルと共に起動してやる. サーバの設定は下記としてみた.

[web]
instances = second
host      = 127.0.0.1
port      = 8349
daemon    = false
debug     = true

[module]
parsers   = juman
databases = dictdb

[textgen:second]
score_threshold = 0.0
nr_retry        = 50
nr_history      = 0
nr_wordclass    = 100
nr_entrypoint   = 0

[markov:second]
level    = 2
maxchain = 350

[parser:morph:second]
type   = Juman
path   = /usr/bin/juman
encode = utf-8

[db:markov:second]
type = Dict
path = markov.json

[db:entrypoint:second]
type = Dict
path = entrypoint.json

形態素解析器に juman を,データストアに dict/json を使い,2階マルコフ連鎖で最大 350 回まで連鎖させる. ただし連鎖数は初期値.連鎖数は学習する文章の単語数から勝手に調整されていく. スコアの初期値も 0 としておいて,閾値は学習から適当に調整させる. 歌詞生成において「最近の話題を」とか「繰り返しは禁止」というようなことは不要なので,ヒストリ等は 0 にしてある.

$ amzweb amzweb.ini
 * Running on http://127.0.0.1:8349/

設定した "second" という名前の人工無脳インスタンスを起動したので, コンソールから "second" インスタンスを操作する.

$ amzcons second
amzcons>

コンソールから learn というコマンドを使って,ファイルから文章を学習することができる.

一行文生成

手始めに西野カナの歌詞 109 個を一行ずつ学習させた. その結果,下記のような状態となった.

amzcons> stat
score threshold: 0.164676
markov maxchain: 6
markov keys:     8942
entrypoints:     1340

実際に文章を生成してみる.

amzcons> print
近すぎると怖くなって [0.167785]

ふむ何やらそれっぽい.最後の数値はこの文章のスコアを示す.

一行文の連結による歌詞の生成

一行ずつ学習させた結果だから一行ずつしか出てこないので,print コマンドを何度か叩いて結果だけを集めた結果がこちら. なお空行は適当に手で入れた.

近すぎると怖くなって
リピートできないくらい泣いて
嫌いだった鏡に問いかける

久々のオフ 天気も最高
ふたりで過ごしたこと
顔くっつけ合って

恋が凍えてる
先週もまた怒られて
ここに戻ってる
側にいたいよ

最後の恋に恋して
顔くっつけ合って

アイライナー濃いめで
苦いコーヒー流しこみ
この世を去った

何だかよく分からないうちに何かが死んでしまった...

「混ぜる」

意味は分からないが何かちょっと面白いので,悪ノリして Luna Sea の歌詞を 106 個ほど追加学習させてみる. 交わりそうにない西野カナ分と Luna Sea 分を混ぜてみるのだ. 結果は下記の通り.

amzcons> stat
score threshold: 0.150078
markov maxchain: 7
markov keys:     14704
entrypoints:     1875

では文章の生成を行ってみる.

amzcons> print
冷たく透き通る瞳の 恋の色☆ [0.155039]

テンションが低いのか高いのかよく分からない. まあ面白いのでこのままいくつか文章を生成させていく.

冷たく透き通る瞳の 恋の色☆
ナビに怒ってる君を愛してる

伝説の夜に 僕が消えて行く

リミットに気持ちが揺れてる
夢から覚めてすべての事があった

先週もまた怒られて
ローマ風の中でずっと叫んでる
せつなくて ずっと昔から知ってるみたいだね
次の日の未来が違っていたんだ

楽園に刻まれた こんな自分を好きに
伝説の夜 抱きしめた…

淋しげな歌を聴いて
雨音を夜まで数え
夢の中 鍵を探している
窓に映った 自分見つめて

思い通りにはいかないかもしれないけど叫ぶ
限り無く 今はほどいて 頼むからどいて

コノ胸ノ アリフレタ 夢に見る

最初と最後,このテンションの差である.

複数行文生成

一行一行生成して,それっぽいところで手動で空行を挿入するというのもまあ良いのだけれど,そうすると人間の脳と手が介在することになってめんどくさい. この人工無脳エンジンは複数行から成る文章の学習と生成にも対応させてあるので,一発で一気に歌詞を生成できるように,一行一行ではなく歌詞全体を一発で学習させてみる.

AKB48 の歌詞 164 個を行毎ではなく作品毎に学習させてみた結果がこちら.

amzcons> stat
score threshold: 0.267828
markov maxchain: 306
markov keys:     18086
entrypoints:     129

複数行から成る文章の場合,文章中に含まれる単語の品詞の羅列をそのままスコアリングに使ってしまうと,恐ろしく低い値となってしまう (長文同士の比較となり全く似ない). そのため複数行の場合でもスコアリングは行毎に行って,その平均値を使う形にしてある.

さてこの状態で print コマンドを打ってみた結果が以下.

amzcons> print
目の前にそびえる
悩みながら
あの日の栞
輝いた青春の熱は
ヘビーローテーション

時は静かに
広がってく波紋
その瞬間
自分のMINDで動けよ
熱く 燃え尽きるまで
別の力
生まれた場所

やさしさを心の道で
見つけた
どこへ行けばいいのか?

喧嘩して 泣いたこと あきらめかけても
木っ端なんか
ここで死ぬのだろう [0.273942]

...また死んだ.なぜだ.

複数行文も「混ぜる」

では AKB48 分と THE BLUE HEARTS 分を混ぜてみよう. THE BLUE HEARTS の歌詞 93 個を追加学習させた結果がこちら.

amzcons> stat
score threshold: 0.169714
markov maxchain: 160
markov keys:     23498
entrypoints:     199

どうやら歌詞の構成の傾向が違うようで,スコア閾値や最大連鎖数がだいぶ下がっているのが見て取れる.

では歌詞を生成してみよう.

amzcons> print
レストラン レストラン
レストランに行きたい
遠くに見えても
何か別の答えを探す
愛し合おうぜ
裸になっていたんだ

M・O・N・K・E・Y 燃えている

校庭は一面
鈍い銀の世界を
忘れられない

楽しい事をたくさんしたい 喚きたい
ミサイルほどのペンを片手に
僕たちの隠した牙

恋は
ずっと手を取り 連れ出したい
妄想だけじゃ
はかれない
目の前のマネキンたち 何かキレる音がした
アイスのときめき
ハートに火を吹くぜ

明日は明日のために
おもしろい事をたくさん見たよ
何よりも しょうがないから
オレの心が騒ぐよ
しまっておけない [0.174378]

何言ってんだこいつ.

3階マルコフ連鎖

ここまで 2階マルコフ連鎖で文章を生成してきたけれど,3階マルコフ連鎖としてみよう. 設定ファイルを下記のように書き換えて学習し直せば,3階マルコフ連鎖で文章生成を行える.

[markov:second]
level    = 3

この状態で Luna Sea の歌詞 106 個を学習させて歌詞を生成.

amzcons> print
この詩 今夜おくろう君に かけがえない君に
変わることない風に
失いかけていたんだ この想いさえ
記憶の扉 鍵を壊して uh 二人の隙間で 育ってゆく物は
消えた 記憶のトビラ 開くカギか

Break your mind,
going back the dream I can't live without you
このまま 君だけは ぬれないで ずっと
さよなら 君だけは 微笑んで ずっと
さよなら 揺れていた せつなくて ずっと
さよなら 揺れていた せつなくて ずっと
このまま 君だけは 大切な事 抱きしめていて

嘘の世界であなたと二人
愛し合ってみたい
キミが欲しい キミの匂いと
あどけない 微笑みが
塞がれた こんな夜には
ROSIER 近づけない
ROSIER 抱き締められない
貴方が与えて呉れた一生をばらばらに壊したい

瞳を閉じて フラッシュの中 散り咲こう 無情な夜
今誓う空虚の中 散り咲こう [0.132440]

やはり学習したフレーズがそのまま出てきてしまう率が上がるように見える. 過去の履歴を加味して次の状態を決める場合,次の状態への分岐が少なくなってしまうため,数値を大きくすると「そのまま感」が出てきてしまう.

ただ学習数を増やせば分岐も増えるはずではあるので,このまま AKB48,THE BLUE HEARTS,西野カナを全て混ぜてみて,文章を生成してみよう.

amzcons> print
夢まで寝静まる街
ベッドから抜け出して
大人を起こさないように

パンパンパン パンパンパン
パーンと弾けて 飛んで行け

前を邪魔する奴は
喧嘩上等 明け暮れて
無意味なことだとわかった
生意気な奴をボコボコにしても
僕はぼんやりと
眺めていた
苦しめたくない でも忘れられない 何故?
涙 拭いて
歩き出そうよ
そこに 岸はあるんだ

やわらかい君の声を聞かせて 涙を止めて
Dancing on me
life is cool.

ありふれた毎日が
Baby I like candy candy oh
そうテレビをつけたって
話題のパンケーキ特集だって
妄想限界 Help me
life is "LOVE IS OVER
I tell you
just wait for beauty…
貴方のため 生まれ変わる [0.167322]

やっぱ混ざらんわ.無理.

まとめ

おそらく,似たテイストを持つアーティストに絞ったりして学習を進めていけば,それっぽいものを吐き出せるようにはなるんじゃないかと思う. ただ,歌詞というものには主題となるものがあって,ある種の一貫性を文章全体として求めてくる. マルコフ連鎖で文章を生成する以上,どこまでも確率によって内容が展開されていくので,主題の違う文章を学習させてしまうと,生成された文章の中で矛盾を生んだりすることになる. 「このインスタンスはこういう文章の生成用」等といったように主題別に学習を進めて行けば,もしかしたらそれっぽいものを吐き出せるようになるかも知れない.

あと複数行から成る文章の学習と生成は昨日ざくっと適当に作ったものなので,まだまだコードとしてのチューニングの余地があるのではと思っている. 特に,スコアリングを一行一行に対して行うようにしたのは悪手だったかも知れないと思っている.全体の構造が無視されてしまうからだ. まあ,この辺はまたおいおいと詰めて行こうと思う.

この世を去った