Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
应用开发上手实例(二): STEM文件格式转换
Bohrium APP
Tutorial
Bohrium APPTutorial
MileAway
Letian
更新于 2024-08-15
推荐镜像 :Basic Image:ubuntu:22.04-py3.10-cuda12.1
推荐机型 :c2_m4_cpu
STEM APP 所用数据集(v1)

Bohrium APP 开发教程(二):标准离线/在线任务

©️ Copyright 2024 @ Authors
作者:阙浩辉 📨 陈乐天 📨
日期:2024-08-05
共享协议:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

目录

  • Part 1: Bohrium® Apps 介绍
  • Part 2: 开发一个 Bohrium App
    • 2.1 案例背景
    • 2.2 将程序转化为 Launching 程序版本
    • 2.3 Bohrium 镜像制作
    • 2.4 发布 APP
    • 2.5 测试 APP
  • Part 3: APP 功能拓展
    • 3.1 增加更多 STEM 文件格式的支持
    • 3.2 自定义图片的尺寸与分辨率
  • 参考资料

Part 1: Bohrium® Apps 介绍

Bohrium® Apps 是一款创新开发工具,旨在帮助开发者在短时间内实现算法代码快速上线为应用软件,从而大幅提高新想法的验证效率。开发者仅需简单地修改算法运行入口代码,即可生成丰富的用户界面和完整的功能套件。

借助 Bohrium® Apps,开发者能够迅速收集用户反馈,为方法的进一步优化提供支持,实现研究成果的落地应用,并创造商业价值。

Apps 开发者平台提供了多种能力,支持低代码部署、自定义 Web 应用框架(Streamlit/Dash/Gradio/...)、AI Agent 等前沿技术,并提供了丰富的功能,包括可视化交互、账单计费、用户管理、用户授权等。此外,还提供了快速迭代算法所需的核心能力,如数据集、模型管理、版本性能评估等。

代码
文本

Part 2: 开发一个标准离线/在线任务 Bohrium App

2.1 什么是标准离线/在线任务

基于DP-Launching开发框架,快速把开发者的算法程序代码封装为平台定义的具有用户界面交互的标准离线/在线任务
简单来说这两个任务的区别是:

  • 标准离线任务:标准的科学软件计算流程:“输入文件”→“软件计算”→“输出文件” 适用于计算时间较长,不需要时时显示结果,会有任务计算记录

  • 标准在线任务:标准离线任务的在线版本,遵循科学软件计算流程,适用于计算时间较短的任务,省去计算节点的开机时间,也会有任务计算记录

  • Bohrium Apps平台支持的三种App应用类型的具体区别见文档:几种应用类型的区别

2.2 案例背景介绍

本案例将以 浅谈STEM图像|机器学习助力材料图像表征 这篇 Notebook 中的代码案例作为例子,来展示如何方便的将算法代码快速上线为应用软件。

在材料领域,常常需要对材料进行实验表征,常见的表征手段包括

  • 扫描电子显微镜(SEM)
  • 透射电子显微镜(TEM)
  • 高倍率透射电子显微镜(HRTEM)
  • 扫描透射电子显微镜(STEM)

扫描电子显微镜(Scanning Electron Microscope,简称SEM)是一种通过用聚焦电子束扫描样品的表面来产生样品表面图像的电子显微镜。透射电子显微镜(Transmission electron microscope,简称TEM)是把经加速和聚集的电子束投射到非常薄的样品上,电子与样品中的原子碰撞而改变方向,从而产生立体角散射。散射角的大小与样品的密度、厚度相关,因此可以形成明暗不同的影像。

扫描透射电子显微镜(Scanning Transmission Electron Microscopy,简称STEM)是一种特殊类型的SEM,利用高能电子束穿透样品,通过检测透射电子的强度变化来获取材料内部的结构信息。它结合了SEM和TEM的原理,既可以获得样品的表面信息,也可以获得样品的内部结构信息。

STEM图像是通过扫描透射电子显微镜获取的高分辨率图像。STEM图像可以显示样品的原子级结构和成分分布,广泛应用于材料科学、生物学、化学等领域。

代码
文本

功能一:读取 TIFF 格式的 STEM 图像

STEM 数据有多种存储格式,tiff 格式是最常见的,我们可以用 tifffile package 将 tiff 格式的 STEM 图像读取为 NumPy 数组。

