WHAT'S UP?

New post every sometimes. Here's OKKAH NET.

日立製作所 研究開発インターンに参加してきた

8/22-9/11の3週間、日立製作所 研究開発グループのIoT向け画像計測・認識アルゴリズムの開発コースのインターンシップに参加してきました。


選考フロー
「書類選考 → Webテスト(玉手箱) → 面接」という流れでした。

書類選考は、研究職だということもあり大学での研究内容について書く量がかなり多い印象がありましたが、それ以外は比較的普通でした。
面接は担当部署の課長さんと一対一で、穏やかな雰囲気ではありつつも、研究については非常に細かいところまで聞かれるといった感じでした。

基本的には大学での研究を通じて得た技術力、主体性、問題解決能力、コミュニケーション能力等を見られていると感じましたが、最終的にはインターンの業務をしっかりとやり遂げられるのかどうかを面接官が直感的に判断しているのだと感じました。


インターンシップの内容
AI活用欠陥画像自動分類技術の研究に取り組みました。

具体的には、新規欠陥画像で既存欠陥のモデルに追加学習をしたとき既存欠陥の分類性能が以前よりも劣ってしまうという問題に対して、新規欠陥画像のみでモデルを学習し既存欠陥の性能を保持できる手法を提案し、既存手法との比較を行いました。

まずは英語の論文から必要な技術やアルゴリズムを学び、環境構築、提案手法の実装・検証、成果報告会の準備・発表といった流れでした。
途中、全インターン生合同で行うアイデアソン、社内施設・他部署見学、社員さんや他の部署のインターン生との飲み会などもありました。


インターンシップを終えて
提案手法独自の損失関数について、英語の論文のみから詳細を理解してコードを実装することが大変でした。

オブジェクトの扱い方が分からず何度もエラーになったり、逆伝搬を求める際の複雑な微分計算に手こずったり、実際にコードが動くようになっても限られた時間で学習を終わらせるために更なる工夫が必要であったりと何度も挫けそうになりました。

こういった課題に対して、まずは紙とペンで与えられた状況を明確化し、ある程度の当たりをつけてからコードの読み込みや検索を行い、粘り強くトライ&エラーを繰り返しました。
また場合によっては社員の方々や他のインターンシップ生から必要な情報を獲得することで解決できたこともありました。
最終的には良い結果を得られ、非常に大きな達成感を味わえたので良かったです。

今回のインターンシップを通じて、仮説を立て、検証し、正誤を判定するという研究の基本姿勢を学ぶことができました。
また、モデル定義やデータ読み込み、Fine-tuningの復習から始まり、オブジェクトの扱い方や独自の損失関数の定義、パラメータチューニング等を学び、プログラミングのスキルアップができました。

Python+OpenCVでラベリング

Python+OpenCVを利用したラベリングについてです。
Pythonのバージョンは3.6.4、OpenCVのバージョンは3.4.1です。


ラベリングとは
二値化画像の白(または黒)の部分において、連続した画素に同じ番号を割り振る処理をラベリングと言います。
通常、同じ番号ごとの幅、高さ、面積(画素数)、重心などの特徴量を求め、オブジェクトの分類や欠陥検査などに利用します。

ラベリングの詳しい説明はこちら。
ラベリング処理アルゴリズム 画像処理ソリューション


OpenCVのラベリング関数
OpenCVのラベリング関数は2種類あります。

・簡易版
ラべリング画像のみを出力する簡易版です。

# ラベリング(簡易版)
nLabels, labelImages = cv2.connectedComponents(image_src)

・nLabels: ラベル数(ただし背景のラベル0もカウントされているため、オブジェクトの数はnLabels - 1)
・labelImages: ラベル番号が入った配列データ(座標 (x, y) のラベル番号は、labelImages[x, y] で参照できる)
・image_src: 二値画像の入力配列


・詳細版
簡易版に加えて、オブジェクトの外接矩形の情報(x, y, width, height)、面積、重心座標も出力する詳細版です。

# ラベリング(詳細版)
nLabels, labelImages, data, center = cv2.connectedComponentsWithStats(image_src)

