PyTorch核心概念:从梯度、计算图到连续性的全面解析(三)

news2024/12/23 22:13:36

文章目录

  • Contiguous vs Non-Contiguous Tensor
    • Tensor and View
    • Strides
    • 非连续数据结构:Transpose( )
    • 在 PyTorch 中检查Contiguous and Non-Contiguous
      • 将不连续张量(或视图)转换为连续张量
      • view() 和 reshape() 之间的区别
      • 总结
  • 参考文献

Contiguous vs Non-Contiguous Tensor

Tensor and View

View使用与原始张量相同的数据块,只是“view”其维度的方式不同
视图只不过是解释原始张量维度的另一种方法,而无需在内存中进行物理复制。例如,我们有一个 1x12 张量,即 [1,2,3,4,5,6,7,8,9,10,11,12],然后使用 .view(4,3) 来改变形状将张量转换为 4x3 结构

x = torch.arange(1,13)
print(x)
>> tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])

x = torch.arange(1,13)
y = x.view(4,3)
print(y)
>>
tensor([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])

如果更改原始张量 x 中的数据,它也会反映在视图张量 y 中,因为视图张量 y 不是创建原始张量 x 的另一个副本,而是从与原始张量相同的内存地址读取数据X。反之亦然,视图张量中的值的更改将同时更改原始张量中的值,因为视图张量及其原始张量共享同一块内存块

x = torch.arange(1,13)
y = x.view(4,3)
x[0] = 100
print(y)
>> 
tensor([[100,   2,   3],
        [  4,   5,   6],
        [  7,   8,   9],
        [ 10,  11,  12]])
        
x = torch.arange(1,13)
y = x.view(4,3)
y[-1,-1] = 1000
print(x)
>> tensor([   1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11, 1000])

可以以连续的方式查看不同维度的数据序列
一维张量A中的元素数量为T,经过view()处理之后的张量B,shape为(K,M,N),则需满足 K × M × N = T K\times M\times N=T K×M×N=T

Strides

在这里插入图片描述

# x is a contiguous data. Recall that view() doesn't change data arrangement in the original 1D tensor
x = torch.arange(1,13).view(6,2)
x
>>
tensor([[ 1,  2],
        [ 3,  4],
        [ 5,  6],
        [ 7,  8],
        [ 9, 10],
        [11, 12]])
        
# Check stride
x.stride()
>> (2, 1)

步长 (2, 1) 告诉我们:我们需要跨过 1 个(维度 0)数字才能到达沿轴 0 的下一个数字,并且需要跨过 2 个(维度 1)数字才能到达沿轴 1 的下一个数字

y = torch.arange(0,11).view(2,2,3)
y
>>
tensor([[[ 0,  1,  2],
         [ 3,  4,  5]],
        [[ 6,  7,  8],
         [ 9, 10, 11]]])
         
# Check stride
y.stride()
>> (6, 3, 1)

检索一维张量中 (A, B, C) 位置的公式如下: A × 6 + B × 3 + C × 1 A \times 6 + B \times 3 + C \times 1 A×6+B×3+C×1

非连续数据结构:Transpose( )

首先,Transpose(axis1, axis2) 只是“swapping the way axis1 and axis2 strides”
在这里插入图片描述

# Initiate a contiguous tensor
x = torch.arange(0,12).view(2,2,3)
x
>>
tensor([[[ 0,  1,  2],
         [ 3,  4,  5]],
        [[ 6,  7,  8],
         [ 9, 10, 11]]])
         
x.stride()
>> (6,3,1)

# Now let's transpose axis 0 and 1, and see how the strides swap
y = x.transpose(0,2)
y
>>
tensor([[[ 0,  6],
         [ 3,  9]],
        [[ 1,  7],
         [ 4, 10]],
        [[ 2,  8],
         [ 5, 11]]])
         
y.stride()
>> (1,3,6)

y 是 x.transpose(0,2),它交换 x 张量在轴 0 和轴 2 上的stride,因此 y 的stride是 (1,3,6)。这意味着我们需要跳转 6 个数字才能获取第 0 轴的下一个数字,跳转 3 个数字才能获取第 1 轴的下一个数字,跳转 1 个数字才能获取第 2 轴的下一个数字(stride公式: A × 1 + B × 3 + C × 6 A \times 1+ B \times 3+C \times 6 A×1+B×3+C×6)
transpose的不同之处在于:现在数据序列不再遵循连续的顺序。它不会从最内层维度逐一填充顺序数据,填满后跳转到下一个维度。现在它在最里面的维度跳跃了6个数字,所以它不是连续的
transpose( ) 具有不连续的数据结构,但仍然是视图而不是副本 ⇒ \Rightarrow 它是一个不连续的“视图”,改变了原始数据的stride方式

# Change the value in a transpose tensor y
x = torch.arange(0,12).view(2,6)
y = x.transpose(0,1)
y[0,0] = 100
y
>>
tensor([[100,   6],
        [  1,   7],
        [  2,   8],
        [  3,   9],
        [  4,  10],
        [  5,  11]])
# Check the original tensor x
x
>>
tensor([[100,   1,   2,   3,   4,   5],
        [  6,   7,   8,   9,  10,  11]])

在 PyTorch 中检查Contiguous and Non-Contiguous

使用PyTorch中的 .is_contigious() 检查张量是否连续

x = torch.arange(0,12).view(2,6)
x.is_contiguous()
>> True

y = x.transpose(0,1)
y.is_contiguous()
>> False

将不连续张量(或视图)转换为连续张量

使用PyTorch中的 .contigious() 将不连续的张量转换成连续的张量

z = y.contiguous()
z.is_contiguous()
>> TRUE

** .contigious() 复制原始的“non-contiguous”张量,然后按照连续顺序将其保存到新的内存块中**

# This is contiguous
x = torch.arange(1,13).view(2,3,2)
x.stride()
>> (6, 2, 1)

# This is non-contiguous
y = x.transpose(0,1)
y.stride()
>> (2, 6, 1)

# This is a converted contiguous tensor with new stride
z = y.contiguous()
z.stride()
>> (4, 2, 1)

print(z.shape)
>> (3, 2, 2)

# The stride across the first dimension is 2*2
# The stride across the second dimension is 2*1
# The stride across the third dimension is 1
(4, 2, 1)=>(2*2, 2*1, 1)

用来区分张量/视图是否连续的一种方法是观察stride中的 ( A , B , C ) (A, B, C) (A,B,C) 是否满足 A > B > C A > B > C A>B>C。如果不满足,则意味着至少有一个维度正在跳过的距离比其上方的维度更长,这使得它不连续
我们还可以观察转换后的连续张量 z 如何以新的顺序存储数据

# y is a non-contiguous 'view' (remember view uses the original chunk of data in memory, but its strides implies 'non-contiguous', (2,6,1).
y.storage()
>>
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
# Z is a 'contiguous' tensor (not a view, but a new copy of the original data. Notice the order of the data is different). It strides implies 'contiguous', (4,2,1)
z.storage()
>>
 1
 2
 7
 8
 3
 4
 9
 10
 5
 6
 11
 12

view() 和 reshape() 之间的区别

虽然这两个函数都可以改变张量的维度,但两者之间的主要区别是:

  1. view():不复制原始张量,使用与原始张量相同的数据块,仅适用于连续数据
  2. reshape():当数据连续时,尽可能返回视图;当数据不连续时,则将数据复制到连续的数据块中,作为副本,它会占用内存空间,而且新张量的变化不会影响原始张量中的原始数值
# When data is contiguous
x = torch.arange(1,13)
x
>> tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])

# Reshape returns a view with the new dimension
y = x.reshape(4,3)
y
>>
tensor([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])
        
# How do we know it's a view? Because the element change in new tensor y would affect the value in x, and vice versa
y[0,0] = 100
y
>>
tensor([[100,   2,   3],
        [  4,   5,   6],
        [  7,   8,   9],
        [ 10,  11,  12]])
        
print(x)
>>
tensor([100,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12])

接下来,让我们看看 reshape() 如何处理非连续数据:

# After transpose(), the data is non-contiguous
x = torch.arange(1,13).view(6,2).transpose(0,1)
x
>>
tensor([[ 1,  3,  5,  7,  9, 11],
        [ 2,  4,  6,  8, 10, 12]])
        
# Reshape() works fine on a non-contiguous data
y = x.reshape(4,3)
y
>>
tensor([[ 1,  3,  5],
        [ 7,  9, 11],
        [ 2,  4,  6],
        [ 8, 10, 12]])
        
# Change an element in y
y[0,0] = 100
y
>>
tensor([[100,   3,   5],
        [  7,   9,  11],
        [  2,   4,   6],
        [  8,  10,  12]])
        
