线性回归
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()
结果图
标签:plt,nn,torch,神经网络,深度,线性,net,data,size From: https://blog.csdn.net/2301_79972308/article/details/140513501