支持AMD GPU的llm.c

anthonix/llm.c: LLM training in simple, raw C/HIP for AMD GPUs (github.com)

llm.c for AMD devices

This is a fork of Andrej Karpathy's llm.c with support for AMD devices.

性能

在单个7900 XTX显卡上使用默认设置,目前的训练步骤耗时约为79毫秒,相比PyTorch的夜间版本(2.4.0.dev20240513)的约97毫秒,以及tinygrad的约440毫秒来说,表现更优。

对于多GPU训练,在装有四个7900 XTX显卡的机器上,吞吐量达到了每秒约210,000个令牌。

更新(2024年5月28日):在单个7900 XTX显卡上,快速注意力分支的训练步骤时间已经降低到58.340831毫秒,或者在四个7900 XTX显卡上达到了每秒318,777个令牌的吞吐量。目前正在研究双缓冲技术以进一步推动性能提升。

状态

  • train_gpt2_fp32(基线,最小改动):使用32位浮点数(FP32)训练GPT-2模型(基线版本,仅进行最小改动)
  • train_gpt2 with BF16(基线,最小改动):使用半精度浮点数(BF16)训练GPT-2模型(基线版本,仅进行最小改动)
  • train_gpt2 with BF16 and multiple GPUs:使用半精度浮点数(BF16)并在多个GPU上训练GPT-2模型
  • RDNA3 优化内核(进行中):针对RDNA3架构优化的内核(仍在开发中)
  • CDNA3 优化内核:针对CDNA3架构优化的内核(具体状态未提及)

快速入门(AMD目标)

安装ROCm 6.1.1,检出仓库,并执行以下步骤:

  1. pip install -r requirements.txt (安装所需的依赖项)
  2. python prepro_tinyshakespeare.py (预处理tinyshakespeare数据集)
  3. export HF_ENDPOINT=https://hf-mirror.com
  4. python train_gpt2.py ((此步骤可能用于生成某种训练数据或配置,但具体细节未在给定指令中明确))
  5. make train_gpt2amd (编译AMD特定版本的GPT-2训练程序)

ROCm 6.0.2报错:

ld.lld: error: unable to find library -ldevice_gemm_operations
ld.lld: error: unable to find library -ldevice_other_operations
ld.lld: error: unable to find library -lstdc++
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:285:train_gpt2amd] 错误 1

不知道ROCm 6.1.1是否能编译成功。

 6. ./train_gpt2amd (运行AMD特定版本的GPT-2训练程序)

[原始README]

karpathy/llm.c

在简单、纯C/CUDA中进行LLM(大型语言模型)训练。无需245MB的PyTorch或107MB的cPython。在单个文件llm.c/train_gpt2.c中,使用CPU和fp32(32位浮点数)训练GPT-2大约需要1,000行干净的代码,而在llm.c/train_gpt2.cu中使用GPU训练大约需要3,000行代码(增加了CUDA内核)。代码立即编译并运行,它与PyTorch的参考实现完全匹配,并且当前速度略快于(编译后的)PyTorch(使用bf16、torch编译和flash attention)。我选择GPT-2作为第一个工作示例,因为它是LLM的鼻祖,也是现代堆栈首次结合在一起的例子。

我们当前的目标是复现GPT-2。要了解当前正在进行的工作的概述,请参阅最新的State of the Union帖子。

2024年5月28日更新:一个有用的近期帖子可能是“在llm.c中用90分钟和20美元复现GPT-2(124M)”,我在其中详细说明了从零开始复现124M/350M模型的GPT-2微系列的步骤。展示启动命令的文件本身是run124M.sh和run350M.sh。

我希望这个仓库只维护C和CUDA代码。这个仓库到其他语言的移植非常受欢迎,但应该在单独的仓库中完成,然后我很乐意在下面的“显著分支”部分链接到它们,就像我在llama2.c分支中所做的那样。

快速入门(GPU,速度慢但稳定且适合学习)

对于“我不在乎其他任何事情,我只想训练,并且我有GPU”的这部分用户。请运行以下命令:

pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
make train_gpt2fp32cu
./train_gpt2fp32cu

以上命令(1)会下载tinyshakespeare数据集,并使用GPT-2的Tokenizer进行分词处理,(2)下载并保存GPT-2(124M)的权重,(3)在C/CUDA中从这些权重初始化,并在tinyshakespeare数据集上使用AdamW优化器进行一轮(epoch)的训练(使用批量大小4,上下文长度1024,总共74步),评估验证损失,并生成一些文本样本。请注意,在这个快速入门中,我们使用的是CUDA代码的fp32版本train_gpt2_fp32.cu。在下一节中,我们将介绍当前“主流”的train_gpt2.cu,它使用混合精度,运行速度大约快2倍。

快速入门(GPU,最前沿的优化)

我想看到它运行得更快。在这种情况下,切换到我们最主要的、优化度最高的 train_gpt2.cu。运行如下命令:

pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
make train_gpt2cu
./train_gpt2cu

如果你额外安装了cuDNN(请参见下面的CUDA部分),你可以通过flash attention实现更快的速度。调整make命令,如下编译带有cudnn/flash attention的版本:

make train_gpt2cu USE_CUDNN=1
./train_gtp2cu

这段话的意思是,如果你已经安装了cuDNN,那么在编译和运行一个名为train_gpt2cu的程序时,可以通过设置USE_CUDNN=1来启用cuDNN的支持,从而利用cuDNN提供的加速功能来提高程序的运行速度。这里的make是一个构建工具,用于自动化编译过程,而./train_gpt2cu则是运行编译后的程序。
请注意,默认的批量大小非常小(4)。如果你的GPU有足够的内存,我建议你将其增加到例如32:

./train_gtp2cu -b 32

我的标准单GPU "生产" 运行(例如使用A100 40GB)不是训练TinyShakespeare,而是训练TinyStories,示例如下:

python dev/data/tinystories.py
make train_gtp2cu USE_CUDNN=1
./train_gtp2cu -i dev/data/tinystories/TinyStories_train.bin \
               -j dev/data/tinystories/TinyStories_val.bin \
               -v 250 -s 250 -g 144 -o stories.log -b 32

-i 标志是输入数据的通配符模式,`-j` 是验证数据。另外,我将验证损失和采样的频率减少到每250步,并且在采样阶段采样144个tokens(大约能装下一篇故事),批量大小为32。
如果你想要训练实际的、真实的预训练数据,查看最近添加的对 fineweb数据集 的支持。与上面的数据集不同,这里的训练/验证tokens 不是放在一个.bin文件中,而是现在有多个数据分片。这里有一个示例:

# 将FineWeb数据以1亿个标记的分片写入到dev/data/fineweb10B
python dev/data/fineweb.py -s 100000000
# 编译并运行
./train_gtp2cu -i "dev/data/fineweb10B/fineweb_train_*.bin" \
               -j "dev/data/fineweb10B/fineweb_val_*.bin" \
               -v 250 -s 250 -g 144 -o fineweb.log -b 32

其中,你会注意到使用了通配符 * 来匹配所有的训练分片。

快速入门(多GPU)

很好,让我们更进一步。我们将使用MPI和NCCL来进行多GPU训练。上面部分的内容依然适用,但需要做以下改变:

# 安装MPI的示例:
sudo apt install openmpi-bin openmpi-doc libopenmpi-dev

# 运行命令现在需要以 mpirun 开头:
mpirun -np <你机器上的GPU数量> ./train_gpt2cu

在最后的命令中,替换为你想要运行的GPU数量。上面部分讨论的所有标志在这里也适用。

快速开始(CPU)

“我是如此贫穷以至于连GPU都没有”的部分。你仍然可以进行训练!但你不会走得太远。你仍然可以微调一个GPT-2小模型(1.24亿参数模型)以输出像莎士比亚式的文本,作为示例:

pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
make train_gpt2
OMP_NUM_THREADS=8 ./train_gpt2

上面的行(1)下载了tinyshakespeare 数据集,使用GPT-2的分词器对其进行分识,(2)下载并保存GPT-2(124M)的权重,(3)在C中从它们初始化并在tineshakespeare上训练40步骤使用AdamW(使用批量大小4,上下文长度只有64),评估验证损失,并抽取一些文本。诚实地讲,除非你有一个强大的CPU(并且可以在启动命令中增加OMP线程的数量),你在CPU上训练大型语言模型(LLMs)不会走得太远,但它可能是一个不错的演示/参考。

训练:更多细节

在`/dev/data/(dataset).py`的数据文件负责下载、分词并将分词保存到文件中。例如,当你运行:

python dev/data/tinyshakespeare.py

我们下载并分词tinyshakespeare数据集。这个输出看起来像这样:

