第4章(下)基于前馈神经网络完成鸢尾花分类任务

2023-11-15

4.5 实践:基于前馈神经网络完成鸢尾花分类

在本实践中,我们继续使用第三章中的鸢尾花分类任务,将Softmax分类器替换为本章介绍的前馈神经网络。
在本实验中,我们使用的损失函数为交叉熵损失;优化器为随机梯度下降法;评价指标为准确率。

4.5.1 小批量梯度下降法

在梯度下降法中,目标函数是整个训练集上的风险函数,这种方式称为批量梯度下降法(Batch Gradient Descent,BGD)。 批量梯度下降法在每次迭代时需要计算每个样本上损失函数的梯度并求和。当训练集中的样本数量 N N N很大时,空间复杂度比较高,每次迭代的计算开销也很大。

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

t t t次迭代时,随机选取一个包含 K K K个样本的子集 B t \mathcal{B}_t Bt,计算这个子集上每个样本损失函数的梯度并进行平均,然后再进行参数更新。
θ t + 1 ← θ t − α 1 K ∑ ( x , y ) ∈ S t ∂ L ( y , f ( x ; θ ) ) ∂ θ , \theta_{t+1} \leftarrow \theta_t - \alpha \frac{1}{K} \sum_{(\boldsymbol{x},y)\in \mathcal{S}_t} \frac{\partial \mathcal{L}\Big(y,f(\boldsymbol{x};\theta)\Big)}{\partial \theta}, θt+1θtαK1(x,y)StθL(y,f(x;θ)),
其中 K K K批量大小(Batch Size) K K K通常不会设置很大,一般在 1 ∼ 100 1\sim100 1100之间。在实际应用中为了提高计算效率,通常设置为2的幂 2 n 2^n 2n

在实际应用中,小批量随机梯度下降法有收敛快、计算开销小的优点,因此逐渐成为大规模的机器学习中的主要优化算法。
此外,随机梯度下降相当于在批量梯度下降的梯度上引入了随机噪声。在非凸优化问题中,随机梯度下降更容易逃离局部最优点。

小批量随机梯度下降法的训练过程如下:

4.5.1.1 数据分组

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

数据迭代器的实现原理如下图所示:

  1. 首先,将数据集封装为Dataset类,传入一组索引值,根据索引从数据集合中获取数据;
  2. 其次,构建DataLoader类,需要指定数据批量的大小和是否需要对数据进行乱序,通过该类即可批量获取数据。

在实践过程中,通常使用进行参数优化。在飞桨中,使用paddle.io.DataLoader加载minibatch的数据,
paddle.io.DataLoader API可以生成一个迭代器,其中通过设置batch_size参数来指定minibatch的长度,通过设置shuffle参数为True,可以在生成minibatch的索引列表时将索引顺序打乱。

4.5.2 数据处理

构造IrisDataset类进行数据读取,继承自paddle.io.Dataset类。paddle.io.Dataset是用来封装 Dataset的方法和行为的抽象类,通过一个索引获取指定的样本,同时对该样本进行数据处理。当继承paddle.io.Dataset来定义数据读取类时,实现如下方法:

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

代码实现如下:

import numpy as np
import paddle
import paddle.io as io
from nndl.dataset import load_data

class IrisDataset(io.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)
paddle.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))
length of train set:  120
4.5.2.2 用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)

4.5.3 模型构建

构建一个简单的前馈神经网络进行鸢尾花分类实验。其中输入层神经元个数为4,输出层神经元个数为3,隐含层神经元个数为6。代码实现如下:

from paddle import nn

