深度学习——线性神经网络

线性回归

1.什么是线性回归

以下是百度百科的参考

线性回归就是去分析一堆自变量X与因变量Y的线性关系,是一种定量的计算

线性回归的应用:比如想要预测房价面积与房龄的关系,就可以表示为面积与房屋年龄分别与对应的元素相求和

房价=W1*房屋面积+W2*房屋年龄+W3*房屋厕所数量+偏置

放到机器学习:
房间就是我们的预测结果   厕所数量等房屋信息的就叫做特征,用矩阵—向量乘法可表示为

其中矩阵X是多个样本所组成的矩阵 

 y_hat=Xw+b

为什么要在数据集中加入噪音?

虽然我们相信给定 x 预测 y 的最佳模型会是线性的,但我们很难找到一个有 n 个样本的真实数据集,其中对于 所有的1 i n y ( i ) 完全等于 w x ( i ) + b 。无论我们使用什么手段来观察特征 X 和标签 y ,都可能会出现少量 的观测误差。因此,即使确信特征与标签的潜在关系是线性的,我们也会加入一个噪声项来考虑观测误差带 来的影响。 就比如厕所面积大约10m^2 也可能是11.5m^2 数据是存在测量上的误差

2损失函数

定义:量化实际值与预测值之间的差距,一般为非复数。

在回归分析中我们一半采用平方误差损失

loss(w,b)=1/2  * (y_hat-y)^2

为了度量模型 在整个数据集上的质量,我们需计算在训练集n 个样本上的损失均值(也等价于求平均)

 在训练模型时,我们希望寻找一组参数(w, b),这组参数能最小化在所有训练样本上的总损失

3.随机梯度下降 

批量梯度下降(BGD)和随机梯度下降(SGD)。在批量梯度下降中,每次迭代时,我们使用所有训练样本来计算损失函数和梯度,并更新参数。这种方法可以获得全局最优解,但是对于大规模数据集来说,计算成本很高。

相比之下,随机梯度下降每次只使用一个样本来计算梯度,并更新参数。这种方法计算成本低,但容易收敛到局部最优解。为了平衡这两个方法的优缺点,还有一种折中方法,称为小批量随机梯度下降

我们采用如下数学公式取更新w和b的参数

总体写写下来就为

 

 其中自定义的参数为学习率lr和批量大小batch_size

5.正态分布

高中知识,只用知道越接近mean,其概率p(X)越大

正态分布(高斯分布)概率密度函数如下:

 6.为什么要使用均方误差衡量损失

因此,在高斯 噪声的假设下,最小化均方误差等价于对线性模型的极大似然估计。

线性回归实现

1.回归数据的产生

def creat_data (w,b,numyangben):#产生一个数据集
    x=torch.normal(0,1,(numyangben,len(w)))#随机产生x
    y=torch.matmul(x,w)+b#y等于两个矩阵相乘加一个偏执b
    y+=torch.normal(0,0.01,y.shape)#加入随机噪音
    return  x,y.reshape((-1,1))#将y转化为一个列向量

测试:

truew=torch.tensor([2,-3.4])
trunb=4.2
X,y=sdata(truew,trunb,1000)
d2l.set_figsize()
d2l.plt.scatter(X[:, (1)].detach().numpy(), y.detach().numpy(), 1)
d2l.plt.show()

结果:

 2.对于SGD随机梯度下降的实现

2.1数据的随机读取

手动
def read(size,X,y):#随机读取
    numX=len(X)#获取有多少个数据量
    indx=list(range(numX))#将数据量存入一个list的列表中
    random.shuffle(indx)#打乱列表
    for i in range(0,numX,size):
        suiji=torch.tensor(indx[i:min(i+size,numX)])#读取i后size个
        yield X[suiji],y[suiji]#卡在i=?等待再次调用
简洁实现
def loding(shuju,size,tai=True):
    dataset=data.TensorDataset(*shuju)#将数据放入随机容器
    return data.DataLoader(dataset,size,shuffle=tai)#打乱

2.2网络梯度的更新

