张量(Tensor)简单介绍

Pytorch最基本的操作对象是Tensor(张量),它表示一个多维矩阵,张量类似于NumPy的ndarrays ,张量可以在GPU上使用以加速计算。

生成数据的常用方法以及基本数据类型:

构造一个随机初始化的矩阵

torch.rand

全 0 矩阵

torch.zeros

全 1 矩阵

orch.ones

直接从数据构造张量

torch.tensor

 32位浮点型        

torch.float32

64位浮点型

torch.float64

 32位整型

torch.int32                                        

 

 


生成数据


x1 = torch.rand(2,3)
# 返回一个张量,包含了从区间[0,1)的均匀分布中抽取的一组随机数,形状由可变参数sizes定义

运行结果:

pytorch 返回张量索引 pytorch的张量_深度学习


 

x2 = torch.randn(3,4)
#返回一个张量,包含了从标准正态分布(均值为 0,方差为 1,即高斯白噪声)中抽取一组随机数

 运行结果:

pytorch 返回张量索引 pytorch的张量_pytorch 返回张量索引_02


x3 = torch.zeros(2,3)
print(x3)
x4 = torch.ones(2,3,4) # 生成2个3x4的全1矩阵。两个二维矩阵组成一个三维矩阵
x4

 运行结果:

pytorch 返回张量索引 pytorch的张量_pytorch 返回张量索引_03


查看数据的形状:

print(x4.size())
x4.shape
# 二者效果一致。但是size()方法可以获取某个维度的长度

x4.size(0) # 查看x4的第一个维度的大小

 运行结果:

pytorch 返回张量索引 pytorch的张量_深度学习_04

pytorch 返回张量索引 pytorch的张量_数据_05

 

 

 


基本数据类型和数据类型转换


32位浮点型:torch.float32

64位浮点型:torch.float64

16位整型:torch.int16

32位整型:torch.int32

64位整型:torch.int64

 

# (1)从列表直接创建一个tensor,并且制定数据类型为torch.float32
y1 = torch.tensor([6,2],dtype=torch.float32)
print('查看y1的数据类型',y1.type())
y1

 运行情况:

pytorch 返回张量索引 pytorch的张量_深度学习_06


y1 = y1.type(torch.int32) # 转换数据类型
print('转换y1的数据类型',y1.type())
y1

 运行情况:

pytorch 返回张量索引 pytorch的张量_pytorch_07


tensor与numpy

Numpy转化为Tensor:torch.from_numpy(numpy矩阵)

Tensor转化为numpy:Tensor矩阵.numpy() 

import numpy as np
y2 = np.random.randn(2,3) # 使用Numpy生成的2x3的正态分布的随机数
print(y2)
y3 = torch.from_numpy(y2) # numpy —> tensor
print(y3)
y4 = y3.numpy() # tensor —> numpy
print(y4)

 运行情况:

pytorch 返回张量索引 pytorch的张量_pytorch_08

pytorch 返回张量索引 pytorch的张量_深度学习_09

 

pytorch 返回张量索引 pytorch的张量_机器学习_10

 


张量的运算

与numpy的运算规则类似:元素相加、广播、下划线代表就地改变。

调整张量的大小/形状,可以使用:torch.view。

单个元素张量,使用.item() 转换为python数据。

z1 = torch.rand(2,3)
z2 = torch.randn(2,3)
print(z1)
z2

 运行结果:

pytorch 返回张量索引 pytorch的张量_机器学习_11


z1+z2 #对应元素相加减
z1+3 # 也会进行广播运算

 运行结果:

pytorch 返回张量索引 pytorch的张量_pytorch_12

pytorch 返回张量索引 pytorch的张量_数据_13

 


z1.add(z2) # 原有的数据没有改变
print(z1)
z1.add_(z2) # z1会改变
print(z1)

运行结果: 

 

pytorch 返回张量索引 pytorch的张量_数据_14

pytorch 返回张量索引 pytorch的张量_pytorch 返回张量索引_15

 


改变数据形状:

# 现在z1是2x3,可以使用view方法改变形状。view这个方法经常用于展平数据
z1.view(3,2) # 但是z1并没有改变

运行结果: 

 

pytorch 返回张量索引 pytorch的张量_pytorch_16

z1.view(-1,1) # (n,1)

 运行结果:

pytorch 返回张量索引 pytorch的张量_数据_17


其它方法:

z1.mean() # z1的平均值
z1_sum = z1.sum() # z1的和
print(z1_sum )

 运行结果:

pytorch 返回张量索引 pytorch的张量_深度学习_18

可以看到z1_sum只有单个数值,当我想把这单个数值转换成一个标量值的话,可以通过item方法返回一个python标量值, 适用于tensor只有一个数值的场景

print(z1_sum.item()) # item方法返回一个标量值,即python中的数值,而不是一个tensor

 

pytorch 返回张量索引 pytorch的张量_pytorch_19

张量的自动微分

如果将torch.tensor的 .requires_grad属性 设置为True的话,PyTorch框架就会开始跟踪该张量的所有操作。

