「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

相关文章

Java内存区域与内存溢出异常的详细探讨

《Java内存区域与内存溢出异常的详细探讨》:本文主要介绍Java内存区域与内存溢出异常的相关资料,分析异常原因并提供解决策略,如参数调整、代码优化等,帮助开发者排查内存问题,需要的朋友可以参考下... 目录一、引言二、Java 运行时数据区域(一)程序计数器(二)Java 虚拟机栈(三)本地方法栈(四)J

Ubuntu上手动安装Go环境并解决“可执行文件格式错误”问题

《Ubuntu上手动安装Go环境并解决“可执行文件格式错误”问题》:本文主要介绍Ubuntu上手动安装Go环境并解决“可执行文件格式错误”问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录一、前言二、系统架构检测三、卸载旧版 Go四、下载并安装正确版本五、配置环境变量六、验证安装七、常见

解决Java异常报错:java.nio.channels.UnresolvedAddressException问题

《解决Java异常报错:java.nio.channels.UnresolvedAddressException问题》:本文主要介绍解决Java异常报错:java.nio.channels.Unr... 目录异常含义可能出现的场景1. 错误的 IP 地址格式2. DNS 解析失败3. 未初始化的地址对象解决

springboot+vue项目怎么解决跨域问题详解

《springboot+vue项目怎么解决跨域问题详解》:本文主要介绍springboot+vue项目怎么解决跨域问题的相关资料,包括前端代理、后端全局配置CORS、注解配置和Nginx反向代理,... 目录1. 前端代理(开发环境推荐)2. 后端全局配置 CORS(生产环境推荐)3. 后端注解配置(按接口

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Idea插件MybatisX失效的问题解决

《Idea插件MybatisX失效的问题解决》:本文主要介绍Idea插件MybatisX失效的问题解决,详细的介绍了4种问题的解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录一、重启idea或者卸载重装MyBATis插件(无需多言)二、检查.XML文件与.Java(该文件后缀Idea可能会隐藏

Nginx 访问 /root/下 403 Forbidden问题解决

《Nginx访问/root/下403Forbidden问题解决》在使用Nginx作为Web服务器时,可能会遇到403Forbidden错误,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录解决 Nginx 访问 /root/test/1.html 403 Forbidden 问题问题复现Ng

Python的pip在命令行无法使用问题的解决方法

《Python的pip在命令行无法使用问题的解决方法》PIP是通用的Python包管理工具,提供了对Python包的查找、下载、安装、卸载、更新等功能,安装诸如Pygame、Pymysql等Pyt... 目录前言一. pip是什么?二. 为什么无法使用?1. 当我们在命令行输入指令并回车时,一般主要是出现以

Nginx部署React项目时重定向循环问题的解决方案

《Nginx部署React项目时重定向循环问题的解决方案》Nginx在处理React项目请求时出现重定向循环,通常是由于`try_files`配置错误或`root`路径配置不当导致的,本文给大家详细介... 目录问题原因1. try_files 配置错误2. root 路径错误解决方法1. 检查 try_f

Python解决雅努斯问题实例方案详解

《Python解决雅努斯问题实例方案详解》:本文主要介绍Python解决雅努斯问题实例方案,雅努斯问题是指AI生成的3D对象在不同视角下出现不一致性的问题,即从不同角度看物体时,物体的形状会出现不... 目录一、雅努斯简介二、雅努斯问题三、示例代码四、解决方案五、完整解决方案一、雅努斯简介雅努斯(Janu