当前位置: 首页 > news >正文

二、神经网络基础与搭建


神经网络基础

  • 前言
  • 一、神经网络
    • 1.1 基本概念
    • 1.2 工作原理
  • 二、激活函数
    • 2.1 sigmoid激活函数
      • 2.1.1 公式
      • 2.1.2 注意事项
    • 2.2 tanh激活函数
      • 2.2.1 公式
      • 2.2.2 注意事项
    • 2.3 ReLU激活函数
      • 2.3.1 公式
      • 2.3.2 注意事项
    • 2.4 SoftMax激活函数
      • 2.4.1 公式
      • 2.4.2 Softmax的性质
      • 2.4.3 Softmax的应用
      • 2.4.4 代码演示
      • 2.4.5 数学计算举例
      • 2.4.6 Softmax的注意事项
  • 三、参数初始化
    • 3.1 均匀分布初始化
    • 3.2 正态分布初始化
    • 3.3 全0初始化
    • 3.4 全1初始化
    • 3.5 固定值初始化
    • 3.6 Kaiming 初始化,也叫做 HE 初始化
      • 3.6.1 正态化的Kaiming 初始化
      • 3.6.2 均匀分布的Kaiming 初始化
    • 3.7 Xavier 初始化,也叫做 Glorot初始化
      • 3.7.1 正态化的Xavier初始化
      • 3.7.2 均匀分布的Xavier初始化
  • 四、构建简单的神经网络
  • 总结


前言

  • 前面我们学习了深度学习当中的基础——张量,接下来我们了解神经网络中的知识。

一、神经网络

  • 神经网络是一种模拟人脑神经元结构和功能的计算模型,旨在解决复杂的模式识别和预测问题

1.1 基本概念

  • 神经元:神经元是神经网络的基本组成单元,它接收输入信号,通过对输入信号的处理产生输出信号。每个神经元都有多个输入和一个输出,输入可以是其他神经元的输出,也可以是外部输入信号。

  • 层级结构:神经网络由多个层级结构组成,包括输入层、隐藏层和输出层。输入层接收来自外部环境的数据,每个神经元代表一个输入特征;隐藏层负责对输入数据进行非线性变换,提取特征;输出层输出预测结果,每个神经元代表一个输出值。

  • 在这里插入图片描述

  • 连接权重:连接不同神经元之间的权重,决定信号的传递强度。这些权重在神经网络的训练过程中不断调整,以实现更好的预测性能。

  • 在这里插入图片描述

  • 激活函数:激活函数用于对神经元输出进行非线性变换,引入非线性特性。常见的激活函数包括sigmoid函数、ReLU函数、tanh函数等。不同的激活函数有不同的性质,可以根据具体的任务需求选择不同的激活函数。

1.2 工作原理

  • 层级传播:信号通过逐层传递,最终到达输出层。
  • 输出预测:输出层的神经元输出预测结果。
  • 误差反向传播:根据预测结果与真实值的误差,通过反向传播算法更新连接权重。反向传播算法通过从输出层向输入层反向传播误差,依次更新权重和偏置,使得网络的预测能力逐渐提高。

二、激活函数

  • 用于对每层的输出数据进行变换,从而为整个网络注入了非线性因素,此时的神经网络就可以拟合各种曲线,提高应对复杂问题的拟合能力。

2.1 sigmoid激活函数

2.1.1 公式

f ( x ) = 1 1 + e − x f(x)=\frac{1}{1+e^{-x}} f(x)=1+ex1

  • 求导后的公式:
    • f ′ ( x ) = ( 1 1 + e − x ) ′ = 1 1 + e − x ( 1 − 1 1 + e − x ) = f ( x ) ( 1 − f ( x ) ) f'(x)=(\frac{1}{1+e^{-x}})'=\frac{1}{1+e^{-x}}(1-\frac{1}{1+e^{-x}})=f(x)(1-f(x)) f(x)=(1+ex1)=1+ex1(11+ex1)=f(x)(1f(x))

代码演示:

import torch
import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# sigmoid函数图像
x = torch.linspace(-20, 20, 1000)
# 输入值x通过sigmoid函数转换成激活值y
y = torch.sigmoid(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('Sigmoid 函数图像')# sigmoid导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.sigmoid(x).sum().backward()# y = 2 * torch.dot(x, x)
# y.backward()
# x.detach():输入值x的数值
# x.grad:计算梯度,求导
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('Sigmoid 导数图像')
plt.show()
  • 函数图像如下
    在这里插入图片描述

2.1.2 注意事项

  • sigmoid函数可以将任意值的输入映射到(0,1)之间,从图中我们可以看出,当输入的值大致在 < -6 或者 >6 的时候,此时输入任何值得到的激活值都差不多,这样就会导致丢失部分信息。
  • 对于sigmoid函数而言,输入值在[-6,6]之间才会有明显差异,输入值在[-3,3]之间才会有比较好的结果
  • 由导函数的图像,导数的数值范围是(0,025),当输入*< -6 或者 >6 的时候,sigmoid激活函数图像的导数接近于0,此时网络参数将更新缓慢或者无法更新
  • 一般来说,sigmoid的网络在五层之内就会产生梯度消失的现象,而且该激活函数不以0为中心,所以在实践中,使用很少。一般只用于二分类的输出层。

2.2 tanh激活函数

2.2.1 公式

f ( x ) = 1 − e − 2 x 1 + e − 2 x f(x)=\frac{1-e^{-2x}}{1+e^{-2x}} f(x)=1+e2x1e2x

  • 求导后的公式:
    f ′ ( x ) = ( 1 − e − 2 x 1 + e − 2 x ) ′ = 1 − f 2 ( x ) f'(x)=(\frac{1-e^{-2x}}{1+e^{-2x}})'=1-f^2(x) f(x)=(1+e2x1e2x)=1f2(x)

代码演示:

import torch
import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
y = torch.tanh(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('Tanh 函数图像')# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.tanh(x).sum().backward()
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('Tanh 导数图像')
plt.show()
  • 在这里插入图片描述

2.2.2 注意事项

  • Tanh函数将输入映射在(-1,1)之间,图像以0为中心,在0点对称,当输入 < -3 或者 >3 的时会被映射成 -1 或者 1 。导函数的取值范围(0,1),当输入的值 < -3 或者 >3 的时,其导函数近似0。
  • 与sigmoid相比,它是以0为中心,并且梯度相对于sigmoid大,使得其收敛速度要比sigmoid快,减少迭代刺水。然而,从图中可以看出,Tanh两侧的导数也为0,同样会出现梯度消失的情况。
  • 若使用的时候,可以再隐藏层使用Tanh函数,在输出层使用sigmoid函数

2.3 ReLU激活函数

2.3.1 公式

f ( x ) = m a x ( 0 , x ) f(x)=max(0, x) f(x)=max(0,x)

  • 求导后的公式:
    f ′ ( x ) = 0 或者 1 f'(x)=0或者1 f(x)=0或者1

代码演示:

# 创建画布和坐标轴
import torch
from matplotlib import pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
y = torch.relu(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('ReLU 函数图像')
# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.relu(x).sum().backward()
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('ReLU 导数图像')
plt.show()
  • 在这里插入图片描述

2.3.2 注意事项

  • ReLU 激活函数将小于0的值映射为 0,而大于 0 的值则保持不变,它更加重视正信号,而忽略负信号,这种激活函数运算更为简单,能够提高模型的训练效率。
  • 当x<0时,ReLU导数为0,而当x>0时,则不存在饱和问题。所以,ReLU能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。然而,随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新。这种现象被称为“神经元死亡”
  • ReLU是目前最常用的激活函数。
    • 与sigmoid相比,RELU的优势是:采用sigmoid函数,计算量大(指数运算),反向传播求误差梯度时,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。
    • siqmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。
    • Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

2.4 SoftMax激活函数

2.4.1 公式

  • Softmax函数的本质是一种归一化函数,它将一个数值向量归一化为一个概率分布向量,且各个概率之和为1。对于一个给定的实数向量z,Softmax函数首先计算每一个元素的指数(e的幂),然后每个元素的指数与所有元素指数总和的比值,就形成了Softmax函数的输出。
    Softmax ( z i ) = e z i ∑ j = 1 K e z j \text{Softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}} Softmax(zi)=j=1Kezjezi

  • 其中, z i z_i zi 表示输入向量 z z z 的第 i i i 个分量, K K K 是类别总数,即向量 z z z 的维度, e e e 是自然对数的底数。

  • 实际计算的时候需要输入向量减去向量中的最大值

    • 在实际应用中,直接计算 e z i e^{z_i} ezi 可能会导致数值溢出,特别是当输入值很大时。为了防止这种情况,可以在计算前减去向量中的最大值。

2.4.2 Softmax的性质

  • 归一化:Softmax保证所有输出值的和为1,使其可以被解释为概率。
  • 可微性:Softmax函数在整个定义域内可微,这使得它可以在基于梯度的优化算法中使用,例如反向传播。
  • 敏感性:Softmax对输入值非常敏感,尤其是当有一个输入远大于其他输入时。

2.4.3 Softmax的应用

  • 多类别分类问题:Softmax函数常用于多类别分类问题中,将输入向量映射为各个类别的概率。在神经网络中,Softmax通常作为输出层的激活函数,将网络的输出转换为类别概率。
  • 交叉熵损失函数:在训练神经网络时,Softmax函数通常与交叉熵损失函数结合使用。交叉熵损失函数用于衡量预测概率分布与真实标签之间的差异,从而进行模型的训练和优化。

2.4.4 代码演示

代码演示:

import torchscores = torch.tensor([0.2, 0.02, 0.15, 0.15, 1.3, 0.5, 0.06, 1.1, 0.05, 3.75])
# dim = 0,按行计算
probabilities = torch.softmax(scores, dim=0)
print(probabilities)

2.4.5 数学计算举例

  • 0、背景:
    • 假设我们有一个神经网络,用于识别手写数字(0 到 9)。神经网络的输出层有 10 个神经元,每个神经元对应一个数字类别。在训练完成后,对于一个新的输入图像,神经网络的输出层会产生一个 10 维的实数向量。我们需要将这个向量转换为一个概率分布,以便确定哪个数字最有可能是正确的。
  • 1、输入向量
    • z = [ 1.0 , 2.0 , 3.0 , 4.0 , 1.0 , 0.5 , 0.0 , − 1.0 , − 2.0 , − 3.0 ] z = [1.0,2.0,3.0,4.0,1.0,0.5,0.0,−1.0,−2.0,−3.0] z=[1.0,2.0,3.0,4.0,1.0,0.5,0.0,1.0,2.0,3.0]
  • 2、减去最大值
    • 为了防止数值溢出,我们先减去向量中的最大值(4.0)
    • z ′ = [ 1.0 − 4.0 , 2.0 − 4.0 , 3.0 − 4.0 , 4.0 − 4.0 , 1.0 − 4.0 , 0.5 − 4.0 , 0.0 − 4.0 , − 1.0 − 4.0 , − 2.0 − 4.0 , − 3.0 − 4.0 ] z'=[1.0−4.0,2.0−4.0,3.0−4.0,4.0−4.0,1.0−4.0,0.5−4.0,0.0−4.0,−1.0−4.0,−2.0−4.0,−3.0−4.0] z=[1.04.0,2.04.0,3.04.0,4.04.0,1.04.0,0.54.0,0.04.0,1.04.0,2.04.0,3.04.0]
    • z ′ = [ − 3.0 , − 2.0 , − 1.0 , 0.0 , − 3.0 , − 3.5 , − 4.0 , − 5.0 , − 6.0 , − 7.0 ] z' = [−3.0,−2.0,−1.0,0.0,−3.0,−3.5,−4.0,−5.0,−6.0,−7.0] z=[3.0,2.0,1.0,0.0,3.0,3.5,4.0,5.0,6.0,7.0]
  • 3、计算指数
    • e z ′ = [ e − 3.0 , e − 2.0 , e − 1.0 , e 0.0 , e − 3.0 , e − 3.5 , e − 4.0 , e − 5.0 , e − 6.0 , e − 7.0 ] e^{z'} = [e^{-3.0},e^{-2.0},e^{-1.0},e^{0.0},e^{-3.0},e^{-3.5},e^{-4.0},e^{-5.0},e^{-6.0},e^{-7.0}] ez=[e3.0,e2.0,e1.0,e0.0,e3.0,e3.5,e4.0,e5.0,e6.0,e7.0]
    import numpy as npz_prime = np.array([-3.0, -2.0, -1.0, 0.0, -3.0, -3.5, -4.0, -5.0, -6.0, -7.0])
    exp_z_prime = np.exp(z_prime)	
    print(exp_z_prime)
    
    • [‘0.0497870684’, ‘0.1353352832’, ‘0.3678794412’, ‘1.0000000000’, ‘0.0497870684’, ‘0.0301973834’, ‘0.0183156389’, ‘0.0067379470’, ‘0.0024787522’, ‘0.0009118820’]
  • 4、计算分母
    • ∑ i = 1 10 e z ′ = 0.0497870684 + 0.1353352832 + 0.3678794412 + 1.0000000000 + 0.0497870684 + 0.0301973834 + 0.0183156389 + 0.0067379470 + 0.0024787522 + 0.0009118820 \sum_{i=1}^{10}e^{z'}= 0.0497870684+0.1353352832+0.3678794412+1.0000000000+0.0497870684+0.0301973834+0.0183156389+0.0067379470+0.0024787522+0.0009118820 i=110ez=0.0497870684+0.1353352832+0.3678794412+1.0000000000+0.0497870684+0.0301973834+0.0183156389+0.0067379470+0.0024787522+0.0009118820
    • ∑ i = 1 10 e z ′ = 1.6614304647 \sum_{i=1}^{10}e^{z'}= 1.6614304647 i=110ez=1.6614304647
  • 5、计算Softmax
    • 将每个指数除以总和,得到概率分布
    • s o f t m a x ( z i ) = e z ′ ∑ i = 1 10 e z ′ softmax(z_i) = \frac{e^{z'}}{\sum_{i=1}^{10}e^{z'}} softmax(zi)=i=110ezez
sum_exp_z_prime = np.sum(exp_z_prime)
softmax_output = exp_z_prime / sum_exp_z_prime
print(softmax_output)
- 输出结果为:[0.0299663871,0.0814570854,0.2214233150,0.6018909737,0.0299663871,0.0181755325,0.0110240177,0.0040555095,0.0014919386,0.0005488535]
  • 6、结果解释
    • 第四个元素的概率最高为0.6018909737,所以预测为 数字 3
    • 其他数字概率较小,所以表示其他数字的可能性较小

2.4.6 Softmax的注意事项

  • 输入值范围:Softmax函数的输入值可以是任意实数,但通常在实际应用中,输入值是经过神经网络计算得到的logits(即未归一化的得分或置信度)。
  • 数值稳定性:在计算Softmax函数时,由于涉及到指数运算,可能会出现数值溢出或下溢的问题。为了解决这个问题,通常会对输入值进行适当的缩放或平移处理。
  • 互斥类别:Softmax函数适用于类别互斥的情况,即每个样本只能属于一个类别。如果问题是多标签分类(即一个样本可能属于多个类别),则需要使用其他方法,如sigmoid函数或其他多标签分类算法。

三、参数初始化

导包:

import torch
import torch.nn.functional as F
import torch.nn as nn

3.1 均匀分布初始化

  • 权重参数初始化从区间均匀随机取值。即在( − 1 d , 1 d \frac{-1}{\sqrt{d}},\frac{1}{\sqrt{d}} d 1,d 1 )均匀分布中生成当前神经元的权重,其中 d d d 为每个神经元的输入数量

代码演示:

linear = nn.Linear(5, 3)
# 从0-1均匀分布产生参数
nn.init.uniform_(linear.weight)
print(linear.weight.data)

3.2 正态分布初始化

  • 随机初始化从均值为0,标准差是1的高斯分布中取样,使用一些很小的值对参数 W W W 进行初始化

代码演示:

linear = nn.Linear(5, 3)
nn.init.normal_(linear.weight, mean=0, std=1)
print(linear.weight.data)

3.3 全0初始化

  • ​ 将神经网络中的所有权重参数初始化为 0

代码演示:

linear = nn.Linear(5, 3)
nn.init.zeros_(linear.weight)
print(linear.weight.data)

3.4 全1初始化

  • ​ 将神经网络中的所有权重参数初始化为 1

代码演示:

linear = nn.Linear(5, 3)
nn.init.ones_(linear.weight)
print(linear.weight.data)

3.5 固定值初始化

  • 将神经网络中的所有权重参数初始化为某个固定值

代码演示:

linear = nn.Linear(5, 3)
nn.init.constant_(linear.weight, 5)  # 里边写 几 就是 用哪个值初始化
print(linear.weight.data)

3.6 Kaiming 初始化,也叫做 HE 初始化

3.6.1 正态化的Kaiming 初始化

  • s t d d e v = 2 f a n i n stddev = \sqrt{\frac{2}{fan_{in}}} stddev=fanin2
  • f a n i n fan_{in} fanin 输入神经元的个数

代码演示:

# kaiming 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_normal_(linear.weight)
print(linear.weight.data)

3.6.2 均匀分布的Kaiming 初始化

  • f a n i n fan_{in} fanin 输入神经元的个数
  • 它从 [ − l i m i t , l i m i t ] [-limit,limit] [limitlimit] 中的均匀分布中抽取样本, l i m i t limit limit 6 f a n i n \sqrt{\frac{6}{fan_{in}}} fanin6

代码演示:

# kaiming 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_uniform_(linear.weight)
print(linear.weight.data)

3.7 Xavier 初始化,也叫做 Glorot初始化

3.7.1 正态化的Xavier初始化

  • s t d d e v = 2 f a n i n + f a n o u t stddev = \sqrt{\frac{2}{fan_{in}+fan_{out}}} stddev=fanin+fanout2
  • f a n i n fan_{in} fanin 输入神经元的个数
  • f a n o u t fan_{out} fanout 输出的神经元个数

代码演示:

# xavier 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_normal_(linear.weight)
print(linear.weight.data)

3.7.2 均匀分布的Xavier初始化

  • 它从 [ − l i m i t , l i m i t ] [-limit,limit] [limitlimit] 中的均匀分布中抽取样本, l i m i t limit limit 6 f a n i n + f a n o u t \sqrt{\frac{6}{fan_{in}+fan_{out}}} fanin+fanout6

代码演示:

# xavier 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_uniform_(linear.weight)
print(linear.weight.data)

四、构建简单的神经网络

  • 案例:我们构建如下网络
    - 定义网络中的层结构,主要是全连接层,并进行初始化
  • 要求如下:
    • 第1个隐藏层:权重初始化采用标准化的xavier初始化 激活函数使用sigmoid
    • 第2个隐藏层:权重初始化采用标准化的He初始化 激活函数采用relu
    • out输出层线性层,采用 softmax 做数据分类输出

代码演示:

"""
在pytorch中定义深度神经网络其实就是层堆叠的过程,继承自nn.Module,实现两个方法:1、__init__方法中定义网络中的层结构,主要是全连接层,并进行初始化2、forward方法,在实例化模型的时候,底层会自动调用该函数。该函数中可以定义学习率,为初始化定义的layer传入数据等。
"""
import torch
import torch.nn as nn
from torchsummary import summary  # 计算模型参数,查看模型结构, pip install torchsummary# 创建神经网络模型类
class Model(nn.Module):# 初始化属性值def __init__(self):super(Model, self).__init__() # 调用父类的初始化属性值self.linear1 = nn.Linear(3, 3) # 创建第一个隐藏层模型, 3个输入特征,3个输出特征nn.init.xavier_normal_(self.linear1.weight) # 初始化权# 创建第二个隐藏层模型, 3个输入特征(上一层的输出特征),2个输出特征self.linear2 = nn.Linear(3, 2)# 初始化权重nn.init.kaiming_normal_(self.linear2.weight)# 创建输出层模型self.out = nn.Linear(2, 2)# 创建前向传播方法,自动执行forward()方法def forward(self, x):# 数据经过第一个线性层x = self.linear1(x)# 使用sigmoid激活函数x = torch.sigmoid(x)# 数据经过第二个线性层x = self.linear2(x)# 使用relu激活函数x = torch.relu(x)# 数据经过输出层x = self.out(x)# 使用softmax激活函数# dim=-1:每一维度行数据相加为1x = torch.softmax(x, dim=-1)return xif __name__ == "__main__":# 实例化model对象my_model = Model()# 随机产生数据my_data = torch.randn(5, 3)print("mydata shape", my_data.shape)# 数据经过神经网络模型训练output = my_model(my_data)print("output shape-->", output.shape)# 计算模型参数# 计算每层每个神经元的w和b个数总和summary(my_model, input_size=(3,), batch_size=5) # 查看模型参数print("======查看模型参数w和b======")for name, parameter in my_model.named_parameters():print(name, parameter)

总结

  • 我们通过学习了激活函数和参数初始化后,我们能实现搭建一个简单的神经网络。

相关文章:

二、神经网络基础与搭建

神经网络基础 前言一、神经网络1.1 基本概念1.2 工作原理 二、激活函数2.1 sigmoid激活函数2.1.1 公式2.1.2 注意事项 2.2 tanh激活函数2.2.1 公式2.2.2 注意事项 2.3 ReLU激活函数2.3.1 公式2.3.2 注意事项 2.4 SoftMax激活函数2.4.1 公式2.4.2 Softmax的性质2.4.3 Softmax的应…...

java导出pdf

引入包 <properties><itext.version>8.0.5</itext.version></properties><dependencies><dependency><groupId>com.itextpdf</groupId><artifactId>itext-core</artifactId><version>${itext.version}</…...

muduo之线程同步CountDownLatch

简介 CountDownLatch称为门阀&#xff0c;用于等待另外线程执行完成 结构 #mermaid-svg-6Azuu15vhIS2hCP1 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6Azuu15vhIS2hCP1 .error-icon{fill:#552222;}#mermaid-s…...

【Python系列】Python中打印详细堆栈信息的技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

SpringBoot中监听器、过滤器、拦截器和AOP详解

SpringBoot中监听器、过滤器、拦截器和AOP详解 在构建 Spring Boot 应用程序时&#xff0c;监听器&#xff08;Listener&#xff09;、过滤器&#xff08;Filter&#xff09;、拦截器&#xff08;Interceptor&#xff09;和面向切面编程&#xff08;AOP&#xff09;是四种常用…...

如何让手机ip变成动态

在数字化浪潮中&#xff0c;手机已成为我们日常生活中不可或缺的一部分。无论是浏览网页、使用社交媒体还是进行在线购物&#xff0c;手机都扮演着举足轻重的角色。然而&#xff0c;在享受网络带来的便利时&#xff0c;我们也需要关注网络安全和隐私保护。静态IP地址可能让手机…...

[Qt platform plugin问题] Could not load the Qt platform plugin “xcb“

Qt platform plugin 是 Qt 应用程序启动时加载的插件。不同的平台有不同的插件。 常见的插件有:linuxfb Wayland xcb 简单来说就是启动一个GUI程序, 离不开这些插件.选择其中一个就好 出现这个问题要么就是没有插件&#xff0c;要么就是插件依赖的库没有。 要么就是插件选则的…...

嵌入式开发人员如何选择合适的开源前端框架进行Web开发

在嵌入式系统的Web开发中&#xff0c;前端框架的选择对于项目的成败有着决定性的影响。一个合适的框架不仅能提高开发效率&#xff0c;还能保证系统的稳定性和可扩展性。本文将介绍几款适用于嵌入式Web开发的开源前端框架&#xff0c;并探讨它们的优缺点。 1. Element Plus V…...

MySQL数据库(七)----查询相关操作(子查询)

子查询是指在一个查询语句&#xff08;主查询&#xff09;内部嵌套的另一个查询语句。子查询可以出现在 SELECT、FROM、WHERE、HAVING 等子句中。它可以将一个复杂的查询问题分解为多个简单的查询步骤&#xff0c;从而更方便地获取所需的数据。 引入子查询&#xff1a; -- 查…...

01_Spring开胃菜

一、 为什么是Spring? 在正式进入Spring内容前我们先看看我们以往经典的程序设计。 当我们去登录时,会调用后端的Controller,Controller接收到用户的请求后会调用业务层的Service进行登录的业务处理,Service业务处理过程中会调用Dao层向DB获取数进行判断。 接下来我们用代…...

SpringBoot使用AspectJ的@Around注解实现AOP全局记录接口:请求日志、响应日志、异常日志

Spring 面向切面编程(AOP),系列文章: 《Spring面向切面编程(AOP)的简单实例》 《Spring使用AspectJ的注解式实现AOP面向切面编程》 《SpringBoot使用AspectJ实现AOP记录接口:请求日志、响应日志、异常日志》 《SpringBoot使用AspectJ的@Around注解实现AOP全局记录接口:…...

WPF下播放Rtmp的解决方案

介绍 在实际的开发过程中&#xff0c;需要在应用内部内嵌播放器进行视频的播放。官方默认的MediaElement控件只能播放有限的视频格式&#xff0c;也不能播放网络流。比较流行的解决方式是vlc的库&#xff0c;但是在实际使用过程中发现有很多问题。这里给大家推荐另一个比较好的…...

7.高可用集群架构Keepalived双主热备原理

一. 高可用集群架构Keepalived双主热备原理 (1)主机+备机keepalived配置(192.168.1.171) ! Configuration File for keepalivedglobal_defs {# 路由id:当前安装keepalived节点主机的标识符,全局唯一router_id keep_101 } #计算机节点(主机配置) vrrp_instance VI_1 {</...

为以人工智能为中心的工作负载重新设计的全局控制台

MinIO 控制台多年来一直是一个不断发展的产品。每次学习时&#xff0c;我们都会思考如何改进交互框架中这个非常重要的部分。首先是控制台&#xff0c;它在推出后的一年内就被广泛采用。更具体地说&#xff0c;超过 10K 个组织。接下来是企业控制台。这从对象存储与其 GUI 之间…...

go channel中的 close注意事项 range取数据

在使用 Go 语言中的 close 函数时&#xff0c;有一些注意事项需要牢记&#xff0c;以确保程序的健壮性和正确性&#xff1a; 1. **仅用于通道&#xff08;channel&#xff09;**&#xff1a; - close 函数只能用于关闭通道&#xff0c;不能用于关闭文件、网络连接或其他资源…...

Vue3 -- 项目配置之eslint【企业级项目配置保姆级教程1】

下面是项目级完整配置1➡eslint&#xff1a;【吐血分享&#xff0c;博主踩过的坑你跳过去&#xff01;&#xff01;跳不过去&#xff1f;太过分了给博主打钱】 浏览器自动打开项目&#xff1a; 你想释放双手吗&#xff1f;你想每天早上打开电脑运行完项目自动在浏览器打开吗&a…...

鸿蒙开发应用权限管理

简介 一种允许应用访问系统资源&#xff08;如&#xff1a;通讯录等&#xff09;和系统能力&#xff08;如&#xff1a;访问摄像头、麦克风等&#xff09;的通用权限访问方式&#xff0c;来保护系统数据&#xff08;包括用户个人数据&#xff09;或功能&#xff0c;避免它们被…...

【数据库】如何保证数据库迁移过程中数据的一致性?

在数据库迁移过程中&#xff0c;保证数据的一致性是非常重要的&#xff0c;尤其是在涉及到多个表、多个数据库或分布式系统的情况下。以下是一些确保数据一致性的最佳实践和方法&#xff1a; 1. 备份数据 在开始迁移之前&#xff0c;进行全面的数据备份是确保数据一致性的第…...

C++之内存管理

​ &#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;C入门 目录 前言 一、C/C内存分配 二、 malloc、calloc、realloc、free 三、C内存管理方式 3.1 new/delete 操作内置类型 3.2 new和detele操作自定义类型…...

ISP是什么?

isp全称为Internet Service Provider&#xff0c;即互联网服务提供商&#xff0c;是一种向用户提供互联网接入服务的公司或组织&#xff0c;它们提供的服务包括互联网接入、域名注册、网站托管等等。 ISP的应用场景非常广泛&#xff0c;几乎所有的互联网用户都需要通过ISP来接…...

机房动环境监控用各种列表已经淘汰了,现在都是可视化图表展示了

在信息技术飞速发展的今天&#xff0c;机房作为数据存储、处理和传输的核心场所&#xff0c;其稳定运行至关重要。过去&#xff0c;机房动环境监控主要依赖各种列表形式来呈现数据&#xff0c;但如今&#xff0c;这种方式已经逐渐被淘汰&#xff0c;取而代之的是更加直观、高效…...

RHCE的练习(12)

写一个脚本&#xff0c;完成以下要求&#xff1a; 给定一个用户&#xff1a; 如果其UID为0&#xff0c;就显示此为管理员&#xff1b;否则&#xff0c;就显示其为普通用户&#xff1b; #!/bin/bash ​ # 使用read命令获取用户名 read -p "请输入用户名: " username ​…...

uniapp自动注册机制:easycom

传统 Vue 项目中&#xff0c;我们需要注册、导入组件之后才能使用组件。 uniapp 框架提供了一种组件自动注册机制&#xff0c;只要你在 components 文件夹下新建的组件满足 /components/组件名/组件名.vue 的命名规范&#xff0c;就能直接使用。 注意&#xff1a;组件的文件夹…...

【论文阅读】(Security) Assertions by Large Language Models

论文笔记:(Security) Assertions by Large Language Models 来源:IEEE TRANSACTIONS ON INFORMATION FORENSICS AND SECURITY I. 引言 计算机系统的安全性通常依赖于硬件的根信任。硬件漏洞可能对系统造成严重影响,因此需要支持安全验证的技术。断言验证是一种流行的验证…...

C++ 编程基础(5)类与对象 | 5.8、面向对象五大原则

文章目录 一、面向对象五大原则1、单一功能&#xff08;Single Responsibility Principle, SRP&#xff09;2、开放封闭原则&#xff08;Open/Closed Principle, OCP&#xff09;3、里氏替换原则&#xff08;Liskov Substitution Principle, LSP&#xff09;4、接口隔离原则&am…...

node.js中express的基本了解

定义 Express是基于Node.js平台&#xff0c;快速、开放、极简的Web开发框架。 本质 Express是一个npm上的第三方包&#xff0c;提供了快速创建Web服务器的便捷方法。 作用 与Node.js内置的http模块类似&#xff0c;Express也是专门用来创建Web服务器的&#xff0c;但它极大地简…...

AI大模型(一):Prompt AI编程

一、Prompt Engineering&#xff0c;提示工程 提示工程也叫指令工程&#xff1a; Prompt是发给大模型的指令&#xff0c;比如【讲个睡前故事】、【用Python写个消消乐游戏】等&#xff1b;本质上大模型相关的工程工作&#xff0c;都是围绕prompt展开的&#xff1b;提示工程门…...

ArcGIS Pro属性表乱码与字段名3个汉字解决方案大总结

01 背景 我们之前在使用ArcGIS出现导出Excel中文乱码及shp添加字段3个字被截断的情况&#xff0c;我们有以下应对策略&#xff1a; 推荐阅读&#xff1a;ArcGIS导出Excel中文乱码及shp添加字段3个字被截断&#xff1f; 那如果我们使用ArGIS Pro出现上述问题&#xff0c;该如何…...

小程序-基于java+SpringBoot+Vue的驾校预约平台设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…...

计算机网络网关简介

网关&#xff0c;在计算机网络中扮演着至关重要的角色&#xff0c;它如同不同语言间的翻译官&#xff0c;让不同网络协议、不同体系结构的网络能够相互通信。简而言之&#xff0c;网关就是一个网络连接到另一个网络的“关口”&#xff0c;负责数据的接收、转换与发送。 在局域…...