Pytorch入门

wang 发布于 2024-12-13 11161 次阅读


PyTorch

张量(Tensor) 处理的

它只有 数值张量

张量的创建

torch.tensor() 基于指定数据创建张量 默认: int:64 float:32

torch.Tensor() 不仅可以基于指定数据创建,还可以基于 形状 创建

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

入门张量

#pytorch 2.7.0 -i 镜像地址
import torch
import numpy as np

t2 = torch.tensor([10])
print(t2)
t1 = torch.Tensor([10],)
print(t1)

t3 = torch.IntTensor(10)
print(t3)

t4 = torch.tensor(np.array(10))
print(t4)

随机张量

"""
案例:
    通过Python代码演示如何创建 线性 和 随机张量.

涉及到的torch包中的函数如下:
    torch.arange() 和 torch.linspace() 创建线性张量 与 正态分布
    torch.random.initial_seed() 和 torch.random.manual_seed() 随机种子设置
    torch.rand/randn() 创建随机浮点类型张量  +n 符合正态分布
    torch.randint(low, high, size=()) 创建随机整数类型张量

掌握:    torch.random.manual_seed()      手动设置随机种子, 如果种子一致, 则随机数也是"固定随机的"    randint()                       创建指定区间的随机整数张量"""

# 导包
import torch
import numpy as np

# todo 演示1: torch.arange() 和 torch.linspace() 创建线性张量
# 1. 创建1 ~ 10之间的线性张量, 步长为: 2
t1 = torch.arange(1, 11, 2)     # 参1: 起始值, 参2: 结束值, 参3: 步长
print(f't1: {t1}')

# 2. 创建1 ~ 10之间的等差数列, 元素个数为: 5
t2 = torch.linspace(1, 10, 5)   # 参1: 起始值, 参2: 结束值(包括), 参3: 元素个数
print(f't2: {t2}')
print('-' * 27)


# todo 演示2: torch.random.initial_seed() 和 torch.random.manual_seed() 随机种子设置
# torch.random.initial_seed()     # 默认采用系统时间(每秒都在变化)作为种子.
torch.random.manual_seed(27)      # 手动设置固定的随机种子

# todo 演示3: torch.rand/randn() 创建随机浮点类型张量
# 1. 创建2行3列的随机张量.
t1 = torch.rand(2, 3)
print(f't1: {t1}')

# 2. 创建2行3列的随机张量 -> 符合正态分布的随机张量.
t2 = torch.randn(2, 3)
print(f't2: {t2}')
print('-' * 27)

# todo 演示4: torch.randint(low, high, size=()) 创建随机整数类型张量
t1 = torch.randint(low=1, high=10, size=(2, 3))     # 2行3列 -> 随机生成1~10之间的随机数, 包左不包右.
print(f't1: {t1}')


# 扩展: Python的random模块下的randint()函数是包左包右的, 要记得和上述的作区分.
# import random
# print(random.randint(1, 1))     # 包左包右的

全0 全1 全指定

"""
案例:
    演示如何创建全0, 全1, 全为指定值的张量.

涉及到的函数如下:
    torch.ones 和 torch.ones_like 创建全1张量
    torch.zeros 和 torch.zeros_like 创建全0张量
    torch.full 和 torch.full_like 创建全为指定值张量

掌握:
    zeros()
"""

# 导包
import torch
import numpy as np

# todo 演示1: torch.ones 和 torch.ones_like 创建全1张量
# 1. 创建指定形状的全1张量.
t1 = torch.ones(2, 3)
print(f't1: {t1}')     # 默认是: float32

# 2. 基于指定(张量)的形状, 创建和其形状相同的全1张量.
my_tensor = torch.tensor([[1, 2], [3, 4], [5, 6]])
# print(my_tensor.shape)      # torch.Size([3, 2])

t2 = torch.ones_like(my_tensor)
print(f't2: {t2}')      # 3行2列的全1张量
print('-' * 27)


# todo 演示2: torch.zeros 和 torch.zeros_like 创建全0张量
t3 = torch.zeros(6, 2)
print(f't3: {t3}')      # 默认是: float32

t4 = torch.zeros_like(my_tensor)
print(f't4: {t4}')      # 3行2列的全0张量
print('-' * 27)


