sagantaf

機械学習/深層学習を組み込んだシステムを構築するために調べたり検証したことをまとめています。

コンテナセキュリティのリスクと対策

はじめに

最近のDockerやKubernetesの発展により、コンテナを利用したサービスやシステムの構築が盛んになっています。 しかし、環境を構築することがまず優先されてしまい、セキュリティに対する意識が薄くなっているそうです。

確かに、コンテナ技術を使ってサービスを構築するにあたり、セキュリティのことは気にはなりつつも、まずはDockerやKubernetesをどう使うかを優先してしまいがちです。

しかし、あらかじめコンテナ技術に対するセキュリティリスクと対策について概要だけでも知っておくことで、Docker、Kubernetesを使うときの考え方・意識が変わるはずです。

そこで、本記事にて「コンテナのセキュリティ対策とはどういうものが必要か?」という疑問を元に、基本的なことをまとめてみました。

ここに書かれていることが全てではありませんが、こういう対策が必要なんだな、程度に読んでイメージを掴んでいただけたら幸いです。


コンテナ技術のセキュリティリスクとは

コンテナは元をたどれば単なる実行プロセスです。そのため基本的にはプロセスのセキュリティ対策と同様の対策が必要になります。何もかも新しいセキュリティの対応が必要、というわけではありません。

ただし、コンテナ技術特有のリスクもあります。例えば、コンテナにマルウェアを仕込みDockerHubに紛らわしい名前でプッシュしておくことで、不特定多数の環境にばらまく、という攻撃などが考えられます。インターネットにあるコンテナイメージをスキャンせずに使うと上記のような攻撃を受けるリスクが上がってしまいます。

ここでは、下記の2種類の軸に沿ってリスクと対策について説明していきます。

  • コンテナのライフサイクルから見えるリスクと対策
    Dockerfile作成、ビルド、コンテナイメージ、レジストリ、コンテナ、デプロイ
  • コンテナ周りのコンポーネントから見えるリスクと対策
    オーケストレータ、ネットワーク、ストレージ、ホストOS


コンテナのライフサイクルから見えるリスクと対策

コンテナのライフサイクルは、下記の図のようになっています。順番を優先するために、プロセス関連(Dockerfile作成、ビルド、デプロイ)と、成果物関連(コンテナイメージ、コンテナレジストリ、コンテナ)の項目を混在させています。

f:id:sagantaf:20190728112132p:plain
コンテナライフサイクル

① Dockerfile作成

このフェーズでのリスクはまず、root権限でコンテナを実行していることで侵入者にroot権限を悪用されてしまうことが考えられます。これには、一般ユーザにてコンテナプロセスを実行する、Dockerfileの脆弱性スキャンを実施する、といった対策が必要になります。

また、リスクとして、Dockerfileに暗号化していないシークレット情報(IDやパスワードなど)を直接記載してしまうことで、第三者に情報を奪われてしまうこともあります。これは、Dockerfileにシークレット情報を直接書くのではなく、シークレット管理ツールを利用することで回避できます。

シークレット管理ツールには、”Vault"というものや”aqua”というものがあるようです。これは実行中のコンテナに、パスワードやSSHの鍵などの秘密情報を注入できる機能を備えています。

www.vaultproject.io

www.aquasec.com

② ビルド

コンテナのメリットはコンテナイメージをあらゆる環境で実行し動かすことができる点です。つまり一度ビルドしたコンテナイメージを使い続けることになります。そのため、セキュリティの観点ではビルド時に注意して対策を練ることが重要になってきます。

対策としては、ビルドの前に自動的にセキュリティテスト実施する仕組みを導入したり、ビルドされたイメージに署名をつけ改ざんに対する防御をすることなどが考えられます。

③ コンテナイメージ

コンテナイメージに関するリスクとしては、内部ファイルのアップデート不足によって脆弱性のあるアプリケーションなどがそのままになってしまっていたり、マルウェアが埋め込まれたイメージをベースとして利用してしまうことが考えられます。

こういったリスクに対しては、まずは定期的にコンテナイメージをアップデートする仕組みを導入し、利用するベースイメージの提供元、作成者、既知の脆弱性の有無、各ツールやライブラリ・ランタイム・OS等のバージョンなどをしっかりと確認することが重要です。信頼されているイメージのみを使うことでリスクをかなり軽減できます。

先述したツールには、イメージスキャンや結果のレポーティング、結果に対してのアクション設定などの機能が備わっており、セキュリティ対策を万全にするためには利用を検討しても良いと思われます。こうしたツールを組み合わせることで、「ビルドの段階でマルウェアが発見されたらイメージをレジストリにpushせずに警告メールを管理者に送る」といった仕組みも作ることができます。

また、レポートにはホストやコンテナ上で発生するセキュリティイベントなどが記録されるため、セキュリティインシデントが発生した時の監査証跡として利用することもできます。

④ コンテナレジストリ

コンテナイメージの取得先としてDockerHubを利用することもできますが、AWSやGitlabを利用して専用のコンテナレジストリを用意することもできます。こういう時に気をつけるべきは、レジストリとの通信の盗聴や、古いイメージのまま使ってしまうことによる脆弱性の発生です。レジストリの通信を暗号化したり、古いイメージを定期的に削除する仕組みを導入する対策が必要です。

また、レジストリへのアクセス権限を適切に設定し、認証を設けることで、不正アクセスを防ぐことができます。セキュリティレベルを高くするために、重要機密を扱うコンテナイメージと通常コンテナイメージのレジストリを分離するといった対策も有効です。

⑤ コンテナ

実行されたコンテナに対するセキュリティリスクとしては、ランタイムソフトウェア(Dockerだとcontainerd、など)の脆弱性や、コンテナに組み込んだアプリケーションの脆弱性が考えられます。どちらに対しても脆弱性スキャンが必須です。

また、マイクロサービスで利用されるアプリケーションはそれぞれにAPIがある可能性があるため、その分エンドポイントが増えることになります。そのため、各APIの発行を必要最小限に制限し、SSO認証を取り入れるなどして、統制を敷くことが重要です。

すでに実行中のプロセスであるため、監視を強化するのも有効な手立てです。疑わしいプロセスの振る舞いを検知し、通知したり、ブロックすることで被害を最小限に抑えることができます。

⑥ デプロイ