writing 32,768 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_val.bin
writing 305,260 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_train.bin

.bin文件包含一个短的头部(1024字节),随后是一个流式的tokens以uint16格式,表明了用GPT-2分词器的分词id。更多数据集可以在`/dev/data`找到。
原则上,一旦我们得到了tokens,我们就准备在这里开始训练模型。然而,当前的代码还不能从零开始训练(很快就会加入),所以我们从OpenAI发布的预训练模型初始化训练并进行微调。为此,我们需要下载GPT-2的权重并将其作为我们可以在C语言中加载的检查点来保存。这就是当你运行以下脚本时发生的事:

python train_gpt2.py

你会认出这段代码,它来自nanoGPT,是一个简单的PyTorch中的GPT-2参考实现。这个脚本将下载GPT-2 (124M)模型,对单批数据进行了10次迭代的超过拟合,运行了几步生成,并且更重要的是它将保存三个文件:1)`gpt2_124M.bin`文件,它包含了原始模型权重以便在C语言中加载,2)`gpt2_124M_debug_state.bin`文件,这也包含了更多的调试状态:输入,目标,逻辑和损失(对于调试和单元测试很有用),最后3)`gpt2_tokenizer.bin`文件,它存储了GPT-2分词器的词汇表,将分词id转换为UTF-8编码字符串片段的字节序列。文件还保存了上述的fp32版本,以及它们的bfloat16版本以供混合精度训练。我们现在可以用这些模型权重来初始化并继续在原始C语言中训练。然后我们用`make`命令来编译训练程序。目前有三个并行实现:

# 简单的,CPU,参考代码版本
make train_gpt2
# 单GPU fp32 CUDA版本
make train_gpt2fp32cu
# 多GPU混合精度CUDA版本
make train_gpt2cu

你可以查阅`Makefile`及其注释。它会尝试自动探测很多工具和库(例如:cuDNN, OpenMP, OpenMPI, nvcc),你要尽量获得尽可能多的勾号。比如当我在我配置完善的机器上运行`make train_gpt2cu USE_CUDNN=1`,我们看到:

✓ cuDNN found, will run with flash-attention
✓ OpenMP found
✓ OpenMPI found, OK to train with multiple GPUs
✓ nvcc found, including GPU/CUDA support

有些人在Ubuntu上编译时遇到问题,请查看Issue 19,简而言之就是你想修改`CFLAGS`:

# 首先尝试这个
CFLAGS="-Ofast -fno-finite-math-only -Wno-unused-result -march=native" make train_gpt2
# 其次尝试这个
CFLAGS="-O3 -Wno-unused-result -march=native" make train_gpt2

一旦编译好了二进制文件,我们就可以运行它。例如最简单的CPU参考版本运行如下:

OMP_NUM_THREADS=8 ./train_gpt2

你应该根据你的CPU拥有多少核心来调整线程数量。该程序将加载模型权重、tokens,它将运行一个微调循环数次与Adam lr 1e-4,然后从模型中生成一个样本。这个文件很可读,你应该看一看。简单来说,就是所有层的前向和后向传递的实现,并且它们被串接在一个大的、手动的、前向/后向/更新循环中。输出看起来像这样在我的MacBook Pro(苹果硅 M3 Max)上:
 

[GPT-2]
max_seq_len: 1024
vocab_size: 50257
num_layers: 12
num_heads: 12
channels: 768
num_parameters: 124439808
train dataset num_batches: 1192
val dataset num_batches: 128
num_activations: 73323776
val loss 5.252026
step 0: train loss 5.356189 (took 1452.121000 ms)
step 1: train loss 4.301069 (took 1288.673000 ms)
step 2: train loss 4.623322 (took 1369.394000 ms)
step 3: train loss 4.600470 (took 1290.761000 ms)
... (trunctated) ...
step 39: train loss 3.970751 (took 1323.779000 ms)
val loss 4.107781
generating:
---
Come Running Away,
Greater conquer
With the Imperial blood
the heaviest host of the gods
into this wondrous world beyond.
I will not back thee, for how sweet after birth
Netflix against repounder,
will not
flourish against the earlocks of
Allay
---

我喜欢Netflix的出现,很明显模型的训练过往仍在影响它。我没有尝试调整微调的超参数,所以这个结果很可能还可以大幅度提高。我还注意到,不同的平台(例如MacOS/Linux)将会(遗憾地)给出非常微小的不同结果,所以可能不要期望得到上文提供的确切的数字或生成结果。