・nLabels: ラベル数(ただし背景のラベル0もカウントされているため、オブジェクトの数はnLabels - 1)
・labelImages: ラベル番号が入った配列データ(座標 (x, y) のラベル番号は、labelImages[x, y] で参照できる)
・data: オブジェクトの詳細の配列データ(x, y, w, h, size = data[ラベル番号] で参照できる。w: width, h: height, size: 面積)
・center: オブジェクトの重心座標 (x, y) (浮動小数点数)
・image_src: 二値画像の入力配列


実際にラベリングしてみる
入力画像
f:id:okkah:20180802161057j:plain


・簡易版

import cv2
import numpy as np
import random
import sys

# 画像の読み込み
img = cv2.imread('sample.jpg')

# グレースケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 大津の二値化
gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

# 白黒反転
gray = cv2.bitwise_not(gray)

# ラベリング処理(簡易版)
n, label = cv2.connectedComponents(gray)

# ラベリング結果書き出し準備
color_src = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
height, width = gray.shape[:2]
colors = []

for i in range(1, n + 1):
    colors.append(np.array([random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)]))

# ラベリング結果を表示
# 各オブジェクトをランダム色でペイント
for y in range(0, height):
    for x in range(0, width):
        if label[y, x] > 0:
            color_src[y, x] = colors[label[y, x]]
        else:
            color_src[y, x] = [0, 0, 0]

# オブジェクトの総数を黄文字で表示
cv2.putText(color_src, str(n - 1), (70, 70), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255))

# 画像の保存
cv2.imwrite('sample_label1.jpg', color_src)


二値化画像
f:id:okkah:20180802161131j:plain

ラベリング画像(簡易版)
f:id:okkah:20180802161312j:plain


・詳細版

import cv2
import numpy as np
import sys

# 画像の読み込み
img = cv2.imread('sample.jpg')

# グレースケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 大津の二値化
gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

# 白黒反転
gray = cv2.bitwise_not(gray)

# ラベリング処理(詳細版)
label = cv2.connectedComponentsWithStats(gray)

# オブジェクト情報を項目別に抽出
n = label[0] - 1
data = np.delete(label[2], 0, 0)
center = np.delete(label[3], 0, 0)

# ラベリング結果書き出し用に二値画像をカラー変換
color_src = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)

# オブジェクト情報を利用してラベリング結果を表示
for i in range(n):
    # 各オブジェクトの外接矩形を赤枠で表示
    x0 = data[i][0]
    y0 = data[i][1]
    x1 = data[i][0] + data[i][2]
    y1 = data[i][1] + data[i][3]
    cv2.rectangle(color_src, (x0, y0), (x1, y1), (0, 0, 255))

    # 各オブジェクトのラベル番号と面積に黄文字で表示
    cv2.putText(color_src, "ID: " +str(i + 1), (x0, y1 + 15), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255))
    cv2.putText(color_src, "S: " +str(data[i][4]), (x0, y1 + 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255))

    # 各オブジェクトの重心座標をに黄文字で表示
    cv2.putText(color_src, "X: " + str(int(center[i][0])), (x1 - 10, y1 + 15), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255))
    cv2.putText(color_src, "Y: " + str(int(center[i][1])), (x1 - 10, y1 + 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255))

# 画像の保存
cv2.imwrite('sample_label2.jpg', color_src)


ラベリング画像(詳細版)
f:id:okkah:20180802161435j:plain

DLLAB DAY 2018 ハッカソンに参加してきた

MicrosoftとPreferred Networksが生んだ、日本で最も勢いがあるディープラーニングコミュニティであるDEEP LEARNING LAB主催のDLLAB DAY 2018 ハッカソンに参加してきました。

f:id:okkah:20180621232852p:plain

dllab.ai


ハッカソンの内容
Computer Visionのコースと、Natural Language Processingのコースがありましたが、自分はCVの方に参加しました。

与えられたデータセットを用いて、9種類のクラスに分けられる約1万5千枚のポテトチップスの写真を自動で判別できるようなモデルを構築することが課題でした。

画像のサンプルはこんな感じです。

