Cutting-edge online technologies for freedom of your mind.
Electric Blue Industries Ltd.

Archives: Qiita Articles

2018-03-08

プロ個人の深層学習作業環境はどうあるべきか

こんにちは。Electric Blue Industries Ltd.のマッツです。

2018-03-08_04-02-41.jpg

note: All works and figures in this captured image are copyrighted to NVIDIA

そろそろDeep Learning作業においてGPUをうまく安く効率的に使っていかなくてはと考え、先ほど(日本時間 3月8日 04:00-05:00)にNVIDIAさんのNGC(NVIDIA GPU CLOUD)の説明ウェビナーをに参加して、これを機会にして、自分はどのような作業環境でDeep Learning作業を行っていくのが効率が良い(作業と思考のシンプルさ・環境の安定度・コストパフォーマンス)のか考えたので、皆さんのご意見も聞きたく投稿します。雑記です。

私自身の会社は小規模事業者であり、Deep Learningにつき次々と変化・進歩が起きている現状では大企業のように大きな投資を先行して大きなリターンを期待するというアプローチをしたくはない状況であり、多くの皆さんが個人として持っている「初めから数十万円も使いたくない」かつ「従量課金で請求書を見て目ん玉飛び出たくもない」と同時に感じる微妙な状況です。できるだけコストを下げ、なおかつコストとリターンのタイミングを近づけたい。ちなみに、現状で私が日常的に使っている環境は下記の通り、

  • 普段の作業: Mac Book Pro
  • 仮想環境: virtualenv(DockerおよびAnacondaは使用しないことにした)
  • Machine Learning ライブラリ: TensorFlow(CPU版)
  • ラッパー: Keras等使わず
  • 言語: Python (2.7)
  • クラウド: 現状ではGCP(GCE)をメインに使っている(AWSは割高な気がしており)
  • クラウドOS: 基本的にCentOS
  • 方向性: Deep Learningを主にウェブサービスに適用したい

です。

1. 様子見の学習までは手元の固定コスト環境で

ディープラーニングの作業は概して

  1. 学習対象の選定
  2. 学習データの収集
  3. 学習データのベクトル表現化
  4. モデル定義
  5. 様子見の学習
  6. 評価とチューニング(状況により4または5へ戻る)
  7. 本学習
  8. デプロイ

の順序で行われるわけですが、ざっくりと「このモデルとこのパラメーターで学習をバンバンすれば有意なモデルができるな」と見切れて7.の本学習へ進めると判断するまでの「様子見の学習」はスピードが遅くとも手元にあるコストが見切れる環境で行って、本学習からはスピード優先の環境で行うのが落とし所だと思います。そこで、問うべきなのが「どれくらい様子見の学習をしたいか?」であり、先ほどウェビナーを受けた「NGC(NVIDIA GPU CLOUD)」は「自分PCで稼働させる場合、GPU購入代金がイニシャルコストにかかるが様子見の学習で試行錯誤により発生するランニングコストが見切れるし一連の作業がそれなりには早く済む」という選択肢を提供するものだと認識しました。ですので、基本的に様子見の学習まではMac Book ProのCPU/GPUで行い、もし、それで様子見の学習するのでは処理が遅すぎるというのであれば、Titan Vとは言わなくてもそこそこのNGC対応GPU(Pascal世代以降)を買って手元の自分PCに様子見学習用に用意するのが良さそうです。すなわち、自分のPCはノートとデスクトップの2台になるという。その後でスピード重視で本学習させるのはクラウドで、と切り分けると。

なお、AWSまたはAzureで様子見学習で稼働させる場合はイニシャルコストは低く抑えられる反面、従量課金での請求額が変動するのが私には嫌だなと思っています。

補足1:多くの方はまずは手持ちのNVIDIA GPUを使いたいと考えるでしょうが、「どのGPUがNGC対応なのか」がよくわからず。ウェビナーでもみんさんが個別に自分のGPUの型名をあげて確認していた。NVIDIAさん、わかりやすいリストを作ってくれませんでしょうか?あるのかな?

補足2:NGCについてはNVIDIAの佐々木様が先月に解説の投稿をなさっておられます→(リンク

2. 個別に最適化するか、全体で共通させるか、それが問題だ

2018-03-08_05-53-34.jpg

NGC(NVIDIA GPU CLOUD)を導入できる環境条件は下記とのこと

  • 環境: AWS または Azure または 自分PC
  • OS: Ubuntu(CentOSでも行そうな様子。WindowsとMacは現状非対応。)
  • GPU: Pascal世代以降のNVIDIA GPU
  • TensorFlow: 利用可能(Kerasは現状で非対応とのこと)
  • 仮想環境: Docker + NVIDIA Docker (virtualenv非対応とのこと)
  • その他: GPUドライバ(CUDA Toolkit不要)

であり、上記でセットアップしたコンテナに対して、最新のコンテナ状態にラクラクアップデートしてくれるので作業環境が安定することがメリットのようです。料金は無料のようで、NVIDIAのGPUの需要が増えるということが利益源になっている様子です。上記の環境条件を満たした場合のみで使えるとのことですが、気づかぬうちに従量課金されたくない私としてはできるだけクラウド環境での様子見の学習は控えたいし、NGCを使うのであれば自分PCにGPUを挿して使う前提で検討することになります。

さて、そうするとここで悩ましい問題が発生します。私はコードを書くとかデータを扱う作業をMac Book Proで行いたいので、Pythonコードを書いたり学習を実行する際に自分のMac Book ProからSSHで別にあるUbuntu 自分PCにログインするのはやぶさかではありませんが、GoogleがTensorFlowの実行仮想環境として(Dockerも可能ですが)vertualenvを推奨しており、Mac Book Proにはvirtualenvで仮想Python環境を持っているので、virtualenvもDockerも使うというようなバラバラな環境にしたくないです。NGCがvirtualenv非対応とのことなので、できればDockerを使わなくてもいい落とし所が「どっかー」にないだろうかと。

machine-learning-next-1.png

そこで、Googleが運用している「Cloud ML Engine」が候補にあがるわけです。私はウェビナーで「Google Cloud ML Engineに対するNGCのアドバンテージは何ですか?」とチャットで訪ねたのですが、時間的制約から回答はいただけなかった(これは仕方ないこと)。私の解釈だと「イニシャルコストはかかるが従量課金の変動が抑えられる」という「コストのバランス」が回答かと思っています。この数年GCPを利用してきましたし、Google Cloud Storageに一連のデータを置けばGPU/TPUでの高速学習も可能だと。GCEインスタンスへのデプロイも敷居が低そうだし、Dockerも使わずに済むし、Ubuntu PCも作らずに済むので環境の共通性は確保できる。Mac Book Proだけ持っていれば世界中どこでも仕事ができる。しかし、従量課金が怖い。

3. そもそも何がコストの不確定性を生んでいるのか?

正直、上記までの私は「あれもやだ、これもやだ」と駄々をこねているように自分でも見えます。そもそも、何がコストの不確定性を生んでいるのかと考えると、学習しても学習してもlossが低いところで収束しなかったりAccuracyが上がらないような学習データとモデル設計と学習時のパラメータ(誤差関数の歩幅など)にあるのであって、ここが改善されるべきところでしょう。と同時に、現時点ではNNMの最適なチューニングについてまだ十分な知見が共有されているとは言えない以上、無駄な計算は致し方ないと考えるべきなのかもしれません。

4. で、どうするの?

「当面はMac Book ProのCPU/GPUで様子見の学習までを行い、無駄な学習計算を極力避けるように予めの注意を払う。そして、本学習は時間が優先する場合にはGoogle Cloud ML Engineで行う。しかし、将来的にNGCが仮想環境にvirtualenvも使用可能になったり、Cloud MLでは費用の見通しがつかないというビジネス判断に至ったらNGCも使用する。」ということにしました。


ということで、皆さん実は迷っているであろう事案につき書き綴りました。「私はこうしてるよ」なんていうお話が聞ければ幸いです。そろそろもっと技術的なトピックもあげていくようにします。どうぞよろしくお願いします。

  マッツ

2017-12-14

ウェブはどんなサイトでできているか(WordPress)

 皆さんこんにちは。香港の小さなIT会社「Electric Blue Industries Ltd.」で国境を越えて地道な活動をしている日本人の「まっつ」です。久しぶりの投稿です。2017年は皆さんにとってどんな1年でしたか?2018年の活躍に向けて1年を総括し計画を立てている頃かもしれませんね。自称愛妻家の私の1年は奥さんに迷惑ばかりかけ、お世話になった反省が多い1年でした。2018年は名誉挽回です。

 さて、弊社は国境を越えて活動をしており、営業・マーケティング活動もネット上のみで行なっているため、ネットにどのようなウェブサイトがあるのかを常に世界中のサイトをクローラーで巡回調査しテラバイトサイズのデータを使って分析をしています。今回は2017年の総括と2018年の計画策定の観点から、ネットに公開されたデータと弊社独自のデータを交えて、推定値を含め我々が暮らすインターネットがどのようなサイトで構成されているかを備忘録も兼ねてざっくりと俯瞰して見ます。なお、数字の導き出し方については下記に参考文献として挙げるCapital Pさんの記事がわかりやすいのでご参照ください。

参考文献

1. 世界には13億の登録済ドメインがある

 今年の流行語大賞にノミネートされた「35億」までは届かないものの、世界には13億のドメインが登録されているそうです。

参考文献:Internet Live Stats – Total number of Websites

2. 実際にアクセス可(=DNS Resolve可)なのはその25%の3億

 サーバーを立てる際に多くの人は独自にドメインネーム(hogehoge.com)を取得し、それをドメインネームサービスにIPアドレスと共に登録(AレコードやCNAMEレコード)してウェブサイトにアクセスできるようにします。しかし、申請取得された3億のドメインのうち75%はドメインネームサービスにおいてウェブサイトのIPアドレスに紐ついていないと言うことだそうです。

参考文献:Netcraft – How many active sites are there?

2.1. CMSを使っていないサイトはその3億の50%の1億5000万

上記の3億サイトのうち、CMS(コンテンツ・マネジメント・システム)を使って運用されていないものは半数の1億5000万に登る、とのことですが、実際には大企業になればなるほど自社開発のCMSを使っていたりして外部からはCMSを使っているか判別できないとう場合もこの50%には含まれているでしょうが、大企業のサイトの数はその他と比べて相対的に微弱と思われます。

参考文献:W3Techs – Usage of content management systems for websites

2.2. CMSとしてWordPressを使っているのがその3億の30%の9,000万

CMSにも様々な形態があり、WordPressに代表されるオールラウンドなコンテンツ管理をするものであったり、ネット販売を主な目的にしたものや、掲示板機能を目的としたものなど多種多様あります。その多種多様なCMSの市場シェアの60%をWordPressが占めるとのことです。CMSを使っているサイトがアクセス可能な3億件の50%とのことなので、アクセス可能なサイト全体の30%である9000万件(= 3億 x 50% x 60% )がWordPressで運用されていることになります。その他のCMSのシェアはJoomla(6.6%)、ホワイトハウスのHPにも使われているのDrupal(4.6%)、コマース向けのMagento(2.3%)が続きますが、WordPressのシェアが圧倒的です。

参考文献:W3Techs – Usage of content management systems for websites

3. WordPressサイトの53.4%弱が英語で、6.0%が日本語

  • 英語 53.4%(アメリカ 49.1%、イギリス 3.3%、オーストラリア 0.6%、カナダ 0.4%)
  • 日本語 6.0%
  • ドイツ語 5.4%
  • 言語不明 4.9%
  • スペイン語 4.8%

参考文献:WordPress – Statistics

というのが参考文献にて言及される要点です。

 弊社でクロールして収集・分析しているデータは、毎月集められるテラバイト級のクロールデータからWordPressを使っているサイトに着目して行なっていて、上記の数字の後半につきほぼ似た知見を得ています(WordPressの言語順位は弊社データだとドイツ語の方が多い)。弊社では実際にひとつひとつのサイトにアクセスしてHTTPレスポンスを解析し、サイトとしては存在するがWordPressをインストールしただけの「開店休業」状態だったり、異常なレスポンスを返したりするサイトは除外しているため、もう少し踏み込んだ考察を得ています。弊社はイーコマース関連の業務をしてるため、WordPressサイトの言語ごとのイーコマース実施状況を調べたところ、

4. イーコマースをしているWordPressサイトは9,000万の4.5%の400万ほど

 全てのアクセス可能なウェブサイト3億のうち上記の9,000万(30%)を占めるWordPressについて、弊社の分析ではその4.5%がイーコマースを実施していると考察(サンプリングによる推計です)しています。その場合、さらにざっくり計算では世界中全サイトでは大小1,300万ほどのイーコマースサイトが存在するのでは?と推測することができます。

5. 日本はイーコマース後進国?ガラパゴス?

 WordPressサイト全体の5%がイーコマース実施と述べましたが、英語(4.6%)、ドイツ語(4.3%)、フランス語(5.3%)、スペイン語(5.9%)であるのに比べ、WordPressでイーコマースをしている日本語サイトは0.5%ほどと他言語の10分の1しか無いと考察しています。この低さの背景にはWordPressではなく日本メインで多用されている「EC Cube」が台頭していることも一つの要因ですが、日本人は自分が管理するサイトで自前でイーコマースする意識が高く無くて、ASP形式のマーケットプレース(アマゾンか楽天がデフォルトか?)にてコマースする傾向が強いことも要因であると考察しています。なお、逆にこのイーコマース率が高いのがオランダ語サイトで7.7%です。


ということで、みなさん今年も大変お世話になりました。来年2018年もどうぞ宜しくお願いいたします。

2017-08-02

画像の複製・拡散を防ぐ方法(3 運用開始)

はじめに

 こんにちは。MATS(まっつ)と申します。5月初頭にアイディアとして投稿した「画像の複製・拡散を防ぐ方法1から3」につき、日本向けは2017年08月01日9:00から、海外向け英語版は同日17:00(PST 00:00)にビジネスサービス「ECLIPS(エクリプス)」として実現し運用を開始しました。その技術的側面からの説明をここにしますが、その意図は、これまでアドバイスくださった皆さんに状況をご報告するとともに、これを使って先に挙げた課題事項が解消へと進むようQiitaメンバーの皆さんのエンジニアとしてのご支援(お知恵・アドバイス)を切にお願いするためであります。

 なお、ECLIPSは画像と動画の両方に使えますが、処理内容が類似しているため、説明の簡便さを考慮して画像について述べます。ワードプレスに適用したサンプルでHTMLソースを見ながら読んでいただけるとわかりやすいかと思います。(以下、簡潔さのためにデスマス調ではなく「である」調で記述します。)
 
 

1. サービス概要

 このサービスは「あらかじめ特定の付加情報とともに本サービス向けデータとしてエンコード(以下、ECLIPSエンコード)した画像及び動画をブラウザにて表示する際、画像と同時にHTMLに記載されるJavaScriptを通じてサーバー側でデコードし、特定の付加情報等を判断要素としてブラウザでの表示/非表示を制御するウェブ・サービス」である。

<利用者とシステムの関係概要図>
ECLIPS解説用の図表.003.jpeg

1.1. ECLIPSサービスの機能

 ECLIPS形式にエンコードされた画像をデコードして元どおりに表示するには、表示されているHTMLにインクルードされているeclips.jsとサーバー側のデコーダーが辻褄のあった連携した処理をすることのみで実現するため、これらが表示を許可した場合しか画像は表示できない。eclips.js自体がECLIPSシステムによって固有の情報を含めて動的に生成されており、eclips.jsを保存して改造してデコードさせようとしてもデコーダーは拒否をするし、HTMLソースを見てデコードされた画像のURLにアクセスしても拒否される。また、eclips.jsは画像がコピー・保存されないにくいよう継続的にブラウザを監視し、eclips.js自体を改造してこれを妨げようという試みも自身でブロックする。これらの機能を活かし、特定のドメインで特定の期間だけ画像を表示できるよう制御したり、ブラウザ画面で画像を見せたいがコピー・保存されないにくいようにする制御することができる。

[補足] ブラウザに表示できる以上は何らかの手段(具体的言及は避けるが)にて画像を保存することはできる。表示非表示ををコントロール(ドメインと期限)し、閲覧できても画像が保存できにくいようにし、保存されてもネットで拡散・転用されにくいように閲覧者の特定可能情報を画像にかぶせるという三段セットのアプローチを本サービスでは取ります。保存できないことのみに固執しないのは、このサービスが発案される背景となったネットの画像にまつわる問題の本質は、「ブラウザで閲覧できたらその見えた画像が保存できること」ではなく、「閲覧された画像が所有者・管理者のコントロールが及ばないところで雪だるま式に拡散されて閲覧者が増えること」だからです。所有者・管理者の許可のもとで閲覧できた人自身が見えた画像を保存できるのは良いのです。それが所有者・管理者の意に反して拡散しなければ問題は最小限に抑えられるのです。

1.2. ECLIPSサービス利用可能環境

 Google Chrome, Microsoft Edge, Mozilla FireFoxでの正常な稼働を確認した(Apple Safariは正常稼働しない状況)。基本的にはJavaScriptが動くブラウザさえあればアプリケーションやプラグインをインストールする必要なく稼働する。この導入への障壁の低さから多くのウェブサイトで容易に導入してもらえる仕様になっている。しかしながら、正常に稼働しない環境も確認されており、例えばWordpressのプラグインであるJetPackがインストールされているウェブサイトでは正常にデコードされない。これは、JetPackがウェブサイトに表示する画像をwordpress.comのサイトに自動でアップロードし画像のURLをwordpress.com配下に変更する挙動特性によるものと認識している。このように、特殊な内部処理をするコードがインストールされた状況では正常に挙動しないことがあるので、使用前に各環境での検証をお願いしたい。
 
 

2. 使用手順と処理の概要

 ECLIPSを利用する手順はIT知識がない人でも見よう見まねで使えるような以下の簡単な手順にした。

(手順1)ECLIPSのウェブサイトで表示条件を指定して画像をエンコードする(アカウント作成が必須)
(手順2)エンコードした画像を通常の画像と同じ要領でHTMLのimgタグを用いてページに貼る
(手順3)imgタグの中にclassをprotect-imageとして指定する
(手順4)HTMLのheaderもしくはbodyにjQueryとECLIPS用JavaScriptをインクルードする

上記の早ければ1分で済む手順を踏んで記述されたHTMLがブラウザに表示された際に発生する通信と処理は下図(上段:ECLIPS無しの通常従来、下段:ECLIPS使用時)のようになる。

<処理フロー概要図>
ECLIPS解説用の図表.001.jpeg

ECLIPS解説用の図表.002.jpeg

2.1. エンコードについて

 エンコードはJPEG画像に対してサーバー側で行う(エンコード用ページはこちら)。その他のフォーマットの画像もサーバー側でJPEGに変換してエンコードする事が可能だが、現状ではPNGのみをImagickでJPEGに変換してからエンコードできるようにした。エンコードできる画像のサイズは3MBを上限とした。エンコード処理の内容は、JPEG画像の画像内容のデータ部分全体のみをECLIPS向けの固有の可逆変換エンコードをし、JPEGヘッダーはExifを削除する以外はそのままにするエンコードとした。このため、コンピュータはエンコード後の画像もJPEGと認識するが、表示される画像は真っ黒かグレーで表示され内容がわからないものになるようにした。なお、動画(MP4)に関しても同様の仕様で実現しており、データ内容の一部分ではなく全体をエンコードする仕様である。

< 画像を貼り表示したいページのURL >
 エンコードされた画像が貼られ表示された時にECLIPSによってデコードされても良いページのURLを記載する。HTTP/HTTPSの区別はせず、このURL及びその配下のURLにてデコードリクエストが発生した場合にのみECLIPSサービスは「表示しても良い」と判定する。この設定によって、自分のウェブサイト以外で画像がデコードされることを防ぐことができる。また、他者に対して「貴方のウェブサイトでの利用に限りライセンスを与えます」のような画像のドメイン制限付きライセンスも可能になる。

< 表示許可期限日時 (UTC) >
 特定の日時までを期限に画像をデコード許可することができる設定。時刻は日本時間ではなくUTC(JST-9)。特定の期日までのみ有効な情報を画像で表示したい場合や、期限付きライセンスの下で表示したい画像(例:タレントを起用した広告など)を制御することに使える。設定可能期限日時はエンコード時点から1年先まで。

< ウォーターマーク >
 デコードされた画像にかぶせる文字やロゴ。これまでに画像の無断利用を防ごうとウォーターマークを画像に描画する手法は存在したが、その実効性は十分とは言えなかった。その理由は、全ての画像に描画されるウォーターマークが静的で同一であるために警告のメッセージは示せても無断コピーをした人物を特定する要因にはなり得ない実効性の不足であった。ECLIPSでは画像がデータとしてコピー・保存されること自体が困難になってはいるが、スクリーンショットを撮られたり何らかの方法で保存されネットで拡散された場合に拡散の出元を特定できる情報(日時・クライアント名)を動的に記載することで拡散を妨げることを狙う。

2.2. デコード

< eclips.js >
 エンコードされた画像が貼られるHTMLに同時にインクルードされるJavaScriptである。内部処理にjQueryを使用しているためjQueryを同時にインクルードする必要がある。サーバー側で動的に生成され、呼び出された瞬間のみ内部処理が有効となるトークンを持つ。処理内容は、HTMLが読み込まれたタイミングをトリガーとしてHTMLを走査し、class=protect-imageであるimgタグがあればそのsrcをECLIPSサーバーにデコード依頼をするという単純な処理がメインである。なお、同様の処理をAjaxで行う場合はcross-domain問題がネックになるが、実現したい処理がAjaxでの非同期処理である必要がない事からAjaxは使わずcross-domain問題も発生しない仕様にした。

< class >
 上記で述べたeclips.jsがデコード対象のECLIPS画像を判別するために使用するclassである。このクラスの有無によりデコードリクエストの有無を決める。idではなくclassにしたのは、言わずもがなではあるが、単一のHTMLには複数のECLIPS画像が貼られる事があるので、固有性を表すidではなく複数存在が仕様的に許容されているclassを使った。

< decoder >
 ECLIPSサーバーにあり、上記のeclips.jsを使ってブラウザがデコードされた画像を取得するために通信する相手である。PHPで記述してある。デコーダーはブラウザから受け取った「エンコードされた画像のURL」にアクセスしてエンコードされた状態の画像を取得する。そして、エンコード時に指定された表示非表示条件(エンコードされた画像の中に格納されている)やその他の条件を元に判断し、表示してもOKの場合はブラウザにデコードされた画像を返す。デコードする際にはブラウザを特定する文字列を画像に記載して、著作権侵害や肖像権侵害時に閲覧者を特定する事ができるようにする。この文字列記載(ウォーターマーク)はImagickを使用して描画する。Imagickでのウォーターマーク描画はCPU&メモリー資源を意外と喰うようで、これの低減についてアルゴリズムの工夫をした。

 ちなみに、ECLIPSでは一切の画像をサーバーに保存せず、デコード処理の中でもHDDに記録しない。デコードリクエストがあるたびに画像所有者が決めたURLにエンコードされた画像を取りに行く。これは、画像の所有者が表示非表示をコントロールしたい対象画像が、第三者であるECLIPSシステムに残されていることはコントロールの理念にそぐわないという考え方からである。画像の所有者が(エンコードされた状態であっても)画像をウェブサーバーから削除すれば完全にネットから抹消される状態を理想と判断し、通信料や処理時間はかかるがサーバーのスペック(通信速度・CPU/GPU速度・アルゴリズム)で補うこととしこの仕様にした。

 デコード処理はGCP(Google Cloud Platform)に仮想化されクラスタリングされたウェブサーバー群にて行う。このような場合、多くの方がAWSを選択肢に挙げると思われるが、コスト計算の結果として本件ではGCPを選択肢した。

2.3. 認証サイト対応

 上記で記載したデコード処理には「ECLIPSサーバーが画像にアクセスできる事」が条件として存在する。仕様案としては「クライアントのブラウザからECLIPSサーバーにエンコードされた画像をアップロードさせればいいのでは?」という疑問があると思う。これを採用しなかった理由は2つあり、

 1 クライアントの通信量が画像データ1往復分多くなってしまうから
 2 対象画像がイントラネットにある場合、イントラ外へのデータ流出を助ける事になるから

である。しかしながら「エクストラネットにあるが画像を閲覧するには認証が必要」というサイトで使用したい場合や「NDAを結べばイントラネットのファイアーウォールに認証付きの穴を開けるから使いたい」という場合もあるだろう。そこで、認証サイトの認証方式がBasic認証である場合は、ECLIPSサービスのアクセス向けに作成してもらったUID/PWDを元にして認証コードを生成し、それをHTMLのimgタグ内に記載してもらう事でECLIPSサーバーのみが認証を通過できる仕様を装備した。この認証コード自体もECLIPSエンコードされているため、それを見た閲覧者が勝手にUID/PWDを得て認証通過することはない。

2.4. 緊急処置への対応(非常停止)

 画像をECLIPSでエンコードし、自分が管理者であるウェブサイトだけであればその画像を削除すれば済むが、他者が管理しているウェブサイト(他社サイト・SNSなど)に掲載されている時、現状では自身が所有する画像でありながらも表示を止める手段はない。ECLIPSでは「緊急非常停止ボタン」を用意しており、マイアカウントにログインしてこのボタンをワンクリックすれば、自分が管理者ではないサイトに貼られていたとしてもECLIPSサービスはデコードしないようになる。なお、非常停止はそのアカウントにてエンコードした全ての画像に対して一括に行われ、個別の画像については行わない。
 
 

3. サービスとしての継続性を確保する(ビジネス観点)

 技術仕様とは関係ない話です。このサービスは「エンコード」「デコード制御」という時間的な幅の中で提供されるサービスであるので、継続性がサービスの付加価値として絶対的に欠かせない。無料で提供できるのであれば無料で提供したいのだが、そうすると存続のために社会に支払うコストが確保できない。私自身、これまでに「企画・マーケティング」と「アーキテクト・エンジニア」の両方を歩いてきた半魚人のような職能の人間なので、自分の中で「お役に立つ最善をできるだけ安価で」というアーキテクト・エンジニアの思いと、「ビジネスとしての存続と成長が無くして社会貢献はない」というマーケッターとしての思いが常に綱引きしている。このような葛藤の中で、エンジニアとしてコスト最適化の観点からサービス継続性に寄与できる要素は以下ではないかと私は考えている。

3.1. 「何が問題で解決しようとしているのか」を常に意識すること

 自分ひとり、コードひとつで全ての人に貢献することはできない。それを目指すと結局は「10得ナイフ」のような、一応全てには対応しているが実際には使われないものが出来上がる。組織として活動していると様々な観点から要件を提示されて、全てを取り込んだ結果、何がしたいのかわからない仕組みになるという有様を私自身沢山見てきた。これに囚われずにキーボードを叩けるかがエンジニアの戦いのように思う。

3.2. コードのアルゴリズムの徹底的な効率化

 無駄な処理が無いか、もっと効率的なアルゴリズムは無いか、嫌になる程にコードを研ぎ澄ましたい。これには上記で述べた「何が目的なのか」が明確になっていて初めて可能なのだと思う。

3.3. コードを稼働させるサーバーの住み分け

 ビジネスでは「存在を知らせる」「理解して納得してもらう」「お金を払ってもらう」のようにコストがかかる時点と利益が得られる時点にギャップが生じる。このギャップの狭間で発生することがあるのが「黒字倒産」であり、キャッシュフローはあるのに売掛金の回収前にコストへの支払いを迎えてしまい立ち行かなくなる事態である。このリスクを最小限にするため、コスト発生と支払い期限のギャップを小さくする工夫が必要である。パソコン販売の業界で言えば「BTO(Built To Order)」という言葉があるが、受注時に先に代金を払ってもらい、それを原資として製品を作るのがBTOである。ウェブサービスで言えば、キャッシュフローは生まない処理は定額料金のサーバーで、キャッシュフローを生む処理は従量制サーバーで処理速度・安定性を最優先して回すような住み分けが有効だと考える。
 

 

以上、2017年5月はじめに皆さんに相談した考え方をサービスとして運用開始し、これから人様のお役に立てるように回していく段になったので、心からの感謝の気持ちを込めてご報告するものです。エンジニアとして「ちょっと試しに使ってみるか」という方がおられたらQiita経由でお知らせいただければ喜んでお話ししますので、アドバイスいただければ幸いです。

最後になりますが、Qiitaという素晴らしいサービスを運営されている皆様にも敬意と感謝を申し上げます。

Mats (Electric Blue Industries Ltd.)
 
 
 
<修正記録>
1) 本サービスを使用することで画像が絶対に保存できなくなるように読める記述を訂正し、「保存しにくくなる」との記述に修正しました。ブラウザに表示される以上は原理的に保存はできますので、その保存をするための敷居を上げ、保存された場合でも拡散元がわかるようにすることで拡散されにくくするというアプローチを取ります。ご指摘くださったユーザーさんに御礼申し上げます。 [2017-08-03 14:00 MATS]

