当前位置: 首页 > article >正文

【Vulkan 入门系列】创建帧缓冲、命令池、命令缓存,和获取图片(六)

这一节主要介绍创建帧缓冲(Framebuffer),创建命令池,创建命令缓存,和从文件加载 PNG 图像数据,解码为 RGBA 格式,并将像素数据暂存到 Vulkan 的 暂存缓冲区中。

一、创建帧缓冲

createFramebuffers 用于创建帧缓冲(Framebuffer)的核心部分,其功能是为交换链(Swap Chain)中的每个图像视图(Image View)创建对应的帧缓冲对象。

void HelloVK::initVulkan() {createInstance();createSurface();pickPhysicalDevice();createLogicalDeviceAndQueue();setupDebugMessenger();establishDisplaySizeIdentity();createSwapChain();createImageViews();createRenderPass();createDescriptorSetLayout();createGraphicsPipeline();createFramebuffers();...
}void HelloVK::createFramebuffers() {swapChainFramebuffers.resize(swapChainImageViews.size());for (size_t i = 0; i < swapChainImageViews.size(); i++) {VkImageView attachments[] = {swapChainImageViews[i]};VkFramebufferCreateInfo framebufferInfo{};framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;framebufferInfo.renderPass = renderPass;framebufferInfo.attachmentCount = 1;framebufferInfo.pAttachments = attachments;framebufferInfo.width = swapChainExtent.width;framebufferInfo.height = swapChainExtent.height;framebufferInfo.layers = 1;VK_CHECK(vkCreateFramebuffer(device, &framebufferInfo, nullptr,&swapChainFramebuffers[i]));}
}

1.1 调整帧缓冲数组大小

根据交换链图像视图的数量调整帧缓冲数组的大小,确保两者一一对应。

swapChainFramebuffers.resize(swapChainImageViews.size());

1.2 遍历交换链图像视图

对每个交换链图像视图创建对应的帧缓冲。

for (size_t i = 0; i < swapChainImageViews.size(); i++) {...}

1.3 定义附件

此处仅使用颜色附件(swapChainImageViews[i]),即渲染结果将写入交换链图像。若需要深度、模板测试,需额外添加对应的图像视图。

VkImageView attachments[] = {swapChainImageViews[i]};

1.4 配置帧缓冲创建信息

VkFramebufferCreateInfo framebufferInfo{};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = renderPass;           // 关联的渲染流程
framebufferInfo.attachmentCount = 1;               // 附件数量
framebufferInfo.pAttachments = attachments;        // 附件数组指针
framebufferInfo.width = swapChainExtent.width;     // 帧缓冲宽度
framebufferInfo.height = swapChainExtent.height;    // 帧缓冲高度
framebufferInfo.layers = 1;                        // 层数(用于多视口/立体渲染)

关键参数

  • renderPass:帧缓冲必须与渲染流程兼容(即附件格式、数量与渲染流程定义一致)。
  • widthheight:必须与交换链图像尺寸一致,否则渲染结果可能无效。
  • layers:通常为 1,用于多图层渲染(如 VR 立体视图)。

1.5 创建帧缓冲

vkCreateFramebuffer 创建实际的 Vulkan 帧缓冲对象。

VK_CHECK(vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]));

二、创建命令池

创建一个命令池,用于分配和管理命令缓冲的内存。命令缓冲用于记录 GPU 执行的渲染或计算指令。

命令池与特定的队列族(Queue Family)绑定,确保命令缓冲被提交到正确的硬件队列(如图形队列)。

void HelloVK::initVulkan() {createInstance();createSurface();pickPhysicalDevice();createLogicalDeviceAndQueue();setupDebugMessenger();establishDisplaySizeIdentity();createSwapChain();createImageViews();createRenderPass();createDescriptorSetLayout();createGraphicsPipeline();createFramebuffers();createCommandPool();...
}void HelloVK::createCommandPool() {QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);VkCommandPoolCreateInfo poolInfo{};poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();VK_CHECK(vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool));
}

2.1 获取队列族索引 QueueFamilyIndices

findQueueFamilies 函数在前面已经详细分析过,用于寻找物理设备支持的图形队列族和呈现队列族。

2.2 配置命令池创建信息

VkCommandPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
  • sType:指定结构体类型为命令池创建信息。
  • flags:控制命令池的行为,此处设置为 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,允许单个命令缓冲通过 vkResetCommandBuffer 重置,而无需重置整个命令池。
  • queueFamilyIndex:指定命令池关联的队列族索引(此处为图形队列族),确保命令缓冲提交到正确的队列。

