ディープラーニング勉強記録②
ディープラーニング備忘録②
はじめに
2日目では,1日目に学んだ分類問題,loss,勾配,MLP,1D-CNNの基礎を踏まえて,より実験・学習設計に近い内容を扱った.
主なテーマは,過学習,汎化,正則化,Adam,Data Augmentation,bias-variance tradeoff,Batch Normalization,Layer Normalizationである.
大きく言うと,2日目の内容は次の問いに対応している.
モデルを作るだけではなく,
どうすれば未知データに対して安定して性能を出せるのか
1.1日目の軽い復習
1日目では,分類問題における基本的な学習の流れを確認した.
入力
↓
モデル
↓
logits
↓
softmax
↓
確率
↓
交差エントロピー
↓
loss
↓
逆伝播
↓
パラメータ更新
ニューラルネットワークは,最終層でsoftmax前の生スコアであるlogitsを出力する.
softmaxはlogitsを確率分布の形に変換する.
交差エントロピーは,予測確率と正解ラベルのずれを測る損失関数である.
one-hotラベルの場合,lossの値そのものは正解クラスの確率だけから決まる.
ただし,softmaxの分母には全クラスのlogitが入るため,不正解クラスのlogitにも勾配が流れる.
softmaxと交差エントロピーを組み合わせたとき,logitに対する勾配は次のようになる.
これは,予測確率と正解ラベルの差がそのまま誤差信号になる,という意味である.
2.機械学習の目的は汎化である
機械学習の目的は,訓練データを丸暗記することではない.
本当の目的は,まだ見たことのない未知データに対して正しく予測することである.
この性質を 汎化 と呼ぶ.
訓練データで当たる
↓
それだけでは不十分
未知データでも当たる
↓
これが重要
したがって,学習では訓練データに対する性能だけでなく,validation dataやtest dataに対する性能を見る必要がある.
3.train / validation / test
機械学習では,データを主に3種類に分ける.
train data:モデルのパラメータ更新に使う
validation data:学習中の性能確認やハイパーパラメータ調整に使う
test data:最終評価に使う
train data
train dataは,モデルを学習するために使うデータである.
loss.backward() と optimizer.step() に直接関係する.
validation data
validation dataは,学習中に未知データへの性能を確認するために使う.
基本的に,validation dataではパラメータ更新を行わない.
test data
test dataは,最終的な性能評価に使う.
本来,test dataは最後までなるべく触らないのが理想である.
4.訓練誤差と汎化誤差
訓練データに対する誤差を 訓練誤差 と呼ぶ.
training loss
training error
未知データに対する誤差を 汎化誤差 と呼ぶ.
validation lossやtest lossは,汎化誤差を推定するために使われる.
理想は次の状態である.
train loss が低い
validation loss も低い
このとき,モデルは訓練データにも未知データにもよく対応できていると考えられる.
5.過学習
過学習 とは,訓練データにはよく合うが,未知データには弱い状態である.
英語では overfitting と言う.
典型的には,学習が進むにつれて次のような挙動になる.
train loss は下がり続ける
validation loss は途中から上がる
これは,モデルが訓練データの本質的なパターンだけでなく,訓練データ特有のノイズや偶然の特徴まで覚えてしまっている状態である.
過学習したモデルは,訓練データには非常に強いが,未知データでは性能が落ちやすい.
6.未学習
未学習 とは,モデルが十分に学習できていない状態である.
英語では underfitting と言う.
未学習では,典型的に次のようになる.
train loss が高い
validation loss も高い
これは,モデルの表現力が足りない,学習が足りない,特徴量が不十分,最適化がうまくいっていない,などの理由で起こる.
7.典型的なlossの見方
学習状態は,train lossとvalidation lossの関係からある程度判断できる.
良い学習
train loss が下がる
validation loss も下がる
訓練データにも未知データにも対応できている.
未学習
train loss が高い
validation loss も高い
モデルが十分に学習できていない.
過学習
train loss は下がり続ける
validation loss は途中から上がる
訓練データに合わせすぎている.
この見方は,実験ログや論文の結果を読むときにも重要である.
8.過学習が起きる理由
過学習が起きる主な理由は次の通りである.
モデルが大きすぎる
訓練データが少ない
ノイズが多い
学習しすぎている
正則化が弱い
データ分布が偏っている
深層学習モデルは表現力が高いため,データが少ない場合やノイズが多い場合には,訓練データに過剰に適合しやすい.
9.正則化
正則化 とは,過学習を防ぐために,モデルが複雑になりすぎないように制約を加える方法である.
英語では regularization と言う.
直感的には,モデルに対して次のような圧力をかける.
訓練データに合わせすぎるな
もっとシンプルに説明しろ
代表的な正則化には次のものがある.
weight decay
Dropout
Early Stopping
Data Augmentation
Batch Normalization
ただし,Batch Normalizationは正則化だけでなく,学習の安定化としての意味も大きい.
10.weight decay
weight decayは,重みが大きくなりすぎることを防ぐ正則化である.
L2正則化と深く関係する.
通常のlossを とすると,weight decayでは重みの大きさに対する罰則を加える.
ここで,
- は通常のデータに対するloss
- は重み
- は正則化の強さ
- は重みの二乗和
である.
重みが大きすぎると,入力の小さな変化に対して出力が大きく変わりやすくなる.
weight decayは,重みを小さめに保つことで,よりなめらかで極端すぎない関数を学習しやすくする.
PyTorchではoptimizerに weight_decay を指定できる.
optimizer = torch.optim.Adam(
model.parameters(),
lr=1e-3,
weight_decay=1e-4
)
ただし,Adamにおける weight_decay と純粋なL2正則化は厳密には少し違う場合がある.
実務では,AdamWがよく使われる.
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-3,
weight_decay=1e-4
)
11.Adam
Adamは,勾配降下法を賢くしたoptimizerである.
正式には Adaptive Moment Estimation の略である.
通常のSGDは,現在の勾配を使ってパラメータを更新する.
一方,Adamは各パラメータごとに,
最近の勾配の平均
最近の勾配の二乗平均
を持ち,更新量を自動的に調整する.
Adamの直感
SGD,Momentum,Adamのイメージは次の通りである.
SGD:
今の勾配だけを見て進む
Momentum:
最近の進行方向も考えて進む
Adam:
最近の進行方向に加えて,
勾配の大きさのばらつきも見て,
パラメータごとに歩幅を調整する
Adamの式
時刻 の勾配を とする.
Adamはまず,勾配の移動平均を持つ.
これは,勾配の平均的な方向を表す.
Momentumに近い役割を持つ.
次に,勾配の二乗の移動平均を持つ.
これは,勾配の大きさの平均のようなものを表す.
ざっくり書くと,Adamは次のように更新する.
ここで, は0除算を防ぐための小さい値である.
つまりAdamは,
よく大きな勾配が出るパラメータは歩幅を抑える
勾配が小さめのパラメータは相対的に歩幅を大きくする
という調整を行う.
Adamの利点と注意点
Adamの利点は次の通りである.
学習が比較的安定しやすい
学習率に少し鈍感
スパースな勾配にも強い
最初に試しやすい
ただし,Adamが常に最強というわけではない.
タスクによっては,SGD + Momentumの方が最終的な汎化性能が良い場合もある.
weight decayを使う場合は,AdamよりAdamWが使われることも多い.
実用上の感覚としては,
基礎理解としてはSGD
最初に試すoptimizerとしてはAdamまたはAdamW
でよい.
12.Dropout
Dropoutは,学習中に一部のニューロンをランダムに無効化する方法である.
例えば,隠れ層の出力が次のようだったとする.
h = [0.2, 1.5, 0.7, 3.0]
Dropoutを適用すると,学習中だけランダムに一部を0にする.
h = [0.2, 0.0, 0.7, 0.0]
のようなイメージである.
Dropoutは,モデルが特定のニューロンに依存しすぎることを防ぐ.
毎回一部のニューロンが使えなくなる
↓
どのニューロンが欠けてもそこそこ予測できるように学習する
↓
より頑健な表現になる
PyTorchでは次のように使う.
self.dropout = nn.Dropout(p=0.5)
p=0.5 は,各要素を50%の確率で0にするという意味である.
Dropoutとtrain / eval
Dropoutは,学習時と評価時で挙動が異なる.
model.train():Dropoutが有効
model.eval():Dropoutが無効
評価時にランダムにニューロンを消すと,出力が不安定になるため,推論時にはDropoutを無効にする.
そのため,Dropoutを使うモデルでは,評価時に model.eval() を忘れないことが重要である.
13.Early Stopping
Early Stoppingは,validation lossが悪化し始めたら学習を止める方法である.
典型的には,
train loss は下がり続ける
validation loss は途中から上がり始める
という状況で使う.
validation lossが最も良かった時点のモデルを保存し,それ以降改善しなくなったら学習を終了する.
Early Stoppingは,
未知データへの性能が一番良かったところで止める
という考え方であり,非常に実用的な正則化である.
14.Data Augmentation
Data Augmentationは,訓練データに変換を加えて,データ数を実質的に増やす方法である.
画像なら,
少し回転する
少し平行移動する
左右反転する
明るさを変える
ノイズを加える
などがある.
時系列データなら,
ノイズを加える
少し時間方向にずらす
一部をマスクする
振幅を少し変える
時間方向に伸縮する
などが考えられる.
Data Augmentationの本質
Data Augmentationで最も重要なのは,
ラベルを維持できる変形だけが有効
という点である.
例えば,猫画像分類で,画像を少し平行移動しても猫であることは変わらない.
そのため,この変形はラベルを維持する.
一方,手書き数字の 6 を上下反転すると 9 になる可能性がある.
このような変形はラベルを壊すため,危険である.
Data Augmentationは,データの種類やタスクに強く依存する.
何でも増やせばよいのではなく,
そのタスクで不変であってほしい変化を入れる
という考え方が重要である.
15.bias-variance tradeoff
bias-variance tradeoff は,モデルの誤差を考える上で重要な概念である.
biasが高い状態
biasが高いとは,モデルが単純すぎて,本来の関係を表現できていない状態である.
未学習に近い.
典型的には,
train loss が高い
validation loss も高い
となる.
varianceが高い状態
varianceが高いとは,訓練データの違いにモデルが敏感すぎる状態である.
過学習に近い.
典型的には,
train loss は低い
validation loss は高い
となる.
biasとvarianceは必ずトレードオフなのか
教科書的には,モデルの複雑さを変えると,biasとvarianceはトレードオフとして説明される.
単純なモデル:
bias 高い,variance 低い
複雑なモデル:
bias 低い,variance 高い
しかし,現実の学習では,biasとvarianceが同時に高くなることもある.
例えば,
モデル構造がタスクに合っていない
データが少なすぎる
ラベルノイズが多い
特徴量が不十分
最適化がうまくいっていない
学習率が悪くて収束していない
train/testの分布が大きく違う
といった場合である.
この場合,モデルは本質的な関係を捉えられていないためbiasが高く,さらにデータや学習の不安定さに敏感なためvarianceも高い,という状態になり得る.
したがって,
理想化された説明ではbiasとvarianceはトレードオフ
現実の学習では両方高くなることもある
と理解しておくのがよい.
16.正規化
正規化とは,中間特徴のスケールを整えることで,学習を安定させる方法である.
ニューラルネットワークでは,学習中に各層の出力分布が変化する.
ある層の出力が急に大きくなったり小さくなったりすると,次の層の学習が不安定になる.
そこで,平均や分散を整えることで,特徴のスケールを扱いやすくする.
標準化の基本形は次の通りである.
ここで,
- は平均
- は分散
- は0除算を防ぐための小さい値
である.
この操作により,平均がだいたい0,分散がだいたい1になるように整える.
17.Batch Normalization
Batch Normalization,略してBatchNormは,mini-batch内の統計量を使って正規化する方法である.
batch内の平均を,
batch内の分散を,
とする.
このとき,BatchNormでは,
と正規化する.
ただし,正規化だけを行うと,出力が常に平均0,分散1に近い形に固定されてしまう.
そこで,学習可能なパラメータ と を使って,スケールとシフトを調整できるようにする.
つまりBatchNormは,
平均と分散を整える
その後,学習可能なscaleとshiftで調整する
という処理である.
BatchNormの効果
BatchNormには次のような効果がある.
学習が安定しやすい
勾配が流れやすくなる
学習率を少し大きくしやすい
初期値への依存が減る
軽い正則化効果がある
BatchNormは主に学習を安定させるための手法であるが,batchごとの統計量を使うため,結果として軽い正則化効果を持つことがある.
BatchNormとtrain / eval
BatchNormでは,学習時と評価時で挙動が異なる.
学習時
学習時は,現在のmini-batchの平均と分散を使う.
model.train()
→ batch内の平均・分散を使う
評価時
評価時は,batch内の平均と分散を使わない.
代わりに,学習中に蓄積したrunning meanとrunning varianceを使う.
model.eval()
→ 学習中に記録した移動平均・移動分散を使う
推論時にはbatch sizeが1の場合もあり,その場合batch内の分散をまともに計算できない.
そのため,評価時には学習中に蓄積した統計量を使う.
PyTorchでのBatchNorm
MLPのように,特徴ベクトルが [batch, features] の場合は,
nn.BatchNorm1d(num_features)
を使う.
例えば,特徴次元が128なら,
self.bn = nn.BatchNorm1d(128)
である.
class MLPWithBN(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(700, 128)
self.bn1 = nn.BatchNorm1d(128)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(128, 256)
def forward(self, x):
x = self.fc1(x) # [batch, 128]
x = self.bn1(x) # [batch, 128]
x = self.relu(x) # [batch, 128]
x = self.fc2(x) # [batch, 256]
return x
典型的には,
Linear / Conv
↓
BatchNorm
↓
Activation
の順で使うことが多い.
Conv1dの出力は,
[batch, channels, length]
である.
例えば,
[64, 16, 700]
なら,16チャネルの特徴マップがある.
この場合は,
nn.BatchNorm1d(16)
を使う.
18.Layer Normalization
Layer Normalization,略してLayerNormは,1つのサンプル内の特徴方向で正規化する方法である.
BatchNormはbatch方向を使って統計量を計算する.
一方,LayerNormはbatch方向を使わない.
例えば,1サンプルの特徴ベクトルが,
h = [h_1, h_2, ..., h_d]
だとする.
LayerNormでは,この1サンプル内の特徴全体について平均と分散を計算する.
そして,
とする.
その後,BatchNormと同様に,
を行う.
BatchNormとLayerNormの違い
一番大事なのは,どの方向で平均・分散を取るかである.
| 項目 | BatchNorm | LayerNorm |
|---|---|---|
| 統計量を取る方向 | batch方向 | feature方向 |
| batch sizeの影響 | 受ける | ほぼ受けない |
| train/evalの挙動 | 異なる | 基本的に同じ |
| よく使われる場所 | CNN | Transformer,RNN |
| running mean/var | 使う | 基本使わない |
BatchNormは,
他のサンプルと比べて,この特徴は大きいか小さいか
を見る.
LayerNormは,
このサンプル自身の中で,特徴のスケールを整える
と考えるとよい.
TransformerとLayerNorm
TransformerではLayerNormがよく使われる.
理由は,LayerNormがbatch sizeに依存しないためである.
Transformerでは,batch sizeや系列長が変わることがある.
また,系列データではbatch内の他のサンプルと比べるより,各サンプルや各トークン内部の特徴を安定させたいことが多い.
そのため,TransformerではBatchNormよりLayerNormがよく使われる.
Transformerブロックでは,次のような構造がよく出る.
入力
↓
Self-Attention
↓
Residual Connection
↓
LayerNorm
↓
Feed Forward
↓
Residual Connection
↓
LayerNorm
また,最近の実装ではLayerNormを先に置くPre-LN構造もよく使われる.
LayerNorm
↓
Self-Attention
↓
Residual
↓
LayerNorm
↓
Feed Forward
↓
Residual
このあたりはTransformerを学ぶときに再度詳しく扱う.
PyTorchでのLayerNorm
PyTorchでは,
nn.LayerNorm(normalized_shape)
を使う.
例えば,特徴次元が128なら,
self.ln = nn.LayerNorm(128)
である.
class MLPWithLN(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(700, 128)
self.ln1 = nn.LayerNorm(128)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(128, 256)
def forward(self, x):
x = self.fc1(x) # [batch, 128]
x = self.ln1(x) # [batch, 128]
x = self.relu(x) # [batch, 128]
x = self.fc2(x) # [batch, 256]
return x
LayerNorm(128) は,各サンプルごとに128次元の特徴ベクトルを正規化する.
19.BatchNormとDropoutの違い
BatchNormとDropoutはどちらも汎化や学習安定化に関係するが,役割は異なる.
BatchNorm:
中間特徴のスケールを整えて学習を安定させる
Dropout:
一部のニューロンをランダムに消して依存を減らす
BatchNormは主に最適化を助ける.
Dropoutは主に過学習を抑える正則化として働く.
ただし,BatchNormにも軽い正則化効果があり,Dropoutも学習挙動に影響する.
完全に役割が分離しているわけではない.
20.学習時と評価時の基本形
DropoutやBatchNormを使う場合,学習時と評価時でモードを切り替える必要がある.
学習時
model.train()
for x, target in train_loader:
optimizer.zero_grad()
logits = model(x)
loss = criterion(logits, target)
loss.backward()
optimizer.step()
評価時
model.eval()
with torch.no_grad():
for x, target in val_loader:
logits = model(x)
loss = criterion(logits, target)
評価時には with torch.no_grad(): を使う.
これは勾配計算を無効にするためである.
評価ではパラメータ更新を行わないため,勾配を計算する必要がない.
これにより,メモリ使用量が減り,計算も軽くなる.
2日目の重要まとめ
2日目の内容をまとめると,次の通りである.
機械学習の目的は訓練データを覚えることではなく,未知データに汎化することである
過学習は,訓練データには合うが未知データに弱い状態である
未学習は,訓練データにも十分に合っていない状態である
train lossとvalidation lossの差を見ると,学習状態を判断しやすい
正則化は,過学習を防ぐための工夫である
weight decayは,重みが大きくなりすぎることを抑える
Adamは,勾配の平均と二乗平均を使って,パラメータごとに更新量を調整するoptimizerである
Dropoutは,学習中に一部のニューロンをランダムに無効化する
Early Stoppingは,validation性能が悪化する前に学習を止める方法である
Data Augmentationは,ラベルを維持できる変形だけが有効である
biasとvarianceは典型的にはトレードオフだが,現実には同時に高くなることもある
BatchNormはbatch方向の統計量を使って正規化する
LayerNormは1サンプル内のfeature方向で正規化する
BatchNormはCNNでよく使われる
LayerNormはTransformerでよく使われる
BatchNormとDropoutを使う場合は,model.train() と model.eval() の切り替えが重要である
現在の進捗メモ
2日目終了時点で,機械学習・深層学習の土台は次の段階まで進んだ.
分類問題の基本
softmaxと交差エントロピー
勾配降下法と逆伝播
MLPのshape
1D-CNNの基本
過学習と汎化
正則化
optimizerの基礎
BatchNormとLayerNorm
次に進む候補は,次の通りである.
1.1D-CNNをもう少し深掘りする
2.CNNの複数層構造,受容野,Global Average Poolingを学ぶ
3.RNN / LSTM / GRUへ進む
4.Transformerへ入る前に,系列データの扱いを整理する
5.Attentionの基礎に進む
今後Transformerを理解するためには,LayerNorm,Residual Connection,Feed Forward Network,Attentionの理解が重要になる.