一、对Tensor的操作

从接口的角度讲,对Tensor的操作可以分为两类:

(1)torch.function (2)tensor.function

比如torch.sum(a, b)实际上和a.sum(b)功能等价。

从存储的角度讲,对Tensor的操作也可以分为两类:

(1)不修改自身数据,如a.add(b),加法结果返回一个新的tensor;

(2)修改自身数据,如a.add_(b),加法结果仍存在a中,a被改变。

函数名以_结尾的称为inplace方式。

二、Tensor的创建

常见的新建tensor的方法:

Tensor(*sizes) 基础构造函数,不分配空间,未初始化

ones(*sizes) 全1的tensor

zeros(*sizes) 全0的tensor

eye(*sizes) 对角线为1,其余为0,不要求行列数相同

arange(s, e, step) 从s到e,步长为step

linspace(s, e, steps) 从s到e,均匀切分成steps份

rand/randn(*sizes) 均匀/标准分布

normal(mean, std)/uniform(from, to) 正态分布/均匀分布

randperm(m) 随机排列

range(start, end, step),返回一个list对象也就是range.object,起始值为start,终止值为end,但不含终止值,步长为step。只能创建int型list。range的step不能是浮点型。

arange(start, end, step),与range()类似,也不含终止值。但是返回一个array对象。需要导入numpy模块(import numpy as np或者from numpy import*),arange可以使用浮点型数据。

Tensor既可以接收一个list,也可以根据指定形状新建tensor,还可以传入其他的tensor。

tensor.size()等价于tensor.shape()。

a = t.Tensor(2, 3)
b = t.Tensor([[1, 2, 3], [4, 5, 6]])
print(b.tolist()) # 把tensor转为list
print(b.size()) # 形状
print(b.numel()) # 元素总个数
c = t.Tensor(b.size())

通过tensor.view方法可以调整tensor的形状,但要保证调整前后元素总数一致。view不会更改自身数据,但是新的tensor与原tensor共享内存。也就是说更改其中一个,另一个也会跟着改变。

如果要添加或减少某一维度,就需要通过squeeze和unsqueeze函数。

a = t.arange(0, 6)
print(a.view(2, 3))
b = a.view(-1, 3) # 当某一维为-1时,系统自动计算大小
print(b)
print(b.unsqueeze(1)) # 在第一维度上增加一维
print(b.unsqueeze(-2)) # 在倒数第二维上增加一维

运行结果:

tensor([[0, 1, 2],
[3, 4, 5]])
tensor([[0, 1, 2],
[3, 4, 5]])
tensor([[[0, 1, 2]], [[3, 4, 5]]])
tensor([[[0, 1, 2]], [[3, 4, 5]]])
a = t.arange(0, 6)
print(a.view(2, 3))
b = a.view(-1, 3) # 当某一维为-1时,系统自动计算大小
c = b.view(1, 1, 1, 2, 3)
print(c.squeeze(0).size())
print(c.squeeze().size()) # 将所有维度为1的压缩

运行结果:

tensor([[0, 1, 2],
[3, 4, 5]])
torch.Size([1, 1, 2, 3])
torch.Size([2, 3])

resize也可以用来调整tensor的大小。如果新尺寸超过了原始尺寸,那么会自动分配新的内存空间;而如果新尺寸小于原尺寸,则之前的数据依旧会保留。

a = t.arange(0, 6)
b = a.view(-1, 3) # 当某一维为-1时,系统自动计算大小
a[1] = 100 # 由于a与b共享内存,所以a改变时b也会改变
b.resize_(1, 3)
print(b)
print(b.resize_(3, 3)) # 之前的数据并没有因为上一步的resize操作丢失

运行结果:

tensor([[  0, 100,   2]])
tensor([[ 0, 100, 2],
[ 3, 4, 5],
[ 31244186271350784, 3775491366621020160, 5936959698761888869]])

Tensor支持与numpy.ndarray相似的索引操作。索引结果与原tensor共享内存。注意以下两种索引的区别:

a = t.randn(3, 4)
print(a[0 : 1, : 2].size())
print(a[0, : 2].size())

运行结果:

torch.Size([1, 2])
torch.Size([2])

选择产生的结果与原tensor不共享内存空间。

torch.FloatTensor(2,3) 构建一个2*3 Float类型的张量

torch.DoubleTensor(2,3) 构建一个2*3 Double类型的张量

torch.ByteTensor(2,3) 构建一个2*3 Byte类型的张量

torch.CharTensor(2,3) 构建一个2*3 Char类型的张量

torch.ShortTensor(2,3) 构建一个2*3 Short类型的张量

torch.IntTensor(2,3) 构建一个2*3 Int类型的张量

