1、torch.tensor()根据指定数据创建张量

import torch
import numpy as np

# 创建张量标量
data = torch.tensor(10)

# 通过numpy创建
data = torch.tensor(np.random.randn(2,3))

# 通过列表创建
data = torch.tensor([[10.,20.,30.],[40.,50.,60]])

执行结果

 tensor(10)
 tensor([[ 0.1345,  0.1149,  0.2435],
 [ 0.8026, -0.6744, -1.0918]], dtype=torch.float64)
 tensor([[10., 20., 30.],
 [40., 50., 60.]])

2、torch.Tensor()根据指定形状创建张量,也可以用来创建指定数据的张量

# 1. 创建2行3列的张量, 默认dtype为float32
data = torch.Tensor(2, 3)

# 2. 注意: 如果传递列表, 则创建包含指定元素的张量
data = torch.Tensor([10])

data = torch.Tensor([10, 20])

执行结果

tensor([[0.0000e+00, 3.6893e+19, 2.2018e+05],
 [4.6577e-10, 2.4158e-12, 1.1625e+33]])
tensor([10.])
tensor([10., 20.])

3、torch.IntTensor()、torch.FloatTensor()、torch.DoubleTensor() 创建指定类型的张量

# 1. 创建2行3列, dtype为int32 的张量
data = torch.IntTensor(2, 3)

# 2. 注意: 如果传递的元素类型不正确, 则会进行类型转换
data = torch.IntTensor([2.5, 3.3])

# 3. 其他的类型初始化
data = torch.ShortTensor()  # int16
data = torch.LongTensor()   # int64
data = torch.FloatTensor()  # float32
data = torch.DoubleTensor() # float64

自行结果

tensor([[1606422944,        880,          0],
        [         0,          0,          0]], dtype=torch.int32)
tensor([2, 3], dtype=torch.int32)
tensor([], dtype=torch.int16)
tensor([], dtype=torch.int64)
tensor([])
tensor([], dtype=torch.float64)

4、torch.arange()、torch.linspace()创建线性张量

# 1. 在指定区间按照步长生成元素[start, end, step)
data = torch.arange(0, 10, 2)

# 2. 在指定区间按照元素个数生成[start, end, steps]
data = torch.linspace(0, 9, 10)

自行结果

 tensor([0, 2, 4, 6, 8])
 tensor([ 0.0000,  1.2222,  2.4444,  3.6667,  4.8889,  6.1111,  7.3333,  8.5556,
 9.7778, 11.0000])

5、设置随机种子保证每次的执行结果一样

import torch  # 需要安装torch模块,虚拟环境中已经安装好了
import numpy as np
import random

SEED = 42

# 1. Python 内置 random 模块
random.seed(SEED)

# 2. NumPy
np.random.seed(SEED)

# 3. PyTorch CPU
torch.manual_seed(SEED)

# 4. PyTorch GPU(如果用 CUDA)
if torch.cuda.is_available():
    torch.cuda.manual_seed(SEED)
    torch.cuda.manual_seed_all(SEED)  # 多 GPU 时用

# 5. 让 cuDNN 行为确定性(可选,但强烈推荐)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False  # 关闭 benchmark,防止 cuDNN 自动优化导致不一致

# 查看随机数种子
print('随机数种子:', torch.random.initial_seed()) # 42

6、torch.zeros()、torch.zeros_like()创建全0张量

# 1. 创建指定形状全0张量
data = torch.zeros(2, 3)

# 2. 根据张量形状创建全0张量
data = torch.zeros_like(data)

执行结果

 tensor([[0., 0., 0.],
 [0., 0., 0.]])
 tensor([[0., 0., 0.],
 [0., 0., 0.]])

7、torch.ones()、torch.ones_like()创建全0张量

# 1. 创建指定形状全1张量
data = torch.ones(2, 3)

# 2. 根据张量形状创建全1张量
data = torch.ones_like(data)

执行结果

