1. 概述

在本教程中,我们将使用 Java 中的 Deeplearning4j 库构建和训练卷积神经网络模型。

2. 图像分类

2.1. 问题陈述

假设我们有一组图像。每个图像表示特定类的对象。此外,图像上的对象属于唯一已知的类。因此,问题陈述是构建能够识别给定图像上对象的类的模型。

例如,假设我们有一组包含十个手势的图像。我们构建一个模型并对其进行训练以对其进行分类。然后经过训练后,我们可以传递其他图像并对它们的手势进行分类。当然,给定的手势应该属于已知的类。

2.2. 图像表示

在计算机内存中,图像可以表示为数字矩阵。每个数字都是一个像素值,范围从 0 到 255。

灰度图像是 2D 矩阵。同样,RGB 图像是具有宽度、高度和深度维度的 3D 矩阵。

正如我们所看到的,图像是一组数字。因此,我们可以构建多层网络模型来训练它们对图像进行分类。

3. 卷积神经网络

卷积神经网络 (CNN) 是一种具有特定结构的多层网络模型。CNN的结构可以分为两个块:卷积层和全连接(或密集)层。让我们逐一看一下。

3.1. 卷积层

每个卷积层都是一组方形矩阵,称为核。最重要的是,我们需要它们对输入图像执行卷积。它们的数量和大小可能会有所不同,具体取决于给定的数据集。我们主要使用 3×3 或 5×5 个内核,很少使用 7×7 个内核。确切的大小和数量是通过反复试验选择的。

此外,我们在训练开始时随机选择核矩阵的变量。它们是网络的权重。

要执行卷积,我们可以将内核用作滑动窗口。我们将内核权重乘以相应的图像像素并计算总和。然后,我们可以使用步幅(向右移动)和填充(向下移动)移动内核以覆盖图像的下一个块。因此,我们将拥有将在进一步计算中使用的值。

简而言之,通过这一层,我们得到了一个卷积图像。某些变量可能小于零。这通常意味着这些变量不如其他变量重要。这就是为什么应用ReLU函数是进一步减少计算的好方法。

3.2. 子采样层

子采样(或池化)层是网络的一个层,通常在卷积层之后使用。卷积后,我们得到了很多计算变量。但是,我们的任务是在其中选择最有价值的。

方法是将滑动窗口算法应用于卷积图像。在每一步中,我们将在方形窗口中选择预定义大小的最大值,通常在 2×2 到 5×5 像素之间。因此,我们将拥有更少的计算参数。因此,这将减少计算。

3.3. 密集层

密集(或全连接)层是由多个神经元组成的层。我们需要这一层来执行分类。此外,可能有两个或更多这样的后续层。重要的是,最后一层的大小应等于要分类的类数。

网络的输出是图像属于每个类的概率。为了预测概率,我们将使用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是用于训练和测试的图像数量。一个epoch持续trainImagesNum/trainBatch步骤。因此,拥有 2048 张批量大小 = 32 的火车图像将导致每个时期 2048 / 32 = 64 步。

5. 深度学习中的卷积神经网络4j

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());
    });
}

周期数是我们可以自己指定的参数。我们有一个小数据集。结果,几百个epoch就足够了。

5.3. 评估模型

最后,我们可以评估现在训练的模型。Deeplearning4j库提供了一种轻松做到这一点的能力:

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

评估是一个对象,其中包含训练模型后的计算指标。这些是准确性、精度、召回率和 F1 分数。此外,它具有友好的可打印界面:

 

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

6. 结论

在本教程中,我们了解了 CNN 模型的架构、优化技术和评估指标。此外,我们还使用Java中的Deeplearning4j库实现了该模型。