代码
文本
[1]
# 先安装一下需要使用的库
!pip install tifffile matplotlib ncempy
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: tifffile in /opt/mamba/lib/python3.10/site-packages (2024.7.24)
Requirement already satisfied: matplotlib in /opt/mamba/lib/python3.10/site-packages (3.9.1.post1)
Requirement already satisfied: numpy in /opt/mamba/lib/python3.10/site-packages (from tifffile) (1.26.2)
Requirement already satisfied: python-dateutil>=2.7 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (2.8.2)
Requirement already satisfied: contourpy>=1.0.1 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (1.2.1)
Requirement already satisfied: packaging>=20.0 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (23.2)
Requirement already satisfied: pillow>=8 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (10.4.0)
Requirement already satisfied: fonttools>=4.22.0 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (4.53.1)
Requirement already satisfied: kiwisolver>=1.3.1 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (1.4.5)
Requirement already satisfied: cycler>=0.10 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (0.12.1)
Requirement already satisfied: pyparsing>=2.3.1 in /opt/mamba/lib/python3.10/site-packages (from matplotlib) (3.1.2)
Requirement already satisfied: six>=1.5 in /opt/mamba/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
代码
文本

原 Notebook 中的 Python 程序 如下:

代码
文本
[2]
### 功能一:读取 TIFF 格式的 STEM 图像

import tifffile
import numpy as np
import matplotlib.pyplot as plt

# 使用tifffile的imread函数读取tiff文件
def tiff_read(file_path):
tiff_data = tifffile.imread(file_path)
return tiff_data

tiff_file_path = '/bohr/stem-sample-joow/v1/tiff_mos2_sample.tiff'
tiff_data = tiff_read(tiff_file_path)

# 显示stem图像
plt.imshow(tiff_data)
plt.title('STEM Image')

# 保存图片到文件
output_image_path = 'stem_tiff_image.png'
plt.savefig(output_image_path)

# 打印相关信息
print('data type:', tiff_data.dtype)
print('shape:', tiff_data.shape)
print('min and max value:', np.min(tiff_data), np.max(tiff_data))
print('sample value:', tiff_data[0:5,0:5])
data type: float32
shape: (630, 361)
min and max value: -0.9979306 0.58522505
sample value: [[-0.6208849  -0.6104048  -0.7464335  -0.52881366 -0.8202625 ]
 [-0.7649823  -0.72672826 -0.8509661  -0.7813429  -0.82904   ]
 [-0.8495891  -0.6903203  -0.9000491  -0.8359004  -0.88514423]
 [-0.82774454 -0.9027067  -0.8497661  -0.9080221  -0.533194  ]
 [-0.87056684 -0.8587523  -0.9317956  -0.88318145 -0.9316725 ]]
代码
文本

关于这段代码:

这段代码接受一个 tiff 文件的文件路径,并返回数据类型、形状、最小值和最大值,示例数字以及以 .png 返回一个最终的图片。


2.3 使用DP-Launching框架封装代码

2.3.1 关于 DP-Launching开发框架

DP-Launching 框架(简称 Launching )是深势科技发布的一款用于定义标准离线任务/标准在线服务类型APP的开发框架。

开发者只需简单地声明一个程序入口文件,就可以把自有代码,转化为标准离线任务/标准在线服务型 APP。

Launching的详细使用方法见Launching的使用手册

