线性神经网络


1.数学原理:

a.线性模型

​ 线性假设是指目标可以表示为特征的加权和,如同式子y=w1x1+w2x2+w3x3+...+wnxn+by=w_1x_1+w_2x_2+w_3x_3+...+w_nx_n+b 的形式,使用矩阵点积进行简洁表示:

y^=WTx+b\hat{y}=W^Tx+b

​ 对于特征集合,即由一组batch_size大小的抽样组成的集合,常常写作:

Y^=XW+b\hat{Y}=XW+b

​ 注意,对于本章来说,所有y^\hat{y}均为预测值,在后续的计算中,需要优化的参数为W,b两个参数,这是对线性模型来说的,后续优化的时候的各类优化方法,都是讲W,b优化进入一个评价度最好的参数中去。

b.损失函数

​ 损失函数是一个重要的评价指标,用于表示与实际值的拟合程度,对于简单的线性模型,一般采用平方误差即可,如下:

li(w,b)=12(yi^yi)2l^{i}(w,b)=\frac{1}{2}(\hat{y_i}-y_i)^2

​ 这个12\frac{1}{2}是为了便于求导后系数没那么多,上面这个式子是对单个的预测值与实际值的损失,实际上在一轮计算时候,是需要计算所有的损失的平均值,比如我这有一组输出共计N个y,那么其总的平均损失为

L(w,b)=1nli(w,b)L(w,b)=\frac{1}{n}\sum{l^{i}(w,b)}

​ 在训练模型的时候,需要找的是平均损失最小的ww^*bb^*

c.解析解

​ 如果讲损失函数看作由x向量之和和y向量之差合成的第三个向量的模,那么很容易发现,在y向量的垂直投影刚好是x向量的加权和之时,就是损失函数最小的时候,这时候得到的解析解为:

w=(XTX)1XTYw^*=(X^TX)^{-1}X^TY

​ 这个方法用于存在解析解的时候,但是很多时候不存在解析解,那还是用其他方法

d.minibatch stochastic gradient descent

​ 小批量随机梯度下降法是一种常用的方法,对于小批量随机梯度下降法,我们需要如下参数:

lr:batch学习率:lr\\ 小批量样本:batch

​ 对于w,b的更新如下面式子所示“

wi+1=wilrbatchx(i)(wiTx+biy(i))bi+1=bilrbatch(wiTx+biy(i))w_{i+1}=w_{i}-\frac{lr}{batch}\sum{x^{(i)}(w_{i}^Tx+b_{i}-y^{(i)})}\\ b_{i+1}=b_{i}-\frac{lr}{batch}\sum{(w_{i}^Tx+b_{i}-y^{(i)})}

​ 注意一个问题,如果被优化的对象较为简单,整个定义域上仅有一个最优值,那这个方法就十分甚至九分的好用,如果有局部最优该怎么办。

2.实现步骤

流程图

3.原理实现

导入需要使用的包

"""
学习线性神经网络的
"""
import math
import time
import numpy as np
import torch
from d2l import torch as d2l
import random

生成需要被线性拟合的样本

def synthetic_data(w,b,num_example):
    """y=w.T*x+b+噪声,用这个功能获取input"""
    x=torch.normal(0,1,(num_example,len(w)))
    #print(x)
    """正态分布函数,0是期望,1是均值"""
    y=torch.matmul(x,w)+b
    #print(y.shape)
    y+=torch.normal(0,0.01,y.shape)
    """这里加个噪声"""
    return x,y
    """这玩意是行转列""
    
true_w=torch.tensor([2,-3.4])
true_b=4.2
feature,labels=synthetic_data(true_w,true_b,1000)

初始化参数模型

"""初始化模型参数"""
w=torch.normal(0,0.01,size=(2,1),requires_grad=True)
b=torch.zeros(1,requires_grad=True)
"""这是需要被计算的w,b的随机初始值"""
"""初始化参数"""
lr=0.03 #学习率
num_epochs=3  #代码周期
net =linreg
loss=loss

定义net,线性回归就是一个简单的模拟神经元,输入加权后得到一个输出

def linreg(x,w,b):
    """定义线性回归模型"""
    return torch.matmul(x,w)+b

loss函数:

def loss(y_hat,y):
    """define loss function"""
    return (y_hat-y)**2/2

获取每次进行计算的小批量

def data_item(batch_size,feature,labels):
    """minibatch stochastis gradient descent
    随机小批量梯度下降法中需要挑选一部分样本"""
    num_example=len(feature)
    indices=list(range(num_example))
    """获取一个0,1,2,3,4,5,6****的玩意"""
    random.shuffle(indices)
    """打乱,注意shuffle只能打乱列表,对于numpy类型的要使用permutation"""
    for i in range(0,num_example,batch_size):
        # print(i)
        batch_indices=torch.tensor(indices[i:min(i+batch_size,num_example)])
        yield feature[batch_indices],labels[batch_indices]
        """注意yield的用法,这是生成一个迭代器,当需要的时候进行计算,相当于return,不过要一个一个弹出
        可以用next进行弹出,弹出所有的输出后终止"""
        """用于执行多次输出的return""

梯度下降算法

def sgd(params,lr,batch_size):
    """输入的params为[w,b],lr为学习率,batch_size为一次计算中的样本数"""
    """定义stochastic gradient descent"""
    with torch.no_grad():
        """with下面为不调用求导的方法,节省算力"""
        for param in params:#所有的wb按照梯度进行下降
            param -= lr*param.grad/batch_size#[w,b]-grad([w,b])
            param.grad.zero_()

训练:

"""开始训练"""
for epoch in range(num_epochs):
    """训练epoch轮"""
    for x, y in data_item(batch, feature, labels):
        """每次随机获取十个样本"""
        #print(x)
        #print(y)
        #print("-------------")
        l=loss(net(x,w,b),y)
        l.sum().backward()#计算了损失函数的梯度
        """反向传播msgd"""
        sgd([w,b],lr,batch)
        """输入w,b,学习率,"""
        #zz+=1
    """注意下面的都是with里面,with在epoch循环里面"""
    with torch.no_grad():
        """如果require_grad打开,会消耗很多资源,这个with下所有的require_grad都将为0"""
        train_l=loss(net(feature,w,b),labels)
        print(w,b)
        print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
print(w,b)

4.调包实现

需要的包:

import torch
from d2l import torch as d2l
from torch.utils import data
from torch import nn

定义初始数据集,和原理实现是一样的

"""定义初始数据集参数来源"""
true_w=torch.tensor([2,-3.4])
true_b=4.2
features,labels=d2l.synthetic_data(true_w,true_b,1000)

pytorch的数据迭代器

def load_array(data_arrays,batch_size,is_train=True):
    """构造一个小批量的pytorch数据迭代器"""
    dataset=data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset,batch_size,shuffle=is_train)
"""==============================================================="""
batch_size=10
data_iter=load_array((features,labels),batch_size)                  

定义net

batch_size=10
data_iter=load_array((features,labels),batch_size

初始化参数模型:

"""初始化参数模型"""
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0

定义损失函数和优化方法

loss=nn.MSELoss()
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
"""定义优化方法"""

开始迭代优化:

num_epochs = 3
for epoch in range(num_epochs):
    for X, y in data_iter:
        l = loss(net(X) ,y)
        trainer.zero_grad()
        """梯度清零"""
        l.backward()
        """反向传播进行梯度优化"""
        trainer.step()
        """更新参数,十分重要"""
    l = loss(net(features), labels)
    print(f'epoch {epoch + 1}, loss {l:f}')

输出:

w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)

文章作者: dlx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 dlx !
评论