2.3 创建命令池

vkCreateCommandPool 调用 Vulkan API 创建命令池。

VK_CHECK(vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool));

三、创建命令缓存

从已创建的命令池(commandPool)中分配一组主命令缓冲(Primary Command Buffers),用于记录 GPU 执行的渲染指令。

使用 MAX_FRAMES_IN_FLIGHT 控制帧的并发数量(如双缓冲或三缓冲),避免 CPU 和 GPU 之间的资源竞争。

void HelloVK::initVulkan() {createInstance();createSurface();pickPhysicalDevice();createLogicalDeviceAndQueue();setupDebugMessenger();establishDisplaySizeIdentity();createSwapChain();createImageViews();createRenderPass();createDescriptorSetLayout();createGraphicsPipeline();createFramebuffers();createCommandPool();createCommandBuffer()...
}void HelloVK::createCommandBuffer() {commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);VkCommandBufferAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;allocInfo.commandPool = commandPool;allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;allocInfo.commandBufferCount = commandBuffers.size();VK_CHECK(vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()));
}

3.1 调整命令缓冲数组大小

根据预定义的 MAX_FRAMES_IN_FLIGHT(代码内设置为 2)设置命令缓冲数组的大小。每个飞行的帧需要一个独立的命令缓冲,确保 CPU 在录制下一帧时不会覆盖正在被 GPU 处理的帧数据。

commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);

3.2 配置命令缓冲分配信息

VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;                // 关联的命令池
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;  // 主命令缓冲级别
allocInfo.commandBufferCount = commandBuffers.size(); // 分配的缓冲数量

关键参数

  • commandPool:指定从哪个命令池分配内存。命令池的类型需与后续提交的队列兼容。
  • level:设置为 VK_COMMAND_BUFFER_LEVEL_PRIMARY,表示分配的是主命令缓冲(可直接提交到队列)。
级别用途
VK_COMMAND_BUFFER_LEVEL_PRIMARY直接提交到队列,可调用次级缓冲。适用于每帧的主要渲染指令。
VK_COMMAND_BUFFER_LEVEL_SECONDARY嵌入到主缓冲中,需通过主缓冲执行。适用于复用指令或并行录制。
  • commandBufferCount:需要分配的缓冲数量,与 MAX_FRAMES_IN_FLIGHT 一致。

3.3 分配命令缓冲

vkAllocateCommandBuffers 从命令池中分配指定数量的命令缓冲。

VK_CHECK(vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()));

3.4 核心概念

3.4.1 主命令缓冲(Primary Command Buffer)
  • 直接提交到队列:主缓冲可独立提交到队列执行,通常包含完整的渲染指令序列。
  • 次级缓冲的依赖:次级缓冲(SECONDARY)需通过 vkCmdExecuteCommands 在主缓冲中调用,适用于复用指令或并行录制。
3.4.2 帧并发控制(MAX_FRAMES_IN_FLIGHT)
  • 双缓冲/三缓冲:通过设置 2 或 3 个缓冲,允许 CPU 准备下一帧数据的同时,GPU 处理当前帧,避免资源冲突。
  • 同步机制:需配合信号量(Semaphore)或栅栏(Fence)确保帧的正确同步。
3.4.3 命令池与缓冲的关系
  • 内存管理:命令池负责底层内存分配,缓冲的生命周期由其所属池控制。
  • 重置行为:若命令池创建时指定了 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,可单独重置缓冲,否则需重置整个池。

3.5 完整工作流程示例

  1. 初始化阶段:创建命令池 → 分配命令缓冲。
  2. 渲染循环:
    • 等待前一帧完成(通过栅栏)。
    • 重置命令缓冲 → 录制渲染指令(如绑定管线、绘制调用)。
    • 提交命令缓冲到队列 → 呈现交换链图像。
  3. 清理阶段:销毁命令池(自动释放所有关联的缓冲)。

四、获取图片

从文件加载 PNG 图像数据,解码为 RGBA 格式,并将像素数据暂存到 Vulkan 的 暂存缓冲区(Staging Buffer) 中,为后续将数据复制到 GPU 专用的纹理图像做准备。