f:id:okkah:20180621221709j:plain

個人的にはのりしおがなかったのが残念笑


学んだ内容
自分が今回のハッカソンを通じて特に学んだ内容は、

1. Dockerはどこでも誰でも同じ環境が作れて便利
2. まだまだデータの読み込みの練習が必要

ということでした。順番に内容を追っていきます。


1. Dockerについて
Dockerは、アプリケーションを構築、展開、実行するためのオープンなプラットフォームです。

今回は、ユーザーが作成したコンテナをアップロードして公開・共有できるサービスであるDocker Hubと、クラウドコンピューティングプラットフォームであるMicrosoft Azureを使用しました。

Docker Hubにある今回のデータセットが入ったコンテナをMicrosoft Azure上に構成し、これをdocker pullコマンドでローカルにプルし、 docker runコマンドで8888番ポートを使ってコンテナを起動しました。

これにより、ブラウザ上でポートにアクセスすることで、Jupyter Notebookによるコーディングができるようになりました。

Dockerによる利点は、

1. コード化されたファイルを共有することで、どこでも誰でも同じ環境が作れる
2. 作成した環境を配布しやすい
3. 安定した開発を進めたり、リリースサイクルの改善にも役立つ

ということを学びました。


2. データの読み込み
今回は、環境構築とデータの読み込みにかなり時間がかかってしまったため、モデル構築や、前処理にかけられる時間が随分と減ってしまいました。

環境構築は運営側の問題でもあったため仕方がなかったとしても、データの読み込みはもっと勉強する必要があると感じました。

from PIL import Image
import os
import numpy as np
import pickle

# train
img_shape=(224,224)
imgs = []
for filename in os.listdir("../data/train/images"):
    img = Image.open("../data/train/images/" + filename)
    img = img.resize(img_shape)
    img = np.asarray(img, dtype='f')
    img /= 255
    img = np.transpose(img, (2, 0, 1))
    imgs.append((filename, img))
    
labels = {}
with open("../data/train/train_labels.txt", "r") as f:
    for line in f:
        labels[line.split()[0]] = line.split()[1]    

train = []
for fn, img in imgs:
    train.append((img, np.int8(labels[fn])))

with open("traindata.pickle", "wb") as f:
    pickle.dump(train, f)


今回はチームメイトの力を借りつつ、Python標準ライブラリにあるpickleモジュールを用いたオブジェクトの直列化・非直列化について学びました。

直列化 (Serialize) はプログラミングにおいてオブジェクトをバイト列に変換することであり、非直列化 (Deserialize) はその逆で、バイト列を元のオブジェクトを復元することです。

これにより、バイト列に変換されたデータをファイルの形で永続化することができます。

モジュール名でもあるpickleという名前は、ハンバーガーにもはさまっているあいつが由来みたいです。

メモリ上にある揮発性で賞味期限の短いオブジェクトを、バイト列の形でファイルに長期保存できる状態にすることをピクルス、つまり漬物に見立てているのだと考えられます。

Chainer公式サンプルMNISTを読み解いてみた

train_mnist.pyのコードを追ってみました。Chainerのバージョンは4.0.0です。

github.com


MNISTとは
手書き数字の画像セット。機械学習の分野で最も有名なデータセットの1つ。
データセットは70000枚。(訓練データ: 60000枚、テストデータ: 10000枚)


処理の流れ
main関数における大まかな処理の流れは
 ⑴ モデルの生成
 ⑵ Optimizerの生成
 ⑶ Iteratorの生成
 ⑷ Trainer、Updaterの生成
 ⑸ Extensionsの登録
 ⑹ 学習ループ
といった感じです。


Trainerについて
Trainerは学習に必要なもの全てをひとまとめにする機能を持っています。
全体図は以下のようになっています。

f:id:okkah:20180501193156p:plain

基本的にTrainerは、渡されたUpdater(必要ならばExtensionsも)を実行するだけですが、
Updaterは中にIteratorとOptimizerを持っています。

Iteratorはデータセットにアクセスする機能を持ち、
Optimizerは重み・バイアスを更新する機能を持ちます。