最后,代码还在变动中。如果发生任何你没预料到或之前运行正常的奇怪事情,请尝试`git pull`,重新运行所有上面的命令,回到这个README文件参考,等等。

测试

我还附上了一个简单的单元测试,以确保我们的 C 代码与 PyTorch 代码一致。以 CPU 为例,编译并且执行如下:

make test_gpt2
./test_gpt2

这将加载 gpt2_124M_debug_state.bin 文件,执行一个前向传递,与 PyTorch 参考实现比较 logits 和 loss,然后进行 10 次迭代的 Adam 训练确保损失与 PyTorch 匹配。要测试 GPU 版本,我运行:

# fp32 测试(不支持 cudnn)
make test_gpt2cu PRECISION=FP32 && ./test_gpt2cu
# 混合精度 cudnn 测试
make test_gpt2cu USE_CUDNN=1 && ./test_gpt2cu

教程

我在这里附上了一个非常小的教程,在 doc/layernorm/layernorm.md。这是一个实现 GPT-2 模型的单层,layernorm 层的简单分步指导。这是理解 C 中是如何实现层的一个好的起点。

CUDA

整个训练循环也在一个文件中使用纯CUDA实现,但是内核的优化还在进行中。目前,我们的速度略微超过了PyTorch Nightly的速度。我们组织代码的方式是,在`dev/cuda`文件夹中收集了越来越多的复杂程度递增的内核,详见dev/cuda/README.md。然后,我们将最好的内核复制粘贴到单一训练文件`train_gpt2cu.cu`中的主要训练循环中。

WIP警告,2024年4月23日。我们合并了第一个版本的混合精度训练代码。我将fp32版本的检查点备份到包含`_fp32`文件名的单独文件中,并希望保留这个版本在仓库的根目录中,因为它1)不需要最新的CUDA,更有可能编译和更加便于移植,2)它更简单,并且充当参考。事实上,我们想让fp32版本朝着纯CUDA的方向发展(例如,默认情况下甚至不调用cuBLAS),用作教育参考,甚至可能是CUDA课程的一个内核。从现在开始,与速度有关的"主线"开发将转移到train_gpt2.cu文件,该文件包含混合精度训练。

在下面的描述中,我现在默认使用fp32版本,因为它当前更加便携和稳定,然后在最后我将介绍新的混合精度版本。

正确性。首先,我们可以做10次训练迭代并验证我们的代码是否与PyTorch完全匹配和再现数字:

make test_gpt2fp32cu
./test_gpt2fp32cu

这会打印出`overall okay: 1`。因此,前向激活、后向梯度和10次迭代的各个损失值都完全匹配。

训练。在单GPU上以fp32进行训练:

make train_gpt2fp32cu
./train_gpt2fp32cu

这将加载tiny_shakespeare数据集的验证和训练划分。在默认设置B=4,T=1024下,有8个验证批次和74个训练批次。该脚本目前配置为以1e-4的学习速率进行单轮微调,并在此过程中评估验证性能和生成样本,例如:

step 1/74: train loss 4.367631 (80.639749 ms)
step 2/74: train loss 4.031242 (77.378867 ms)
step 3/74: train loss 4.034144 (77.315861 ms)
step 4/74: train loss 3.859865 (77.357575 ms)
...
step 72/74: train loss 3.085081 (78.850895 ms)
step 73/74: train loss 3.668018 (78.197064 ms)
step 74/74: train loss 3.467508 (78.009975 ms)
val loss 3.516490
generating:
---
?Where will you go?
I take you wherefore I can, myself, and must.
I cast off my beak, that I may look him up on the point;
For on his rock shall he be opencast.

<|endoftext|>My little nephew:
Keep on with me, my

这在我的A100上大约运行了~10秒。我们可以这样与naive PyTorch进行比较,我们开启了`torch.compile`和使用TensorCores,它使用的是tf32类型:

python train_gpt2.py --write_tensors 0 --sequence_length 1024 --batch_size 4 --compile 1 --tensorcores 1

编译(第一次迭代)大约需要~27秒,但之后在我的A100上目前的运行速度约为每次迭代~80ms。

混合精度。新的CUDA混合精度版本,未来大部分开发将在此进行,是train_gpt2.cu,以及它的测试test_gpt2.cu。在这里,许多计算以较低精度格式(fp16或bf16)进行,这使我们能够以非常快的速度运行(约为上面TF32性能的2倍)。注意,我描述的基线实现作为`fp32`,但更精确地说,实际上是`tf32`(TensorFloat32)。训练和测试的命令都一样,只需省略fp32部分:

make train_gpt2cu
./train_gpt2cu

make test_gpt2cu
./test_gpt2cu

如果您有最新的CUDA,应该期望它可以编译OK,并且应该看到性能大幅改进。

Flash Attention。截至2024年5月1日,我们现在支持来自cuDNN的Flash Attention。因为cuDNN使编译时间从几秒增加到约一分钟,并且这个代码路径现在非常 新颖,目前默认情况下是禁用的。您可以通过以下方式编译来启用它:

make train_gpt2cu USE_CUDNN=1

这将尝试使用cudnn进行编译并运行。您必须在您的系统上安装cuDNN。通过apt-get安装的cuDNN安装说明将获取默认的cuDNN包集。对于最小安装来说,cuDNN dev包是足够的,例如在Ubuntu 22.04上为CUDA 12.x:

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install libcudnn9-dev-cuda-12

除此之外,您还需要cuDNN前端,但这只是头文件。只需将仓库克隆到您的磁盘即可。如果您将其放在其他地方,将`CUDNN_FRONTEND_PATH=/path/to/your/cudnn-frontend/include`添加到`make`命令行中。

多GPU训练。截至2024年4月26日,现在还支持使用MPI和NCCL进行多GPU训练。确保您安装了MPI,例如在Linux上:

sudo apt install openmpi-bin openmpi-doc libopenmpi-dev

然后:

make train_gpt2cu
mpirun -np <GPU数量> ./train_gpt2cu

fp32版本的代码不支持多GPU。这是因为我们希望GPT-2 fp32版本成为CUDA优化课程的一个不错的教育终点。混合精度版本是我们进行前沿开发的版本,因此这是支持多GPU训练的版本。

实验/扫描

现在基本的 argparse 和日志功能已存在于 .cu 脚本中,我们可以开始进行第一轮学习率扫描。目前这还相当手动,但是下面记录了一个示例过程,展示了在一台拥有4个GPU的机器上针对TinyStories数据集进行学习率扫描的过程。在你当然已经使用 chmod u+x sweep.sh 命令赋予了sweep.sh脚本执行权限后,运行一个名为 sweep.sh 的shell脚本:

#!/bin/bash

learning_rates=(3e-5 1e-4 3e-4 1e-3)

for i in {0..3}; do
    export CUDA_VISIBLE_DEVICES=$i
    screen -dmS "tr$i" bash -c "./train_gpt2cu -i data/TinyStories -v 250 -s 250 -g 144 -l ${learning_rates[$i]} -o stories$i.log"
done

# 你可以使用以下命令关闭这些屏幕会话
# screen -ls | grep -E "tr[0-3]" | cut -d. -f1 | xargs -I {} screen -X -S {} quit

这个例子打开了4个screen会话,并使用不同的学习率运行四个命令。这会将所有损失写入日志文件 stories$i.log,你可以按照自己的意愿在Python中进行绘制。解析和绘制这些日志文件的一个快速例子可以在 dev/vislog.ipynb 中找到。

代码仓库理念

关于我希望这个代码仓库`llm.c`能够成为的几点想法:
首先,我希望`llm.c`能成为一个教学场所。举个例子,我们的`dev/cuda`文件夹是一个包含了各种手写、文档齐全的内核库,从最简单的内核开始,到更复杂/更快速的内核。如果您有带有不同权衡的新内核,请随时贡献至此。
话虽如此,我也希望`llm.c`能够非常快速,甚至在实际中用于训练网络。比如,首先,我们应该能复现大型GPT-2(1.6B)的训练过程。这需要我们整合各种最快的内核,包含使用如cuBLAS、cuBLASLt、CUTLASS、cuDNN等库。我同样认为这样做对于确立一个专家级的上限,并作为一种度量单位,具有教育意义。比如,你可以说你手写的内核速度达到了cuBLAS的80%等。然后你可以选择进行一个超快的运行,或者你可以选择 "拖放 "任何你想使用的手动内核,并用那些运行。
然而,作为一个限制,我希望保持根目录下的主线`llm.c`简单且可读。如果有一个PR能够改进性能2%,但它“花费了”500行复杂的C代码,可能还有一些非主流的第三方依赖,我可能会拒绝这个PR,因为复杂性不值得。具体的一个例子 - 让cuBLAS成为根训练循环的默认矩阵乘法是明智的:它让主线代码快了很多,它是一行易于理解的代码,而且是一个非常常见的依赖。在这一侧,我们可以在`dev/cuda`中有与cuBLAS竞争的手写实现。
最后,对于项目根目录中包含主要/默认文件的部分,我会对复杂性更加敏感。相比之下,`dev/`文件夹更像是一个草稿空间,供我们开发内核或类的库,分享有用或相关的或教育性代码,其中一些代码是可以接受的(局部)复杂性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用IDEA在WSL2的Ubuntu的docker中运行项目

1、新建项目 1.1 从远程仓库拉取代码 2、配置环境 2.1 配置IDEA运行环境 2.1.1 配置JDK 注意&#xff1a;Ubuntu 20.04运行项目请使用JDK11&#xff0c;使用JDK8会编译报错&#xff0c;报错如下&#xff1a; 2.1.2 配置Maven 2.1.3 配置运行环境 2.1.4 配置远程Debug 2.2、配…

“两客一危”车辆综合监控信息化产品及应用分析

引言 随着科技的不断进步和社会的发展&#xff0c;“两客一危”车辆&#xff08;即长途客车、旅游包车和危险品运输车&#xff09;的安全监管问题日益凸显。为了提升车辆的安全性能和管理效率&#xff0c;综合监控信息化产品应运而生。本文将对这一产品进行详细介绍&#xff0…

【一百零一】【算法分析与设计】差分,1109. 航班预订统计,P4231 三步必杀,P5026 Lycanthropy

1109. 航班预订统计 这里有 n 个航班&#xff0c;它们分别从 1 到 n 进行编号。 有一份航班预订表 bookings &#xff0c;表中第 i 条预订记录 bookings[i] [first(i), last(i), seats(i)] 意味着在从 first(i) 到 last(i) &#xff08;包含 first(i) 和 last(i) &#xff09;…

在Linux kali下载、安装Perl环境

目录 Perl介绍 下载安装 官网下载 在Windows安装 在Linux和Mac OS安装 Perl介绍 Perl一种功能丰富的计算机程序语言&#xff0c;运行在超过100种计算机平台上&#xff0c;适用广泛&#xff0c;从最初是为文本处理而开发的&#xff0c;现在用于各种任务&#xff0c;包括系统…

【Qt知识】Qt框架中的信号(Signals)与槽(Slots)机制

Qt框架中的信号&#xff08;Signals&#xff09;与槽&#xff08;Slots&#xff09;机制是一种强大的通信方式&#xff0c;允许对象之间相互通信而无需对象之间直接引用或了解对方。这一机制简化了应用程序的事件处理和组件之间的交互&#xff0c;是Qt的一大特色和核心概念。 …

【SQL学习进阶】从入门到高级应用【企业真题】

文章目录 第一题第二题第三题第四题第五题第六题第七题第八题第九题MySQL行转列使用case whengroup by完成 第十题 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f495;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f495;希望您在这…

【RuoYi】实现文件的上传与下载

一、前言 首先&#xff0c;最近在做一个管理系统&#xff0c;里面刚好需要用到echarts图和富文本编辑器&#xff0c;然后我自己去看了官网觉得有点不好懂&#xff0c;于是去B站看来很多视频&#xff0c;然后看到了up主【程序员青戈】的视频&#xff0c;看了他讲的echarts图和富…

社交媒体数据恢复:飞信

请注意&#xff0c;本教程只适用于飞信&#xff0c;并且不涉及推荐任何数据恢复软件。 一、备份飞信聊天记录 在开始恢复飞信聊天记录之前&#xff0c;我们建议您先备份现有的聊天记录。这样&#xff0c;即使恢复过程中出现问题&#xff0c;您也可以通过备份文件找回重要的聊…

搭建基于Django的博客系统增加广告轮播图(三)

上一篇&#xff1a;ChatGPT搭建博客Django的web网页添加用户系统&#xff08;二&#xff09; 下一篇&#xff1a;搭建基于Django的博客系统数据库迁移从Sqlite3到MySQL&#xff08;四&#xff09; 功能概述 增加轮播图显示广告信息。 需求详细描述 1. 增加轮播图显示广告信…

