Deeplearning4j
Community ForumND4J JavadocDL4J Javadoc
ZH 1.0.0-beta6
ZH 1.0.0-beta6
  • 核心概念
  • 开始
    • 快速入门
    • 速查表
    • 示例教程
    • 初学者
    • Eclipse贡献者
    • 从源码构建
    • 贡献
    • 基准测试准则
    • 关于
    • 发行说明
  • 配置
    • GPU/CPU设置
    • CPU 与 AVX
    • 内存管理
    • Maven
    • SBT/Gradle和其它构建工具
    • cuDNN
    • 快照
    • 内存工作间
  • ND4J
    • 快速入门
    • 概述
  • SAMEDIFF
    • 变量
    • 操作
    • 添加操作
  • 调优与训练
    • 故障排查
    • 可视化
    • 评估
    • 迁移学习
    • 早停
    • T-SNE数据可视化
  • 分布式深度学习
    • 介绍与入门
    • 在Spark上使用DL4J:操作指南
    • 技术说明
    • Spark数据管道指南
    • API参考
    • 参数服务器
  • Keras导入
    • 概述
    • 入门
    • 支持功能
      • 正则化器
      • 损失
      • 初始化器
      • 约束
      • 激活
      • 优化器
    • Functional模型
    • Sequential模型
  • ARBITER
    • 概述
    • 层空间
    • 参数空间
  • DATAVEC
    • 概述
    • 记录
    • 概要
    • 序列化
    • 转换
    • 分析
    • 读取器
    • 执行器
    • 过滤器
    • 运算
  • 语言处理
    • 概述
    • Word2Vec
    • Doc2Vec
    • SentenceIterator
    • Tokenization
    • Vocabulary Cache
  • 模型
    • 计算图
    • 多层网络
    • 循环神经网络
    • 层
    • 顶点
    • 迭代器
    • 监听器
    • 自定义层
    • 模型持久化
    • 动物园用法
    • 激活
    • 更新器
  • 移动端
    • Android概述
    • Android先决条件
    • Android分类器
    • Android图片分类器
  • FAQ
  • 新闻
  • 支持
  • 为什么要深度学习?
Powered by GitBook
On this page
  • 在Android应用中使用深度学习和神经网络
  • 先决条件
  • 配置你的Android Studio项目
  • 启动异步任务
  • 创建一个神经网络
  • 创建训练数据
  • 结论

Was this helpful?

Edit on Git
Export as PDF
  1. 移动端

Android概述

在Android应用中使用深度学习和神经网络

Previous更新器NextAndroid先决条件

Last updated 5 years ago

Was this helpful?

在Android应用中使用深度学习和神经网络

内容

一般来说,训练一个神经网络是一项最适合有多个GPU的强大计算机的任务。但如果你想在你简陋的安卓手机或平板电脑上做呢?好吧,这绝对是可能的。然而,考虑到一个普通的Android设备的规格,它很可能会相当慢。如果这对你来说不是问题,继续读下去。

在本教程中,我将向您展示如何使用 ,一个流行的基于Java的深度学习库,在Android设备上创建和训练神经网络。

为了获得最佳效果,您需要以下各项:

  • 运行API级别21或更高的安卓设备或模拟器,内部存储空间大约为200 MB。我强烈建议您首先使用模拟器,因为您可以快速调整它,以防内存或存储空间不足。

  • Android Studio 2.2 或更新版本

  • 这里可以找到在Android应用程序中使用DL4J的更深入的研究。本指南涵盖依赖项、内存管理、保存设备训练模型以及在应用程序中加载预先训练的模型。

要在项目中使用Deeplearning4J,请将以下实现依赖项添加到应用程序模块的build.gradle文件中:

implementation (group: 'org.deeplearning4j', name: 'deeplearning4j-core', version: '{{page.version}}') {
    exclude group: 'org.bytedeco', module: 'opencv-platform'
    exclude group: 'org.bytedeco', module: 'leptonica-platform'
    exclude group: 'org.bytedeco', module: 'hdf5-platform'
}
implementation group: 'org.nd4j', name: 'nd4j-native', version: '{{page.version}}'
implementation group: 'org.nd4j', name: 'nd4j-native', version: '{{page.version}}', classifier: "android-arm"
implementation group: 'org.nd4j', name: 'nd4j-native', version: '{{page.version}}', classifier: "android-arm64"
implementation group: 'org.nd4j', name: 'nd4j-native', version: '{{page.version}}', classifier: "android-x86"
implementation group: 'org.nd4j', name: 'nd4j-native', version: '{{page.version}}', classifier: "android-x86_64"
implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.7-1.5.2'
implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.7-1.5.2', classifier: "android-arm"
implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.7-1.5.2', classifier: "android-arm64"
implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.7-1.5.2', classifier: "android-x86"
implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.7-1.5.2', classifier: "android-x86_64"
implementation group: 'org.bytedeco', name: 'opencv', version: '4.1.2-1.5.2'
implementation group: 'org.bytedeco', name: 'opencv', version: '4.1.2-1.5.2', classifier: "android-arm"
implementation group: 'org.bytedeco', name: 'opencv', version: '4.1.2-1.5.2', classifier: "android-arm64"
implementation group: 'org.bytedeco', name: 'opencv', version: '4.1.2-1.5.2', classifier: "android-x86"
implementation group: 'org.bytedeco', name: 'opencv', version: '4.1.2-1.5.2', classifier: "android-x86_64"
implementation group: 'org.bytedeco', name: 'leptonica', version: '1.78.0-1.5.2'
implementation group: 'org.bytedeco', name: 'leptonica', version: '1.78.0-1.5.2', classifier: "android-arm"
implementation group: 'org.bytedeco', name: 'leptonica', version: '1.78.0-1.5.2', classifier: "android-arm64"
implementation group: 'org.bytedeco', name: 'leptonica', version: '1.78.0-1.5.2', classifier: "android-x86"
implementation group: 'org.bytedeco', name: 'leptonica', version: '1.78.0-1.5.2', classifier: "android-x86_64"

如果选择将依赖项的快照版本与gradle一起使用,则需要在根目录中创建pom.xml文件,并从终端对其运行 mvn -U compile 。您还需要在build.gradle文件的repository{}块中包含mavenLocal()。下面提供了一个pom.xml文件示例。

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.deeplearning4j</groupId>
    <artifactId>snapshots</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <dependencies>
       <dependency>
            <groupId>org.nd4j</groupId>
            <artifactId>nd4j-native-platform</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.deeplearning4j</groupId>
            <artifactId>deeplearning4j-core</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>sonatype-nexus-snapshots</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
    </repositories>
</project>

Android Studio 3.0引入了新的Gradle,现在也应该定义annotationProcessors如果您正在使用它,请向Gradle依赖项添加以下代码:

NeuralNetConfiguration.Builder nncBuilder = new NeuralNetConfiguration.Builder();
nncBuilder.updater(Updater.ADAM);

如您所见,DL4J依赖于ND4J,Java的N维缩写,它是一个提供快速N维数组的库。ND4J在内部依赖于一个名为OpenBLAS的库,该库包含特定于平台的本地代码。因此,您必须加载与您的Android设备架构相匹配的OpenBLAS和ND4J版本。

DL4J和ND4J的依赖项有几个同名的文件。为了避免构建错误,请将以下排除参数添加到packagingOptions中。

packagingOptions {
    exclude 'META-INF/DEPENDENCIES'
    exclude 'META-INF/DEPENDENCIES.txt'
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/license.txt'
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/notice.txt'
    exclude 'META-INF/INDEX.LIST'
}

编译后的代码将有超过65536个方法。要处理此情况,请在defaultConfig中添加以下选项:

multiDexEnabled true

现在,按Sync now更新项目。最后,确保APK不同时包含lib/armeabi和lib/armeabi-v7a子目录。如果是,请将所有文件移动到其中一个或另一个,因为某些Android设备将同时存在这两个文件。

训练神经网络是CPU密集型的,这就是为什么您不想在应用程序的UI线程中进行训练。我不太确定DL4J是否在默认情况下异步训练其网络。为了安全起见,我现在将使用AsyncTask类生成一个单独的线程。

AsyncTask.execute(new Runnable() {
    @Override
    public void run() {
        createAndUseNetwork();
    }
});

因为createAndUseNetwork()方法还不存在,所以创建它。

private void createAndUseNetwork() {
}

DL4J有一个非常直观的API。现在让我们用它来创建一个简单的多层感知器与隐藏层。它将获取两个输入值,并输出一个输出值。要创建层,我们将使用DenseLayer和OutputLayer类。相应地,将以下代码添加到在上一步中创建的createAndUseNetwork()方法中:

DenseLayer inputLayer = new DenseLayer.Builder()
        .nIn(2)
        .nOut(3)
        .name("Input")
        .build();
DenseLayer hiddenLayer = new DenseLayer.Builder()
        .nIn(3)
        .nOut(2)
        .name("Hidden")
        .build();
