9.23-9.29学习周报

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


目录

摘要

本周开始了神经网络的学习,了解了神经网络的结果,各层功能,理解前向传播和反向传播的原理和代码。并且开始进行cnn有关方面的学习,了解了cnn的应用和cnn的结构作用,能够理解卷积层所谓的"卷积"操作是如何进行的,能够手动推算过程。pytorch本周学习了DataLoader可以更方便地迭代训练数据集,学习了用nn.module来搭建神经网络。

Abstract

This week, I started the study of neural networks, understanding the results of neural networks, the functions of each layer, and understanding the principles and codes of forward propagation and backpropagation. In addition, I began to study CNN, understand the application of CNN and the structural role of CNN, understand how the so-called “convolution” operation of convolutional layer is carried out, and be able to manually calculate the process. This week, pytorch learned how DataLoader can more easily iterate on training datasets, and learned how to use nn.module to build neural networks.


提示:以下是本篇文章正文内容,下面案例可供参考

一、神经网络

无论是线性回归还是逻辑回归都有这样一个缺点,即:当特征太多时,计算的负荷会非常大。当我们使用 x 1 x_1 x1, x 2 x_2 x2 的多次项式进行预测时,我们可以应用的很好。假设我们有非常多的特征,例如大于100个变量,我们希望用这100个特征来构建一个非线性的多项式模型,结果将是数量非常惊人的特征组合,即便我们只采用两两特征的组合 ( x 1 x 2 + x 1 x 3 + x 1 x 4 + . . . + x 2 x 3 + x 2 x 4 + . . . + x 99 x 100 ) (x_1x_2+x_1x_3+x_1x_4+...+x_2x_3+x_2x_4+...+x_{99}x_{100}) (x1x2+x1x3+x1x4+...+x2x3+x2x4+...+x99x100),我们也会有接近5000个组合而成的特征。这对于一般的逻辑回归来说需要计算的特征太多了。
普通的逻辑回归模型,不能有效地处理这么多的特征,这时候我们需要神经网络。

神经网络的结构可以理解为我们人脑的迷你版。有很多个神经元组成,每个神经元由激活函数构成。在神经网络中,参数又可被称为权重(weight)

