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

news2024/11/27 19:53:30

目录

1 小批量梯度下降法

        1.0 展开聊一聊~

        1.1 数据分组

        1.2 用DataLoader进行封装

        1.3 模型构建

        1.4 完善Runner类

        1.5 模型训练

        1.6 模型评价 

        1.7 模型预测        

思考

总结

参考文献


首先基础知识铺垫~       

继续使用第三章中的鸢尾花分类任务,将Softmax分类器替换为前馈神经网络

  • 损失函数:交叉熵损失;
  • 优化器:随机梯度下降法;
  • 评价指标:准确率;

1 小批量梯度下降法

        1.0 展开聊一聊~

        在梯度下降法中,目标函数是整个训练集上的风险函数,这种方式称为批量梯度下降法(Batch Gradient Descent,BGD)。批量梯度下降法在每次迭代时需要计算每个样本上损失函数的梯度并求和。为了减少每次迭代的计算复杂度,我们可以在每次迭代时只采集一小部分样本,计算在这组样本上损失函数的梯度并更新参数,这种优化方式称为小批量梯度下降法(Mini-Batch Gradient Descent,Mini-Batch GD)。

        梯度下降算法一般情况下主要说的是三种,批量梯度下降随机梯度下降小批量梯度下降。

        知道大家跟我一样不爱看一大段一大段的定义,巴拉巴拉一堆的,所以我大概总结了一下,快拿出你们的小本本!!!

首先,要明确梯度下降算法都是优化算法,用于求解目标函数的最优参数:

  • 批量梯度下降(Batch Gradient Descent,BGD)
  • 随机梯度下降(Stochastic Gradient Descent,SGD)
  • 小批量梯度下降(Mini-Batch Gradient Descent,MBGD)

        批量梯度下降(BGD):最早出现的梯度下降方法是批量梯度下降。BGD在每一次迭代中使用所有训练样本来计算梯度,并更新模型参数,步骤如下:

  • 对于每个训练样本,计算梯度。
  • 将所有梯度求平均,得到一个全局梯度。
  • 根据学习率和全局梯度更新模型参数。

优点:

  • 收敛性较好,能够达到全局最优(目标函数是凸函数)。
  • 梯度计算相对准确,参数更新稳定。
  • 收敛速度最快,可以保证每一步都是准确地向着极值点的方向趋近,所需要的迭代次数最少。

缺点:

  • 计算梯度时需要处理大量数据,计算开销较大。
  • 参数更新只能在整个训练集上进行,但大规模数据集通常会有大量冗余数据,所以不适用于大规模数据集。
  • 容易陷入局部最优(目标函数是非凸函数)。

        这里需要提一下~对所有样本的计算,可以利用向量运算进行并行计算来提升运算速度。

        随机梯度下降(SGD):为了解决批量梯度下降在处理大规模数据集时的计算开销问题,随机梯度下降方法被提出。SGD在每一次迭代中仅使用一个训练样本来计算梯度,并更新模型参数。具体步骤如下:

  • 随机选择一个训练样本。
  • 计算该样本的梯度。
  • 根据学习率和该样本的梯度更新模型参数。

优点:

  • 计算开销较小,适用于大规模数据集。
  • 参数更新频繁,可能更容易逃离局部最优。

缺点:

  • 每次迭代只使用一个样本,但是单个样本计算出的梯度不能够很好的体现全体样本的梯度。
  • 参数更新的方向较不稳定,可能会产生参数震荡。
  • 参数更新非常的频繁,在最优点附近晃来晃去,收敛速度大大降低。

小批量梯度下降(MBGD):为了兼顾批量梯度下降和随机梯度下降的优点,小批量梯度下降方法被引入。小批量梯度下降算法又被叫做小批量随机梯度下降算法。MBGD在每一次迭代中使用一小部分训练样本(通常称为mini-batch)来计算梯度,并更新模型参数。具体步骤如下:

  • 随机选择一小部分训练样本(mini-batch)。
  • 计算这些样本的梯度。
  • 根据学习率和这些样本的梯度更新模型参数。

优点:

  • 兼具BGD和SGD的优点,计算开销适中,参数更新相对稳定。
  • 可以利用矩阵运算的高效性,提高计算效率。
  • 较容易并行化处理,适用于大规模数据集。

