1
头图
作者:京东科技隐私计算产品部 孙晓军

1. Jupyter Notebook介绍





图1 Jupter项目整体架构

[https://docs.jupyter.org/en/l...]

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/l...]

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)项目的主要模块结构如下:

模块说明
notebookNotebook功能模块。
terminal终端模块。为Jupyter提供控制台交互能力。
view文件可视化模块。比如pdf文件的显示。
tree工作区目录树
nbconvert格式转换模块,可以把Jupyter Notebook转换成html,pdf等格式
kernelJupyter Notebook 内核
servicesJupyter Notebook REST API模块
i18nJupyter 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_rootFalse为了安全,Jupyter默认不允许使用root用户启动。如果需要以root用户的身份启动Jupyter,需要开启此设定
c.NotebookApp.allow_origin''当需要Jupyter内嵌到iframe时,可以设置为“*“来避免跨origin的限制
c.NotebookApp.iplocalhost当需要通过外网地址来访问Jupyter服务时,需要设置一个有效的服务器IP地址。
c.NotebookApp.port8888Jupyter server对外服务端口
c.NotebookApp.notebook_dir/Jupyter的工作空间,默认可以访问服务器上当前用户的所有文件系统
c.NotebookApp.open_browserTrue启动服务后是否立即通过浏览器打开服务地址
c.NotebookApp.default_url/treeJupyter服务的默认地址
c.NotebookApp.extra_static_paths[]扩展静态文件目录
c.NotebookApp.extra_template_paths[]扩展模板文件目录
c.KernelSpecManager.allowed_kernelspecsset()默认允许使用所有的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。

  1. 交互式Notebook文档

传统的技术文档或者说明书,通过静态的文本,配合图片和视频,来描述和讲解特定的技术或功能。有了Jupyter Notebook后,我们仍然可以使用Notebook来编写类似传统的技术文档。在此基础上,我们可以加入更生动的代码交互单元格,用户通过查看文档说明,并与文档中提供的代码进行互动,可以更生动地介绍产品中的功能和技术。每个Jupyter Notebook的ipynb文件,都对应了一个独立的访问地址: http://x.x.x.x:8899/notebooks... ,通过分享此文件的地址,其他用户可以方便地使用包含了富文本和可执行的代码的交互式Notebook文档。

  1. 离线Notebook文档

我们通过逐步执行文档中的所有单元格,得到一个包含了我们编写的说明和代码,以及代码执行的输出结果的完整文档。之后点击【文件】-> 【另存为】,选择一种合适的文件格式。我们可以把文档导出为一份静态文件,通过共享此静态文件,我们实现了Notebook文档的离线分享。

5.4. 魔法函数

Jupyter Notebook提供了一些列魔法函数来增强Jupyter Code单元格的功能,通过魔法函数,我们能够执行javascript脚本,html代码,运行另一个可执行程序等许多额外的功能。

我们可以在Jupyter代码单元格中使用 %lsmagic命令来查看所有的魔法函数,如果要阅读详细的魔法函数的使用说明,可以参考: https://ipython.readthedocs.i...

魔法函数分为行魔法函数,单元格魔法函数和会话魔法函数。顾名思义,行魔法函数只对当前行起作用,而单元格魔法函数则作用于整个单元格,会话魔法函数则作用于整个会话期间。

一些常用的魔法函数:

指令说明
%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.readth...

要使用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.readthedoc...

8. 总结

Jupyter Notebook以其丰富的功能,简单易用,强大的交互能力和扩展能力,成为数据科学和机器学习开发中的神器。目前,Jupyter Notebook支持超过40种编程语言,被应用于Google Colab, Kubeflow, 华为云,kaggle等多个知名项目中,大量机器学习和数据科学的论文中使用到了Jupyter。Jupyter在数据可视化,提升工作效率,改善用户体验和丰富文档功能方面显现了巨大的威力。除此之外,Jupyter还提供的灵活强大的扩展能力,更是为Jupyter的深层次使用提供了更广阔的想象空间。如果你还没有开始接触Jupyter,那么就从现在开始吧。


京东云开发者
3.3k 声望5.4k 粉丝

京东云开发者(Developer of JD Technology)是京东云旗下为AI、云计算、IoT等相关领域开发者提供技术分享交流的平台。