じぶんメモ

プログラミングのメモ、日常のメモとか。

【ゼロから作るDeep Learning】要点まとめ 第6章

6章 - 学習に関するテクニック

勾配法の種類

  • 勾配法の種類はSGD, Momentum, AdaGrad, Adamがある。(AdaGrad,Adamが学習スピードが早い)

重みパラメータと活性化関数での出力値

  • 重みパラメータの初期値は小さくすることで過学習を防げるが、0にすると各層での誤差逆伝播法の出力が均等になってしまうので避けること。
  • 重みパラメータの初期値はランダムである必要がある。
  • 各隠れ層のアクティベーション(活性化関数で出力された値)が、0と1に傾くと勾配損失が発生し、層を深くする意味がなくなってしまう。
  • アクティベーションを分散させるには重みパラメータのスケール(標準偏差)にHeの定数、Xavierの定数を適用させる。
  • 活性化関数が線形(sigmoid, tanh等)の場合はXavierの定数、ReLUの場合はHeの定数が適している。
  • 強制的にアクティベーションの分布を制御するには活性化関数の前にBatch Normalization(正規化)をする。
  • 正規化をしない場合、適切なスケールを設定しないといつまでたってもしっかりと学習されない。
  • 正規化を使用すると重みの初期値にロバストする。(初期値に依存しない)

過学習

  • 特定の訓練データにだけ適応しすぎてしまい、訓練データに含まれないデータにはうまく対応できない状態。
  • 訓練データが少なかったり、パラメータが大量で表現力の高いモデル(隠れ層のノードが多い)場合に発生しやすい。
  • 過学習を避けるためには重みパラメータを抑制するためにWeigt Decay(荷重減衰)または、Dropoutを使用する。
  • Weight Decayは損失関数に対して重みの1.2ノルムを加算する。(ただしハイパーパラメータの設定が必要)
  • Dropoutはニューロンをランダムに消去しながら学習を行う。
  • ハイパーパラメータを適正な値に設定するには検証データを使用する。
  • テストデータをもとにしてハイパーパラメータを設定するのはNG。テストデータのみに適したハイパーパラメータになってしまうため。
  • 検証データを用意する最も簡単な方法は訓練データの20%を分離して使用すること。
  • 最適なハイパーパラメータを求めるには、ハイパーパラメータの範囲を定め、その範囲の中からランダムにサンプリングし、認識精度の評価を行う。それを数回繰り返して最適な値を狭めていく。

【ゼロから作るDeep Learning】要点まとめ 第4章, 第5章

4章 - ニューラルネットワークの精度を高めるためには

損失関数

勾配法

  • 微分  = ある関数でのパラメータの変化の様子
  • 偏微分 = 引数が複数ある関数での1つの引数の微分のことを示す
  • 勾配  = 偏微分をベクトル(一次元配列)で示したもの。勾配が示す方向は、各場所において関数の値を最も減らす方向
  • 損失関数の結果を最小にするには、勾配法(学習率を使って決められたステップ数、重みパラメータの初期値から勾配を引いて更新していく。)を使用する。
  • 上記のような学習を最急降下法SGD)という
  • 勾配法で使用する学習率はハイパーパラメータといい、唯一人間が与える必要があるもの(重みパラメータは勾配法を使用して自動的に更新される想定)

5章 - 誤差逆伝播

順伝播(Affine)で解いた結果から、逆の方向から各隠れ層の微分を求めることで、 重みパラメータの勾配を高速に求めることができる。

誤差逆伝播法を使用するには以下の組み合わせが必要。 - 分類問題では出力層でソフトマックス関数、損失関数に交差エントロピー誤差を使用する。 - 回帰問題では出力層で恒等関数、損失関数に二乗和誤差を使用する。

【ゼロから作るDeep Learning】要点まとめ 第3章ニューラルネットワーク

最近オライリー社から出版されている「ゼロから作るDeep Learning」を読み始めた。
数学の知識がない僕には結構難しかったので、備忘録として要点をまとめていこうと思う。
1,2章に関してはpythonの話や、ANDゲート等の基本情報的な内容が多いので、ここでは省略する。