代码
文本
[2]
# 我们可能需要安装 Launching 程序
!pip install --upgrade "dp-launching-sdk"
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Requirement already satisfied: dp-launching-sdk in /opt/mamba/lib/python3.10/site-packages (0.12.0)
Requirement already satisfied: dict-deep>=4.1.2 in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (4.1.2)
Requirement already satisfied: pydantic>=1.10.5 in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (1.10.17)
Requirement already satisfied: wcmatch in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (8.5)
Requirement already satisfied: fastapi in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (0.112.0)
Requirement already satisfied: pydantic-cli>=4.3.0 in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (4.3.0)
Requirement already satisfied: Deprecated in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (1.2.14)
Requirement already satisfied: uvicorn in /opt/mamba/lib/python3.10/site-packages (from dp-launching-sdk) (0.30.5)
Requirement already satisfied: typing-extensions>=4.2.0 in /opt/mamba/lib/python3.10/site-packages (from pydantic>=1.10.5->dp-launching-sdk) (4.9.0)
Requirement already satisfied: wrapt<2,>=1.10 in /opt/mamba/lib/python3.10/site-packages (from Deprecated->dp-launching-sdk) (1.16.0)
Requirement already satisfied: starlette<0.38.0,>=0.37.2 in /opt/mamba/lib/python3.10/site-packages (from fastapi->dp-launching-sdk) (0.37.2)
Requirement already satisfied: h11>=0.8 in /opt/mamba/lib/python3.10/site-packages (from uvicorn->dp-launching-sdk) (0.14.0)
Requirement already satisfied: click>=7.0 in /opt/mamba/lib/python3.10/site-packages (from uvicorn->dp-launching-sdk) (8.1.7)
Requirement already satisfied: bracex>=2.1.1 in /opt/mamba/lib/python3.10/site-packages (from wcmatch->dp-launching-sdk) (2.4)
Requirement already satisfied: anyio<5,>=3.4.0 in /opt/mamba/lib/python3.10/site-packages (from starlette<0.38.0,>=0.37.2->fastapi->dp-launching-sdk) (4.1.0)
Requirement already satisfied: idna>=2.8 in /opt/mamba/lib/python3.10/site-packages (from anyio<5,>=3.4.0->starlette<0.38.0,>=0.37.2->fastapi->dp-launching-sdk) (3.4)
Requirement already satisfied: sniffio>=1.1 in /opt/mamba/lib/python3.10/site-packages (from anyio<5,>=3.4.0->starlette<0.38.0,>=0.37.2->fastapi->dp-launching-sdk) (1.3.0)
Requirement already satisfied: exceptiongroup>=1.0.2 in /opt/mamba/lib/python3.10/site-packages (from anyio<5,>=3.4.0->starlette<0.38.0,>=0.37.2->fastapi->dp-launching-sdk) (1.2.0)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
代码
文本

2.3.2 将程序转化为 Launching 程序版本

让我们将上述的普通 Python 代码转换成符合 Launching 规范的可部署代码。

下方的代码无法直接在Notebook运行,请讲代码封装到一个python文件app.py中。

代码
文本
[ ]
import os
import sys
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
import tifffile
from dp.launching.cli import default_minimal_exception_handler, to_runner
# 这里是引入 Launching SDK 提供的方法
from dp.launching.typing import BaseModel, Field, InputFilePath, Int, OutputDirectory
from ncempy.io import dm

# 这一段,按照 Luanching 框架的要求,声明算法的输入参数、输出路径
class IOOptions(BaseModel):
height: Int = Field(default=10, description="The height of the image to be generated, in inches.")
width: Int = Field(default=6, description="The width of the image to be generated, in inches.")
dpi: Int = Field(default=300, description="The resolution of the image to be generated.")
input_file: InputFilePath = Field(
ftypes=["tiff", "dm4"], description="The input file path, which is a tiff or dm4 file."
)
output_dir: OutputDirectory

# 在这里定义输入文件的格式
class InputFile:
def __init__(self, input_file: InputFilePath):
self.input_file = input_file
self.file_type = self.get_file_extension()

def get_file_extension(self) -> str:
_, file_extension = os.path.splitext(self.input_file)
return file_extension

def read(self) -> np.ndarray:
print(f"Reading file: {self.input_file} with type: {self.file_type}")
match self.file_type:
case ".tiff":
data = np.array(tifffile.imread(self.input_file))
return data
case ".dm4":
return dm.dmReader(self.input_file)["data"]
case _:
raise ValueError("Unsupported file type.")


def main_runner(opts: IOOptions) -> int:

status = 0

# 在这里,接收传入的参数,执行开发者自定义的算法
img_data = InputFile(opts.input_file).read()
plt.figure(figsize=(opts.width, opts.height))
plt.imshow(img_data)
plt.title("STEM Image")
# 这一段,存图片到png文件
output_dir = Path(opts.output_dir.get_path())
output_dir.mkdir(parents=True, exist_ok=True)
output_image_path = "stem_tiff_image.png"
plt.savefig(os.path.join(output_dir, output_image_path), dpi=opts.dpi)

return status

# 这一段,按照Luanching框架的要求,定义to_parser方法
def to_parser():
return to_runner(
IOOptions,
main_runner,
version="0.1.0",
exception_handler=default_minimal_exception_handler,
)


if __name__ == "__main__":
to_parser()(sys.argv[1:])



