NLP中的对抗训练(附PyTorch实现)

news2024/11/22 8:50:21

对抗样本的基本概念

要认识对抗训练,首先要了解"对抗样本",它首先出现在论文Intriguing properties of neural networks之中。简单来说,它是指对于人类来说"看起来"几乎一样,但对于模型来说预测结果却完全不一样的样本,比如下面的经典例子(一只熊猫加了点扰动就被识别成了长臂猿)

那么,什么样的样本才是好的对抗样本呢?对抗样本一般需要具有两个特点:

  1. 相对原始输入,所添加的扰动是微小的
  2. 能使模型犯错

对抗训练的基本概念

GAN之父lan Goodfellow在15年的ICLR中第一次提出了对抗训练的概念,简言之,就是在原始输入样本 x x x上加一个扰动 Δ x \Delta x Δx,得到对抗样本之后,用其进行训练。也就是说,问题可以被抽象成这样一个模型:
max ⁡ θ P ( y ∣ x + Δ x ; θ ) \begin{aligned} \max_{\theta} P(y|x+\Delta x;\theta) \end{aligned} θmaxP(yx+Δx;θ)
其中, y y y为ground truth, θ \theta θ为模型参数。那扰动 Δ x \Delta x Δx如何计算呢?Goodfellow认为:神经网络由于其线性的特点,很容易受到线性扰动的攻击

This linear behavior suggests that cheap, analytical perturbations of a linear model should also damage neural networks

于是,他提出了Fast Gradinet Sign Method(FGSM),来计算输入样本的扰动。扰动可以被定义为:
Δ x = ϵ ⋅ sgn ( ∇ x L ( x , y ; θ ) ) \Delta x = \epsilon \cdot \text{sgn}(\nabla_x L(x, y;\theta)) Δx=ϵsgn(xL(x,y;θ))
其中, sgn \text{sgn} sgn为符号函数, L L L为损失函数(很多地方也用 J J J来表示)。Goodfellow发现, ϵ = 0.25 \epsilon=0.25 ϵ=0.25时,这个扰动能给一个单层分类器造成99.9%的错误率。看似这个扰动的发现有点拍脑门,但仔细想想,其实这个扰动计算的思想可以理解为:将输入样本想着损失上升的方向再进一步,得到的对抗样本就能造成更大的损失,提高模型的错误率

