【踩坑】pytorch中的索引与copy_结合不会复制数据及其解决方案

news2025/7/1 9:49:35

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn]

如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~

目录

背景知识

实验验证

结论分析

错误案例

处理方法

注意事项

附加说明

基本索引返回视图

高级索引返回副本

赋值操作都是原地操作


以下内容若有错误,欢迎指出!

背景知识

        我们现在知道以下几个知识点:

  1. copy_函数:pytorch中变量的copy_函数,可以将变量inplace地复制到另一个变量中。比如buffer.copy_(a),将a中的数据直接复制到了buffer中。
  2. 视图(View): 视图是指不复制数据的情况下,返回一个与原始张量共享内存的张量。例如,切片操作通常会返回一个视图。
  3. 副本(Copy): 副本是指返回一个新的张量,包含了原始张量的数据,但不共享内存布尔掩码索引返回的就是这样的副本。
  4. PyTorch和Numpy中的情况:在通过索引访问张量的内容时,PyTorch 遵循 Numpy 的行为,即基本索引返回视图,而高级索引返回副本。通过基本索引或高级索引进行的赋值都是原地操作
  5. 切片():切片由中括号冒号组成,如[:10]、[2:10]、[2:]。
  6. 基本索引:使用整数切片来访问数组的元素。
  7. 高级索引:指的是使用整数数组布尔数组或者其他序列来访问数组的元素。相比于基本索引,高级索引可以访问到数组中的任意元素,并且可以用来对数组进行复杂的操作和修改。
来自:https://cloud.tencent.com/developer/article/1755699
来自:PyTorch入门笔记-索引和切片

        好了,现在有一个问题,如果结合索引与copy_操作,那是否会复制成功?

实验验证

        答案是,不会成功。我们可以用代码测试一下:

import torch

print('>> 使用=号直接复制 <<')
buff = torch.arange(5)
mask = [True, False, False, True, False]
print('输出原始变量:', buff)
print('输出索引掩码:', mask)
print('输出索引变量:', buff[mask])
buff[mask][0] = 10
print('索引变量修改:', buff)
buff[mask] = torch.tensor([8, 9])
print('索引变量赋值:', buff)

print('*' * 50)

buff = torch.arange(5)
print('输出原始变量:', buff)
print('输出切片索引:', '1:3')
buff_indices = buff[1:3]
print('输出切片变量:', buff[buff_indices])
buff[1:3][0] = 10
print('切片变量修改:', buff)
buff[1:3] = torch.tensor([8, 9])
print('切片变量赋值:', buff)

print('=' * 50)

print('>> 使用copy_原地复制 <<')

buff = torch.arange(5)
mask = [True, False, False, True, False]
print('输出原始变量:', buff)
print('输出索引掩码:', mask)
print('输出索引变量:', buff[mask])
buff[mask].copy_(torch.tensor([8, 9]))
print('索引变量copy:', buff)

print('*' * 50)

buff = torch.arange(5)
print('输出原始变量:', buff)
print('输出切片索引:', '1:3')
print('输出切片变量:', buff[1:3])
buff[1:3].copy_(torch.tensor([8, 9]))
print('切片变量copy:', buff)

输出结果(改变的地方加粗了):

>> 使用=号直接复制 <<
输出原始变量: tensor([0, 1, 2, 3, 4])
输出索引掩码: [True, False, False, True, False]
输出索引变量: tensor([0, 3])
索引变量修改: tensor([0, 1, 2, 3, 4])
索引变量赋值: tensor([8, 1, 2, 9, 4])
**************************************************
输出原始变量: tensor([0, 1, 2, 3, 4])
输出切片索引: 1:3
输出切片变量: tensor([1, 2])
切片变量修改: tensor([ 0, 10,  2,  3,  4])
切片变量赋值: tensor([0, 8, 9, 3, 4])
==================================================
>> 使用copy_原地复制 <<
输出原始变量: tensor([0, 1, 2, 3, 4])
输出索引掩码: [True, False, False, True, False]
输出索引变量: tensor([0, 3])
索引变量赋值: tensor([0, 1, 2, 3, 4])
**************************************************
输出原始变量: tensor([0, 1, 2, 3, 4])
输出切片索引: 1:3
输出切片变量: tensor([1, 2])
切片变量赋值: tensor([0, 8, 9, 3, 4])

结论分析

        在PyTorch中,当你使用布尔掩码或索引来访问张量时,通常会创建一个新的张量,而不是对原始张量进行原地修改。在PyTorch中,切片操作通常会返回一个视图,而不是数据的副本。这意味着切片操作返回的张量和原始张量共享相同的内存。因此,对切片后的张量进行的任何修改都会影响到原始张量。与此相对,布尔掩码索引返回的是数据的副本,因此修改索引得到的张量不会影响原始张量。

        因此可见,由于索引返回的是新张量,而copy_是原地复制,因此对于原来的变量来说并没有影响,所以不会复制成功

        而=号这个赋值操作,不管是基本索引还是高级索引,由于底层都是对张量的原地操作,因此确实可以赋值成功。

