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

从零开始搭建CLIP模型实现基于文本的图像检索

目录

  • CLIP原理简介
  • 代码实现
  • 参考链接

CLIP原理简介

论文链接,源码链接

CLIP模型由OpenAI在2021年提出,利用双Decoder(Dual Encoder)的架构来学习图像和文本之间的对应关系,是多模态大模型的开创之作,为后续许多高效的多模态模型的提出打下基础。CLIP是一个预训练模型(Pre-trained Model),在学习到图像–文本特征之间的关联后可以迁移到各种下游任务中,如图像分类,文本引导图像分割和目标检测,图像文本检索等。由于模型学习到的是文本语义和图像语义之间的关联,使得其zero-shot能力非常强大,根据论文中的描述,CLIP在很多数据集上zero-shot的结果甚至超越了许多训练好的模型的效果。CLIP的训练范式如下:

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/1d112d364a60434bba8dd07d42d2a1c6.png

CLIP的结构非常简单,数据集包含大量的图像文本对,图像经过图像编码器得到图像特征,文本经过文本编码器得到文本特征,将图像特征和文本特征按照数据集中的对应关系进行配对,不配对的特征给予惩罚,从上图中可以看出,我们希望矩阵中蓝色的值趋近于1,其余值趋近于0,采用对比学习的方式对模型进行训练,算法的伪代码如下:

在这里插入图片描述
从损失函数中可以看出,分别对特征对比矩阵的行和列进行交叉熵损失函数计算,并取平均得到最终的loss。图像编码器一般有两种选择:ResNet和ViT;文本编码器采用Transformer Encoder,均是各自领域中优秀的特征提取网络。
CLIP的推理范式如下:

在这里插入图片描述
在推理阶段,图像编码器中输入图像获取图像特征,文本编码器中输入文本获取文本特征,将图像特征向量和文本特征向量的转置相乘得到每张图像对每个文本的特征相似度,相似度最高的文本即描述了该图像中物体所属的类别。

代码实现

Flickr8k数据集下载,提取码:fbfz
DistilBert模型文件下载

我的运行环境:
CUDA 11.8
pytorch 2.2.2
transformers 4.44.0 # 用于从HuggingFace上加载预训练模型


数据集预览:
图片示例

图片示例

在这里插入图片描述

文本示例

由于作者的显卡算力有限,选取Flickr8k数据集进行模型训练,其中包含8k个图像文本对,其中一张图像对应5条文本。图像编码器采用ResNet50,直接从timm库中导入;文本编码器采用DistilBert,即轻量化的Bert模型,从HuggingFace上下载。闲话少说,小二,上菜!

