重生归来,我要成功 Python 高手--day35 深度学习 Pytorch

PyTorch:基于python语言的深度学习框架,将数据封装为张量

下载包:pip istall 报名 -i 镜像

特点

1.类似于numpyd 的张量计算

2.自动微分模块

3.深度学习库

4.动态学习库

5.GPU加速

6.支持多种应用场景

7.支持跨平台

张量的创建:张量:元素为同一数据类型的多维矩阵

0维:标量 1维:向量/矢量 2维:矩阵 3维:矩阵数组(2维张量的堆叠)

3,h, w: 3:通道数 h:高度 w:宽度

【3,4,5】三个四行五列的数组的堆叠

API:

torch.tensor:根据指定形状创建张量

torch.Tensor:根据形状创建张量(未初始化),其也可以用来创建指定数据类型的张量

torch.IntTensor torch.FloatTensor torch.DounbleTensor 创建指定类型的张量

复制代码
import torch
import numpy as np
# 数据类型创建张量【标量,list,numpy】
def f01():
    out=torch.tensor(5,)
    print(type(out))
    out2=torch.tensor([4,3,2])
    print(type(out2))
    out3=torch.tensor(np.array([1,2,3]))
    print(type(out3))
# 根据数据形状来创建没有初始化
def f02():
    # 通过指定维度大小创建张量
    out=torch.Tensor(2,3)
    print(out,out.shape,type(out),out.dtype)
    # 将numpy数组转化为张量
    out2 = torch.Tensor(np.array([5,6,7]))
    print(out2, out2.shape, type(out2), out2.dtype)



# 创建指定类型的张量没有数值,所有只创建了形状
def f03():
    # 创建整型
    out=torch.IntTensor(2,3)
    print(out,out.shape,type(out),out.dtype)
    # 创建单精度浮点型
    out2 = torch.FloatTensor(2,3)*0
    print(out2, out2.shape, type(out2), out2.dtype)
    # 创建双精度浮点型
    out3 = torch.DoubleTensor(2,3)
    print(out3, out3.shape, type(out3), out3.dtype)

if __name__ == '__main__':
    # f01()

    # f02()

    f03()

torch 运行时数据类型要求一致

线性张量和随机张量:

API:

torch.arange(1,10,2) 起始元素,终止元素,步长 包左不包右

torch.linspace(1,20,5) 起始元素,终止元素,几个元素 都包

torch.rand(300,500) 创建均匀分布的浮点型张量

torch.randn(300,500) 创建正态分布的浮点型张量

torch.initial_seed() 查看随机种子

torch.manual_seed(18) 固定随机种子

复制代码
import torch
import matplotlib.pyplot as plt

# 线性张量,arange   linspace
def f01():
    out=torch.arange(1,10,2)
    print(out,type(out),out.dtype)

    out2=torch.linspace(1,20,5)
    print(out2,type(out2),out2.dtype)



'''
随机张量
0-1之间的  rand
标准高斯正态分布 randn
randint 整型
initial_seed 返回随机数种子
manual_seed(v) 随机数种子的设置

'''

# rand
def f02():
    out=torch.rand(300,500)
    print(out,type(out),out.dtype)
    # 将高维降到低维
    out=out.flatten()
    plt.hist(out)
    plt.show()

# randn
def f03():
    out=torch.randn(300,500)
    # print(out,type(out),out.dtype)
    # 将高维降到低维
    out=out.flatten()
    plt.hist(out)
    plt.show()


# print(f'输出随机数种子{torch.initial_seed()}')
# 固定随机数种子
torch.manual_seed(18)
print(torch.initial_seed())
# randint 随机整型
def f04():
    out=torch.randint(0,100,(10,10))
    print(out,type(out),out.dtype)
    # 将高维降到低维
    out=out.flatten()
    # plt.hist(out)
    # plt.show()

if __name__ == '__main__':
    # f01()
    # f02()
    # f03()
    f04()

创建全零或者全一的张量

torch.zeros(5,5) 创建五乘五的全零张量

torch.ones(5,5) 创建五乘五的全一张量

torch.full((5,5),100) 创建每个值为100的五乘五张量

torch.zeros_like 根据传入的张量形状创建全零张量

torch.ones_like 根据传入的张量形状创建全一张量

复制代码
import torch

# 全零张量
def f01():
    out=torch.zeros(5,5)
    print(out,out.shape,out.dtype)

# 全1张量
def f02():
    out=torch.ones(5,5)
    print(out,out.shape,out.dtype)

# 指定值张量
def f03():
    out=torch.full((5,5),100)
    print(out,out.shape,out.dtype)

# like
def f04():
    # 形状
    tem=torch.rand(2,5)
    out=torch.zeros_like(tem)
    print(out,out.shape,out.dtype)
    print('-'*100)
    out2=torch.ones_like(tem)
    print(out2,out2.shape,out2.dtype)
    print('-' * 100)
    out3=torch.full_like(tem,50)
    print(out3,out3.shape,out3.dtype)


if __name__ == '__main__':
    # f01()
    # f02()
    # f03()
    f04()

张量元素的转化:

data.type(torch.float64)

data.half()/double()/float()/short()/int()/long()

复制代码
import torch
# data.type(torch.类型)  进行转化

def f01():
    out=torch.rand(3,3)
    print(out,out.dtype)
    out2=out.type(torch.float64)
    print(out2,out2.dtype)
    out3=out2.type(torch.int64)
    print(out3,out3.dtype)


def f02():
    out=torch.rand(3,3)
    print(out.dtype)
    print(out.half().dtype)
    print(out.double().dtype)
    print(out.float().dtype)
    print(out.short().dtype)
    print(out.int().dtype)
    print(out.long().dtype)

if __name__ == '__main__':
    # f01()
    f02()

张量的类型转换

张量转化为numpy数组:

Tensor.numpy 浅拷贝

copy()深拷贝

复制代码
# 张量转化为numpy数组
def f01():
    tem=torch.randint(0,10,(3,5))
    out2=tem.numpy().copy()
    tem[0,0]=99
    print(tem,type(tem))
    out=tem.numpy()
    print(out,type(out))
    print(out2,type(out2))

获取数字 item()

复制代码
# 获取数值
def f03():
    tem=torch.randn(1)
    print(tem.item(),type(tem),type(tem.item()))

numpy数组转化为张量:

torch_form_numpy()浅拷贝 clone()深拷贝

torch.tensor(data)深拷贝

复制代码
# 数组转化为张量
def f02():
    tem=np.array([1,4,7,10])
    print(tem,type(tem))

    out3=torch.from_numpy(tem).clone()
    print(out3,type(out3))

    tem[0]=5

    # 转化1
    out=torch.tensor(tem)
    print(out,type(out))
    # 转化2
    out2=torch.from_numpy(tem)
    print(out2,type(out2))

张量的基本运算:

加减乘除 形状相同

add,sub,mul,div,neg

add_,sub_,mul_,div_,neg_的会修改原数据

**点乘:**相同形状的张量对应位置进行乘法

矩阵的乘法 @ 或者是 torch.matmul 第一个矩阵的列=第二个矩阵的行

复制代码
import torch
# 基本运算 加减乘除,取反
def f01():
    out=torch.tensor(1.)
    out2=torch.tensor(2.)
    # 运算符
    print(out+out2)
    print(out-out2)
    print(out*out2)
    print(out/out2)
    # api
    print(out.add(out2))
    # 取反
    d=torch.rand(3,4)
    print(d)
    print(d.neg())

# 点乘
def f02():
    a=torch.randint(0,5,(2,3))
    print(a)
    b=torch.randint(6,10,(2,3))
    print(b)
    print('----------------------')
    print(a*b)
    print(a.mul(b))

# 叉乘
def f03():
    a = torch.randint(0, 5, (3, 2))
    print(a)
    b = torch.randint(6, 10, (2,3))
    print(b)
    # print(a@b)
    print(a.matmul(b))

if __name__ == '__main__':
    # f01()
    # f02()
    f03()

常见的计算函数

复制代码
import torch

def f01():
    # 创建张量
    # 随机种子
    torch.manual_seed(1)
    emp=torch.randint(1,10,(3,2),dtype=torch.float64)
    print(emp)
    # 均值,dim=1为行的均值
    print(f'行的均值为{emp.mean(dim=1)}')
    # dim=0为列的均值
    print(f'列的均值为{emp.mean(dim=0)}')
    # 求和
    print(f'行的求和为{emp.sum(dim=1)}')
    print(f'列的求和为{emp.sum(dim=0)}')
    # 极大值极小值
    print(f'行的极大值为{emp.max(dim=1)}')
    print(f'列的极大值为{emp.max(dim=0)}')
    # 极小值
    print(f'行的极小值为{emp.min(dim=1)}')
    print(f'列的极小值为{emp.min(dim=0)}')
    # 平方根
    print(f'emp的平方根是{emp.sqrt()}')
    # 幂运算
    print(f'emp的幂运算为{emp.pow(2)}')
    # 指数运算
    print(f'emp的指数运算为{emp.exp()}')
    # 对数运算
    print(f'对数运算log为{emp.log()}')
    print(f'对数运算log2为{emp.log2()}')
    print(f'对数运算log10为{emp.log10()}')

if __name__ == '__main__':
    f01()

张量的索引和多维索引操作

复制代码
import torch

torch.manual_seed(12)
emp=torch.randint(1,10,(4,5))
# 行列倒叙
print(emp)
# dims=0  为只反转行  1 只反转列  0,1都反转
print(torch.flip(emp,[0,1]))
#
# print(emp)
# print(f'行索引{emp[1]}')
# print(f'列索引{emp[:,0]}')
# # 列表索引返回(0,1)和(1,2)两个位置的元素
# print(f'(0,1)的元素{emp[0,1]}')
# print(f'(1,2)的元素{emp[1,2]}')
# # 返回两行两列的元素
# print(f'返回第0,1两行和1,2两列的元素为{emp[0:2,1:3]}')
# # 返回范围索引的内容
# print(f'前三行的前两列数据{emp[0:3,0:2]}')
# print(f'第二行到最后的前两列的数据{emp[1:,0:2]}')
# # 布尔索引
# print(f'第三列数值大于5的完整行数据{emp[emp[:,2]>5]}')
# print(f'第二行数值大于5的元素对应的完整列数据{emp[:,emp[1,:]>5]}')
# 多维索引,创建一个  n  h  w 的矩阵
out=torch.randint(0,10,(3,4,5))
print(out)
print(f'获取0轴上的第一个元素{out[0]}')
print(f'获取1轴上的第一个元素{out[:,0,:]}')
print(f'获取2轴上的第一个元素{out[:,:,0]}')

张量形状的改变: 都是浅拷贝

reshape: 保证张量数据不变的前提下改变数据的维度,将其转化为指定维度 -1:会自动计算剩下维度

squeeze:删除形状为1的维度

unsqueeze:在指定位置添加形状为的维度

transpose:只能交换两个维度的位置

permute:可以交换多个维度的位置

view:改变维度但是内存要连续

is_contiguous:判断内存是否连续 返回True/False

contiguous:强制内存连续

API:

复制代码
import torch
# reshape:修改形状
a=torch.randn([2,3,4])
print(a.shape)
print(a.reshape(2,-1).shape)
print()

#squeeze删除维度为一的内容
a=torch.randn([1,2,3,4,1,1,2,3])
print(a.shape)
print(a.squeeze().shape)
print()

# unsqueeze 扩维,在对应位置上添加形状为1的维度
b=torch.randn([2,3,4])
out=b.unsqueeze(0)
print(out.shape)
out2=b.unsqueeze(1)
print(out2.shape)
print()

# transpose 维度交换,只能交换两个维度
a=torch.randn([2,3,4])
print(a.shape)
print(a.transpose(0,1).shape)
print(a.transpose(0,2).shape)
print()

#permute 可以交换多个张量,有几个轴填写几个数字
b=torch.randn([2,3,4,5])
print(b.shape)
print(b.permute(0,3,2,1).shape)
print(b.permute(3,1,2,0).shape)
print()

# 使用view进行改变维度
a=torch.randn([2,3,4])
print(a.shape)
print(a.view(2,-1).shape)
a=a.transpose(0,1)
print(a.is_contiguous())
a=a.contiguous()
print(a.is_contiguous())
print(a.view(3,-1).shape)

张量的拼接操作

torch.cat() :将多个张量根据指定的维度进行拼接,不改变维度数(维度的总个数不变)除拼接以外的维度要相同

torch.stack():会在一个新的维度上连接一系列张量,这会增加一个新维度,并且所有输入的张量必须完全相同 新增加维度的大小为堆叠张量的数量 形状必须相同

复制代码
import torch

# 张量的拼接,除了拼接的维度可以不同,其他的维度要相同
a=torch.randn(2,3,4)
b=torch.randn(2,3,5)
print(torch.cat([a,b],2).shape)
# print(torch.cat([a,b],1).shape) 报错因为剩下的维度的形状不同

print()
# 张量的堆叠
a=torch.randn(5,4)
b=torch.randn(5,4)
c=torch.randn(5,4)
print(torch.stack([a,b],0).shape)
print(torch.stack([a,b],1).shape)
print(torch.stack([a,b],2).shape)
print(torch.stack([a,b,c],1).shape)

自动微分模块:

对损失函数求导,结合自动微分模块,更新权重参数w和b

backward方法 grad属性来完成梯度的计算和访问 使用的算法是反向传播

反向传递过程:基于预测值和真实的得出误差,得到损失函数,对损失函数求导得到梯度,通过梯度的更新来反向更新权重和偏置

单梯度下降:

requires_grad=True,启动了自动微分模块

复制代码
import torch

# 权重
w=torch.tensor([10,20],requires_grad=True,dtype=torch.float32)
# 梯度
loss=2*w**2

# 自动微分
loss.sum().backward()
# 自动计算梯度
print(f'原梯度值为{w.data},学习率为{0.01},更新后的梯度为{w.grad},下一个权重为{w.data-0.01*w.grad}')

多梯度下降:

梯度会累加所以每次需要对梯度进行清零处理

复制代码
import torch

# 权重
w=torch.tensor([10],requires_grad=True,dtype=torch.float32)
# 多轮梯度
epochs=500
for epoch in range(epochs):
    # 损失函数
    loss = w**2+20
    # 梯度清零
    if w.grad is not None:
        w.grad.zero_()
    # 自动微分
    loss.sum().backward()
    # 自动计算梯度
    print(f'当前轮次为{epoch+1},当前权重为{w.data},学习率为{0.01},更新后的梯度为{w.grad},下一个权重为{w.data-0.01*w.grad}')
    # 更新梯度
    w.data=w.data-0.01*w.grad

梯度基本运算:

Pytorch不支持向量张量对向量张量的求导,只支持标量张量对标量张量的求导

所以如果w是张量y必须是标量才能进行求导 loss.sum().backward() 将向量转化为张量进行计算

复制代码
import torch
# 记录初始的权重
# 参数 初始值    是否自动微分,这个参数为True的时候就可以求导   参数的类型
w=torch.tensor(10,requires_grad=True,dtype=torch.float)
# 定义损失函数变量
loss=2*w**2   # 求梯度(求导)  为  4w
# 查看梯度函数的类型,即曲线函数类型
# print(type(loss.grad_fn))
#
# 计算梯度=损失函数的导数,计算完毕之后,会记录到w.grad属性中
loss.backward()
# loss.sum().backward()   保证损失函数一定是一个标量,进行求导
#
# 就是求导得出来的梯度
print(w.grad)
# 带入权重更新公式: w新=w旧 - 学习率*梯度
w.data=w.data-0.01*w.grad
print(w.data)

梯度下降求最优解:

只有反向传播的时候才有梯度 先对梯度进行判断是否为空,为空进行梯度清零

复制代码
import torch
# 计算梯度下降最优解就是损失函数最小,
# 定义初始权重w=10
# 参数   初始权重值     进行自动微分(求导)   数据类型
w = torch.tensor(10, requires_grad=True, dtype=torch.float32)
# 损失函数为loss=w**2+20
loss=w**2+20
# 定义学习率为0.01
# 输出初始值
print(f'初始权重为{w},(0.01*w.grad):无, loss:{loss}')
# 迭代1000次求最优解
for  i  in range(1,460):
    # 需要更新损失函数
    loss = w ** 2 + 20
    # 先判断梯度是否为None
    if w.grad is not None:
        # 不为空就需要进行梯度清空
        w.grad.zero_()
    # 进行自动微分和反向传播
    loss.sum().backward()
    # 更新权重
    w.data=w.data-0.01*w.grad
    # print(f'第{i}次,权重的初始值为{w.data} (0.01*w.grad):{0.01*w.grad}),loss:{loss}')
    print(f'第{i}次,权重的初始值为{w:.5f} (0.01*w.grad):{(0.01*w.grad):.5f}),loss:{loss:.5f}')

# 最终结果
print(f'最终结果为:权重:{w:.5f},梯度:{w.grad:.5f},loss:{loss:.5f}')

梯度计算的注意点:不能将自动微分的张量转化为numpy数组会发生报错,使用detch()方法将张量进行拷贝

复制代码
import torch
import numpy as np
# 创建张量
a=torch.tensor([[1,2,3],[4,5,6],[7,8,9]],requires_grad=True,dtype=torch.float32)
# b=a.numpy()
print(type(a))
# print(b,type(b))

a1=a.detach()
print(type(a1))
print(a.requires_grad)
print(a1.requires_grad)
print(type(a1.numpy()))

# 最终版   a1=a.detach().numpy()

自动微分模块的应用:

复制代码
import torch

# 特征矩阵
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
# 创建损失函数对象
loss_fn=torch.nn.MSELoss()
# 使用损失函数
loss=loss_fn(z,y)
print(f'loss:{loss}')
# 进行自动微分
loss.backward()
# 返回更新后的梯度
print(f'更新前的w:{w}')
print(f'更新前的b:{b}')
print(f'更新w的梯度:{w.grad}')
print(f'更新b的梯度:{b.grad}')

综合案例:

1.造数据 封装为张量 将张量转化为张量数据集 再转化为数据迭代器对象 分批获取数据

2,创建回归模型对象

3,创建损失函数

4,创建优化器对象

5,外层遍历轮次,内层遍历每一批次

优化器帮我们自动更新权重和梯度使用step()函数

API:

复制代码
# 导包
import torch
from torch.utils.data import TensorDataset          # 构造数据集对象
from torch.utils.data import DataLoader             # 数据加载器

from torch import nn                                # nn模块中有平方损失函数和假设函数
from torch import optim                             # 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,  # 100个样本
        n_features=1,   # 1个特征
        noise=10,      # 噪声,噪声越大样本点越分散,越小越密集、
        coef=True,      # 返回权重
        bias=14.5,      # 偏置
        random_state=3 # 随机种子
    )
    # 对x,y进行数据类型的转化
    x=torch.tensor(x,dtype=torch.float32)
    y=torch.tensor(y,dtype=torch.float32)
    return x,y,coef


# 定义函数,进行模型的训练
def train_model(x,y,coef):
    # 创建数据集对象
    dataset=TensorDataset(x,y)
    # 创建加载器对象
    # 参数: 数据集对象,每批次的样本数,是否打乱样本
    dataloader=DataLoader(dataset,batch_size=16,shuffle=True)
    # 创建线性模型
    # 参数:   输入的特征数   输出的标签数
    model=nn.Linear(1,1)
    # 创建损失函数对象
    criterion=nn.MSELoss()
    # 创建优化器对象
    # 参数  模型待调整的参数      学习率
    optimizer=optim.SGD(model.parameters(),lr=0.001)
    # 初始化 轮数   每轮的平均损失值 训练总损失值  训练的样本数
    epochs=1000
    loss_list=[]
    tolal_loss=0.0
    tolal_sample=0
    # 循环论数
    for epoch in range(epochs):
        # 计算每轮的每批的损失
        for x_train,y_train in dataloader:
            # 模型的预测
            y_pred=model(x_train)
            # 计算损失
            # 参数    预测值 真实值,
            # 因为训练的数据为100行1列所有生成的预测值也是100行一列所有要把真实值改变形状
            loss=criterion(y_pred,y_train.reshape(-1,1))
            # 计算总损失和样本的批次数
            # 每批次累加损失值
            tolal_loss+=loss.item()
            # 每使用一批进行加一
            tolal_sample+=1
            # 进行梯度清零,反向传播,梯度更新
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            # 将每轮的平均损失加入到列表中
        loss_list.append(tolal_loss / tolal_sample)
        print(f'轮数{epoch+1},平均损失函数为{tolal_loss/tolal_sample}')
    print(f'{epochs}轮的平均损失函数为{loss_list}')
    print(f'权重:{model.weight} 偏置为{model.bias}')

    # 绘制损失曲线
    plt.plot(range(epochs),loss_list)
    plt.title('损失值曲线变化图')
    plt.grid()
    plt.show()
    # 绘制样本点的分布
    plt.scatter(x,y)
    # 9.2 绘制训练模型的预测值(分离梯度并转 numpy)
    y_pred = torch.tensor([(v * model.weight + model.bias).detach().numpy() for v in x])
    # 9.3 计算真实值(确保为数值类型)
    y_true = torch.tensor([(v * coef + 14.5).numpy() if isinstance(v, torch.Tensor) else (v * coef + 14.5) for v in x])

    # 9.4 绘图时,若 x 是张量也需转 numpy
    plt.plot(x.detach().numpy(), y_pred.numpy(), color='red', label='预测值')
    plt.plot(x.detach().numpy(), y_true.numpy(), color='green', label='真实值')
    plt.legend()
    plt.grid()
    plt.show()





if __name__ == '__main__':
    x,y,coef=create_dataset()
    # print(f'x:{x},y:{y},coef:{coef}')
    # print(f'x的形状为:{x.shape},y:{y.shape},coef:{coef}')
    train_model(x,y,coef)
相关推荐
java1234_小锋2 小时前
[免费]基于Python的深度学习豆瓣电影数据可视化+情感分析推荐系统(Flask+Vue+LSTM+scrapy)【论文+源码+SQL脚本】
python·信息可视化·flask·电影数据可视化
齐齐大魔王2 小时前
深度学习系列(二)
人工智能·深度学习
xier_ran2 小时前
深度学习:学习率衰减(Learning Rate Decay)
人工智能·深度学习·机器学习
Francek Chen2 小时前
【CANN】开启AI开发新纪元,释放极致计算效率
人工智能·深度学习·cann·ai开发
CoovallyAIHub2 小时前
结构化数据迎来“ChatGPT时刻”!LimitX:一个模型统一所有表格任务
深度学习·算法·计算机视觉
PieroPc3 小时前
一个基于Python Streamlit sqlite3 的销售单管理系统,提供商品管理、客户管理、销售单管理及打印,和应收对账单等功能
python·oracle·sqlite·streamlit
月下倩影时3 小时前
视觉进阶篇—— PyTorch 安装
人工智能·pytorch·python
ThreeS_tones3 小时前
ppo爬坡代码及解释
人工智能·深度学习
OpenBayes3 小时前
教程上新丨Deepseek-OCR 以极少视觉 token 数在端到端模型中实现 SOTA
人工智能·深度学习·机器学习·ocr·大语言模型·文本处理·deepseek