デプロイのフェーズでは、デプロイ自身にリスクがあるというよりは、いかに素早くセキュリティ対策を利用環境にデプロイできるかどうかです。

自動的なCI/CDの仕組みを導入し、セキュリティパッチを必要な環境に素早く適用できるようにします。 例えば、イメージのスキャンによって脆弱性を検知したらコンテナイメージを改修してレジストリに上げる。このレジストリへのpushをトリガーに、自動的にビルドとデプロイが実施される、というイメージです。


コンテナ周りのコンポーネントから見えるリスクと対策

コンテナ周りでセキュリティリスクがある部分は、オーケストレータ、ネットワーク、ストレージ、ホストOSです。

オーケストレータ

オーケストレータはKubernetesなどのコンテナ管理アプリケーションのことを指します。コンテナのデプロイやスケーリング、管理などを司る部分であるため、セキュリティ対策が非常に重要になります。

リスクとしては、甘い権限設定による特権アクセスや、設定不備によるクラスタ侵入や認証情報盗難などがあります。

特権アクセスに対してはこれまでと同様、最小権限をユーザに付与することが対策となります。設定不備に対しては、設定のスキャンや事前テストを導入することで、不備に気づかないままデプロイしてしまうことを避けられます。

また、セキュリティの対策というよりも、影響の範囲を狭めるという意味で、機密度レベルに応じたコンテナやロールをグループ化することも有効です。オーケストレーションレベルでお互いの通信を制限できるため、セキュリティインシデントがあったとしても、そのグループ内に影響を閉じ込めることができます。

そのほか、大規模なサービスの開発になると、複数のクラスタ利用や複数のクラウド環境(AWSGCP、Azure)/オンプレミス環境を組み合わせることがあります。そういう場合には、各環境にまたがったセキュリティ対策を実施するために、Rancherのような個々のクラスタや環境の操作・管理を統一して行うツールが必須になるでしょう。

rancher.com


ネットワーク

コンテナのネットワーク設定はデフォルトでは外部との通信はできませんが、利用する上で少なからず外部向けのポートを設定するかと思います。また、内部通信は自由にできるようになっているため、一度悪意あるユーザに不正に侵入されてしまうと無制限にコンテナにアクセスできてしまう可能性があります。

コンテナ技術に関係なく一般的なネットワークセキュリティの対策としてできることは、F/Wやホワイトリストの利用、Develop/Test/Production環境の分離、ファイルシステムに対するRead-Onlyモードの適用などです。 ただし、コンテナは起動する場所があらかじめ決まっているわけではないため、F/WやホワイトリストIPアドレス・ポートを利用するとネットワーク構成が複雑化してしまいます。コンテナのネットワーク周りの設定のために生まれたEnvoyやIstioといったサービスディスカバリを使うことでシンプルなネットワーク構造を保つことができます。

また、コンテナ特有の対策としては、ロードバランサやプロキシとして稼働するコンテナのみに公開ポートを設定する、内部でのコンテナ間の通信にVPNや専用のI/Fを使う、などです。


ストレージ

ストレージは、永続ボリュームであれ、共有ディスクであれ、あらゆるデータが格納される場所です。そのため、最小限のアクセス権限設定と通信時の暗号化を実施し、データ漏洩や盗聴を防ぐ必要があります。

まずは使っているストレージのセキュリティ機能を利用して、SSLによる暗号化やアクセス制限を実施します。その上でコンテナツール側(Docker、Kubernetes、Rancherなど)のセキュリティ対策を実施することで万全の体制を整えることができます。

コンテナツール側の対策としては、NFSやEBSを利用するときのストレージプラグイン脆弱性チェックや、コンテナ側からのアクセス制限、などです。例えば、Kubernetesでは永続ボリュームを設定するときに、マウントするストレージに対してReadWriteOnce、ReadOnlyMany、ReadWriteManyの設定が選べます。


ホストOS

コンテナはホストとカーネルを共有しているため、ホスト側のセキュリティ設定をしっかり実施しておく必要があります。

ホストOS自身への対策としては、定期的なOSアップデート確認および適用は必須です。

また、下記のようなホストOSのセキュリティ機能を利用して、コンテナプロセスの動きを制限することも可能です。

  • SELinuxMAC(強制アクセス制御)を使い、他の空間のリソースは使えないようにする
  • Cgoupsを使ってプロセスのリソース使用量(CPU、メモリ、ディスクIO、ネットワークなど)を制限し、1つのコンテナにDoS攻撃を受けてリソースが圧迫されても、同じホスト上の別のコンテナがリソース不足になることを防ぐ
  • Capabilityにて一部のroot権限が必要な機能のみをコンテナプロセスに与える

別の観点として、ホストOSからのコンテナの設定として下記の対策も有効です。

  • コンテナに特化したホストOSを利用する
  • コンテナが呼べるカーネルコールを制限する
  • DockerやKubernetesAPIコマンドの範囲をローカルネットワークのみなどに制限する


まとめ

以上が、コンテナを使う上でのセキュリティリスクと対策の基本事項になります。

様々な観点からセキュリティ対策を実施していかないといけませんが、全てを人がやろうとすると開発/運用スピードが落ちたり、抜け漏れが出てきたりしてしまいます。 そうならないためにも、スキャンやアップデート、脆弱性情報の更新などはCI/CDプロセスに組み込むなどして自動化させることが重要です。 これにより、「DevOpsサイクルの鈍足化」および「セキュリティ対応の抜け漏れ」を防止できます。


参考資料

SP 800-190, Application Container Security Guide | CSRC

DevSecOpsも実現できる。コンテナアプリを脅威から簡単・確実に守る方法:コンテナセキュリティ、5つの勘所とは? - @IT

DevOps/マイクロサービスに欠かせないコンテナセキュリティ – 導入前に知っておきたいリスクと対策 – Nissho Electronics USA Corporation

Docker

Docker

評論家にならずに行動する人間になる! 〜仕事をする時に意識すること〜

はじめに

仕事をするときに意識すべきこと。

それは、 評論家にならない  こと。

  私自身、入社当時から上司に「評論家のようになるなよ」と言われてきましたが、最近 THE 評論家 と言えるような人と仕事をするようになってしまってから、特に意識するようになりました。

備忘録の意味もこめて、

  • 評論家とはどういう状態か?
  • なぜ評論家じゃダメなのか?
  • じゃあどうすれば良いのか?