# Check the original tensor, and nothing was changed
x
>>
tensor([[ 1,  3,  5,  7,  9, 11],
        [ 2,  4,  6,  8, 10, 12]])

最后,让我们看看 view() 是否可以处理非连续数据。No, it can’t!

# After transpose(), the data is non-contiguous
x = torch.arange(1,13).view(6,2).transpose(0,1)
x
>>
tensor([[ 1,  3,  5,  7,  9, 11],
        [ 2,  4,  6,  8, 10, 12]])
        
# Try to use view on the non-contiguous data
y = x.view(4,3)
y
>>
-------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
----> 1 y = x.view(4,3)
      2 y
RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.

总结

  1. view”使用与原始张量相同的内存块,因此该内存块中的任何更改都会影响所有视图以及与其关联的原始张量
  2. 视图可以是连续的或不连续的。一个不连续的张量视图可以转换为连续的张量视图,并且会复制不连续的视图张量到新的内存空间中,因此数据将不再与原始数据块关联
  3. stride位置公式:给定一个stride ( A , B , C ) (A,B,C) (ABC),索引 ( j , k , v ) (j, k, v) (j,k,v) 在 1D 数据数组中的位置为 ( A × j + B × k + C × v ) (A \times j + B \times k + C \times v) (A×j+B×k+C×v)
  4. view()reshape() 之间的区别:view() 不能应用于 '非连续的张量/视图,它返回一个视图;reshape() 可以应用于“连续”和“非连续”张量/视图

《PyTorch核心概念:从梯度、计算图到连续性的全面解析(一)》
《PyTorch核心概念:从梯度、计算图到连续性的全面解析(二)》

参考文献

1、Contiguous vs Non-Contiguous Tensor / View — Understanding view(), reshape(), transpose()

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

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

相关文章

「IDE」集成开发环境专栏目录大纲

✨博客主页何曾参静谧的博客📌文章专栏「IDE」集成开发环境📚全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定…

Kafka经典面试题

1、kafka消息发送的流程? producer发送过程中启动两个线程 一个main线程 一个sender线程,在main线程中先创建一个双端队列(RecordAccumlator、producerbatch),main将我们需要发送的东西经过拦截器,序列化&a…

手把手写深度学习(29):将DDP训练代码改成DeepSpeed

手把手写深度学习(0):专栏文章导航 前言:deepspeed已经成为了大模型时代训练模型的常规武器,这篇博客以一个基于DDP的 Stable Diffusion模型训练为例,讲解如何从将DDP训练代码改成DeepSpeed。 目录 构建optimizer 构建scheduler…

信息收集系列(二):ASN分析及域名收集

内容预览 ≧∀≦ゞ 信息收集系列(二):ASN分析及域名收集前言一、ASN 分析1. 获取 ASN 码2. 使用 ASNMap 获取 IP 范围3. 将 IP 范围转化为 IP 列表 二、关联域名收集1. 顶级域(TLD)收集测试方法 2. 根域名收集常用方法…

《数学分析》中不等式及补充

说明:此文章用于本人复习巩固,如果也能帮到大家那就更加有意义了。 注:1)《数学分析》中的不等式及不等式的补充

HTML之图片和超链接的学习记录

图片 在HTML中&#xff0c;我们可以使用img标签来显示一张图片。对于img标签&#xff0c;我们只需要掌握它的三个属性&#xff1a;src、alt和title。 <img src"" alt"" title"" /> src用于指定图片所在的路径&#xff0c;这个路径可以是…

unity显示获取 年月日周几【日期】