神经网络基本结构通常包括以下部分:
1.输入层:接收输入数据,每个神经元对应输入特征的一个维度。
2.隐藏层:一个或多个中间层,包含神经元,通过激活函数处理输入。层数和神经元数量决定了网络的复杂性。
3.输出层:产生最终的预测结果,其结构取决于任务类型(分类或回归)。
4.神经元:每个神经元接收来自前一层的输入,进行加权求和后通过激活函数输出结果。
5.激活函数:非线性函数(如ReLU、Sigmoid、Tanh)用于引入非线性,帮助网络学习复杂的模式。
6.连接权重:每个连接都有一个权重,表示输入对输出的重要性,训练过程中会调整这些权重。
在这里插入图片描述
该图为一个普通的神经网络。总共有四层,中间三层为隐藏层。隐藏层中的每个小圆圈对应一个神经元,神经元接收来自上一层的输出,经过激活函数处理后加权求和输出给下一次处理,第四层的输出层输出最终结果。其中 a i ( j ) a_{i}^{\left( j \right)} ai(j) 代表第 j j j 层的第 i i i 个激活单元(上层下个

1.前向传播

前向传播是将输入数据通过神经网络的各层传递,计算输出的过程。我们来看以下例子。
在这里插入图片描述
特征通过向量x输入到第一层,第一层有25个神经元,他们分别对输入的特征进行处理,即g(w11x+b11)…g(w2525x+b2525)。经过第一层处理后的结果我们用向量a1来表示,接着我们将向量a1传入第二层,经过第二层神经元的处理,即g(w21a1+b21)…g(w215a1+b215),最终得到a2。将a2传到第三层,g(w3a2+b3)得到最终结果a3
在这里插入图片描述
在这里插入图片描述
我们还可以用代码的形式表示一个前向传播。

import torch
import torch.nn as nn

# 定义神经网络模型
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(10, 5)  #第一层: 输入的是10个特征,输出的是5个特征
        self.relu = nn.ReLU()         # ReLU激活函数
        self.fc2 = nn.Linear(5, 1)    # 第二层:输入5个特征,也就是第一层的输出,输出1个特征

    def forward(self, x):
        x = self.fc1(x)              # 第一层前向传播
        x = self.relu(x)             # 应用ReLU激活
        x = self.fc2(x)              # 第二层前向传播
        return x

# 创建模型实例
model = SimpleNN()

# 生成随机输入数据
input_data = torch.randn(1, 10)  # 批量大小为1,特征维度为10

# 前向传播
output = model(input_data)

# 打印输出
print("Model output:", output)


在此解释一下,输入输出的维度指的是特征和类别的个数,隐藏层的维度指的是神经元的数量在这里插入图片描述前向传播用于生成模型的输出,并计算损失函数(例如,均方误差、交叉熵等)来评估预测结果与真实标签之间的差距。

2.反向传播

前面说到我们利用前向传播算出来模型的输出或者损失函数,当我们求出结果以后想要知道各个特征对于最终结果的影响大小并且更新我们的参数,这时我们就要通过反向传播来计算。
反向传播是通过链式法则计算损失函数关于每个权重(参数)的梯度,并更新权重(参数)的过程。
我们来看以下例子:
在这里插入图片描述
如图所示,我们根据下x,y,z三个参数通过前向传播得到了我们的输出f=-12,此时我们想要减小我们的输出f,应该如何调整我们的参数x,y,z?

我们先要求出各个参数的权重,也就是要对各个参数求偏导:根据链式法则:
在这里插入图片描述
下面我们来通过代码来实现反向传播:

import torch
import torch.nn as nn
import torch.optim as optim

# 1. 创建一个简单的全连接神经网络
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(1, 10)  # 输入层到隐藏层
        self.fc2 = nn.Linear(10, 1)   # 隐藏层到输出层

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 使用ReLU激活函数
        x = self.fc2(x)
        return x

# 2. 生成随机数据
# y = 2 * x + 1
x_data = torch.randn(100, 1)  # 100个样本,1个特征
y_data = 2 * x_data + 1 + 0.1 * torch.randn(100, 1)  # 添加一些噪声

# 3. 实例化模型、定义损失函数和优化器
model = SimpleNN()
criterion = nn.MSELoss()  # 均方误差损失
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 随机梯度下降优化器

# 4. 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    # 前向传播
    optimizer.zero_grad()  # 清除之前的梯度
    outputs = model(x_data)  # 获取模型输出
    loss = criterion(outputs, y_data)  # 计算损失

    # 反向传播
    loss.backward()  # 计算梯度
    optimizer.step()  # 更新权重

    # 每100个epoch打印一次损失
    if (epoch+1) % 100 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

# 5. 测试模型
with torch.no_grad():
    test_data = torch.tensor([[1.0]])  # 测试输入
    predicted = model(test_data)  # 预测输出
    print(f'Prediction for input 1.0: {predicted.item():.4f}')

首先我们先按照常规步骤,用nn.module定义和初始化神经网络骨架,写好我们的前向传播,生成随机输入。因为反向传播是通过结果来对我们的参数特征进行调整,所以我们用个for循环来对我们的神经网络进行训练,再运用反向传播backward()来计算权重,使用我们的优化器: SGD(随机梯度下降)来更新参数。
在这里插入图片描述
可以看到,随着我们不断地训练,通过不断地反向传播来进行参数的更新,我们的代价函数越来越小。

二、Dataloader

DataLoader用于将Dataset对象封装成可迭代的数据加载器。它提供了批量加载数据、数据打乱、并行加载等功能。DataLoader使得用户可以更方便地迭代训练数据集,并且支持多线程和多进程的数据加载,提高了数据加载的效率。
如下图所示,dataloader将dataset的数据通过batch_size来决定每次抽取的一个batch中有多少个数据而这些数据可以通过dataset中的getitem来返回。下面来看个具体例子:
在这里插入图片描述

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

test_set=torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
test_loader=DataLoader(dataset=test_set,batch_size=4,shuffle=True,num_workers=0,drop_last=False)

img,target=test_set[0]
writer=SummaryWriter("dataloader")
step=0
for data in test_loader:
    imgs,targets=data
    # print(imgs.shape)
    # print(targets)
    writer.add_images("test_loader",imgs,step)
    step=step+1

writer.close()

首先定义好我们的数据集将其用ToTensor转变为tensor格式,因为add_images要求tensor格式的数据,将batch_size设为4利用for循环调整步幅,最后记得把writer关闭。
在这里插入图片描述

三、 nn.module构建神经网络基本框架

关于如何去搭建神经网络,我们可以从pytorch的官方文档来查看:在这里插入图片描述
torch.nn中的nn是神经网络(neural network)的缩写,我们创建该实例必须要继承这个module。因为他是所有神经网络的基类。

线性图层: nn.Linear,nn.Bilinear
卷积层 :nn.Conv1d,nn.Conv2d,nn.Conv3d,nn.ConvTranspose2d
非线性: nn.Sigmoid,nn.Tanh,nn.ReLU,nn.LeakyReLU
池化层: nn.MaxPool1d,nn.AveragePool2d
Recurrent网络 :nn.LSTM,nn.GRU
标准化 :nn.BatchNorm2d
Dropout nn.Dropout,nn.Dropout2d
Embedding - nn.Embedding
损失函数 :nn.MSELoss,nn.CrossEntropyLoss,nn.NLLLoss

下面我们通过一个例子来搭建神经网络的框架:

import torch
import torch.nn as nn

class Lzj(nn.Module):
    def __init__(self):
        super(Lzj, self).__init__()##继承moudle基类并初始化
        self.layer1=nn.Linear(2,3) #第一层输入2个神经元(输入维度为2),输出3个神经元(输出维度为3)
        self.sigmoid=nn.Sigmoid()
        self.layer2=nn.Linear(3,1)#第二层输入3个神经元(输入维度为3),输出1个神经元(输出维度为1)

    def forward(self,input): #定义前向传播
        input=self.layer1(input)
        input=self.sigmoid(input)
        input=self.layer2(input)

        return input
lzj=Lzj()#创建神经网络实例

x=torch.randn(1,2)#生成随机输入,输入批量为1,通过2个神经元处理

output=lzj(x)

print(output)






该神经网络大致如下图所示:
在这里插入图片描述
由于是随机生产的输入结果,每次的输出结果都会有所不同:在这里插入图片描述

四、初识CNN

CNN就是我们所说的卷积神经网络。卷积神经网络的结构一般包括:

输入层:接受输入图像。
多个卷积层和池化层:进行特征提取。
一个或多个全连接层:用于分类任务。
输出层:生成最终输出(如类别概率)

卷积层(Convolutional Layer)(主要负责提取特征)
卷积操作:使用卷积核(滤波器)在输入数据上滑动,对输入进行局部特征提取。卷积操作可以挖掘输入图像中的局部关联性。
参数共享:同一卷积核在整个输入上共享权重,减少了参数的数量,从而降低了模型复杂度。
激活函数:通常在卷积层后使用激活函数(如 ReLU),以引入非线性因素。

池化层(Pooling Layer)(主要负责压缩特征)
目的:减小特征图的尺寸,从而降低计算量,并使特征具有平移不变性。
最大池化(Max Pooling):取池化窗口内的最大值。
平均池化(Average Pooling):取池化窗口内的平均值。

在这里插入图片描述
从模型上看传统神经网络更像是个二维的,而cnn是个三维的神经网络。严格来说,卷积层是个错误的叫法,因为它所表达的运算其实是互相关运算(cross-correlation),而不是卷积运算

卷积层首先对我们输入的数据进行区域划分,然后对每个区域的特征进行提取。我们来看一下例子:在这里插入图片描述
我们输入图片进入卷积层后,首先要根据卷积核对图片进行分割,分割完成后通过卷积核与对应部分图片进行互相关运算,也就是对应位置进行相乘结果再相加得到我们的特征值。然后再滑动卷积核进行运算算出其他特征值得到我们的特征图。

注意:分割好的图片与卷积核进行计算时千万不要搞成矩阵乘法!
在这里插入图片描述
上图中我们通过输入一个5x5的图片得到一个特征图就是执行一次卷积操作的结果。

卷积核我们可以是不变的,也可以定义多个。
在大多数标准卷积神经网络(CNN)中,卷积核在训练过程中是固定的,意味着每次应用相同的卷积核来处理输入图像的不同区域。这些卷积核的参数在训练阶段通过反向传播算法进行更新,但在每个前向传播步骤中,它们的结构是一样的。

在某些特殊的模型(例如动态卷积网络)中,卷积核可能在每次计算中是不同的。这种情况下,卷积核的参数可以根据输入动态生成。这种方法通常用于提高模型的表达能力和适应性。

总结

下周继续对cnn进行理论和代码相结合的学习,争取能够用代码来构建cnn对图片进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值