为了帮助读者理解上面一段话的含义,我们首先回顾一下梯度下降:在神经网络中,为了使得降低模型的损失,我们有这么一个简单的式子:
KaTeX parse error: Expected '}', got '_' at position 11: \text{new_̲weights = old_w…

如果要我指出其中最重要的部分,那必然是减号。这个减号使得无论当前梯度gradients是正还是负,最终new_weights的前进方向必然是使得loss下降的方向。那么反过来,如果将减号改为加号,并且将weights改为 x x x,对抗训练中使得损失上升的思想就出来了
x = x + Δ x x = x + \Delta x x=x+Δx

上图中,我们看到两个箭头代表了两种不同的梯度调整策略。左侧的方程是训练神经网络最常见方程,它朝着梯度下降、损失下降的方向前进。右侧的方程则不是这样,它朝着梯度上升、损失上升的方向前进

实际上公式中的 sgn \text{sgn} sgn函数作用仅仅只是为了防止 ∇ x L ( x , y ; θ ) \nabla xL(x,y;\theta) xL(x,y;θ)过大所做的缩放,除了 sgn \text{sgn} sgn函数以外,还有一种常见的方式是:
Δ x = ϵ ⋅ ∇ x L ( x , y ; θ ) ∣ ∣ ∇ x L ( x , y ; θ ) ∣ ∣ \Delta x = \epsilon·\frac{\nabla_x L(x,y;\theta)}{||\nabla_xL(x,y;\theta)||} Δx=ϵxL(x,y;θ)xL(x,y;θ)

最后,Goodfellow还总结了对抗训练的两个作用:

  1. 提高模型应对恶意对抗样本时的鲁棒性
  2. 作为一种regularization,减少overfitting,提高泛化能力

Min-Max公式

Madry在2018年的ICLR论文Towards Deep Learning Models Resistant to Adversarial Attacks中总结了之前的工作。总的来说,对抗训练可以统一写成如下格式:
min ⁡ θ E ( x , y ) ∼ D [ max ⁡ Δ x ∈ Ω L ( x + Δ x , y ; θ ) ] \min_{\theta}\mathbb{E}_{(x,y)\sim\mathcal{D}}\left[\max_{\Delta x\in\Omega}L(x+\Delta x, y;\theta)\right] θminE(x,y)D[ΔxΩmaxL(x+Δx,y;θ)]
其中 D \mathcal{D} D代表数据集, x x x代表输入, y y y代表标签, θ \theta θ是模型参数, L ( x , y ; θ ) L(x,y;\theta) L(x,y;θ)是单个样本的loss, Δ x \Delta x Δx是扰动, Ω \Omega Ω是扰动空间。这个式子可以分步理解如下:

  1. x x x里注入扰动 Δ x \Delta x Δx Δ x \Delta x Δx的目标是让 L ( x + Δ x , y ; θ ) L(x+\Delta x, y;\theta) L(x+Δx,y;θ)越大越好,也就是说尽可能让现有模型的预测出错
  2. 当然 Δ x \Delta x Δx也不是无约束的,它不能太大,否则达不到"看起来几乎一样"的效果,所以 Δ x \Delta x Δx要满足一定的约束,常规的约束是 ∣ ∣ Δ x ∣ ∣ ≤ ϵ ||\Delta x||\leq \epsilon Δxϵ,其中 ϵ \epsilon ϵ是一个常数
  3. 每个样本都构造出对抗样本 x + Δ x x+\Delta x x+Δx之后,用 ( x + Δ , y ) (x+\Delta,y) (x+Δ,y)作为数据去最小化loss来更新参数 θ \theta θ(梯度下降)
  4. 反复交替执行1、2、3步

从CV到NLP

对于CV领域的任务,上述对抗训练的流程可以顺利执行下来,因为图像可以视为普通的连续实数向量, Δ x \Delta x Δx也是一个实数向量,因此 x + Δ x x+\Delta x x+Δx依然可以是有意义的图像。但NLP不一样,NLP的输入是文本,它本质上是one-hot向量,而两个不同的one-hot向量,其欧式距离恒为 2 \sqrt{2} 2 ,因此对于理论上不存在什么"小扰动"

一个自然的想法是像论文Adversarial Training Methods for Semi-Supervised Text Classification一样,将扰动加到Embedding层

Because the set of high-dimensional one-hot vectors does not admit infinitesimal perturbation, we define the perturbation on continuous word embeddings instead of discrete word inputs.

这个思路在操作上没有问题,但问题是,扰动后的Embedding向量不一定能匹配上原来的Embedding向量表,这样一来对Embedding层的扰动就无法对应上真实的文本输入,这就不是真正意义上的对抗样本了,因为对抗样本依然能对应一个合理的原始输入

那么,在Embedding层做对抗扰动还有没有意义呢?有!实验结果显示,在很多任务中,在Embedding层进行对抗扰动能有效提高模型的性能

Fast Gradient Method(FGM)

上面提到,Goodfellow在15年的ICLR中提出了Fast Gradient Sign Method(FGSM),随后,在17年的ICLR中,Goodfellow对FGSM中计算扰动的部分做了一点简单的修改。假设输入文本序列的Embedding vectors [ v 1 , v 2 , . . . , v T ] [v_1,v_2,...,v_T] [v1,v2,...,vT] x x x,Embedding的扰动为
Δ x = ϵ ⋅ g ∣ ∣ g ∣ ∣ 2 g = ∇ x L ( x , y ; θ ) \begin{aligned} \Delta x &= \epsilon · \frac{g}{||g||_2}\\ g &= \nabla_x L(x,y;\theta) \end{aligned} Δxg=ϵg2g=xL(x,y;θ)
实际上就是取消了符号函数,用二范式做了一个scale,需要注意的是:这里的norm计算的是,每个样本的输入序列中出现过的词组成的矩阵的梯度norm。原作者提供了一个TensorFlow的实现,在他的实现中,公式里的 x x x是Embedding后的结果(batch_size, seq_len, hid_dim),对其梯度 g g g的后面两维计算norm,得到的是一个维度为(batch_size, 1, 1)的向量 ∣ ∣ g ∣ ∣ 2 ||g||_2 g2。为了实现插件式的调用,笔者将一个batch抽象成一个样本,一个batch统一用一个norm,其实norm本来也只是一个缩放的作用,影响不大。实现如下:

class FGM():
    def __init__(self, model):
        self.model = model
        self.backup = {}

    def attack(self, epsilon=1., emb_name='emb'):
        # emb_name这个参数要换成你模型中embedding的参数名
        # 例如,self.emb = nn.Embedding(5000, 100)
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name:
                self.backup[name] = param.data.clone()
                norm = torch.norm(param.grad) # 默认为2范数
                if norm != 0:
                    r_at = epsilon * param.grad / norm
                    param.data.add_(r_at)

    def restore(self, emb_name='emb'):
        # emb_name这个参数要换成你模型中embedding的参数名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name: 
                assert name in self.backup
                param.data = self.backup[name]
        self.backup = {}

需要使用对抗训练的时候,只需要添加五行代码:

# 初始化
fgm = FGM(model)
for batch_input, batch_label in data:
  # 正常训练
  loss = model(batch_input, batch_label)
  loss.backward() # 反向传播,得到正常的grad
  # 对抗训练
  fgm.attack() # embedding被修改了
  # optimizer.zero_grad() # 如果不想累加梯度,就把这里的注释取消
  loss_sum = model(batch_input, batch_label)
  loss_sum.backward() # 反向传播,在正常的grad基础上,累加对抗训练的梯度
  fgm.restore() # 恢复Embedding的参数
  # 梯度下降,更新参数
  optimizer.step()
  optimizer.zero_grad()

Projected Gradient Descent(PGD)

FGM的思路是梯度上升,本质上来说没有什么问题,但是FGM简单粗暴的"一步到位"是不是有可能并不能走到约束内的最优点呢?当然是有可能的。于是,一个新的想法诞生了,Madry在18年的ICLR中提出了Projected Gradient Descent(PGD)方法,简单的说,就是"小步走,多走几步",如果走出了扰动半径为 ϵ \epsilon ϵ的空间,就重新映射回"球面"上,以保证扰动不要过大:
x t + 1 = ∏ x + S ( x t + α g ( x t ) ∣ ∣ g ( x t ) ∣ ∣ 2 ) g ( x t ) = ∇ x t L ( x t , y ; θ ) \begin{aligned} x_{t+1}&=\prod_{x+S}(x_t+\alpha\frac{g(x_t)}{||g(x_t)||_2})\\ g(x_t)&=\nabla_{x_t}L(x_t,y;\theta) \end{aligned} xt+1g(xt)=x+S(xt+αg(xt)2g(xt))=xtL(xt,y;θ)
其中 S = { r ∈ R d : ∣ ∣ r ∣ ∣ 2 ≤ ϵ } S=\{r\in \mathbb{R}^d:||r||_2\leq \epsilon\} S={rRd:r2ϵ}为扰动的约束空间, α \alpha α为小步的步长

由于PGD理论和代码比较复杂,因此下面先给出伪代码方便理解,然后再给出代码

对于每个x:
  1.计算x的前向loss,反向传播得到梯度并备份
  对于每步t:
    2.根据Embedding矩阵的梯度计算出r,并加到当前Embedding上,相当于x+r(超出范围则投影回epsilon内)
    3.t不是最后一步: 将梯度归0,根据(1)的x+r计算前后向并得到梯度
    4.t是最后一步: 恢复(1)的梯度,计算最后的x+r并将梯度累加到(1)5.将Embedding恢复为(1)时的值
  6.根据(4)的梯度对参数进行更新

可以看到,在循环中 r r r是逐渐累加的,要注意的是最后更新参数只使用最后一个x+r算出来的梯度

class PGD():
    def __init__(self, model):
        self.model = model
        self.emb_backup = {}
        self.grad_backup = {}

    def attack(self, epsilon=1., alpha=0.3, emb_name='emb', is_first_attack=False):
        # emb_name这个参数要换成你模型中embedding的参数名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name:
                if is_first_attack:
                    self.emb_backup[name] = param.data.clone()
                norm = torch.norm(param.grad)
                if norm != 0:
                    r_at = alpha * param.grad / norm
                    param.data.add_(r_at)
                    param.data = self.project(name, param.data, epsilon)

    def restore(self, emb_name='emb'):
        # emb_name这个参数要换成你模型中embedding的参数名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name: 
                assert name in self.emb_backup
                param.data = self.emb_backup[name]
        self.emb_backup = {}
        
    def project(self, param_name, param_data, epsilon):
        r = param_data - self.emb_backup[param_name]
        if torch.norm(r) > epsilon:
            r = epsilon * r / torch.norm(r)
        return self.emb_backup[param_name] + r
        
    def backup_grad(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                self.grad_backup[name] = param.grad.clone()
    
    def restore_grad(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                param.grad = self.grad_backup[name]

使用的时候要麻烦一点:

pgd = PGD(model)
K = 3
for batch_input, batch_label in data:
    # 正常训练
    loss = model(batch_input, batch_label)
    loss.backward() # 反向传播,得到正常的grad
    pgd.backup_grad() # 保存正常的grad
    # 对抗训练
    for t in range(K):
        pgd.attack(is_first_attack=(t==0)) # 在embedding上添加对抗扰动, first attack时备份param.data
        if t != K-1:
            optimizer.zero_grad()
        else:
            pgd.restore_grad() # 恢复正常的grad
        loss_sum = model(batch_input, batch_label)
        loss_sum.backward() # 反向传播,并在正常的grad基础上,累加对抗训练的梯度
    pgd.restore() # 恢复embedding参数
    # 梯度下降,更新参数
    optimizer.step()
    optimizer.zero_grad()

Virtual Adversarial Training

除了监督任务,对抗训练还可以用在半监督任务中,尤其对于NLP任务来说,很多时候我们拥有大量的未标注文本,那么就可以参考Distributional Smoothing with Virtual Adversarial Training进行半监督训练

首先,抽取一个随机标准正态扰动 ( d ∼ N ( 0 , 1 ) ∈ R d ) (d\sim \mathcal{N}(0, 1) \in \mathbb{R}^d) (dN(0,1)Rd),加到Embedding上,并用KL散度计算梯度:
g = ∇ x ′ D K L ( p ( ⋅ ∣ x ; θ ) ∣ ∣ p ( ⋅ ∣ x ′ ; θ ) ) x ′ = x + ξ d \begin{aligned} g &= \nabla_{x'} D_{KL}(p(·\mid x;\theta)||p(·\mid x';\theta))\\ x' &= x + \xi d \end{aligned} gx=xDKL(p(x;θ)p(x;θ))=x+ξd
然后,用得到的梯度,计算对抗扰动,并进行对抗训练:
min ⁡ θ D K L ( p ( ⋅ ∣ x ; θ ) ∣ ∣ p ( ⋅ ∣ x ∗ ; θ ) ) x ∗ = x + ϵ g ∣ ∣ g ∣ ∣ 2 \begin{aligned} \min_\theta & D_{KL}(p(\cdot|x;\theta)||p(\cdot|x^*;\theta)) \\\\ x^* &= x+\epsilon \frac{g}{||g||_2} \end{aligned} θminxDKL(p(x;θ)p(x;θ))=x+ϵg2g
实现起来有很多细节,并且笔者对于NLP的半监督任务了解并不多,因此这里就不给出实现了

实验对照

为了说明对抗训练的作用,网上有位大佬选了四个GLUE中的任务进行了对照试验,实验代码使用的Huggingface的transformers/examples/run_glue.py,超参都是默认的,对抗训练用的也是相同的超参

任务MetricsBERT-BaseFGMPGD
MRPCAccuracy83.686.885.8
CoLAMatthew’s corr56.056.056.8
STS-BPerson/Spearmean corr89.3/88.889.3/88.889.3/88.8
RTEAccuracy64.366.864.6

可以看出,对抗训练还是有效的,在MRPC和RTE任务上甚至可以提高三四个百分点。不过,根据我们使用的经验来看,是否有效有时也取决于数据集

为什么对抗训练有效?

Adversarial Training 能够提升 Word Embedding 质量的一个原因是:

有些词与比如(good 和 bad),其在语句中 Grammatical Role 是相近的,我理解为词性相同(都是形容词),并且周围一并出现的词语也是相近的,比如我们经常用来修饰天气或者一天的情况(The weather is good/bad; It’s a good/bad day),这些词的 Word Embedding 是非常相近的。文章中用 Good 和 Bad 作为例子,找出了其最接近的 10 个词:

可以发现在 Baseline 和 Random 的情况下, good 和 bad 出现在了彼此的邻近词中,而喂给模型经过扰动之后的 X-adv 之后,也就是 Adversarial 这一列,这种现象就没有出现,事实上, good 掉到了 bad 接近程度排第 36 的位置

我们可以猜测,在 Word Embedding 上添加的 Perturbation 很可能会导致原来的good变成bad,导致分类错误,计算的 Adversarial Loss 很大,而计算 Adversarial Loss 的部分是不参与梯度计算的,也就是说,模型(LSTM 和最后的 Dense Layer)的 Weight 和 Bias 的改变并不会影响 Adversarial Loss,模型只能通过改变 Word Embedding Weight 来努力降低它,进而如文章所说:

Adversarial training ensures that the meaning of a sentence cannot be inverted via a small change, so these words with similar grammatical role but different meaning become separated.

这些含义不同而语言结构角色类似的词能够通过这种 Adversarial Training 的方法而被分离开,从而提升了 Word Embedding 的质量,帮助模型取得了非常好的表现

梯度惩罚

这一部分,我们从另一个视角对上述结果进行分析,从而推出对抗训练的另一种方法,并且得到一种关于对抗训练更直观的几何理解

假设已经得到对抗扰动 Δ x \Delta x Δx,那么我们在更新 θ \theta θ时,考虑对 L ( x + Δ x , y ; θ ) L(x+\Delta x,y;\theta) L(x+Δx,y;θ)的泰勒展开:
min ⁡ θ E ( x , y ) ∼ D [ L ( x + Δ x , y ; θ ) ] ≈   min ⁡ θ E ( x , y ) ∼ D [ L ( x , y ; θ ) + ⟨ ∇ x L ( x , y ; θ ) , Δ x ⟩ ] \begin{aligned} &\min_{\theta}\mathbb{E}_{(x,y)\sim\mathcal{D}}\left[L(x+\Delta x, y;\theta)\right]\\ \approx&\, \min_{\theta}\mathbb{E}_{(x,y)\sim\mathcal{D}}\left[L(x, y;\theta)+\langle\nabla_x L(x, y;\theta), \Delta x\rangle\right] \end{aligned} θminE(x,y)D[L(x+Δx,y;θ)]θminE(x,y)D[L(x,y;θ)+xL(x,y;θ),Δx]

其中, ⟨ x , y ⟩ = x ⋅ y = x T y \langle x,y \rangle = x·y = x^Ty x,y=xy=xTy

对应 θ \theta θ的梯度为
∇ θ L ( x , y ; θ ) + ⟨ ∇ θ ∇ x L ( x , y ; θ ) , Δ x ⟩ \nabla_{\theta} L(x,y;\theta)+\langle \nabla_{\theta}\nabla{x}L(x,y;\theta), \Delta x\rangle θL(x,y;θ)+θxL(x,y;θ),Δx
带入 Δ x = ϵ ∇ x L ( x , y ; θ ) \Delta x = \epsilon \nabla_x L(x,y;\theta) Δx=ϵxL(x,y;θ),得到
∇ θ L ( x , y ; θ ) + ϵ ⟨ ∇ θ ∇ x L ( x , y ; θ ) , ∇ x L ( x , y ; θ ) ⟩ =   ∇ θ ( L ( x , y ; θ ) + 1 2 ϵ ∥ ∇ x L ( x , y ; θ ) ∥ 2 ) \begin{aligned}&\nabla_{\theta}L(x, y;\theta)+\epsilon\langle\nabla_{\theta}\nabla_x L(x, y;\theta), \nabla_x L(x, y;\theta)\rangle\\ =&\,\nabla_{\theta}\left(L(x, y;\theta)+\frac{1}{2}\epsilon\left\Vert\nabla_x L(x, y;\theta)\right\Vert^2\right) \end{aligned} =θL(x,y;θ)+ϵθxL(x,y;θ),xL(x,y;θ)θ(L(x,y;θ)+21ϵxL(x,y;θ)2)

KaTeX parse error: No such environment: align* at position 8: \begin{̲a̲l̲i̲g̲n̲*̲}̲ &\langle \frac…

这个结果表示,对输入样本施加 ϵ ∇ x L ( x , y ; θ ) \epsilon \nabla_x L(x,y;\theta) ϵxL(x,y;θ)的对抗扰动,一定程度上等价于往loss里边加入**“梯度惩罚”**
1 2 ϵ ∣ ∣ ∇ x L ( x , y ; θ ) ∣ ∣ 2 \frac{1}{2}\epsilon ||\nabla_x L(x,y;\theta)||^2 21ϵxL(x,y;θ)2
如果对抗扰动 Δ x = ϵ ∇ x L ( x , y ; θ ) ∣ ∣ ∇ x L ( x , y ; θ ∣ ∣ \Delta x = \epsilon \frac{\nabla_x L(x,y;\theta)}{||\nabla_x L(x,y;\theta||} Δx=ϵxL(x,y;θxL(x,y;θ),那么对应的梯度惩罚项则是 ϵ ∣ ∣ ∇ x L ( x , y ; θ ) ∣ ∣ \epsilon ||\nabla_x L(x,y;\theta)|| ϵxL(x,y;θ)

总结

这篇博客梳理了NLP对抗训练发展的来龙去脉,介绍了对抗训练的数学定义,并对于两种经典的对抗训练方法,提供了插件式的实现,做了简单的实验对照。由于笔者接触对抗训练的时间也并不长,如果文中有理解偏差的地方,希望读者不吝指出。另外还有一些对抗训练算法,读者有兴趣可以查看一文搞懂NLP中的对抗训练以及对抗训练的理解,以及FGM、PGD和FreeLB的详细介绍这两篇文章

References

  • Adversarial Attacks on Neural Networks: Exploring the Fast Gradient Sign Method
  • 对抗训练浅谈:意义、方法和思考(附Keras实现)
  • 功守道:NLP中的对抗训练 + PyTorch实现
  • 一文搞懂NLP中的对抗训练
  • 关于 Adversarial Training 在 NLP 领域的一些思考

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

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

相关文章

[附源码]JAVA毕业设计公务用车管理智慧云服务监管平台(系统+LW)

[附源码]JAVA毕业设计公务用车管理智慧云服务监管平台(系统LW) 目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff0…

[附源码]Python计算机毕业设计SSM蓝色港湾房产交易与租赁系统(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

最近基于深度学习大火的AIGC将会抢原创工作者的饭碗?

NLG | CLIP | Diffusion Model GAN | AIGC | Stable Diffusion 随着CLIP、DALLE、Diffusion Model、Magic3D、Stable Diffusion等技术的快速发展,AIGC在全球各大科技巨头间可谓是高频词汇,连带着AI这个老生常谈的话题也一并火热起来。 去年三月&#xf…

【R】R包MethylCal安装问题解决 Rtools is required to build R packages

文章目录写在前面问题描述解决过程【1】安装INLA【2】安装Rtools写在前面 吐槽一番: 一般情况下,不是在万不得已,真心不想用R,最让人望而却步的就是包的安装问题,动不动就出现版本不兼容问题,或者下载这个…

Chapter9.5:线性系统的状态空间分析与综合考研参考题

此系列属于胡寿松《自动控制原理题海与考研指导》(第三版)习题精选,仅包含部分经典习题,需要完整版习题答案请自行查找,本系列属于知识点巩固部分,搭配如下几个系列进行学习,可用于期末考试和考研复习。 自动控制原理(…

Java本地高性能缓存的几种实现方式

Java缓存技术可分为远端缓存和本地缓存,远端缓存常用的方案有著名的redis和memcache,而本地缓存的代表技术主要有HashMap,Guava Cache,Caffeine和Encahche。本篇博文仅覆盖了本地缓存,且突出探讨高性能的本地缓存。 本…

美信监控易:网络管理之链路专线管理

专线通常是指运营商为企事业单位提供的专用网络线路,用于满足其业务需求。专线管理可以提供对专线基础信息的维护,以及性能数据的监测能力。通过系统自动地、周期性地执行专线测试,获取指标数据,实现专线连通性、性能数据的全面感…

图数据结构之邻接链表Adjacency List(Python版)

前面学过两种图的数据结构,有兴趣的可以查阅:图数据结构之字典实现(Python版)https://blog.csdn.net/weixin_41896770/article/details/128125901 图数据结构之邻接矩阵Adjacency Matrix(Python版)https://blog.csdn.net/weixin_41896770/article/detai…

中文Stable Diffusion模型太乙使用教程

中文Stable Diffusion模型太乙使用教程 太乙模型介绍 在线体验地址: Stable Diffusion 太乙模型,首个开源的中文Stable Diffusion模型,基于0.2亿筛选过的中文图文对训练。 生成内容一直被视为 AI 领域中最具有挑战性的能力,最近大火的 AI 绘…

文献管理软件Zotero的安装和使用

文章目录前言一、Zotero简介二、安装与使用1、账号注册2、软件安装3、插件安装4、关联账户设置5、坚果云扩充(WebDAV)6、保存路径设置7、与Connected Papers联动8、参考文献的引用前言 随着阅读文献数量的增加,感觉一个好用的文献管理工具必…

08【SpringMVC的放行规则】

文章目录二、SpringMVC的放行规则2.1 SpringMVC提供的拦截规则2.2 缺省Servlet放行2.3 resources放行2.4 Handler放行2.5 放行规则小结二、SpringMVC的放行规则 2.1 SpringMVC提供的拦截规则 *.form:代表以*.form结尾的后缀请求都会进入springmvc管/:代…

Vue2.0开发之——Vue基础用法-axios(29)

一 概述 axios-使用axios发起基本的Get请求axios-结合async和await调用axiosaxios-使用解构赋值axios-基于axios.get和axios.post发起请求 二 axios-使用axios发起基本的Get请求 2.1 axios介绍 axios(发音:艾克C奥斯)是前端圈最火的、专注于数据库请求的库 在后面…

Linux---awk

Linux三剑客之一awk 简单介绍一下awk的用法 再谈三剑客 grep awk sed 三个并称Linux的三剑客 awk:适合编辑,处理匹配到的文本内容 grep:擅长单纯的查找或匹配文本内容 链接: Linux—grep sed:适合格式化文本内容,对文本进行复杂处理 链接: Linux—sed 文章目录Lin…

如何选择合适的香港物理服务器?

所有企业在部署自己的网络业务时,要有目标,正确的技术,尤其是服务器,可以帮助他们实现这些目标。比如,国内站长开展大型外贸业务又想要国内访问速度快,可以选择合适的香港物理服务器来解决这个问题。那么&a…

天舟系列货运飞船介绍

天舟系列货运飞船是由中国空间技术研究院研制的一款货运飞船,其主要任务是在我国空间站建造及运营期间进行物资运输补给。 天舟系列货运飞船主要用于对中国空间站在轨运行期间,。天舟系列货运飞船包括天舟一号、天舟二号、天舟三号、天舟四号、天舟五号等…

Chatbot(五)

一、走进聊天机器人 目标 知道常见的bot的分类知道企业中常见的流程和方法 1.1 目前企业中的常见的聊天机器人 QA BOT (问答机器人) : 回答问题 1.代表:智能名服 2.比如: 提问和回答TASK BOT(任务机器人): 助人们做事情 1.代表: siri 2.比如:设五明天早上9点的闹钟CHAT BOT…

虹科方案|HK-ATTO 和西部数据为性能要求苛刻的应用构建存储解决方案

解决方案特点 科学、医疗、工程和其他高性能环境需要同样高性能的存储。该解决方案必须存储大量数据。它还必须提供突破当今固态驱动器设备极限的速度。同时,组织需要一个软件定义的组件,使他们能够构建满足其技术和预算要求的完整存储基础架构。 昂贵的…

[附源码]Python计算机毕业设计Django动漫电影网站

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

初学者学习JS很吃力怎么办?到底该如何学习JS?

前言 觉得吃力是很正常的,首先这证明你在某些知识点上没有理解透彻,JS挺多的知识点点其实是比较抽象的,比如闭包、原型和原型链等,其次便是不会变通运用,这主要是敲代码熟练度的问题,所以我针对你这种情况…

PCA主成分分析法浅理解

ML课刚学,发现更多是对线性代数的回顾。更进一步说,统计机器学习方法就是以高数、线代和概率论为基石构筑的“一栋大厦”。下面主要沿着老师ppt的思路讲讲对PCA方法的个人理解。 这里u1Tx(i)u_1^Tx^{(i)}u1T​x(i)是x(i)x^{(i)}x(i)在单位方向向量u1u_1u…