### 模型参数配置 ###
import argparse
from dataclasses import dataclassparser = argparse.ArgumentParser(description="CLIP from zero")
parser.add_argument("--image_dir", default="user/Flickr8k/Images", help='path to image folder')  # 存放图像的文件路径
parser.add_argument("--caption_dir", default="user/Flickr8k", help='path to caption folder')  # 存放文本的文件路径
parser.add_argument("--weight_dir", default='user/checkpoints', help='path to save output weight')  # 存放训练权重的文件路径
args = parser.parse_args()@dataclass
class CLIPConfig:image_path: str = args.image_dir  # 图像存放路径image_size: int = 224  # resize后的图像尺寸,便于构建Dataloadercaption_path: str = args.caption_dir  # 文本存放路径batch_size: int = 8  # 一个批次中的数据数量epochs: int = 3  # 训练世代image_encoder_model: str = "resnet50"  # 图像编码器的名称image_embedding_dim: int = 2048  # 图像特征的维度text_encoder_model: str = "distilbert-base-uncased"  # 文本编码器的名称text_embedding_dim: int = 768  # 文本特征的维度text_tokenizer: str = text_encoder_model  # 文本分词器模型的名称max_length: int = 200  # 文本编码器可输入的最长文本长度pretrained: bool = False  # 是否加载预训练好的编码器trainable: bool = True  # 在训练过程中是否更新编码器的参数temperature: float = 1.0  # 计算loss时的正则化系数proj_dim: int = 256  # 图像特征和文本特征统一后的维度dropout_rate: float = 0.1  # dropout系数,避免过拟合### 载入数据集并初始化 ###
import torch
from torch.utils.data import Dataset, DataLoader
from transformers import DistilBertModel, DistilBertConfig, DistilBertTokenizer
import albumentations as A
import pandas as pd
import cv2class CLIPDataset(Dataset):def __init__(self, config, image_path, caption_path, transforms=True):"""图片文件名和标题的长度必须相同如果一个图片对应多个标题,该图片文件名需要重复多次"""self.image_path = image_path  # 图像路径self.caption_path = caption_path  # 文本路径self.dataframe = pd.read_csv(f"{self.caption_path}/captions.csv")  # 读取文本self.tokenizer = DistilBertTokenizer.from_pretrained(config.text_tokenizer)  # 载入分词器self.image_filenames = self.dataframe["image"].values  # 获取图像文件名self.captions = list(self.dataframe["caption"].values)   # 获取图像对应的描述文本self.encoded_captions = self.tokenizer(self.captions, padding=True, truncation=True, max_length=config.max_length)  # 文本分词self.transforms = transforms  # 对输入图像进行预处理def __getitem__(self, idx):  # 获取数据集中第idx个数据,其中包含图片名称和对应的标题(可能不止一个)item = {key: torch.tensor(values[idx]) for key, values in self.encoded_captions.items()}image = cv2.imread(f"{self.image_path}/{self.image_filenames[idx]}")  # 获取原始图像image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)if self.transforms:image = self.get_transforms(mode="train")(image=image)["image"]  # 对图像进行预处理item["image"] = torch.tensor(image).permute(2, 0, 1).float()  # 将图片转换为tensor格式,并调整为RGB顺序item["caption"] = self.captions[idx]  # 获取标题return itemdef __len__(self):return len(self.captions)  # 获取文本长度def get_transforms(self, mode="train"):if mode == "train":return A.Compose([A.Resize(config.image_size, config.image_size, always_apply=True),  # 对图像进行resizeA.Normalize(max_pixel_value=255.0, always_apply=True)  # 对像素值进行归一化])### 图像编码器 ###
import torch.nn as nn
import timmclass ImageEncoder(nn.Module):"""图像编码器,采用ResNet50"""def __init__(self, config):super().__init__()self.model = timm.create_model(config.image_encoder_model, pretrained=config.pretrained, num_classes=0, global_pool="avg")  # 创建ResNet50for p in self.model.parameters():p.requires_grad = config.trainable  # 设置参数可训练def forward(self, x):image_encoded = self.model(x)  # 获得图像特征编码,形状为[batch_size, image_embedding_dim]return image_encoded### 文本编码器 ###
class TextEncoder(nn.Module):"""文本编码器,采用DistilBERT"""def __init__(self, config):super().__init__()if config.pretrained:self.model = DistilBertModel.from_pretrained(config.text_encoder_model)  # 导入下载好的模型文件else:self.model = DistilBertModel(DistilBertConfig())for p in self.model.parameters():p.requires_grad = config.trainable  # 设置参数可训练self.target_token_idx = 0# 提取出和图像对应的文本特征向量def forward(self, input_ids, attention_mask):output = self.model(input_ids=input_ids, attention_mask=attention_mask)text_encoded = output.last_hidden_state[:, self.target_token_idx, :]  # [batch_size, text_embedding_dim]return text_encoded### 投影层 (MLP) ###
class ProjectionHead(nn.Module):"""将图像编码和文本编码映射到相同维度"""def __init__(self, config, input_embedding_dim):super().__init__()self.proj = nn.Linear(input_embedding_dim, config.proj_dim)self.act_fn = nn.GELU()self.fc = nn.Linear(config.proj_dim, config.proj_dim)self.dropout = nn.Dropout(config.dropout_rate)self.layer_norm = nn.LayerNorm(config.proj_dim)def forward(self, x):x_proj = self.proj(x)x = self.act_fn(x_proj)x = self.fc(x)x = self.dropout(x)x = x + x_projx = self.layer_norm(x)return x### 定义损失函数 ###
def cross_entropy(logits, labels, reduction='none'):log_softmax = nn.LogSoftmax(dim=-1)loss = (-labels * log_softmax(logits)).sum(dim=1)if reduction == 'mean':return loss.mean()else:return loss.sum()### 模型主体 ###
import torch.nn.functional as Fclass CLIP(nn.Module):def __init__(self, config):super().__init__()self.image_encoder = ImageEncoder(config)  # 实例化图像编码器self.text_encoder = TextEncoder(config)  # 实例化文本编码器self.image_proj = ProjectionHead(config, config.image_embedding_dim)  # 图像特征投影self.text_proj = ProjectionHead(config, config.text_embedding_dim)  # 文本特征投影self.temperature = config.temperaturedef forward(self, batch):image_features = self.image_encoder(batch["image"])  # 图像编码# 文本编码,tokenizer处理后的文本序列自带input_ids和attention_masktext_features = self.text_encoder(batch["input_ids"], batch["attention_mask"])image_embeddings = self.image_proj(image_features)  # 图像特征投影text_embeddings = self.text_proj(text_features)  # 文本特征投影logits = (text_embeddings @ image_embeddings.T) / self.temperature  # tensor形状为[batch_size, batch_size]images_similarity = image_embeddings @ image_embeddings.T  # tensor形状为[batch_size, batch_size]text_similarity = text_embeddings @ text_embeddings.T  # tensor形状为[batch_size, batch_size]# 软标签,不配对的位置设置为较小的数,而非0labels = F.softmax((images_similarity + text_similarity) / 2 * self.temperature, dim=-1)  loss_T = cross_entropy(logits, labels)  # 计算文本损失loss_I = cross_entropy(logits.T, labels.T)  # 计算图像损失total_loss = (loss_T + loss_I) / 2  # 对比学习平均损失return total_loss, logits### 训练函数 ###
def train(model, optimizer, scheduler, train_loader, device):model.train()  # 模型设置为训练模式train_loss = 0train_loader = tqdm(train_loader, total=len(train_loader))  # 显示训练进度条cnt = 0for batch in train_loader:# print(batch.keys())cnt += 1batch = {k: v.to(device) for k, v in batch.items() if k != "caption"}  # 将dataloader中一个batch的数据转换为字典形式loss, _ = model(batch)optimizer.zero_grad()loss.backward()optimizer.step()scheduler.step(metrics=loss.item())  # 根据上次训练的损失更新学习率train_loss += loss.item()# 训练100个batch显示一次lossif cnt % 100 == 0:print(f' ==> Epoch: {epoch + 1}, Batch: {cnt}, Loss: {loss.item():.4f}')return train_loss / len(train_loader)  # 平均训练损失### 测试函数 ###
def eval(model, val_loader, device):model.eval()  # 模型设置为测试模式val_loss = 0val_loader = tqdm(val_loader, total=len(val_loader))with torch.no_grad():for batch in val_loader:batch = {k: v.to(device) for k, v in batch.items() if k != "caption"}loss, _ = model(batch)val_loss += loss.item()return val_loss / len(val_loader)  # 平均测试损失if __name__ == '__main__':config = CLIPConfig()  # 实例化配置信息model = CLIP(config)  # 实例化CLIP模型device = "cuda" if torch.cuda.is_available() else "cpu"model = model.to(device)# 查看模型的总参数量total_params = sum(p.numel() for p in model.parameters())print(f"Total parameters: {total_params / 1e6} M")optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-3)scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", patience=2, factor=0.5)dataset = CLIPDataset(config, args.image_dir, args.caption_dir)  # 读取并预处理数据train_dataset, val_dataset = torch.utils.data.random_split(dataset, [0.8, 0.2])  # 80%为训练数据,20%为测试数据dataloader = DataLoader(dataset, batch_size=config.batch_size, shuffle=False)train_loader = DataLoader(train_dataset, batch_size=config.batch_size, shuffle=True)val_loader = DataLoader(val_dataset, batch_size=config.batch_size, shuffle=False)# 开始训练best_loss = float("inf")for epoch in range(config.epochs):print(f"Epoch: {epoch + 1}")train_loss_avg = train(model, optimizer, scheduler, train_loader, device)val_loss_avg = eval(model, val_loader, device)if val_loss_avg < best_loss:best_loss = val_loss_avgtorch.save(model.state_dict(), f'{args.weight_dir}' + f'/CLIP_{epoch}.pth')print("Best model saved!")# 图像文本检索推理并可视化# dataframe = pd.read_csv(f"{config.caption_path}/captions.csv")# tokenizer = DistilBertTokenizer.from_pretrained(config.text_tokenizer)# model.load_state_dict(torch.load(f'{args.weight_dir}' + f'/CLIP_1.pth', map_location=device))# model.eval()# # image_embeddings = []# with torch.no_grad():#     for batch in tqdm(dataloader):#         image_features = model.image_encoder(batch["image"].to(device))  # 获取图像特征#         cur_image_embeddings = model.image_proj(image_features)  # [batch_size, proj_dim]  # 图像特征投影#         image_embeddings.append(cur_image_embeddings)  # 将一个batch的图像特征保存# # image_embeddings = torch.cat(image_embeddings, dim=0)  # [image_number, proj_dim]# input_query = "two dogs sitting on the grass"  # 输入文本# image_filenames = dataframe["image"].values  # 待检索的图片# # encoded_query = tokenizer([input_query])  # 对输入文本进行分词# batch = {key: torch.tensor(values).to(device) for key, values in encoded_query.items()}# # with torch.no_grad():#     text_features = model.text_encoder(batch["input_ids"], batch["attention_mask"])  # 获取文本特征#     text_embeddings = model.text_proj(text_features)  # 文本特征投影,与图像特征维度一致# # image_embeddings_n = F.normalize(image_embeddings, dim=-1)  # [image_number, proj_dim]# text_embeddings_n = F.normalize(text_embeddings, dim=-1)  # [1, proj_dim]# dot_similarity = text_embeddings_n @ image_embeddings_n.T  # 输入文本的特征和数据集中每张图像特征之间的相似度# # values, indices = torch.topk(dot_similarity.squeeze(0), k=45)  # 获取前45个相似度最高的图像# matches = [image_filenames[idx] for idx in indices[::5]]  # 获取对应的图像文件名(9张图像)# # f, axes = plt.subplots(3, 3, figsize=(10, 10))# f.suptitle(f"Retrieving text: {input_query}")  # 设置主标题# for match, ax in zip(matches, axes.flatten()):  # 显示检索出的图像#     image = cv2.imread(f"{args.image_dir}/{match}")#     image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)#     ax.imshow(image)#     ax.axis("off")# # plt.show()

理想结果:

在这里插入图片描述

参考链接

https://towardsdatascience.com/simple-implementation-of-openai-clip-model-a-tutorial-ace6ff01d9f2/

相关文章:

从零开始搭建CLIP模型实现基于文本的图像检索

目录 CLIP原理简介代码实现参考链接 CLIP原理简介 论文链接&#xff0c;源码链接 CLIP模型由OpenAI在2021年提出&#xff0c;利用双Decoder&#xff08;Dual Encoder&#xff09;的架构来学习图像和文本之间的对应关系&#xff0c;是多模态大模型的开创之作&#xff0c;为后续许…...

健康养生之道

在快节奏的现代生活中&#xff0c;健康养生不再是中老年人的专属话题&#xff0c;越来越多的人开始意识到&#xff0c;合理的养生方式是保持良好身体状态和生活质量的关键。​ 饮食养生是健康的基石。遵循 “食物多样、谷类为主” 的原则&#xff0c;保证每天摄入足够的蔬菜、…...

基于autoware.1.14与gazebo联合仿真进行Hybrid A* 算法规划控制代价地图版

1.首先安装autoware &#xff0c;大家可以以下一下博客进行安装&#xff0c;如果缺少库什么的直接问ai安装对应的库就行。ubuntu18.04安装Autoware1.14---GPU版 最全环境配置说明_autoware1.14安装教程-CSDN博客 安装成功后运行&#xff1a; source install/setup.bash roslau…...

