Mars——基於矩陣的統一分佈式計算框架

很高興在這裡宣佈我們的新項目:Mars,一個基於矩陣的統一分佈式計算框架。我們已經在 Github 開源:https://github.com/mars-project/mars 。

背景

Python

Python 是一門相當古老的語言了,如今,在數據科學計算、機器學習、以及深度學習領域,Python 越來越受歡迎。

大數據領域,由於 hadoop 和 spark 等,Java 等還是佔據著比較核心的位置,但是在 spark 上也可以看到,pyspark 的用戶佔據很大一部分。

深度學習領域,絕大部分的庫(tensorflow、pytorch、mxnet、chainer)都支持 Python 語言,且 Python 語言也是這些庫上使用最廣泛的語言。

對 MaxCompute 來說,Python 用戶也是一股重要力量。

PyData(numpy、scipy、pandas、scikit-learn、matplotlib)

Python 在數據科學領域,有非常豐富的包可以選擇,下圖展示了整個 Python 數據科學技術棧。

Mars——基於矩陣的統一分佈式計算框架

可以看到 numpy 作為基礎,在其上,有 scipy 面向科學家,pandas 面向數據分析,scikit-learn 則是最著名的機器學習庫,matplotlib 專注於可視化。

對 numpy 來說,其中最核心的概念就是 ndarray——多維數組,pandas、scikit-learn 等庫都構建於這個數據結構基礎之上。

問題

雖然 Python 在這些領域越來越流行,PyData 技術棧給數據科學家們提供了多維矩陣、DataFrame 上的分析和計算能力、基於二維矩陣的機器學習算法,但這些庫都僅僅受限於單機運算,在大數據時代,數據量一大,這些庫的處理能力都顯得捉襟見肘。

雖然大數據時代,有各種各樣基於 SQL 的計算引擎,但對科學計算領域,這些引擎都不太適合用來進行大規模的多維矩陣的運算操作。而且,相當一部分用戶,尤其是數據科學家們,習慣於使用各種成熟的單機庫,他們不希望改變自己的使用習慣,去學習一些新的庫和語法。

此外,在深度學習領域,ndarray/tensor 也是最基本的數據結構,但它們僅僅限制在深度學習上,也不適合大規模的多維矩陣運算。

基於這些考量,我們開發了 Mars,一個基於 tensor 的統一分佈式計算框架,前期我們關注怎麼將 tensor 這層做到極致。

我們的工作

Mars 的核心用 python 實現,這樣做的好處是能利用到現有的 Python 社區的工作,我們能充分利用 numpy、cupy、pandas 等來作為我們小的計算單元,我們能快速穩定構建我們整個系統;其次,Python 本身能輕鬆和 c/c++ 做繼承,我們也不必擔心 Python 語言本身的性能問題,我們可以對性能熱點模塊輕鬆用 c/cython 重寫。

接下來,主要集中介紹 Mars tensor,即多維矩陣計算的部分。

Numpy API

Numpy 成功的一個原因,就是其簡單易用的 API。Mars tensor 在這塊可以直接利用其作為我們的接口。所以在 numpy API 的基礎上,用戶可以寫出靈活的代碼,進行數據處理,甚至是實現各種算法。

下面是兩段代碼,分別是用 numpy 和 Mars tensor 來實現一個功能。

import numpy as np
a = np.random.rand(1000, 2000)
(a + 1).sum(axis=1)
import mars.tensor as mt
a = mt.random.rand(1000, 2000)
(a + 1).sum(axis=1).execute()

這裡,創建了一個 1000x2000 的隨機數矩陣,對其中每個元素加1,並在 axis=1(行)上求和。

目前,Mars 實現了大約 70% 的 Numpy 常用接口。

可以看到,除了 import 做了替換,用戶只需要通過調用 execute 來顯式觸發計算。通過 execute 顯式觸發計算的好處是,我們能對中間過程做更多的優化,來更高效地執行計算。

不過,靜態圖的壞處是犧牲了靈活性,增加了 debug 的難度。下個版本,我們會提供 instant/eager mode,來對每一步操作觸發計算,這樣,用戶能更有效地進行 debug,且能利用到 Python 語言來做循環,當然性能也會有所損失。

使用 GPU 計算

Mars tensor 也支持使用 GPU 計算。對於某些矩陣創建的接口,我們提供了 gpu=True 的選項,來指定分配到 GPU,後續這個矩陣上的計算將會在 GPU 上進行。

import mars.tensor as mt
a = mt.random.rand(1000, 2000, gpu=True)
(a + 1).sum(axis=1).execute()

這裡 a 是分配在 GPU 上,因此後續的計算在 GPU 上進行。

稀疏矩陣

Mars tensor 支持創建稀疏矩陣,不過目前 Mars tensor 還只支持二維稀疏矩陣。比如,我們可以創建一個稀疏的單位矩陣,通過指定 sparse=True 即可。

