2015 年やったこと - Mozc 編

1 年遅れぐらいになりますが,OSS Mozc 関係で 2015 年にやったことのまとめです.

空き時間を利用したプロダクトチーム外からのコミットということで,新規機能に関しては引き続き何も行っていません.前年と同じく OSS プロジェクトとしての環境整備と技術的負債の解消に注力した年でした.

以下が主な活動内容です.

  • Google Code (Subversion) から GitHub (git) への移行を完了
    • 過去のコミット履歴を可能な限り維持
    • ドキュメントを Markdown で書き直す
    • Travis CI および AppVeyor を利用し,サポートしている全プラットフォームについて CI (Continuous Integration) を実現
      • Android
      • Linux desktop
      • NaCl
      • Windows
      • macOS
  • コードの簡略化
    • プロダクションに使われなかった実験的コードの削除
    • サポートを終了した古い OS 向けコードの削除
    • 積極的にコンパイラをアップグレードし,C++ 11 のライブラリでコードを書き換え
      • Windows 環境は Visual C++ 2010 から 2013 を経て 2015 へ
      • 非 Windows 環境は GCC から Clang / libc++ に移行
      • base/hash_tables.hstd::unordered_map / std::unordered_set に置き換え
      • mozc::scoped_ptr<T>std::unique_ptr<T> に置き換え
  • Windows 10 向けの緊急性の高い問題の修正

コミット単位でみる作業まとめ

Windows XP 向けコードの削除

以前は最低サポート環境が Windows XP であったため,Windows Vista 以降に追加された API は GetProcAddress で動的にリンクするというスタイルで統一されていました.Windows XP 廃止後も同様のコードは動くことは動くのですが,コードが不必要に長くなるだけでなく,Loader Lock に代表されるような同期的モジュール解決の問題すらも不必要に呼び込んでしまいます.そこで,Windows Vista 以降に追加された API に関しても可能な限り暗黙的なリンク (Implicit Linking) に変更したのが主な変更内容です.

少し冒険してみた点としては,DLL の Import Library が提供されない input.dll についても,ビルドルールを工夫して暗黙的にリンクするようにしてみたということでしょうか.基本的には DLL から「正しい」LIB ファイルを作るには と同じことを行っています.

Android 版の不要なコードの削除

サポートバージョンを上げたことにより不要になったコードを削除しました.

Visual C++ 2013 への移行

Mozc の Windows 向けビルドは,2015 年始めの時点では依然として Visual C++ 2010 を使用しており,これが C++ 11 移行の大きな障害となっていました.これをまずは Visual C++ 2013 段階までアップグレードするという試みです.これに付随して,Windows Kit (Windows SDK) 8.1 に追加されたライブラリや定数を使ったコードの簡略化も行いました.

この過程で遂に実現できたもののひとつに,NOMINMAX マクロをプロジェクト全体に適用することに成功した,というものがあります.そうです,<windows.h> を include するだけで,min/max というプリプロセッサマクロが定義されてしまうという問題が,commit 2cc1a055 によってついに過去のものとなったのでした.

Visual C++ 2015 への移行準備

2015 年の年末にかけて,さらに Visual C++ 2013 から Visual C++ 2015 への移行の下準備を行いました.移行の完成は 2016 年を待つことになりますが,2015 年の段階である程度の下準備 (Google TestProtocol Buffers のアップデート等) を完了することができました.

C++ 11 対応

Visual C++ 2013 への移行でいよいよ C++ 11 対応の目途がたったことから,まずは全プラットフォームで C++ 11 が前提とできるようにビルドルールの変更等と行いました.この過程で STLPort を利用した Android ビルドを非サポートとしたり,非 Windows 環境のデフォルトコンパイラを Clang に統一したりといった変更も行っており,全体としてはビルドルールの簡略化に貢献できたものを考えています.

その後,実際に C++ 11 の新しいライブラリを用いて以下のような置き換えを行いました.技術的に難しいところはないものの,単純に多数のファイルを変更する必要があるため,時間に余裕があるときでないとなかなか難しい作業です.

  • base/hash_tables.hstd::unordered_map / std::unordered_set に置き換え
  • mozc::scoped_ptr<T>std::unique_ptr<T> に置き換え

実験的コードの削除

Remove unused code from mozc_tool · google/mozc@51b1f78 · GitHub

もしかしたら将来使うかも,と導入したものの,結局プロダクションで使われなかったコードの削除も行いました.例えば上記コミットで削除されているコードは,1,000 行以上もありながら Windows 専用かつプロダクションでは一度も使われていないという正真正銘デッドコードです.

ibus-mozc 廃止に向けた下準備

予定されていた ibus-mozc廃止は結局 2015 年中に行われませんでしたが,そのための下準備としていくつか ibus-mozc 関連のコードのクリーンアップを行っています.

