1. 概要

このチュートリアルでは、JavaのDeeplearning4jライブラリを使用して、畳み込みニューラルネットワークモデルを構築およびトレーニングします。

ライブラリの設定方法の詳細については、Deeplearning4jガイドを参照してください。

2. 画像分類

2.1. 問題文

画像のセットがあるとします。 各画像は、特定のクラスのオブジェクトを表しています。 さらに、画像上のオブジェクトは、唯一の既知のクラスに属しています。 したがって、問題のステートメントは、指定された画像上のオブジェクトのクラスを認識できるモデルを構築することです。

たとえば、10個の手のジェスチャーを含む一連の画像があるとします。 モデルを作成し、それらを分類するためにトレーニングします。 次に、トレーニング後、他の画像を渡し、それらの手のジェスチャーを分類する場合があります。 もちろん、指定されたジェスチャは既知のクラスに属している必要があります。

2.2. 画像表現

コンピュータのメモリでは、画像は数値の行列として表すことができます。 各数値は、0から255の範囲のピクセル値です。

グレースケール画像は2Dマトリックスです。 同様に、RGB画像は、幅、高さ、奥行きの次元を持つ3Dマトリックスです。

ご覧のとおり、画像は数字のセットです。 したがって、マルチレイヤーネットワークモデルを構築して、画像を分類するようにトレーニングすることができます。

3. 畳み込みニューラルネットワーク

畳み込みニューラルネットワーク(CNN)は、特定の構造を持つ多層ネットワークモデルです。 CNNの構造は、畳み込み層と完全に接続された(または密な)層の2つのブロックに分割できます。 それぞれを見てみましょう。

3.1. 畳み込み層

畳み込み層は、kernelsと呼ばれる正方行列のセットです。 とりわけ、入力画像に対して畳み込みを実行するためにそれらが必要です。 それらの量とサイズは、特定のデータセットによって異なる場合があります。 私たちは主に3×3または5×5のカーネルを使用しますが、7×7のカーネルを使用することはめったにありません。 正確なサイズと量は試行錯誤によって選択されます。

さらに、トレインの開始時にカーネル行列の変数をランダムに選択します。 それらはネットワークの重みです。

畳み込みを実行するために、カーネルをスライディングウィンドウとして使用できます。 カーネルの重みを対応する画像ピクセルに乗算し、その合計を計算します。 次に、ストライド(右に移動)とパディング(下に移動)を使用して、カーネルを移動して画像の次のチャンクをカバーします。 その結果、以降の計算で使用される値が得られます。

つまり、このレイヤーを使用すると、畳み込み画像が得られます。 一部の変数はゼロ未満である可能性があります。 これは通常、これらの変数が他の変数よりも重要でないことを意味します。 そのため、 ReLU 関数を適用することは、計算をさらに少なくするための優れたアプローチです。

3.2. サブサンプリングレイヤー

サブサンプリング(またはプーリング)層はネットワークの層であり、通常は畳み込み層の後に使用されます。 畳み込みの後、多くの計算された変数を取得します。 しかし、私たちの仕事はそれらの中から最も価値のあるものを選ぶことです

アプローチは、スライディングウィンドウアルゴリズムを畳み込み画像に適用することです。 各ステップで、事前定義されたサイズの正方形のウィンドウで最大値を選択します。通常は2×2〜5×5ピクセルです。 その結果、計算されるパラメーターが少なくなります。 したがって、これにより計算が削減されます。

3.3. 高密度レイヤー

密な(または完全に接続された)層は、複数のニューロンで構成される層です。 分類を実行するには、このレイヤーが必要です。 さらに、そのような結果として生じる層が2つ以上存在する可能性があります。 重要なのは、最後のレイヤーのサイズが分類用のクラスの数と等しいことです。

ネットワークの出力は、各クラスに属する画像の確率です。 確率を予測するために、Softmax活性化関数を使用します。

3.4. 最適化手法

トレーニングを実行するには、重みを最適化する必要があります。 最初はこれらの変数をランダムに選択することを忘れないでください。 ニューラルネットワークは大きな機能です。 そして、それは多くの未知のパラメータ、私たちの重みを持っています。

画像をネットワークに渡すと、答えが返されます。 次に、損失関数を作成します。これは、この回答に依存します。 教師あり学習に関しては、実際の答え、つまり真のクラスもあります。 私たちのミッションは、この損失関数を最小化することです。 私たちが成功すれば、私たちのモデルはよく訓練されています。

関数を最小化するには、ネットワークの重みを更新する必要があります。 これを行うために、これらの未知のパラメーターのそれぞれに関する損失関数の導関数を計算できます。 次に、各重みを更新できます。

