实验问题记录:PyTorch Tensor 也会出现 a = b 赋值后,修改 a 会影响 b 的情况
问题阐述:
crop_center_bbox = data['search_anno'][0]# shape = crop_center_bbox.shape
crop_center_bbox[0], crop_center_bbox[1] = 0.5 - crop_center_bbox[2]/2, 0.5 - crop_center_bbox[3]/2
crop_center_bbox[2], crop_center_bbox[3] = 0.5 + crop_center_bbox[2]/2, 0.5 + crop_center_bbox[3]/2
data['crop_center_bbox'] = [crop_center_bbox]
执行上述代码前,
而执行后
咦?怎么search_anno 也同步变了呢
很奇怪Σ(っ °Д °;)っ
解决办法
tensor 利用 clone()
crop_center_bbox = data['search_anno'][0].clone()
非常重要的事!!!
因此,在根据预定算法 完成代码 的写作过程中,一定要注意这些细节。如果不注意,这种会影响 预设 的变量 的形式,会对算法的真实完整实现 造成很大的 干扰。
不仅如此,在模型网络中的 tensor 前向传播的过程中, 中间凭空生成的或者使用的 新tensor也要注意 clone() 的使用,避免对 数据造成影响。
此外,不仅tensor有这个机制, list等也有这个机制,注意 浅拷贝的使用
对于list等形式的数据,可通过
a = [1, 2, 3]
b = a.copy()
来避免这个问题。
看看大模型怎么说
为什么 PyTorch Tensor 也会出现 a = b
赋值后,修改 a
会影响 b
的情况?
这和 Python 的变量赋值机制 以及 PyTorch Tensor 的内存管理方式 有关。下面详细解释:
1. Python 的变量赋值机制(所有对象通用)
在 Python 中,变量赋值(=
)只是创建了一个新的引用(指针),而不是复制对象。
-
对于不可变对象(如
int
,float
,str
,tuple
):
修改时会创建新对象,所以不会影响原对象。
a = 10
b = a # b 和 a 都指向 10
b = 20 # b 现在指向 20,a 仍然是 10(因为 int 不可变)
print(a) # 10
print(b) # 20
对于可变对象(如 list
, dict
, set
, PyTorch Tensor
):
修改时会直接操作原对象,所以所有引用都会受影响
a = [1, 2, 3]
b = a # b 和 a 指向同一个列表
b[0] = 99 # 修改 b 也会影响 a
print(a) # [99, 2, 3]
print(b) # [99, 2, 3]
PyTorch Tensor 也是可变对象,所以 a = b
只是让 a
和 b
指向同一个 Tensor,修改 a
会影响 b
。
2. PyTorch Tensor 的特殊之处
PyTorch Tensor 是 存储在 GPU/CPU 内存中的多维数组,它的赋值行为和 Python 列表类似:
-
a = b
:只是让a
指向b
的内存地址,没有复制数据。 - 修改
a
:直接修改b
的内存数据,所以b
也会变。 -
示例验证
-
import torchb = torch.tensor([1.0, 2.0, 3.0]) # 原始 Tensor a = b # a 和 b 指向同一个 Tensor a[0] = 99.0 # 修改 a 也会影响 b print(b) # tensor([99., 2., 3.])
可以看到,
b
被修改了,因为a
和b
是同一个 Tensor。如何避免这个问题?
如果你希望
a
是b
的 独立副本(修改a
不影响b
),必须 显式复制 Tensor:(1) 使用
.clone()
(推荐) -
a = b.clone() # 创建独立副本 a[0] = 99.0 # 修改 a 不会影响 b print(b) # tensor([1., 2., 3.])
(2) 使用
torch.clone()
(函数形式)a = torch.clone(b) # 等同于 b.clone()
4. 为什么 PyTorch 不默认深拷贝?
PyTorch 的设计选择
a = b
不复制数据,主要是为了 性能优化: - 深度学习中,Tensor 数据可能很大(如图像、视频),如果每次赋值都复制,内存和计算开销会很大。
- 默认共享内存 可以提高效率,但需要开发者 显式调用
.clone()
来避免意外修改。