基于前馈神经网络实现鸢尾花分类并与Softmax回归完成鸢尾花分类做对比

目录

基于前馈神经网络完成鸢尾花分类

实现代码:

实验结果:

不同训练轮数实验结果 :

修改偏置b后的实验结果:

 不同学习率实验结果:

总结实验: 

重点:小批量梯度下降法进行训练。

实验中新学习的库或方法:

基于Softmax回归完成鸢尾花分类 

实现代码:

实验结果:

不同训练轮数实验结果:

前馈神经网络实现鸢尾花分类与Softmax回归完成鸢尾花分类做对比分析


 

基于前馈神经网络完成鸢尾花分类

实现代码:

import torch
import torch.utils.data as io
import torch.nn.functional as F
from nndl.dataset import load_data
from torch import nn
from torchmetrics import Metric
import torch.optim as opt
import matplotlib.pyplot as plt

class IrisDataset(io.Dataset):
    def __init__(self, mode='train', num_train=120, num_dev=15):
        super(IrisDataset, self).__init__()
        X, y = load_data(shuffle=True)
        if mode == 'train':
            self.X, self.y = X[:num_train], y[:num_train]
        elif mode == 'dev':
            self.X, self.y = X[num_train:num_train + num_dev], y[num_train:num_train + num_dev]
        else:
            self.X, self.y = X[num_train + num_dev:], y[num_train + num_dev:]

    def __getitem__(self, idx):
        return self.X[idx], self.y[idx]

    def __len__(self):
        return len(self.y)

torch.manual_seed(12)
train_dataset=IrisDataset(mode='train')
dev_dataset=IrisDataset(mode='dev')
test_dataset=IrisDataset(mode='test')
print("length of train set:",len(train_dataset))

# 用DataLoader进行封装
# 批量大小
batch_size=16
# 加载数据
train_loader=io.DataLoader(train_dataset,batch_size=batch_size,shuffle=True)
dev_loader=io.DataLoader(dev_dataset,batch_size=batch_size)
test_loader=io.DataLoader(test_dataset,batch_size=batch_size)

# 模型构建
class Model_MLP_L2_V3(nn.Module):
    def __init__(self,input_size,output_size,hidden_size):
        super(Model_MLP_L2_V3,self).__init__()
        # 构建第一个全连接层
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc1.weight.data.normal_(mean=0.0, std=0.01)
        self.fc1.bias.data.fill_(1.0)
        # 构建第二全连接层
        self.fc2 = nn.Linear(hidden_size, output_size)
        self.fc2.weight.data.normal_(mean=0.0, std=0.01)
        self.fc2.bias.data.fill_(1.0)


        self.act=nn.Sigmoid()

    def forward(self, inputs):
        outputs = self.fc1(inputs)
        outputs = self.act(outputs)
        outputs = self.fc2(outputs)
        return outputs

fnn_model=Model_MLP_L2_V3(input_size=4,output_size=3,hidden_size=6)


class Accuracy(Metric):
    def __init__(self,is_logist=True):
        """
               输入:
                  - is_logist: outputs是logist还是激活后的值
        """
        # 用于统计正确样本数
        self.num_corretc=0
        # 用于统计样本个数
        self.num_count=0

        self.is_logist=is_logist

    def update(self,outputs,labels):
        """
            输入:
                - outputs: 预测值, shape=[N,class_num]
                - labels: 标签值, shape=[N,1]
        """
        if outputs.shape[1]==1:
            outputs=torch.squeeze(outputs,dim=-1)
            if self.is_logist:
                # logist判断是否大于0
                preds = (outputs >= 0).float()
            else:
                # 如果不是logist,判断每个概率值是否大于0.5,当大于0.5时,类别为1,否则类别为0
                preds = (outputs >= 0.5).float()

        # 多分类时,使用torch.argmax计算最大元素索引引用类别
        else:
            preds=torch.argmax(outputs,dim=1)

        # 获取本批数据中预测正确的样本个数
        labels=torch.squeeze(labels,dim=-1)
        batch_correct = torch.sum((preds == labels).float()).item()

        batch_count=len(labels)

        # 更新num_correct和num_count
        self.num_correct+=batch_correct
        self.num_count+=batch_count

    def compute(self):
        # 使用累计的数据,计算总的指标
        if self.num_count==0:
            return 0
        return self.num_correct/self.num_count

    def reset(self):
        # 重置正确的数目和总数
        self.num_correct=0
        self.num_count=0
    def name(self):
        return "Accuracy"