代码
文本
[5]
# 将代码写入文件app.py
code = """
import os
import sys
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
import tifffile
from dp.launching.cli import default_minimal_exception_handler, to_runner
# 这里是引入 Launching SDK 提供的方法
from dp.launching.typing import BaseModel, Field, InputFilePath, Int, OutputDirectory
from ncempy.io import dm

# 这一段,按照 Luanching 框架的要求,声明算法的输入参数、输出路径
class IOOptions(BaseModel):
height: Int = Field(default=10, description="The height of the image to be generated, in inches.")
width: Int = Field(default=6, description="The width of the image to be generated, in inches.")
dpi: Int = Field(default=300, description="The resolution of the image to be generated.")
input_file: InputFilePath = Field(
ftypes=["tiff", "dm4"], description="The input file path, which is a tiff or dm4 file."
)
output_dir: OutputDirectory

# 在这里定义输入文件的格式
class InputFile:
def __init__(self, input_file: InputFilePath):
self.input_file = input_file
self.file_type = self.get_file_extension()

def get_file_extension(self) -> str:
_, file_extension = os.path.splitext(self.input_file)
return file_extension

def read(self) -> np.ndarray:
print(f"Reading file: {self.input_file} with type: {self.file_type}")
match self.file_type:
case ".tiff":
data = np.array(tifffile.imread(self.input_file))
return data
case ".dm4":
return dm.dmReader(self.input_file)["data"]
case _:
raise ValueError("Unsupported file type.")


def main_runner(opts: IOOptions) -> int:

status = 0

# 在这里,接收传入的参数,执行开发者自定义的算法
img_data = InputFile(opts.input_file).read()
plt.figure(figsize=(opts.width, opts.height))
plt.imshow(img_data)
plt.title("STEM Image")
# 这一段,存图片到png文件
output_dir = Path(opts.output_dir.get_path())
output_dir.mkdir(parents=True, exist_ok=True)
output_image_path = "stem_tiff_image.png"
plt.savefig(os.path.join(output_dir, output_image_path), dpi=opts.dpi)

return status

# 这一段,按照Luanching框架的要求,定义to_parser方法
def to_parser():
return to_runner(
IOOptions,
main_runner,
version="0.1.0",
exception_handler=default_minimal_exception_handler,
)


if __name__ == "__main__":
to_parser()(sys.argv[1:])

"""

with open("app.py", "w") as file:
file.write(code)

print("Code has been written to app.py")

Code has been written to app.py
代码
文本

IOOptions 类通过继承 Launching 中的 BaseModel 类,定义了 APP 与用户交互时的相关设置选项。

main_runner 函数执行 APP 的主要程序,并将结果返回到输出文件夹中。