をまとめました。

  

「評論家」とはどういう状態か?

ここで「評論家」と言われる人とは、業務の現状を把握・分析し、 "○○であることがわかった"、"こうすべきだ"、"こうしないとダメだ" と言うだけにとどまり、実際の行動に移らない人のことを指しています。

会社のため、チームのためを思って考えたことを発信しているため、決して悪いことではありません。

しかし、発言するだけで終わってしまう人が多く、そう言う人たちは「評論家」と揶揄されてしまいます。

確かに、いろいろ調べて何かが分かると満足してしまうことがあります。

例えば、開発が遅れてスケジュール通りに進まない時に、どうすればスケジュール通り進めるのかを調べ「こういう開発の手法にすべきだ!」とか「ここに時間かけすぎだよね」と言うだけ言って何も行動せずに終わってしまったり。

また、システムの動きが遅い時に、ログや状態を確認して原因を突き止めたら、「こういう原因で遅くなっています」と報告して、「で、どうすれば早くなるの?」に答えられなかったり。

 

なぜ評論家じゃダメなのか?

上記の例のような状態だと、何にも前には進まないし、時間をかけて調査したり分析したりした意味がなくなってしまいます。   これは書籍「カイゼンジャーニー」の冒頭でも言及されています。

僕は、会社でぼんやりとした人たちに、こうすべき、ああすべき、こう考えるべき、なぜこうしない、とさんざん言いちらしてきた。でも、自分一人で何かを始めることはなかった。「何をしている人なのか?」に答えられるようなお話を持っていなかった。
ーー 市谷 聡啓,新井 剛. カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

評論家になってしまうと、

  1. お客さんからお金をもらえない
  2. 自分の成長や社内の評価に繋がらない

ということが起きてしまいます。

1. お客さんからお金をもらえない

仕事をしてお金をもらっていることの根本にあるのは、

「自分が行動して生み出した結果に対して、お客さんに対価を払ってもらう」

ということです。それなのに実際の行動を起こさずに評論で終わってしまうと、 仕事をやり切っていない  とみなされ、お客さんからお金を払ってもらえないことになります。

行動して結果を生み出さなけらば、お金をもらうに値しません。 (もちろん仕事が評論すること自体であれば、その評論した結果をアウトプットにお客さんからお金をもらえると思うので問題は無いと思います。)

2. 自分の成長や社内の評価に繋がらない

また、評論だけで終わると、実際に何もしていないから、成果は何も残りません。先ほどのカイゼンジャーニーの例のように、「何をしている人なのか?」と言う質問に対する答えが無い状態です。

その結果、「あいつは結局何をしたんだ?」「どんな成果をあげたんだっけ?」と上司から思われ、評価されずに終わってしまいます。  

じゃあどうすれば良いのか?

じゃあどうすれば評論家にならず、行動力のある人間になれるでしょうか。

書いてしまうと単純なことですが、「行動することに時間をかける」「定期的に仕事を振り返る」ことが行動力を上げるために効果的な方法です。

行動することに時間をかける

仕事を進めている最中にする対策として、行動する時間の割合を大きくして、評論で終わらないようにします。

どこまでが評論=調査・分析でどこからが実際の行動か、を常に明確していれば、行動する時間の割合を意識的に増やせます。

定期的に仕事を振り返る

仕事を終えたあとにする対策として次の二言を自分に問い、仕事を振り返ります。

「で、結局自分はどんな成果をあげたんだっけ?」

「自社や顧客のためになったことは?」

定期的な振り返りをすることで、自分は今何をやっているか、知らず知らずのうちに評論家になっていないか、をチェックできます。


以上の二つを実践するだけでもかなり評論家から離れ、実際に行動できる人間になれると思います。


周りの「評論家」に対しては、どう対処するか

自分が評論家になることを避ける以外に、周りの「評論家」と仕事をするときの対処も必要です。

周りに「この人、評論家で実際に何もしようとしてないな」という人がいたら、行動に移るように促すことが大切です。

例えば、部下に対しては、直接「じゃあどうするか」を伝えることで、行動することについて考える癖をつけさせます。

上司や他のチームメンバーなどに対しては、オブラートに包んで「現状や、すべきことは明確になりました。では、実際にどう行動するか、どう進めるかを相談させてください」と伝え、一緒に行動に移していきます。

こうすることで、評論状態で停滞していた仕事が進む上、自らが仕事を引っ張っていく感覚も得られ、成長に繋がります。


まとめ

評論家だと揶揄されている人とは、あーだこーだ言って、実際の行動には移らない人のことを指します。実際の行動をしないままでいると、お客さんからお金をもらえなかったり、自分の成長や社内の評価に繋がらずに終わってしまいます。

そうならないようにするためには、「行動することに時間をかける」「定期的に仕事を振り返る」ことが重要になります。また、周りに「評論家」がいた場合は、行動するよう促します。


「評論家にならない」=「行動する人間になる」 と言うことを意識して仕事をするだけで抜群に成長できると思いますので、ぜひ参考にしてみてください。  

なお、途中で引用した「カイゼンジャーニー」や下記の「アクションバイアス」を読んでみることもお勧めします。

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

アクション・バイアス: 自分を変え、組織を動かすためになすべきこと

アクション・バイアス: 自分を変え、組織を動かすためになすべきこと


「アクション・バイアス」については、日本語が少し読みにくい部分がありますが、書いてあることは大変参考になりました。内容を以下にまとめているので、まずはこちらを確認してから書籍を読んでみても良いかと思います。

sagantaf.hatenablog.com

   

 

Kubernetes入門〜Docker for Mac でKubernetesをインストールしJupyter notebookを起動してみる

はじめに

Macを使って手軽にKubernetesを体験してみるための手順です。

環境

Docker for Mac のインストール

まずは下記のページにアクセスして、Docker for Macをダウンロードします。

Docker Hub

右上の「Please Login To Download」に進みます。

f:id:sagantaf:20190709235257p:plain
Downloadページ

DockerIDとパスワードを入力してログインします。

f:id:sagantaf:20190717235251p:plain
ログイン画面

アカウントがない場合は、「create account」にて作成してからログインしてください。

ログインに成功すると先ほどのボタンが「Get Docker」になっているので、ポチってダウンロードします。

