V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
tool2d
V2EX  ›  程序员

踩到 Protobuf 解析坑了,如何才能严格解析 Protobuf?

  •  
  •   tool2d · 2023-09-21 18:03:17 +08:00 · 2418 次点击
    这是一个创建于 438 天前的主题,其中的信息可能已经有所发展或是发生改变。
    解析是指 protobuf 二进制文件。这协议和 json 不一样,数据类型并不是 1 对 1 的。

    比如一个 Length-delimited 类型,int 是 2 ,同时对应多个子类型。可以是嵌入式 messages ,可以是 utf8 文本字符串,也可以是纯 bytes 数组。

    现在写了一个解析器,是什么类型,要纯粹靠猜。先尝试 utf8 ,不行再退回到嵌入式 messages ,解析一次。如果还是不行,就默认为 bytes 数组。

    总觉得很不靠谱的样子,在没有 proto 辅助的前提下,如何才能优雅的转为 json?
    22 条回复    2023-09-22 10:39:09 +08:00
    AoEiuV020JP
        1
    AoEiuV020JP  
       2023-09-21 18:10:42 +08:00
    在用 protobuf ,这玩意儿难道不是自动生成序列化和反序列化代码然后再也不改的?
    还是你解析的是别人的 protobuf 消息不知道真实格式?这当然只能猜了,多整点数据排除所有错误答案才能得出结果,
    tool2d
        2
    tool2d  
    OP
       2023-09-21 18:19:06 +08:00
    @AoEiuV020JP 我在用微软 ai 推理模型,用的是 protobuf 格式。

    pb 本身是序列化格式没错,但是大部分模型推导的结构都比较松散,而且 onnx 里面的 layers 复杂度比较高。会夹杂各种没遇到过的 operators 。用库不太方便,一些 OP 会变。

    复杂度一高,代码就会变复杂。就希望能写一个稍微通用一点的转换工具了,化简 AI 推导流程。
    stamhe
        3
    stamhe  
       2023-09-21 18:19:23 +08:00
    proto 本身就会定义数据类型啊。。。还有不知道的?
    tool2d
        4
    tool2d  
    OP
       2023-09-21 18:22:15 +08:00
    @stamhe AI 模型和通讯协议不一样,并没有 proto 文本数据。

    就只给一个模型 pb 二进制文件,我要反推内部的输入参数,把 input/output 对接上才行。

    每个模型权重输入,每个版本都不太一样。
    pkoukk
        5
    pkoukk  
       2023-09-21 18:22:19 +08:00   ❤️ 1
    我以为你在吐槽隔壁那个帖子,没想到你是认真的
    thinkershare
        6
    thinkershare  
       2023-09-21 18:28:45 +08:00
    @tool2d proto 不是自包含和自解释协议,因此你的想法不对。
    tool2d
        7
    tool2d  
    OP
       2023-09-21 18:33:21 +08:00
    @thinkershare 这个开源工具可以解析任意 proto 生成的二进制文件,不需要原始格式

    https://protobuf-decoder.netlify.app/

    这工具用起来没问题,但是我去看源代码实现方式,核心功能是依靠 try catch 实现的,说白了就是靠猜,这就很尴尬了。
    sujin190
        8
    sujin190  
       2023-09-21 18:36:46 +08:00 via Android   ❤️ 4
    预定义格式不是自解析的不靠猜靠啥,不知道你在无厘头吐槽啥
    thinkershare
        9
    thinkershare  
       2023-09-21 18:38:28 +08:00
    @tool2d protobuf 的官网已经明确说明,没有 proto 的原始定义下,如果要实现子描述,你需要自己实现。
    tool2d
        10
    tool2d  
    OP
       2023-09-21 18:40:10 +08:00
    @sujin190 当年 google 发明 protobuf 的时候,如果想弄成 json 这种自解析,就是举手之劳。但就是偏不,我想吐槽这一点。

    把文本和 messages 分开有那么难嘛,不就是一个 byte 类型,就能解决的事情。
    billlee
        11
    billlee  
       2023-09-21 19:06:09 +08:00 via Android
    @tool2d 发明 protobuf 就是为了不自解析,已经有 json 和 xml 了,为什么要重新造轮子呢
    lasuar
        12
    lasuar  
       2023-09-21 19:07:45 +08:00
    lightweight, compact
    seakingii
        13
    seakingii  
       2023-09-21 19:11:03 +08:00
    还自解析....你太自以为是了吧
    PB 尽量的压缩数据,做自解析不是和目标相勃了
    changnet
        14
    changnet  
       2023-09-21 19:19:22 +08:00
    @tool2d 你这说法就怪了
    当初之所以弄一个 protobuf 出来,就是因数 json 是自解析的,包含了太多数据,导致编码后的数据太大,效率也不高,才做出来的。

    假如做成和 json 一样,那为什么不直接用 json 。或者,你想找的是 bson ,而不是 protobuf 。

    为什么非要按 json 的方式去使用 protobuf ,他们本来就不是一样的东西。想吃青菜就买青菜,而不是买了个萝卜,再想这萝卜的味道为什么和青菜不一样。
    duke807
        15
    duke807  
       2023-09-21 19:27:45 +08:00 via Android
    @tool2d

    你需要的是用 msgpack 代替 json
    exch4nge
        16
    exch4nge  
       2023-09-21 19:49:09 +08:00   ❤️ 1
    可以用 protoc --decode_raw 解析任意二进制到 protobuf 的 text format ,没 proto ,最多只能到这个程度。
    lsry
        17
    lsry  
       2023-09-21 20:00:22 +08:00   ❤️ 1
    /t/975214
    模仿是吧
    bianhui
        18
    bianhui  
       2023-09-22 08:39:15 +08:00
    没理解,为啥要自己写?现成的不能用吗?第二,为啥要自解析,你想转 json ,那你就先转为程序的对象,在序列化为 json 呗。为啥不要 proto ,你是爬取别的数据吗?获取不到别人的 proto 吗?
    sujin190
        19
    sujin190  
       2023-09-22 08:51:57 +08:00 via Android
    @tool2d 发明 protobuf 本来就是为了解决现有压缩率和性能不足的问题,否则文本型有 json ,二进制型有 msgpack ,为啥要再造一个,再说选 protobuf 的场景本来就是看重其编码效率、压缩率和兼容性方案,你居然偏偏吐槽 protobuf 之所以被选择有优势的地方设计的不行
    sujin190
        20
    sujin190  
       2023-09-22 09:09:27 +08:00 via Android
    @tool2d 而且顺便说,protobuf 之所以能在数据库,分布式系统和 AI 学习场景中得到广泛应用。很大程度就是因为你吐槽设计不行的预定义格式不自解析,可靠而稳定的数据结构才能保证这些系统的可靠性与准确性,不自解析预定义格式又有良好兼容性才是 protobuf 设计的好的地方
    ggvoking
        21
    ggvoking  
       2023-09-22 10:07:12 +08:00
    建议先了解一下 protobuf 原理,类型本来就是固定的,要实现定义好,tlv 格式,读到 tag 就知道是对应的什么类型了。你想 pb 转 json 的话,首先要有数据文件,然后还需要
    1. proto 生成的类自定义代码类文件,这样这个类包含 tag 和类型,然后走反射转 json 。
    2. 有 proto 文件,可以不生成代码,可以直接走 proto 反射,golang 就有反射库[protoreflect]<https://github.com/jhump/protoreflect> ,其他语言自己找
    isFire
        22
    isFire  
       2023-09-22 10:39:09 +08:00
    难搞,之前做过动态解析 protobuf 格式数据的功能,方法可以参考一下,要解析最好还是先拿到 Message ,然后识别每个字段的顺序和类型,然后依次解析
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6087 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 02:13 · PVG 10:13 · LAX 18:13 · JFK 21:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.