tag:blogger.com,1999:blog-89958629478080383662024-03-16T16:36:16.675+09:00hasegaw bloghasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.comBlogger182125tag:blogger.com,1999:blog-8995862947808038366.post-68957867462416055732024-03-09T08:13:00.013+09:002024-03-09T08:25:26.353+09:00BOSE SoundBar 900 のメンテナンスと覚え書き<p> 暫く iOS アプリなどから連携不可能な状態になっていた BOSE SoundBar 900 を復旧したので覚え書き。</p><p><br /></p><p><b>問題</b></p><p>手元では下記の問題がありました。</p><p></p><ul style="text-align: left;"><li>ルータの設定上の問題か、 BOSE 社サイトへの通信が通らずアクティベーションできない (iOSアプリにて連携できない)</li><li>アクティベーションされた際、最新ファームウェアへのアップデートが始まるが、完了しない</li></ul><div>この問題を解決するための手順は、最終的に、下記のとおりになりました。</div><div><ul style="text-align: left;"><li>DHCPでアドレス取得ができるネットワークに有線で接続</li><li>ファームウェアリセットのため Bluetooth + 早送り> ボタンを長押しする</li><li>BOSE社サイトからファームウェアファイル product_update.zip をダウンロードする</li><li>SoundBar 900 が掴んでいる IP アドレスを見つける</li><ul><li>今回はルータの DHCP リース状況からIPアドレスを特定</li><li>BOSE社サイトで案内されているMACの prefix がアテにならない</li></ul><li>http://x.x.x.x:17008/update.html にアクセスする</li><li>表示されたファームウェアアップロード画面にて product_update.zip をアップロード</li><ul><li>ファームウェアアップロード画面をリロードしてファームウェアバージョンが上がっても我慢</li><li>白いダッシュ(−)LEDが点滅しているうちはFWアップデートが続いているので1~2時間かかるつもりで放置</li><li>サウンドバー本体からファクトリーリセット時の起動音がしたらアップデート完了</li></ul><li>DHCPでアドレス取得ができ、素直に通信できるインターネット環境に接続</li><ul><li>今回はLTE無線&有線ルータを上流として使用</li><li>SoundBar 900 を同ルータに接続して有線 DHCP でアドレス取得した状態とする</li><li>iOS端末を同ルータのL2セグメントに接続</li></ul><li>iOS端末にて SoundBar 900 を登録、アクティベート</li><li>本来のネットワークにイーサネットで接続し DHCP でアドレスを取得しなおす</li><ul><li>有線 -> 有線であれば WiFi のパラメータが絡まず、上流を置き換えても問題がおきない模様</li></ul></ul><div>普通の人に「これやりなよ」とカジュアルに言えるかというと、かなり微妙です。</div><div>知人が同じ問題に悩んでいても、面倒なので、教えてあげたり手伝ってあげたりする気には、正直なりません。</div><div>このようにファームウェアの挙動が常に判りづらく、デジタルガジェット的観点な感想として、かなり低めの評価になります。</div></div><div><br /></div><div><br /></div><div><b>ファームウェアアップデートについて</b></div><div><br /></div><div>事前にファームウェアをアップデートする理由は、アクティベート成功後、自動的にファームウェアアップデートが開始されますが、iOS上でファームウェアアップデートが開始された後に失敗しても何も理由が表示されません。アップデートは一度で30分弱かかると書かれていますが、ファイルの転送段階でアボートしていても把握できないようです。</div><div><br /></div><div>LTE経由でファームウェアアップデートが走ったとしても、ここでダウンロードされるファイルが 600MB ほどになり、光回線などがあれば、LTEで転送することは合理的ではありません。PC等でファームウェアを事前ダウンロードしておけばリトライも簡単ですし、試行あたりの待ち時間や総転送量も減るでしょう。</div><div><br /></div><div>実際にファームウェア更新ページで試してみるとわかるのですが、ファームウェアアップロード時、 SoundBar 900 のフラッシュストレージ畳に過去の失敗ファイルが残っていることがあるようで、その場合にはファームウェア更新のワークエリアが十分にとれずに失敗することがあるようです。この問題を回避するためには Bluetooth ボタン + 早送り> ボタンを同時長押しして、あらかじめファクトリーリセットしておくと、ワークエリアがリセットされるのか、空き容量不足になるエラーが解消できました。</div><div><br /></div><div>いちどファームウェアが更新できれば、LTE回線を上流としたネットワーク環境でも、アクティベート後の自動的なファームウェアアップデートも発生せず、期待通りデバイスが制御できるようになりました。</div><div><br /></div><div>最近のファームウェアでは HDMI で接続されたソースが起動したときにこちらに入力を切り替えるような変更が入っているようですね。何かの拍子に入力ソースが切り替わった後に、テレビ等からの音が聞こえずモヤモヤするということは減るのかもしれません。(音が鳴らないと HDMI のリンクが落ちているのか、単に入力ソースの問題なのかという二択が頭によぎる時点でかなりUXが低い印象でしたが、これが改善しているかもしれません)</div><div><br /></div><div><br /></div><div><b>中身は Android なのね</b></div><div><br /></div><div>サービス用の Type-C コネクタを介して疑似イーサネット?接続することも可能なようですが、手元ではすぐにイーサネットとして認識されなかったので、切り分けも面倒なので早々に諦めて有線ネットワーク経由でアクセスしました(このアップロードページは、これはこれでセキュリティ的にどうなんだという作りですが)。</div><div><br /></div><div>Type-Cで接続したところ Android デバイスとして認識されたので、これ中身の OS は Android なんですね。ファームウェアファイルが600MBもあったのに驚きましたが、なんか納得というかんじです。 Raspberry Pi にのっているような STB 用のプロセッサ等で制御しているんでしょうね。</div><div><br /></div><div><div><b><br class="Apple-interchange-newline" />HDMIのリンク落ち問題</b></div><div><br /></div><div>経験してみて判ったのですが BOSE SoundBar シリーズは HDMI で接続中に HDMI のリンクが落ちるとコールドスタート(電源ケーブル抜き差し)まで復旧しないようで、ネットで調べるとフラストレーションを感じている人が日本語でも他の言語でもいっぱいいます。私が弄った個体でもこの問題は発生していて、以下の対策をしています。</div><div><br /></div><div>1)Ultra High Speed HDMI 認証のケーブルに交換で接続</div><div>2)HDMI ソース側(今回は SONY BRAVIA)の外部入力設定において HDMI リンクモードを拡張から標準に変更</div><div>3)簡単にリセットできるように電源ケーブルにスイッチを増設 :-(</div><div><br /></div><div>Ultra High Speed HDMI は、 8K 対応として売られているケーブルです。メーカーがズルをしていなければ、このロゴを付けられるケーブルは 8K のデータが転送できることを確認している(よりテクニカルには 48Gbps のデータ伝送で問題ないことが確認された製品)ということになります。Ultra High Speed HDMI はいまのところ HDMI シリーズでいちばんノイズ耐性をもとめる規格です。1m程度のケーブルは銅線などで単に接続されているパッシブタイプのケーブルが一般的ですが、高ノイズ耐性なケーブルであれば迂闊な HDMI の信号ロックはずれに頻度も減るだろうという狙いです(自分で HDMI 信号を扱ってきた際の体験談に基づいてのロジックです)。実際、体感的には、コレでかなり音が消える頻度が下がった気がします。</div><div><br /></div><div>SoundBar 900 は eARC の製品ですが、どうせオーディオしか伝送しないだろうに、高いビットクロックでソースとシンクが HDMI 信号をロックしてて、ちょっとしたノイズで簡単に HDMI 信号のロックが外れると電源入れ直しまで復旧しないとか、そんな感じの挙動に見えます。おそらく付属のケーブルでも同期がとれなくなるケース多いのでしょうが、私みたいに古いケーブルなどをうっかり使い回すような人は、かなり痛い目にあうのでしょう。</div><div><br /></div><div>HDMI信号ロックが外れたときのために SoundBar 900 の通電用ケーブルは簡単にリセットできるように電源スイッチを自分で追加する加工をしてあります。電源タップ側で簡単に電源オンオフできればそれでいいと思いますが、電源タップがアウトレットごとの独立制御に対応していなかったので、ケーブルを加工しました。電源ケーブルを抜き差しする手間がないだけでもかなりストレス軽減です。</div><div><br /></div><div>今回、テレビ側の設定を見ていたら HDMI のリンクモードを拡張・標準で選べるようなので、これを変更したときに具体的に何がおきるかは判っていないのですが、これで HDMI のビットクロックを落とせたら安定性が増すかな、みたいな期待で、こちらの設定を標準モードに変更してみました。これで安定性が増すといいけども...</div></div><p></p>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-14105050586036961722022-04-30T17:56:00.003+09:002022-04-30T17:56:45.312+09:00ES Modules から YouTube IFrame Player API を使う<p>YouTube IFrame Player API は、手元の Web サイトなどに YouTube 動画を埋め込みできる YouTube 公式のAPIです。</p><p><a href="https://developers.google.com/youtube/iframe_api_reference?hl=ja">iframe 組み込みの YouTube Player API リファレンス</a></p><p>以下に Iframe Player API のサイトにあるサンプルコードを引用します。</p><pre><!DOCTYPE html>
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '360',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
</body>
</html></pre><p><br /></p><p>Iframe Player API は ESM として実装されていないので、 ESM として実装した Javascript などのコードから利用する場合にはいくらかの工夫が必要になります。</p><p>API の紹介サイトでは同 API の初期化終了後にコールバックされる onYouTubeIframeAPIReady() をグローバル名前空間で宣言していますが、これは ESM の名前空間からみれば window.onYouTubeIframeAPIReady() にあたります。また、同 API の初期化が完了すると YT が定義されますが、これは ESM の名前空間からみると window.YT になります。</p><p>この考慮点を反映して ESM としてサンプルを再実装したものが下記になります。</p>
<script src="https://gist.github.com/hasegaw/8d1d7059bb5459eefd81c6c08665c8e0.js"></script><p>実際には ESM として実装する場合には、クラスとして実装するケースが多いでしょう。下記の例では、埋め込んだプレイヤーからのコールバックをインスタンスのメンバ変数として実装しています。</p>
<script src="https://gist.github.com/hasegaw/d9d1ac87040148625be95a2e8b4fa1f5.js"></script>
<p>※コード上は動画のロードが完了し次第自動再生するような実装になっていますが、本記事執筆時点ではそのように動作していないようです。これは API のサイトにあるオリジナルのサンプルの問題です。</p>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-50882339309243741702022-03-28T12:51:00.005+09:002022-03-28T13:13:42.835+09:00 シェルスクリプトで unixtime を扱う<p>シェルスクリプト内で unixtime を得るには /bin/date +%s が利用できます。この方法で取得した unixtime はシェルスクリプト内で加算・減算したり、比較したりできます。</p><p>以下は、 sleep に頼らずに $TIMEOUT 秒間待機する例です。単純に sleep $TIMEOUT と記述するよりも、柔軟な待機ループを実装できます。</p><pre>TIMEOUT=10
TIME_START=`/bin/date +%s` # ループ開始時刻(いま)
TIME_END=$((${TIME_START} + ${TIMEOUT})) # ループ脱出時刻
echo -n running
while [ `/bin/date +%s` -lt ${TIME_END} ]; do
sleep 1
echo -n .
# MySQL Server への接続性が確認できたら $TIMEOUT 秒待たずにループを抜ける
mysql -e 'SHOW STATUS' 1> /dev/null 2> /dev/null && break
done</pre>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-71829276775908711282022-03-25T15:25:00.003+09:002022-03-25T15:32:46.386+09:00Linux KVM + virtio-net のレイテンシーを削減するヘンな方法Linux KVM の virtio-net を利用している際にリモートホストへの PING 結果がマイクロ秒のオーダーで安定しない(ブレる)という話を見かけました。<div><br /></div><div>Linux KVM の仕組みや QEMU のデバイスエミュレーションの仕組みを考えれば「そんなもの」かなと思い、調査および追加の実験をしてみました。なお、本記事は x86 アーキテクチャの Linux KVM の動作に基づきます。</div><div><br /></div><div><br /></div><h3 style="text-align: left;">パケットが送信される仕組み</h3><div>ping コマンドなどにより発生した、送信パケットは OS のネットワークスタック(L3, L2)を通じてイーサネットのドライバに引き渡されます。</div><div>今回はLinux KVMのデバイスエミュレーションを利用した際のレイテンシーに注目したいため、プロセスからデバイスドライバまでデータ届く流れについては触れません。 Linux KVM の仮想マシンで使われる virtio-net に注目します。</div><div>仮想的なネットワークインターフェイスである virtio-net 、またそのベースとなる、ホスト−ゲスト間の通信に使われる virtio-pci では、ゲストOSのメモリ空間にある送信対象データをバッファへのポインタをリングバッファに積み、I/Oポートを叩くことで VMM (Linux KVM) 側に通知します。</div><div>このあたりの仕組み(PCIデバイスに模倣する virtio のゲスト・ホスト間通信の仕組み)は過去に<a href="https://www.slideshare.net/TakeshiHasegawa1/20101126hbstudy17">エンジニアなら知っておきたい仮想マシンのしくみ</a> スライドにて解説しているので、そちらもご確認ください。</div><div><br /></div><div><a href="https://github.com/torvalds/linux/blob/4f50ef152ec652cf1f1d3031019828b170406ebf/drivers/net/virtio_net.c#L1762">https://github.com/torvalds/linux/blob/4f50ef152ec652cf1f1d3031019828b170406ebf/drivers/net/virtio_net.c#L1762</a> に、ホストへ通知すべき送信データが準備できた際ホスト側の virtio-net に通知するブロックがあります。</div><pre> if (kick || netif_xmit_stopped(txq)) {
if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
u64_stats_update_begin(&sq->stats.syncp);
sq->stats.kicks++;
u64_stats_update_end(&sq->stats.syncp);
}
}
</pre><div><br /></div><div><div>virtqueue_notify(sq->vq) は仮想デバイスの I/O ポートへのアクセスする実装となっています。そのセンシティブ命令を契機としてゲストから VMM に制御が移ります。デバイスモデル(qemu-kvm)のI/Oポートハンドラがゲストからの割り込み理由を判断し、 virtio-net のゲスト側リングバッファにあるデータをバックエンドのネットワークインターフェイスに渡します。</div></div><div>この際(Intel 表記で) VMX non-root → VMX root の kvm → qemu-kvm (ring3) と遷移し、場合によっては qemu-kvm がネットワークスタックにパケットを渡す前にプリエンプションが発生する可能性があり、送信タイミングが遅れる原因になり得ます。</div><div><br /></div><h3 style="text-align: left;"> パケットが受信される仕組み
</h3><div><br /></div><div>では、パケットが届いた場合はどうなるでしょうか? qemu-kvm がゲスト行きの受信データを受け取ると、予め用意されているゲスト側のメモリ領域に受信データを書き込み「ゲストに対して割り込みをかけます」。</div><div>本物のx86のプロセッサであれば、IRQ(Interrupt ReQuest)を受け付けるための信号線があり、それを介して割り込みを通知する方法と、割り込み通知用のアドレス空間に対するメモリ書き込みトランザクションにより割り込みを通知するMSI(MSI-X)割り込みがあります。仮想マシンの場合、仮想プロセッサにはIRQ線、MSI通知用のアドレス空間にメモリトランザクションを行ってもそれを受けてくれる相手がいないので、仮想マシンのプロセッサを「割り込みがかかった状態」にすることで割り込む挿入を実現することになります。</div><div><br /></div><div><a href="https://github.com/torvalds/linux/blob/0564eeb71bbb0e1a566fb701f90155bef9e7a224/arch/x86/kvm/vmx/vmx.c#L4574">https://github.com/torvalds/linux/blob/0564eeb71bbb0e1a566fb701f90155bef9e7a224/arch/x86/kvm/vmx/vmx.c#L4574</a> にある vmx_inject_irq() に、 Intel VT でゲストに割り込みを通知する実装があります。</div><pre>static void vmx_inject_irq(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
uint32_t intr;
int irq = vcpu->arch.interrupt.nr;
trace_kvm_inj_virq(irq);
++vcpu->stat.irq_injections;
if (vmx->rmode.vm86_active) {
int inc_eip = 0;
if (vcpu->arch.interrupt.soft)
inc_eip = vcpu->arch.event_exit_inst_len;
kvm_inject_realmode_interrupt(vcpu, irq, inc_eip);
return;
}
intr = irq | INTR_INFO_VALID_MASK;
if (vcpu->arch.interrupt.soft) {
intr |= INTR_TYPE_SOFT_INTR;
vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
vmx->vcpu.arch.event_exit_inst_len);
} else
intr |= INTR_TYPE_EXT_INTR;
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr);
vmx_clear_hlt(vcpu);
}</pre><div><div>ここでのキモは intr |= INTR_TYPE_EXT_INTR もしくは INTR_TYPE_SOFT_INTR です。 Intel VT では、仮想プロセッサの状態を管理するVMCS構造体に対して特定のビットを立てておくと、「次にその仮想マシンを実行するときに、ゲスト側で割り込みハンドラに処理が移される」仕組みです。ただし、ここでは実際に仮想マシンの実行し、割り込みハンドラに処理を移してはいないことに注意が必要です。</div><div><br /></div><div>では、具体的にいつ、仮想マシンの割り込みハンドラが実行されるのでしょうか?答えは、Linux KVM + qemu-kvm の場合 qemu-kvm のメインループでCPUスレッドが改めて VMX non-root モードに移行するように要求したときです。</div><div><br /></div><div>「次に仮想CPUを実行するときは割り込みハンドラを実行する必要があるよ」設定されても、その次にスケジュールされるタイミングは qemu-kvm の仮想CPU実行スケジュール、Linuxのスケジューラに依存することになります。仮想マシンのCPU負荷が低い場合には、qemu-kvmはVMX non-rootへの遷移を抑制して他のプロセスへのプリエンプションを許すことにより負荷を下げます。しかし、パケットが届いた後にqemu-kvmのCPUスレッドにプリエンプションが発生し、VMX non-rootへ遷移するまでがネットワークレイテンシーの増加として見えることになります。</div></div><div><br /></div><div><br /></div><h3 style="text-align: left;">VMX non-root でのビジーループは解決策になるか</h3><div>では、ゲストがビジー状態でCPUを使い続ければ他のプロセスへのプリエンプションが発生せず、レイテンシーに改善が見られるのではないか?という仮説がありました。この方法で、ゲストOSがHLT命令などを発効してCPUを手放すことが減るというメリットは確かにありそうですが、2つの考慮点があります。</div><div><ul style="text-align: left;"><li>仮想プロセッサが割り込みハンドラに制御を移すのはVMX rootからVMX non-rootに制御を移すタイミングです。このため、VMX non-rootでビジーループを回っていても割り込みハンドラに制御が移るわけではありません。</li><li>VMX non-rootでビジーループを回り続けた果てにVMX rootに遷移したとき、Linux カーネルから見れば、そのCPUスレッドは「大量のCPU時間を消費した」プロセスと認識します。このため、負荷が高いシステムでは、Linuxカーネルは他のプロセスに積極的にプリエンプションしようとするでしょう。これでは、次回のVMX non-rootへの遷移が遅れてしまいます。</li></ul></div><div><br /></div><div><br /></div><h3 style="text-align: left;">ちょっとしたカーネルモジュールでレイテンシー性能を改善する</h3><div>ここでは、ちょっとしたカーネルモジュールをロードして、レイテンシー改善が可能かを試してみました。コードは <a href="https://github.com/hasegaw/cheetah/blob/master/cheetah.c">https://github.com/hasegaw/cheetah/blob/master/cheetah.c</a> です。以下の関数をカーネルスレッドとしてビジーループで回します。</div><div><br /></div><pre>static void kthread_main(void)
{
u32 vmx_msr_low, vmx_msr_high;
rdmsr(MSR_IA32_UCODE_REV, vmx_msr_low, vmx_msr_high);
schedule();
}</pre><div><br /></div><div>rdmsr は、 x86 アーキテクチャにある Machine-Specific Register を読み取ります。この命令はデバイスモデルでのエミュレーションが必要になるセンシティブ命令であるため、強制的に VMEXIT が発生して VMX non-root → VMX root への遷移が発生し、qemu-kvmでRDMSRのエミュレーションが行われ、その結果をもって再度VMENTERされます。</div><div>RDMSRのエミュレーションは未改造のqemu-kvmにおいて比較的コストの低いエミュレーション処理で、特に副作用が想定されないため、これを選んでいます。HLTなどを利用するとVMMがすぐにゲストに処理を戻さないかもしれませんが、RDMSRであれば、他プロセスへのプリエンプションがない限りは、すぐに再度VMENTERによりVMX non-rootに移行することが想定され、このタイミングで割り込みハンドラへの制御が移るわけです。</div><div><br /></div><div><br /></div><h3 style="text-align: left;">測定結果</h3><div>Linux KVMで動作するシステム上のLinuxゲスト間でpingコマンドを実行した際のレイテンシーを測定してみました。下記が90%パーセンタイル値です。</div><div><ul style="text-align: left;"><li>RDMSRのビジーループなし(通常の状態) —— 614us (100.0%)</li><li>RDMSRのビジーループなし、ゲスト内で perl -e 'while(1) {}' でビジーループ —— 516us (84.0%)</li><li>RDMSRのビジーループあり —— 482us (78.5%)</li></ul><div>ごく一般的なLinuxゲストと比較すると、先のRDMSRのビジーループを回したLinuxゲストでは20%程度のレイテンシー低下が確認できました。</div><div><br /></div><div>このデータは2021年3月(本記事の執筆時点からちょうど1年前)に割とノリで試したもので、であまり細かいデータを取っていないため、上記の値しか残っていないことにはご容赦ください。</div></div><div><br /></div><div><br /></div><div><h3 style="text-align: left;">割り込み通知からポーリングループへの移行</h3><div>ゲストがビジー状態で回り続けていても通知を受けられないのなら、ひとつの選択肢としてはポーリングループでホストからの通知が受けられたらいいのに、という発想になるかと思います。実際、DPDKではプロセスがループでポーリングし続けることで大幅にレイテンシーを短縮しているわけです。ホストOSからゲストOSへの通知をポーリングループで監視すればよいのではないでしょうか?</div><div><br /></div><div><div>今回は、virtio-netに対して手を入れるような事はしなかったのですが、ホストOSからの割り込み通知を待たずにリングバッファへ新着データを拾いにいくことは可能な気がします。しかし、本当にレイテンシー面を気にするのでれば SRIOV などを検討するほうがいいでしょう。</div></div><div><br /></div></div><div>Linux KVM ではありませんが、同じく Intel VT ベースで仮想マシン技術を提供する VMware 社のホワイトペーパー <a href="https://www.vmware.com/techpapers/2011/best-practices-for-performance-tuning-of-latency-s-10220.html" rel="nofollow" target="_blank">Best Practices for Performance Tuning of Latency-Sensitive Workloads in vSphere VMs</a> には、下記の記述があります。</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi0AdlVSH7mbJZTwASk6wbQSTM4LRYETTZ_StSQrG2WOIpml52UQSqWHmlrRWibu6E9okmG2_s3WeTihsVLxcTyq3_sfQINFBZoW_hTgxXAQTtlFOORPlIWVxQ-GdWkQqVunnllhYsS8SoMXSJR6eSR8ILnMDPDd_oZ45HXeOKdV0b1iPICDTr2KGjk" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="2250" data-original-width="1970" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEi0AdlVSH7mbJZTwASk6wbQSTM4LRYETTZ_StSQrG2WOIpml52UQSqWHmlrRWibu6E9okmG2_s3WeTihsVLxcTyq3_sfQINFBZoW_hTgxXAQTtlFOORPlIWVxQ-GdWkQqVunnllhYsS8SoMXSJR6eSR8ILnMDPDd_oZ45HXeOKdV0b1iPICDTr2KGjk=w350-h400" width="350" /></a></div><br /></div><div><br /></div><h3 style="text-align: left;">まとめ</h3><div>Linux KVM の virtio-net を利用している際にリモートホストへの PING 結果がマイクロ秒のオーダーで安定しない(ブレる)理由について、Linux KVM、qemu-kvmとゲスト側カーネルの間で何がおきるかを考えてみました。</div><div>また、ゲストへの割り込み挿入タイミングを増やすために、ゲストカーネル上で数行で書けるカーネルスレッドを動かすことにとって、実際にレイテンシー性能がいくらか向上することを確認しました。</div><div>マイクロ秒オーダーの時間のブレを気にする場合は、最終的にはSRIOVやポーリングモードの導入、そもそも(VMENTER/VMEXITだって遅いので)VMM上ではなく物理的なマシンの利用が解決策になると思いますが、仮想マシンのしくみがこんな物なんだと理解しておくのは悪くない事かと思います。</div><div><br /></div><div><br /></div><div><br /></div><div><br /></div>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-68471945710165610132022-03-24T16:11:00.003+09:002022-03-24T16:28:11.101+09:00シェルスクリプトで MySQL サーバーが起動してくるのを待つ<p> 10年ほど前にメッチャ MySQL で TPC-C を回していたときに使っていた方法です。</p><pre>echo -n "Waiting for the database ready...."
while true; do
sleep 1
mysql -h ${TPCC_HOST} -P ${TPCC_PORT} -u ${TPCC_USER} --password=${TPCC_PASSWORD} \
-e 'show status' 1> /dev/null 2> /dev/null && break</pre><pre> echo -n '.'
done
echo 'up'</pre>
<p>MySQLクライアントでサーバに接続し適当なクエリを実行できるかでアクセス性があるか判断しています。このクエリが実行できるようになるまでここでブロックし、問題なくクエリが実行できれば終了コードとして 0 が返されますので && break が実行されループを抜けます。</p>
<p>今回はサーバがクエリを受け付けられるようになるまで待っていますが、同じ方法を用いて、クエリが実行できるかどうかで処理内容を条件分けすることもできますね。</p>
<pre>
mysql -h ${TPCC_HOST} -P ${TPCC_PORT} -u ${TPCC_USER} --password=${TPCC_PASSWORD} \
-e 'show status' 1> /dev/null 2> /dev/null
# 上記 mysql コマンドの終了コードが格納された $? を見て処理を分岐する
if [ $? -eq 0 ]; then
echo "クエリが成功した"
else
echo "サーバに接続できなかった、クエリが失敗した"
exit 1 # ゼロ以外の値でシェルスクリプトを異常終了させる
fi
exit 0 # 正常終了
</pre>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-63670461517683492752022-03-01T19:11:00.007+09:002022-03-01T19:28:40.259+09:00IkaLogの開発で得た知見:大量の動画や画像を取り扱う際の Tips<p>スプラトゥーンの画像解析ツール IkaLog を作った際に得た知見をいくつか共有したいと思います。特に動画や画像を取り扱った際に苦しんだ点、工夫した点、良かった点などを紹介します。</p><p><b>資産として動画データを蓄積する</b></p><div>IkaLog では Nintendo Switch コンソールが出力した生の画像データを扱いますが、ただし開発にあたって「取りっぱなし」のビデオの利用が適切とは言えません。撮りっぱなしの 1 時間 1GB の動画ファイルと、1分間15MBの動画ファイルであれば、後者のほうが取り扱いやすいこと感覚的にわかるかと思います。</div><div><br /></div><div>長い動画ファイルから目的のシーンを探し出すことには作業として手間がかかります。VLC などの動画再生ソフト、もしくは動画編集ソフトによる作業をしようとした場合、長い動画から目的のシーンを的確に見つけて作業するためには、シークバーを正確に操作しなければいけません。そもそもコンソール上で作業しづらいという事になります。</div><div><br /></div><div>また、自動テストをまわすとしても時間がかかります。たくさんのフレームをデコードするためにはプロセッサなどの性能を使用するほか、ビデオ内の時間を指定してビデオをシークするとしても、ファイルの先頭から可変長のフレームデータをパースしフレーム数を数えなければいけないこともあり、時間がかかるのです。</div><div><br /></div><div><div>この問題を解決するためには、以下のような方針でビデオを管理します。</div><div><ul style="text-align: left;"><li>目的の画像がわかっていて、確実に取得する方法がある場合には、そのシーンを再現して、そのシーンだけ録画する。</li><li>撮りっぱなしは1時間程度〜長くても数時間程度にとどめる。長くなりすぎた撮りっぱなしビデオは、ある程度の長さ(2-3時間程度)に分割してから扱う</li><li>最終的には目的のシーンを切り出して、内容が明確にわかるファイル名などを付与して扱う</li><li>必要なレベルのフレームレートに落とす(ファイルサイズ削減、画質向上が期待できる)</li></ul><div><br /></div><div><b>動画ファイルから目的の部分を切り出す</b></div><div><br /></div><div>動画ファイルからの切り出しには FFMPEG を使用する場合、 ffmpeg -i 入力ファイル名 -ss 開始時間 -t 秒数 -c:a copy -c:v copy 出力ファイル名 などを使用します。開始時間が 38分22秒であれば、その時刻は bash 等のシェル上で $((38*60)+22) などとして秒数に変換ができることも憶えておくと便利です。</div></div><div><br /></div><div>GUIで編集しやすいソフトウェアとして VidCutter があります。このソフトウェアは動画ファイル内にある圧縮済みの動画データを再エンコードしないため画質が劣化せず、高速にシーンを切り出せるため、とても便利です。</div><div><br /></div></div><p></p><p><b>自分の目を活用する:画像タイルの中から違うものを探すのが得意</b></p><p>以下の画像を見て、分類に間違いがあるものを見つけてみてください。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjuybP5bOjQrMgQ7TEV9dD7mlEVbucapI6FeWa6WXvh1ng767Lb5muGRnkqEJmdVvMrIZzP3jm5ulELdjribzNXQykKQlp-IlylIUEFfo8YPX6ii9U8fbp2i5rZe7mruyShIbPCyfHXL8YrWcDw0zCYdEg9AaTAOoTmslOI34r8qkEi_mIit_NzuiV9" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="648" data-original-width="870" height="297" src="https://blogger.googleusercontent.com/img/a/AVvXsEjuybP5bOjQrMgQ7TEV9dD7mlEVbucapI6FeWa6WXvh1ng767Lb5muGRnkqEJmdVvMrIZzP3jm5ulELdjribzNXQykKQlp-IlylIUEFfo8YPX6ii9U8fbp2i5rZe7mruyShIbPCyfHXL8YrWcDw0zCYdEg9AaTAOoTmslOI34r8qkEi_mIit_NzuiV9=w400-h297" width="400" /></a></div><div><br /></div>どうでしょうでしょうか?不規則なものにすぐ気づけると思います。<p></p><p>画像をこのように並べて表示するにはどうしたらいいでしょうか? 分類済の画像ファイルがある場合、 IMG タグ(だけ)を並べたHTMLファイルを準備するだけでよいですから、最小限でよければシェル上でワンライナーとして書くこともできます。<br /><br /></p><p><b>多数のデータを扱う場合は、ほどほどの個数にわけて扱う</b></p><p>初代スプラトゥーン向けの IkaLog では、ブキ画像の分類問題の機械学習やその精度検証用としておよそ300万サンプルのブキ画像(PNGファイル)を用意していました。便利なデータ管理ツールなどを使っているわけではありません。このようなデータはいくつかのサブグループに分けて扱うほうが簡単です。</p><p>スプラトゥーンの場合およそ100のブキが存在し、それらのブキのクラス分類をするために機械学習を利用しました。1クラスあたり3万サンプルと思えばデータセットは少し小さくなってくるのですが、作業には手間がかかります。</p><p>データセットが大きいと「目 grep 」時に見落としたり、注目したデータを見つけたり加工したりするにも時間がかかります。一方、扱いやすい規模よりも小さなデータセットに細かく分割してしまうと、手間が増えるため効率が悪くなります。</p><p><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjITv6twSAikYMGDTmFLRk_RHmJ3tvZs4vYf7GYRH_8eyEyP_FiivZgHgdxLtTfJL0OR-RhYkMrAQfSk9HoPsfatkayFtE1ooWzr_beQN1VcDWS8ZLyub-sO2SvZONFn_lqNDPVduyo6YQgSC-VGN-hwk-qP0X4iq8f6JU_KesX24177r2Mfr1bx59C" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="1012" data-original-width="920" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjITv6twSAikYMGDTmFLRk_RHmJ3tvZs4vYf7GYRH_8eyEyP_FiivZgHgdxLtTfJL0OR-RhYkMrAQfSk9HoPsfatkayFtE1ooWzr_beQN1VcDWS8ZLyub-sO2SvZONFn_lqNDPVduyo6YQgSC-VGN-hwk-qP0X4iq8f6JU_KesX24177r2Mfr1bx59C" width="218" /></a></p><p>経験上、先に示したようなブキ画像を扱う場合などでは、データセットを 5,000 ~ 10,000 程度ごとにグループ化すると扱いやすいです。この規模は、アイコンサイズの画像であれば、横 25カラムであれば縦200行〜400行程度。この規模であれば、先のIMGタグによるタイル表示や Finder / Explorer などを用いて目視で確認する場合も、ざっと確認したいだけなら10秒〜20秒で見渡すことができる分量です。</p><p>たとえば IMG タグを多数並べたファイルを作成した HTML ファイルを閲覧して誤分類された画像ファイルが 5つほど目に留まり、それを Finder などで除外したい場合を想像してみてください。30,000のファイルから5つに注目するより、5,000のファイルから5つに注目するほうが簡単で、素早く対応できます。</p><p><br /></p><p><b>”不労所得”を得る:自分が努力しなくてもソースが集まるような工夫</b></p><p>大量のデータを用いて機械学習やそのテストをしたい場合、もしくは目的達成のために大量のデータを集めたい場合、自分自身でそのデータを集めてまわるのは非効率です。</p><p>IkaLog の場合は開発当初から常用してくれるユーザという資産、また stat.ink との連携ができたので、ここからリザルト画面などの画像データを得ることができました。自分ひとりがゲームをプレイして1日10ゲーム程度だとして、 stat.ink には毎日のように数千ゲームのスクリーンショットが投稿されていました。また、その中には録画状況が不適切なものなどが混じっているなど、実際のワークロードとしてどれぐらいの分散(variance)があるのかという情報も含まれています。一通りの開発が終わった後は、この基盤があることによりブキ判定の強化を素早く進めることができました。</p><p>2022年になって、スプラトゥーン2向けに幾らかエンジニアリングしなおしていますが、ここでは YouTube に投稿された有名配信者の生配信ビデオを多く使用しています。スプラトゥーン向けのIkaLogを開発していた際もほかの方のプレイ動画を利用できないか検討しましたが、当時の動画配信サービス上のビデオは開発にあたり必要としている画質を満たすものが少なく、難しく感じました。現在は、開発に利用できるほど良好な画質のものが多く投稿されています。</p><p>使えそうな動画があれば、コマンドラインで利用できるダウンローダを用いてそのアーカイブを取得するためにコマンドラインで一行入力すればよく、数時間分のビデオが十分ほどで入手できたりします。ある程度の精度で目的のシーンを検出できるようになっていれば、大量のビデオに対してバッチ実行しておけば目的のシーンを自動的に探し出せますし、機械学習用のデータを自動的に集められることになります。</p><p></p><p>ただし、特定のチャンネルの動画のみを利用すると、エンコードされた動画の画質が偏る、たとえばそのプレイヤーが色覚サポートモードを有効にしている場合ゲーム内のインク色が特定2色に偏る(実ワークロードに対して偏ったデータが集まる)といったこともあります。画質については手元でビットレートを変更して再エンコードし種を増やすことが可能ですが、データセットに含まれるインク色が偏る問題は、そういった偏りがないチャンネルを選んだり、(色覚サポートを使うユーザばかりにならないよう)複数のチャンネルをデータセットに加えるといった対策が必要です。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEglhQZW30_yf7_uo4G65nz6lk0ZGnM7U-Em8Cyzu9ihneFKVcgSZMoojRHvcVBw6rs4fMcwALsuIcGA6Pe2tYf8hWnpe-H-Ld6W45ISnTFHMnoTU_vQXpdiKDqGNJ03ynC_j5yX1KTbKDut-UBFRzqhsmby2HFcKnA5u9XMtbU1BhEcpLmjLe0GARnb" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="608" data-original-width="1834" height="133" src="https://blogger.googleusercontent.com/img/a/AVvXsEglhQZW30_yf7_uo4G65nz6lk0ZGnM7U-Em8Cyzu9ihneFKVcgSZMoojRHvcVBw6rs4fMcwALsuIcGA6Pe2tYf8hWnpe-H-Ld6W45ISnTFHMnoTU_vQXpdiKDqGNJ03ynC_j5yX1KTbKDut-UBFRzqhsmby2HFcKnA5u9XMtbU1BhEcpLmjLe0GARnb=w400-h133" width="400" /></a></div><br /><br /><p></p><p><br /></p>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-82949913596627126052022-01-01T16:40:00.002+09:002022-01-01T16:45:59.539+09:00OpenCVでサイゼリヤの「超難解 大人の間違い探し」を台無しにする<div class="separator" style="clear: both; text-align: center;"><br /></div><br /><p> あけましておめでとうございます。</p>
<blockquote class="twitter-tweet"><p dir="ltr" lang="ja">久々にサイゼリヤで外食したら「超難解 大人の間違い探し」があったので、解いてみました。おやすみ <a href="https://t.co/neRyrUjsBp">pic.twitter.com/neRyrUjsBp</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1467573188511301632?ref_src=twsrc%5Etfw">December 5, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
<p><br /></p><p>先日、久々にサイゼリヤで外食をした際、レジにて間違い探しを配っているのに気づきました。自分がこれを手にした瞬間に頭のなかで間違いを見つけるプログラムができたのですが、数日後の深夜に実際にコードに落として、動くものができました。</p><p>今回は、どのようにしてこの出力を得たかについて、具体的なコード例とあわせて紹介します。</p><p><br /></p><p><b>基本的な考え方</b></p><p>サイゼリヤの間違い探しは、左右反転した状態で絵の違いを見つけるものです。今回はAKAZE特徴量を用いてふたつの画像を重ね合わせた上で、差異部分に色をつけてマークしていくことにします。</p><p><br /></p><p><b>入力画像を用意する</b></p><p>今回サイゼリヤで入手した間違い探しはA4サイズのコピー用紙に印刷されたものです(配達のときに同梱したりしているようですね)。後でAKAZE特徴量のアルゴリズムで取り扱うため、きちんと平面がでた状態でスキャンします。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7IiO2j5p3m0lZg7GODdzZBjfoVI3BiHMHlbJR0aNVdf0z41vakkj6ebQxDdJcSrGnwSM96n5eWUbVSerRH52WcC1Oq23V6LojHZmcerex1qP-y-QXtE1bZQkM6n-g51NBRqXjYY5lX2Y/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1440" data-original-width="1920" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7IiO2j5p3m0lZg7GODdzZBjfoVI3BiHMHlbJR0aNVdf0z41vakkj6ebQxDdJcSrGnwSM96n5eWUbVSerRH52WcC1Oq23V6LojHZmcerex1qP-y-QXtE1bZQkM6n-g51NBRqXjYY5lX2Y/w400-h300/FF3d5PVUcAko3um.jpeg" width="400" /></a></div><br /><br /><p></p><p>今回は手元にあったドキュメントスキャナ(Canon ImageFormla DR-C125)を使いましたが、きちんと平らにできれば、携帯電話のカメラを使ったりしてもいいですし、コンビニのコピー機で適当な形式で保存してきても構いません。</p><p>また、ソースの特性を考慮し、可能な限り、白・黒に二値化します。必須ではないのですが、これをしておくことで後の処理がしやすくなるでしょう。二値化はPhotoshop, GIMPなどの画像編集ツールやドキュメントスキャナのスキャン時設定にて行えるでしょう。</p><p>入力画像を2ファイルに分割する</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8FtVYSf4CoDdQDEl1HhbIfPyKL986SspGXvV6C0cg0GIQmxCohRXeZKncdyD5aITlw0FwzAqfazuws4jST1iZsNv_BSNNi1599aIpV8ZXRxRpru83Z7vE8dkviSOA_S4ECTCsbyjhNrs/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="776" data-original-width="1378" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8FtVYSf4CoDdQDEl1HhbIfPyKL986SspGXvV6C0cg0GIQmxCohRXeZKncdyD5aITlw0FwzAqfazuws4jST1iZsNv_BSNNi1599aIpV8ZXRxRpru83Z7vE8dkviSOA_S4ECTCsbyjhNrs/" width="320" /></a></div><br /><div style="text-align: left;"><br /></div></div>img1.jpg, img2.jpg として対象の画像を保存します。今回は macOS 標準のスクリーンショット機能を用いて、とても雑にファイルを生成しました。後でAKAZE特徴量を用いて重ね合わせるつもりですので、ここで傾きや大きさ、ピクセルのシフト量など、正確さを求める必要はありません。今回は JPEGを使用しましたが、 OpenCV が対応する形式であれば PNG などでも構いません。<p></p><p><br /></p><p><b>作業環境</b></p><p>今回は Juypter Notebook 上で、 Python 3.8 の環境に OpenCV 4.x をインストールし作業していきます。 OpenCV は下記操作でインストールするとよいでしょう。 opencv-contrib-python パッケージをインストールすることで、のちに使う AKAZE 特徴量などのアルゴリズムもすぐ使える状態になっています。</p><pre>!pip install opencv-contrib-python</pre><pre><span style="font-family: Times; white-space: normal;"><b>画像の読み込み</b></span></pre><pre><span style="font-family: Times;"><span style="white-space: normal;">cv2.imread() で画像を読み取って ndarray にします。元画像は原則モノクロですし、面倒を減らすため、読み込み時に1チャンネルのグレースケール画像としておきました。このほうが後での画像のマッチングや比較も簡単です。</span></span></pre><pre>import cv2<br />import numpy as np<br />from math import sqrt</pre><pre>img1 = cv2.imread("saizeriya_akaze/img1.jpg", cv2.IMREAD_GRAYSCALE)<br />img2 = cv2.imread("saizeriya_akaze/img2.jpg", cv2.IMREAD_GRAYSCALE)</pre>
<p>img1 と img2 は左右反転していますので、 img2 を左右反転させておきます。</p><pre>img2 = cv2.flip(img2, 1)</pre><pre><b>2枚の画像を重ね合わせる</b></pre>
<p>AKAZE特徴量を使って画像をマッチングします。</p>
<pre>akaze = cv2.AKAZE_create()<br />kpts1, desc1 = akaze.detectAndCompute(img1, None)<br />kpts2, desc2 = akaze.detectAndCompute(img2, None)<br />matcher = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING)</pre>
<pre>nn_matches = matcher.knnMatch(desc1, desc2, 2)<br />matched1 = []<br />matched2 = []<br />nn_match_ratio = 0.8 # Nearest neighbor matching ratio</pre><pre>for m, n in nn_matches:<br /> if m.distance < nn_match_ratio * n.distance:<br /> matched1.append(kpts1[m.queryIdx])<br /> matched2.append(kpts2[m.trainIdx])</pre><pre>inliers1 = []<br />inliers2 = []<br />good_matches = []<br />inlier_threshold = 1000 # Distance threshold to identify inliers with homography check<br />for i, m in enumerate(matched1):<br /> col = np.ones((3,1), dtype=np.float64)<br /> col[0:2,0] = m.pt<br /> dist = sqrt(pow(col[0,0] - matched2[i].pt[0], 2) +\<br /> pow(col[1,0] - matched2[i].pt[1], 2))<br /> if dist < inlier_threshold:<br /> good_matches.append(cv2.DMatch(len(inliers1), len(inliers2), 0))<br /> inliers1.append(matched1[i])<br /> inliers2.append(matched2[i])</pre><p>これで img1 と img2(左右反転) 画像の特徴を対応が得られます。これを画像として出力してみます。</p><pre>res = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)<br />cv2.drawMatches(img1, inliers1, img2, inliers2, good_matches, res)<br />cv2.imwrite("saizeriya_akaze/result.png", res)</pre><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWiD5-Nl7KGdWdyfuDTMLxAJcj46W_UCtUNOnzzcvQR0UHYuTGuk5_rgyLlZ2PJ8d-rCAEFwAAVKiLkSM2ZKhX09DkEhgrpoSup2kRsl5L6kO1Nt_Tm8RSXereUk9KqfzwipSAhnKOOfg/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="594" data-original-width="630" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWiD5-Nl7KGdWdyfuDTMLxAJcj46W_UCtUNOnzzcvQR0UHYuTGuk5_rgyLlZ2PJ8d-rCAEFwAAVKiLkSM2ZKhX09DkEhgrpoSup2kRsl5L6kO1Nt_Tm8RSXereUk9KqfzwipSAhnKOOfg/" width="255" /></a></div><br /><br />コピー&ペーストでソースコードをいじった時に少しおかしくなったように見えるけど、実用上問題なさそうなのでヨシ。<div><br /></div><div>もちろん、間違い探しという特性上、画像が意図的に異なるので、マッチしない特徴もあるわけですが、十分な数の特徴量がマッチすれば、やりたい事に対して問題はありません。<div><p></p><div>この特徴量をもとに2枚の映像を重ね合わせます。 img1 の位置を基準とし、 img2 が img1 に重なるようにワープフィルタをかけた img3 を得ます。この処理は IkaLog というプログラムから一部を持ってきました。そのため画像名にキャリブレーションイメージ、キャプチャイメージという名前が付いていますが、そのまま利用しています。<pre>Acalibration_image_gray = img1
capture_image_gray = img2
matcher = cv2.BFMatcher(cv2.NORM_HAMMING)
capture_image_keypoints, capture_image_descriptors = \
akaze.detectAndCompute(capture_image_gray, None)</pre><pre>calibration_image_keypoints, calibration_image_descriptors = \
akaze.detectAndCompute(calibration_image_gray, None)
print('caputure_image - %d features' % (len(capture_image_keypoints)))
print('matching...')
def filter_matches(kp1, kp2, matches, ratio=0.75):
mkp1, mkp2 = [], []
for m in matches:
if len(m) == 2 and m[0].distance < m[1].distance * ratio:
m = m[0]
mkp1.append(kp1[m.queryIdx])
mkp2.append(kp2[m.trainIdx])
p1 = np.float32([kp.pt for kp in mkp1])
p2 = np.float32([kp.pt for kp in mkp2])
kp_pairs = zip(mkp1, mkp2)
return p1, p2, kp_pairs</pre><pre>raw_matches = matcher.knnMatch(
calibration_image_descriptors,
trainDescriptors=capture_image_descriptors,
k=2)
p1, p2, kp_pairs = filter_matches(
calibration_image_keypoints,
capture_image_keypoints,
raw_matches,)
if len(p1) >= 4:
H, status = cv2.findHomography(p1, p2, cv2.RANSAC, 5.0)
print('%d / %d inliers/matched' % (np.sum(status), len(status)))
else:
H, status = None, None
print('%d matches found, not enough for homography estimation' % len(p1))
raise Exception()
assert H is not None
if len(status) < 1000:
raise WarpCalibrationNotFound()
calibration_image_height, calibration_image_width = img1.shape
corners = np.float32(
[[0, 0],
[calibration_image_width, 0],
[calibration_image_width, calibration_image_height],
[0, calibration_image_height]])
pts1 = np.float32(cv2.perspectiveTransform(
corners.reshape(1, -1, 2), H).reshape(-1, 2) + (0, 0))
pts2 = np.float32([
[0, 0],
[calibration_image_width, 0],
[calibration_image_width, calibration_image_height],
[0, calibration_image_height]])
print('pts1: %s' % [pts1])
print('pts2: %s' % [pts2])
M = cv2.getPerspectiveTransform(pts1, pts2)
img3 = cv2.warpPerspective(img2, M, (calibration_image_width, calibration_image_height))</pre></div><div>これにより img1 とできるだけマッチするようワープフィルタを適用した img3 が得られました。</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzzLpUKiSmruCeA46hwdfE_rSrJm5nL4B_iRLtr-c-Cjbz1QQNS49aoLDWbfD9sSwIZY-yjDXiKUPYquPQpOjxHjUUxbYae9jzL95Z3BoNbmpq1jCJCoGfcc42c4ncSB3StSbZUkcLHtE/" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="736" data-original-width="2058" height="143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzzLpUKiSmruCeA46hwdfE_rSrJm5nL4B_iRLtr-c-Cjbz1QQNS49aoLDWbfD9sSwIZY-yjDXiKUPYquPQpOjxHjUUxbYae9jzL95Z3BoNbmpq1jCJCoGfcc42c4ncSB3StSbZUkcLHtE/w400-h143/Screen+Shot+2022-01-01+at+16.01.01.jpg" width="400" /></a></div><div></div><div><br /></div><div>img1 と img2 の縦横ピクセル数は一致していないのですが、 img1 にあわせてワープフィルタをかけた img3 は img1 と同じピクセル数になっているので、このことを確認しておきます。</div><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6OerBMAnvzDt24j3rsXY0UerFIOVsP89NpVbWdbxMl3FBnT2k9nL4MmY94s0zkqOa3ueY3K8_C0gvjybNXTH03_lnpA2O5nSXp7To5eIKbS4G_KZVIl87tVk9rRD2MEJ4qJRjAiave7A/" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="662" data-original-width="1812" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6OerBMAnvzDt24j3rsXY0UerFIOVsP89NpVbWdbxMl3FBnT2k9nL4MmY94s0zkqOa3ueY3K8_C0gvjybNXTH03_lnpA2O5nSXp7To5eIKbS4G_KZVIl87tVk9rRD2MEJ4qJRjAiave7A/w400-h146/Screen+Shot+2022-01-01+at+15.27.03.jpg" width="400" /></a></p><p>こんな面倒なことをしなくても、他のツールを使ってあらかじめ重ね合わせておくことも可能です。ただ、この重ね合わせ処理含めて実装したので、サイゼリヤの間違い探しの新しいバージョンが出ても、入力画像を差し替える以上の労力をかける必要はなくなりました。</p><p><br /></p><p><b>画像の差分をとる</b></p><p>img1 と img3 の差の絶対値をとります。これにより1プレーン8ビット(256色調)色調の画像に対して、差がなければ0、差があれば255の値が得られます。なお img1 および img3 は符号なし8ビット整数の1プレーン モノクロ画像ですが、差を取るにあたり -255 ~ 255 までの範囲をとりうるため、 符号付き32ビット整数として扱っています。絶対値をとった時点では 0~255 に収まっているため、 img_abs は 0~255 の符号付き32ビット整数です。</p><pre>img_abs = abs(img1.astype(np.int32) - img3.astype(np.int32))</pre><p>img_abs の内容をモノクロ画像として出力した例を参考までに掲載しておきます。 img1, img2 で差があった部分が白く浮き上がっていることがわかるでしょう。</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjScNdeYq1psEZ_QynCRq-7zNl_bTg6hi2bN26FKsYFfZkRhawp6tptc8Pb8tcjhsR9JaVtVhegIuT8uZo1_rSB6FZ0mDq-pp6VHKEe9lNGYXa3I2cU-uC1PXYx2aGgXoXp7cCOVTWYwOw/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1682" data-original-width="1674" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjScNdeYq1psEZ_QynCRq-7zNl_bTg6hi2bN26FKsYFfZkRhawp6tptc8Pb8tcjhsR9JaVtVhegIuT8uZo1_rSB6FZ0mDq-pp6VHKEe9lNGYXa3I2cU-uC1PXYx2aGgXoXp7cCOVTWYwOw/w398-h400/img_abs.png" width="398" /></a></div><br /><p><br /></p><p><b>差分強調画像を作成し出力する</b></p><p>最終結果を出力します。ここではimg1を基として答えの画像を作成します。この画像は HSV フォーマットとして扱うことにします。HSVとは Hue(色相), Saturation(彩度)、明るさ(Brightness) の3要素で色を表現します。モノクロ画像をHSV色空間に変換していますので、S=0、V=0~255, Hについては未定義(結果としてゼロが入っているが)という状態になります。</p><pre>img_bgr = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)<br />img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)</pre><p>このうち彩度のプレーンを、先ほど得た img1 と img3 の絶対値 img_abs で置き換えます。差のある部分はほぼ 0 、差がある部分だけ彩度があがるため、結果として img1 の画像に対して、 img1 と img3 の差がある部分には何らかの色が付きます。どのような色がつくかは色相チャンネルによりますが、今回 cv2.cvtColor() はこのチャンネルを0で初期化していますので、これに対応して赤色になります。</p><p>img_hsv[:, :, 1] = img_abs</p><p>生成した画像を cv2.imwrite() で画像ファイルに落とします。 cv2.imwrite() は BGR フォーマットのカラー画像をとりますのでHSV色空間からBGR色空間へ変換も行います。</p><pre>cv2.imwrite("saizeriya_akaze/result.png", cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR))</pre><div class="separator" style="clear: both; text-align: center;"><br /></div><b>出力結果</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXlrfy3L80IFCRSEe-hMCK1mWHrmf1E4ZxKdmUeyVgbZDj8GHJ-kBGbHCQZg_XMLAiNMaK94b6juV-4HhPARtwfJrd2RaaDkxFl5Tto0ze6Op6DS2J3K6MpRJK7MnCdIwkwdjCrx09Cx0/" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="1682" data-original-width="1674" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXlrfy3L80IFCRSEe-hMCK1mWHrmf1E4ZxKdmUeyVgbZDj8GHJ-kBGbHCQZg_XMLAiNMaK94b6juV-4HhPARtwfJrd2RaaDkxFl5Tto0ze6Op6DS2J3K6MpRJK7MnCdIwkwdjCrx09Cx0/w398-h400/result.png" width="398" /></a></div><div><br />今年もよろしく御願いします。</div><div><br /><p></p><p><br /></p></div></div>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-22395963915162538232021-12-30T00:29:00.014+09:002021-12-31T14:36:46.689+09:00日本語訳:Apex Legends のALGSマッチを機械学習で解析した件 Using Machine Learning, I analyzed 2.3TB of competitive apex to track everything<p>This is a translation of Reddit post <a href="https://www.reddit.com/r/CompetitiveApex/comments/rm00xv/series_1_using_machine_learning_i_analyzed_23tb/" rel="nofollow" target="_blank">Using Machine Learning, I analyzed 2.3TB of competitive apex to track everything</a> into Japanese.</p><p><a href="https://www.reddit.com/r/CompetitiveApex/comments/rm00xv/series_1_using_machine_learning_i_analyzed_23tb/" rel="nofollow" target="_blank">Apex Legends のゲームプレイについて機械学習を用いて分析した結果</a>が Reddit に投稿されており話題になっていました。興味深い内容なので、翻訳サービスなどを用いて読んでいる日本の方も多いと思います。しかし、機械翻訳では判りづらい点もありますので、適当に日本語に翻訳したものを置いておきます。</p><p>英語にはあまり自信がなく、誤訳などもあるかもしれませんが、お気づきの点がありましたら @hasegaw までお知らせいただけますと幸いです。</p><p><b>予備知識</b></p><p>この投稿者は統計について研究されている大学院生で、 Apex Legends の ALGS 3大会のビデオから得られた情報をコンピュータに入力したり、もしくは関連するゲーム配信をコンピュータビジョンのアプローチから分析し、下記の内容の論文を書きました。</p><p>今回、コンピュータを用いてたくさんのデータを集計し、そこから規則性などを見いだす方法として機械学習(Machine Learning)と呼ばれるものが使われました。これは、最近AI(人工知能)として話題になっている技術のひとつです。</p><p>~~~</p><p>私は、以下の7つ問いについて分析した。</p><p></p><ul style="text-align: left;"><li>ジブラルタルは再現性が高く、そしてゲームを壊すほどに強力なのか?</li><li>コントローラ(Pad)プレイヤーは、本当に短距離の交戦を支配しているのか?エイムアシストは効きすぎているのか?</li><li>リコイルチートを使用するプロプレイヤーは存在するのか?</li><li>最適な交戦時間は?</li><li>最適な安置移動(Rotation)ははどれぐらいの速度か?</li><li>最適なバックパックの構成は?</li><li>イロ(ELO)レーティングが最も高いプレイヤーは誰か。また、その理由は?</li></ul><p></p><p><br /></p><p><b>■概要</b></p><p>Kirk Matrix は、サッカーのランキングアルゴリズム Colley Matrix を基にカスタマイズしたものである。また、グループ競技における個人のレーティングのために、 Bradley-Terry ニューラルネットワークモデルを用いた。この方法は、シンプルな統計的原理と変数に基づき、柔軟で、バイアスがないようにしたものである。</p><p><br /></p><p><b>■</b><b>わかったこと</b></p><p><b>ジブラルタル</b></p><p>ジブラルタルは時間あたりのダメージ量が(他のレジェンドより)低く、個人としての撃ち合いによる勝率が低く、受けるダメージ量も大きく、またキルタイム(TTK)が最も短い(訳者注:相手を落とす時間が短いという意味だと思います)。</p><p>ジブラルタルは、独立した(他部隊の介入がない)3v3 の交戦において、もっとも死亡しやすい。これは、次点のブラッドハウンドよりも 23.1% 高い確率であった。ジブラルタルは最もフォーカスされやすいキャラクタである。</p><p>ドームファイトによる交戦勝率は 50%-50% で、他のチームより特に優れているチームは存在しなかった。ドームファイトは平均48秒で、6人あたり4人がノックされる。</p><p><i>(訳者注釈)ここで言っているのは、接敵でジブラルタルが戦闘でフォーカスされやすく、落ちやすく、1プレイヤーとしての成績が低くなりやすいと統計的データに基づいて説明しているのであって、決して「チームとしての勝率が低い」という話ではありません。</i></p><p>他レジェンドとの入れ替わりもあるが、ジブラルタルのキャラクターとしてのELOは最下位であり、実証データもこれを裏付けている。</p><p><br /></p><p><b>エイムアシスト</b></p><p>ALGSにおいては長距離交戦が非常に少なく、中距離交戦とまとめて扱う必要があった。</p><p style="text-align: left;"></p><ol style="text-align: left;"><li>ドームファイトの交戦勝率: KB/Mouse 54% : 46% Pad</li><li>短距離の交戦勝率: KB/Mouse 52% : 48% Pad</li><li>中・長距離の交戦勝率: KB/Mouse 51% : 49% Pad</li><li>ワンクリップシーンでの勝率 KB/Mouse 38% : 62% Pad</li><li>KB/Mouse の ADS 振り向き速度の優位性により、混沌としたドームファイトを制することを可能としている。</li><li>エイムアシストがあったとしても、 Pad はあらゆる距離での接敵において KB/Mouse に対して劣っているが、一方でコントローラプレイヤーは即時キル(one clip)を繰り返すこともでき、良い結果にも悪い結果にもなる。</li></ol><div>(訳者注:KB/Mouse のほうがトータルとしては優れているが、 Pad プレイヤーは下振れもすれば上振れすることも多いということになります)</div><div><br /></div><p></p><p><b>チーター</b></p><p>驚いたことに、NA/EU/APAC NorthのALGSプレイヤーにおいてリコイルチートを使用するプレイヤーはひとりも検出されなかった。私はこの結果が正しいものと信じている。</p><p><br /></p><p><b>最適な交戦時間</b></p><p>交戦時間よりも、サードパーティー(漁夫)がノックアウトを取るうえで大きな相関があると分かった。これは、間違いなく、キルフィード(キルログ)管理、サードパーティー(漁夫)されないこと、敵対チームの把握によるものである。なお、このセクションにおける知見は重大な欠陥があるため、断りなく使用するべきではない。</p><p>(※訳者注:要するに、うまく漁夫して、漁夫られないよう気をつけることが大事だとのこと)</p><p><br /></p><p><b>最適な安置移動(Rotations)速度</b></p><p>ここでも、私は明確な答えを見つけることができなかったが、興味深い発見があった。 KB/Mouse プレイヤーの移動速度は、 Pad プレイヤーの移動速度よりも平均 6% 速いのである。この違いは、ランドマークからランドマークまで(??)の移動で、壁キック2回、スライドジャンプ4回に相当するものである。 Pad プレイヤーは、これらの動きを追加することにより、(※訳者注:何に対して?)移動を約 16 秒短縮できるかもしれない。</p><p><br /></p><p><b>最適なバックパックの構成</b></p><p>残念ながら、こちらも明確な答えを見つけることができなかった。ただし、金バックパックをを持っていることが、Apex Legendsのどのアイテムよりも、勝利と強い相関があった。</p><p><br /></p><p><b>上位ELOレーティング</b></p><p>(※訳者注:ELOレーティングとは、平均的な実力のプレイヤーと接敵した場合に予想された勝率に推定したものとされる。Wikipediaによれば対数が使われるとのこと。Redditの投稿にはELOのどこのように算出したかは記述がないが、投稿の最後にあるリンクを読み解けば細かいことがわかるかもしれない)</p><ol class="_1eJr7K139jnMstd4HajqYP" style="background-color: white; border: 0px; color: #1a1a1b; font-family: "Noto Sans", Arial, sans-serif; font-size: 14px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; list-style-image: initial; list-style-position: outside; margin: 4px 0px 4px 8px; padding: 0px; vertical-align: baseline;"><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Ras .9987</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Senoxe .9363</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Lou .9246</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Dezignful .9244</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Mo-Mon .8331</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Sweet .8075</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Genburten .8009</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Hardecki .7977</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Dooplex .7865</p></li><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Ojrein .78647</p></li></ol><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="background-color: white; border: 0px; color: #1a1a1b; font-family: "Noto Sans", Arial, sans-serif; font-size: 14px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin: 0px; padding: 0.8em 0px 0.25em; vertical-align: baseline;">ImperialHalはわずか .00002 の差で次点。</p><ol class="_1eJr7K139jnMstd4HajqYP" style="background-color: white; border: 0px; color: #1a1a1b; font-family: "Noto Sans", Arial, sans-serif; font-size: 14px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; list-style-image: initial; list-style-position: outside; margin: 4px 0px 4px 8px; padding: 0px; vertical-align: baseline;"><li class="_3gqTEjt4x9UIIpWiro7YXz" style="border: 0px; font: inherit; margin: 0.4em 1em; padding: 0px; vertical-align: baseline;"><p class="_1qeIAgB0cPwnLhDF9XSiJM" style="border: 0px; font: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">Hal .78645</p></li></ol><p>利用したモデルはRasによって破綻されられるほどで、RasはELO算出に用いられた12の変数のうち11つが並め〜低いのだが、接敵時の移動速度については例外だ。接近戦やドームファイトにおいて、他の ALGS プレイヤーと比較して、Ras はわずか3分の1のダメージしか受けない。</p><p>現在のところ、Rasと他の競技者との差は、おもに彼の移動テクニック(※キャラコン)によるものである。他のプレイヤーが同等のテクニックを極めた場合、この差は大きく縮まるかもしれない。</p><p><br /></p><p>私の経歴について:統計学の学士号、修士号を所得。本内容の論文を提出しており、通過し次第(2~3日)、本分析のグラフやデータを公開できるようになる見込みです。</p><p>使用したツールについて:すべてのツールはパブリックに利用可能なものですが、フォークされ、私の特定のニーズに合わせてカスタマイズされています。</p><p>〜〜〜</p><p>「所詮AIの判断だろ」といった意見もありますが、これは機械学習アルゴリズムを用いてALGSの成績を定量的に分析した結果なので、ALGSという限られたマッチ本数での分析によりバイアスはかかっているのでしょうが、ここに書かれた分析の範囲では、だいたい正しいことだろうなと思っています。</p><p>私は以前 IkaLog という<a href="https://www.slideshare.net/TakeshiHasegawa1/ikalog20161125nsstudy" rel="nofollow" target="_blank">スプラトゥーンのビデオから自動的に戦績を解析・出力するソフト</a>を作成し、これを <a href="https://stat.ink">stat.ink</a> というサイトがとりまとめ、蓄積されたデータを基に分析する方もいらっしゃったのを思い出しました。ゲームとはいえ、データを分析して考察するのはとても面白いですね。 Apex Legends に限らず、色々なゲームで、一般プレイヤーのプレイも含めて、このような分析ができると、いろいろと面白いのでしょうが。</p><p><br /></p><p>おまけ:過去に投稿して話題になったツイートのスレッド。ネットゲームのチート対策は攻撃者のほうが有利で、対策は色々と難しいところもあるということを感じてもらえればと思います(もちろん、マッチしてしまうプレイヤーとしてはたまったものじゃないですが)。</p>
<blockquote class="twitter-tweet"><p dir="ltr" lang="ja">普通に調べごとしてたら偶然 Apex Legends のチートの実装にたどり付いたんだけど、特定バイト列探して目的データを見つけるのは古典的な方法として、UEFIにプログラムロードしてるのね……。OSからも見えないところで下でチートツール動いてるやん。これにまともに対処しろってのが無理だわ……。</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1376711711932092417?ref_src=twsrc%5Etfw">March 30, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-51745704621469492632021-11-03T03:34:00.002+09:002021-12-30T00:23:25.795+09:00 Radeon RX 6800 XT の OpenCL を有効化する (スクリプト化編)<p><a href="https://d.ballade.jp/2021/04/radeon-rx-6800-xt-opencl.html">Radeon RX 6800 XT の OpenCL を有効化する</a> に記述したレジストリ操作について、毎回手作業で実施することが面倒なため Python スクリプトに起こした。</p><p></p><pre>#! python
import os
import winreg
base_path = r"C:\Windows\System32\DriverStore\FileRepository"
def detect_amdocl():
amdocl_list = []
for curDir, dirs, files in os.walk(base_path):
for file in files:
if not file.lower() == "amdocl64.dll":
continue
amdocl_fullpath = os.path.join(curDir, file)
amdocl_timestamp = os.stat(amdocl_fullpath).st_mtime
amdocl_list.append({'path': amdocl_fullpath, 'ts': amdocl_timestamp})
if len(amdocl_list) == 0:
return None
amdocl_list = sorted(amdocl_list, key=lambda e:e['ts'])
return amdocl_list[-1]['path']
def remove_old_values(regkey, latest_amdocl=None):
i = 0
while True:
value_name = None
try:
value_name = winreg.EnumValue(regkey, i)[0]
i += 1
except OSError:
# Will be here when the enumeration is done.
break
if not value_name.lower().endswith("amdocl64.dll"):
continue
if latest_amdocl:
if value_name.lower() == latest_amdocl.lower():
print("latest value: %s" % value_name)
continue
print("delete value: %s" % value_name)
try:
winreg.DeleteValue(regkey, value_name)
except Exception as e:
print(e)
if __name__ == "__main__":
amdocl_path = detect_amdocl()
if not amdocl_path:
raise Exception("Could not determine path of amdocl64.dll")
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE, )
regkey = winreg.OpenKey(reg, r"SOFTWARE\Khronos\OpenCL\Vendors",
0, winreg.KEY_ALL_ACCESS)
# Delete old values.
remove_old_values(regkey, amdocl_path)
# Add a new key.
winreg.SetValueEx(regkey, amdocl_path, 0, winreg.REG_DWORD, 0x00000000)
winreg.CloseKey(reg)
print("done")
</pre><p></p><p>PowerShell での実装がより理想的かもしれないが。今度 cxFreeze による EXE バイナリ化などを試してみようと思う。</p><p><br /></p>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-71312386734610692532021-05-28T07:45:00.020+09:002021-06-20T10:53:38.247+09:00A Puzzle A Day のソルバーを書いてみた(6/20更新)<h3 style="text-align: left;">更新内容</h3><div>6/20 ... C言語版について追記しました。</div><div><br /></div><h3 style="text-align: left;">面白そうなパズルとの出会い</h3><p>Twitter で A Puzzle A Day というカレンダーパズルを見かけた。</p><p></p>
<blockquote class="twitter-tweet"><p dir="ltr" lang="ja">明日の答えです(閲覧注意) <a href="https://t.co/jzU5CbZWDU">pic.twitter.com/jzU5CbZWDU</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1397427370089275398?ref_src=twsrc%5Etfw">May 26, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
<p></p><p><br /></p><p>このパズルは1月〜12月、1日〜31日までのセルがあり、任意の日付(たとえば5月28日だとか6月1日だとか)をパズルを通して表現できる、というもののようだ。テトリスにでてきそうなブロックを組み合わせて、目的の日付にかかわる部分以外をキレイで埋められれば完成。毎日パズルが楽しめるし、1年後に同じ日付の答えを得ようとしても改めて楽しめそうで、とても面白そうだ。</p><p>久々に「このパズルは私も欲しい!」と思った。</p><p>国内の販売店が普通に売ってるようなものだったらうっかりオーダーしていたかもしれない。どうやらノルウェーのほうでレーザープリンタを用いて作ってるような感じで、持っている人は少ないのではないか。 Twitter タイムラインをみると紙やら木材のレーザーカットやら思い思いの方法で手作りをして楽しんでいる人もいるようで、私も何か作ろうと思った。</p><p>その結果として、ソルバーができた。</p><p><a href="https://github.com/hasegaw/puzzle-a-day-solver">https://github.com/hasegaw/puzzle-a-day-solver</a></p><p><br /></p><h3 style="text-align: left;">ソルバー?</h3><p>ソルバー(Solver)というのは答えを求めるツールだ。たとえば今回のソルバーの場合、5月28日であればこうすると良い感じにブロックがはまりますよ、というのを教えてくれる。このパズルは365通りの目標があるほか、それぞれに複数の解法があるので、趣味などとしてソルバーを書いてみても楽しいだろうと思って、作ってみた。</p><p>私はコンピュータサイエンスを学んだエンジニアでも競プロ勢でもアルゴリズムに強いわけでもないので、ここで紹介するアルゴリズムについてはツッコミどころもあると思う。この記事の内容は、とりあえず趣味で簡単なプログラムを書いているだけでも、このパズルのソルバーはこれぐらいの考えで作れる内容だよ、という紹介ということでご理解いただきたい。</p><p><br /></p><h3 style="text-align: left;">ルールの確認</h3><p>このパズルのボードは下記の構造になっている。</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMERODJVY6HPS81uip8D0kdYtGRLZwX3ZFvGaQhJrFHe4fFkrfoWnE-y7kJMEa1aVCm_QWg8P_Twey8vJHsDQyQfYNJgdN_ED6HT5CsOkZ8jfugHvRVLaCQEmQ-a_oYdGEjwDWKQaCjLU/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="536" data-original-width="1718" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMERODJVY6HPS81uip8D0kdYtGRLZwX3ZFvGaQhJrFHe4fFkrfoWnE-y7kJMEa1aVCm_QWg8P_Twey8vJHsDQyQfYNJgdN_ED6HT5CsOkZ8jfugHvRVLaCQEmQ-a_oYdGEjwDWKQaCjLU/w400-h125/Screen+Shot+2021-05-28+at+6.52.50.jpg" width="400" /></a></div><br /><div style="text-align: left;"><br /></div></div><p>左が、パズルの舞台となる盤面で、ここにブロックを詰めていくことになる。黒色のセルはブロックが置けない場所で、オレンジ色のセルは、一例として5月28日を表現する場合においてブロックで隠れてはいけないセルだ。</p><p>右側に示した 8つのブロックを盤面に並べていく。各ひとつ使えるのだが、各ブロックは回転させても良いし、反転させても良いようだ。なので、ひとつのブロックでも盤面上では最大で8つの姿をとりうる。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgupIwaO8xsYCV0CrzUAAHrl75xk_gsd5FBFV3CyBv_OUCVXg0H4KfdLD3P_SzQRwJMVwhDNuNXngRTN8mt_M5GaQqtPFJNZF8L5B2SWjSsLB3C9jZiq_T5SnWFWr-6gRbY5kxxduxTvDc/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="604" data-original-width="756" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgupIwaO8xsYCV0CrzUAAHrl75xk_gsd5FBFV3CyBv_OUCVXg0H4KfdLD3P_SzQRwJMVwhDNuNXngRTN8mt_M5GaQqtPFJNZF8L5B2SWjSsLB3C9jZiq_T5SnWFWr-6gRbY5kxxduxTvDc/w400-h320/Screen+Shot+2021-05-28+at+7.55.28.jpg" width="400" /></a></div><br /><br /><p></p><p>盤面の黒色セルおよびオレンジのセルに重ならないように、これらの8つのブロックを配置できたらパズルが解けたことになる。</p><p><br /></p><h3 style="text-align: left;">基本的な考え方</h3><p>ボードサイズは7x7のマトリックスで表現できる。ここで、ブロックを置いてはいけないセルを 1 、それ以外を 0 としたマトリックスを作る。ルール上絶対にブロックが乗ってはいけない部分のみ 1 としたマトリックスの例、それに加えて目的の日付セルも 1 としたマトリックスの例を示す。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI9Sw6yXhJzsY1fFtvIakGL9FA-y6s9Rr_OyDEgDG-6rNQ68WP3uDzL_5RqgwTUYVngFcSW4AjkBtff5IKDjdKU0FDOTlayvfvN3ibMb95uK3ni8Drek_Lw8W8nYOXmW9Qp3xrmNLzWSM/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="418" data-original-width="1194" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI9Sw6yXhJzsY1fFtvIakGL9FA-y6s9Rr_OyDEgDG-6rNQ68WP3uDzL_5RqgwTUYVngFcSW4AjkBtff5IKDjdKU0FDOTlayvfvN3ibMb95uK3ni8Drek_Lw8W8nYOXmW9Qp3xrmNLzWSM/w400-h140/Screen+Shot+2021-05-28+at+6.55.37.jpg" width="400" /></a></div><br /><br /><p></p><p>ここで黒色セルと日付セルをわけて考えてもよいのだが、候補を見つけていくには、黒色セルおよび日付セルの両方がフラグされている後者のマトリックスが基点になる。</p><p>これに対して、特定のブロックを特定の回転・反転・位置の条件で配置する場合に、どのセルにあたるかを示す行列(以後、候補とよぶ)を作成する。ここではふたつの例を示す。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3bjzw_fFzc7qUYapABbNdMRY-vzZZRrx2IsMMJwph_Ga7pETybvwOnKjke08uzrDvtGWqISdCOoW51vkbcYMg7Cs4XzQ2b5zewCs4JruoY0Yezc-sEJ25D3j0E0FqLNXk4kUMZSb9qLE/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="426" data-original-width="1100" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3bjzw_fFzc7qUYapABbNdMRY-vzZZRrx2IsMMJwph_Ga7pETybvwOnKjke08uzrDvtGWqISdCOoW51vkbcYMg7Cs4XzQ2b5zewCs4JruoY0Yezc-sEJ25D3j0E0FqLNXk4kUMZSb9qLE/w400-h155/Screen+Shot+2021-05-28+at+6.57.51.jpg" width="400" /></a></div><br />候補がボードにはまるかどうかは、現状のボードの状況を示すマトリックスと候補のマトリックスを加算してみればわかる。整数値の加算結果として 1 を超えるセルが発生する場合は、ブロックと何かがぶつかってしまい、そこに当てはめられない事を意味する。(ここで、後の最適化で触れる論理積を使ってもいい)<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZE5sQyEe_JrJAx0-PX-57glbOJbGg6wriWetwDFoxJcLB0KT2JCaXuq2Rc7lSPxk_IL2F8eUhSrcJYN-WxnQ0xdipuErWoV-DL3tYFEKMCRk9YmRDgi3O5QfEEOfSFPQkwvOfPMDUMU/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="776" data-original-width="1806" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZE5sQyEe_JrJAx0-PX-57glbOJbGg6wriWetwDFoxJcLB0KT2JCaXuq2Rc7lSPxk_IL2F8eUhSrcJYN-WxnQ0xdipuErWoV-DL3tYFEKMCRk9YmRDgi3O5QfEEOfSFPQkwvOfPMDUMU/w400-h171/Screen+Shot+2021-05-28+at+6.59.27.jpg" width="400" /></a></div><br />当てはめられる候補を見つけたら、再帰的に他のブロックも当てはまる所を探していって、全てのブロックを使い切ったら解法が見つかったことになる。<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizynm_Vih0UOGWtE-lmGXlfZp4B2etIX0HNu69yrrTAKegbZKr_oyy5D263WUs-6GVCZE0WOREXvEZsYTSJ8Q5uKSShfODizRwTQw9eXqiJ8OhUvYR5QHyYyd8lOQmU-YFajaemCv6Z_Y/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="412" data-original-width="1792" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizynm_Vih0UOGWtE-lmGXlfZp4B2etIX0HNu69yrrTAKegbZKr_oyy5D263WUs-6GVCZE0WOREXvEZsYTSJ8Q5uKSShfODizRwTQw9eXqiJ8OhUvYR5QHyYyd8lOQmU-YFajaemCv6Z_Y/w400-h93/Screen+Shot+2021-05-28+at+7.01.16.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><span style="text-align: left;">実際のところ、これを適当に置いていってもブロックが素直に収まってくれる可能性はかなり低い。黒色セルとオレンジの日付セルを除いて全てのセルをブロックで埋めないと答えにたどり着かないことを利用して、マトリックスのふち側のセルから優先して埋める。これにより、隙間の発生により絶対に解法にたどり着けないことが自明な候補を探索対象から外すことができる。</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhw3ANbVAA6K2En2RnPTP23BuswkZ3r4VxJGyFZFNm2Xsq-3Oe3dNyOkJ4sESg0uLXAvqXeC4X8GUEOs6trWozROHj0y783mJJUsNaxIatBo6BzXHw9nmsBdB9NBRNxOZ4-dovx12ZHa4/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="420" data-original-width="1792" height="94" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhw3ANbVAA6K2En2RnPTP23BuswkZ3r4VxJGyFZFNm2Xsq-3Oe3dNyOkJ4sESg0uLXAvqXeC4X8GUEOs6trWozROHj0y783mJJUsNaxIatBo6BzXHw9nmsBdB9NBRNxOZ4-dovx12ZHa4/w400-h94/Screen+Shot+2021-05-28+at+7.02.19.jpg" width="400" /></a></div><br /><br /><p></p><p>私の実装では左上から右へ、行が埋まったら次の行へ、という順番でセルを埋めるようにしている。次に埋めるセルを見つけるには、ボードの最新盤面におけるゼロのセルを見つければよい。候補がそのセルを埋めてくれるかは、その候補において目的のセルが 1 になっているかを見ればよい。候補が目的セルを埋めなくても解法に繋がる可能性はあるが、後に別のセルを埋める際に改めて評価されるので、ここでは候補から除外してよい。とにかくフチから埋めて、ボード上に隙間ができない候補から試したほうがよいからだ。</p><p>これを繰り返していくと、ボード上のセルでゼロがなくなり(すべて 1 になる)、未使用ブロックもなくなっているはずだ。この方法で総当たりしていけば、解法にたどり付ける。</p><p>実装については Pyhthon + NumPy を利用した。 NumPy で上記において必要となるマトリックス演算のほとんどが実現できるほか、この後に触れるベクタライゼーションを意識した記述にすることで、さらなる高速化が期待できる。</p><p><br /></p><h3 style="text-align: left;">ベクタライゼーション (Vectorization)</h3><p>上記のアルゴリズムは、どのようなプログラムで書いてもよい。私は Python を使用したが、別に Ruby を使ってもいいし、 JavaScript/TypeScript でも、 Perl でも、 Golang でも C でも Pascal でも、 C# でも、 Java でも、 BASIC でもなんでもよい。</p><p>ただ、このような処理を愚直にループ処理で書いても、コンピュータはこれを速く処理ができない。このため、コンピュータが高速に処理できるような、まとまった行列演算にできるだけ落とし込んでいく。たとえば盤面に対して次の候補を探すためにマトリックスを加算する場合に、まとめて加算をしたほうが速い。</p><p>もちろん加算すべきは ボードの現状 × 候補の数 なので計算すべき量は一緒なのだが、 Python コードとして繰り返しを書くよりも、 NumPy などの C 言語ベースで書かれたライブラリ内でループをしたほうが速い。場合によっては、バックエンドのライブラリ内において、 CPU の SIMD 命令で計算することにより、より実行時間を短縮してくれる可能性がある。</p><p>具体的には、 10x10 のボードに対して 10x10 の候補が 10,000 あった場合、 Python レベルで10,000回加算するよりも、 10000x10x10 の候補に対して 10x10 のマトリックスを加算するほうが速く実行できる。</p><p></p><pre>#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cProfile
import numpy as np
mat1 = np.zeros((10000, 10, 10), dtype=np.uint8)
mat2 = np.zeros((10, 10), dtype=np.uint8)
mat1[:, :, :] = 3
mat2[::, :] = 3
def func1():
mat1 + mat2
def func2():
for m in mat1:
m + mat2
if __name__ == '__main__':
cProfile.run('func1()')
cProfile.run('func2()')</pre><p></p><p></p><pre>% python bench.py
4 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 bench.py:12(func1)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
4 function calls in 0.005 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.005 0.005 <string>:1(<module>)
1 0.005 0.005 0.005 0.005 bench.py:15(func2)
1 0.000 0.000 0.005 0.005 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
</module></string></module></string></pre><p></p><p>また、大抵の場合、 for ループなどを使用し最小値を探すよりも、 NumPy.argmin() などのライブラリ関数を活用したほうが速い。</p><p>このような観点でベクタライゼーションをある程度進めたところ、当初手元のコンピュータ(MacBook Pro 2019, 2.5GHz)では 600秒(10分)かかっていた探索が60秒以内で完了するようになった 。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">うっかり vectorize して、昨晩から20倍ぐらい速くなった <a href="https://t.co/Z3IJzyMgaJ">pic.twitter.com/Z3IJzyMgaJ</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1397513721769910279?ref_src=twsrc%5Etfw">May 26, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p><br /></p><h3 style="text-align: left;">バイナリ化</h3><p>ベクタライゼーションにより特定の日付向けの解法が60秒以内に得られるようになったが、もう少し速くしてみようかなと思い、内部表現をバイナリ化してみることにした。</p><p>ここまでの作業は (7, 7) の大きさのマトリックスで、各要素は 8bit の整数値として扱ってきた。しかし 7x7 というサイズで、上記アルゴリズムでは基本的に 0 と 1 のみ(衝突検出のみ 2 が登場)で成り立っているので、2進数で表現できる。これにより 7x7=49バイトで表現していた盤面や候補が8バイトで表現できるようになり、メモリ上の表現が7分の1になること、uint64(64ビット符号なし整数)表現でのビット演算は現在のプロセッサだと1命令で実行できる。大幅な高速化が望めるだろう。</p><p>盤面の各ビットを以下のように割り当てることにした。最上位ビットから利用して最下位ビット側を未使用にしているのは若干気持ち悪く見えるかもしれないが、当初はブロックをシフトした際の範囲外判定のために右側のビットを残しておこうと思ったのでこのような割り当てになっている(結局使わなかったが)。気に入らなければ後述するルックアップテーブルの値を調整すればよい。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf_WIbnrBlsDb2YAtbTfgL4vS6AiPvC3FlkUO5RZSNkjU24VLASMs_rWJuNxi0ysObdEMTjFYuBhDR5WrlD1zRYxNa187Vm1clWh7Ew2ybbZ250gCUAgokJez3W34yueQcuQoS7NdSMwI/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="556" data-original-width="602" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf_WIbnrBlsDb2YAtbTfgL4vS6AiPvC3FlkUO5RZSNkjU24VLASMs_rWJuNxi0ysObdEMTjFYuBhDR5WrlD1zRYxNa187Vm1clWh7Ew2ybbZ250gCUAgokJez3W34yueQcuQoS7NdSMwI/w400-h369/Screen+Shot+2021-05-28+at+7.22.36.jpg" width="400" /></a></div>追記)このようにビットアサインするつもりだったが、実際には違うビットアサインをしていた。上記のビットアサイン表は参考例としてそのまま掲載しておく。<br /><br /><p></p><p>既存のソースコードの (7, 7) のマトリックスの内部表現からこのバイナリ64ビットの内部表現に変換するため、以下のような関数を定義した。本格的なループ処理の前後で使われるだけなので、かなり適当な書き方だが、ここでの実行時間は大したことないので問題ない。</p><p></p><pre>def generate_mat2bin_lut():
lut = np.zeros((7, 7), dtype=np.uint64)
for y in range(7):
for x in range(7):
b = 8 * y + x
lut[y, x] = base_bit >> (63- 8 * y - x)
return lut
def mat2bin(mat):
assert mat.shape[0] == 7 and mat.shape[1] == 7
lut = mat2bin_lut.copy()
lut[mat == 0] = 0
return np.sum(lut) # as np.unit64
def bin2mat(b):
mat = np.zeros((7, 7), dtype=np.uint8)
for y in range(7):
for x in range(7):
if (b & mat2bin_lut[y, x]):
mat[y, x] = 1</pre><pre>mat2bin_lut = generate_mat2bin_lut()</pre><p></p><p>二進数について理解している人なら(もっといいやりかたがあるよという指摘はいくらでもあるだろうが)何をしているか判ると思うので、詳細は省略する。</p><p>これで mat2bin() によりマトリックス表現からバイナリ表現に変換し、 bin2mat() によりバイナリ表現からマトリックス表現に変換できるので、既存コードにある初期値や出力用の関数はほぼそのまま使い回せる。</p><p>バイナリ表現化したことで盤面のほか候補についても64bitで表現できるようになったし、いっそのこと、あらかじめ8つのブロックの方向・反転・位置スライドの全パターンをメモリ上に展開しておくことにした。たとえばひとつのブロックの候補は以下のような196のuint64値で表現できる。</p><p><ore>000000000000030e
000000000000061c
000000000000070c
0000000000000c07
0000000000000c38
0000000000000e03
0000000000000e18
000000000000180e
0000000000001870
0000000000001c06
0000000000001c30
000000000000301c
000000000000380c
0000000000003860
0000000000006038
0000000000007018
0000000000030e00
0000000000061c00
0000000000070c00
00000000000c0700
00000000000c3800
00000000000e0300
00000000000e1800
0000000000180e00
0000000000187000
00000000001c0600
00000000001c3000
0000000000301c00
0000000000380c00
0000000000386000
0000000000603800
0000000000701800
0000000001010302
0000000001030202
0000000002020301
0000000002020604
0000000002030101
0000000002060404
00000000030e0000
0000000004040602
0000000004040c08
0000000004060202
00000000040c0808
00000000061c0000
00000000070c0000
0000000008080c04
0000000008081810
00000000080c0404
0000000008181010
000000000c070000
000000000c380000
000000000e030000
000000000e180000
0000000010101808
0000000010103020
0000000010180808
0000000010302020
00000000180e0000
0000000018700000
000000001c060000
000000001c300000
0000000020203010
0000000020206040
0000000020301010
0000000020604040
00000000301c0000
00000000380c0000
0000000038600000
0000000040406020
0000000040602020
0000000060380000
0000000070180000
0000000101030200
0000000103020200
0000000202030100
0000000202060400
0000000203010100
0000000206040400
000000030e000000
0000000404060200
00000004040c0800
0000000406020200
000000040c080800
000000061c000000
000000070c000000
00000008080c0400
0000000808181000
000000080c040400
0000000818101000
0000000c07000000
0000000c38000000
0000000e03000000
0000000e18000000
0000001010180800
0000001010302000
0000001018080800
0000001030202000
000000180e000000
0000001870000000
0000001c06000000
0000001c30000000
0000002020301000
0000002020604000
0000002030101000
0000002060404000
000000301c000000
000000380c000000
0000003860000000
0000004040602000
0000004060202000
0000006038000000
0000007018000000
0000010103020000
0000010302020000
0000020203010000
0000020206040000
0000020301010000
0000020604040000
0000030e00000000
0000040406020000
000004040c080000
0000040602020000
0000040c08080000
0000061c00000000
0000070c00000000
000008080c040000
0000080818100000
0000080c04040000
0000081810100000
00000c0700000000
00000c3800000000
00000e0300000000
00000e1800000000
0000101018080000
0000101030200000
0000101808080000
0000103020200000
0000180e00000000
0000187000000000
00001c0600000000
00001c3000000000
0000202030100000
0000202060400000
0000203010100000
0000206040400000
0000301c00000000
0000380c00000000
0000386000000000
0000404060200000
0000406020200000
0000603800000000
0000701800000000
0001010302000000
0001030202000000
0002020301000000
0002020604000000
0002030101000000
0002060404000000
00030e0000000000
0004040602000000
0004040c08000000
0004060202000000
00040c0808000000
00061c0000000000
00070c0000000000
0008080c04000000
0008081810000000
00080c0404000000
0008181010000000
000c070000000000
000c380000000000
000e030000000000
000e180000000000
0010101808000000
0010103020000000
0010180808000000
0010302020000000
00180e0000000000
0018700000000000
001c060000000000
001c300000000000
0020203010000000
0020206040000000
0020301010000000
0020604040000000
00301c0000000000
00380c0000000000
0038600000000000
0040406020000000
0040602020000000
0060380000000000
0070180000000000</ore></p><p>この値を bin2mat でデコードしてみるとブロックが見えてくる。</p><p></p><pre>% python
Python 3.8.1 (default, Mar 12 2020, 17:27:26)
[Clang 11.0.0 (clang-1100.0.33.17)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import puzzle_a_day_solver
>>><stdin><stdin>
>>> puzzle_a_day_solver.bin2mat([0x000000000000030e])
array([[0, 1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]], dtype=uint8)
>>> puzzle_a_day_solver.bin2mat([0x000000000000061c])
array([[0, 0, 1, 1, 1, 0, 0],
[0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]], dtype=uint8)</stdin></stdin></pre><p></p><p>8ブロック合計では、重複を除くと合計1196パターンあり、正味9568バイトのデータ量に収まるので、全てのパターンを予め展開しておいても、Core 2 DuoのプロセッサでももしかするとL1キャッシュに収まってしまうかもしれないデータ量だといえる(プロファイリングしていないので実際にどうなっているかは判らない)。</p><p>ブロックの衝突チェックは、従来方法では足し算をしていたが、今回は論理積(AND)を使用する。盤面 AND 候補を計算した結果、重複ビットがあるとゼロ以外の値になるので、論理積の結果がゼロ以外の候補は除外する。ここでも NumPy による vectorization を行う。</p><p></p><pre> blocks_f2_masked = blocks_f1_uint64 & mat_uint64
blocks_f2_bool =blocks_f2_masked == 0
blocks_f2_uint64 = blocks_f1_uint64[blocks_f2_bool]</pre><p></p><p>特定セルを埋めてくれる候補かどうかを判断するためには、特定セルを示すビットが 1 である候補に絞り込めばよい。 mat2bin/bin2mat 向けに作った、各セルに対するビットを示すルックアップテーブルから 64bit のビットマスクを得て、先と同様にフィルタリングする。</p><p></p><pre> bit_pos = mat2bin_lut[pos[0], pos[1]]
blocks_uint64_masked = blocks_uint64 & bit_pos
blocks_f1_bool =blocks_uint64_masked != 0
blocks_f1_uint64 = blocks_uint64[blocks_f1_bool]</pre><p>基本的なアルゴリズムは変えずに内部表現だけ変更しているので、得られる結果は一緒だが、49秒かかっていた処理が3.5秒まで短縮できた。</p><p>単純な計算部分だけで考えればもっと速くなる(1秒は切れるだろう)と思っていたので、思ったより遅かった。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">うっかり今晩も最適化して、昨晩から14倍速くなった。私にはこれぐらいが限界かも。 <a href="https://t.co/moY3RjJs4Q">pic.twitter.com/moY3RjJs4Q</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1397882107225993219?ref_src=twsrc%5Etfw">May 27, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><br /><div style="text-align: left;"><br /></div><h3 style="text-align: left;">C言語で再実装してみた</h3><p>翌週、<a href="https://github.com/hasegaw/puzzle-a-day-solver/blob/binary_optimization/solver.c" target="_blank">実はC言語で再実装してみた</a>。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">A Puzzle of the Day のソルバーが 10分 → 60秒 → 4秒 → 1.3秒 → 0.04秒 イマココ <a href="https://t.co/LhYqLqnxeR">pic.twitter.com/LhYqLqnxeR</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1401163005732130816?ref_src=twsrc%5Etfw">June 5, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p>もうこれ以上は最適化なんてしないって思っていた。でも1秒を切れなかったのがやはり心残りだったんだと思う。</p><p>基本的なアルゴリズムは Python バージョンと一緒だが、本質的ではないところで 楽をしたり、異なる実装をしたりている。</p><p>まず Python バージョンでは盤面の制約やブロックの形状を配列として表現しておき、実行時に 64bit のバイナリ表現を得ていた。 C 言語でこれを書き直そうとするとちょっと面倒なので、 Python バージョンが得られたバイナリ表現をソースコード中にLUTとして埋め込みしておく。</p><p>ブロックのLUTと、ブロックのメタデータ(LUT内の開始位置と数量)を独立したデータとして持っている。各ブロックの大きさや形状の違いからブロック数量が異なる。このためLUT自体はひとつ一次元配列で持っているので、CPU L1キャッシュを無駄にしない。</p><p>現状のコードは日付の指定や結果の出力機能を持っていない。 Python バージョンと同じデータ構造なので、 Python モジュールとしてコンパイルしてしまい、 Python バージョンを宿主として足りない部分は既存コードを使い回そうかなと思っている。</p><p>C言語で書くと有り難いのが次に攻略すべきセルを選択する部分で、ここはどうしても Python 上で速くする方法を思いついていなかった。いくつかのパターンを試した感じでは NumPy に任せておいたほうが速かったので、そうなっていた。</p><span style="font-family: monospace;"><span style="white-space: pre;"># バイナリ化前<br /></span></span><div><span style="font-family: monospace; white-space: pre;">def next_cell(context):
</span><span style="font-family: monospace;"><span style="white-space: pre;"> mat = context['mat']
pos = np.unravel_index(np.argmin(mat), mat.shape)
minval = mat[pos[0], pos[1]]
if minval != 0:
return None
return pos</span>
<br /><span style="white-space: pre;">
# バイナリ化後
def next_cell(mat):</span></span><span style="font-family: monospace; white-space: pre;">
</span><span style="font-family: monospace; white-space: pre;"> mat = mat2bin_lut & mat
</span><span style="font-family: monospace; white-space: pre;"> pos = np.unravel_index(np.argmin(mat), mat.shape)
</span><span style="font-family: monospace; white-space: pre;"> minval = mat[pos[0], pos[1]]
</span><span style="font-family: monospace; white-space: pre;"> if minval != 0:
</span><span style="font-family: monospace; white-space: pre;"> return None
</span><span style="font-family: monospace; white-space: pre;"> return pos</span><p>この部分はC言語であれば素直に書ける。</p><pre>/* 盤面 board に対して次のセルを選んで、その bit の値を返す */
inline uint64_t next_cell_bit(uint64_t board) {
for (int y = 0 ; y < 7; y++)
for (int x = 0 ;x < 7; x++) {
uint64_t done = board & mat2bin_lut[y][x];
if (! done)
return mat2bin_lut[y][x];
}
return 0;
}</pre><p>ある時点のC言語バージョンでは gcc の最適化なしで 40ms (0.04秒)、 -O3 で 20ms まで実行時間を短縮できる事を確認できた。M1 Macでは10msで完了したという報告ももらった(速っ!)。現時点のものは、もう少し最適化が進んでいる。 </p><p><br /></p><h3 style="text-align: left;">キャッシュミス分析</h3><p>このソルバーは約10KBのLUTを使って、最大8回の再帰呼び出しするだけなので、この規模であれば、ここ10年のプロセッサーではCPUのL1 Cacheに載りきってしまうことが想像できる。以下は Ryzen 9 3900X の Linux box において cachegrind でこのソルバーをプロファイルしてみた結果である。</p><pre>$ valgrind --tool=cachegrind ./solver
==114519== Cachegrind, a cache and branch-prediction profiler
==114519== Copyright (C) 2002-2017, and GNU GPL'd, by Nicholas Nethercote et al.
==114519== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==114519== Command: ./solver
==114519==
--114519-- warning: L3 cache found, using its data for the LL simulation.
50 solutions found
==114519==
==114519== I refs: 100,596,976 .... 命令の参照数
==114519== I1 misses: 1,140 .... L1 キャッシュミス
==114519== LLi misses: 1,116 .... L3 キャッシュミス
==114519== I1 miss rate: 0.00%
==114519== LLi miss rate: 0.00%
==114519==
==114519== D refs: 19,428,245 (18,233,828 rd + 1,194,417 wr) .... データ読み書き数
==114519== D1 misses: 3,401 ( 2,718 rd + 683 wr) .... L1 キャッシュミス
==114519== LLd misses: 2,817 ( 2,213 rd + 604 wr) .... L3 キャッシュミス
==114519== D1 miss rate: 0.0% ( 0.0% + 0.1% )
==114519== LLd miss rate: 0.0% ( 0.0% + 0.1% )
==114519==
==114519== LL refs: 4,541 ( 3,858 rd + 683 wr)
==114519== LL misses: 3,933 ( 3,329 rd + 604 wr)
==114519== LL miss rate: 0.0% ( 0.0% + 0.1% )</pre><p>I1 miss rate および D1 miss rate が 0.0% となっていることで、プログラム自体もデータも L1 キャッシュに収まっていることがわかる。念のためソルバーの実行回数を増やしたものを同じくプロファイラにかけてみたりもしたが、大きくキャッシュミスが増えたり、キャッシュミス率が上昇したりする状況を確認できなかった。</p><p>LLd miss rate の 2213 rd は恐らく 64bit のキャッシュラインへの読み込みが2213回発生したということだと思うので、 2,213*8=17,704 [bytes] で、コード中で使っている LUT サイズが 10KB 前後、あとはヒープや自分が書いたものではない関数内のメモリ操作をあわせると、こんなものなんだなと思っている。</p><p>知識として CPU のキャッシュの事は知っていたけども、こういったデータを具体的に見る機会は今までなかったので、パズルついでにここまで楽しめるのはお得感があった。</p><p><br /></p><h3 style="text-align: left;">これで終わりだと思うけど</h3><div><br /></div><div>一度「もうこれ以上はやらない」と書いていたのに色々と手を入れてしまったので、ほかにも思いついている最適化を試してしまうかもしれない。</div><div><ul style="text-align: left;"><li>mat2bin_lut の unroll<br />試した範囲では認識できるほどの差がないことがわかっている</li><li>mat2bin_lut を引くのをやめて毎回計算で求める (のとどちらが速い?)</li><li>AVX512</li></ul></div><p><br /></p><h3 style="text-align: left;">おわりに</h3><p>とりあえず数日間でソルバーを書いて遊んでみた内容をまとめてみた。</p><p>A Puzzle A Day のパズルはアナログでありながら、365日飽きもせずに遊べそうで、とても面白いと思う。同時に盤面は 7x7 未満とかなり小さく、私みたいに総当たりしてもそれほど難しくないので、プログラミング経験が浅くてもソルバーを実装にチャレンジするにはお手頃な問題ではないかと思う。</p><p><br /></p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">今日はパターンが多く難易度低めのようなので、持ってる人はパズル楽しんで欲しい <a href="https://t.co/ZQ8BtgLcf2">pic.twitter.com/ZQ8BtgLcf2</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1397974178460934148?ref_src=twsrc%5Etfw">May 27, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p></div>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-70512756745382474592021-05-28T04:13:00.004+09:002021-05-28T04:31:22.054+09:00これまで使ってきた Mac を回想する<p>私が普段使いのコンピュータを Mac に変えたのは 2007 年のことだった。知人が悪名高き MacBook Air (初代で何もしなくてもCPUスロットルするようなひどい世代)を可愛がることに決めて、私に 2006 年モデルの白色プラスチックモデルの MacBook を譲ってくれたので、 Mac に乗り換えることにした。 CoreDuo, 4GB RAM とかの時代のモデルで、快適に使えていた気がする。後述の 2008 年モデル購入後に、さらに知人に引き取られていった。</p><p>時間軸としてはこちらのほうが前なのだが、もともと 2004年頃に G4 Mac を購入して持っていて、まあ16年以上前のことだから書いてしまってもいいかな。まだ所属会社のセキュリティポリシも緩かったので、会社への申請を通して自分の G4 Mac を会社のデスクに設置、社内ネットワークに接続して、いつもロードアベレージが高いメールサーバからメールを吸い上げて、 imapd を動かして最強のメールスプールとして使っていた。数年後には社内のセキュリティポリシの変化に伴い、社内にもっていた私物 PC (ほかに自作FreeBSD PCのIRCサーバなども置いていた)は撤収することになった。</p><p>新品で買った MacBook は 2008 年モデルの 13 インチで、この個体では FreeBSD のソースコード読み込んだり、勉強会などに参加したりでかなり使い込んだ。仕事用 Windows PC は Cygwin, xinetd などを組み合わせ、普段使いは gVim な環境になっていたが MacBook 上は普通に UNIX ですっきりした環境でよかった。今でも手元に残ってはいるけど、通電はほとんどしていない。</p><p>2011年、転職のタイミングで MacBook Air 13インチを購入してメインPCにした。外回りのセールスになって、会社からの支給コンピュータは MacBook 13 インチだったが、一日に 3 アポとか都内を走り回る業務スタイルにおいてあの重さのコンピュータを常に携帯するのは負担だったので、自分でコンピュータを持ち込んでいた。当時は国内に社員が3~4名しかいない会社でやり放題(?)していたが、いまだと許されないかもしれない。</p><p>翌年の MacBook Air 2012 13インチを買ったのは、上記 Air のハードウェア故障で修理に出している間にコンピュータがないのは困るということで、買い換えた。当時の Air はフルスペックでも20万しなかったし、ノート型コンピュータをとても酷使していたので、1年しか使ってなくても買い換えていいかなというぐらいの気持ちで買い換えた。 2011 年モデルと比べると内蔵グラフィックスの性能向上がすごくて、良いコンピュータだった。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">SandyBridge MacBook Air 1.8GHz->IvyBridge MacBook Air 2.0GHzだけどビデオの性能があがったからかな?twitterで体感できる性能アップとはこれやいかにw</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/212919961209929728?ref_src=twsrc%5Etfw">June 13, 2012</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p>この頃の Mac はリーマンショック後の円高の影響で、スペックの高い個体がかなり安く買えていたこともあって、エンジニアにとっての Mac は安くてコスパのいい使い捨てマシンだったという感じがあった。</p><p>退職後、 MacBook Pro 2014 15インチを購入。 Pre Type-C 世代としては2015年モデルが最強だったが、 2014年モデルもハードウェア、ソフトウェア的に非常がバランス取れていて良いコンピュータだった。IkaLogの開発に使用したのもこのコンピュータである。冷却機構に埃がたまりサーマルスロットリングの病気が発生、掃除が必要だったが、当初はそれぐらいのトラブルで、とても快適な個体だった。残念ながら、手元の個体はディスプレイやキーボードの破損などが度々発生し、維持しつづけても負債になると考えて、保証切れとともに手放すことにした。30万以上したが、15万円ぐらいで売れた。</p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">FPGA関係のオモチャとかVisual Studio系とかインストールしだすとMacBook Airでは心許ない。そろそろMacBook Pro Retinaがほしいけど、しかし私はニートである</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/535550893874114562?ref_src=twsrc%5Etfw">November 20, 2014</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">つまり私いったんIvyBridgeのMacBook Airに逆戻りするのが正解なのでは?</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/668329567564664832?ref_src=twsrc%5Etfw">November 22, 2015</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p>2017年に現職に入った際、 MacBook Pro 2016インチをメインマシンにして、ここでは(いまごろ私が改めて言う話でもないが)バタフライキーボード等のデキが悪くて正直かなり使いづらいコンピュータになっていた。とはいえソフトウェア面での仕上がりは悪くなくて、 MS OneNote が同期に失敗しはじめると無限に CPU 時間を消費してとネットワークトラフィックを吐き続けることぐらいだったと思う。</p><p>なおこの MacBook Pro 2016 、 2019年の AppleCare 保証が切れ&リースアップ前にキーボードの保守交換(在庫の都合上UK->US)でめちゃくちゃ良いマシンになったと思う。酷評されていたバタフライキーボードも、改善版になってからはびっくりするほど入力しやすくなった。</p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">MacBook Pro 2017のキートップが外れてしまいメンディングテープ貼ってあるんだけど(意外とこれで困らない結果、私が修理に出したくない) 情シスが「まるで我々が故障機を放置しているように見えて落ち着かないので早くマシン買い換えか修理してください」と逆に怒られている <a href="https://t.co/n0AL3aMBAT">https://t.co/n0AL3aMBAT</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1129222585902718976?ref_src=twsrc%5Etfw">May 17, 2019</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">ぼくの大事な大事な UK キーボードの MacBook Pro は修理にだしました <a href="https://t.co/e0AfYNHG40">pic.twitter.com/e0AfYNHG40</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1141260912579371009?ref_src=twsrc%5Etfw">June 19, 2019</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">MacBook Proを修理に出したら、KBアセンブリ交換、配列変更が発生したのでトップカバー交換、KBアセンブリと一体化しているバッテリーも交換、起動後数分でパキッと音がする問題があり、切り分け結果画面側フレームの問題で液晶ごと交換になった結果、ロジックボードと底板しか元のパーツ残っていない</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1192080725052313605?ref_src=twsrc%5Etfw">November 6, 2019</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p>キーボード交換の際、バッテリ交換、本体シャーシ交換、温まったときにクラック音が生じていた問題があり液晶パネル交換となり、システムボード以外は新品同様になったのでこのまま暫く使い続ける選択肢も考えたのだが、過去の経験上 Mac を修理なしで使い続けられるという感覚がなく、使い続けても故障のタイミングで想定外のキャッシュアウトを会社に負担させるのもどうかと思ったので、リースアップの際に泣く泣く手放した。</p><p>2019年、本当はノート型コンピュータなんて1台だけ持っていれば十分だと思っていたのだが、情シスなどと相談したうえで海外出張時の PC を普段使いと分けることになって、 MacBook Air 2019 を併用しはじめた。正直、あまり使っていないし思い入れのない個体。もっと使ってくれる人のところに行けたら、よかったのにね。のちにコロナウイルスの蔓延もあり、本当にほとんど出番がない。</p>
<p>いま在宅で普段使いしているコンピュータは MacBook Pro 2019 16インチで、キーボードのタイプ感がまた変化した。個人的には2016年の改善版のバタフライキーボードでもよかったかなと思うけど、まあ過去には戻れないので仕方がない。コロナウイルス禍にあり家から出ない日も増えたし、 MacBook Pro 2019 16インチは最強のリモートワーク母艦となっている。</p><p>ただ、この普段使い MacBook Pro 2019 、またOSのアップデートが増えてから、いまいちOSとして安定しなくなってきた。ハードウェアとしては気に入っているんだけども、ソフトウェアとのバランスが微妙になったのかなーと感じている。</p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">MacBook Pro 2016 のキーボードは最初薄すぎるだろうと思ったけども、なれたら意外と心地よかったな。最新 MacBook Pro のキーの深さが気になる。タイプ中に指がキーにひっかかる</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1230731960525320200?ref_src=twsrc%5Etfw">February 21, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">確かに最新の 16インチ MacBook Pro は良いデキな気がする。2014年の 15 インチモデルもかなり気に入っていて、バタフライキーボード&タッチバー採用前が最盛期だったのかと思っていたが、 2019年型は、2016年型で感じていモヤモヤは一通り解消された気がする。</p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1284533982156054528?ref_src=twsrc%5Etfw">July 18, 2020</a></blockquote>
<p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">正直にいって Mac はここ5年ぐらいで徐々に使い物にならなくなってきた。変に重く感じて再起動してもコレ。ハードは一切構成変更せず、特別なドライバなどいれているわけでもなく。道具として厳しい <a href="https://t.co/lHysnPpqit">pic.twitter.com/lHysnPpqit</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1396102619341332481?ref_src=twsrc%5Etfw">May 22, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>
<p>「インストールしているソフトウェアや接続しているハードウェアが悪いんじゃないか」「俺のMacは暴れねえよ」などとは度々言われるのだが、なぜかうちの Mac はどうしても暴れてしまう。ここ1年ぐらいで kernel_task の CPU 時間消費が極端になってきて実用に耐えないレベルになりつつあるので、仕事する上で困るし、対策を打たないといけない。</p><p>自分にとっていちばん Mac が使いやすかったのは、 2012年~2015年のことだった。2017年以降、新しい Mac を手にする際には毎回「これが自分にとって最後の Mac になるかもしれない」と思っている。</p>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-44567346250686509362021-04-10T20:13:00.003+09:002022-07-02T03:49:23.973+09:00高リフレッシュレート対応4K液晶ディスプレイ ASUS ROG Strix XG27UQ を購入した<p>2022/6 追記</p><p>本記事は 144Hz 4K ディスプレイの選択肢がまだほとんどなかった頃に XG27UQ を購入した際の内容です。</p><p>どうしても DisplayPort 入力が2ポート欲しい、 4K 144Hz 仕様としては割安なディスプレイが欲しいという理由であれば XQ27UQ を候補になると思いますが、そうれでなければ、現在では LG 27GP850 をはじめ複数の HDMI2.1 対応 4K ディスプレイが流通しています。これから検討される方は他の 4K 144Hz ディスプレイも確認されることをお勧めします。</p><p> ~~</p><p><br /></p><p>高リフレッシュレートなディスプレイに買い換えようと思って以来半年近くたち、ようやく本命のディスプレイが手元に届きました。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK1GuBDaBr5qnyhsbq6AhexebiUfDw5Ru3OTW9M7Xh-QeDY3ubGm6LggVijqVQlfwxgI9h52mL42gjWBqjRMi5qR8_RH4gLNy90mPOQPN418ZGjgswOn3Igaq7NOwMgrtNJnH3bwwRmao/" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="1000" data-original-width="1000" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK1GuBDaBr5qnyhsbq6AhexebiUfDw5Ru3OTW9M7Xh-QeDY3ubGm6LggVijqVQlfwxgI9h52mL42gjWBqjRMi5qR8_RH4gLNy90mPOQPN418ZGjgswOn3Igaq7NOwMgrtNJnH3bwwRmao/w400-h400/XG27UQ_1.jpeg" width="400" /></a></div><br /><br /><p></p><p>今回のXG27UQは2021年2月に国内向けに発表されたモデルで、これまで秋葉原などでお店を回っても実物を見かけることはありませんでした。発表当初にすぐ予約された方は2月中に入手できたようですが、4月に入ってようやく実物が届いたぐらいで、現時点で欲しくても実物を見られる方は限られていると思います。このモデルは実売で10万円近くしますし、「失敗したくないので少しでも多く情報が欲しい」という方もいらっしゃるかと思います。このため、所感をまとめておくことにしました。</p><p>調べてみると、メーカーからテスト機を借り受けたブロガー等がすでにレビュー記事を投稿されていますし、そういった方でカバーされている分については、そういった記事にお任せすることにしました。私の記事では、他の記事ではあまり触れられていない部分について触れていこうと思います。</p><p><br /></p><h2 style="text-align: left;">ファースト・インプレッション編</h2><h3 style="text-align: left;">マニュアル冊子が付属していない</h3><p>本製品は付属品として製品保証についての冊子、1枚っきりのクイックスタートガイド、およびキャリブレーションレポートが付属していますが、マニュアルは同梱されていません。スタンド部分を外す方法がわからずに困っていたところ、 ASUS のサイトにはマニュアルが PDF で存在していることがわかりました。</p><p><a href="https://dlcdnets.asus.com/pub/ASUS/LCD%20Monitors/XG27UQ/XG27UQ_Japanese.pdf">https://dlcdnets.asus.com/pub/ASUS/LCD%20Monitors/XG27UQ/XG27UQ_Japanese.pdf</a></p><p>マニュアル冊子なんて一度使い始めたらほとんど見返すこともないのは事実ですし、意図的に省略されているのでしょう。とはいえ、 10 万円近いモニタですし、今回の製品はマニュアルを見ないとよく判らない機能やギミックも積まれているモデルです。紙媒体でマニュアルが付属されていたり、もしくは少なくともURLや検索キーワード、QRコード等でもよいので、マニュアルへの案内があると良かったなと思いました。</p><p><br /></p><h2 style="text-align: left;">日常の利用編</h2><h3 style="text-align: left;">複数ソースの切り替えが面倒。ファームウェア更新による改善を期待</h3><p>XG27UQ は DisplayPort 2入力、 HDMI 2入力で合計4入力利用できる点がひとつの特長です。ディスプレイです。しかし、ディスプレイの入力を切り替えるためには画面裏側右手の赤いスティックを使い、クリック→下→下→下→右と操作し、その上で入力ソースをスティックで選択する流れになっており、煩雑です。</p><p>赤いスティックの下にはゲーミングモードを設定する画面へのショートカットがふたつあります。これらのボタンで、GamePlus設定画面、およびGameVisual設定画面への直接遷移できるようになっていますが、たぶん、私は、どちらもほとんど押す機会がないでしょう。これらのボタンから入力ソースの切り替え画面へ遷移できるような設定が可能となるファームウェアアップデートに期待したいです。複数の入力ソースを接続する方の多くは、同じような感想をお持ちになるのではないでしょうか。</p><p><br /></p><h3 style="text-align: left;">USB3.0ハブ機能は、ディスプレイの主電源と連動/非連動が選べる</h3><p>XG27UQ は USB3.0 の2ポートUSBハブ機能を搭載しています。私の場合、ダウンストリームには、ディスプレイの付近にあるデバイスとして、Webカメラとして利用している一眼デジタルカメラ(Canon EOS Kiss X6i)とアイトラッカー(Tobii Eye Tracker 5)を接続しています。ディスプレイ自体にこの機能を求めてはいないのですが、セットアップがすっきりした点についてはメリットを感じました。</p><p><br /></p><p>このUSBハブ機能はディスプレイ機能と独立して動きますが、ディスプレイの主電源がオンの状態でのみUSBハブが動作する連動設定と、ディスプレイの主電源の状態にかかわらず外部電源が供給されていればUSBハブが動作する非連動設定のどちらかを選ぶことができます。</p><p>工場出荷時は主電源と連動する設定になっていますが、私の場合で常時通電のデスクトップPCとの組み合わせで利用するため、USBハブが常時動作する設定に切り替えました。</p><p><br /></p><h2 style="text-align: left;">ディスプレイアームとの組み合わせ利用について</h2><p>XG27UQ はディスプレイアームへの取り付けに対応しています。ただし、アームの取り付け時に標準スタンドの取り外し方がすぐに判からず、マニュアルを見ながら試行錯誤したほか、この機種特有の考慮点があるので、ここで紹介したいと思います。</p><p><br /></p><iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/F15rhi0ETTM" title="YouTube video player" width="560"></iframe><p><br /></p><h3 style="text-align: left;">標準スタンドの取り外し方</h3><p>この作業には、化粧パーツの取り外しにマイナスドライバー、M4ネジを付け外しするためのプラスドライバーが必要です。</p><p>工場出荷時にはスタンド用の足が取り付けられた状態になっています。足のまわりにある半リング形状の化粧パーツを取り外します。スタンドの裏を覗き込むとマイナスドライバーを差し込める隙間があるので、ここにマイナスドライバーを差し込んで化粧パーツを引き上げます。</p><p>パーツが浮いてきたら、半リング形状の化粧パーツ2点を、ディスプレイ本体から平行に離すように取り外します。取り外し時に多少力をかける必要がありますが、樹脂パーツ自体は十分な強度があるので、丁寧に外せば問題ありません。この作業を終えると、VESA規格のM4ネジが4本露出します。</p><p>足のまわりに見えてきたVESA規格のM4ネジを4本はずすと、標準スタンド用の足がはずれて、ディスプレイアームを取り付け可能な状態となります。</p><p>半リング形状の化粧パーツは取り外したスタンドに取り付けられるので、保管時にはスタンドにはめて保管しておくとよいでしょう。</p><p><br /></p><h3 style="text-align: left;">VESAマウントのネジ穴は25mm の窪みの中にある</h3><p>ディスプレイアームの種類によっては、カメラのクイックシューのように、あらかじめディスプレイ側に小さな部品を取り付けておいて、設置済みのディスプレイアームに固定できるような機能をもった物があります。このような場合VESA標準のネジ穴のまわりに十分なクリアランスが必要です。また、スタンドを非純正品に交換した場合にも注意が必要なポイントでしょう。</p><p>今回は colebrook bosson saunders 製の Wishbone ディスプレイアームに取り付けるつもりでいたので、この部分は気になっていましたが、結果的には十分なクリアランスがあり、Wishbone アームに対して、問題なく載せたり外したりできることが確認できました。 </p><p><br /></p><h3 style="text-align: left;">ディスプレイアーム利用時、ビデオ用ケーブルを完全に隠せない</h3><p>XG27UQ は下側から DisplayPort/HDMI などのケーブルを差し込みます。標準スタンドを利用する場合にはあまり気にならないでしょうが、ディスプレイアームに載せる場合は、ビデオ用のケーブルが正面から見えてしまう可能性があります。</p><p>がんばって隠すことも不可能ではないのですが XG27UQ は DisplayPort 1.4 に対応した 4K 144Hz 対応のディスプレイで、これを利用する場合には DisplayPort 1.4 に対応した比較的太いケーブルを使用することになるのではないでしょうか。</p><p>しかし、上向きに刺さった太いケーブルをディスプレイの裏側で片付けるだけの十分なスペースがないため、正面から見たときには、ビデオ用のケーブルはディスプレイの下側に少し見えるぐらいのセッティングに落ち着くかと思います。もちろん気合いで見えないように隠してもよいでしょうが、アームを動かしたときにケーブルやコネクタに負担がかからないようにある程度の遊びも必要ですし、この点は諦めることにしました。</p><p><br /></p><h2 style="text-align: left;">その他編</h2><h3 style="text-align: left;">当然ながら 4K 144Hz には高品質なケーブルが必要</h3><p>これまで、2012年に購入した 7m の DisplayPort 1.2ケーブルでPCとディスプレイを接続し、4K 60fpsで動作させていました。このケーブルを利用していたのは諸事情により「手元で余っていた」というのが最大の理由です。(今でも未使用の新品が1本手元にあります...)</p><p>このケーブルでも 4K 144Hz はいちおう映ったのですが、不定期に画面がブラックアウトする現象が発生しました。恐らくケーブルの品質的に映像信号が時々乱れているのだと想像できます。</p><p>FullHD 144Hz に対して 4K 144Hz は時間あたりに表示するピクセル数が4倍になります。このためビデオケーブルの中を流れる信号の速度が上がっています。 Wikipedia の DisplayPort ページで調べてみたところ、 4K 144Hz は DisplayPort 1.4 仕様からの仕様で、ケーブルの中を 25.92Gbps の信号が流れているようです。 1.2 の時代は 17.28Gbps だったので、データの転送量が1.5倍になっていて、恐らくそれだけDisplayPortケーブル内のビットクロックも上がっているようです。</p><p>ディスプレイに付属する DisplayPort 1.4 ケーブルを利用することも考えましたが、手元では昇降デスクやディスプレイアームを利用しており、 3m 程度のケーブル長を必要としていたので、 3m の DisplayPort 1.4 対応ケーブルを購入して交換しました。</p><p>また、ビデオカードの DisplayPort コネクタの片方が緩いようで、本体への衝撃ですぐブラックアウトしてしまう事があったので、もう片方の DisplayPort コネクタに装着して安定を確認しました(ビデオカードのメーカー保証で交換依頼をしてもいいかもしれませんが、手間を考えるとこの対応でいいかなぁと思っています)。</p><p><br /></p><h3 style="text-align: left;">MacBook Pro 16インチ (2019) から HDMI で 4K 60Hz で安定出力できている</h3><p>MacBook Pro から 4K 解像度で出力する際になかなか安定しないイメージを持っていましたが、XG27UQ では HDMI ケーブルを接続するだけで 4K 60Hz で出力された点が拍子抜けでした。ここ一週間ほど、ノートラブルで動作しています。</p><p>LG 社のディスプレイでは 4K 60Hz を受け付けるためには追加の設定(DeepColor)が必要だったりして、この設定を行うと映る時と映らない時があるなどしてストレスを感じたので DisplayPort 接続による 4K 60Hz もしくは HDMI 接続による 4K 60Hz を使い分けていました。</p><p>不都合が感じたら DisplayPort での 4K 60Hz に切り替えることを考えるでしょうが、実用上問題を感じないうちは、試しに HDMI の 4K 60Hz で使ってみようかと思います。</p><p><br /></p><h2 style="text-align: left;">まとめ</h2><div>XG27UQ は、4系統入力の4K解像度・高リフレッシュレートディスプレイとしては期待通りの仕上がりだと感じています。</div><div><br /></div><div>一点だけ不便な点を挙げるとすれば、入力系統の切り替えに必要な操作数が多いことです。この部分は4系統入力を魅力に感じて購入するユーザーにとっては非常に重要なポイントです。もしエンドユーザ側でファームウェアアップデートが可能な仕組みが用意されているのなら、後からでも改善できる点ですから、ASUSには是非検討を御願いしたいところです。</div><div><br /></div><div>これまで液晶ディスプレイといえばシャープ、LGなど自社で液晶パネル技術を製造できるメーカーの製品を利用していました。今回のASUS ROG XG27UQは実売価格で10万円近くするモデルで、下手な4Kディスプレイの2倍以上の価格です。ASUS自体は液晶パネルを作れるわけではないので買ってきている(というか製品規格だけで、他メーカーに仕様を指定して生産させている可能性も高い)メーカーですので、正直に言えば、そういったメーカーの製品を選定すること自体に抵抗もありました。最初の一週間から「買わなければ良かった」みたいな悪い印象にもならず、ホッとしています。</div><div><br /></div><h2 style="text-align: left;">To Be Continued</h2><div>フォトトランジスタを使って応答速度などをの特性を測定しているため、結果がまとまったら続編としてまとめたいと思います。</div><div><br /></div>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-26908009998685236142021-04-08T03:50:00.006+09:002021-04-08T03:56:20.042+09:00 Radeon RX 6800 XT の OpenCL を有効化する<p>Radeon RX 6800 XT で OpenCL プログラムを動かそうとすると、OpenCL プラットフォームとして同 GPU が列挙されてこなかったので、調べたら、レジストリをちょっと弄る必要があるっぽい。どうやら OpenCL プログラムはこのキーから OpenCL プラットフォームの実装を見つけてるようだ。</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjup6xL0B4Nb6Xx0evVeeQ8QjUw0bFWdgkppsSleCJPGArNfcdYtJdczf9bY-o7SZbLmKdU-A3b3wYCP8y0pU5TmjUm7Z7Z6UoPp7kxpgFiAO9z6A6sg2d1fJgpCmNlzMxO0dYwYzNNHK0/" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="244" data-original-width="2041" height="48" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjup6xL0B4Nb6Xx0evVeeQ8QjUw0bFWdgkppsSleCJPGArNfcdYtJdczf9bY-o7SZbLmKdU-A3b3wYCP8y0pU5TmjUm7Z7Z6UoPp7kxpgFiAO9z6A6sg2d1fJgpCmNlzMxO0dYwYzNNHK0/w400-h48/opencl-1.JPG" width="400" /></a></div><br /><p></p><p>Radeon のドライバをインストールもしくはアップデートしたタイミングで、以下のようなディレクトリ、ファイルができる。</p><p></p><p>C:\Windows\System32\DriverStore\FileRepository\*.inf_amd64_*\amdocl64.dll</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgObIKUdHLZNs1T_hcdIfKBqdPC2Nahiq59J8pCRv8kYhP4tuV7Hm7_8jk2sI_xu0EHoeGQbt775DWcfzCfcBITmRfv5al3-wFCtvhgPo91vjYHqdBrVEHW9DlYXhPDdC2MveyOJHhIq7Y/" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="614" data-original-width="1629" height="151" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgObIKUdHLZNs1T_hcdIfKBqdPC2Nahiq59J8pCRv8kYhP4tuV7Hm7_8jk2sI_xu0EHoeGQbt775DWcfzCfcBITmRfv5al3-wFCtvhgPo91vjYHqdBrVEHW9DlYXhPDdC2MveyOJHhIq7Y/w400-h151/opencl-2.JPG" width="400" /></a></div><p><br /></p><p>amdocl64.dll のフルパスが確認できたら、 regedit.exe を起動して、 コンピューター\HKEY_LOCAL_MACHINES\SOFTWARE\Khronos\OpenCL\vendors に、以下のキーを作成する。</p>
<ul>
<li>名前: 上記 amdocl64.dll のフルパス</li>
<li>種類: REG_DWORD</li>
<li>データ: 0x00000000 (0)</li>
</ul><div>このキーを作成した後に OpenCL を利用するプログラムを実行すると、 Radeon GPU が OpenCL デバイスとして認識される。もし認識されない場合は amdocl64.dll へのパスがおかしいとか、過去のドライババージョンの amdocl64.dll へのパスになっていないかを確認するとよさそうだ。</div><div><br /></div><div>手元で Radeon のドライバを更新するたびにコレでひっかかってる気がするが、どうしてドライバのインストール時に自動的にやってくれないのかねえ。何も見ずに何すればいいか思い出せるほどの頻度でやることではないが単純作業ではあるので、いっそのことツールなど書いて自動化すると幸せかもしれない。。。</div>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-26531078301887369832021-03-14T09:43:00.005+09:002021-12-30T00:24:46.834+09:00ゲーミングディスプレイは本当に役に立つのか?<div><div>2021年にもなって、久々にFPSとしてApex Legendsをプレイしている。ヘタクソなのはそうなのだが、恐らくこの半年間でPS4 Pro/PC版あわせて700~800時間はプレイしているはずだ。久々にFPSをプレイしているので、ゲーミングディスプレイを試して、比較してみることにした。</div><div><br /></div><h3 style="text-align: left;">ゲーミングディスプレイに対する謳い文句への懐疑感</h3><div><br /></div><div><div>これまで LG 27UD55-BK と LG 27UL850-W (どちらも 27インチ4K液晶)をデュアルディスプレイにしていて、このうち、 2020 年に購入した 27UL850-W をゲームプレイに使用していた。このディスプレイはどちらかと言えば発色などがキレイなことがウリだ。</div><div><br /></div></div><div>もちろんリフレッシュレート60Hzの液晶ディスプレイが十分だとは思っていなかった。もともと私は初めてのFPSといえば液晶ディスプレイが普及する前である1990年代の初代DOOMだし、また2000年前後は三菱のダイアモンドトロン管ディスプレイ RD17V で、100Hz 程度のリフレッシュレートでFPSを遊んでいた経験があるので、液晶ディスプレイかつ60Hzが大きな制約であることは理解していた。敢えていえば液晶になる前なら100Hz程度は当たり前だった。また最近のトレンド Oculus Rift などのヘッドセットを見ていても、60Hz では不足だが 90Hz もあれば脳を騙せることが知られているので、60Hzで足りなくても、100Hzぐらいの頻度で更新されれば十分だろうと思っている。</div><div><br /></div><div><div>しかし、周りのプレイヤーからは「60Hzよりも高リフレッシュレートのほうがよい」だけで終わらず、「敵レジェンドが止まって見える」「ディスプレイを変えるだけでキル数が増える」などという主張をされるし、販促ビデオでは相手より素早く反応できると謳われている。果たして、そこまでの効果があるのだろうかと、懐疑的に思っていた。</div><div><br /></div></div><h3 style="text-align: left;">買おうと決意したものの、欲しいものの在庫がない</h3><div><div><br /></div><div>とはいえ、そろそろゲームに適したモニタが欲しくなってきた。コロナ禍でほとんど外出することもなく、スノーボードは2シーズン連続でスルーしており、月々の大きな支出としては家賃とメシ代(自炊するようになったため2年前の1/4〜3/1ぐらい)ぐらいなのだ。この半年で FPS を500時間以上プレイしているのだから、多少投資してもいいのではないだろうかと。</div><div><br /></div></div><div>実は 11 月頃にゲーミングディスプレイの購入を決意したが思ったようなモデルがなく、2月に ASUS が発表した XG27UQ (4K 144Hz)をバックオーダーしている状態である。手元の古いLG 27UB55(27インチ 4K)で何十秒も残像が出る不具合が出ているので、買い換えるなら、同じ利用感で仕事にも使えるゲーミングディスプレイを、と思い、このモデルにたどり付いた。</div><div><br /></div><div>しかし、昨今の自動車をはじめとする部品不足問題のためか中々納期が確定せず、少なくとも3月中にも手に入らないことがほぼ確定的になった。この機種に限らず、ある程度スペックや型番にこだわりを持って液晶ディスプレイを購入しようすれば、流通量の少なさにすぐ気づくだろう。正直なところ現時点で表示されている納品時期が守られるのかも判らない。</div><div><br /></div><h3 style="text-align: left;">とりあえず、繋ぎのつもりで買ってみた</h3><div><br /></div><div>今回は MSI Optix G241 を購入してみた。スペックを妥協して市中在庫から選べば3万円でお釣りがくる価格感だ。半年近く「ゲーミングディスプレイの在庫がネェ……」と考える日々が続いていたことを考えたら、さっさと買ってしまったほうが精神的に良かったのではないかとさえ思える。</div><div><br /></div><div>中途半端なものを買いたくなかった最大の理由は、設置場所の都合だ。27インチ×2+MacBook Proでギリギリだったが、やむを得ず、なんとか3枚目のディスプレイを追加した。ディスプレイアームに載せてあるので利用シーンによってある程度片付けたり引っ張り出したりはできる状態にある。</div><div><br /></div><h3 style="text-align: left;">とりあえずの印象</h3><div><br /></div><div>早速 Optix G241 を Windows PC に繋げてみると、マウスカーソルの動きがかなり滑らかになった(というか見える残像が増えた)のはすぐわかり、印象的だった。ウインドウのドラッグなども全体的に滑らかになっているのもわかる。</div><div><br /></div><div>Forza Horizon 4 を動かしてみると 60Hz と 144Hz では高速道路を高速巡航しているときに横を流れていく鉄柱の滑らかさが印象的だった。</div><div><br /></div><div>過去に多少試したことがある Aim Lab を改めて試してみると、これまで 30,000 点ちょっとの印象だったテストで 50,000 点台が出てきて驚いた。ただ、ディスプレイの変更だけでなく自分のプレイスキルの向上もあると思うので、そこは考慮しないといけない(特に最近は Apex Legends の仕様アップデートに伴いウイングマンでの練習をはじめている)。</div><div><br /></div><div><br /></div><div>ゲーミングディスプレイによるメリットはこの時点である程度体感できていたが、もう少し定量的に比較してみることにした。</div><div><br /></div><h3 style="text-align: left;">比較環境のセットアップ</h3><div><br /></div><div>今回は GPU (Radeon RX 6800 XT)から、これまで使っていた 27UL850-W (60Hz 4K 5ms) と今回の Optix G241 (144Hz FullHD 1ms) を DisplayPort で同時接続し、 Windows の機能で両方のモニタに映像をミラーする。なお、 Windows の機能で画面をミラーした場合に遅延が増加するかどうかは判っていなくて、この部分を定量的に測定する方法を持っていないので、この観点については無視する。</div><div><br /></div><div>フレッシュレートは各ディスプレイの最大値が適用されているので、従来のディスプレイでは 60Hz 、ゲーミングディスプレイでは 144Hz で表示される状況となる。これで、どちらを見るかだけで利用できるディスプレイをスイッチできる環境ができた。</div><div><br /></div><div>定量的に比較できるように、引き続き Aim Lab を使って、プレイ中のディスプレイの表示状況をデジタルカメラのビデオ撮影機能で 60FPS 撮影し比較することにした。ディスプレイの前に三脚を立てて、富士フィルムのX-T3カメラで両方のディスプレイを撮影できるようにした。ひとつのカメラのセンサで両方のディスプレイの出力映像を記録することで、1コマ単位で見比べて比較できる。</div></div><div><br /></div><div><div>もちろん、本来 60Hz と 144Hz の違いを検証するのなら 60FPS では不十分だ。少なくとも 144Hz の倍の 288Hz(FPS) 前後のフレームレートで撮影したほうがいいだろうが、私はそこまでの機材は持っていないから、手持ちの機材でできる範囲での検証とする。</div></div><div><br /><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsV940zpBZL7CXFlDYw7FFbAV4anZyfL5xtLRzg4o1wNeviAXZmfrgYT7yfSd3pys1nq_cBR_GABNyaWnFsIgHW96f1W41L8SZxLQ8FHSGVrkZwMVuwQrkGJX5allY4fPEg8pAYp7eWoM/s2048/144hz-1.jpeg" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="1120" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsV940zpBZL7CXFlDYw7FFbAV4anZyfL5xtLRzg4o1wNeviAXZmfrgYT7yfSd3pys1nq_cBR_GABNyaWnFsIgHW96f1W41L8SZxLQ8FHSGVrkZwMVuwQrkGJX5allY4fPEg8pAYp7eWoM/s400/144hz-1.jpeg" width="400" /></a></div>
<div><br /></div><div>写真左側が LG 27UL850 、右側が MSI Optix G241だ。</div><div><br /></div><div>なお、正面からの撮影ではないとはいえ、この写真で見ればわかるとおり、発色については Optix G241 に対して 27UL850 のほうが圧倒的にキレイだ。手元で試している限り、 27UL850 と比較できる環境で見れば、 Optix G241 は全体的に色褪せて見える(色温度などの設定でカバーできる範囲ではない)。これらは両方とも IPS パネルだ。</div><div><br /></div><div><br /></div><h3 style="text-align: left;">応答速度を比べてみる</h3><div><br /></div><div>とりあえず動画撮影をしながら、両方のモニタで Aim Lab を比較してみたところ、今回購入した G241 のほうがボヤケが明らかに少ないことがわかった。このため目が疲れにくい印象を受けた。これは動画からフレームを切り出してみても判る。</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl_mOyx878GRk43YWm1S3wHQhXtzhGQhberCTuW1jif_hrkjxCOhc-pSY-e52xyOzJjqU_B7lhD4TS324OxvmAvJN-dJg5zHRvRKiBgMiqTftgPBa4rYrBwavgYfubiGMxTSHfGiCCHgc/s1280/144hz-2.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="700" data-original-width="1280" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl_mOyx878GRk43YWm1S3wHQhXtzhGQhberCTuW1jif_hrkjxCOhc-pSY-e52xyOzJjqU_B7lhD4TS324OxvmAvJN-dJg5zHRvRKiBgMiqTftgPBa4rYrBwavgYfubiGMxTSHfGiCCHgc/w400-h219/144hz-2.jpeg" width="400" /></a></div><br /><div>この写真では下にあったターゲットをエイムしてから上にあるターゲットに移ろうとしているが、その際に27UL850ではひとつ前のフレームが残像として映っている。実物では、この残像がボヤけに見えている。Optix G241では、この残像感がとても抑えられている。60Hz 5msのスペックを謳うディスプレイの残像は、デジタルカメラを用いて60フレーム/秒で撮影したレベルでも十分に記録できるほどだった。</div><div><br /></div><h3 style="text-align: left;">表示遅延を比べてみる</h3><div><br /></div><div>録画を確認するとOptix G241のほうが常に若干新しいフレームが描画されていると感じられる。実際には144Hzのリフレッシュレートで更新されていることもあり、操作に対してダイレクトにフィードバックがかかるので、エイム操作がしやすくなる感覚はあった。</div><div><br /></div><div>動画の各フレームを確認していくと、以下のフレームが見つかった。28UL850では過去のフレームに対して新しいフレームが表示されようとしており、Optix G241ではより新しいフレームが表示されている。</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJKc-34_Ewbd_FuR9msIjBfHRbUgwbi37q54nf5AIZyvdaZf8P06waqcbABY_fRh6rmdN0uo1EdXXdMQszRisrA-gHai7SpnnpjXztCZYW8LnL9lYUWeOA2qW0yAKGhCJOlypzZQV6ulQ/s1153/144hz-3.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="603" data-original-width="1153" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJKc-34_Ewbd_FuR9msIjBfHRbUgwbi37q54nf5AIZyvdaZf8P06waqcbABY_fRh6rmdN0uo1EdXXdMQszRisrA-gHai7SpnnpjXztCZYW8LnL9lYUWeOA2qW0yAKGhCJOlypzZQV6ulQ/w400-h209/144hz-3.JPG" width="400" /></a></div><br /><div>どちらのディスプレイでも、いちばん右のターゲットにはこれから表示される武器の陰がかぶっているが、このかぶり方が非常に似ているのは面白いポイントだと思う。144Hzのほうが明らかにより新しいフレームが表示されている。しかし、60Hzモニタは更新頻度が低いとはいえ、特別に遅延が大きいわけではないようだ。</div><div><br /></div><div>遅延がどれぐらいあるかはカウントダウンの瞬間などを比較するとわかりやすい。5,4,3...とカウントダウンがなされる時の60Hzディスプレイでの描画の遅れは、表示開始までの遅延は1フレーム(16.6ms)前後、表示が安定するまで2フレーム(32.2ms)未満だった。</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzIEYxhju04812apNmxCG1AOPJnYEQ4aiXkGM3vQZFZuaJnCFxXcyUNxCe5tNbT2ZK7IPtAEuxaa36fU4XQCg' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div><br /><br /></div><div>1/144秒毎に更新されているディスプレイとの比較として考えると、1/60秒毎にしか更新されておらず、画面の残像感が1フレーム分残る液晶パネルであることを考慮すれば、妥当な挙動だ。32.2msはデジタルカメラの撮影機能が60FPSであることから想定した最悪値だ。実際の遅延はこれより少ないだろう。</div><div><br /></div><h3 style="text-align: left;">ゲーミングディスプレイの宣伝文句は本当か?</h3><div><br /></div><div>ゲーミングディスプレイの宣伝文句として「フレームレートが高いほど、相手がより早く見える」といった表現がされていたり、それをイメージさせるデモ映像がある。</div><div><br /></div><div>今回の比較を見る限り、あの宣伝文句はかなり大げさな表現だが、一般的な 60Hz ディスプレイと比べれば確かに10~20ミリ秒ほど早く画面上に敵が映り込んだり、より新しい位置に敵が見えたりするのは事実だろう。</div><div><br /></div><div>とはいえ、10ミリ秒を切ってくると現在のインターネットにおけるピア間の遅延のほうが大きくなりうるし、それをごまかすための補間や予測などもされているわけなので、まあ、そうね、というレベル感で捉えている。</div><div><br /></div><h3 style="text-align: left;">実際のゲームだとどうなる?</h3><div><br /></div><div>同じように Apex Legends でダミー撃ちする映像をフレーム単位で見てみたが、複雑なApex Legendsの画面は144Hzを60FPSで録画しても、複数フレームが同時に映りこんで逆に破綻した画像になってしまった。体感と異なり144Hzの画像のほうが見づらく、紹介に紹介するような内容にならなかったので、ここでは省略する。</div><div><br /></div><div>感覚的には、マウス操作による視線移動が発生した場合にダミーや周りの景色がはっきり見えることにより、プレイしやすくなると感じた。</div><div><br /></div><h3 style="text-align: left;">ゲーミングディスプレイはゲーミングディスプレイだった</h3><div><br /></div><div>今回、はじめて60Hzを越えるリフレッシュレートに対応した液晶ディスプレイを買ってみたが、ゲーム画面が見やすくなるなどのメリットが確認できた。特に、 FPS のように視点移動によって画面の表示が大きく変化するようなゲームでは、残像感が大幅に減少するため、疲れにくくなりそうだ。</div><div><br /></div><div>まだ「ゲーミングディスプレイにするだけでキル数が伸びる」かどうかはわかっていないが、ぼちぼち実践で試してみようと思う。</div>
</div>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-49516944924583994922021-01-16T04:29:00.004+09:002021-01-16T04:42:17.072+09:00コロナ禍でやっと自宅ごはんが定着してきたアラフォーのキッチン環境の話<p>自炊なんてする気はまったくなかったのに、コロナウイルスのせいで日々の95%の食事が自炊になってしまった。まあ、自炊と言えるほどのしっかりした自炊でもないので、敢えて自宅ごはんと書くことにしよう。</p><p>コロナウイルスが話題になりはじめてからの直近1年弱で、購入してよかったと思えるキッチン用品などを挙げてみる。</p><p><br /></p><h3 style="text-align: left;">冷蔵庫: SHARP SJ-GW41F</h3><p><p><a href="https://www.amazon.co.jp/%E3%82%B7%E3%83%A3%E3%83%BC%E3%83%97-SHARP-%E3%83%97%E3%83%A9%E3%82%BA%E3%83%9E%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC-%E4%B8%A1%E9%96%8B%E3%81%8D%E3%83%BB%E3%82%AC%E3%83%A9%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%97-SJ-GW41F-W/dp/B089NH2F7T/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B089NH2F7T&qid=1610739295&sr=8-2&linkCode=li2&tag=wyrm-22&linkId=adc3b07cb2cb402bee6eff0eab34b48b&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B089NH2F7T&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B089NH2F7T" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/%E3%82%B7%E3%83%A3%E3%83%BC%E3%83%97-SHARP-%E3%83%97%E3%83%A9%E3%82%BA%E3%83%9E%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%BF%E3%83%BC-%E4%B8%A1%E9%96%8B%E3%81%8D%E3%83%BB%E3%82%AC%E3%83%A9%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%97-SJ-GW41F-W/dp/B089NH2F7T/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B089NH2F7T&qid=1610739295&sr=8-2&linkCode=li2&tag=wyrm-22&linkId=adc3b07cb2cb402bee6eff0eab34b48b&language=ja_JP" target="_blank" rel="nofollow">シャープ SHARP プラズマクラスター 冷蔵庫 どっちもドア(両開き・ガラスタイプ) 幅60.0cm スリムタイプ 412L 5ドア ホワイト SJ-GW41F-W</a></p><p>最近まで、2004年の就職のタイミングで購入した130L台の小さな冷蔵庫を使っていたが、日常的に自宅で食事を準備しようとすると、容量的にはかなり不満を感じるサイズだった。また、1-2年前から変なリレー音が聞こえるようになっていたので、冷蔵庫を買い換えたいと思っていた。</p><p>ペットボトル等の飲料類がたくさん冷やせることを求めると観音開きは自分に向いていない気がして、また転居の際にもドアの方向がネックにならないようにと考えてシャープの両開きドアにした。別にもっと大きいサイズの冷蔵庫でもいいかなと思ったけど、412Lであれば当面は不自由ないだろうし、横幅600mmであれば転居の際に冷蔵庫の設置場所が制約事項になることはないだろう、という判断でこのサイズに決めた。</p><p><br /></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">酔った勢いでIYHしたアレが納品された <a href="https://t.co/N89LUlIiEo">pic.twitter.com/N89LUlIiEo</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1288693283388977153?ref_src=twsrc%5Etfw">July 30, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p>しばらく使ってみて感じるのは、もっと冷凍スペースが大きくてもいいかな、という事。冷蔵庫が割とスカスカで、冷凍庫の利用率が非常に高い(後述するエアオーブンが非常に便利だからだ。冷蔵庫とエアオーブンの相乗効果とも言えるかもしれない)。</p><p><br /></p><h3 style="text-align: left;">水切りラック: ヨシカワ 1306081</h3><p><a href="https://www.amazon.co.jp/%E3%83%A8%E3%82%B7%E3%82%AB%E3%83%AF-Yoshikawa-%E6%B0%B4%E5%88%87%E3%82%8A%E3%83%A9%E3%83%83%E3%82%AF%E7%94%A8-15%C3%9757cm-1306081/dp/B07KVFN9LT/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B07KVFN9LT&qid=1610739668&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=4dcc2226d1a898d98583572653984fe9&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B07KVFN9LT&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B07KVFN9LT" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/%E3%83%A8%E3%82%B7%E3%82%AB%E3%83%AF-Yoshikawa-%E6%B0%B4%E5%88%87%E3%82%8A%E3%83%A9%E3%83%83%E3%82%AF%E7%94%A8-15%C3%9757cm-1306081/dp/B07KVFN9LT/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B07KVFN9LT&qid=1610739668&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=4dcc2226d1a898d98583572653984fe9&language=ja_JP" target="_blank" rel="nofollow">ヨシカワ 日本製 水切りラック シンクサイド 幅の広がる 2段水切り 15~27.5×57cm 1306081</a></p><p>キッチンの左側スペースに余裕があったので、この奥行きにあわせた水切りラックを購入した。二階建てで、自炊初心者には贅沢すぎるようなサイズである。</p><p>後に包丁ホルダーも購入した(同社製品もあるが、私は他社製品を組み合わせている)。これをつけて以降、メインの包丁の定位置はココになった。外れて危ないのではないかと言われることがあるが、インシュロックで固定してあるので、震度7の地震でラック全体がひっくり返る状況でもなければ包丁が飛び出すことはない。</p><p><br /></p><blockquote class="twitter-tweet"><p dir="ltr" lang="en">My new gear… <a href="https://t.co/DQiYXL0iYS">pic.twitter.com/DQiYXL0iYS</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1274716165118386177?ref_src=twsrc%5Etfw">June 21, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p>食器棚を持っていないためシステムキッチンの収納スペースしか食器や調理器具の格納場所がなく不便なので、褒められた状況ではないが、水切りラックにモノが残りがち。その状況で、このサイズ感はとても便利に使っている。</p><p>この水切りラックはいまの賃貸物件のキッチンの作りにぴったりな仕様のものにしてしまった。日本メーカー製で比較的高級ナモノだけど、将来引っ越しをしたときには、この水切りラックがうまく使えないかもしれない。でもいまのキッチンでの日々が幸せだから、それはそれでいい。</p><p><br /></p><h3 style="text-align: left;">炊飯用の鍋: ストウブ ココットでゴハン S</h3><p><a href="https://www.amazon.co.jp/staub-%E3%82%B9%E3%83%88%E3%82%A6%E3%83%96-%E3%80%90%E6%97%A5%E6%9C%AC%E6%AD%A3%E8%A6%8F%E8%B2%A9%E5%A3%B2%E5%93%81%E3%80%91-Cocotte-40509-653/dp/B001J6N1VY/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B001J6N1VY&qid=1610739367&sr=8-2&linkCode=li2&tag=wyrm-22&linkId=8adfda669047c127a1574bb07d1736a8&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B001J6N1VY&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B001J6N1VY" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/staub-%E3%82%B9%E3%83%88%E3%82%A6%E3%83%96-%E3%80%90%E6%97%A5%E6%9C%AC%E6%AD%A3%E8%A6%8F%E8%B2%A9%E5%A3%B2%E5%93%81%E3%80%91-Cocotte-40509-653/dp/B001J6N1VY/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B001J6N1VY&qid=1610739367&sr=8-2&linkCode=li2&tag=wyrm-22&linkId=8adfda669047c127a1574bb07d1736a8&language=ja_JP" target="_blank" rel="nofollow">staub ストウブ 「 ラ ココット de GOHAN ブラック S 12cm 」 ご飯鍋 炊飯 1合 鋳物 ホーロー 鍋 炊飯器 【日本正規販売品】 La Cocotte de GOHAN 40509-653</a></p><p>何年か前に、購入から15年ほど経過した炊飯器の蓋部分が壊れてしまい、それ以後自宅で炊飯できなくなっていた。新しい炊飯器はコレを買う1年前ぐらいから探しはじめていて、ふるさと納税で入手しようかとか、折角だから美味しく炊ける炊飯器がいいなとか色々と考えて市中のラインナップを見ていたのだが、特に美味しそうに炊飯できそうなのはファミリー向けサイズで、私のような独身にちょうど良さそうなサイズのものはあまり選択肢がないと感じていた。</p><p>このホーロー鍋に水 200ml と米 1合をいれてしばらく時間をおいた後、ガスコンロ強火で一気に沸騰させて、沸騰したら一度全体をかき混ぜ、蓋をして弱火に。5分後に火を止めたら10分ほど蒸らし、食べられる。炊飯にかかる手間は、強火の間の数分間と、キッチンタイマーからの割り込みが発生した瞬間だけ。平行で洗い物などをしているとこの時間はロスには感じないし、炊飯器での炊き上がりまで数十分待っていた頃がバカらしくなる手軽さである。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">うまくて、私は突然米を炊き始め、ほかの人が野菜を追加で買いに行った <a href="https://t.co/0AI0wLVK91">pic.twitter.com/0AI0wLVK91</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1265960514699452416?ref_src=twsrc%5Etfw">May 28, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p>米はゆめぴりかの無洗米を使っているので、といではいない。とぐ手間が発生すると自分的にはかなりハードルが上がるかなと思う。毎回1合で炊いているが、大抵は0.5合ぐらいでよかったりもするので、半分はジップロック容器に移して冷凍している。冷凍された米は容器から出してジップロック袋に移し、過去に炊いたが食べていない米はストックしている。本当にすぐに食事にありつきたい時などは、このストックが活躍している。</p><p>このホーロー鍋は底の径がかなり小さいので、標準的なガスコンロでは標準の五徳に乗らない。このため、小さい鍋などが載せられる五徳を併用している。</p><p><a href="https://www.amazon.co.jp/%E3%83%91%E3%83%BC%E3%83%AB%E9%87%91%E5%B1%9E-%E5%A4%96%E5%BE%8414cm-%E9%89%84%E9%8B%B3%E7%89%A9%E8%A3%BD%E3%83%9F%E3%83%8B-%E3%83%9B%E3%83%BC%E3%83%AD%E3%83%BC%E5%8A%A0%E5%B7%A5-HB-4198/dp/B07K44NV78/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B07K44NV78&qid=1610739430&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=6937f8932ac6680960d749e78f55a610&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B07K44NV78&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B07K44NV78" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/%E3%83%91%E3%83%BC%E3%83%AB%E9%87%91%E5%B1%9E-%E5%A4%96%E5%BE%8414cm-%E9%89%84%E9%8B%B3%E7%89%A9%E8%A3%BD%E3%83%9F%E3%83%8B-%E3%83%9B%E3%83%BC%E3%83%AD%E3%83%BC%E5%8A%A0%E5%B7%A5-HB-4198/dp/B07K44NV78/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B07K44NV78&qid=1610739430&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=6937f8932ac6680960d749e78f55a610&language=ja_JP" target="_blank" rel="nofollow">パール金属 五徳 ブラック 外径14cm 鉄鋳物製ミニ ホーロー加工 フェール HB-4198</a></p><p>実はいま使っているのはふたつ目。洗い物を終えた後にガスコンロで加熱して乾かしたりしていたのだが、ひとつ目の個体を加熱しすぎて底を割ってしまったので、二つ目を購入した。空焚きしてはいけないのだが、温度センサーつきのガスコンロだから大丈夫だろうと油断していたら破損してしまった。まあ底が割れていても使っていいみたいだけども、表面のガラス質が欠けていてカケラを食べるるのは気持ち的に嫌だし、錆びやすくもなっており扱いが面倒で、買い直した。</p><p><br /></p><h3 style="text-align: left;">包丁: 京セラ セラミックナイフ</h3><p><a href="https://www.amazon.co.jp/%E4%BA%AC%E3%82%BB%E3%83%A9-%E3%82%BB%E3%83%A9%E3%83%9F%E3%83%83%E3%82%AF-%E6%BC%82%E7%99%BD%E9%99%A4%E8%8F%8COK-%E7%84%A1%E6%96%99%E7%A0%94%E3%81%8E%E7%9B%B4%E3%81%97%E5%88%B8%E4%BB%98-FKR-160GR/dp/B00N9OFLGM/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B00N9OFLGM&qid=1610739616&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=6dc17ecb2cb171285099d29758102aee&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B00N9OFLGM&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B00N9OFLGM" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/%E4%BA%AC%E3%82%BB%E3%83%A9-%E3%82%BB%E3%83%A9%E3%83%9F%E3%83%83%E3%82%AF-%E6%BC%82%E7%99%BD%E9%99%A4%E8%8F%8COK-%E7%84%A1%E6%96%99%E7%A0%94%E3%81%8E%E7%9B%B4%E3%81%97%E5%88%B8%E4%BB%98-FKR-160GR/dp/B00N9OFLGM/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B00N9OFLGM&qid=1610739616&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=6dc17ecb2cb171285099d29758102aee&language=ja_JP" target="_blank" rel="nofollow">京セラ 包丁 ファイン セラミック 三徳包丁 16cm グリーン 漂白 除菌 対応 無料研ぎ直し券付 Kyocera FKR-160GR</a></p><p>これまで2000円程度の包丁を使っていて、研いでみたりもしたけども、やはり慣れていない人間が研いでもなかなか切れるようにはならなかった。このセラミックナイフは今のところ非常に快適に利用できている。タマネギを切っていても目が痛くならないだけでも大変助かっている。固い食材に対してだと刃が欠けたり、捻ると割れたりというリスクはあると思うが、そういう事はしないように注意している(場合によっては古い包丁を併用)。</p><p><br /></p><h3 style="text-align: left;">エアーオーブン: レコルト Air Oven エアーオーブン ノンフライヤー RAO-1<span style="font-size: 18.72px;"> </span></h3>
<p><a href="https://www.amazon.co.jp/%E3%83%AC%E3%82%B3%E3%83%AB%E3%83%88-Oven-%E3%82%A8%E3%82%A2%E3%83%BC%E3%82%AA%E3%83%BC%E3%83%96%E3%83%B3-%E3%83%8E%E3%83%B3%E3%83%95%E3%83%A9%E3%82%A4%E3%83%A4%E3%83%BC-RAO-1/dp/B082TPBN6N/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B082TPBN6N&qid=1610739471&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=3465f89b4c00ba208fb82cdd8ad8688d&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B082TPBN6N&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B082TPBN6N" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/%E3%83%AC%E3%82%B3%E3%83%AB%E3%83%88-Oven-%E3%82%A8%E3%82%A2%E3%83%BC%E3%82%AA%E3%83%BC%E3%83%96%E3%83%B3-%E3%83%8E%E3%83%B3%E3%83%95%E3%83%A9%E3%82%A4%E3%83%A4%E3%83%BC-RAO-1/dp/B082TPBN6N/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B082TPBN6N&qid=1610739471&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=3465f89b4c00ba208fb82cdd8ad8688d&language=ja_JP" target="_blank" rel="nofollow">レコルト Air Oven エアーオーブン ノンフライヤー RAO-1 レッド</a></p><p>妹の家で、フィリップス製のノンフライヤーでフライドポテトをさくさくっと作っているのを見て、ノンオイルフライヤーは便利で良さそうだなと思っていた。ただ、フィリップス製のノンオイルフライヤーはもう廃番になっており、中古品しか市中では見かけないので、代わりになるものを探していた。グリルやオーブンレンジの代替として利用しているが、かなり手軽に使えるので気に入っている。購入してからの利用頻度は当初を想像を大幅に超えて高い。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">新兵器を導入したのでもうポテト恋しさにマクドナルド行かなくていい <a href="https://t.co/xVQKTyOtJQ">pic.twitter.com/xVQKTyOtJQ</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1292016686258774017?ref_src=twsrc%5Etfw">August 8, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p>このモデルは、ノンオイルフライヤーというよりは、製品タイトルにあるとおりエアオーブンだ。中に電熱器とファンが入っていて、稼働中に空気をかき混ぜる仕組みになっている。フィリップスの本物なノンフライヤーは掃除機並の音を出していた(それぐらい空気を高速に循環させている)が、この製品はそこまでのものではない。</p><p>本物のエアフライヤーと比べれば格段に静かなので集合住宅で真夜中に使っても迷惑をかけない点はメリットだが、ノンフライヤーとしてはパワー不足。 空気をかき混ぜてくれて、しみ出した油分がカゴの底に貯まるオーブンだと捉えたほうがいい。他の製品と比べると角張っているので、洗い物はしやすい方で、それが頻繁に利用する上で心理的障壁を下げているように感じる(その代わり空気の循環がトレードオフになっているかもしれない)。</p><p>電子レンジのオーブン機能で冷凍フライドポテトを加熱するのが地味に手間だが、これを使うととても簡単だ。魚の切り身を焼くのにも使える。コンロのグリルを使わなくてもいいので掃除する場所も減る(私は、もうグリルを使うことはないと思って、排気口を封印してしまった)。冷凍唐揚げは、一度油で揚げられたモノはうまくいくが、揚げる手前で冷凍された唐揚げには対応できないと思ったほうがいい。ノンフライヤーとしての機能を求めるなら、たぶん他にもっといいモデルがあるだろう(買い換えてもいいかもしれない)。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">幸せな食生活 <a href="https://t.co/QXUDHtxxZ5">pic.twitter.com/QXUDHtxxZ5</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1340968213903855622?ref_src=twsrc%5Etfw">December 21, 2020</a></blockquote><p><br /></p><h3 style="text-align: left;">PVCキッチンマット</h3><p><a href="https://www.amazon.co.jp/%E3%82%AD%E3%83%83%E3%83%81%E3%83%B3%E3%83%9E%E3%83%83%E3%83%88-45%C3%97180cm-%E5%8E%9A%E3%81%951-5mm-%E3%82%AF%E3%83%AA%E3%82%A2%E3%83%9E%E3%83%83%E3%83%88-%E3%81%8A%E6%89%8B%E5%85%A5%E3%82%8C%E7%B0%A1%E5%8D%98/dp/B07YWS9ZKS/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B07YWS9ZKS&qid=1610739541&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=6d8c651d58f9755925d934f346d4501e&language=ja_JP" target="_blank" rel="nofollow"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B07YWS9ZKS&Format= _SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=wyrm-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=wyrm-22&language=ja_JP&l=li2&o=9&a=B07YWS9ZKS" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p> <p><a href="https://www.amazon.co.jp/%E3%82%AD%E3%83%83%E3%83%81%E3%83%B3%E3%83%9E%E3%83%83%E3%83%88-45%C3%97180cm-%E5%8E%9A%E3%81%951-5mm-%E3%82%AF%E3%83%AA%E3%82%A2%E3%83%9E%E3%83%83%E3%83%88-%E3%81%8A%E6%89%8B%E5%85%A5%E3%82%8C%E7%B0%A1%E5%8D%98/dp/B07YWS9ZKS/ref=as_li_ss_il?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=B07YWS9ZKS&qid=1610739541&sr=8-1&linkCode=li2&tag=wyrm-22&linkId=6d8c651d58f9755925d934f346d4501e&language=ja_JP" target="_blank" rel="nofollow">キッチンマット クリア PVC 45×180cm 厚さ1.5mm クリアマット 台所マット 透明マット ソフト 撥水 おしゃれ 汚れ防止 お手入れ簡単 床暖房対応 滑り止め (180*45cm)</a></p><p>今回のキッチンでは、PVCの透明なキッチンマットを使用している。液体をこぼしても、モップで拭き取るだけで済む。物件の床を汚さないで済むし、洗濯機で洗わなくても簡単に掃除できるのがとても便利。今後も同じようなものを使い続けるだろう。</p><p><br /></p><h3 style="text-align: left;">これを言ってしまうと身も蓋もないシリーズ1: 広いキッチン</h3><p></p><p>最後に、装備というよりは環境的要素について。フルサイズのキッチンは本当に便利だ。自炊慣れしていないシロートの私のような存在にとって、横幅1メートルにコンロと流し台が集約されているようなユニットキッチンでの料理は、経験がない上でハンデを背負わされているようなものだ。広いキッチンがあるだけで、自炊の難易度はガクッと下がる。</p><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">当初はキッチン全然使えなかったが、15年間で気づいたこと。水栓のアナログ操作に慣れること。食中毒と加熱について最低限のしくみを理解する(Cooking for Geeksなど)。<br /><br />あと、大きなキッチンを使うこと。コレ。単身者向け物件のなんちゃってキッチンは素人には難しすぎる。余裕のある鍋を使うこと。 <a href="https://t.co/6db5MRdIjd">pic.twitter.com/6db5MRdIjd</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1262000141155762178?ref_src=twsrc%5Etfw">May 17, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><p><br /></p><h3 style="text-align: left;">これを言ってしまうと身も蓋もないシリーズ2: グロサリー店へのアクセス</h3><p>2020年までは坂が多い地域に住んでいて、スーパーで食材を購入して自宅に持ち帰るためには必ず坂道を登らないといけなかった。これはかなりのハードルだった。首都圏で車は持っていないので徒歩がメイン、坂が多いこともあり自転車も持っていなかった。</p><p>いまは複数のグロサリー店へ徒歩5分以内にアクセスできる立地になったことで、食材を買いにいく行為に対する障壁がとても下がっている。隣のブロックのコンビニに行くレベルの感覚で、ただ税別100円のカットねぎだけを買うつもりで外出するのすら苦ではないレベルである。次に引っ越しするときも、スーパーなどが近い場所にしようと思う。</p><p><br /></p><h3 style="text-align: left;">まとめ: 環境が揃ったら自宅ごはんが楽しくなった </h3><p>私はもともと、食事を準備するために時間をかけたくないと思っている。引っ越し前は、起きたらすき家に行って朝食メニューを頼むような生活をしていた。コロナウイルスが問題にならなかったら、こんなに普段から自宅でごはんを食べていなかったか、弁当などに依存していたと思う。1年前の食生活と比べて、1日あたりのコストはコンサバに見積もっても半額以下になっていて、冷蔵庫以外はすでに投資対効果は得られている。</p><p>使いやすいツールを揃えるということは、台所に対する苦手意識を和らげてくれて、場合によっては手間や苦痛を取り除いてくれるんだなあと改めて感じている。スノーボードでも下着やフリースなどをユニクロから山用に変更したときに、それまでの苦労から解放されてとても快適になった。自宅でごはんを食べるのも、同じようなものだなあと思う。</p><p>この一年間の食生活の変化は、自分の残りの人生の食習慣そのものを変えることになることを確信している。</p><p><br /></p> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p><blockquote class="twitter-tweet"><p dir="ltr" lang="ja">夜にほとんど食べずに寝ちゃったので朝からごちそうを用意した <a href="https://t.co/NWNTguiTtS">pic.twitter.com/NWNTguiTtS</a></p>— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1347334454285504513?ref_src=twsrc%5Etfw">January 8, 2021</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script><p></p>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com1tag:blogger.com,1999:blog-8995862947808038366.post-37847362437583494922019-12-10T12:32:00.001+09:002019-12-10T12:32:21.732+09:00ARM搭載FPGAボードでHDMI->VNCサーバーを動かした話この記事は<a href="https://qiita.com/advent-calendar/2019/sakura">さくらインターネット Advent Calendar 2019</a> の 6日目です。<br />
<br />
こんにちわ。さくらインターネット在籍の @hasegaw です。今年も Advent Calendar に参加……していたのですが体調不良により投稿が大幅に遅れました😫<br />
<br />
今回は、2019年4月に開催されたAI・人工知能EXPO さくらインターネットブースで展示したデモンストレーションの構築時に使ったトリック(?)を紹介します。<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img alt="" class="aligncenter wp-image-1968200105" height="266" sizes="(max-width: 690px) 100vw, 690px" src="https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/02R2-1024x682.jpg" srcset="https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/02R2-1024x682.jpg 1024w, https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/02R2-300x200.jpg 300w, https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/02R2-768x512.jpg 768w" style="margin-left: auto; margin-right: auto;" width="400" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">弊社ブース@AI人工知能EXPO 2019</td></tr>
</tbody></table>
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img alt="" class="aligncenter wp-image-1968200100" height="266" sizes="(max-width: 690px) 100vw, 690px" src="https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/07R2-1024x682.jpg" srcset="https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/07R2-1024x682.jpg 1024w, https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/07R2-300x200.jpg 300w, https://www.sakura.ad.jp/information/wp-content/uploads/2019/04/07R2-768x512.jpg 768w" style="margin-left: auto; margin-right: auto;" width="400" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">今回展示したデモ</td></tr>
</tbody></table>
<br />
<br />
<b>デモ制作の背景</b><br />
<br />
2019年は、さくらインターネットとしてもこれまでより大きなブースを作ることになり、立ち寄られた方に楽しんでもらえる「インタラクティブなデモ」をしよう、ということになりました。<br />
<br />
以前の展示会でのデモは私が制作していたのですが、時間の都合もあり、今回のデモの実装は <a href="https://jp.pegara.com/">Pegara</a> 社にお願いしました。<br />
<br />
<br />
<b>データセンター内で映像デモを構築</b><br />
<br />
高火力コンピューティングのノードを展示会場で稼働させることにしたのですが、その場での推論結果を大型ディスプレイに表示するには、 Tesla V100 では役不足です(同モデルにはビデオ出力がない)。サーバー用の組み込みビデオプロセッサでは、ビデオの出力性能が貧弱で、今回のデモのようなインタラクティブな描画には向きません。このため、 Tesla の代わりに Quadro RTX 5000 を搭載し、同ボードから映像を出すことにしました。<br />
<br />
実質的に「Quadro RTX 5000 を搭載したデュアルプロセッサのワークステーション」ですが、非常に大きなマシンなので、搬出・搬入も一苦労します。このため、最初から最後までデータセンター内でマシン(予備機を含めて2台)のセットアップを済ませておき、データセンターからビックサイトの展示会場まで直送することにしました。<br />
<br />
ただ、会場でデモ中に映像が途切れるようなことがあってはテンションだだ下がりです。このため、データセンターに置いたまま、デモの動作が途切れないかを確認するための手段が必要でした。<br />
<br />
通常のサーバーであれば、 BMC のリモートコンソール機能が有効ですが、後から Quadro RTX 5000 ビデオカードを増設した場合には、そのような便利機能は使えません。<br />
<br />
IP-KVM 装置でも倉庫に転がっていればよかったのですが、そもそもホスティング事業が主なビジネスともいえる弊社の場合、KVM切り替え機すらほとんど見かけません。このため、 Quadro から出力された映像をリモートから確認するというイレギュラーな要件に適したオモチャを適当に見繕う必要がありました。<br />
<br />
<br />
<b>データセンター内のHDMI映像を観測するためにどうするか</b><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo4GW9Gda6hDumm8exNRgmXUrrfQntBH6wCWqR75yeS7LB3W5hDq3gSI3QFAS_EPk2a-YR5LhYkq2lHaMKIhDIA-evSq55iIZ10zlEnAfviueXEQ7RQMUc7v9nfY0VZ7qbOBoHaptdUOE/s1600/Screen+Shot+2019-12-09+at+20.59.00.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="36" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo4GW9Gda6hDumm8exNRgmXUrrfQntBH6wCWqR75yeS7LB3W5hDq3gSI3QFAS_EPk2a-YR5LhYkq2lHaMKIhDIA-evSq55iIZ10zlEnAfviueXEQ7RQMUc7v9nfY0VZ7qbOBoHaptdUOE/s400/Screen+Shot+2019-12-09+at+20.59.00.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
いちばん最初に思いつくのは HDMI キャプチャデバイスなどをサーバラック内に仕込む方法です。ただ、この方法では別途 PC 等を用意する必要があり、面倒です。このため、今回は ARM 搭載 FPGA ボードを利用することにしました。<br />
<br />
FPGA と言っても、今回利用した PYNQ-Z1 ボードでは、用意されているイメージを microSD カードに書きこむだけで、 HDMI ポートからの DVI-D 信号キャプチャーが可能です。<br />
<br />
プログラマブルロジックに Xilinx の <a href="https://japan.xilinx.com/products/intellectual-property/axi_video_dma.html">AXI Video DMA</a> IP がインプリメントされているので、このレジスタを<a href="https://gist.github.com/hasegaw/9f677da6cfaf631245757072efffa558">自分でARMコア側から叩いてやれば、DVI-D から1フレームを読み取るのは割と簡単</a>です。<br />
<br />
以前、実験的に「<a href="https://github.com/hasegaw/hdmi_vncserver">PYNQ-Z1にDVI-Dで入力された映像がが映るVNCサーバ</a>」を試作していたため、それを使いました(使ってみたかったw)<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbywqUdgkrf1Lp1Dd8Fi1ZHqt7UxpRt93EEHYO49XKlPCUw6GHNqSKA4GWk8qA8q2pH1ePAhW2f2K-ALYlSTi7zu3tRRPBqEsHQOHqWyvDtVlwsEICfMeQYe0HrAmZTaIiOLVpt6ftJiQ/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2019-02-14+12.02.11.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbywqUdgkrf1Lp1Dd8Fi1ZHqt7UxpRt93EEHYO49XKlPCUw6GHNqSKA4GWk8qA8q2pH1ePAhW2f2K-ALYlSTi7zu3tRRPBqEsHQOHqWyvDtVlwsEICfMeQYe0HrAmZTaIiOLVpt6ftJiQ/s400/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2019-02-14+12.02.11.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">DVI-D信号が映る謎なVNCサーバー</td></tr>
</tbody></table>
<br />
<b>4-in-1 HDMI マルチビューアの利用</b><br />
<br />
今回、会期中にマシン障害が発生した場合の対策として本番機と予備機の2台を準備しました。この2台のマシンの出力を同時にモニタリングするために複数映像を同時表示できるHDMIマルチビューアを利用しました。<br />
<br />
この装置を介しておくとマシンの再起動中などにも常に 1080p60 の信号が出続ける特徴があり、長期間にわたるビデオキャプチャのトラブルを防ぐ上でも有効です。<br />
<br />
今回使用した 4-in-1 マルチビューアは<a href="https://github.com/hasegaw/hdmi_switcher">シリアルコンソール操作により表示内容の切り替えも可能</a>ですので、両方の画面を出力したり、片方の画面をフルスクリーン表示したり、と遠隔操作することも可能です。<br />
<br />
<br />
<b>データセンターに設置</b><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxTTEM-641EBwpMwoEPtnL8968nzqGWEA-ZWA3HkrchbKE3QbFt0xMQh28MdBXf6pNwOOV9K3ET8XMOw_ABS7Nc3kZ1fiK6BEZUfW8k2BXA_Wnh0DZU5-E1l48KOoHM5MmWKGR38K0Jgs/s1600/Screen+Shot+2019-12-10+at+10.52.13.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxTTEM-641EBwpMwoEPtnL8968nzqGWEA-ZWA3HkrchbKE3QbFt0xMQh28MdBXf6pNwOOV9K3ET8XMOw_ABS7Nc3kZ1fiK6BEZUfW8k2BXA_Wnh0DZU5-E1l48KOoHM5MmWKGR38K0Jgs/s400/Screen+Shot+2019-12-10+at+10.52.13.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">全体像</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0UiPCKu_xFyBtLVW9DYPsR1zBqkpcjU9W42QK5-XOHN8L_dlKX2ilmrxVnqFRNFDyR28KxFTGut83ChqgYj72FNaRjxbAh5iiCltnCFbHtl-jVELplI2eCZi015mI3TrehBRs_WuHFWw/s1600/Screen+Shot+2019-12-10+at+10.58.03.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="323" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0UiPCKu_xFyBtLVW9DYPsR1zBqkpcjU9W42QK5-XOHN8L_dlKX2ilmrxVnqFRNFDyR28KxFTGut83ChqgYj72FNaRjxbAh5iiCltnCFbHtl-jVELplI2eCZi015mI3TrehBRs_WuHFWw/s400/Screen+Shot+2019-12-10+at+10.58.03.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="font-size: 12.8px;">データセンターから送られてきたサーバーの映像<br />(Ubuntu 16.04と、BIOSのPOST画面が映っている)</td></tr>
</tbody></table>
<br />
これでリモートからVNC経由でデータセンター内の画面を表示できるようになりました。この仕組みは1ヶ月以上無事に動き続け、でデモの開発はほぼリモートで行われ、実際にマシンの前で作業を行ったのは搬出前の動作確認(1日)のみで済みました。<br />
<br />
<br />
<b>最適化の余地</b><br />
<br />
コードを見られるとすぐわかるのですが、非常に雑な実装でフレームバッファのコピーを繰り返しています。<br />
<br />
PYNQのbitstreamに含まれているビデオキャプチャはOpenCVで用いられる1pxあたり24bit BGR順フォーマットに合わせられており、libvncserverが求める1pxあたり32bit RGB順のピクセルフォーマットとは異なっています。このため、今回のコードではOpenCVをcvtColor関数を用いてソフトウェアでフォーマット変換していますが、ちゃんと性能を出したければ PL 側で libvncserver が要求するビデオフォーマットに変換した状態で DMA コントローラに食わることでゼロコピー化も可能でしょう。<br />
<br />
以前から事情が変わっていなければOpenCVをNEON命令を利用するように再コンパイルするだけでも上記の色変換処理の速度はあがるのですが、PYNQ-Z1のメモリ帯域幅は細いのので PL からビデオのピクセルデータを受け取る時点で工夫するのが理想です。<br />
<br />
また、フレームバッファのなかで変化した範囲を libvncserver に渡せれば画面の差分転送が可能になるので、そこまでやりきれば、一般的なデスクトップ画面などを転送する場合にパフォーマンスが高いものが作れるのではないかと思っています。<br />
<br />
VNCは、変更があった領域のみを転送することが可能なプロトコルですので、各種パフォーマンスのチューニングをしていけば今後で活用余地が見いだせるのではないかと思っています。<br />
<br />
<br />
<b>別の実装方法</b><br />
<br />
今回使用したVNCサーバーは、まだホントに画面が映るだけで差分転送をしていないので画面全体を毎回再転送するため非効率でした。正直なところ、性能だけを考えれば、入力フレームを<a href="https://github.com/hasegaw/IkaLog/blob/master/ikalog/outputs/webserver/preview.py">Motion JPEG にエンコードしてストリーミング</a>する実装を使ったほうが良かったと思います。<br />
<blockquote class="twitter-tweet">
<div dir="ltr" lang="ja">
最新の <a href="https://twitter.com/hashtag/IkaLog?src=hash&ref_src=twsrc%5Etfw">#IkaLog</a> with PYNQ-Z1 開発風景 <a href="https://t.co/ZM7BPrfSrC">https://t.co/ZM7BPrfSrC</a> <a href="https://t.co/A62lbn62MA">pic.twitter.com/A62lbn62MA</a></div>
— IkaLog_JA (@IkaLog_ja) <a href="https://twitter.com/IkaLog_ja/status/834782461011718145?ref_src=twsrc%5Etfw">February 23, 2017</a></blockquote>
<br />
別のハードウェアを使う方法として Raspberry Pi シリーズは H.264 エンコーダを持っているので、映像のストリーム送信の用途には向いています。CSI-2 カメラインターフェイスに<a href="https://www.mouser.jp/Embedded-Solutions/Interface-Modules/_/N-5g1o?P=1y9f2kt">HDMI to CSI変換モジュール</a>を取り付けるとHDMI映像をキャプチャできます。私がこの作業を行ったときはまだ <a href="https://github.com/shiguredo/momo">OpenMomo</a>などが利用できる状況にはなかったのですが、今時だとH.264+WebRTCなどもアリですね。<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO5nk3tOUb4ZAhf5-fa-vgDKXNrzQSaUyIaXse3FoNa2DLiae9-iD37IgSVmHSjyw6s2X6FTzz0_cEYOkEkcartMyrjX0TLwgm-r1EswJnZhgmVVGV_FRbuFgozy3c42I3jp0ejiGEKhI/s1600/IMG_0844.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiO5nk3tOUb4ZAhf5-fa-vgDKXNrzQSaUyIaXse3FoNa2DLiae9-iD37IgSVmHSjyw6s2X6FTzz0_cEYOkEkcartMyrjX0TLwgm-r1EswJnZhgmVVGV_FRbuFgozy3c42I3jp0ejiGEKhI/s400/IMG_0844.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"> 手元でも Raspberry Pi 4 + B101 ボードで色々試しています。</td></tr>
</tbody></table>
<br />
<b>まとめ</b><br />
<br />
映像デモマシンをデータセンター内に設置して開発するために、今回は手持ちの ARM+FPGA ボードでこしらえた「受信したDVI-D映像を表示できるVNCサーバー」を使ってみました。<br />
HDMI映像をIP経由でストリーミングできる手段は増えてきていますが、こんな方法もあるということで参考になれば幸いです。<br />
<br />
<br />
この記事は<a href="https://qiita.com/advent-calendar/2019/sakura">さくらインターネット Advent Calendar 2019</a> の 6日目でした。7日目の記事もお楽しみに。<br />
<br />
<br />
<b>過去に参加した Advent Calendar まとめ</b><br />
<ul>
<li>2018年12月: <a href="http://d.ballade.jp/2018/12/amdgpu.html">AMD GPUによるディープラーニング環境の構築</a></li>
<li></li>
<li>2015年12月: <a href="http://d.ballade.jp/2015/12/blog-post.html">スプラソン機材セットをつくりました</a></li>
<li>2015年12月: <a href="http://d.ballade.jp/2015/12/entrance-monitoring.html">おうちハックで戦った話</a></li>
<li>2015年12月: <a href="http://d.ballade.jp/2015/12/fluentbit-meets-xbee.html">Fluent-bit と XBee で作るセンサーネットワーク</a></li>
<li>2013年12月: <a href="http://d.ballade.jp/2013/12/ejectio.html">次世代I/Oインターフェイス「Eject-io」</a></li>
<li>2012年12月: <a href="http://d.ballade.jp/2012/12/interrupts-for-guest-vms.html">割り込みはいかにしてゲストの割り込みハンドラに届くのか</a></li>
<li>2011年1月: <a href="http://d.ballade.jp/2011/01/FreeBSD-vimage.html">FreeBSD VIMAGEを使ったTCP/IPのルーティング デモンストレーション</a></li>
</ul>
<br />
<br />
<br />
<br />hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-14020570437452625252019-09-25T21:49:00.003+09:002019-09-25T22:41:22.661+09:00iOSのAPNプロファイルをダウンロードして再インストールの時に備える現在、メインの携帯電話キャリアとして IIJmio を使用していますが、地味に手間なのが APN の設定です。<br />
<br />
APNプロファイルをダウンロードすればよいのですが、例えば海外出張から戻ってきて、現地の SIM カードから国内の SIM カードに戻すと、 APN プロファイルの設定やダウンロードが必要になります。ダウンロードするには LTE 通信ができるか、 WiFi アクセスポイントにたどり着かないといけません。すると、移動中にさくっと APN 設定を復元できなかったりします。<br />
<br />
ここでは、 iOS 系のデバイス(iPhone や iPad)で、オフラインのまま APN プロファイルを再インストールできる方法を紹介します。インターネットに接続できない状態で APN プロファイルをインストールできるよう、内蔵フラッシュ領域にコピーを置いておき、必要時にはあらかじめダウンロード済みの APN プロファイルをロードします。<br />
<br />
Safari で IIJmio APN プロファイルのダウンロードページを開きます。<br />
<a href="https://www.iijmio.jp/hdd/devices/config.jsp">https://www.iijmio.jp/hdd/devices/config.jsp</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjMcPBOqV6rmVgLX5r61jWyE7LuiASTr5XgP6Pbzbat8jyXGyJIsjsJyc-2fNSwVV6GmcrwOFnjn3vcxVunpkFUieb_7sVf5h-QdD4mSV_87pS-VX921xhQ5J7bCpK8GWI9zsAxTVxK10/s1600/868C6809-BDC7-4961-B655-014D33723474.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="739" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjMcPBOqV6rmVgLX5r61jWyE7LuiASTr5XgP6Pbzbat8jyXGyJIsjsJyc-2fNSwVV6GmcrwOFnjn3vcxVunpkFUieb_7sVf5h-QdD4mSV_87pS-VX921xhQ5J7bCpK8GWI9zsAxTVxK10/s320/868C6809-BDC7-4961-B655-014D33723474.png" width="147" /></a></div>
<br />
Cellular Payload 版の APN プロファイルの画像を長押しして、ポップアップを開き、リンク先のファイルをダウンロード を選択します。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxzb2hnmqIYsP2YTbMicbqWv24UYGzMdMQKHKberoJb06uJD6J5s0qndfB1YfAIpUn3BcPd7Z-3ovh-A9mDUhYqHJpp0V8_mp0K1xZ1RCCF1-ecVI_bfclGZlsy1djXiqjapz-cok5byc/s1600/F2CF892D-D577-4423-9E2F-76D5219D58A6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="739" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxzb2hnmqIYsP2YTbMicbqWv24UYGzMdMQKHKberoJb06uJD6J5s0qndfB1YfAIpUn3BcPd7Z-3ovh-A9mDUhYqHJpp0V8_mp0K1xZ1RCCF1-ecVI_bfclGZlsy1djXiqjapz-cok5byc/s320/F2CF892D-D577-4423-9E2F-76D5219D58A6.png" width="147" /></a></div>
<br />
<br />
Files アプリを起動し、ダウンロード済みファイルを確認すると iijmio-celluar ファイルが確認できます。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZjLqiNwTS5mFbCu_ea0Fespcwh2zxSVycY6SMA12vXeVupngZBcHoTOdrp1eqAC8nedXmygwN3Bhe0UiJnRNwlMDGng6z4WPuMAFu1zTklQ3fF0ZUnDHHH6Zm4oua2kXWr8F3jlEbnbk/s1600/95784F12-D30E-4BEA-9D0A-4F5698B842ED.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a><img border="0" data-original-height="1125" data-original-width="1125" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZjLqiNwTS5mFbCu_ea0Fespcwh2zxSVycY6SMA12vXeVupngZBcHoTOdrp1eqAC8nedXmygwN3Bhe0UiJnRNwlMDGng6z4WPuMAFu1zTklQ3fF0ZUnDHHH6Zm4oua2kXWr8F3jlEbnbk/s320/95784F12-D30E-4BEA-9D0A-4F5698B842ED.jpeg" width="320" /></div>
<br />
<br />
ただし、このダウンロード先フォルダは iCloud 上となっており、いざというときにアクセスできないかもしれません。<br />
<br />
画面右上の Select をクリックし、プロファイル ファイルを選択状態にして、画面下部からフォルダアイコンをタップしてプロファイルの移動画面を出します。そしてローカルストレージにコピーしましょう(このiPhone内もしくはiPad内)。まだ大事なAPNプロファイルを保存するのに適したフォルダを持っていなければ、この機会に作るとよいでしょう。私は hasegaw/private のなかにとりあえず保存しておくことにしました。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlJgZqcWeETuE4Ek-xKRVOALGmDk7EvL626fj04IUmQbkebBMkkKclLUJ9uz018N4BV5r9ExsGaTbyvbi1F1CkX595NXVEL1VKsh8UYNtHJkwol1g82pa7pdTALlsDRZC5ca8dl4owGnY/s1600/BB45881A-3EDA-4B90-9472-9B2379F1A68C.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1256" data-original-width="1125" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlJgZqcWeETuE4Ek-xKRVOALGmDk7EvL626fj04IUmQbkebBMkkKclLUJ9uz018N4BV5r9ExsGaTbyvbi1F1CkX595NXVEL1VKsh8UYNtHJkwol1g82pa7pdTALlsDRZC5ca8dl4owGnY/s320/BB45881A-3EDA-4B90-9472-9B2379F1A68C.jpeg" width="286" /></a></div>
<br />
<br />
Files から、今回ローカルストレージに保存した APN プロファイルをクリックすることによって、プロファイルをインストールできます。クリックしたプロファイルは IIJmio サイトからダウンロードした場合と同様に Settings からプロファイルのインストールを別途許可する必要があります。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2JLsRz6KIAvUdvLA0OWZ0N8JHnU0-eL4QDJ3i37c2rK-tBts6RwfT5wMHoJdae0bZXVN3ns1mJ-U6VslwmIDJwx4njJxG5kzzuP4QtfgY0D0KCXoQDBKTXrUhD_88NbcfIon71_hT-4I/s1600/789BA9C8-640A-4631-841A-23A4414E73EF.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1125" data-original-width="1125" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2JLsRz6KIAvUdvLA0OWZ0N8JHnU0-eL4QDJ3i37c2rK-tBts6RwfT5wMHoJdae0bZXVN3ns1mJ-U6VslwmIDJwx4njJxG5kzzuP4QtfgY0D0KCXoQDBKTXrUhD_88NbcfIon71_hT-4I/s320/789BA9C8-640A-4631-841A-23A4414E73EF.jpeg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
また iCloud 上にこのようなファイルを集めておけば、まとめてプロファイルを復旧するときにまとめてインストールできて便利です。たとえば、オレオレ証明書の pfx ファイルなどを置いておくと便利ですよ。
<br />
<br />
<blockquote class="twitter-tweet">
<div dir="ltr" lang="ja">
みおぽんアプリからプロファイルを入れています。 <a href="https://t.co/EI6Hgxl8uR">pic.twitter.com/EI6Hgxl8uR</a></div>
— know94space (@know94space) <a href="https://twitter.com/know94space/status/1176850061927469058?ref_src=twsrc%5Etfw">September 25, 2019</a></blockquote>
ガガーン・・・!<br />
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-6056985022419165162019-06-26T15:41:00.004+09:002019-06-26T15:42:48.586+09:00iPhone XでGoogle Fiをアクティベートしてみたアメリカ出張中にBestBuyでGoogle Fi SIMを普通に買うことができたので、買って契約してみました。<br />
<blockquote class="twitter-tweet">
<div dir="ltr" lang="ja">
店頭売りされていたので買った(2枚) <a href="https://t.co/JIUCNUhkFQ">pic.twitter.com/JIUCNUhkFQ</a></div>
— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/1142842305096716288?ref_src=twsrc%5Etfw">June 23, 2019</a></blockquote>
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
Google Fi は日本ではほとんど知られていないと思いますが、 Google が米国で提供する携帯電話サービスです。だいたいのサービスの特徴として<br />
<ul>
<li>20ドルで1電話回線(通話、Text、データ)を利用可能。10USD/1GB利用、ただし80USD/月で課金打ち止め</li>
<li>15GBぐらいまでは使える</li>
<li>世界170カ国ぐらいで、上記価格でLTEデータ通信が使えるので海外行きには便利</li>
<li>日本に持ってきているとUSの番号にかかってきた電話がローミングで受けられる?</li>
</ul>
<div>
といった感じになっています。詳しくは <a href="https://fi.google.com/">https://fi.google.com</a> を見てみてください。</div>
<div>
<br />
<br /></div>
<div>
<b>今まではどうしていたか</b></div>
<div>
<br /></div>
<div>
これまでは個人的にアメリカと連絡をとったりするときのために SkypeIn 番号をとっていました。はじめての海外がユタだったことから愛着もあり 1-801-****-**** の番号を押さえていました。</div>
<div>
<br /></div>
<div>
また、 iPad Pro の Apple SIM で 150日間で10GB程度使える $10 のプランこれまで3-4回契約してきました。だいたいの場合はこれで困らないのですが、以下のパターンでちょっと手間だなーというのがありました。</div>
<div>
<ul>
<li>カーナビゲーションに iPhone を使うときに毎回 iPad Pro 経由でテザリングを有効にしないといけないのが地味に面倒</li>
<li>Apple SIM から T-Mobile 契約をアクティベートできずにハマったことがある。LTEがある前提でいったら宿泊先の情報をUS到着後に確認せねばならず、LTEなしで別のホテルで泣きついてWiFiを借りるという苦労を去年テキサス州でしました。SIMアクティベートに苦労した詳細は <a href="http://d.ballade.jp/2018/11/apple-sim.html">IIJmio SIM カードが入った iPad Pro (2017) 10.5インチモデルで Apple SIM を使おうとして苦労した話</a> にまとめてあります。</li>
<li>結局、毎回 iPhone X 用に SIM が欲しいという状態になり、そのたびに AT&T や Verizon に駆け込み</li>
</ul>
<div>
<b><br /></b>
<b>Google Fi SIM を BestBuy で普通に発見</b></div>
</div>
<div>
<br /></div>
<div>
ちょっと目立たないところではありましたが、 Google Fi の SIM が BestBuy の携帯電話売り場に普通に売られて居ることに気づいて、とりあえず二枚買ってみました。一枚おおよそ10ドルしますが、10ドル分のデポジットがあるので実質タダになります(申し込みをした場合は無料で宅配で送ってもらえるものを店頭で値付けしているが、その分はデポジットになるという仕組みです)。もしかしたらSIMを使わずに放置したら有効期限切れになってしまうかもしれませんが、まあ男の子のおもちゃ的要素も強いので、そのときは、まあ、それでいいでしょう(その場でプリペイドカードを activate している感じなどはないので、たぶん大丈夫だとは思います)<br />
<br />
なお BestBuy での店頭売りがはじまったのは 2019年3月頃からのようです。</div>
<div>
<br />
<br /></div>
<div>
<b>アクティベートに必要なもの</b></div>
<div>
<b><br /></b></div>
<div>
翌日、早速契約してみることにします。事前に調べていたこともあり、だいたい必要なのはこんな感じだということがわかっていました。</div>
<div>
<ul>
<li>SIM カードを手元に準備する必要がある</li>
<li>Google US のアカウントでないとサインアップできないらしい?</li>
<li>US 内の住所が必要</li>
<li>課金用クレジットカードも US みたいな話をみかける</li>
</ul>
<div>
SIMカードは Google Fi の Web サイトから郵送を申し込むと1週間以上かかるそうでホテル宿泊者にはつらいですが、 BestBuy で小売りがはじまったことで一気にハードルが下がりました。<br />
<br /></div>
</div>
<div>
Google のアメリカのアカウントは作ればいいだけです。 Google Fi 申し込み時だけ在住国をアメリカに変更すればいいという話も見かけるのですが、何か面倒がおきて普段使いの Google アカウントに影響が出る場合を嫌って、今回は新しく Google US アカウントを独立したかたちで取り直しました。<br />
<br /></div>
<div>
US 内の住所は持っていませんが、「滞在先ホテルの住所を使う(嘘はついていない)」「勤務先会社のブランチオフィスの住所を使う」「知り合いの家の住所を借りる」「コワーキングオフィスの住所を借りる」といった手があるかと思います。残念ながらいまは雇用関係にある会社で直接米国内にブランチをもっていないので、関連会社の住所とか借りちゃおうかといろいろ悪巧みの考えたのですが、最終的にはホテル住所を入れ、アパート名として「The North Side Inn Guest」という要領で登録して、無事に開通までこぎ着けました。すべて正直で、嘘は一切ついていません。<br />
<br /></div>
<div>
最後の課金用クレジットカードでUS発行のものを用意する方法は思いつかなかったのですが、Webサイトで前例を調べていたら、US国内で買えるVISAなどのプリペイドカードに現金をチャージするという方法があるそうです。たとえば50ドルをスーパーマーケットなどで支払うとVISAのクレジットカードとしてプリペイド分だけ使えるカードを発行してもらえます。<br />
この手を使おうかなと思ったのですが、カードに残高を追加する refill が日本国内からできないであろうことを考え、とりあえず自分が持っているカードでダメ元で試すことにします。</div>
<div>
<br />
<br /></div>
<div>
<b>Google USアカウントを作成する</b></div>
<div>
<br /></div>
<div>
まずは US 内で Google アカウントを作成します。 Google アカウントの作成自体は特に普通のことですし細かくは書きません。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>Google Fi に加入する</b></div>
<div>
<br /></div>
<div>
米国内のホテルの WiFi を使って <a href="https://fi.google.com/signup">https://fi.google.com/signup</a> から申し込みを進めていきます。今回は端末を購入せずに Apple Store で購入済みの iPhone X と手元に準備した SIM カードを使用します。その条件で画面を遷移していくと 1回線20USD+データ10USD/1GB/mo.のプランが表示されます。</div>
<div>
<br /></div>
<div>
サービスアドレス(サービスを受けるメインの住所、おそらく緊急車両などを呼ぶ場合のベースエリアになる)の入力があったので、宿泊中のホテルの住所などをベースで入力します。(スタバWiFiなどで自宅住所のZIPコードをきかれたりしますが、とりあえずホテルのものを入れておくと通過できたりしますね)</div>
<div>
<br /></div>
<div>
課金先は、日本で発行された Delta American Express Gold を使っているので、こちらでの支払いという形にしたらあっさりと契約できました。</div>
<div>
<br />
<br /></div>
<div>
<b>Google Fi アプリを入手する</b></div>
<div>
<br /></div>
<div>
Google Fi は日本でサービスされていないので、 Apple のアカウントが日本在住になっていると Google Fi アプリが iPhone X 上の App Store で見つけられません。このため、一時的に普段使いの Apple アカウントを US に変更することにしました。</div>
<div>
<br /></div>
<div>
Apple サイトにログインし個人情報を変更します。先と同じ要領でホテル住所でアカウントを作成しました。ここで請求先クレジットカードを登録するように求められるのですが、単に None (なし)のみを選択して先に進みます。ここでは、 Google が許してくれた日本のクレジットカードは通りませんでした。また、一度でもカード番号などを入れ始めてしまうと None を選択してもカード番号が不正といったエラーメッセージが出て咲きに進めなくなってしまいました。</div>
<div>
<br /></div>
<div>
Apple アカウントが US ベースになってから iPhone X の App Store が US の App Store ベースになると、 Google Fi アプリが検索で出てくるようになりますので、インストールします。</div>
<div>
<br /></div>
<div>
ここまでが終わったら、 Apple アカウントの設定をまた日本に戻しておきます。</div>
<div>
<br />
<br /></div>
<div>
<b>Google Fi SIM をアカウントに追加する</b></div>
<div>
<br /></div>
<div>
続いて SIM を使えるようにしていきます。購入済みの SIM をスロットに差し込み、先ほど iPhone X にダウンロードした Google Fi アプリで SIM をアクティベーションします。SIMパッケージに付属のワンタイムキー入力、またAPN設定などを済ませると、端末を再起動し次第サービスが利用できるようになりますという旨のメッセージが表示されます。</div>
<div>
<br />
<br /></div>
<div>
<b>おつかれさまでした</b></div>
<div>
<br /></div>
<div>
上記で、割とあっけなく Google Fi の SIM を開通させることができました。</div>
<div>
<br />
<br /></div>
<div>
<b>どう使うつもり?</b></div>
<div>
<br /></div>
<div>
海外出張に出たときに、米国のほか Google Fi のサービスエリアであれば、空港に降り立った瞬間から音声、LTEデータが使える回線を手元に持つことができるのは十分なメリットあると思っています。<br />
<br />
現地のAT&Tマンスリープランと比べて同じぐらいかちょっと高いぐらいの利用料ですが、データ通信が少なければ割安になりそうですし、データ通信は基本的に iPad Pro で利用できるプランでテザリングすれば Google Fi での通信量を抑えられ、Fi に課金されないので、USの電話番号とLTEデータ通信が iPhone X から利用できるというメリットが発生します。<br />
<br />
Google Fi のLTEデータが高いと思うのなら、SIMを入手するまでの予備回線として利用するのもありかもしれません(まあ、それならAT&TとかのSIMカードを事前購入してアクティベートだけしろよという話はありそうですが)。</div>
<div>
<br /></div>
<div>
また米国内で取得したSIMを日本にもってきても、サービス的にはユーザがSIMを持って海外旅行した状態になります。米国電話番号に対する音声通話もローミングされる認識ですし、ある意味 SkypeIn みたいなものを SIM として持った状態になります。しかも多分 Text はできる。</div>
<div>
<br /></div>
<div>
また、日本で利用する場合、日本のMVNOと比べれば割高ではありますが、最大月80ドルで15GB以上通信できる非常用SIMとしても利用できます。</div>
<div>
<br /></div>
<div>
月20ドルを1年間寝かせても年間240ドルですし、激安とは思わないものの、SkypeIn番号を取得するのだけに月13ドルかかっているぐらいなら Google Fi を契約し続けても正直月7ドルぐらいしかランニングコストは変わりません。このため、 Google Fi はアクティブな状態で Skype In は解約することにしました。<br />
<br /></div>
<div>
<br /></div>
<div>
<b>eSIM じゃダメなの?</b></div>
<div>
<br /></div>
<div>
私が持っている iPhone X が eSIM 対応だったら eSIM で考えたかもしれません。ただ普通の SIM として持っていると、帰国後に自宅で余っているLTE端末などにさして電話を受けるといったことも可能なので、物理 SIM がいいかなーという思いはあります。</div>
<div>
<br />
<br /></div>
<div>
<b>おわりに</b></div>
<div>
<br /></div>
<div>
正直身構えた割にあっけなく開通した Google Fi ですが、しばらく使って(?)みようと思います。飽きたりコスパ悪いなと思ったら解約するかもしれませんが。</div>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-33721212983447532252018-12-04T18:18:00.001+09:002018-12-05T00:49:05.427+09:00AMD GPUによるディープラーニング環境の構築こんにちわ。さくらインターネット 高火力コンピューティングの雑用担当 @hasegaw です。このエントリは<a href="https://qiita.com/advent-calendar/2018/sakura">さくらインターネット Advent Calendar 2018</a> 4日目のエントリです。なお、前日のエントリは <a href="https://ravelll.hatenadiary.jp/entry/2018/12/03/131432">UIT#5 で登壇してきました + 資料への補足</a> でした。<br />
<br />
<br />
<b>新しい Radeon GPU が登場</b><br />
<br />
1ヶ月ほど前になりますが、2018年11月6日に、AMDが新しいGPU 「Radeon Instict MI60」を発表しました。4096のストリームプロセッサー、1TB/sの高帯域幅な32GB HBM2メモリを搭載し、PCIe 4.0 16レーンに対応したGPUです。また、ストリームプロセッサーが 3840 に変更された Radeon Instict MI50 というモデルを紹介されています。<br />
<br />
AMDが7nm提供開始、Vega「Radeon Instinct MI60」と最大64コアのRomeこと新「EPYC」を発表<br />
<a href="http://ascii.jp/elem/000/001/768/1768981/">http://ascii.jp/elem/000/001/768/1768981/</a><br />
<br />
<br />
<b>ディープラーニングと Radeon GPU</b><br />
<br />
Radeon GPUといえば、2018年はマイニングで話題になったりもしましたが、OpenCLによる計算用途にも利用できます。また、最近では ROCm と呼ばれるソフトウェア群によってディープラーニング目的でも使えるようになりました。<br />
<br />
<b>本当に動くの?</b><br />
<br />
Radeon でディープラーニングってきちんと動くの?ちょっと試してみないと判らないな……と思われたりするでしょうか?<br />
<br />
私は、高火力コンピューティングの仕事をしつつ、サイドプロジェクトで GPU を使ったりもするので、そのときはデータセンターをおいたマシンを使ったりもするのですが、かといって高価な Tesla を常に浪費するのも心が痛むので、最近は 10分の1のコストで済む Radeon で事足りる作業なら Radeon GPU を使ってみています。にわか機械学習マンとしては、現状 Radeon GPU で困ったことはありません。<br />
<br />
最近は TensorFlow もアップストリームに追従するかたちで ROCm 対応版が作られており、動かしてみても、だいたいの場合は問題なく動くようです。また、 Radeon Instict シリーズに一気にいかなくとも、秋葉原で手に入る Radeon シリーズでとりあえずの味見をすることも可能です。<br />
<br />
「本当に自分が持っているワークロードが動くの?」と気になる方は、 Pegara 社の GPU EATER をお試しになられてはいかがでしょうか。<br />
<br />
GPU EATER<br />
<a href="https://www.gpueater.com/">https://www.gpueater.com/</a><br />
<br />
なんと1時間あたり1ドル未満で、RadeonシリーズのGPUサーバーを試せます。また、ログインは事前に用意したSSH公開鍵に対応する秘密鍵でSSHするだけ。利用開始も簡単で、最初から ROCm フレームワークや TensorFlow サンプルなども入っています。<br />
<br />
<div style="border: 1x solid black;">
<span style="font-family: monospace;">root@C-2b457c0e-0884-4f80-94fc-4bbeec7ecb4c-685:~/deep_learning_yolo_v3# python3 yolo.py image.jpg</span><br />
<span style="font-family: monospace;">Using TensorFlow backend.</span><br />
<span style="font-family: monospace;">2018-10-10 04:56:03.761749: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1519] Found device 0 with properties:</span><br />
<span style="font-family: monospace;">name: Device 687f</span><br />
<span style="font-family: monospace;">AMDGPU ISA: gfx900</span><br />
<span style="font-family: monospace;">memoryClockRate (GHz) 1.622</span><br />
<span style="font-family: monospace;">pciBusID 0000:03:00.0</span><br />
<span style="font-family: monospace;">Total memory: 7.98GiB</span><br />
<span style="font-family: monospace;">Free memory: 7.73GiB</span><br />
<span style="font-family: monospace;">2018-10-10 04:56:03.761786: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1630] Adding visible gpu devices: 0</span><br />
<span style="font-family: monospace;">2018-10-10 04:56:03.761820: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1039] Device interconnect StreamExecutor with strength 1 edge matrix:</span><br />
<span style="font-family: monospace;">2018-10-10 04:56:03.761829: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] 0</span><br />
<span style="font-family: monospace;">2018-10-10 04:56:03.761848: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1058] 0: N</span><br />
<span style="font-family: monospace;">2018-10-10 04:56:03.761907: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1178] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 7524 MB memory) -> physical GPU (device: 0, name: Device 687f, pci bus id: 0000:03:00.0)</span><br />
<span style="font-family: monospace;">model_data/yolo.h5 model, anchors, and classes loaded.</span><br />
<span style="font-family: monospace;">(416, 416, 3)</span><br />
<span style="font-family: monospace;">Found 5 boxes for img</span><br />
<span style="font-family: monospace;">person 0.94 (143, 281) (216, 495)</span><br />
<span style="font-family: monospace;">person 0.97 (112, 17) (207, 331)</span><br />
<span style="font-family: monospace;">person 0.99 (239, 297) (317, 514)</span><br />
<span style="font-family: monospace;">person 0.99 (253, 98) (319, 364)</span><br />
<span style="font-family: monospace;">person 1.00 (38, 165) (102, 436)</span><br />
<span style="font-family: monospace;">20.274007220985368</span><br />
<span style="font-family: monospace;">Output => image.jpg.out.jpg</span></div>
<br />
<br />
<b>ROCm 環境のインストールって難しくないの? → 思ったより簡単でした</b><br />
<br />
手元に実際の Radeon GPU を用意し、環境を構築するにはどれぐらいの苦労があるでしょうか?実際 Ubuntu 16.04 ベースで試してみたときは、思ったほど難しくはありませんでした。 <a href="https://github.com/hasegaw/rocm-tensorflow-ansible/">https://github.com/hasegaw/rocm-tensorflow-ansible/</a> に、私が環境作成に使用している Ansible role から抜粋したものをおいておきますので、必要に応じて加工して利用してください。何をしているかというと<br />
<br />
ROCM 環境の構築)<br />
<br />
<ul>
<li>カーネルの更新</li>
<li>apt に ROCm レポジトリを追加</li>
<li>ROCm 関連パッケージをインストール。カーネルモジュールは DKMS で設定されます</li>
<li>/etc/profile.d/ に設定ファイルを展開</li>
<li>必要に応じてユーザ(既存/今後の作成時のデフォルト)のグループ設定を変更</li>
</ul>
<div>
TensorFlow のインストール)</div>
<div>
<ul>
<li>virtualenv をインストール</li>
<li>virtualenv 上に tensorflow-rocm をインストール</li>
</ul>
</div>
<div>
といった感じです。 ROCm は repo.radeon.com からのパッケージを拾えば動きますし、 TensorFlow も AMD 社がポートしたバージョンを PyPI に適宜パブリッシュしてくれているので、 pip install するだけの時代が来ているのです。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>利用感はどう?</b></div>
<div>
<br /></div>
<div>
どちらかといえば、パフォーマンスの面よりも、秋葉原などの店頭でカジュアルに手に入る Radeon Vega 64 は 8GB メモリモデルぐらいしか市場で見かけておらず、 Radeon Vega Frontier Edition (12GB) がほぼ市場から消えている状況で利用できるメモリ量が少ない点が、がつがつワークロードを回そうと思うと、ちょっと気になるかもしれません。</div>
<div>
<br /></div>
<div>
ワークロードによるので一概に言えないのですが、私が試した範囲では Radeon Vega 64 で NVIDIA TITAN X の8割から同等程度のパフォーマンスが得られていました。 GDDR5 搭載の NVIDIA GPU が HBM 搭載の Radeon Vega 64 に対して優位なのは NVIDIA すごいなーと思いますし、 Radeon 上でのチューニングはこれからなのかな、という感じがします。</div>
<div>
<br /></div>
<div>
現状の tensorflow-rocm は、CUDAバージョンのカーネルをコンバートして使っているようなので、このあたりの最適化が進めばさらに性能が伸びる余地もありそうです。例えば GitHub 上のアクティビティを眺めていると、和算+活性の "Fusion" カーネルの実装なども最近行われていました。どんどんアップデートされているので、今後が楽しみです。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>まとめ</b></div>
<div>
<br /></div>
<div>
AMD Radeon シリーズでのディープラーニングもそろそろ実用段階に入ってきたのではないか、という感じがしています。</div>
<div>
<br /></div>
<div>
ただ、ディープラーニング用途で Radeon 系 GPU をすでに持っている方はほとんどいないでしょう。そんな時でも、ご紹介したとおり、 Pegara 社が非常にお安い価格で Radeon GPU を利用できる GPU EATER を提供されていますので、興味が湧いたら、こちらのサービスを試してみてはいかがでしょうか。</div>
<div>
<br /></div>
<div>
<a href="https://qiita.com/advent-calendar/2018/sakura">さくらインターネット Advent Calendar 2018</a></div>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-70651976209140048032018-12-02T17:15:00.000+09:002018-12-02T17:51:22.521+09:00ジオラインとスポーツタイツで出張を乗り切るここ1〜2年で出張が多くなった(たぶんいままでの人生でいちばん移動してる)のだけども、移動にあたってはスノーボード等で色々試してきたノウハウを適用している。基本はモンベル ジオラインとスポーツタイツだ。今回はどうして私がジオラインとスポーツタイツの組み合わせを勧めるのかを紹介してみたい。<br />
<br />
<div>
<br /></div>
<div>
<b>ジオラインは日常生活でも便利な下着</b></div>
<div>
<br /></div>
<div>
ジオラインは綿のシャツよりも軽く、かさばらず、速乾性をもった素材で作られているアンダーウェアだ。汗をかいても、その汗を上のレイヤの方にさくっと移してくれる。結果として体から出た汗を肌から離してくれるので、汗冷めをしない。</div>
<div>
<br /></div>
<div>
ジオラインシリーズはこちら</div>
<div>
<div>
https://webshop.montbell.jp/goods/list.php?category=71000</div>
</div>
<div>
<br /></div>
<div>
私が知っている範囲でジオラインの下着は4種類ある。</div>
<div>
<br /></div>
<div>
・クールメッシュタイプ</div>
<div>
・薄手(L.W. = Light Weight</div>
<div>
・中厚手(M.W. = Middle Weight)</div>
<div>
・厚手(EXPedition)</div>
<div>
<br /></div>
<div>
仕事や町中での日常生活、もしくは出張で使うとしたら、クールメッシュタイプもしくは薄手タイプになる。クールメッシュタイプというのは、ユニクロでいうエアリズムラインのような、夏場に肌がさらさらに感じるようなタイプ。薄手をはじめとする他のタイプは、繊維のなかに空気を保持して、そこに体温で温まった空気が留まるため、暖かく感じる。なお、個人的には、いちばん汎用性が高いのはクールメッシュタイプかなと思っている。クールメッシュといっても不必要に冷感があるようなものではないので、冬でも「肌をドライに保ってくれる下着」として活躍する。</div>
<div>
<br /></div>
<div>
ジオラインをインナーとして利用していてメリットがあるのは、寒暖差があるところを行き来したときに汗をかいたりしてもへっちゃらなことだ。例えば、冬場だと、仕事を終えてからコートを着て駅まで歩き、電車にのったら電車内で暖房がかかっていて汗をかき、コートの下で汗びっしょりになった下着に凍えたり、とか、そんな経験はないだろうか。<br />
<br />
ジオラインだとこのようなタイミングで汗をかいても上のレイヤに汗を発散してくれるので寒いと感じる事がほとんどない。ジオラインを使うようになる前に使っていたユニクロ ヒートテックなどを久々に着ると、ここでとても差があって、「うわ!今すぐ家にかえって着替えたい!」と思う程度には快適さに違いがある。</div>
<div>
<br /></div>
<div>
薄手のジオラインは基本的に暖かく感じるモデルなので、これは夏に来ていると本人はきにしていないくてもそれなりに汗をかいて服が濡れて、周りが「このひと汗っかき!」と驚かれたりするので、できれば夏はクールメッシュタイプを使うほうがいい。冬でも薄手が暑すぎるようならクールメッシュタイプでいいと思う。<br />
<br />
個人差はあるだろうが、町中での仕事や電車・飛行機でなどの交通機関での移動なら中厚手・厚手タイプは不要だ。中厚手タイプは、私の場合はスノーボードで山にはいるとき(氷点下以下)にジャケットやフリースの下の肌着として着るレベル、厚手は冬山を縦走するような人向けのラインなので、少なくとも、どちらも町中で使うようなものではないだろう。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>ジオラインを旅や出張で使うメリット</b></div>
<div>
<br /></div>
<div>
ジオラインを旅や出張で使うと大きなメリットがある。かさばらない、軽い、手洗いですぐ乾く、一枚で幅広い気温差に対応できる、の4点だ。</div>
<div>
<br /></div>
<div>
ジオラインは実際も手にしてみると判るけども、下手な綿の下着よりも薄い生地なので、替えを持っていっても、かさばらない。また、軽いので、下手な綿の下着を持っていくよりも荷物重量をセーブできるように感じる。</div>
<div>
<br /></div>
<div>
手洗いですぐ乾くのは、旅先や出張先でとても便利だ。ホテルに戻ってから洗面台やバスタブのなかで水/お湯洗いし、十分にしぼり、バスタオルなどで残りの水分を吸い取って干しておけば、最短30分後には着られる状態になるし、朝までには十分乾く。完璧ではなくても、着ると自分の体温で下着が温まって水分がとぶので、客室で着替えや歯磨きなどの準備をしているうちに落ち着く。<br />
<br />
これが綿の下着だったりすると、夜に手洗いした下着が朝に着られる状態になっているなんてことは、まずあり得ない。アメリカなどではホテル客室のエアコン設定温度が18度前後みたいなことも多い(外出時に設定温度をあげておくことは可能だけどもハウスキーピングスタッフがウェッってなるだろう)。出先のホテルでなかなか綿の下着なんて乾かない、でもジオラインなら朝には着られる状態になるのだ。</div>
<div>
<br /></div>
<div>
ここまで書くと「下着の予備もっていかなくていいの?」という感じになるけど、実際のところジオラインだと毎日手洗い対応で1枚で数日間の日程を回せてしまったりする。でも実際には夕食などでホテル客室への戻りが遅くなったりとか、時差ボケなどで疲れていて「明日のために下着を洗う」なんて元気がないこともあるので、荷物のなかにはスペアのジオラインが1〜2着準備してあったりするが、3枚とも使うようなことはまず無い。</div>
<div>
<br /></div>
<div>
<b>ジオラインで下着量が減れば荷物が減り、他の用意を増やせる</b></div>
<div>
<br /></div>
<div>
シャツタイプの下着のほか、パンツも利用している。こちらも基本的に同じ使い方ができて、綿のパンツだったら手洗いで乾かすのがほぼ無理に等しくても、ジオラインだったら客室のなかでカジュアルに手洗いして乾かすことができる。出発日に着ているものを含めて3着あれば、ほぼ無限に回せるので、長期間の出張でも着替えを増やしたり、ランドリーサービスで1品に3ドルなど取られる必要もない。</div>
<div>
<br /></div>
<div>
ジオラインのおかげでスーツケース内の下着量を減らせたので(これも下着だが)靴下を日数分+α分いれるようにしている。靴下は薄くなるとは着心地が悪くなるし、厚みがあるということは手洗い&客室内で乾かすのが難しいからだ(手洗いできて客室で1日以内に乾く快適な靴下があれば紹介してほしい、本当に)。<br />
<br />
古い靴下が溜まっている場合には、古くなった靴下を履いては捨てる、履いては捨てる、みたいなことをして帰って来るときには身軽になっていたりもする。靴下だってホテルで洗濯を頼むと数ドル取られたりするので、こういう方法をとっている。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>気温差を吸収できるスポーツ用タイツは移動にも便利</b></div>
<div>
<br /></div>
<div>
ワコールが販売するスポーツ用タイツ CW-X を使い始めたのは、スノーボード仲間の間で流行っていたからだ。</div>
<div>
<br /></div>
<div>
https://www.cw-x.jp/men/</div>
<div>
<br /></div>
<div>
これが移動中でもけっこう便利だったりする。 CW-X を出張などの遠出で使うメリットは「寒くても冷えない」「暑くても汗でベトベトしない」「あまりムレない」「まだ手で洗える」の4点だ。</div>
<div>
<br /></div>
<div>
CW-X のタイツは、アマチュアからプロのランナーまで、スキーやスノーボード、その他にも様々なスポーツをする人が持っているスポーツウェアのひとつだと思う。この CW-X タイツ、冬場にランニングしていても寒く感じない。自分がかいた汗を外側に発散して肌をドライに保ってくれる上、CW-Xが空気の層を作ってくれるので、寒さが和らぐ。</div>
<div>
<br /></div>
<div>
たとえば羽田を離陸してサンフランシスコまで10時間近く飛行機のなかでエコノミー席に座っていても、CW-Xをはいているとブランケットがかかっていなくても大丈夫だったりする。</div>
<div>
<br /></div>
<div>
また、真夏のむしむしした台湾で町中の歩けば汗をかき、それがズボンにつけばべとべとした感覚になるが、そういう感覚が和らぐのだ。ジーパンはホテルの客室で手洗いしても乾かしようがないが、 CW-X なら洗った後にバスタオルで吸い取ったり、肌につけていれば、水分は自然に飛んでいく。ベタベタするズボンを洗うより全然現実的なのだ。</div>
<div>
<br /></div>
<div>
ただし夏にCW-Xをズボンのなかに履くのはある程度ムレたりもするので、それが気になりそうな気候だった場合には、移動日以外はモンベルのジオライン クールメッシュタイプのタイツを使っていたりもする。</div>
<div>
<br /></div>
<div>
なお CW-X も着圧効果はあるとはいえ SKINS などだと血の巡りをよくしてエコノミー症候群を防ぐような効果が訴求されている?みたいなので、新たに買うのなら、そういった着圧タイプを選んだほうがいいのかもしれない。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>ジオライン + スポーツタイツで夏・冬気候を行き来もして大丈夫</b></div>
<div>
<br /></div>
<div>
2017年の夏、オーストラリアのメルボルンまで出張で行ったときには、実際に ジオライン + CW-X を使った。</div>
<div>
<br /></div>
<div>
出張予算を削減する必要があったので、航空会社はタイ航空。タイ経由でオーストラリアに行くということは、真夏の日本から赤道の下みたいなタイを経由して、真冬のオーストラリアに行く、ということだ。しかも、帰路はオーストラリアを夜11時発、タイに朝6時頃に到着して、深夜の日本行きフライトに乗る、みたいな旅程で、つまりはオーストラリア市内とタイ市内でまる2日間、だらだら過ごすことになった。</div>
<div>
<br /></div>
<div>
この出張では、実際に神奈川の自宅を出発して飛行機にのりタイ経由でオーストラリアに到着、出張期間は現地の大学に行き、オーストラリア出発日はオーストラリア市内をふらふらして、翌日はタイ市内をふらふらしたけども、この間、実際にジオラインの薄手 + CW-X の組み合わせで乗り切ってしまった(さすがにタイとオーストラリアで、その上のレイヤリングは変えている。ズボンは替えなかった)。タイー羽田便は熟睡、目の前にすわっていたフライトアテンダントが「よくお休みになられていましたね」と声をかけてくるほどだった。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>まとめ: ジオライン + スポーツタイツは長距離移動で活躍する</b></div>
<div>
<br /></div>
<div>
まとめると、ジオラインとスポーツタイツは「体を冷やさない」「必要以上に暑くならない」「汗が外に抜けていき肌をドライを保ってくれる」ので、気候変化が大きいような日程を組んだり、その途中で飛行機など体を冷やしがちな移動手段を使っても凍えるような思いを防ぐ下着として利用できる。<br />
<br />
普段とは違う気候の場所でも、過ごしやすくければ見知らぬ地でのストレスも軽減されたりするので、出張先や移動中体が冷えたり暑かったり、持っていく下着の枚数を何枚にするか悩んでしまったりする時には、ジオラインやスポーツタイツを試してみてほしい。</div>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-28422089227330136232018-11-12T22:17:00.001+09:002018-11-12T22:21:21.206+09:00IIJmio SIM カードが入った iPad Pro (2017) 10.5インチモデルで Apple SIM を使おうとして苦労した話出張先(米国内)で内蔵 Apple SIM を使用して T-Mobile に接続しようとしたら、できなくて困った。<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-GcNj8-jWpnT4Rhg4FzE0NS8FZjrfJmK3fFisyJOHWk95ztHmye5cqQ1lKXP1UysxuKkaOXdfwTGfSQ3_4a-YufMZjoE9yVD-6d0aNWAVOu2NBBdZpGf7P3itTnHJNhNl2GecvbZPFMA/s1600/IMG_0261.PNG" imageanchor="1"><img border="0" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-GcNj8-jWpnT4Rhg4FzE0NS8FZjrfJmK3fFisyJOHWk95ztHmye5cqQ1lKXP1UysxuKkaOXdfwTGfSQ3_4a-YufMZjoE9yVD-6d0aNWAVOu2NBBdZpGf7P3itTnHJNhNl2GecvbZPFMA/s400/IMG_0261.PNG" width="400" /></a><br />
<br />
本来ならここで「データ通信プランを選択」というグループに、トレイに入っている SIM カードから NTT DoCoMo 、 Apple SIM で契約済みの T-Mobile 、そしてその他のキャリアへの新規加入が可能なメニュー選択肢が出るはず。<br />
<br />
まずは IIJmio での接続に必要なAPNプロファイルを削除してみる。これが入っているとどちらにせよ T-Mobile で通信できないだろう。削除しても、 T-Mobile や Apple SIM の選択肢は出てこなかった。<br />
<br />
次に iOS をリスタートしてみる。残念ながらこれでも改善しなかった。<br />
<br />
続いて、 General > Reset > Reset Network Settings でネットワーク系の設定をリセットしてみる。これでも Apple SIM が見えない。困った。<br />
<br />
Apple Support アプリから現地のサポートにチャットで相談してみたら、下記のとおりアドバイスをもらった。<br />
<br />
・SIMスロットに入っている SIM カードを取り外してみる。<br />
・それでだめならバックアップをとって Factory Reset (ひえー)<br />
<br />
SIM スロットには IIJmio (DoCoMo)の SIM が刺さりっぱなし。そういえば前回渡米したときは IIJmio じゃなくて、さくらインターネットのセキュアモバイルコネクトを挿していたはずなので、前回問題なかった時とは状況が違うのは確か。<br />
<br />
SIM スロットをイジェクトするピンを持ち合わせていなくて困ったのだが、宿泊先の施設に知っている日本人が泊まっていて(笑)ピンを借りることができた。で、 IIJmio の SIM カードを取り外してみると。。。<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_e0xuDeQb_HR89Fipw5ReCSdB9Qr5EydhtFC4K1xcvZsm4u94QyIMvQHkfmBUQJOAcGKNA08Z90V57ImnqXEpSRVCf-KOk-FXVfFo1hMkszEqjZKsuMica-QZ4n3SiKxR3L_MGY76NA4/s1600/IMG_0263.jpg" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_e0xuDeQb_HR89Fipw5ReCSdB9Qr5EydhtFC4K1xcvZsm4u94QyIMvQHkfmBUQJOAcGKNA08Z90V57ImnqXEpSRVCf-KOk-FXVfFo1hMkszEqjZKsuMica-QZ4n3SiKxR3L_MGY76NA4/s400/IMG_0263.jpg" width="400" /></a><br />
<br />
おうー。まじかよ! T-Mobile きましたわー。<br />
ということで一件落着。<br />
<br />
・IIJmio (DoCoMo) SIM が挿さった状態だと Apple SIM が見えない?状態になる<br />
・この状態だと「データ通信プラン」(英語表記では Celluar Plans)が出てこない。<br />
・SIM カードを抜くと Apple SIM が見える、ことが実際におきた<br />
・出張セットのなかには SIM カード取り出し用のピンを忘れずに入れておくようにしましょう<br />
<br />hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-10484871277829572642017-12-23T13:59:00.002+09:002021-12-30T00:28:55.388+09:00【第1回 Cpaw AI competition】乱入レポート<i>この記事は、<a href="https://qiita.com/advent-calendar/2017/sakura">さくらインターネット Advent Calendar 2017</a> 23日目の記事です。</i><br />
<i>22日目の記事: <a href="https://knowledge.sakura.ad.jp/12439/">日本初の競技機械学習大会!【第1回 Cpaw AI competition】開催レポート</a></i><br />
<i>24日目の記事: (追記予定)</i><br />
<br />
こんにちわ。 hasegaw こと、さくらインターネット 高火力コンピューティングの長谷川です。<br />
<br />
今回は、22日の記事にて紹介された<a href="https://knowledge.sakura.ad.jp/12439/">第1回Cpaw AI Conpetition</a>について、続きってわけでもないのですが、続編をお届けします。同コンペティションを開催したCpawの伊東さんは高火力コンピューティングにチームでアルバイトしてくれていまして、ある日のこと。<br />
<br />
「AIコンペティションを開催したくて、場所を探しています」<br />
「え?ウチ使えるよ」<br />
<br />
ということで、さくらインターネットの西新宿セミナールームで開催することになりました。当日は台風が接近していたこともあり、参加者が少なくなってしまうのではないかと心配したのですが、悪天候のなか歩留まり6割というのは最近の機械学習系のイベントとしては良い意味で裏切られた気持ちでした。<br />
<br />
<img alt="" class="size-large wp-image-12490 aligncenter" height="300" sizes="(max-width: 680px) 100vw, 680px" src="https://knowledge.sakura.ad.jp/images/2017/12/IMG_0881-e1512111295559-680x510.jpg" srcset="https://knowledge.sakura.ad.jp/images/2017/12/IMG_0881-e1512111295559-680x510.jpg 680w, https://knowledge.sakura.ad.jp/images/2017/12/IMG_0881-e1512111295559-440x330.jpg 440w, https://knowledge.sakura.ad.jp/images/2017/12/IMG_0881-e1512111295559-768x576.jpg 768w" width="400" /><br />
<br />
先の記事のとおり、 Cpaw AI Competition では、さくらのクラウド 12コア・96GBメモリのインスタンス(Ubuntu 16.04)を用いて、与えられたデータセットに対する分類器を生成、分類結果を Web サイトから提出します。提出したスコアはそのまま 1% == 1ポイントとして加算されます。つまり65.2% の分類器をつくれば 65 ポイント獲得できるわけですね。<br />
<br />
競技時間は 13:30-18:00 のおよそ 4.5 時間。さくらインターネットの社員(わたし含めて2名)は会場運営支援で現地にいたのですが、 4 時間ボケっとしているのは、ちょっと暇です。と、いうわけで。<br />
<br />
「伊東くん、私にも問題解かせてよ」<br />
<br />
とお願いして、他の参加者と同じように問題を解いてみることにしました。下記は、実際に問題を解いた手順を再現したものですが、当時書いたコードは既に失ってしまったので、書き直した「再現コード」で解説します。<br />
<br />
<br />
<b>■ 芸能人ブログ記事の分類問題→絶望</b><br />
<br />
最初に手を出したのは芸能人ブログの分類問題(entertainer_blog)です。データセットは Cpaw オリジナルのもので(本稿執筆のために Cpaw から提供を受けていますが)、 Cpaw の皆さんがあらかじめスクレイプ、1記事1テキストファイルに変換されたものです。ブログエントリの教師データを用いて分類器を訓練し、クラスラベルが与えられていないブログエントリを分類することが目標です。<br />
<br />
entertainer_blog/train/<br />
entertainer_blog/train/mamoru_miyano<br />
entertainer_blog/train/mamoru_miyano/10.txt<br />
entertainer_blog/train/mamoru_miyano/1000.txt<br />
entertainer_blog/train/mamoru_miyano/1005.txt<br />
entertainer_blog/train/mamoru_miyano/1021.txt<br />
entertainer_blog/train/sano_hinako<br />
entertainer_blog/train/sano_hinako/1004.txt<br />
entertainer_blog/train/sano_hinako/1008.txt<br />
entertainer_blog/train/sano_hinako/1012.txt<br />
entertainer_blog/train/sano_hinako/1014.txt<br />
entertainer_blog/train/shinozaki_ai<br />
entertainer_blog/train/shinozaki_ai/1003.txt<br />
entertainer_blog/train/shinozaki_ai/1006.txt<br />
entertainer_blog/train/shinozaki_ai/1010.txt<br />
entertainer_blog/train/shinozaki_ai/1018.txt<br />
entertainer_blog/train/shinozaki_ai/102.txt<br />
....<br />
<br />
データファイルの内容の例<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguEgBn6tYwH_QK11WN5EkTfu8ahlg0cVJ_vJY__ImhjxsyG0drPwsZ_3hc6E1NMsUhcYiuQDOeFudln34twMbPEmzqfRJe76S3nk99jk_dZFmd4AMky3AUIlXias_jHjS4QvXPWxjJvHo/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+14.04.29.png" imageanchor="1"><img border="0" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguEgBn6tYwH_QK11WN5EkTfu8ahlg0cVJ_vJY__ImhjxsyG0drPwsZ_3hc6E1NMsUhcYiuQDOeFudln34twMbPEmzqfRJe76S3nk99jk_dZFmd4AMky3AUIlXias_jHjS4QvXPWxjJvHo/s320/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+14.04.29.png" width="320" /></a><br />
<br />
訓練用データセットは下記のとおりの構成でした。<br />
<br />
訓練用データ(ラベルあり)<br />
461 shinozaki_ai<br />
509 uesaka_sumire<br />
397 mamoru_miyano<br />
210 sano_hinako<br />
合計 1577<br />
<br />
テスト用データ(ラベルなし;スコア獲得用)<br />
合計 1972<br />
<br />
データセットを数ファイル覗いてみると、これらの芸能人が誰なのか正直全然わからないですけども、クラスによっては特定の締め方があったり、顔文字の傾向があったり、ということがわかりました。今回は、このデータセットを手軽に処理する目的で Jubatus を用いることにしました。 Jubatus の場合 ngram を用いた特徴量への変換などが標準で備わっていますので、今回のようなデータセットなら、簡単に「とりあえず」食わせられるからです。<br />
<br />
<tt>wget http://download.jubat.us/apt/ubuntu/xenial/binary/pool/jubatus_1.0.6-1_amd64.deb<br />
apt install ./jubatus_1.0.6-1_amd64.deb<br />
pip3 install --user jubatus</tt><br />
<br />
今回は分類問題なので Jubatus のなかでも jubaclassifier を使用します。以下のようなファイルを作成します。 n=6 にしましたが、ここには強い理由はありません(とりあえずノリで決めました)。既存のサンプルを参考に、設定ファイルに指定して jubaclassifier を起動します。<br />
<br />
<script src="https://gist.github.com/hasegaw/dd2938434d500124b714f22d07b9931b.js"></script>
jubaclassifier はポート 9199 で待ち受けており、 Python で記述する学習&予測プログラムから利用します。<br />
<br />
<tt><br class="Apple-interchange-newline" />jubaclassifier --configpath jubaclassifier.json</tt><br />
<br />
そして訓練用データセットがクラスラベルごとにディレクトリで分けられていること、データセットサイズに対してインスタンスのメモリ容量が十分なことから、下記関数でデータセットを読み込むことにしました。<br />
<br />
<script src="https://gist.github.com/hasegaw/3d7fef7f2802246aa751741c1b309fe0.js"></script>
次のコードが Jubatus を用いてデータセットを分類し、Cpaw AI Competition での提出用CSVフォーマットで stdout に出力するソースコードです。<br />
<br />
<script src="https://gist.github.com/hasegaw/48749bf63362fc3f0e58fc8acdde9ee7.js"></script>
<script src="https://gist.github.com/hasegaw/ed4ff9a1ea953bee128f4e3c69a381a8.js"></script>
ここまで準備ができたら、実際にデータセットをロードして、 jubaclassifier を用いてオンライン学習し、テストデータを分類します。ここで、標準出力に表示される結果の例を示します。<br />
<br />
<span style="font-family: monospace;">0.txt,uesaka_sumire</span><br />
<span style="font-family: monospace;">1.txt,shinozaki_ai</span><br />
<span style="font-family: monospace;">2.txt,uesaka_sumire</span><br />
<span style="font-family: monospace;">3.txt,uesaka_sumire</span><br />
<span style="font-family: monospace;">4.txt,mamoru_miyano</span><br />
<span style="font-family: monospace;">5.txt,mamoru_miyano</span><br />
<span style="font-family: monospace;">6.txt,shinozaki_ai</span><br />
<span style="font-family: monospace;">7.txt,shinozaki_ai</span><br />
<span style="font-family: monospace;">8.txt,uesaka_sumire</span><br />
<span style="font-family: monospace;">9.txt,shinozaki_ai</span><br />
<br />
このデータをコンペティションの採点システムに提出すると、得られていた精度はなんと 30% 以下!!4クラス分類だと完全ランダムでも25%前後になるはずですから、いっそのこと全部 shinozaki_ai ラベルで提出した場合のスコアと大差がない。まったく駄目!!<br />
<br />
正直、高火力コンピューティングをお客様に紹介して回ったり、プレゼンして回ったりする立場の私がコレなのは本当に恥ずかしてお客様などに顔向けできないなぁ、と思い、動揺し、死にたくなりました。いっそのこと Cpaw に貸してあげた採点サーバーに root で乗り込んでいって DROP DATABASE クエリを叩き込んでしまいたいという気持ちになりましたが、個人的な感情でそんなことをするわけにもいきません。実は、当日は ngram の n=2 で精度が得られなかったため順番に増やしていって 6 まで上げたのですが、これだけで、精度はあがりません。<br />
<br />
一旦あきらめて、とりあえず他のデータセットに取り組むことにします。<br />
<br />
<b>■ 泣きそうになりながら、マルウェアURLの分類問題</b><br />
<br />
次に取り組んだのは、マルウェアURLの分類問題です。下記URLで取得できる、URLデータセットが先と同じように1サンプル1テキストファイルとして用意されており、オリジナルデータからラベルが取り除かれたテストデータが正常なURLか、グレイゾーンなURLかを判断することが目標です。<br />
<br />
Malware URL<br />
<a href="http://malwareurls.joxeankoret.com/">http://malwareurls.joxeankoret.com/</a><br />
<br />
データセットのディレクトリ/ファイル構造<br />
<span style="font-family: monospace;">train/normal/</span><br />
<span style="font-family: monospace;">train/normal//1007.txt</span><br />
<span style="font-family: monospace;">train/normal//101.txt</span><br />
<span style="font-family: monospace;">train/normal//1011.txt</span><br />
<span style="font-family: monospace;">train/normal//1013.txt</span><br />
<span style="font-family: monospace;">train/malicious/</span><br />
<span style="font-family: monospace;">train/malicious//0.txt</span><br />
<span style="font-family: monospace;">train/malicious//1.txt</span><br />
<span style="font-family: monospace;">train/malicious//10.txt</span><br />
<span style="font-family: monospace;">train/malicious//100.txt</span><br />
<span style="font-family: monospace;">...</span><br />
<br />
あるデータファイルの中身の例<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglW3f7YHavMPnOWXMrRn6BKl9egkwFgrDte8V6_7lsx8WV4sAYgOcdhYkASnORrlleOqWG4g_IiYBTzQqCesjvNEiRU9wOxnuKpewKYlC9odmXKboNvYS6Ikxo-4r83FZYpKb3YBex45w/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+13.21.38_small.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglW3f7YHavMPnOWXMrRn6BKl9egkwFgrDte8V6_7lsx8WV4sAYgOcdhYkASnORrlleOqWG4g_IiYBTzQqCesjvNEiRU9wOxnuKpewKYlC9odmXKboNvYS6Ikxo-4r83FZYpKb3YBex45w/s400/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+13.21.38_small.png" /></a><br />
<br />
テキストファイルの中が芸能人のブログ記事からURLにかわり、ラベルが変わっただけで、基本的にデータフォーマットは一緒です。<br />
<br />
というわけで、遠慮なく先程の dataset.py と classifier.py に突っ込んでみます。 URL は基本的にアルファベットや数字の集合で、N の値はそこそこ大きい必要があるでしょう。なので N はとりあえず、引き続き 6 ぐらいにしておきます。<br />
<br />
<script src="https://gist.github.com/hasegaw/0e5caaed52db9b1d7ee1b03b828e3313.js"></script>
先程起動した jubaclassifier は芸能人ブログの学習データを持っているので、ここでいったん同プロセスを再起動しておきます(もっといい方法があるのでしょうか?使い慣れているわけではないので、よくわかっていません)。malware_urls.py を実行した結果がこちら。<br />
<br />
採点サーバに送ると、またもや精度は 60% にも及びません(2クラス分類なので全く駄目な結果ということです)。もうだめだー!!!逃げたい!!!<br />
<br />
そう思っていたところで、 Cpaw 運営側から採点システムの不具合があり、正確な採点がされていないので,データを再提出するようにという指示。先の芸能人ブログ分類、マルウェアURL分類の結果を再提出した結果、こんな感じになりました。<br />
<br />
<span style="font-family: monospace;">entertainer_blog: 精度 94.6%</span><br />
<span style="font-family: monospace;">malware_urls: 精度 83.7%</span><br />
<br />
なんだぁ〜〜〜〜。ちゃんと分類できてるんじゃん!本当に焦って泣きそうでしたよ!!よかった。<br />
<br />
<b>■ 調子に乗りながら、マルウェア分析の分類問題</b><br />
<br />
次はマルウェア分析問題にとりかかっていきます。このデータセットは下記サイトから入手できる MalwareTrainingSets が先と同様のフォーマット(ただしJSON)に変換されているものです。<br />
<br />
<span style="background-color: white; color: #24292e; font-family: , , "segoe ui" , "helvetica" , "arial" , sans-serif , "apple color emoji" , "segoe ui emoji" , "segoe ui symbol"; font-size: 16px;">Free Malware Training Datasets for Machine Learning</span><br />
<a href="https://github.com/marcoramilli/MalwareTrainingSets">https://github.com/marcoramilli/MalwareTrainingSets</a><br />
<br />
データセットのディレクトリ/ファイル構造<br />
<span style="font-family: monospace;">train/APT1/1046.json</span><br />
<span style="font-family: monospace;">train/APT1/1051.json</span><br />
<span style="font-family: monospace;">train/APT1/1063.json</span><br />
<span style="font-family: monospace;">train/APT1/1065.json</span><br />
<span style="font-family: monospace;">train/Crypto/0.json</span><br />
<span style="font-family: monospace;">train/Crypto/100.json</span><br />
<span style="font-family: monospace;">train/Crypto/1000.json</span><br />
<span style="font-family: monospace;">train/Crypto/1002.json</span><br />
<span style="font-family: monospace;">train/Locker/1004.json</span><br />
<span style="font-family: monospace;">train/Locker/1012.json</span><br />
<span style="font-family: monospace;">train/Locker/1037.json</span><br />
<span style="font-family: monospace;">train/Locker/1048.json</span><br />
<span style="font-family: monospace;">train/Zeus/1.json</span><br />
<span style="font-family: monospace;">train/Zeus/10.json</span><br />
<span style="font-family: monospace;">train/Zeus/1001.json</span><br />
<span style="font-family: monospace;"></span><br />
<span style="font-family: monospace;">train/Zeus/1005.json</span><br />
<span style="font-family: monospace;">...</span><br />
<br />
あるデータファイルの中身の例<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnne4lXCTtiNufaDne2T70KrV-Dm4u_5Jb-kGhO8f9fgsd-lziLWwrGFgMCQkLQFVE8QJlJCeLxfz7uaIRszbFxAmomNz7G-zFs7IqR2BD9sSZcmlVc3NElA33MQBvvQxcMadPGRzELbw/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+13.25.14_small.png" imageanchor="1"><img border="0" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnne4lXCTtiNufaDne2T70KrV-Dm4u_5Jb-kGhO8f9fgsd-lziLWwrGFgMCQkLQFVE8QJlJCeLxfz7uaIRszbFxAmomNz7G-zFs7IqR2BD9sSZcmlVc3NElA33MQBvvQxcMadPGRzELbw/s400/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+13.25.14_small.png" width="400" /></a><br />
<br />
Cpawからデータセットのフォーマットが事実上先程と同じなので、遠慮なく分類器にかけていきます。もしかすると、当日では、JSONを解析して特定の値のみを評価したかもしれません(よく憶えていません)。<br />
<br />
<script src="https://gist.github.com/hasegaw/0e5caaed52db9b1d7ee1b03b828e3313.js"></script>
得られた結果は以下のとおり。<br />
<span style="font-family: monospace;">malware_analysis: 精度 99.6%</span><br />
<div>
<span style="font-family: monospace;"><br /></span></div>
実はこのデータセットはある見方をするとルールベースで 100% を達成することができました。しかし、それでも追加のコードを書いたりせずに機械学習で殴っておけば 99% の精度が出せる点が、機械学習のメリットだと思います。<br />
<br />
さてここまで entertainer_blog 94.6%, malware_urls 83.7%, malware_analysis 99.6% の精度が出せたので、私のスコアは 94+83+99 で合計 276 となり、二番手グループに大躍進です!! (会場スポンサーですけど)<br />
<br />
<br />
<b>■ ニューラルネットワークで"ファッションMNI?T"</b><br />
<br />
さてさて!<br />
<br />
気分がよくなってきたところで、次のデータセットに取り組んでいきましょう。ここまではテキストのデータセットばかりを選んできましたが、残っているデータセットは「ファッションMNI?T」と「古代文字」のふたつ。どちらかを先に試すか?と思ったら、まずは前者かな、と思いました。 MNIST といえば 28x28 の 10 クラス分類問題で、名前から想像するに同じような要領でいけるのではないか、と思い、データセットを覗いてみることに。<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz2BUjGe4WdTZuMsWsbVkrgGk7Mqxk6YWzCRNOnud9CXCTHnd_-2jc7gigol65_4WOZZNfue-26zEzS8l9znhOe4yjpUJD1HpIqkWvUDMkADw9OAfdnuxT6N4_IsZLr_acdyv40HqbnK8/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+11.59.42.png" imageanchor="1"><img border="0" height="335" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz2BUjGe4WdTZuMsWsbVkrgGk7Mqxk6YWzCRNOnud9CXCTHnd_-2jc7gigol65_4WOZZNfue-26zEzS8l9znhOe4yjpUJD1HpIqkWvUDMkADw9OAfdnuxT6N4_IsZLr_acdyv40HqbnK8/s400/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+11.59.42.png" width="400" /></a><br />
<br />
これもボーナス問題ですね!オリジナルの Fashion MNIST データセットでは黒塗りマスクがないのですが、今回のは黒塗りマスクのイタズラがされているデータでした。<br />
<br />
これはイケる、という確信を得ます。MNIST同様、28x28のモノクロサイズの10クラス分類。データセットをひと目みるとわかりますが、全ての画像に同一パターンの黒塗りがかかっています。畳み込みニューラルネットワークを使用するとこの黒塗りエッジ部分などが邪魔をするかもしれませんが、このデータを単純に線形結合で入力する場合は、オリジナルのファッション MNIST を 14x14 にリサイズされた状態である、と解釈できるのではないでしょうか。もう、これは 14x14 の MNIST にしか、私には見えません。<br />
<br />
この問題をどう解くか、ですが Cpaw AI Competition のレギュレーションでは、イベントで提供された 12コア96GB を使いまくっていいので(畳み込んでいるとあっという間に時間が過ぎてしまいそうですが)線形結合で殴るぐらいの計算リソースと残り時間はあります。また、畳み込むと上にかぶっているマスクが邪魔になるだろうでしょうから、結果が予測できません。なので、線形結合モデルでいくことにします。<br />
<br />
とりあえず、Chainerフレームワークをインストールします。<br />
<br />
<span style="font-family: monospace;">pip3 install chainer</span><br />
<br />
データセットはこれまで通り各クラスがディレクトリで分けられて提供されていましたが、テキストファイルではなく画像なので、データセット読み込みを実装します。普段は cv2.imread() のほうが使い慣れているのですが、cv2モジュールがすぐインポートできなかったので、今回はPILを使ってみました。<br />
<br />
<script src="https://gist.github.com/hasegaw/72a919edf1b99a0eb35f1f7c04cbbe4f.js"></script>
以下が Chainer を使ってニューラルネットワークを訓練し、テストデータを予測するためのコードの例です。<br />
<br />
<script src="https://gist.github.com/hasegaw/d830a4dba151bae6638ec8b6bf3d064f.js"></script>
<script src="https://gist.github.com/hasegaw/e8bb605e188d8bffdac808d03e8be58a.js"></script>
このコードを実行し、得られた結果を採点サーバに送信したところ 81% の精度が得られ、私は大会で暫定首位に躍り出ました。(会場スポンサーですけど)<br />
<br />
<br />
<b>■ これは引っ掛けデータセットな「古代文字」</b><br />
<br />
さて、残りは古代文字データセットです。このデータセットは下記URLから入手できる古代文字画像が、一文字ごと、画像ファイルに分割された状態で提供されました。<br />
<br />
文学オープンデータ共同利用センター / Center for Open Data in the Humanities<br />
<a href="http://codh.rois.ac.jp/">http://codh.rois.ac.jp/</a><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivrWFlgtQwCb3kRUh9LImzSL9mkT5Ftnts-HuLwVl_dzmbjTZr-nFVddRwqOArGPchRpEK8KRRUUWoTxlELeZeI6NY8tTD8RO85IMeZ7jyZ2jHKQ8qjiJ253W9YXPmp-pDb9q_wCsy2dU/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+12.20.58.png" imageanchor="1"><img border="0" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivrWFlgtQwCb3kRUh9LImzSL9mkT5Ftnts-HuLwVl_dzmbjTZr-nFVddRwqOArGPchRpEK8KRRUUWoTxlELeZeI6NY8tTD8RO85IMeZ7jyZ2jHKQ8qjiJ253W9YXPmp-pDb9q_wCsy2dU/s400/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2017-12-23+12.20.58.png" width="400" /></a><br />
<br />
正直、このデータセットはちらっと見るだけでも 13:30-18:00 のコンペティションの中で扱うデータセットとしては非常に重いです。ファッションMNISTのようにある程度の正規化がされているわけでもなく、さすがに畳み込みニューラルネットワークなどのアプローチで、きちんと回さないと、精度が出ないのではないか?という気がします。<br />
<br />
とはいえ、この段階で残り1時間ほど。チャレンジできるところまでチャレンジしましょう。(会場スポンサーですけど)<br />
<br />
<br />
<b>■ 突然のカーテンコール</b><br />
<br />
……と思ったところで、運営からその時点の暫定順位の発表があり、運営の伊東さんから下記の案内がありました。<br />
<br />
「あ、ちなみにこの hasegaw って人は会場スタッフなので表彰対象外です」<br />
<br />
<blockquote class="twitter-tweet" data-lang="en">
<div dir="ltr" lang="ja">
表彰対象外とは….</div>
— Takeshi HASEGAWA (@hasegaw) <a href="https://twitter.com/hasegaw/status/924547121243492353?ref_src=twsrc%5Etfw">October 29, 2017</a></blockquote>
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
というわけで、私の AI Competition は散って終わったのでした。<br />
<br />
<img alt="" class="size-large wp-image-12827 aligncenter" height="210" sizes="(max-width: 680px) 100vw, 680px" src="https://knowledge.sakura.ad.jp/images/2017/12/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2017-12-19-12.00.20-680x359.png" srcset="https://knowledge.sakura.ad.jp/images/2017/12/スクリーンショット-2017-12-19-12.00.20-680x359.png 680w, https://knowledge.sakura.ad.jp/images/2017/12/スクリーンショット-2017-12-19-12.00.20-440x232.png 440w, https://knowledge.sakura.ad.jp/images/2017/12/スクリーンショット-2017-12-19-12.00.20-768x406.png 768w" width="400" /><br />
<br />
なお、今回のブログ記事執筆のために作成しなおしたコードでは、下記のスコアが得られました。<br />
<br />
<span style="font-family: monospace;">entertainer_blog: 精度 94.6%</span><br />
<span style="font-family: monospace;">malware_urls: 精度 83.7%</span><br />
<span style="font-family: monospace;">malware_analysis: 精度 99.6%</span><br />
<span style="font-family: monospace;">fashion_mnist: 精度 81.9%</span><br />
<br />
小数点以下切り捨ての合計スコアは357ですので、当日このスコアが出せていたら、トップに踊りでて Google Home mini を勝ち取っていたかもしれません。😭<br />
<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggQYAPnZMh_f125t94bK14zhdpB8r8ZALARzXtsG8aFnpjqJ8Bx2rcdKUhTUNCAJmLoBEQ5iSL65sTi0r7bqgWcv650brGrev6EN9nGhPOW3lkdvb84vwpNSVozGBJfjGOWtepHSRHbhk/s1600/IMG_3589+2.JPG" imageanchor="1"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggQYAPnZMh_f125t94bK14zhdpB8r8ZALARzXtsG8aFnpjqJ8Bx2rcdKUhTUNCAJmLoBEQ5iSL65sTi0r7bqgWcv650brGrev6EN9nGhPOW3lkdvb84vwpNSVozGBJfjGOWtepHSRHbhk/s320/IMG_3589+2.JPG" width="320" /></a></div>
<div style="text-align: center;">
後日自分で購入した Google Home mini</div>
<br />
もちろん、今回はたまたまデータセットと私のとった手段がうまくはまってスコアが伸びただけしかありません。会場には、スコアを伸ばすことを重きにおくのではなく、フルスクラッチで機械学習アルゴリズムを実装するところからスコアを積み上げていた方もいらっしゃるようで、本当に頭がさがります。<br />
<br />
次の機会には、もし会場スポンサーの立場であっても、きちんと参加登録してコンペティションに臨んでみたいと思います。<br />
<br />
<br />
<b>■ 終わりに</b><br />
<br />
機械学習って、聞いたことがあるけど未だ試していなかったり、もしくはちょっと勉強してみたという方も増えてきているのではないでしょうか。<br />
<br />
私も、もともと「機械学習やディープラーニングってすごいなぁ」と思いながら、 <a href="https://www.slideshare.net/TakeshiHasegawa1/ikalog-data-collector-for-splatoon-and-machine-learning-jan-2017-softbank">IkaLog</a> というスプラトゥーンの画像認識ソフトを作っていく過程で、意図せず、各種機械学習アルゴリズムのパワーを体感して、そこから Coursera の Machine Learning コースを受講した程度の知識しかありません。1年ほどスプラトゥーンの画像データに取り組んだ経験がある以外は、機械学習について凡人レベル、もしくはそこに毛が生えた程度の知識しかありません。<br />
<br />
しかし機械学習は、ちょっとモチベーションがあると、その状況なりの使い道や楽しみ方が見つかります。また、今回のような問題で7割8割の精度が出せれば、業務上でも自分の仕事の手間を削減したり、ちょっとした業務効率化で効いたりするものです。さくらインターネットでも、機械学習未経験のデータセンター現地スタッフが独学で Jubatus を用いたオペレーション業務の効率化にも取り組んだりもしています。<br />
<br />
Cpaw では、今後とも同様のオンラインイベントやオフラインイベントを開催すると伺っています。機会があれば、このようなイベントにぜひとも参加してみてください。<br />
<br />
<b>■ おまけ</b><br />
<br />
過去に参加したアドベントカレンダー<br />
<br />
<ul>
<li>2015年12月: <a href="http://d.ballade.jp/2015/12/blog-post.html">スプラソン機材セットをつくりました</a></li>
<li>2015年12月: <a href="http://d.ballade.jp/2015/12/entrance-monitoring.html">おうちハックで戦った話</a></li>
<li>2015年12月: <a href="http://d.ballade.jp/2015/12/fluentbit-meets-xbee.html">Fluent-bit と XBee で作るセンサーネットワーク</a></li>
<li>2013年12月: <a href="http://d.ballade.jp/2013/12/ejectio.html">次世代I/Oインターフェイス「Eject-io」</a></li>
<li>2012年12月: <a href="http://d.ballade.jp/2012/12/interrupts-for-guest-vms.html">割り込みはいかにしてゲストの割り込みハンドラに届くのか</a></li>
<li>2011年1月: <a href="http://d.ballade.jp/2011/01/FreeBSD-vimage.html">FreeBSD VIMAGEを使ったTCP/IPのルーティング デモンストレーション</a></li>
</ul>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-8325728294996719122017-09-04T10:41:00.001+09:002017-09-04T10:41:19.192+09:00Python 向け OpenCV 3.3.0 (Win32) ビルド済みライブラリのビルドオプション下記サイトから入手可能な opencv_python-3.3.0-cp36-cp36m-win32.whl の cv2.getBuildInformation() の結果。<br />
<br />
<ul>
<li><a href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv">Unofficial Windows Binaries for Python Extension Packages</a></li>
</ul>
<br />
<br />
<pre>General configuration for OpenCV 3.3.0 =====================================
Platform:
Timestamp: 2017-08-05T02:46:14Z
Host: Windows 10.0.15063 AMD64
CMake: 3.7.2
CMake generator: Visual Studio 14 2015
CMake build tool: C:/Program Files (x86)/MSBuild/14.0/bin/MSBuild.exe
MSVC: 1900
CPU/HW features:
Baseline: SSE SSE2
requested: SSE2
required: SSE2
Dispatched code generation: SSE4_1 SSE4_2 FP16 AVX AVX2
requested: SSE4_1 SSE4_2 AVX FP16 AVX2
SSE4_1 (2 files): + SSE3 SSSE3 SSE4_1
SSE4_2 (1 files): + SSE3 SSSE3 SSE4_1 POPCNT SSE4_2
FP16 (1 files): + SSE3 SSSE3 SSE4_1 POPCNT SSE4_2 FP16 AVX
AVX (5 files): + SSE3 SSSE3 SSE4_1 POPCNT SSE4_2 AVX
AVX2 (7 files): + SSE3 SSSE3 SSE4_1 POPCNT SSE4_2 FP16 FMA3 AVX AVX2
C/C++:
Built as dynamic libs?: YES
C++11: YES
C++ Compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe (ver 19.0.24218.1)
C++ flags (Release): /DWIN32 /D_WINDOWS /W4 /GR /EHa /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:fast /arch:SSE /arch:SSE2 /wd4251 /wd4324 /wd4275 /wd4589 /MP12 /MD /O2 /Ob2 /DNDEBUG /Zi
C++ flags (Debug): /DWIN32 /D_WINDOWS /W4 /GR /EHa /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:fast /arch:SSE /arch:SSE2 /wd4251 /wd4324 /wd4275 /wd4589 /MP12 /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
C Compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/cl.exe
C flags (Release): /DWIN32 /D_WINDOWS /W3 /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:fast /arch:SSE /arch:SSE2 /MP12 /MD /O2 /Ob2 /DNDEBUG /Zi
C flags (Debug): /DWIN32 /D_WINDOWS /W3 /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS /Gy /bigobj /Oi /fp:fast /arch:SSE /arch:SSE2 /MP12 /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
Linker flags (Release): /machine:X86 /INCREMENTAL:NO /debug
Linker flags (Debug): /machine:X86 /debug /INCREMENTAL
ccache: NO
Precompiled headers: YES
Extra dependencies: comctl32 gdi32 ole32 setupapi ws2_32 vfw32 glu32 opengl32
3rdparty dependencies:
OpenCV modules:
To be built: core flann imgproc ml objdetect photo video dnn imgcodecs shape videoio highgui superres ts features2d calib3d stitching videostab python3
Disabled: python2 world
Disabled by dependency: -
Unavailable: cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev java viz
Windows RT support: NO
GUI:
QT: NO
Win32 UI: YES
OpenGL support: YES (glu32 opengl32)
VTK support: NO
Media I/O:
ZLib: build (ver 1.2.8)
JPEG: build (ver 90)
WEBP: build (ver encoder: 0x020e)
PNG: build (ver 1.6.24)
TIFF: build (ver 42 - 4.0.2)
JPEG 2000: build (ver 1.900.1)
OpenEXR: build (ver 1.7.1)
GDAL: NO
GDCM: NO
Video I/O:
Video for Windows: YES
DC1394 1.x: NO
DC1394 2.x: NO
FFMPEG: YES (prebuilt binaries)
avcodec: YES (ver 57.89.100)
avformat: YES (ver 57.71.100)
avutil: YES (ver 55.58.100)
swscale: YES (ver 4.6.100)
avresample: YES (ver 3.5.0)
GStreamer: NO
OpenNI: NO
OpenNI PrimeSensor Modules: NO
OpenNI2: NO
PvAPI: NO
GigEVisionSDK: NO
DirectShow: YES
Media Foundation: NO
XIMEA: NO
Intel PerC: NO
Parallel framework: Concurrency
Trace: YES (with Intel ITT)
Other third-party libraries:
Use Intel IPP: 2017.0.2 [2017.0.2]
at: D:/Build/OpenCV/opencv-3.3.0-vc14-x32-py36/3rdparty/ippicv/ippicv_win
Use Intel IPP IW: prebuilt binaries (2017.0.2)
Use Intel IPP Async: NO
Use Lapack: NO
Use Eigen: NO
Use Cuda: NO
Use OpenCL: NO
Use OpenVX: NO
Use custom HAL: NO
Python 2:
Interpreter: X:/Python27/python.exe (ver 2.7.13)
Python 3:
Interpreter: X:/Python36-x32/python.exe (ver 3.6.2)
Libraries: X:/Python36-x32/libs/Python36.lib (ver 3.6.2)
numpy: X:/Python36-x32/lib/site-packages/numpy/core/include (ver 1.13.1)
packages path: X:/Python36-x32/Lib/site-packages
Python (for build): X:/Python27/python.exe
Java:
ant: NO
JNI: X:/Java18/include X:/Java18/include/win32 X:/Java18/include
Java wrappers: NO
Java tests: NO
Matlab: NO
Documentation:
Doxygen: NO
Tests and samples:
Tests: YES
Performance tests: YES
C/C++ Examples: NO
Install path: D:/Build/OpenCV/opencv-3.3.0-vc14-x32-py36/install
cvconfig.h is in: D:/Build/OpenCV/opencv-3.3.0-vc14-x32-py36
-----------------------------------------------------------------
</pre>
hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-80265933141910295712017-02-08T02:05:00.001+09:002017-02-08T02:09:34.035+09:00ブートイメージからカーネル、rootfs、configを取り出すimage.ub ファイルからカーネル、rootfs、/proc/configを取り出す<br />
<br />
SDSoC 2016.3に含まれる ZYBO 向け Software Platform からカーネル、 rootfs、/proc/config を取り出したかったので取り出した。<br />
<br />
<h3>
そもそも image.ub ってなんだ</h3>
<br />
ARMで使えるブートローダu-bootが扱うイメージフォーマットらしい。<br />
<br />
<pre>$ mkimage -l image.ub
FIT description: PetaLinux arm uImage with single Linux kernel and FDT blob
Created: Fri Nov 18 04:07:34 2016
Image 0 (kernel@1)
Description: PetaLinux Kernel
Created: Fri Nov 18 04:07:34 2016
Type: Kernel Image
Compression: gzip compressed
Data Size: 8747883 Bytes = 8542.85 kB = 8.34 MB
Architecture: ARM
OS: Linux
Load Address: 0x00008000
Entry Point: 0x00008000
Hash algo: crc32
Hash value: 252654ca
Image 1 (fdt@1)
Description: Flattened Device Tree blob
Created: Fri Nov 18 04:07:34 2016
Type: Flat Device Tree
Compression: uncompressed
Data Size: 13962 Bytes = 13.63 kB = 0.01 MB
Architecture: ARM
Hash algo: crc32
Hash value: 66629950
Default Configuration: 'conf@1'
Configuration 0 (conf@1)
Description: PetaLinux Boot Linux kernel with FDT blob
Kernel: kernel@1
FDT: fdt@1
</pre>
<br />
<br />
<h3>
カーネルを取り出す</h3>
<br />
まずこのイメージからカーネルを取り出す。 mkimage -l の結果から gzip compressed であることがわかっているので、 magic を頼りに探すと 240バイト目から gzip データがあることがわかる。 mkimage の結果からファイルは 8747883 バイトであることがわかる。<br />
<br />
<pre>
$ grep -P -a -b --only-matching $'\x1F\x8B\x08' image.ub
240:
</pre>
<br />
なので<br />
<br />
<pre>$ dd if=image.ub of=linux.bin.gz bs=1 skip=240 count=8747883
8747883+0 records in
8747883+0 records out
8747883 bytes (8.7 MB, 8.3 MiB) copied, 6.91697 s, 1.3 MB/s
$ file linux.bin.gz
linux.bin.gz: gzip compressed data, was "linux.bin",
last modified: Thu Nov 17 19:07:33 2016, max compression, from Unix
</pre>
<br />
<br />
<h3>
カーネルの中から gzip データを取り出す</h3>
<br />
さらにこのアーカイブの中にrootfsが含まれている。cpioフォーマットで入っているかと思い、cpioフォーマットのヘッダである"070707"をgrepしたら発見... と思ったがハズレだった。これはcpioアーカイブじゃなくてcpioアーカイブを探すプログラムが参照している文字列っぽい。ということは...<br />
<br />
<pre>$ grep -P -a -b --only-matching $'\x1F\x8B\x08' linux.bin
6278680:
8588960:
9923536:
</pre>
<br />
gzip のヘッダらしきものが3つ見つかった。まずひとつ目は...<br />
<br />
<pre>$ dd if=linux.bin skip=6278680 bs=1 | gzip -dc > hoge
gzip: stdin: decompression OK, trailing garbage ignored
toor@gpusv:~/zynq7/extract_initramfs$ file hoge
hoge: Linux make config build file, ASCII text
</pre>
<br />
ASCIIだと!?<br />
<br />
<pre>$ head hoge
#
# Automatically generated file; DO NOT EDIT.
# Linux/arm 4.6.0 Kernel Configuration
#
CONFIG_ARM=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_MIGHT_HAVE_PCI=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_NO_IOPORT_MAP=y
</pre>
<br />
...config.gz だった。まあ、ついでなので保存。<br />
<br />
<pre>$ mv hoge config
</pre>
<br />
<br />
では次。<br />
<br />
<pre>$ dd if=linux.bin skip=8588960 bs=1 | gzip -dc > hoge
gzip: stdin: decompression OK, trailing garbage ignored
toor@gpusv:~/zynq7/extract_initramfs$ file hoge
hoge: ASCII cpio archive (SVR4 with no CRC)
toor@gpusv:~/zynq7/extract_initramfs$ cat hoge | cpio -it | head
cpio: Substituting `.' for empty member name
.
dev
dev/pts
etc
etc/opkg
etc/opkg/arch
etc/rpm
etc/rpm/sysinfo
etc/rpm-postinsts
etc/network
</pre>
<br />
今回は間違いなくinitrdイメージだ。<br />
<br />
<pre>$ mv hoge initrd
</pre>
<br />
<br />
目的な達成したけど、3つめはなんじゃらほい。<br />
<pre>dd if=linux.bin skip=9923536 bs=1 | gzip -dc > hoge
gzip: stdin has flags 0xce -- not supported
</pre>
<br />
<br />
これは有効なgzipじゃなかった。"070707" 同様に gzip をデコードするルーチンが参照している定数かも。hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0tag:blogger.com,1999:blog-8995862947808038366.post-40267036965717934082017-01-19T17:25:00.000+09:002017-01-19T17:36:49.899+09:00Oculus Rift CV1 に近視レンズを組み込んだ<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqH5PyczOpPrDPEG_7XidjTdKiwRMKoqyoUGXzqEQva2iu_4oCHAgHTNmxX7XKempIRXtJ6UPNPrP1hWR_CLQ7DDIfOTkHcGm0YBkNRwpY0dslWGQKEjKgN_KCC7imqU3RXDvEa3Mj4NA/s1600/Oculus-Rift-vs-HTC-Vive-vs-PlayStation-VR-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqH5PyczOpPrDPEG_7XidjTdKiwRMKoqyoUGXzqEQva2iu_4oCHAgHTNmxX7XKempIRXtJ6UPNPrP1hWR_CLQ7DDIfOTkHcGm0YBkNRwpY0dslWGQKEjKgN_KCC7imqU3RXDvEa3Mj4NA/s320/Oculus-Rift-vs-HTC-Vive-vs-PlayStation-VR-1.jpg" width="320" /></a></div>
<br />
Oculus Rift CV1 用のレンズアダプターで近視レンズを組み込んだので、久々にブログにまとめようかと。<br />
<br />
<h3>
皆さんの VR ライフ満喫していますか?</h3>
実は... 私はあまり満喫できていませんでした。眼鏡男子の私にとって Oculus Rift CV1 の利用それほど手軽ではなかったからです。<br />
<br />
普段、私は乱視矯正・近視矯正の両方が入った眼鏡をかけています。例外的に、冬にスノーボードを楽しむ時にはワンデータイプのコンタクトレンズを使っています。このため、 Oculus Rift CV1 で何か VR コンテンツを楽しむにあたっても、 Lucky's Tale 程度のコンテンツなら裸眼で問題ないとはいえ、 EVE: Valkyrie にょうな UI であったり、細かい文字を読み取らないといけないようなコンテンツではコンタクトレンズを装着しないと楽しめない状況でした。また、私が利用しているのはワンデータイプのコンタクトレンズです。ふらっと Oculus Rift で遊ぶときにワンデーコンタクトを消費するとなると、心理的なハードルはさらに高くなります。<br />
<br />
<h3>
CV1 用レンズアダプターを入手!</h3>
そんなことを思っていたら、Oculus Rift CV1 ヘッドセットにメガネ用のレンズを装着し近視矯正を可能にするアダプターの 3D モデルデータを見つけました。<br />
<br />
<blockquote class="twitter-tweet" data-lang="ja">
<div dir="ltr" lang="ja">
Oculus Rift CV1 にはめこんで使えるレンズフレームの3Dデータ。市販の眼鏡のレンズデザインに合わせてあるらしく、そのデータがあればお店でレンズを加工してもらえそう。これは早速プリントして、レンズはめ込んでみたい。 <a href="https://t.co/EDa3IWXylx">https://t.co/EDa3IWXylx</a></div>
— もつなべおじさん (@hasegaw) <a href="https://twitter.com/hasegaw/status/741709726640017409">2016年6月11日</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
このレンズアダプターは Oculus Rift CV1 にぴったりとはまるようにデザインされていて、レンズには、一般的な眼鏡用のレンズが利用できます。当初より公開されている、オリジナル版のアダプターでは、<a href="http://www.zennioptical.com/450021-metal-alloy-full-rim-frame-with-spring-hinge.html">Zenni Optical の #450021</a> 用に作られた、直径 40mm の円型の眼鏡用レンズを装着できます。<br />
<br />
これをどこかでプリントしてもらうか、プリントしてもらうなら送料ケチるために複数オーダーしたほうがいいかなとか色々考えつつ、手を出せていなかったのですが……。もう半年以上前に見つけたこのレンズアダプターですが、最近 3D プリンターを購入したという知人がこのアダプターをプリントしてくれたので、ついに実物を手に入れることができました。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmcS4QwhwGuY8vflBMn1Gh8cNHwT8NY5vf-6ebGucj01K9Q-aVDUZevVsez8GUh0PXxaoVjbLn5y0dsFoE6Hw35YJKbIy_f4d_Nyza-evITd-pBVWpxszhfNdu_6ReWM3anJMuaSWbvOk/s1600/Photo+1-19-29+H%252C+4+17+17+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmcS4QwhwGuY8vflBMn1Gh8cNHwT8NY5vf-6ebGucj01K9Q-aVDUZevVsez8GUh0PXxaoVjbLn5y0dsFoE6Hw35YJKbIy_f4d_Nyza-evITd-pBVWpxszhfNdu_6ReWM3anJMuaSWbvOk/s320/Photo+1-19-29+H%252C+4+17+17+PM.jpg" width="320" /></a></div>
<br />
写真は見やすい白い樹脂でプリントしたものを掲載しましたが、実際に CV1 に取り付けたものは黒色のアダプターです。<br />
<br />
<h3>
レンズを入手するための方法は?</h3>
そして、次のチャレンジは、「眼鏡のレンズをどうするか」です。今回入手したアダプターは先のとおり Zenni Optical #450021 と互換性があります。このアダプターに対応するレンズを入手する方法として、まずは下記2パターンが考えられます。<br />
<br />
<br />
<ol>
<li>同フレームのみ購入して、レンズは日本で作る</li>
<li>同フレームとあわせて、レンズも購入する</li>
</ol>
<br />
ずっと悩んでいたのですが、今回は結局、後者「レンズを購入したらフレームもついてくる」という形で入手することにしました。<br />
<br />
<h3>
はじめての通販眼鏡オーダー</h3>
次の問題は、いままで眼鏡購入は街のメガネ屋に依頼して作ってもらっていて、通販で眼鏡のレンズなんて買ったことがない、という点です。このため、過去に購入したコンタクトレンズや眼鏡のパラメータを参考にオーダーすることになります。<br />
<br />
<h4>
コンタクトレンズの度数でオーケー</h4>
先述のとおり、私は近視矯正用のコンタクトレンズを使用しているので、そのコンタクトレンズを見ることで自分が必要とする近視矯正のパラメータがわかります(というか何百回もコンタクトレンズを使っているので、近視の強さはもう憶えてしまっています)。手元のコンタクトレンズによる近視矯正のパラメータは下記のとおりでした。<br />
<br />
<ul>
<li>左目 -3.25</li>
<li>右目 -2.75</li>
</ul>
<br />
私のコンタクトレンズは乱視矯正タイプではありません。コンタクトレンズは乱視矯正が入るとモノが分厚くなります。個人差がありますが、私の場合、装着感が悪くなり、外れやすくなります。コンタクトレンズを購入するにあたって色々相談したり試した結果、「乱視矯正をせず、近視矯正だけにする」ことにしました(ただし近視矯正を多少強めに入れています)。過去12年ほど、ずっと同じ度数でワンデータイプのコンタクトレンズを使っておりこのコンタクトレンズで遠くにいる仲間の姿、顔や、トラック、遠くの看板など、アウトドアで必要十分な視界が得られることがわかっており、CV1でも問題ありません。このコンタクトレンズと同じ度数の眼鏡レンズを CV1 に入れれば問題ないはずです。<br />
<br />
<h4>
IPDは、眼球と眼球の距離</h4>
IPDは左右の眼球の中心の距離を示すパラメータのようです。コンタクトレンズは眼球自体に装着するので IPD の値がわからないのですが、 Ocuus Rift CV1 のセッティングでは 62mm がもっともはっきりして見えるほか、定規で自分の眼球の距離を測ってみてもおよそ 65mm ぐらいでした。「指定できるIPDの値がジャストでない場合は狭い方の値を選べ」ということですし、 CV1 で 62mm という数値が出ていたので、今回は 62mm で作成することにしました。<br />
<br />
<h4>
眼鏡購入時の伝票やカルテからも、必要となる値はわかるはず</h4>
眼鏡を持っていても自分の左右の目の矯正パラメータを憶えていることはそうそう無いと思いますが、眼鏡を作ってもらったときの資料が残っていれば、そこに矯正のパラメータが書かれているので、確認することができます。もしくは、眼鏡を作った眼科やお店に問い合わせれば、カルテが残っているはずです。<br />
<br />
<h4>
私がオーダーしたレンズのパラメータは?</h4>
先述の近視矯正のみであれば、Zenni Optical の眼鏡オーダー時に下記のパラメータでオーダーすれば十分です。CYL、Axisは乱視矯正の場合のパラメータですので、近視矯正だけの場合はゼロで問題ないのだと思われます。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3bwiqdN-XjEfh-OeIuaIB0FDJ9iY1fIUiagIyhOBMvp7OZdnlgKTwrM_Ng7FeYFsw_ATwOgiBp7AVBt0KV07Ld7TCUpqjjENOx1mTNhu95-8rrB9fQiGf3G9BQps3awK542xN63q1Fxw/s1600/Screen+Shot+2017-01-19+at+17.09.24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3bwiqdN-XjEfh-OeIuaIB0FDJ9iY1fIUiagIyhOBMvp7OZdnlgKTwrM_Ng7FeYFsw_ATwOgiBp7AVBt0KV07Ld7TCUpqjjENOx1mTNhu95-8rrB9fQiGf3G9BQps3awK542xN63q1Fxw/s400/Screen+Shot+2017-01-19+at+17.09.24.png" width="400" /></a></div>
<br />
<br />
一般的に眼鏡のレンズは矯正がつよいほどレンズが分厚くなり、高価なレンズほど値段が安くなります。つまり安価なレンズで矯正を強くするとレンズが太くなります。今回、私は 1.57 Mid-Index Single Vision のレンズでオーダーしました。<br />
<br />
Oculus Rift CV1への装着感、見え方など含めて、私の度数ではこの設定で特に問題はなさそうです。近視が私より大幅に強い人は、薄い購入レンズを選ぶか悩まれるかもしれません。<br />
<br />
コーティングは下記のみにしました。どうせ VR 用ですし。<br />
<ul>
<li>Anti‐Reflection Coating</li>
<li>Standard anti‐reflective coating</li>
</ul>
<br />
<h4>
価格は?</h4>
レンズ(+フレーム)代金は14.90ドル、日本への送料が9.95ドルでした。クレジットカードへの最終的な請求金額は下記のとおり、3000円弱でした。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsIu-LgvuyTpX476JegDe0SQ4_J-iu_RL6zNmXKA183Waxs8bZXZ46pSdDqZQx7WB98FnAPrnnmWbbLN_eoaOY7-UHLOW1uO2N923jh5t7HRJ98Yk2xt7JRakqS3g76LJuttZJ355AwnY/s1600/Screen+Shot+2017-01-19+at+16.48.15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="75" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsIu-LgvuyTpX476JegDe0SQ4_J-iu_RL6zNmXKA183Waxs8bZXZ46pSdDqZQx7WB98FnAPrnnmWbbLN_eoaOY7-UHLOW1uO2N923jh5t7HRJ98Yk2xt7JRakqS3g76LJuttZJ355AwnY/s320/Screen+Shot+2017-01-19+at+16.48.15.png" width="320" /></a></div>
<br />
<br />
<h3>
配達されてきた</h3>
オーダーしたレンズ(+フレーム)は香港で製造され、日本に向けて出荷されたようです。封筒に眼鏡ケースを入れて送られてきました。(写真は後でとったもので、レンズは取り外し済みです)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiphlenyNCDBM3V9AyaDxpFiriThYA3RnwgBV6s-5tewHx0qUOJMUi99hW5UzG68RfH86rPiB1U7q0QPiaDF9Z0fQSaS1STmM6ArW2ze4k5bcg9qV3p_1Dx-jKbOZe0EUiod4RnlKuz6r0/s1600/Photo+1-19-29+H%252C+4+12+07+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiphlenyNCDBM3V9AyaDxpFiriThYA3RnwgBV6s-5tewHx0qUOJMUi99hW5UzG68RfH86rPiB1U7q0QPiaDF9Z0fQSaS1STmM6ArW2ze4k5bcg9qV3p_1Dx-jKbOZe0EUiod4RnlKuz6r0/s320/Photo+1-19-29+H%252C+4+12+07+PM.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg76PupKmk_Tnj_UNl6bnEhEd56qbre-4_yLRBksa6QK0LYxSe1PIJhnoIQTurq2LLya6MMkxR9HJ4JxM_hnzz97dUMJr0o5UZLB7aSUo3sWHj7DoZAqry9flylr0oaQXqpPH0ZHF3nZU4/s1600/Photo+1-19-29+H%252C+4+12+41+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg76PupKmk_Tnj_UNl6bnEhEd56qbre-4_yLRBksa6QK0LYxSe1PIJhnoIQTurq2LLya6MMkxR9HJ4JxM_hnzz97dUMJr0o5UZLB7aSUo3sWHj7DoZAqry9flylr0oaQXqpPH0ZHF3nZU4/s320/Photo+1-19-29+H%252C+4+12+41+PM.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
ちなみに常用している日本ブランドの眼鏡と比べると、ノーズパッドのは幅に大きな差があります。日本人は鼻が低いですもんねー。</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyxCCYM0tewmzwkk5Mo_Oxw-wB2TyIOBu32-h8SZNOGDsJTsvTpaOzgl55_YPb426ftWEcHlOGw3ol2nMX_urvNPHw-jVrAB-lVhoHTb3sQvOXk-a0oCafly3Xj9wrzaEeW027soNLeWI/s1600/Photo+1-19-29+H%252C+4+13+22+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyxCCYM0tewmzwkk5Mo_Oxw-wB2TyIOBu32-h8SZNOGDsJTsvTpaOzgl55_YPb426ftWEcHlOGw3ol2nMX_urvNPHw-jVrAB-lVhoHTb3sQvOXk-a0oCafly3Xj9wrzaEeW027soNLeWI/s320/Photo+1-19-29+H%252C+4+13+22+PM.jpg" width="320" /></a></div>
<br />
<br />
出来上がった眼鏡の状態で見え方に問題がないかを確認しても、とくに問題はありませんでした。<br />
<br />
<h3>
重要! レンズを外す前に</h3>
レンズを外す前に、コーティングを痛めないようなメンディングテープや付箋をレンズにはり、上下がわかるようにしておくことをお勧めします。<br />
<ul>
<li>右目レンズか、左目レンズか</li>
<li>レンズのどの部分が上か(円形レンズなので方向がわからなくなる)</li>
</ul>
特に、<b>乱視矯正レンズだと方向は絶対に大事</b>なので、やはり方向がわからなくならないよう、特に注意してください。<br />
<div>
<br /></div>
実は、私の場合この眼鏡に対応できる精密ドライバーが手元になかったので、普段お世話になっている眼鏡ショップでレンズを外してもらいました(店舗によっては嫌がられるでしょうから、これが当たり前だとは思わないでください!)。この際、どちらが上であったか等を示す印をつけないまま外してもらった都合、購入時点でどの部分が上だったかは分からなくなっており、反省点です。(IPDがおかしいことになっているかも)<br />
<br />
<h3>
CV1への装着</h3>
まず、眼鏡のレンズ2枚を装着します。レンズアダプターに必要以上の力をかけないように注意しながらはめこみます。一度はめ込んでしまえば、アダプターからレンズがすぐにポロッと落ちることはないでしょう。少しゆるく感じるかもしれませんが、CV1に組み込めば、もっと安定します。<br />
<br />
CV1の顔に当たるスポンジ部分は、その樹脂フレームと一緒に、Rift本体から分離できます。液晶側(スポンジがついていない方)からレンズアダプタの下のレール部分をはめこみます。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiL1FT8jzPaVP34V2T9KIwzr4UgP0B4vL2nN4zxYp8U8XpQgorywkkYzuiBxuHcaCJ6OUONmCOHhS4fA4QkYYlhVcj6MQNMkp_zQrX5Tx0IOO4RzYQ5vXYmk94gkN4R9qRHwebcKyYv5Cs/s1600/Oculus-Rift-CV1-Prescription-Lens-Adapter-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiL1FT8jzPaVP34V2T9KIwzr4UgP0B4vL2nN4zxYp8U8XpQgorywkkYzuiBxuHcaCJ6OUONmCOHhS4fA4QkYYlhVcj6MQNMkp_zQrX5Tx0IOO4RzYQ5vXYmk94gkN4R9qRHwebcKyYv5Cs/s320/Oculus-Rift-CV1-Prescription-Lens-Adapter-1.jpg" width="320" /></a></div>
<div style="text-align: center;">
Thingverse に投稿されている写真より</div>
<div>
<br /></div>
そして、同パーツとレンズアダプタをOculus Rift CV1本体にはめ込めば取り付け完了です。<br />
<br />
<h3>
利用感</h3>
映像の見え方としてはバッチリです。<br />
<br />
普段利用している眼鏡を外さないといけないのはまだまだ不便ではあるのですが、それでもコンタクトレンズなしで CV1 を装着すれば VR 内で表示された小さな文字まできちんと読めるので大変便利です。実はまだ Touch をオーダーしていないのですが、今後 Touch を入手するのが楽しみになりました。<br />
<br />
<h3>
まとめ</h3>
普段から視力矯正が必要な人が VR ヘッドセットをかぶるのはちょっと大変です。でも、 CV1 に今回紹介したレンズアダプター、そして安く作れるレンズを組み合わせることで、 VR ライフがより身近なものになります。<br />
<br />
私のような、眼鏡を常用しており、結果として Oculus Rift CV1 から遠ざかってしまっているオーナーの方もいるかと思います。そんな方には本アダプターがとても役にたつかとと思います。<br />
<br />hasegawhttp://www.blogger.com/profile/06201819038509668863noreply@blogger.com0