「torch.cosine_smilarity() = 0」引发的关于cpu与gpu精度问题的探讨

2023-11-22 05:12

本文主要是介绍「torch.cosine_smilarity() = 0」引发的关于cpu与gpu精度问题的探讨,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:2023年11月21日下午16:00 许,本篇博客记录由「torch.cosine_smilarity()计算余弦相似度计算结果为0」现象引发的关于 CPU 与 GPU 计算精度的探索。

事情的起因是,本人在使用 torch.cosine_smilarity() 函数计算GPU上两个特征的余弦相似度时,发现得出的结果为 0,百思不得其解。首先排出特征维度的问题,然后尝试5种不同的相似度计算方法:

  • scipy.spatial.distance.cosine
  • torch.cosine_similarity
  • F.cosine_similarity
  • torch.nn.CosineSimilarity
  • 基于余弦相似度公式的torch代码

整体代码如下:

import torch
torch.set_printoptions(profile="full")
import torch.nn.functional as F
from scipy.spatial.distance import cosine
# device = "cuda" if torch.cuda.is_available() else "cpu"
device = "cpu"import clip
from PIL import Image
clip_model, processor = clip.load("ViT-L/14", device=device)
srcpath = '/newdata/SD/DEFAKE/data_test/9709_glide.png'
despath = '/newdata/SD/outputs/0_9_sd1.5.png'
src_feature = clip_model.encode_image(processor(Image.open(srcpath)).unsqueeze(0).to(device)).squeeze(0)  
des_feature = clip_model.encode_image(processor(Image.open(despath)).unsqueeze(0).to(device)).squeeze(0)sim_1 = 1 - cosine(src_feature.cpu(), des_feature.cpu())sim_2 = torch.cosine_similarity(src_feature, des_feature, dim=0).item()sim_3 = F.cosine_similarity(src_feature, des_feature, dim=0).item()cos = torch.nn.CosineSimilarity(dim=0)
sim_4 = cos(src_feature, des_feature).item()sim_5 = torch.div(torch.sum(src_feature * des_feature,0),torch.sqrt(torch.sum(torch.pow(src_feature,2),0))* torch.sqrt(torch.sum(torch.pow(des_feature,2),0))).item()print(sim_1, sim_2, sim_3, sim_4, sim_5)
# 0.5302734375 0.0 0.0 0.0 0.53076171875

发现,上述代码在CPU和GPU上运行结果不一致:

上述代码在 CPU 上的运行结果为:

0.5301393270492554
0.5301393270492554
0.5301393270492554
0.5301393270492554
0.5301393270492554

上述代码在 GPU 上的运行结果为:

0.5302734375
0.0
0.0
0.0
0.53076171875

这是一个很有意思的现象,在CPU上计算出的5种相似度结果惊人一致,而在GPU上计算出的5种相似度结果中,中间三种基于torch函数调用的方式计算结果均为0,而第一种首先将特征搬运到CPU上然后使用scipy.spatial.distance.cosine()函数的计算结果和第五种直接在GPU上使用基于余弦相似度公式的torch代码的计算结果又与CPU上计算出的结果各有不同。


然后,我把由 CLIP 预训练模型提取的两张图像的特征(维度为768维) src_featuredes_feature 换成两个随机初始化的张量 ,其余代码不变:


# import clip
# from PIL import Image
# clip_model, processor = clip.load("ViT-L/14", device=device)
# srcpath = '/newdata/SD/DEFAKE/data_test/9709_glide.png'
# despath = '/newdata/SD/outputs/0_9_sd1.5.png'
# src_feature = clip_model.encode_image(processor(Image.open(srcpath)).unsqueeze(0).to(device)).squeeze(0)  
# des_feature = clip_model.encode_image(processor(Image.open(despath)).unsqueeze(0).to(device)).squeeze(0)# 将上面代码注释掉,换为:src_featre = torch.tensor([1.0, 2.0, 3.0])
des_feature = torch.tensor([4.0, 5.0, 6.0])

可见上述示例代码在CPU和GPU上运行结果是一致的:

上述代码在 CPU 上的运行结果为:

