konchangakita

KPSを一番楽しんでいたブログ 会社の看板を背負いません 転載はご自由にどうぞ

【DeepLearning特訓】CNN を TensorFlow で実装

E資格向けの自習アウトプット
自分用メモ

TensorFlow は、Googleさんが公開している機械学習で便利なライブラリ
現在のところPython では、PyTorch と2大巨頭って感じ?今まで PyTorch 使いなれてきましたが、KPS 的に TensorFlow 使いこなせるようになったほうがよさげなので、この度初挑戦

余談ですが、「テンサー」か「テンソル」かは、Googleの中の人もどっちも使うって言ってた(ようするにどっちでもおk)
なんとなく、ちゃんと学問として線形代数とかやってた人はテンソル派な気がする(なんか頭よさそー)

TensorFlow でモデルを作る下準備

まずは開発環境のバージョンを確認

import sys
import tensorflow as tf
続きを読む

【DeepLearning特訓】CNN 実装のポイント

E資格向けの自習アウトプット
自分用メモ

CNN実装するには、Pythonでの計算する行列のカタチを意識してやるのが重要です
その基本的なテクニックについて
E資格的には numpy での実装方法が聞かれるのかな

画像の読み込みと確認方法

まずは基本中の基本で画像を一枚読み込んで、チャネルごとのイメージを掴んで見る
Pillow で画像の読み込んで、numpy array でチャネルごとの成分を「0」にして RGB の画像を確認する

import matplotlib.pyplot as plt
from PIL import Image
from io import BytesIO
import numpy as np

filename = 'dataset/FF14.jpg'
img = Image.open(filename)
img_array = np.asarray(img)  # (H, W, Ch)

def get_channel(image,channel='r'):
    # イメージをコピー
    new_image = image.copy()
    if channel=='r':
        # 「r」が指定された場合、「g」「b」は0にする
        new_image[:,:,1] = 0
        new_image[:,:,2] = 0
    elif channel=='g':
         # 「g」が指定された場合、「r」「b」は0にする
        new_image[:,:,0] = 0
        new_image[:,:,2] = 0
    elif channel=='b':
         # 「g」が指定された場合、「r」「b」は0にする
        new_image[:,:,0] = 0
        new_image[:,:,1] = 0
    return new_image


print("REDチャンネル")
image_2 = get_channel(img_array,channel='r')
plt.imshow( image_2 )
plt.axis("off")
plt.show()

print("GREENチャンネル")
image_2 = get_channel(img_array,channel='g')
plt.imshow( image_2 )
plt.axis("off")
plt.show()

print("BLUEチャンネル")
image_2 = get_channel(img_array,channel='b')
plt.imshow( image_2 )
plt.axis("off")
plt.show()


f:id:konchangakita:20210115095904p:plain

画像を計算しやすい行列に変換

入力される画像データは4次元(画像枚数 N, チャネル数 Ch, H, W)ではいってきて、カーネル(フィルタ)で局所的な演算をするわけなので、そのまんまでは扱いにくい
f:id:konchangakita:20210114235653p:plain


畳み込み処理(カーネルサイズ、ストライプ数)、プーリングの設定に合わせて、行列を組み直してからカーネルとの計算をおこなうと具合がよい
f:id:konchangakita:20210115005918p:plain
(行 x 列だとの計算しやすい)


Numpy だけで行うとこの実装が結構ややこしくて、確認が何度も必要だったりするので実装が結構大変だが、PyTorch や TensorFlow では簡単に実装できる関数が用意されていたりする

PyTorch は過去にトライしたりもしている
PyTorchを使ったDeep Learningのお勉強 画像認識編(CIFAR-10) - konchangakita

畳み込みを効率よくするには

畳み込みネットワークは特徴量の学習コストが高い

計算コストを減らすための工夫
 ・ランダムなカーネルを利用
 ・層ごとの貪欲事前学習(問題を分割し、要素ごとに最適化)
 ・教師なし学習の利用


さいごに