5G基站设计难题:尺寸、重量、功耗和散热

设计5G基站的工程师们必须应对能源消耗、重量、尺寸和散热等问题&#xff0c;这些因素会影响到设计决策。 5G新空口&#xff08;NR&#xff09;采用了多用户大规模多输入多输出&#xff08;MU-MIMO&#xff09;技术、集成接入与回传&#xff08;IAB&#xff09;技术&#xff0…...

【leetcode100】分割等和子集

1、题目描述 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5, 5] 和 [11…...

sed命令笔记250419

sed命令笔记250419 sed&#xff08;Stream Editor&#xff09;是 Linux/Unix 系统中强大的流编辑器&#xff0c;主要用于对文本进行过滤和转换&#xff08;按行处理&#xff09;。它支持正则表达式&#xff0c;适合处理文本替换、删除、插入等操作。以下是 sed 的详细解析&…...

LinearLayout 线性布局

目录 Android LinearLayout&#xff08;线性布局&#xff09;简单介绍与使用示例 一、效果介绍 二、布局文件&#xff08;XML&#xff09; 三、Java 代码 四、程序运行效果 五、总结 在 Android 移动应用开发中&#xff0c;LinearLayout&#xff08;线性布局&#xff09;…...

System.in 详解

System.in 详解 System.in 是 Java 提供的标准输入流&#xff08;InputStream 类型&#xff09;&#xff0c;默认关联键盘输入&#xff0c;通常用于从控制台读取用户输入。由于它是字节流&#xff08;InputStream&#xff09;&#xff0c;直接使用较麻烦&#xff0c;一般会配合…...

JAVA IO、BIO、NIO、AIO及零拷贝

概述 IO,常写作 I/O,是 Input/Output 的简称,是 Input/Output 的简称,即输入/输出。通常指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其他周边设备之间的输入和输出。 目前有三种 IO 共存。分别是 BIO、NIO 和 AIO。 BIO 全称 Block-IO 是一种同步且阻塞的…...

AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年4月19日第57弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀6-8个和值&#xff0c;可以做到100-300注左右。 (1)定…...

REST 架构详解:从概念到应用的全面剖析

REST&#xff08;Representational State Transfer&#xff09;即表述性状态转移&#xff0c;是一种用于构建网络应用程序的架构风格和设计理念&#xff0c;由计算机科学家罗伊・菲尔丁&#xff08;Roy Fielding&#xff09;在 2000 年提出。以下是关于它的详细介绍&#xff1a…...

SICAR程序标准功能块 FB1512 “Robot_kuka_FB“

1、FB1512功能块截图 2、FB1512 功能块引脚功能定义 一、输入引脚 EN:使能输入,决定功能块是否执行。IDENTIFIER(WSTRING#"FW010_R01"):设备标识,指定关联的机器人设备。OPMODE_USER_INTERFACE_OUT:操作模式输入,定义机器人工作模式(如手动、自动),数据源…...

win安装软件

win安装软件 jdk安装 jdk安装 首先去官网下载适合系统版本的JDK&#xff0c;下载地址&#xff1a; http://www.oracle.com/technetwork/java/javase/downloads/index.html进入下载页面&#xff0c;如下图&#xff1a; 首先选择&#xff1a;Accept License Agreement单选按钮&…...

文本生成与采样策略 (Text Generation Sampling)

我们已经学习了如何构建和训练一个基于 Transformer Decoder-only 的语言模型。模型训练的目标是学习预测给定前缀下下一个 token 的概率分布。但是,训练完成后,我们如何利用这个模型来生成全新的、连贯的文本呢? 这就涉及到推理过程和采样策略。推理是模型投入实际使用、生…...

为什么 waitress 不支持 WebSocket?

waitress 是一个纯 Python 实现的 WSGI 服务器&#xff0c;主要用于生产环境部署 Python Web 应用。但它不支持 WebSocket 协议&#xff0c;因为它只实现了 WSGI 规范&#xff0c;而 WebSocket 协议需要 ASGI&#xff08;Asynchronous Server Gateway Interface&#xff09;支持…...

[C++] 高精度加法(作用 + 模板 + 例题)

高精度加法-目录 高精度加法用途高精度加法模板string转数位数组int 转数位数组(附加型知识点)高精度输出高精度加法函数大合集!!! 高精度加法用途 高精度加法通常用于加很大的数(真的很大, 超unsigned long long的那种). 高精度加法模板 注: 本篇数组下标0(x[0])存储的是该…...

python程序的流程

三大基本流程&#xff1a; 顺序结构、分支结构&#xff08;又称为选择结构&#xff09;、循环结构 分支结构又分为单分支、双分支、多分支 从键盘上输入一个数字&#xff0c;并输出奇数或偶数 #从键盘上输入一个数字&#xff0c;并输出奇数或偶数 nint(input("n ")…...

基于大模型的下肢静脉曲张全流程预测与诊疗方案研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 1.3 研究方法与数据来源 二、下肢静脉曲张概述 2.1 定义与病理生理 2.2 风险因素与临床表现 2.3 诊断方法与现有治疗手段 三、大模型预测原理与构建 3.1 大模型技术简介 3.2 预测模型的数据收集与预处理 3.…...

Android 应用wifi direct连接通信实现

一. 打开Wi-Fi direct 1.必须启用Wi-Fi功能&#xff1a;在设备设置中开启Wi-Fi主开关&#xff08;即使未连接路由器&#xff09; 关闭冲突功能&#xff1a;若已开启「热点共享」或连接到其他Wi-Fi网络&#xff0c;需先关闭相关功能以避免硬件占. <!-- Wi-Fi Direct 核心权限…...

AI写代码工具分享:Cursor 高效使用攻略与实战秘籍

写在前面 在软件开发领域,效率和生产力是永恒的追求。集成开发环境(IDE)作为开发者的核心工具,其能力直接影响着开发速度和质量。近年来,人工智能(AI)的浪潮席卷了各个行业,编程领域也不例外。Cursor IDE 正是这股浪潮中的佼佼者,它以 AI-First 的理念,在广受欢迎的…...

关于viewpager常见的泄漏

在一个页面中 如果有用到tab&#xff0c;有需要进行fragment的切换&#xff0c;经常就看到了private var fragments arrayListOf<Fragment>()private fun initFragment() {arguments?.let {hopeToPosition it.getInt(IntentConstant.MAIN_PAGE_GO, 0)workoutType it.…...

vue3专题1------父组件中更改子组件的属性

理解 Vue 3 中父组件如何引用子组件的属性是一个很重要的概念。 这里涉及到 defineExpose 和 ref 这两个关键点。 方法&#xff1a;使用 defineExpose 在子组件中暴露属性&#xff0c;然后在父组件中使用 ref 获取子组件实例并访问暴露的属性。 下面我将详细解释这个过程&…...

代谢组数据分析(二十四):基于tidymass包从质谱原始数据到代谢物注释结果的实践指南

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据准备原始数据处理导入massDataset数据对象交互图数据探索更新样本表格信息峰分布情况缺失值情况数据清洗数据质量评估去除噪声代谢特征过滤立群样本填补缺失值数据标准化…...

Java使用javacv实现的多种音视频格式播放器

一、前言 最近写了一款图形界面版的音视频播放器&#xff0c;可以支持多种音视频格式的播放&#xff0c;比如MP4、avi、mkv、flv、MP3、ogg、wav等多种格式&#xff0c;非常好用&#xff0c;可以本地打开多种格式音视频。 二、实现 1.通过引入javacv相关依赖实现&#xff0c;如…...

csdn教程

hello,大家好&#xff0c;我是黑名单小羊&#xff0c;今天给大家分享一下csdn怎么换背景喵~ 成品&#xff1a; 首先&#xff0c;点击管理博文喵~ 然后&#xff0c;把任务栏往下翻喵~ 你就会看见博客设置&#xff0c;点击喵~ 再点击等级&#xff0c;如果你开通了 vip&#xff0…...

React 第三十三节 ReactRouter 中 useSearchParams 使用详解及注意事项

一、useSearchParams 定义 基本用法 定义&#xff1a;用于返回当前 URL 的 URLSearchParams 的元组和用于更新它们的函数。设置 search params 会导致导航。 import { useSearchParams } from react-router-dom export default function orderCenter() {const [searchParams,…...

@EnableAsync+@Async源码学习笔记之四

接上一篇&#xff0c;我们进入 AsyncAnnotationAdvisor 的分析&#xff0c;源码如下&#xff1a; package org.springframework.scheduling.annotation;import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.LinkedHashSet; import java.util…...

【java实现+4种变体完整例子】排序算法中【快速排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是快速排序的详细解析&#xff0c;包含基础实现、常见变体的完整代码示例&#xff0c;以及各变体的对比表格&#xff1a; 一、快速排序基础实现 原理 通过分治法选择一个基准元素&#xff08;pivot&#xff09;&#xff0c;将数组分为两部分&#xff1a; 左边元素均小于…...

MAUI项目iOS应用以进 App Store 分发

目录 一.通过Visual Studio分发应用1. 登录Apple 开发者帐户到 Visual Studio2.创建分发证书和配置文件3. 分发应用4. 在App Store Connect 中创建应用程序记录5. 如果你想使用mac发布应用 一.通过Visual Studio分发应用 1. 登录Apple 开发者帐户到 Visual Studio 首先我们要…...

Linux——firewalld防火墙(笔记)

目录 一&#xff1a;Firewalld防火墙的概述 &#xff08;1&#xff09;firewalld简介 &#xff08;2&#xff09;firewalld&iptables的关系 &#xff08;3&#xff09;firewalld与iptables service的区别 1. ‌规则管理方式‌ 2. ‌默认策略与设计逻辑‌ 3. ‌配置文…...

SICAR标准功能块 FB1514 “Robot_request_FB”

1、功能块截图 2、引脚功能描述 输入引脚: EN:使能输入,控制功能块运行。PLANT_IDENTIFIER:工厂或设备标识符(如 #FWO10_RO1_SEGM_201),用于标识操作对象。OPMODE_USER:操作模式输入(用户模式)。INTERFACE_OUT:连接系统数据库的操作模式接口(SYSTEM_DB.OPmode[2].U…...

vue3 watch和watchEffect 的用法和区别

在 Vue 3 里&#xff0c;watch 和 watchEffect 都是用于响应式数据变化的 API&#xff0c;但它们在使用方法和应用场景上存在差异。下面详细介绍它们的用法和区别。 用法 watch watch 用于监听特定的响应式数据源&#xff0c;当数据源发生变化时&#xff0c;会执行相应的回调…...

Linux | I.MX6ULL 使用 Yocto 文件系统开发 QT

01 Yocto 文件系统默认支持了 QT,那么我们要怎么在 Yocto 文件系统来运行我们的 QT 程序呢?本章节我们就来学习上在 yocto 文件系统+Ubuntu 环境来开发 QT 程序。 注意,开发环境是基于“qtcreator-3.5.1”(Ubuntu16.04.6),库文件是Qt5.5.1 02 QT 安装 (1)首先我们…...

论文阅读:2024 ICLR Workshop. A STRONGREJECT for Empty Jailbreaks

总目录 大模型安全相关研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 A STRONGREJECT for Empty Jailbreaks https://arxiv.org/pdf/2402.10260 https://github.com/dsbowen/strong_reject https://strong-reject.readthedocs.io/en/latest/ …...

数据结构实验7.2:二叉树的基本运算

文章目录 一&#xff0c;实验目的二&#xff0c;问题描述三&#xff0c;基本要求四&#xff0c;实验操作五&#xff0c;示例代码六&#xff0c;运行效果 一&#xff0c;实验目的 深入理解树与二叉树的基本概念&#xff0c;包括节点、度、层次、深度等&#xff0c;清晰区分二叉…...

关于一对多关系(即E-R图中1:n)中的界面展示优化和数据库设计

前言 一对多&#xff0c;是常见的数据库关系。在界面设计时&#xff0c;有时为了方便&#xff0c;就展示成逗号分割的字符串。例如&#xff1a;学生和爱好的界面。 存储 如果是简单存储&#xff0c;建立数据库&#xff1a;爱好&#xff0c;课程&#xff0c;存在一张表中。 但…...

Jenkins设置中文显示

1 安装插件 依次进入菜单&#xff1a; Jenkins -> Manage Jenkins -> Plugin Manager -> Avaliable 1.1 安装插件Locale plugin 1.2 安装插件Localization: Chinese&#xff08;Simplified&#xff09; 2 修改配置 点击菜单Manage Jenkins进入系统管理 点击菜单C…...

【MATLAB海洋专题】历史汇总

【MATLAB海洋专题】历史汇总 目录 01&#xff1a;海洋专题进阶教学 02&#xff1a;海洋数据处理 03&#xff1a;海洋数据下载 04&#xff1a;海洋配色 05&#xff1a;海洋专题基础教学 06: 其他基础画图 07&#xff1a;python 画海图专题 08&#xff1a;模式相关文件制作 01…...

【java实现+4种变体完整例子】排序算法中【归并排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是归并排序的详细解析&#xff0c;包含基础实现、常见变体的完整代码示例&#xff0c;以及各变体的对比表格&#xff1a; 一、归并排序基础实现 原理 通过分治法将数组分为两半&#xff0c;递归排序子数组&#xff0c;最后合并有序子数组。 代码示例 public class Mer…...

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

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

spring-batch批处理框架(2)

文章目录 八、作业控制8.1 作业启动8.1.1 SpringBoot 启动8.1.2 Spring 单元测试启动8.1.3 RESTful API 启动 8.2 作业停止方案1&#xff1a;Step 步骤监听器方式方案2&#xff1a;StepExecution停止标记 8.3 作业重启8.3.1 禁止重启8.3.2 限制重启次数8.3.3 无限重启 九、Item…...

[Java · 初窥门径] Java 注释符

&#x1f31f; 想系统化学习 Java 编程&#xff1f;看看这个&#xff1a;[编程基础] Java 学习手册 0x01&#xff1a;Java 注释符简介 在编写程序时&#xff0c;为了使代码易于理解&#xff0c;通常会为代码加一些注释。Java 注释就是用通俗易懂的语言对代码进行描述或解释&a…...

linux下C++性能调优常用的工具

性能优化的常见流程 发现问题--->定位问题--->解决问题--->验证问题 发现问题的常见工具 1.定位内存问题 top指令&#xff0c;发现占用内存多的线程 asan 发现内存问题。 2.定位cpu问题 top指令&#xff0c;发现占用cpu多的进程&#xff0c;线程 一般对内存和…...

MinnowBoard MAX单板UEFI BIOS代码编译教程

此教程用于UEFI EDK2代码的研究&#xff0c;虽然EDK2框架代码开源&#xff0c;但是都是在模拟器上跑仿真&#xff0c;差点意思&#xff0c;搞过嵌入式大的应该有一个共识&#xff0c;是骡子是马&#xff0c;你得把板子点亮啊。MinnowBoard MAX单板是intel10多年前发布的软硬件全…...

真实波幅策略思路

该策略是一种基于ATR&#xff08;Average True Range&#xff09;指标的交易策略&#xff0c;主要用于期货市场中的日内交易。策略的核心思想是利用ATR指标来识别市场的波动范围&#xff0c;并结合均线过滤来确定买入和卖出的时机。 交易逻辑思维 1. 数据准备与初始化 - 集合竞…...

【每天一个知识点】模式识别

“模式识别”是一种从数据中识别出规律、结构或趋势的技术&#xff0c;它广泛应用于人工智能、机器学习、图像处理、语音识别、自然语言处理等领域。简单来说&#xff0c;就是让计算机学会“看出”数据中的规律&#xff0c;比如&#xff1a; 从图像中识别人脸&#xff08;人脸识…...

Node.js 创建 HTTP 服务端

Node.js 创建 HTTP 服务端的用法总结&#xff0c;内容涵盖了 核心模块、基本用法、Express 简化用法、常见场景、错误处理、以及实用小贴士。 ✅ 一、Node.js 创建 HTTP 服务的方式 Node.js 使用内置的 http 模块即可快速创建一个 Web 服务&#xff0c;无需额外安装依赖。 ✅ …...

深入浅出伯努利分布:从 0‑1 随机世界到统计学习基石

深入浅出伯努利分布&#xff1a;从 0‑1 随机世界到统计学习基石 “当你能把一个问题拆解成一系列“是/否”答案时&#xff0c;伯努利分布就是第一块砖。” 目录 引言&#xff1a;伯努利分布为何如此重要&#xff1f;历史回顾&#xff1a;从赌博到信息论形式化定义与基本表示三…...

x-ui重新申请ssl证书失败

由于某些需要我们重新申请ssl证书&#xff0c;x-ui自动化脚本不能强制更新&#xff0c;根据x-ui仓库源码&#xff1a; https://github.com/vaxilu/x-ui/blob/main/x-ui.sh 在申请ssl证书的地方稍作修改&#xff0c;得到&#xff0c;运行下面的脚本就可以重新申请ssl证书&#…...

Python Requests 库:从安装到精通

摘要 本文详细介绍 Python Requests 库的安装与使用&#xff0c;通过常见示例让你轻松掌握。 一、引言 在当今的互联网时代&#xff0c;与各种 Web 服务进行交互是非常常见的需求。Python 作为一门功能强大且易于学习的编程语言&#xff0c;提供了许多用于网络请求的库&…...