import mars.tensor as mt
a = mt.eye(1000, sparse=True, gpu=True)
b = (a + 1).sum(axis=1)

這裡看到,gpu 和 sparse 選項可以同時指定。

基於 Mars tensor 的上層建築

這部分在 Mars 裡尚未實現,這裡提下我們希望在 Mars 上構建的各個組件。

DataFrame

相信有部分同學也知道 PyODPS DataFrame,這個庫是我們之前的一個項目,它能讓用戶寫出類似 pandas 類似的語法,讓運算在 ODPS 上進行。但 PyODPS DataFrame 由於 ODPS 本身的限制,並不能完全實現 pandas 的全部功能(如 index 等),而且語法也有不同。

基於 Mars tensor,我們提供 100% 兼容 pandas 語法的 DataFrame。使用 mars DataFrame,不會受限於單個機器的內存。這個是我們下個版本的最主要工作之一。

機器學習

scikit-learn 的一些算法的輸入就是二維的 numpy ndarray。我們也會在 Mars 上提供分佈式的機器學習算法。我們大致有以下三條路:

  1. scikit-learn 有些算法支持 partial_fit,因此,我們直接在每個 worker 上調用 sklearn 的算法。
  2. 提供基於 Mars 的 joblib 後端。由於 sklearn 使用 joblib 來做並行,因此,我們可以通過實現 joblib 的 backend,來讓 scikit-learn 直接跑在 Mars 的分佈式環境。但是,這個方法的輸入仍然是 numpy ndarray,因此,總的輸入數據還是受限於內存。
  3. 在 Mars tensor 的基礎上實現機器學習算法,這個方法需要的工作量是最高的,但是,好處是,這些算法就能利用 Mars tensor 的能力,比如 GPU 計算。以後,我們需要更多的同學來幫我們貢獻代碼,共建 Mars 生態。

細粒度的函數和類

Mars 的核心,其實是一個基於 Actor 的細粒度的調度引擎。因此,實際上,用戶可以寫一些並行的 Python 函數和類,來進行細粒度的控制。我們可能會提供以下幾種接口。

函數

用戶能寫普通的 Python 函數,通過 mars.remote.spawn 來將函數調度到 Mars 上來分佈式運行

import mars.remote as mr
def add(x, y):
return x + y
data = [
(1, 2),
(3, 4)
]
for item in data:
mr.spawn(add, item[0], item[1])

利用 mr.spawn,用戶能輕鬆構建分佈式程序。在函數里,用戶也可以使用 mr.spawn,這樣,用戶可以寫出非常精細的分佈式執行程序。

有時候,用戶需要一些有狀態的類,來進行更新狀態等操作,這些類在 Mars 上被稱為 RemoteClass。

import mars.remote as mr
class Counter(mr.RemoteClass):
def __init__(self):
self.value = 0
def inc(self, n=1):
self.value += n
counter = mr.spawn(Counter)
counter.inc()

目前,這些函數和類的部分尚未實現,只是在構想中,所以屆時接口可能會做調整。

內部實現

這裡,我簡單介紹下 Mars tensor 的內部原理。

客戶端

在客戶端,我們不會做任何真正的運算操作,用戶寫下代碼,我們只會在內存裡用圖記錄用戶的操作。

對於 Mars tensor 來說,我們有兩個重要的概念,operand 和 tensor,分別如下圖的藍色圓和粉色方塊所示。Operand 表示算子,tensor 表示生成的多維數組。

比如,下圖,用戶寫下這些代碼,我們會依次在圖上生成對應的 operand 和 tensor。

Mars——基於矩陣的統一分佈式計算框架

當用戶顯式調用 execute 的時候,我們會將這個圖提交到 Mars 的分佈式執行環境。

我們客戶端部分,並不會對語言有任何依賴,只需要有相同的 tensor graph 序列化,因此可以用任何語言實現。下個版本我們要不要提供 Java 版本的 Mars tensor,我們還要看是不是有用戶需要。

分佈式執行環境

Mars 本質上是一個對細粒度圖的執行調度系統。

對於 Mars tensor 來說,我們接收到了客戶端的 tensor 級別的圖(粗粒度),我們要嘗試將其轉化成 chunk 級別的圖(細粒度)。每個 chunk 以及其輸入,在執行時,都應當能被內存放下。我們稱這個過程叫做 tile。

Mars——基於矩陣的統一分佈式計算框架

在拿到細粒度的 chunk 級別的圖後,我們會將這個圖上的 Operand 分配到各個 worker 上去執行。

總結

Mars 在九月份的雲棲大會發布,目前我們已經在 Github 開源:https://github.com/mars-project/mars 。我們項目完全以開源的方式運作,而不是簡單把代碼放出來。

期待有更多的同學能參與 Mars,共建 Mars。

努力了很久,我們不會甘於做一個平庸的項目,我們期待對世界做出一點微小的貢獻——我們的征途是星辰大海!


分享到:


相關文章: