全连接神经网络

news2024/9/27 19:23:50

这里写目录标题

  • 全连接神经网络vs前馈神经网络
  • 基于全连接神经网络的手写数字识别
    • 使用Pytorch实现
    • 纯Python实现
  • 全连接神经网络的局限

端到端学习
深度学习有时也称为端到端机器学习(end-to-end machine learning)。这里所说的端到端是指从一端到另一端的意思,也就是从原始数据(输入)中获得目标结果(输出)的意思。

数据驱动
神经网络的性能依赖于大量的数据,通过训练数据来学习模式和特征。

大模型解决运筹优化问题中,一种端到端的方式是,输入问题描述,直接生成模型。而不需要经过中间的参数提取,结构化建模信息

全连接神经网络vs前馈神经网络

前馈神经网络是一类广义的神经网络架构,其中信号从输入层经过一系列隐藏层最终到达输出层,且信号只向前传播,不存在反馈连接。全连接神经网络是前馈神经网络的一种特殊形式。

全连接神经网络是一种特殊的前馈神经网络,其中每一层的每一个神经元都与下一层的每一个神经元相连。这意味着每个节点都接收来自前一层所有节点的输入,并对这些输入进行加权求和,然后通过激活函数输出。

z ( l ) = X W ( l ) ( ) z^{(l)} = XW^{(l)}() z(l)=XW(l)()

基于全连接神经网络的手写数字识别

mini-batch学习(小批量学习)
MNIST数据集的训练数据有60000个,如果以全部数据为对象求损失函数的和,则计算过程需要花费较长的时间。再者,如果遇到大数据,数据量会有几百万、几千万之多,这种情况下以全部数据为对象计算损失函数是不现实的。因此,我们从全部数据中选出一部分,作为全部数据的“近似”。神经网络的学习也是从训练数据中选出一批数据(称为mini-batch,小批量),然后对每个mini-batch进行学习。比如,从60000个训练数据中随机选择100笔,再用这100笔数据进行学习。这种学习方式称为mini-batch学习。

计算电视收视率时,并不会统计所有家庭的电视机,而是仅以那些被选中的家庭为统计对象。比如,通过从关东地区随机选择 1000个家庭计算收视率,可以近似地求得关东地区整体的收视率。这 1000个家庭的收视率,虽然严格上不等于整体的收视率,但可以作为整体的一个近似值。和收视率一样,mini-batch的损失函数也是利用一部分样本数据来近似地计算整体。也就是说,用随机选择的小批量数据(mini-batch)作为全体训练数据的近似值。

损失函数
交叉熵损失(Cross-Entropy Loss)在分类任务中非常常用,尤其是多分类问题。交叉熵损失的公式如下:
L ( Y , Y ^ ) = − 1 m ∑ i = 1 m ∑ j = 1 C Y i j log ⁡ ( Y ^ i j ) L(Y, \hat{Y})= -\frac{1}{m} \sum_{i=1}^{m} \sum_{j=1}^{C} Y_{ij} \log(\hat Y_{ij}) L(Y,Y^)=m1i=1mj=1CYijlog(Y^ij)

其中:

  • Y Y Y 是真实标签(one-hot编码形式), Y ^ \hat{Y} Y^ 是模型预测的概率分布。
  • m m m 是样本数量。
  • C C C 是类别数量。
  • Y i j Y_{ij} Yij是第 i i i 个样本在第 j j j 类的真实标签(1或0)。
  • Y ^ i j \hat{Y}_{ij} Y^ij是第 i i i 个样本在第 j j j 类的预测概率。

使用Pytorch实现

步骤

  1. 数据预处理:
    • 使用 transforms.ToTensor() 将图像转换为张量。
    • 使用 transforms.Normalize() 进行归一化处理。
  2. 加载数据集:
    • 使用 torchvision.datasets.MNIST 加载MNIST数据集。
    • 使用 torch.utils.data.DataLoader 创建数据加载器。
  3. 定义神经网络模型:
    • 使用 nn.Module 定义一个简单的全连接神经网络(FCNN)。
    • 包含三个全连接层和ReLU激活函数。
  4. 定义损失函数和优化器:
  5. 使用 nn.CrossEntropyLoss 作为损失函数。使用 optim.Adam 作为优化器。
  6. 训练模型:进行前向传播、计算损失、反向传播和参数更新。
  7. 测试模型。在测试数据集上评估模型性能,计算准确率。

完整代码

# 下载数据集
from torchvision import datasets, transforms
import torchvision
import torch
import torch.nn as nn  # torch.nn 模块包含了构建和训练神经网络所需的各种类和函数
import torch.optim as optim  # torch.optim 模块包含了各种优化算法

import matplotlib.pyplot as plt

batch_size = 256  # 一次处理图片的数量
# Data set
train_dataset = torchvision.datasets.MNIST(
    root="./data",  # 数据集下载位置
    train=True,  # 是否作为训练集
    download=True,  # =True为从网络下载数据集,若已经下载,则不会再次下载
    transform=transforms.ToTensor(),  # 一般来说,下载的是numpy格式,要转为tensor
)

test_dataset = torchvision.datasets.MNIST(
    root="./data", train=False, transform=transforms.ToTensor()
)

# Data loader
train_loader = torch.utils.data.DataLoader(
    dataset=train_dataset, batch_size=batch_size, shuffle=True
)

test_loader = torch.utils.data.DataLoader(
    dataset=test_dataset, batch_size=batch_size, shuffle=False
)
print(train_dataset)
print(test_dataset)
print(train_loader, type(train_loader), len(train_loader))
print(test_loader)

# train_loader 是一个 DataLoader 对象,它实现了迭代器协议,因此可以在 for 循环中使用。每次迭代时,train_loader 会返回一个批次的数据和对应的标签。

fig, axes = plt.subplots(16, 16)
for batch_idx, (data, target) in enumerate(train_loader):
    print(f"batch index : {batch_idx}")
    print(f"data shape: {data.shape}")
    print(f"target shape :{target.shape}")
    for batch_index in range(16):
        for j in range(16):
            index = batch_index * 16 + j
            image = data[index].numpy().squeeze()
            axes[batch_index][j].imshow(image, cmap="gray")
            axes[batch_index][j].set_title(f"{target[index]}", fontsize=12)
            axes[batch_index][j].axis(
                "off"
            )  # 隐藏每个子图的坐标轴,移除子图的坐标轴线、刻度和刻度标签
    fig.tight_layout(pad=0.2, w_pad=0, h_pad=0)
    plt.show()
    break


# 定义全连接神经网络模型
class FCNN(nn.Module):
    # 这里定义了一个名为 FCNN 的类,继承自 nn.Module。nn.Module 是所有神经网络模块的基类。
    """
    这个网络是一个简单的三层全连接神经网络,用于处理MNIST手写数字识别任务。MNIST数据集中的每张图像是28x28像素的灰度图像,表示0到9的手写数字。"""

    def __init__(self):
        super(FCNN, self).__init__() # 调用父类 nn.Module 的初始化方法。
        self.fc1 = nn.Linear(28 * 28, 512) # 定义第一个全连接层(线性层),输入大小为28x28(784个像素),输出大小为512个神经元。
        self.fc2 = nn.Linear(512, 256) # 定义第二个全连接层,输入大小为512个神经元,输出大小为256个神经元。
        self.fc3 = nn.Linear(256, 10) # 定义第三个全连接层,输入大小为256个神经元,输出大小为10个神经元(对应0到9的10个类别)。

    def forward(self, x):
        x = x.view(-1, 28 * 28)  # 将输入展平
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x


model = FCNN()

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() #  PyTorch 中用于多分类任务的损失函数
"""
optim.Adam 是 PyTorch 中的 Adam 优化器,它是一种自适应学习率优化算法,结合了 AdaGrad 和 RMSProp 的优点。
model.parameters() 返回模型中所有需要优化的参数(即权重和偏置)
lr=0.001 设置了优化器的学习率,学习率决定了每次参数更新的步长
"""
optimizer = optim.Adam(model.parameters(), lr=0.001)



# 训练模型
num_epochs = 5
loss_list = []
for epoch in range(num_epochs):
    running_loss = 0.0
    for batch_index, data in enumerate(train_loader, 0):
        inputs, labels = data

        optimizer.zero_grad() # 清除梯度缓存

        outputs = model(inputs) # 前向传播
        loss = criterion(outputs, labels) #  计算损失
        loss.backward() # 反向传播
        optimizer.step() # 更新模型参数

        running_loss += loss.item() # 累积损失
        if batch_index % 100 == 99:  # 每100个批次打印一次损失
            avg_loss = running_loss / 100
            loss_list.append(avg_loss)
            print(f"Epoch {epoch + 1}, Batch {batch_index + 1}, Loss: {running_loss / 100:.3f}")
            running_loss = 0.0

print("Finished Training")

# 测试模型
correct = 0
total = 0

with torch.no_grad():
    for data in test_loader:
        images, labels = data
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f"Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%")


在这里插入图片描述

纯Python实现

import torch
import torchvision
import torchvision.transforms as transforms
import numpy as np

# 定义数据转换
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# 加载训练和测试数据集
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)

# 定义神经网络模型
class SimpleNN:
    def __init__(self, input_size, hidden_size, output_size):
        # 初始化权重和偏置
        """
        使用标准正态分布生成随机权重是一种常见的初始化方法,原因如下:
        用标准正态分布(均值为0,标准差为1)生成随机权重,可以帮助保持每层的激活值的方差稳定。具体来说:
            如果权重初始化得太大,激活值可能会爆炸(变得非常大),导致梯度爆炸问题。
            如果权重初始化得太小,激活值可能会消失(变得非常小),导致梯度消失问题。
        通过使用标准正态分布生成随机权重,可以在一定程度上避免这些问题,使得激活值在合理的范围内变化,从而有助于稳定训练过程。
        """
        
        self.W1 = np.random.randn(input_size, hidden_size) * 0.01 # 这样做的目的是将权重初始化为较小的值,避免初始权重过大导致的梯度爆炸问题。
        self.b1 = np.zeros((1, hidden_size))
        self.W2 = np.random.randn(hidden_size, output_size) * 0.01
        self.b2 = np.zeros((1, output_size))

    def relu(self, Z):
        return np.maximum(0, Z)

    def relu_derivative(self, Z):
        return Z > 0

    def softmax(self, Z):
        expZ = np.exp(Z - np.max(Z, axis=1, keepdims=True))
        return expZ / np.sum(expZ, axis=1, keepdims=True)

    def forward(self, X):
        # 前向传播
        self.Z1 = np.dot(X, self.W1) + self.b1
        self.A1 = self.relu(self.Z1)
        self.Z2 = np.dot(self.A1, self.W2) + self.b2
        self.A2 = self.softmax(self.Z2)
        return self.A2

    def compute_loss(self, Y, Y_hat):
        # 计算交叉熵损失
        m = Y.shape[0]
        log_likelihood = -np.log(Y_hat[range(m), Y])
        loss = np.sum(log_likelihood) / m
        return loss

    def backward(self, X, Y, Y_hat):
        # 反向传播
        m = X.shape[0]
        dZ2 = Y_hat
        dZ2[range(m), Y] -= 1
        dZ2 /= m

        self.dW2 = np.dot(self.A1.T, dZ2)
        self.db2 = np.sum(dZ2, axis=0, keepdims=True)
        dA1 = np.dot(dZ2, self.W2.T)
        dZ1 = dA1 * self.relu_derivative(self.Z1)

        self.dW1 = np.dot(X.T, dZ1)
        self.db1 = np.sum(dZ1, axis=0, keepdims=True)

    def update_parameters(self, learning_rate):
        # 更新参数
        self.W1 -= learning_rate * self.dW1
        self.b1 -= learning_rate * self.db1
        self.W2 -= learning_rate * self.dW2
        self.b2 -= learning_rate * self.db2

# 训练模型
def train(model, trainloader, epochs, learning_rate):
    for epoch in range(epochs):
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0):
            print("batch index", i)
            inputs, labels = data
            inputs = inputs.view(inputs.size(0), -1).numpy()  # 展平输入
            labels = labels.numpy()

            # 前向传播
            Y_hat = model.forward(inputs)
            
            # 计算损失
            loss = model.compute_loss(labels, Y_hat)
            
            # 反向传播
            model.backward(inputs, labels, Y_hat)
            
            # 更新参数
            model.update_parameters(learning_rate)
            
            running_loss += loss
            if i % 100 == 99:  # 每100个批次打印一次损失
                avg_loss = running_loss / 100
                print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {avg_loss:.3f}')
                running_loss = 0.0

# 初始化模型
"""
input_size  在全连接神经网络中,输入层的神经元数量应与输入数据的特征数量相同
hidden_size 藏层的神经元数量是一个超参数,需要通过实验进行调整。隐藏层的神经元数量决定了网络的容量和复杂度。更多的神经元可以捕捉到更复杂的特征,但也可能导致过拟合和计算开销增加。128个神经元是一个合理的起点,可以在实际应用中根据需要进行调整。
输出层(output_size = 10):与分类任务的类别数量相同,MNIST数据集有10个类别,因此输出层的神经元数量为10。
"""
input_size = 784  # 28x28
hidden_size = 128
output_size = 10
model = SimpleNN(input_size, hidden_size, output_size)

# 训练模型
epochs = 5
learning_rate = 0.1
train(model, trainloader, epochs, learning_rate)

# 测试模型
def predict(model, testloader):
    correct = 0
    total = 0
    for data in testloader:
        inputs, labels = data
        inputs = inputs.view(inputs.size(0), -1).numpy()  # 展平输入
        labels = labels.numpy()

        Y_hat = model.forward(inputs)
        predictions = np.argmax(Y_hat, axis=1)
        total += labels.size
        correct += (predictions == labels).sum()

    accuracy = correct / total
    print(f'Accuracy: {accuracy * 100:.2f}%')

predict(model, testloader)

全连接神经网络的局限

全连接的神经网络中使用了全连接层(Affine层)。在全连接层中,相邻层的神经元全部连接在一起,输出的数量可以任意决定。这会有一个问题:那就是数据的形状被忽视了。

比如,输入数据是图像时,图像通常是高、长、通道方向上的3维形状。但是,向全连接层输入时,需要将3维数据拉平为1维数据。实际上,前面提到的使用了MNIST数据集的例子中,输入图像就是1通道、高28像素、长28像素的(1, 28, 28)形状,但却被排成1列,以784个数据的形式输入到最开始的Affine层。

图像是3维形状,这个形状中应该含有重要的空间信息。比如,空间上邻近的像素为相似的值、RGB的各个通道之间分别有密切的关联性、相距较远的像素之间没有什么关联等,3维形状中可能隐藏有值得提取的本质模式。但是,因为全连接层会忽视形状,将全部的输入数据作为相同的神经元(同一维度的神经元)处理,所以无法利用与形状相关的信息。

而卷积层可以保持形状不变。当输入数据是图像时,卷积层会以3维数据的形式接收输入数据,并同样以3维数据的形式输出至下一层。因此,在CNN中,可以(有可能)正确理解图像等具有形状的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2165642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

西门子因为TC在与PTC及达索的混战中占据优势,西门子与SAP的合作价值几何?(2)

今天这篇文章是通过腾讯会议先录了一个视频然后转录的,看看效果怎么样。 主要是我昨天写了一篇公众号的文章,这篇文章是转自国外的一个记者。写的是他对这个工业软件三巨头西门子、达索和PTC之间的竞争做的一个访谈性质的文章,谈了他的一些看…

1.1.5 计算机网络的性能指标(上)

信道: 表示向某一方向传送信息的通道(信道!通信线路)一条通信线路在逻辑上往往对应一条发送信道和一条接收信道。 速率: 指连接到网络上的节点在信道上传输数据的速率。也称数据率或比特率、数据传输速率。 速率单…

python常见的魔术方法

什么是魔术方法 Python类的内置方法,各自有各自的特殊功能,被称之为魔术方法 常见的魔术方法有以下: __init__:构造方法 __str__:字符串方法 __lt__:小于、大于符号比较 __le__:小于等于、大于等于符合比较 __eq__:等于符合比较__init__ c…

【论文速看】DL最新进展20240925-医学图像分割、目标跟踪、图像超分

目录 【医学图像分割】【目标跟踪】【图像超分】 【医学图像分割】 [2024] UU-Mamba: Uncertainty-aware U-Mamba for Cardiovascular Segmentation 论文链接:https://arxiv.org/pdf/2409.14305 代码链接:https://github.com/tiffany9056/UU-Mamba 在深…

【NLP】循环神经网络--RNN学习.day3

一.初步认识RNN 循环神经网络(Recurrent Neural Network, RNN)是一种用于处理序列数据的深度学习模型。与传统的静态神经网络相比,RNN 可以有效处理输入数据的时间序列特性。这使得 RNN 在处理自然语言处理(NLP)、时间…

