构建简单神经网络

构建简单神经网络

1.简单的网络

1.1基本数据

batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10

1.2构建输入,权重,输出

输入为100个具有1000个特征的数据,输入层到隐藏层的权重为w1,隐藏层到输入层的权重为w2,输出结果为100个具有10个分类结果的数据。

x = torch.randn(batch_n, input_data)#输入100个具有1000个特征的数据
w1 = torch.randn(input_data, hidden_layer)#输入层到隐藏层
w2 = torch.randn(hidden_layer, output_data)#隐藏层到输出层
y = torch.randn(batch_n, output_data)#输出100个具有10个分类结果值的数据

1.3定义学习速率和后向传播次数

学习速率用于控制梯度更新的快慢,如果学习速率过快,参数的更新跨步就会变大 ,易出现局部最优和抖动;如果学习速率过慢,梯度更新的迭代次数就会增加,参数更新、优化的时间也会变长。
后向传播的过程实际上就是复合函数求导的过程。

epoch_n = 20 #后向传播次数
learning_rate = 1e-6 #梯度下降学习速率

1.4前向传播

#y的预测值是x * w1 * w2
h1 = torch.mm(x, w1)
h1 = h1.clamp(min=0)#小于0的为0
y_pred = torch.mm(h1, w2)

在这里插入图片描述其中clamp(min=0)起到了ReLu激活函数的作用(ReLU 函数通过比较0 和输入数据 x 中大小进行输出,即如果 x 小于 0,则输出结果 0;如果 x大于 0 ,则输出 结果 x )

1.5计算Loss(预测值和真实值的差)

loss = (y - y_pred).pow(2).sum()

1.6后向传播

#q求偏导得到w2的梯度
grad_y_pred = 2*(y_pred - y)
grad_w2 = h1.t().mm(grad_y_pred)
#进而得到w1的梯度
grad_h = grad_y_pred.clone()
grad_h = grad_h.mm(w2.t())
grad_h.clamp_(min=0)
grad_w1 = x.t().mm(grad_h)
#梯度下降,更新参数
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2

代码实现

import torch
"""
每批有100个数据,每个数据有1000个特征
经过隐藏层处理后,保留的特征有100个
输出数据为10,代表100个数据被分为10类
"""
batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10

#参数进行 后向传播 的过程就是一个复合函数求导的过程
# 梯度 是将多元函数的各个参数求得的偏导数以向量的形式展现出来,也叫作多元函数的梯度
#梯度下降:对参数对象的更新

x = torch.randn(batch_n, input_data)#输入100个具有1000个特征的数据
w1 = torch.randn(input_data, hidden_layer)#输入层到隐藏层
w2 = torch.randn(hidden_layer, output_data)#隐藏层到输出层
y = torch.randn(batch_n, output_data)#输出100个具有10个分类结果值的数据

epoch_n = 20 #后向传播次数
learning_rate = 1e-6 #梯度下降学习速率

for epoch in range(epoch_n):

    #前向传播
    #y的预测值是x * w1 * w2
    h1 = torch.mm(x, w1)
    h1 = h1.clamp(min=0)#小于0的为0
    y_pred = torch.mm(h1, w2)

    #以均方误差计算loss
    loss = (y - y_pred).pow(2).sum()
    print(f"Epoch:{epoch}, Loss:{format(loss, '.0f')}")

    #后向传播
    #计算梯度
    #求偏导得到w2
    grad_y_pred = 2*(y_pred - y)
    grad_w2 = h1.t().mm(grad_y_pred)

    #求偏导得到w1
    grad_h = grad_y_pred.clone()
    grad_h = grad_h.mm(w2.t())
    grad_h.clamp_(min=0)
    grad_w1 = x.t().mm(grad_h)

    #梯度下降,更新参数
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

2.通过autograd实现后向传播梯度的自动计算

2.1torch.autograd包,Variable 类

torch. autograd 包的功能是完成神经网络后向传播中的链式求导,实现自动梯度功能的过程大致为:先通过Tenso前向传播梳理流程,然后后向传播计算梯度,并且更新。完成自动梯度需要用到 torch.autograd 包中的 Variable 类对我们定义的 Tensor数据类型变量进行封装,在封装后,计算图中的各个节点就是一个 Variable 对象。
Variable是篮子,而tensor是鸡蛋,鸡蛋应该放在篮子里才能方便拿走(定义variable时一个参数就是tensor)Variable篮子里除了装了tensor外还有requires_grad参数,表示梯度计算时是否保留梯度值,默认为False。
访问梯度值时使用 X.grad.data
Variable包含三个属性:
data:存储了Tensor,是本体的数据
grad:保存了data的梯度,是个Variable而非Tensor,与data形状一致
grad_fn:指向Function对象,用于反向传播的梯度计算之用

