一、什么是前馈网络 / 全连接网络?​

前馈网络(Feedforward Neural Network)是信号单向传播的网络:输入层→隐藏层→输出层,没有反馈回路,就像水流从高处往低处流,不会回头。​

而全连接网络(Fully Connected Network, FCN) 是前馈网络的 “经典款”—— 它的每一层神经元,都会和下一层的所有神经元建立连接。比如输入层有 10 个神经元,隐藏层有 20 个神经元,那这两层之间就有 10×20=200 个连接(每个连接对应一个权重参数)。​

优点:结构简单、易于理解;缺点:参数多,容易过拟合(后面会讲怎么解决)。​

二、最小单元:单个神经元的构造与激活函数​

全连接网络的 “积木” 是单个神经元,先搞懂它,再看多层网络就很简单了。​

2.1 单个神经元的结构​

一个神经元的工作流程分 3 步:​

  1. 接收输入:比如特征向量 ​

    x1​,x2​,...,xn​;​

  1. 线性组合:给每个输入加个 “权重”(重要性),再加上 “偏置”(调整基线),公式是 ​

    z=i=1∑n​wi​xi​+b;​

  1. 非线性变换:通过激活函数把线性结果 “掰弯”,得到输出 ​a=f(z)
    —— 没有这一步,多层网络就等价于单层线性模型,根本拟合不了复杂数据!​

2.2 3 个常用激活函数(附 MindSpore 调用)​

激活函数的选择直接影响模型效果,这 3 个是实战中最常用的,记牢它们的特点和用法:​

激活函数​

公式​

核心特点​

适用场景​

MindSpore API​

Sigmoid​

σ(z)=1+e−z1​

输出范围 (0,1),可表示概率;但输入绝对值大时会 “梯度消失”​

二分类输出层、早期隐藏层​

mindspore.nn.Sigmoid()​

ReLU​

ReLU(z)=max(0,z)

解决梯度消失,计算快;但输入为负时神经元会 “死亡”(永久失效)​

隐藏层(最常用)​

mindspore.nn.ReLU()​

Softmax​

softmax(zi​)=∑j=1k​ezj​ezi​​

输出是概率分布(和为 1),多分类任务必用​

多分类输出层​

mindspore.nn.Softmax(axis=-1)​

小技巧:隐藏层优先用 ReLU,多分类输出层固定用 Softmax;如果 ReLU “死亡” 严重,换成 Leaky ReLU(mindspore.nn.LeakyReLU(alpha=0.1))。​

三、模型怎么训练?参数求解的核心逻辑​

全连接网络的训练,本质是 “优化权重 ​w和偏置 ​b”,让模型预测越来越准。整个过程分两步:定目标、找方法。​

3.1 第一步:定优化目标 —— 损失函数​

损失函数是 “裁判”,用来衡量模型预测值 ​y^​和真实标签 ​y的差距。不同任务选不同的损失函数:​

(1)回归任务(预测连续值,如房价、温度)​用均方误差(MSE),计算预测值和真实值的平方差平均值:​

公式:​L=N1​i=1∑N​(yi​−y^​i​)2

​MindSpore 调用:mindspore.nn.MSELoss()​

(2)分类任务(预测离散类别,如图片分类)​

用交叉熵损失,结合 Softmax 把输出转成概率,再算负对数似然(对多分类超友好):​

公式:​L=−N1​i=1∑N​c=1∑k​yi,c​log(y^​i,c​)

​MindSpore 调用:mindspore.nn.CrossEntropyLoss()(内置 Softmax,输入直接传 logits 就行,不用自己加 Softmax 层!)​

3.2 第二步:找优化方法 —— 梯度下降与反向传播​

有了损失函数,怎么让损失变小?靠梯度下降:沿损失函数的梯度负方向更新参数(梯度指 “损失增大最快的方向”,负方向就是 “损失减小最快的方向”)。​

而反向传播(Backpropagation) 是计算梯度的 “高效工具”—— 不用暴力遍历所有参数,而是用链式法则从输出层往输入层 “倒推”,快速算出每个参数的梯度。​

重点:MindSpore 会自动做反向传播!不用你手动推公式,框架通过 “自动微分” 帮你算好梯度,只管调用优化器就行。​

四、实战必看:4 个常用优化器(附 MindSpore 用法)​

基础梯度下降收敛慢、易震荡,实战中我们用改进后的优化器。这 4 个是业界主流,记好它们的优缺点:​

优化器​

核心逻辑​

优点​

注意事项​

MindSpore API​

动量(Momentum)​

累积历史梯度的 “动量”,像滚雪球一样加速收敛​

减少震荡,收敛更快​

需调 “动量因子”(通常设 0.9)​

nn.Momentum(net.trainable_params(), lr=0.01, momentum=0.9)​

Adagrad​

对稀疏特征用小学习率,密集特征用大学习率​

适合稀疏数据(如 NLP)​

学习率会单调下降,后期可能停滞​

nn.Adagrad(net.trainable_params(), lr=0.01)​

RMSprop​

改进 Adagrad,用 “指数移动平均” 代替累积梯度​

解决 Adagrad 停滞问题​

衰减系数默认 0.9,一般不用改​

nn.RMSprop(net.trainable_params(), lr=0.01, decay=0.9)​

Adam​

结合动量(一阶矩)和 RMSprop(二阶矩),自适应学习率​

收敛快、稳定,几乎万能​

学习率默认 0.001,大多数场景够用​

nn.Adam(net.trainable_params(), lr=0.001)​

实战建议:优先用 Adam!除非数据是稀疏的(如文本),再试 Adagrad/RMSprop。​

