关于查询milvus的向量精度问题
Wimeremce7 opened this issue · 17 comments
看到SearchParam的withFloatVectors方法,入参是‘’Float‘’ ,用float的话,会导致精度丢失,这个有什么解决方案吗?
为什么用float会导致精度丢失?据我所知还没有用double向量的模型
float精度只有小数点后7位,milvus存储的向量和embedding转化的向量都不止这些。 存储的向量:
embedding转化的向量:
然后查询的时候只能用float的话,其实是会把精度丢失掉
你错误理解了精度和展示的定位。精度的意思,指的就是后面虽然有很多位,但是都不准。你用的是float数据类型,精度就只用这么多。展示出来的东西精度本来就是不对的,原因是js只能支持64位float,也就是double
看到SearchParam的withFloatVectors方法,入参是‘’Float‘’ ,用float的话,会导致精度丢失,这个有什么解决方案吗?
为什么用float会导致精度丢失?据我所知还没有用double向量的模型
float精度只有小数点后7位,milvus存储的向量和embedding转化的向量都不止这些。 存储的向量:
embedding转化的向量:
然后查询的时候只能用float的话,其实是会把精度丢失掉你错误理解了精度和展示的定位。精度的意思,指的就是后面虽然有很多位,但是都不准。你用的是float数据类型,精度就只用这么多。展示出来的东西精度本来就是不对的,原因是js只能支持64位float,也就是double
好的,了解了
大概率你这个数据存错了,用了double格式。这点精度对于搜索不会有任何区别
但是获取到以后是这样的
请问你是用什么办法获取的? restful api? @XueJian-Zhang
大概率你这个数据存错了,用了double格式。这点精度对于搜索不会有任何区别
经过提醒。我查看了代码。没有用double,因为定义集合时设置了向量类型是FloatVector,在存储数据时,不能用double格式的,那样会产生“Type mismatch for field 'feature': Float vector field's value type must be List”错误,所以用的List。然后存储的时候向量值是
,但是在milvus的可视化平台中,存储的向量值和postman中发送的请求参数一致。
他们目前不支持double,至于attu客户端显示的向量小数位数,是因为js会自动补小数,并不能当真。
但是获取到以后是这样的
请问你是用什么办法获取的? restful api? @XueJian-Zhang
直接调用milvus的api就可以获取到,网上有很多教程。你可以参考下这位博主的方法:https://blog.csdn.net/lsqingfeng/article/details/138212915
大概率你这个数据存错了,用了double格式。这点精度对于搜索不会有任何区别
经过提醒。我查看了代码。没有用double,因为定义集合时设置了向量类型是FloatVector,在存储数据时,不能用double格式的,那样会产生“Type mismatch for field 'feature': Float vector field's value type must be List”错误,所以用的List。然后存储的时候向量值是
,但是在milvus的可视化平台中,存储的向量值和postman中发送的请求参数一致。
他们目前不支持double,至于attu客户端显示的向量小数位数,是因为js会自动补小数,并不能当真。
好的,谢谢。
python/javascript这些语言的浮点型是跟系统的位数走的,64位系统就会以64位来表示浮点数,但实际上在调用milvus rpc接口的时候其实都是以float32传输。对于用户来说就像变了个魔术似的。
但java是强制要求Float也就是32位输入,熟悉java的用户不应该有这种迷惑。
以32位浮点输入就已经明确告诉你向量在后台是以32位数据传输,存储,以及计算。所以它根本不可能再变出64位精度的小数给你。
向量近似近邻检索已经是一个模糊检索的概念,用来比对相似的事物。如果说我们要比较两张人脸是否相似,难道我们会去关心这两人的头发数量是否相等么?在大部分场景下,用64位精度的向量就相当于掩耳盗铃,非但对召回率没什么影响,计算负载和内存负载还大了一倍,得不偿失。
python/javascript这些语言的浮点型是跟系统的位数走的,64位系统就会以64位来表示浮点数,但实际上在调用milvus rpc接口的时候其实都是以float32传输。对于用户来说就像变了个魔术似的。 但java是强制要求Float也就是32位输入,熟悉java的用户不应该有这种迷惑。 以32位浮点输入就已经明确告诉你向量在后台是以32位数据传输,存储,以及计算。所以它根本不可能再变出64位精度的小数给你。 向量近似近邻检索已经是一个模糊检索的概念,用来比对相似的事物。如果说我们要比较两张人脸是否相似,难道我们会去关心这两人的头发数量是否相等么?在大部分场景下,用64位精度的向量就相当于掩耳盗铃,非但对召回率没什么影响,计算负载和内存负载还大了一倍,得不偿失。
你好,我使用python的两种方式查询了同一个id的向量值,可是得到的向量值却不相同,一种是根据向量id,另一种是根据向量值。请问为什么查询结果向量值的精度会不一样呢?
你用的是python sdk,我说过python语言对于浮点型的数值总是转成64位显示。
如果你懂得怎么在python sdk里调试的话,你会看到query()接口会调用到这里:https://github.com/milvus-io/pymilvus/blob/473f62fee6cb5e446f571471884d0d7303d01ab6/pymilvus/client/entity_helper.py#L481
我们把这几行代码改成如下:
if field_data.type == DataType.FLOAT_VECTOR:
dim = field_data.vectors.dim
if len(field_data.vectors.float_vector.data) >= index * dim:
start_pos, end_pos = index * dim, (index + 1) * dim
entity_row_data[field_data.field_name] = []
print(field_data.vectors.float_vector)
for x in field_data.vectors.float_vector.data[start_pos:end_pos]:
print(x)
entity_row_data[field_data.field_name].append(np.single(x))
print(entity_row_data[field_data.field_name])
打断点进入,你会看到 field_data.vectors.float_vector 这个是由Milvus rpc接口返回的结构体,打印出来的值是32位浮点型。
然后for x in field_data.vectors.float_vector.data[start_pos:end_pos] 这行里的 x 打印出来就变成了64位浮点型,所以知道我为何说“python语言对于浮点型的数值总是转成64位显示”了吧。
后面几行又做了什么呢? append(np.single(x)),看到np.single(x)了吧,这是numpy的single,指代float32浮点型。这里是把64位的x又cut成了32位浮点数。
所以你看到的query的结果里都是以32位浮点型显示。
再来看search()接口干了什么。
https://github.com/milvus-io/pymilvus/blob/473f62fee6cb5e446f571471884d0d7303d01ab6/pymilvus/client/abstract.py#L480
if dtype == DataType.FLOAT_VECTOR:
field2data[name] = vectors.float_vector.data[start * dim : end * dim], field_meta
continue
它直接把rpc接口返回的response包装成SearchResult给你,然后SearchResult里面是直接提取向量数据,没有经过numpy.single的转化,所以python自动用64位浮点型来表示。
再强调一遍,milvus服务端处理向量,无论是存储,计算还是输出,都是以float32来处理。各个SDK拿到的向量数据都是32位浮点型。如果你看到的是64位浮点数,那是因为某些语言本身自动把32位转成了64位表示,实际上32位精度之外的数字都是随机数字,没有任何意义。