つまりUpdaterは
 ⑴ データセットからデータを取り出す。(Iterator)
 ⑵ モデルに渡してロスを計算する。(Model = Optimizer.target)
 ⑶ モデルのパラメータを更新する。(Optimizer)
といった一連の学習の主要部分を担っています。

Extensionsは、可視化やログの保存などの様々な便利な機能を持つので、
必要に応じて使いましょう。


実際にMNISTのサンプルコードを追ってみる
1. 必要なライブラリやモジュールをimport

from __future__ import print_function

import argparse

import chainer
import chainer.functions as F
import chainer.links as L
from chainer import training
from chainer.training import extensions

・__future__: Python2系とは互換性の無い3系の機能を、2系でも使用可能にする。
・argparse: コマンドライン引数を扱えるようにする。
・chainer.functions: パラメータを持たない関数。
・chainer.links: パラメータを持つ関数。
・training: trainer


2. モデルの生成

# Set up a neural network to train    
# Classifier reports softmax cross entropy loss and accuracy at every    
# iteration, which will be used by the PrintReport extension below.    
model = L.Classifier(MLP(args.unit, 10))    
if args.gpu >= 0:
    # Make a specified GPU current
    chainer.backends.cuda.get_device_from_id(args.gpu).use()
    model.to_gpu()  # Copy the model to the GPU
# Network definition
class MLP(chainer.Chain):

    def __init__(self, n_units, n_out):
        super(MLP, self).__init__()
        with self.init_scope():
            # the size of the inputs to each layer will be inferred
            self.l1 = L.Linear(None, n_units)  # n_in -> n_units
            self.l2 = L.Linear(None, n_units)  # n_units -> n_units
            self.l3 = L.Linear(None, n_out)  # n_units -> n_out

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)

model: Classifierインスタンス。このmodelにデータを渡すと順伝播が始まる。
MLP: レイヤー構成を定義するクラス。
・chainer.Chain: パラメータを持つlinksをまとめておくクラス。
 Optimizerが更新するパラメータを簡単に取得できるように一箇所にまとめる。
・__init__: モデルを構成するレイヤーを定義するメソッド。インスタンス化。
・__call__: クラスのインスタンスを関数として呼び出すメソッド。
L.Linear: 全結合層を実現するクラス。
 データがその層に入力されると、必要な入力ユニット数を自動的に計算し、
 (n_in) x (n_units)の大きさの行列を生成し、パラメータとして保持する。
・relu: 活性化関数(→ゼロから作るDeep Learning 3章)

モデルのインスタンスは以下のようになります。
f:id:okkah:20180501230144p:plain

3. コマンドライン引数の設定

    parser = argparse.ArgumentParser(description='Chainer example: MNIST')
    parser.add_argument('--batchsize', '-b', type=int, default=100,
                        help='Number of images in each mini-batch')
    parser.add_argument('--epoch', '-e', type=int, default=20,
                        help='Number of sweeps over the dataset to train')
    parser.add_argument('--frequency', '-f', type=int, default=-1,
                        help='Frequency of taking a snapshot')
    parser.add_argument('--gpu', '-g', type=int, default=-1,
                        help='GPU ID (negative value indicates CPU)')
    parser.add_argument('--out', '-o', default='result',
                        help='Directory to output the result')
    parser.add_argument('--resume', '-r', default='',
                        help='Resume the training from snapshot')
    parser.add_argument('--unit', '-u', type=int, default=1000,
                        help='Number of units')
    parser.add_argument('--noplot', dest='plot', action='store_false',
                        help='Disable PlotReport extension')
    args = parser.parse_args()

    print('GPU: {}'.format(args.gpu))
    print('# unit: {}'.format(args.unit))
    print('# Minibatch-size: {}'.format(args.batchsize))
    print('# epoch: {}'.format(args.epoch))
    print('')

argparseモジュールを使うと、コマンドライン引数を扱うことができます。
これにより、Pythonを実行するときに様々なパラメータを指定することができます。

例)

$ python train_mnist.py -g 0 -e 10
GPU: 0
# unit: 1000
# Minibatch-size: 100
# epoch: 10

