从零开始实现大语言模型(十三):预训练大语言模型GPTModel

news2025/3/12 6:09:40

1. 前言

使用梯度下降算法通过下一个token预测任务预训练大语言模型GPTModel,前向传播流程每次会输入一个batch的长度均为context_len的训练样本,执行 batch_size × context_len \text{batch\_size}\times\text{context\_len} batch_size×context_len次下一个token预测任务,共预测输出 batch_size × context_len \text{batch\_size}\times\text{context\_len} batch_size×context_len个tokens。后向传播流程首先会使用交叉熵(Cross Entropy)损失函数计算大语言模型GPTModel的预测输出与训练样本标签之间的损失(loss),再通过后向传播算法计算大语言模型参数梯度,最后使用梯度下降算法更新大语言模型的参数。

本文使用交叉熵损失函数计算生成大语言模型GPTModel的预测输出与训练样本标签之间的loss,介绍大语言模型的预训练流程,并实现预训练大语言模型的函数pretrain_model

2. 损失函数Cross Entropy

交叉熵损失函数可以度量大语言模型的预测输出与训练样本标签之间的差异。损失函数计算生成的loss值越大,表明大语言模型的预测输出与训练样本标签之间的差异越大,loss值越小,表明大语言模型的预测输出与训练样本标签之间的差异越小。

对输入文本做tokenization,将输入文本转换成包含context_len个token ID的列表,并输入大语言模型GPTModel,可以得到context_len个维度为vocabulary_size的logits向量,第 i i i个logits向量是大语言模型根据前 i i i个token预测生成的下一个token的概率分数向量,logits向量中的第 k k k个概率分数值越大,表明大语言模型预测生成的下一个token的ID为 k k k的概率越高。

使用softmax函数将大语言模型预测生成的logits向量归一化,得到大语言模型预测生成的下一个token的概率分布,概率分布中对应样本标签位置的概率值表示大语言模型预测输出的token为相应训练样本标签的概率。对应样本标签位置的概率值越接近1,表明大语言模型预测输出的token为相应训练样本标签的概率越高,大语言模型的预测输出与训练样本标签之间的差异越小。

图一

使用梯度下降算法预训练大语言模型GPTModel的前向传播流程中,大语言模型每次会预测生成 batch_size × context_len \text{batch\_size}\times\text{context\_len} batch_size×context_len个下一个token的概率分布。如下图所示,交叉熵损失函数会分别获取 batch_size × context_len \text{batch\_size}\times\text{context\_len} batch_size×context_len个概率分布中对应样本标签位置的概率值,使用对数函数计算这些概率值的对数,并计算所有对数值的均值,最后将对数均值的相反数作为大语言模型GPTModel的预测输出与训练样本标签之间的损失loss。

图二

如下面的代码所示,使用torch.tensor函数创建训练样本inputs及训练样本标签targets,将训练样本inputs输入大语言模型gpt2_small,并使用softmax函数将大语言模型的输出张量logits归一化,得到 2 × 3 2\times3 2×3个下一个token的概率分布,其中每个概率分布的维度均等于词汇表的大小50257。分别获取 2 × 3 2\times3 2×3个下一个token的概率分布中对应样本标签位置的概率值,使用torch.log函数计算这些概率值的对数,并计算所有对数值均值的相反数,可以得到大语言模型gpt2_small的预测输出与样本标签targets之间的交叉熵损失:

import torch
# from [从零开始实现大语言模型(七):多头注意力机制] import MultiHeadAttention
# from [从零开始实现大语言模型(八):Layer Normalization] import LayerNorm
# from [从零开始实现大语言模型(九):前馈神经网络与GELU激活函数] import GELU, FeedForward
# from [从零开始实现大语言模型(十一):构建大语言模型GPTModel] import TransformerBlock, GPTModel

torch.manual_seed(123)

embedding_dim = 768
num_layers = 12
num_heads = 12
context_len = 1024
vocabulary_size = 50257
dropout = 0.1
qkv_bias = False

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
)

inputs = torch.tensor(
    [[16833, 3626, 6100],  # [["every effort moves"],
     [40, 1107, 588]]      # ["I really like"]]
)

targets = torch.tensor(
    [[3626, 6100, 345],  # [[" effort moves you"],
     [588, 428, 11311]]  # [" really like chocolate"]]
)

with torch.no_grad():
    logits = gpt2_small(inputs)
probas = torch.softmax(logits, dim=-1)

target_probas_1 = probas[0, [0, 1, 2], targets[0]]
target_probas_2 = probas[1, [0, 1, 2], targets[1]]

log_probas = torch.log(torch.cat((target_probas_1, target_probas_2)))
avg_log_probas = torch.mean(log_probas)
neg_avg_log_probas = avg_log_probas * -1

print("probas shape:", probas.shape)
print("target_probas_1:", target_probas_1)
print("target_probas_2:", target_probas_2)
print("log_probas:", log_probas)
print("avg_log_probas:", avg_log_probas)
print("cross entropy loss:", neg_avg_log_probas)

执行上面代码,打印结果如下:

probas shape: torch.Size([2, 3, 50257])
target_probas_1: tensor([2.6369e-05, 1.5997e-05, 1.6926e-05])
target_probas_2: tensor([1.5638e-05, 8.9422e-06, 1.7967e-05])
log_probas: tensor([-10.5433, -11.0431, -10.9867, -11.0658, -11.6247, -10.9270])
avg_log_probas: tensor(-11.0318)
cross entropy loss: tensor(11.0318)

可以直接使用PyTorch内置的cross_entropy函数执行上述计算流程,得到大语言模型gpt2_small的预测输出logits与样本标签targets之间的交叉熵损失:

loss = torch.nn.functional.cross_entropy(logits.flatten(0, 1), targets.flatten())
print(loss)

执行上面代码,打印结果如下:

tensor(11.0318)

根据打印结果可知,上述6个步骤计算得到的损失值与PyTorch内置的cross_entropy函数计算得到的交叉熵损失完全相同。交叉熵损失本质上就是大语言模型预测生成的 batch_size × context_len \text{batch\_size}\times\text{context\_len} batch_size×context_len个下一个token的概率分布中对应样本标签位置概率值的对数均值的相反数。

3. 大语言模型预训练流程

预训练大语言模型的流程与训练普通神经网络模型本质上并没有任何不同。如下图所示,预训练大语言模型可以把整个训练数据集扫几个epoch,每个epoch会把整个训练数据集扫一遍,每次会使用训练数据集中一个batch的训练样本训练一次大语言模型。前向传播流程会将一个batch的训练样本输入大语言模型,得到大语言模型的预测输出logits。后向传播流程首先会使用交叉熵损失函数计算大语言模型的预测输出logits与训练样本标签targets之间的损失loss,再通过后向传播算法计算大语言模型参数梯度,最后使用梯度下降算法更新大语言模型的参数。

图三

可以使用如下代码定义计算一个batch样本数据交叉熵损失的函数calc_loss_batch,以及计算整个数据集上所有样本数据交叉熵损失的函数calc_loss_loader。函数calc_loss_batch将一个batch的样本数据输入大语言模型,得到大语言模型的预测输出logits,并使用torch.nn.functional.cross_entropy函数计算大语言模型的预测输出logits与样本标签targets之间的损失loss。函数calc_loss_loader每次取数据集中一个batch的样本数据,使用calc_loss_batch函数计算该batch样本数据的交叉熵损失,并返回数据集上所有样本数据损失loss的均值:

def calc_loss_batch(input_batch, target_batch, model, device):
    input_batch = input_batch.to(device)
    target_batch = target_batch.to(device)
    logits = model(input_batch)
    loss = torch.nn.functional.cross_entropy(
        logits.flatten(0, 1), target_batch.flatten()
    )
    return loss

def calc_loss_loader(data_loader, model, device, num_batches=None):
    model.eval()
    total_loss = 0.0
    if num_batches is None:
        num_batches = len(data_loader)
    else:
        num_batches = min(num_batches, len(data_loader))

    with torch.no_grad():
        for i, (input_batch, target_batch) in enumerate(data_loader):
            if i < num_batches:
                loss = calc_loss_batch(input_batch, target_batch, model, device)
                total_loss += loss.item()
            else:
                break
    return total_loss / num_batches

实现预训练大语言模型的函数pretrain_model,可以使用for循环将整个训练数据集扫num_epochs遍,并在每次训练大语言模型的循环中,首先使用optimizer.zero_grad函数将大语言模型所有参数的梯度置为0,然后使用函数calc_loss_batch计算一个batch训练样本的交叉熵损失loss。使用loss.backward函数可以执行后向传播流程,计算大语言模型所有参数的梯度,并通过optimizer.step函数使用梯度下降算法更新大语言模型参数。具体代码如下所示:

# from [从零开始实现大语言模型(十二):文本生成策略] import generate_text

def pretrain_model(
        model, optimizer, train_loader, num_epochs, device,
        eval_freq, eval_iter, tokenizer, start_context,
        save_freq, checkpoint_dir, 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 = -1

    train_losses, val_losses, track_tokens_seen = [], [], []
    tokens_seen, global_step = 0, -1

    for 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()
            loss = calc_loss_batch(input_batch, target_batch, model, device)
            loss.backward()
            optimizer.step()

            tokens_seen += input_batch.numel()
            global_step += 1
            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


def 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
):
    train_loss, val_loss = None, None
    if global_step % eval_freq == 0:
        if val_loader is not None:
            train_loss = calc_loss_loader(train_loader, model, device, eval_iter)
            val_loss = calc_loss_loader(val_loader, model, device, eval_iter)
            print(f"Epoch {epoch + 1} (Step {global_step:06d}): Train loss {train_loss:.3f}, Val loss {val_loss:.3f}")
        generated_sample_text = generate_text(
            model, start_context, max_new_tokens=50, tokenizer=tokenizer,
            context_size=model.pos_emb.weight.shape[0], top_k=1, compact_format=True
        )
        print(f"Generated Sample Text: {generated_sample_text}")
        print("=====================================================================")

    if global_step % save_freq == 0:
        checkpoint += 1
        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")
        torch.save(model.state_dict(), model_checkpoint_path)
        torch.save(optimizer.state_dict(), optimizer_checkpoint_path)
    return checkpoint, train_loss, val_loss

PyTorch中神经网络模型的state_dict是一个字典对象,字典中的key为神经网络模型中参数的名称,value为相应的参数。使用.state_dict函数可以一次性获取神经网络模型中的所有参数,并通过torch.save函数将所有参数保存为一个checkpoint。torch.load函数可以读取指定checkpoint,通过.load_state_dict函数可以将神经网络模型中的参数修改为checkpoint中的记录值。

所有具有自适应能力的优化器(如AdamW可以根据历史梯度信息动态调整学习率)都需要记录每个神经网络参数的历史梯度等信息,同样可以使用.state_dict一次性获取优化器中的所有数据记录,以及通过.load_state_dict函数从指定checkpoint中还原这些记录数据。

如下面的代码所示,使用从零开始实现大语言模型(二):文本数据处理中构建的Dataset创建训练集train_dataset及验证集val_dataset,并通过PyTorch内置的torch.utils.data.DataLoader类创建训练集及验证集对应的DataLoader。使用torch.optim.AdamW实例化训练大语言模型的优化器optimizer,最后使用函数pretrain_model预训练大语言模型gpt2_small

import os
import random
import tiktoken
from torch.utils.data import Dataset, DataLoader

# from [从零开始实现大语言模型(二):文本数据处理] import LLMDataset

train_data_path = "train_data"
val_data_path = "val_data"
vocabulary = "gpt2"
special_token_id = 50256
context_len = 1024
stride = 1024
batch_size = 2

num_epochs = 10
eval_freq = 5
eval_iter = 1
save_freq = 5
checkpoint_dir = "checkpoint"
start_context = "萧炎,斗之力,三段"
tokenizer = tiktoken.encoding_for_model(vocabulary)
device = torch.device("cpu")
gpt2_small.to(device)
optimizer = torch.optim.AdamW(gpt2_small.parameters(), lr=0.0006, weight_decay=0.1)

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)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, drop_last=True)
val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False, drop_last=False)
print(f"train_loader len: {len(train_loader)}")

train_losses, val_losses, tokens_seen = pretrain_model(
    gpt2_small, optimizer, train_loader, num_epochs, device,
    eval_freq, eval_iter, tokenizer, start_context,
    save_freq, checkpoint_dir, val_loader=val_loader
)

执行上面代码,打印结果如下:

train_loader len: 7
Epoch 1 (Batch 000000): Train loss 11.034
Epoch 1 (Step 000000): Train loss 9.827, Val loss 9.784
Generated Sample Text: 萧炎,斗之力,三段 Knowledge�缌�缌缌�703 clashes�缌 longest,,缌,���,缌缌�
=====================================================================
Epoch 1 (Batch 000001): Train loss 9.940
Epoch 1 (Batch 000002): Train loss 8.811
Epoch 1 (Batch 000003): Train loss 7.954
Epoch 1 (Batch 000004): Train loss 7.286
Epoch 1 (Batch 000005): Train loss 6.629
Epoch 1 (Step 000005): Train loss 5.980, Val loss 6.003
Generated Sample Text: 萧炎,斗之力,三段,,,,,,,,,,,,,,,,�
=====================================================================
Epoch 1 (Batch 000006): Train loss 6.027
Epoch 1 (Step 000006): Train loss 5.390, Val loss 5.479
Generated Sample Text: 萧炎,斗之力,三段,,,�,,,��,,,,,�,�,,,
=====================================================================
Epoch 1 finished, checkpoint: 000002
Epoch 2 (Batch 000000): Train loss 5.401
Epoch 2 (Batch 000001): Train loss 5.028
Epoch 2 (Batch 000002): Train loss 4.788
Epoch 2 (Batch 000003): Train loss 4.616
Epoch 2 (Step 000010): Train loss 4.511, Val loss 4.526
Generated Sample Text: 萧炎,斗之力,三段,�,�,�,�,�,�,�,�,�,��,�,
=====================================================================

[...]

Epoch 9 (Step 000060): Train loss 2.561, Val loss 3.470
Generated Sample Text: 萧炎,斗之力,三段���是在脸�的�,�炣�殸废是萧炣也是曰�,萧�
=====================================================================
Epoch 9 (Batch 000005): Train loss 2.560
Epoch 9 (Batch 000006): Train loss 2.558
Epoch 9 (Step 000062): Train loss 2.456, Val loss 3.455
Generated Sample Text: 萧炎,斗之力,三段���,脸庿,炎�,萧炎萧�炎�萧�,萧�的�
=====================================================================
Epoch 9 finished, checkpoint: 000021
Epoch 10 (Batch 000000): Train loss 2.525
Epoch 10 (Batch 000001): Train loss 2.388
Epoch 10 (Batch 000002): Train loss 2.663
Epoch 10 (Step 000065): Train loss 2.270, Val loss 3.468
Generated Sample Text: 萧炎,斗之力,三段��技萧�的萧炣也�,萧�讵��更中着曰萧�着�
=====================================================================
Epoch 10 (Batch 000003): Train loss 2.464
Epoch 10 (Batch 000004): Train loss 2.602
Epoch 10 (Batch 000005): Train loss 2.511
Epoch 10 (Batch 000006): Train loss 2.557
Epoch 10 (Step 000069): Train loss 2.117, Val loss 3.474
Generated Sample Text: 萧炎,斗之力,三段��,这的�法的萧�炼�萧�法,萧�级级父了�
=====================================================================
Epoch 10 finished, checkpoint: 000023

从上面的打印结果可知,使用梯度下降算法训练大语言模型gpt2_small,可以减小大语言模型的预测输出与样本标签之间的交叉熵损失,并显著提升大语言模型的文本生成能力。在训练刚开始时,将萧炎,斗之力,三段输入大语言模型gpt2_small,生成的是Knowledge�缌�缌缌�703 clashes�缌 longest,,缌,���,缌缌�或者,,,,,,,,,,,,,,,,�这样不包含任何有效信息的自然语言文本序列。在仅包含7个batch训练样本的数据集上训练10个epoch,大语言模型gpt2_small已经可以生成���,脸庿,炎�,萧炎萧�炎�萧�,萧�的�以及��,这的�法的萧�炼�萧�法,萧�级级父了�这样与训练数据集存在一定关联的自然语言文本了。

可以使用如下代码,分别绘制大语言模型gpt2_small在训练集及验证集上交叉熵损失的变化情况图像:

import matplotlib.pyplot as plt

def plot_losses(epochs_seen, tokens_seen, train_losses, val_losses):
    fig, ax1 = plt.subplots(figsize=(5, 3))
    ax1.plot(epochs_seen, train_losses, label="Training loss")
    ax1.plot(epochs_seen, val_losses, linestyle="-.", label="Validation loss")
    ax1.set_xlabel("Epochs")
    ax1.set_ylabel("Loss")
    ax1.legend(loc="upper right")
    ax2 = ax1.twiny()
    ax2.plot(tokens_seen, train_losses, alpha=0)
    ax2.set_xlabel("Tokens seen")
    fig.tight_layout()
    plt.show()

epochs_tensor = torch.linspace(0, num_epochs, len(train_losses))
plot_losses(epochs_tensor, tokens_seen, train_losses, val_losses)

执行上面代码,生成交叉熵损失的变化情况图像如下:

图四

从上面的交叉熵损失变化情况图像可知,在训练刚开始时,训练集及验证集上的交叉熵损失都非常大。使用梯度下降算法训练大语言模型gpt2_small,可以减小大语言模型的预测输出与样本标签之间的交叉熵损失,使大语言模型的预测输出与样本标签之间的差异性更小。

随着训练的进行,训练集和验证集上交叉熵损失的差异会越来越大,训练集上的交叉熵损失值会比验证集小的越来越明显,表明大语言模型在训练数据集上的过拟合情况越来越严重。在工业界的预训练大语言模型实践中,并不会在一个很小的训练数据集上训练多个epoch,而是会在一个非常大的训练数据集上训练少数几个甚至只训练一个epoch,这种训练策略可以很大程度上解决预训练大语言模型时的过拟合问题。

4. 结束语

前向传播流程将一个batch的训练样本输入大语言模型,共预测输出 batch_size × context_len \text{batch\_size}\times\text{context\_len} batch_size×context_len个维度为vocabulary_size的logits向量。后向传播流程首先使用交叉熵损失函数计算大语言模型的预测输出与训练样本标签之间的损失loss,并通过后向传播算法计算大语言模型参数梯度,最后使用梯度下降算法更新大语言模型的参数。

预训练大语言模型就是不断从训练数据集中获取一个batch的训练样本,然后执行这个操作直至收敛的过程。

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

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

相关文章

Permute for Mac v3.12.1 文件格式转换器 支持M、Intel芯片

Mac毒搜集到的Permute 提供简单的视频格式转换功能&#xff0c;可以简单的将视频文件转换为你想要的格式。将你想要转换的视频拖到软件窗口内&#xff0c;然后选择你想要转换的格式即可。 应用介绍 Permute是一款Mac上易用的媒体格式转换工具&#xff0c;支持视频、音乐和图像…

智慧消防新篇章:4G液位/压力传感器,筑牢安全防线!

火灾无情&#xff0c;防患未“燃”&#xff01;在智慧消防时代&#xff0c;如何实现消防水系统的实时监测、预警&#xff0c;保障人民生命财产安全&#xff1f;山东一二三物联网深耕物联网领域&#xff0c;自主研发4G液位、4G压力智能传感器&#xff0c;为智慧消防水位、水压无…

C++ primier plus 函数探幽第二部分

系列文章目录 C primer plus 第一节 步入C-CSDN博客 C primer plus 第二节 hello world刨析-CSDN博客 C primer plus 第三节 数据处理-CSDN博客 C primer plus 第四节 复合类型-CSDN博客 C primer plus 第五节 循环-CSDN博客 C primier plus 第七节 函数探幽第一部分-CSDN博客 …

用低代码平台集成人工智能:无需专业开发也能实现智能化

引言&#xff1a;人工智能的普及与企业需求 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;越来越多的企业开始意识到其在提升运营效率、优化客户体验和推动业务创新方面的巨大潜力。从智能客服到自动化决策支持&#xff0c;从数据分析到个性化推荐&#x…

第六课:数据库集成:MongoDB与Mongoose技术应用

本文详细介绍了如何在Node.js应用程序中集成MongoDB数据库&#xff0c;并使用Mongoose库进行数据操作。我们将涵盖MongoDB在Ubuntu 20系统中的安装、Bash命令的CRUD操作、Mongoose数据建模&#xff08;Schema/Model&#xff09;、关联查询与聚合管道&#xff0c;以及实战案例—…

TypeError: Cannot set properties of undefined (setting ‘xxx‘)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…

windows下使用msys2编译ffmpeg

三种方法&#xff1a; 1、在msys2中使用gcc编译 2、在msys2中使用visual studio编译&#xff08;有环境变量&#xff09; 3、在msys2中使用visual studio编译&#xff08;无环境变量&#xff09; 我的环境&#xff1a; 1、msys2-x86_64-20250221 2、vs2015 3、ffmpeg-7.1…

可视化+图解链表

链表&#xff08;Linked list&#xff09;是一种常用的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含数据域和指针域。指针域存储了下一个节点的地址&#xff0c;从而建立起各节点之间的线性关系。 1、链表节点 1.1 节点构成 链表节点如下图所示&#xff…

Docker参数,以及仓库搭建