从零实现
def sgd(params,lr,size):#size为批量大小
    with torch.no_grad():#更新时不参与梯度计算
       for param in params:
           param-=lr*param.grad/size
           param.grad.zero_()
简洁实现
sgd=torch.optim.SGD(net.parameters(),lr=0.01)#将梯度下降搞出来

3网络实现

从0实现
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)#随机来个权重
b=torch.tensor([0.0],requires_grad=True)#定义偏执为0
def net(X,w,b):#定义函数
    return torch.matmul(X,w)+b
def loss(y_hat,y):#定义损失函数
    return (y_hat-y)**2/2
简洁实现
net=nn.Sequential(nn.Linear(2,1))#定义输入长度2输出为1
# net[0].weight.data.normal_(0,0.01)#设置方差为0.01
# net[0].bias.data.fill_(0)#将b设置为0
loss=nn.MSELoss()#定义损失函数

4整体

从0
import  matplotlib
import torch
import random
import os
from d2l import torch as d2l
def sdata (w,b,numyangben):#产生一个数据集
    x=torch.normal(0,1,(numyangben,len(w)))#随机产生x
    y=torch.matmul(x,w)+b#y等于两个矩阵相乘加一个偏执b
    y+=torch.normal(0,0.01,y.shape)#加入随机噪音
    return  x,y.reshape((-1,1))#将y转化为一个列向量
truew=torch.tensor([2,-3.4])
trunb=4.2
X,y=sdata(truew,trunb,1000)
# d2l.set_figsize()
# d2l.plt.scatter(X[:, (1)].detach().numpy(), y.detach().numpy(), 1)
# d2l.plt.show()
def read(size,X,y):#随机读取
    numX=len(X)#获取有多少个数据量
    indx=list(range(numX))#将数据量存入一个list的列表中
    random.shuffle(indx)#打乱列表
    for i in range(0,numX,size):
        suiji=torch.tensor(indx[i:min(i+size,numX)])#读取i后size个
        yield X[suiji],y[suiji]#卡在i=?等待再次调用
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)#随机来个权重
b=torch.tensor([0.0],requires_grad=True)#定义偏执为0
def net(X,w,b):#定义函数
    return torch.matmul(X,w)+b
def loss(y_hat,y):#定义损失函数
    return (y_hat-y)**2/2
def sgd(params,lr,size):
    with torch.no_grad():#更新时不参与梯度计算
       for param in params:
           param-=lr*param.grad/size
           param.grad.zero_()
lr=0.001
ci=100

for x in range(ci):#总循环次数
    for M,n in read(10,X,y):#随机梯度
        l=loss(net(M,w,b),n)#计算损失
        l.sum().backward()#求和反向传播
        sgd([w,b],lr,10)#梯度下降
    with torch.no_grad():
      tl=loss(net(X,w,b),y)#计算损失
      print(f'epoch{x+1},loss{float(tl.mean()):f}')

简洁
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
true_w=torch.tensor([2,-3.4])
true_b=4.2
shuru,shuchu=d2l.synthetic_data(true_w,true_b,1000)#随机产生数据

def loding(shuju,size,tai=True):
    dataset=data.TensorDataset(*shuju)#将数据放入随机容器
    return data.DataLoader(dataset,size,shuffle=tai)#打乱
size=10
data_iter=loding((shuru,shuchu),size)
from torch import nn
net=nn.Sequential(nn.Linear(2,1))#定义输入长度2输出为1
# net[0].weight.data.normal_(0,0.01)#设置方差为0.01
# net[0].bias.data.fill_(0)#将b设置为0
loss=nn.MSELoss()#定义损失函数
sgd=torch.optim.SGD(net.parameters(),lr=0.01)#将梯度下降搞出来
xxx= []  # 用于保存每轮的损失值
ci=10
for i in range(ci):
    for X, y in data_iter:
        l = loss(net(X), y)
        sgd.zero_grad()
        l.backward()
        sgd.step()
    l = loss(net(shuru), shuchu).item()  # 获取当前轮次的损失值
    print(f'epoch {i + 1}, loss {l:f}')
    xxx.append(l)  # 保存当前轮次的损失值