2017-05-03

画像の複製・拡散を防ぐ方法(2)

前回の第二部では課題と技術的制限を付き合わせて仕様を見定めました。今回はその仕様に沿って作成したデモ・サービスの紹介です。


7. 実際に動かしてみる

 前二部で述べた仕組みをWebサービス(デモ環境)にしたので、それを皆さんに使ってみていただきたい。実際には皆さんのようなIT知識が豊富な人々ではない利用者にこそ使ってもらい課題の解決に役立てたいので、皆さんにそのような人々の気持ちを感じてもらうためにお見せする内容は意図的に絞ってシンプルにしました。特に「これを使って子供や女性が悲しい目に合わなくて済む助けになるだろうか?」という、彼ら自身や彼らの家族の目線でみていただけると有り難いです。

7.1. JPEG画像をエンコードする

私の管理下のサーバーにこの仕組み用に画像をエンコードするページ(Qiita管轄下ではない外部サイトです。)を置きました。

Step-1: エンコードするJPEGファイルを指定します

画像形式: JPEGまたはPNG、動画形式:MP4
ファイルサイズ: 最大3MB

に限定します。サーバー側では高速処理のため揮発性メモリ上で処理をして画像は保存しませんが、念のためプライバシーの問題にならなそうな無難な画像を使ってください。

