C++读取 npy 保存的 float16 精度的二进制文件 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sunhk25
V2EX    C++

C++读取 npy 保存的 float16 精度的二进制文件

  •  
  •   sunhk25 2022-12-02 14:04:19 +08:00 3288 次点击
    这是一个创建于 1043 天前的主题,其中的信息可能已经有所发展或是发生改变。

    numpy 以浮点型( float32 )来保存,然后 C++以浮点型( float )可以正常读取数值。 为了减少保存文件的大小以半精度浮点型来保存的话,无法读取到正确的数值。 请问有知道 C++的读取问题出在哪里吗?

    用 Python 保存 npy 文件

    import numpy as np outputDirectory = './t.npy' data [1] * (5) # npData = np.array(data, dtype=np.float32).reshape(5) npData = np.array(data, dtype=np.float16).reshape(5) np.save(outputDirectory, npData) 

    用 C++来读取 npy 文件 ※参照以下库的写法 https://github.com/llohse/libnpy/blob/master/include/npy.hpp#L554

    // ··· // read the data //stream.read(reinterpret_cast<char*>(data.data()), sizeof(Scalar) * size); stream.read(reinterpret_cast<char*>(data.data()), 2 * 3); 
    第 1 条附言    2022-12-03 22:34:14 +08:00

    下面是测试代码片段 ·59957800大小的npy数组不论float16还是32Python的numpy来load的话仅需0.047s ·float32型npy通过C++来读取需要0.115s(增加近两倍) ·float16型npy通过C++来读取+转换需要1.7s(增加近35倍) 从结论来看npy以float32来保存还比较实用。

    std::vector<float> data; int total = 59957800; data.resize(total); // float32型npy(二维数组214135 * 280)用Python的numpy来load的话仅需0.047s // stream.read(reinterpret_cast<char*>(&data[0]), 4 * total); // 用时0.115s // float16型npy(二维数组214135 * 280)用Python的numpy来load的话跟32bit一样仅需0.047s uint16_t f16; for (int i = 0; i <= total; i = i + 1) { stream.read(reinterpret_cast<char*>(&f16), 2); // https://www.programiz.com/cpp-programming/online-compiler/ data[i] = float16_to_float32(f16); } // 用时1.7s 
    第 2 条附言    2022-12-08 17:29:13 +08:00
    最近找到了下面这个 float16 精度的库,配合 npy 读取文件库可以相对快速读取 float16 精度的 npy 文件。
    https://half.sourceforge.net/index.html#doc
    https://github.com/melowntech/half

    npy 读取文件库:
    https://github.com/PyMesh/PyMesh/blob/main/src/Misc/numpy.hpp

    以上的处理速度是原生的 1.8 倍左右
    https://github.com/numpy/numpy/blob/3544fae2859d8ecac378b9ddc8f909c69455a831/numpy/core/src/npymath/halffloat.c
    16 条回复    2023-01-07 15:31:54 +08:00
    lonewolfakela
        1
    lonewolfakela  
       2022-12-02 14:12:54 +08:00
    你这个 data vector 里的 Scalar 是啥类型呢
    sunhk25
        2
    sunhk25  
    OP
       2022-12-02 14:20:01 +08:00
    @lonewolfakela
    Scalar 是 float 类型,C++不太理解好像没有 numpy 对应的 float16 。
    numpy 可以正常读取保存的 float16 类型。
    lonewolfakela
        3
    lonewolfakela  
       2022-12-02 14:25:55 +08:00
    你把 16 位的数据塞进 32 位 float 的 vector 当然没法得到正确数据啦
    tool2d
        4
    tool2d  
       2022-12-02 14:50:49 +08:00
    需要用 gcc 编译,VC 并不支持 float16 硬件类型。

    https://gcc.gnu.org/onlinedocs/gcc/Half-Precision.html

    在 x86 上,如果没开 mavx512fp16 ,就是纯软件的 float16 ,计算速度会相当慢。不如转换到 float32 。
    sunhk25
        5
    sunhk25  
    OP
       2022-12-02 15:01:00 +08:00
    @lonewolfakela
    16 位的数据时我读取的时候指定的大小是 2 ( float 的时候 sizeof 是 4 )
    lonewolfakela
        6
    lonewolfakela  
       2022-12-02 15:07:23 +08:00
    @sunhk25 #5 你指定大小是 2 它也对不了啊,两个 float16 被你塞到一个 float32 里去了你觉得你能读出来什么呢……
    sunhk25
        7
    sunhk25  
    OP
       2022-12-02 15:12:16 +08:00
    @tool2d
    Python 里 float16 和 float32 的计算速度之前有过比较没有变慢所以才想到保存为半精度也没有问题。
    想着用 C++来再提高下速度,就遇到了这个问题了。
    gcc 编译的话好像挺麻烦的样子 我了解了解。
    sunhk25
        8
    sunhk25  
    OP
       2022-12-02 15:17:04 +08:00
    @lonewolfakela
    对 是这个问题。不知道如何指定 float16 类型。
    刚才那位说了不支持 float16 需要编译一下。
    kirory
        9
    kirory  
       2022-12-03 00:13:20 +08:00
    可以提出指数和小数部分之后再放到 float 里
    kirory
        10
    kirory  
       2022-12-03 00:53:25 +08:00   1
    sunhk25
        11
    sunhk25  
    OP
       2022-12-03 08:38:55 +08:00 via Android
    @kirory
    以 16bit 从二进制文件取出来后放到数组,然后再进行转换吗,效率会不会是个问题。
    稍候测一下。
    kirory
        12
    kirory  
       2022-12-03 19:13:27 +08:00
    @sunhk25 边读边转,转换肯定比 IO 快,影响应该很小
    sunhk25
        13
    sunhk25  
    OP
       2022-12-03 22:37:43 +08:00
    @kirory
    刚才测了一下转换是没有问题,效率有点慢。
    比 numpy 的 load 处理慢了 35 倍。
    c0xt30a
        14
    c0xt30a  
       2022-12-17 09:38:37 +08:00   1
    OP 为啥不直接 dump 内存?

    array.tofile( ... )
    array.fromfile( ... )

    就可以了啊

    C++ 里也是类似处理
    sunhk25
        15
    sunhk25  
    OP
       2022-12-17 21:08:27 +08:00 via Android
    @c0xt30a numpy 按 16bit 的 array 数组存到文件,然后 c++dump 这个文件后,数组再转换到 float ?这个方案可以参考下。
    hunk
        16
    hunk  
       2023-01-07 15:31:54 +08:00
    新手小白插一句,浮点真的比较坑,最近看华泰的 sdk 学到一招,浮点数统统乘 1000 ,瞬间安静。
    仅供参考。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1247 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 17:21 PVG 01:21 LAX 10:21 JFK 13:21
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86