缺点:

  • 学习率选择较为敏感,需要进行合适的调参。

        总结:三种梯度下降方法各有优劣。批量梯度下降收敛性好,但计算开销大;随机梯度下降计算开销小,但更新不稳定;小批量梯度下降在两者之间取得平衡,并且对于大规模数据集有较好的适应性。在实际应用中,根据具体问题的规模和特点选择合适的梯度下降方法。

        1.1 数据分组

        为了小批量梯度下降法,我们需要对数据进行随机分组。目前,机器学习中通常做法是构建一个数据迭代器,每个迭代过程中从全部数据集中获取一批指定数量的数据。原理图展示一下:

        首先,将数据集封装为Dataset类,传入一组索引值,根据索引从数据集合中获取数据;

        其次,构建DataLoader类,需要指定数据批量的大小和是否需要对数据进行乱序,通过该类即可批量获取数据。

import torch.utils.data as Data


class IrisDataset(Data.Dataset):
    def __init__(self, mode='train', num_train=120, num_dev=15):
        super(IrisDataset, self).__init__()
        # 调用第三章中的数据读取函数,其中不需要将标签转成one-hot类型
        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)

__getitem__:根据给定索引获取数据集中指定样本,并对样本进行数据处理;

__len__:返回数据集样本个数。

train_dataset = IrisDataset(mode='train')
dev_dataset = IrisDataset(mode='dev')
test_dataset = IrisDataset(mode='test')

print("length of train set: ", len(train_dataset))

 

        1.2 用DataLoader进行封装

batch_size = 16

# 加载数据
train_loader = Data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
dev_loader = Data.DataLoader(dev_dataset, batch_size=batch_size)
test_loader = Data.DataLoader(test_dataset, batch_size=batch_size)

        1.3 模型构建

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.fc2 = nn.Linear(hidden_size, output_size)
        # 定义网络使用的激活函数
        self.act = nn.Sigmoid()
        nn.init.normal_(self.fc1.weight, mean=0., std=0.01)
        nn.init.constant_(self.fc1.bias, 1.0)
        nn.init.normal_(self.fc2.weight, mean=0., std=0.01)
        nn.init.constant_(self.fc2.bias, 1.0)

    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)

        1.4 完善Runner类

class Accuracy(object):
    def __init__(self, is_logist=True):
        """
        输入:
           - is_logist: outputs是logist还是激活后的值
        """

        # 用于统计正确的样本个数
        self.num_correct = 0
        # 用于统计样本的总数
        self.num_count = 0

        self.is_logist = is_logist

    def update(self, outputs, labels):
        """
        输入:
           - outputs: 预测值, shape=[N,class_num]
           - labels: 标签值, shape=[N,1]
        """

        # 判断是二分类任务还是多分类任务,shape[1]=1时为二分类任务,shape[1]>1时为多分类任务
        if outputs.shape[1] == 1:  # 二分类
            outputs = torch.squeeze(outputs, axis=-1)
            if self.is_logist:
                # logist判断是否大于0
                preds = (outputs >= 0).to(torch.float32)
            else:
                # 如果不是logist,判断每个概率值是否大于0.5,当大于0.5时,类别为1,否则类别为0
                preds = (outputs >= 0.5).to(torch.float32)
        else:
            # 多分类时,使用'paddle.argmax'计算最大元素索引作为类别
            preds = torch.argmax(outputs, dim=1).int()

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

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

    def accumulate(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"

        完善RunnerV3类

import torch


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()  #无clear_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.accumulate()

        # 记录验证集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)

        注意torch环境中没有clear_grad方法,这儿需要调用zero_grad方法。 

        1.5 模型训练

        这里把RunnerV3放入runner.py存储在nndl文件夹中

import torch.optim as opt
from nndl.runner import RunnerV3
import torch.nn.functional as F

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)

        使用训练集和验证集进行模型训练,共训练150个epoch。在实验中,保存准确率最高的模型作为最佳模型。

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

        可视化观察训练集损失和训练集loss变化情况,代码如下:

import matplotlib.pyplot as plt


