当前位置: 首页 > article >正文

dl学习笔记:(5)深度神经网络的正向传播

这小节的任务不多,使用封装好的torch.nn模块来实现一个完整的多层神经网络的正向传播。假设我们有500条数据,20个特征,标签为3分类。我们现在要实现一个三层神经网络,这个神经网络的架构如下:第一层有13个神经元,第二层有8个神经元,第三层是输出层。其中,第一层的激活函数是relu,第二层是sigmoid。

(1)导库

import torch
import torch.nn as nn
from torch.nn import functional as F

(2)定义数据张量

torch.manual_seed(250)
x = torch.rand((500,20),dtype = torch.float32)
y = torch.randint(low = 0,high = 3,size = (500,1),dtype = torch.float32)

由于是500条数据,20个特征,所以x是(500,20)

由于是3分类任务,所以这里的y取到的是0,1,2,这里的函数是左闭右开,所以参数是0和3

(3)定义model类

class model(nn.Module):
    def __init__(self,in_features = 20,out_features = 3):
        super(model,self).__init__()
        self.linear1 = nn.Linear(in_features,13,bias = True)
        self.linear2 = nn.Linear(13,8,bias = True)
        self.output = nn.Linear(8,out_features,bias = True)
    def forward(self,x):
        z1 = self.linear1(x)
        sigma1 = torch.relu(z1)
        z2 = self.linear2(sigma1)
        sigma2 = torch.sigmoid(z2)
        z3 = self.output(sigma2)
        sigma3 = F.softmax(z3,dim = 1)
        return sigma3

首先定义__init__,由于开始的传入和最后的输出和模型没什么关系,取决于你的数据和任务,所以这里作为参数传入in_features和out_features

  • super(model, self):这里的 super() 表示调用父类 nn.Module 的方法,第一个参数 model 是当前子类的名称,第二个参数 self 是当前实例对象。super(model, self) 返回父类 nn.Module 的代理对象。
  • super(model, self).__init__():调用父类 nn.Module 的构造函数(__init__()),这样就可以在子类中正确地初始化父类的部分。

nn.Module 中有许多有用的功能和初始化机制,比如管理模型的参数、注册模型的子模块、以及其他自动化的功能。如果你不调用父类的构造函数,就会失去这些功能。因此,必须调用 super().__init__() 来确保父类的构造方法被正确地执行,避免遗漏父类中的初始化代码。

后面定义linear的函数在上一节已经介绍过了,里面的参数按照具体的任务来就行。

 当然nn.Module中的init函数还有很多其他的东西,如下图我们用到具体某一个的时候会提及:

同理下面的前向传播也是一样,在前面的小节中已经介绍过了,这里也只是简单调用

这里我们简单拓展一下python中的self:

Python 中的 self 确实与 C++ 中隐式的 this 指针有类似的作用。它们都是用于引用当前对象的机制。

  • 设计哲学:Python 选择显式地使用 self,符合 Python 的设计哲学 "Explicit is better than implicit"(明确优于隐式)。这种做法让代码的意图更加清晰,易于理解。当你看到方法定义时,明确知道 self 是指向当前对象的引用,而不需要隐式的规则来推断。

  • 避免歧义:通过显式地使用 self,Python 避免了像 C++ 中的 this 可能引起的歧义。例如,在 C++ 中,如果某个方法名称和类成员变量相同,this 指针可能会引发混淆,而在 Python 中,self 的明确存在避免了这种问题。

  • C++

    • 在实例化对象时,编译器首先为对象分配内存(根据类的大小计算),然后调用构造函数。
    • 构造函数会初始化对象的状态(如成员变量)。
    • 对象在创建时,this 指针就指向该对象的内存地址,所以实例方法可以使用 this 来访问成员变量和方法。
  • Python

    • 在实例化时,Python 会动态为对象分配内存,内存大小由 Python 的对象模型决定。
    • 在 Python 中,self 是显式传递的,代表当前对象实例的引用。每当你调用实例方法时,Python 会将 self(即当前对象)作为第一个参数传递给方法。
    • 因为 Python 对象是动态管理的,所以内存的分配、垃圾回收等过程都由 Python 运行时来处理。

(4)实例化model

先定义输入和输出参数:

input_features = x.shape[1]
output_features = len(y.unique())

实例化:

torch.manual_seed(250)
net = model(in_features = input_features,out_features = output_features)
net.forward(x)

至此一个完整的前向传播就已经完成了,结果如下:

下一步我们可以查看一下层的各种属性:

可以看到输出是500条数据,对于三个类别的概率,这也和最后的softmax层输出结果一致

同样的我们也可以查看,对应层的权重和b:

下面我们将每一层的形状输出来:

我们会发现,这里面的每一层权重的形状都是下一层的神经元个数和上一层神经元个数,是反过来的。例如这里的第一层,输入是20个特征第一层有13个神经元,这里却是(13,20)。这是因为为了矩阵乘法的维度匹配,整个流程的形状变化过程如下:

1.先将输入的特征矩阵转置变成(20,500)

2.第一层:(13,20)*(20,500) = (13,500)

3.第二层:(8,13)*(13,500)= (8,500)

4.输出层:(3,8)*(8,500) = (3,500)

5.最后softmax函数输出的时候会再次转置调回来,得到输出(500,3)


http://www.kler.cn/a/512646.html

相关文章:

  • CTTSHOW-WEB入门-爆破25-28
  • 内存 管理
  • 递归练习六(普通练习11-15)
  • SDL2:Android APP编译使用 -- SDL2多媒体库使用音频实例
  • 学习第七十四行
  • 故障诊断 | BWO白鲸算法优化KELM故障诊断(Matlab)
  • 使用minio高性能存储图片
  • 电子应用设计方案91:智能AI花洒系统设计
  • C# 常用的文件处理方法
  • 【STM32-学习笔记-12-】PWR电源控制
  • 数据结构(精讲)----绪论
  • C# 委托(Delegate)的使用方法及使用场景
  • MySQL可直接使用的查询表的列信息
  • Nginx:从入门到实战使用教程
  • 如何在Mac上优雅的使用nvm管理Node.js
  • 【 MySQL 学习2】常用命令
  • Chrome远程桌面无法连接怎么解决?
  • Vue.js组件开发-解决PDF签章预览问题
  • Python基础学习(五)文件和异常
  • AI之HardWare:英伟达NvidiaGPU性价比排名(消费级/专业级/中高端企业级)以及据传英伟达Nvidia2025年将推出RTX 5090/5080、华为2025年推出910C/910D
  • Android系统开发(八):从麦克风到扬声器,音频HAL框架的奇妙之旅
  • Docker 之mysql从头开始——Docker下mysql安装、启动、配置、进入容器执行(查询)sql
  • 深度学习基础:自动梯度、线性回归与逻辑回归的 PyTorch 实践
  • 【GORM】初探gorm模型,字段标签与go案例
  • 手写 拖拽 修改参数
  • HDFS的Java API操作