Python与PyTorch的浅拷贝与深拷贝

news2025/1/19 18:40:21

1.Python赋值操作的原理

在python中,x= something, 这样的赋值操作,准确的理解是:给存储something建立一个索引x (即存储地址), x通过访问something的存储内容,获得something的值。

在下面代码中:

# 情况1: 原变量地址不变,但是内容发生修改
a = torch.rand(4)
print('before a', a, id(a))
b = a 
print('before b', b, id(a))
a[2] = 5
print('after a', a, id(a))
print('after b', b, id(b))

输出:

before a tensor([0.7519, 0.1700, 0.7580, 0.2318]) 4613605632
before b tensor([0.7519, 0.1700, 0.7580, 0.2318]) 4613605632
after a tensor([0.7519, 0.1700, 5.0000, 0.2318]) 4613605632
after b tensor([0.7519, 0.1700, 5.0000, 0.2318]) 4613605632

解析:从上面id信息可以看出,在我们设置b = a 后,a,b均指向同一个内容。当对a[2]进行修改时,该地址内容变化后,对应a,b均发生变化。这是经典的使用赋值方法的浅拷贝方法。

# 情况2:原始变量指向新地址
a = torch.rand(4)
print('before a', a, id(a))
b = a 
print('before b', b, id(a))
a = torch.rand(4)
print('after a', a, id(a))
print('after b', b, id(b))
before a tensor([0.7991, 0.6592, 0.4349, 0.6903]) 4615172560
before b tensor([0.7991, 0.6592, 0.4349, 0.6903]) 4615172560
after a tensor([0.4795, 0.3145, 0.6954, 0.3496]) 4615149584
after b tensor([0.7991, 0.6592, 0.4349, 0.6903]) 4615172560

解析:b=a时,b指向a最初所指向的地址内容,后面重新对a的指向地址和内容进行更新,实际仅影响a的指向,对b没有影响。

2. copy()

copy()是python中常见的一个函数,属于浅拷贝的一种,但是在复制过程中会出现两种情况:

  • 第一种情况:当复制的对象种无复杂子对象的时候,原来值的改变不影响浅复制的值,同时原来值的id和浅拷贝的id不一致;
  • 第二种情况:当复制的对象种存在复杂子对象的时候,如果改变其中复杂子对象的值,浅复制的值也会发生改变;但是改变其他非复杂对象值,则不会影响赋值的值。主要原因是在 copy()中,将复杂子类使用一个公共镜像存储起来,当镜像改变了之后,另一个使用该镜像的值也发生改变。

import copy
a = [[1, 2], 3, 4]
print('before a', a, id(a))
b = copy.copy(a) 
print('before b', b, id(b))
a[0][0] = 0
print('after a', a, id(a))
print('after b', b, id(b))
a[2] = 5
print('after a', a, id(a))
print('after b', b, id(b))
before a [[1, 2], 3, 4] 4615194240
before b [[1, 2], 3, 4] 4614455104
after a [[0, 2], 3, 4] 4615194240
after b [[0, 2], 3, 4] 4614455104
after a [[0, 2], 3, 5] 4615194240
after b [[0, 2], 3, 4] 4614455104

3. deepcopy()

采用deepcopy函数进行赋值时,将被复制对象完全再复制一遍,生成一个新的独立的个体。

from copy import deepcopy
a = [[1, 2], 3, 4]
print('before a', a, id(a))
b = deepcopy(a) 
print('before b', b, id(b))
a[0][0] = 0
print('after a', a, id(a))
print('after b', b, id(b))
a[2] = 5
print('after a', a, id(a))
print('after b', b, id(b))
before a [[1, 2], 3, 4] 4614452352
before b [[1, 2], 3, 4] 4614564032
after a [[0, 2], 3, 4] 4614452352
after b [[1, 2], 3, 4] 4614564032
after a [[0, 2], 3, 5] 4614452352
after b [[1, 2], 3, 4] 4614564032

4. PyTorch中的深拷贝与浅拷贝

4.1. inplace=True

inplace=True的意思是原地操作,例如 x = x + 5, 就是对x进行原地操作,这样操作能够节省内存。

4.2. .Tensor, .tensor, .from_numpy, .as_tensor的区别

.Tensor和.tensor是深拷贝,在内存中创建一个额外的数据副本,不共享内存,所以不受数组改变的影响。

.from_numpy和as_tensor是浅拷贝,在内存中共享数据。

import numpy as np
import torch

a = np.array([1, 2, 3, 4])
a1 = torch.from_numpy(a)
a2 = torch.Tensor(a)
a3 = torch.tensor(a)
a4 = torch.as_tensor(a)
print('before a', a, id(a))
print('before a1', a1, id(a1))
print('before a2', a2, id(a2))
print('before a3', a3, id(a3))
print('before a4', a4, id(a4))

