日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

作者:DJL-Keerthan&Lanking

 

HelloGitHub 推出的《講解開源項(xiàng)目》 系列。這一期是由亞馬遜工程師:Keerthan Vasist,為我們講解 DJL(完全由 JAVA 構(gòu)建的深度學(xué)習(xí)平臺(tái))系列的第 4 篇。

一、前言

很長時(shí)間以來,Java 都是一個(gè)很受企業(yè)歡迎的編程語言。得益于豐富的生態(tài)以及完善維護(hù)的包和框架,Java 擁有著龐大的開發(fā)者社區(qū)。盡管深度學(xué)習(xí)應(yīng)用的不斷演進(jìn)和落地,提供給 Java 開發(fā)者的框架和庫卻十分短缺。現(xiàn)今主要流行的深度學(xué)習(xí)模型都是用 Python 編譯和訓(xùn)練的。對于 Java 開發(fā)者而言,如果要進(jìn)軍深度學(xué)習(xí)界,就需要重新學(xué)習(xí)并接受一門新的編程語言同時(shí)還要學(xué)習(xí)深度學(xué)習(xí)的復(fù)雜知識(shí)。這使得大部分 Java 開發(fā)者學(xué)習(xí)和轉(zhuǎn)型深度學(xué)習(xí)開發(fā)變得困難重重。

 

為了減少 Java 開發(fā)者學(xué)習(xí)深度學(xué)習(xí)的成本,AWS 構(gòu)建了 Deep Java Library (DJL),一個(gè)為 Java 開發(fā)者定制的開源深度學(xué)習(xí)框架。它為 Java 開發(fā)者對接主流深度學(xué)習(xí)框架提供了一個(gè)橋梁。

用 Java 訓(xùn)練深度學(xué)習(xí)模型,原來能這么簡單

 

在這篇文章中,我們會(huì)嘗試用 DJL 構(gòu)建一個(gè)深度學(xué)習(xí)模型并用它訓(xùn)練 MNIST 手寫數(shù)字識(shí)別任務(wù)。

二、什么是深度學(xué)習(xí)?

在我們正式開始之前,我們先來了解一下機(jī)器學(xué)習(xí)和深度學(xué)習(xí)的基本概念。

 

機(jī)器學(xué)習(xí)是一個(gè)通過利用統(tǒng)計(jì)學(xué)知識(shí),將數(shù)據(jù)輸入到計(jì)算機(jī)中進(jìn)行訓(xùn)練并完成特定目標(biāo)任務(wù)的過程。這種歸納學(xué)習(xí)的方法可以讓計(jì)算機(jī)學(xué)習(xí)一些特征并進(jìn)行一系列復(fù)雜的任務(wù),比如識(shí)別照片中的物體。由于需要寫復(fù)雜的邏輯以及測量標(biāo)準(zhǔn),這些任務(wù)在傳統(tǒng)計(jì)算科學(xué)領(lǐng)域中很難實(shí)現(xiàn)。

 

深度學(xué)習(xí)是機(jī)器學(xué)習(xí)的一個(gè)分支,主要側(cè)重于對于人工神經(jīng)網(wǎng)絡(luò)的開發(fā)。人工神經(jīng)網(wǎng)絡(luò)是通過研究人腦如何學(xué)習(xí)和實(shí)現(xiàn)目標(biāo)的過程中歸納而得出一套計(jì)算邏輯。它通過模擬部分人腦神經(jīng)間信息傳遞的過程,從而實(shí)現(xiàn)各類復(fù)雜的任務(wù)。深度學(xué)習(xí)中的“深度”來源于我們會(huì)在人工神經(jīng)網(wǎng)絡(luò)中編織構(gòu)建出許多層(layer)從而進(jìn)一步對數(shù)據(jù)信息進(jìn)行更深層的傳導(dǎo)。深度學(xué)習(xí)技術(shù)應(yīng)用范圍十分廣泛,現(xiàn)在被用來做目標(biāo)檢測、動(dòng)作識(shí)別、機(jī)器翻譯、語意分析等各類現(xiàn)實(shí)應(yīng)用中。

三、訓(xùn)練 MNIST 手寫數(shù)字識(shí)別

3.1 項(xiàng)目配置

你可以用如下的 gradle 配置來引入依賴項(xiàng)。在這個(gè)案例中,我們用 DJL 的 api 包 (核心 DJL 組件) 和 basicdataset 包 (DJL 數(shù)據(jù)集) 來構(gòu)建神經(jīng)網(wǎng)絡(luò)和數(shù)據(jù)集。這個(gè)案例中我們使用了 MXNet 作為深度學(xué)習(xí)引擎,所以我們會(huì)引入 mxnet-engine 和 mxnet-native-auto 兩個(gè)包。這個(gè)案例也可以運(yùn)行在 PyTorch 引擎下,只需要替換成對應(yīng)的軟件包即可。

