Java深度學(xué)習(xí)庫(kù)DJL實(shí)現(xiàn)Python的NumPy方式
1 NDArray 的背景介紹
在Python的世界,調(diào)用NDArray的標(biāo)準(zhǔn)包叫做NumPy。為了給Java開發(fā)者創(chuàng)造同一種工具,亞馬遜云服務(wù)開源了DJL,一個(gè)基于Java的深度學(xué)習(xí)庫(kù)。盡管它包含了深度學(xué)習(xí)模塊,但是它最核心的NDArray庫(kù)可以被用作NumPy的java替代工具庫(kù)。
官網(wǎng):https://djl.ai/
同時(shí)它具備優(yōu)良的可擴(kuò)展性,全平臺(tái)支持,以及強(qiáng)大的后端引擎支持 TensorFlowPaddlePaddle, PyTorch, Apache MXNet等)。無論是CPU還是GPU, PC還是安卓,DJL都可以輕而易舉的完成任務(wù)。
1.1 架構(gòu)
在這個(gè)系列文章中,我們將帶你了解NDArray,并且教你如何寫與Numpy同樣簡(jiǎn)單的Java代碼以及如何將NDArray使用在現(xiàn)實(shí)中的應(yīng)用之中。
NDArray相當(dāng)于python numpy的java實(shí)現(xiàn),解決復(fù)雜的矩陣運(yùn)算問題。多維數(shù)組存在于native C++ 內(nèi)存里,如此可以方便調(diào)用下面的加速庫(kù):
- 矩陣加速庫(kù):LAPACK, BLAS
- CPU加速庫(kù):oneDNN(MKLDNN)
- GPU加速庫(kù):CUDA, cuDNN
NDArray提供了豐富的api,如:
- 四則運(yùn)算: add, sub, mul, div, …
- 矩陣運(yùn)算:matMul
- 比較運(yùn)算:eq, gt, ….
- 歸約運(yùn)算:sum, max, min, …
- 其它運(yùn)算:abs, exp,…
- 改變形狀:reshape, swapAxes, …
為了更好的管理NDArray,管理數(shù)據(jù)的創(chuàng)建及生命周期, 創(chuàng)建所有NDArray都需要通過NDManager。如此可以高效的利用內(nèi)存,防止內(nèi)存泄露等問題。
NDManager是DJL中的一個(gè)class可以幫助管理NDArray的內(nèi)存使用。通過創(chuàng)建NDManager,可以及時(shí)的對(duì)內(nèi)存進(jìn)行清理。當(dāng)這個(gè)block里的任務(wù)運(yùn)行完成時(shí),內(nèi)部產(chǎn)生的NDArray都會(huì)被清理掉。這個(gè)設(shè)計(jì)保證了我們?cè)诖笠?guī)模使用NDArray的過程中,可以更高效的利用內(nèi)存。
try (NDManager manager = NDManager.newBaseManager()) { ... }
熟練掌握了NDArray的使用后,除了可以完成復(fù)雜的矩陣處理,計(jì)算外,如何用于模型的推理部署呢?
模型的推理可以概括為三個(gè)步驟:
- 數(shù)據(jù)預(yù)處理
- 推理
- 數(shù)據(jù)后處理
在預(yù)處理過程中,我們需要完成把圖片轉(zhuǎn)成RGB數(shù)組,把文字轉(zhuǎn)換成索引id,把音頻轉(zhuǎn)換成float數(shù)組,數(shù)據(jù)歸一化等操作。
在后處理過程中,我們需要完成把概率轉(zhuǎn)換為對(duì)應(yīng)的標(biāo)簽,把文字索引轉(zhuǎn)換回文字等操作。
在數(shù)據(jù)預(yù)處理/數(shù)據(jù)后處理過程中,NDArray起了最關(guān)鍵的作用。
DJL為了統(tǒng)一代碼處理邏輯,增加代碼的復(fù)用性,提供了高級(jí)接口Translator:
public NDList processInput(TranslatorContext ctx, I) public O processOutput(TranslatorContext ctx, NDList list) 12
對(duì)NDArray有了基本的了解后,通過學(xué)習(xí)后續(xù)的教程,可以進(jìn)一步掌握NDArray的使用。
2 JavaDJL使用
隨著數(shù)據(jù)科學(xué)在生產(chǎn)中的應(yīng)用逐步增加,使用N維數(shù)組靈活的表達(dá)數(shù)據(jù)變得愈發(fā)重要。我們可以將過去數(shù)據(jù)科學(xué)運(yùn)算中的多維循環(huán)嵌套運(yùn)算簡(jiǎn)化為簡(jiǎn)單幾行。由于進(jìn)一步釋放了計(jì)算并行能力,這幾行簡(jiǎn)單的代碼運(yùn)算速度也會(huì)比傳統(tǒng)多維循環(huán)快很多。這種數(shù)學(xué)計(jì)算的包已經(jīng)成為于數(shù)據(jù)科學(xué),圖形學(xué)以及機(jī)器學(xué)習(xí)領(lǐng)域的標(biāo)準(zhǔn)。同時(shí)它的影響力還在不斷的擴(kuò)大到其他領(lǐng)域。
在Python的世界,調(diào)用NDArray的標(biāo)準(zhǔn)包叫做NumPy。但是如今在Java領(lǐng)域中,并沒有與之同樣標(biāo)準(zhǔn)的庫(kù)。為了給Java開發(fā)者創(chuàng)造同一種使用環(huán)境,亞馬遜云服務(wù)開源了DJL,一個(gè)基于Java的深度學(xué)習(xí)庫(kù)。盡管它包含了深度學(xué)習(xí)模塊,但是它最核心的NDArray系統(tǒng)可以被用作N維數(shù)組的標(biāo)準(zhǔn)。它具備優(yōu)良的可擴(kuò)展性,全平臺(tái)支持,以及強(qiáng)大的后端引擎支持(TensorFlow、PyTorch、Apache MXNet)。無論是CPU還是GPU,PC還是安卓,DJL都可以輕而易舉的完成任務(wù)。
2.1 安裝DJL
可以通過下方的配置來配置gradle項(xiàng)目,或者也可以跳過設(shè)置直接使用我們的
plugins { id 'java' } repositories { jcenter() } dependencies { implementation "ai.djl:api:0.6.0" // PyTorch runtimeOnly "ai.djl.pytorch:pytorch-engine:0.6.0" runtimeOnly "ai.djl.pytorch:pytorch-native-auto:1.5.0" }
然后,我們就可以開始上手寫代碼了。
2.2 基本操作
首先嘗試建立一個(gè)Try block來包含我們的代碼(如果使用在線JShell可跳過此步):
try(NDManager manager = NDManager.newBaseManager()) { }
NDManager是DJL中的一個(gè)Class,可以幫助管理NDArray的內(nèi)存使用。通過創(chuàng)建NDManager,我們可以更及時(shí)地對(duì)內(nèi)存進(jìn)行清理。當(dāng)這個(gè)Block里的任務(wù)運(yùn)行完成時(shí),內(nèi)部產(chǎn)生的NDArray都會(huì)被清理掉。這個(gè)設(shè)計(jì)保證了我們?cè)诖笠?guī)模使用NDArray的過程中,可以通過清理其中的NDManager來更高效地利用內(nèi)存。為了做對(duì)比,我們可以參考NumPy在Python之中的應(yīng)用。
import numpy as np
2.3 創(chuàng)建NDArray
Ones
是一個(gè)創(chuàng)建全是1的N維數(shù)組操作。
Python (Numpy)
nd = np.ones((2, 3)) [[1. 1. 1.] [1. 1. 1.]]
Java (DJL NDArray)
NDArray nd = manager.ones(new Shape(2, 3)); /* ND: (2, 3) cpu() float32 [[1., 1., 1.], [1., 1., 1.], ] */
我們也可以嘗試生成隨機(jī)數(shù)。比如需要生成一些從0到1的隨機(jī)數(shù):
Python (Numpy)
nd = np.random.uniform(0, 1, (1, 1, 4)) # [[[0.7034806 0.85115891 0.63903668 0.39386125]]]
Java (DJL NDArray)
NDArray nd = manager.randomUniform(0, 1, new Shape(1, 1, 4)); /* ND: (1, 1, 4) cpu() float32 [[[0.932 , 0.7686, 0.2031, 0.7468], ], ] */
這只是簡(jiǎn)單演示一些常用功能?,F(xiàn)在NDManager支持多達(dá)20種在NumPy中創(chuàng)建NDArray的方法。
2.4 數(shù)學(xué)運(yùn)算
我們可以使用NDArray進(jìn)行一系列數(shù)學(xué)操作。假設(shè)想對(duì)數(shù)據(jù)做一個(gè)轉(zhuǎn)置操作,然后對(duì)所有數(shù)據(jù)加一個(gè)數(shù)的操作??梢詤⒖既缦碌膶?shí)現(xiàn):
Python (Numpy)
nd = np.arange(1, 10).reshape(3, 3) nd = nd.transpose() nd = nd + 10 [[11 14 17] [12 15 18] [13 16 19]]
Java (DJL NDArray)
NDArray nd = manager.arange(1, 10).reshape(3, 3); nd = nd.transpose(); nd = nd.add(10); /* ND: (3, 3) cpu() int32 [[11, 14, 17], [12, 15, 18], [13, 16, 19], ] */
DJL現(xiàn)在支持60多種不同的NumPy數(shù)學(xué)運(yùn)算,基本涵蓋了大部分的應(yīng)用場(chǎng)景。
2.5 Get和Set
其中一個(gè)對(duì)于NDArray最重要的亮點(diǎn)就是它輕松簡(jiǎn)單的數(shù)據(jù)設(shè)置/獲取功能。我們參考了NumPy的設(shè)計(jì),將Java過去對(duì)于數(shù)據(jù)表達(dá)中的困難做了精簡(jiǎn)化處理。假設(shè)想篩選一個(gè)N維數(shù)組所有小于10的數(shù):
Python (Numpy)
nd = np.arange(5, 14) nd = nd[nd >= 10] # [10 11 12 13]
Java (DJL NDArray)
NDArray nd = manager.arange(5, 14); nd = nd.get(nd.gte(10)); /* ND: (4) cpu() int32 [10, 11, 12, 13] */
是不是非常簡(jiǎn)單?接下來,我們看一個(gè)稍微復(fù)雜一些的應(yīng)用場(chǎng)景。假設(shè)現(xiàn)在有一個(gè)3×3的矩陣,然后我們想把第二列的數(shù)據(jù)都乘以2:
Python (Numpy)
nd = np.arange(1, 10).reshape(3, 3) nd[:, 1] *= 2 [[ 1 4 3] [ 4 10 6] [ 7 16 9]]
Java (DJL NDArray)
NDArray nd = manager.arange(1, 10).reshape(3, 3); nd.set(new NDIndex(":, 1"), array -> array.mul(2)); /* ND: (3, 3) cpu() int32 [[ 1, 4, 3], [ 4, 10, 6], [ 7, 16, 9], ] */
在上面的案例中,我們?cè)贘ava引入了一個(gè)NDIndex的Class。它復(fù)刻了大部分在NumPy中對(duì)于NDArray支持的get/set操作。只需要簡(jiǎn)單的放進(jìn)去一個(gè)字符串表達(dá)式,開發(fā)者在Java中可以輕松玩轉(zhuǎn)各種數(shù)組的操作。
現(xiàn)實(shí)中的應(yīng)用場(chǎng)景
上述的操作對(duì)于龐大的數(shù)據(jù)集是十分有幫助的?,F(xiàn)在我們來看一下這個(gè)應(yīng)用場(chǎng)景:基于單詞的分類系統(tǒng)訓(xùn)練。在這個(gè)場(chǎng)景中,開發(fā)者想要利用從用戶中獲取的數(shù)據(jù)來進(jìn)行情感分析預(yù)測(cè)。NDArray被應(yīng)用在了對(duì)于數(shù)據(jù)進(jìn)行前后處理的工作中。
2.6 分詞操作
在輸入到NDArray數(shù)據(jù)前,我們需要對(duì)于輸入的字符串進(jìn)行分詞操作并編碼成數(shù)字。
下面代碼中看到的Tokenizer是一個(gè)Map<String, Integer>。它是一個(gè)單詞到字典位置的映射。
String text = "The rabbit cross the street and kick the fox"; String[] tokens = text.toLowerCase().split(" "); int[] vector = new int[tokens.length]; /* String[9] { "the", "rabbit", "cross", "the", "street", "and", "kick", "the", "fox" } */ for (int i = 0; i < tokens.length; i++) { vector[i] = tokenizer.get(tokens[i]); } vector /* int[9] { 1, 6, 5, 1, 3, 2, 8, 1, 12 } */
2.7 NDArray處理
經(jīng)過編碼操作后,我們創(chuàng)建了NDArray。然后需要轉(zhuǎn)化數(shù)據(jù)的結(jié)構(gòu):
NDArray array = manager.create(vector); array = array.reshape(new Shape(vector.length, 1)); // form a batch array = array.div(10.0); /* ND: (9, 1) cpu() float64 [[0.1], [0.6], [0.5], [0.1], [0.3], [0.2], [0.8], [0.1], [1.2], ] */
最后,我們將數(shù)據(jù)傳入深度學(xué)習(xí)模型中。如果使用Java要達(dá)到這些需要更多的工作量:如果需要實(shí)現(xiàn)類似于Reshape的方法,我們需要?jiǎng)?chuàng)建一個(gè)N維數(shù)組:List<List<List<…List…>>>來保證不同維度的可操作性。同時(shí)我們需要能夠支持插入新的List來創(chuàng)建最終的數(shù)據(jù)格式。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于spring boot實(shí)現(xiàn)一個(gè)全局異常處理器
在項(xiàng)目開發(fā)中,我們可以基于spring boot提供的切面特性,來很輕松的實(shí)現(xiàn)全局異常的處理,所以本文主要為大家介紹了如何基于spring boot實(shí)現(xiàn)一個(gè)全局異常處理器,有需要的可以參考下2023-09-09Java中的@Conditional條件注解詳細(xì)解析
這篇文章主要介紹了Java中的@Conditional條件注解詳細(xì)解析,@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件給容器注冊(cè)bean,需要的朋友可以參考下2023-11-11java鏈表數(shù)據(jù)結(jié)構(gòu)LinkedList插入刪除元素時(shí)間復(fù)雜度面試精講
這篇文章主要為大家介紹了java LinkedList插入和刪除元素的時(shí)間復(fù)雜度面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10Mybatis多參數(shù)及實(shí)體對(duì)象傳遞實(shí)例講解
在使用Mybatis的時(shí)候,經(jīng)常會(huì)有各種各樣的參數(shù)傳遞,不同類型,不同個(gè)數(shù)的參數(shù),下面小編通過例子給大家講解下Mybatis多參數(shù)及實(shí)體對(duì)象傳遞,一起看看吧2016-12-12Java設(shè)置session超時(shí)的幾種方式總結(jié)
這篇文章主要介紹了Java設(shè)置session超時(shí)的幾種方式總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-07-07SpringSecurity在SpringBoot中的自動(dòng)裝配過程
這篇文章主要介紹了SpringSecurity在SpringBoot中的自動(dòng)裝配過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07springboot開啟mybatis駝峰命名自動(dòng)映射的三種方式
這篇文章給大家總結(jié)springboot開啟mybatis駝峰命名自動(dòng)映射的三種方式,文章并通過代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-02-02Java was started but returned exit code=13問題解決案例詳解
這篇文章主要介紹了Java was started but returned exit code=13問題解決案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09SpringSecurity數(shù)據(jù)庫(kù)進(jìn)行認(rèn)證和授權(quán)的使用
本文主要介紹了用戶的賬號(hào)、密碼以及角色信息在數(shù)據(jù)庫(kù)中的認(rèn)證和授權(quán),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08