このあたりは試験対策の為に、考え方が重要なので理解しておく
実装は PyTorch はすでに挑戦したので、TensorFlow での実装をおこなってみようかな

【DeepLearning特訓】CNN入門

E資格向けの自習アウトプット
自分用メモ

CNN(Convolutional Neural Network)は、畳み込みニューラルネットワークと呼ばれる、畳み込みという圧縮に似た(圧縮ではない)処理で入力次元を削減しつつ、特徴量をあぶり出していく手法です
主に画像のクラス分類や物体検出、領域分割(セグメンテーション)などに使われることが多い模様

CNNの概念

画像データは、ちょっとした解像度のデータでも入力データとしては非常に大きい次元になる。チャネル数 x H x W (カラーだとRGB 3チャネル)
ちょっとしたスマホのカメラでも何万画素になるので、各層のパラメータもすごくでかくなりがち
また画像は人間の目からすると、見た目は変わらない1ピクセルずらしたただけでも入力データとしては、全く別物と扱われてしまう
これを改善する処理が 畳み込み(Convolution)プーリング(Pooling)
近い位置の情報も統合して圧縮したりするので、少しの移動にも強い

処理の流れは以下な感じ
f:id:konchangakita:20210113192830p:plain

畳み込み

画像データは3次元(チャネル数 x H x W )の形状であり、空間的に近いピクセルは似たような値であったり、逆にとおいピクセルは同士は関わりが薄かったり、RGBそれぞれは関連性があったりとその形状に特徴がある
畳み込み層は、この3次元の形状は維持しながら、カーネル(フィルタ)を使って特徴量をあぶり出してゆく

やってることは、画像のフィルター処理のようなもの
カーネル(フィルタ)をずらしながら積和演算を繰り返していく
f:id:konchangakita:20210113202414p:plain
重みとバイアスは学習パラメータ

学習パラメータであるカーネル(フィルタ)が共有され使いまわしできるので、メモリの使用量が減る

重要な設定項目

パディング:隅っこのピクセルは使われる回数が少なくなるので、周りゼロ埋めする
f:id:konchangakita:20210113223855p:plain

numpyでは、np.pad を使うだけ

gazo = np.arange(9).reshape(3,3)
np.pad(gazo, 1, 'constant')

===
array([[0, 0, 0, 0, 0],
       [0, 0, 1, 2, 0],
       [0, 3, 4, 5, 0],
       [0, 6, 7, 8, 0],
       [0, 0, 0, 0, 0]])

ストライド:1度のフィルタ計算をどれだけずらすか
f:id:konchangakita:20210114124854p:plain
f:id:konchangakita:20210114124948p:plain

プーリング

局所的な領域から重要は特徴のみを抽出する
学習パラメータを持たず、実装はシンプルだが強力
小さな移動があっても同じ結果を返してくれる

最大値プーリング、カーネル内の最大値を一つ返す
平均値プーリング、カーネル内での平均値を返す
f:id:konchangakita:20210113234753p:plain


まとめ

画像処理は IoT でも需要なので、熱心にお勉強中
試験でもここはパーフェクトしたい
この後は、Python実装のためのお作法をおさえていきます

【DeepLearning特訓】MLPの基礎 バッチ正規化(Batch Normalization)

E資格向けの自習アウトプット
自分用メモ

Batch Normalization(Batch Norm)は、ミニバッチ単位で正規化を行いスケールを揃えること。重みの初期値が適切だと、各層のアクティベーション分布に適切な広がりをもち、学習がスムーズに行える 
Batch Norm は、各層のアクティベーション分布を適度な広がりを持つように調整することにある
Batch Norm のレイヤをアフィン変換と活性化関数の間に挿入する

【Batch Norm のメリット】
・学習を速く進行させることができる
・初期値にそれほど依存しない
過学習を抑制する

f:id:konchangakita:20210110183724p:plain

Batch Normalization のアルゴリズム

ミニバッチの単位で正規化する
1.入力 x の平均をとる
f:id:konchangakita:20210110175635p:plain

2.分散をもとめ
f:id:konchangakita:20210110175659p:plain

