深度学习中的优化算法二(Pytorch 19)

一 梯度下降

尽管梯度下降(gradient descent)很少直接用于深度学习,但了解它是理解下一节 随机梯度下降算法 的关键。例如,由于学习率过大,优化问题可能会发散,这种现象早已在梯度下降中出现。同样地,预处理 (preconditioning)是梯度下降中的一种常用技术,还被沿用到更高级的算法中。让我们从简单的一维梯度 下降开始。

1.1 一维梯度下降

即在一阶近似中,f(x + ϵ)可通过x处的函数值f(x)和一阶导数f ′ (x)得出。我们可以假设在负梯度方向上移动 的ϵ会减少f。为了简单起见,我们选择固定步长η > 0,然后取ϵ = −ηf′ (x)。将其代入泰勒展开式我们可以得到。

                x \leftarrow x - \eta {f}'(x)

因此,在梯度下降中,我们首先 选择初始值x和常数η > 0,然后使用它们 连续迭代x直到停止条件达成。例如, 当梯度|f ′ (x)|的幅度足够小 迭代次数达到某个值 时。

下面我们来展示如何实现梯度下降。为了简单起见,我们选用目标函数f(x) = x^2。尽管我们知道x = 0时f(x)能 取得最小值,但我们仍然使用这个简单的函数来观察x的变化。

%matplotlib inline
import numpy as np
import torch
from d2l import torch as d2ldef f(x):return x ** 2def f_grad(x):return 2 * x

接下来,我们使用 x = 10作为初始值,并假设η = 0.2。使用梯度下降法 迭代x共10次,我们可以看到,x的值 最终将接近最优解。

def gd(eta, f_grad):x = 10.0result = [x]for i in range(10):x -= eta * f_grad(x)result.append(float(x))print(f'epoch 10, x: {x:f}')return result
results = gd(0.2, f_grad)

对进行x优化的过程可以绘制如下。

def show_trace(results, f):n = max(abs(min(results)), abs(max(results)))f_line = torch.arange(-n, n, 0.01)d2l.set_figsize()d2l.plot([f_line, results], [[f(x) for x in f_line], [f(x) for x in results]], 'x', 'f(x)', fmts = ['-', '-o'])show_trace(results, f)

1.1.1 学习率

学习率(learning rate)决定目标函数能否收敛到局部最小值,以及何时收敛到最小值。学习率η可由算法设 计者设置。请注意,如果我们使用的学习率太小,将导致 x的更新非常缓慢,需要更多的迭代。例如,考虑同 一优化问题中η = 0.05的进度。如下所示,尽管经过了10个步骤,我们仍然离最优解很远。

show_trace(gd(0.05, f_grad), f)

相反,如果我们使用过高的学习率,|ηf′ (x)|对于一阶泰勒展开式可能太大。也就是说,(11.3.1)中 的O(η 2f ′2 (x))可能变得显著了。在这种情况下,x的迭代不能保证降低f(x)的值。例如,当学习率为η = 1.1时, x超出了最优解x = 0并逐渐发散

show_trace(gd(1.1, f_grad), f)

1.1.2 局部最小值

为了演示非凸函数的梯度下降,考虑函数f(x) = x · cos(cx),其中c为某常数。这个函数有无穷多个局部最小 值。根据我们选择的学习率,我们最终可能只会得到许多解的一个。下面的例子说明了(不切实际的)高学习率如何导致较差的局部最小值

c = torch.tensor(0.15 * np.pi)def f(x):return x * torch.cos(c * x)def f_grad(x):return torch.cos(c * x) - c * x * torch.sin(c * x)show_trace(gd(2, f_grad), f)

1.2 多元梯度下降

现在我们对单变量的情况有了更好的理解,让我们考虑一下x = [x1, x2, . . . , xd] ⊤的情况。即目标函数f : R d → R将向量映射成标量。相应地,它的梯度也是多元的,它是一个由d个偏导数组成的向量。

换句话说,在ϵ的二阶项中,最陡下降的方向由负梯度−∇f(x)得出。选择合适的学习率η > 0来生成典型的梯 度下降算法:

                X \leftarrow X - \eta \bigtriangledown f(x)