一。Docker的构建参数 注释&#xff1a; 1.对于CMD&#xff0c;如果不想显示&#xff0c;而是使用交互界面&#xff1a;docker run -ti --rm --name test2 busybox:v5 sh 2.对于CMD&#xff0c;一个交互界面只可以使用一个&#xff0c;如果想多次使用CMD&#xff0c;则用ENTR…

正十七边形尺规作图证明——从高斯的发现到几何实现

正十七边形尺规作图证明——从高斯的发现到几何实现 1. 引言&#xff1a;一个历史性的数学突破 在欧几里得几何中&#xff0c;尺规作图&#xff08;仅使用直尺和圆规&#xff09;是最为基础的几何构造方法。古希腊数学家已知如何构造正三角形、正方形和正五边形&#xff0c;但…

常见Web应用源码泄露问题

文章目录 前言一、常见的源码泄露漏洞git源码泄露SVN源码泄露DS_Store文件泄漏网站备份压缩文件泄露WEB-INF/web.xml泄露CVS泄露.hg源码泄露Bazaar/bzr泄露.swp文件泄露 前言 在Web应用方面对于安全来说&#xff0c;可能大家对SQL注入、XSS跨站脚本攻击、文件上传等一些漏洞已…

使用Modelsim手动仿真

FPGA设计流程 在设计输入之后,设计综合前进行 RTL 级仿真,称为综合前仿真,也称为前仿真或 功能仿真。前仿真也就是纯粹的功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟。在完成一个设计的代码编写工作之后,可以直接对代码进行仿真,…

利用 ArcGIS Pro 快速统计省域各市道路长度的实操指南

在地理信息分析与处理的工作中&#xff0c;ArcGIS Pro 是一款功能强大的 GIS 软件&#xff0c;它能够帮助我们高效地完成各种复杂的空间数据分析任务。 现在&#xff0c;就让我们一起深入学习如何借助 ArcGIS Pro 来统计省下面各市的道路长度&#xff0c;这一技能在城市规划、…

1.4 单元测试与热部署

本次实战实现Spring Boot的单元测试与热部署功能。单元测试方面&#xff0c;通过JUnit和Mockito等工具&#xff0c;结合SpringBootTest注解&#xff0c;可以模拟真实环境对应用组件进行独立测试&#xff0c;验证逻辑正确性&#xff0c;提升代码质量。具体演示了HelloWorld01和H…

掌握Kubernetes Network Policy,构建安全的容器网络

在 Kubernetes 集群中&#xff0c;默认情况下&#xff0c;所有 Pod 之间都是可以相互通信的&#xff0c;这在某些场景下可能会带来安全隐患。为了实现更精细的网络访问控制&#xff0c;Kubernetes 提供了 Network Policy 机制。Network Policy 允许我们定义一组规则&#xff0c…

结合rpart包的决策树介绍

决策树与CART算法 决策树是一种基于树状结构的监督学习算法。它通过从根节点开始递归地对特征进行划分&#xff0c;构建出一棵树来进行决策。决策树的构建过程需要解决的重要问题有三个&#xff1a;如何选择自变量、如何选择分割点、确定停止划分的条件。解决这些问题是希望随…

VScode代码格式化插件black失效问题

之前有如下提示&#xff1a; 没太当回事&#xff0c;发现还能用。之后突然就用不了了&#xff0c;跟着官方插件的文档来查看log&#xff1a; 查看发现提示&#xff1a; Message: TypeError: type object is not subscriptable 在github界面找到解决方案&#xff1a;安装Versio…

【经验分享】Ubuntu20.04编译RK3568 AI模型报错问题(已解决)

【经验分享】Ubuntu20.04编译RK3568 AI模型报错问题&#xff08;已解决&#xff09; 前言问题现象问题分析解决方案总结 前言 这里使用的是Rockchip提供的rknn_model_zoo&#xff0c;https://github.com/airockchip/rknn_model_zoo/tree/main 此解决方案适用于Rockchip芯片在U…

AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

云边有个稻草人-CSDN博客 目录 引言 一、什么是DeepSeek&#xff1f; 1.1 DeepSeek平台概述 1.2 DeepSeek的核心功能与技术 二、蓝耘通义万相2.1概述 2.1 蓝耘科技简介 2.2 蓝耘通义万相2.1的功能与优势 1. 全链条智能化解决方案 2. 强大的数据处理能力 3. 高效的模型…

基于SpringBoot实现旅游酒店平台功能一

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高&#xff0c;旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求&#xff0c;旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上&#xff0…