【AIGC系列】4:Stable Diffusion应用实践和代码分析
AIGC系列博文:
【AIGC系列】1:自编码器(AutoEncoder, AE)
【AIGC系列】2:DALL·E 2模型介绍(内含扩散模型介绍)
【AIGC系列】3:Stable Diffusion模型原理介绍
【AIGC系列】4:Stable Diffusion应用实践和代码分析
【AIGC系列】5:视频生成模型数据处理和预训练流程介绍(Sora、MovieGen、HunyuanVideo)
目录
- 1 AutoEncoder
- 2 CLIP text encoder
- 3 UNet
- 4 应用
- 4.1 文生图
- 4.2 图生图
- 4.3 图像inpainting
- 5 其他
上一篇博文我们学习了Stable Diffusion的原理,这一篇我们继续深入了解Stable Diffusion的应用实践和代码分析。
1 AutoEncoder
SD采用基于KL-reg的autoencoder,当输入图像为512x512时将得到64x64x4大小的latent。autoencoder模型是在OpenImages数据集上基于256x256大小训练的,但是由于模型是全卷积结构的(基于ResnetBlock),所以可以扩展应用在尺寸>256的图像上。
下面我们使用diffusers库来加载autoencoder模型,实现图像的压缩和重建,代码如下:
import torch
from diffusers import AutoencoderKL
import numpy as np
from PIL import Imageprint(torch.cuda.is_available())#加载模型: autoencoder可以通过SD权重指定subfolder来单独加载
print("Start...")
autoencoder = AutoencoderKL.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="vae")
autoencoder.to("cuda", dtype=torch.float16)
print("Get weight successfully")# 读取图像并预处理
# raw_image = Image.open("liuyifei.jpg").convert("RGB").resize((256, 256))
raw_image = Image.open("liuyifei.jpg").convert("RGB")
image = np.array(raw_image).astype(np.float32) / 127.5 - 1.0
image = image[None].transpose(0, 3, 1, 2)
image = torch.from_numpy(image) # 压缩图像为latent并重建
with torch.inference_mode(): latent = autoencoder.encode(image.to("cuda", dtype=torch.float16)).latent_dist.sample() rec_image = autoencoder.decode(latent).sample rec_image = (rec_image / 2 + 0.5).clamp(0, 1) rec_image = rec_image.cpu().permute(0, 2, 3, 1).numpy() rec_image = (rec_image * 255).round().astype("uint8") rec_image = Image.fromarray(rec_image[0]) rec_image.save("liuyifei_re.jpg")
重建效果如下所示,对比手表上的文字,可以看出,autoencoder将图片压缩到latent后再重建其实是有损的。
为了改善这种畸变,stabilityai在发布SD 2.0时同时发布了两个在LAION子数据集上精调的autoencoder,注意这里只精调autoencoder的decoder部分,SD的UNet在训练过程只需要encoder部分,所以这样精调后的autoencoder可以直接用在先前训练好的UNet上(这种技巧还是比较通用的,比如谷歌的Parti也是在训练好后自回归生成模型后,扩大并精调ViT-VQGAN的decoder模块来提升生成质量)。我们也可以直接在diffusers中使用这些autoencoder,比如mse版本(采用mse损失来finetune的模型):
autoencoder = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse/")
2 CLIP text encoder
SD采用CLIP text encoder来对输入的文本生成text embeddings,采用的CLIP模型是clip-vit-large-patch14,该模型的text encoder层数为12,特征维度为768,模型参数大小是123M。文本输入text encoder后得到最后的hidden states特征维度大小为77x768(77是token的数量),这个细粒度的text embeddings将以cross attention的方式输入UNet中。
在transofmers库中,使用CLIP text encoder的代码如下:
from transformers import CLIPTextModel, CLIPTokenizer text_encoder = CLIPTextModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="text_encoder").to("cuda")
# text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14").to("cuda")
tokenizer = CLIPTokenizer.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="tokenizer")
# tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14") # 对输入的text进行tokenize,得到对应的token ids
prompt = "a photograph of an astronaut riding a horse"
text_input_ids = tokenizer( prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt"
).input_idsprint(f" \n\n text_input_ids: {text_input_ids} \n\n")# 将token ids送入text model得到77x768的特征
text_embeddings = text_encoder(text_input_ids.to("cuda"))[0]
print(f" \n\n text_embeddings: {text_embeddings} \n\n")
输出如下:
text_input_ids: tensor([[49406, 320, 8853, 539, 550, 18376, 6765, 320, 4558, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,49407, 49407, 49407, 49407, 49407, 49407, 49407]])text_embeddings: tensor([[[-0.3884, 0.0229, -0.0522, ..., -0.4899, -0.3066, 0.0675],[ 0.0290, -1.3258, 0.3085, ..., -0.5257, 0.9768, 0.6652],[ 0.4595, 0.5617, 1.6663, ..., -1.9515, -1.2307, 0.0104],...,[-3.0421, -0.0656, -0.1793, ..., 0.3943, -0.0190, 0.7664],[-3.0551, -0.1036, -0.1936, ..., 0.4236, -0.0189, 0.7575],[-2.9854, -0.0832, -0.1715, ..., 0.4355, 0.0095, 0.7485]]],device='cuda:0', grad_fn=<NativeLayerNormBackward0>)
值得注意的是,这里的tokenizer最大长度为77(CLIP训练时所采用的设置),当输入text的tokens数量超过77后,将进行截断,如果不足则进行paddings,这样将保证无论输入任何长度的文本(甚至是空文本)都得到77x768大小的特征。在上面的例子里,输入的tokens数量少于77,所以后面都padding了id为49407的token。
在训练SD的过程中,CLIP text encoder模型是冻结的。在早期的工作中,比如OpenAI的GLIDE和latent diffusion中的LDM均采用一个随机初始化的tranformer模型来提取text的特征,但是最新的工作都是采用预训练好的text model。比如谷歌的Imagen采用纯文本模型T5 encoder来提出文本特征,而SD则采用CLIP text encoder,预训练好的模型往往已经在大规模数据集上进行了训练,它们要比直接采用一个从零训练好的模型要好。
3 UNet
SD的扩散模型是一个860M的UNet,其主要结构如下图所示,其中encoder部分包括3个CrossAttnDownBlock2D模块和1个DownBlock2D模块,而decoder部分包括1个UpBlock2D模块和3个CrossAttnUpBlock2D模块,中间还有一个UNetMidBlock2DCrossAttn模块。
encoder和decoder两个部分是完全对应的,中间有skip connection。3个CrossAttnDownBlock2D模块最后均有一个2x的downsample操作,而DownBlock2D模块是不包含下采样的。
其中CrossAttnDownBlock2D模块的主要结构如下图所示,text condition将通过CrossAttention模块嵌入进来,此时Attention的query是UNet的中间特征,而key和value则是text embeddings。
SD和DDPM一样采用预测noise的方法来训练UNet,其训练损失也和DDPM一样。基于diffusers库,我们可以实现SD的训练,其核心代码如下:
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image
from diffusers import AutoencoderKL, UNet2DConditionModel, DDPMScheduler
from transformers import CLIPTextModel, CLIPTokenizer
import torch.nn.functional as F# 自定义Dataset类
class CustomImageTextDataset(Dataset):def __init__(self, image_paths, text_descriptions, transform=None):self.image_paths = image_pathsself.text_descriptions = text_descriptionsself.transform = transformdef __len__(self):return len(self.image_paths)def __getitem__(self, idx):image_path = self.image_paths[idx]text_description = self.text_descriptions[idx]# 加载图像image = Image.open(image_path).convert("RGB")if self.transform:image = self.transform(image)return {'image': image,'text': text_description}# 数据准备
image_paths = ["path/to/image1.jpg", "path/to/image2.jpg"] # 替换为实际的图像路径
text_descriptions = ["description for image1", "description for image2"] # 替换为实际的文本描述# 图像转换(预处理)
transform = transforms.Compose([transforms.Resize((256, 256)), # 调整大小transforms.ToTensor(), # 转换为张量
])# 创建数据集实例
dataset = CustomImageTextDataset(image_paths=image_paths, text_descriptions=text_descriptions, transform=transform)# 创建DataLoader
train_dataloader = DataLoader(dataset, batch_size=4, shuffle=True, num_workers=0)# 加载autoencoder
vae = AutoencoderKL.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="vae")
# 加载text encoder
text_encoder = CLIPTextModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="text_encoder")
tokenizer = CLIPTokenizer.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="tokenizer")model_config = {"sample_size": 32,"in_channels": 4,"out_channels": 4,"down_block_types": ("DownBlock2D", "CrossAttnDownBlock2D", "CrossAttnDownBlock2D", "CrossAttnDownBlock2D"),"up_block_types": ("UpBlock2D", "CrossAttnUpBlock2D", "CrossAttnUpBlock2D", "CrossAttnUpBlock2D"),"block_out_channels": (320, 640, 1280, 1280),"layers_per_block": 2,"cross_attention_dim": 768,"attention_head_dim": 8,
}
# 初始化UNet
unet = UNet2DConditionModel(**model_config)# 定义scheduler
noise_scheduler = DDPMScheduler(beta_start=0.00085,beta_end=0.012,beta_schedule="scaled_linear",num_train_timesteps=1000
)# 冻结vae和text_encoder
vae.requires_grad_(False)
text_encoder.requires_grad_(False)opt = torch.optim.AdamW(unet.parameters(), lr=1e-4)# 训练循环
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
unet.to(device)
vae.to(device)
text_encoder.to(device)for epoch in range(10): # 假设训练10个epochunet.train()for step, batch in enumerate(train_dataloader):with torch.no_grad():# 将image转到latent空间latents = vae.encode(batch["image"].to(device)).latent_dist.sample()# rescaling latentslatents = latents * vae.config.scaling_factor# 提取text embeddingstext_input_ids = tokenizer(batch["text"],padding="max_length",max_length=tokenizer.model_max_length,truncation=True,return_tensors="pt").input_ids.to(device)text_embeddings = text_encoder(text_input_ids)[0]# 随机采样噪音noise = torch.randn_like(latents)bsz = latents.shape[0]# 随机采样timesteptimesteps = torch.randint(0, noise_scheduler.num_train_timesteps, (bsz,), device=device).long()# 将noise添加到latent上,即扩散过程noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps)# 预测noise并计算lossmodel_pred = unet(noisy_latents, timesteps, encoder_hidden_states=text_embeddings).sampleloss = F.mse_loss(model_pred.float(), noise.float(), reduction="mean")opt.zero_grad()loss.backward()opt.step()if step % 10 == 0:print(f"Epoch {epoch}, Step {step}, Loss: {loss.item()}")# 在训练完成后保存模型
model_save_path = 'path/to/your/unet_model.pth'
torch.save(unet.state_dict(), model_save_path)
print(f"Model has been saved to {model_save_path}")optimizer_save_path = 'path/to/your/optimizer.pth'
torch.save(opt.state_dict(), optimizer_save_path)
print(f"Optimizer state has been saved to {optimizer_save_path}")# 加载模型进行推理或继续训练
unet_load_path = 'path/to/your/unet_model.pth'
unet_loaded = UNet2DConditionModel(**model_config) # 创建一个与原模型结构相同的实例
unet_loaded.load_state_dict(torch.load(unet_load_path))
unet_loaded.to(device)
unet_loaded.eval() # 设置为评估模式# 恢复优化器的状态以继续训练
opt_load_path = 'path/to/your/optimizer.pth'
opt_loaded = torch.optim.AdamW(unet_loaded.parameters(), lr=1e-4) # 创建一个新的优化器实例
opt_loaded.load_state_dict(torch.load(opt_load_path))# 使用unet_loaded进行推理或者用opt_loaded继续训练。
注意的是SD的noise scheduler虽然也是采用一个1000步长的scheduler,但是不是linear的,而是scaled linear,具体的计算如下所示:
betas = torch.linspace(beta_start**0.5, beta_end**0.5, num_train_timesteps, dtype=torch.float32) ** 2
在训练条件扩散模型时,往往会采用Classifier-Free Guidance (CFG),即在训练条件扩散模型的同时也训练一个无条件的扩散模型,同时在采样阶段将条件控制下预测的噪音和无条件下的预测噪音组合在一起来确定最终的噪音,CFG对于提升条件扩散模型的图像生成效果是至关重要的。
4 应用
4.1 文生图
根据文本生成图像是文生图的最核心的功能,SD的文生图的推理流程图:首先根据输入text用text encoder提取text embeddings,同时初始化一个随机噪音noise(latent上的,512x512图像对应的noise维度为64x64x4),然后将text embeddings和noise送入扩散模型UNet中生成去噪后的latent,最后送入autoencoder的decoder模块得到生成的图像。
使用diffusers库,我们可以直接调用StableDiffusionPipeline来实现文生图,具体代码如下所示:
import torch
from diffusers import StableDiffusionPipeline
from PIL import Image # 组合图像,生成grid
def image_grid(imgs, rows, cols): assert len(imgs) == rows*cols w, h = imgs[0].size grid = Image.new('RGB', size=(cols*w, rows*h)) grid_w, grid_h = grid.size for i, img in enumerate(imgs): grid.paste(img, box=(i%cols*w, i//cols*h)) return grid # 加载文生图pipeline
pipe = StableDiffusionPipeline.from_pretrained( "runwayml/stable-diffusion-v1-5", # 或者使用 SD v1.4: "CompVis/stable-diffusion-v1-4" torch_dtype=torch.float16
).to("cuda") # 输入text,这里text又称为prompt
prompts = [ "a photograph of an astronaut riding a horse", "A cute otter in a rainbow whirlpool holding shells, watercolor", "An avocado armchair", "A white dog wearing sunglasses"
] generator = torch.Generator("cuda").manual_seed(42) # 定义随机seed,保证可重复性 # 执行推理
images = pipe( prompts, height=512, width=512, num_inference_steps=50, guidance_scale=7.5, negative_prompt=None, num_images_per_prompt=1, generator=generator
).images # 保存每个单独的图片
for idx, img in enumerate(images):img.save(f"image_{idx}.png")# 创建并保存组合后的网格图
grid = image_grid(images, rows=1, cols=len(prompts))
grid.save("combined_images.png")
print("所有图片已保存到本地。")
生成的结果如下:
重要参数说明:
-
指定width和height来决定生成图像的大小:前面说过SD最后是在512x512尺度上训练的,所以生成512x512尺寸效果是最好的,但是实际上SD可以生成任意尺寸的图片:一方面autoencoder支持任意尺寸的图片的编码和解码,另外一方面扩散模型UNet也是支持任意尺寸的latents生成的(UNet是卷积+attention的混合结构)。但是生成512x512以外的图片会存在一些问题,比如生成低分辨率图像时,图像的质量大幅度下降等等。
-
num_inference_steps:指推理过程中的去噪步数或者采样步数。SD在训练过程采用的是步数为1000的noise scheduler,但是在推理时往往采用速度更快的scheduler:只需要少量的采样步数就能生成不错的图像,比如SD默认采用PNDM scheduler,它只需要采样50步就可以出图。当然我们也可以换用其它类型的scheduler,比如DDIM scheduler和DPM-Solver scheduler。我们可以在diffusers中直接替换scheduler,比如我们想使用DDIM:
from diffusers import DDIMScheduler # 注意这里的clip_sample要关闭,否则生成图像存在问题,因为不能对latent进行clip
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config, clip_sample=False)
-
guidance_scale:当CFG的guidance_scale越大时,生成的图像应该会和输入文本更一致。SD默认采用的guidance_scale为7.5。但是过大的guidance_scale也会出现问题,主要是由于训练和测试的不一致,过大的guidance_scale会导致生成的样本超出范围。
-
negative_prompt:这个参数和CFG有关,去噪过程的噪音预测不仅仅依赖条件扩散模型,也依赖无条件扩散模型,这里的negative_prompt便是无条件扩散模型的text输入,前面说过训练过程中我们将text置为空字符串来实现无条件扩散模型,所以这里negative_prompt = None 。但是有时候我们可以使用不为空的negative_prompt来避免模型生成的图像包含不想要的东西,因为从上述公式可以看到这里的无条件扩散模型是我们想远离的部分。
4.2 图生图
图生图(image2image)是对文生图功能的一个扩展,这个功能来源于SDEdit这个工作,其核心思路也非常简单:给定一个笔画的色块图像,可以先给它加一定的高斯噪音(执行扩散过程)得到噪音图像,然后基于扩散模型对这个噪音图像进行去噪,就可以生成新的图像,但是这个图像在结构和布局和输入图像基本一致。
相比文生图流程来说,这里的初始latent不再是一个随机噪音,而是由初始图像经过autoencoder编码之后的latent加高斯噪音得到,这里的加噪过程就是扩散过程。要注意的是,去噪过程的步数要和加噪过程的步数一致,就是说你加了多少噪音,就应该去掉多少噪音,这样才能生成想要的无噪音图像。
在diffusers中,我们可以使用StableDiffusionImg2ImgPipeline来实现文生图,具体代码如下所示:
import torch
from diffusers import StableDiffusionImg2ImgPipeline
from PIL import Image# 加载图生图pipeline
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda")# 读取初始图片
init_image = Image.open("liuyifei.jpg").convert("RGB").resize((512, 512))
print(init_image.size)
init_image.save("liuyifei_512.jpg")# 推理
prompt = "A girl wearing a hat on her head."
generator = torch.Generator(device="cuda").manual_seed(2023)image = pipe(prompt=prompt,image=init_image,strength=0.8,guidance_scale=7.5,generator=generator
).images[0]# 保存生成的图像
output_path = "generated_liuyifei.jpg"
image.save(output_path)
print(f"Generated image saved to {output_path}")
原始图片:
效果如下:
相比文生图的pipeline,图生图的pipeline还多了一个参数strength,这个参数介于0-1之间,表示对输入图片加噪音的程度,这个值越大加的噪音越多,对原始图片的破坏也就越大,当strength=1时,其实就变成了一个随机噪音,此时就相当于纯粹的文生图pipeline了。
4.3 图像inpainting
图像inpainting和图生图一样也是文生图功能的一个扩展。SD的图像inpainting不是用在图像修复上,而是主要用在图像编辑上:给定一个输入图像和想要编辑的区域mask,我们想通过文生图来编辑mask区域的内容。
它和图生图一样,首先将输入图像通过autoencoder编码为latent,然后加入一定的高斯噪音生成noisy latent,再进行去噪生成图像,但是这里为了保证mask以外的区域不发生变化,在去噪过程的每一步,都将扩散模型预测的noisy latent用真实图像同level的nosiy latent替换。
在diffusers中,使用StableDiffusionInpaintPipelineLegacy可以实现文本引导下的图像inpainting,具体代码如下所示:
import torch
from diffusers import StableDiffusionInpaintPipelineLegacy
from PIL import Image # 加载inpainting pipeline
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionInpaintPipelineLegacy.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda") # 读取输入图像和输入mask
input_image = Image.open("overture-creations-5sI6fQgYIuo.png").resize((512, 512))
input_mask = Image.open("overture-creations-5sI6fQgYIuo_mask.png").resize((512, 512)) # 执行推理
prompt = ["a mecha robot sitting on a bench", "a cat sitting on a bench"]
generator = torch.Generator("cuda").manual_seed(0) with torch.autocast("cuda"): images = pipe( prompt=prompt, image=input_image, mask_image=input_mask, num_inference_steps=50, strength=0.75, guidance_scale=7.5, num_images_per_prompt=1, generator=generator, ).images # 保存每个单独的图片
for idx, img in enumerate(images):img.save(f"image_{idx}.png")print("所有图片已保存到本地。")
5 其他
Colab上开源的Stable Diffusion 2.1 GUI:stable_diffusion_2_0.ipynb。
最强大且模块化的具有图形/节点界面的稳定扩散GUI:ComfyUI。
Huggingface模型库:https://huggingface.co/stabilityai。
Huggingface的Diffuser库:https://github.com/huggingface/diffusers。
相关文章:
【AIGC系列】4:Stable Diffusion应用实践和代码分析
AIGC系列博文: 【AIGC系列】1:自编码器(AutoEncoder, AE) 【AIGC系列】2:DALLE 2模型介绍(内含扩散模型介绍) 【AIGC系列】3:Stable Diffusion模型原理介绍 【AIGC系列】4࿱…...
【Python爬虫(81)】当量子计算邂逅Python爬虫:一场技术变革的预演
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发…...
Java Web应用中获取客户端的真实IP地址
Java Web应用中获取客户端的真实IP地址,尤其在存在代理服务器的情况下。 代码示例: public static String getClientIP(HttpServletRequest request) {String ip = parseCommaSeparatedIPs(request.getHeader("X-Forwarded-For"));if (isInvalid(ip)) {ip = pars…...
R语言+AI提示词:贝叶斯广义线性混合效应模型GLMM生物学Meta分析
全文链接:https://tecdat.cn/?p40797 本文旨在帮助0基础或只有简单编程基础的研究学者,通过 AI 的提示词工程,使用 R 语言完成元分析,包括数据处理、模型构建、评估以及结果解读等步骤(点击文末“阅读原文”获取完整代…...
LangChain原理解析及开发实战指南(2025年最新版)
一、LangChain核心架构解析 1.1 框架设计理念 LangChain是基于提示工程(Prompt Engineering)构建的LLM应用开发框架,其核心思想是通过模块化组件实现大语言模型与业务系统的无缝对接。该框架采用分层设计: 接口层:统一对接OpenAI、DeepSee…...
赋能农业数字化转型 雏森科技助力“聚农拼”平台建设
赋能农业数字化转型,雏森科技助力“聚农拼”平台建设 在数字化浪潮席卷各行业的今天,农业领域也在积极探索转型升级之路。中农集团一直以“根植大地,服务三农”为核心,以“乡村振兴,农民增收”为目标,及时…...
CMU15445(2023fall) Project #2 - Extendible Hash Index 匠心分析
胡未灭,鬓已秋,泪空流 此生谁料 心在天山 身老沧州 ——诉衷情 完整代码见: SnowLegend-star/CMU15445-2023fall: Having Conquered the Loftiest Peak, We Stand But a Step Away from Victory in This Stage. With unwavering determinati…...
深度剖析Seata源码:解锁分布式事务处理的核心逻辑
文章目录 写在文章开头如何使用源码(配置转掉)基于AT模式详解Seata全链路流程Seata服务端启动本地服务如何基于GlobalTransaction注解开启事务客户端如何开启分布式事务RM和TC如何协调处理分支事务RM生成回滚日志事务全局提交与回滚小结参考写在文章开头 在当今分布式系统日益…...
python配置mmcv与mmdet环境
首先查看自己的cuda版本 nvcc --version 安装与cuda对应的torch版本,对应关系 Previous PyTorch Versions | PyTorch 安装对应的mmcv版本,使用下面命令可以自动安装匹配的版本,使用mim安装 mim install mmcv-full -f https://download.o…...
ESP 32控制无刷电机2
import machine import time import socket import network from machine import I2C, Pin, ADC def start_ap(): """ 启动ESP32的AP模式 """ ap network.WLAN(network.AP_IF) ap.active(True) ssid ESP32_APTest …...
【uniapp原生】实时记录接口请求延迟,并生成写入文件到安卓设备
在开发实时数据监控应用时,记录接口请求的延迟对于性能分析和用户体验优化至关重要。本文将基于 UniApp 框架,介绍如何实现一个实时记录接口请求延迟的功能,并深入解析相关代码的实现细节。 前期准备&必要的理解 1. 功能概述 该功能的…...
wps角标快速生成
使用^#符号匹配数字,将[^#]内容找到,随后在格式-字体中选择上标,逐个/批量替换即可(比一点点改效率翻倍)...
Azure Speech
1、文字转语音(Text-To-Speech, TTS) 2、语音转文字(Speech-To-Text): Azure Speech to Text 1- 环境配置:Microsoft Azure 注册使用免费服务: 需要信用卡,本人没有,所以没有完成注册...
SHELL32!ILCombine函数分析之连接两个idl
SHELL32!ILCombine函数分析之连接两个idl 第一部分: STDAPI_(LPITEMIDLIST) ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { // Let me pass in NULL pointers if (!pidl1) { if (!pidl2) { return NULL; …...
学习threejs,使用ShaderMaterial自定义着色器材质
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.ShaderMaterial1.1.1…...
使用 Selenium 和 Requests 自动化获取动态 Referer 和 Sign 的完整指南
在现代网络爬虫和自动化任务中,动态生成的参数(如 Referer 和 Sign)常常是绕过反爬虫机制的关键。本文将详细介绍如何使用 Python 的 Selenium 和 Requests 库,从目标网页中提取动态 Referer 和 Sign,并完成后续的请求…...
1.2.3 使用Spring Initializr方式构建Spring Boot项目
本实战概述介绍了如何使用Spring Initializr创建Spring Boot项目,并进行基本配置。首先,通过Spring Initializr生成项目骨架,然后创建控制器HelloController,定义处理GET请求的方法hello,返回HTML字符串。接着…...
Cursor+pycharm接入Codeuim(免费版),Tab自动补全功能平替
如题,笔者在Cursor中使用pycharm写python程序,试用期到了Tab自动补全功能就不能用了,安装Codeuim插件可以代替这个功能。步骤如下: 1. 在应用商店中搜索扩展Codeuim,下载安装 2. 安装完成后左下角会弹出提示框&#x…...
Ruby基础
一、字符串 定义 283.to_s //转为string "something#{a}" //定义字符串,并且插入a变量的值 something//单引号定义变量 %q(aaaaaaaaa) // 定义字符串,()内可以是任何数,自动转义双引号%Q("aaaaa"…...
wzl-django学习
####################################################总的urls.py from django.contrib import admin from django.urls import path,include, re_path from django.views.static import serve from django.conf import settings from drf_yasg import openapi from drf_yas…...
《AI强化学习:元应用中用户行为引导的智能引擎》
在科技飞速发展的当下,元应用正以前所未有的速度融入我们的生活,从沉浸式的虚拟社交到高度仿真的工作模拟,元应用构建出一个个丰富多彩的虚拟世界。而在这背后,人工智能的强化学习技术宛如一位无形却强大的幕后推手,深…...
Django基础环境准备
Django基础环境准备 文章目录 Django基础环境准备1.准备的环境 win11系统(运用虚拟环境搭建)1.1详见我的资源win11环境搭建 2.准备python环境2.1 winr 打开命令提示符 输入cmd 进入控制台2.2 输入python --version 查看是否有python环境2.3在pyhton官网下…...
机器视觉线阵相机分时频闪选型/机器视觉线阵相机分时频闪选型
在机器视觉系统中,线阵相机的分时频闪技术通过单次扫描切换不同光源或亮度,实现在一幅图像中捕捉多角度光照效果,从而提升缺陷检测效率并降低成本。以下是分时频闪线阵相机的选型要点及关键考量因素: 一、分时频闪技术的核心需求 多光源同步控制 分时频闪需相机支持多路光源…...
【企业场景】上线的项目如何进行限流
一、常见的四种速率限流算法 对于限流,最为直接的就是速率限流了 固定窗口算法 比如 10r/s 就是把时间线分为 1s 一段,也就是周期为 1s,对一个时间段的请求进行计数,超过 10 则舍弃,未超过则直接处理经过 1s 后&…...
【FL0090】基于SSM和微信小程序的球馆预约系统
🧑💻博主介绍🧑💻 全网粉丝10W,CSDN全栈领域优质创作者,博客之星、掘金/知乎/b站/华为云/阿里云等平台优质作者、专注于Java、小程序/APP、python、大数据等技术领域和毕业项目实战,以及程序定制化开发…...
用大白话解释缓存Redis +MongoDB是什么有什么用怎么用
Redis和MongoDB是什么? Redis:像你家的“小冰箱”,专门存高频使用的食物(数据)。它是基于内存的键值数据库,读写速度极快(每秒超10万次操作)。比如你每次打开手机App,用…...
软件测试需求分析如何实施?专业软件测试服务公司分享
在现代软件开发中,软件测试需求分析被认为是确保软件质量的关键环节之一。软件测试需求分析是指在软件开发过程中,对测试需求进行系统性分析的过程。它旨在确定软件系统功能、性能及其他非功能性需求的具体细节,从而为后续的测试活动提供指导…...
pg pg_prewarm用法
按照插件 > create extension pg_prewarm ;缓存表 > test# select pg_prewarm(weather,buffer ) ; pg_prewarm > ------------ > 1缓存表部分内容 test# select pg_prewarm(weather,buffer,main,0,0) ;pg_prewarm ------------1 (1 row)表大小只有0号…...
2025年光电科学与智能传感国际学术会议(ICOIS 2025)
重要信息 官网:www.ic-icois.org 时间:2025年3月14-16日 地点:中国-长春 简介 2025年光电科学与智能传感国际学术会议(ICOIS 2025)将于2025年3月14-16日在中国-长春隆重召开。会议将围绕“光学光电”、“智能传感”…...
uni小程序wx.switchTab有时候跳转错误tab问题,解决办法
在一个子页面里面使用uni.switchTab或者wx.switchTab跳转到tab菜单的时候,先发送了一个请求,然后执行跳转到tab菜单,但是这个时候,出错了........也是非常的奇怪,不加请求就没问题......但是业务逻辑就是要先执行某个请…...
python-leetcode-下一个排列
31. 下一个排列 - 力扣(LeetCode) class Solution:def nextPermutation(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""# Step 1: Find the first decreasing element …...
如何获取mac os 安装盘
发现虚拟机VirtualBox支持Mac虚拟,就想尝试一下。但是发现Mac的安装盘特别难拿到,因此留档。 第一种方法 在mac环境下,使用softwareupdate命令来获取mac安装,能获得当前设备支持的系统。 使用这个命令:/usr/sbin/soft…...
常见AI写作工具介绍(ChatGPT 4o、DeepClaude、Claude 3.5 Sonnet 、DeepSeek R1等)
AI写作工具介绍 1. ChatGPT-4o ChatGPT-4o是OpenAI于2024年5月发布的最新旗舰模型,相比之前的版本,它在多模态支持和实时推理能力上有了显著提升。它能够处理和理解音频、图像和文本数据,适用于复杂的图像分析、语音识别等应用场景[1]。 2…...
环境会影响你的决策:K近邻算法(KNN)
环境会影响你的决策:K近邻算法(KNN) 1. 核心思想与流程 KNN是一种基于局部相似性的分类算法,核心思想是“近朱者赤”:待测样本的类别由其最近的k个邻居的多数类别决定。 关键步骤: 定义空间与距离:通常采…...
JMeter 中实现 100 个用户在 3 秒内并发登录
在 JMeter 中实现 100 个用户在 3 秒内并发登录,需要合理配置线程组、定时器和测试逻辑。以下是具体步骤: 1. 创建测试计划 打开 JMeter。右键点击“Test Plan”,选择 Add > Threads (Users) > Thread Group。 : 设置为 100(模拟 100 个用户)。 : 设置为 3...
2-3文件的属性信息
文章目录 1 file命令2 stat命令 1 file命令 用来识别文件类型 # 参数的位置是任意的 file 文件名 [参数]-b 只显示文件类型和文件编码,不显示文件名-i 显示文件的MIME类型-F 设置输出字符串的分隔符-L 查看软链接文件自身文件属性liyblyb:/tmp$ file xxxtmp.log …...
【云原生之kubernetes实战】在k8s环境中高效部署Vikunja任务管理工具(含数据库配置)
【【云原生之kubernetes实战】在k8s环境中高效部署Vikunja任务管理工具(含数据库配置) 前言一、Vikunja介绍1.1 Vikunja简介1.2 Vikunja主要特点1.3 使用场景二、相关知识介绍2.1 本次实践存储介绍2.2 k8s存储介绍三、本次实践介绍3.1 本次实践简介3.2 本次环境规划3.3 部署前…...
(IDE接入DeepSeek)简单了解DeepSeek接入辅助开发与本地部署建议
重点:IDE接入DeepSeek是否收费 收费! 本文章主要是为了给小白避雷,目前很多文章告诉大家怎么接入DeepSeek,但是并未告知大家是否收费。如果是想白嫖的,就可以不用去接入了。 一、引言 最近爆火的AI人工智能工具DeepSe…...
TCP的三次握手与四次挥手:建立与终止连接的关键步骤
引言 TCP(传输控制协议)工作在OSI模型的传输层。OSI模型将计算机网络功能划分为七个层级,从底层到顶层依次是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。传输层负责在网络节点之间提供可靠的端到端通信&a…...
CMU15445(2023fall) Project #3 - Query Execution(上)详细分析
晚日寒鸦一片愁 柳塘新绿却温柔 若教眼底无离恨 不信人间有白头 ——鹧鸪天 完整代码见: SnowLegend-star/CMU15445-2023fall: Having Conquered the Loftiest Peak, We Stand But a Step Away from Victory in This Stage. With unwavering determination, we pre…...
.sql文件怎么打开
.sql 文件是一个 SQL 脚本文件,通常包含了数据库的 SQL 查询语句,可以是创建数据库、创建表、插入数据、查询数据等操作。要打开并查看 .sql 文件,你可以使用以下几种方法: 1. 使用文本编辑器打开 .sql 文件是一个文本文件&…...
【Swift 算法实战】城市天际线问题解法
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
Linux的软件安装
Linux命令行内的“应用商店” yum命令安装软件。 yum命令: yum:RPM软件管理器,用于自动化安装配置Linux软件,可以自动解决依赖问题。 语法:yum [-y] [install | remove | search] 软件名称 选项:-y。自动确…...
需求和开发模型
文章目录 什么是需求?用户需求软件需求用户需求和软件需求的不同 开发模型什么是“模型”?软件的生命周期常见的开发模型瀑布模型(Waterfall Model)螺旋模型增量模型、迭代模型敏捷模型 测试模型V 模型W 模型(双 V 模型…...
unity学习61:UI布局layout
目录 1 布局 layout 1.1 先准备测试UI,新增这样一组 panel 和 image 1.2 新增 vertical layout 1.3 现在移动任意一个image 都会影响其他 1.3.1 对比 如果没有这个,就会是覆盖效果了 1.3.2 对比 如果没有这个,就会是覆盖效果了 1.4 总结…...
腾讯混元文生图大模型(Hunyuan-DiT)与Stable Diffusion(SD)对比分析
腾讯混元文生图大模型(Hunyuan-DiT)与Stable Diffusion(SD)对比分析 腾讯混元文生图大模型(Hunyuan-DiT)与Stable Diffusion(SD)作为当前文生图领域的两大代表模型,各自…...
Flume
Flume安装配置 使用的三台主机名称分别为bigdata1,bigdata2,bigdata3。所使用的安装包名称按自己的修改,安装包可去各大官网上下载 1.解压 将Master节点Flume安装包解压到/opt/module目录下 tar -zxvf /opt/software/apache-flume-1.9.0-bi…...
【Python LeetCode】面试经典 150 题
数组 / 字符串快慢指针(双指针)总结88. 合并两个有序数组27. 移除元素26. 删除有序数组中的重复项80. 删除有序数组中的重复项 II Boyer-Moore 投票算法169. 多数元素扩展:寻找 n/3 多数元素 翻转法189. 轮转数组 贪心121. 买卖股票的最佳时机…...
营养助力:进行性核上性麻痹患者的饮食管理
进行性核上性麻痹是一种复杂的神经系统退行性疾病,科学的饮食管理不仅能够改善患者的营养状况,还能为神经系统提供必要的支持,延缓病情进展。 这种疾病会导致吞咽困难、营养吸收障碍等问题,增加营养不良的风险。针对性的饮食调理能…...
spineNET模型详解及代码复现
模型背景 在SpineNet模型诞生之前,多尺度特征融合已成为计算机视觉领域的研究热点。研究者们提出了各种方法来处理不同尺度的特征,如 特征金字塔网络(FPN) 和 深度可分离卷积 。然而,这些方法在跨尺度特征融合方面仍存在局限性。 FPN通过自上而下的路径融合不同尺度的特…...