# 绘制训练集和验证集的损失变化以及验证集上的准确率变化曲线
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="#e4007f",
                           dev_color='#f19ec2',
                           fontsize='large',
                           train_linestyle="-",
                           dev_linestyle='--'):
    global dev_steps
    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='x-large')

    # 绘制评价准确率变化曲线
    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='x-large')

    plt.savefig(fig_name)
    plt.show()

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

 

        1.6 模型评价 

        使用测试数据对在训练过程中保存的最佳模型进行评价,观察模型在测试集上的准确率以及Loss情况,代码如下:

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

        1.7 模型预测        

        同样地,也可以使用保存好的模型,对测试集中的某一个数据进行模型预测,观察模型效果。代码如下

# 获取测试集中第一条数据
X, label = train_dataset[0]
logits = runner.predict(X)

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

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

思考

softmax、svm、前馈神经网络三种进行比较,svm代码如下:

from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score
def SVC_split(x_train, y_train, x_test, y_test):
    # 定义SVM分类器
    svm = SVC()

    # 定义参数空间
    param_grid = {
        'C': [0.01, 0.1, 1, 10],
        'kernel': ['linear', 'rbf', 'poly'],
        'gamma': ['scale', 'auto']
    }
    # 使用GridSearchCV进行交叉验证和参数选择
    grid_search = GridSearchCV(svm, param_grid=param_grid, cv=5)
    grid_search.fit(x_train, y_train.ravel())

    # 在测试集上评估模型性能
    y_pred = grid_search.predict(x_test)
    accuracy = accuracy_score(y_test, y_pred)
    print("Accuracy on test set: {:.2f}%".format(accuracy * 100))



SVC_split(train_dataset.X,train_dataset.y ,test_dataset.X, test_dataset.y)

调用实验四的softmax函数的结果如下:

        很明显我们发现softmax回归的准确率远远低于前馈神经网络和svm,简单总结一下都有什么原因吧:

               softmax回归是一个线性模型,其只能学习到线性关系。对于复杂的非线性分类问题,Softmax回归的表达能力可能不足以捕捉到数据中的更复杂模式。相比之下,前馈神经网络具有更强大的非线性建模能力,可以通过多个隐藏层和非线性激活函数来学习到更复杂的特征表示。SVM也可以通过核函数将低维输入映射到高维空间,从而进行非线性分类。

        由此得出结论,但需要注意的是,Softmax回归在所有二分类任务上表现都会远远低于前馈神经网络和SVM。对于一些简单的线性可分问题或数据分布较为简单的情况下,Softmax回归可能表现得很好。然而,对于更复杂的问题和数据集,使用更复杂的模型如前馈神经网络和SVM通常能够获得更好的性能。

        但是有个疑问前馈神经网络和SVM究竟哪个更好一点?

        简而言之,神经网络是个“黑匣子”,优化目标是基于经验风险最小化,易陷入局部最优,训练结果不太稳定,一般需要大样本;

        而支持向量机有严格的理论和数学基础,基于结构风险最小化原则, 泛化能力优于前者,算法具有全局最优性, 是针对小样本统计的理论。

        就目前我的理论知识,好像想搞明白哪个好哪个坏可能有点难,而且模型好像很难说哪个好哪个坏,可能针对不同的数据集表现也会不一样,害,浅浅插个眼,等之后,对深度学习有了一定程度的了解的时候再回来,看看有没有一个答案吧。

总结

        到此为止前馈神经网络结束啦,有了一点搭建神经网络的经验了吧,大概流程如下:

  1. 定义网络结构:首先需要确定网络的结构,包括输入层、隐藏层和输出层的大小和数量。

  2. 初始化参数:对于每个神经元,需要初始化权重和偏置值。权重和偏置值通常是随机初始化的,以避免初始状态过于相似导致模型收敛缓慢。

  3. 定义损失函数:损失函数用来衡量预测值和真实值之间的误差。二分类问题通常使用交叉熵损失函数,回归问题可以使用均方误差损失函数。

  4. 定义优化器:优化器用于更新模型的参数,使损失函数最小化。常见的优化器包括随机梯度下降 (SGD)、Adam等。

  5. 训练模型:通过传递数据进行前向传播和反向传播,更新模型的参数。在训练过程中,需要将数据分为训练集、验证集和测试集。

  6. 模型评价:在训练完成之后,可以通过输入新数据并进行前向传播来得到预测结果。也可以进行可视化等等。

        本次实验对前馈神经网络的应用有更为明确的理解,同时针对softmax,svm,CNN的对比,在实验和搜索资料的过程中,也明白了什么模型更适合应用在什么范围内,softmax和CNN的具体的应用区别还没弄明白算是个小小的遗憾吧,等有更多深度学习经验的时候看看能不能再回来解答这个问题吧~