错误案例

        根据以上内容就知道,有时候我们如果这样用,那就是错的:

buff = torch.arange(5)
mask = [True, False, False, True, False]
buff[mask].copy_(torch.tensor([8, 9]))

处理方法

        如果确实想结合索引和copy_一起用怎么办?那么可以试试masked_scatter_

torch.Tensor.masked_scatter_ — PyTorch 2.4 documentation

注意事项

  1. 对于 [1,2,3] 这种,仍然是位置索引,并不是切片,所以效果等同于上面的布尔索引。通常,PyTorch中的张量索引使用逗号分隔的整数索引来指定每个维度上的具体位置。如果你想对一个一维张量进行切片,应该使用冒号:来指定范围。

附加说明

        对于背景知识里的第4点,我们也来通过代码验证一下。

基本索引返回视图

基本索引包括标量索引、切片操作和整数索引。PyTorch通常会返回原始张量的视图,这意味着它们共享相同的底层数据。因此,对视图的修改会影响原始张量。例如:

import torch

a = torch.tensor([1, 2, 3, 4])
b = a[:2]  # 基本索引,b 是 a 的视图
b[0] = 10  # 修改视图会影响原始张量
print(a)   # 输出: tensor([10,  2,  3,  4])

高级索引返回副本

高级索引包括使用布尔数组、整数数组或多维索引。PyTorch和NumPy一样,高级索引会返回一个新的张量,即副本,不与原始数据共享内存。因此,对副本的修改不会影响原始张量。例如:

import torch

a = torch.tensor([1, 2, 3, 4])
indices = torch.tensor([0, 2])
b = a[indices]  # 高级索引,b 是 a 的副本
b[0] = 10       # 修改副本不会影响原始张量
print(a)        # 输出: tensor([1, 2, 3, 4])
print(b)        # 输出: tensor([10,  3])

赋值操作都是原地操作

无论是通过基本索引还是高级索引,赋值操作都是原地操作,这意味着它们会直接修改原始张量的内容。例如:

  1. 基本索引赋值

    a = torch.tensor([1, 2, 3, 4])
    a[:2] = torch.tensor([10, 20])  # 原地修改 a
    print(a)  # 输出: tensor([10, 20,  3,  4])
    
  2. 高级索引赋值

    a = torch.tensor([1, 2, 3, 4])
    indices = torch.tensor([0, 2])
    a[indices] = torch.tensor([10, 20])  # 原地修改 a
    print(a)  # 输出: tensor([10,  2, 20,  4])
    

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

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

相关文章

SS9283403 sqlite3交叉编译并部署到SS928(六)

1.Sqlite3下载 连接&#xff1a;SQLite Download Page 2.解压 tar zxvf sqlite-autoconf-3460000.tar.gz 3.配置并编译 进入解压目录&#xff0c;打开命令行&#xff0c;输入如下命令 ./configure CCaarch64-mix210-linux-gcc --hostarm-linux --prefix/home/mc/work/sqlite…

002发那科ROBOGUIDE仿真导入模型

打开已经创建好的工程&#xff0c;找到“机器” 右键&#xff0c;添加机器->CAD文件(F) 找到本地的3D模型&#xff0c;然后点击&#xff0c;打开 设置模型位置[0,0,0,0,0,0] 然后就导入进来啦

对比速览 | Alluxio 企业版 v.s. 社区版

当前诸多企业面临着日益增长的数据量和复杂的数据管理挑战。特别是在模型训练的过程中&#xff0c;诸如GPU短缺、GPU利用率不高等问题已经成为许多企业在技术实施中面临的挑战。同时&#xff0c;大数据分析中跨云数据访问速度慢、成本高等问题也给企业带来了痛点。为了应对这些…

redolog和binlog的两阶段提交和区别

redolog和binlog区别 redo log 是 InnoDB 引擎特有的&#xff1b;binlog 是 MySQL 的 Server 层实现的&#xff0c;所有引擎都可以使用。redo log 是物理日志&#xff0c;记录的是“在某个数据页上做了什么修改”&#xff1b;binlog 是逻辑日志&#xff0c;记录的是这个语句的…

Shell编程 --函数语法与重定向

文章目录 Shell编程shell函数语法函数参数 Shell 输入/输出重定向输出重定向输入重定向重定向深入讲解/dev/null 文件 总结 Shell编程 Shell是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令&…

Postman入门:环境变量和全局变量

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、发送请求 二、设置并引用环境变量 比如&#xff1a;我建的这个生产环境 使用环境有两个方式&#xff0c;一个是点击每个环境后面的对勾&#xff1b;另一种方式…

【Linux操作系统】进程的基本概念(PCB对象)详解