GPU: 0 (0: GPUを使用、-1: CPUを使用)
epoch: 10 (学習の反復回数: 10回)
で実行することができます。(他はデフォルトのまま)



4. Optimizerの生成

    # Setup an optimizer
    optimizer = chainer.optimizers.Adam()
    optimizer.setup(model)

モデルによって順伝播・逆伝播が実行され勾配が計算されますが、
その値を重み・バイアスに反映するのがOptimizerの仕事です。
役割上、モデルをラップするような形になります。

・Adam: パラメータの更新(→ゼロから作るDeep Learning 6章)


5. Iteratorの生成

    # Load the MNIST dataset
    train, test = chainer.datasets.get_mnist()

    train_iter = chainer.iterators.SerialIterator(train, args.batchsize)
    test_iter = chainer.iterators.SerialIterator(test, args.batchsize,
                                                 repeat=False, shuffle=False)

Iteratorでデータセットにアクセスします。

・get_mnist: mnistのデータをtrainとtestに入れる。
・SerialIterator: データを順番に取り出すもっともシンプルなIterator
・batchsize: 何枚の画像データを一括りにして取り出すかどうか。
・repeat: 何周もデータを繰り返し読むかどうか。
・shuffle: 取り出すデータの順番をepochごとにランダムに変更するかどうか。

ここまでが初期化に関する処理です。


6. Trainer、Updaterの生成

    # Set up a trainer
    updater = training.updaters.StandardUpdater(
        train_iter, optimizer, device=args.gpu)
    trainer = training.Trainer(updater, (args.epoch, 'epoch'), out=args.out)

ここから学習ループに関する処理に入ります。

・StandardUpdater: Updaterの処理を遂行するための最もシンプルなクラス。
・args.epoch: stop_trigger。学習をどのタイミングで終了するか。
・out: Extensionsで描画したグラフ画像の保存先。


7. Extensionsの登録

    # Evaluate the model with the test dataset for each epoch
    trainer.extend(extensions.Evaluator(test_iter, model, device=args.gpu))

    # Dump a computational graph from 'loss' variable at the first iteration
    # The "main" refers to the target link of the "main" optimizer.
    trainer.extend(extensions.dump_graph('main/loss'))

    # Take a snapshot for each specified epoch
    frequency = args.epoch if args.frequency == -1 else max(1, args.frequency)
    trainer.extend(extensions.snapshot(), trigger=(frequency, 'epoch'))

    # Write a log of evaluation statistics for each epoch
    trainer.extend(extensions.LogReport())

    # Save two plot images to the result dir
    if args.plot and extensions.PlotReport.available():
        trainer.extend(
            extensions.PlotReport(['main/loss', 'validation/main/loss'],
                                  'epoch', file_name='loss.png'))
        trainer.extend(
            extensions.PlotReport(
                ['main/accuracy', 'validation/main/accuracy'],
                'epoch', file_name='accuracy.png'))

    # Print selected entries of the log to stdout
    # Here "main" refers to the target link of the "main" optimizer again, and
    # "validation" refers to the default name of the Evaluator extension.
    # Entries other than 'epoch' are reported by the Classifier link, called by
    # either the updater or the evaluator.
    trainer.extend(extensions.PrintReport(
        ['epoch', 'main/loss', 'validation/main/loss',
         'main/accuracy', 'validation/main/accuracy', 'elapsed_time']))

    # Print a progress bar to stdout
    trainer.extend(extensions.ProgressBar())

・Extensions: 可視化やログの保存などの様々な便利な機能を持つ。
 ・Evaluator: モデルの評価。
 ・dump_graph: グラフの保存。
 ・snapshot: Trainerを保存。
 ・LogReport: ログを保存。
 ・PlotReport: ロスを可視化して保存。
 ・PrintReport: ログを出力。
 ・ProgressBar: 学習の進行状況を出力。


8. 最後に

    if args.resume:
        # Resume from a snapshot
        chainer.serializers.load_npz(args.resume, trainer)

    # Run the training
    trainer.run()


if __name__ == '__main__':
    main()