3章 - ニューラルネットワークについて

Affine空間

  • 入力値xと重みパラメータ、バイアスを使って行列の計算をする。 例)x1, x2、一層目の隠れ層が3つのノードからなるとき。 入力値が2つで出力が3つを求められるので、重みは3×2の配列で必要。
x1w11 + x2w12 + b = a1
x1w21 + x2w22 + b = a2
x1w31 + x2w32 + b = a3

↑のような行列の計算をAffineという。

  • 一層目に出力された値を活性化関数を使って更に計算する(シグモイド関数、RELU)
  • 最終層への出力時は、活性化関数に、恒等関数(回帰問題)、ソフトマックス関数(分類問題)を使用する。

活性化関数

Affineの結果から次のノードに渡すべき値を出力する関数。

  • シグモイド関数
  • RELU(出力の値が0以上ならそのまま値を、0未満なら0を出力する)

出力層の活性化関数

  • ソフトマックス関数: 出力される値の合計が1になるため、確率を求めることができる。分類問題に使用される。基本的にAffineの結果が一番大きい値を使用するので、学習フェーズ以外では使用されない。
  • 恒等関数: 入力された値をそのまま返却する。回帰問題に使用される。

出力層のノードの個数

期待する候補の数だけ必要。 例えば与えられた数値が何なのかを判定する場合は0~9のうちのどれかということになるので、 出力層は10個になる。

バッチ処理

画像のような二次元配列のデータを使う場合に、纏めて複数のデータをニューラルネットワークに投入して結果を得る方法のこと。

例) 10個の画像データ。1データが28 * 28の784ピクセル隠れ層は2つ、それぞれ50, 100のノードを保つ場合。

x  = 100 × 784
w1 = 784 × 50(隠れ層1への重み付け)
w2 = 50  × 100(隠れ層2への重み付け)
w3 = 100 × 10(出力層への重み付け)

railsでポリモーフィック関連でインターフェースっぽく振る舞わせる

railsにもインターフェースはないのかな?と思い調べてみると、
ポリモーフィック関連というものを使うそうです。
例として、Article、Eventという二つのモデルを用意し、
その両方ともにCommentモデルをhas_manyの関係で保持させたいとします。

テーブル定義

  • articlesテーブル
idID
titleタイトル
body本文
created_at作成日時
updated_at更新日時


  • eventsテーブル
idID
titleタイトル
body内容
created_at作成日時
updated_at更新日時


  • commentsテーブル
idID
commentable_id関連元レコードID
commentable_type関連元レコード種別
name発言者名
body内容
created_at作成日時
updated_at更新日時

commentable_id は、どのレコードに対するコメントなのか、
commentable_type は、commentable_idに対してどのテーブルへの関連なのかを示します。

モデル定義

class Article < ApplicationRecord
  has_many :comments, as: :commentable
end
class Event < ApplicationRecord
  has_many :comments, as: :commentable
end
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true, inverse_of: :comments
end

has_manyに as: :commentable とすることで、ポリモーフィック関連でのアソシエーションを生成します。
commentモデル側では belongs_to :commentable, polymorphic: true とすることで、
article、eventのどちらのモデルからも参照される・することを定義しています。

インターフェース部分を別ファイルに切り出すと、以下のような感じ

class Article < ApplicationRecord
  include Commentable
end
class Event < ApplicationRecord
  include Commentable
end
module Commentable
  extend ActiveSupport::Concern

  included do
    has_many :comments, as: :commentable
  end
end
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true, inverse_of: :comments
end

has_manyな関連テーブルのレコードのカラムでソート

チャットとかchat(チャットルーム) has_many chat_messages(チャットのメッセージ)みたいなテーブル構造になると思うが、 この時、チャットルームをメッセージが来た順に並び変えたいとかあると思う。 メッセージの投稿日時がmaxのもので比較してソートする必要があるが、書き方がわからなかったので調べた。

テーブル構造はこんな感じ

chatsテーブル

idID
created_at作成日時
updated_at更新日時

chat_messagesテーブル

idID
chat_idチャットID
message本文
created_at作成日時
updated_at更新日時
select chats.*, max_created_at from chats
left outer join (
  select max(chat_messages.created_at) max_created_at , chat_id
  from chat_messages
  group by chat_id
) cm on chats.id = cm.chat_id
order by max_created_at desc;

Sweet Alertで簡単に綺麗なアラート画面を作る

普通にjavascriptでalert()を使うと味気ないアラートウィンドウしか出ないが、sweet alertを使うと簡単に綺麗なアラート画面を出せる。
jQuery依存でなくプレーンなjavascriptで使用できる。

導入

  • npmでも公式サイトでjsとcssを落とすでもOK。

  • 落としてきたら必要なcssとjsをインクルードしておく。

<link rel="stylesheet" type="text/css" href="dist/sweetalert.css">
<link rel="stylesheet" type="text/css" href="themes/twitter.css">
  • あとはjavascriptでswal()と呼び出すだけで綺麗なアラートが出る。
swal({
  title: "データを消しますか?",
  text: "消されたデータは元に戻すことができません。",
  type: "warning",
  showCancelButton: true,
  confirmButtonColor: "#DD6B55",
  confirmButtonText: "OK",
  cancelButtonText: "キャンセル",
  closeOnConfirm: false
},
function(){
  swal("削除しました!", "データは正常に削除されました。", "success");
});

細かい使い方は公式を参照。

SweetAlert

モーダルのサンプル

なにかとモーダルが使われているサービスが多く、気になったので調べた。
z-indexを使ってモーダルと、モーダルの後ろの画面を隠すためのオーバーレイを前面にするのがポイント。
あとはボタン押下でdisplay: noneを解除してあげればOK。

<html lang="ja">
<head>
  <title>test</title>
  <link href="test.css" rel="stylesheet" type="text/css" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>

<body>
  <!-- モーダルのオープン -->
  <a id="modal-open" class="button-link">クリックするとモーダルウィンドウを開きます。</a>
  <!-- モーダルのボディ -->
  <div id="modal-content">
    <p>「閉じる」か「背景」をクリックするとモーダルウィンドウを終了します。</p>
    <a id="modal-close" class="button-link">閉じる</a>
  </div>
  <!-- モーダルを強調させるためのオーバーレイ -->
  <div id="modal-overlay"></div>
</body>

<script type="text/javascript">
  // モーダル表示
  $("#modal-open").click(
   function(){
      $(this).blur();
      if ($('#modal-overlay').css('display') != 'none') { return; }
      $("#modal-overlay, #modal-content").fadeIn("fast");
      centeringModalSyncer();
   }
  );

  // モーダル非表示
  $("#modal-overlay,#modal-close").unbind().click(function(){
    $("#modal-content,#modal-overlay").fadeOut("fast");
  });

  //センタリングをする関数
  function centeringModalSyncer(){
   var w      = $(window).width();
   var h      = $(window).innerHeight();
   var cw     = $("#modal-content").outerWidth(true);
   var ch     = $("#modal-content").outerHeight(true);
   var pxleft = ((w - cw)/2);
   var pxtop  = ((h - ch)/2);
   $("#modal-content").css({"left": pxleft + "px"});
   $("#modal-content").css({"top": pxtop + "px"});
  }
</script>
</html>
#modal-overlay{
    z-index:1;
    display:none;
    position:fixed;
    top:0;
    left:0;
    width:100%;
    height:120%;
    background-color:rgba(0,0,0,0.3);
}

#modal-content{
  z-index:2;
  display:none;
  position:fixed;
    width:50%;
    margin:1.5em auto 0;
    padding:10px 20px;
    border:2px solid #aaa;
    background:#fff;
}

.button-link{
    color:#00f;
    text-decoration:underline;
}

.button-link:hover{
    cursor:pointer;
    color:#f00;
}

こちらの記事を参考にさせていただきました。

syncer.jp