plugins {
    id 'java'
}
repositories {                           
    jcenter()
}
dependencies {
    implementation platform("ai.djl:bom:0.8.0")
    implementation "ai.djl:api"
    implementation "ai.djl:basicdataset"
    // MXNet
    runtimeOnly "ai.djl.mxnet:mxnet-engine"
    runtimeOnly "ai.djl.mxnet:mxnet-native-auto"
}

3.2 NDArray 和 NDManager

NDArray 是 DJL 存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)和數(shù)學(xué)運(yùn)算的基本結(jié)構(gòu)。一個(gè) NDArray 表達(dá)了一個(gè)定長的多維數(shù)組。NDArray 的使用方法類似于 Python 中的 numpy.ndarray。

 

NDManager 是 NDArray 的老板。它負(fù)責(zé)管理 NDArray 的產(chǎn)生和回收過程,這樣可以幫助我們更好的對 Java 內(nèi)存進(jìn)行優(yōu)化。每一個(gè) NDArray 都會(huì)是由一個(gè) NDManager 創(chuàng)造出來,同時(shí)它們會(huì)在 NDManager 關(guān)閉時(shí)一同關(guān)閉。

 

NDManager 和 NDArray 都是由 Java 的 AutoClosable 構(gòu)建,這樣可以確保在運(yùn)行結(jié)束時(shí)及時(shí)進(jìn)行回收。想了解更多關(guān)于它們的用法和實(shí)踐,請參閱我們前一期文章:DJL 之 Java 玩轉(zhuǎn)多維數(shù)組,就像 NumPy 一樣

 

Model

在 DJL 中,訓(xùn)練和推理都是從 Model class 開始構(gòu)建的。我們在這里主要講訓(xùn)練過程中的構(gòu)建方法。下面我們?yōu)?Model 創(chuàng)建一個(gè)新的目標(biāo)。因?yàn)?Model 也是繼承了 AutoClosable 結(jié)構(gòu)體,我們會(huì)用一個(gè) try block 實(shí)現(xiàn):

try (Model model = Model.newInstance()) {
    ...
    // 主體訓(xùn)練代碼
    ...
}

準(zhǔn)備數(shù)據(jù)

MNIST(Modified National Institute of Standards and Technology)數(shù)據(jù)庫包含大量手寫數(shù)字的圖,通常被用來訓(xùn)練圖像處理系統(tǒng)。DJL 已經(jīng)將 MNIST 的數(shù)據(jù)集收錄到了 basicdataset 數(shù)據(jù)集里,每個(gè) MNIST 的圖的大小是 28 x 28。如果你有自己的數(shù)據(jù)集,你也可以通過 DJL 數(shù)據(jù)集導(dǎo)入教程來導(dǎo)入數(shù)據(jù)集到你的訓(xùn)練任務(wù)中。

int batchSize = 32; // 批大小
Mnist trainingDataset = Mnist.builder()
        .optUsage(Usage.TRAIN) // 訓(xùn)練集
        .setSampling(batchSize, true)
        .build();
Mnist validationDataset = Mnist.builder()
        .optUsage(Usage.TEST) // 驗(yàn)證集
        .setSampling(batchSize, true)
        .build();

這段代碼分別制作出了訓(xùn)練和驗(yàn)證集。同時(shí)我們也隨機(jī)排列了數(shù)據(jù)集從而更好的訓(xùn)練。除了這些配置以外,你也可以添加對于圖片的進(jìn)一步處理,比如設(shè)置圖片大小,對圖片進(jìn)行歸一化等處理。

制作 model(建立 Block)

當(dāng)你的數(shù)據(jù)集準(zhǔn)備就緒后,我們就可以構(gòu)建神經(jīng)網(wǎng)絡(luò)了。在 DJL 中,神經(jīng)網(wǎng)絡(luò)是由 Block(代碼塊)構(gòu)成的。一個(gè) Block 是一個(gè)具備多種神經(jīng)網(wǎng)絡(luò)特性的結(jié)構(gòu)。它們可以代表 一個(gè)操作, 神經(jīng)網(wǎng)絡(luò)的一部分,甚至是一個(gè)完整的神經(jīng)網(wǎng)絡(luò)。然后 Block 可以順序執(zhí)行或者并行。同時(shí) Block 本身也可以帶參數(shù)和子 Block。這種嵌套結(jié)構(gòu)可以幫助我們構(gòu)造一個(gè)復(fù)雜但又不失維護(hù)性的神經(jīng)網(wǎng)絡(luò)。在訓(xùn)練過程中,每個(gè) Block 中附帶的參數(shù)會(huì)被實(shí)時(shí)更新,同時(shí)也包括它們的各個(gè)子 Block。這種遞歸更新的過程可以確保整個(gè)神經(jīng)網(wǎng)絡(luò)得到充分訓(xùn)練。

 