a[1] = 0
print('after a', a, id(a))
print('after a1', a1, id(a1))
print('after a2', a2, id(a2))
print('after a3', a3, id(a3))
print('after a4', a4, id(a4))
before a [1 2 3 4] 4615260944
before a1 tensor([1, 2, 3, 4]) 4615062928
before a2 tensor([1., 2., 3., 4.]) 4614685696
before a3 tensor([1, 2, 3, 4]) 4615208048
before a4 tensor([1, 2, 3, 4]) 4615436944
after a [1 0 3 4] 4615260944
after a1 tensor([1, 0, 3, 4]) 4615062928
after a2 tensor([1., 2., 3., 4.]) 4614685696
after a3 tensor([1, 2, 3, 4]) 4615208048
after a4 tensor([1, 0, 3, 4]) 4615436944

从这里来看,a和a1, a4两个变量相互影响。

4.3. .detach()和.clone()

.clone() 是深拷贝,创建新的存储地址,而不是引用保存旧的tensor,在梯度回传的时候,clone()充当中间变量,会将梯度传给源张量进行叠加,但是本身不保存其grad,值为None.

.detach()是浅拷贝,新的tesnor会脱离计算图,不回牵涉梯度计算。

import torch

x = torch.tensor([2.0, 3.0, 4.0], requires_grad=True)
clone_x = x.clone()
detach_x = x.detach()
clone_detach_x = x.clone().detach()

y = 2*x + 10
y.backward(torch.FloatTensor([1.0, 2.0, 1.0]))

print(x.grad)
print(clone_x.requires_grad)
print(clone_x.grad)
print(detach_x.requires_grad)
print(clone_detach_x.requires_grad)
tensor([2., 4., 2.])
True
None
False
False
/var/folders/ll/nwlhsbw14ds8cs419pf18fn80000gn/T/ipykernel_20906/929467759.py:13: UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won't be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations. (Triggered internally at /Users/runner/work/_temp/anaconda/conda-bld/pytorch_1670525473998/work/build/aten/src/ATen/core/TensorBody.h:485.)
  print(clone_x.grad)

4.4. contiguous函数

在pytorch中,很多操作都用到浅拷贝的思路,只是重新定义下标与元素的对应关系。

import torch

x = torch.randn(3,2)
y = torch.transpose(x, 0, 1)
print('before')
print('x:', x)
print('y:', y)

print('after')
y[0, 0] = 12
print('x:', x)
print('y:', y)

使用contiguous()之后,

import torch

x = torch.randn(3,2)
y = torch.transpose(x, 0, 1).contiguous()
print('before')
print('x:', x)
print('y:', y)

print('after')
y[0, 0] = 12
print('x:', x)
print('y:', y)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2279021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【RAG落地利器】向量数据库Qdrant使用教程

TrustRAG项目地址🌟:https://github.com/gomate-community/TrustRAG 可配置的模块化RAG框架 环境依赖 本教程基于docker安装Qdrant数据库,在此之前请先安装docker. Docker - The easiest way to use Qdrant is to run a pre-built Docker i…

【逆境中绽放:万字回顾2024我在挑战中突破自我】

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” 文章目录 一、引言二、个人成长与盘点情感与心理成长学习与技能提升其它荣誉 三、年度创作历程回顾创作内容概…

HTTP / 2

序言 在之前的文章中我们介绍过了 HTTP/1.1 协议,现在再来认识一下迭代版本 2。了解比起 1.1 版本,后面的版本改进在哪里,特点在哪里?话不多说,开始吧⭐️! 一、 HTTP / 1.1 存在的问题 很多时候新的版本的…

于灵动的变量变幻间:函数与计算逻辑的浪漫交织(下)

大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。 这一节我们主要来学习单个函数的声明与定义,static和extern… 这里写目录标题 一、单个函数…

pthread_create函数

函数原型 pthread_create 是 POSIX 线程&#xff08;pthread&#xff09;库中的一个函数&#xff0c;用于在程序中创建一个新线程。 #include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *a…

VSCode 的部署

一、VSCode部署 (1)、简介 vsCode 全称 Visual Studio Code&#xff0c;是微软出的一款轻量级代码编辑器&#xff0c;免费、开源而且功能强大。它支持几乎所有主流的程序语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比Diff、版本管理GIT等特性&…

模之屋模型导入到UE5