2.2代码实现

#后向传播梯度的自动计算
#torch.autograd 完成后向传播中的链式求导
#Variable类对tensor数据类型进行封装

import torch
from torch.autograd import Variable

#100个数据, 每个数据包含1000个特征
#经过隐藏层每个数据保留100个特征
#输出为10,代表100个数据分为10类
batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10

#在进行梯度计算时是否保留梯度值
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
w1 = Variable(torch.randn(input_data, hidden_layer), requires_grad=True)
w2 = Variable(torch.randn(hidden_layer, output_data), requires_grad=True)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

epoch_n = 20
learning_rate =1e-6 #10的-6次方

for epoch in range(epoch_n):
    #计算预测值
    y_pred = x.mm(w1).clamp(min=0).mm(w2)
    # 均方差公式 计算损失值
    loss = (y_pred - y).pow(2).sum()
    print(f"Epoch:{epoch}, Loss:{format(loss, '.0f')}")
    #后向计算
    loss.backward()
    #梯度下降更新参数
    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data
    #本次计算的各个参数节点梯度值归0
    w1.grad.data.zero_()
    w2.grad.data.zero_()

3.自定义传播函数

3.1介绍

通过构建一个继承了 torch.nn.Module的新类 , 来完成对前向传播函数和后向传播函数的重写 。

3.2重点实现

#定义 前向 和 后向 传播函数
class Model(torch.nn.Module):
    
    def __init__(self):
        super(Model, self).__init__()
        
    def forward(self, input, w1, w2):
        y_pred = input.mm(w1).clamp(min=0).mm(w2)
        return y_pred
        
    def backward(self):
        pass

3.3代码实现

#自定义传播参数
import torch
from torch.autograd import Variable

batch_n = 64
input_data = 1000
hidden_layer = 100
output_data = 10

#定义 前向 和 后向 传播函数
class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()

    def forward(self, input, w1, w2):
        y_pred = input.mm(w1).clamp(min=0).mm(w2)
        return y_pred

    def backward(self):
        pass

model = Model()
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
w1 = Variable(torch.randn(input_data, hidden_layer), requires_grad=True)
w2 = Variable(torch.randn(hidden_layer, output_data), requires_grad=True)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

epoch_n = 30
learning_rate = 1e-6

for epoch in range(epoch_n):
    y_pred = model(x, w1, w2)
    loss = (y_pred - y).pow(2).sum()
    print(f"Epoch:{epoch}, Loss:{format(loss.data, '.0f')}")
    loss.backward()
    # 梯度下降更新参数
    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data
    # 本次计算的各个参数节点梯度值归0
    w1.grad.data.zero_()
    w2.grad.data.zero_()

4.使用方法进行模型搭建和参数优化

torch.nn 包提供了很多与实现神经网络中的具体功能相关的类,这些类涵盖了深度神经网络模型在搭建和参数优化过程中的常用内容,如神经网络中的卷积层、池化层 、全连接层这类层次构造的方法、防止过拟合的参数归一化方法、 Dropout 方法,还有激活函数部分的线性激活函数、非线性激活函数相关的方法 。

4.1基本数据

batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10

4.2构建输入输出

与之前的不同,由于torch.nn包中的类可以帮助我们自动生成和初始化对应维度的权重参数,在此不必构建权重参数

#删除权重参数代码,因为torch.nn包中的类可以帮助我们自动生成和初始化对应维度的权重参数
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

4.3建立模型

torch.nn.sequential中的参数会按照我们定义好的序列自动传递下去
模块的加入一般有两种方式 , 第一种使用的直接嵌套,第二种是以 orderdict 有序字典的方式进行传入,这两种方式的唯一区别是,使用后者搭建的模型可以对每个模块自定义名字 , 而前者默认使用模块内使用的方法作为每个模块的名字。(使用orderdict更加智能)
两者对比如下:

#第一种直接嵌套
import torch
from torch.autograd import Variable
batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10
models = torch.nn.Sequential(
    #输入层到隐藏层的线性变换
    torch.nn.Linear(input_data, hidden_layer),
    #经过激活函数
    torch.nn.ReLU(),
    #隐藏层到输出层的线性变换
    torch.nn.Linear(hidden_layer, output_data)
)

---------------------输出结果-------------------------------------
Sequential(
  (0): Linear(in_features=1000, out_features=100, bias=True)
  (1): ReLU()
  (2): Linear(in_features=100, out_features=10, bias=True)
)

                            
#第二种使用orderdict对每个模块定义名字
from collections import OrderedDict
models = torch.nn.Sequential(
    OrderedDict([
    ("Line1", torch.nn.Linear(input_data, hidden_layer)),
    ("Relu1", torch.nn.ReLU()),
    ("Line2", torch.nn.Linear(hidden_layer, output_data))])
)  
---------------------输出结果-------------------------------------
Sequential(
  (Line1): Linear(in_features=1000, out_features=100, bias=True)
  (Relu1): ReLU()
  (Line2): Linear(in_features=100, out_features=10, bias=True)
)                           

torch.nn.Linear 类用于定义模型的线性层 ,即不同的层之间的线性变换 。
参数包括输入,输出, 也可以设置是否转置
torch.nn.ReLU 类属于非线性激活函数,在定义时默认不需要传入参数,也可以设置其他激活函数

4.4设置学习速率,后向传播次数,计算损失值

torch.nn.MSELoss 类使用均方误差函数对损失值进行计算 ,在定义类的对象时不用传入参数,但在使用时需要输入两个维度一样的参数方可进行计算

4.5代码实现

import torch
from torch.autograd import Variable
from collections import OrderedDict
batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10

#删除权重参数代码,因为torch.nn包中的类可以帮助我们自动生成和初始化对应维度的权重参数
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

models = torch.nn.Sequential(OrderedDict([
    ("Line1", torch.nn.Linear(input_data, hidden_layer, )),#输入, 输出, 是否转置
    ("Relu1", torch.nn.ReLU()),
    ("Line2", torch.nn.Linear(hidden_layer, output_data))
]))
epoch_n = 10001
learning_rate = 1e-4
loss_fn = torch.nn.MSELoss()

for epoch in range(epoch_n):
    y_pred = models(x)
    loss = loss_fn(y_pred, y)
    if epoch%1000 ==0 :
        print(f"Epoch:{epoch},Loss:{format(loss.data, '.4f')}")
    models.zero_grad()

    loss.backward()

    for param in models.parameters():
        param.data -= param.grad.data * learning_rate

5.参数自动优化

在 PyTorch 的 torch.optim 包中提供了非常多的可实现参数自动优化的类,比如 SGD 、AdaGrad 、RMSProp 、Adam 等。
这里使用了 torch.optim 包中的 torch .optim.Adam 类作为我们的模型参数的优化函数 ,在 torch.optim.Adam 类中输入的是被优化的参数和学习速率的初始值 ,学习速率默认使用 0.001 这个值。需要优化的是模型中的全部参数 ,所以传递给tAdam 类的参数是 models. parameters。
Adam 优化函数还有一个强大的功能,就是可以对梯度更新使用到的学习速率进行自适应调节。

5.1代码实现

import torch
from torch.autograd import Variable
from collections import OrderedDict
batch_n =100
input_data = 1000
hidden_layer = 100
output_data = 10

#删除权重参数代码,因为torch.nn包中的类可以帮助我们自动生成和初始化对应维度的权重参数
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

models = torch.nn.Sequential(OrderedDict([
    ("Line1", torch.nn.Linear(input_data, hidden_layer, )),#输入, 输出, 是否转置
    ("Relu1", torch.nn.ReLU()),
    ("Line2", torch.nn.Linear(hidden_layer, output_data))
]))

epoch_n = 20
learning_rate = 1e-4
loss_fn = torch.nn.MSELoss()

optimizer = torch.optim.Adam(models.parameters(), lr=learning_rate)

for epoch in range(epoch_n):
    y_pred = models(x)
    loss = loss_fn(y_pred, y)
    print(f"Epoch:{epoch},Loss:{format(loss.data, '.4f')}")
    optimizer.zero_grad() #调用optimizer.zero_grad完成对模型参数梯度的归零
    loss.backward()
    optimizer.step()#使用计算得到的梯度值对各个节点的参数进行梯度更新
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值