class RunnerV3(object):
    def __init__(self, model, optimizer, loss_fn, metric, **kwargs):
        self.model = model
        self.optimizer = optimizer
        self.loss_fn = loss_fn
        self.metric = metric  # 只用于计算评价指标

        # 记录训练过程中的评价指标变化情况
        self.dev_scores = []

        # 记录训练过程中的损失函数变化情况
        self.train_epoch_losses = []  # 一个epoch记录一次loss
        self.train_step_losses = []  # 一个step记录一次loss
        self.dev_losses = []

        # 记录全局最优指标
        self.best_score = 0

    def train(self, train_loader, dev_loader=None, **kwargs):
        # 将模型切换为训练模式
        self.model.train()

        # 传入训练轮数,如果没有传入值则默认为0
        num_epochs = kwargs.get("num_epochs", 0)
        # 传入log打印频率,如果没有传入值则默认为100
        log_steps = kwargs.get("log_steps", 100)
        # 评价频率
        eval_steps = kwargs.get("eval_steps", 0)

        # 传入模型保存路径,如果没有传入值则默认为"best_model.pdparams"
        save_path = kwargs.get("save_path", "best_model.pdparams")

        custom_print_log = kwargs.get("custom_print_log", None)

        # 训练总的步数
        num_training_steps = num_epochs * len(train_loader)

        if eval_steps:
            if self.metric is None:
                raise RuntimeError('Error: Metric can not be None!')
            if dev_loader is None:
                raise RuntimeError('Error: dev_loader can not be None!')

        # 运行的step数目
        global_step = 0

        # 进行num_epochs轮训练
        for epoch in range(num_epochs):
            # 用于统计训练集的损失
            total_loss = 0
            for step, data in enumerate(train_loader):
                X, y = data
                # 获取模型预测
                logits = self.model(X)
                loss = self.loss_fn(logits, y)  # 默认求mean
                total_loss += loss

                # 训练过程中,每个step的loss进行保存
                self.train_step_losses.append((global_step, loss.item()))

                if log_steps and global_step % log_steps == 0:
                    print(
                        f"[Train] epoch: {epoch}/{num_epochs}, step: {global_step}/{num_training_steps}, loss: {loss.item():.5f}")

                # 梯度反向传播,计算每个参数的梯度值
                loss.backward()

                if custom_print_log:
                    custom_print_log(self)

                # 小批量梯度下降进行参数更新
                self.optimizer.step()
                # 梯度归零
                self.optimizer.zero_grad()

                # 判断是否需要评价
                if eval_steps > 0 and global_step > 0 and \
                        (global_step % eval_steps == 0 or global_step == (num_training_steps - 1)):

                    dev_score, dev_loss = self.evaluate(dev_loader, global_step=global_step)
                    print(f"[Evaluate]  dev score: {dev_score:.5f}, dev loss: {dev_loss:.5f}")

                    # 将模型切换为训练模式
                    self.model.train()

                    # 如果当前指标为最优指标,保存该模型
                    if dev_score > self.best_score:
                        self.save_model(save_path)
                        print(
                            f"[Evaluate] best accuracy performence has been updated: {self.best_score:.5f} --> {dev_score:.5f}")
                        self.best_score = dev_score

                global_step += 1

            # 当前epoch 训练loss累计值
            trn_loss = (total_loss / len(train_loader)).item()
            # epoch粒度的训练loss保存
            self.train_epoch_losses.append(trn_loss)

        print("[Train] Training done!")

    # 模型评估阶段,使用'paddle.no_grad()'控制不计算和存储梯度
    @torch.no_grad()
    def evaluate(self, dev_loader, **kwargs):
        assert self.metric is not None

        # 将模型设置为评估模式
        self.model.eval()

        global_step = kwargs.get("global_step", -1)

        # 用于统计训练集的损失
        total_loss = 0

        # 重置评价
        self.metric.reset()

        # 遍历验证集每个批次
        for batch_id, data in enumerate(dev_loader):
            X, y = data

            # 计算模型输出
            logits = self.model(X)

            # 计算损失函数
            loss = self.loss_fn(logits, y).item()
            # 累积损失
            total_loss += loss

            # 累积评价
            self.metric.update(logits, y)

        dev_loss = (total_loss / len(dev_loader))
        dev_score = self.metric.compute()

        # 记录验证集loss
        if global_step != -1:
            self.dev_losses.append((global_step, dev_loss))
            self.dev_scores.append(dev_score)

        return dev_score, dev_loss

    # 模型评估阶段,使用'paddle.no_grad()'控制不计算和存储梯度
    @torch.no_grad()
    def predict(self, x, **kwargs):
        # 将模型设置为评估模式
        self.model.eval()
        # 运行模型前向计算,得到预测值
        logits = self.model(x)
        return logits

    def save_model(self, save_path):
        torch.save(self.model.state_dict(), save_path)

    def load_model(self, model_path):
        model_state_dict = torch.load(model_path)
        self.model.load_state_dict(model_state_dict)
# 模型训练
lr=0.2

# 定义网络
model=fnn_model

# 定义优化器
optimizer = opt.SGD(model.parameters(), lr=lr)

# 定义损失函数,softmax+交叉熵
loss_fn=F.cross_entropy

# 定义评价指标

metric = Accuracy(is_logist=True)
runner=RunnerV3(model,optimizer,loss_fn,metric)

# 启动训练
log_steps=100
eval_steps=50
runner.train(train_loader,dev_loader,num_epochs=500,log_steps=log_steps,eval_steps=eval_steps,save_path="best_model.pdparams")

# 可视化观察训练集损失和训练集loss变化情况。
# 绘制训练集和验证集的损失变化以及验证集上的准确率变化曲线
def plot_training_loss_acc(runner, fig_name,
                           fig_size=(16, 6),
                           sample_step=20,
                           loss_legend_loc="upper right",
                           acc_legend_loc="lower right",
                           train_color="#8E004D",
                           dev_color='#E20079',
                           fontsize='x-large',
                           train_linestyle="-",
                           dev_linestyle='--'):
    plt.figure(figsize=fig_size)

    plt.subplot(1, 2, 1)
    train_items = runner.train_step_losses[::sample_step]
    train_steps = [x[0] for x in train_items]
    train_losses = [x[1] for x in train_items]

    plt.plot(train_steps, train_losses, color=train_color, linestyle=train_linestyle, label="Train loss")
    if len(runner.dev_losses) > 0:
        dev_steps = [x[0] for x in runner.dev_losses]
        dev_losses = [x[1] for x in runner.dev_losses]
        plt.plot(dev_steps, dev_losses, color=dev_color, linestyle=dev_linestyle, label="Dev loss")
    # 绘制坐标轴和图例
    plt.ylabel("loss", fontsize=fontsize)
    plt.xlabel("step", fontsize=fontsize)
    plt.legend(loc=loss_legend_loc, fontsize=fontsize)

    # 绘制评价准确率变化曲线
    if len(runner.dev_scores) > 0:
        plt.subplot(1, 2, 2)
        plt.plot(dev_steps, runner.dev_scores,
                 color=dev_color, linestyle=dev_linestyle, label="Dev accuracy")

        # 绘制坐标轴和图例
        plt.ylabel("score", fontsize=fontsize)
        plt.xlabel("step", fontsize=fontsize)
        plt.legend(loc=acc_legend_loc, fontsize=fontsize)

    plt.savefig(fig_name)
    plt.show()


plot_training_loss_acc(runner, 'fw-loss.pdf')

# 加载最优模型
runner.load_model('best_model.pdparams')
# 模型评价
score, loss = runner.evaluate(test_loader)
print("[Test] accuracy/loss: {:.4f}/{:.4f}".format(score, loss))

# 获取测试集中第一条数据
X, label = next(iter(test_loader))
logits = runner.predict(X)

pred_class = torch.argmax(logits[0]).numpy()
label = label[0].numpy()

# 输出真实类别与预测类别
print("The true category is {} and the predicted category is {}".format(label, pred_class))

实验结果:

不同训练轮数实验结果 :
  • 训练100轮:

  • 训练150轮:

  • 训练200轮:

  • 训练400轮:

  • 训练600轮:

 分析:由训练数据,随着训练的轮数的增加,在验证集上,训练的准确率是呈逐渐升高的变化规律,直至稳定在0.933....左右,损失是呈逐渐降低的趋势变化的。在测试集上,准确率和损失是不变的,维持在1和1.0183,应该是对于测试集,100轮训练已经足够对它进行预测了,我试了下40轮训练发现,它的准确率很高并且损失也很小,应该是对于测试集过拟合了。

修改偏置b后的实验结果:
  • 随机初始化:

  • 初始化为1:

  • 初始化为0.5:

  • 初始化为0:

 根据实验结果来看,在训练集上,随机初始化的结果是最好的,相同条件下能够达到损失最小,但是对于测试集初始化为0损失是最低的,但是根据之前的了解,这个应该只是对于这个数据集好一点,一般情况下如果所有的偏置都初始化为零,可能会导致网络的对称性问题,使得每一层的输出相同。因此,零初始化在实践中很少使用,一般还是使用随机初始化相对好一点,也可以增加多样性。

 不同学习率实验结果:
  • 学习率为0.1:

  • 学习率为0.2:

  • 学习率为0.5:

  • 学习率为1.0: 

  •  学习率为3.0:

  

分析:相同的训练轮数,不同的学习率,对应的验证集损失和准确率都是逐渐优化的,但是在测试集上,损失先降低后升高,说明对于我们的模型来说,学习率的最优值是存在于这个区间的,越接近于最优值,训练收敛情况越好,当学习率太大时,会导致如下图所示的情况,导致网络无法收敛,产生梯度爆炸。学习率的设置还是根据经验设置,经过手动不断的测试,观察拟合情况,达到对于学习率的最优值。

总结实验: 

重点:小批量梯度下降法进行训练。

梯度下降法优化模型主要是将整个训练集上的风险函数(即损失函数)降到最低,这样是批量梯度下降法,每次迭代都计算数据集中所有样本的损失函数的梯度求和,当数据集样本容量很大时,将会导致训练的计算复杂度高,每次迭代开销也很大。

小批量梯度下降法就是为了解决这个问题:在每次迭代时都只随机采集含有K个样本(K:批量大小),只计算这一部分样本的损失并更新参数。这种方法收敛快,计算开销小。

实验中新学习的库或方法:

  • torch.utils.data.DataLoader:它的功能有对数据的自动批处理、并行加载和数据打乱等功能。接受一个数据集对象作为输入,并根据指定的参数将数据集划分成多个小批次进行加载。在该实验中就是使用它加载minibatch的数据,进行批处理。DataLoader的主要功能包括:
  1. 自动批处理:根据指定的batch_size参数,将数据集划分成小批次进行加载。
  2. 并行加载:可以使用多个子进程并行加载数据,加快数据加载速度。
  3. 数据打乱:可以在每个epoch开始前打乱数据顺序,增加数据的随机性和泛化能力。
  • torchmetrics :是一个用于评估模型性能的PyTorch库,其中的Metric类提供了各种常见的评估指标的计算和跟踪功能。它包含了许多常见的分类、回归和聚类任务的评估指标,如准确率、精确率、召回率、F1分数、均方根误差等。Metric类的功能包括:
  1. 计算指标:Metric类提供了计算各种评估指标的方法,可以根据预测值和真实值计算相应的指标。
  2. 跟踪指标:Metric类可以在每个批次或每个epoch结束时更新和跟踪指标的值,以便在训练或验证过程中进行监控和记录。

定义一个自定义的Metric类时,继承自Metric类,需要实现相应的计算逻辑和更新方法。

  1. 计算逻辑:
    class CustomMetric(Metric):
        def __init__(self):
            super().__init__()
            # 初始化指标的相关变量
    
        def update(self, preds, target):
            # 根据预测值和真实值更新指标的值
    
        def compute(self):#(需要注意:在paddle的模型中,这里是accumulate)
            # 计算并返回指标的最终值
  2. 更新方法:

    metric = CustomMetric()
    metric.update(preds, target)
  3. 使用compute方法计算并获取指标的最终值。
    score = metric.compute()

  • torch.optim:PyTorch中用于优化模型参数的库。它提供了多种优化算法的实现,如随机梯度下降(SGD)、Adam、RMSprop等。torch.optim库的功能

1.定义优化器:torch.optim库提供了各种优化算法的类,可以通过实例化这些类来创建相应的优化器对象。常用的优化器类包括SGD、Adam、RMSprop等。

SGD:随机梯度下降。更新公式:

parameter = parameter - learning_rate* gradient

Adam:自适应学习率的优化算法

m = beta1 * m + (1 - beta1) * gradient

v = beta2 * v + (1 - beta2) * gradient^2