# todo 演示3: torch.full 和 torch.full_like 创建全为指定值张量
t5 = torch.full(size=(2, 3), fill_value=27)
print(f't5: {t5}')

t6 = torch.full_like(my_tensor, fill_value=27)
print(f't6: {t6}')      # 3行2列的全27张量

改变类型

dtype 或者 直接点出来 .short .long .float .int .double .half-(一半)比如int64 -> int32

t1 = torch.tensor([1,2,3,4], dtype=torch.float32)
t2 = t1.type(torch.float64)
print(t2,t2.dtype)

张量的类型转换🪭

张量numpyndarray之间的转换

张量 -> ndarray对象

t1.numpy().copy()

ndarray -> 张量

torch.from_numpy()共享内存

torch.tensor() 不共享

提取0维张量:

0张量.item()

"""
案例:
    演示PyTorch的张量 和 Numpy的ndarray类型相互转换.

涉及到的函数如下:
    1. tensor#numpy()       可以变量张量 -> ndarray数组, 默认:共享内存.
    2. torch.from_numpy()   把 ndarray -> 张量, 默认: 共享内存.
    3. torch.tensor()       把 ndarray -> 张量, 默认: 不共享内存.
    4. item()函数()          从张量中提取一个值.
"""

# 导包
import numpy as np
import torch

# 场景1: 张量 -> ndarray
# 1. 创建张量.
t1 = torch.tensor([1, 2, 3])
print(f't1: {t1}')      # t1: tensor([1, 2, 3])

# 2. 把上述的张量 -> ndarray对象
n1 = t1.numpy()             # 共享内存
n2 = t1.numpy().copy()      # 不共享内存
print(f'n1: {n1}, n2: {n2}')

# 3. 修改张量的内容, 观察结果.
t1[0] = 100

# 4. 重新打印上述的张量信息.
print(f'张量的内容为: {t1}')  # [10, 2, 3]
print(f'ndarray的内容为: {n1}, {n2}')       # [100   2   3], [1 2 3]
print('-' * 27)


# todo 2. ndarray  -> 张量
# 1. 创建ndarray对象.
n_obj = np.array([11, 22, 33])
# print(f'n_obj: {n_obj}, type: {type(n_obj)}')       # 11 22 32], type: <class 'numpy.ndarray'>

# 2. 把上述的ndarray对象 -> 张量对象.
# 写法1: 共享内存
t3 = torch.from_numpy(n_obj)
print(f't3: {t3}, type: {type(t3)}')                 # <class 'torch.Tensor'>

# 写法2: 不共享内存
t4 = torch.from_numpy(n_obj.copy())
print(f't4: {t4}, type: {type(t4)}')

# 写法3: 不共享内存
t5 = torch.tensor(n_obj)
print(f't5: {t5}, type: {type(t5)}')                 # <class 'torch.Tensor'>

# 3. 修改ndarray对象, 观察结果.
n_obj[0] = 100

# 4. 打印修改后的内容.
print(f'ndarray的内容为: {n_obj}')      # [100, 22, 33]
print(f't3: {t3}')  # tensor([100,  22,  32], dtype=torch.int32)
print(f't4: {t4}')  # tensor([11, 22, 32], dtype=torch.int32)
print(f't5: {t5}')  # tensor([11, 22, 32], dtype=torch.int32)
print('-' * 27)


# todo 3: 演示 标量张量(1个值) 如何获取其中的 数值.
# 1. 创建一个标量张量.
t6 = torch.tensor(100)
print(f't6: {t6}, 类型: {type(t6)}')  # tensor类型

# 2. 从上述的张量中, 提取数值.
a = t6.item()       # item()函数: 只适用于 (标量)张量
print(f'a: {a}, 类型: {type(a)}')     # int类型

张量运算函数

如add_() sub_() 加_表示 inplace=True

当然,我们 + - * / 用的多

加-add

t1 = torch.tensor([1,2,3,4,5],dtype=torch.int64)
print(t1)

t2 = t1.add(10)
print(t1)
print(t2)

t3 = t1.add_(10)
print(t3)
-------------------------------------------------------------
t1 = torch.tensor([1, -2, 3], dtype=torch.int64)
print(t1.add(10))       # tensor([11,  8, 13])
print(t1 + 10)          # 效果同上

