Jupyter Notebook是一套基於web的互動式開發環境。用戶可以線上開發和分享包含代碼和輸出的互動式文檔,支持實時代碼,數學方程,可視化和 markdown等。用途包括:數據清理和轉換,數值模擬,統計建模,機器學習等等。 ...
作者:京東科技隱私計算產品部 孫曉軍
1. Jupyter Notebook介紹
圖1 Jupter項目整體架構
[https://docs.jupyter.org/en/latest/projects/architecture/content-architecture.html]
Jupyter Notebook是一套基於web的互動式開發環境。用戶可以線上開發和分享包含代碼和輸出的互動式文檔,支持實時代碼,數學方程,可視化和 markdown等。用途包括:數據清理和轉換,數值模擬,統計建模,機器學習等等。
Jupyter Notebook內部通過內核維護狀態並運行代碼片段,瀏覽器顯示代碼片段和其執行的結果。Jupyter Notebook提供了一個用戶互動式的開發環境,用戶可以通過執行一部分代碼片段,並觀察執行結果。這種互動式設計,使得Jupyter Notebook非常適合數據科學和機器學習的開發工作。
註意本文的代碼和腳本,均基於Jupyter Notebook v6.5.2穩定版本。
2. Jupyter的工作方式
圖2 Jupter Notebook工作方式
[https://docs.jupyter.org/en/latest/projects/architecture/content-architecture.html]
Jupyter的主要工作單元是Jupyter Server和Kernel。其中Jupyter Server用來提供基於Web的界面和API服務,Kernel用來執行代碼片段。瀏覽器通過Http和Websockets的方式和Jupyter Server進行交互,Jupyter Server和kernel之間,通過ZeroMQ進行數據通信。
Jupyter Server採用經典的MVC模式,使用了tornado作為web伺服器,用來提供地址映射和控制器邏輯,使用jinja2來提供模板視圖功能。
Jupyter Notebook(v6.5.2)項目的主要模塊結構如下:
模塊 | 說明 |
---|---|
notebook | Notebook功能模塊。 |
terminal | 終端模塊。為Jupyter提供控制台交互能力。 |
view | 文件可視化模塊。比如pdf文件的顯示。 |
tree | 工作區目錄樹 |
nbconvert | 格式轉換模塊,可以把Jupyter Notebook轉換成html,pdf等格式 |
kernel | Jupyter Notebook 內核 |
services | Jupyter Notebook REST API模塊 |
i18n | Jupyter Notebook多語言資源 |
3. 安裝Jupyter Notebook
前置條件
Python和pip
不同的Jupyter Notebook對Python有不同的版本要求。我們安裝的最新的穩定版本v6.5.2的Jupyter Notebook,要求Python的最低版本為3.6。註意這個Python的版本,不同於內核的Python版本。對於Jupyter內核來說,支持的Python版本和Jupyter Notebook依賴的Python版本沒有關係。
在Linux系統下安裝Jupyter Notebook
使用pip安裝Jupyter notebook非常簡單。如果伺服器同時擁有Python2和Python3的pip,註意需要使用pip3來替換命令中的pip。
# 更新pip
pip install --upgrade pip
# 安裝jupyter
pip install jupyter
# 檢查安裝的jupyter
jupyter --version
//輸出 notebook : 6.5.2
4. 配置和啟動Jupyter
Jupyter提供了大量的啟動參數,用來配置Jupyter Server。我們可以在啟動Jupyter服務時,通過命令行參數的方式配置當前啟動的服務,但更普遍的方式是使用Jupyter的配置文件。
# 生成配置文件
jupyter notebook --generate-config
// 預設生成的配置文件位置:
/root/.jupyter/jupyter_notebook_config.py
# 修改Jupyter配置文件...
# 啟動jupyter
jupyter notebook
Jupyter直接使用一個Python文件來配置Jupyter服務,所有的配置項均通過Python代碼來完成。常用的配置項及其說明如下:
名稱 | 預設值 | 說明 |
---|---|---|
c.NotebookApp.allow_root | False | 為了安全,Jupyter預設不允許使用root用戶啟動。如果需要以root用戶的身份啟動Jupyter,需要開啟此設定 |
c.NotebookApp.allow_origin | '' | 當需要Jupyter內嵌到iframe時,可以設置為“*“來避免跨origin的限制 |
c.NotebookApp.ip | localhost | 當需要通過外網地址來訪問Jupyter服務時,需要設置一個有效的伺服器IP地址。 |
c.NotebookApp.port | 8888 | Jupyter server對外服務埠 |
c.NotebookApp.notebook_dir | / | Jupyter的工作空間,預設可以訪問伺服器上當前用戶的所有文件系統 |
c.NotebookApp.open_browser | True | 啟動服務後是否立即通過瀏覽器打開服務地址 |
c.NotebookApp.default_url | /tree | Jupyter服務的預設地址 |
c.NotebookApp.extra_static_paths | [] | 擴展靜態文件目錄 |
c.NotebookApp.extra_template_paths | [] | 擴展模板文件目錄 |
c.KernelSpecManager.allowed_kernelspecs | set() | 預設允許使用所有的kernel |
c.NotebookApp.nbserver_extensions | {} | 允許載入的Jupyter Server擴展 |
5. 使用Jupyter
5.1. 創建Notebook
啟動Jupyter 後,在瀏覽器內輸入 http://伺服器地址:埠/,Jupyter會預設重定向到.default_url指定的工作區目錄樹地址,預設是工作區目錄樹的界面。
如果在訪問的過程中,使用了預設的token作為其認證方式,那麼在首次打開時,需要輸入Jupyter Notebook的token值,這個值可以在啟動Jupyter時的控制台輸出中找到,或者使用Jupyter命令來查詢
# 查詢運行的jupyter notebook
jupyter notebook list
//返回結果中包含了http://x.x.x.x:8899?token=ABC 的信息,其中的ABC就是我們需要的token
圖3 Jupter Notebook的預設工作區目錄樹頁面
Jupyter Notebook通過Jupyter Server提供基於Web的平臺無關的工作方式,這使得跨平臺開發和協作,代碼分享等能力變得比傳統IDE更加容易。
在Jupyter 工作區管理界面,用戶可以靈活地以類似文件系統的方式管理工作區的數據。可以創建文件和文件夾,編輯文件和文件夾,可以上傳和下載文件。通過選擇一個Jupyter內核,可以創建一個Notebook文件。
圖4 通過Jupyter內核創建一個Notebook
5.2. 使用Notebook
使用Python3內核創建一個Notebook後,我們得到一個xxx.ipynb(IPython Notebook)文件。這個文件是一個json格式的文本文件,其中包含了我們在Notebook中編寫的代碼和文本內容,也包含了界面上沒有顯示的元數據信息。通過在工作區目錄界面選擇一個notebook文件,點擊編輯,我們可以查看到ipynb文件的原始內容。
圖5 ipynb文件的原始內容
我們可以像使用其它IDE類似的方式來使用Notebook,在使用Notebook上,我們主要關註下Jupyter內核和單元格。
內核是執行單元格代碼的核心進程,不同的內核,決定了我們在單元格中能夠編寫哪些語言的代碼,以及對應了指定的編程語言的哪個版本等信息。
單元格是整個Notebook的核心組成部分,我們編寫的代碼和文本,通過一些列Notebook單元格來組成。Notebook提供了Code,Markdown, Raw NBConvert, Heading四種類型的單元格。
•Code單元格。用來編寫內核指定語言的程式代碼
•Markdown單元格。使用Markdown編輯器的語法來編輯富文本
•Raw NBConvert單元格。原始的文本,不會被當作代碼或markdown被解釋執行
•Heading單元格。Heading是Mardown的一個子集,對應了Markdown中的標題編寫語法
Jupyter Notebook使用了機器學習中檢查點的概念,在我們修改Notebook的過程中,Jupyter會自動保存我們的修改,我們也可以通過【文件】->【保存】來手動保存檢查點。檢查點文件包含了我們編寫的Notebook內容,以及執行代碼單元格之後的輸出。我們可以在工作空間的“.ipynb_checkpoints”文件夾下,找到這些檢查點文件。
圖6 使用Jupyter單元格來編寫互動式代碼
5.3. 分享Notebook
相較於使用傳統的IDE編寫的代碼,基於Web服務的Jupyter Notebook在代碼分享上擁有著天然的優勢。
在Jupyter Notebook中,我們可以通過兩種不同的方式分享我們創作的nootbook。
- 互動式Notebook文檔
傳統的技術文檔或者說明書,通過靜態的文本,配合圖片和視頻,來描述和講解特定的技術或功能。有了Jupyter Notebook後,我們仍然可以使用Notebook來編寫類似傳統的技術文檔。在此基礎上,我們可以加入更生動的代碼交互單元格,用戶通過查看文檔說明,並與文檔中提供的代碼進行互動,可以更生動地介紹產品中的功能和技術。每個Jupyter Notebook的ipynb文件,都對應了一個獨立的訪問地址: http://x.x.x.x:8899/notebooks/my_notebook.ipynb ,通過分享此文件的地址,其他用戶可以方便地使用包含了富文本和可執行的代碼的互動式Notebook文檔。
- 離線Notebook文檔
我們通過逐步執行文檔中的所有單元格,得到一個包含了我們編寫的說明和代碼,以及代碼執行的輸出結果的完整文檔。之後點擊【文件】-> 【另存為】,選擇一種合適的文件格式。我們可以把文檔導出為一份靜態文件,通過共用此靜態文件,我們實現了Notebook文檔的離線分享。
5.4. 魔法函數
Jupyter Notebook提供了一些列魔法函數來增強Jupyter Code單元格的功能,通過魔法函數,我們能夠執行javascript腳本,html代碼,運行另一個可執行程式等許多額外的功能。
我們可以在Jupyter代碼單元格中使用 %lsmagic命令來查看所有的魔法函數,如果要閱讀詳細的魔法函數的使用說明,可以參考: https://ipython.readthedocs.io/en/stable/interactive/magics.html
魔法函數分為行魔法函數,單元格魔法函數和會話魔法函數。顧名思義,行魔法函數只對當前行起作用,而單元格魔法函數則作用於整個單元格,會話魔法函數則作用於整個會話期間。
一些常用的魔法函數:
指令 | 說明 |
---|---|
%matplotlib | 設置matplot繪圖的顯示模式 |
%%javascript | 單元格內的代碼被識別為javascript代碼 |
%%html | 單元格內的代碼被識別為html代碼 |
%run | 執行外部腳本文件 |
%pwd | 獲取當前工作的目錄位置(非工作空間目錄位置) |
%writefile | 以文件形式保存當前單元格代碼 |
%timeit | 獲取本行代碼的執行時間 |
%debug | 激活調試模式 |
6. 管理Jupyter
6.1. 多語言
Jupyter Notebook使用i18n目錄下的資源來進行多語言翻譯。在Jupyter Notebook啟動時,會載入i18n目錄下的多語言資源。之後根據http請求指定的語言,為響應數據提供對應的多語言翻譯。如果沒有對應的翻譯,則保留原始的多語言標簽值(英文)。如果調整了多語言翻譯,需要重新啟動Jupyter Notebook才能使用新的語言包。
Jupyter Notebook的翻譯資源主要分佈在三個po文件中:
•nbjs.po - js文件中的多語言數據
•nbui.po - UI界面中的多語言數據
•notebook.po - notebook中的多語言數據
原始的po文件,需要通過pybabel工具,把po文件編譯成mo文件,之後部署在$notebook/i18n/${LANG}/LC_MESSAGES/目錄下($notebook是notebook的安裝目錄),才能在Jupyter Notebook中作為多語言的資源包來使用。
# 使用pybabel編譯多語言po文件
pybabel compile -D notebook -f -l ${LANG} -i ${LANG}/LC_MESSAGES/notebook.po -o ${LANG}/LC_MESSAGES/notebook.mo
pybabel compile -D nbui -f -l ${LANG} -i ${LANG}/LC_MESSAGES/nbui.po -o ${LANG}/LC_MESSAGES/nbui.mo
pybabel compile -D nbjs -f -l ${LANG} -i ${LANG}/LC_MESSAGES/nbjs.po -o ${LANG}/LC_MESSAGES/nbjs.mo
圖7 使用了中文語言包後的中文Notebook界面
6.2. 內核管理
內核(kernel)是獨立於jupyter服務和界面之外的用來運行Jupyter代碼單元格的進程,Jupyter預設提供了ipykernel內核來支持Python開發語言。Jupyter社區提供了jupyterC, IJava,xeus-cling, xeus-sql等眾多其它編程語言的內核,用來支持C/C++, Java, SQL等編程語言。
ipykernel預設使用系統環境下的Python來提供服務。我們可以使用ipykernel安裝多個Python kernel來提供Python2.x, Python3.x等多個Python內核環境。
安裝kernel後,kernel的信息被保存在kernel.json文件中,我們可以在 /usr/local/share/jupyter/kernels 目錄,找到Jupyter安裝的所有kernel以及對應的kernel.json文件。
kernel可以直接繼承自安裝kernel的Python指令,也可以使用Python虛擬環境。
# 1.直接繼承自Python指令的kernel安裝
# 安裝ipykernel
pip install ipykernel
# 安裝kernel
python -m ipykernel install --name tensorflow2 --display-name "tensorflow2"
# 2. 在Python虛擬環境下的kernel安裝
# 激活虛擬環境
source activate myenv
# 安裝ipykernel
pip install ipykernel
# 安裝kernel
python -m ipykernel install --name myenv --display-name "Python3 (myenv)"
如果需要查看當前的kernel列表,以及刪除已經安裝的kernel,可以使用如下的Jupyter命令:
# 查看已經安裝的kernel列表
jupyter kernelspec list
# 刪除列表中指定的kernel
jupyter kernelspec remove kernelname
6.3. REST API
Jupyter提供了REST API介面來和Jupyter server進行交互。藉助REST API的能力,我們可以以編程的方式和Jupyter Server進行交互,靈活地管理Jupyter Server。另外REST API為現代化的軟體開發提供了一個優秀的能力:自動化。
藉助Jupyter Notebook REST API,可以實現文件的上傳和下載,檢查點管理,會話管理,內核管理,終端管理等一些列管理能力。完整的Jupyter REST API介面列表可以參考: https://jupyter-server.readthedocs.io/en/latest/developers/rest-api.html
要使用REST API,需要在請求中攜帶認證信息。Jupyter支持直接把token作為query string的方式來認證,也可以使用標準的Http Authorization頭信息來完成認證。使用Authorization頭來認證的格式如下:
Authrozation: token 527a9f1430ccfed995ebcf15517583a2547c2469bc3c47a6
圖8 使用Postman來調用Jupyter REST API介面
6.4. 安全管理與多人協作
Jupyter提供了靈活強大的能力,用以支持線上的互動式文檔和代碼的編寫。但Jupyter項目自身沒有提供精細化的安全管理體系,用以支持多用戶下靈活地使用Jupyter Notebook的功能。對於文件安全,Jupyter依賴於啟動服務的linux用戶,合理地配置啟動Jupyter的用戶的許可權,才能保證使用Jupyter的用戶,不會對系統或項目造成破壞。Jupyter工作空間的設定,僅起到了方便Jupyter使用者管理必要文件的易用性,不能阻擋用戶訪問和管理工作空間外的文件系統。另外,配合使用Python虛擬環境,可以防止Jupyter Notebook提供的 pip install ,pip uninstall功能,對現有項目環境造成破壞。
在多人協作方面,JupyterHub項目提供了多人協作Jupyter Notebook和Jupyter lab開發的能力。使用JupyterHub,不同職能的用戶可以在自己獨立的空間內進行Notebook的編寫工作,不同用戶間也可以方便地分享各自的Notebook。
7. 擴展Jupyter
7.1. 前端擴展
Jupyter Notebook前端擴展(front end extension)是使用Javascript語言編寫的非同步模塊,可以用來繪製Jupyter界面的儀錶盤,Notebook,工具欄等,。定義一個前端擴展必須要實現一個load_ipython_extension方法,當前端控制項被載入時,Jupyter client會調用load_ipython_extension方法。
Jupyter Notebook前端擴展能力目前還不是一個穩定的版本,不保證代碼能夠向後相容。Jupyter的JS API目前也沒有官方的文檔,需要通過源代碼或者實際載入的JS來查看Jupyter前端腳本的成員和方法。
我們實現一個簡單的前端擴展腳本,在jupyter前端的工具條中,添加一個自定義工具,當點擊自定義工具時,彈出提示信息。
define([
'base/js/namespace'
], function(
Jupyter
) {
function load_ipython_extension() {
var handler = function () {
alert('歡迎使用前端擴展!');
};
var action = {
icon: 'fa-comment-o',
help : '前端擴展',
help_index : 'zz',
handler : handler
};
var prefix = 'my_extension';
var action_name = 'show-alert';
var full_action_name = Jupyter.actions.register(action, action_name, prefix); // returns 'my_extension:show-alert'
Jupyter.toolbar.add_buttons_group([full_action_name]);
}
return {
load_ipython_extension: load_ipython_extension
};
});
完前端擴展代碼後,我們把腳本保存到main.js文件,放置在/opt/my_extension目錄下。接下來我們使用jupyter nbextension工具來安裝和啟用前端擴展
# 安裝前端擴展
jupyter nbextension install /opt/my_extension
# 啟用前端擴展
jupyter nbextension enable my_extension/main
# 禁用前端擴展
jupyter nbextension disable my_extension/main
# 查看前端擴展列表
jupyter nbextension list
# 卸載前端擴展
jupyter nbextension uninstall my_extension
圖9 在Notebook工具條中加入的前端擴展
7.2. 服務端擴展
Jupyter服務端擴展(server extension)是使用Python語言編寫的模塊,可以用來處理髮送到Jupyter Server的Http請求。使用Jupyter服務端擴展,可以更改現有Jupyter請求的數據和行為,也可以為jupyter Server定義新的服務處理程式。
定義一個服務端擴展模塊要實現一個load_jupyter_server_extension方法,其中包含一個類型為notebook.notebookapp.NotebookApp的參數serverapp,serverapp的詳細屬性和方法可以通過Jupyter Notebook源代碼中的notebookapp.py文件來查看。當服務端擴展被載入時,Jupyter Server會調用load_jupyter_server_extension方法。在load_jupyter_server_extension方法中,我們可以通過調用serverapp的web_app屬性的add_handlers方法來註冊處理程式,用來處理特定的服務端請求。處理程式類需要繼承自Jupyter的IPythonHandler類。在處理程式的方法中,可以使用Jupyter提供的@web.authenticated裝飾器來為方法增加身份認證保護。
通過服務端擴展,還可以與前端擴展聯動,實現一個功能豐富的Jupyter Notebook前端控制項。
# 定義一個處理程式
from tornado import (
gen, web,
)
from notebook.base.handlers import IPythonHandler
class HelloWorldHandler(IPythonHandler):
@web.authenticated
@gen.coroutine
def get(self):
self.finish(f'Hello, world!')
# 實現load_jupyter_server_extension方法並註冊處理程式
def load_jupyter_server_extension(serverapp):
handlers = [
('/myextension/hello', HelloWorldHandler)
]
serverapp.web_app.add_handlers('.*$', handlers)
完成服務端擴展代碼後,我們把代碼保存為__init__.py文件,要在Jupyter Notebook中使用處理程式,我們還需要進行服務端擴展的安裝和啟用。不同於前端擴展,服務端擴展不能直接使用指令來安裝,需要我們手動編寫安裝程式。此外,Jupyter提供了自動啟用服務端擴展和前端擴展的方法,需要我們在腳本的根目錄提供啟用擴展的配置文件。
jupyter-config/
├── jupyter_notebook_config.d/
│ └── my_server_extension.json
└── nbconfig/
└── notebook.d/
└── my_front_extension.json
setup.py
加入了自動啟用擴展的配置,我們的服務端擴展目錄結構如下:
hello-extension/
├── __init__.py
jupyter-config/
├── jupyter_notebook_config.d/
└── hello_extension.json
hello_extension.json文件的內容為:
{
"ServerApp": {
"jpserver_extensions": {
"hello_extension": true
}
}
}
接下來我們通過安裝程式,安裝服務端擴展的信息保存在/root/.jupyter/jupyter_notebook_config.json文件中。在安裝完成後,我們可以通過jupyter serverextesion工具來股那裡服務端擴展
# 啟用服務端擴展
jupyter serverextension enable hello_extension
# 禁用服務端擴展
jupyter serverextension disable hello_extension
# 服務端擴展直接卸載的方法,需要我們通過pip uninstall 卸載安裝程式,
# 再通過手工修改/root/.jupyter/jupyter_notebook_config.json文件刪除擴展信息來完成卸載
圖10 在瀏覽器中測試安裝的服務端擴展程式
7.3. 界面定製
Jupyter沒有提供標準的界面定製的能力,但我們可以手工調整jupyter生成的模板視圖文件和樣式文件,達到整條調整jupyter notebook的界面的能力。
Jupyter Notebook模板文件的位置為:$notebook/templates,樣式和腳本定製推薦的方案是使用/.jupyter/custom/custom.css和/.jupyter/custom/custom.js文件。我們可以直接在此基礎上對文件進行修改,還可以通過extra_template_paths和extra_static_paths來引入其它位置的模板和其它靜態文件。
圖11 通過直接調整模板文件加入的界面定製按鈕
7.4. 小部件
小部件(Widgets)是Jupyter互動式可視化數據呈現部件。Jupyter Widgets同時包含了訪問後端數據和前端呈現的能力,可以用於在Jupyter Notebook上生動地展示服務端的數據和數據變化。
在v6.5.2穩定版本上,我們目前只能使用系統提供的小部件,還不能開發自定義小部件。在Jupyter notebook7.x版本中,開始提供了小部件的自定義開發能力。
# 確保全裝了ipywidgets和traitlets
pip install --upgrade traitlets
pip install --upgrade ipywidgets
# 安裝和啟用小部件
jupyter nbextension install --py widgetsnbextension
jupyter nbextension enable --py widgetsnbextension
在安裝和啟用了小部件後,我們可以在notebook中直接使用系統提供的小部件。
圖12 在Notebook中使用小部件
完整的小部件列表和使用方式可以參考: https://ipywidgets.readthedocs.io/en/7.x/examples/Widget List.html
8. 總結
Jupyter Notebook以其豐富的功能,簡單易用,強大的交互能力和擴展能力,成為數據科學和機器學習開發中的神器。目前,Jupyter Notebook支持超過40種編程語言,被應用於Google Colab, Kubeflow, 華為雲,kaggle等多個知名項目中,大量機器學習和數據科學的論文中使用到了Jupyter。Jupyter在數據可視化,提升工作效率,改善用戶體驗和豐富文檔功能方面顯現了巨大的威力。除此之外,Jupyter還提供的靈活強大的擴展能力,更是為Jupyter的深層次使用提供了更廣闊的想象空間。如果你還沒有開始接觸Jupyter,那麼就從現在開始吧。