3.正規化する
f:id:konchangakita:20210110180615p:plain

Batch Norm を計算グラフであらわすと

こんな感じでよいのだろうか
f:id:konchangakita:20210111154320p:plain

まとめ

一旦 MLPの基礎としてはここまで
これからは画像認識や自然言語処理強化学習など、いよいよディープラーニングの本番に突入

【DeepLearning特訓】MLPの基礎 学習のいろいろな工夫

E資格向けの自習アウトプット
自分用メモ

学習の工夫して、汎化性能をあげつつ学習速度の向上、計算リソースの削減をしたり対策していく
取り組む問題によって、組み合わせてみたり

パラメータ拘束とパラメータ共有

パラメータ拘束

パラメータの適切な値がわからない場合は、近いモデルを参考にすると良いのでは、という考え方
互いのパラメータの近さを表現する手法
L2正則化(重み減衰)で、0から遠ざかることに対してペナルティをかける

例として、タスクが似ている2つのモデルA, Bは、パラメータも近いと想定できる
下記をノルムペナルティとする
f:id:konchangakita:20210110002857p:plain
(L2ノルム以外でも可能)
この値に上限を設けて、互いにパラメータ拘束する

パラメータ共有

複数のモデルである部分のパラメータを同じにする
メモリの節約にもなる
CNNのフィルタが典型的な例

アンサンブル学習

複数のモデル(弱学習器)で個々に学習させる

バギング(bootstrap aggregation)

複数モデルを組み合わせ汎化誤差を減少させる
有名どころ:ランダムフォレスト
f:id:konchangakita:20210110013235p:plain

ブースティング

確率分布に基づいて分割、逐次計算していく
f:id:konchangakita:20210110013309p:plain

ドロップアウトとドロップコネクト

ドロップアウト

中間層での出力をランダムで削除(0にする)する。削除する割合はハイパーパラメータとして設定
計算量が少なく、非常に実用性が高い
訓練データが少なすぎるとダメ

# ドロップアウト
# まずはマスクを作る
ratio = 0.2 # 20% 削除
x = np.random.randn(3,10)
randammatrix = np.random.rand(*x.shape)
mask = randammatrix > ratio

# 出力を0にする
x = x * mask

# 勾配は同じマスクする
dout = dout * mask
ドロップコネクト

中間層の重みをランダムに0、性能面ではドロップアウトより優れているが、乱数の値で同じ性能を出す難しいので、実用的でない

その他の工夫

ノイズの注入
スパース表現:ベクトルの多くを0にする
 ・L1正則化:重みをスパース
 ・ReLU:表現をスパース
教師あり学習
 ・最初の段階では教師あり学習、そのあと教師なし学習に移行
マルチタスク学習
 ・タスクの類似性を活かしながら、全タスクを同時に解く。
蒸留
 ・教師モデルの入出力を用いて、軽量な生徒モデルで学習
 ・精度は落ちるが、計算リソースの削減
早期終了
プルーニング
 ・貢献度の低い重みを枝切り

まとめ

実用性的には、ドロップアウトが多いのかな
実際のところはいろんなフレームワークに組み込まれていたりするので、関数呼び出すだけで使えることが多い
ここは試験対策用に用語まとめ的な意味合い
次は、正規化(正則化は前回やった)

【DeepLearning特訓】MLPの基礎 正則化

E資格向けの自習アウトプット
自分用メモ

正則化は、過学習(学習データに特化しすぎる)を防ぎ、汎化性能と予測
精度の向上を両立させる処理
正則化と正規化はこんがらがりがち)

バイアスとバリアンス

バイアスとバリアンスは推定量の誤差を生じる2つの発生源を測定するもの
バイアス:関数やパラメータの真の値からの期待偏差(予測値の平均誤差)
バリアンス:データのサンプル化の方法に起因する期待推定値からの偏差(入力データのとり方による予測のばらつき)
(何言ってるかわからない)