勾配がわかっているため、損失関数の極小値を見つけるために重み値を増減する場合があります。 さらに、このプロセスは反復的であり、最急降下法と呼ばれます。 バックプロパゲーションは、勾配降下法を使用して、ネットワークの最後から最初に重みの更新を伝播します。

このチュートリアルでは、確率的勾配降下法(SGD)最適化アルゴリズムを使用します。 主なアイデアは、各ステップで列車の画像のバッチをランダムに選択することです。 次に、バックプロパゲーションを適用します。

3.5. 評価指標

最後に、ネットワークをトレーニングした後、モデルのパフォーマンスに関する情報を取得する必要があります。

最もよく使用されるメトリックは精度です。 これは、すべての画像に対する正しく分類された画像の比率です。 一方、再現率、適合率、F1スコアは、画像分類にとっても非常に重要な指標です。

4. データセットの準備

このセクションでは、画像を準備します。 このチュートリアルでは、埋め込まれたCIFAR10データセットを使用してみましょう。 画像にアクセスするためのイテレータを作成します。

public class CifarDatasetService implements IDataSetService {

    private CifarDataSetIterator trainIterator;
    private CifarDataSetIterator testIterator;

    public CifarDatasetService() {
         trainIterator = new CifarDataSetIterator(trainBatch, trainImagesNum, true);
         testIterator = new CifarDataSetIterator(testBatch, testImagesNum, false);
    }

    // other methods and fields declaration

}

いくつかのパラメータを自分で選択できます。 TrainBatchtestBatchは、それぞれトレインと評価ステップごとの画像の数です。 TrainImagesNumおよびtestImagesNumは、トレーニングおよびテスト用の画像の数です。 1つのエポックはtrainImagesNum/trainBatchステップを持続します。 したがって、バッチサイズ= 32の2048個のトレインイメージがあると、1エポックあたり2048/32=64ステップになります。

5. Deeplearning4jの畳み込みニューラルネットワーク

5.1. モデルの構築

次に、CNNモデルを最初から作成しましょう。 これを行うには、畳み込み、サブサンプリング(プーリング)、および完全に接続された(高密度)レイヤーを使用します。

MultiLayerConfiguration configuration = new NeuralNetConfiguration.Builder()
  .seed(1611)
  .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
  .learningRate(properties.getLearningRate())
  .regularization(true)
  .updater(properties.getOptimizer())
  .list()
  .layer(0, conv5x5())
  .layer(1, pooling2x2Stride2())
  .layer(2, conv3x3Stride1Padding2())
  .layer(3, pooling2x2Stride1())
  .layer(4, conv3x3Stride1Padding1())
  .layer(5, pooling2x2Stride1())
  .layer(6, dense())
  .pretrain(false)
  .backprop(true)
  .setInputType(dataSetService.inputType())
  .build();

network = new MultiLayerNetwork(configuration);

ここでは、学習率、更新アルゴリズム、モデルの入力タイプ、および階層化アーキテクチャを指定します。 これらの構成を試すことができます。 したがって、さまざまなアーキテクチャとトレーニングパラメータを使用して多くのモデルをトレーニングできます。 さらに、結果を比較して最適なモデルを選択できます。

5.2. モデルのトレーニング

次に、構築されたモデルをトレーニングします。 これは、数行のコードで実行できます。

public void train() {
    network.init();    
    IntStream.range(1, epochsNum + 1).forEach(epoch -> {
        network.fit(dataSetService.trainIterator());
    });
}

エポックの数は、自分で指定できるパラメーターです。 小さなデータセットがあります。 結果として、数百エポックで十分です。

5.3. モデルの評価

最後に、トレーニング済みのモデルを評価できます。 Deeplearning4jライブラリは、それを簡単に実行する機能を提供します。

public Evaluation evaluate() {
   return network.evaluate(dataSetService.testIterator());
}

Evaluation はオブジェクトであり、モデルのトレーニング後に計算されたメトリックが含まれています。 それらは、精度、適合率、再現率、およびF1スコアです。 さらに、使いやすい印刷可能なインターフェイスがあります。

==========================Scores=====================
# of classes: 11
Accuracy: 0,8406
Precision: 0,7303
Recall: 0,6820
F1 Score: 0,6466
=====================================================

6. 結論

このチュートリアルでは、CNNモデルのアーキテクチャ、最適化手法、および評価指標について学習しました。 さらに、JavaのDeeplearning4jライブラリを使用してモデルを実装しました。

いつものように、この例のコードはGitHubから入手できます。