在完成了一系列计算之后,可以在最后的结果上去调用 .backward() ,它会自动计算所有的梯度,并将该张量的梯度累加到张量的 .grad 属性中。

 

pytorch 返回张量索引 pytorch的张量_深度学习_20

Tensor在pytorch中的数据结构:由data、grad、grad_fn组成。
data:记录它原始的值。
grad:代表张量的梯度,当设置requires_grad=True时,通过计算,最后调用backwaed计算出它 的梯度,梯度放在grad属性中。
 grad_fn:记录这个tensor的来源,即它是由什么函数计算出来的 。

 

a = torch.ones(2,2,requires_grad=True) #设置张量a的requires_grad属性为true
a.data

 运行结果:

pytorch 返回张量索引 pytorch的张量_机器学习_21


b = a+2 # 这个b是通过计算得来的,说明它有grad_fn属性
print(b)
b.grad_fn

 运行结果:

pytorch 返回张量索引 pytorch的张量_数据_22

pytorch 返回张量索引 pytorch的张量_pytorch_23

 


c = b*b+3
out = c.mean()
c

 

pytorch 返回张量索引 pytorch的张量_pytorch_24


# 在out上计算梯度,使用自动微分。这个结果其实就是 d out/dx。这个微分结果就记录在a.grad里面
# out = (a+2)^2+3,再求一个均值
out.backward()

a.grad

 结果:

pytorch 返回张量索引 pytorch的张量_数据_25


自动微分运算在我们模型工作中,经常在loss上调用backward方法,从而计算出每一个变量的梯度,然后对这个变量进行改变 

 在另外一些场景中,我们不需要跟踪这个计算,可以通过将这段代码包装在with torch.no_grad这个上下文中。另外,如果想得到a原有的值,不想要它的requires_grad,可以使用detach获得原有的值,即不包含梯度的值。也可使用 .detach() 来获得具有相同内容但不需要跟踪运算的新Tensor :

with torch.no_grad():
    #这里面的计算并不会被跟踪
    #无法计算它们的梯度
    pass

d = a.detach() # 得到的是a不包含梯度的值,不需要被跟踪运算
d.requires_grad

 结果:

pytorch 返回张量索引 pytorch的张量_数据_26

 当然,也可以使用 requires_grad_ 方法就地改变张量requires_grad属性。

d.requires_grad_(True)

 附上篇文章单变量线性回归例子的分解写法

import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from torch import nn

plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负号

# 使用pandas的read_csv读取数据集
data = pd.read_csv('../2、深度学习基础与线性回归/daatset/Income1.csv')
data.info()

plt.figure(0)
plt.scatter(data.Education,data.Income)
plt.xlabel('受教育年限')
plt.ylabel('收入情况')
plt.show()

X = torch.from_numpy(data.Education.values.reshape(-1,1).astype(np.float32)) # 样本特征
Y = torch.from_numpy(data.Income.values.reshape(-1,1).astype(np.float32))    # 标签

# 分解写法
# 由于是线性问题,所以要先初始化w和b。这里使用正态分布的方式进行初始化。
w = torch.randn(1,requires_grad=True) 
    # w是优化的参数,所以要设置可以被跟踪。由于是单变量线性回归,所以形状是1
b = torch.zeros(1,requires_grad=True)

# 模型的公式:W@x+b
lr = 0.0001 # 学习速率

or epoch in range(5000):    #对全部数据训练5000次
    for x,y in zip(X,Y):
        y_predict = torch.matmul(x,w)+b # matmul是矩阵乘法
        loss = (y-y_predict).pow(2).mean()  
            # (y-y_predict).pow(2)是差的平方,mean再求均值。求均方误差
        if not w.grad  is None:   
                # 在反向传播计算w和b的梯度前,先要将变量的梯度清零,否则梯度会累计进去,而不 
                # 是覆盖掉。
            w.grad.data.zero_() # w.grad.data是梯度的值,清零。
        if not b.grad is None:
            b.grad.data.zero_()
        loss.backward() #进行反向传播,根据损失函数,从而优化参数
        # 梯度的方向就是上升的方向
        # 这样,w和b上就有梯度值了。为了让梯度下降,要将 参数的值 减去 学习率*求得到梯度。让参 
            # 数沿着梯度下降。
        with torch.no_grad:
            # 为了避免引起强烈的震荡,别把梯度全部减掉
            # 这部分计算并不需要被跟踪,所以用了一个上下文。
            w.data -= w.grad.data * learning_rate
            b.data -= b.grad.data * learning_rate

print("w:",w)
print("b:",b)

结果:

pytorch 返回张量索引 pytorch的张量_数据_27


plt.figure(1)
plt.scatter(data.Education,data.Income)
plt.plot(X.numpy(),(X*w+b).data.numpy(),c='r')    # (X*w+b).data模型预测结果的值
plt.show()

 结果:

pytorch 返回张量索引 pytorch的张量_深度学习_28