PyTorch1: 张量的性质
1.张量
张量的概念在深度学习领域里,是可以使用GPU进行运算的多维数组。
- 0维张量是一个标量(scalar);
- 1维张量是一个矢量(vector);
- 2维张量是一个矩阵(matrix);
- 3维以上的张量并没有通俗的表示方式。
2.张量的数据类型
张量一共有三种类型,分别是:整数型、浮点型和布尔型。其中整数型和浮点型张量的精度分别有8位、
16位、32位和64位。
整数型:
- 8位:torch.int8
- 16位:torch.int16 或 torch.short
- 32位:torch.int32 或 torch.int
- 64位:torch.int64 或 torch.long
浮点型:
- 16位:torch.float16 或 torch.half
- 32位:torch.float32 或 torch.float
- 64位:torch.float64 或 torch.double
布尔型:
- torch.bool
获得一个张量的数据类型可以通过指令 Tensor.dtype
实现;
如果给这个表达式赋值,则将这个张量的数据类型改为目标类型。
3.PyTorch的不同形态
PyTorch可以通过不同方式形态达到同样的目的。
3.1 函数功能:torch.function()与Tensor.function()
约定:如果有写Tensor.xxx()
,那么这个Tensor
指的是一个具体的张量。
在Pytorch中,张量的很多运算既可以通过它自身的方法,也可以作为Pytorch中的一个低级函数来实现。
比如两个张量a
和b
相加,既可以写成torch.add(a,b)
,也可以写成a.add(b)
。
3.2 赋值语句:
很多张量的属性既可以在创建时声明,也可以在之后任何时间声明。
比如把一个值为1
的 32 位整数张量赋给变量a
,可以在生成时一步到位,
a = torch.tensor(1, dtype=torch.int32)
也可以先生成a
的张量,然后再改变它的数据类型。
a = torch.tenor(1)
a.dtype = torch.int32
4.张量的存储
张量存储在连续的内存中,被torch.Storage
控制。
一个Storage是一个一维的包含数据类型的内存块。
一个 PyTorch 的Tensor
本质上是一个能够索引一个Storage的视角。
例如:你可以访问一个Tensor
的Storage:
>>> points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
>>> points.storage()
1.0
4.0
2.0
1.0
3.0
5.0
[torch.FloatStorage of size 6]
你不能对一个Storage进行二维索引。
因为Storage是一维的张量的存储,修改它同样会改变张量本身。
5.张量的size,storage offset 和stride
我们先定义一个张量:
>>> points = torch.tensor([[1.0, 4.0], [2.0, 1.0], [3.0, 5.0]])
>>> points
tensor([[1., 4.],
[2., 1.],
[3., 5.]])
5.1 张量的 size
获得一个张量的形状有四种方法:
Tensor.size()
>>> points.size()
torch.Size([3, 2])
Tensor.shape
>>> points.shape
torch.Size([3, 2])
可以看出,两者的区别在于 Tensor.shape
没有 ()
。
Tensor.numel()
查看 tensor 内的元素个数。
>>> points.numel()
6
-
Tensor.dim()
或Tensor.ndim
查看张量的维数,即有几维。
5.2 张量的 storage offset
查看张量内的相应元素与内存中第一个元素的相对位移。
>>> second_point = points[1]
>>> second_point.storage_offset()
2
因为 points
的 storage
是 1.0, 4.0, 2.0, 1.0, 3.0, 5.0
,second_point
距离这个张量在内存中的第一个元素的距离是 2。
5.3 张量的 stride
指的是当索引增加 1 时,每个维度内需要跳过的元素个数,是一个元组。
>>> points.stride()
(2, 1)
6. 张量的变形、升维与降维
6.1 张量的变形:Tensor.view()
,Tensor.reshape()
或 Tensor.resize()
括号里面的数值用小括号、中括号或者不用括号括起来都可以,维数自定,只要所有数字的乘积与原尺寸的乘积相同即可。Tensor.view()
和 Tensor.reshape()
的维度中可以有一个 -1,表示该维的长度由其他维度决定。Tensor.resize()
的维度中不能有 -1。
>>> points.reshape((1, 2, 1, -1))
tensor([[[[1., 4., 2.]],
[[1., 3., 5.]]]])
6.2 张量的转置:Tensor.t()
Tensor.T
或 Tensor.transpose(dim1, dim2)
Tensor.t()
只能转置维度小于等于 2 的张量,转置第 0、1 维。
>>> a = torch.arange(4).reshape(2, 2)
>>> a.t()
tensor([[0, 2],
[1, 3]])
Tensor.T
把整个张量的维度进行颠倒。
>>> new_points = points.reshape(1, 2, -1, 1, 3)
>>> new_points.shape
torch.Size([1, 2, 1, 1, 3])
>>> new = new_points.T
>>> new.shape
torch.Size([3, 1, 1, 2, 1])
而 Tensor.transpose(dim1, dim2)
可以转置任意两个维度。
>>> new2 = new_points.transpose(1, 4)
>>> new2.shape
torch.Size([1, 3, 1, 1, 2])
6.3 张量的降维:Tensor.squeeze()
所谓降维,就是消去元素个数为 1 的维度。可以指定想消去的维度,若该维度不能消去,则该命令无效,但是不报错。若没有指定维度,则消去所有长度为 1 的维度。
>>> new_points2 = new.squeeze(1)
>>> new_points2.shape # 降维成功
torch.Size([3, 1, 2, 1])
>>> new_points3 = new.squeeze(0)
>>> new_points3.shape # 降维失败
torch.Size([3, 1, 1, 2, 1])
>>> new_points4 = new_points.squeeze()
>>> new_points4.shape # 降维成功
torch.Size([2, 3])
6.4 张量的升维:Tensor.unsqueeze()
升维必须指定增加的维度,必须在张量的已有维度 (-dim-1, dim+1)
之间。相当于在两个维度之间“加塞”,后面的维度顺移一位。
>>> new_points4.unsqueeze(2).shape
torch.Size([2, 3, 1])
7. 张量的复制与原地修改
因为张量本质上是连续内存地址的索引,我们把一段内存赋值给一个变量,再赋值给另一个变量后,修改一个变量中的索引往往会改变另一个变量的相同索引:
>>> a = torch.tensor([1, 2, 3, 4])
>>> b = a
>>> b[1] = 10
>>> a, b
(tensor([ 1, 10, 3, 4]), tensor([ 1, 10, 3, 4]))
我们希望能够控制这种现象。
7.1 张量的复制
使用 Tensor.clone()
复制一段内存上的数据到另一段内存上,这两个张量相互独立。
>>> a = torch.tensor([1, 2, 3, 4])
>>> b = a.clone()
>>> b[1] = 10
>>> a, b
(tensor([ 1, 10, 3, 4]), tensor([ 1, 10, 3, 4]))
7.2 张量的原地修改
如果我们能够避免引入新张量,直接在原始张量上修改,不就可以避免混淆了吗?很多张量操作都支持原地(in-place)操作,只要在原始函数后面加上 _
就表明是原地修改。比如:
>>> a = torch.ones(2, 2) # 创建一个 2 x 2 的全 1 张量
>>> a
tensor([[1., 1.],
[1., 1.]])
>>> a.add_(1) # 原地每个元素加 1
>>> a
tensor([[2., 2.],
[2., 2.]])
- TransactionScope和Enterprise Libray 3.0 Data Access Application Block
- 《Python Web开发 - 测试驱动方法》阅后感
- 微信小程序分享——会话服务器和业务服务器合并
- 微信官方开源UI库-WeUI
- ViewFlipper实现多页面切换
- Ubuntu & Fedora Mono 2.8 安装脚本
- android下拉加载更多
- 在 Windows 上安装Rabbit MQ 指南
- CentOS 7 安装RabbitMQ 3.3
- 神经网络
- Node.js Leap Motion Hello World——开启AR的小窗
- 微信小游戏:无法进行网络请求的解决方案
- 微信跳一跳之深度实践
- 前端工程师在业余时间如何提高自身能力——造轮子
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SQL 计算公司的期初资产
- nested exception is java.lang.IllegalStateException: refreshAfterWrite requires
- 除了会排序,你对ORDER BY的用法可能一无所知!
- 修改xposed特征并刷机
- Python 爬虫进阶必备 | 关于某租房网站数据加密的分析
- CMAKE学习记录(二)
- maven 中的版本依赖冲突问题
- Manual for Ubuntu Installation
- 修改自定义站点监控页面的样式
- 快速建站“新玩具”—glitch.me
- 踩坑记 | Flutter升级影响了NestedScrollView?
- Android | xml和view的那些事
- Android | 资源冲突覆盖的一些思考
- 如何用脚本自动转化,一个protobuf文件到json格式
- 聊聊dubbo-go的forkingCluster