我们还需要两个辅助函数:第一个是update函数,并将其应用于初始值20次;第二个函数会显示x的轨迹。

def train_2d(trainer, steps = 20, f_grad = None):   #@savex1, x2, s1, s2 = -5, -2, 0, 0results = [(x1, x2)]for i in range(steps):if f_grad:x1, x2, s1, s2 = trainer(x1, x2, s1, s2, f_grad)else:x1, x2, s1, s2 = trainer(x1, x2, s1, s2)results.append((x1, x2))print(f'epoch {i + 1}, x1: {float(x1): f}, x2: {float(x2): f}')return results
def show_trace_2d(f, results): #@saved2l.set_figsize()d2l.plt.plot(*zip(*results), '-o', color = '#ff7f0e')x1, x2 = torch.meshgrid(torch.arange(-5.5, 1.0, 0.1),torch.arange(-3.0, 1.0, 0.1), indexing = 'ij')d2l.plt.contour(x1, x2, f(x1, x2), colors = '#1f77b4')d2l.plt.xlabel('x1')d2l.plt.ylabel('x2')

接下来,我们观察 学习率η = 0.1时优化变量x的轨迹。可以看到,经过20步之后,x的值接近其位于[0, 0]的最小值。虽然进展相当顺利,但相当缓慢

def f_2d(x1, x2):return x1 ** 2 + 2 * x2 ** 2def f_2d_grad(x1, x2):return (2 * x1, 4 * x2)def gd_2d(x1, x2, s1, s2, f_grad):g1, g2 = f_grad(x1, x2)return (x1 - eta * g1, x2 - eta * g2, 0, 0)eta = 0.1
show_trace_2d(f_2d, train_2d(gd_2d, f_grad = f_2d_grad))

1.2.1 自适应方法

选择“恰到好处”的学习率η是很棘手的。如果我们把它选得太小,就没有什么进展;如果太大,得到的解就会振荡,甚至可能发散。如果我们可以自动确定η,或者完全不必选择学习 率,会怎么样?除了考虑目标函数的值和梯度、还考虑它的曲率的二阶方法可以帮我们解决这个问题。虽然 由于计算代价的原因,这些方法不能直接应用于深度学习,但它们为如何设计高级优化算法提供了有用的思维直觉,这些算法可以模拟下面概述的算法的许多理想特性。

也就是说,作为优化问题的一部分,我们 需要将Hessian矩阵H求逆

举一个简单的例子,对于f(x) = 1 / 2 x ^ 2,我们有∇f(x) = x和H = 1。因此,对于任何x,我们可以获得ϵ = −x。 换言之,单单一步就足以完美地收敛,而无须任何调整。我们在这里比较幸运:泰勒展开式是确切的,因 为f(x + ϵ) = 1/2 x^2 + ϵx + 1/2 ϵ^2。

让我们看看其他问题。给定一个凸双曲余弦函数c,其中c为某些常数,我们可以看到经过几次迭代后,得到 了x = 0处的全局最小值。

c = torch.tensor(0.5)def f(x): # O目标函数return torch.cosh(c * x)def f_grad(x): # 目标函数的梯度return c * torch.sinh(c * x)def f_hess(x): # 目标函数的Hessianreturn c**2 * torch.cosh(c * x)def newton(eta=1):x = 10.0results = [x]for i in range(10):x -= eta * f_grad(x) / f_hess(x)results.append(float(x))print('epoch 10, x:', x)return resultsshow_trace(newton(), f)

现在让我们考虑一个非凸函数,比如f(x) = x cos(cx),c为某些常数。请注意在牛顿法中,我们最终将除 以Hessian。这意味着如果二阶导数是负的,f的值可能会趋于增加。这是这个算法的致命缺陷!让我们看看 实践中会发生什么。

c = torch.tensor(0.15 * np.pi)def f(x):return x * torch.cos(c * x)def f_grad(x):return torch.cos(c * x) - c * x * torch.sin(c * x)def f_hess(x):return - 2 * c * torch.sin(c * x) - x * c ** 2 * torch.cos(c * x)show_trace(newton(), f)

这发生了惊人的错误。我们怎样才能修正它?一种方法是用取Hessian的绝对值来修正另一个策略是重新引入学习率。这似乎违背了初衷,但不完全是——拥有二阶信息可以使我们在曲率较大时保持谨慎,而在目 标函数较平坦时则采用较大的学习率。让我们看看在学习率稍小的情况下它是如何生效的,比如η = 0.5。如 我们所见,我们有了一个相当高效的算法。

show_trace(newton(0.5), f)

小结:

  • 学习率的大小很重要:学习率太大会使模型发散,学习率太小会没有进展
  • 梯度下降会可能陷入局部极小值,而得不到全局最小值。
  • 在高维模型中,调整学习率是很复杂的
  • 预处理 有助于调节比例。
  • 牛顿法在凸问题中一旦开始正常工作,速度就会快得多。
  • 对于非凸问题,不要不作任何调整就使用牛顿法。

1.3 随机梯度下降

在前面的章节中,我们一直在训练过程中使用随机梯度下降,但没有解释它为什么起作用。为了澄清这一点,本节继续更详细地说明 随机梯度下降(stochastic gradient descent)。

%matplotlib inline
import math
import torch
from d2l import torch as d2l

在深度学习中,目标函数通常是训练数据集中每个样本的损失函数的平均值。给定n个样本的训练数据集,我们假设fi(x)是关于索引i的训练样本的损失函数,其中x是参数向量。

def f(x1, x2): # 目标函数return x1 ** 2 + 2 * x2 ** 2def f_grad(x1, x2): # 目标函数的梯度return 2 * x1, 4 * x2def sgd(x1, x2, s1, s2, f_grad):g1, g2 = f_grad(x1, x2)# 模拟有噪声的梯度g1 += torch.normal(0.0, 1, (1,)).item()g2 += torch.normal(0.0, 1, (1,)).item()eta_t = eta * lr()return (x1 - eta_t * g1, x2 - eta_t * g2, 0, 0)def constant_lr():return 1eta = 0.1
lr = constant_lr # 常数学习速度
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))

1.3.1 动态学习率

用与时间相关的学习率η(t)取代η增加了控制优化算法收敛的复杂性。特别是,我们需要弄清η的衰减速度。 如果太快,我们将过早停止优化。如果减少的太慢,我们会在优化上浪费太多时间。

正如预期的那样,参数的方差大大减少。但是,这是以未能收敛到最优解x = (0, 0)为代价的。即使经过1000个,迭代步骤,我们仍然离最优解很远。事实上,该算法根本无法收敛。另一方面,如果我们使用多项式衰减,其中学习率随迭代次数的平方根倒数衰减,那么仅在50次迭代之后,收敛就会更好。

def polynomial_lr():# 在函数外部定义,而在内部更新的全局变量global tt += 1return (1 + 0.1 * t) ** (-0.5)t = 1
lr = polynomial_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))

小结:

  • 对于凸问题,我们可以证明,对于广泛的学习率选择,随机梯度下降将收敛到最优解
  • 对于深度学习而言,情况通常并非如此。但是,对凸问题的分析使我们能够深入了解如何进行优化,即逐步降低学习率,尽管不是太快。
  • 如果学习率太小或太大,就会出现问题。实际上,通常只有经过多次实验后才能找到合适的学习率。
  • 当训练数据集中有更多样本时,计算梯度下降的每次迭代的代价更高,因此在这些情况下,首选随机梯度下降。
  • 随机梯度下降的最优性保证在非凸情况下一般不可用,因为需要检查的局部最小值的数量可能是指数级的。

二 小批量随机梯度下降

到目前为止,我们在基于梯度的学习方法中遇到了两个极端情况:一是使用完整数据集来计算梯度并更新参数,二是一次处理一个训练样本来取得进展。二者各有利弊:每当数据非常相似时,梯度下降并不是非常“数据高效”。而由于 CPU和GPU无法充分利用向量化,随机梯度下降并不特别“计算高效”。这暗示 了两者之间可能有折中方案,这便涉及到 小批量随机梯度下降(minibatch gradient descent)。

2.1 向量化和缓存

使用 小批量的决策的核心是计算效率。当考虑与多个GPU和多台服务器并行处理时,这一点最容易被理解。 在这种情况下,我们需要向每个GPU发送至少一张图像。有了每台服务器8个GPU和16台服务器,我们 就能得到大小为128的小批量

当涉及到单个GPU甚至CPU时,事情会更微妙一些:这些设备有多种类型的内存、通常情况下多种类型的计算单元以及在它们之间不同的带宽限制。例如,一个CPU有少量寄存器(register),L1和L2缓存,以及L3缓存(在不同的处理器内核之间共享)。随着缓存的大小的增加,它们的延迟也在增加,同时带宽在减少。可以说,处理器能够执行的操作远比主内存接口所能提供的多得多。

首先,具有16个内核和AVX‐512向量化的2GHz CPU每秒可处理高达2 · 109 · 16 · 32 = 1012个字节。同时,GPU的 性能很容易超过该数字100倍。而另一方面,中端服务器处理器的带宽可能不超过100Gb/s,即不到处理器满负荷所需的十分之一。更糟糕的是,并非所有的内存入口都是相等的:内存接口通常为64位或更宽(例如,在 最多384位的GPU上)。因此读取单个字节会导致由于更宽的存取而产生的代价。

其次,第一次存取的额外开销很大,而按序存取(sequential access)或突发读取(burst read)相对开销较小

除了计算效率之外,Python和深度学习框架 本身带来的 额外开销 也是相当大的。回想一下,每次我们执行代码时,Python解释器都会向深度学习框架发送一个命令,要求将其插入到计算图中并在调度过程中处理它。 这样的额外开销可能是非常不利的。总而言之,我们最好用 向量化(和矩阵)。

%matplotlib inlineimport numpy as np
import torch
from torch import nn
from d2l import torch as d2ltimer = d2l.Timer()
A = torch.zeros(256, 256)
B = torch.randn(256, 256)
C = torch.randn(256, 256)

按元素分配只需遍历分别为B和C的所有行和列,即可将该值分配给A。

timer.start()
for i in range(256):for j in range(256):A[i, j] = torch.dot(B[i, :], C[:, j])timer.stop()   # 0.6227602958679199

更快的策略是执行按列分配。

# 逐列计算A=BC
timer.start()
for j in range(256):A[:, j] = torch.mv(B, C[:, j])
timer.stop()  # 0.01296234130859375

最有效的方法是在一个区块中执行整个操作。让我们看看它们各自的操作速度是多少。

# 一次性计算A=BC
timer.start()
A = torch.mm(B, C)
timer.stop()
# 乘法和加法作为单独的操作(在实践中融合)
gigaflops = [2/i for i in timer.times]
print(f'performance in Gigaflops: element {gigaflops[0]:.3f}, 'f'column {gigaflops[1]:.3f}, full {gigaflops[2]:.3f}')# performance in Gigaflops: element 3.212, column 3.670, full 154.293

2.2 读取数据集

让我们来看看如何从数据中有效地生成小批量。下面我们 使用NASA开发的测试机翼的数据集不同飞行器产 生的噪声132 来比较这些优化算法。为方便起见,我们只使用前1, 500样本。数据已作预处理:我们移除了均值 并将方差重新缩放到每个坐标为1。

让我们来看看如何从数据中有效地生成小批量。下面我们使用NASA开发的测试机翼的数据集不同飞行器产 生的噪声132来比较这些优化算法。为方便起见,我们只使用前1, 500样本。数据已作预处理:我们移除了均值 并将方差重新缩放到每个坐标为1。

#@save
d2l.DATA_HUB['airfoil'] = (d2l.DATA_URL + 'airfoil_self_noise.dat','76e5be1548fd8222e5074cf0faae75edff8cf93f')
#@save
def get_data_ch11(batch_size=10, n=1500):data = np.genfromtxt(d2l.download('airfoil'),dtype=np.float32, delimiter='\t')data = torch.from_numpy((data - data.mean(axis=0)) / data.std(axis=0))data_iter = d2l.load_array((data[:n, :-1], data[:n, -1]),batch_size, is_train=True)return data_iter, data.shape[1]-1

2.3 从零开始实现

已经实现过小批量随机梯度下降算法。我们在这里将它的输入参数变得更加通用,主要是为了方 便本章后面介绍的其他优化算法也可以使用同样的输入。具体来说,我们添加了一个状态输入states并将超 参数放在字典hyperparams中。此外,我们将在训练函数里对各个小批量样本的损失求平均,因此优化算法中 的梯度不需要除以批量大小。

def sgd(params, states, hyperparams):for p in params:p.data.sub_(hyperparams['lr'] * p.grad)p.grad.data.zero_()

下面实现一个通用的训练函数,以方便本章后面介绍的其他优化算法使用。它初始化了一个线性回归模型, 然后可以使用小批量随机梯度下降以及后续小节介绍的其他算法来训练模型。

#@save
def train_ch11(trainer_fn, states, hyperparams, data_iter,feature_dim, num_epochs=2):# 初始化模型w = torch.normal(mean=0.0, std=0.01, size=(feature_dim, 1),requires_grad=True)b = torch.zeros((1), requires_grad=True)net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss# 训练模型animator = d2l.Animator(xlabel='epoch', ylabel='loss',xlim=[0, num_epochs], ylim=[0.22, 0.35])n, timer = 0, d2l.Timer()for _ in range(num_epochs):for X, y in data_iter:l = loss(net(X), y).mean()l.backward()trainer_fn([w, b], states, hyperparams)n += X.shape[0]if n % 200 == 0:timer.stop()animator.add(n/X.shape[0]/len(data_iter),(d2l.evaluate_loss(net, data_iter, loss),))timer.start()print(f'loss: {animator.Y[0][-1]:.3f}, {timer.avg():.3f} sec/epoch')return timer.cumsum(), animator.Y[0]

让我们来看看批量梯度下降的优化是如何进行的。这可以通过将小批量设置为1500(即样本总数)来实现。 因此,模型参数每个迭代轮数只迭代一次。

def train_sgd(lr, batch_size, num_epochs=2):data_iter, feature_dim = get_data_ch11(batch_size)return train_ch11(sgd, None, {'lr': lr}, data_iter, feature_dim, num_epochs)gd_res = train_sgd(1, 1500, 10)

当批量大小为1时,优化使用的是随机梯度下降。为了简化实现,我们选择了很小的学习率。在随机梯度下 降的实验中,每当一个样本被处理,模型参数都会更新。在这个例子中,这相当于每个迭代轮数有1500次更 新。可以看到,目标函数值的下降在1个迭代轮数后就变得较为平缓。尽管两个例子在一个迭代轮数内都处理 了1500个样本,但实验中随机梯度下降的一个迭代轮数耗时更多。这是因为随机梯度下降更频繁地更新了参 数,而且一次处理单个观测值效率较低。

sgd_res = train_sgd(0.005, 1)

mini1_res = train_sgd(.4, 100)

mini2_res = train_sgd(.05, 10)

d2l.set_figsize([6, 3])
d2l.plot(*list(map(list, zip(gd_res, sgd_res, mini1_res, mini2_res))),'time (sec)', 'loss', xlim=[1e-2, 10],legend=['gd', 'sgd', 'batch size=100', 'batch size=10'])d2l.plt.gca().set_xscale('log')

2.4 简洁实现

下面用深度学习框架自带算法实现一个通用的训练函数。

#@save
def train_concise_ch11(trainer_fn, hyperparams, data_iter, num_epochs=4):# 初始化模型net = nn.Sequential(nn.Linear(5, 1))def init_weights(m):if type(m) == nn.Linear:torch.nn.init.normal_(m.weight, std=0.01)net.apply(init_weights)optimizer = trainer_fn(net.parameters(), **hyperparams)loss = nn.MSELoss(reduction='none')animator = d2l.Animator(xlabel='epoch', ylabel='loss',xlim=[0, num_epochs], ylim=[0.22, 0.35])n, timer = 0, d2l.Timer()for _ in range(num_epochs):for X, y in data_iter:optimizer.zero_grad()out = net(X)y = y.reshape(out.shape)l = loss(out, y)l.mean().backward()optimizer.step()n += X.shape[0]if n % 200 == 0:timer.stop()# MSELoss计算平方误差时不带系数1/2animator.add(n/X.shape[0]/len(data_iter),(d2l.evaluate_loss(net, data_iter, loss) / 2,))timer.start()print(f'loss: {animator.Y[0][-1]:.3f}, {timer.avg():.3f} sec/epoch')