# 定义前馈神经网络
class Model_MLP_L2_V3(nn.Layer):
    def __init__(self, input_size, output_size, hidden_size):
        super(Model_MLP_L2_V3, self).__init__()
        # 构建第一个全连接层
        self.fc1 = nn.Linear(
            input_size,
            hidden_size,
            weight_attr=paddle.ParamAttr(initializer=nn.initializer.Normal(mean=0.0, std=0.01)),
            bias_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=1.0))
        )
        # 构建第二全连接层
        self.fc2 = nn.Linear(
            hidden_size,
            output_size,
            weight_attr=paddle.ParamAttr(initializer=nn.initializer.Normal(mean=0.0, std=0.01)),
            bias_attr=paddle.ParamAttr(initializer=nn.initializer.Constant(value=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)

4.5.4 完善Runner类

基于RunnerV2类进行完善实现了RunnerV3类。其中训练过程使用自动梯度计算,使用DataLoader加载批量数据,使用随机梯度下降法进行参数优化;模型保存时,使用state_dict方法获取模型参数;模型加载时,使用set_state_dict方法加载模型参数.

由于这里使用随机梯度下降法对参数优化,所以数据以批次的形式输入到模型中进行训练,那么评价指标计算也是分别在每个批次进行的,要想获得每个epoch整体的评价结果,需要对历史评价结果进行累积。这里定义Accuracy类实现该功能。

from paddle.metric import Metric

class Accuracy(Metric):
    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 = paddle.squeeze(outputs, axis=-1)
            if self.is_logist:
                # logist判断是否大于0
                preds = paddle.cast((outputs>=0), dtype='float32')
            else:
                # 如果不是logist,判断每个概率值是否大于0.5,当大于0.5时,类别为1,否则类别为0
                preds = paddle.cast((outputs>=0.5), dtype='float32')
        else:
            # 多分类时,使用'paddle.argmax'计算最大元素索引作为类别
            preds = paddle.argmax(outputs, axis=1, dtype='int64')

        # 获取本批数据中预测正确的样本个数
        labels = paddle.squeeze(labels, axis=-1)
        batch_correct = paddle.sum(paddle.cast(preds==labels, dtype="float32")).numpy()[0]
        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 paddle.nn.functional as F

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.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()'控制不计算和存储梯度
    @paddle.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()'控制不计算和存储梯度
    @paddle.no_grad()
    def predict(self, x, **kwargs):
        # 将模型设置为评估模式
        self.model.eval()
        # 运行模型前向计算,得到预测值
        logits = self.model(x)
        return logits

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

    def load_model(self, model_path):
        model_state_dict = paddle.load(model_path)
        self.model.set_state_dict(model_state_dict)

4.5.5 模型训练

实例化RunnerV3类,并传入训练配置,代码实现如下:

import paddle.optimizer as opt

lr = 0.2

# 定义网络
model = fnn_model

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

# 定义损失函数。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") 
[Train] epoch: 0/150, step: 0/1200, loss: 1.09839
[Evaluate]  dev score: 0.33333, dev loss: 1.11195
[Evaluate] best accuracy performence has been updated: 0.00000 --> 0.33333
[Train] epoch: 12/150, step: 100/1200, loss: 1.11506
[Evaluate]  dev score: 0.33333, dev loss: 1.10269
[Evaluate]  dev score: 0.26667, dev loss: 1.10302
[Train] epoch: 25/150, step: 200/1200, loss: 1.09337
[Evaluate]  dev score: 0.40000, dev loss: 1.08780
[Evaluate] best accuracy performence has been updated: 0.33333 --> 0.40000
[Evaluate]  dev score: 0.33333, dev loss: 1.09006
[Train] epoch: 37/150, step: 300/1200, loss: 1.05136
[Evaluate]  dev score: 0.40000, dev loss: 1.08156
[Evaluate]  dev score: 0.53333, dev loss: 1.04042
[Evaluate] best accuracy performence has been updated: 0.40000 --> 0.53333
[Train] epoch: 50/150, step: 400/1200, loss: 0.95090
[Evaluate]  dev score: 0.73333, dev loss: 0.92996
[Evaluate] best accuracy performence has been updated: 0.53333 --> 0.73333
[Evaluate]  dev score: 0.93333, dev loss: 0.77590
[Evaluate] best accuracy performence has been updated: 0.73333 --> 0.93333
[Train] epoch: 62/150, step: 500/1200, loss: 0.60114
[Evaluate]  dev score: 0.66667, dev loss: 0.64114
[Evaluate]  dev score: 0.80000, dev loss: 0.54386
[Train] epoch: 75/150, step: 600/1200, loss: 0.41520
[Evaluate]  dev score: 0.73333, dev loss: 0.49194
[Evaluate]  dev score: 0.93333, dev loss: 0.44057
[Train] epoch: 87/150, step: 700/1200, loss: 0.47822
[Evaluate]  dev score: 1.00000, dev loss: 0.40918
[Evaluate] best accuracy performence has been updated: 0.93333 --> 1.00000
[Evaluate]  dev score: 0.93333, dev loss: 0.38295
[Train] epoch: 100/150, step: 800/1200, loss: 0.39690
[Evaluate]  dev score: 1.00000, dev loss: 0.36390
[Evaluate]  dev score: 1.00000, dev loss: 0.34143
[Train] epoch: 112/150, step: 900/1200, loss: 0.18279
[Evaluate]  dev score: 1.00000, dev loss: 0.32409
[Evaluate]  dev score: 0.93333, dev loss: 0.30322
[Train] epoch: 125/150, step: 1000/1200, loss: 0.30731
[Evaluate]  dev score: 1.00000, dev loss: 0.29018
[Evaluate]  dev score: 0.93333, dev loss: 0.27057
[Train] epoch: 137/150, step: 1100/1200, loss: 0.18368
[Evaluate]  dev score: 0.93333, dev loss: 0.25629
[Evaluate]  dev score: 0.93333, dev loss: 0.24290
[Evaluate]  dev score: 0.93333, dev loss: 0.23029
[Train] Training done!

可视化观察训练集损失和训练集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="#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')
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/cbook/__init__.py:2349: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  if isinstance(obj, collections.Iterator):
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/cbook/__init__.py:2366: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  return list(data) if isinstance(data, collections.MappingView) else data

png

从输出结果可以看出准确率随着迭代次数增加逐渐上升,损失函数下降。

4.5.6 模型评价

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

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

4.5.7 模型预测

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

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

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

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

4.6 小结

本章介绍前馈神经网络的基本概念、网络结构及代码实现,利用前馈神经网络完成一个分类任务,并通过两个简单的实验,观察前馈神经网络的梯度消失问题和死亡ReLU问题,以及对应的优化策略。
此外,还实践了基于前馈神经网络完成鸢尾花分类任务。

4.7 实验拓展

尝试基于MNIST手写数字识别数据集,设计合适的前馈神经网络进行实验,并取得95%以上的准确率。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第4章(下)基于前馈神经网络完成鸢尾花分类任务 的相关文章

  • 【PTA】最长的括号子串 模拟

    给出一个长度为 n 的 仅包含字符 和 的字符串 计算最长的格式正确的括号子串的长度 例1 对于字符串 来说 最长的格式正确的子串是 长度为 2 例2 对于字符串 来说 最长的格式正确的子串是 长度为 4 字符串长度 0 n 5 10 5

随机推荐

  • 【SSD 代码精读】之 model (Backbone)& loss

    model 1 Backbone 1 ResNet 50 2 截取 ResNet 50 的前半部分作为 backbone 2 Module 3 Loss Function 1 location loss 2 confidence loss
  • Ubuntu下跑Aplaca报错:torch.cuda.0utofMemoryError: CUDA out of memory.解决办法(查看CUDA占用情况&清除GPU缓存)

    缓存不够 并非内存容量不够 错误提示 torch cuda 0utofMemoryError CUDA out of memory Tried to allocate 2 00 MiB PU 0 23 69 GiB total capaci
  • 计算机教育中缺失的一课:命令行环境

    点击蓝字 关注我们 内容来源于 计算机教育中缺失的一课 在 Attribution NonCommercial ShareAlike 4 0 International CC BY NC SA 4 0 下获得许可 另外 还可在蓝桥云课社区
  • linux修改密码提示权限拒绝,linux – ssh命令后权限被拒绝,即使密码正确

    我已经通过网线将Raspberry Pi 2连接到我的笔记本电脑 我正在尝试将文件从计算机传输到raspi但是命令ssh usr blabla local 要求我输入密码 我确信密码是正确的但是我得到了权限否认 请再试一次 我能做什么 我无
  • uni-app App端半屏连续扫码

  • 双向可控硅的工作原理

    先看下图的工作原理 如果想简单一点只要记住一句话即可 只要在G端有信号 那么T1 T2这条路就是通的 只有G在零点的时候才不会导通 主要来看一下应用吧 来看我们公司的一个电路图 其实双向可控硅多数用在交流电路中 简单介绍一下 Q5是三极管
  • 期权开户流程、交易时间和规则详解清晰易懂

    本文将介绍期权开户流程 交易时间和规则详解清晰易懂则 包括期权的定义 期权交易的时间 期权交易的规则和期权交易的风险 本文的结论是 期权交易的时间和规则非常重要 应该遵守交易规则 并且要注意风险 本文来源 期权酱 券商开通期权账户和期权分仓
  • 【ISO14229_UDS_0x23服务详解】

    目录 1 0x23服务 根据地址读取内存服务 2 请求报文格式 2 1 请求报文定义 2 2 请求报文中子函数参数定义 2 3 请求报文中数据参数定义 3 肯定应答报文 3 1 肯定应答报文格式定义 3 2 肯定应答报文数据参数定义 4 支
  • 解决mysql重新安装时输入原密码问题

    1 清除MYSQL的安装目录 默认是C Program Files 2 清除MYSQL数据存放目录 一般在C Documents and Settings All Users windows Application Data目录下 需要注意
  • python练习题

    练习 对于任意数字列表 从键盘输入一个数字 sum表示 找到列表中两两相加等于sum的数字 num list 3 2 4 7 1 sum 5 打印列表 3 2 4 1 fou循环实现 num list 3 2 4 7 1 sum 5 lis
  • ES搜索引擎之ES介绍,安装以及辅助插件Kibana的安装

    文章目录 ES搜索引擎之ES介绍 安装以及辅助插件Kibana的安装 ElasticSearch介绍 1 1为什么会有ElasticSearch搜索引擎 1 2ES的介绍 1 3什么是倒排索引 ElasticSearch的安装 下载elas
  • 强大的4开关升降压BOB电源 可升可降能大能小

    原文来自公众号 工程师 基于电感器的开关架构电源有3中常见的拓扑结构 分别是BUCK降压电源 BOOST升压电源以及BUCK BOOST负压电源 今天介绍的第4中拓扑 4开关BOB电源 在手机 汽车 嵌入式等领域都有广泛应用 它的基本工作原
  • http响应头connection的作用

    http chenchendefeng iteye com blog 461248 有的网站会在服务器运行一段时间后down掉 有很多原因可能造成这种现象 比如tomcat堆和非堆内存设置不足 程序没能释放内存空间造成内存溢出 或者某些进程
  • 渗透测试信息收集

    信息收集 渗透的本质是信息收集 信息收集分为主动信息收集和被动信息收集 主动信息收集能够收集到更多的信息 但是会产生痕迹 容易被溯源 被动信息收集是信息收集的第一步 通过第三方工具进行收集 不与主机直接交互 需要收集的信息包括 域名 子域名
  • TCP\UDP服务器与客户端

    作业 1 搭建TCP服务器 客户端 2 搭建UDP服务器 客户端 TCP服务器 include
  • 关于Java锁的面试总结

    面试过程中 也被问过几次关于Java中锁的问题 面试官一般是这么问 你了解Java中的锁吗 有几种 都有什么区别 讲一讲 大致可以分为这几点 锁是什么 有什么用 有哪几种锁 锁的区别 一 锁是什么 有什么用 锁主要用来实现资源共享的同步 只
  • Java实战项目(一)---编写聊天室程序

    刚开始学java 参考 java从入门到精通 这本书 学到网络程序设计基础这一章节 尤其与其他计算机进行通信 觉得还挺有意思的 所有深入地试试做一个小程序 聊天室程序 在代码中加入我自己的理解和困惑 希望能和大家一起探讨 每行的代码基本都有
  • [新人向]MySQL和Navicat下载、安装及使用详细教程

    MySQL和Navicat下载和安装及使用详细教程 因为这些软件的安装很多都是纯英文 作为新手安装真的需要摸索好久 包括我自己 所以Pipi酱就把自己的经验分享给大家 MySQL的安装教程 一 下载安装包链接 1 下载MySQL https
  • 广东电信:故障是外力强加导致 警方介入调查

    昨日下午5时50分开始 广东省内电信网络出现故障 省内多个地区均出现网络宽带无法连接 浏览器无法打开网页等现象 消息发布后 不少外省网友跟帖也表示网络塞车 涉及湖北 湖南 广西 海南和上海等省市区 广东本地不少市民在拨打电信 10000 热
  • 第4章(下)基于前馈神经网络完成鸢尾花分类任务

    文章目录 4 5 实践 基于前馈神经网络完成鸢尾花分类 4 5 1 小批量梯度下降法 4 5 1 1 数据分组 4 5 2 数据处理 4 5 2 2 用DataLoader进行封装 4 5 3 模型构建 4 5 4 完善Runner类 4