Step-2: デコードして表示しても良いページのURLを記入

 その画像が貼られた際にデコードされて見えることを許可するドメインです。例えば、あなたが『https://anata.com/blog/』 というURLで始まるのブログサイトを持っていて、そこに画像が貼られた場合だけは画像をデコードして表示しても良いという場合は『https://anata.com/blog/』 と記入します。なお、プロトコルはhttpsのみで正常挙動します。httpでは正常には挙動しません。

Step-3: デコードして表示しても良い期限の日時を記入

 画像には著作権や肖像権があるので、画像のオーナーがその法的権利を適切に行使できるよう、表示許可期間を指定できるようにしました。また、未成年者が(困ったことに)相手との関係が悪くならないよう請われて裸の画像を送ってしまったりすることが多発しているそうなので、個人的には「そんな関係なら切りなさい!」と小一時間の説教をしたいくらいなのですが、それが見通せないのが子供なので、せめて数分間ほどの閲覧可能時間を指定することにも使えるのかなと。時間設定はUTCであり、日本時間ー9時間です。

Step-4: 「エンコード」ボタンを押してエンコード開始

 数秒でブラウザにエンコード済みの画像がダウンロードされます。ダブルクリックして開いてみるとグレーまたはブラックの画像です。これをご自身のパソコンに保存しておいてください。ここでは「sample_jpg_eclips」という仮の名前にして、次節のhtmlにて記載します。

7.2. エンコードした画像をHTMLに貼ってみる

 次に、上記でエンコードした画像をHTMLに貼り、デコードがされるように「jQueryとECLIPSのJavaScriptをheadにインクルード」及び「画像のimgタグにprotect-imageというクラスを追加」しましょう。記述例は下記です。なお、ここで作ったhtmファイルは、画像をエンコードした際に指定した「デコードして表示しても良いページのドメイン」の配下に置く必要があります。エンコードした画像はanata.comのドキュメントルート直下のblogフォルダにsample_jpg_eclipsという名前でおいたことにしてあります。みなさんの環境でここは適宜書き換えてください。

eclips.htm

もし、自由にこのhtmlや画像を置ける環境が無い方は、サンプルとして私のサーバーに上記のhtmlと画像を置きましたので、これで見て見てください。

画像・ビデオ版 ↓
2017-07-09_10-56-11.jpg

8. ハッキングしてみよう!

 上記で用意したhtmファイルにブラウザでアクセスして見ましょう。画面にエンコードしたはずの画像がデコードされて表示されましたか?ページを開いた直後に一瞬だけグレーかブラックの画像が表示され、直後にデコードされた画像におきかわりませんでしたか?画像の上には白い文字で、アクセスした時刻とあなたの端末のホスト名が表示されていますよね?その状態になったら、ハッカーになったつもりで、この仕組みの弱点を探して見ましょう。

  • ブラウザの機能を用いて、エンコードした時の状態のプレーンな画像を保存できますか?
  • HTMLを読んで画像のURLを探して直接取得できますか?HTTP404エラーが出ますよね?
  • でも、ブラウザのリロードボタンを押した場合は毎回画像は表示されますよね?

などなど、エンコードした時のプレーン画像を取得できるか試して見てください。

 ご自身でhtmファイルを作成してご自身のサーバーにおいた方は、そのhtmファイルをローカルで開いた時には画像がデコードされないことをご確認ください。また、エンコード時に許可していないドメインにおいた場合もデコードされません。これは、その画像がどこのドメイン配下のページで表示されようとしているかを判別して、エンコード時に許可したドメインだけで表示するためです。

 なお、画像表面にアクセス日時とアクセス端末名が記載されるので、これを拡散すれば拡散元の人物は特定可能です。表示する位置については改善が必要と考えています。しかしながら、画像の販売が目的で、購入者にはこのタイムスタンプとホスト名を除去してあげたい場合もあるでしょう。そういう場合は(今回は省きましたが)エンコード時にパスワードを指定し、購入者がそのパスワードを使ってタイムスタンプとホスト名が無い画像を取得するという方法も可能です。また、諸般の事情によりタイムスタンプとホスト名はいらないよという場合もエンコード時に指定可能です。

9. ひとまずまとめ

ものすごい駆け足でのご提案となりましたが、雰囲気を掴んでいただけましたでしょうか?この投稿では仕組みの概要をシンプルなデモでご案内しました。この方法で社会の課題(特に子供や女性が理不尽な悲しい目に遭う事件)が減らせたらいいなと切に思います。実際のサーバー側のデータ処理を見ていると結構重い処理をしています。ですので、本気でやるとしたら設備にお金がかかりそうなので、「未成年者は無料、大人と企業は有料」のようなビジネスとして運用資金を調達して行かざるを得ないなと思います。

 皆さんからのコメントをいただけると有り難いです。特に「ここがダメ」のような至らぬ点のご指摘ほど有り難いです。なお、もし更なる投稿のご要望があった場合は検討させていただきます。

 長い投稿となりましたが、ここまでお読みくださった皆様に心から感謝申し上げます。

2017-05-01

画像の複製・拡散を防ぐ方法(1)

0. はじめに

 この投稿では最新の技術の紹介ではなく、いかにシンプルに社会にある課題のひとつを解消できるかを書く。話の中心にあるのは「インターネットにある画像」で、ブラウザで画像が表示できるようになった1990年代前半からあるものである。

 次々にインターネットに関する新しい技術や考え方が脚光を浴び様々な利便性を提供してきたと同時に、多くの課題ももたらしてきたことも事実である。全て挙げればキリがないのだが、インターネットと不可分な社会の課題のうち、この10年ほど変わらずもっとも多くに関与しているのは「画像」のように思う。

 私自身、インターネット上での画像の扱いにつき元から漠然とした課題意識は持ってはいたのだが、インターネット上の画像がもっと洗練された使い方をされれば防げたかもしれない様々な課題の中でも「幼い子供や女性に対する卑劣な犯罪」が一向に無くならないことを口惜しく思い、これをまとめた。実現方法の策定にあたっては、せっかくならできるだけ多くの課題解決に使えればと多くの課題に適用できる案を目指し、結果としてある程度の課題範囲を包括する案ができたように思う。

 この投稿は、1部にまとめると長くて読むのが困難なので、要点に絞ってコンパクトにしたうえで下記の3部に分けてする。なお、私はプログラミング能力はプロのレベルにはなく、理念が発端になって本提案をまとめたので、追って記載するコードが美しくないことはあらかじめご容赦いただきたい。アドバイスも喜んで伺いたい。私と同じ社会貢献の意図を持ってのご質問があれば喜んで個別に具体的にお答えします。

第一部 問題の整理(←イマココね)

 どのような理念に基づいてどのような課題を解消すべきか、要因とアプローチの整理をする。

第二部 具体的なアプローチ

 課題と技術的制限を照らし合わせ、どのような落とし所が適切か整理する。

第三部 実際に作成したプロトタイプ

 実際に作成したプロトタイプを見せながら、皆さんのご意見やアドバイスを期待する。

1. 解消すべき課題

この数年間だけを振り返っても、インターネットと画像に関わる社会的問題は枚挙にいとまがない。SNSが悪いとか、スマホが悪いとか十把一絡げな議論もあるが、それらをブレイクダウンして分類しながら本質的要因が何かを考えてみよう。よく耳にするものだけでも課題を分類をすると下記の4つに分類できると思う。

1.1. コンテンツ要素としての画像のパクリ(労力のタダ乗り)

  • 自身が書いたブログ・記事・論文の画像を無許可で転用される
  • 自分で撮った販売製品の画像を他人が無許可で使う
  • 作品として販売している画像をコピー共有され商機を失う

今年に入ってからも某IT系企業が人様が苦労して作ったブログ記事や画像を無断で拝借して稼いでいたことが露見し社会問題になりましたね。ネット売買サービスを見ればなぜか同じ製品写真が別の人に使われていたり。これは転売屋さんに多いようですね。中には落札してもいないものの製品画像を勝手に使って、落札前に販売するなんていうツワモノもいるそうです。また、プロのカメラマンさんやイラストレーターさんが時間と労力をかけて形にした作品を、そのままお金も払わずにネットで使っているのも目にします。有料画像サイトで販売した画像がネットでばら撒かれたりしてビジネスにならずに消え去ったサイトも多々あります。

1.2. 人物に関する画像が本人の意図・意思に反して利用(肖像権の侵害)

  • 無断で顔写真等を利用されアイデンティティーを無断利用・剽窃される(偽造・背乗り)
  • 過去の人間関係を示す現在は不都合な画像が不祥事発覚後も閲覧される(過去の恋人関係)
  • 判断ミスで他人に送った恥ずかしい画像が拡散される(リベンジポルノ・デジタルタトゥー)
  • 子供や女性の画像が不特定多数に見られ犯罪の対象選定に利用される(性犯罪への巻き込まれ)
  • 有名人がクラウドに不正アクセスされて個人的な写真を勝手に閲覧される(プライバシー)
  • メールやクラウドサーバーにある画像が採取され個人の思想分別に使われる(プライバシー)

ここがこの提案がもっとも解決したい分類です。私も一昨年、LinkedIn経由で某企業から転職のお誘いを受けたのですが、そのアカウントのプロフィール画像(欧米系女性)なのに文章が男性的なので調べたところ、プロフィール画像を勝手に拝借して作った詐欺アカウントでした。クレジットカードや銀行口座の情報を盗み取る「フィッシング・サイト」も健全なサイトの画像を無断拝借して似せて作られます。私はLineはしませんが、Lineでもそういう詐欺アカウントはあるのでしょうか?で、私が非常に危機感を持っている「性犯罪」ですが、よく知られるようにSNSなどに子供や女性の写真が掲載されて不特定多数に閲覧されてターゲットにされることがあるといいます。最近の事件ではベトナム人の女の子を毒牙にかけたのが保護者会の人物の可能性が高いという。もう誰を信じていいのかわからない状態です。この事件にネット画像が関与したかは不明ですが、インターネットが人を見つけるのに有効な手段である以上、危機感を持っておいた方が良さそうです。また、この一週間でもありましたが、朝ドラ出演の女優さんのクラウド画像保存サービスに他人が不正ログインしてプライベートな写真を見ていたという事案がありました。

1.3. 有効期間がある画像が期間満了後も使用(情報の時間的制御不能)

  • 広告の契約期間満了後のタレントの画像が事務所や代理店の許可なく利用され続ける
  • 不祥事を起こしたタレントの広告画像がネット上に存在し続け、スポンサー企業のブランドを損なう

画像は情報量が多いので多くの情報発信に用いられるわけだが広告もそのひとつ。広告にタレントさんを起用する場合、タレントさんの事務所と企業の間で一定期間の契約を交わしてタレントさんが映った画像を広告に使う。タレントさんには個々にブランド価値があるので、そのブランドと製品を紐つけて広告する。以前、ある携帯電話会社の顔として広告に出ていたタレントが、その契約終了後にライバル会社の広告の顔になった事があったが、ネットを見ると両方の広告画像が見つかる。こういう場合、元の契約の会社の広告画像は契約切れなので、存在を消してしまいたいだろう。しかし今の画像データではこれはできない。また、清廉潔白で売っていたタレントさんが実は不倫をしていて、それが発覚した直後に広告契約が打ち切りになることも多い。企業としてはその広告自体の存在を抹消してしまいたいだろうが、現状の画像データではこれができない。

1.4. 守秘義務情報を含む画像が持ち出され組織に不利益(情報の漏洩)

  • 社外秘資料が持ち出されて社外で閲覧される

組織や企業がイントラネット内限定で守秘義務情報を共有している場合、これが外部に持ち出されて彼らの社会的信用を低下させるばかりでなく、組織・企業としての存続の危機に立たされる場合がある。多くの組織・企業ではイントラネットに接続できる端末を管理・制限し、USBを接続できないようにしたり、外部とのメールのやりとりを監視したり、機密情報だらけの場所では携帯電話・スマートフォンの持ち込みも禁止したり。非常に気を使って対応している分野であるが、なぜか情報漏洩は止まらない。

2. 課題の本質とアプローチ

上に列挙した課題の本質的原因は、インターネットでは「著しい劣化を受けずにデータの複製が容易にできること」と「拡散が容易にできること」と「他人の管理下にあるデータは作成者の制御が及ばないこと」という3要因に起因すると考える。画面に表示されるページ構成情報がクライアント(ブラウザ)側にすべて渡されるというHTTPの特性を根拠にして、「ウェブサイトでページに表示された画像は容易に複製されるのはしょうがなく、また作成者の意向を十分に反映せずに勝手に拡散されるのは仕方ない」という認識が不幸にも常識となっているが、前章に挙げた現存する深刻な課題を前に、私はその諦めにも似た認識を素直に受け入れるつもりは毛頭ない。もし、これら3要因への対応が適切になされた場合、「解消すべき課題」にあげた現存する多くの課題の解消・軽減が期待できると考え、これら3要因の発生を完全に阻止することはできないとしても、画像の取得に技術や手間がかかるようにすることで費用対効果的に採算が合わないようにし、また許可なく複製・拡散することのリスクを顕在化することで問題の発生を減らすというスタンスに立つ。以下にこれら3要因の本質とアプローチにつき述べる。

2.1. 複製について

「既知の手順で容易には複製できず、複製できても拡散を抑制する」という、拡散防止と合わせたスタンスを取る。スマホ及びPCで画像データを複製保存される主な方法は「1. UIの機能を使っての保存」「2. htmlソースを分析して画像のURLを特定し保存」「3. ページを丸ごとローカル保存」「4. スクリーンショット保存」である。1についてはJava ScriptやCSSを用いた方法が知られるところであり、これを踏襲し拡張した方法を提案する。2については「ブラウザ画面には表示されるがHTMLを見ても取得はできない」というトークンと暗号化を用いた新たな方法を提案する。3と4については技術的に封じることが現状で困難であることに加え、個人としての画像の閲覧の利便性というそもそものインターネットの存在意義の観点からその実施可能性を残し、後述する「拡散を防止する」ことに実被害の発生を防ぐ対応を期待するものとする。

2.2. 拡散について

「技術的に阻止ではなく、拡散により社会的制裁を受けることを示唆する」というスタンスを取る。現状で多くの画像が「Watermark(画像に著作権者のトレードマーク等を被せた半透明のマーク)」を用いているが、これが十分に拡散を防げているとは思えない。というのは、対象の画像をデータ保存もしくはスクリーンショット保存できた場合、保存した画像は任意に拡散することは可能であり、誰が拡散し始めたのかを特定できない以上、匿名性が高いインターネットでは拡散し始めた人物が適切かつ迅速に制裁を受けることは過度に期待できない。しかしながら、保存した画像に保存した端末を特定する情報(時刻やホスト名)を動的に記載し、拡散が発生した場合にはその画像を見れば拡散の出元がわかるようにした場合、自身が保存した画像を拡散開始させることを踏みとどまらせることができると考える。

2.3. 制御について

インターネット上に送り出した画像はその送り出した先が他者が管轄するサーバー上である場合、多くの場合、管轄者が特段の権限を付与しない場合にはその画像を自力で消すことも出来ない。この提案では、他者が管轄するサーバーにあっても画像と所有者を紐つけておき、画像を表示することを許可するかを画像が他者の管轄下にあっても画像の所有者が一方的に決められる余地を残すスタンスを取る。

3. 目指す状態の実現にあたり

前章で挙げた3つの「複製」「拡散」「制御」に関する施策を実現するにあたり、実際に多くの人々の役に立つためには以下が担保されるべきと考える。