下面使用这个训练函数,复现之前的实验。

data_iter, _ = get_data_ch11(10)
trainer = torch.optim.SGD
train_concise_ch11(trainer, {'lr': 0.01}, data_iter)

小结:

  • 由于减少了深度学习框架的额外开销,使用更好的内存定位以及CPU和GPU上的缓存,向量化使代码更加高效
  • 随机梯度下降的“统计效率”与大批量一次处理数据的“计算效率”之间存在权衡。小批量随机梯度下 降提供了两全其美的答案:计算和统计效率
  • 在小批量随机梯度下降中,我们处理通过训练数据的随机排列获得的批量数据(即每个观测值只处理 一次,但按随机顺序)。
  • 在训练期间降低学习率有助于训练
  • 一般来说,小批量随机梯度下降比随机梯度下降和梯度下降的速度快,收敛风险较小

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

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

相关文章

民国漫画杂志《时代漫画》第25期.PDF

时代漫画25.PDF: https://url03.ctfile.com/f/1779803-1248635084-fd4794?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了,截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

03:PostgreSQL逻辑结构(表空间、数据库、模式、表、索引)

环境规划&#xff1a; 操作系统&#xff1a;CentOS 7.9 64bitPostgreSQL 版本&#xff1a;16.x 或 15.x安装用户&#xff1a;postgres软件安装目标路径&#xff1a;/usr/pgsql-<version>数据库数据目录&#xff1a;/pgdata 目录 表空间Tablespace 默认表空间 手动创建…

民国漫画杂志《时代漫画》第15期.PDF

时代漫画15.PDF: https://url03.ctfile.com/f/1779803-1247458444-8befd8?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps:资源来源网络&#xff01;

【LeetCode:2769. 找出最大的可达成数字 + 模拟】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Nodejs(文件操作,构建服务器,express,npm)

文章目录 文件操作1.读取文件1&#xff09;步骤2&#xff09;范例 2.写文件1&#xff09;步骤2&#xff09;范例 3.删除文件4.重命名文件夹5删除文件夹 Url1.url.parse()2.url.fomat() Query1.query.parse()2.query.stringfy()3.编码和解码 第三方模块1.nodemailer2.body-parse…

BUUCTF-Misc24

从娃娃抓起1 1.打开附件 是两个文本文件 2.电报码 电报码在线翻译网站&#xff1a;https://usetoolbar.com/convert/cccn.html 3.汉字五笔编码 汉字五笔编码在线网站查询&#xff1a;https://www.qqxiuzi.cn/bianma/wubi.php 4.转化为MD5值 将文字保存到文本文档 用winR输入…

部署ELK日志分析系统——超详细

ELK日志分析系统 文章目录 ELK日志分析系统资源列表基础环境一、环境准备二、部署Elasticsearch软件2.1、安装Elasticsearch软件2.2、加载系统服务2.3、更改Elasticsearch主配置文件2.4、创建数据存放路径并授权2.5、启动Elasticsearch2.6、查看节点信息 三、安装Elasticsearch…

【WEEK13】 【DAY5】Shiro第五部分【中文版】

2024.5.24 Friday 接上文【WEEK13】 【DAY4】Shiro第四部分【中文版】 目录 15.7.Shiro请求授权的实现15.7.1.修改ShiroConfig.java15.7.1.1.添加一行验证授权的代码15.7.1.2.重启 15.7.2.修改MyController.java15.7.3.修改ShiroConfig.java15.7.4.重启15.7.5.修改UserRealm.ja…

Jenkins 动态salve简单配置连接 EKS

安装Jenkins helm repo add jenkins https://charts.jenkins.io helm repo update # 当前版本 jenkins-5.1.18.tgz瘦身后的 values.yaml # grep -Ev ^\s*#|^$ values.yaml nameOverride: fullnameOverride: namespaceOverride: clusterZone: "cluster.local" kubern…

C#对文件进行批量重命名或者对某个单独的文件进行改名

