01.张量的创建

tensor转numpy

使用tensor.numpy函数可以将张量转换为ndarray数组,但是共享内存,可以使用copy函数避免共享

import numpy as np
import torch

#print(torch.tensor(10))

#data_np=np.random.rand(2,3)
#print(torch.tensor(data_np))

#data=torch.tensor([[1,2.],[3,4]])
#print(data)

#print(torch.Tensor(2,3))

#print(torch.ShortTensor(2,3))
#print(torch.LongTensor(2,3))#int64,运用较广泛
#print(torch.FloatTensor(2,3))
#print(torch.DoubleTensor(2,3))

#创建线性张量
#print(torch.arange(1,10,2))#不包含终止值,2为步长
#print(torch.linspace(1,10,10))#10个数,包含终止值

#随机种子设置
#print(torch.rand(2,3))
#seed=torch.random.initial_seed()
#torch.random.manual_seed(seed)
#print(torch.rand(2,3))

#全01张量
data=torch.rand(4,5)
#print(torch.zeros(2,3))
#print(torch.zeros_like(data))
#print(torch.ones(2,3))
#print(torch.ones_like(data))

#print(torch.full((2,3),5))
#print(torch.full_like(data,5))

#元素类型转换
#print(data.long().dtype)
#print(data.float().dtype)
#print(data.double().dtype)
#print(data.short().dtype)
#print(data.int().dtype)
#print(data.type('torch.IntTensor').dtype)
import torch
import numpy as np

# torch.random.manual_seed(2)
#data_tensor=torch.randint(1,10,(2,3))
# print(type(data_tensor))
#
data_numpy=data_tensor.numpy().copy()
# print(type(data_numpy))
#
# data_numpy[0][0]=100
# print(data_tensor)
# print(data_numpy)

# data_numpy1=np.array([1,2,3])
data_tensor=torch.from_numpy(data_numpy.copy())
data_tensor=torch.Tensor(data_numpy)
# data_tensor[0]=100
# print(data_numpy)
# print(data_tensor)

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

02张量的基本运算

import torch

# torch.random.manual_seed(22)
# data1=torch.randint(0,10,[2,3])
# print(data1)
#
# # print(data.add(10))
# # print(data.sub(10))
# # print(data.mul(10))
# # print(data.div(10))
# # print(data.neg()
# # #add_等带下划线的版本会修改原数据
#
# torch.random.manual_seed(22)
# data2=torch.randint(0,10,[2,3])
# print(data2)
#
# print(torch.mul(data1,data2))#点乘
#
# print(data1*data2)

#矩阵乘法
torch.random.manual_seed(22)
data1=torch.randint(0,10,[3,4])
print(data1)

torch.random.manual_seed(22)
data2=torch.randint(0,10,[4,5])
print(data2)

print(data1 @ data2)
print(torch.matmul(data1,data2))

03张量的运算函数

import torch
torch.random.manual_seed(22)
data=torch.randn([3,4])
print(data)

print(data.mean)
print(data.mean(dim=0))
print(data.mean(dim=1))

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

print(data.sqrt())
print(torch.pow(data,2))
print(torch.pow(2,data))
print(torch.exp())

print(torch.log(data))
print(torch.log10(data))
print(torch.log2(data))

04张量的形状操作

1.reshape函数可以在保证张量数据不变的前提下改变数据的维度

2.squeeze和unsqueeze函数可以用来增加或减少维度

3.transpose函数可以实现交换张量形状的指定维度,permute可以一次交换更多的维度

4.view函数也可以用于修改张量的形状,但他要求被转换的张量内存必须连续,所以一般配合contiguous函数使用

5.cat函数可以将张量按照指定的维度拼接起来,其他维度要求相同

import torch

torch.manual_seed(22)
data1=torch.randint(0,10,[2,3])
# print(data1.shape)
# print(data1.size(2))
# print(data1.reshape(4,-1,3).shape)

#unsqueeeze与squeeze增加或减少维度
# data2=data1.unsqueeze(dim=1).unsqueeze(dim=-1)
# print(data2.shape)
# print(data2.squeeze().shape)

#transpose与permute转置
# data2=torch.transpose(data1,0,2)
# data3=torch.transpose(data2,1,2)
# data4=torch.transpose(data3,2,3)
# print(data4.shape)
# print(data1.permute(0,2,3,1).shape)
# print(torch.permute(data1,[0,2,3,1]).shape)

print(data1.is_contiguous())
print(data1.view(3,-1).shape)
data2=torch.transpose(data1,0,1)
print(data2.is_contiguous())
data3=data2.contiguous()
print(data3.view(3,-1).shape)

if data1.is_contiguous():
    data1.view(-1)
else:
    data1.contiguous().view(-1)

05自动微分

import torch
#数据 特征+目标
# x=torch.tensor(5)
# y=torch.tensor(0.)
x=torch.ones(2,5)
y=torch.zeros(2,3)
#参数 权值+偏置
# w=torch.tensor(1,requires_grad=True,dtype=torch.float32)
# b=torch.tensor(3,requires_grad=True,dtype=torch.float32)
w=torch.randn(5,3,requires_grad=True)
b=torch.randn(3,requires_grad=True)
#预测
# z=w*x+b
z=torch.matmul(x,w)+b
#损失
loss=torch.nn.MSELoss()
loss=loss(z,y)
#微分
loss.backward()
#梯度
print(w.grad)
print(b.grad)

06线性回归案例

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

x,y,coef=make_regression(n_samples=100,n_features=1,noise=10,coef=True)
'''
n_samples=100:生成 100 组样本
n_features=1:每个样本只有1 个自变量 X(一元线性)
noise=10:加入高斯噪声,数值越大散点越乱
coef=True:返回真实权重系数 coef(默认不返回)'''
# plt.scatter(x,y)#画散点图
y_true=[coef*v+1.5 for v in x]
plt.plot(x,y_true)#画连续直线
plt.show()

#数据获取
x=torch.tensor(x)
y=torch.tensor(y)
dataset=TensorDataset(x,y)#张量数据集容器,作用:把特征 x 和标签 y 一一配对打包,dataset[i] = (x[i], y[i]),取第 i 组数据。
dataloader=DataLoader( dataset=dataset,batch_size=8,shuffle=True,drop_last=False)#分批迭代器,用来分批次取数据,每次遍历全部数据前打乱样本顺序(训练防止过拟合)

#模型构建
model=torch.nn.Linear(1,1)#输入特征数为1,输出特征数为1的线性模型

#模型训练
#损失函数
loss=torch.nn.MSELoss()#均方误差损失函数,适用于回归问题
#优化器
optimizer=torch.optim.SGD(model.parameters(),lr=0.001)
#遍历
loss_num=[]
for i in range(100):
    sum=0
    sample=0
    #获取batch数据
    for x,y in dataloader:
        #模型预测
        x=x.float()
        y_pred=model(x)#y_pred:Linear(1,1)输出 → [batch, 1] → (2,1)
        #损失计算
        l=loss(y_pred,y.reshape(-1,1))#y的形状为torch.Size([2]),需要调整为torch.Size([2,1]),与y_pred的形状一致
        sum+=l.item()
        sample=len(y)#取出当前这一批数据的样本个数2
        #梯度清零
        optimizer.zero_grad()
        #自动微分
        l.backward()
        #参数更新
        optimizer.step()
    loss_num.append(sum/sample)

#画损失曲线
plt.plot(range(100),loss_num)
plt.grid()
plt.show()

#绘制拟合直线
x=torch.linspace(x.min(),x.max(),1000)# 从原始X最小值~最大值,均匀生成1000个连续x点
#linspace(a,b,N):在[min,max]之间均分 1000 个浮点数据,用来画光滑直线。
w=model.weight.detach().item()#取出权重值,detach切断梯度,item()取出数值
b=model.bias.detach().item()#取出偏置值,detach切断梯度,item()取出数值
y1=torch.tensor([v*w+b for v in x])
y2=torch.tensor([v*coef+1.5 for v in x])
plt.plot(x,y1,label='train')
plt.plot(x,y2,label='true')
plt.grid()#显示背景网格
plt.legend()#在图片空白处生成图例,区分训练拟合线、真实基准线;
plt.show()

07常见的激活函数-sigmoid 激活函数

  • sigmoid 函数可以将任意的输入映射到

    之间,当输入的值大致在

    或者

    时,意味着输入任何值得到的激活值都是差不多的,这样会丢失部分的信息。比如:输入 100 和输出 10000 经过 sigmoid 的激活值几乎都是等于 1 的,但是输入的数据之间相差 100 倍的信息就丢失了。
  • 对于 sigmoid 函数而言,输入值在

    之间输出值才会有明显差异,输入值在

    之间才会有比较好的效果。
  • 通过上述导数图像,我们发现导数数值范围是

    ,当输入

    或者

    时,sigmoid 激活函数图像的导数接近为 0,此时网络参数将更新极其缓慢,或者无法更新。
  • 一般来说,sigmoid 网络在 5 层之内就会产生梯度消失现象。而且,该激活函数并不是以 0 为中心的,所以在实践中这种激活函数使用的很少。sigmoid函数一般只用于二分类的输出层。

import torch
import matplotlib.pyplot as plt

x = torch.linspace(-20, 20, 1000)
y = torch.sigmoid(x)
plt.plot(x, y)
plt.grid()
plt.show()

#导函数
x=torch.linspace(-20,20,1000,requires_grad=True)
torch.sigmoid( x).sum().backward()#sum():把所有张量元素求和,把多维张量压缩成单个标量(一个数字)
#PyTorch 规定:只有标量才能直接调用.backward()做自动求导
plt.plot(x.detach(), x.grad)
plt.grid()
plt.show()
'''
完整训练一轮顺序
前向传播:
x→预测→算 loss
反向传播:
loss.backward()求梯度
优化器:
opt.step() w=w−lr×grad 更新参数
 '''

08常见的激活函数 -tanh 激活函数

  • Tanh 函数将输入映射到 (−1,1) 之间,图像以 0 为中心,在 0 点对称,当输入大概<−3或者>3时将被映射为 -1 或者 1。其导数值范围 (0,1),当输入的值大概<−3或者>3时,其导数近似 0。
  • 与 Sigmoid 相比,它是以 0 为中心的,且梯度相对于 sigmoid 大,使得其收敛速度要比 Sigmoid 快,减少迭代次数。然而,从图中可以看出,Tanh 两侧的导数也为 0,同样会造成梯度消失。
  • 若使用时可在隐藏层使用 tanh 函数,在输出层使用 sigmoid 函数。

09常用的激活函数 - ReLU 激活函数

  • ReLU 激活函数将小于 0 的值映射为 0,而大于 0 的值则保持不变,它更加重视正信号,而忽略负信号,这种激活函数运算更为简单,能够提高模型的训练效率。
  • 当x<0时,ReLU 导数为 0,而当x>0时,则不存在饱和问题。所以,ReLU 能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。然而,随着训练的推进,部分输入会落入小于 0 区域,导致对应权重无法更新。这种现象被称为 “神经元死亡”。
  • ReLU 是目前最常用的激活函数。与 sigmoid 相比,RELU 的优势是: 采用 sigmoid 函数,计算量大(指数运算),反向传播求误差梯度时,计算量相对大,而采用 Relu 激活函数,整个过程的计算量节省很多。sigmoid 函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。Relu 会使一部分神经元的输出为 0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

10常用的激活函数-SoftMax激活函数

softmax就是将网络输出的logits通过softmax函数,就映射成为(0,1)的值,而这些值的累加和为1(满足概率的性质),理解成概率,选取概率最大(也就是值对应最大的)节点,作为我们的预测目标类别。

激活函数的选择方法

激活函数的作用:向神经网络中添加非线性因素

对于隐藏层:

  1. 优先选择 ReLU 激活函数
  1. 如果 ReLu 效果不好,那么尝试其他激活,如 Leaky ReLu 等。
  1. 如果你使用了 ReLU,需要注意一下 Dead ReLU 问题,避免出现大的梯度从而导致过多的神经元死亡。
  1. 少使用 sigmoid 激活函数,可以尝试使用 tanh 激活函数

对于输出层:

  1. 二分类问题选择 sigmoid 激活函数
  1. 多分类问题选择 softmax 激活函数
  1. 回归问题选择 identity 激活函数

11参数初始化

初始化方法的选择

一般我们在使用PyTorch构建网络模型时,每个网络层的参数都有默认的初始化方法,优先选择kaming的初始

化,xavier初始化方式。

均匀分布初始化

权重参数初始化从区间均匀随机取值。即在(-1/d1/2,1/d1/2)均匀分布中生成当前神经元的权重,其中d为每个神经元的输入数量

正态分布初始化

随机初始化从均值为0,标准差是1的高斯分布中取样,使用一些很小的值对参数W进行初始化

全0初始化

将神经网络中的所有权重参数初始化为0

全1初始化

将神经网络中的所有权重参数初始化为1.

固定值初始化

将神经网络中的所有权重参数初始化为某个固定值.

kaiming初始化,也叫做HE初始化

HE初始化分为正态分布的HE初始化、均匀分布的HE初始化.

正态化的he初始化

stddev = sqrt(2/fan_in)

均匀分布的he初始化

它从[-limit,limit]中的均匀分布中抽取样本,limit是sqrt(6/fan_in)

fan_in输入神经元的个数

xavier初始化,也叫做Glorot初始化

该方法也有两种,一种是正态分布的xavier初始化、一种是均匀分布的xavier初始化

正态化的Xavier初始化

stddev = sqrt(2/ (fan_in + fan_out))

均匀分布的Xavier初始化

[-limit, limit]中的均匀分布中抽样本, limit 是sqrt(6/(fan_in +fan_out)

fan_in是输入神经元的个数,fan_out是输出的神经元个数

12模型构建

1.神经网络的搭建方法

定义继承自nn.Module的模型类

在_init_方法中定义网络中的层结构

在forward方法中定义数据传输方式

2.网络参数量的统计方法

统计每一层中的权重w和偏置b的数量

import torch
from torch import nn
from torchsummary import summary

class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear1=nn.Linear(3,3)
        nn.init.kaiming_normal_(self.linear1.weight)
        self.linear2=nn.Linear(3,2)
        nn.init.xavier_normal_(self.linear2.weight)
        self.out=nn.Linear(2,2)
        nn.init.uniform_(self.out.weight)

    def forward(self,x):
        x_layer1=self.linear1(x)
        x_layer1=torch.sigmoid(x_layer1)
        x_layer2=self.linear2(x_layer1)
        x_layer2=torch.relu(x_layer2)
        out=self.out(x_layer2)
        out=torch.softmax(out,dim=-1)#永远在最后一维做softmax,适配各种形状的分类输出,该维度上所有数字 → 转为概率
        return out



if __name__=="__main__":
    my_model=model()
    x=torch.randn(10,3)
    out=my_model(x)
    print(out.shape)
    summary(my_model,(3,),batch_size=10)
    for name,parameters in my_model.named_parameters():
        print(name)
        print(parameters)

神经网络的优缺点

1.优点

精度高,性能优于其他的机器学习方法,甚至在某些领域超过了人类

可以近似任意的非线性函数随之计算机硬件的发展,

近年来在学界和业界受到了热捧,有大量的框架和库可供调。

2.缺点

黑箱,很难解释模型是怎么工作的

训练时间长,需要大量的计算力

网络结构复杂,需要调整超参数

小数据集上表现不佳,容易发生过拟合

13分类任务的损失函数

多分类损失函数——交叉熵

损失函数是用来衡量模型参数的质量的函数

在多分类任务通常使用softmax将Iogits转换为概率的形式,所以多分类的交叉熵损失也叫做softmax损失,它的计算方法是:

其中:

1.y是样本x属于某一个类别的真实概率

2.而f(x)是样本属于某一类别的预测分数

3.S是softmax激活函数,将属于某一类别的预测分数转换成概率

4.L用来衡量真实值y和预测值f(x)之间差异性的损失结果

import torch
import torch.nn as nn

#y_true=torch.tensor([0,1,2],dtype=torch.int64)
y_true=torch.tensor([[1,0,0],[0,1,0],[0,0,1]],dtype=torch.float32)
y_pred=torch.tensor([[8,9,10],[12,4,6],[3,8,6]],dtype=torch.float32)
loss_fn=nn.CrossEntropyLoss()
print(loss_fn(y_pred,y_true))

二分类任务损失函数——交叉熵

在处理二分类任务时,我们不再使用softmax激活函数,而是使用sigmoid激活函数,那损失函数也相应的进行调整,使用二分类的交叉熵损失函数:

其中:

1.y是样本x属于某一个类别的真实概率

2.而y^是样本属于某一类别的预测概率

3.L用来衡量真实值y与预测值y^之间差异性的损失结果。

在pytorch中实现时使用nn.BCELoss(),如下所示:

y_true=torch.tensor([0,1,0,1],dtype=torch.float32)
y_pred=torch.tensor([0.1,0.9,0.2,0.8],dtype=torch.float32)
loss_fn=nn.BCELoss()
print(loss_fn(y_pred,y_true))

14.回归任务的损失函数

MAE损失函数

MSE损失函数

smooth L1损失函数

15梯度下降算法

梯度下降法是一种寻找使损失函数最小化的方法。从数学上的角度来看,梯度的方向是函数增长速度最快的方向,那么梯度的反方向就是函数减少最快的方向,所以有:

其中,n是学习率,如果学习率太小,那么每次训练之后得到的效果都太小,增大训练的时间成本。如果,学习率太大,那就有可能直接跳过最优解,进入无限的训练中。解决的方法就是,学习率也需要随着训练的进行而变化。

在进行模型训练时,有三个基础的概念:

1.Epoch:使用全部数据对模型进行以此完整训练,训练轮次

2.Batch_size:使用训练集中的小部分样本对模型权重进行以此反向传播的参数更新,每次训练每批次样本数量3.Iteration:使用一个Batch数据对模型进行一次参数更新的过程

假设数据集有50000个训练样本,现在选择Batch Size=256对模型进行训练。每个Epoch要训练的图片数量:50000

训练集具有的Batch个数:50000/256+1=196

每个Epoch具有的Iteration个数:196

10个Epoch具有的Iteration 个数:1960

前向传播和反向传播是什么?

前向传播:指的是数据输入的神经网络中,逐层向前传输,一直到运算到输出层为止。

反向传播(Back Propagation):利用损失函数ERROR,从后往前,结合梯度下降算法,依次求各个参数的偏导,并进行参数更新

梯度下降优化算法中,可能会碰到以下情况:

1.碰到平缓区域,梯度值较小,参数优化变慢

2.碰到“鞍点”,梯度为0,参数无法优化

3.碰到局部最小值,参数不是最优

对于这些问题,出现了一些对梯度下降算法的优化方法,例如:Momentum、AdaGrad、RMSprop、Adam等

16梯度下降的优化方法-指数加权平均

指数移动加权平均则是参考各数值,并且各数值的权重都不同,距离越远的数字对平均数计算的贡献就越小(权重较小),距离越近则对平均数的计算贡献就越大(权重越大)。计算公式可以用下面的式子来表示:

import torch
import matplotlib.pyplot as plt

t=torch.randint(0,40,[30])
days=torch.arange(0,30)
plt.plot(days,t)
plt.scatter(days,t)
plt.show()

t_avg=[]
beta=0.7
for i,temp in enumerate(t):
    if i==0:
        t_avg.append(temp)
        continue
    t2=beta*t_avg[i-1]+(1-beta)*temp
    t_avg.append(t2)
plt.plot(days,t_avg)
plt.scatter(days,t_avg)
plt.show()

梯度下降的优化方法-动量算法Momentum

梯度计算公式:Dt=β*St-1+(1-β)*Wt

1.St-1表示历史梯度移动加权平均值

2.Wt表示当前时刻的梯度值

3.Dt为当前时刻的指数加权平均梯度值

4.β为权重系数

假设:权重β为0.9,例如:

第一次梯度值:s1=d1=w1

第二次梯度值:d2=s2=0.9*s1+w2*0.1

第三次梯度值:d3=s3=0.9*s2+w3*0.1

第四次梯度值:d4=s4=0.9*s3+W4*0.1

梯度下降公式中梯度的计算,就不再是当前时刻t的梯度值,而是历史梯度值的指数移动加权平均值。公式修改为:

Wt+1=Wt-a*Dt

当处于鞍点位置时,由于当前的梯度为0,参数无法更新。但是Momentum动量梯度下降算法已经在先前积累了一些梯度值,很有可能使得跨过鞍点。

由于mini-batch普通的梯度下降算法,每次选取少数的样本梯度确定前进方向,可能会出现震荡,使得训练时间变长。Momentum使用移动加权平均,平滑了梯度的变化,使得前进方向更加平缓,有利于加快训练过程。

17梯度下降的优化方法-AdaGrad

18梯度下降的优化方法-RMSProp

19学习率调整的策略

1.等间隔衰减

lr_scheduler. StepLR(optimizer,step_size,gamma=0.1)

参数:

step_size:调整间隔数=50

gammna:调整系数=0.5

调整方式:lr=lr*gamma

2.指定间隔衰减

lr_scheduler. MultiStepLR(optimizer, milestones,gamma=0.1)

主要参数:

milestones:设定调整轮次:[50,125,160]

gamma:调整系数

调整方式:lr= lr*gamma

3.指数衰减

lr_scheduler. ExponentialLR (optimizer, gamma)

主要参数:

gamma:指数的底

调整方式: lr= lr* gamma epoch

import torch
import matplotlib.pyplot as plt

#网络数据初始化
epochs=200
lr0=0.1
iter=100
x=torch.tensor([1.0])
w=torch.tensor([1.0],requires_grad=True)
y=torch.tensor([1.0])
#优化器
optimizer=torch.optim.SGD([w],lr=lr0,momentum=0.9)
#学习率调度器
#scheduler_lr=torch.optim.lr_scheduler.StepLR(optimizer,step_size=20,gamma=0.8)
#scheduler_lr=torch.optim.lr_scheduler.MultiStepLR(optimizer,milestones=[20,50,150,180],gamma=0.8)
scheduler_lr=torch.optim.lr_scheduler.ExponentialLR(optimizer,gamma=0.9)
#遍历轮次
epoch_list=[]
lr_list=[]
for epoch in range(epochs):
    lr_list.append(scheduler_lr.get_last_lr())#获取当前最新学习率,并存入列表
    epoch_list.append(epoch)
    #迭代次数
    for i in range(iter):
        # 计算损失
        loss=(w*x-y)**2*0.5
        # 反向传播
        loss.backward()
        # 更新参数
        optimizer.step()
        optimizer.zero_grad()
    scheduler_lr.step()

plt.plot(epoch_list,lr_list)
plt.grid()
plt.show()

20正则化方法

在设计机器学习算法时希望在新样本上的泛化能力强。许多机器学习算法都采用相关的策略来减小测试误差,这些策略被统称为正则化。

神经网络的强大的表示能力经常遇到过拟合,所以需要使用不同形式的正则化策略。

目前在深度学习中使用较多的策略有范数惩罚,DropOut,特殊的网络层等

1.Dropout正则化

在练神经网络中模型参数较多,在数据量不足的情况下,很容易过拟合。Dropout(随机失活)是一个简单有效的正则化方法。

在训练过程中,Dropout的实现是让神经元以超参数p的概率停止工作或者激活被置为0,未被置为0的进行缩放,缩放比例为1/(1-p)。训练过程可以认为是对完整的神经网络的一些子集进行训练,每次基于输入数据只更新子网络的参数。

在测试过程中,随机失活不起作用。

import torch
import torch.nn as nn

data=torch.randn([1,4])
layer=nn.Linear(4,5)
y=layer(data)
print(y)

dropout=nn.Dropout(p=0.75)
y_dropout=dropout(y)
print(y_dropout)

2.批量归一化(BN层)

多用于计算机视觉领域

1、正则化的作用

缓解过拟合

2、随机失活DropOut策略

让神经元以超参数p的概率停止工作或者激活被置为0

3、BN层是什么?

对数据标准化,再对数据重构(缩放+平移)

21.手机价格分类案例

import pandas as pd
from sklearn.model_selection import train_test_split
import torch
from torch import nn
from torch.utils.data import TensorDataset, DataLoader
from torchsummary import torchsummary


#读取数据
data= pd.read_csv("data/data.csv")
x=data.iloc[:,:-1]#iloc 按位置索引(整数位置)选取数据。
#:(行位置)表示选取所有行。
#1:-1(列位置)表示从第 2 列(索引 1)开始,一直到倒数第 2 列(索引 -2)结束(不包含最后一列)。也就是说排除了第 1 列(索引 0)和最后一列(索引 -1)。
y=data.iloc[:,-1]#选取所有行、最后一列(索引 -1)

#将数据拆分为训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
#它把 x 和 y 按相同的索引顺序随机拆分成训练集和测试集,测试集占 20%
x_train=torch.tensor(x_train.values, dtype=torch.float32)
y_train=torch.tensor(y_train.values, dtype=torch.int64)
x_test=torch.tensor(x_test.values, dtype=torch.float32)
y_test=torch.tensor(y_test.values, dtype=torch.int64)

#封装 数据集
train_dataset=TensorDataset(x_train,y_train)
test_dataset=TensorDataset(x_test,y_test)

#构建数据迭代器
train_dataloader=DataLoader(train_dataset,batch_size=8,shuffle=True)
test_dataloader=DataLoader(test_dataset,batch_size=8,shuffle=False)

#创建模型
class PhoneModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1=torch.nn.Linear(20,64)
        self.layer2=torch.nn.Linear(64,128)
        self.layer3=torch.nn.Linear(128,4)
        self.dropout=torch.nn.Dropout(0.3)

    def forward(self,x):
        x=self.layer1(x)
        x=self.dropout(x)
        x=torch.relu(x)
        x=self.layer2(x)
        x=self.dropout(x)
        x=torch.relu(x)
        out=self.layer3(x)
        return out

def train():
    phone_model = PhoneModel()
    cri=nn.CrossEntropyLoss()
    optimizer=torch.optim.SGD(phone_model.parameters(),lr=0.01)
    epoches=20
    for epoch in range(epoches):
        loss_sum=0
        sample=0
        for x,y in train_dataloader:
            y_predict=phone_model(x)
            loss=cri(y_predict,y)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            loss_sum+=loss.item()
            sample+=1
        print(f"Epoch: {epoch}, Loss: {loss_sum/sample}")
    torch.save(phone_model.state_dict(),"C:\\artificial\\python\\test\\02神经网络\\data\\phone_model.pth")

def test():
    my_model=PhoneModel()
    my_model.load_state_dict(torch.load("C:\\artificial\\python\\test\\02神经网络\\data\\phone_model.pth"))

    correct=0
    for x,y in test_dataloader:
        y_predict=my_model(x)
        index=torch.argmax(y_predict,dim=1)
        correct+=(index==y).sum()
    acc=correct/len(test_dataloader.dataset)
    print(f"Accuracy: {acc}")


if __name__ == '__main__':
    model=PhoneModel()
    summary=torchsummary.summary(model,(20,),batch_size=10)
    #train()
    test()

22.卷积神经网络

图像是由像素点组成的,每个像素点的取值范围为:【0,255】uint8。彩色图由RGB3个通道组成

卷积神经网络(Convolutional Neural Network)是含有卷积层的神经网络.卷积层的作用就是用来自动学习、提取图像的特征.

CNN网络主要由三部分构成:卷积层、池化层和全连接层构成:

1.卷积层负责提取图像中的局部特征;

2.池化层用来大幅降低参数量级(降维);

3.全连接层用来输出想要的结果。

卷积层

1.卷积运算本质上就是在卷积核和输入数据的局部区域间做点积。

2.通过上面的卷积计算过程,最终的特征图比原始图像小很多,如果想要保持经过卷积后的图像大小不变,可以在原图周围添加 padding来实现.

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np

img_path=(r"C:\artificial\python\test\data\QQ图片20260417232325(2).jpeg")
img = Image.open(img_path)
img = img.resize((640, 640))
img = np.array(img)
img=torch.tensor(img, dtype=torch.float32).permute(2, 0, 1).unsqueeze(0)
print(img.shape)

layer=nn.Conv2d(3,10,(3,5),(2,3),1)
out=layer(img)#[batch, channel, height, width]
print(out.shape)

特征图大小

池化层

池化层(Pooling)降低维度,缩减模型大小,提高计算速度.

池化的分类:最大池化和平均池化

import torch
import torch.nn as nn

# inputs=torch.tensor([[[0,1,2],[3,4,5],[6,7,8]]]).float()
# print(inputs.shape)
inputs=torch.tensor([[[0,1,2],[3,4,5],[6,7,8]], [[10,11,12],[13,14,15],[16,17,18]], [[20,21,22],[23,24,25],[26,27,28]]]).float()
print(inputs.shape)

pooling=nn.MaxPool2d(2,1,0)
print(pooling(inputs))
pooling1=nn.AvgPool2d(2,1,0)
print(pooling1(inputs))

23图像分类案例

import os

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchsummary import summary
from torchvision.datasets import CIFAR10
from torchvision.transforms import ToTensor, Compose
import matplotlib.pyplot as plt
os.environ['TORCHVISION_DATASET_URL'] = 'https://mirrors.tuna.tsinghua.edu.cn/pytorch/datasets/'

#数据获取
train_data=CIFAR10(root="data",train=True,transform=Compose([ToTensor()]),download=True)
test_data=CIFAR10(root="data",train=False,transform=Compose([ToTensor()]),download=True)

# print(train_data.data.shape)
# print(test_data.data.shape)
# print(train_data.classes)
# print(train_data.class_to_idx)
#
# plt.imshow(train_data.data[100])
# print(train_data.targets[100])
# plt.show()

#模型构建
class img_classifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1=nn.Conv2d(3,6,3,1,0)
        self.pooling1=nn.MaxPool2d(2,2,0)
        self.conv2=nn.Conv2d(6,16,3,1,0)
        self.pooling2=nn.MaxPool2d(2,2,0)
        self.layer1=nn.Linear(576,120)
        self.layer2=nn.Linear(120,84)
        self.layer3=nn.Linear(84,10)

    def forward(self,x):
        x=torch.relu(self.conv1(x))
        x=self.pooling1(x)
        x=torch.relu(self.conv2(x))
        x=self.pooling2(x)
        x=torch.reshape(x,[x.size(0),-1])
        x=torch.relu(self.layer1(x))
        x=torch.relu(self.layer2(x))
        x=self.layer3(x)
        return x

img_model=img_classifier()
#
# summary(img_model,(3,32,32),batch_size=1)

#模型训练

def train():
    cri=nn.CrossEntropyLoss ()
    optimizer=torch.optim.Adam(img_model.parameters(),lr=0.001,betas=(0.9,0.999))
    #beta1=0.9:一阶动量,平滑梯度,缓解梯度抖动;beta2=0.999:二阶动量,自适应调整每个参数学习率;
    epoches=10
    loss_mean=[]
    for epoch in range(epoches):
        dataloader=DataLoader(train_data,batch_size=2,shuffle=True)
        loss_sum=0
        sample=0
        for x,y in dataloader:
            y_predict=img_model(x)
            loss=cri(y_predict,y)
            loss_sum+=loss.item()
            sample+=1
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            break
        loss_mean.append(loss_sum/sample)
        print(f"Epoch: {epoch}, Loss: {loss_sum/sample}")
    print(loss_mean)
    torch.save(img_model.state_dict(),r"C:\artificial\python\test\CNN\model.pth")
train()

24自然语言处理

自然语言处理(Nature language Processing,NLP)研究的主要是通过计算机算法来理解自然语言。对于自然语言来说,处理的数据主要就是人类的语言,例如:汉语、英语、法语等,该类型的数据不像我们前面接触的过的结构化数据、或者图像数据可以很方便的进行数值化。

词嵌入层

接下来,我们将会学习如何将词转换为词向量,其步骤如下:

1.先将语料进行分词,构建词与索引的映射,我们可以把这个映射叫做词表,词表中每个词都对应了一个唯一的索引

2.然后使用nn.Embedding构建词嵌入矩阵,词索引对应的向量即为该词对应的数值化后的向量表示。

import jieba
import torch
from torch import nn

#分词
text="我今天要学习自然语言处理"
words=jieba.cut(text)
#去重
un_words=list(set(words))
num=len(un_words)
embeds=nn.Embedding(num_embeddings=num,embedding_dim=3)
#num_embeddings表示词的个数,embedding_dim表示词向量的维度
#print(embeds(torch.tensor(1)))

for i,word in enumerate(un_words):
    print(word)
    print(embeds(torch.tensor(i)))

25.RNN网络原理

文本数据是具有序列特性的

例如:”我爱你",这串文本就是具有序列关系的,“爱"需要在"我"之后,“你"需要在"爱”之后,如果颠倒了顺序,那么可能就会表达不同的意思。为了表示出数据的序列关系,需要使用循环神经网络(Recurrent Nearal Networks,RNN)来对数据进行建模,RNN是一个作用于处理带有序列特点的样本数据

首先初始化出第一个隐藏状态h0,一般都是全0的一个向量,然后将"我"进行词嵌入,转换为向量的表示形式,送入到第一个时间步,然后输出隐藏状态h1,然后将h1和"爱"输入到第二个时间步,得到隐藏状态h2,将h2送入到全连接网络,得到"你"的预测概率。

RNN= torch. nn. RNN(input_size, hidden_size, num layer)

参数意义

1.input_size:输入数据的维度,一般设为词向量的维度;

2.hidden_size:隐藏层h的维数,也是当前层神经元的输出维度;

3.num_layer:隐藏层h的层数,默认为1.

输入数据和输出结果

将RNN实例化就可以将数据送入其中进行处理,处理的方式如下所示:

output, hn = RNN(x, h0)

输入数据:输入主要包括词嵌入的x、初始的隐藏层h0

1.x的表示形式为[seq_len,batch,input_size],即[向子的长度,batch的大小,词向量的维度]

2.h0的表示形式为[num_layers, batch, hidden_size],即[隐藏层的层数,batch的大小,隐藏层h的维数]

输出结果:主要包括输出结果output,最后一层的hn

1.output的表示形式与输入x类似,为[seq_len, batch,hidden_size,即[向子的长度,batch的大小,输出向量的维度]

2.hn的表示形式与输入h0一样,为[num_layers,batch, hidden_size],即[隐藏层的层数,batch的大,隐藏层h的维度]

import torch
import torch.nn as nn

rnn=nn.RNN(input_size=128,hidden_size=64,num_layers=1)
x=torch.randn(12,24,128)
h=torch.randn(1,24,64)
y,hn=rnn(x,h)
print(y.shape)#torch.Size([12, 24, 64])
print(hn.shape)#torch.Size([1, 24, 64])

26.模型构建

1.词嵌入层:用于将语料转换为词向量

2.循环网络层:提取句子语义

3.全连接层:输出对词典中每个词的预测概率

#构建词表
import jieba
import torch
from torch import nn
from torch.utils.data import Dataset, DataLoader


def build_vocab():
    all_words=[]
    unique_words=[]
    # 1.读取数据
    for line in open(r'C:\artificial\python\test\04RNN\jaychou_lyrics.txt', 'r', encoding='utf-8'):
        # 2.分词
        words = list(jieba.cut(line))
        all_words.append(words)
        #print(all_words)
        # 3.去重
        for word in words:
            if word not in unique_words:
                unique_words.append(word)

    #4.构建字典
    word2index={word: i for i,word in enumerate(unique_words)}
    #5.文本转id
    corpus_id=[]
    for words in all_words:
        temp=[]
        for word in words:
            temp.append(word2index[word])
            #print(temp) [0,1,2,3,40]
        temp.append(word2index[' '])
        corpus_id.extend(temp)#list.extend(序列):把 temp 里面每一个元素逐个追加到 corpus_id 列表末尾,不嵌套
    return unique_words, word2index, len(unique_words), corpus_id

#构建数据集
class LyricsDataset(Dataset):
    def __init__(self,corpus_id,num_char):
        self.corpus_id=corpus_id
        self.num_char=num_char
        self.word_count=len(self.corpus_id)
        self.num=len(self.corpus_id)//self.num_char

    def __len__(self):
        return self.num

    def __getitem__(self, idx):
        start=min(max(idx,0),self.word_count-self.num_char-2)
        x=self.corpus_id[start:start+self.num_char]
        y=self.corpus_id[start+1:start+1+self.num_char]
        return torch.tensor(x),torch.tensor(y)

#模型构建
class TextGenerator(nn.Module):
    def __init__(self,world_count):
        super(TextGenerator, self).__init__()
        #嵌入层
        self.embedding=nn.Embedding(num_embeddings=world_count,embedding_dim=128)
        #RNN层
        self.rnn=nn.RNN(input_size=128,hidden_size=256,num_layers=1)
        #全连接层
        self.out=nn.Linear(256,world_count)

    def forward(self,x,hidden):
        embeds=self.embedding(x)
        #得到形状:[batch_size, seq_len, 128]
        out,hid=self.rnn(embeds.transpose(0,1),hidden)
        #[seq_len, batch_size, 128]
        #out:RNN 每一个时间步的输出,形状 [seq_len, batch, 256]
        #hid:最后一步的隐状态,用于下一段文本续写
        out=self.out(out.reshape(-1,256))
        return out

    def init_hidden(self,batch_size):
        return torch.zeros(1,batch_size,256)
#模型训练
def train(dataset,model):
    cri=nn.CrossEntropyLoss()
    optimizer=torch.optim.Adam(model.parameters(),lr=0.0001,betas=(0.9,0.999))
    epoches=10
    for epoch in range(epoches):
        dataloader=DataLoader(dataset,batch_size=2,shuffle=True)
        loss_sum=0
        sample=0.001
        for x,y in dataloader:
            h0=model.init_hidden(batch_size=2)
            out=model(x,h0)
            y=torch.transpose(y,0,1).contiguous().view(-1)
            loss=cri(out,y)
            loss_sum+=loss.item()
            sample+=1
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            break
        print(f"Epoch: {epoch}, Loss: {loss_sum/sample}")
    torch.save(model.state_dict(), r'C:\artificial\python\test\04RNN\model.pth')

#模型预测
def predict(model,start_words,len,unique_words,word2index):
    model.load_state_dict(torch.load(r'C:\artificial\python\test\04RNN\model.pth'))
    #读取本地 .pth 模型权重文件,把文件里保存的网络参数(权重、偏置)加载成字典 state_dict
    wor_index=word2index[start_words]
    h0=model.init_hidden(batch_size=1)
    word_list=[]
    for _ in range(len):
        out=model(torch.tensor([[wor_index]]),h0)
        wor_index=torch.argmax(out)
        word_list.append(unique_words[wor_index])
    for word in word_list:
        print(word,end='')

if __name__ == '__main__':
    unique_words, word2index, word_count, corpus_id=build_vocab()
    dataset=LyricsDataset(corpus_id,5)
    print(dataset[0])
    model=TextGenerator(word_count)
    # print( model.parameters())
    # train(dataset,model)
    predict(model,'青春',50,unique_words,word2index)

27.内容总结

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