・serializers.load_npz: snapshotから再開。
・trainer.run: 学習を開始。
・if __name__ == '__main__':
 直接実行されていればTrue、importされて実行されていればFalse。

ゼロから作るDeep Learning学習備忘録(5〜8章)

ゼロから作るDeep Learning学習備忘録(1〜4章) - OKKAH NETの続きです。


5章 誤差逆伝播
順伝播: 入力→出力へと計算 ・逆伝播: 出力→入力へと計算
誤差逆伝播法(Backpropagation): 損失関数を誤差と見立てて、
 逆伝播によって重みとバイアスを修正していくアルゴリズム
 連鎖律で逆伝播を行い、最急降下法で誤差を最小にする。
 ・連鎖律(chain rule): 合成関数の微分はそれぞれの導関数の積で与えられる。
 ・最急降下法(gradient discent): 関数の傾きのみから関数の最小値を探索する。
勾配確認: 数値微分誤差逆伝播法の結果を比較することで、
 誤差逆伝播法の実装に謝りがないことを確認できる。


6章 学習に関するテクニック
・パラメータの更新: 4章のSGD(確率的勾配降下法)の欠点を改善する手法3つ。
 ・Momentum: 慣性力を利用。関連性のある方向へSGDを加速させ振動を抑制する。
 ・AdaGrad: 学習係数を各パラメータ毎にその勾配の大きさに従って減らしていく。
  ・RMSProp: 過去の更新を徐々に忘れることで、いずれ更新量が0になる点を補う。
 ・Adam: MomentumとAdaGradの融合。
Batch Normalization: NNの学習を加速させる汎用的で強力な手法。
 2015年にGoogleのLoffeさんらによって提案された。
 各層でのアクティベーションの分布を、適度な広がりを持つように調整する。
 具体的には、各ミニバッチごとにデータ分布を平均0、分散1になるように正規化。
 これにより、学習効率が上がり、初期値依存性も小さく、かつ過学習を抑制する。
・正規化: モデルの表現力が高い時、訓練データが少ない時は、過学習の対策が必要。
 ・Weight decay(荷重減衰): 大きな重みを持つことに対してペナルティを課す。
  L2正則化。複雑なニューラルネットワークには対応しきれない。
 ・Dropout: ニューロンをランダムに消去しながら学習する。
  Weight decayだけでは対応が困難なときに使用する。
ハイパーパラメータ: 学習を行う際に人が予め設定しておく必要のあるパラメータ。
 例)ニューロンの数、バッチサイズ、学習係数、Weight decay
 ・検証データ: ハイパーパラメータの調整用のデータ。
 ・ハイパーパラメータの最適化
 ⑴ハイパーパラメータの範囲を指定する。
 ⑵指定した範囲から、ランダムにサンプリングする。
 ⑶学習を行い、検証データで認識精度を評価(epochは小さく設定)。
 ⑷⑵⑶をある程度繰り返し、認識精度からハイパーパラメータの範囲を狭める。
 他にはベイズの最適化で行う方法もある。


7章 畳み込みニューラルネットワーク
全結合: 隣接する層の全てのニューロン間で結合がある。
 問題点はデータの形状が無視されてしまう点。
畳み込みニューラルネットワーク(CNN):
 これまでの全結合のネットワークに畳み込み層プーリング層が加わる。
 画像処理や音声認識など至るところで使われている。
畳み込み層(Convolutionレイヤ): データの形状を維持することができる。
 ・特徴マップ: 畳み込み層の入出力データ。
 ・畳み込み演算: 画像処理でいうところのフィルター演算
  フィルターという用語はカーネルという言葉で表現されることもある。
  フィルターのウィンドウを一定の感覚でスライドさせながら適用していく。
  それぞれで、フィルターと入力の対応する要素を乗算し、その和を求める。
  バイアス項の加算は、フィルター適用後のデータに対して行われる。
 ・パディング: 入力データの周囲に固定データ(例えば0)を埋めること。
 ・ストライド: フィルターを適用する位置の間隔。
  例)ストライド=2 → フィルターを適用する窓の間隔が2要素ごとになる。
 ・3次元の畳み込み演算→直方体のブロックで考えるとわかりやすい。
 ・バッチ処理→N回分の処理を1回にまとめて行う。