バイアス 大、バリアンス 小 ➔ 正解率が低い
バイアス 小、バリアンス 大 ➔ 正解率が高いが、学習データに過学習している
トレードオフな関係ぽい)

回帰問題における平均二乗誤差をバイアス・バリアンス分解
f:id:konchangakita:20210109183358p:plain


バリアンスが大きく過学習している状態で、予測をできるだけブレないようにするのが正則化
バリアンスを小さくするには、モデルの複雑さに制限をかける

ちょっとかじったくらいでは、この式の成り立ちを理解するのはむずかしかったので、丸暗記にしておこう。。。

パラメータノルムペナルティ

正則化の代表的なアプローチのひとつ
目的関数 𝐽(𝜃;𝑋,𝑦) に対しノルムペナルティ Ω(𝜃) を追加する
f:id:konchangakita:20210109211713p:plain

重みのパラメータのノルムで正則化を行う
ノルムペナルティを種類

Lpノルム

f:id:konchangakita:20210109211754p:plain

L1ノルム(マンハッタン距離)

f:id:konchangakita:20210109211830p:plain

L2ノルム(ユークリッド距離):重み減衰(weight decay)

f:id:konchangakita:20210109211902p:plain

重みパラメータのL2ノルムを正則化項として加えると、重みが全体的に小さくなる方向に進んでいく、これを 重み減衰 という
f:id:konchangakita:20210109230359p:plain

これはちょっと手を加えるだけで組み込めそう

# 重み減衰
weight_decay_lambda = 0.1 # 重み減衰の係数
w1, w2, w3 = np.random.randn(3) #適当に
loss = 1 # 適当に

def lp_norm(w, p=2):
    return np.sum(np.abs(w)**p)**(1/p)

# loss に重みL2ノルムを加える
for w in (w1, w2, w3):
    loss += 0.5 * weight_decay_lambda * (lp_norm(w)**2)

# 勾配計算の時
dw1 += weight_decay_lambda * w1
dw2 += weight_decay_lambda * w2
dw3 += weight_decay_lambda * w3


【L1とL2の覚え方】
f:id:konchangakita:20210109215300p:plain

回帰と正則化項の組み合わせ

Lasso回帰:L1ノルムペナルティ
Ridge回帰:L2ノルムペナルティ
Elastic Net:L1とL2の両方用いる

まとめ

正則化(正規化と間違えがち)以外の方法にもいろいろと工夫ができるので
次回に、学習途中にノイズを入れる方法や、パラメータを拘束、アンサンブル学習やブースティングなど

【DeepLearning特訓】MLPの基礎 学習アルゴリズムの Python実装

E資格向けの自習アウトプット
自分用メモ

学習アルゴリズムを、実装してみて実際の学習の推移を確認してみたいと思います
今回は Python のクラスをちゃんと用いて学習モデルを作っていきます
一気に本格的な感じに

まず挑む問題ですが、過去にも Pytorch でも取り組んだ基本中の基本の MNIST のデータセットを使います
PyTorchを使ってDeep Learningのお勉強 画像認識編(MNIST) - konchangakita

こんなふうな数字の画像と 正解ラベル「4」がセットになっています
f:id:konchangakita:20210109144758p:plain

画像データセットの読み込み

MNIST データセットを読み込み
正解ラベルを One-Hot-Vector に変換します

import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

#乱数シード指定
np.random.seed(seed=0)

# MNIST画像データ読み込み 
from sklearn.datasets import fetch_openml
mnist = fetch_openml(name='mnist_784', version=1)

# 画像とラベルを取得
X, T = mnist.data, mnist.target
# 訓練データとテストデータに分割
x_train, x_test, t_train, t_test = train_test_split(X, T, test_size=0.2)

# ラベルデータをint型にし、one-hot-vectorに変換
t_train = np.eye(10)[t_train.astype("int")]
t_test = np.eye(10)[t_test.astype("int")]

# Dataframe を numpy に変換
x_train = np.array(x_train.values)
x_test = np.array(x_test.values)

print('訓練データ(数, サイズ) \t', x_train.shape)
続きを読む