to_parser() 函数是定义 APP 入口的函数。由以下几个部分组成:

  1. 用户定义 to_parser 函数: 该函数必须存在于描述文件中,是用来桥接 launching 的入口
  2. 命令行执行入口 to_parser()[sys.argv[1:]: launching 会将用户在 UI Form 上填写的参数作为命令行参数回传给该 python 描述文件,因此开发者需要在该文件中声明命令行执行语句
  3. to_parser 函数中需要返回 to_runner 函数,其参数由如下几部分:
    1. cls: 算法参数模型,如上述例子中的 GlobalOptions
    2. runner_func: 当 launching 将用户从 UI Form 上填写的参数通过命令行参数执行该描述文件时,launching 会将用户参数解析为 a 中 Model 的数据结构并将其作为参数执行该回调函数
    3. description: 该功能的描述
    4. version: 该功能的版本
    5. exception_handler: 执行 b 中回调函数发生错误时的钩子函数
    6. prologue_handler: 执行 b 中回调函数前的钩子函数
    7. epilogue_handler: 执行 b 中回调函数后的钩子函数
代码
文本

在定义完一个 APP 后,我们需要将包含入口文件和我们的运行的环境打包为一个 Bohrium 镜像,接下来我们进行 Bohrium 镜像的制作。

代码
文本

2.4 Bohrium 镜像制作

镜像,其实就是我们 APP 的运行环境,不同的 APP 所需要的依赖软件不同。因此,我们需要为 APP 构建镜像,在 Bohrium 构建镜像的方式十分简单。

步骤一:创建容器节点

在 Bohrium 节点管理页右上角选择"创建容器节点",本案例中镜像选择 ubuntu:20.04-py3.10,所属项目选择节点对应项目,机器类型、系统盘以及自动关机选项无需修改,保保持默认值即可。创建后通常需要 1 分钟左右的时间来启动 管理节点,等节点状态从"启动中"变为"运行中"时,即可登录使用。

步骤二:配置环境、导入代码

通过 SSH 登陆创建好的 Bohrium 节点,在节点中导入代码,并安装好代码运行所需的环境依赖

注意,代码和环境依赖,不能放在以下三个目录下,这几个目录下的文件,并不会随项目被打包到镜像当中:

  • /personal
  • /bohr
  • /share

步骤三:基于节点生成镜像

回到 Bohrium 节点页面,在刚才创建的新节点上点击右下角「更多」按钮,在下拉框中选择「创建镜像」,填写信息后等待镜像创建,这个过程可能需要几分钟,等待完成后,镜像就创建完毕了。

Tips

  • 通过 SSH 连接节点时,既可以直接使用网页页面,也可以使用本地 SSH,还可以使用 VSCode 等本地 IDE。

  • 开发机的 50001-50005 端口对外可用,可以用来提供对外服务。

代码
文本

2.5 发布 App

有关如何发布标准离线任务型 App,可参考 发布标准离线任务型 App

有关如何发布标准在线任务型 App,可参考 发布标准在线任务型 App

代码
文本

2.6 测试 App

在新构建的 APP 的版本列表中,我们可以测试某版本的 APP 点击「查看测试链接」,测试 APP 的输入参数设置是否正确(下图左)。

点击提交,进入任务运行页面(下图中),如果任务运行错误,会输出标准错误文件,据此调试你的程序。

任务运行成功后,会在 outputs 文件夹中返回运行结果(下图右),点击即可下载结果到本地。

alt alt alt
代码
文本

到此为止,我们已经成功部署了一款用来可视化 STEM tiff 格式文件的 APP,点击发布,获取程序的访问链接,或者通过 APP Store 进入,即可快速访问 APP 将 STEM tiff 的结果生成为可视化图像。

对于本期 Notebook 教程而言,我们生成的示例 APP 地址在这里:STEM-Demo APP

转换图像格式是相对来说对算力要求小,出结果快的应用,因此更适合将应用构建成 标准在线任务。本应用的标准在线任务App地址为:STEM-online

但是我们目前只是定义了「输入文件」一个参数,让我们来定义更多参数,来实现 APP 的更多功能。

代码
文本

Part 3: 功能拓展(选读)

3.1 增加对更多 STEM 结果文件格式的支持

DM3/DM4 是 STEM 图像一种常用的特殊格式。

DM4(DigitalMicrograph 4)格式是一种用于存储和处理电子显微镜图像的文件格式。它是由Gatan公司开发的 Digital Micrograph 软件所使用的格式。DM4 文件包含了原始的电子显微镜图像数据,以及与图像相关的元数据,如成像参数、设备信息和处理记录等。

Python 的 ncempy package 支持对 DM4 格式的文件进行读取。


原始的 Python 代码如下:

代码
文本
[ ]
# 你可能需要安装 ncempy
# !pip install ncempy -q
代码
文本
已隐藏单元格
代码
文本

实现不同文件格式的图片转化方式很简单,我们只需要判断文件的后缀名,执行相应的程序即可,让我们对原先的 APP 程序做一些改动。

代码
文本
已隐藏单元格
代码
文本

在上面的代码中,新增了一个 InputFile 对象,用来对不同的文件类型返回图像数据。

3.2 自定义图片的尺寸与分辨率

进一步,我们添加一些图像设置的选项,例如图像的高度、宽度、分辨率等参数。

代码
文本
已隐藏单元格
代码
文本

在上面的代码中,我们在 IOOptions 类中新增了三个自定义的图片设置选项,分别是 高度 heidht, 宽度 width 和分辨率 dpi。并提供了默认值和参数描述(参数描述会显示在 APP 界面上提示用户)

在主要程序中,我们调用 IOOptions 的这些属性,设置保存的图片。

plt.figure(figsize=(opts.width, opts.height))  # 设置图片宽度和高度

...

plt.savefig(os.path.join(output_dir, output_image_path), dpi=opts.dpi)  # 设置保存图片的分辨率
代码
文本

到目前为止,我们已经了解了使用 Bohrium App 的基本功能。我们可以继续拓展原 Notebook 中的代码,实现更多的 App 功能,这些实现方式对 APP 功能的调用大同小异,主要的区别在于内部程序,这里不再赘述。

参考资料

需要了解更多关于构建 APP 的技术,可以参阅:

  1. Bohrium APP 快速入门
  2. Bohrium APP 操作指南
  3. Launching 框架
代码
文本
Bohrium APP
Tutorial
Bohrium APPTutorial
点个赞吧
推荐阅读
公开
应用开发上手实例(一): 开发专属于你的科学计算器
Bohrium AppsBohrium APP
Bohrium AppsBohrium APP
Letian
更新于 2024-08-06
1 赞1 转存文件
公开
Bohrium Notebook 新手入门指南
bohriumNBHub
bohriumNBHub
喇叭花
发布于 2023-07-06
4 赞3 转存文件