减-sub

print(t1.sub(10))       # tensor([ -9, -12,  -7])
print(t1 - 10)          # 效果同上

乘-mul

print(t1.mul(10))       # tensor([ 10, -20,  30])
print(t1 * 10)          # 效果同上

除-div

print(t1.div(10))       # tensor([ 0.1000, -0.2000,  0.3000])
print(t1 / 10)          # 效果同上

取反-neg

print(t1.neg())         # tensor([-1,  2, -3])
print(t1 * -1)          # 效果同上

张量索引操作

"""
案例:
    演示pytorch中的索引相关操作.

分类:
    1. 简单的行列索引
    2. 列表索引
    3. 范围索引
    4. 布尔索引
    5. 多维索引
"""

# 导包
import torch

# todo 0.准备数据
# 1. 设置随机种子.
torch.manual_seed(27)

# 2. 随机生成4行5列的整数张量
t1 = torch.randint(0, 10, (4, 5))
print(f't1: {t1}')
print('-' * 27)

# todo 1. 演示简单的行列索引
print(t1[0])    # 获取第一行的数据


# todo 2. 演示列表索引
# 1. 获取(0, 1), (1, 2)两个位置的元素.
#          行       列
print(t1[[0, 1], [1, 2]])

# 2. 获取(0, 2), (3, 4)两个位置的元素.
print(t1[[0, 3], [2, 4]])   # 你: [9, 6], 我: [4, 2]

# 3. 返回0, 1行的 1,2列共4个元素.
print(t1[[[0], [1]], [1, 2]])       # 写法可以, 不报错, 但是不推荐, 会报警告.
print(t1[:2, [1, 2]])               # 推荐
print('-' * 27)


# todo 3. 演示范围索引
# 1. 获取前3行的前2列数据
print(t1[:3, :2])

# 2. 获取第2行到最后(一行)的 前2列数据
print(t1[1:, :2])

# 3. 获取所有行,所有列, 步长为2的数据
print(t1[::2, ::2])
print('-' * 27)


# todo 4. 演示布尔索引
# 1. 获取第4列大于8的行数据
print(t1[t1[:, 3] > 8])

# 2. 第2行大于5的列数据
print(t1[:, t1[1] > 5])     # : 表示所以行
print(t1[1, t1[1] > 5])     # 前边的1表示: 第2行(索引为1)
print('-' * 27)

# todo 5. 演示多维索引
# 1. 创建3个4行5列的, 随机整数张量.
t2 = torch.randint(0, 10, (3, 4, 5))
print(f't2: {t2}')
print('-' * 27)

# 2. 获取0轴上的第1个元素.       # [3, 4, 5] -> [1, 4, 5]
print(t2[0, :, :])  # 即: 第1个4行5列的矩阵

# 3. 获取1轴上的第1个元素.       # [3, 4, 5] -> [3, 1, 5]
print(t2[:, 0, :])  # 即: 获取3个(4行5列)矩阵的 第1行数据

# 4. 获取2轴上的第1个元素.       # [3, 4, 5] -> [3, 4, 1]
print(t2[:, :, 0])  # 即: 获取3个(4行5列)矩阵的 第1列数据

张量形状操作

.shape[0/1]

size()[0/1]

张量的转换.reshape()

"""
案例:
    演示pytorch中操作形状相关的函数.

涉及到的函数如下:
reshape()        改变张量的形状    
squeeze()        删除张量中维度为1的维度(降维)    
unsqueeze()      增加一个维度(升维)
"""

# 导包
import torch


# todo 1. 演示reshape()函数
def dm01_reshape():
    # 1. 创建2行3列的矩阵(张量)
    t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])

    # 2. 打印上述张量的形状
    print(f'形状为: {t1.shape}, 行数: {t1.shape[0]}, 列数: {t1.shape[1]}')     # torch.Size([2, 3]), 2, 3
    print(f'形状为: {t1.size()}, 行数: {t1.size(0)}, 列数: {t1.size(1)}')      # 效果同上.

    # 3. 改变张量的形状
    # 3.1 从2行3列 -> 3行2列
    t2 = t1.reshape(3, 2)
    print(f't2: {t2}')


# todo 6. 测试代码
if __name__ == '__main__':
    # 1. 测试: reshape()函数
    dm01_reshape()