【Python报错已解决】TypeError: forward() got an unexpected keyword argument ‘labels‘

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 专栏介绍 在软件开发和日常使用中,BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

使用API有效率地管理Dynadot域名,注册域名服务器(NS)信息

前言 Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮箱&…

【9.模块化开发和代码重用之——头文件、动静态库】

目录 前言软件工程的基本原则程序的模块化开发和代码重用技术开发自己的头文件定义实现自己的头文件编写实现文件(源文件)编译代码链接目标文件到可执行文件 实现类似标准库效果的几种方法实际使用的开发方法头文件库 尝试自动链接静态库(好像…

替换jar包中class文件

虽然.jar文件是一种Java归档文件,可以使用压缩软件打开,但是并不能通过压缩软件来修改其内容,只能通过jar命令来更新文件。 一、背景 在使用血氧仪SDK时出现了问题,经过分析是在申请权限时版本不兼容导致的闪退异常,…

大数据新视界 --大数据大厂之 Kylin 多维分析引擎实战:构建数据立方体

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

全国信息学奥赛泄题事件:一场对公平与公正的严峻考验

在科技与教育日益融合的今天,信息学奥林匹克竞赛作为选拔计算机科学领域未来人才的重要平台,始终承载着培养青少年逻辑思维、编程能力和创新潜力的重任。然而,2024年9月发生的一起全国CSP-J/S认证考试泄题事件,却如同一枚重磅炸弹…

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架 一、 什么是Shiro二、Shiro 组件核心组件其他组件 三、流程说明shiro的运行流程 四、SpringBoot 集成 Shiro (shiro-spring-boot-web-starter方式)1. 添加 Shiro 相关 maven2…

领导让部署一个系统服务,我该怎么弄?

文章目录 Dockerdocker基础通过Dockerfile构建镜像打包镜像,离线使用docker修改代理内容 Nginxubuntu安装nginxnginx基本操作 问题Sqlalchemy可以反射一些表,另外一些反射为None查看服务器的架构和版本,查看本机外网IPPG数据库创建角色创建库…

CentOS7 离线部署docker和docker-compose环境

一、Docker 离线安装 1. 下载docker tar.gz包 下载地址: Index of linux/static/stable/x86_64/ 本文选择版本:23.0.6 2.创建docker.service文件 vi docker.service文件内容如下: [Unit] DescriptionDocker Application Container Engi…

SpringBoot中XXL-JOB实现灵活控制的分片处理方案

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

9.25盒马鲜生一面

1.自我介绍 2.css两种盒子模型 ​3.rem和em 4.px概念 5.transition和animation的区别 6.移动端适配方案 7.vh、vw、% 8.js基本数据类型 9.call、apply、bind的区别 10.js实现继承的方法 11.get和post的区别 12.web安全&#xff08;XSS&#xff0c;CSRF&#xff09; …

甩锅笔记:好好的服务端应用突然起不来,经定位是无法访问外网了?测试又说没改网络配置,该如何定位?

在工作中、团队协作时&#xff0c;可能遇到的问题&#xff0c;如集成测试等场景。但是作为偏前端的全栈&#xff0c;锅从天上来&#xff0c;不是你想甩就能甩&#xff0c;尤其面对测试等比较强势的团体&#xff08;bug创造者&#xff09;&#xff0c;你必须有强大的心理承受能力…

Vscode Run Code Py中文乱码问题

F1打开命令行界面&#xff0c;找到settings.json文件&#xff1b;选Workspace这个 找/直接输"code-runner.executorMap" python值改为"$pythonPath $fullFileName"

进程和线程的区别;线程的多种创建方式;Thread 类及常见方法;线程的状态

文章目录 进程和线程的区别线程的创建方式继承Thread&#xff0c;重写run&#xff08;创建单独的类/匿名内部类&#xff09;实现Runnable&#xff0c;重写run&#xff08;创建单独的类/匿名内部类&#xff09;实现Callable&#xff0c;重写call&#xff08;创建单独的类/匿名内…

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建 Jupyter Notebook

828华为云征文 | 云服务器Flexus X实例&#xff0c;Docker集成搭建 Jupyter Notebook Docker 部署 Jupyter Notebook 是一个方便且快速的方式&#xff0c;可以帮助你搭建一个用于数据分析、机器学习和科学计算的环境 华为云端口放行 服务器放行对应端口9955 Docker安装并配置镜…