parameter = parameter - learning_rate * m / (sqrt(v) + epsilon)

其中,m和v分别是梯度的一阶矩估计(mean)和二阶矩估计(uncentered variance),beta1和beta2是衰减率,epsilon是一个很小的常数,用于避免除以零。

RMSprop: 自适应学习率的优化算法。它通过平均梯度的平方根来调整学习率。更新公式:

v = decay_rate * v + (1 - decay_rate) * gradient^2

parameter = parameter - learning_rate * gradient / (sqrt(v) + epsilon)

其中,v是梯度的平方根的移动平均,decay_rate是衰减率,epsilon是一个很小的常数,用于避免除以零。

2.更新模型参数:优化器对象可以通过调用step()方法来更新模型的参数。在每个训练迭代中,通常会先计算损失函数的梯度,然后调用优化器的step()方法来更新模型的参数。

3.调整学习率:优化器对象还提供了调整学习率的功能。可以通过设置学习率参数或使用学习率调度器来动态调整学习率。(如torch.optim.lr_scheduler模块中的类)

调用其中的方法:

1.创建模型对象和优化器对象:

model = ...

optimizer = optim.SGD(model.parameters(), lr=0.01)

2.在训练循环中,计算损失函数的梯度并更新模型参数:

optimizer.zero_grad()  # 清零梯度(注:paddle这里是optimizer.clear_grad())

loss = ...

loss.backward()  # 计算梯度

optimizer.step()  # 更新参数

3.调整学习率:

scheduler=optim.lr_scheduler.StepLR(optimizer,step_size=1,gamma=0.1)

scheduler.step()

  使用学习率调度器类StepLR来设置学习率的调整策略。

详细了解torch.argmax

  • torch.argmax(input, dim=None, keepdim=False):其中input是输入张量,dim是指定维度,如果不指定则返回整个张量中最大值的索引,keepdim表示是否保留维度。在多分类任务中,可以使用torch.argmax来判断模型对于输入样本的分类结果。

判断步骤:

  1. 通过模型对输入样本进行前向传播,得到输出张量。输出张量的形状通常(batch_size, num_classes),其中batch_size表示输入样本的数量,num_classes表示分类的类别数量。
  2. 使用torch.argmax函数在指定维度上找到输出张量中每个样本的最大值的索引。通常,dim参数会设置为1,表示在第二个维度上寻找最大值的索引。这样,得到的结果是一个大小为(batch_size,)的张量,其中每个元素是对应样本的预测类别的索引。
  3. 根据预测类别的索引,可以将其与真实标签进行比较,从而计算模型在该批次样本上的准确率或其他评估指标。

基于Softmax回归完成鸢尾花分类 

实现代码:

from sklearn.datasets import load_iris
import pandas
import numpy as np

iris_features = np.array(load_iris().data, dtype=np.float32)
iris_labels = np.array(load_iris().target, dtype=np.int32)
print(pandas.isna(iris_features).sum())
print(pandas.isna(iris_labels).sum())

import matplotlib.pyplot as plt #可视化工具

# # 箱线图查看异常值分布
# def boxplot(features):
#     feature_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
#
#     # 连续画几个图片
#     plt.figure(figsize=(5, 5), dpi=200)
#     # 子图调整
#     plt.subplots_adjust(wspace=0.6)
#     # 每个特征画一个箱线图
#     for i in range(4):
#         plt.subplot(2, 2, i+1)
#         # 画箱线图
#         plt.boxplot(features[:, i],
#                     showmeans=True,
#                     whiskerprops={"color":"#E20079", "linewidth":0.4, 'linestyle':"--"},
#                     flierprops={"markersize":0.4},
#                     meanprops={"markersize":1})
#         # 图名
#         plt.title(feature_names[i], fontdict={"size":5}, pad=2)
#         # y方向刻度
#         plt.yticks(fontsize=4, rotation=90)
#         plt.tick_params(pad=0.5)
#         # x方向刻度
#         plt.xticks([])
#     plt.savefig('ml-vis.pdf')
#     # plt.show()
# boxplot(iris_features)

import copy
import torch