torch.LongTensor(2,3) 构建一个2*3 Long类型的张量

torch.Tensor是默认的tensor类型(torch.FlaotTensor)的简称。

三、tensor数据类型转换

torch.long() 将tensor转换为long类型

torch.half() 将tensor转换为半精度浮点类型

torch.int() 将该tensor转换为int类型

torch.double() 将该tensor转换为double类型

torch.float() 将该tensor转换为float类型

torch.char() 将该tensor转换为char类型

torch.byte() 将该tensor转换为byte类型

torch.short() 将该tensor转换为short类型

几种数据类型转换的方式如下:

a = t.Tensor(2, 3)
b = a.float()
c = a.type_as(b)
d = a.new(2, 3)

四、选择

gather操作

对于一个二维tensor,输出的每个元素如下:

out[i][j] = input[index[i][j]][j] # dim = 0
out[i][j] = input[i][index[i][j]] # dim = 1
a = t.arange(0, 16).view(4, 4)
index = t.LongTensor([[0, 1, 2, 3]])
print(a.gather(0, index)) # 提取对角线元素
index = t.LongTensor([[3, 2, 1, 0]]).t() # 针对2D tensor转置
print(a.gather(1, index)) # 提取反对角线元素
index = t.LongTensor([[3, 2, 1, 0]])
print(a.gather(0, index)) # 提取反对角线元素

运行结果:

tensor([[ 0,  5, 10, 15]])
tensor([[ 3],
[ 6],
[ 9],
[12]])
tensor([[12, 9, 6, 3]])

gather的逆操作是scatter_,gather是把数据从input中按照index取出,而scatter_是把取出的数据再放回去。

高级索引

x[[1, 2], [1, 2], [2, 0]] # x[1, 1, 2]和x[2, 2, 0]
x[[2, 1, 0], [0], [1]] # x[2, 0, 1], x[1, 0, 1], x[0, 0, 1]
x[[0, 2], ...] # x[0]和x[2]

五、逐元素操作

其中clamp实现的功能如下:

六、归并操作

使输出形状小于输入形状,并沿着某一维度进行指定操作。比如加法sum,既可以计算整个tensor的和,也可以计算tensor中每一行或者每一列的和。常用的归并操作如下:

以上函数几乎都有一个dim参数,类似于numpy的axis,用于指定这些操作在哪个维度上执行。简单来说,假设输入形状为(m, n, k):

如果dim=0,则输出形状为(1, n, k)或(n, k);

如果dim=1,则输出形状为(m, 1, k)或(m, k);

如果dim=2,则输出形状为(m, n, 1)或(m, n)。

size中是否有“1”,取决于参数keepdim,如果keepdim=True会保留维度1。其中keepdim默认值为False。

七、比较操作

t.max(tensor) 返回tensor中最大的一个数

t.max(tensor, dim) 指定维度上的最大的数,返回tensor和下标

t.max(tensor1, tensor2) 比较两个tensor相比较大的元素

如果要比较一个tensor和一个数字,可以使用clamp函数。

a = t.linspace(0, 15, 6).view(2, 3)
b = t.linspace(15, 0, 6).view(2, 3)
print('a=', a)
print('b=', b)
print('a[a > b]=', a[a > b])
print('t.max(a)=', t.max(a))
print('t.max(b, dim = 1)=', t.max(b, dim = 1))
print('t.max(a, b)=', t.max(a, b))

运行结果:

a= tensor([[ 0.,  3.,  6.],
[ 9., 12., 15.]])
b= tensor([[15., 12., 9.],
[ 6., 3., 0.]])
a[a > b]= tensor([ 9., 12., 15.])
t.max(a)= tensor(15.)
t.max(b, dim = 1)= (tensor([15., 6.]), tensor([0, 0]))
t.max(a, b)= tensor([[15., 12., 9.],
[ 9., 12., 15.]])

八、线性代数

pytorch的线性函数主要封装了Blas和Lapack。常用的线性代数函数如下:

矩阵的转置会导致存储空间不连续,需要调用它的.contiguous方法将其转为连续。

九、Tensor和Numpy

numpy和tensor共享内存。当输入数组的某个维度的长度为1时,计算时沿此维度复制扩充成一样的形状。

广播的手动实现:

(1)unsqueeze或view:为数据某一维的形状补1;

(2)expand或expand_as:重复数组。不会占用额外的空间(repeat会复制多份数据,所以会占用额外空间)。

Numpy的广播法则:

(1)所有输入数组都向shape最长的数组看齐,shape中不足的部分通过在前面加1维补齐;

(2)两个数组要么在某一个维度上的长度一致,要么其中一个为1,否则不能计算。

尽量使用向量化计算,少用for循环。