去模之屋随便下个模型 安装Blender2.8 插件 cats-blender-plugin &#xff0c; 打开blender 2.8转换 pmx转换fbx https://github.com/absolute-quantum/cats-blender-plugin Index of /release/Blender2.80/ 修改单位 修复贴图 更高清了 点fix model 修复模型 改为编辑模式…

用Cursor生成一个企业官网前端页面(生成腾讯、阿里官网静态页面)

用Cursor生成一个企业官网前端页面 第一版&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

css 实现自定义虚线

需求&#xff1a; ui 画的图是虚线&#xff0c;但是虚线很宽正常的border 参数无法做到 进程&#xff1a; 尝试使用 border&#xff1a;1px dashed 发现使用这个虽然是虚线但是很短密密麻麻的 这并不是我们想要的那就只能换方案 第一个最简单&#xff0c;让ui 画一个图然…

【鸿蒙】0x02-LiteOS-M基于Qemu RISC-V运行

OpenHarmony LiteOS-M基于Qemu RISC-V运行 系列文章目录更新日志OpenHarmony技术架构OH技术架构OH支持系统类型轻量系统&#xff08;mini system&#xff09;小型系统&#xff08;small system&#xff09;标准系统&#xff08;standard system&#xff09; 简介环境准备安装QE…

力扣动态规划-2【算法学习day.96】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

细说STM32F407单片机电源低功耗SleepMode模式及应用示例

目录 一、STM32F4的低功耗模式 1、睡眠(Sleep)模式 2、停止(Stop)模式 3、待机(Standby)模式 二、睡眠模式 1、进入睡眠模式 2、睡眠模式的状态 3、退出睡眠模式 4、SysTick的影响 三、应用示例 1、工程配置 &#xff08;1&#xff09; 时钟、DEBUG、GPIO、CodeGen…

【竞技宝】LOL:ning直播再次锐评

北京时间1月18日,目前英雄联盟LPL2025正在如火如荼的进行之中,很多队伍都已经打完了新赛季的首场比赛,其中就包括AL战队,AL在休赛期进行了大幅度的人员调整,整体实力相比之前增强了不少,在16日的比赛中,AL3-0轻松击败LGD拿下了赛季开门红,而AL的打野选手tarzan在本场比赛中表现…

构建安全防线:基于视频AI的煤矿管理系统架构创新成果展示

前言 本文我将介绍一款AI产品的成果展示——“基于视频AI识别技术的煤矿安全生产管理系统”。这款产品是目前我在创业阶段和几位矿业大学的博士共同从架构设计、开发到交付的全过程中首次在博客频道发布, 我之前一直想写但没有机会来整理这套系统的架构, 因此我也特别感谢CSDN平…

QT笔记- Qt6.8.1 Android编程 添加AndroidManifest.xml文件以支持修改权限

1. 切换项目选项卡&#xff0c;找到构建的步骤下的最后一项构建安卓APK&#xff0c;展开后找到应用程序栏&#xff0c;点击安卓自定义中的创建模板. 2. 弹出对话框勾选图中选项后点完成 3. 回到项目&#xff0c;查看.pro文件&#xff0c;里面多了很多内容不管&#xff0c;在下…

STM32-笔记43-低功耗

一、什么是低功耗&#xff1f; 低功耗‌是指通过优化设计和采用特定的技术手段&#xff0c;降低电子设备在运行过程中消耗的能量&#xff0c;从而延长电池寿命、提高性能和减少发热。低功耗设计主要从芯片设计和系统设计两个方面进行&#xff0c;旨在减少所有器件的功率损耗&am…

重温STM32之环境安装

缩写 CMSIS&#xff1a;common microcontroller software interface standard 1&#xff0c;keil mdk安装 链接 Keil Product Downloads 安装好后&#xff0c;开始安装平台软件支持包&#xff08;keil 5后不在默认支持所有的平台软件开发包&#xff0c;需要自行下载&#…

【三国游戏——贪心、排序】

题目 代码 #include <bits/stdc.h> using namespace std; using ll long long; const int N 1e510; int a[N], b[N], c[N]; int w[4][N]; int main() {int n;cin >> n;for(int i 1; i < n; i)cin >> a[i];for(int i 1; i < n; i)cin >> b[i…

想品客老师的第一天:值类型使用

前面两章的摘要 ECMAscript&#xff08;也就是ES&#xff09;是JavaScript的一个标准&#xff0c;就像c的c11和c99一样&#xff0c;几把的一年出一套标准 freeze()是一个对象方法&#xff0c;表示锁定、固定一个对象不可改变&#xff08;因为const对于标量不可变&#xff0c;…

leetcode刷题记录(六十七)——21. 合并两个有序链表

&#xff08;一&#xff09;问题描述 21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09;21. 合并两个有序链表 - 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a;[https://assets.leetcode…