3.1. 利用者にとって煩わしくないこと

画像の所有者及び閲覧者の双方にとって容易に理解できる方法で実現する必要がある。HTMLやJava Script等の知識が無ければ導入できないものであれば導入できない人も多くなるし、閲覧者にとって従来のウェブサイトの使い勝手から逸脱したものであれば、ウェブサイトの本来の目的である「知らせる」という目的にそぐわなくなる。

3.2. 実現する技術が従来の基本的な技術を逸脱しないこと

例えば、新たなプラグインのインストールを求めたりした場合にはそれをためらう人もいるだろうし、また、CMSで動的にページを生成している人々が多い実情を考えると、コードに大幅な修正を必要とする場合は導入をためらうだろう。最新のライブラリが無ければ導入できなかったりもNG。できれば、既存のページやコードにコピペ中心で1分以内に終わるような工数で実現できれば多くの人は実施できると考える。

3.3. 仕組みの有効性が客観的に評価できること

仕組みを秘密にすることで安全性を担保しようとすれば、その秘密が露見した時点で安全性は完全崩壊する。実現する仕組みは、多くの人がその便益を確信を持って享受できるためには、彼ら自身が有効性を客観的に評価できる機会がある仕組みにすべきである。これを踏まえ、本提案では仕組みを秘密にすることで安全性を担保するのではなく、データの暗号化技術の適用により「計算量的安全性」を提供する。

4. ブラウザに表示された画像はどのように複製保存されるか

まず、ブラウザに表示された画像がどんな手順で閲覧者のローカル端末に保存されるかを洗い出してみよう。下記の4パターンがある。

4.1. ブラウザに備わった機能を用いて

・画像を右クリック(PC)
・長押しして表示されるメニューを使用(スマホ)
・画像をドラッグ&ドロップして保存
・ページを丸ごと保存(画面上で右クリックして出るメニューを使用)
・ページを丸ごと保存(ブラウザ画面外のメニューを使用)

4.2. HTMLのソースを見て画像のURLを特定して

・ソースコードのimg src=xxxxを見て、その画像のURLに直接アクセスして保存

4.3. スクリーンショットや画面の撮影によって

・OSに装備されたスクリーンショット保存機能を使用
・画面に別のカメラを向けて撮影
・スクリーンショット用アプリケーションを使用

4.4. ブラウザ自体以外のアプリケーションを用いて

・ブラウザのアドオンを使ったページの丸ごと保存
・ページ巡回収集アプリケーションを用いたページの丸ごとの保存

5. 複製保存された画像はどのように拡散されるか

 HTTPで配信される多くのウェブサイトに転載される他、メールで人に送られたり、FTPやファイル共有によって人から人、システムからシステムに拡散されていく。様々な方法で画像は拡散していくが、ひとつ確かなのは、「自分が見られない画像は拡散しない」です。何が写っているかわからない画像を拡散することはまずない。なので、「画像を閲覧できる場所(ドメイン等)を制御する」ことが拡散自体を防ぐ。この制御については後述する。

6. 画像の複製保存を防ぐ対応案

 画像の保存の目的は「画像がほぼ劣化せずに保存できて初めて意味があるケース(商用画像など)」と、「ある程度劣化しても被写体が判別可能であれば良いケース(情報漏洩・リベンジポルノなど)」の2種類がある事に注意したい。つまり、単純に「画像の一部分を隠したり、画質を劣化すればいいだろう」という考えでは役に立たない後者のケースがあるという事を実際の対策を検討する際は忘れないようにしたい。なお、以下にIT技術的な視点で対応策を記載するが、それを実現する技術はどれも目新しいものではなく、レベルも高くない。

6.1. 対象画像にCSSで透明PNGを被せる

 この方法は特にスマートフォンでの閲覧者に画像の保存をさせない方法として知られた方法である。スマホのブラウザ画面に表示された画像を長押しするとメニューが開いて保存ができるが、保存されるのは被せた透明PNG画像であるため、目的の画像は保存できない。しかしながら、PCで閲覧している場合は「ChromeのInspectモード」や「FirefoxのFirebug」を用いてCSSで被せた透明PNG画像をひっぱがすことができてしまうという弱点がある。(後述するサービス化では不採用とした)

6.2. 対象画像の上でマウス右クリック及びドラッグ&ドロップを継続的に無効化する

 上記の透明PNGを弱点を突いて剥がされた場合を考慮し、被せた透明PNGの下にある画像にJavaScriptで「右クリック無効」と「ドラッグ&ドロップ無効」の属性を与える。そして、この無効化をPNG画像の時と同じくInspectモードで剥がされないよう、JavaScriptのsetIntervalを用いて継続的にかけ続ける。こうして高橋名人の毎秒16連打のようにかけられた無効化は、Inspectモードで外されても一瞬で元に戻る。しかしこれにも弱点があり、ページを丸ごとローカル保存して、JavaScriptのインクルードを外したり、JavaScript自体を外されたら無効化がされなくなる。そこで、後述する6.4.及び6.5.の施策により、ページのローカル保存やJavaScriptの改造をすると画像自体が見られなくなる方法を導入する。

6.3. キーとウィンドウの状態の検出で見分ける

 煩わしいのが「スクリーンショット」「画面の別カメラでの撮影」である。結論から言うと、コードや仕組みでこれらを完全に防ぐことは現状でできない。なので、撮影されることを完全に防ぐのではなく、撮影された後の拡散を防ぐようにする。なお、だからと言ってあまりにも簡単に撮影されるのは癪なので、OSに装備されたスクリーンショット機能を使おうとすると画像が消えるようにJavaScriptでキーとウインドウの状態を監視する仕掛けをする。なお、スマートフォンにおいてスクリーンショットを撮影する際に押すキー(電源+ホーム)をブラウザ上で動いているJava Scriptが検出することはできない。

6.4. 対象画像をエンコードし、特定の条件を満たす場合のみサーバー側でデコードする

 6.1.と6.2.で述べたように、これまで共有されてきたCSSとJSによるブロックは外す方法が現実的にある。このあたりの実情を鑑みて「ブラウザに表示された画像はパクられるのは仕方ない」と言われている気がする。私の提案では、ここを乗り越える。画像をあらかじめ「とあるアルゴリズム」でエンコードしておいて、ページが表示されるときにJavaScriptでサーバーと通信してデコードするのだが、「そのJavaScriptを改造されたら終わりじゃん」と言う声が聞こえる。ノンノン。チッチッ。そのJavaScriptを改造すると今度は画像がデコードされなくなる方法が次の6.5.である。

ちなみに、画像を表示(つまりデコード)しても良い条件をエンコード時に画像に属性として付加しておけるようにし、「自分のサイトでは画像は表示されるが、その他のサイトでは表示されない」などの制約を画像の所有者がかけられるようにしておく。

6.5. 上記のデコードは動的に生成されたトークンを持つJavaScriptで行う

 上記のデコードを行うJavaScriptはページからインクルードで呼び出されるたびに動的に生成し、その中に記述された動的に生成されたトークンで、ページが読み込まれた瞬間しかサーバーはデコードを受け付けないようにする。こうすると、読み込まれたページの上にはデコードされた画像が表示されるが、JavaScriptを改造してデコードだけ行わせようとしても、改造する前にすでにトークンが無効になりデコードが受け付けられなくなる。htmlソースを読んで画像のURLに直接アクセスしてもデコードするためのトークンがないので画像は表示されない。

補足)検討したが却下した他の方法

上記の6.1.から6.5.を対応案とする過程で他の案も検討したが採用には至らなかった。それらと却下理由を記載する。

却下案1:ページ上全体でのマウス右クリックでのメニューを非表示にし「ページを保存」が選べないようにする( → 画像が貼られるページのユーザビリティーに制約を起こすため「やりすぎ」と判断)

却下案2:ブラウザのクライアント領域からマウスのポインタが出たら画像を隠す( → マウスの動きが早い場合はポインタの位置を正確に捉えられないため実効性が薄いと判断)

却下案3:CSSの機能を用いて画像をbackground imageとして貼る( → ページを保存しても保存されたデータの中に画像は含まれないが、HTMLソースを調べられたら容易に画像URLを知られることは何も変わらない)

却下案4:画像をピクセルや行に分解して画面上で並べて1枚の画像のように見せる( → 手間がかかる割にはスクリーンショットに弱いしコードが煩雑になる)

7. 実装の感じ

上記を実際に加味して作ったJavaScriptの概要がこちら。実際のURLなどを記載しておくとかえって紛らわしくてご迷惑なので、サンプルっぽくシンプルにしました(これをこのまま使っても動きません。動くものは次回お見せします。)。JavaScript書きの方は雰囲気がお分りいただけると思う。このJavaScriptをHTMLのheadタグの中にjQueryと一緒に

のようにインクルードし、保護したい画像に

のように protect というクラスを付ければ実装できる。そんだけ。なので、Wordpressへの適用も容易(JetPackのように画像に対して複雑な処理をするアドオンとは共存できない場合があるが)だし、既存のFacebookのようなSNSへも(彼らがその気があれば)容易。数秒のコピペで実装が可能です。

eclips.js