プーリング層(poolingレイヤ): 縦・横方向の空間を小さくする演算。
 学習するパラメータがない、チャンネル数不変、
 微小な位置変化に対してロバスト、といった特徴がある。
 例) 領域の最大値をとるMaxプーリング、平均値をとるavarageプーリング
im2col(image to column):
 フィルター(重み)によって都合の良いように入力データを展開する関数。
・代表的なCNN
 ・LeNet: 最初のCNN。手書き数字認識を行うネットワーク。
  シグモイド関数、サブサンプリングによる中間データの縮小を採用。
  (現在はReLU、Maxプーリングが主流)
 ・AlexNet: ディープラーニング・ブームの火付け役。
  ReLU、LRN、Dropoutを採用している点以外はLeNetとあまり変わらず。
ディープラーニングの発展に、ビッグデータGPUが大きく貢献している。    


8章 ディープラーニング
Data Augmentation: 訓練画像を回転、平行移動、切り出し(crop)、
 左右反転(flip)、輝度変化などによって、人工的に増やす手法。
・ネットワークを深くすることの利点
 ・より少ないパラメータで同レベル以上の表現力を達成できる。
 ・各層がより簡単なタスクに取り組むことになるので効率的。
ImageNet: ILSVRC(2012)で使われた100万枚を超える画像データセット
ディープラーニングフレームワーク
 ・VGG(2014):
  畳み込み層とプーリング層から構成される基本的なCNN。
  3x3の小さなフィルターによる畳み込み層を連続して行い、
  重みのある層(畳み込み層や全結合層)は16~19層。
 ・GoogLeNet(2015):
  ネットワークが横方向にも幅を持つインセプション構造
  サイズの違うフィルター(とプーリング)を複数適用し、その結果を適合。
  1x1のフィルターの畳み込み層を多くの場所で使用する事で、
  チャンネル方向にサイズを減らし、パラメータを削減。
 ・ResNet(2015):
  畳み込み層の一部をまたぐスキップ構造(ショートカット、バイパス)
  学習時のBPの勾配消失問題を軽減できる(微分が1に近くなる)。
  これにより150層以上を繋げることができるようになった。
転移学習: 学習済みの重み(の一部)を別のNNにコピーして再学習を行う。
 手元にあるデータセットが少ない場合において特に有効な手法。
GPUや分散学習、ビット精度の削減などによって学習の高速化を実現。
ディープラーニングの実用事例
 ・物体検出: 画像中から物体の位置の特定を含めてクラス分類を行う。
  R-CNN、Faster R-CNNの手法が有名。
 ・セグメンテーション: 画像のピクセルレベルでのクラス分類を行う。
  FCNという全てが畳み込み層からなるネットワークが使われる。
 ・画像キャプション設定: 入力画像の説明文を自動で生成する。
  代表的な手法はNIC(画像を理解するディープなCNNと、
  自然言語や時系列データを扱うRNNから構成)と呼ばれる。
 ・画像スタイル変換: アーティストのような画像を描かせる。
 ・画像生成: 画像をゼロから生成。DCGAN。
 ・自動運転: SegNet(CNNベース)
 ・強化学習: Deep Q-Network。最適価値行動関数。


github.com

ゼロから作るDeep Learning学習備忘録(1〜4章)

ゼロから作るDeep Learningの学習備忘録です。

github.com


目的
・最低限の外部ライブラリだけ利用し、Pythonを使って、ゼロからディープラーニングによるプログラムを実装する。
・簡単な機械学習の問題からスタートし、最終的には画像を高精度に認識するシステムを実装する。


1章 Python入門
Python: 汎用のプログラミング言語。コードがシンプルで扱いやすい。
Anaconda: データ分析などに必要なライブラリを一括してインストールできる。
NumPy: 数値計算のためのライブラリ。
Matplotlib: グラフ描写のためのライブラリ。


