Solverの役割と最適化アルゴリズム
深層学習モデルの学習過程では、損失関数を最小化する最適なパラメータを見つける必要があります。CaffeのSolverは、この最適化プロセスを担当します。Solverは、指定された最適化アルゴリズムに基づいてネットワークの重みを更新します。Caffeは以下の6種類の最適化アルゴリズムをサポートしています。
- Stochastic Gradient Descent (SGD)
- AdaDelta
- AdaGrad
- Adam
- Nesterov’s Accelerated Gradient
- RMSprop
これらのアルゴリズムは、Solver設定ファイル(solver.prototxt)内の`type`パラメータで選択します。
Solver設定ファイルの主要なパラメータ
Solverの動作は、`solver.prototxt`ファイルで詳細に制御できます。主なパラメータは以下の通りです。
net: "examples/mnist/lenet_train_test.prototxt" # 学習するネットワークの定義ファイル
test_iter: 100 # 1回のテストで実行するイテレーション数
test_interval: 500 # テストを実行する間隔(イテレーション数)
base_lr: 0.01 # 基礎学習率
momentum: 0.9 # モーメンタム
type: SGD # 使用する最適化アルゴリズム
weight_decay: 0.0005 # 重み減衰(L2正則化)
lr_policy: "inv" # 学習率の調整戦略
gamma: 0.0001 # 学習率調整戦略のパラメータ
power: 0.75 # 学習率調整戦略のパラメータ
display: 100 # 画面にログを表示する間隔
max_iter: 3000 # 最大イテレーション数
snapshot: 500 # スナップショットを保存する間隔
snapshot_prefix: "examples/mnist/lenet" # スナップショットファイルのプレフィックス
solver_mode: CPU # 実行モード(GPUまたはCPU)
学習率ポリシー (lr_policy)
`lr_policy`は、学習率をどのように変化させるかを定義します。主な戦略は以下の通りです。
- fixed: 学習率を`base_lr`で固定します。
- step: 一定のステップサイズごとに学習率を`gamma`倍します。`stepsize`パラメータが必要です。
- exp: 各イテレーションで学習率を`gamma`の指数関数的に減少させます。
- inv: イテレーション数に基づいて学習率を逆比例的に減少させます。`power`パラメータが必要です。
- multistep: 指定されたイテレーション数で学習率を`gamma`倍します。`stepvalue`パラメータが必要です。
- poly: 多項式関数に基づいて学習率を減少させます。
- sigmoid: シグモイド関数に基づいて学習率を減少させます。
Pythonを使用したSolver設定ファイルの生成
以下は、Pythonスクリプトを使用してSolver設定ファイルを生成する例です。この例では、SGDオプティマイザとステップ学習率ポリシーを設定しています。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import caffe.proto.caffe_pb2 as caffe_pb2
# SolverParameterオブジェクトの作成
solver_config = caffe_pb2.SolverParameter()
# ネットワークとテストネットワークの設定
solver_config.train_net = "path/to/train.prototxt"
solver_config.test_net.extend(["path/to/val.prototxt"])
# 学習とテストのパラメータ
solver_config.test_interval = 500
solver_config.test_iter.extend([100])
solver_config.max_iter = 100000
# 最適化アルゴリズムのパラメータ
solver_config.base_lr = 0.001
solver_config.momentum = 0.9
solver_config.weight_decay = 5e-4
solver_config.lr_policy = "step"
solver_config.stepsize = 26067
solver_config.gamma = 0.1
# ログとスナップショットの設定
solver_config.display = 1000
solver_config.snapshot = 10000
solver_config.snapshot_prefix = "path/to/snapshot"
# 実行モードの設定
solver_config.type = "SGD"
solver_config.solver_mode = caffe_pb2.SolverParameter.GPU
# 設定ファイルの書き出し
output_path = "solver_config.prototxt"
with open(output_path, 'w') as f:
f.write(str(solver_config))
ネットワーク層の詳細
ネットワークの構造は、`prototxt`ファイルで定義されます。主な層タイプとそのパラメータを説明します。
1. データ層 (Data Layer)
データ層は、学習データとラベルを読み込みます。様々なバックエンド(LMDB, HDF5, 画像ファイルなど)をサポートしています。
# LMDBソースを使用する例
layer {
name: "cifar_train"
type: "Data"
top: "data"
top: "label"
include { phase: TRAIN }
transform_param {
scale: 0.00390625
mirror: true
crop_size: 227
}
data_param {
source: "path/to/cifar10_train_lmdb"
batch_size: 64
backend: LMDB
}
}
# HDF5ソースを使用する例
layer {
name: "hdf5_data"
type: "HDF5Data"
top: "data"
top: "label"
hdf5_data_param {
source: "path/to/train_data.h5"
batch_size: 32
}
}
2. 畳み込み層 (Convolution Layer)
畳み込み層は、入力データに畳み込み演算を適用して特徴マップを生成します。
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param { lr_mult: 1 } # 重みの学習率係数
param { lr_mult: 2 } # バイアスの学習率係数
convolution_param {
num_output: 32 # 出力チャネル数(フィルタ数)
kernel_size: 3 # フィルタのサイズ
stride: 1 # ストライド
pad: 1 # パディング
weight_filler { type: "xavier" } # 重みの初期化方法
bias_filler { type: "constant" } # バイアスの初期化方法
}
}
3. プーリング層 (Pooling Layer)
プーリング層は、空間的な次元を縮小し、計算コストを削減し、位置の変化に対するロバスト性を高めます。
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX # プーリング方法(MAXまたはAVE)
kernel_size: 2 # プーリングウィンドウのサイズ
stride: 2 # ストライド
}
}
4. 活性化層 (ReLU Layer)
ReLU層は、非線形性を導入し、ネットワークが複雑なパターンを学習できるようにします。
layer {
name: "relu1"
type: "ReLU"
bottom: "pool1"
top: "pool1"
}
5. 全結合層 (InnerProduct Layer)
全結合層は、入力をフラットにして線形変換を適用し、分類などのタスクの出力を生成します。
layer {
name: "fc1"
type: "InnerProduct"
bottom: "pool2"
top: "fc1"
param { lr_mult: 1 }
param { lr_mult: 2 }
inner_product_param {
num_output: 256 # 出力ユニット数
weight_filler { type: "xavier" }
bias_filler { type: "constant" }
}
}
# テスト時の精度評価層
layer {
name: "accuracy"
type: "Accuracy"
bottom: "fc2"
bottom: "label"
top: "accuracy"
include { phase: TEST }
}
Python Layer APIを使用したネットワーク定義
Caffeは、Python APIを提供しており、ネットワーク構造をプログラムで定義できます。以下は、LeNetアーキテクチャを生成する例です。
import sys
caffe_root = '/path/to/caffe/'
sys.path.insert(0, caffe_root + 'python')
from caffe import layers as L
from caffe import params as P
import caffe
def create_lenet_network(lmdb_path, batch_size):
# ネットワーク仕様の作成
net_spec = caffe.NetSpec()
# データ層の定義
net_spec.data, net_spec.label = L.Data(batch_size=batch_size, backend=P.Data.LMDB,
source=lmdb_path, transform_param=dict(scale=1./255), ntop=2)
# 畳み込み層とプーリング層の定義
net_spec.conv1 = L.Convolution(net_spec.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier'))
net_spec.pool1 = L.Pooling(net_spec.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX)
net_spec.conv2 = L.Convolution(net_spec.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier'))
net_spec.pool2 = L.Pooling(net_spec.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX)
# 全結合層と活性化層の定義
net_spec.fc1 = L.InnerProduct(net_spec.pool2, num_output=500, weight_filler=dict(type='xavier'))
net_spec.relu1 = L.ReLU(net_spec.fc1, in_place=True)
net_spec.fc2 = L.InnerProduct(net_spec.relu1, num_output=10, weight_filler=dict(type='xavier'))
# 損失層の定義
net_spec.loss = L.SoftmaxWithLoss(net_spec.fc2, net_spec.label)
return net_spec.to_proto()
# 訓練用ネットワークの生成と保存
with open('lenet_train.prototxt', 'w') as f:
f.write(str(create_lenet_network('path/to/mnist_train_lmdb', 64)))
# テスト用ネットワークの生成と保存
with open('lenet_test.prototxt', 'w') as f:
f.write(str(create_lenet_network('path/to/mnist_test_lmdb', 100)))