五、避坑关键:正则化解决过拟合​

训练时最头疼的问题就是过拟合:模型在训练集上准确率 99%,一到测试集就掉成 60%—— 这是因为模型 “死记” 了训练数据的噪声,没学会通用规律。​

5.1 过拟合 vs 欠拟合​

先分清两种常见问题:​

问题​

表现​

原因​

过拟合​

训练集准,测试集差​

模型太复杂(参数多)、数据少 / 噪声大​

欠拟合​

训练集、测试集都差​

模型太简单(层数少)、特征没选好​

5.2 4 个实战级正则化方法(附 MindSpore 实现)​

重点解决过拟合,这 4 个方法简单有效,直接上代码:​

(1)权重衰减(L2 正则化)​

给损失函数加个 “权重惩罚”,限制权重不能太大。MindSpore 不用改损失函数,直接在优化器里加参数:​

​# 给Adam优化器加权重衰减(正则化系数1e-4是常用值)​

optimizer = nn.Adam(net.trainable_params(), lr=0.001, weight_decay=1e-4)​

​(2)Dropout:随机 “关掉” 部分神经元​

训练时随机让一部分神经元输出为 0(保留概率 0.5~0.8),强迫模型不依赖单个神经元:​

​# 定义网络时,在隐藏层后加Dropout(保留概率0.5)​

class FCNet(nn.Cell):​

def __init__(self):​

super().__init__()​

self.fc1 = nn.Dense(100, 64, activation=nn.ReLU())​

self.drop = nn.Dropout(keep_prob=0.5) # 关键:Dropout层​

self.fc2 = nn.Dense(64, 10)​

def construct(self, x):​

x = self.fc1(x)​

x = self.drop(x) # 前向传播时经过Dropout​

return self.fc2(x)​

​(3)早停(Early Stopping)​

训练时监控验证集损失,一旦连续几轮不下降就停止,避免过度训练:​

​from mindspore.train.callback import EarlyStopping​

​# 定义早停:监控验证集准确率,连续3轮不涨就停​

early_stop = EarlyStopping(monitor='val_accuracy', patience=3, mode='max')​

​# 训练时传入早停回调​

model.train(epochs=20, train_dataset=train_ds, val_dataset=val_ds, callbacks=[early_stop])​

​(4)数据增强:给数据 “加戏”​

对训练数据做随机变换(如图片旋转、翻转),增加数据多样性,让模型学通用规律:​

​import mindspore.dataset.vision as vision​

​# 对图片数据集做增强:随机水平翻转(概率0.5)+随机裁剪(224x224)​

train_ds = train_ds.map(​

operations=[​vision.RandomHorizontalFlip(prob=0.5),​vision.RandomCrop(size=(224, 224))​],​

input_columns=["image"]​)​

​六、MindSpore 全流程实战:搭建全连接网络​

最后,把前面的知识点串起来,用 MindSpore 搭一个全连接网络,做 10 分类任务(比如 MNIST):​

步骤 1:导入库​

​import mindspore as ms​

import mindspore.nn as nn​

from mindspore.train import Model, EarlyStopping​

from mindspore.dataset import MnistDataset, vision, transforms​

​步骤 2:加载并预处理数据​​

# 加载MNIST数据集​

train_ds = MnistDataset('train')​

val_ds = MnistDataset('val')​

​# 数据预处理:转Tensor+归一化+展平(MNIST是28x28图片,展平成784维向量)​

trans = transforms.Compose([​

vision.ToTensor(), # 转成Tensor,像素值归一化到[0,1]​

vision.Reshape((-1, 784)) # 展平:(batch_size, 784)​])​

​train_ds = train_ds.map(operations=trans, input_columns=["image"]).batch(32)​

val_ds = val_ds.map(operations=trans, input_columns=["image"]).batch(32)​

​步骤 3:定义全连接网络​

​class FCNet(nn.Cell):​

def __init__(self, in_dim=784, hidden_dim=128, out_dim=10):​

super().__init__()​

self.fc1 = nn.Dense(in_dim, hidden_dim, activation=nn.ReLU())​

self.drop = nn.Dropout(keep_prob=0.7) # Dropout防止过拟合​

self.fc2 = nn.Dense(hidden_dim, out_dim) # 输出层:10个类别​

​def construct(self, x):​

# 前向传播​

x = self.fc1(x)​

x = self.drop(x)​

x = self.fc2(x)​

return x​

​# 初始化网络​

net = FCNet()​

​步骤 4:定义损失、优化器和模型​​

# 损失函数:多分类用交叉熵​

loss_fn = nn.CrossEntropyLoss()​

​# 优化器:Adam+权重衰减​optimizer = nn.Adam(net.trainable_params(), lr=0.001, weight_decay=1e-4)​​

# 早停回调​

early_stop = EarlyStopping(monitor='val_accuracy', patience=3, mode='max')​

# 封装模型(加准确率评估指标)​

model = Model(net, loss_fn=loss_fn, optimizer=optimizer, metrics={"accuracy"})​

​步骤 5:训练模型​

# 训练20轮,用验证集监控,早停防止过拟合​

model.train(​

epochs=20,​

train_dataset=train_ds,​

val_dataset=val_ds,​

callbacks=[early_stop],​

dataset_sink_mode=False # 非下沉模式,方便调试​

)​

​# 评估模型在测试集的效果​

acc = model.eval(val_ds)​

print(f"验证集准确率:{acc['accuracy']:.4f}")​

​运行代码,你会看到模型准确率稳步上升,早停会在合适的时候停止训练 —— 这样训练出的模型,泛化能力会更强!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