一番入れたかった変更は commit 7a129e65 で,mozc_server 中にある ibus-mozc 専用コードを今のうちに削除しておくというものです.このコードは,IMR_QUERYCHARPOSITION NSTextInputClient firstRect と同様の機能をなんとか Gtk+ IM Module 上に実現しようとしたものの名残で,クライアントコードはなるべく簡潔にするという Mozc の設計思想に基づき mozc_server 側にエミュレーションコードが実装されました.しかしながら,Mozc Issue #243 で議論されているように本質的に解決できないコーナーケースが存在すること,および ibus-mozc 以外では使用されていないこと,という 2 点の理由から,ibus-mozc 廃止前に完全に削除しておきたかったのでした.

GitHub への移行と Continuous Integration (CI) の整備

Google Code のサービスを終了にともない,OSS Mozc についても GitHub への移行を行うこととなりました.当時は私自身あまり git に慣れていなかったこともあり,Subversion から git への移行をあれこれ試行錯誤するのにずいぶんと時間を使ったように思います.

とはいえ移行が済んだあとは GitHub のエコシステムに感心するばかりでした.特に CI については最終的にサポートしている全プラットフォームについて自動ビルドをセットアップすることができ,マルチプラットフォーム対応に価値を置いているプロジェクトとしては本当に助かっています.

Travis CI のセットアップ

AppVeyor のセットアップ

gclient から git submodule への移行

Windows 10 対応

Windows 10 で状況が変わった点についてもいくつか緊急的な修正を行いました.

  • 言語バーが Store App でも使われるようになったことへの対処
  • サンドボックス下で実行されるアプリケーションから mozc_server プロセスを起動できないという制約が Windows 8.1 時代よりも目立つようになったため,いくつかの対症療法的な変更

不安定なテストの改善

Travis CI 上で不安定だったテストについて安定化を試みました.

透明度付き PNG ファイルを PBGRA32 形式の Bitmap ファイルの変換するツールを作成

ちょうど 2015 年,会社のロゴが更新され,候補ウィンドウに表示される画像も変更する必要ができました.

Windows 版の mozc_renderer は,会社ロゴの表示に GDI の AlphaBlend API を利用しています.問題はこの API はいわゆる乗算済みアルファ フォーマット (正確には PBGRA32 形式) を期待していることです.デザイナーさんから渡された PNG ファイルを PBGRA32 に変更する必要があったですが,適当なツールがみつからなかったので急遽作ったのがこちらのコードでした.

雑感

以前から興味のあった GitHub 上での作業や CI について一通り体験することができたのは非常に有意義でした.また,git filter-branchgit rebase を使ったコミット履歴の編集を学ぶ上でも良い機会でした.

一方,前年に引き続きメンテナンス作業に注力して実感したのは,ソフトウェアのメンテナンスというのは本当にコストがかかるというというものでした.OSS Mozc に関して言うと,以下の作業だけで年間 100 時間は軽くかかっています.

  • コンパイラのバージョンを上げる
  • 依存するライブラリのバージョンを上げる
  • 丁寧にリリースノートを書く
  • ドキュメントを最新の状態に維持する
  • Issure Tracker に報告された問題に丁寧に答える

自分の場合これらの作業に有給休暇 10 日分以上を消費していることになるわけで,今後も同程度の貢献が継続可能かというと大変に疑問です.各種 Linux ディストリビューションで OSS Mozc が採用されるのはありがたい一方,最大の不安は期待値が高くなりすぎることです.将来のメンテナンスも含めて,あくまで無保証で提供されているという点を今一度思い出していただければという次第.

過去の関連エントリ

Android 7.1 に追加した API

github.com github.com github.com github.com

  • BaseInputConnection#commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle)
  • EditorInfo#contentMimeTypes
  • InputConnection#INPUT_CONTENT_GRANT_READ_URI_PERMISSION
  • InputConnection#commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle)
  • InputConnectionWrapper#commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle)
  • InputContentInfo#InputContentInfo(android.net.Uri, android.content.ClipDescription)
  • InputContentInfo#InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri)
  • InputContentInfo#describeContents()
  • InputContentInfo#getContentUri()
  • InputContentInfo#getDescription()
  • InputContentInfo#getLinkUri()
  • InputContentInfo#writeToParcel(android.os.Parcel, int)
  • InputContentInfo#CREATOR

Android 7.0 Nougat に追加した API

github.com

  • View#dispatchFinishTemporaryDetach()
  • View#dispatchStartTemporaryDetach()
  • View#isTemporarilyDetached()

github.com

  • InputConnection#closeConnection()
  • InputConnectionWrapper#closeConnection()
  • BaseInputConnection#closeConnection()

github.com

  • InputConnection#getHandler()
  • InputConnectionWrapper#getHandler()
  • BaseInputConnection#getHandler()

github.com

  • Settings#ACTION_KEYBOARD_LAYOUT_SETTINGS