そして、実際にエンコードした画像が下記。改造等の手を加えられていない上記のJavaScriptがサーバーにデコード依頼をし、画像の所有者がエンコードした際に設定した条件(表示しても良いドメインや時間など)を満たしている場合のみに画像は表示される。これらの条件情報は全て画像内部に埋め込んであり、デコードするサーバーには画像は保存されていない。なお、このように「特定の条件が揃った場合のみに見られる」ということが皆既日食みたいだなと思ったので、この仕組みの名前を「ECLIPS(エクリプス:皆既日食)」と呼ぶことにした。

エンコードしていない画像:
01.jpg

エンコードされた画像:
02.jpg

なお、エンコードされた画像はエンコード前の画像と同じようにシステムには画像として認識され、サムネイルがある場合はOSのファイル縮小表示では画像が表示される。だけども実寸大表示ができない。JPEGのバイナリーデータ構造に詳しい方はバイナリー・エディタで開いて見てみてほしい。どこのマーカーがエンコード前後で変わっているか。


ということで、今回は実際にどのような施策を行うかを技術的制限を加味しながらまとめた。次回は実際に動くサービスとしてお見せし、みなさんからのアドバイスに耳を傾ける。

(次回の投稿は2017年5月3日です。) → こちら

2017-02-20

TensorFlowを理解するための基礎情報共有(6)

前回の投稿からあっという間に1年が経過しましたが、皆さんいかがお過ごしでしょうか?TensorFlowの発表と公開(2015年11月)から1年以上経ち、巷の大企業の「人工知能を使った○○」という売り文句も耳慣れた感じがします。と同時に、スマホが普及する前に各社の各携帯電話で仕様が異なるために一般的にはまだモバイル・インターネットが普及していなかった頃(2005年ごろ)のような「敷居が高い」感じの足踏み感も伺えます。こうした俯瞰的な話を含めて今後は定期的に投稿していきますので宜しくお願いいたします。


前回はMNIST For ML Beginnersで難しい箇所について言及しました。

 前回 http://qiita.com/MATS_ELB/items/db85de80c72be28fc60b

今回は多くの方が足踏みする箇所に見えるDeep MNIST for Expertsについての補足説明です。Expertsになって急に難しくなりました。この章では「Multilayer Convolutional Network(多層畳み込みネットワーク)」という話がページ中盤から出てきて、まずはこの「多層畳み込みネットワーク」の考案のの背景にある話の流れから言及します。

 章の前半では「MNIST For ML Beginners」で登場したモデルの作り方が語られています(Pythonのコードは「MNIST For ML Beginners」と同じなので前回の記述を参照されたし)。このモデルは下記のような1層からなるモデルで、認識する28 pixel x 28 pixel(合計784 pixel)の画像を全てのピクセルを1行にした1次元の入力データとして学習および評価させるシンプルなものでした[図1]。

図1 MNIST For ML Beginnersで用いた一層の単純なニューラルネットワークモデル

これを使って1000回の学習(毎回50セットの画像を読ませたので学習した画像はのべ50000枚)を行ってみると精度は91%だったと。精度が低すぎる。この精度の低さは何が原因か考え下記のように考えたそうです。

 アイディア1:層を複数にしたらいいのでは?

理論上は入力と出力の関係を表す数式が細かくなって繊細になり精度が上がるはずなのだが、やってみたところニューラルネットワークの特徴である「学習(誤差逆伝播法/バックプロパゲーション:出力に出た誤差を修正するためひとつ手前の層の重みを調整し、そうするとその前の層の重みをこれくらい調整し。。。)」において、入力に近い層の重みがブレて精度が期待したほど上がらないという由々しき事態(過学習)に遭遇した。まるで、曲がらない棒で黒板を指すと棒の先は思い通りに定まるが、いろんな場所を指せるよう棒に関節をいくつもつけたら棒がクニャクニャ曲がって棒の先がうまく定まらないのと似た状態です。そこで再び考えた↓。

 アイディア2:学習する際に一部の重みを無視して感度を下げたらいいのでは?

ということで、学習する際に各層の各重み全てを修正するのではなくて、一部(確率的に選ぶことが多いようです)を学習時には無視して残りの重みだけ修正するという「学習感度を下げる」方法を編み出した。これを「Dropout(ドロップアウト)」と呼びます。これにより学習のブレは抑制できましたが、さらに下記のように考えた↓。

 アイディア3:そもそも、画像を1行のデータにして入力するのは適切なのか?

これは学習データが画像であるから改善方法として出るアイディアで全てのタイプの学習に適用される手法ではありませんが、例えば、画像に表現されている絵(A)が全体で右に1ピクセル移動した画像(B)があった場合、人間の脳はほぼ同じ絵と認識するはずなのに、画像を1行のデータにしてしまうと(A)と(B)はまったく異なるデータとなってしまい、ニューラルネットワークは非常に理不尽な学習をしてしまうだろうと。このような画像の枝葉末節な違いではなく、人間が映像を捉える時のように「少しざっくりと、画像としての特徴をつかむような」捉え方をしたデータをニューラルネットワークの入力にしてはどうかと。

上記の経緯を経て、本性で扱われる「多層畳み込みネットワーク」が考案されたとのことです。


次回の投稿では、技術や数学の観点を少し離れて、「この一年の機械学習・人工知能の発展推移を見て考える、あるべき今後と課題」に言及します。

2015-12-16

TensorFlowを理解するための基礎情報共有(5)

今回はMNIST For ML Beginnersの解説です。何人かの方々がわかりやすい解説を既にされていますので、それらには言及されていない箇所に重きをおいて記述します。まず、TensorFlow.orgの当該ページで五月雨式に書かれているPythonのコードをまとめて書きますと下記です。

2018/01/30 追記: TensorFlow ver 1.5のSyntaxに対応してコードをアップデートしました。

上記で難しそうに感じる箇所は下記の3箇所かと思います。おのおのにつき一般論ではなくTensorFlowを前提として述べます。

1) y = tf.nn.softmax(tf.matmul(x, W) + b) の matmul()

 第3回目の情報共有では割愛しましたが、数値の掛け合わせと行列の掛け合わせは計算のルールが異なります。高校数学で習う「内積」や「外積」です。ニューラルネットワークの構造の定義としてxとWの掛け合わせをしますが、行列同士なので行列の「内積」の形をとります。行列の内積の計算、左は横方向に右は縦方向に掛け合わせて足していくという面倒な計算です。なので、TensorFlowにはライブラリにこの「内積」を計算する関数が用意されているので、それを使ってtf.matmul(x, W)として内積の計算を行います。matmulは「mathematical multiplication(数学的掛け合わせ)」の略だと思われます。なお、この定義から考えるとmatmulを使って掛け合わせるものは普通にスカラー量でもいいのだと推測されます。

2) y = tf.nn.softmax(tf.matmul(x, W) + b) の softmax()

 「ソフトマックス」と聞くと、バケツで作ったプリンのような何か柔らかくてでっかいものが想像されますが、この「ソフトマックス」は「無制限の実数範囲の入力xに対して0から1までの値であるyに変換して出力する関数」です。なお、このように0から1に収めることを「正規化する」といいます。式とグラフの記載は控えますが、上記のこのソフトマックス関数は自然対数の底であるe(実際の値は2.7182818….)を使った特殊な性質を持った数式で、ニューラルネットの学習最適化を行う際(最も誤差が大きい方向に修正する)に必要となる「微分計算」が容易に出来るという性質があります。この理由から、「正規化」を行える関数は他にも「ステップ関数」などがあるのですが、その微分に関する便利な性質から、ソフトマックス関数が多用されます。

 では、なぜ出力を正規化(0から1に収める)をするのでしょうか?その方が、後述する「クロスエントロピー」を用いて学習の出来具合を計算するうえで都合が良いのです。また、出力を正規化しても問題が無いことを、少し的がずれるかもしれませんが我々の実生活に置き換えて考えてみます。仮に「リンゴ」や「ミカン」といわれたら『くだもの』と答え、「キャベツ」や「にんじん」といわれたら『野菜』と答えるパターン認識ゲームをしたとします。このゲーム、小声で「リンゴ」といわれたら小声で「くだもの」と答え、大声で「リンゴ」といわれたら大声で「くだものぉぉ!」と大声で答えることに意味はあるでしょうか?このゲームの本質は入力である言葉と出力である言葉の関係性のパターンを当てることであって、声のボリュームには意味はありません。もし、仮に、小声の「リンゴ」が「果物」で、大声の「リンゴ」が「野菜」という場合があるのであれば、入力変数xに「声のボリューム」を変数として追加して学習すれば出力を正規化しても問題ないはずです。

その3) cross_entropy = -tf.reduce_sum(y_*tf.log(y))

 「クロスエントロピー」または「交差エントロピー」。ものすごくざっくりと述べますと、「ある数値の軍団Aと、ある数値の軍団Bがどれくらい異なるか」を表す概念です。エントロピーとは、これもざっくり述べますと「乱雑さの度合い」です。この「エントロピー」という概念は様々な理工学分野で用いられまして、上下に分離したドレッシングの瓶をシャカシャカ振ってよく混ざった状態にすると「エントロピーが増えた」となります。ということで、機械学習でいうと「学習データの出力と、実際のニューラルネットワークの学習結果としての出力がどれくらい異なるか」を表します。このクロスエントロピーを用いる際に比較対象となる「数値の軍団」は正規化されている必要があり、前項のソフトマックス関数で正規化しています。私はお決まりの呪文だとして機械的に使っています。

