使用IPython做高級計算
如果你的主要編程語言是python,那一定聽說過IPython這個增強互動式編程環境(REPL)。IPython不僅僅是一個互動式編程環境(REPL),隨著IPython集成庫的更新,如今可以將其用於輔助高級計算任務。在這篇文章中,我們將看到多語言支持及分散式計算兩項功能。
IPython提供了對文檔的便捷訪問,與matplotlib的集成,持久歷史以及許多其他功能,可以極大地簡化Python的互動式工作。IPython還附帶了一系列「magic」命令,可以改變單行或代碼塊的效果;例如:您只需在輸入Python語句之前在提示符下鍵入
%% time
,即可為代碼計時。當使用帶有IPython內核的Jupyter notebook時,所有這些功能也還有效,這樣,就可以在使用相同命令的同時,在終端和基於瀏覽器的界面之間自由切換。多語言計算
沒有一種語言可以適合一切。IPython和Jupyter notebook允許在單個note或互動式會話中體現多種語言支持的優勢。
下圖,是一個Jupyter notebook片段,以最簡單的方式體現了多語言功能。
%% ruby
這個magic命令(雙%%
表示magic命令將應用於整個代碼塊)使得代碼塊的內容由Ruby解釋器處理。--out
標誌將代碼塊的輸出存儲到命名變數中,並且這個全局變數可用於其他基於Python內核的代碼塊。接下來代碼將Ruby的字元串輸出轉換為整數(注意,int()
是合法的Python函數,但不是Ruby函數)。Ruby代碼簡單地將整數從1加到100;最終結果存儲在a中。這可以在不安裝任何IPython或Jupyter內核擴展的情況下完成,僅需要安裝Ruby。使用Perl,Bash或sh可以完成同樣的事情,可以通過編輯
path to IPython]/core/magics/script.py
源文件中的列表來添加其他解釋語言。F2PY
是NumPy / SciPy
的一個組件,它可以編譯和包裝Fortran子常式,以便Fortran可以與Python一起使用。如果能夠充分利用Fortran的快速數值運算以及Python的高級便利性和交互性,這將非常可人。使用F2PY
需要幾個手動步驟,但是,一個名為Fortran magic的第三方擴展(可以用pip
安裝)提供了一個在底層使用F2PY
進行編譯和界面創建的magic。所需要的只是Fortran代碼塊中的某一行或者一個函數(如果系統中尚不存在Fortran編譯器,則可能需要安裝Fortran編譯器)。下圖顯示了該過程。首先,定義一個名為
eap()
的python函數,該函數用於收斂到自然數e,它計算d個連續近似值,最後返回結果。接下來載入Fortran magic,這將生成一個用戶警告(已摺疊省略),因為這是為舊版本的IPython / Jupyter開發的(但一切仍然有效)。
load
命令定義我們在之後代碼塊中使用的代碼塊magic,這個代碼塊是一個相同功能的Fortran函數,稱為eaf()
。執行該代碼塊時,IPython會編譯代碼並生成Python介面。最後兩步,在打開定時的情況下調用這兩個程序,輸出兩個程序的執行時間,明顯Fortran版本的速度提高了大約24倍。只需一個magic命令,就可以打包編譯的Fortran命令,以便在終端或Jupyter notebook中互動式使用。由於程序的數字部分都是最容易翻譯成Fortran的,這個過程受益最大,也是加速計算最簡單方法,同時這也是IPython生態系統強大功能的一個很好的證明。
並行和分散式計算
IPython提供了許多方便的解決方案,用於在單個機器或多個聯網計算機的處理核心之間分布計算。IPython並行計算工具可以完成大部分設置; 在簡單的情況下,它允許在互動式上下文中執行並行計算,幾乎與正常的單處理器計算一樣簡單。
在多個處理器上運行代碼通常是為了加快速度或提高吞吐量。但是,這僅適用於某些類型的問題,並且只有在節省演算法的時間超過在處理器之間移動數據的開銷時才有效果。
如果你為了實現最大計算速度,那麼在嘗試利用並行或分散式計算之前,你必須儘可能地提高串列性能(在單個處理核心上的速度)。
這篇文章(
https://hpc.nih.gov/training/handouts/171121_python_in_hpc.pdf
)簡明扼要地介紹了當核心語言是Python時可能遇到此問題的各種解決方法,並介紹了一些並行化策略。有很多方法可以加速Python,但這些方法都超出了本文的考慮範圍(而且,無論語言如何,第一種方法都應該是對演算法和數據結構的批判性研究)。除了試圖加快計算速度之外,網路化分散式計算的另一個目的是從計算機集群中收集信息或運行測試。例如,位於世界某地的一個Web伺服器的管理員,可以利用下面的技術通過單個命令從所有伺服器收集性能數據,並使用IPython會話作為中央控制中心。
首先是關於
NumPy
的說明。並行化Python計算的最簡單方法就是在可能的情況下將其表示為NumPy
數組上的一系列數組操作。這將自動在您的機器上的所有核心之間分配陣列數據,而且並行執行陣列演算法(如果有任何疑問,請在觀察CPU監視器(例如
htop
)時提交較長的NumPy
計算,將看到所有核心都已啟用)。並非每種計算都能以這種方式表達出來; 但如果程序已經允許並行執行的方式使用NumPy
,而且嘗試在多個核心上運行程序,這會引入不必要的進程間通信,減慢速度而不是加快速度。如果程序不適合
NumPy
的陣列處理,IPython提供了其他幾乎同樣方便的方法來利用多個處理器。要使用這些工具,必須安裝ipyparallel
庫(pip install ipyparallel
)。IPython和
ipyparallel
庫支持並行和分散式計算的各種樣式和範例。我已經構建了一些示例,並做了簡單的演示。這只是一些提示,你可以立即開始實驗,只需最少的設置,並了解可用的範圍。要了解更多內容,請參閱文檔(https://media.readthedocs.org/pdf/ipyparallel/latest/ipyparallel.pdf
)。
第一個例子在每台機器的CPU核心上複製計算。如上所述,
NumPy
會自動在這些核心之間劃分工作,但是使用IPython,您可以通過其他方式訪問。首先,您必須創建一個計算「集群」。 隨著IPython和ipyparallel
的安裝,有幾個好用的命令。創建集群的命令是:$ ipcluster start --n=x
通常,x設置為系統中的核心數;我的筆記本電腦有四個,所以
--n = 4
。該命令應該會生成一條消息,表明已創建集群。您現在可以在IPython或Jupyter notebook中與它進行交互。下圖顯示了使用群集的Jupyter會話的一部分。前兩行導入
ipyparallel
庫並實例化客戶端。第三行檢查所有四個核心是否實際可用,顯示Client
實例的
ID
列表。接著導入choice()
函數,它從一個集合中隨機選擇一個元素,用於繪圖的pylab
,並配置matplotlib
。請注意
%% px
這個magic命令。這個命令位於代碼塊頂部,將單元格中的計算複製到每個核心的單獨進程中。由於我們使用四個核心啟動了我們的集群,因此將有四個進程,每個進程都有自己的所有變數的私有版本,並且每個進程獨立於其他變數運行。接下來的兩個代碼塊計算一個具有一百萬步的2D隨機遊走。它們都由
%% timeit
magic命令裝飾,用於計算演算法次數。第一個單元使用
--targets
參數將計算限制為單個核心上的單個進程(核心「0」; 我們可以選擇0到3之間的任何數字); 第二個使用%% px
表示使用所有核心。注意,在這種並行計算方式中,每個變數(包括每個列表)都在核心之間進行複製。這與NumPy
中的數組計算形成對比,NumPy
中的數組在核心之間分配,每個核心都處理一個較大問題的一部分。而在此示例中,每個核心將單獨的計算所有百萬步隨機遊走。按照輸出的計時數據,實際上第二種情況下,在相同的時間內完成了四倍的工作,因為計算完成了四次。然而,第二個程序實際上花了兩倍多的時間,這意味著我們只實現了大約兩倍的加速。這是由於進程間通信和設置的開銷,並且隨著計算變得更加冗長而減少。
如果將一個繪圖命令附加到上述程序中,看看隨機行走是什麼樣的,會發生什麼?下圖顯示了每個進程如何生成自己的繪圖(使用自己的隨機種子)。這種多處理方式可以是一種方便的方法,可以並排比較不同程序的計算,而無需一個接一個地運行。
還可以使用%px在群集上執行
「 one-liner 」
命令,可以在代碼塊中混合串列和並行代碼。如在導入隨機整數函數(randint()
)之後:輸出單元按順序標記並顯示了四個計算核心中的每一個產生了的結果。
當希望每個處理器在其自己獨立運行時,
%% px
和%px
magic命令是在處理器集群之間複製計算的簡便方法。使用多個處理器加速列表計算的經典技術遵循不同的模式:列表在處理器之間劃分,每個處理器在其各個段上工作,並將結果重新組合成單個列表,如果每個數組元素的計算不依賴於其他元素,則此方法效果最佳。IPython提供了一些便利功能,使這些計算易於表達。我們看看最有用的那個。
首先,考慮Python的
map()
函數:list(map(lambda
x:f(x), ra
nge(16)))
這將函數
f()
應用於列表[0..15]
的每個元素並返回結果列表。它將在一個處理器上執行此操作,一次一個元素。但是,如果我們如上所述啟動了一個集群,我們可以這樣寫:rp[:].map_sync(lambda x:f(x), range(16))
這會將列表分成四個相等長度的段,將每個段發送到一個單獨的處理器,然後將結果重新放在一起,替換原始列表。可以通過索引
rp
來控制使用哪些處理器,這樣就可以輕鬆告訴rp [0:1]
在一個數組上工作,而rp [2:3]
則執行其他操作。使用的處理器不必是本地計算機上的核心。它們可以是Internet或本地網路訪問的任何計算機上。通過網路進行計算的最簡單設置是使用SSH訪問的計算機。當然,配置比簡單地輸入
ipcluster
命令要複雜一些。我寫了一個文檔(https://github.com/leephillips/ipyparallelSSHconfig/blob/master/advipSupp.pdf
)來描述最小的示例配置,它將使您開始通過SSH在網路集群上進行計算。20多年來,計算科學家依靠各種並行計算方法作為執行大型計算的唯一方法。隨著對更準確氣候建模的渴望,處理越來越大的機器學習數據集,更好地模擬星系演化,許多不同領域中需要超過單處理器的更強大的計算功能,採用並行處理可以打破這個瓶頸。這使得人們願意重寫演算法以將特殊並行庫合併到他們的Fortran或C程序中,以及根據個人超級計算機的特點定製他們的程序的專屬領域。
使用
ipyparallel
庫的IPython提供了前所未有的能力,將科學Python的探索能力與幾乎即時訪問多個計算核心相結合。系統可以直觀地與本地或網路的計算節點集群進行交互,而不管集群的實現方式如何。這種易於交互使用幫助IPython和Python成為各種學科的科學計算和數據科學的流行工具。例如,這篇論文(https://link.springer.com/content/pdf/10.1007%2Fs10472-017-9556-8.pdf
)提出了機器學習和生物化學交叉問題的研究,得益於ipyparallel
的易用性。有時,一種語言更容易表達,或者計算會以另一種語言更快地運行。以前多語言計算需要精心設計的介面來使用多個編譯器或在單獨的解釋器中工作。通過允許用戶隨意使用不同語言進行編碼,增強IPython和Jupyter計算的流動性和探索性的能力,實現了與計算機交互的真正新方法。
IPython和Jupyter不僅僅是解釋器的介面。本文中描述的計算體驗增強是相當新穎的,但不僅僅是軟體開發人員的好奇——它們已經被科學家和工程師使用。諸如此類的工具是創造力的槓桿;有趣的事情將會很有趣。
英文原文:https://lwn.net/SubscriberLink/756192/ebada7ecad32f3ad/
譯者:朱僑文
※Firefox、Edge均將支持WebP圖片格式(該格式來自Google)
※Salmon:一個基於Python語言的郵件伺服器
TAG:Python程序員 |