ARTICLE DETAIL

资讯详情

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

darktable AI 子系统开发指南:基于 ONNX Runtime 的推理后端架构与实战

darktable AI 子系统开发指南:基于 ONNX Runtime 的推理后端架构与实战 darktable AI 子系统开发指南基于 ONNX Runtime 的推理后端架构与实战【免费下载链接】darktabledarktable is an open source photography workflow application and raw developer项目地址: https://gitcode.com/GitHub_Trending/da/darktabledarktable 的 AI 子系统AI Subsystem是一套以 ONNX Runtime 为唯一推理后端的模块化框架支撑交互式对象蒙版SAM/SegNext、神经降噪RGB 域与 Raw 域以及超分辨率放大等功能。本文以 dev-doc/AI.md 为核心结合仓库源码深入剖析其三层架构、执行提供者Execution Provider解析、模型注册表与下载机制并给出从零添加一个全新 AI 任务Task的完整步骤。读完本文你将掌握 darktable AI 功能从模型加载、推理调度到接入 UI 的全链路开发方法。一、架构总览三层解耦的 AI 子系统darktable 的 AI 子系统在逻辑上分为三层职责清晰、依赖单向src/ai/ ONNX Runtime 后端darktable_ai 静态库 backend.h 公共 API类型定义、模型加载、推理 backend_common.c 环境、模型注册表、provider 解析 backend_onnx.c ONNX Runtime C API 封装 src/common/ai/ 高层 AI 模块编译进 lib_darktable segmentation.c/.h SAM/SegNext 交互式蒙版 restore.c/.h 通用 env/ctx 生命周期 模型加载器 restore_common.h restore_* 共享的私有结构体定义 restore_rgb.c/.h RGB 路径降噪 放大分块推理、阴影提升、DWT 细节恢复 restore_raw_bayer.c/.h RawNIND Bayer 降噪批处理 管道预览 restore_raw_linear.c/.h RawNIND linear/X-Trans 降噪 src/common/ai_models.c/.h 模型注册表、下载、偏好设置集成 src/gui/preferences_ai.c AI 偏好设置页签关键分离原则src/ai/是一个完全自包含的静态库不依赖任何 darktable 核心只依赖 GLib 与 ONNX Runtime这使得后端可以被独立测试和复用而src/common/ai/负责把 AI 后端与 darktable 核心 APIDWT 小波、图像缓冲区、配置系统等桥接起来并仅在USE_AION时编译。从 src/ai/backend.h 可以看到后端头文件只包含stdint.h与glib.h印证了这一自包含设计。构建标志Build FlagsFlag默认值作用USE_AIOFF启用 AI 子系统USE_AI_DOWNLOADON当USE_AI开启时允许从仓库下载模型当USE_AION时预处理器会定义HAVE_AI启用下载时还会定义HAVE_AI_DOWNLOAD。在 src/common/ai_models.h 中下载相关 API 全部包裹在#ifdef HAVE_AI_DOWNLOAD之内说明下载能力是可选特性。运行时开关默认关闭懒初始化AI 功能在偏好设置中默认关闭。当关闭时不加载任何 ONNX Runtime不创建、不扫描任何模型目录所有dt_ai_env_init()/dt_ai_load_model()调用直接返回 NULL依赖 AI 的模块通过reload_defaults()隐藏自身入口。用户可在偏好设置 - AI - enable AI features中启用。启用后的初始化是延迟进行的dt_ai_models_init_lazy()负责在运行时重新启用 AI 时执行延迟初始化创建目录、读取 provider 配置、加载模型注册表、扫描本地模型无需重启 darktable。对应实现见 src/common/ai_models.h 的注释与声明。二、ONNX Runtime 集成从加载到推理2.1 初始化进程级单例 懒加载ONNX Runtime 通过 GLib 的g_once()单例机制懒初始化g_ort—OrtApi指针每进程一份g_env—OrtEnv实例每进程一份。两者在首次模型加载或 provider 探测时创建并在进程生命周期内常驻。在 Linux 上ONNX Runtime 始终通过g_module_open()懒加载而非在进程启动时静态链接。这样做的目的是防止 GPU provider 库如 MIGraphX/ROCm在进程启动阶段就初始化——在不支持的 GPU 上这些库可能在 darktable 有机会检查偏好设置之前就abort()崩溃。2.2 模型加载调用链dt_ai_load_model(env, model_id, model_file, provider) - dt_ai_load_model_ext(env, model_id, model_file, provider, opt_level, dim_overrides, n_overrides) - dt_ai_onnx_load_ext(model_dir, model_file, provider, opt_level, dim_overrides, n_overrides)加载一个模型的完整流程对应 src/ai/backend_common.c 中dt_ai_load_model_ext的实现解析 provider将DT_AI_PROVIDER_CONFIGURED/DT_AI_PROVIDER_AUTO解析为具体 EP并在此处统一应用模型声明的cpu_only安全约束解析图优化级别DT_AI_OPT_DEFAULT时读取模型 manifest 中的ort_optimization任何具体级别都是对 manifest 的显式覆盖通过环境中的模型注册表把model_id解析为目录路径创建OrtSessionOptions开启全核 intra-op 并行设置图优化级别Graph Optimization Level应用符号维度覆盖针对动态形状模型调用_enable_acceleration()挂接选定的执行提供者从.onnx文件创建OrtSession内省所有输入/输出的名称、类型与形状检测动态输出形状任一维度 0以启用 ORT 内部分配输出模式。注意dt_ai_load_model()只是dt_ai_load_model_ext()的便捷封装默认参数为DT_AI_OPT_DEFAULT, NULL, 0见 src/ai/backend_common.c。2.3 推理接口dt_ai_run与张量描述符调用方通过dt_ai_tensor_t数组传入输入、接收输出typedef struct dt_ai_tensor_t { void *data; // 指向原始数据缓冲 dt_ai_dtype_t type; // 元素数据类型 int64_t *shape; // 维度数组 int ndim; // 维度数量 } dt_ai_tensor_t;该结构定义于 src/ai/backend.h不包含字节长度字段——缓冲长度由shape各维度乘积乘以sizeof(elem)隐式确定data与shape指针均为借用后端在dt_ai_run期间不会拷贝它们调用方负责分配足够空间。辅助函数dt_ai_tensor_element_count()可计算形状对应的元素个数。dt_ai_run()透明处理两个特殊场景Float16 自动转换若调用方提供 Float32 数据而模型期望 Float16后端在推理前即时转换输出方向同理动态输出形状若任一输出带符号维度ORT 在内部分配输出张量。推理完成后后端把数据拷贝到调用方缓冲并用实际维度回写调用方的 shape 数组。2.4 图优化级别Graph Optimization Levels级别枚举值适用场景AllDT_AI_OPT_ALL默认、最快适用于大多数模型BasicDT_AI_OPT_BASIC仅做常量折叠 冗余节点消除。SAM2 decoder必须使用激进的优化会在动态维度上破坏形状推断DisabledDT_AI_OPT_DISABLED预留暂未使用在 src/ai/backend.h 中还有一个额外的哨兵值DT_AI_OPT_DEFAULT -1由dt_ai_load_model传入时表示读取 manifest 的ort_optimization字段缺省回退 ALL而dt_ai_load_model_ext的调用方传具体级别即可覆盖 manifest。2.5 符号维度覆盖Symbolic Dimension Overrides带符号维度的模型例如 SAM2 decoder 的num_labels会让 ONNX Runtime 的形状推断失败。此时应使用dt_ai_load_model_ext()配合dt_ai_dim_override_t绑定具体值dt_ai_dim_override_t overrides[] { { num_labels, 1 } }; ctx dt_ai_load_model_ext(env, id, file, provider, DT_AI_OPT_BASIC, overrides, 1);dt_ai_dim_override_t结构src/ai/backend.h只有name符号维度名如num_labels与value具体值两个字段。注意name指针只在加载调用期间被读取后端会自行拷贝所需内容调用方可在加载返回后立即释放字符串。三、执行提供者Execution Providers3.1 Provider 表Provider枚举配置字符串平台AutoDT_AI_PROVIDER_AUTOauto全部CPUDT_AI_PROVIDER_CPUCPU全部Apple CoreMLDT_AI_PROVIDER_COREMLCoreMLmacOSNVIDIA CUDADT_AI_PROVIDER_CUDACUDALinux, WindowsAMD MIGraphXDT_AI_PROVIDER_MIGRAPHXMIGraphXLinuxIntel OpenVINODT_AI_PROVIDER_OPENVINOOpenVINOLinux, Windows, macOS (x86_64)Windows DirectMLDT_AI_PROVIDER_DIRECTMLDirectMLWindows在 src/ai/backend_common.c 的dt_ai_providers[]表中可以直观看到每个 provider 的config_string、display_name与编译期平台守卫#if defined(...)控制的available字段。available决定哪些 provider 出现在 UI 中运行时是否真的可用会另行探测见 3.4 节。此外DT_AI_PROVIDER_CONFIGURED#define值为 -1见 src/ai/backend.h是dt_ai_load_model()/dt_ai_load_model_ext()的哨兵值它会在调用时从darktablerc读取用户的 provider 偏好。它不是真实 provider绝不能存入配置或 provider 表。消费方遵循两条规则需要尊重用户设置如 restore、segmentation就传CONFIGURED需要强制特定 EP如强制 decoder 走 CPU就直传该 EP。3.2 自动探测策略AUTO当用户选择DT_AI_PROVIDER_AUTO或从CONFIGURED解析得到 AUTO时后端优先尝试平台原生加速失败则优雅回退macOSCoreML - CPUWindowsDirectML - CPULinuxCUDA - MIGraphX - ROCmlegacy- CPU3.3 运行时 Provider 加载Provider 函数通过运行时动态符号查找加载Unix 上用GModule/dlsymWindows 上用GetProcAddress从已链接的 ONNX Runtime 共享库中解析。这带来三个好处无编译期对 provider 专属头文件的依赖provider 是可选的——缺失的符号被优雅处理同一份二进制同时兼容 CPU-only 与 GPU-enabled 的 ORT 构建。3.4 Provider 探测dt_ai_probe_provider()dt_ai_probe_provider()在不加载模型的前提下测试某 provider 能否在运行时初始化。它创建临时的OrtSessionOptions尝试挂接 provider返回 1可用或 0不可用。偏好设置 UI 用它来在用户选中不可用的 provider 时给出警告。3.5 多 GPU 设备选择逃生通道对于同一厂商有多张 GPU 的系统如笔记本的 iGPUdGPU或双 NVIDIA 卡工作站默认device_id为0平台枚举的第一块。高级用户可通过配置键或环境变量覆盖同时设置时环境变量优先Provider配置键环境变量CUDAplugins/ai/cuda_device_idDT_CUDA_DEVICE_IDMIGraphX / ROCmplugins/ai/migraphx_device_idDT_MIGRAPHX_DEVICE_IDDirectMLplugins/ai/dml_device_idDT_DML_DEVICE_ID索引语义遵循各 provider 自身的枚举方式CUDA索引与nvidia-smi一致并尊重CUDA_VISIBLE_DEVICESMIGraphX / ROCm索引对应rocminfo中的 GPU agent 顺序DirectML索引对应IDXGIFactory1::EnumAdapters1顺序。OpenVINO 与 CoreML 是单设备或自管理不读取 device_id 键。修改后需重启 darktable 生效。后端提供了dt_ai_device_id_changed_since_load()等辅助函数来检测配置已变但进程内 ORT 仍是旧状态的情形见 src/ai/backend.h。3.6 ONNX Runtime 发行包来源平台包来源包含的 ProvidersmacOSGitHub releasesCPUCPU、CoreML经 Apple frameworksLinux (x86_64)GitHub releasesGPUCPU、CUDA、TensorRTLinux (aarch64)GitHub releasesCPU仅 CPULinux系统包发行版仅 CPUDebian/Ubuntu/Fedora 的包不含 GPU providerWindowsNuGetDirectML 变体CPU、DirectML构建系统 cmake/modules/FindONNXRuntime.cmake 在系统找不到 ONNX Runtime 时会自动下载合适的包Linux x86_64 默认下载 GPU 变体以启用 CUDA 加速而系统包如 Debian/Ubuntu 的libonnxruntime-dev仅含 CPU不含 GPU provider。四、模型发现与注册表Model Registry4.1 目录布局模型通过扫描子目录中的config.json被发现扫描路径为传入dt_ai_env_init()的自定义路径分号分隔user_data_dir/darktable/models/Linux~/.local/share/darktable/models/Windows%APPDATA%\darktable\models\macOS~/.local/share/darktable/models/重复 ID 以先发现者为准重复项被跳过。模型下载ai_models.c也解压到同一路径因此下载的模型立即可被发现。扫描实现见 src/ai/backend_common.c 的_scan_directory/_scan_all_paths逐个读取config.json解析字段并用哈希表model_paths记录id - 路径映射以去重。用户还可以通过配置键plugins/ai/models_path覆盖模型目录dt_ai_resolve_models_path_override()支持~展开见 src/ai/backend_common.c。4.2 config.json 格式每个模型目录必须包含config.json{ id: mask-object-segnext-b2hq, name: mask segnext vitb-sax2 hq, description: SegNext ViT-B SAx2 HQ fine-tuned for interactive masking, task: mask, arch: segnext, backend: onnx }字段必填默认值说明id是--唯一标识符name是--UI 中显示的展示名description否简短描述task否general任务类型denoise、upscale、mask、depthbackend否onnx后端类型目前仅支持onnxarch否模型架构如sam2、segnextnum_inputs否1模型输入数量除了这些基础字段后端还支持一组可选行为提示存放在attributes对象中例如attributes: { shadow_boost: true, tile_factor: 1.5, color_space: sRGB }dt_ai_model_attribute_*系列访问器src/ai/backend.h会按需解析 JSON缺失的键或类型不符的键返回传入的默认值bool/string 变体返回 FALSE/NULL。dt_ai_model_attribute_string()支持点分路径如variants.bayer.onnx中间段必须是 JSON 对象实现见 src/ai/backend_common.c。类似地manifest 还可以声明cpu_only数组或按 onnx 文件名 stem 分组的对象声明哪些 EP 对模型不安全、coreml_formatneuralnetwork或mlprogram、ort_optimization与ort_optimization_provider按 provider 覆盖图优化级别。这些字段会被后端序列化为 JSON 字符串存入dt_ai_model_info_tsrc/ai/backend.h。4.3 模型 ID 命名约定模式task-model[-size]全部小写、连字符分隔第一个组件是任务类型denoise、mask、upscale、depth蒙版任务的第二个组件是子任务object存在多种尺寸时追加尺寸后缀small、base、large。示例denoise-nind、mask-object-sam21-small、upscale-bsrgan、mask-depth-da2-small。当前仓库内置的模型目录 data/ai_models.json 包含mask-object-sam21-small、mask-object-segnext-b2hq、denoise-nind、rawdenoise-nind、upscale-realplksr五个条目每个都带min_version与default标记。五、模型仓库darktable-ai与下载机制darktable 中可下载的模型作为 release 资产托管在darktable-ai 仓库中。该仓库还包含转换脚本——将 PyTorch 模型导出为 darktable 期望格式的 ONNX正确的 I/O 名称、动态轴、把插值烘焙进计算图等打包脚本——把config.json ONNX 文件打包为.dtmodel归档zip用于分发模型元数据——ai_models.json源文件列出所有可用模型及其任务、描述、资产文件名。下载流程darktable 读取随构建分发的 data/ai_models.json得知存在哪些模型用户在 AI 偏好设置中点击下载ai_models.c通过 GitHub API 从 darktable-ai 最新 release 拉取.dtmodel资产归档解压到~/.local/share/darktable/models/模型立即被dt_ai_env_init()发现。仓库在darktablerc中配置plugins/ai/repositorydarktable-org/darktable-ai从 src/common/ai_models.h 可以看到仓库可以额外发布未包含在捆绑目录中的模型versions.json是 release 内容的超集支持第三方仓库plugins/ai/third_party_repositories与 sha256 校验和验证模型还有DT_AI_MODEL_UPDATE_AVAILABLE/DT_AI_MODEL_UPDATE_REQUIRED的版本状态机——UPDATE_REQUIRED表示当前代码无法使用已安装模型UPDATE_AVAILABLE只是软提示。向仓库添加新模型用转换脚本把模型导出为 ONNX或参照现有示例编写新脚本创建带正确id、task、arch字段的config.json打包为.dtmodel归档在 darktable-ai 的ai_models.json中新增模型条目发布新 release并把.dtmodel作为资产附上更新 darktable 源码中的 data/ai_models.json加入新模型条目。用户也可以从本地.dtmodel文件安装模型dt_ai_models_install_local()src/common/ai_models.h接受 zip 归档路径。六、如何添加一个全新的 AI 功能这是 dev-doc/AI.md 的核心实战章节完整步骤如下。Step 1创建 AI 模块在src/common/ai/下创建你的处理模块。使用不透明类型opaque types封装模块内部包装ai/backend.h的dt_ai_*调用对外暴露干净的公共 API// src/common/ai/your_task.h #pragma once #include glib.h typedef struct dt_your_task_env_t dt_your_task_env_t; typedef struct dt_your_task_ctx_t dt_your_task_ctx_t; dt_your_task_env_t *dt_your_task_env_init(void); void dt_your_task_env_destroy(dt_your_task_env_t *env); dt_your_task_ctx_t *dt_your_task_load( dt_your_task_env_t *env); void dt_your_task_free(dt_your_task_ctx_t *ctx); gboolean dt_your_task_available( dt_your_task_env_t *env); int dt_your_task_process( dt_your_task_ctx_t *ctx, const float *in, float *out, int width, int height);// src/common/ai/your_task.c #include common/ai/your_task.h #include ai/backend.h #include common/ai_models.h #define TASK_KEY your_task struct dt_your_task_env_t { dt_ai_environment_t *ai_env; }; struct dt_your_task_ctx_t { dt_ai_context_t *ai_ctx; dt_your_task_env_t *env; }; dt_your_task_ctx_t *dt_your_task_load( dt_your_task_env_t *env) { if(!env) return NULL; char *model_id dt_ai_models_get_active_for_task(TASK_KEY); if(!model_id || !model_id[0]) { g_free(model_id); return NULL; } dt_ai_context_t *ai_ctx dt_ai_load_model( env-ai_env, model_id, NULL, DT_AI_PROVIDER_CONFIGURED); g_free(model_id); if(!ai_ctx) return NULL; dt_your_task_ctx_t *ctx g_new0(dt_your_task_ctx_t, 1); ctx-ai_ctx ai_ctx; ctx-env env; return ctx; } int dt_your_task_process( dt_your_task_ctx_t *ctx, const float *in, float *out, int width, int height) { // prepare input tensor (convert colorspace, layout) // call dt_ai_run(ctx-ai_ctx, ...) // post-process output return 0; }这段示例揭示了一条关键约定dt_ai_models_get_active_for_task(TASK_KEY)定义于 src/common/ai_models.h按任务从集中式配置键plugins/ai/models/active/{task}解析当前激活的模型若未设置则回退到该任务的默认下载模型并写回配置键。加载时传入DT_AI_PROVIDER_CONFIGURED让 provider 决策尊重用户偏好。Step 2注册进构建系统在 src/CMakeLists.txt 的USE_AI分支中添加源文件FILE(GLOB SOURCE_FILES_AI common/ai_models.c common/ai/segmentation.c common/ai/restore.c common/ai/restore_rgb.c common/ai/restore_raw_bayer.c common/ai/restore_raw_linear.c common/ai/your_task.c # add here ... )Step 3添加模型条目在 data/ai_models.json 中添加模型{ id: your-task-model-name, name: your task model name, description: description of the model, task: your_task, github_asset: your-task-model-name.dtmodel, default: true }.dtmodel文件是一个 zip/tar 归档内含config.json和 ONNX 模型文件一个包可含多个 ONNX如 rawdenoise 的model_bayer.onnxmodel_linear.onnx。Step 4创建 UI 消费方lighttable 模块创建src/libs/your_module.cdarkroom IOP创建src/iop/your_module.c。UI 模块只能包含你的src/common/ai/头文件——绝不直接包含ai/backend.h或common/ai_models.h以维持分层边界#include common/ai/your_task.h // in gui_init or job startup: dt_your_task_env_t *env dt_your_task_env_init(); // check availability: gboolean avail dt_your_task_available(env); // process: dt_your_task_ctx_t *ctx dt_your_task_load(env); dt_your_task_process(ctx, input, output, w, h); dt_your_task_free(ctx);七、可用任务一览与消费方任务任务键API消费方对象蒙版masksrc/common/ai/segmentation.hsrc/develop/masks/object.cRaw 降噪Bayerrawdenoisesrc/common/ai/restore_raw_bayer.hsrc/libs/neural_restore.cRaw 降噪Linearrawdenoisesrc/common/ai/restore_raw_linear.hsrc/libs/neural_restore.c降噪denoisesrc/common/ai/restore_rgb.hsrc/libs/neural_restore.c放大upscalesrc/common/ai/restore_rgb.hsrc/libs/neural_restore.c各任务的具体模型要求、I/O 规格、分块tiling策略、色彩空间约定、ONNX 导出说明与 config.json 示例详见配套参考文档AI_Tasks.md。摘要如下对象蒙版maskSAM 2.1 与 SegNext 两种架构。图片先被导出为 sRGB uint8经 SAM encoder 编码为图像嵌入每图一次、带缓存与磁盘缓存用户点击放置前景/背景点后轻量 decoder 产出蒙版前一低分辨率蒙版会反馈回 decoder 做迭代精化has_mask_input区分首击 0.0 与精化 1.0。dt_seg_reset_prev_mask()只清蒙版缓存dt_seg_reset_encoding()清全部换图时调用。SAM2 decoder 输出带num_labels符号维度因此需要用DT_AI_OPT_BASIC 维度覆盖加载Raw 降噪rawdenoise在 darktable 管线之前对 raw CFA 马赛克做传感器级降噪输出 DNG 再导入可被完整管线正常调色。Bayer 变体把 2T×2T CFA 块打包为 4 通道 T×T 张量RGGB 顺序非 RGGB 传感器强制裁剪到 RGGB 原点模型内部经 PixelShuffle 去马赛克后输出 3 通道 camRGBLinear 变体X-Trans、Foveon 等先跑最小 darktable 管线rawprepare→highlights→demosaic得到 3 通道浮点再经lin_rec2020矩阵与曝光提升后推理降噪denoise对完整管线导出的线性 Rec.709 图像做 sRGB 域推理可选 DWT 小波细节恢复把原始细纹理混合回结果输出 TIFF内嵌 ICC 与 EXIF后自动导入放大upscale2x/4x 超分辨率同一模型可经model_x2.onnx/model_x4.onnx提供两种倍率TIFF 输出采用逐扫描线流式写入以应对超大输出4x 放大 6000 万像素原图约需 3.6GB 内存。neural-restore 消费方denoise / upscale / rawdenoise会把输出写到源文件的同级文件TIFF 或 DNG再经_import_image自动导入库中与源图像分组并继承源图像的用户标签、星级、颜色标签等元数据因此输出会出现在源图像所在的任何筛选视图或收藏集中。注意darktable|*内部自动标签会被跳过。八、添加新的执行提供者EP如果需要接入一个新的 ONNX Runtime 执行提供者按以下 5 步操作在 src/ai/backend.h 的dt_ai_provider_t枚举中添加枚举值必须放在DT_AI_PROVIDER_COUNT之前在dt_ai_providers[]表中添加条目包含配置字符串、显示名与平台守卫在 src/ai/backend_onnx.c 的_enable_acceleration()中添加case在 src/ai/backend_onnx.c 的dt_ai_probe_provider()中添加case文件中的_Static_assert会确保表与枚举保持同步漏改即编译失败。九、小结darktable 的 AI 子系统通过自包含后端src/ai 高层任务模块src/common/ai 注册表/偏好集成src/common/ai_models.c、src/gui/preferences_ai.c三层结构把 ONNX Runtime 的能力以可扩展、可配置、可下载模型的方式接入摄影工作流。理解本文的 provider 解析、模型 manifest 契约与UI 只依赖src/common/ai/头文件的分层纪律是扩展新任务与新执行提供者的关键。深入各任务细节请继续阅读 AI_Tasks.md源码级参考可查阅 backend.h、backend_common.c 与 ai_models.h。【免费下载链接】darktabledarktable is an open source photography workflow application and raw developer项目地址: https://gitcode.com/GitHub_Trending/da/darktable创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表