张量拼接操作

Cat() 只能在已有的维度上做拼接

stack() 可以在新的维度上做拼接

"""
案例:
    演示Pytorch中的张量拼接动作

涉及到的函数如下:
    cat()       只能在已有的维度上拼接, 不会改变维度数.
    stack()     可以在新的维度上做拼接, 可以改变维度数.
细节:
    1. 使用cat()函数拼接时, 拼接的那个维度值可以不同, 但是其它维度值必须相同.
        例如:
            按照0维拼接, 可以是: (3, 2) + (5, 2) = (8, 2)
            按照1维拼接, 可以是: (2, 5) + (2, 3) = (2, 8)
"""

# 导包
import torch


# todo 1. 演示 cat()函数实现拼接
# 1. 创建2个随机的2维张量.
t1 = torch.randint(0, 10, (2, 3))
t2 = torch.randint(0, 10, (2, 3))
print(f't1: {t1}')
print(f't2: {t2}')

# 2. 再0维上做拼接, 即: (2, 3) + (2, 3)  -> (4, 3)
t3 = torch.cat([t1, t2], dim=0)
print(f't3: {t3}')

# 3. 再1维上做拼接, 即: (2, 3) + (2, 3)  -> (2, 8)
t4 = torch.cat([t1, t2], dim=1)
print(f't4: {t4}')

#                                        0维 1维 2维
# 4. 再2维上做拼接, 即: (2, 3) + (2, 3)  -> (2, 3, 2)
# t5 = torch.cat([t1, t2], dim=2)
# print(f't5: {t5}')      # 报错, cat()函数拼接的维度不能超过张量的维度数.
print('-' * 27)


# todo 2. 演示stack函数实现拼接.
# 1. 创建2个随机的2维张量.
t1 = torch.randint(0, 10, (2, 3))
t2 = torch.randint(0, 10, (2, 3))
print(f't1: {t1}')
print(f't2: {t2}')

# 2. 再0维上做拼接, 即: (2, 3) + (2, 3)  -> (②, 2, 3)
t3 = torch.stack([t1, t2], dim=0)
print(f't3: {t3}, 形状: {t3.shape}')

# 3. 再1维上做拼接, 即: (2, 3) + (2, 3)  -> (2, ②, 3)
t4 = torch.stack([t1, t2], dim=1)
print(f't4: {t4}, 形状: {t4.shape}')

# 4. 再2维上做拼接, 即: (2, 3) + (2, 3)  -> (2, 3, ②)
t5 = torch.stack([t1, t2], dim=2)
print(f't5: {t5}, 形状: {t5.shape}')      # 3维

# 5. 扩展: 再5维上做拼接.
# t6 = torch.stack([t1, t2], dim=5)
# print(f't6: {t6}, 形状: {t6.shape}')         # 期望: (2, 3, 1, 1, ②),  结果是: 报错, 超出了维度数.

自动微分模块

自动求导


w = torch.tensor([10,20,30,40],requires_grad=True,dtype=torch.float32)
loss_fn =  2*w**2    #梯度公式 这里方便计算随便写的,如:准确率 召回率 F1 MAE MSE RMSE等
print(w.requires_grad)#查看梯度
print(w.data)#查看数据
loss_fn.sum().backward()#自动微分模块计算梯度
print(w.grad)#拿梯度

requires_grad 是否开启梯度跟踪

.grad:获取梯度

.data 查看数据

.backward 计算梯度

import torch
w = torch.tensor(10.0,requires_grad=True,dtype=torch.float32)
for i  in range(1,100):
    loss_fn = w**2
    if w.grad is not None:
        w.grad.zero_() #它的梯度会叠加 所以要清空-------梯度清零
    loss_fn.backward()
    w.data = w.data - w.grad * 0.01
    print(f'第{i}次,{w.grad:.5f}|{w.data:.5f}'

梯度计算的注意点

如果一个张量 使用 自动微分动作不能ndarray转换

可以用 detach 进行备份 再 转ndarray

w = torch.tensor(10.0,requires_grad=True,dtype=torch.float32)
w1 = w.detach().numpy()
print(w,type(w))
print(w1,type(w1))
一名热爱海贼的AI开发者
最后更新于 2025-12-13