f:id:sagantaf:20190709235527p:plain
ログイン後の画面

ダウンロードできたらDocker.dmgをクリックして開き、インストールします。

インストールが完了したらDockerが自動的に起動します。

f:id:sagantaf:20190717235044p:plain
Docker起動中

DockerIDとPasswordを入力してログインする項目がありますが、特にログインしなくても起動は完了します。

Kubernetes環境を構築する

Dockerが無事起動したら、次はKubernetes環境の構築に入ります。

と言ってもDocker for Macにはあらかじめボタン一つでインストールとセットアップができてしまう方法が用意されているため、とても簡単です。

右上のバーにあるDockerマークから「Preferences」をクリックします。

f:id:sagantaf:20190722220104p:plain
Docker Preferences

下記のように、環境設定WindowのKubernetesのタブに移動し、「Enable Kubernetes」と「Kubernetes」にチェックし、「Apply」を押してください。

f:id:sagantaf:20190722220513p:plain
Kubernetesを有効化

少し時間がかかりますが、Macの環境にKubernetesがインストールされ、自動でKubernetesクラスタ環境が構築されます。

contextの切り替え

ここでMacの環境でKubernetesを操作するために、contextの切り替えを実施します。(contextとは何か、については後述します。) 下記のコマンドを実行するとcontextというものが2種類あり、minikubeが有効になっていることがわかると思います。

$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER                      AUTHINFO             NAMESPACE
          docker-for-desktop   docker-for-desktop-cluster   docker-for-desktop
*         minikube             minikube                     minikube

このcontextをdocker-for-desktopに切り替える必要があります。下記のコマンドを実行してください。

$ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".
$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER                      AUTHINFO             NAMESPACE
*         docker-for-desktop   docker-for-desktop-cluster   docker-for-desktop
          minikube             minikube                     minikube

再度contextを確認するコマンドを実行することで、docker-for-desktopに切り替えられたことが確認できます。

さて、このcontext、これはKubernetesの環境を分けるための定義です。 KubernetesのリソースであるClusterNamespace、およびユーザーをグループ化したものになります。

Clusterとは、稼働させるコンテナやネットワーク、ストレージの設定などをクラスタリングしたKubernetesのリソースです。本番用、テスト用、開発用など環境を分けたい時にClusterをその分用意し、それぞれのアクセスを制限できます。

Namespaceとは、Cluster内でさらに仮想的なクラスタを作成できるリソースです。 下記のコマンドで確認できるように、あらかじめ、default, docker, kube-public, kube-systemの4つが用意されています。

$ kubectl get namespace
NAME          STATUS   AGE
default       Active   28d
docker        Active   28d
kube-public   Active   28d
kube-system   Active   28d

システム管理用、Webサービス用、データ操作用など、各チームでアクセス範囲を制限したい時に利用できます。

図で表すと下記のようなイメージです。

f:id:sagantaf:20190727205037p:plain
contextとは

実際にどう設定されているか、は下記のコマンドで確認できます。clusterやnamespaceの情報も合わせて確認できますが、Namespaceはあってもなくても良いのでデフォルトでは定義されていません。

$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    insecure-skip-tls-verify: true
    server: https://localhost:6443
  name: docker-for-desktop-cluster
- cluster:
    certificate-authority: /Users/hoge/.minikube/ca.crt
    server: https://192.168.XXX.XXX:8443
  name: minikube
contexts:
- context:
    cluster: docker-for-desktop-cluster
    user: docker-for-desktop
  name: docker-for-desktop
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: docker-for-desktop
kind: Config
preferences: {}
users:
- name: docker-for-desktop
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: minikube
  user:
    client-certificate: /Users/hoge/.minikube/client.crt
    client-key: /Users/hoge/.minikube/client.key

Jupyter notebookを起動するためのマニフェストファイルを作成する

それでは、Kubernetesを使ってJupyter Notebookを起動するために、DeploymentおよびServiceのマニフェストファイルを作成します。

まずは、Jupyter notebookのコンテナを記載したjupyter-deployment.yamlファイルを作成します。

$ cat jupyter-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jupyter
  labels:
    app: jupyter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jupyter
  template:
    metadata:
      labels:
        app: jupyter
    spec:
      containers:
      - name: jupyter-minimal
        image: jupyter/minimal-notebook:latest
        ports:
        - containerPort: 8888

ここではコンテナイメージとしてjupyter/minimal-notebook:latestを指定し、ポート番号を8888を指定しています。

もう一つ、ブラウザからJupyterにアクセスできるようにするため、ポート番号を記載したjupyter-service.yamlファイルを作成します。

$ cat jupyter-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: jupyter-service
spec:
  type: NodePort
  selector:
    app: jupyter
  ports:
  - port: 8888
    targetPort: 8888
    nodePort: 30008

nodePortの項目に指定したポート番号でブラウザからアクセスできるようになります。

デプロイの実施

では、作成したマニフェストファイル2つを反映させます。反映にはkubectl applyコマンドを使います。

$ kubectl apply -f jupyter-deployment.yaml
deployment.apps/jupyter created
$ kubectl apply -f jupyter-service.yaml
service/jupyter-service created

これで指定したコンテナイメージがPullされ、起動されます。

イメージのPullには少し時間がかかります。下記のコマンドでPodの状態を確認し、Runningになっていれば、準備完了となります。

$ kubectl get pod
NAME                       READY   STATUS    RESTARTS   AGE
jupyter-5cd7b64d58-sz2jf   1/1     Running   0          2h

またServiceの状態は下記のコマンドで確認できます。ポート番号が指定した通り30008になっています。

$ kubectl get service
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
jupyter-service   NodePort    10.106.16.138   <none>        8888:30008/TCP   21m
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP          38d

アクセス確認

起動したJupyter-notebookにブラウザからアクセスします。

まずは認証のためのtokenを確認します。通常はJupyterを起動したら標準出力としてコンソールにtokenが表示されますが、KubernetesやDockerで起動した場合は出力されません。

ここではPodのログとして出力されるため、kubectl logsコマンドで確認します。 (コマンドの引数に、kubectl get podで確認できるNAMEを指定します。)

$ kubectl logs jupyter-5cd7b64d58-sz2jf
Executing the command: jupyter notebook
[I 08:07:01.867 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret
[I 08:07:02.459 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.7/site-packages/jupyterlab
[I 08:07:02.459 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 08:07:02.463 NotebookApp] Serving notebooks from local directory: /home/jovyan
[I 08:07:02.463 NotebookApp] The Jupyter Notebook is running at:
[I 08:07:02.463 NotebookApp] http://(jupyter-5cd7b64d58-sz2jf or 127.0.0.1):8888/?token=1e692521e72f8827a7bee3b72ffaf461dc04324429e21bcd
[I 08:07:02.464 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 08:07:02.469 NotebookApp]

    To access the notebook, open this file in a browser:
        file:///home/jovyan/.local/share/jupyter/runtime/nbserver-7-open.html
    Or copy and paste one of these URLs:
        http://(jupyter-5cd7b64d58-sz2jf or 127.0.0.1):8888/?token=1234567890abcdefghijk
[I 10:38:15.805 NotebookApp] 302 GET / (192.168.65.3) 1.88ms
[I 10:38:15.819 NotebookApp] 302 GET /tree? (192.168.65.3) 5.35ms

下の方に表示されているtoken=以降の文字列(1234567890abcdefghijk)をコピーしておきます。

次に、ブラウザを開き、localhost:30008をURL欄に入力しアクセスします。

認証画面になるので、先ほどコピーしたtokenを入力することでJupyterの管理ページにアクセスできるようになります。

f:id:sagantaf:20190727200927p:plain
Jupyter Notebook の認証後の画面

まとめ

MacbookにDocker for Macをインストールし、Kubernetesでアプリケーション(Jupyter Notebook)を起動してみました。DeploymentやService以外にもKubernetesにはいろんな使い方をするためのリソースが用意されています。 下記の参考文献などを参考にして、触ってみてください。 いろんな本を読んだ中で、下記の2つの本が基本を習得する上では、わかりやすく進めやすいと思います。

参考文献

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門

こちらの本は、KubernetesだけではなくDockerについての説明もあります。Dockerをこれから学ぶ人はもちろん、すでに習得している人の復習としても使えます。Kubernetesの部分は、細かく詳細を説明しているのではなく、まずは触って実際に構築してみて理解していく内容になっているため、初学者にとって進めやすく、おすすめです。

しくみがわかるKubernetes Azureで動かしながら学ぶコンセプトと実践知識

しくみがわかるKubernetes Azureで動かしながら学ぶコンセプトと実践知識

こちらの本はAzureを使ってKubernetesを解説している本になりますが、基本的な説明から実用的な可用性や保守性などにフォーカスした説明もあります。実際にシステムを本番導入する上で非常に役に立つ内容になっているため、おすすめです。

「何でもやりたい病」を「勝てそうなものだけに集中する」という習慣に変える

なんでもやりたい病

「何をやろうとしても、いろいろなことに気が散る。何でも学んでやろうという好奇心が働き、自分の時間という資源を薄く広く分散してしまっている。そして、どの分野も中途半端に身についてそのまま忘れていく。」

 こういう症状は「何でもやりたい病」と呼ばれます。 前向きなだけに本人は悪いことをしている気はしていないですが、興味対象があっちこっちにブレてしまい、ブレる度に頭の中は混乱します。おまけに、その時々の流行で、「○○○を勉強しないと乗り遅れる」といった外野の声に惑わされ、「何でもやりたい病」の症状がドンドン進み、焦りの気持は倍化し、自信喪失につながってしまいます。


勝てることに集中する

そこで、一つのことに集中する、余計なものを捨てるという考え方が必要になります。

企業で考えてみて下さい。個人がなんでもやりたくなるのと同じで、企業も目の前に魅力的に思える事業機会が山のようにあります。今だったら、AI、医療、農業、健康事業などです。

しかし、魅力度の高い分野に行けば利益をあげられるのかと良いのかというと、それは間違っていることは分かるでしょう。 魅力度の高い分野だったら、自分の会社が進出して、利益を取れると思ったら大間違いで、競争相手に対して勝てるだけの比較優位性を持たなければ勝てないのです。

個人も同じです。

魅力を感じるからと言ってやってみようとしても、そう簡単に同じ土俵の人たちに勝てるようにはなりません。 “本当に自分は興味があって、周りの人に勝ちたいと思っているか?勝てる算段があるのか?”と自問自答が必要です。

こういう考えを持つことで、「何でもやりたい病」を「勝てそうなものだけに集中する」という習慣に変えられるのではないでしょうか。

皆さんもチャレンジしてみてください。

シェルスクリプトとプログラミング言語の関係は?


意外と分からなくなる人が多いはず…と思ってまとめました。


答え

シェルスクリプトプログラミング言語のひとつ。


解説

そもそもプログラミング言語には、スクリプト言語コンパイル言語の2種類存在します。

まず、人間がコーディングしたプログラムは、機械が読み込めるように機械語というバイナリファイル(0と1の集合)に変換する必要があります。 このバイナリファイルへの変換がいつ実行されたかによって、スクリプト言語コンパイル言語に分けられることになります。


スクリプト言語

スクリプト言語は、作成したプログラムを実行するときに、機械語へ変換し、処理を稼働させるスタイルです。

インタプリタというツールがソースコード機械語へ変換する役割を担っています。

例えば、シェル、AWKPythonPHPJavaScriptなどがスクリプト言語のスタイルを採用しています。シェルにはさらにbashcshkshtcshpowershellなど多種類存在します。

実行の流れ:

  1. ユーザによるプログラムのコーディング
  2. ユーザがプログラムを実行するためのコマンドを叩く
  3. 変換&処理を1行単位で進める

変換と処理を1行ずつ進める点がポイントです。


コンパイル言語

これに対してコンパイル言語は、その名の通りあらかじめ機械語へ変換(コンパイル)し、バイナリファイルを作っておくことで、プログラム実行時にはすぐに処理を稼働させる言語です。

コンパイラというツールがソースコード機械語へ変換する役割を担っています。

例えば、C、C++Javaなどの言語がコンパイル言語のスタイルを採用しています。(Javaは正確にはインタプリタによる変換もあるため、中間に位置する)

実行の流れ:

  1. ユーザによるプログラムのコーディング
  2. ユーザによるコンパイルの実行
  3. ユーザがプログラムを実行するためのコマンドを叩く
  4. 処理が稼働する


それぞれのメリデメ

スクリプト言語は非常に学習コストが低いため複雑な処理も簡単に書けます。しかしコンパイルしながらの実行になるため、処理が遅いデメリットがあります

一方で、コンパイル言語は実行時にはすでに機械語になっているため処理が早いという特徴があります。しかし、あらかじめコンパイルしておくという手間が発生する点がデメリットになります

つまり、処理速度と実行までにかかる時間のトレードオフの関係になります。

実際に使うときには、作りたいアプリケーションやシステムによって、このトレードオフを考えて選択することになります。


まとめ

シェルスクリプトプログラミング言語の中のスクリプト言語の一つであり、実行中に機械語に変換され処理が稼働するという特徴があります。

ついでにシェルとOSとの関係を理解するには、以下のページがわかりやすいです。
eng-entrance.com

RNNとLSTMを理解する



この記事の目的

RNN, LSTMの理論を理解し、Kerasで実装できるようにするために、理論部分をまとめた記事。



0. 通常のNeural NetworkやConvolutional Neural Networkの問題

これまでNNやCNNは入力サイズが固定だった。そのため、毎回同じ入力をするしかなく、時系列情報を入力させることができなかった。

RNN・LSTMは、入力を可変にして過去の出力結果も学習に利用できるようにしたニューラルネットワークのモデルである。



1. RNN (Recurrent Neural Network)

RNNの基本的な構造は、「現在入力値と前回の出力値を合計し、活性化関数としてtanhを適用して出力とする」という流れ。

f:id:sagantaf:20190603233207p:plain
RNNの基本的な構造

上図でいうと、現在の入力がx_tとなり、前回の出力値がh_{t-1}となる。

f:id:sagantaf:20190603233243p:plain
1つのセルの中身

隠れ層では活性化関数としてtanhが一般的に選ばれる。

数式で表すと、
 h_t = tanh(x_t + h_{t-1})
となる。

tanhx_th_{t-1}の和を-1〜+1の範囲に正規化する。

tanhが選ばれる理由は、2次微分の減衰がかなりゆっくりとゼロになり勾配消失問題が起きにくいため。



2. 勾配消失(爆発)問題

過去データに対する重みが発散、消失する問題のこと。下記サイトの解説が分かりやすい。

ニューラルネットワークと深層学習

発散・消失する理由は、最初の方のレイヤーの逆伝播計算時に、何度も重みwとシグモイドの微分を掛け合わせるからである。

シグモイド関数微分は0~0.25の範囲である。そのため、重みwが1以下だったら、最大でも w*σ'(z)= 1 * 0.25 = 0.25 となるので、0.25を繰り返し乗算することで、勾配がほぼ0になってしまう。これが勾配消失と呼ばれる理由。

また、重みwが0.25をかけたらかなり大きくなる値(100とか)の場合、0 ~ 0.25 × 100 = 0 ~ 25 の範囲になるため、最悪25×25×25×…となってしまい、勾配が発散してしまう、勾配爆発問題が起きる。(これはバイアスでも同じ話)

このように最初のレイヤーの重みとバイアスがかなり小さくなってしまうことにより、新たな入力値を学習しようとしてもかなり小さくなってしまうため、モデルの学習に寄与しなくなってしまう。

RNNでも数十ステップの短期依存(short-term dependencies)には対応できる。しかし、1000ステップのような長期の系列になると、tanhを使って上記の問題を和らげるとはいえ、無視できないくらい勾配が小さく(もしくは大きく)なってしまい、上述の勾配消失(爆発)問題が発生する。



3. LSTM (Long-short term model)

この対処法としては下記のようにいくつかある。

  • 行列Wを適切に初期化する
  • tanhではなくReLUを使用する
  • 教師なしで層を事前学習する
  • LSTM, GRUなどを利用する

中でも4番目に記載した「LSTM」では過去のデータを保持する仕組みを使って、勾配消失問題を回避している。

LSTMは過去のデータをsigmoidやtanhではなく「線形和」で保持するため、逆伝播しても勾配が極端に大きくなったり小さくなったりしないため、勾配消失問題が発生しない。

LSTMの様々な構成パターンが存在するが、以下では基本的な構成要素をまとめた。

  • CEC:過去のデータを保存するためのユニット
  • 入力ゲート:「前のユニット(1つ前の時間のユニット)の入力をどの程度受け取るか」を調整するためのゲート
  • 出力ゲート:「前のユニット(1つ前の時間のユニット)の出力をどの程度受け取るか」を調整するためのゲート
  • 忘却ゲート:「過去の情報が入っているCECの中身をどの程度残すか」を調整するためのゲート

f:id:sagantaf:20190604220957p:plain
LSTMの構成要素

基本的な流れは緑の線であり、入力x_ttanhによって活性化され出力h_tとなることは変わらない。そこにCEC C_tと各種ゲートが追加された構成になっている。

図の上の部分C_tが長期記憶(Long)を担い、下の部分h_tが短期記憶(Short)を担う。これがLong-Short Time Modelと言われる所以となっている。

入力ゲートと出力ゲートはなんのために用意されたか?

RNNでは、入力重み衝突、出力重み衝突という問題が内在していた。

これは、学習過程で新たな入力・出力がきた時に、

  • 前と同じパターンが来た
     →今回のパターンにさらに適合するように重みW1を大きくしてW2を小さくしよう
  • 前と違うパターンが来た
     →新しいパターンに適合するようにW1を小さくしてW2を大きくしよう

という動きが繰り返され、重みWが上下してなかなか精度が上がらないという問題である。

この問題に対処するために、入力ゲート・出力ゲートを用意することで、

  • 前と同じパターンが来た
     →入力ゲートW_{in}は前に来たパターンを通すように適合しているので、そのままそのパターンを通そう
     →そして、今回のパターンにさらに適合するようにW1を大きくしてW2を小さくしよう
  • 前と違うパターンが来た
     →入力ゲートW_{in}は違うパターンを通すような内容になっていないので、通さない
     →変化0なので、W1、W2に変化はない

という動きを実現できる。

ゲートとして通す・通さない仕組みは、重みとしてほぼ0か1への活性化ができるSigmoid関数を利用することで実現している。 Tanh関数の場合0か1ではなく、-1〜1になってしまうためゲートとしての役割を担えない。

下記のサイトで詳しく解説されている。
わかるLSTM ~ 最近の動向と共に - Qiita

Long Short-term Memory

忘却ゲートはなんのために用意されたか?

忘却ゲートがないモデルの場合、大きな状況の変化に対応できないという欠点が存在する。

CECは線形和で過去のすべての入力を重み1で渡しつづけるため、ある時に大きな変化のある入力が来たとしても、相対的にその入力の影響は小さくなり、今まで通りの結果しか出力されなくなってしまう。

この問題に対処するためにSigmoid関数による忘却ゲートを導入し、入力系列のパターンががらりと変わったとき、セルの状態を一気に更新することを実現した。

例えば、現在CECの中身が [0,0,0,10,10,10,0,0,0] であり、今回の入力が [100,100,0,0,0,0,0,100,100] であった場合、忘却ゲートの値は [1,1,0,0,0,0,0,1,1] となり、CECは [0,0,0,0,0,0,0,0,0] になる。つまり過去の長期記憶がきちんと消えている。

図にすると以下のようなイメージ。

f:id:sagantaf:20190604223730p:plain
忘却ゲートの前後

そのほか

入力はtanhによって活性化されているが、ReLUに変更しても対して精度は変わらないことがわかっている。(RNNにReLUを適用するのは効果的)

LSTMモデルに対してドロップアウトを適用する場合は、non-recurrentな接続にのみ適用する必要がある。 つまり入力ゲートなどの再帰的な処理ではない部分に適用することになる。

CECh_{t-1}ドロップアウトを適用した場合、過去のデータをランダムに落としてしまうことになるため、学習がうまくできなくなってしまう。



最後に

今回RNNとLSTMについてまとめてみて、理解するのに時間がかかると感じた。

いまだに研究されている領域なので、何が最適かわかっていない部分も多々あるらしい。

そのため完璧に理論を理解しようとすることは避け、業務で使えるレベルの知識に留めておき、あとは目の前のデータに合う形で試行錯誤を繰り返すことが最短ルートになると思われる。

また、画像データに対する深層学習のアルゴリズムであるConvolutional Neural Network(CNN)のまとめは下記。

sagantaf.hatenablog.com



参考にした書籍やサイト

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

TensorFlowではじめるDeepLearning実装入門 (impress top gear)

TensorFlowではじめるDeepLearning実装入門 (impress top gear)

PythonとKerasによるディープラーニング

PythonとKerasによるディープラーニング

わかるLSTM ~ 最近の動向と共に - Qiita

わかるLSTM ~ 最近の動向と共に - Qiita

再帰型ニューラルネット in 機械学習プロフェッショナルシリーズ輪読会

LSTM (Long short-term memory) 概要

LSTMネットワークの概要 - Qiita

http://isw3.naist.jp/~neubig/student/2015/seitaro-s/161025neuralnet_study_LSTM.pdf

LSTM 〜Long Short-Term Memory〜(Vol.18)

ニューラルネットワークと深層学習

CNN(Convolutional Neural Network)を理解する

この記事の目的

CNNの理論を理解し、Kerasで実装できるようにするために、理論部分をまとめた記事。


0. 通常のニューラルネットワークの問題

通常のニューラルネットワークにある全結合層では2次元以上のデータを1次元(1列のデータ)に並べ替えて入力している。

そのため、すべての数値を同じものと捉えて学習していた。 この場合、2次元以上→1次元、とデータの次元数を落としているので、数値同士の位置情報が無視されてしまい、学習の精度が上がらない。

f:id:sagantaf:20190526144525p:plain
次元を落として入力するため位置情報を学習できない

そのため、データの位置情報を無視することなく、画像だったら画像の形のまま学習できるように、畳み込みニューラルネットワーク Convolutional Neural Network(以下、CNN)が開発された。


1. CNNの基本

基本的には、データの特徴を畳み込み層であぶり出し、プーリング層で他のデータでも使えるようにぼやかすことを繰り返す。

CNNではConvolutional層Pooling層の2つが一般的に使われる。

Convolutional層とPooling層を適用した後、Affine層を通し、結果を出力する。 例えば下記のような形になる。

f:id:sagantaf:20190526144801p:plain
CNNのネットワーク例

また、後述するDropout層、BatchNormalization層といったレイヤーも使われる。


2. 畳み込み層(Convolutional層)

Convolutional層では、入力データにフィルタ(=カーネルとも呼ばれる)を利用して畳み込み演算を行う。

f:id:sagantaf:20190526144951p:plain
畳み込み演算の流れ

上図の緑色の部分を重ね合わせ、乗算し、全て合計して計算する。

入力画像とフィルタが似たような配置だった場合、乗算によってより数値が高くなり、画像の特徴として抽出できる仕組み。様々なフィルタを適用することで、各画像の様々な場所の特徴を捉えたフィルタ群が完成していく。

畳み込みの処理をしていくにあたっては、

  • フィルタのサイズをどうするか
  • どうフィルタを適用していくか(ストライド
  • 出力サイズをどうするか(パディング)

を決めることになる。

フィルタのサイズをどうするか

フィルタのサイズに厳密な決まりごとはないが、奇数かつ小さいサイズの方が精度が出るため、3×3や5×5がよく利用される。

詳しい解説は下記に記載されている。

Deciding optimal filter size for CNNs - Towards Data Science

どうフィルタを適用していくか(ストライド

通常は入力画像に対してフィルタを1つずつずらしながら畳み込み演算を実施するが、ずらす数を設定することもできる。このフィルタを適用する位置の間隔のことをストライドと呼ぶ。

ストライドを1から2や3に増やすことで、大雑把に畳み込み演算することになるため、出力サイズが小さくなり、処理が短時間になる一方で、画像の特徴を取りこぼす可能性がある。そのため畳み込み層ではストライドはあまり使われない。 よっぽどサイズが大きい画像に特徴抽出したい対象が大きく写っている場合は、ストライドを適用しても特徴を失うことなく効率的に処理ができる。

逆に、後述するPooling層ではストライドは積極的に利用される。

出力サイズをどうするか(パディング)

入力データの周りに固定データを合わせることで入力のサイズを大きくし、出力サイズを調整することができる。 これをパディングと呼び、画像のはじの特徴も捉えることができる、出力サイズが小さくなって演算ができなくなることを避けられる、といったメリットがある。 周辺を0で埋める「ゼロパディング」がよく利用されるが、この場合、周辺が暗くなってしまう。それを回避するために、周辺の画素数をそのまま外挿するパディング方法なども存在する。

データ形状の変化

入力時のデータ形状は [縦×横×チャネル数(色の数)] になる。

28×28のサイズのRGB画像であれば、 28 × 28 × 3 になる。

この入力画像に適用するConvolitional層として、
 3×3のフィルタを32枚、ストライド1、パディング1
を設定した場合、畳み込み処理後のデータのサイズは 28 × 28 × 32 となる。

つまり、畳み込み層の出力は、 [縦×横×フィルタ数] となる。

ただし、フィルタサイズ、ストライド、パディングの設定値によっては計算ができない場合もあるため、注意する。

たとrば、10*10の入力画像に対してフィルタが3*3でストライドを3にした場合だと割り切れないため、場合によってはエラーになる(ライブラリによっては自動で可能な部分だけ計算してくれるものもある)。

畳み込みまとめ

畳み込み層は画像の特徴を抽出するためのレイヤーになっている。そのため、畳み込み層を2つ連続で続けるなど、レイヤーを増やすと、1つ目に適用した結果に対して2回目の畳み込みをするため、より小さい特徴を捉えられるようになる。

ネットワークを深くして精度が上がった有名なネットワークもある(AlexNet,VGGなど)。

ただし、深くしすぎると勾配消失問題が起きたり、過学習したりするという別の問題が発生するため、別途対処が必要になる。


3. 活性化関数について

畳み込み後の活性化関数は、勾配消失問題に対応するため ReLU が使われることが多い。

ReLUは正の値をそのまま出力し、マイナスの値は0にしてしまう関数。 畳み込み処理後のデータは特徴が正の大きな値となって現れてくる。そもそもマイナスの値である部分は特徴としてフィルタリングされなかった部分であるため、0にしてしまっても問題ない。


4. プーリング層(Pooling層)

畳み込み層で浮き出てきた特徴をぼやけさせ、他の似たような特徴と同じとみなして学習させることを目的としている。

そうすることで同じものが写った別の画像でも特徴を検知できるようになる。(汎化能力アップ)

同様の理屈で、プーリング層の出力には活性化関数を適用しない。活性化関数を使うと特徴を際立たせることになってしまい、ぼやかした意味がなくなってしまう。

プーリングの手法は、最大プーリングや平均プーリングが代表的。ただし、効果の違いなどまだ不明なことも残されている。

また畳み込み層と同じくストライドを設定して計算することもできる。ぼやかす機能として役に立つため、畳み込み層とは違いストライドを2以上に設定することが多い。


5. CNNの特徴

CNNの特徴は下記2つある。

・局所受容野(local receptive field):
  全結合とは違い、特的のユニット同士のみが結合されるため、局所的な特徴を学習できる。また、データの形状も特徴として捉えることができる。

・重み共有:
  1種類の画像(縦-横-チャネル)に対しては同一の重みとバイアスを共有し適用するため、似た特徴を捉えやすい。どこにあってもきちんと特徴を抽出できるようになる。また、パラメタが減り全結合層よりも計算時間が短縮できる。どちらも学習効率が良くなる効果が得られる。


6. そのほか利用される層

Dropout層

学習に必要なエポック数が増えるが、過学習を抑制できる。

BatchNormalization層

平均0分散1に正規化する層。正規化によって、

  • 学習が早くなる
  • 初期値にあまり依存しない=初期値にロバスト
  • 過学習を抑制する(Dropoutなどの必要性を減らす)

といった利点が生まれる。

また、Dropout層と併用するときには注意する。逆効果になる可能性がある。

参考ページ

Understanding the Disharmony between Dropout and Batch Normalization by Variance Shift · Issue #608 · arXivTimes/arXivTimes · GitHub

このBatchNormalizationは、データ数が多くパラメタが少ないような過学習しにくいモデルの場合は不要。(逆にない時よりも精度が悪くなる可能性がある)


7. CNNの設計

捉えたい特徴を確認し、最初は基本的な形からスタートする。

その後、少しずつ変更してみる。

ネットワークを深くしたり、Augmentationをしたり、Dropout層やBatchNormalization層を追加したり。

下記のような記事を参考に過去の精度の高いネットワークで試すのもあり。

畳み込みニューラルネットワーク(CNN)の設計(一) - Qiita

畳み込みニューラルネットワークの高精度化と高速化


8. CNNの精度向上のために考えること

まずはデータを疑う。データがきちんと整っていないと、どんなにアーキテクチャーやハイパラメタを調整しても精度は上がらない。

入力データの問題

  • 画像サイズは一定か
  • 画像サイズに対して対象が小さすぎないか(小さすぎると特徴が捉えられない)
  • 反射したりして特徴が複雑になっている画像ではないか(パターンが捉えられない=もっと画像が必要になる)

アーキテクチャの問題

  • ぼやかすタイミングがあっているか?畳み込みでstrideしていないか?
  • 過学習していないか?しているのであれば画像の枚数を増やす、Dropoutする
  • 逆に過学習を避けようとしてDropoutやBatchNormalizationをつけすぎていないか(DropoutをConv層はやめてDense層だけにしてみるとか)
  • DropoutとBatchNormalizationを併用していないか
  • レイヤーが少ない方が精度が高くないか?(勾配爆発消失)

上記の問題を考えてみた上で、

  • ネットワークを深くする  畳み込み-ReLU-Pooling のセットを増やしてみる。

  • Augumentationする  画像を回転させたり、拡大させたり、反転させたりして同じ画像を複数枚に増やす。

を実施してみることで精度が上がることもある。


参考にした書籍やサイト

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

直感 Deep Learning ―Python×Kerasでアイデアを形にするレシピ

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

TensorFlowではじめるDeepLearning実装入門 (impress top gear)

TensorFlowではじめるDeepLearning実装入門 (impress top gear)

PythonとKerasによるディープラーニング

PythonとKerasによるディープラーニング

定番のConvolutional Neural Networkをゼロから理解する - DeepAge

畳み込みニューラルネットワークの仕組み | POSTD

たたみ込みの理解 - Qiita

畳み込みニューラルネットワークの仕組み | POSTD



なお、時系列データに対する深層学習のアルゴリズムであるRNNおよびLSTMのまとめは下記にあります。

sagantaf.hatenablog.com