2章 パーセプトロン
パーセプトロン: ニューラルネットワークの起源。入出力を備えたアルゴリズム
 複数の信号を入力として受け取り、ひとつの信号を出力する。
 重みとバイアスをパラメータとして設定する。
・単層パーセプトロン→AND, NAND, OR, 線形領域
・多層パーセプトロン→XOR, 非線形領域
・多層のパーセプトロンは理論上コンピュータを実装可能。
 

3章 ニューラルネットワーク
ニューラルネットワーク: パーセプトロンの重みをデータから自動で学習できる。
 入力層、中間層(隠れ層)、出力層からなる。
 入力層で重み付けされた入力値に対して、
 中間層で重みとバイアス値を利用して多次元配列の行列計算を行い、
 活性化関数のいずれかを利用してさらに加工して結果を出力する。
活性化関数: 入力信号の総和がどのように発火するかを決定する。
 ・シグモイド関数: 入力値が大きいほど1に近づき、小さいほど0に近づく。
 ・ステップ関数: 入力値が0以下のとき0、0より大きいとき1を出力。
 ・ReLU関数: 入力値が0以下のとき0、0より大きいとき入力値をそのまま出力。
機械学習の分類
 ・分類問題: データがどのクラスに属するか。例)人の画像から性別を判断
  出力層はソフトマックス関数(1つの出力層に全ての入力が結びつく)。
 ・回帰問題: データから数値の予測。例)人の画像から体重を判断
  出力層は恒等関数(入力をそのまま出力する)。
MNIST: 手書き数字の画像セット。機械学習の分野で最も有名なデータセットの1つ。
バッチ処理: 入力データをまとめることで計算を高速化。


4章 ニューラルネットワークの学習
・データから学習する
 ・訓練データ: 学習を行い、最適なパラメータを探索する。
 ・テストデータ: 訓練したモデルの実力を評価する。
損失関数: ニューラルネットワークの学習で用いられる指標。
 損失関数を指標として、値が小さくなるように重みパラメータを更新する。
 2乗和誤差交差エントロピー誤差などがある。
・学習の流れ
 ⑴ミニバッチ学習
  膨大な量のデータに対して損失関数を計算するのは現実的ではないので、
  一部データを無作為で抽出し、近似として利用する。
  選ばれたデータをミニバッチという。
 ⑵勾配の算出
  ミニバッチの損失関数を減らすために、各重みパラメータの勾配を求める。
  勾配は、損失関数の値を最も減らす方向を示す。
 ⑶パラメータの更新
  重みパラメータを勾配方向に微小量だけ更新する。
 ⑴〜⑶を繰り返す。
・数値微分による計算は時間がかかるが簡単。
 5章の誤差逆伝播法は複雑だが高速に勾配を求めることができる。


続きはこちら
okkah.hateblo.jp

pyenvでPythonのバージョンを切り替える

pyenvは、Pythonのバージョンを簡単に切り替えてくれるツールです。2系列と3系列の切り替えに便利です。


1. pyenvのインストール
まずはpyenvをインストールしましょう。以下のコマンドでgitからcloneします。

$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv


2. pyenvのパスを通す
bash, zshと、fishの場合で設定ファイルに記述する内容が違うので気をつけて下さい。

・~/.bash_profileや~/.zshenvを編集する場合

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)


・~/.config/fish/config.fishを編集する場合

set -gx PYENV_ROOT "$HOME/.pyenv"
set -x PATH $PATH "$PYENV_ROOT/bin"
status --is-interactive; and . (pyenv init - | psub)


これで、pyenvコマンドが使えるようになるはずです。


3. pyenvでPythonをインストール
では、pyenvを用いてPythonをインストールしてみましょう。

$ pyenv install 2.x.x
$ pyenv install 3.x.x


以下のコマンドで現在利用できるバージョンを確認することができます。

$ pyenv install --list


4. pyenvでバージョンを切り替える
バージョンの切り替えをします。localの場合は今いるディレクトリに、globalの場合は全体に反映されます。

$ pyenv local x.x.x
$ pyenv global x.x.x


以下のコマンドでPythonのバージョンを確認することができます。

$ python --version
Python x.x.x