tensor([[1., 1., 1.],
 [1., 1., 1.]])
tensor([[1., 1., 1.],
 [1., 1., 1.]])

8、torch.full()、torch.full_like()创建全为指定值张量

# 1. 创建指定形状指定值的张量
data = torch.full([2, 3], 10)

# 2. 根据张量形状创建指定值的张量
data = torch.full_like(data, 20)

执行结果

tensor([[10, 10, 10],
 [10, 10, 10]])
tensor([[20, 20, 20],
 [20, 20, 20]])

9、张量元素类型转换

data = torch.full([2, 3], 10)

data = data.type(torch.float)

data = data.type(torch.float64)

data = data.type(torch.DoubleTensor)

data = data.type(torch.int32)

data = data.type(torch.int64)

data = data.type(torch.IntTensor)

data = data.double()

data = data.short()

data = data.int()

data = data.long()

data = data.float()

执行结果

torch.int64
torch.float32
torch.float64
torch.float64
torch.int32
torch.int64
torch.int32
torch.float64
torch.int16
torch.int32
torch.int64
torch.float32

10、NumPy数组和张量互相转换

data_tensor = torch.tensor([2, 3, 4])

# numpy转tensor
# 不copy会共享内存,数据修改时会互相影响
data_tensor = torch.from_numpy(np.array([2, 3, 4]).copy())

data_tensor = torch.tensor(np.array([2, 3, 4]).copy())

# tensor转numpy
data_numpy = data_tensor.numpy().copy()

执行结果

tensor([2, 3, 4])
tensor([2, 3, 4], dtype=torch.int32)
tensor([2, 3, 4], dtype=torch.int32)
[2 3 4]

11、标量张量和数字转换

# 当张量只包含一个元素时, 可以通过 item() 函数提取出该值
data = torch.tensor([30,])

data = torch.tensor(30)

执行结果

30
30

12、张量基本运算add、sub、mul、div、neg、matmul

import torch  # 需要安装torch模块,虚拟环境中已经安装好了
import numpy as np
import random

data = torch.randint(0, 10, [2, 3])
print('data =', data)

# 1. 不修改原数据
new_data = data.add(10)  # 等价new_data = data + 10
print("data + 10 =", new_data)

# 2. 直接修改原数据注意: 带下划线的函数为修改原数据本身
data.add_(10)  # 等价data += 10
print("data + 10 =", data)

# 3. 其他函数
print("data - 100 =", data.sub(100))
print("data1 * 100 =", data.mul(100))
print("data1 / 100 =", data.div(100))
print("data1 * (-1) =", data.neg())

data1 = torch.tensor([[1, 2], [3, 4]])
data2 = torch.tensor([[5, 6], [7, 8]])
# 矩阵点乘
# 第一种方式
data = torch.mul(data1, data2)
print("data1 * data2 =", data)
# 第二种方式
data = data1 * data2
print("data1 * data2 =", data)

# 矩阵乘法运算
# 第一种方式
data = data1 @ data2
print("data1 @ data2 =", data)
# 第二种方式
data = torch.matmul(data1, data2)
print("data1 @ data2 =", data)

data = data.type(torch.float64)
print('data =', data)
print('data.mean() =', data.mean())
print('data.mean(dim=0) =', data.mean(dim=0))  # 按列计算均值
print('data.mean(dim=1) =', data.mean(dim=1))  # 按行计算均值

print('data.sum() =', data.sum())
print('data.sum(dim=0) =', data.sum(dim=0))
print('data.sum(dim=1) =', data.sum(dim=1))

print('torch.pow(data, 2) =', torch.pow(data, 2))

# 计算平方根
print('data.sqrt() =', data.sqrt())
# 指数计算, e^n次方
print('data.exp() =', data.exp())
# 对数计算
print('data.log() =', data.log())  # 以e 为底
print('data.log2() =', data.log2())
print('data.log10() =', data.log10())

执行结果

data = tensor([[6, 3, 2],
        [2, 0, 8]])
data + 10 = tensor([[16, 13, 12],
        [12, 10, 18]])
data + 10 = tensor([[16, 13, 12],
        [12, 10, 18]])
data - 100 = tensor([[-84, -87, -88],
        [-88, -90, -82]])
data1 * 100 = tensor([[1600, 1300, 1200],
        [1200, 1000, 1800]])
data1 / 100 = tensor([[0.1600, 0.1300, 0.1200],
        [0.1200, 0.1000, 0.1800]])
data1 * (-1) = tensor([[-16, -13, -12],
        [-12, -10, -18]])
data1 * data2 = tensor([[ 5, 12],
        [21, 32]])
data1 * data2 = tensor([[ 5, 12],
        [21, 32]])
data1 @ data2 = tensor([[19, 22],
        [43, 50]])
data1 @ data2 = tensor([[19, 22],
        [43, 50]])
data = tensor([[19., 22.],
        [43., 50.]], dtype=torch.float64)
data.mean() = tensor(33.5000, dtype=torch.float64)
data.mean(dim=0) = tensor([31., 36.], dtype=torch.float64)
data.mean(dim=1) = tensor([20.5000, 46.5000], dtype=torch.float64)
data.sum() = tensor(134., dtype=torch.float64)
data.sum(dim=0) = tensor([62., 72.], dtype=torch.float64)
data.sum(dim=1) = tensor([41., 93.], dtype=torch.float64)
torch.pow(data, 2) = tensor([[ 361.,  484.],
        [1849., 2500.]], dtype=torch.float64)
data.sqrt() = tensor([[4.3589, 4.6904],
        [6.5574, 7.0711]], dtype=torch.float64)
data.exp() = tensor([[1.7848e+08, 3.5849e+09],
        [4.7278e+18, 5.1847e+21]], dtype=torch.float64)
data.log() = tensor([[2.9444, 3.0910],
        [3.7612, 3.9120]], dtype=torch.float64)
data.log2() = tensor([[4.2479, 4.4594],
        [5.4263, 5.6439]], dtype=torch.float64)
data.log10() = tensor([[1.2788, 1.3424],
        [1.6335, 1.6990]], dtype=torch.float64)

13、索引操作

import torch  # 需要安装torch模块,虚拟环境中已经安装好了
import numpy as np
import random

data = torch.randint(0, 10, [4, 5])
print('data =', data)

# 列表索引
# 第1行所有列
print('data[0] =', data[0])
# 所有行第0列
print('data[:, 0] =', data[:, 0])
# [0,2], [1,3]
print('data[[0, 1], [2, 3]] =', data[[0, 1], [2, 3]])
# [0,1], [0,2], [1,1], [1,2]
print('data[[[0], [1]], [1, 2]] =', data[[[0], [1]], [1, 2]])

# 范围索引
# 前3行的前2列数据
print('data[:3, :2] =', data[:3, :2])
# 第2行到最后的前2列数据
print('data[2:, :2] =', data[2:, :2])

# 布尔索引
# 所有列数据,筛选行的条件:第三列大于5的行数据
print('data[data[:, 2] > 5] =', data[data[:, 2] > 5])
# 所有行数据,筛选列的条件:第二行大于5的列数据
print('data[:, data[1] > 5] =', data[:, data[1] > 5])

# 多维索引
data = torch.randint(0, 10, [3, 4, 5])
print('data =', data)
# 获取0轴上的第一个数据
print('data[0, :, :] =', data[0, :, :])
# 获取1轴上的第一个数据
print('data[:, 0, :] =', data[:, 0, :])
# 获取2轴上的第一个数据
print('data[:, :, 0] =', data[:, :, 0])

执行结果

data = tensor([[7, 3, 4, 5, 2],
        [7, 9, 8, 6, 2],
        [2, 9, 6, 6, 8],
        [1, 3, 7, 5, 7]])
data[0] = tensor([7, 3, 4, 5, 2])
data[:, 0] = tensor([7, 7, 2, 1])
data[[0, 1], [2, 3]] = tensor([4, 6])
data[[[0], [1]], [1, 2]] = tensor([[3, 4],
        [9, 8]])
data[:3, :2] = tensor([[7, 3],
        [7, 9],
        [2, 9]])
data[2:, :2] = tensor([[2, 9],
        [1, 3]])
data[data[:, 2] > 5] = tensor([[7, 9, 8, 6, 2],
        [2, 9, 6, 6, 8],
        [1, 3, 7, 5, 7]])
data[:, data[1] > 5] = tensor([[7, 3, 4, 5],
        [7, 9, 8, 6],
        [2, 9, 6, 6],
        [1, 3, 7, 5]])
data = tensor([[[2, 1, 1, 4, 8],
         [7, 6, 5, 1, 0],
         [1, 2, 6, 0, 9],
         [8, 4, 3, 6, 5]],

        [[7, 8, 5, 7, 6],
         [9, 9, 9, 2, 9],
         [6, 7, 4, 7, 9],
         [1, 7, 9, 3, 0]],

        [[6, 8, 4, 3, 1],
         [0, 0, 8, 8, 7],
         [0, 5, 0, 1, 4],
         [2, 2, 6, 5, 3]]])
data[0, :, :] = tensor([[2, 1, 1, 4, 8],
        [7, 6, 5, 1, 0],
        [1, 2, 6, 0, 9],
        [8, 4, 3, 6, 5]])
data[:, 0, :] = tensor([[2, 1, 1, 4, 8],
        [7, 8, 5, 7, 6],
        [6, 8, 4, 3, 1]])
data[:, :, 0] = tensor([[2, 7, 1, 8],
        [7, 9, 6, 1],
        [6, 0, 0, 2]])

14、reshape函数

reshape 函数可以在保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状。

data = torch.tensor([[10, 20, 30], [40, 50, 60]])

# 1. 使用shape 属性或者size 方法都可以获得张量的形状
print(data.shape, data.shape[0], data.shape[1])
print(data.size(), data.size(0), data.size(1))

# 2. 使用reshape 函数修改张量形状
new_data = data.reshape(1, 6)
print(new_data.shape)

new_data = data.reshape(3, 2)
print(new_data.shape)

new_data = data.reshape(1, 6)
print(new_data.shape)

new_data = data.reshape(-1)
print(new_data.shape)

执行结果

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

15、squeeze()和unsqueeze()函数

squeeze 函数删除形状为1 的维度(降维),unsqueeze 函数添加形状为1的维度(升维)。

mydata1 = torch.tensor([1, 2, 3, 4, 5])
print('mydata1--->', mydata1.shape, mydata1)  # 一个普通的数

# 组1维数据
mydata2 = mydata1.unsqueeze(dim=0)
print('在0维度上拓展维度:', mydata2, mydata2.shape)  # 1*5

mydata3 = mydata1.unsqueeze(dim=1)
print('在1维度上拓展维度:', mydata3, mydata3.shape)  # 5*1

mydata4 = mydata1.unsqueeze(dim=-1)
print('在最后1个维度上拓展维度:', mydata4, mydata4.shape)  # 5*1

mydata5 = mydata4.squeeze()
print('压缩维度:', mydata5, mydata5.shape)  # 1*5

执行结果

mydata1---> torch.Size([5]) tensor([1, 2, 3, 4, 5])
在0维度上拓展维度: tensor([[1, 2, 3, 4, 5]]) torch.Size([1, 5])
在1维度上拓展维度: tensor([[1],
        [2],
        [3],
        [4],
        [5]]) torch.Size([5, 1])
在最后1个维度上拓展维度: tensor([[1],
        [2],
        [3],
        [4],
        [5]]) torch.Size([5, 1])
压缩维度: tensor([1, 2, 3, 4, 5]) torch.Size([5])

16、transpose()和permute()函数

transpose 函数可以实现交换张量形状的指定维度, 例如: 一个张量的形状为(2, 3, 4) 可以通过transpose 函数把3 和4 进行交换, 将张量的形状变为(2, 4, 3) 。permute 函数可以一次交换更多的维度。

data = torch.tensor(np.random.randint(0, 10, [3, 4, 5]))
print('data shape:', data.size())
# 1 交换1和2维度
mydata2 = torch.transpose(data, 1, 2)
print('mydata2.shape--->', mydata2.shape)
# 2 将data 的形状修改为(4, 5, 3), 需要变换多次
mydata3 = torch.transpose(data, 0, 1)
mydata4 = torch.transpose(mydata3, 1, 2)
print('mydata4.shape--->', mydata4.shape)
# 3 使用permute 函数将形状修改为(4, 5, 3)
# 3-1 方法1
mydata5 = torch.permute(data, [1, 2, 0])
print('mydata5.shape--->', mydata5.shape)
# 3-2 方法2
mydata6 = data.permute([1, 2, 0])
print('mydata6.shape--->', mydata6.shape)

执行结果

data shape: torch.Size([3, 4, 5])
mydata2.shape---> torch.Size([3, 5, 4])
mydata4.shape---> torch.Size([4, 5, 3])
mydata5.shape---> torch.Size([4, 5, 3])
mydata6.shape---> torch.Size([4, 5, 3])

17、view()和contiguous()函数

view 函数也可以用于修改张量的形状,只能用于存储在整块内存中的张量。在PyTorch 中,有些张量是由不同的数据 块组成的,它们并没有存储在整块的内存中,view 函数无法对这样的张量进行变形处理,例如: 一个张量经过了 transpose 或者permute 函数的处理之后,就无法使用view 函数进行形状操作。

data = torch.tensor([[10, 20, 30], [40, 50, 60]])
print('data--->', data, data.shape)
# 1 判断是否使用整块内存
print(data.is_contiguous())  # True
# 2 view
mydata2 = data.view(3, 2)
print('mydata2--->', mydata2, mydata2.shape)
# 3 判断是否使用整块
print('mydata2.is_contiguous()--->', mydata2.is_contiguous())
# 4 使用transpose 函数修改形状
mydata3 = torch.transpose(data, 0, 1)
print('mydata3--->', mydata3, mydata3.shape)
print('mydata3.is_contiguous()--->', mydata3.is_contiguous())
# 5 需要先使用contiguous 函数转换为整块内存的张量,再使用view 函数
print(mydata3.contiguous().is_contiguous())
mydata4 = mydata3.contiguous().view(2, 3)
print('mydata4--->', mydata4.shape, mydata4)

执行结果

data---> tensor([[10, 20, 30],
        [40, 50, 60]]) torch.Size([2, 3])
True
mydata2---> tensor([[10, 20],
        [30, 40],
        [50, 60]]) torch.Size([3, 2])
mydata2.is_contiguous()---> True
mydata3---> tensor([[10, 40],
        [20, 50],
        [30, 60]]) torch.Size([3, 2])
mydata3.is_contiguous()---> False
True
mydata4---> torch.Size([2, 3]) tensor([[10, 40, 20],
        [50, 30, 60]])

18、torch.cat()

torch.cat()函数可以将两个张量根据指定的维度拼接起来,不改变维度数。

data1 = torch.randint(0, 10, [1, 2, 3])
data2 = torch.randint(0, 10, [1, 2, 3])
print(data1)
print(data2)
# 1. 按0维度拼接
new_data = torch.cat([data1, data2], dim=0)
print(new_data)
print(new_data.shape)
# 2. 按1维度拼接
new_data = torch.cat([data1, data2], dim=1)
print(new_data)
print(new_data.shape)
# 3. 按2维度拼接
new_data = torch.cat([data1, data2], dim=2)
print(new_data)
print(new_data.shape)

执行结果

tensor([[[4, 9, 0],
         [4, 1, 1]]])
tensor([[[4, 4, 8],
         [4, 5, 1]]])
tensor([[[4, 9, 0],
         [4, 1, 1]],

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

19、自动微分模块

训练神经网络时,最常用的算法就是反向传播。在该算法中,参数(模型权重)会根据损失函数关于对应 参数的梯度进行调整。为了计算这些梯度,PyTorch内置了名为torch.autograd的微分引擎。它支持任意 计算图的自动梯度计算:

接下来我们使用这个结构进行自动微分模块的介绍。我们使用backward 方法、grad 属性来实 现梯度的计算和访问

import torch


def test01():
    x = torch.tensor(5)
    y = torch.tensor(0.)
    w = torch.tensor(1., requires_grad=True, dtype=torch.float32)
    b = torch.tensor(3., requires_grad=True, dtype=torch.float32)
    z = w * x + b
    loss = torch.nn.MSELoss()
    loss = loss(z, y)
    loss.backward()
    print("W梯度:", w.grad)
    print("b梯度:", b.grad)


test01()


def test02():
    x = torch.ones(2, 5)
    y = torch.zeros(2, 3)
    w = torch.randn(5, 3, requires_grad=True)
    b = torch.randn(3, requires_grad=True)
    z = x @ w + b
    # print('x = ', x, 'w = ', w)
    # print('z = ', z, ' x @ w = ', x @ w, 'b = ', b)
    loss = torch.nn.MSELoss()
    loss = loss(z, y)
    loss.backward()
    print(w.grad)
    print(b.grad)


test02()

20、PyTorch构建线性回归模型相关API

import torch
from torch.utils.data import TensorDataset, DataLoader
from torch import nn, optim
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


def create_dataset():
    x, y, coef = make_regression(
        n_samples=100,
        n_features=1,
        noise=10,
        coef=True,
        bias=1.5,
        random_state=40,
    )

    x = torch.tensor(x)
    y = torch.tensor(y)

    return x, y, coef


def dm01():
    # 构造数据集
    x, y, coef = create_dataset()
    # 构造数据集对象
    dataset = TensorDataset(x, y)
    # 构造数据加载器
    # dataset=:数据集对象
    # batch_size=:批量训练样本数据
    # shuffle=:样本数据是否进行乱序
    dataloader = DataLoader(dataset=dataset, batch_size=16, shuffle=True)
    # 构造模型
    # in_features指的是输入张量的大小size
    # out_features指的是输出张量的大小size
    model = nn.Linear(in_features=1, out_features=1)
    # 构造平方损失函数
    criterion = nn.MSELoss()
    # 构造优化函数
    optimizer = optim.SGD(params=model.parameters(), lr=1e-2)

    epochs = 100
    # 损失的变化
    loss_epoch = []
    total_loss = 0.0
    train_sample = 0.0
    for _ in range(epochs):
        for train_x, train_y in dataloader:
            # 将一个batch的训练数据送入模型
            y_pred = model(train_x.type(torch.float32))
            # 计算损失值
            loss = criterion(y_pred, train_y.reshape(-1, 1).type(torch.float32))
            total_loss += loss.item()
            train_sample += len(train_y)
            # 梯度清零
            optimizer.zero_grad()
            # 自动微分(反向传播)
            loss.backward()
            # 更新参数
            optimizer.step()
            # 获取每个batch的损失
        loss_epoch.append(total_loss / train_sample)

    # 绘制损失变化曲线
    plt.plot(range(epochs), loss_epoch)
    plt.title('损失变化曲线')
    plt.grid()
    plt.show()
    # 绘制拟合直线
    plt.scatter(x, y)
    x = torch.linspace(x.min(), x.max(), 100)
    y1 = torch.tensor([v * model.weight + model.bias for v in x])
    y2 = torch.tensor([v * coef + 1.5 for v in x])
    plt.plot(x, y1, label='训练')
    plt.plot(x, y2, label='真实')
    plt.grid()
    plt.legend()
    plt.show()


dm01()

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