Java為什么不能真正支持機(jī)器/深度學(xué)習(xí)?到底還欠缺了什么
如何讓團(tuán)隊(duì)開(kāi)始使用ML以及如何最好地將ML與我們運(yùn)行的現(xiàn)有系統(tǒng)集成?
實(shí)際上沒(méi)有用Java構(gòu)建的ML框架(有DL4J,但我真的不知道有誰(shuí)使用它,MXNet有一個(gè)Scala API而不是Java,而且它不是用Java編寫(xiě)的,Tensorflow有一個(gè)不完整的Java API),但是Java在企業(yè)中擁有巨大的使用范圍,在過(guò)去的20年中,在全球范圍內(nèi)投資了數(shù)萬(wàn)億美元的金融服務(wù),交易,電子商務(wù)和電信公司 - 這個(gè)名單是無(wú)窮無(wú)盡的。對(duì)于機(jī)器學(xué)習(xí),“第一個(gè)公民”編程語(yǔ)言不是Java,而是Python。
就個(gè)人而言,我喜歡用Python和Java編寫(xiě)代碼,但Frank Greco提出了一個(gè)讓我思考的有趣問(wèn)題:
Java還需要什么才可在ML中與Python競(jìng)爭(zhēng)?如果Java認(rèn)真對(duì)待真正支持機(jī)器學(xué)習(xí)怎么辦?
很重要么?
自1998年以來(lái),就多個(gè)企業(yè)的變革而言,Java一直處于領(lǐng)先地位 - 網(wǎng)絡(luò),移動(dòng),瀏覽器與原生,消息傳遞,i18n和l10n全球化支持,擴(kuò)展和支持各種企業(yè)信息存儲(chǔ)值得一提的是,從關(guān)系數(shù)據(jù)庫(kù)到Elasticsearch。
機(jī)器學(xué)習(xí)行業(yè)并非如此。Java團(tuán)隊(duì)如果進(jìn)入ML只能有兩個(gè)選擇:
- 在Python中重新訓(xùn)練/共同訓(xùn)練。
- 使用供應(yīng)商API為您的企業(yè)系統(tǒng)添加機(jī)器學(xué)習(xí)功能。
這兩種選擇都不是真的很好。第一個(gè)需要大量的前期時(shí)間和投資加上持續(xù)的維護(hù)成本,而第二個(gè)風(fēng)險(xiǎn)是供應(yīng)商鎖定,供應(yīng)商解除支持,引入第三方組件(需要支付網(wǎng)絡(luò)價(jià)格),這可能是一個(gè)性能關(guān)鍵系統(tǒng),并且需要您可以在組織邊界之外共享數(shù)據(jù) - 對(duì)某些人來(lái)說(shuō)是不行的。
在我看來(lái),最具破壞性的是文化消耗的可能性?- 團(tuán)隊(duì)無(wú)法改變他們不理解或無(wú)法維護(hù)的代碼,Java團(tuán)隊(duì)有可能在企業(yè)計(jì)算的下一波浪潮機(jī)器學(xué)習(xí)浪潮中落后 。
因此,Java編程語(yǔ)言和平臺(tái)擁有一流的機(jī)器學(xué)習(xí)支持是非常重要,如果沒(méi)有,Java將面臨被未來(lái)5到10年內(nèi)支持ML的語(yǔ)言慢慢取代的風(fēng)險(xiǎn)。
為什么Python在ML中占據(jù)主導(dǎo)地位?
首先,讓我們考慮為什么Python是機(jī)器學(xué)習(xí)和深度學(xué)習(xí)的主要語(yǔ)言。
我懷疑這一切都始于一個(gè)功能 - 列表的切片slicing支持。這種支持是可擴(kuò)展的:任何實(shí)現(xiàn)__getitem__和__setitem__方法的Python類都可以使用這種語(yǔ)法進(jìn)行切片。下面的代碼段顯示了這個(gè)Python功能的強(qiáng)大和自然性。
a = [1, 2, 3, 4, 5, 6, 7, 8]
print(a[1:4])
#returns [2, 3, 4] - -挑選出中間元素的切片
print(a[1:-1])
#returns [2, 3, 4, 5, 6, 7] - 跳過(guò)第0和最后一個(gè)元素
print(a[4:])
#returns [5, 6, 7, 8] - 終點(diǎn)默認(rèn)
print(a[:4])
#returns [1, 2, 3, 4] -開(kāi)始點(diǎn)被默認(rèn)
當(dāng)然,還有更多。與舊的Java代碼相比,Python代碼更簡(jiǎn)潔,更簡(jiǎn)潔。支持未經(jīng)檢查的異常,開(kāi)發(fā)人員可以輕松地編寫(xiě)一次性Python腳本來(lái)嘗試填充,而不會(huì)陷入“一切都是一個(gè)類”的Java思維模式中。使用Python很容易。
但是現(xiàn)在我認(rèn)為是主要因素 - 盡管Python社區(qū)在維持2.7和3之間的凝聚力方面做了一頓狗晚餐,但他們?cè)跇?gòu)建設(shè)計(jì)良好,快速的數(shù)字計(jì)算庫(kù)(NumPy)方面做得更好 。Numpy是圍繞ndarray構(gòu)建的 - N維數(shù)組對(duì)象。直接來(lái)自文檔:“ NumPy的主要對(duì)象是同構(gòu)多維數(shù)組。它是一個(gè)元素表(通常是數(shù)字),所有相同的類型,由正整數(shù)元組索引 “。
NumPy中的所有內(nèi)容都是將數(shù)據(jù)放入ndarray然后對(duì)其執(zhí)行操作。NumPy支持多種類型的索引,廣播,矢量化以提高速度,并且通常允許開(kāi)發(fā)人員輕松創(chuàng)建和操作大型數(shù)字?jǐn)?shù)組。
下一個(gè)片段顯示了ndarray 索引和正在進(jìn)行的廣播,這些是ML / DL中的核心操作。
import numpy as np
#Simple broadcast example
a = np.array([1.0, 2.0, 3.0])
b = 2.0
c = a * b
print(c)
#returns [ 2. 4. 6.] - the scalar b is automatically promoted / broadcast and applied to the vector a to create c
#return返回[2. 4. 6.] - 標(biāo)量b被自動(dòng)提升/廣播并應(yīng)用于向量a以創(chuàng)建c
#2-d (matrix with rank 2) indexing in NumPy - this extends to Tensors - i.e. rank > 2
y = np.arange(35).reshape(5,7)
print(y)
# array([[ 0, 1, 2, 3, 4, 5, 6],
# [ 7, 8, 9, 10, 11, 12, 13],
# [14, 15, 16, 17, 18, 19, 20],
# [21, 22, 23, 24, 25, 26, 27],
# [28, 29, 30, 31, 32, 33, 34]])
print(y[0,0])
# 單個(gè)單元格訪問(wèn) - notation is row-major, returns 0
print(y[4,])
# returns all of row 4: array([28, 29, 30, 31, 32, 33, 34])
print(y[:,2])
# returns all of column 2: array([ 2, 9, 16, 23, 30])
處理大型多維數(shù)字?jǐn)?shù)組是機(jī)器學(xué)習(xí)編碼的核心,尤其是深度學(xué)習(xí)。深度神經(jīng)網(wǎng)絡(luò)是節(jié)點(diǎn)格和邊格的數(shù)字模型。在訓(xùn)練網(wǎng)絡(luò)或?qū)ζ溥M(jìn)行推理時(shí)的運(yùn)行時(shí)操作需要快速矩陣乘法。
NumPy已經(jīng)促成并啟用了更多 - ?scipy,pandas和許多其他依賴于NumPy的庫(kù)。領(lǐng)先的深度學(xué)習(xí)庫(kù)(Tensorflow來(lái)自谷歌,PyTorch來(lái)自Facebook)都投入巨資在Python。Tensorflow還有其他用于Go,Java和JavaScript的API,但它們不完整且被視為不穩(wěn)定。PyTorch最初是用Lua編寫(xiě)的,當(dāng)它們從2017年相當(dāng)小的語(yǔ)言轉(zhuǎn)移到主要的Python ML生態(tài)系統(tǒng)時(shí),它的受歡迎程度大幅上升。
Python的缺點(diǎn)
Python不是一種完美的語(yǔ)言 - 特別是最流行的Python運(yùn)行時(shí) - CPython - 具有全局解釋器鎖(GIL),因此性能縮放并不簡(jiǎn)單。此外,像PyTorch和Tensorflow這樣的Python DL框架仍然將核心方法交給不透明的實(shí)現(xiàn)。
例如,NVidia 的cuDNN庫(kù)對(duì)PyTorch中[url=
https://pytorch.org/docs/stable/nn.html#rnn]RNN / LSTM實(shí)現(xiàn)[/url]的范圍產(chǎn)生了深遠(yuǎn)的影響。RNN和LSTM是一種非常重要的DL技術(shù),特別適用于商業(yè)應(yīng)用,因?yàn)樗鼈儗iT(mén)用于對(duì)順序,可變長(zhǎng)度序列進(jìn)行分類和預(yù)測(cè) - 例如網(wǎng)絡(luò)點(diǎn)擊流,文本片段,用戶事件等。
為了公平對(duì)待Python,這種不透明度/限制幾乎適用于任何未用C或C ++編寫(xiě)的ML / DL框架。為什么?因?yàn)闉榱双@得核心的最大性能,像矩陣乘法這樣的高頻操作,開(kāi)發(fā)人員盡可能“接近底層冶金工藝”。
Java需要做些什么才能參與競(jìng)爭(zhēng)?
我建議Java平臺(tái)有三個(gè)主要的補(bǔ)充,如果存在的話,會(huì)促使Java中一個(gè)健康且蓬勃發(fā)展的機(jī)器學(xué)習(xí)生態(tài)系統(tǒng)的萌芽:
1.在核心語(yǔ)言中添加本機(jī)索引/切片支持,以與Python的易用性和表現(xiàn)力相媲美,可能以現(xiàn)有的有序集合List
接口為中心。這種支持還需要承認(rèn)重載以支持#2點(diǎn)。
2.構(gòu)建Tensor實(shí)現(xiàn) - 可能在java.math包中,但也可以橋接到Collections API。這組類和接口將作為ndarray的等價(jià)物,并提供額外的索引支持 - 特別是三種類型的NumPy索引:字段訪問(wèn),基本切片和編碼ML所必需的高級(jí)索引。
3.支持廣播 - 任意(但兼容)維度的標(biāo)量和張量。
如果在核心Java語(yǔ)言和運(yùn)行時(shí)中存在這三件事,它將開(kāi)辟構(gòu)建“ NumJava ” 的道路,相當(dāng)于NumPy。巴拿馬項(xiàng)目還可以用于提供對(duì)CPU,GPU,TPU等運(yùn)行的快速?gòu)埩坎僮鞯氖噶炕图?jí)訪問(wèn),以幫助Java ML成為最快的。
我并不是說(shuō)這些補(bǔ)充是微不足道的 - 遠(yuǎn)非如此,但Java平臺(tái)的潛在優(yōu)勢(shì)是巨大的。
下面的代碼片段展示了我們的NumPy廣播和索引示例如何在NumJava中使用Tensor類,核心語(yǔ)言支持切片語(yǔ)法,并尊重當(dāng)前對(duì)運(yùn)算符重載的限制。
//Java廣播的張量
//使用Java 10中的var語(yǔ)法進(jìn)行簡(jiǎn)潔性
// Java不支持運(yùn)算符重載,所以我們不能做“a * b”
//我們應(yīng)該將其添加到需求列表中嗎?
var a = new Tensor([1.0, 2.0, 3.0]);
var b = 2.0;
var c = a.mult(b);
/**
* And a snippet showing how the Java Tensor class could look.
*顯示Java Tensor類的外觀的片段。
*/
import static java.math.Numeric.arange;
//arange returns a tensor instance and reshape is defined on tensor
var y = arange(35).reshape(5,7);
System.out.println(y);
// tensor([[ 0, 1, 2, 3, 4, 5, 6],
// [ 7, 8, 9, 10, 11, 12, 13],
// [14, 15, 16, 17, 18, 19, 20],
// [21, 22, 23, 24, 25, 26, 27],
// [28, 29, 30, 31, 32, 33, 34]])
System.out.println(y[0,0]);
// single cell access - notation is row-major, returns 0
System.out.println(y[4,]);
// returns all of row 4 (5th row starting from 0 idx): tensor([28, 29, 30, 31, 32, 33, 34])
System.out.println(y[:,2]);
// returns all of column 2 (3rd col starting from 0 idx): tensor([ 2, 9, 16, 23, 30])
總結(jié)
從本文中概述的實(shí)用起點(diǎn)開(kāi)始,我們可以擁有用Java編寫(xiě)并在JRE上運(yùn)行的盡可能多的機(jī)器/深度學(xué)習(xí)框架,因?yàn)槲覀冇蠾eb,持久性或XML解析器 - 想象一下!我們可以設(shè)想Java框架支持卷積神經(jīng)網(wǎng)絡(luò)(CNN)用于前沿計(jì)算機(jī)視覺(jué),像LSTM這樣的循環(huán)神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)對(duì)于順序數(shù)據(jù)集(對(duì)業(yè)務(wù)至關(guān)重要),具有尖端的ML功能,如自動(dòng)差異化等。然后,這些框架將為下一代企業(yè)級(jí)系統(tǒng)提供動(dòng)力并為其提供動(dòng)力 - 所有這些系統(tǒng)都使用相同的工具 - IDE,測(cè)試框架和持續(xù)集成。