當(dāng)我們構(gòu)建這些 Block 的過程中,最簡單的方式就是將它們一個(gè)一個(gè)的嵌套起來。直接使用準(zhǔn)備好 DJL 的 Block 種類,我們就可以快速制作出各類神經(jīng)網(wǎng)絡(luò)。

 

根據(jù)幾種基本的神經(jīng)網(wǎng)絡(luò)工作模式,我們提供了幾種 Block 的變體。SequentialBlock 是為了應(yīng)對順序執(zhí)行每一個(gè)子 Block 構(gòu)造而成的。它會(huì)將前一個(gè)子 Block 的輸出作為下一個(gè) Block 的輸入 繼續(xù)執(zhí)行到底。與之對應(yīng)的,是 ParallelBlock 它用于將一個(gè)輸入并行輸入到每一個(gè)子 Block 中,同時(shí)將輸出結(jié)果根據(jù)特定的合并方程合并起來。最后我們說一下 LambdaBlock,它是幫助用戶進(jìn)行快速操作的一個(gè) Block,其中并不具備任何參數(shù),所以也沒有任何部分在訓(xùn)練過程中更新。

用 Java 訓(xùn)練深度學(xué)習(xí)模型,原來能這么簡單

 

我們來嘗試創(chuàng)建一個(gè)基本的 多層感知機(jī)(MLP)神經(jīng)網(wǎng)絡(luò)吧。多層感知機(jī)是一個(gè)簡單的前向型神經(jīng)網(wǎng)絡(luò),它只包含了幾個(gè)全連接層 (LinearBlock)。那么構(gòu)建這個(gè)網(wǎng)絡(luò),我們可以直接使用 SequentialBlock。

int input = 28 * 28; // 輸入層大小
int output = 10; // 輸出層大小
int[] hidden = new int[] {128, 64}; // 隱藏層大小
SequentialBlock sequentialBlock = new SequentialBlock();
sequentialBlock.add(Blocks.batchFlattenBlock(input));
for (int hiddenSize : hidden) {
    // 全連接層
    sequentialBlock.add(Linear.builder().setUnits(hiddenSize).build());
    // 激活函數(shù)
    sequentialBlock.add(activation);
}
sequentialBlock.add(Linear.builder().setUnits(output).build());

當(dāng)然 DJL 也提供了直接就可以拿來用的 MLP Block :

Block block = new Mlp(
        Mnist.IMAGE_HEIGHT * Mnist.IMAGE_WIDTH,
        Mnist.NUM_CLASSES,
        new int[] {128, 64});

訓(xùn)練

當(dāng)我們準(zhǔn)備好數(shù)據(jù)集和神經(jīng)網(wǎng)絡(luò)之后,就可以開始訓(xùn)練模型了。在深度學(xué)習(xí)中,一般會(huì)由下面幾步來完成一個(gè)訓(xùn)練過程:

用 Java 訓(xùn)練深度學(xué)習(xí)模型,原來能這么簡單

 

  • 初始化:我們會(huì)對每一個(gè) Block 的參數(shù)進(jìn)行初始化,初始化每個(gè)參數(shù)的函數(shù)都是由 設(shè)定的 Initializer 決定的。
  • 前向傳播:這一步將輸入數(shù)據(jù)在神經(jīng)網(wǎng)絡(luò)中逐層傳遞,然后產(chǎn)生輸出數(shù)據(jù)。
  • 計(jì)算損失:我們會(huì)根據(jù)特定的損失函數(shù) Loss 來計(jì)算輸出和標(biāo)記結(jié)果的偏差。
  • 反向傳播:在這一步中,你可以利用損失反向求導(dǎo)算出每一個(gè)參數(shù)的梯度。
  • 更新權(quán)重:我們會(huì)根據(jù)選擇的優(yōu)化器(Optimizer)更新每一個(gè)在 Block 上參數(shù)的值。