unity显示获取 年月日周几【日期】 public void ShowDate(Text txt){//txt.text DateTime now DateTime.Now; // 获取当前时间int year now.Year; // 获取年份int month now.Month; // 获取月份&#xff08;1-12&#xff09;int day now.Day; // 获取天数&#xff08;1-31&…

【区块链】深入理解智能合约 ABI

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 深入理解智能合约 ABI&#xff08;应用程序二进制接口&#xff09;一、ABI 基础…

鸿蒙ZRouter动态路由框架—生命周期管理能力

文章目录 基本使用(单个页面生命周期&#xff09;页面的全局生命周期监听工作流程图源码 ZRouter从1.1.0版本开始支持生命周期函数管理能力&#xff0c;主要有以下特点&#xff1a; 不影响你原有的生命周期业务逻辑&#xff0c;对NavDestination页面保持着零侵入性&#xff0c;…

代码随想录算法训练营第十九天|理论基础、77. 组合、216.组合总和III、17.电话号码的字母组合

理论基础 文章链接&#xff1a;代码随想录 视频讲解&#xff1a;带你学透回溯算法&#xff08;理论篇&#xff09;| 回溯法精讲&#xff01;_哔哩哔哩_bilibili关于回溯算法&#xff0c;我公众号里已经讲完了&#xff0c;并且将回溯算法专题整理成一本PDF&#xff0c;该PDF共…

uniapp的基本使用(easycom规范和条件编译)和uview组件的安装和使用

文章目录 1、uniapp1.uview组件安装2.uview-plus组件安装 2、条件编译3、easycom规范1.组件路径符合规范2.自定义easycom配置的示例 总结 1、uniapp UniApp的UI组件库&#xff0c;如TMUI、uViewUI、FirstUI、TuniaoUI、ThorUI等&#xff0c;这些组件库适用于Vue3和TypeScript&…

深入探索GDB调试技巧及其底层实现原理

本文分为两个大模块&#xff0c;第一部分记录下本人常用到的GDB的调试方法和技巧&#xff0c;第二部分则尝试分析GDB调试的底层原理。 一、GDB调试 要让程序能被调试&#xff0c;首先得编译成debug版本&#xff0c;当然release版本的也能通过导入符号表来实现调试&#xff0c…

Kubernetes的基本概念

Kubernetes是谷歌以Borg为前身,基于谷歌15年生产环境经验的基础上开源的一个项目,Kubernetes致力于提供跨主机集群的自动部署、扩展、高可用以及运行应用程序容器的平台。 一、资源对象概述 Kubernetes中的基本概念和术语大多是围绕资源对象(Resource Object)来说的,而资…

JavaWeb后端开发案例——苍穹外卖day01

day1遇到问题&#xff1a; 1.前端界面打不开&#xff0c;把nginx.conf文件中localhost:80改成81即可 2.前后端联调时&#xff0c;前端登录没反应&#xff0c;application.yml中默认用的8080端口被占用&#xff0c;就改用了8081端口&#xff0c;修改的时候需要改两个地方&…

(一)<江科大STM32>——软件环境搭建+新建工程步骤

一、软件环境搭建 &#xff08;1&#xff09;安装 Keil5 MDK 文件路径&#xff1a;江科大stm32入门教程资料/Keil5 MDK/MDK524a.EXE&#xff0c;安装即可&#xff0c;路径不能有中文。 &#xff08;2&#xff09;安装器件支持包 文件路径&#xff1a;江科大stm32入门教程资料…

软件开发的各类模型

目录 软件的生命周期 常见开发模型 瀑布模型 螺旋模型 增量模型、迭代模型 敏捷模型 Scrum模型 常见测试模型 V模型 W模型&#xff08;双V模型&#xff09; 软件的生命周期 软件的生命周期包括需求分析&#xff0c;计划&#xff0c;设计&#xff0c;编码&#xff0c;…

ElasticSearch学习笔记一:简单使用

一、前言 该系列的文章用于记录本人从0学习ES的过程&#xff0c;首先会对基本的使用进行讲解。本文默认已经安装了ES单机版本&#xff08;当然后续也会有对应的笔记&#xff09;&#xff0c;且对ES已经有了相对的了解&#xff0c;闲话少叙&#xff0c;书开正文。 二、ES简介 …

C++笔记---异常

1. 异常的概念 1.1 异常和错误 异常通常是指在程序运行中动态出现的非正常情况&#xff0c;这些情况往往是可以预见并可以在不停止程序的情况下动态地进行处理的。 错误通常是指那些会导致程序终止的&#xff0c;无法动态处理的非正常情况。例如&#xff0c;越界访问、栈溢出…

python opencv3

三、图像预处理2 1、图像滤波 为图像滤波通过滤波器得到另一个图像。也就是加深图像之间的间隙&#xff0c;增强视觉效果&#xff1b;也可以模糊化间隙&#xff0c;造成图像的噪点被抹平。 2、卷积核 在深度学习中&#xff0c;卷积核越大&#xff0c;看到的信息越多&#xff0…

ENSP作业——小型园区网

题目 根据上图&#xff0c;可得需求为&#xff1a; 1.配置交换机上的VLAN及IP地址。 2.设置SW1为VLAN 2/3的主根桥&#xff0c;设置SW2为VLAN 20/30的主根桥&#xff0c;且两台交换机互为主备。 3.可以使用super vlan。&#xff08;本次实验中未使用&#xff09; 4.上层通过静…