ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Metaflow Cards 完整指南:用 @card 装饰器与自定义模板为机器学习任务自动生成 HTML 报告

Metaflow Cards 完整指南:用 @card 装饰器与自定义模板为机器学习任务自动生成 HTML 报告 MLOps工作流自动化数据工程【免费下载链接】metaflowBuild, Manage and Deploy AI/ML Systems项目地址https://gitcode.com/gh_mirrors/me/metaflow点击查看免费下载Metaflow Cards 是 Metaflow 内置的报告卡机制只要在step上放置一个card装饰器Metaflow 就会在该任务执行完成后自动生成一份人类可读的 HTML 报告用来观察运行结果、可视化模型产物并与非技术背景的同事分享结论。本文以 docs/cards.md 为主体结合仓库源码card_decorator.py、card_cli.py、card_client.py、card_modules 等逐层讲解如何用内置default卡片零改动出报告、如何通过current.card在 step 代码中动态拼装组件、如何使用 Card CLI 与 Notebook 客户端查看卡片以及如何编写并打包属于自己的可安装卡片模板。Cards 是什么从任务到 HTML 报告Metaflow Cards 使得从任意 Metaflow 任务中自动产出人类可读的报告卡成为可能。你可以用这个特性观察 Metaflow 运行结果、可视化模型、并把成果分享给非技术利益相关者。它的核心能力可以概括为三点开箱即用Metaflow 自带一个默认卡片DefaultCard无需修改任何代码即可展示任务的全部输出几行代码定制通过自定义卡片你可以改变报告的结构与内容突出对自己重要的数据可扩展、可离线任何人都可以把卡片模板制作成标准 Python 包分享出去Cards 可以通过 Metaflow CLI 访问即使没有互联网连接也能使用因此可以安全地用在重视安全隔离的环境中。Cards 还集成在 Metaflow GUI 的最新版本中允许你用应用特有的信息丰富既有任务视图。卡片的生产流程从架构上看卡片的产生遵循如下链路对应 docs/cards.md 与 card_decorator.py将card装饰器放置在step之上卡片会在该 Metaflow 任务每个step的一次实例化执行完成后创建单个step可以挂多个card装饰器每个装饰器都有一个type参数默认值为default对应 MetaflowCard.type任务完成时每个card装饰器会各自启动一个独立子进程调用card createCLI 命令由该命令生成并把 HTML 页面存储到 CardDatastore因为卡片存放在 datastore 中之后可以通过card view/get命令见 Card CLI或get_cards客户端函数见 Notebook 访问访问。从源码看CardDecorator.task_finished 在任务成功is_task_ok时依次调用self.card_creator.create(moderender, finalTrue, ...)与create(moderefresh, finalTrue, ...)即先渲染最终 HTML再写入最终数据更新。装饰器的完整默认参数也定义在源码中defaults { type: default, options: {}, scope: task, rank: None, # 可以是 high / medium / low用于 UI 上的排序 timeout: 45, id: None, save_errors: True, customize: False, refresh_interval: 5, }来源card_decorator.pycard 装饰器card装饰器实现位于 card_decorator.py通过继承StepDecorator实现。把它放到step之上即可为该任务生成一个可视化任务信息的 HTML 文件。参数说明参数类型默认值说明typestrdefault要创建的MetaflowCard类型对应MetaflowCard.type。optionsdict{}用于实例化MetaflowCard的选项会以options关键字参数传给卡片类。例如DefaultCard支持{only_repr: True}。timeoutint45在杀死卡片渲染子进程之前等待的时间秒。save_errorsboolTrue若为True渲染MetaflowCard失败时会生成一张携带完整失败堆栈的ErrorCard替代若为False则会直接抛出异常。idstrNone当一个 step 上有多个card时用id区分卡片配合current.card[myid]使用。customizeboolFalse标记该卡片为默认可编辑卡片current.card.append将作用到它。一个step上只能有一个card(customizeTrue)。refresh_intervalint5运行时卡片的刷新频率秒用于限制current.card.refresh的调用频率。rankstrNone在 GUI 上为卡片排序提供的提示值high/medium/low。注意type与id必须匹配正则^[a-zA-Z0-9_]$见 exception.py 中的TYPE_CHECK_REGEX/CARD_ID_PATTERN。若id不匹配card_decorator.py的task_pre_step会发出警告并把_user_set_card_id置为None此时无法通过current.card[myid]访问该卡片。使用语义示例from metaflow import FlowSpec, step, card class ModelTrainingFlow(FlowSpec): step def start(self): self.next(self.train) card( typedefault, options{only_repr: False}, timeout100, save_errorsFalse ) step def train(self): import random import numpy as np self.loss np.random.randn(100,100)*100 self.next(self.end) step def end(self): print(Done Computation) if __name__ __main__: ModelTrainingFlow()运行python myflow.py run后train任务完成时就会自动生成一张default类型卡片。options{only_repr: False}表示不强制用reprlib.repr压缩序列化产物源码实现见 basic.py 中DefaultCard.__init__对only_repr的处理。CardDatastore卡片的存储层CardDatastore 被 Card CLI 和get_cards卡片客户端共同使用负责解析一个pathspec对应的卡片元信息CardInfotype、hash、id、filename给出卡片在 datastore 中的读写路径保存/读取卡片的 HTMLsave_card/get_card_html与运行时数据 JSONsave_data/get_card_data。从源码看CardDatastore 会根据存储后端类型解析根目录s3对应CARD_S3ROOT、azure对应CARD_AZUREROOT、gs对应CARD_GSROOT、local/spin对应CARD_LOCALROOT见 card_datastore.py。卡片文件命名规则为TYPE-HASH.html或TYPE-ID-HASH.htmlget_card_location因此 CLI 和客户端都能通过--hash/--id精确定位到某一张卡。info_from_path会按此规则反解出CardInfo。此外存储路径同时支持含 steps 目录与不含 steps 目录两种格式_make_path的with_steps参数2022 年 6 月之前的旧版本客户端写出的卡片没有steps/stepname层级_list_card_paths会先读新路径为空时回退读取旧路径保证向后兼容。Card CLI命令行工具Card 相关命令由 card_cli.py 中的click.group()子命令组card提供。运行方式为python myflow.py card 子命令 pathspec。create创建卡片create命令负责在 datastore 中为某个 Task 创建卡片。传入--render-error-card时若所选type的卡片渲染失败会渲染一张携带堆栈的ErrorCard不传该参数时CLI 会直接抛出异常CardClassFoundException、IncorrectCardArgsException或UnrenderableCardException见 exception.py。# 语法python myflow.py card create pathspec --type type_of_card --timeout timeout_for_card --options {} python myflow.py card create 100/stepname/1000 --type default --timeout 10 --options {only_repr:false} --render-error-card常用参数--type要创建的卡片类型默认default--options传给卡片构造函数的 JSON 选项--timeout允许创建卡片的最大秒数--render-error-card渲染失败时生成错误卡片而非抛异常--id卡片 id须匹配正则--component-file/--mode/--data-file/--card-uuid等为内部参数运行时由current.card机制传递序列化组件与数据。view / get查看卡片view会在浏览器中打开与 pathspec 关联的卡片get取出卡片的 HTML 字符串并打印也可通过追加path参数保存到文件如python myflow.py card get start a.html --type default。二者都支持--hash、--type、--id过滤并支持--follow-resumed获取被 resume 任务的原始origin任务所对应的卡片。# 语法python myflow.py card view pathspec --hash hash_of_card --type type_of_card python myflow.py card view 100/stepname/1000 --hash ads34 --type default --follow-resumedresolve_card函数支持三种 pathspec 形态stepname、runid/stepname、runid/stepname/taskidcard_cli.py其中只传 stepname 时自动取该 flow 最新一次 run 中对应的 task。--hash支持完整哈希或前 5 位短哈希NUM_SHORT_HASH_CHARS 5。list / server枚举与本地服务list不带 pathspec 时枚举最近一次 run 中所有任务的全部卡片支持--as-json、--file输出带 pathspec 时列出该任务匹配的卡片清单含 Card Id / Type / Hash / Path并给出可直接复制的访问命令server启动一个本地卡片查看器服务--port默认8324、--poll-interval默认5秒、--max-cards默认30适合持续观察正在运行任务的实时卡片。在 Notebook 中访问 Cards除 CLI 之外Metaflow 还提供get_cards客户端用于在 CLI 之外例如 Jupyter Notebook解析卡片from metaflow import Task from metaflow.cards import get_cards taskspec MyFlow/1000/stepname/100 task Task(taskspec) card_iterator get_cards(task) # 也可以直接传字符串get_cards(taskspec) # 在浏览器中查看卡片 card card_iterator[0] card.view() # 获取卡片的 HTML html card_iterator[0].get()实现细节见 card_client.pyget_cards接受Task对象或形如{flow_name}/{run_id}/{step_name}/{task_id}的 pathspec另有可选参数id、type和follow_resumed默认True跟随 resume 链路解析原始任务返回的CardContainer是类列表的只读对象支持cards[0]、len(cards)、for c in cards迭代卡片内容采用惰性加载get_cards只解析路径真正从 datastore 拉取 HTML 发生在首次调用Card.get()或卡片在 Notebook 中渲染_repr_html_时因此即使单张卡片数据量很大get_cards也很快Card.view()使用 Python 内置webbrowser模块打开本地临时文件。MetaflowCard 基类MetaflowCard 是创建自定义卡片card types的基类。所有子类都必须实现render(task)方法其返回值是一个 HTML 字符串。下面是一个使用 mustache 模板渲染自定义 HTML 的示例from metaflow.cards import MetaflowCard # 自定义 HTML 文件的路径该文件是一个 mustache 模板。 PATH_TO_CUSTOM_HTML myhtml.html class CustomCard(MetaflowCard): type custom_card def __init__(self, options{no_header: True}, graphNone, components[], flowNone, **kwargs): super().__init__() self._no_header True self._graph graph if no_header in options: self._no_header options[no_header] def render(self, task): pt self._get_mustache() data dict( graphself._graph, headerself._no_header ) html_template None with open(PATH_TO_CUSTOM_HTML) as f: html_template f.read() return pt.render(html_template, data)基类提供_get_mustache()方法返回一个基于 mustache 语法的 chevron 模板引擎对象你可以用它重写 HTML 模板文件示例中的PATH_TO_CUSTOM_HTML就是承载 mustache 模板的文件。类属性type (str)卡片的类型名需要全局唯一类似 Python 包名card(typeT)即据此解析到对应卡片类ALLOW_USER_COMPONENTS (bool)置为True表示卡片允许用户编辑即允许通过current.card添加组件详见 从 step 代码编辑卡片RUNTIME_UPDATABLE (bool)置为True表示支持运行时更新render_runtime/refreshRELOAD_POLICY控制 UI 何时重载中间卡片取值never/always/onchange其中onchange通过reload_content_token(task, data)派生重载令牌。init参数components (List[str])在step运行期创建、已经render过的MetaflowCardComponent列表它们通过临时文件路径以--component-file参数传给card create子进程graph (Dict[str, dict])与该 flow 关联的 DAG形如stepname: step_attributes的字典options (dict)控制单个卡片行为的选项字典。例如DefaultCard支持{only_repr: True}——置True时所有产物都用reprlib.repr序列化而非原生对象序列化源码中TaskToDict的only_repr参数即此开关见 convert_to_native_type.py。MetaflowCardComponent 组件MetaflowCardComponent的render方法返回一个字符串或字典。它既可以在MetaflowCard类内部调用也可以在任务运行期通过current.card传入。下面是在MetaflowCard内部组合多个组件的示例from metaflow.cards import MetaflowCard, MetaflowCardComponent class Title(MetaflowCardComponent): def __init__(self, text): self._text text def render(self): return h1%s/h1 % self._text class Text(MetaflowCardComponent): def __init__(self, text): self._text text def render(self): return p%s/p % self._text class CustomCard(MetaflowCard): type custom_card HTML htmlhead/headbody{data}body/html def __init__(self, options{no_header: True}, graphNone, components[], flowNone, **kwargs): super().__init__() self._no_header True self._graph graph if no_header in options: self._no_header options[no_header] def render(self, task): pt self._get_mustache() data \n.join([ Title(Title 1).render(), Text(some text comes here).render(), Title(Title 2).render(), Text(some text comes here again).render(), ]) data dict(datadata) html_template self.HTML return pt.render(html_template, data)源码层面组件会被_render_card_componentcomponent_serializer.py校验与安全渲染只有返回str或可 JSON 序列化dict的组件才会被采纳渲染抛异常或返回非法类型的组件会被静默丢弃从而保证最终卡片 HTML 的健壮性。DefaultCard 与内置组件DefaultCard 是 Metaflow 暴露的默认卡片当card不带type参数或typedefault时使用也是 CLI 的默认卡片。它基于 HTML 模板 base.html配合 main.js 与 bundle.css 工作模板把任务的 JSON 数据与 JS/CSS 一起渲染成完整 HTML 页面JS/CSS 由 cards-ui 目录下的 JS 应用构建而来——该应用负责把 JSON 对象动态生成为 HTML 视图。DefaultCard会通过TaskInfoComponentbasic.py自动组织页面内容Task Metadata创建/完成时间、Tags、Attempt、Duration、User、Task Codestep 源码、Flow Parameters、Artifacts自动识别表格与图片类型单独成区、DAG 图等。同文件还定义了BlankCard只有用户组件、options{title: ...}可设标题与ErrorCard展示渲染失败堆栈。DefaultCard/BlankCard都可以从step代码接收MetaflowCardComponent。通过metaflow.cards暴露的主要内置组件实现见 components.pyArtifact在任务运行期记录任意 Python 对象Artifact(some_variable, compressTrue)使用截断表示大对象用reprlib截断Table在卡片 HTML 中创建表格Table.from_dataframe(df)可从 Pandas DataFrame 直接生成默认对大表做截断truncateTrueImage在卡片 HTML 中创建图片Image(bytearr, my Image from bytes)直接从bytes创建Image.from_pil_image(pilimage, From PIL Image)从PIL.Image创建Image.from_matplotlib(plot, My matplotlib plot)从 Matplotlib 图创建接受Figure、Axes、AxesSubplot。注意图片数据以 base64 内嵌进卡片无需外部文件即可展示Error显示错误的包装子组件接受exception和title参数常用于在卡片上展示step里捕获的异常堆栈Markdown在 HTML 模板中渲染 Markdown 文本自动textwrap.dedent缩进且支持运行期update。此外仓库还提供ProgressBar、ValueBox、VegaChart、PythonCode、JSONViewer、YAMLViewer、EventsTimeline等组件完整导出列表见 cards.py其中标有REALTIME_UPDATABLE True的组件如Artifact、Markdown、ProgressBar支持通过各自的update(...)方法在任务运行期实时更新卡片内容。从 step 代码编辑 Cardscurrent.cardMetaflowCard可以通过current.card接口在step代码中被编辑。只有当一个card装饰器被放置在step上时current.card接口才会激活。考虑下面的例子card(typeblank, ida) card(typedefault) step def train(self): from metaflow.cards import Markdown from metaflow import current current.card[a].append(Markdown(# This is present in the blank card with id a)) current.card.append(Markdown(# This is present in the default card)) self.t dict( hi1, hello2 ) self.next(self.end)上述场景中有两个card装饰器被current.card定制current.card.append/current.card[a].append只接受MetaflowCardComponent的子类对象current.card.append/current.card[a].append只把组件添加到一张卡片上当一个step上有多张卡片时会解析出一个**默认可编辑卡片default editable card**来消歧只有它拥有current.card.append/current.card.extend的权限上例中current.card.append会把 Markdown 组件加到typedefault的卡片上current.card[a].append会把 Markdown 加到ida的blank卡片上。current.cardCardComponentCollectorCardComponentCollectorcomponent_serializer.py是负责把MetaflowCardComponent解析到card装饰器所引用卡片的对象。要点如下因为一张 step 可以有多张卡片CardComponentCollector提供了_finalize函数它在最后一个card装饰器调用task_pre_step回调时被调用从该 step 的全部card中找出默认可编辑卡片若存在多个没有id的可编辑卡片用户调用current.card.append时会收到警告而不是报错因为current.card无法判定组件归属此时应给所有card设置id再通过current.card[myid].append精确指定目标card还暴露了customizeTrue参数一个step上只能有一个card(customizeTrue)。从 CLI 运行 flow 时也可以额外加卡片customizeTrue会把该装饰器对应的卡片设为默认可编辑即current.card.append会追加到这张卡片。若有多个card(customizeTrue)current.card会发出警告且append不生效源码中_finalize对customize_cards的检查见 component_serializer.pycurrent.card的一个重要设计是永不失败多张可编辑卡片导致歧义时只警告不报错访问不存在的 idcurrent.card[my_non_existant_card]时返回一个不被引用的空list并发出一次警告同时把WarningComponent加入卡片显示一张MetaflowCard可被用户编辑的前提是ALLOW_USER_COMPONENTSTrueALLOW_USER_COMPONENTSFalse的卡片不能编辑无法使用current.card.append。不可编辑的卡片仍可通过两种方式追加组件显式设置id后用current.card[myid].append或按类型查找current.card.get(typepytorch)返回该类型所有卡片的组件数组列表当step执行完成每个card装饰器都会调用current.card._serializeCardComponentCollector._serialize_components得到 JSON 可序列化的str/dict列表_serialize_components内部逐个调用组件的render函数把列表json.dump到tempfile再传给card create子进程供MetaflowCard在最终输出中使用。此外current.card还暴露了get(type...)、components、clear()、refresh(data)等能力refresh默认按refresh_interval限流forceTrue可强制刷新完整 API 见CardComponentManager的用法注释component_serializer.py。创建可安装的自定义 Cards自定义卡片可以通过metaflow_extensions命名空间包安装。每个包含自定义卡片的metaflow_extensions模块都应遵循下面的目录结构your_package/ # 目录名无关紧要 ├ setup.py ├ metaflow_extensions/ │ └ organizationA/ # 不需要 __init__.py这是命名空间包 │ └ plugins/ # 不需要 __init__.py这是命名空间包 │ └ cards/ # 不需要 __init__.py这是命名空间包 │ └ my_card_module/ # 卡片模块名 │ ├ __init__.py # 必须有 __init__.py 才能被识别为包 │ └ somerandomfile.py # 包内的其他文件metaflow_extensions.organizationA.plugins.cards.my_card_module的__init__.py需要暴露一个CARDS属性它是一个由MetaflowCard子类构成的列表。例如下面这个__init__.py暴露了一个type为y_card2的MetaflowCardfrom metaflow.cards import MetaflowCard class YCard(MetaflowCard): type y_card2 ALLOW_USER_COMPONENTS True def __init__(self, options{}, components[], graphNone, flowNone, **kwargs): self._components components def render(self, task): return I am Y card %s % \n.join([comp for comp in self._components]) CARDS [YCard]只要把这个metaflow_extensions模块放进PYTHONPATH即可生效。自定义卡片也可以直接复用 Metaflow 提供的组件例如继承BlankCard并组合Artifact/Tablefrom metaflow.cards import BlankCard from metaflow.cards import Artifact, Table class MyCustomCard(BlankCard): type my_custom_card def render(self, task): art_com [ Table( [[Artifact(k.data, k.id)] for k in task] ).render() ] return super().render(task, components[art_com]) CARDS [MyCustomCard]从源码看get_card_class(card_type)会遍历metaflow.plugins.CARDS注册表按type匹配卡片类component_serializer.pycard create子进程在实例化时会用options...、components...、graph...、flow...等关键字调用构造函数card_cli.py并兼容只接受graph的第三方旧式卡片通过探测构造函数签名是否含graph_info决定是否传入新格式的图信息。实战建议与常见问题排查多卡片并存时务必设置 id同一个 step 使用多个card时若不做区分current.card.append只会发出警告而不会写入任何卡片。建议约定一个默认卡 若干带 id 的卡的组织方式。渲染超时与错误卡片timeout默认 45 秒长任务或复杂模板可适当调大save_errorsTrue时渲染失败会自动生成ErrorCard卡片上会呈现完整堆栈方便在 GUI 或card view中直接定位问题。离线可用卡片以 HTML 文件存放在 datastore本地、S3、Azure、GCS 或 spin中card view/card get全程无需联网适合安全受限环境。resume 链路--follow-resumed与get_cards(..., follow_resumedTrue)会解析到被 resume 前的原始任务卡片避免因重跑而丢失历史报告。命名约束type与id必须匹配^[a-zA-Z0-9_]$不匹配时 CLI 会给出红色警告并将id置空。数据更新频率运行时刷新受refresh_interval默认 5 秒限流配合REALTIME_UPDATABLE组件如ProgressBar、Markdown、Artifact的update()可实现接近实时的进度/指标看板。以上就是 Metaflow Cards 从零改动默认报告到深度定制可安装卡片的完整路径先用card装饰器让每个任务自动产出 HTML 报告再通过current.card在 step 内动态拼装Artifact/Table/Image/Markdown等组件最后用metaflow_extensions命名空间包把自定义MetaflowCard打包分发——配合 CLI、Notebook 客户端与 GUI即可把一次机器学习运行变成一份可分享、可追溯、可离线查看的工程化报告。赞分享MLOps工作流自动化数据工程【免费下载链接】metaflowBuild, Manage and Deploy AI/ML Systems项目地址https://gitcode.com/gh_mirrors/me/metaflow点击查看免费下载相关推荐Mobile Security Framework自动化报告生成自定义模板与数据可视化完整指南Mobile Security Framework MobSF 是一款功能强大的移动应用安全测试框架支持Android、iOS和Windows平台的静态和动态应用安全网络安全渗透测试逆向工程ScienceFair核心架构深度拆解Electron、dat/hyperdrive与choo如何协作构建去中心化科研文献管理桌面应用ScienceFair核心架构深度拆解Electron、dat/hyperdrive与choo如何协作构建去中心化科研文献管理桌面应用 ScienceFair使用 Isaac Lab 模板生成器构建自己的机器人学习项目与任务使用 Isaac Lab 模板生成器构建自己的机器人学习项目与任务 本文系统讲解 Isaac Lab 提供的 template generator模板生成器人工智能强化学习机器人具身智能深度学习创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表