DJL 利用了 Trainer 結(jié)構(gòu)體精簡了整個(gè)過程。開發(fā)者只需要?jiǎng)?chuàng)建 Trainer 并指定對應(yīng)的 Initializer、Loss 和 Optimizer 即可。這些參數(shù)都是由 TrainingConfig 設(shè)定的。下面我們來看一下具體的參數(shù)設(shè)置:

  • TrainingListener:這個(gè)是對訓(xùn)練過程設(shè)定的監(jiān)聽器。它可以實(shí)時(shí)反饋每個(gè)階段的訓(xùn)練結(jié)果。這些結(jié)果可以用于記錄訓(xùn)練過程或者幫助 debug 神經(jīng)網(wǎng)絡(luò)訓(xùn)練過程中的問題。用戶也可以定制自己的 TrainingListener 來對訓(xùn)練過程進(jìn)行監(jiān)聽。
DefaultTrainingConfig config = new DefaultTrainingConfig(Loss.softmaxCrossEntropyLoss())
    .addEvaluator(new Accuracy())
    .addTrainingListeners(TrainingListener.Defaults.logging());
try (Trainer trainer = model.newTrainer(config)){
    // 訓(xùn)練代碼
}

當(dāng)訓(xùn)練器產(chǎn)生后,我們可以定義輸入的 Shape。之后就可以調(diào)用 fit 函數(shù)來進(jìn)行訓(xùn)練。fit 函數(shù)會(huì)對輸入數(shù)據(jù),訓(xùn)練多個(gè) epoch 是并最終將結(jié)果存儲(chǔ)在本地目錄下。

/*
 * MNIST 包含 28x28 灰度圖片并導(dǎo)入成 28 * 28 NDArray。
 * 第一個(gè)維度是批大小, 在這里我們設(shè)置批大小為 1 用于初始化。
 */
Shape inputShape = new Shape(1, Mnist.IMAGE_HEIGHT * Mnist.IMAGE_WIDTH);
int numEpoch = 5;
String outputDir = "/build/model";

// 用輸入初始化 trainer
trainer.initialize(inputShape);

TrainingUtils.fit(trainer, numEpoch, trainingSet, validateSet, outputDir, "mlp");

這就是訓(xùn)練過程的全部流程了!用 DJL 訓(xùn)練是不是還是很輕松的?之后看一下輸出每一步的訓(xùn)練結(jié)果。如果你用了我們默認(rèn)的監(jiān)聽器,那么輸出是類似于下圖:

[INFO ] - Downloading libmxnet.dylib ...
[INFO ] - Training on: cpu().
[INFO ] - Load MXNet Engine Version 1.7.0 in 0.131 ms.
Training:    100% |████████████████████████████████████████| Accuracy: 0.93, SoftmaxCrossEntropyLoss: 0.24, speed: 1235.20 items/sec
Validating:  100% |████████████████████████████████████████|
[INFO ] - Epoch 1 finished.
[INFO ] - Train: Accuracy: 0.93, SoftmaxCrossEntropyLoss: 0.24
[INFO ] - Validate: Accuracy: 0.95, SoftmaxCrossEntropyLoss: 0.14
Training:    100% |████████████████████████████████████████| Accuracy: 0.97, SoftmaxCrossEntropyLoss: 0.10, speed: 2851.06 items/sec
Validating:  100% |████████████████████████████████████████|
[INFO ] - Epoch 2 finished.NG [1m 41s]
[INFO ] - Train: Accuracy: 0.97, SoftmaxCrossEntropyLoss: 0.10
[INFO ] - Validate: Accuracy: 0.97, SoftmaxCrossEntropyLoss: 0.09
[INFO ] - train P50: 12.756 ms, P90: 21.044 ms
[INFO ] - forward P50: 0.375 ms, P90: 0.607 ms
[INFO ] - training-metrics P50: 0.021 ms, P90: 0.034 ms
[INFO ] - backward P50: 0.608 ms, P90: 0.973 ms
[INFO ] - step P50: 0.543 ms, P90: 0.869 ms
[INFO ] - epoch P50: 35.989 s, P90: 35.989 s

當(dāng)訓(xùn)練結(jié)果完成后,我們可以用剛才的模型進(jìn)行推理來識(shí)別手寫數(shù)字。

四、最后

在這個(gè)文章中,我們介紹了深度學(xué)習(xí)的基本概念,同時(shí)還有如何優(yōu)雅的利用 DJL 構(gòu)建深度學(xué)習(xí)模型并進(jìn)行訓(xùn)練。

分享到:
標(biāo)簽:深度 學(xué)習(xí)
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定