目录 一、FolderBrowserDialog 二、OpenFileDialog 三、Path 四、ui设计 五、代码部分 一、FolderBrowserDialog FolderBrowserDialog是一个用于选择文件夹的对话框控件&#xff0c;可以在windows Forms应用程序中使用。使用它可以让用户选择一个文件夹&#xff0c;并返…

【编译原理复习笔记】中间语言

中间语言 中间语言的特点和作用 &#xff08;1&#xff09;独立于机器 &#xff08;2&#xff09;复杂性介于源语言和目标语言之间 中间语言可以使编译程序的结构在逻辑上更为简单明确 常用的中间语言 后缀式 图表示&#xff1a;抽象语法树&#xff0c;有向无环图 三地址代…

【软件设计师】先导

一、考试科目&#xff1a; 上午&#xff1a;计算机与软件工程知识&#xff0c;考试时间150min&#xff0c;75空单选题&#xff08;不一定一题一空&#xff09; 下午&#xff1a;软件设计&#xff0c;考试时间150分钟&#xff0c;问答题&#xff0c;6道只做5大题&#xff08;前四…

【论文阅读】Prompt Fuzzing for Fuzz Driver Generation

文章目录 摘要一、介绍二、设计2.1、总览2.2、指导程序生成2.3、错误程序净化2.3.1、执行过程净化2.3.2、模糊净化2.3.3、覆盖净化 2.4、覆盖引导的突变2.4.1、功率调度2.4.2、变异策略 2.5、约束Fuzzer融合2.5.1、论据约束推理2.5.1、模糊驱动融合 三、评估3.1、与Hopper和OSS…

QTextEdit将多个字符作为一个整体,不可单独修改

考虑一个问题&#xff0c;QTextEdit如何实现类似微信和QQ聊天输入框中的“xxx”效果&#xff0c;其内容作为一个整体&#xff0c;以突出颜色显示&#xff0c;并且不可以单独编辑修改&#xff0c;只能整体删除修改。 突出颜色显示有很多方式可以实现&#xff0c;例如 通过setT…

Rust学习心得

我分享一下一年的Rust学习经历&#xff0c;从书到代码都一网打尽。 关于新手如何学习Rust&#xff0c;我之前在Hacker News上看到了这么一篇教程&#xff1a; 这篇教程与其他教程不同的时&#xff0c;他不是一个速成教程&#xff0c;而是通过自己的学习经历&#xff0c;向需要…

记录一次Netty的WSS异常

概述 业务场景 应用通过 WSS 客户端连接三方接口。在高并发压测时&#xff0c;出现了请求服务器写入失败的异常&#xff0c;该异常是偶发&#xff0c;出现的概率不到千分之一&#xff0c;异常如下图所示。 问题概述 注意&#xff1a; 因为握手是通过 http 协议进行的。所以…

tcpdump源码分析

进入tcpdump.c&#xff08;函数入口&#xff09;之前&#xff0c;先看一些头文件netdissect.h里定义了一个数据结构struct netdissect_options来描述tcdpump支持的所有参数动作&#xff0c;每一个参数有对应的flag, 在tcpdump 的main 里面&#xff0c; 会根据用户的传入的参数来…

鸿蒙ArkTS声明式开发:跨平台支持列表【触摸事件】

触摸事件 当手指在组件上按下、滑动、抬起时触发。 说明&#xff1a; 开发前请熟悉鸿蒙开发指导文档&#xff1a; gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独…

总是等不是办法,向媒体投稿你得学会用新方法

初入信息宣传领域,我怀揣着对文字的热爱与传播价值的热情,肩负起了单位活动的宣传报道重任。那时的我,满脑子都是传统的投稿思维:精心撰写每一篇稿件,然后逐一搜寻各大媒体的投稿邮箱,一封封邮件满怀期待地发出,像播撒希望的种子,渴望在广袤的媒体土壤中生根发芽。然而,理想很丰…

红蓝对抗-HW红蓝队基本知识(网络安全学习路线笔记)

第一, 什么是蓝队 蓝队&#xff0c;一般是指网络实战攻防演习中的攻击一方。 蓝队一般会采用针对目标单位的从业人员&#xff0c;以及目标系统所在网络内的软件、硬件设备同时执行多角度、全方位、对抗性的混合式模拟攻击手段&#xff1b;通过技术手段实现系统提权、控制业务、…