OutputLayer outputLayer = new OutputLayer.Builder()
        .nIn(2)
        .nOut(1)
        .name("Output")
        .build();

现在我们的层已经准备好了,让我们创建一个NeuralNetConfiguration.Builder对象来配置我们的神经网络。

NeuralNetConfiguration.Builder nncBuilder = new NeuralNetConfiguration.Builder();
nncBuilder.updater(Updater.ADAM);

我们现在必须创建一个NeuralNetConfiguration.ListBuilder对象来实际连接我们的层并指定它们的顺序。

NeuralNetConfiguration.ListBuilder listBuilder = nncBuilder.list();
listBuilder.layer(0, inputLayer);
listBuilder.layer(1, hiddenLayer);
listBuilder.layer(2, outputLayer);

另外,通过添加以下代码启用反向传播:

listBuilder.backprop(true);

此时,我们可以将神经网络生成并初始化为多层网络类的实例。

MultiLayerNetwork myNetwork = new MultiLayerNetwork(listBuilder.build());
myNetwork.init();

为了创建我们的训练数据,我们将使用ND4J提供的INDArray类

INPUTS      EXPECTED OUTPUTS
------      ----------------
0,0         0
0,1         1
1,0         1
1,1         0

正如你可能已经猜到的,我们的神经网络将表现得像一个异或门。训练数据有四个样本,您必须在代码中提到它。

final int NUM_SAMPLES = 4;

现在,为输入和预期输出创建两个INDArray对象,并用零初始化它们。

INDArray trainingInputs = Nd4j.zeros(NUM_SAMPLES, inputLayer.getNIn());
INDArray trainingOutputs = Nd4j.zeros(NUM_SAMPLES, outputLayer.getNOut());

注意,输入数组中的列数等于输入层中的神经元数。类似地,输出数组中的列数等于输出层中的神经元数。

用训练数据填充这些数组很容易。只需使用putScalar()方法:

// If 0,0 show 0
trainingInputs.putScalar(new int[]{0, 0}, 0);
trainingInputs.putScalar(new int[]{0, 1}, 0);
trainingOutputs.putScalar(new int[]{0, 0}, 0);
// If 0,1 show 1
trainingInputs.putScalar(new int[]{1, 0}, 0);
trainingInputs.putScalar(new int[]{1, 1}, 1);
trainingOutputs.putScalar(new int[]{1, 0}, 1);
// If 1,0 show 1
trainingInputs.putScalar(new int[]{2, 0}, 1);
trainingInputs.putScalar(new int[]{2, 1}, 0);
trainingOutputs.putScalar(new int[]{2, 0}, 1);
// If 1,1 show 0
trainingInputs.putScalar(new int[]{3, 0}, 1);
trainingInputs.putScalar(new int[]{3, 1}, 1);
trainingOutputs.putScalar(new int[]{3, 0}, 0);

我们不会直接使用INDArray对象。相反,我们将把它们转换成一个DataSet。

DataSet myData = new DataSet(trainingInputs, trainingOutputs);

此时,我们可以通过调用神经网络的fit()方法并将数据集传递给它来开始训练。for循环控制通过网络的数据集的迭代。在本例中,它被设置为1000次迭代。

for(int l=0; l<=1000; l++) {
    myNetwork.fit(myData);
}

就这些。你的神经网络已经可以使用了。

在本教程中,您看到了在Android Studio项目中使用Deeplearning4J库创建和训练神经网络是多么容易。不过,我想提醒你的是,在低功耗、电池供电的设备上训练神经网络可能并不总是一个好主意。

第二个例子DL4J Android应用程序包括一个用户界面可以在这里找到。这个例子使用Anderson的iris数据集在设备上训练一个神经网络,用于iris类型分类。该应用程序包括用户输入的测量值,并返回这些测量值属于三种iris类型(Iris serosa, Iris versicolor, 和 Iris virginica)之一的概率。

移动设备处理能力和电池寿命的限制使得训练健壮、多层网络不可行。作为在设备上训练网络的替代方法,应用程序使用的神经网络可以在桌面机上训练,通过ModelSerializer保存,然后作为预先训练的模型加载到应用程序中。第三个例子DL4J Android应用程序可以在这里找到,它加载一个预先训练的MNIST网络,并使用它对用户绘制的数字进行分类。

配置你的Android Studio项目
启动异步任务
创建一个神经网络
创建训练数据
结论
Deeplearning4J
先决条件
先决条件
配置你的Android Studio项目
启动异步任务
创建一个神经网络
创建训练数据
结论