# 加载数据集
def load_data(shuffle=True):
    """
    加载鸢尾花数据
    输入:
        - shuffle:是否打乱数据,数据类型为bool
    输出:
        - X:特征数据,shape=[150,4]
        - y:标签数据, shape=[150]
    """
    # 加载原始数据
    X = np.array(load_iris().data, dtype=np.float32)
    y = np.array(load_iris().target, dtype=np.int32)

    X = torch.tensor(X)
    y = torch.tensor(y)

    # 数据归一化
    X_min = torch.min(X, 0)[0]
    X_max = torch.max(X, 0)[0]
    X = (X - X_min) / (X_max - X_min)

    # 如果shuffle为True,随机打乱数据
    if shuffle:
        idx = torch.randperm(X.shape[0])
        X = X[idx]
        y = y[idx]
    return X, y

# 固定随机种子
torch.manual_seed(102)

num_train = 120
num_dev = 15
num_test = 15

X, y = load_data(shuffle=True)
print("X shape: ", X.shape, "y shape: ", y.shape)
X_train, y_train = X[:num_train], y[:num_train]
X_dev, y_dev = X[num_train:num_train + num_dev], y[num_train:num_train + num_dev]
X_test, y_test = X[num_train + num_dev:], y[num_train + num_dev:]


# 打印X_train和y_train的维度
print("X_train shape: ", X_train.shape, "y_train shape: ", y_train.shape)

# 打印前5个数据的标签
print(y_train[:5])

from nndl import op

# 输入维度
input_dim = 4
# 类别数
output_dim = 3
# 实例化模型
model = op.model_SR(input_dim=input_dim, output_dim=output_dim)

from nndl import op, metric, opitimizer, RunnerV2

# 学习率
lr = 0.2

# 梯度下降法
optimizer = opitimizer.SimpleBatchGD(init_lr=lr, model=model)
# 交叉熵损失
loss_fn = op.MultiCrossEntropyLoss()
# 准确率
metric = metric.accuracy

# 实例化RunnerV2
runner = RunnerV2(model, optimizer, metric, loss_fn)

# 启动训练
runner.train([X_train, y_train], [X_dev, y_dev], num_epochs=500, log_epochs=10, save_path="best_model.pdparams")


from nndl import plot

plot(runner,fig_name='linear-acc3.pdf')

# 加载最优模型
runner.load_model('best_model.pdparams')
# 模型评价
score, loss = runner.evaluate([X_test, y_test])
print("[Test] score/loss: {:.4f}/{:.4f}".format(score, loss))

logits = runner.predict(torch.tensor(X_test))
# 观察其中一条样本的预测结果
pred = torch.argmax(logits[0]).item()
# 获取该样本概率最大的类别
label = y_test[0].item()
# 输出真实类别与预测类别
print("The true category is {} and the predicted category is {}".format(label, pred))

实验结果:

不同训练轮数实验结果:
  • 训练100轮:

  • 训练150轮:

  • 训练200轮:

  • 训练600轮:

  • 训练1000轮: 

 分析:由训练数据,随着训练的轮数的增加,在验证集上,训练的准确率是呈逐渐升高的变化规律,直至稳定在0.7333....左右,损失是呈逐渐降低的趋势变化的,但是收敛的很慢。在测试集上,也是损失逐渐下降,准确率逐渐升高,差不多训练2000轮才勉强和前馈神经训练100轮差不多,但是没有过拟合的情况,即使训练10000轮也没有过拟合。

前馈神经网络实现鸢尾花分类与Softmax回归完成鸢尾花分类做对比分析

通过这些训练数据比对可以看出:在验证集中,相同训练轮数下对鸢尾花数据集的分类中,基于前馈神经网络要明显比前面基于Softmax回归收敛的快,分类精确度高,损失也少。在测试集中,前馈神经网络的准确率能够达到1,但是损失却也高于Softmax回归。应该是由于前馈神经网络的分类拟合能力太强,导致过拟合,泛化性能降低,损失反而升高。

随着训练轮数的增加,两种方法在验证集上的准确率都有增加,损失都有或多或少的减少,但是明显前馈神经网络要收敛的快,准确。但是因为它收敛的太快了,当训练轮数很大时,它的损失反而会升高,产生过拟合,泛化性能降低。

总而言之,前馈神经网络的多分类训练结果要明显优于基于Softmax回归的训练结果,收敛速度快,准确率高。但是缺点是对于较小,较简单数据集,由于它的训练能力太强,尤其要注意不能训练太多而导致过拟合,泛化性能降低。从实现上说,前馈神经网络也具有更复杂的模型结构和更多的参数,而Softmax回归相对简单,训练时间和计算复杂度较低。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值