参考文献

torch.nn.Module所有方法总结及其使用举例_torch.nn.module cuda-CSDN博客
torch.nn — PyTorch master documentation

NNDL 实验五 前馈神经网络(3)鸢尾花分类-CSDN博客
神经网络 VS SVM_svm和神经网络的区别-CSDN博客

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

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

相关文章

OCS2工具箱

实时系统优化控制工具箱 参考视频:ETH 最优控制/MPC 实时求解器 OCS2 使用入门 参考文档:OCS2 求解器入门 选择OCS2 OCS2 是一个 MPC 实时求解器 (SLQ/iLQR),依赖 Pinocchio 构建机器人动力学模型,采用 RViz 或者 RaiSim 验证 (…

Ansible 自动化运维工具 --- playbook 剧本

文章目录 1. Host inventory ---- 主机清单1.1 简介1.2 inventory文件1.3 Inventory 文件的构成1.3.1 主机与组1.3.2 变量 1.4 inventory 中的常用变量 2. Ansible-playbook剧本2.1 简介2.2 Playbook的结构组成2.3 编写playbook的基本格式与写法2.3.1 基本格式2.3.2 语句的横向…

C语言打印出九九乘法表

#include<stdio.h> int main() {int i,j;for(i1;i<9;i){for(j1;j<9;j){printf("%d*%d%d\t",i,j,i*j); //\t制表符}printf("\n"); //\n输出个回车} }

Redis03-过期策略和淘汰策略

目录 Redis数据过期策略 Redis数据淘汰策略 Redis数据过期策略 Redis使用一种基于过期策略来处理键的过期和自动失效。这种策略可以确保不再需要的数据被自动删除&#xff0c;以释放内存并避免数据过期后仍然在缓存中存留。 Redis的过期删除策略主要有两种&#xff1a; 惰性…

【MySQL数据库】 四

本文主要介绍了mysql数据库的几种常见的约束. 一.数据库约束 我们希望存储的数据是靠谱的,mysql提供一些机制来辅助我们自动的依赖程序对数据进行检查 . 这类查数据的机制,就是约束 一旦约束好了,后续在进行增 删 改的时候,mysql就会自动的对修改的数据做出检查,如果不符合…

并发编程: 2. 线程管控

给定一个线程&#xff0c;只要令std::thread对象与之关联&#xff0c;就能管控该线程的几乎每个细节。 2.1 线程的基本管控 2.1.1 发起线程 线程通过构建std::thread对象而启动&#xff0c;该对象指明线程要运行的任务&#xff08;函数&#xff09;。简单的任务&#xff0c;…

【大数据】NiFi 中的重要术语

NiFi 中的重要术语 1.Flow Controller2.Processor3.Connection4.Controller Service5.Process Group6.FlowFile 那些一个个黑匣子称为 Processor&#xff0c;它们通过称为 Connection 的队列交换名为 FlowFile 的信息块。最后&#xff0c;FlowFile Controller 负责管理这些组件…

隐私安全|隐私安全已从国家法律法规转向商业企业应用,如何理解以及落地建设,相信大家正在经历隐私安全的困扰

网络空间的隐私安全主要是指网络隐私权不受侵犯&#xff0c;网络隐私权是指自然人在网上享有的&#xff0c;与公共利益无关的个人活动领域与个人信息秘密依法受到保护&#xff0c;不被他人非法侵扰&#xff0c;知悉收集&#xff0c;利用和公开的一种人格权&#xff0c;也包括第…

基于鹰栖息算法的无人机航迹规划-附代码

基于鹰栖息算法的无人机航迹规划 文章目录 基于鹰栖息算法的无人机航迹规划1.鹰栖息搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用鹰栖息算法来优化无人机航迹规划。 1.鹰栖息…

ActiveMq学习⑧__ActiveMQ的消息持久化机制

ActiveMQ的消息存储和持久化 MQ的高可用 事务持久签收可持久化 &#xff08;类似于与mq消息的同步机制&#xff09; 为了避免意外宕机以后丢失信息&#xff0c;需要做到重启后可以恢复消息队列&#xff0c;消息系统一半都会采用持久化机制。 ActiveMQ的消息持久化机制 Act…

canvas实现刮奖功能

canvas刮奖原理很简单&#xff0c;就是在刮奖区添加两个canvas&#xff0c;第一个canvas用于显示刮开后显示的内容&#xff0c;可以是一张图片或一个字符串&#xff0c;第二个canvas用于显示涂层&#xff0c;可以用一张图片或用纯色填充&#xff0c;第二个canvas覆盖在第一个ca…

逆向学习记录(5)刷机

首要前提&#xff1a;手机刷机必须OEM解锁&#xff08;BL解锁&#xff09;&#xff0c;否则不能刷机&#xff01; 1、根据手机机型下载手机系统包&#xff0c;首次登陆网址需要同意协议。然后在右侧选机型&#xff0c;中间就出来各种适合本机型的系统。 下载网址 https://dev…

47基于matlab的水印提取,将水印和载体进行图像融合

基于matlab的水印提取&#xff0c;将水印和载体进行图像融合&#xff0c;成为一体&#xff0c;可对合成图像进行加噪处理&#xff0c;剪切处理&#xff0c;小波压缩处理&#xff0c;旋转处理等操作&#xff0c;最后对合成图像实现水印提取&#xff0c;程序已调通&#xff0c;可…

【AI好好玩02】利用Lama Cleaner本地实现AIGC试玩:擦除对象、替换对象、更换风格等等

目录 一、安装二、擦除功能1. LaMa模型实操实例一&#xff1a;去除路人实操实例二&#xff1a;去水印实操实例三&#xff1a;老照片修复 2. LDM模型3. ZITS模型4. MAT模型5. FcF模型6. Manga模型 三、替换对象功能1. sd1.52. sd23. anything44. realisticVision1.45. 四个模型的…

Tomcat安装配置教程

目录 1、安装tomcat1.1、查看JDK版本1.2、 匹配对应的JDK版本1.3、 下载Tomcat1.3.1、 安装包版&#xff08;推荐&#xff0c;不用配环境&#xff09;1.3.2、 压缩包版 2、 运行Tomcat3、 不能运行问题 1、安装tomcat 1.1、查看JDK版本 由于不同版本tomcat对于jdk的版本有要求…

Mac 下安装golang环境

一、下载安装包 安装包下载地址 下载完成&#xff0c;直接继续----->下一步到结束即可安装成功&#xff1b; 安装成功之后&#xff0c;验证一下&#xff1b; go version二、配置环境变量 终端输入vim ~/.zshrc进入配置文件&#xff0c;输入i进行编辑 打开的不管是空文本…

redis教程 二 redis客户端Jedis使用

文章目录 Redis的Java客户端-JedisJedis快速入门创建工程&#xff1a;引入依赖&#xff1a;建立连接测试&#xff1a;释放资源Jedis连接池创建Jedis的连接池改造原始代码 Redis的Java客户端-SpringDataRedis快速入门导入pom坐标配置文件测试代码 数据序列化器StringRedisTempla…

“第六十一天”

这三个也算一类的&#xff0c;减和加的处理差不多&#xff0c;不过这个题多了限制是被减数大于减数&#xff0c;要是想再完整一点&#xff0c;可以把小于的情况也考虑进去&#xff0c;不过这个我是如果被减数小于减数的话&#xff0c;我就用减数加被减数&#xff0c;然后最后打…

JVM 各个参数详解

在一些规模稍大的应用中&#xff0c;Java虚拟机&#xff08;JVM&#xff09;的内存设置尤为重要&#xff0c;想在项目中取得好的效率&#xff0c;GC&#xff08;垃圾回收&#xff09;的设置是第一步。 PermGen space&#xff1a;全称是Permanent Generation space.就是说是永久…

ActiveMq学习⑤__ActiveMq的Broker

ActiveMq的Broker 是什么&#xff1f; 相当于一个ActiveMq的服务器实例 Broker其实就是实现了用代码的形式启动ActiveMQ将MQ嵌入到Java 代码中&#xff0c;以便随时用随时启动&#xff0c;在用的时候再去启动这样节省了资源&#xff0c;也保证了可靠性。 按照不同的配置文件…