0.9746318459510803
0.9746317863464355
0.9746317863464355
0.9746317863464355
0.9746317863464355

上述代码在 GPU 上的运行结果为:

0.9746318459510803
0.9746317863464355
0.9746317863464355
0.9746317863464355
0.9746317863464355

由上述结果可以发现,第一种基于scipy.spatial.distance.cosine()函数的计算结果与其余四组基于torch的计算结果略有不同,说明后四种方法实现的底层逻辑应该是类似的,但由于给定特征的某些不可知原因,有时会出现中间三种基于torch函数调用的方法结果为0的情况,所以保险起见,如果要使用基于torch的计算方法,首选第5种相似度计算方法,当然,时间允许的情况下,直接在CPU上使用第一种方法无疑是精度最高的计算方法。


接下来放一个时间对比图(如下),可见在GPU上使用最后一种计算方法效率最高,在CPU上使用第一种方法效率最低。

time for spicy(gpu):  0.004714250564575195, [0.5361, 0.5303, 0.5220, 0.5059, 0.5430, 0.5469, 0.5078, 0.5293, 0.5283, 0.5337]
time for torch(gpu): 0.0005323886871337891, [0.5361, 0.5308, 0.5225, 0.5063, 0.5435, 0.5469, 0.5078, 0.5298, 0.5283, 0.5332]
time for spicy(cpu):  0.009323358535766602, [0.5358, 0.5301, 0.5222, 0.5060, 0.5426, 0.5467, 0.5077, 0.5298, 0.5279, 0.5333]
time for torch(cpu): 0.0025298595428466797, [0.5358, 0.5301, 0.5222, 0.5060, 0.5426, 0.5467, 0.5077, 0.5298, 0.5279, 0.5333]

PS:鉴于第一种方法无法进行余弦相似度的批量计算(1vN计算),追求速度的话,还是选择第五种方法吧~👀 附赠批量计算方法

src_feature = clip_model.encode_image(processor(Image.open(srcpath)).unsqueeze(0).to(device))  # [1,768]
des_features = torch.stack([clip_model.encode_image(processor(Image.open(path)).unsqueeze(0).to(device)) for path in despaths]).squeeze(1)  # [N,768]
sims = torch.div(torch.sum(src_feature * des_features,1),torch.sqrt(torch.sum(torch.pow(src_feature,2),1))* torch.sqrt(torch.sum(torch.pow(des_features,2),1)))  # 长度为N的张量
sims = sims.cpu().detach().numpy().tolist()  # 转化为列表,方便计算

参考资料

  1. GPU和CPU计算上的精度差异_cpu和gpu训练结果不同-CSDN博客

这篇关于「torch.cosine_smilarity() = 0」引发的关于cpu与gpu精度问题的探讨的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/407758

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

AI Toolkit + H100 GPU,一小时内微调最新热门文生图模型 FLUX

上个月,FLUX 席卷了互联网,这并非没有原因。他们声称优于 DALLE 3、Ideogram 和 Stable Diffusion 3 等模型,而这一点已被证明是有依据的。随着越来越多的流行图像生成工具(如 Stable Diffusion Web UI Forge 和 ComyUI)开始支持这些模型,FLUX 在 Stable Diffusion 领域的扩展将会持续下去。 自 FLU

如何用GPU算力卡P100玩黑神话悟空?

精力有限,只记录关键信息,希望未来能够有助于其他人。 文章目录 综述背景评估游戏性能需求显卡需求CPU和内存系统需求主机需求显式需求 实操硬件安装安装操作系统Win11安装驱动修改注册表选择程序使用什么GPU 安装黑神话悟空其他 综述 用P100 + PCIe Gen3.0 + Dell720服务器(32C64G),运行黑神话悟空画质中等流畅运行。 背景 假设有一张P100-

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

题目1254:N皇后问题

题目1254:N皇后问题 时间限制:1 秒 内存限制:128 兆 特殊判题:否 题目描述: N皇后问题,即在N*N的方格棋盘内放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在同一斜线上。因为皇后可以直走,横走和斜走如下图)。 你的任务是,对于给定的N,求出有多少种合法的放置方法。输出N皇后问题所有不同的摆放情况个数。 输入

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode