用pytorch实现 bp网络 判别异或

用pytorch实现 bp网络 判别异或

小记

2022.3.28 在写完上篇博客用python实现BP算法_是Mally呀!的博客-CSDN博客用python实现一个bp网络 判别异或之后,想用pytorch再判别看看。

这一篇的网络结构在上一篇有画图

尝试的想法来自于看到这篇博客, pytorch 实现BP神经网络_ThinkZtoA的博客-CSDN博客_pytorch实现bp神经网络,该博客用pytroch实现了异或,但是代码不是很简洁。

强推 Pytorch入门+实战系列二:Pytorch基础理论和简单的神经网络实现_翻滚的小@强的博客-CSDN博客 ,根据这个教程实现了本文。

代码

代码1:只用了pytorch的自动求导

import torch
from icecream import  ic
import torch.utils.data as Data
from matplotlib import  pyplot as plt

# 不写这个运行的时候会出错
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

def run(learning_rate):

    # 随机初始化权重,需要保留梯度,后面要用自动求导
    # Tensor从区间[0, 1)的均匀分布中抽取的一组随机数。
    w1 = torch.rand(2, 5, requires_grad=True)
    w2 = torch.rand(5, 1, requires_grad=True)


    show_losss = []
    show_epoch = []
    e = 0
    for epoch in range(epochs):
        for x0, label in train_data:
            # 前向传播
            y1 = x0.mm(w1)
            x1 = y1.sigmoid()
            y2 = x1.mm(w2)
            x2 = y2.sigmoid()

            loss =0.5*(y2 - labels).pow(2).sum()


            # 反向传播,使用自动求导机制
            loss.backward()

            with torch.no_grad():
                # ic(w2)
                # ic(w1)
                w2 -= learning_rate * w2.grad
                w1 -= learning_rate * w1.grad

                w1.grad.zero_()
                w2.grad.zero_()
                """
                  这里还有个关键的地方,就是Pytorch的求导机制是默认采用累加的方式,
                也就是每一代求完梯度,不会自动清零,下一代的梯度是前一代加上本一代的梯度,
                这时候就错了,所以我们得自动每一代之后,梯度清零
                """

    
            if epoch % show_interval == 0:
                e += loss.item()

        if epoch % show_interval == 0:
            show_losss.append(e / len(train_data))
            show_epoch.append(epoch)
            e=0    # 忘记把这个写上了,结果损失值越来越大到怀疑人生

    return  show_epoch,show_losss

if __name__=='__main__':
    #数据集
    #把tensor里的要投射为double类型
    cases=torch.tensor([[0, 0],
            [0, 1],
            [1, 0],
            [1, 1]    ]).float()
    labels = torch.tensor([[0],[0],[0],[1]])

    #把数据集打包,并且顺序弄混
    Dataset=Data.TensorDataset(cases,labels)
    train_data=Data.DataLoader(dataset=Dataset,shuffle=True,batch_size=1)

    #训练的迭代次数
    epochs=600
    show_interval=100

    epoch1, loss1 = run(learning_rate=1e-2)
    epoch2, loss2 = run(learning_rate=1e-3)
    epoch3, loss3 = run(learning_rate=1e-4)


    #画图
    plt.figure()
    plt.subplot(1, 1, 1)
    plt.plot(range(0, len(epoch1) * show_interval, show_interval), loss1, label='learn=0.01')
    plt.plot(range(0, len(epoch2) * show_interval, show_interval), loss2, label='learn=0.001')
    plt.plot(range(0, len(epoch3) * show_interval, show_interval), loss3, label='learn=0.0001')

    # 显示标签,如果不加这句,即使在plot中加了label='一些数字'的参数,最终还是不会显示标签
    plt.legend(loc="upper right")
    plt.show()

代码结果

mark

代码2:自定义nn Modules

import torch
from icecream import  ic
import torch.utils.data as Data
from matplotlib import  pyplot as plt
from torch import  nn

# 不写这个运行的时候会出错
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"


class BPModel(torch.nn.Module):
    def __init__(self,input_n,hidden_n,ouput_n):
        super(BPModel, self).__init__()

        self.layer1=nn.Sequential(nn.Linear(input_n,hidden_n),nn.Sigmoid())
        self.layer2=nn.Sequential(nn.Linear(hidden_n,ouput_n),nn.Sigmoid())

    def forward(self,x0):
        x1=self.layer1(x0)
        x2=self.layer2(x1)
        return x2

def run(lr=3e-2):
    model = BPModel(2, 5, 1)
    criterion = nn.MSELoss(reduction='mean')
    optimizer = torch.optim.SGD(model.parameters(), lr)

    show_losss = []
    show_epoch = []

    for k in range(1000):
        # 前向传播
        bp = model(cases)
        # 计算损失值
        loss = criterion(bp, labels)
        #  反向传播,更新参数
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()  #更新参数
        if k % show_interval == 0:
            show_losss.append(loss.item())
            show_epoch.append(k)

    plt.plot(range(0, len(show_epoch) * show_interval, show_interval), show_losss, label=str(lr))


if __name__=='__main__':

    cases = torch.tensor([[0, 0],
                          [0, 1],
                          [1, 0],
                          [1, 1]]).float()
    labels = torch.tensor([[0], [0], [0], [1]]).float()

    # 把数据集打包,并且顺序弄混
    Dataset = Data.TensorDataset(cases, labels)
    train_data = Data.DataLoader(dataset=Dataset, shuffle=True, batch_size=1)

    show_interval=100

    #画图
    plt.figure()
    plt.subplot(1,1,1)
    run(lr=1e-2)
    run(lr=1e-3)
    run(lr=1e-4)
    plt.legend(loc="upper right")
    plt.show()

代码结果

mark

查阅的资料

nn.Sequential()构建网络层

nn.Module可以是神经网络的某个层,也可以是包含多层的神经网络,常见做法是继承nn.Module,实现自己的网络/层

nn.MSELoss()

MSE是mean squared error的缩写,即平均平方误差,简称均方误差
M S E = 1 N ∑ i = 1 n ( x i − y i ) 2 MSE=\frac{1}{N}\sum_{i=1}^n (x_i-y_i)^2 MSE=N1i=1n(xiyi)2

PyTorch中MSELoss的使用

torch.nn.MSELoss(size_average=None, reduce=None, reduction: str = ‘mean’)

size_averagereduce在当前版本的pytorch已经不建议使用了,只设置reduction就行了。

reduction`的可选参数有:`'none'` 、`'mean'` 、`'sum'

reduction='none':求所有对应位置的差的平方,返回的仍然是一个和原来形状一样的矩阵。

reduction='mean':求所有对应位置差的平方的均值,返回的是一个标量。

reduction='sum':求所有对应位置差的平方的和,返回的是一个标量。

optim.SGD(model.parameters(), lr = 0.01, momentum=0.9)

SGD是 Stochastic Gradient Descent 是用训练集每个样本的损失值对参数的梯度来更新参数

PyTorch官方中文文档:torch.optim 优化器参数 - 交流_QQ_2240410488 - 博客园 (cnblogs.com) GOOD

pytorc的激活函数

Pytorch的22个激活函数 - 云+社区 - 腾讯云 (tencent.com)

torch.mm

torch.Tensor的4种乘法_da_kao_la的博客-CSDN博客_tensor乘法 把tensor的乘法讲的很清楚

数学里的矩阵乘法,要求两个Tensor的维度满足矩阵乘法的要求.

DataLoader

【PyTorch】torch.utils.data.DataLoader 简单介绍与使用_想变厉害的大白菜的博客-CSDN博客

pytorch默认使用float32

pytorch默认使用单精度float32训练模型,原因在于:使用float16训练模型,模型效果会有损失,而使用double(float64)会有2倍的内存压力,且不会带来太多的精度提升

with torch.no_grad()

在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。而对于tensor的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():,强制之后的内容不进行计算图构建。

pytorch中with torch.no_grad():_这是一只小菜鸡的博客-CSDN博客_torch.nograd

关于pytorch和手动建框架的一些想法

  1. 数据打包随机抽取
  2. 自动求导
  3. 层隐层,构成类
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是Mally呀!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值