ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

CCV NNC Dataframe 详解:以 Pull 模型驱动异步数据加载与训练

CCV NNC Dataframe 详解:以 Pull 模型驱动异步数据加载与训练 计算机视觉深度学习【免费下载链接】ccvC-based/Cached/Core Computer Vision Library, A Modern Computer Vision Library项目地址https://gitcode.com/gh_mirrors/cc/ccv点击查看免费下载导读CCVC-based/Cached/Core Computer Vision Library的 NNCNeural Network Collection在ccv_cnnp_dataframe_*系列 API 中提供了一套轻量级 dataframe 抽象用于管理喂入 NNC 计算图的训练数据它支持按行列组织数据、随机打乱、迭代与预取、以 map 函数派生新列、以 reduce/sample 函数合并多行为单行并通过 stream context流上下文实现数据准备与图计算异步重叠。本文以仓库文档 doc/nnc-df.rst 为主线结合 lib/nnc/ccv_cnnp_dataframe.c、lib/nnc/ccv_cnnp_dataframe_core.c、lib/nnc/ccv_cnnp_dataframe_addons.c 等源码实现与 test/int/nnc/cifar.tests.c 的实战用例帮你掌握从原始 dataframe 到 addons 高层 API 的完整数据管道搭建能力。为什么 NNC 需要 Dataframe 抽象NNC 的训练通常需要把原始数据图片路径、标签、类别转换成可直接喂入计算图的张量。如果每个训练脚本都自行实现数据过滤、对齐alignment、批处理batching代码会迅速失控也难以复用。文档指出一个 dataframe 抽象对任何机器学习框架都更合适因为它统一处理了这三类问题数据过滤只挑选需要的行/列进入训练流程对齐把不同来源的数据如文件名与标签按行对齐到同一张表批处理把多行记录合并成一批张量供图计算一次消费。在 CCV 中这个职责由ccv_cnnp_dataframe_t定义见 lib/nnc/ccv_nnc.h承担它是 NNC 五级 API 中的 Level-5 Dataframe API。核心模型行、列与三种数据操作加载进 dataframe 的数据以行和列组织。基础能力对应文档 Operations on the Data 一节如下迭代可以用迭代器遍历选定的若干列打乱ccv_cnnp_dataframe_shuffle随机重排行顺序派生新列依据你指定的 map 函数从若干已有列推导出一个新列合并多行依据你指定的 reduce 函数把多行归约成一行。从源码结构看struct ccv_cnnp_dataframe_s见 lib/nnc/ccv_cnnp_dataframe.c一个 dataframe 内部保存了row_count/column_size行数与列数shuffled_idx打乱后的行索引表首次调用 shuffle 时惰性创建data_ctx以 stream context 为键的哈希表用于缓存各列已取出的数据实体避免重复分配原始列column_data[]与派生列derived_column_data记录 map 函数、依赖列、stream_type、析构函数等。迭代器与流上下文数据加载与计算异步重叠文档 Iteration 一节介绍了迭代器的完整用法这也是 dataframe 与普通数组遍历的本质区别ccv_cnnp_dataframe_iter_new(dataframe, column_idxs, column_idx_size)创建迭代器可指定要遍历的列子集ccv_cnnp_dataframe_iter_set_cursor(iter, idx)控制访问位置设为 0 即回到开头重置游标会使已预取prefetch的记录失效——从源码看ccv_cnnp_dataframe_iter_set_cursor会调用_ccv_cnnp_null_prefetches清空预取队列见 lib/nnc/ccv_cnnp_dataframe.c因为游标跳变后旧的预取内容已无意义ccv_cnnp_dataframe_iter_prefetch(iter, prefetch_count, stream_context)预先取出若干条记录放入缓存之后ccv_cnnp_dataframe_iter_next直接从缓存返回ccv_cnnp_dataframe_iter_next(iter, data_ref, column_idx_size, stream_context)返回下一个记录语义为0成功、-1无更多行、-2迭代已结束见 lib/nnc/ccv_nnc.h 与iter_next实现 lib/nnc/ccv_cnnp_dataframe.c。双流上下文乒乓预取模式文档重点描述了一个典型用例数据准备与图计算使用两个不同的流上下文。如果提供了 stream context预取和迭代都会在该流上异步执行在流 A 上取到一条记录交给图在流 A 上计算同时在流 B 上立即预取下一条记录图计算完成后切到流 B 取回记录开始下一轮。这样数据准备读盘、解码、增广、拷入 GPU与计算天然重叠避免了单独开 IO 线程。这正是 test/int/nnc/cifar.tests.c 中训练循环的做法ccv_nnc_stream_context_t* stream_contexts[2]; stream_contexts[0] ccv_nnc_stream_context_new(CCV_STREAM_CONTEXT_GPU); stream_contexts[1] ccv_nnc_stream_context_new(CCV_STREAM_CONTEXT_GPU); int p 0, q 1; ccv_cnnp_dataframe_iter_prefetch(iter, 1, stream_contexts[p]); // 训练循环 ccv_cnnp_dataframe_iter_next(iter, (void**)input_fits, device_count * 2, stream_contexts[p]); ccv_nnc_stream_context_wait(stream_contexts[q]); ccv_cnnp_model_fit(cifar_10, /*...*/, stream_contexts[p]); ccv_cnnp_dataframe_iter_prefetch(iter, 1, stream_contexts[q]); CCV_SWAP(p, q, t);MapPull 语义的列派生文档 Map 一节指出数据准备管道可能很长因此 dataframe 优先采用pull模型当某一列被请求迭代/预取触发时它才拉取依赖列的数据并执行变换而不是提前全部算好。map 函数负责具体变换典型应用包括把数据从 CPU 搬运到 GPU 设备对图片做数据增广把文件名解码成图像矩阵。核心签名是ccv_cnnp_dataframe_map(dataframe, map, stream_type, data_deinit, column_idxs, column_idx_size, context, context_deinit, name)见 lib/nnc/ccv_nnc.h其中参数含义map派生函数入参是多个依赖列的数据、批量大小出参是新列数据stream_type该派生列兼容的流类型每列只兼容一种流类型0表示 CPU/默认data_deinit派生数据的析构函数column_idxs参与派生的依赖列索引数组context/context_deinit随列携带的自定义上下文及其析构函数map 的结果是在现有 dataframe 内新增一列并返回新列的索引。源码中的递归拉取逻辑见_ccv_cnnp_dataframe_column_datalib/nnc/ccv_cnnp_dataframe.c它会先递归取得所有依赖列的数据再调用map并在派生列流类型与当前流不一致时通过ccv_nnc_stream_context_emit_signal_new/ccv_nnc_stream_context_wait_signal做流间同步。基于 map 的常用内置列操作ccv_cnnp_dataframe_core.c提供了两个基于 map 的通用工具ccv_cnnp_dataframe_extract_value从结构体列中按offsetof提取出某个字段成新列lib/nnc/ccv_cnnp_dataframe_core.cccv_cnnp_dataframe_make_tuple把若干列打包成一个void*数组形式的元组列供下游一次取多个值lib/nnc/ccv_cnnp_dataframe_core.c。Reduce / Sample多行归约为一行文档 Reduce 一节说明reduce 函数把多行合并成一行典型用途是把多条记录 batch 成一个张量喂给计算图。与 map 不同reduce 会产生新的 dataframemap 只是在现有 dataframe 中加列。在源码中对应实现是ccv_cnnp_dataframe_sample_new文档中的reduce_new即此概念当前仓库以 sample 命名见 lib/nnc/ccv_cnnp_dataframe_core.c。其内部机制很有意思创建一个内部迭代器ccv_cnnp_dataframe_iter_new遍历原 dataframe 的指定列按batch_size逐段ccv_cnnp_dataframe_iter_prefetchccv_cnnp_dataframe_iter_next拉取batch_size行交给ccv_cnnp_column_data_sample_f采样函数归约为一行新 dataframe 的行数为(row_count batch_size - 1) / batch_size。因为归约后行数发生了变化所以必须新建 dataframe。同样地reduce 也是 pull 语义——数据只有被请求时才真正拉取。为什么应该使用 Addons API 而非原始 API文档 Use Dataframe with Addons 一节明确建议原始 dataframe API 难用应当与 addons API 交互。原始 APIccv_cnnp_dataframe_new、ccv_cnnp_dataframe_map、ccv_cnnp_dataframe_reduce_new要求你自己填写ccv_cnnp_column_data_t结构体见 lib/nnc/ccv_nnc.h该结构包含stream_type、name、data_enum数据枚举函数、data_deinit析构函数、context与context_deinit六个字段。与ccv_nnc_easy.h里CPU_TENSOR_NCHW这类辅助函数不同仓库有意不提供填充该结构的辅助函数——因为 addons API 已经用原始 API 实现好了这些细节。Addons 的能力矩阵addons API 全部实现在 lib/nnc/ccv_cnnp_dataframe_addons.c以原始 API 为基础封装API功能ccv_cnnp_dataframe_from_array_new把一个ccv_array_t包装成 dataframe未来/现状还支持 CSV 等来源ccv_cnnp_dataframe_read_image把存放文件名的列解码为图像CCV_IO_ANY_FILE \| CCV_IO_RGB_COLOR支持structof从结构体字段取文件名ccv_cnnp_dataframe_image_random_jitter对图像列做随机增广对比度、饱和度、亮度、PCA 光照抖动、裁剪、翻转、归一化等ccv_cnnp_dataframe_one_hot从标签字段生成 one-hot 张量列支持CCV_32F/CCV_16Fccv_cnnp_dataframe_copy_to_gpu把张量列拷到指定 GPU 设备ccv_cnnp_dataframe_add_aux为每行附带一个按参数生成的辅助张量如输出占位ccv_cnnp_dataframe_combine_new把多个列各自 batch 成张量返回新 dataframe即文档中的batching_new概念见 lib/nnc/ccv_nnc.hccv_cnnp_dataframe_from_csv_new从 CSV 文件/内存读取数据建 dataframe见 lib/nnc/ccv_cnnp_dataframe_csv.c文档中未来从 CSV、SQLite 读取的能力在仓库里 CSV 已落地ccv_cnnp_dataframe_from_csv_new按 RFC 4180 解析支持自定义分隔符与引号、CRLF/LF/LFCR终止符以及 header 行采用两遍扫描先统计引号与奇偶换行再复制出以\0结尾的连续页并记录各列起始指针可参考 lib/nnc/ccv_nnc.h 的设计说明。random jitter 参数详解ccv_cnnp_random_jitter_tlib/nnc/ccv_nnc.h是数据增广的核心配置字段语义如下字段取值语义contrast/saturation/brightness随机扰动幅度最终值落在[1/(1v), 1v]区间lightingAlexNet 风格、基于 PCA 的光照抖动aspect_ratio长宽比拉伸幅度[1/(1v), 1v]symmetric是否做水平x 轴随机翻转seed随机种子为 0 时用ccv_nnc_stream_context_genrand_uint32(0)播种center_crop启用中心裁剪否则随机裁剪resize.min/max/roundup缩放目标在min (max-min)*random_unit之间且宽高为roundup的倍数size.rows/cols最终图像尺寸offset.x/yx/y 轴额外随机偏移normalize.mean[3]/std[3]归一化pixel (pixel - mean) / std源码会把std预转为倒数见 lib/nnc/ccv_cnnp_dataframe_addons.c注意ccv_cnnp_dataframe_image_random_jitter目前只支持CCV_32F输出源码中有assert(datatype CCV_32F)。端到端实战CIFAR-10 训练数据管道test/int/nnc/cifar.tests.c 给出了一个完整的 addons 组合范例一行一行对应文档描述的能力// 1. 把 ccv_array_t训练集包成 dataframe ccv_cnnp_dataframe_t* const raw_train_data ccv_cnnp_dataframe_from_array_new(training_set); // 2. 配置随机增广resize 到 32x32、水平翻转、±4 随机裁剪偏移、均值归一化 const ccv_cnnp_random_jitter_t random_jitter { .resize { .min 32, .max 32 }, .size { .rows 32, .cols 32 }, .symmetric 1, .normalize { .mean { mean[0], mean[1], mean[2] } }, .offset { .x 4, .y 4 }, .seed 1, }; // 3. 从结构体字段抽取图像矩阵列、做随机增广、生成 one-hot 标签列 const int images ccv_cnnp_dataframe_extract_value(raw_train_data, 0, offsetof(ccv_categorized_t, matrix), 0); const int jitter_images ccv_cnnp_dataframe_image_random_jitter(raw_train_data, images, CCV_32F, random_jitter, 0); const int one_hot ccv_cnnp_dataframe_one_hot(raw_train_data, 0, offsetof(ccv_categorized_t, c), 10, 1, 0, CCV_32F, CCV_TENSOR_FORMAT_NCHW, 0); // 4. 把增广图 one-hot 标签按 batch_size 合批生成 batch dataframe ccv_cnnp_dataframe_t* const batch_train_data ccv_cnnp_dataframe_combine_new( raw_train_data, COLUMN_ID_LIST(jitter_images, one_hot), batch_size, device_count, CCV_TENSOR_FORMAT_NCHW); // 5. 拷到 GPU、附上输出占位张量列创建迭代器 train_device_columns[i] ccv_cnnp_dataframe_copy_to_gpu(batch_train_data, 0, i * 2, 2, i, 0); train_device_columns[device_count i] ccv_cnnp_dataframe_add_aux(batch_train_data, params, 0); ccv_cnnp_dataframe_iter_t* const iter ccv_cnnp_dataframe_iter_new(batch_train_data, train_device_columns, device_count * 2);每个 epoch 结束时还会ccv_cnnp_dataframe_shuffle(raw_train_data)并ccv_cnnp_dataframe_iter_set_cursor(iter, 0)复位迭代器test/int/nnc/cifar.tests.c——这正好对应文档数据可被打乱以及重置游标会使预取失效的说明。已知限制与设计取舍文档 Others 一节诚实地列出了当前实现的边界这一点在源码中同样可以印证不支持排序不支持更通用的过滤可用 reduce 做有限度的过滤但能力受限不支持多 dataframe 连接join。作者的解释是在保证实现不成为瓶颈的前提下这些功能的高效实现方式尚不清晰。反过来正因为实现够 raw上述基础能力行/列迭代、打乱、map、reduce在性能上是足够高效的。结语一种表达与执行分离的数据抽象从架构上看dataframe addons 最关键的收益是文档结尾强调的计算表达与真实执行解耦。你可以在构建阶段自由地组合from_array_new → read_image → image_random_jitter → one_hot → combine_new → copy_to_gpu这条管道而真实的执行读盘、解码、增广、拷贝到 GPU只在iter_prefetch/iter_next触碰数据时才发生再叠加双流上下文的乒乓预取NNC 得以在单线程表达、异步执行的前提下实现数据加载与训练的深度重叠。这套抽象正是 CIFAR 训练等高层用例的底座值得在搭建你自己的训练数据管道时直接复用。相关文件核心实现 lib/nnc/ccv_cnnp_dataframe.c、归约与工具列 lib/nnc/ccv_cnnp_dataframe_core.c、addons 层 lib/nnc/ccv_cnnp_dataframe_addons.c、CSV 支持 lib/nnc/ccv_cnnp_dataframe_csv.c、完整 API 文档 lib/nnc/ccv_nnc.h以及端到端示例 test/int/nnc/cifar.tests.c。赞分享计算机视觉深度学习【免费下载链接】ccvC-based/Cached/Core Computer Vision Library, A Modern Computer Vision Library项目地址https://gitcode.com/gh_mirrors/cc/ccv点击查看免费下载相关推荐深入理解liuliu/ccv项目中的NNC Dataframe数据处理框架深入理解liuliu/ccv项目中的NNC Dataframe数据处理框架 痛点深度学习数据处理的效率瓶颈 在深度学习项目开发中数据处理往往是性能瓶颈的关键计算机视觉深度学习如何解锁联想拯救者BIOS隐藏选项LEGION Y7000系列Insyde高级设置工具的完整解决方案如何解锁联想拯救者BIOS隐藏选项LEGION Y7000系列Insyde高级设置工具的完整解决方案 对于联想拯救者Y7000系列用户来说BIOS高级选项被固件atomic_write_json 指数退避重试Webnovel Writer 如何优雅处理文件占用atomic_write_json 指数退避重试Webnovel Writer 如何优雅处理文件占用 Webnovel Writer 是一个基于 Claude机器学习深度学习AutoML大数据后端上一篇超强实战适配器与装饰器模式在中间件中的完美融合下一篇MiniMax-M2 模型架构深度解析MoE 专家路由、Sigmoid 门控与部署实战self-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表