python解决flask启动的同时启动定时任务

业务场景描述&#xff1a;在常规的开发中&#xff0c;我们开发接口服务&#xff0c;一般会将数据放在数据库、文件等第三方文件&#xff0c;启动服务后&#xff0c;服务到后台数据库中加载数据&#xff0c;这样做的好处当然是开发会更加便利以及数据的可复用性较高&#xff0c;…

一键实现文件夹批量高效重命名:轻松运用随机一个字母命名,让文件管理焕然一新!

在数字化时代&#xff0c;文件夹管理是我们日常生活和工作中不可或缺的一部分。然而&#xff0c;随着文件数量的不断增加&#xff0c;文件夹命名的繁琐和重复成为了一个让人头疼的问题。你是否曾因为手动一个个重命名文件夹而感到枯燥乏味&#xff1f;你是否曾渴望有一种方法能…

arm cortex-m架构 SVC指令详解以及其在freertos的应用

1. 前置知识 本文基于arm cortex-m架构描述&#xff0c; 关于arm cortex-m的一些基础知识可以参考我另外几篇文章&#xff1a; arm cortex-m 架构简述arm异常处理分析c语言函数调用规范-基于arm 分析 2 SVC指令 2.1 SVC指令位域表示 bit15 - bit12&#xff1a;条件码&#…

深入分析 Android BroadcastReceiver (一)

文章目录 深入分析 Android BroadcastReceiver (一)1. Android BroadcastReceiver 设计说明1.1 BroadcastReceiver 的主要用途 2. BroadcastReceiver 的工作机制2.1 注册 BroadcastReceiver2.1.1 静态注册2.1.2 动态注册 3. BroadcastReceiver 的生命周期4. 实现和使用 Broadca…

Android下HWC以及drm_hwcomposer普法(上)

Android下HWC以及drm_hwcomposer普法(上) 引言 按摩得全套&#xff0c;错了&#xff0c;做事情得全套&#xff0c;普法分析也是如此。drm_hwcomposer如果对Android图形栈有一定研究的童鞋们应该知道它是Android提供的一个的图形后端合成处理HAL模块的实现。但是在分析这个之前…

yolov8使用:数据格式转换(目标检测、图像分类)多目标跟踪

安装 yolov8地址&#xff1a;https://github.com/ultralytics/ultralytics git clone https://github.com/ultralytics/ultralytics.git安装环境&#xff1a; pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple目标检测 标注格式转换 若使用 labelimg…

sql注入-布尔盲注

布尔盲注&#xff08;Boolean Blind SQL Injection&#xff09;是一种SQL注入攻击技术&#xff0c;用于在无法直接获得查询结果的情况下推断数据库信息&#xff1b;它通过发送不同的SQL查询来观察应用程序的响应&#xff0c;进而判断查询的真假&#xff0c;并逐步推断出有用的信…

微服务学习Day9

文章目录 分布式事务seata引入理论基础CAP定理BASE理论 初识Seata动手实践XA模式AT模式TCC模式SAGA模式 高可用 分布式事务seata 引入 理论基础 CAP定理 BASE理论 初识Seata 动手实践 XA模式 AT模式 TCC模式 Service Slf4j public class AccountTCCServiceImpl implements A…

C语言 | Leetcode C语言题解之第126题单词接龙II

题目&#xff1a; 题解&#xff1a; char** list; int** back; int* backSize;// DFS uses backtrack information to construct results void dfs(char*** res, int* rSize, int** rCSizes, int* ans, int last, int retlevel) {int i ans[last];if (i 0) {res[*rSize] (c…

DALL·E 2详解:人工智能如何将您的想象力变为现实!

引言 DALLE 2是一个基于人工智能的图像生成模型&#xff0c;它通过理解自然语言描述来生成匹配这些描述的图像。这一模型的核心在于其创新的两阶段工作流程&#xff0c;首先是将文本描述转换为图像表示&#xff0c;然后是基于这个表示生成具体的图像。 下面详细介绍DALL-E2的功…

Vivado Design Suite一级物件

Vivado Design Suite一级物件 按设计过程导航内容 Xilinx文档围绕一组标准设计流程进行组织&#xff0c;以帮助您 查找当前开发任务的相关内容。本文件涵盖 以下设计过程&#xff1a; •硬件、IP和平台开发&#xff1a;为硬件创建PL IP块 平台&#xff0c;创建PL内核&#xff0…