以上、ご指摘やアドバイス、喜んで伺いたく宜しくお願い致します。

続編はこちらへ http://qiita.com/MATS_ElectricBlueIndustries/items/a0ef52be42b0c4e6cfb5

2015-12-14

TensorFlowを理解するための基礎情報共有(4)

前回はTensorFlow.org掲載の「GET STARTED」をテンソル版に拡張した例を用いて行った学習過程および結果のデータをTensorBoardで可視化して機械の学習の様子を見てみました。

 前回 http://qiita.com/MATS_ELB/items/e5761be146a400586392

今回は「精度の高い学習」について哲学的に考えます。
ほぼ「閑話休題」レベルの話です。

我々が生活している地面について「東経○○度、北緯○○度は標高○○メートル」という実際の計測データを集めて、「それなら、行ったこと無いけど、100メートル向こうは標高○○メートルだろう」と推測するモデルを機械学習で作る作業を考えた場合、推測の精度を考える上でいくつかの疑問が浮かびます。

 疑問1:実測データ(=学習データ)はどれぐらいの数を集めれば良いのか?
 疑問2:計測するポイントの間隔はどれぐらいの距離が適切なのか?

つまり、ホントに正確な標高を推測したければ1ミリ間隔で標高を計測して膨大な学習データを用意していけばいいわけで、そうなるとわざわざ推測モデルを作ることに意味あるの?実際に計測しまくればいいんじゃない?となりそうです。逆に、10メートル間隔で標高を計測していった場合、道路にあるマンホールのように1カ所だけ急激に標高が変化する場所を見落としてしまうのではということになります。と考えると、そもそもこの推測モデルは誰が何のために使うんだったっけ?という話になりそうです。象の地図に使うのであれば数十センチの段差は気にもならないでしょうし、蟻の地図に使うのであれば数センチの段差も大事な情報でしょう。使用目的によって適切な尺度というのがありそうです。

余談ですが、アラブの遊牧民達はラクダの呼び方について年齢や性別からはじまり「水を飲んでいるラクダ」「寝ているラクダ」「草を食べているラクダ」などラクダの状況によって異なる呼称を持っています。我々と異なり、彼らの生活はラクダと密接な関係にありますから、その分だけラクダを認識する尺度が繊細なのでしょう。彼らに対して我々の感覚で「ラクダとヤギを判別するシステム」を提供したとしても「どの状態のラクダかまで判別できないと困る」といわれるかもしれません。

ということで、機械学習の精度については使用目的によって適切な尺度を考慮することが大事なようですが、皮肉なことにこの「適切」は人間が判断するしかないのでしょうか?それとも、機械学習によって「このユーザーはこのレベルの違いには関心無いな」などと自動で調節するようになるのでしょうか?現時点での機械学習に対する一般的な認識を総括すると「できるだけ多くのデータを持っている方が有利」との傾向が感じられます。しかし、これは一昔前に「できるだけ多くのメールアドレスを持っている方が広告配信に有利」といわれていた状態に似ている気がします。結果として、多くの人々はメールで送られる広告に見向きもしなくなりました。闇雲にデータ量に依存するのではなく、「目的に叶った適切さか」を見極める「チューニング力」が我々に求められているのではと思います。

次回はTensorFlowの技術的な話に戻ります。皆さんからのアドバイス・ご意見をいただきたく。

 続編はこちらへ http://qiita.com/MATS_ELB/items/db85de80c72be28fc60b

2015-12-11

TensorFlowを理解するための基礎情報共有(3)

前回はTensorFlow.org掲載の「GET STARTED」をスカラー版からテンソル版(つまり学習させるデータが数値ではなくベクトルorテンソル)に拡張した例を共有しました。

 前回 http://qiita.com/MATS_ELB/items/fec7f54de2dd18b043ae

今回は、その学習データを記録し、TensorFlowに装備されているTensorBoardを用いて可視化し、機械の学習とは何かを考えてみます。

[1] コードを書き換える

前回記載したPythonのコードを少し改修して、TensorBoardが読み込むデータを生成し書き込むようにします。前回とは変わらない部分のコメントは削除し、今回の改修部分にコメントを記載しました。

introduction_vector_with_summary.py

上記を実行すると、サーバの /tmp/tf_logs ディレクトリの下に「event」で始まるログファイルが出来ます。これが機械学習の過程と結果を記録したSummaryデータです。

[2] TensorBoardで学習でできたSummaryデータを見る

※「TensorBoardはウェブサーバで画面を表示し、見る人はブラウザで見るので、SummaryデータがあるサーバでApacheなどのHTTPdが動いている必要があります。それを前提に」と投稿時に書いたのですが、誤りでした。TensorBoardを利用する際、HTTPdを走らせる必要は無いことを確認しました。

下記を実行します。

 tensorboard –logdir=/tmp/tf_logs

そして、ブラウザでそのサーバのポート6006を指定してアクセスすると、TensorBoard画面が開きます。EVENTSのビューには「学習のダメ程度」を表すlossの推移が、HISTOGRAMSのビューには学習で得られたWとbの推移が表示されています(下図)。

2015-12-11_11-37-57.jpg

2015-12-11_11-50-03.jpg

これらの意味を考えてみましょう。lossの値は学習回数が30回程度で0に収束していますので、用いた評価関数(学習データのy_dataと実出力のyの差分の2乗)で見て『学習ができている』様子が伺えます。Wもbもそれぞれ収束しているように伺えます。こうして可視化することによって「学習が適切に行われたか」をざっくり把握することができます。

[3] これでいいのか?

上記では「ざっくり把握することができる」と曖昧に書きました。それはなぜでしょうか?機械が学習の対象とする学習データが内包するパターンorルールが今回のケース(数学でいえば1次関数の入力と出力)のようなシンプルなケースの場合、評価関数が示す誤差がしばらく0であれば正常に学習が完了したと見なせるでしょうが、複雑なケースの場合はどうでしょうか?また、今回のケースでは学習最適化の手法を「最急降下法(勾配法)」という、いわば「lossを標高に見立てて、最も低い場所に辿り着くために、その時点で自分がいる場所で坂が一番急な方向に進むことを繰り返す」方法で行いました。自分がいる世界(=学習データのパターン)が下るだけの坂道世界ならその方法で一番低い場所(学習データの本当の正常完了)に辿り着けるかもしれません。歩いていく歩幅が大きい場合、最も低い場所をまたいでしまうかもしれませんが。自分がいる世界が山あり谷ありの地形だったらどうでしょう?遠くの山の向こうには今いる場所よりも深い谷があるかもしれないのに、ひたすら下に下るという学習最適化手法であるために山越えをせず局所的な「一番低い場所」に甘んじてしまうのではないでしょうか?例えば、鎖国していた頃の日本人は「富士山は世界一高い」と思っていたが、鎖国が解けて、海外にはもっと高い山があると知った状態です。

ということで、次回は精度の高い学習をするために何をどうしたら良いのかを考えてみます。みなさんからのアドバイス、喜んで伺いたいのでどうぞ宜しくお願い致します。

 続編はこちらへ http://qiita.com/MATS_ELB/items/98d32ca79c3e8261ff1a

2015-12-10

TensorFlowを理解するための基礎情報共有(2)

前回はTensorFlowの最初の利用方法紹介である「GET STARTED」を題材にしてスカラー・ベクトル・テンソルの違いに言及しました。

 前回 http://qiita.com/MATS_ELB/items/dfc50149d52e47e5a07b

その「GET STARTED」ではスカラー量(ひとつの数字で表現できる)を使ってTensorFlowの挙動が説明されていますが、その後のチュートリアルでは急にテンソルを使った数字の画像認識が題材となっていて、テンソルの扱い方が理解しにくくなっているように思います。なので、「GET STARTED」で扱われたケースを少しだけ改造してテンソル版にしたものを掲載し、日本語でコメントを記載します。

2018/01/31 追記: TensorFlow ver 1.5のSyntaxに対応してコードをアップデートしました。

introduction_vector.py

これを実行すると下記のような出力(学習の結果としてのWとb)が得られます。

0 [[ 0.06333046 0.27613732] [ 0.27408534 0.65764177]] [ 0.12632947 0.0456607 ] :
中略
:
1000 [[ 1.00000262e-01 2.38718428e-07] [ 2.14710980e-07 1.00000240e-01]] [ 0.29999986 0.29999986]

読みやすいように改行を調整したりしますと

学習回数 1000
Wの値  [[ 1.00000262e-01 2.38718428e-07], [ 2.14710980e-07 1.00000240e-01]] bの値  [ 0.29999986 0.29999986]

ということで、学習結果のWはW_dataの値(というかテンソル)に、近づいていっています。
というように、テンソルを使ってTensorFlowを使う場合、基本的には「GET STARTED」で扱われたスカラーのケースと同じです。ただ、行列の計算は行・列の数に整合性を求めるのでそこの帳尻が合っているかに気をつけたいです。

以上、どなたかのお役に立てればと思い記載致しましたが、私、このサイトの投稿が初心者なので上手くなくて申し訳ありません。今後も学習しながらお役に立てるように情報共有して参ります。アドバイスなどありましたら是非是非いただきたく。

 続編はこちらへ http://qiita.com/MATS_ELB/items/e5761be146a400586392