github.com

  • TextView#getImeHintLocales()
  • TextView#setImeHintLocales()

github.com

  • LocaleSpan#LocaleSpan(LocaleList)
  • LocaleSpan#getLocales()

github.com

  • SuggestionSpan#getLocaleObject()

github.com

  • InputConnection#deleteSurroundingTextInCodePoints(int, int)

github.com

  • InputMethodManager#dispatchKeyEventFromInputMethod(View, KeyEvent)

github.com

  • InputMethodSubtype#getLanguageTag()
  • InputMethodSubtype.InputMethodSubtypeBuilder#setLanguageTag(String)
  • SpellCheckerSubtype#getLanguageTag()

github.com

  • EditorInfo#locales()

github.com

  • LocaleList#describeContents()
  • LocaleList#writeToParcel(Parcel, int)
  • LocaleList#CREATOR

Windows 10 Insider Preview Build 14332 実験ノート: ブラウザと IME のプライベートモード連携

Windows 10 Preview ビルド 14328 でお試しいただける日本語 IME の変更点について – Windows & Devices 開発統括部

入力履歴の管理が便利になりました。人に見られたくない履歴が候補リストに表示されて困った経験はありませんか?
プライベートモード(仮称)を使えば、その間に蓄積された入力履歴はモードの終了時には削除され、その後意図しない場面で表示されてしまうことを防ぐことができます。
プライベートモード(仮称)はIME のアイコンをクリックして表示されるメニューから「プライベートモード」を選択することでオン・オフすることができます。Edge や Internet Explorer で InPrivate ブラウズ機能をお使いの場合は、本機能が自動的に オン・オフ されます。
プライベートモード(仮称)で蓄積された入力履歴はプライベートモードの間だけ有効となり、モードの終了時には削除されます。それまでにプライベートモード以外で蓄積されていた入力履歴のデータには影響ありません。

ブラウザと IME のプライベートモード連携は,自分にとっても時間があったらやれたらいいなぁと思っていた機能だったこともあって,週末を利用して少し調べてみました,がどうも時間切れっぽいのでメモだけでも残しておきます.想定読者はブラウザ開発者,IME 開発者,および IME API 開発者という感じですが,正直に言えば自分用のメモです.

この機能,名前に (仮称) が付いているようにまだまだフィードバックしだいで色々変わりうる段階と思われます.というわけでまだちょっと調べたりないのですが,実験したい人向けにメモでも残しておく次第です.

疑問点

  1. そもそも Internet Explorer / Edge と MS-IME はどのようなプロトコルでこの動作を行っているのか?
  2. サードパーティ製のブラウザと MS-IME の組み合わせで同じことができるか?
  3. Internet Explorer / Edge とサードパーティー製の IME で同じことができるか?

今回の調査結果

そもそも Internet Explorer / Edge と MS-IME はどのようなプロトコルでこの動作を行っているのか?

時間内に絞り込み切れませんでした.無念……

サードパーティ製のブラウザと MS-IME の組み合わせで同じことができるか?

上の結果が確定しなかったため確たる結論に至れず.残念……

Internet Explorer / Edge とサードパーティー製の IME で同じことができるか?

公開 API のみで,InPrivate モードの検出が可能であることまでは確認.少なくとも見かけ上は可能.

調べたこと

  • ITfTextInputProcessorEx::ActivateEx に指定される flags は,InPrivate かどうかで変化するか?
  • ITfThreadMgr::GetGlobalCompartmentITfCompartmentMgr::EnumCompartments の結果は InPrivate かどうかで変化するか?
  • ITfThreadMgr::QueryInterfaceITfCompartmentMgr::EnumCompartments の結果は InPrivate かどうかで変化するか?
  • ITfDocumentMgr::QueryInterfaceITfCompartmentMgr::EnumCompartments の結果は InPrivate かどうかで変化するか?
  • ITfContext::QueryInterfaceITfCompartmentMgr::EnumCompartments の結果は InPrivate かどうかで変化するか?
  • ITfContext::EnumProperties で列挙される ITfProperty に対応しそうなものはあるか?
  • Edge の設定する InputScope は InPrivate かどうかで変化するか?
  • InputScope の一種 IS_PRIVATE (== 61) で MS-IME は動作を変化させるか?
  • Windows 10 Anniversary SDK Preview Build 14332 の API ヘッダの差分および InPrivate と付いた API に関連しそうなものはあるか?

得られた知見

  • Build 14332 時点で,正式な InPrivate 連携 API が Text Services Framework (TSF) に存在するかどうかは疑わしい.InputScope を含め,TSF の API で観測可能な範囲内に InPrivate モードの有効無効を示唆するものは一切見つけられなかった.
  • Build 14332 時点で,InputScope の一種 IS_PRIVATE によって MS-IME をプライベートモードにすることはできなかった.
  • Internet Explorer であれば,ieframe.dll のエクスポート関数 IEIsInPrivateBrowsing が依然として利用可能.ただしこの API は Edge のプロセスには読み込まれない.
  • Windows 10 SDK では,ProcessInPrivateInfo という列挙値が processthreadsapi.h に追加されている (少なくとも 10.0.10586.0 SDK の時点で既に存在する).
typedef enum _PROCESS_INFORMATION_CLASS {
    ProcessMemoryPriority,
    ProcessMemoryExhaustionInfo,
    ProcessAppMemoryInfo,
    ProcessInPrivateInfo,
    ProcessInformationClassMax
} PROCESS_INFORMATION_CLASS;

Build 14332 時点で,以下のコードは Internet Explorer および Edge 共に InPrivate モードのみ true を返す.

bool is_process_in_private() {
  BYTE value = 0;
  if (!::GetProcessInformation(GetCurrentProcess(),
                               ProcessInPrivateInfo,
                               &value,
                               sizeof(value)) {
    return false;
  }
  return value != 0;
}

フィードバックアイディア

ちょっと裏付け不足でまだ未登録なのですが,概ね以下の点についてもうちょい調べてみないとなーと思っております.

  • プライベートモード連携に関しては,TSF の公開 API 内で完結させ,サードパーティー製ブラウザおよびサードパーティー製 IME との相互運用性に配慮して欲しい.ファーストパーティ製ブラウザおよびファーストパーティ製 IME の間のみで使われるプライベートプロトコルは好ましくない.
  • ProcessInPrivateInfo は,現状取得のみが可能なように見える.これに該当する特殊プロセスの作成に非公開 API が必要なのであれば,ファーストパーティ製ブラウザのみがそれを使用可能という状況は好ましくない.

関連事例

(同一プロセスで動く IME で使うことを前提とした) Accessibility API を利用したプライベートモード検出

書くいう自分も,2013 年末ごろには MSAA を使ってプライベートモードの検出ができるかどうか実験したりしていました,がチームを移ったあとのごたごたで結局プロダクションでは使われてなかったりします.その辺のコードがいまもここに.

mozc/src/win32/base/browser_info.cc BrowserInfo::IsInIncognitoMode

sufix は typo ですすみません.あとで直します……

Chromium Bug 311180: Chrome OS: Incognito window is not really incognito for IME users

Issue 311180 - chromium - Chrome OS: Incognito window is not really incognito for IME users - Monorail

Chromium OS での同様の機能リクエスト.長いこと放置されていて辛い感じです.

Chromium Bug 601951: Android keyboard suggestions leak information typed in incognito window

Issue 601951 - chromium - Android keyboard suggestions leak information typed in incognito window - Monorail

Android 版 Chromium での同様の機能リクエスト.

この件については SwiftKey のサポートページにも以下のように書かれていたり.

Can I turn off learning in incognito mode with SwiftKey Keyboard for Android? – SwiftKey Support

Unfortunately, the keyboard actually does not know that you are in this special mode in the Chrome app because that is not something Google passes on to other apps.

改定履歴

  • 2016-05-02: ProcessInPrivateInfo の追加時期について表現を変更.少なくとも 10.0.10586.0 SDK の時点で存在する.

My OSS Wish List

f:id:NyaRuRu:20150914052437p:plain

業務外にパッチを書いたりしている OSS プロジェクト,だいぶやりたいことが溜まっているので,優先順位をつける意味でもまとめてみた. 業務と基本無関係なので,代わりにやっていただくのは大歓迎.なので以下は Wish List ということにしておきたい.

OSS Mozc 関係

[Mozc] Windows 版向けのインストーラーをビルドできるようにする

2013 年に Windows 版のコードを概ねオープンソース化したときに,面倒で後回しにしたのがこの部分. プロダクト版の WiX スクリプトは実際公開済みではあるのだけど,自動アップデート関係の設定等もここで行っているため OSS 版のインストーラにそのまま転用できなくなっている. 技術的な障害は何もなく,OSS 版向きでない処理を取り除くだけ,なんだけどずるずるとはや 2 年半ぐらい.

やること.

  • OSS Mozc 向けに,余計なものを取り除いた WiX スクリプトを書く
  • ビルドに必要な WiX のインストール方法を決める.OSS Mozc のリポジトリにチェックインしてしまうか,choco install wixtoolset あたりを使う.

[Mozc] DirectWrite を使うと真っ白になる問題を再現させる

候補ウィンドウの DirectWrite で表示するというコードを実装したのがだいぶ前の 2013 年 12 月ごろ.先日こいつが安定版に取り込まれ,それなりの数のユーザーにリリースされたところ,文字が全く表示されなくなるという問題が各所で起こることが判明.急遽該当コードを無効化するという事態に. 報告を読む限り Windows 7 環境限定っぽいのですが手元で再現できていないので詳しいことはよくわからず.

やること.

  • 再現環境を入手する
  • Mozc の実装に問題があるかどうかを調査する.問題があれば修正する.
  • もし環境側の問題であれば,それを検出する方法があるか調査する.
  • DirectWrite を用いた表示を無効化する設定を設定ダイアログに追加するべきか検討する.必要があればその実装.

[Mozc] ソースコードのチェックアウトプロセスから Subversion 依存を取り除く

Mozc Issue #299 参照. 技術的な障害は何もなく,淡々と手を動かせば終わるはず.

[Mozc] 依存する外部リポジトリの管理を gclient から Git submodule に変更

Subversion 依存が取り除かれれば,あとは機械的に対応可能.

[Mozc] ibus-mozc の削除

Mozc Issue #287 及び Mozc Issue #194 参照. これは割と自分の都合でお願いして削除することを決めてもらった話なので,早いところ何とかしたい.

ibus-mozc に関しては主に 2 つの理由からサポートをやめたいと思っていた.ひとつはメンテナー不在という問題,もうひとつは互換性問題の多発による周辺プロジェクトの疲弊がある.

メンテナー不在に関しては単純で,自分の空き時間の使い道としては優先順位が高くない,というのが理由である. 自分が OSS Mozc のメンテナンスを引き受け始めたころには,既に Chromium OS は IBus の使用をやめており,ibus-mozc を業務でメンテナンスする人間はいなかった. 自分の場合 OSS 関係のプロジェクトに関しては基本的に業務外時間で面倒を見ていて,そのため土日にできる範囲で作業するというスタンスを取っている. 日本語入力については,Windows と Android であれば日常的に使っているという意味もあってまだ興味が持てるものの,Linux Desktop 上で日本語入力することは基本的にない. そのため,既知のバグを概ね直しきったところで手を引くべきだと考えていた. Mozc Issue #194 という Issue を立てメンテナーを社内外から募集してみたのが 2 年ほど前. 残念ながら特に引き取り手は現れなかったので,まだ作業する余裕があるうちにコードを削除してしまおうというのが現在の考えである. というものの実際ここ数ヶ月は時間がとれずに作業が進んでいなかったので,もう少し早く始めていれば良かったのかもしれない.

互換性問題に関しては,複雑だ. IBus 1.4 あたりから,IBus の様々な処理が非同期プロセス間呼び出しとして実装されているのだけど,自分が普段使っているアプリケーションを中心にこれが何度も互換性問題を引き起こしている.

自分の理解が正しければ,もともと Chromium OS でのパフォーマンスを稼ぐために寄せられたパッチ群がもとで ibus が非同期処理を多用し始めた,という歴史だったように思う.とすれば不幸としか言いようがない. とはいえ同僚が今もこの件で時間を消費していることを考えると,多くのユーザーには IBus 以外の実装に移って欲しいという気持ちもある.心境としては複雑ではあるのだけど.

やること.

  • 社内リポジトリで変更済みの ibus-mozc 関係の更新を全て OSS 化
  • ibus-mozc 関係のコードを全削除
  • fcitx-mozc 等の代替ソフトウェアに足りない機能があれば,可能な範囲でそちらへの協力.
  • IBus の非同期モードが問題を引き起こしている周辺プロジェクトへのできる限りの協力.

[Mozc] tsf-mozc の Windows 10 関係の互換性問題の調査

やること.

  • Windows 10 環境を作る
  • 色々と言われている問題が再現するか調査.再現するなら直す.

[Mozc] Windows 環境での縦書きサポート

ずっと言われているのでどこかで時間を取って何とかしたい.候補ウィンドウ側に関してはハッカソンで一回動くところまで作ったことがあって,2 日もあればそこまではできることは確認済み. 問題は変換エンジン側で,縦書き時にカーソルキーの意味が変わるという動作をきちんとプロトコルレベルで定義する必要がある.

やること.

  • 候補ウィンドウの縦書きを実装.テストも追加.
  • 縦書きと横書きでキーマップを入れ替えるためのプロトコルを定義する

[Mozc] Qt 5.x への移行

Mozc では依然として Qt 4.8.x 系を使っているのだけど,いくつかの理由から 5.x へのアップグレードを急ぐ必要がある.

  • Qt 4.8.x では Windows の HiDPI 環境をサポートできない.これはだいぶ深刻.
  • 様々な Linux ディストリビューションが Qt 4.x のサポートを打ち切りたがっている.

基本的には Qt のアップグレードでビルドが通らなくなるところをひたすら直していく以外にないのだけど,Qt にパッチを当てずに移行可能かはまだ未知数. また,ビルドが通っても特定ユーザー環境で問題が発生する可能性もあり,先は長い.

[Mozc] Linux および Android 向け Continuous Build / Test 環境の整備.

現在の OSS Mozc は,Windows と OS X に関してある程度の Continuous Build / Test 環境が有効化されているものの,Travis CI が長らく Linux 12.04 にとどまっているため Linux および Android に関しては有効化できていなかった. 最近 Travis CI が Docker をサポートを追加したらしく,そろそろ何とかなりそうな気がしている.

[Mozc] その他溜まっている OSS Mozc の更新

Mozc の開発は現在も社内リポジトリが master. OSS リポジトリの更新タイミングは,基本的に誰かの手が空いているときであって,ここ 1 年半ぐらいは自分が土日及び休暇の空き時間を利用して行っている. で,ここのところ時間がとりにくかったのもあって,OSS 化すべき更新が 7 ヶ月分ぐらい溜まっている.

やること.

  • 作業のさらなる自動化.
  • ビルド確認の手間を減らすべく CI の拡充.

gclient から git submodule に移行すれば,GitHub 界隈のエコシステムをもうちょっとうまいこと活用できるんではないかと期待.

GYP 関係

[GYP] Revert された 540e4b1e665 の再有効化

これは完全に巻き込まれ案件なのだけど,個人的に気になっていて何とかしたい.以下時系列.

  1. いくつかのビルドツールで問題を起こすことから,GYP は同一ビルドターゲット内に (ディレクトリだけ異なる) 同名ファイルが存在することを許さない.一方,社内外からこの制限が不便だという声があがっていた.
  2. 数年前,社内リポジトリにとりこまれたバージョンの GYP に,このファイル名チェックを回避するオプションを追加するローカルパッチが提案され,メンテナンスを担当していた自分はうかつにもこれを受け入れてしまう.以後,アップデートのたびにパッチを当てなおす必要がうまれメンテナンスコストが増大.
  3. 自分が中心となって,GYP upstream に同等のオプションを実装 GYP r1947
  4. 上記機能が実装された GYP を社内にインポート.いくつかのプロジェクトがそのオプションを有効にする.
  5. とある Chromium 開発者,この制限を完全に取り除くパッチを提案.受け入れられる.GYP r1993
  6. 上記機能が実装された GYP を社内にインポート.不要になったオプションは削除される.
  7. GYP r1993 が,Chromium のビルドで警告を引き起こすことが分かり revert される.GYP c0cf1f22eb

というわけで,最新の GYP をそのまま社内にインポートすると,いくつかのプロジェクトでビルドが壊れることが分かっている.何とかしたい. この問題,自分の理解では OS X の libtools の制限によるもので,XCode では技巧的な方法で回避済み.同じことを GYP の Ninja ジェネレータでも実装すれば済む話,なんだけど時間が取れずまだ何もできていない.

が,こうやって書いてみると,自分的には最新の GYP がインポートできれば十分なので,もう一回社内の該当プロジェクトにオプション追加すれば良いだけのような気もしてきた……

やること.

  • 自分で直すまたは代わりにやってくれる人をみつける.

Chromium 関係

[Chromium] Web MIDI の実装に Windows 10 の新 MIDI API が使えるか調査

Chromium Issue #512433 参照. Windows 10 には MIDI API が追加されていて,Windows 版 Chromium の Web MIDI がもっと使いやすくなる可能性がある.

やること.

  • 自分でやるまたは代わりにやってくれる人をみつける.
  • 自分でやる場合,まずは Windows 10 環境を作る.

[Chromium] その他 Chromium の Web MIDI サポートで担当者募集中バグの修正

2015 年 9 月 13 日現在 24 個の担当者募集中バグがある. しかしこれはちょっと分量的につらいかも.

やること.

  • 自分でやるまたは代わりにやってくれる人をみつける.
  • MIDI の meetup 等で協力者を募る.

[Chromium] Android Lollipop で追加された新 IME API のサポート

Chromium Issue #424866 参照. 去年 Android Lollipop に追加した CursorAnchorInfo API,Chromium でまだサポートされていないのでなんとかしたい. 実はパッチまでは既にあるのだけど,Chromium 特有のレビューコスト・パフォーマンスに関する敷居の高さに阻まれ中断中. これはひょっとしたら業務時間中にやりきる口実を見つけられる可能性もゼロではないのだけど,その時間を Android 本体に使ったほうがどう考えても合理的なので早いところ担当してくれる Chromium 関係者を見つけるべきだと思っている.

やること.

  • 代わりにやってくれる人をみつける.あるいは気合を入れて自分でやりきる.

Firefox 関係

[Firefox] Android Lollipop で追加された新 IME API のサポート

Mozilla Issue #1094729 参照. 去年 Android Lollipop に追加した CursorAnchorInfo API,Firefox でまだサポートされていないのでサポートされて欲しい. 新 IME API が自社製品でしか使われないというシナリオは避けたい.心の底から.それが Microsoft ウォッチャーとして Text Services Framework から得た教訓なのですな.

やること.

Docker 上に IPython Notebook 実行環境を作って DeepDream を動かす

DeepDream を動かしてみようと思ったら 9 割ぐらい IPython Notebook と必要なライブラリの環境整備だったのでそのまとめ.

  • 作業日
    • 2015 年 7 月 4 日
  • 作業前の筆者の状況及びそこから導かれる想定読者
    • IPython Notebook を使ったことがない.環境構築もしたことがない.
      • Mathematica は使ったことがあるかもしれない.
    • docker コマンドが動く Linux Desktop 環境を,実機,または VM 内 (Windows にインストールした VMWare 等) にもっている.
    • Deep Neural Network と呼ばれる技術について,特に知らないし,特に自分で手を動かして何かしたこもなく,業務でも当面使う予定はない.
    • インターネットからの数 GB 程度のデータダウンロードが可能である.
  • 目標
    • docker コマンドが動く環境ならどこでも DeepDream のチュートリアルを実行できるようになる.
  • 目標ではない
    • Deep Neural Network と呼ばれる技術について,何らかの知見を得る.

Deep Neural Network 素人であるところの筆者が理解できた範囲の話の背景

6 月中旬ごろ,不思議な画像を生み出す画像処理アルゴリズムが Google Brain Project に所属する研究者たちによって公表されました.

Inceptionism の背景ですが,たとえば 10 段から 30 段にもなるニューラルネットワークが存在したとき,各段の振る舞いが実際に何をやっているのかは自明な話ではありません.この疑問に対する実験の 1 つとして,特定の段のニューロンの特性を使って入力画像を強調してみたらどうなるか,というのがどうも Inceptionism の意義というか立ち位置のようです.

実際,ランダムノイズ画像に上記強調処理を行った結果何やら物体めいたものが見えてきたというのが,ブログの前半で述べられていることです.

So here’s one surprise: neural networks that were trained to discriminate between different kinds of images have quite a bit of the information needed to generate images too.

さて,異なる画像を識別するように訓練されたニューラルネットワークは,画像を生成するために必要な情報をある程度持っているのであれば,これを使って面白画像が生成できないかというのが後半パートです.

Inceptionism ブログ記事では,実際の画像強調処理の具体的なアルゴリズムは記述されていませんでしたが,7月1日になって,IPython Notebook というインタラクティブな Python 実行環境を使ってチュートリアル的に行う方法が公開されました. この GitHub リポジトリの名前が DeepDream です.

ちなみに DeepDream として新たに公開されたのは,数十行程度の反復処理アルゴリズムだけで,Inceptionism ブログ記事の画像を再現するために公開が必要だった本当にこの反復処理アルゴリズムだけであったことが分かります. DeepDream では,GoogLeNet という訓練済みニューラルネットワークを用いており,このデータは 2014 年 12 月に公開済みでした.

さて問題は,普段この種の処理と無縁な生活をしている人間にとって,まずこの IPython Notebook の実行環境を (DeepDream に必要なライブラリを揃えつつ) 整えるのが大変面倒だ,ということです. というわけで Docker の出番です.

なぜ Docker を使うのか

まず最初になぜ Docker を選んだのかについて書いておきます.筆者の気づいた範囲で,DeepDream の実行環境を整えるにあたって面倒なのは次のような点です:

  • Caffe というライブラリを正しくインストール・設定する必要がある
    • GoogLeNet のデータセットが含まれていなければならない
    • 特定 GPU / ドライバへの依存を避けるために,Caffe は CPU 処理モードになっていて欲しい
  • pip コマンドで複数の Python ライブラリをインストールする必要がある
  • IPython Notebook はブラウザをフロントエンドに使用するため,実行環境にはブラウザがインストールされている必要がある

これらの処理を,普段使用している Linux Desktop 環境を汚さず,かつ (なるべく) 再現可能な形で,Linux ディストリビューション間の非互換性に煩わされることなく行いたいというのが Docker を使用する目的です. Docker を用いることで,仮に IPython Notebook 実行環境を予期せず壊してしまっても,すぐに最初からやり直すことが可能です. また,いったんコンテナイメージを作ってしまえば,ホスト環境が変わってもすぐに同じ実験を行うことが可能です.

ほんと,Docker みたいなのが自分の学生時代にも欲しかったものです……

(Docker) ホスト Linux

以下では Ubuntu 14.04.1 64-bit 版を想定していますが,必要な環境は Docker コンテナ内に用意するため,ホスト環境に要求するのは以下の 2 点です.

  • Docker が動く
  • (表示用のブラウザを X11 経由でホスト画面に表示するため) GUI ログイン可能である

Docker のセットアップについては詳しく述べませんので,Supported installation - Docker から辿ってインストールしてみてください.

なお,以下では sudo なしで docker コマンドが実行可能なように設定されていることを前提に書かれています.その設定を望まない場合は各自 sudo を付けて読み替えてください.

Docker コンテナのダウンロードとインストール

必要なコンテナは DockerHub にアップロード済みです.

docker pull nyaruru/deepdream-ipython-notebook

セキュリティが気になる人・自分で再現を試みたい人は,deepdream-ipython-notebook/dockerfile/ で Dockerfile を確認することができます.

何か問題・改善点がありましたら GitHub 上のNyaRuRu/deepdream-ipython-notebook までお知らせください. また,今回は github.com/visionai/clouddream をベースイメージに使わせていただいており,Caffe のセットアップ等大部分の処理はそちらで行われています.

Docker コンテナの実行

まず,コンテナ内からホストへの X11 接続を許可しておきます.

xhost +local:

DeepDream を一通り実行するだけであれば,以下のように docker コマンドを実行するだけで十分です.

docker run -i -t --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:ro nyaruru/deepdream-ipython-notebook

上手くいけば,コンテナ内で Firefox が起動され,そのウィンドウがホスト GUI 環境に表示されるはずです. 終了するには,ターミナル上で Ctrl-C を実行すれば OK です.

docker コンテナ起動時に --rm オプションを付けていることに注意してください.この結果,コンテナ終了時に作業内容は全て失われますが,もう一度実行しなおすことで確実に動く状態からやり直すことが可能です.

DeepDream IPython Notebook チュートリアルの実行

Docker コンテナを起動すると,すでに IPython Notebook が起動しているはずです.DeepDream のディレクトリが表示されているはずですので,そこから dream.ipynb を選択します.

f:id:NyaRuRu:20150705091726p:plain

IPython Notebook が表示されます.Mathematica 経験者であれば,あの Notebook みたいなもの,と思えばとっつきやすいかも.

上の方に ▸ ボタンがありますので,それを押していくとチュートリアルの内容が上から順に実行されてきます.

f:id:NyaRuRu:20150705091711p:plain

以下の箇所を実行することで,チュートリアルのサンプル設定での DeepDream が画像を強調処理していく様子をリアルタイムに見ていくことができます.

_=deepdream(net, img)

デフォルトのパラメータは,関数定義に書いてあるとおり以下のようになります.

  • ter_n=10
  • octave_n=4
  • octave_scale=1.4
  • end='inception_4c/output'

さらに DeepDream を楽しむために

パラメータを変える

こちらについても詳細についてはチュートリアルに書かれています.たとえば,

net.blobs.keys()

を実行することでニューロン層のリストが表示されます.強調処理に使う層を inception_3b/5x5_reduce に変更してみるというのが

_=deepdream(net, img, end='inception_3b/5x5_reduce')

の行っていることです.

ホスト環境のディレクトリを Docker コンテナ内に見せる

ここまで来ると,実際に色々な画像で実験してみたくなります. Docker のホストとコンテナでファイルをやり取りする方法はいくつかあるかと思いますが,ここでは -v オプションでホストの特定ディレクトリをコンテナ内に公開することにします.

docker run -i -t --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:ro -v $HOME/Pictures:/opt/pictures nyaruru/deepdream-ipython-notebook

これで,ホスト環境の $HOME/Pictures がコンテナ内の /opt/pictures と共有されます. たとえば foobar.jpg を $HOME/Pictures に置いたとします.IPython Notebook のデータを読み込んでいる次の行を探してください.

img = np.float32(PIL.Image.open('sky1024px.jpg'))
showarray(img)

これを,

img = np.float32(PIL.Image.open('/opt/pictures/foobar.jpg'))
showarray(img)

に書き換え,フォーカスを合わせた状態で実行 ▸ ボタンを押します. これで画像が読み込めれば成功です. あとは改めて deepdream を行っている行を実行します. 結果は,ブラウザの「画像に名前を付けて保存」で保存してもいいでしょうし,Python で

frame=deepdream(net, img)
PIL.Image.fromarray(np.uint8(frame)).save("/opt/pictures/foobare_result.jpb")

と書いても良いでしょう.

その他の実装

github.com/jcjohnson/cnn-vis にて,独立実装による Inceptionism の再現実験が試みられています.こちらでは,MIT Places データセットに対して訓練された GoogLeNet のデータを用いることで,建物に反応する (と思われる) ニューロン層を使った実験も行われています.

Future Work

今回の Dockerfile はあくまで IPython Notebook チュートリアルの実行を目標としているので,DeepDream の処理を動画に対して行ったり,GPU を使って高速化したりはまた別リポジトリで行いたいと思っています.

そのうえで,いくつか気になっている点としては,

  • Caffe が CPU モードで動くのはいいんだけど,CPU 1 コアしか使っていない気がする.
  • ホスト環境のファイル受け渡しが若干面倒なので何とかしたい.
  • ベースにしている Docker イメージから引き継いだ特性として,コンテナ内のユーザーが root な のが若干気にいらない.出来れば root でブラウザを動かしたくない.

あたりでしょうか.この辺はまた時間が取れたら見ていきたいところです,

Docker とか Caffe とか普段触ることがないので,詳しい方ぜひおすすめテクニック等教えてください.