目录 一、进程的基本概念二、进程的描述组织&#xff08;PCB对象&#xff09;1.PCB的基本概念2.为什么要有PCB对象&#xff08;操作系统对进程的组织管理&#xff09;3.PCB对象的内部属性&#xff08;tast_struct结构体&#xff09; 三、查看进程1.ps指令2.top指令3.通过 /proc…

【LeetCode 1991 找到数组的中间位置 / LeetCode 724 寻找数组的中心下标】中间索引问题

1991 题目描述 暴力解法1&#xff1a; 思路&#xff1a; 遍历下标&#xff0c;求出左边和和右边和比较两边是否相等相等直接返回值没有符合的返回 -1 class Solution {public int findMiddleIndex(int[] nums) {int lennums.length;//初始化一个变量 midIndex 为 -1&#xff…

前端性能优化-script标签中的async与defer

前言 当浏览器解析 DOM 时候&#xff0c;遇到 script 标签时&#xff0c;会暂停 DOM 的解析&#xff0c;先加载并执行 script 中的代码&#xff0c;然后再继续 DOM 的解析。 比如 <script>window.env {version: "production",}; </script>上面的代码…

KVM——虚拟机添加设备与挂载磁盘

目录 一. 图形化方式添加设备 1. 添加磁盘 2. 添加网卡 二. 命令行形式添加设备 方式一&#xff1a; 方式二&#xff1a; 磁盘格式raw和qcow2 raw格式 qcow2格式 如何选择 挂载磁盘 一. 图形化方式添加设备 1. 添加磁盘 2. 添加网卡 先关机 给宿主机添加一块网…

华南理工大学-大学物理实验 迈克尔逊干涉仪

迈克尔逊干涉仪的调整与使用 引言 迈克尔逊( Albert Abrham Michelson, 1852-1931) , 著名的实验物理学家,近现代干涉仪的开山鼻祖。他设计了至今仍在广泛应用的迈克尔逊干涉仪。该仪器设计非常巧妙,测量极其精密,是近代许多干涉仪的基础。迈克尔逊当时设计该仪器的目的之…

HCIA复习 | HCIP基础

目录 Days01&#xff08;24.8.1&#xff09; IPv4 Header OSI七层模型 TCP、UDP数据结构 TCP/IP模型 OSI模型与TCP/IP模型区别 ARP Days02&#xff08;24.8.2&#xff09; 交换机 封装和解封装 IPv6 Header 路由 RIP Days01&#xff08;24.8.1&#xff09; IPv4 …

【面试题】【简历版】完整版

一、Java 基础 java 面向对象特性 封装&#xff08;Encapsulation&#xff09;&#xff1a; public class Student {// 将name和age封装起来private String name;private int age;// 提供方法设置和获取这些属性public void setName(String name){this.name name;}public Str…

JavaEE: 查看线程信息

示例用代码 public class Main {static class MyThread extends Thread {Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}public st…

基于Java+SpringBoot+Vue的网上超市的设计与实现

基于JavaSpringBootVue的网上超市的设计与实现 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f34…

canal监听mysql增量数据发布到rabbitmq

canal工作原理 canal 依靠mysql主从备份的原理&#xff0c;模拟 MySQL slave 的交互协议&#xff0c;伪装自己为 MySQL slave &#xff0c;向 MySQL master 发送dump 协议MySQL master 收到 dump 请求&#xff0c;开始推送 binary log 给 slave (即 canal )canal 解析 binary …

python模块01-pymysql数据库连接查询

PyMySQL 是用于连接 MySQL 服务器的一个库 1 安装&#xff1a; pip install pymysql 2 数据库连接 conn pymysql.connect(host"127.0.0.1",port3306,user"localhost",password"123456",charset"utf8",cursorclassDictCursor ) cur…

Redisson看门狗机制和mulitLock原理保姆级别

Redisson看门狗机制 这段代码主要实现了异步处理一个任务&#xff0c;并根据任务结果来执行不同的操作。 首先&#xff0c;调用handleNoSync方法进行异步处理&#xff0c;并返回一个表示异步计算结果的CompletionStage<Long>对象&#xff0c;这里使用了threadId和ttlRe…

mathtype7.8永久激活码下载并安装激活MathType7.8破解版

“我好像被数学公式PUA了……” 最近&#xff0c;有位朋友跟我吐槽&#xff1a;自己每次做数学题、写论文&#xff0c;只要遇到复杂的公式和符号&#xff0c;就会特别焦虑。她觉得&#xff0c;自己好像被数学公式PUA了。 “明明知道它很重要&#xff0c;但就是不想面对它。” 其…

[Git][多人协作][下]详细讲解

目录 1.不同分支下多人协作2.远程分⽀删除后&#xff0c;本地git branch -a依然能看到 1.不同分支下多人协作 ⼀般情况下&#xff0c;如果有多需求需要多⼈同时进⾏开发&#xff0c;是不会在⼀个分⽀上进⾏多⼈开发&#xff0c;⽽是⼀个需求或⼀个功能点就要创建⼀个feature分…