# 绘制损失随迭代次数变化的曲线
import matplotlib.pyplot as plt
plt.subplot2grid((1,2),(0,1))
plt.plot(range(1, ci+1), xxx, '-o')  # x轴为迭代次数,y轴为损失值
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss vs. Epoch')
plt.subplot2grid((1,2),(0,0))
print(shuru.detach().numpy()[:,0].shape)
print(shuchu.detach().numpy().reshape(-1).shape)
plt.scatter(shuru.detach().numpy()[:,1],shuchu.detach().numpy().reshape(-1))
w=net[0].weight.data[0,1]
y_hat=w*shuru.detach().numpy()[:,1]+net[0].bias.data
plt.plot(shuru.detach().numpy()[:,1],y_hat.numpy(),color="red")
plt.show()

结果:

 softmax回归

1.目的

去对一堆图片去做类别概率的预测,并希望得到正确的分类

与线性回归的区别在于线性回归预测的是值  而softmax回归预测的是类别概率

Softmax回归的输出不是一个实值,而是一个在0和1之间的概率

2独热编码 

独热编码是一个向量,它的分量和类别一样多。类别对 应的分量设置为1 ,其他所有分量设置为 0

 例如:对于马桶,牙刷,杯子三个物品的图片进行分类,这三个物品的独热编码可以为

(1,0,0) (0,1,0)(0,0,1)

3.网络结构

 将784个特征值通过权重(784*10)矩阵输出为10个的特征值

4.softmax运算

既然我们要求10个输出中的概率最大值,那为什么不直接去求10个输出的最大值而是进行softmax操作呢?

1.概率不为负数而10个直接输可能为负数

2.10个输出相加不一定为1

我们首先对每个未规范化的预测求幂,这样可以确保输出非负。为了确保最终输出的概率值总和为1,我们再让每个求幂后的结果除以它们的总和

 尽softmax是一个非线性函数,但softmax回归的输出仍然由输入特征的仿射变换决定。因此,softmax回 归是一个线性模型

5交叉熵损失

对于多分类问题,我们采用交叉熵损失来作为衡量的损失

由于我们采用独热编码的形式  除去正确定的Yi都是0,所以 

 损失函数对未规范化o的导数为

softmax回归的实现

1.对于数据集的下载

我们采用FashionMNIST数据集来训练我们的网络

注意由于win的多线程机制,dataloder中由于多线程问题会报错,可以采用如下方法

1.使用if __name__=="main"保护主程序

2.使用d2l.use_svg_display绕过线程限制

3.使用dataloder时禁用多线程

import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l
d2l.use_svg_display()
trans=transforms.ToTensor()#预处理 将图片转化为张量
mins_train=torchvision.datasets.FashionMNIST(root="../data",train=True,transform=trans,download=True)#下载训练数据,train代表训练数据集,transfrom为张量格式,默认网上下载
mnist_test=torchvision.datasets.FashionMNIST(root="../data",train=False,transform=trans,download=True)#训练数据集
print(mnist_test[0][0].shape)
import matplotlib.pyplot as plt

# 设置图像的行数和列数
num_rows = 2
num_cols = 5
fig, axes = plt.subplots(num_rows, num_cols, figsize=(15, 6))
for i in range(10):
    ax = axes[i // num_cols, i % num_cols]
    image, label = mnist_test[i]
    image_np = image.permute(1, 2, 0).numpy()
    ax.imshow(image_np, cmap='gray')
    ax.set_title(f'Label: {label}')
plt.tight_layout()
plt.show()
利用d2l来实现
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

结果图:

 2随机梯度下降的实现

trainer=torch.optim.SGD(net.parameters(),lr=0.15)#传入网络参数

3.网络的实现

net=nn.Sequential(nn.Flatten(),nn.Linear(784,10))
#nn.Sequential 是 PyTorch 中一个非常有用的类,用于构建神经网络模型
#Flatten强制转化为二维的张量
def inx(m):
    if type(m)==nn.Linear:
        print(m.weight.data.shape)
        nn.init.normal_(m.weight,std=0.01)
#init初始化
#nn.init.normal 是 PyTorch 中用于对神经网络模型参数进行正态分布初始化的函数
net.apply(inx)
loss=nn.CrossEntropyLoss()#定义损失函数

4整体

import torch
from torch.utils import data
from torch import nn
from d2l import torch as d2l
d2l.use_svg_display()
bea=256
train_inter,test_inter=d2l.load_data_fashion_mnist(bea)
net=nn.Sequential(nn.Flatten(),nn.Linear(784,10))
#nn.Sequential 是 PyTorch 中一个非常有用的类,用于构建神经网络模型
#Flatten强制转化为二维的张量
def inx(m):
    if type(m)==nn.Linear:
        print(m.weight.data.shape)
        nn.init.normal_(m.weight,std=0.01)
#init初始化
#nn.init.normal 是 PyTorch 中用于对神经网络模型参数进行正态分布初始化的函数
net.apply(inx)
#net.apply() 是 PyTorch 中用于对神经网络模型的所有参数进行初始化或其他操作的函数
loss=nn.CrossEntropyLoss()
#交叉熵
trainer=torch.optim.SGD(net.parameters(),lr=0.15)
#sgd算法更新
def acc(y_hat,y):#计算正确的数量
    if len(y_hat.shape)>1 and (y_hat.shape[1])>1:
        y_hat=y_hat.argmax(axis=1)
    cmp=y_hat.type(y.dtype)==y
    return float(cmp.type(y.dtype).sum())
class Accumalator:
    def __init__(self,n):
        self.data=[0.0]*n#初始化函数,创建长度为 n 的数据列表,用于存储累加结果。
    def add(self,*args):
        self.data=[a+float(b) for a,b in zip(self.data,args)]#将传入的参数与对应位置的数据相加并累加到数据列表中
    def reset(self):
        self.data=[0.0]*len(self.data)#重置数据列表,将所有元素设置为 0.0。
    def __getitem__(self, idx):
        return self.data[idx]#索引

def netce(net,data_iter):
    if isinstance(net,torch.nn.Module):
        net.eval()#评估模式
    metric = Accumalator(2)#计入数值为2
    for X,y in data_iter :#将数据交出
        metric.add(acc(net(X),y),y.numel())#计算正确数和总数
        return metric[0]/metric[1]#正确率
def train_han(net,train_iter,loss,updater):
    if isinstance(net,torch.nn.Module):#假如是nn网络
        net.train()#训练模式
    metric=Accumalator(3)#记录数据
    for X,y in train_iter:#迭代器给数据
        y_hat=net(X)
        l=loss(y_hat,y)
        if isinstance(updater,torch.optim.Optimizer):#更新器
            updater.zero_grad()#梯度清零
            l.backward()#求梯度
            updater.step()#更新梯度
            metric.add(float(l)*len(y),acc(y_hat,y),y.numel())#总损失 正确数 样本数
        else :
            l.sum().backward()#求梯度
            updater(X.shape[0])#更新
            metric.add(float(l.sum()),acc(y_hat,y),y.numel())
    return metric[0]/metric[2],metric[1]/metric[2]
cesun=list()
xunsun=list()
xunloss=list()
ci=5
def xun(net,train_iter,test_iter,loss,ci,updater):
    for i in range(ci):
        print((float(i + 1) / ci) * 100, '%')
        k,l=train_han(net,train_iter,loss,updater)
        n=netce(net,test_iter)
        cesun.append(n)
        xunsun.append(l)
        xunloss.append(k)
xun(net,train_inter,test_inter,loss,ci,trainer)
import matplotlib.pyplot as plt

plt.plot(range(1, ci+1), cesun, '-o')
plt.plot(range(1, ci+1), xunsun, '-o')
plt.plot(range(1, ci+1), xunloss, '-o') # x轴为迭代次数,y轴为损失值
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss vs. Epoch')
plt.legend(['test', 'train', 'train_loss'])
plt.show()

结果图

 

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值