从零开始实现大语言模型(十四):高阶训练技巧
1. 前言
预训练大语言模型的流程与训练普通神经深度网络模型本质上并没有任何不同。可以使用深度学习实践中已经被证明非常有效的高阶训练技巧,优化大语言模型预训练流程,使大语言模型预训练效率更高,训练过程更稳定。
本文介绍深度学习领域优化训练学习率的两种方法Learning Rate Warmup和Cosine Decay,优化深度神经网络模型参数梯度的方法Gradient Clipping,以及优化训练超参数的方法Hyperparameters Search,并实现预训练大语言模型的函数hyper_pretrain_model
。
2. 优化训练学习率
2.1 Learning Rate Warmup
学习率是训练深度学习模型过程中最关键的超参数,没有之一。学习率可以控制深度神经网络模型参数的迭代更新速度,学习率越大,则参数的迭代更新速度越快,学习率越小,则参数的更新速度越慢。但是过大的学习率会导致损失函数在Error Surface上发生跳跃,使训练过程不稳定,模型难以收敛。如果如学习率太小,则会导致参数深度神经网络参数每次更新的幅度很小,使神经网络模型的训练效率很低,而且容易使损失函数陷入Error Surface中的局部最优解。
Learning Rate Warmup(学习率预热)是一种经过深度学习实践证明非常有效的优化深度神经网络前几次迭代训练学习率,以降低深度神经网络参数随机初始化带来的不确定性风险,从而提升训练过程稳定性的方法。Learning Rate Warmup会指定一个非常小的初始学习率initial_lr
,以及预热步骤warmup_steps
,并在训练深度神经网络的前warmup_steps
次迭代流程中,将学习率逐步从initial_lr
提升至不使用Learning Rate Warmup时设定的值peak_lr
。在深度学习实践中,预热步骤warmup_steps
一般会占总训练次数的 0.1 % 0.1\% 0.1%至 10 % 10\% 10%。
如下面的代码所示,假设学习率的设定值peak_lr
为0.01,Learning Rate Warmup指定的初始学习率initial_lr
为0.0001,warmup_steps
为15。使用Learning Rate Warmup优化训练学习率,需要在训练深度神经网络的前warmup_steps
次迭代流程中,计算当次迭代训练使用的学习率大小,并修改优化器中使用学习率的值:
import os
import torch
import random
import tiktoken
from torch.utils.data import Dataset, DataLoader# from [从零开始实现大语言模型(二):文本数据处理] import LLMDataset
# from [从零开始实现大语言模型(七):多头注意力机制] import MultiHeadAttention
# from [从零开始实现大语言模型(八):Layer Normalization] import LayerNorm
# from [从零开始实现大语言模型(九):前馈神经网络与GELU激活函数] import GELU, FeedForward
# from [从零开始实现大语言模型(十一):构建大语言模型GPTModel] import TransformerBlock, GPTModeltorch.manual_seed(123)train_data_path = "train_data"
vocabulary = "gpt2"
special_token_id = 50256
context_len = 1024
stride = 1024
batch_size = 2embedding_dim = 768
num_layers = 12
num_heads = 12
context_len = 1024
vocabulary_size = 50257
dropout = 0.1
qkv_bias = Falsenum_epochs = 15
initial_lr = 0.0001
peak_lr = 0.01
warmup_steps = 15train_dataset = LLMDataset(train_data_path, vocabulary, special_token_id, context_len, stride)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, drop_last=True)gpt2_small = GPTModel(embedding_dim=embedding_dim,num_layers=num_layers,num_heads=num_heads,context_len=context_len,vocabulary_size=vocabulary_size,dropout=dropout,qkv_bias=qkv_bias
)optimizer = torch.optim.AdamW(gpt2_small.parameters(), weight_decay=0.1)
lr_increment = (peak_lr - initial_lr) / warmup_stepsglobal_step = -1
track_lrs = []for epoch in range(num_epochs):for input_batch, target_batch in train_loader:optimizer.zero_grad()global_step += 1if global_step < warmup_steps:lr = initial_lr + global_step * lr_incrementelse:lr = peak_lrfor param_group in optimizer.param_groups:param_group["lr"] = lrtrack_lrs.append(optimizer.param_groups[0]["lr"])
可以使用如下代码绘制大语言模型gpt2_small
的每轮迭代训练过程所使用的学习率:
import matplotlib.pyplot as pltplt.ylabel("Learning rate")
plt.xlabel("Step")
total_training_steps = len(train_loader) * num_epochs
plt.plot(range(total_training_steps), track_lrs)
plt.show()
执行上面代码,生成大语言模型gpt2_small
的整个迭代训练流程中的学习率变化情况图像如下:
2.2 Cosine Decay
在深度学习实践中,一般会将Learning Rate Warmup与Cosine Decay结合起来,共同优化训练学习率。Learning Rate Warmup只作用于深度神经网络的前warmup_steps
轮迭代训练过程(预热阶段),使训练学习率从一个很小的initial_lr
逐步提升至peak_lr
。Cosine Decay会在预热阶段之后的全部迭代训练过程中,以余弦曲线的方式逐步减小训练学习率,以降低模型参数的更新速度,减少损失函数越过Error Surface上极小值的概率,提升训练过程稳定性。
如下面的代码所示,在预热阶段之后使用Cosine Decay策略调整训练学习率,需要使用global_step - warmup_steps
得到预热阶段后的迭代训练步数,以及使用total_training_steps - warmup_steps
计算出预热阶段后的总迭代训练次数,并通过(global_step - warmup_steps) / (total_training_steps - warmup_steps)
计算出去掉预热阶段后的训练进度百分比progress
。使用math.cos(math.pi * progress)
可以计算得到一个介于1到-1之间的余弦值,当progress
为0时,余弦值为1,当progress
为1时,余弦值为-1,余弦值的变化速率曲线为余弦曲线。使用0.5 * (1 + math.cos(math.pi * progress))
对余弦值做变换,使余弦值的取值范围由[1, -1]
变换到[1, 0]
,最后使用 min_lr + (peak_lr - min_lr) * 0.5 * (1 + math.cos(math.pi * progress))
计算得到当前迭代训练步数对应的训练学习率:
import mathmin_lr = 0.1 * initial_lrtrack_lrs = []
global_step = -1for epoch in range(num_epochs):for input_batch, target_batch in train_loader:optimizer.zero_grad()global_step += 1if global_step < warmup_steps:lr = initial_lr + global_step * lr_increment else:progress = (global_step - warmup_steps) / (total_training_steps - warmup_steps)lr = min_lr + (peak_lr - min_lr) * 0.5 * (1 + math.cos(math.pi * progress))for param_group in optimizer.param_groups:param_group["lr"] = lrtrack_lrs.append(optimizer.param_groups[0]["lr"])
可以使用如下代码绘制使用Learning Rate Warmup与Cosine Decay策略后的学习率变化情况图像:
plt.ylabel("Learning rate")
plt.xlabel("Step")
plt.plot(range(total_training_steps), track_lrs)
plt.show()
执行上面代码,生成的学习率变化情况图像如下:
3. 优化模型参数梯度
3.1 Gradient Clipping
Gradient Clipping(梯度裁剪)是一种通过限制参数梯度大小,以解决深度神经网络训练过程中的梯度爆炸问题,从而提升训练过程稳定性的模型参数梯度优化方法。深度学习实践中常用的Gradient Clipping方法有两种:基于梯度值的裁剪和基于梯度范数的裁剪。
基于梯度值的裁剪方法的原理非常简单,其会直接将深度神经网络参数的梯度中大于clip_value
的梯度设置成clip_value
,并将小于-clip_value
的梯度设置成-clip_value
,使深度神经网络参数梯度的绝对值值不超过clip_value
。基于梯度范数的裁剪方法首先会计算神经网络参数梯度的p-范数,如果p-范数大于max_norm
,则会将每个梯度值均乘以 max_norm p_norm \frac{\text{max\_norm}}{\text{p\_norm}} p_normmax_norm,使神经网络参数梯度的p-范数等于max_norm
。
假设深度神经网络共包含4个参数,后向传播流程计算出的参数梯度 G = [ 1 2 2 4 ] G=\begin{bmatrix}1&2\\2&4\end{bmatrix} G=[1224],使用基于梯度范数的裁剪方法优化模型参数梯度,设置参数梯度2-范数的最大值max_norm
为2.0,首先需要计算神经网络参数梯度的2-范数 ∥ G ∥ 2 = 1 2 + 2 2 + 2 2 + 4 2 = 25 = 5 \|G\|_2=\sqrt{1^2+2^2+2^2+4^2}=\sqrt{25}=5 ∥G∥2=12+22+22+42=25=5。因为 ∥ G ∥ 2 > 2 \|G\|_2>2 ∥G∥2>2,因此会将每个梯度值均乘以 max_norm p_norm = 2 5 \frac{\text{max\_norm}}{\text{p\_norm}}=\frac{2}{5} p_normmax_norm=52,即将神经网络参数梯度裁剪成 G ′ = 2 5 × G = [ 2 5 4 5 4 5 8 5 ] G'=\frac{2}{5}\times G=\begin{bmatrix}\frac{2}{5}&\frac{4}{5}\\ \frac{4}{5}&\frac{8}{5}\end{bmatrix} G′=52×G=[52545458]。
如下面的代码所示,定义计算深度神经网络参数梯度最大值的函数find_largest_gradient
,并使用torch.tensor
函数创建训练样本input_batch
及训练样本标签target_batch
。将训练样本input_batch
输入大语言模型gpt2_small
,使用calc_loss_batch
函数计算大语言模型的预测输出与训练样本标签之间的交叉熵损失loss,并通过loss.backward()
计算大语言模型参数梯度。最后使用find_largest_gradient
函数打印输入大语言模型参数梯度的最大值:
# from [从零开始实现大语言模型(十三):预训练大语言模型GPTModel] import calc_loss_batchdef find_largest_gradient(model):max_grad = Nonefor param in model.parameters():if param.grad is not None:grad_values = param.grad.data.flatten()max_grad_param = grad_values.max()if max_grad is None or max_grad_param > max_grad:max_grad = max_grad_paramreturn max_graddevice = torch.device("cpu")
input_batch = torch.tensor([[16833, 3626, 6100], # [["every effort moves"],[40, 1107, 588]] # ["I really like"]]
)
target_batch = torch.tensor([[3626, 6100, 345], # [[" effort moves you"],[588, 428, 11311]] # [" really like chocolate"]]
)loss = calc_loss_batch(input_batch, target_batch, gpt2_small, device)
loss.backward()
print(find_largest_gradient(gpt2_small))
执行上面代码,打印结果如下:
tensor(0.6413)
使用上述基于梯度范数的裁剪方法优化模型参数梯度,设置大语言模型参数梯度的2-范数最大值max_norm
为1.0,并打印经过Gradient Clipping优化之后的大语言模型参数梯度的最大值:
torch.nn.utils.clip_grad_norm_(gpt2_small.parameters(), max_norm=1.0)print(find_largest_gradient(gpt2_small))
执行上面代码,打印结果如下:
tensor(0.0348)
4. 实现高阶预训练函数
可以结合上述3种高阶训练技巧实现预训练大语言模型的函数hyper_pretrain_model
。修改前文从零开始实现大语言模型(十三):预训练大语言模型GPTModel中实现的预训练大语言模型的函数pretrain_model
,在每轮for循环使用calc_loss_batch
函数计算大语言模型的预测输出与训练样本标签之间的交叉熵损失之前,先使用2中所述优化训练学习率的两种方法Learning Rate Warmup和Cosine Decay,计算当次迭代训练使用的学习率大小,并修改训练优化器中使用学习率的值。在使用optimizer.step()
方法更新大语言模型参数之前,先使用3中所述优化模型参数梯度的方法Gradient Clipping,优化模型参数梯度。具体代码如下所示:
# from [从零开始实现大语言模型(十三):预训练大语言模型GPTModel] import calc_loss_loader, val_and_savedef hyper_pretrain_model(model, optimizer, train_loader, num_epochs, device, eval_freq, eval_iter, tokenizer, start_context, save_freq, checkpoint_dir, warmup_steps=10, initial_lr=3e-05, min_lr=1e-6, max_norm=1.0,checkpoint=None, val_loader=None
):if not os.path.exists(checkpoint_dir):os.makedirs(checkpoint_dir, exist_ok=True)if checkpoint is not None:model_checkpoint_path = os.path.join(checkpoint_dir, f"model_{checkpoint:06d}.pth")optimizer_checkpoint_path = os.path.join(checkpoint_dir, f"optimizer_{checkpoint:06d}.pth")model.load_state_dict(torch.load(model_checkpoint_path))optimizer.load_state_dict(torch.load(optimizer_checkpoint_path))else:checkpoint = -1train_losses, val_losses, track_tokens_seen, track_lrs = [], [], [], []tokens_seen, global_step = 0, -1peak_lr = optimizer.param_groups[0]["lr"]total_training_steps = len(train_loader) * num_epochslr_increment = (peak_lr - initial_lr) / warmup_stepsfor epoch in range(num_epochs):model.train()for i, (input_batch, target_batch) in enumerate(train_loader):if global_step % eval_freq == 0:model.train()optimizer.zero_grad()global_step += 1if global_step < warmup_steps:lr = initial_lr + global_step * lr_increment else:progress = (global_step - warmup_steps) / (total_training_steps - warmup_steps)lr = min_lr + (peak_lr - min_lr) * 0.5 * (1 + math.cos(math.pi * progress))for param_group in optimizer.param_groups:param_group["lr"] = lrtrack_lrs.append(lr)loss = calc_loss_batch(input_batch, target_batch, model, device)loss.backward()if global_step > warmup_steps:torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=max_norm)optimizer.step()tokens_seen += input_batch.numel()print(f"Epoch {epoch + 1} (Batch {i:06d}): Train loss {loss.item():.3f}")checkpoint, train_loss, val_loss = val_and_save(model, optimizer, train_loader, val_loader, epoch, global_step, eval_freq,eval_iter, start_context, tokenizer, save_freq, checkpoint_dir, checkpoint, device)if train_loss is not None:train_losses.append(train_loss)val_losses.append(val_loss)track_tokens_seen.append(tokens_seen)checkpoint, _, _ = val_and_save(model, optimizer, train_loader, val_loader, epoch, global_step, 1,eval_iter, start_context, tokenizer, 1, checkpoint_dir, checkpoint, device)print(f"Epoch {epoch + 1} finished, checkpoint: {checkpoint:06d}")return train_losses, val_losses, track_tokens_seen, track_lrs
5. 优化训练超参数
5.1 Hyper-parameters Search
超参数(hyper-parameters)是指需要在搭建和训练深度神经网络之前手动设置的一些参数。在深度学习中,有两类超参数,一类超参数是深度神经网络结构超参数,比如深度神经网络的层数,Embedding向量的维度等等。另一类超参数是训练超参数,例如训练深度神经网络使用的学习率,每个batch中训练样本数量等等。
优化深度神经网络结构超参数的方法被统称为神经网络结构搜索(NAS, neural architecture search)。神经网络结构搜索方法大致可分类3类,其中一类被称为“大海捞针”,即根据实践经验定义一个有限的超参数搜索空间,逐一使用搜索空间中的超参数组合构建并训练深度神经网络直至收敛,取验证集上测试指标最高的超参数组合作为搜索结果。另一类是不可微方法,其一般会将验证集上的测试指标作为环境给的奖励,使用强化学习算法搜索出较优的超参数组合。还有一类是可微方法,其核心思想是定义一个神经网络结构超参数的可微函数作为目标函数,基于Super-net对目标函数关于超参数求梯度,直接使用梯度更新超参数。
本文不会详细介绍深度神经网络结构超参数优化方法,不同大语言模型的结构基本相同,Embedding向量维度等结构超参数一般会取决于可用的计算资源,工业界实践中一般不会使用神经网络架构搜索方法确定大语言模型的结构超参数。《从零开始实现大语言模型》系列专栏全部完成之后,我应该会写几篇博客详细神经网络结构搜索,感兴趣的读者可以关注我的个人博客。
预训练大语言模型的时间成本及计算成本都非常高,例如训练大语言模型Llama 2的数据共包含2T(万亿)个tokens,花费184320 A100 GPU时,换算成云计算资源价值,大约需要690000美元。在预训练大语言模型的工业界实践中,一般会在正式开始训预训练大语言模型之前,在相对小的数据集上,使用Hyper-parameters Search得到一个比较好的训练超参数组合。Hyper-parameters Search的核心思想就是“大海捞针”,即定义一个有限的超参数搜索空间HPARAM_GRID
,逐一使用搜索空间中的超参数组合训练大语言模型,取验证集上交叉熵损失最小的超参数组合作为正式预训练大语言模型时所用的训练超参数。具体代码如下所示:
import itertoolsdef hparams_search_train(model, optimizer, train_loader, val_loader, num_epochs, device,eval_iter, warmup_steps, initial_lr, min_lr, max_norm
):global_step = -1peak_lr = optimizer.param_groups[0]["lr"]total_training_steps = len(train_loader) * num_epochslr_increment = (peak_lr - initial_lr) / warmup_stepsfor epoch in range(num_epochs):model.train()for input_batch, target_batch in train_loader:optimizer.zero_grad()global_step += 1if global_step < warmup_steps:lr = initial_lr + global_step * lr_incrementelse:progress = (global_step - warmup_steps) / (total_training_steps - warmup_steps)lr = min_lr + (peak_lr - min_lr) * 0.5 * (1 + math.cos(math.pi * progress))for param_group in optimizer.param_groups:param_group["lr"] = lrloss = calc_loss_batch(input_batch, target_batch, model, device)loss.backward()if global_step > warmup_steps:torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=max_norm)optimizer.step()train_loss = calc_loss_loader(train_loader, model, device, eval_iter)val_loss = calc_loss_loader(val_loader, model, device, eval_iter)return train_loss, val_lossHPARAM_GRID = {"batch_size": [2, 4, 8, 16],"dropout": [0.0, 0.1, 0.2],"warmup_steps": [10, 20, 30],"weight_decay": [0.1, 0.01, 0.0],"max_norm": [1.0, 0.5, 2.0],"peak_lr": [0.0001, 0.0005, 0.001, 0.005],"initial_lr": [0.00005, 0.0001],"min_lr": [0.00005, 0.00001, 0.0001],"num_epochs": [5, 10, 15, 20, 25],
}
hyperparameter_combinations = list(itertools.product(*HPARAM_GRID.values()))
print(f"Total hyperparameter configurations: {len(hyperparameter_combinations)}")device = torch.device("cpu")
val_data_path = "val_data"
train_dataset = LLMDataset(train_data_path, vocabulary, special_token_id, context_len, stride)
val_dataset = LLMDataset(val_data_path, vocabulary, special_token_id, context_len, stride)best_val_loss, best_train_loss = float("inf"), float("inf")
best_hparams = {}for i, combination in enumerate(hyperparameter_combinations):print(f"Evaluating configuration {i + 1} of {len(hyperparameter_combinations)}")HPARAM_CONFIG = dict(zip(HPARAM_GRID.keys(), combination))torch.manual_seed(123)train_loader = DataLoader(dataset=train_dataset, batch_size=HPARAM_CONFIG["batch_size"], shuffle=True, drop_last=True)val_loader = DataLoader(dataset=val_dataset, batch_size=HPARAM_CONFIG["batch_size"], shuffle=False, drop_last=False)model = GPTModel(embedding_dim=embedding_dim, num_layers=num_layers, num_heads=num_heads, context_len=context_len,vocabulary_size=vocabulary_size, dropout=HPARAM_CONFIG["dropout"], qkv_bias=qkv_bias)model.to(device)optimizer = torch.optim.AdamW(model.parameters(), lr=HPARAM_CONFIG["peak_lr"],weight_decay=HPARAM_CONFIG["weight_decay"])train_loss, val_loss = hparams_search_train(model, optimizer, train_loader, val_loader, HPARAM_CONFIG["num_epochs"], device, eval_iter=1,warmup_steps=HPARAM_CONFIG["warmup_steps"], initial_lr=HPARAM_CONFIG["initial_lr"],min_lr=HPARAM_CONFIG["min_lr"], max_norm=HPARAM_CONFIG["max_norm"])if val_loss < best_val_loss:best_val_loss = val_lossbest_train_loss = train_lossbest_hparams = HPARAM_CONFIGprint(f"Evaluating configuration {i + 1} completed.")print(f"Current best hyper-parameters: {best_hparams}")print(f"Current best Val loss: {best_val_loss} | Training loss {best_train_loss}")print("============================================================================")print("Hyper-parameter search completed.")
print(f"Best hyper-parameters: {best_hparams}")
print(f"Best Val loss: {best_val_loss} | Training loss {best_train_loss}")
神经网络结构搜索领域的不可微方法并不适用于大语言模型训练超参数搜索,训练大语言模型所需的计算量太大,且使用强化学习算法搜索超参数,需要从头开始完整训练一次大语言模型才能获得1个奖励,强化学习算法一般至少需要上万至数十万次奖励反馈才能收敛。
神经网络结构搜索领域的可微方法同样不适用于大语言模型训练超参数搜索,所有可微方法的核心思想都是定义一个神经网络结构超参数的可微函数作为目标函数,然而基本没有办法找到一个神经网络训练超参数的可微函数。
6. 结束语
预训练大语言模型的流程与训练普通神经深度网络模型本质上并没有任何不同,其难度不在于算法,而在于数据,更在于算力。绝大部分企业都没有预训练大语言模型的算力资源,因此如何利用开源大语言模型成了大语言模型工业实践中的重中之重,接下来一起看看如何加载开源大语言模型参数吧!
相关文章:

从零开始实现大语言模型(十四):高阶训练技巧
1. 前言 预训练大语言模型的流程与训练普通神经深度网络模型本质上并没有任何不同。可以使用深度学习实践中已经被证明非常有效的高阶训练技巧,优化大语言模型预训练流程,使大语言模型预训练效率更高,训练过程更稳定。 本文介绍深度学习领域…...

Spring-framework源码编译
版本统一(搭配其他版本会遇到不可知错误): 1)spring 5.2.X(5.5.26) 2)JDK8 3)Gradle:5.6.4 可以在gradle-wrapper.properties中修改 https\://services.gradle.org/distribution…...
分布式系统的核心挑战与解决方案
1、分布式系统的引入 在移动互联网、云计算和物联网的推动下,现代软件系统需要处理亿级用户请求、PB级数据存储和毫秒级响应需求。传统的单体架构受限于单机性能瓶颈和容灾能力,逐渐被分布式系统取代。例如,电商平台在“双十一”期间需应对每…...
fastjson漏洞
fastjson漏洞 fastjson工作原理攻击原理补充 例子 fastjson工作原理 fastjson的作用是将JAVA对象转换成对应的json表示形式,也可以反过来将json转化为对应的Java对象。fastjson使用AutoType功能进行反序列化,AutoType使用type标记字符的原始类型&#x…...

upload-labs详解(13-20)文件上传分析
目录 upload-labs-env upload-labs-env第十三关 文件包含漏洞 代码 测试 上传一个.jpg图片 上传一个.png文件 上传一个.gif图片 upload-labs-env第十四关 代码 思路 upload-labs-env第十五关 代码 思路 upload-labs-env第十六关 代码 思路 测试 上传gif格式…...

HTML第四节
一.复合选择器 1.后代选择器 注:1.后代选择器会选中后代所有的要选择的标签 2.儿子选择器 3.并集选择器 注:1.注意换行,同时选中多种标签 4.交集选择器 注:1.标签选择器放在最前面,例如放在类选择器的前面 2.两个选择…...

基于 LeNet 网络的 MNIST 数据集图像分类
1.LeNet的原始实验数据集MNIST 名称:MNIST手写数字数据集 数据类型:灰度图 (一通道) 图像大小:28*28 类别数:10类(数字0-9) 1.通过torchvision.datasets.MNIST下载并保存到本地…...

win11编译llama_cpp_python cuda128 RTX30/40/50版本
Geforce 50xx系显卡最低支持cuda128,llama_cpp_python官方源只有cpu版本,没有cuda版本,所以自己基于0.3.5版本源码编译一个RTX 30xx/40xx/50xx版本。 1. 前置条件 1. 访问https://developer.download.nvidia.cn/compute/cuda/12.8.0/local_…...
Spring Boot静态资源访问顺序
在 Spring Boot 中,static 和 public 目录都用于存放静态资源(如 HTML、CSS、JavaScript、图片等文件),但它们在使用上有一些细微的区别。以下是它们的详细对比: 1. 默认优先级 Spring Boot 会按照以下优先级加载静态…...

电脑总显示串口正在被占用处理方法
1.现象 在嵌入式开发过程中,有很多情况下要使用串口调试,其中485/422/232转usb串口是非常常见的做法。 根据协议,接口芯片不同,需要安装对应的驱动程序,比如ch340,cp2102,CDM212364等驱动。可…...
工具介绍《HACKBAR V2》
HackBar V2 是一款功能强大的浏览器渗透测试工具,主要用于测试 SQL 注入、XSS 漏洞、POST 传参等安全场景。以下是其核心功能、用法及实际案例操作的综合介绍: 一、核心功能与用法详解 1. 基础操作 Load URL 功能:将当前浏览器地址栏的 URL …...
Java算法语法学习 美丽子集的数目 - 力扣 Map接口
文章目录 题目解题思路题解统计数组中每个数字按模k分组的出现次数,并保持数值有序作用 **merge(x, 1, Integer::sum)**解释**检查键是否存在**:**合并现有值**: 示例在代码中的应用**计算余数**:**存储余数及其出现次数**: merge 的常见用法统计频率合并字符串合并…...

Vue项目通过内嵌iframe访问另一个vue页面,获取token适配后端鉴权(以内嵌若依项目举例)
1. 改造子Vue项目进行适配(ruoyi举例) (1) 在路由文件添加需要被外链的vue页面配置 // 若依项目的话是 router/index.js文件 {path: /contrast,component: () > import(/views/contrast/index),hidden: true },(2) 开放白名单 // 若依项目的话是 permission.js 文件 cons…...
梯度本质论:从黎曼流形到神经网络的拓扑寻优
一、微分几何框架下的梯度再诠释 在标准数学分析中,梯度被定义为标量场 f : R n → R f:\mathbb{R}^n→\mathbb{R} f:Rn→R的导数张量 ∇ f ( ∂ f ∂ x 1 , . . . , ∂ f ∂ x n ) \nabla f(\frac{\partial f}{\partial x_1},...,\frac{\partial f}{\partial x_n…...

计算机毕业设计SpringBoot+Vue.js网络海鲜市场系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

一文对比RAGFLOW和Open WebUI【使用场景参考】
一、RAGFLOW与Open WebUI RAGFLOW是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不…...

2025年03月07日Github流行趋势
项目名称:ai-hedge-fund 项目地址url:https://github.com/virattt/ai-hedge-fund项目语言:Python历史star数:12788今日star数:975项目维护者:virattt, seungwonme, KittatamSaisaard, andorsk, arsaboo项目…...

实训任务2.2 使用Wireshark捕获数据包并分析
目录 【实训目标】 【实训环境】 【实训内容】 【实训步骤】 1.启动WireShark 2. 使用Wireshark捕获数据包 (1)选择网络接口 (2)捕获数据包 (1)设置Wireshark过滤器并捕获数据包 (2&…...
C# Lambda 表达式 详解
总目录 前言 在C#编程中,Lambda表达式是一种简洁而强大的语法特性,它提供了一种更加灵活和直观的方式来编写匿名函数。无论是在LINQ查询、事件处理还是异步编程中,Lambda表达式都扮演着重要角色。本文将详细介绍Lambda,帮助您更好…...
wordpress自定the_category的输出结构
通过WordPress的过滤器the_category来自定义输出内容。方法很简单,但是很实用。以下是一个示例代码: function custom_the_category($thelist, $separator , $parents ) {// 获取当前文章的所有分类$categories get_the_category();if (empty($categ…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
Linux中INADDR_ANY详解
在Linux网络编程中,INADDR_ANY 是一个特殊的IPv4地址常量(定义在 <netinet/in.h> 头文件中),用于表示绑定到所有可用网络接口的地址。它是服务器程序中的常见用法,允许套接字监听所有本地IP地址上的连接请求。 关…...

【threejs】每天一个小案例讲解:创建基本的3D场景
代码仓 GitHub - TiffanyHoo/three_practices: Learning three.js together! 可自行clone,无需安装依赖,直接liver-server运行/直接打开chapter01中的html文件 运行效果图 知识要点 核心三要素 场景(Scene) 使用 THREE.Scene(…...