void HelloVK::initVulkan() {createInstance();createSurface();pickPhysicalDevice();createLogicalDeviceAndQueue();setupDebugMessenger();establishDisplaySizeIdentity();createSwapChain();createImageViews();createRenderPass();createDescriptorSetLayout();createGraphicsPipeline();createFramebuffers();createCommandPool();decodeImage();...
}void HelloVK::decodeImage() {std::vector<uint8_t> imageData = LoadBinaryFileToVector("texture.png",assetManager);if (imageData.size() == 0) {LOGE("Fail to load image.");return;}// Make sure we have an alpha channel, not all hardware can do linear filtering of RGB888.const int requiredChannels = 4;unsigned char* decodedData = stbi_load_from_memory(imageData.data(),imageData.size(), &textureWidth, &textureHeight, &textureChannels, requiredChannels);if (decodedData == nullptr) {LOGE("Fail to load image to memory, %s", stbi_failure_reason());return;}if (textureChannels != requiredChannels) {textureChannels = requiredChannels;}size_t imageSize = textureWidth * textureHeight * textureChannels;VkBufferCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;createInfo.size = imageSize;createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;VK_CHECK(vkCreateBuffer(device, &createInfo, nullptr, &stagingBuffer));VkMemoryRequirements memRequirements;vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements);VkMemoryAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;allocInfo.allocationSize = memRequirements.size;allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);VK_CHECK(vkAllocateMemory(device, &allocInfo, nullptr, &stagingMemory));VK_CHECK(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0));uint8_t *data;VK_CHECK(vkMapMemory(device, stagingMemory, 0, memRequirements.size, 0,(void **)&data));memcpy(data, decodedData, imageSize);vkUnmapMemory(device, stagingMemory);stbi_image_free(decodedData);
}

4.1 加载图像文件到内存

调用 LoadBinaryFileToVector 将文件内容读取到字节数组 imageData。若文件加载失败(如路径错误或文件不存在),记录错误并退出。

std::vector<uint8_t> imageData = LoadBinaryFileToVector("texture.png", assetManager);
if (imageData.size() == 0) {LOGE("Fail to load image.");return;
}

4.2 解码图像数据

使用 STB 图像库中的函数 stbi_load_from_memory 从内存解码图像。

const int requiredChannels = 4;
unsigned char* decodedData = stbi_load_from_memory(imageData.data(), imageData.size(), &textureWidth, &textureHeight, &textureChannels, requiredChannels
);
if (decodedData == nullptr) {LOGE("Fail to load image to memory, %s", stbi_failure_reason());return;
}if (textureChannels != requiredChannels) {textureChannels = requiredChannels; // 强制设为 4
}
  • requiredChannels = 4:强制解码为 RGBA 格式(4 通道),确保兼容性(某些 GPU 对 RGB 格式的线性过滤支持不佳)。
  • 输出参数:textureWidthtextureHeight(图像尺寸)、textureChannels(实际解码的通道数)。

4.3 计算图像数据大小

size_t imageSize = textureWidth * textureHeight * textureChannels; // 总字节数

4.4 创建暂存缓冲区

暂存缓冲区作为 CPU 与 GPU 之间的数据传输桥梁。后续需通过传输命令将数据从此缓冲区复制到 GPU 专用的纹理图像。

VkBufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = imageSize;                           // 缓冲区大小
createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;   // 用途:传输源
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;    // 独占访问模式
VK_CHECK(vkCreateBuffer(device, &createInfo, nullptr, &stagingBuffer));

关键参数

  • usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT:标记为传输源。
  • sharingMode = VK_SHARING_MODE_EXCLUSIVE:缓冲区仅由图形队列独占使用(无需多队列共享)。

4.5 查询内存需求

调用 vkGetBufferMemoryRequirements 获取缓冲区的内存需求(大小、对齐、内存类型掩码)。

VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements);

4.6 分配暂存内存

调用 vkAllocateMemory 用于分配暂存内存。

VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
);
VK_CHECK(vkAllocateMemory(device, &allocInfo, nullptr, &stagingMemory));
  • VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT:内存可被 CPU 直接访问(通过 vkMapMemory)。
  • VK_MEMORY_PROPERTY_HOST_COHERENT_BIT:确保 CPU 与 GPU 内存访问的自动一致性(无需手动刷新缓存)。

findMemoryType 用于找到符合特定缓冲区内存要求的内存堆的索引。Vulkan 将这些要求以位集的形式管理,在这种情况下通过 uint32_t 来表示。

uint32_t HelloVK::findMemoryType(uint32_t typeFilter,VkMemoryPropertyFlags properties) {VkPhysicalDeviceMemoryProperties memProperties;vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags &properties) == properties) {return i;}}assert(false);  // failed to find suitable memory type!return -1;
}
  1. 调用 vkGetPhysicalDeviceMemoryProperties 获取物理设备的内存信息,包括内存类型(memoryTypes)和内存堆(memoryHeaps)。
  2. 遍历所有可用的内存类型(通常数量较小)。
  3. typeFilter & (1 << i) 检查第 i 位是否为 1。若为真,表示内存类型 i 是候选类型。
  4. (memProperties.memoryTypes[i].propertyFlags & properties) == properties 确保内存类型的属性(propertyFlags)包含 properties 的所有标志。例如,若 properties 要求内存同时是主机可见和一致的,则内存类型必须同时具备这两个属性。
  5. 返回第一个满足条件的内存类型索引。
  6. 若未找到合适内存类型,触发断言错误(调试模式下终止程序),并返回无效值 -1。

4.7 绑定内存到缓冲区

将分配的内存与缓冲区关联,偏移量设为 0(从内存起始位置绑定)。

VK_CHECK(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0));

4.8 映射内存并拷贝数据

uint8_t *data;
VK_CHECK(vkMapMemory(device, stagingMemory, 0, memRequirements.size, 0, (void **)&data));
memcpy(data, decodedData, imageSize);
vkUnmapMemory(device, stagingMemory);
  1. vkMapMemory 将 GPU 内存映射到 CPU 可访问的指针 data
  2. memcpy 将解码后的像素数据复制到映射的内存中。
  3. vkUnmapMemory 解除映射,确保数据写入完成。

4.9 释放解码数据

STB 库要求手动释放解码后的像素数据,避免内存泄漏。

stbi_image_free(decodedData);

4.10 关键概念

4.10.1 暂存缓冲区(Staging Buffer)

GPU 专用内存通常无法直接被 CPU 访问,需通过暂存缓冲区中转。

典型流程

  1. CPU 将数据写入暂存缓冲区。
  2. 提交传输命令(如 vkCmdCopyBufferToImage),将数据复制到设备本地纹理。
  3. 销毁暂存资源。
4.10.2 内存一致性

HOST_COHERENT_BIT:确保 CPU 写入的数据立即可被 GPU 读取(无缓存同步问题)。若无此标志需手动调用 vkFlushMappedMemoryRangesvkInvalidateMappedMemoryRanges 刷新缓存。

相关文章:

【Vulkan 入门系列】创建帧缓冲、命令池、命令缓存,和获取图片(六)

这一节主要介绍创建帧缓冲&#xff08;Framebuffer&#xff09;&#xff0c;创建命令池&#xff0c;创建命令缓存&#xff0c;和从文件加载 PNG 图像数据&#xff0c;解码为 RGBA 格式&#xff0c;并将像素数据暂存到 Vulkan 的 暂存缓冲区中。 一、创建帧缓冲 createFramebu…...

【Git】fork 和 branch 的区别

在 Git 中&#xff0c;“fork” 和 “branch” 是两个不同的概念&#xff0c;它们用于不同的场景并且服务于不同的目的。理解这两者的区别对于有效地使用 Git 进行版本控制非常重要。 1. Fork&#xff08;分叉&#xff09; 定义 Fork 是指在 GitHub、GitLab 等代码托管平台上…...

Qt 下载的地址集合

Qt 下载离线安装包 download.qt.io/archive/qt/5.14/5.14.2/ Qt 6 安装下载在线安装包 Index of /qt/official_releases/online_installers/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror...

java将pdf转换成word

1、jar包准备 在项目中新增lib目录&#xff0c;并将如下两个文件放入lib目录下 aspose-words-15.8.0-jdk16.jar aspose-pdf-22.9.jar 2、pom.xml配置 <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><versi…...

ubuntu下gcc/g++安装及不同版本切换

1. 查看当前gcc版本 $ gcc --version# 查看当前系统中已安装版本 $ ls /usr/bin/gcc*2. 安装新版本gcc $ sudo apt-get update# 这里以版本12为依据&#xff08;也可以通过源码方式安装&#xff0c;请自行Google&#xff01;&#xff09; $ sudo apt-get install -y gcc-12 g…...

缓存与内存;缺页中断;缓存映射:组相联

文章目录 内存&#xff08;RAM&#xff09;与缓存&#xff08;Cache&#xff09;Memory Management Unit缺页中断 多级缓存缓存替换策略缓存的映射方式 内存&#xff08;RAM&#xff09;与缓存&#xff08;Cache&#xff09; 缓存&#xff1a; CPU 内部或非常靠近的高速存储&a…...

FPGA入门学习Day1——设计一个DDS信号发生器

目录 一、DDS简介 &#xff08;一&#xff09;基本原理 &#xff08;二&#xff09;主要优势 &#xff08;三&#xff09;与传统技术的对比 二、FPGA存储器 &#xff08;一&#xff09;ROM波形存储器 &#xff08;二&#xff09;RAM随机存取存储器 &#xff08;三&…...

微信小程序拖拽排序有效果图

效果图 .wxml <view class"container" style"--w:{{w}}px;" wx:if"{{location.length}}"><view class"container-item" wx:for"{{list}}" wx:key"index" data-index"{{index}}"style"--…...

elasticsearch 查询检索

一、查询方式列举 1、多维度查询 关键词&#xff1a;bool must match {"query": {"bool": {"must": [{"match": {"server_name": "www.test.com"}},{"range": { //时间查询"createTime": …...

WT2000T专业录音芯片:破解普通录音设备信息留存、合规安全与远程协作三大难题

在快节奏的现代商业环境中&#xff0c;会议是企业决策、创意碰撞和战略部署的核心场景。然而&#xff0c;传统会议记录方式常面临效率低、信息遗漏、回溯困难等痛点。如何确保会议内容被精准记录并高效利用&#xff1f;会议室专用录音芯片应运而生&#xff0c;以智能化、高保真…...

【Python 学习笔记】 pip指令使用

系列文章目录 pip指令使用 文章目录 系列文章目录前言安装配置使用pip 管理Python包修改pip下载源 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 当前文章记录的是我在学习过程的一些笔记和思考&#xff0c;可能存在有误解的地方&#xff0c;仅供大家…...

与Ubuntu相关命令

windows将文件传输到Ubuntu 传输文件夹或文件 scp -r 本地文件夹或文件 ubuntu用户名IP地址:要传输到的文件夹路径 例如&#xff1a; scp -r .\04.py gao192.168.248.129:/home/gao 如果传输文件也可以去掉-r 安装软件 sudo apt-get update 更新软件包列表 sudo apt insta…...

C# 文件读取

文件读取是指使用 C# 程序从计算机文件系统中获取文件内容的过程。将存储在磁盘上的文件内容加载到内存中&#xff0c;供程序处理。主要类型有&#xff1a;文本文件读取&#xff08;如 .txt, .csv, .json, .xml&#xff09;&#xff1b;二进制文件读取&#xff08;如 .jpg, .pn…...

leetcode125.验证回文串

class Solution {public boolean isPalindrome(String s) {s s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();for(int i0,js.length()-1;i<j;i,j--){if(s.charAt(i)!s.charAt(j))return false;}return true;} }...

【Android面试八股文】Android系统架构【一】

Android系统架构图 1.1 安卓系统启动 1.设备加电后执行第一段代码&#xff1a;Bootloader 系统引导分三种模式&#xff1a;fastboot&#xff0c;recovery&#xff0c;normal&#xff1a; fastboot模式&#xff1a;用于工厂模式的刷机。在关机状态下&#xff0c;按返回开机 键进…...

NLP高频面试题(五十二)——BERT 变体详解

在现代自然语言处理领域,BERT 系列模型不断演进,衍生出多种变体,它们通过改进预训练任务、模型结构和训练策略,在不同应用场景下取得了更优表现。本文首先概览主要 BERT 变体(如 ALBERT、RoBERTa、ELECTRA、SpanBERT、Transformer-XL 等),随后针对以下几个关键问题逐一展…...

【数据可视化-21】水质安全数据可视化:探索化学物质与水质安全的关联

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...

CSS 选择器介绍

CSS 选择器介绍 1. 基本概念 CSS&#xff08;层叠样式表&#xff09;是一种用于描述 HTML 或 XML 文档外观的语言。通过 CSS&#xff0c;可以控制网页中元素的布局、颜色、字体等视觉效果。而 CSS 选择器则是用来指定哪些 HTML 元素应该应用这些样式的工具。 2. 基本选择器 …...

【prometheus+Grafana篇】从零开始:Linux 7.6 上二进制安装 Prometheus、Grafana 和 Node Exporter

&#x1f4ab;《博主主页》&#xff1a;奈斯DB-CSDN博客 &#x1f525;《擅长领域》&#xff1a;擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(MongoDB)有了解 &#x1f496;如果觉得文章对你有所帮…...

STM32(M4)入门:GPIO与位带操作(价值 3w + 的嵌入式开发指南)

一&#xff1a;GPIO 1.1 了解时钟树&#xff08;必懂的硬件基础&#xff09; 在 STM32 开发中&#xff0c;时钟系统是一切外设工作的 “心脏”。理解时钟树的工作原理&#xff0c;是正确配置 GPIO、UART 等外设的核心前提。 1.1.1 为什么必须开启外设时钟&#xff1f; 1. 计…...

树莓派超全系列教程文档--(42)树莓派config.txt旧版配置HDMI和杂项选项

树莓派config.txt旧版配置HDMI和杂项选项 Raspberry Pi 4 HDMI遗留的杂项选项avoid_warningslogging_level 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 Raspberry Pi 4 HDMI IMPORTANT: 使用VC4 KMS图形驱动程序时&#xff0c;完整的显示管道…...

Linux419 三次握手四次挥手抓包 wireshark

还是Notfound 没连接 可能我在/home 准备配置静态IP vim ctrlr 撤销 u撤销 配置成功 准备关闭防火墙 准备配置 YUM源 df -h 未看到sr0文件 准备排查 准备挂载 还是没连接 计划重启 有了 不重启了 挂载准备 修改配置文件准备 准备清理缓存 ok 重新修改配…...

CSS-跟随图片变化的背景色

CSS-跟随图片变化的背景色 获取图片的主要颜色并用于背景渐变需要安装依赖 colorthief获取图片的主要颜色. 并丢给背景注意 getPalette并不是个异步方法 import styles from ./styles.less; import React, { useState } from react; import Colortheif from colorthief;cons…...

解决Docker 配置 daemon.json文件后无法生效

vim /etc/docker/daemon.json 在daemon中配置一下dns {"registry-mirrors": ["https://docker.m.daocloud.io","https://hub-mirror.c.163.com","https://dockerproxy.com","https://docker.mirrors.ustc.edu.cn","ht…...

虚幻基础:ue碰撞

文章目录 碰撞&#xff1a;碰撞体 运动后 产生碰撞的行为——碰撞响应由引擎负责&#xff0c;并向各自发送事件忽略重叠阻挡 碰撞响应关系有忽略必是忽略有重叠必是重叠有阻挡不一定阻挡&#xff08;双方都为阻挡&#xff09; 碰撞启用&#xff1a;纯查询&#xff1a;开启移动检…...

2025.04.23【探索工具】| STEMNET:高效数据排序与可视化的新利器

文章目录 1. STEMNET工具简介2. STEMNET的安装方法3. STEMNET常用命令 1. STEMNET工具简介 在生物信息学领域&#xff0c;分析和处理大规模数据集是研究者们面临的日常挑战。STEMNET工具应运而生&#xff0c;旨在提供一个强大的平台&#xff0c;用于探索和分析单细胞RNA测序&a…...

GitLab Runner配置并行执行多个任务

检查并修改方法&#xff1a; 打开 Runner 的配置文件&#xff08;通常位于 /etc/gitlab-runner/config.toml 或 ~/.gitlab-runner/config.toml&#xff09;。 确保 concurrent 值大于 1&#xff0c;例如&#xff1a; concurrent 4 # 允许最多 4 个任务同时运行重启 Runner…...

深入理解前端安全:CSRF与XSS攻击详解

引言 在Web开发的世界里&#xff0c;安全性就像是房子的门锁。你可能觉得它不显眼&#xff0c;但一旦没了它&#xff0c;麻烦可就大了&#xff01;本文将深入探讨两大前端安全威胁&#xff1a;CSRF&#xff08;跨站请求伪造&#xff09;和XSS&#xff08;跨站脚本攻击&#xf…...

Docker 中运行 JAR 文件

文章目录 步骤 1&#xff1a;准备文件结构步骤 2&#xff1a;编写 Dockerfile步骤 3&#xff1a;构建 Docker 镜像步骤 4&#xff1a;运行容器常见问题解决Q1&#xff1a;容器启动后立即退出Q2&#xff1a;时区不一致Q3&#xff1a;依赖外部服务&#xff08;如MySQL&#xff09…...

数据治理体系的“三驾马车”:质量、安全与价值挖掘

1. 执行摘要 数据治理已从合规驱动的后台职能&#xff0c;演变为驱动业务成果的战略核心。本文将深入探讨现代数据治理体系的三大核心驱动力——数据质量、数据安全与价值挖掘——它们共同构成了企业在数字时代取得成功的基石。数据质量是信任的基石&#xff0c;确保决策所依据…...