大多数t.function都有一个参数out,产生的结果可以保存在out指定的tensor中。

t.set_printoptions可以用来设置打印tensor时的数值精度和格式。

十、练习:线性回归

代码:

import torch.nn as nn
import torch as t
from torch.autograd import Variable
import torch.nn.functional as F
import torch.optim as optim
import torchvision as tv
import torchvision.transforms as transforms
from torchvision.transforms import ToPILImage
from matplotlib import pyplot as plt # 设置随机数种子,保证在不同的计算机上运行时产生的输出一致
t.manual_seed(1000) def get_fake_data(batch_size = 8):
# 产生随机数据,加入噪声
x = t.rand(batch_size, 1) * 20
y = x * 2 + (1 + t.randn(batch_size, 1)) * 3
return x, y x, y = get_fake_data() # 随机初始化参数
w = t.rand(1, 1)
b = t.zeros(1, 1) lr = 0.001 for ii in range(20000):
# forward
y_pred = x.mm(w) + b.expand_as(y)
loss = 0.5 * (y_pred - y) ** 2
loss = loss.sum() # backward
dloss = 1
dy_pred = dloss * (y_pred - y) dw = x.t().mm(dy_pred)
db = dy_pred.sum() # update parameters
w.sub_(lr * dw)
b.sub_(lr * db) x2 = t.arange(0, 20, 1.0).view(-1, 1)
y2 = x2.mm(w) + b plt.plot(x2.numpy(), y2.numpy())
plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
plt.show()

运行结果:

Pytorch学习笔记(二)——Tensor的更多相关文章

  1. 莫烦pytorch学习笔记(二)——variable

    .简介 torch.autograd.Variable是Autograd的核心类,它封装了Tensor,并整合了反向传播的相关实现 Variable和tensor的区别和联系 Variable是篮子, ...

  2. 莫烦 - Pytorch学习笔记 [ 二 ] CNN ( 1 )

    CNN原理和结构 观点提出 关于照片的三种观点引出了CNN的作用. 局部性:某一特征只出现在一张image的局部位置中. 相同性: 同一特征重复出现.例如鸟的羽毛. 不变性:subsampling下图 ...

  3. tensorflow学习笔记二:入门基础 好教程 可用

    http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础   TensorFlow用张量这种数据结构来表示所有的数据.用一 ...

  4. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  5. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  6. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  7. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  8. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  9. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  10. 《SQL必知必会》学习笔记二)

    <SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...

随机推荐

  1. Mockplus设计大赛获奖选手专访 | Intimate:你的专属密友音乐播放器

    “Intimate中文意思是密友,就是想让这个音乐APP成为最懂用户的一款软件.” 如果,你随身听的音乐APP,可以成为知你懂你的密友,你幸福,她清唱一首<小幸运>:你悲伤,她低声浅吟&l ...

  2. 关于Markdown格式转PDF格式

    Markdown转PDF格式 个人使用的Markdown编辑平台:有道云笔记网页版 当我们编辑好自己的随笔以后,在网页的[客户端下载]下面有一个[更多]的圆形图标选项,点击后在菜单中有一处[打印]选项 ...

  3. Android Messenger

    说到Android进程间通信,大家肯定能想到的是编写aidl文件,然后通过aapt生成的类方便的完成服务端,以及客户端代码的编写.如果你对这个过程不熟悉,可以查看Android aidl Binder ...

  4. hdu2653之BFS

    Waiting ten thousand years for Love Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/3 ...

  5. Java文件路径

    几大常用的方法 Class.getResource("")    返回的是当前Class这个类所在包开始的位置 getClassLoader().getResource(" ...

  6. Java NIO学习-详细内容(三)

    九.nio.file 该包是1.7新出的,包含了一系列高级的文件和目录操作方法 1.控制目录属性,只读,系统之类的 2.监控文件及文件夹的改变的WatchService public void sta ...

  7. [LeetCode 题解]:Best Time to Buy and Sell Stock

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述 Say you ha ...

  8. IO--RAID

    RAID IO计算 Raid 0 –每个磁盘的I/O计算= (读+写) /磁盘个数 Raid 1 --每个磁盘的I/O计算= [读+(2*写)]/2 Raid 5 --每个磁盘的I/O计算= [读+( ...

  9. CentOS下Docker与.netcore(五)之 三剑客之一Docker-swarm集群

    CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.netcore(二) 之 Dockerfile CentOS下Docker与.netcore(三)之 三剑客 ...

  10. System.Data.OracleClient.dll方式操作oracle数据库

    System.Data.OracleClient.dll方式操作oracle数据库 一.查询语句: using (OracleConnection conn = new OracleConnectio ...