使用HuggingFace实现 DiffEdit论文的掩码引导语义图像编辑

本文中,我们将实现Meta AI和Sorbonne Universite的研究人员最近发表的一篇名为DIFFEDIT的论文。对于那些熟悉稳定扩散过程或者想了解DiffEdit是如何工作的人来说,这篇文章将对你有所帮助。

什么是DiffEdit?

简单地说,可以将DiffEdit方法看作图像到图像的一个更受控制的版本。DiffEdit接受三个输入-

  1. 输入图像
  2. 标题-描述输入图像
  3. 目标查询文本-描述想要生成的新图像的文本

模型会根据查询文本生成原始图像的修改版本。如果您想对实际图像进行轻微调整而不需要完全修改它,那么使用DiffEdit是非常有效的。

从上图中可以看到,只有水果部分被梨代替了。这是一个非常惊人的结果!

论文作者解释说,他们实现这一目标的方法是引入一个遮蔽生成模块,该模块确定图像的哪一部分应该被编辑,然后只对遮罩部分执行基于文本的扩散。

从上面这张论文中截取的图片中可以看到,作者从输入的图像中创建了一个掩码,确定了图像中出现水果的部分(如橙色所示),然后进行掩码扩散,将水果替换为梨。作者提供了整个DiffEdit过程的良好可视化表示。

这篇论文中,生成遮蔽掩码似乎是最重要的步骤,其他的部分是使用文本条件进行扩散过程的调节。使用掩码对图像进行调节的方法与在“Hugging face”的In-Paint 实现的想法类似。正如作者所建议的,“DiffEdit过程有三个步骤:

步骤1:为输入图像添加噪声,并去噪:一次参考提示文本,一次参考查询文本(或无条件,也就是不参考任何文本),并根据去噪结果的差异推导出一个掩码。

步骤2:对输入图像进行DDIM编码,估计与输入图像相对应的潜在值

步骤3:在文本查询条件下执行DDIM解码,使用推断的掩码将背景替换为来自编码过程中相应时间步" 1 "的像素值

下面我们将这些思想实现到实际的代码中。

让我们从导入所需的库和一些辅助函数开始。

 import torch, logging
 
 ## disable warnings
 logging.disable(logging.WARNING)  
 
 ## Imaging  library
 from PIL import Image
 from torchvision import transforms as tfms
 
 
 ## Basic libraries
 from fastdownload import FastDownload
 import numpy as np
 from tqdm.auto import tqdm
 import matplotlib.pyplot as plt
 %matplotlib inline
 from IPython.display import display
 import shutil
 import os
 
 ## For video display
 from IPython.display import HTML
 from base64 import b64encode
 
 
 ## Import the CLIP artifacts 
 from transformers import CLIPTextModel, CLIPTokenizer
 from diffusers import AutoencoderKL, UNet2DConditionModel, DDIMScheduler
 
 ## Helper functions
 
 def load_artifacts():
     '''
     A function to load all diffusion artifacts
     '''
     vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae", torch_dtype=torch.float16).to("cuda")
     unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet", torch_dtype=torch.float16).to("cuda")
     tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16)
     text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16).to("cuda")
     scheduler = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", clip_sample=False, set_alpha_to_one=False)    
     return vae, unet, tokenizer, text_encoder, scheduler
 
 def load_image(p):
     '''
     Function to load images from a defined path
     '''
     return Image.open(p).convert('RGB').resize((512,512))
 
 def pil_to_latents(image):
     '''
     Function to convert image to latents
     '''
     init_image = tfms.ToTensor()(image).unsqueeze(0) * 2.0 - 1.0
     init_image = init_image.to(device="cuda", dtype=torch.float16) 
     init_latent_dist = vae.encode(init_image).latent_dist.sample() * 0.18215
     return init_latent_dist
 
 def latents_to_pil(latents):
     '''
     Function to convert latents to images
     '''
     latents = (1 / 0.18215) * latents
     with torch.no_grad():
         image = vae.decode(latents).sample
     image = (image / 2 + 0.5).clamp(0, 1)
     image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
     images = (image * 255).round().astype("uint8")
     pil_images = [Image.fromarray(image) for image in images]
     return pil_images
 
 def text_enc(prompts, maxlen=None):
     '''
     A function to take a texual promt and convert it into embeddings
     '''
     if maxlen is None: maxlen = tokenizer.model_max_length
     inp = tokenizer(prompts, padding="max_length", max_length=maxlen, truncation=True, return_tensors="pt") 
     return text_encoder(inp.input_ids.to("cuda"))[0].half()
 
 vae, unet, tokenizer, text_encoder, scheduler = load_artifacts()

让我们还选择了一个图像,将在代码实现过程中使用它。

 p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
 init_img = load_image(p)
 init_img

DiffEdit的代码实现

下面我们开始按照作者建议的那样实现这篇论文。

1、掩码创建:这是DiffEdit过程的第一步

对于第一步,论文中有更详细的解释,我们这里只看重点提到的部分-

  1. 使用不同的文本条件(参考文本和查询文本)对图像去噪,并从结果中取差异。这个想法的理论是在不同的部分有更多的变化,而不是在图像的背景不会做过多的改变。
  2. 重复这个差分过程10次
  3. 求出这些差异的平均值并将其二值化

这里需要注意的是掩码创建的第三步(平均和二值化)在论文中没有解释清楚,这使得我花了很多实验时间才做对。

下面的prompt_2_img_i2i函数,可以返回图像的潜在空间,而不是重新缩放和解码后的去噪图像。

 def prompt_2_img_i2i(prompts, init_img, neg_prompts=None, g=7.5, seed=100, strength =0.8, steps=50, dim=512):
     """
     Diffusion process to convert prompt to image
     """
     # Converting textual prompts to embedding
     text = text_enc(prompts) 
     
     # Adding an unconditional prompt , helps in the generation process
     if not neg_prompts: uncond =  text_enc([""], text.shape[1])
     else: uncond =  text_enc(neg_prompt, text.shape[1])
     emb = torch.cat([uncond, text])
     
     # Setting the seed
     if seed: torch.manual_seed(seed)
     
     # Setting number of steps in scheduler
     scheduler.set_timesteps(steps)
     
     # Convert the seed image to latent
     init_latents = pil_to_latents(init_img)
     
     # Figuring initial time step based on strength
     init_timestep = int(steps * strength) 
     timesteps = scheduler.timesteps[-init_timestep]
     timesteps = torch.tensor([timesteps], device="cuda")
     
     # Adding noise to the latents 
     noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
     init_latents = scheduler.add_noise(init_latents, noise, timesteps)
     latents = init_latents
     
     # Computing the timestep to start the diffusion loop
     t_start = max(steps - init_timestep, 0)
     timesteps = scheduler.timesteps[t_start:].to("cuda")
     
     # Iterating through defined steps
     for i,ts in enumerate(tqdm(timesteps)):
         # We need to scale the i/p latents to match the variance
         inp = scheduler.scale_model_input(torch.cat([latents] * 2), ts)
         
         # Predicting noise residual using U-Net
         with torch.no_grad(): u,t = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(2)
             
         # Performing Guidance
         pred = u + g*(t-u)
 
         # Conditioning  the latents
         #latents = scheduler.step(pred, ts, latents).pred_original_sample
         latents = scheduler.step(pred, ts, latents).prev_sample
     
     # Returning the latent representation to output an array of 4x64x64
     return latents.detach().cpu()

下一步是创建create_mask函数,它的参数是使用的初始图像、引导提示和查询提示,以及我们需要重复这些步骤的次数。论文中作者认为在他们的实验中,n=10和强度为0.5是可行的。因此函数的默认值被调整为该值。Create_mask函数执行以下步骤-

  1. 创建两个去噪的潜在空间,一个条件是参考文本,另一个条件是查询文本,并取这些潜在空间的差值
  2. 重复此步骤n次
  3. 取这些差异的平均值并进行标准化
  4. 选择0.5的阈值进行二值化并创建掩码
 def create_mask(init_img, rp, qp, n=10, s=0.5):
     ## Initialize a dictionary to save n iterations
     diff = {}
     
     ## Repeating the difference process n times
     for idx in range(n):
         ## Creating denoised sample using reference / original text
         orig_noise = prompt_2_img_i2i(prompts=rp, init_img=init_img, strength=s, seed = 100*idx)[0]
         ## Creating denoised sample using query / target text
         query_noise = prompt_2_img_i2i(prompts=qp, init_img=init_img, strength=s, seed = 100*idx)[0]
         ## Taking the difference 
         diff[idx] = (np.array(orig_noise)-np.array(query_noise))
     
     ## Creating a mask placeholder
     mask = np.zeros_like(diff[0])
     
     ## Taking an average of 10 iterations
     for idx in range(n):
         ## Note np.abs is a key step
         mask += np.abs(diff[idx])  
         
     ## Averaging multiple channels 
     mask = mask.mean(0)
     
     ## Normalizing 
     mask = (mask - mask.mean()) / np.std(mask)
     
     ## Binarizing and returning the mask object
     return (mask > 0).astype("uint8")
 
 mask = create_mask(init_img=init_img, rp=["a horse image"], qp=["a zebra image"], n=10)

让我们在图像上可视化生成的掩码。

 plt.imshow(np.array(init_img), cmap='gray') # I would add interpolation='none'
 plt.imshow(
     Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
     cmap='cividis', 
     alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)  
 )

正如我们在上面看到的,制作的掩码覆盖了马的部分,这的确是我们想要的结果。

2、掩码扩散:DiffEdit论文的步骤2和步骤3

步骤2和3需要在同一个循环中实现,因为作者是说基于参考文本对非掩码部分和查询文本对掩码部分进行条件处理。使用这个简单的公式将这两个部分结合起来,创建组合的潜在空间

 def prompt_2_img_diffedit(rp, qp, init_img, mask, g=7.5, seed=100, strength =0.7, steps=70, dim=512):
     """
     Diffusion process to convert prompt to image
     """
     # Converting textual prompts to embedding
     rtext = text_enc(rp) 
     qtext = text_enc(qp)
     
     # Adding an unconditional prompt , helps in the generation process
     uncond =  text_enc([""], rtext.shape[1])
     emb = torch.cat([uncond, rtext, qtext])
     
     # Setting the seed
     if seed: torch.manual_seed(seed)
     
     # Setting number of steps in scheduler
     scheduler.set_timesteps(steps)
     
     # Convert the seed image to latent
     init_latents = pil_to_latents(init_img)
     
     # Figuring initial time step based on strength
     init_timestep = int(steps * strength) 
     timesteps = scheduler.timesteps[-init_timestep]
     timesteps = torch.tensor([timesteps], device="cuda")
     
     # Adding noise to the latents 
     noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
     init_latents = scheduler.add_noise(init_latents, noise, timesteps)
     latents = init_latents
     
     # Computing the timestep to start the diffusion loop
     t_start = max(steps - init_timestep, 0)
     timesteps = scheduler.timesteps[t_start:].to("cuda")
     
     # Converting mask to torch tensor
     mask = torch.tensor(mask, dtype=unet.dtype).unsqueeze(0).unsqueeze(0).to("cuda")
     
     # Iterating through defined steps
     for i,ts in enumerate(tqdm(timesteps)):
         # We need to scale the i/p latents to match the variance
         inp = scheduler.scale_model_input(torch.cat([latents] * 3), ts)
         
         # Predicting noise residual using U-Net
         with torch.no_grad(): u, rt, qt = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(3)
             
         # Performing Guidance
         rpred = u + g*(rt-u)
         qpred = u + g*(qt-u)
 
         # Conditioning  the latents
         rlatents = scheduler.step(rpred, ts, latents).prev_sample
         qlatents = scheduler.step(qpred, ts, latents).prev_sample
         latents = mask*qlatents + (1-mask)*rlatents
     
     # Returning the latent representation to output an array of 4x64x64
     return latents_to_pil(latents)

让我们可视化生成的图像

 output = prompt_2_img_diffedit(
     rp = ["a horse image"], 
     qp=["a zebra image"],
     init_img=init_img, 
     mask = mask, 
     g=7.5, seed=100, strength =0.5, steps=70, dim=512)
 
 ## Plotting side by side
 fig, axs = plt.subplots(1, 2, figsize=(12, 6))
 for c, img in enumerate([init_img, output[0]]): 
     axs[c].imshow(img)
     if c == 0 : axs[c].set_title(f"Initial image ")
     else: axs[c].set_title(f"DiffEdit output")

将掩码和扩散过程整合成一个简单的函数。

 def diffEdit(init_img, rp , qp, g=7.5, seed=100, strength =0.7, steps=70, dim=512):
     
     ## Step 1: Create mask
     mask = create_mask(init_img=init_img, rp=rp, qp=qp)
     
     ## Step 2 and 3: Diffusion process using mask
     output = prompt_2_img_diffedit(
         rp = rp, 
         qp=qp, 
         init_img=init_img, 
         mask = mask, 
         g=g, 
         seed=seed,
         strength =strength, 
         steps=steps, 
         dim=dim)
     return mask , output

我们还可以为DiffEdit创建一个可视化函数,显示原始输入图像、掩码图像和最终输出图像。

 def plot_diffEdit(init_img, output, mask):
     ## Plotting side by side
     fig, axs = plt.subplots(1, 3, figsize=(12, 6))
     
     ## Visualizing initial image
     axs[0].imshow(init_img)
     axs[0].set_title(f"Initial image")
     
     ## Visualizing initial image
     axs[2].imshow(output[0])
     axs[2].set_title(f"DiffEdit output")
     
     ## Visualizing the mask 
     axs[1].imshow(np.array(init_img), cmap='gray') 
     axs[1].imshow(
         Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
         cmap='cividis', 
         alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)  
     )
     axs[1].set_title(f"DiffEdit mask")

下面可以在一些其他的图像上测试这个函数。

 p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
 init_img = load_image(p)
 mask, output = diffEdit(
   init_img, 
   rp = ["a horse image"], 
   qp=["a zebra image"]
 )
 plot_diffEdit(init_img, output, mask)

效果还不错太,再试一个。

 p = FastDownload().download('https://raw.githubusercontent.com/johnrobinsn/diffusion_experiments/main/images/bowloberries_scaled.jpg')
 init_img = load_image(p)
 mask, output = diffEdit(
   init_img, 
   rp = ['Bowl of Strawberries'], 
   qp=['Bowl of Grapes']
 )
 plot_diffEdit(init_img, output, mask)

FastDiffEdit:一个更快的DiffEdit实现

现在我们已经看到了我们自己手写代码的实现,但是我们这个实现没有经过任何的优化。为了在速度结果方面表现的更好,可以对原来的DiffEdit过程进行一些改进。我们称这些改进为FastDiffEdit。

1、掩码创建:FastDiffEdit掩码过程

掩码创建的最大的问题是它花费太多的时间(在A4500 GPU上大约50秒)。我们可能不需要运行一个完整的扩散循环来去噪图像,只需要在一个观察中使用原始样本的U-net预测,并将重复增加到20次。在这种情况下,可以将计算从10*25 = 250步改进到20步(少了12次循环)。让我们看看这在实践中是否有效。

 def prompt_2_img_i2i_fast(prompts, init_img, g=7.5, seed=100, strength =0.5, steps=50, dim=512):
     """
     Diffusion process to convert prompt to image
     """
     # Converting textual prompts to embedding
     text = text_enc(prompts) 
     
     # Adding an unconditional prompt , helps in the generation process
     uncond =  text_enc([""], text.shape[1])
     emb = torch.cat([uncond, text])
     
     # Setting the seed
     if seed: torch.manual_seed(seed)
     
     # Setting number of steps in scheduler
     scheduler.set_timesteps(steps)
     
     # Convert the seed image to latent
     init_latents = pil_to_latents(init_img)
     
     # Figuring initial time step based on strength
     init_timestep = int(steps * strength) 
     timesteps = scheduler.timesteps[-init_timestep]
     timesteps = torch.tensor([timesteps], device="cuda")
     
     # Adding noise to the latents 
     noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
     init_latents = scheduler.add_noise(init_latents, noise, timesteps)
     latents = init_latents
     
     # We need to scale the i/p latents to match the variance
     inp = scheduler.scale_model_input(torch.cat([latents] * 2), timesteps)
     # Predicting noise residual using U-Net
     with torch.no_grad(): u,t = unet(inp, timesteps, encoder_hidden_states=emb).sample.chunk(2)
          
     # Performing Guidance
     pred = u + g*(t-u)
 
     # Zero shot prediction
     latents = scheduler.step(pred, timesteps, latents).pred_original_sample
     
     # Returning the latent representation to output an array of 4x64x64
     return latents.detach().cpu()

创建一个新的掩码函数,它使用prompt_2_img_i2i_fast函数。

 def create_mask_fast(init_img, rp, qp, n=20, s=0.5):
     ## Initialize a dictionary to save n iterations
     diff = {}
     
     ## Repeating the difference process n times
     for idx in range(n):
         ## Creating denoised sample using reference / original text
         orig_noise = prompt_2_img_i2i_fast(prompts=rp, init_img=init_img, strength=s, seed = 100*idx)[0]
         ## Creating denoised sample using query / target text
         query_noise = prompt_2_img_i2i_fast(prompts=qp, init_img=init_img, strength=s, seed = 100*idx)[0]
         ## Taking the difference 
         diff[idx] = (np.array(orig_noise)-np.array(query_noise))
     
     ## Creating a mask placeholder
     mask = np.zeros_like(diff[0])
     
     ## Taking an average of 10 iterations
     for idx in range(n):
         ## Note np.abs is a key step
         mask += np.abs(diff[idx])  
         
     ## Averaging multiple channels 
     mask = mask.mean(0)
     
     ## Normalizing 
     mask = (mask - mask.mean()) / np.std(mask)
     
     ## Binarizing and returning the mask object
     return (mask > 0).astype("uint8")

看看这个新的函数是否能产生好的蔽效果。

 p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
 init_img = load_image(p)
 mask = create_mask_fast(init_img=init_img, rp=["a horse image"], qp=["a zebra image"], n=20)
 plt.imshow(np.array(init_img), cmap='gray') # I would add interpolation='none'
 plt.imshow(
     Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
     cmap='cividis', 
     alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)  
 )

效果还是可以的虽然没有完整的函数来的准确,但计算时间在我的机器上从~50秒减少到~10秒(提高了5倍!),我们可以通过添加cv2的处理来改进效果。这将使掩码更平滑一点。

 import cv2
 def improve_mask(mask):
     mask  = cv2.GaussianBlur(mask*255,(3,3),1) > 0
     return mask.astype('uint8')
 
 mask = improve_mask(mask)
 plt.imshow(np.array(init_img), cmap='gray') # I would add interpolation='none'
 plt.imshow(
     Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
     cmap='cividis', 
     alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)  
 )

掩码变得更加平滑,覆盖了更多的区域。

2、将掩码扩散的流程替换为?inpaint的流程

在?diffusers库中有一个叫做inpaint pipeline的特殊管道,所以我们可以使用它来执行掩码扩散。它接受查询提示、初始图像和生成的掩码返回生成的图像。

 from diffusers import StableDiffusionInpaintPipeline
 pipe = StableDiffusionInpaintPipeline.from_pretrained(
     "runwayml/stable-diffusion-inpainting",
     revision="fp16",
     torch_dtype=torch.float16,
 ).to("cuda")

让我们使用inpaint来进行改进

 pipe(
     prompt=["a zebra image"], 
     image=init_img, 
     mask_image=Image.fromarray(mask*255).resize((512,512)), 
     generator=torch.Generator("cuda").manual_seed(100),
     num_inference_steps = 20
 ).images[0]
 image

inpaint管道创建了一个更真实的斑马图像。让我们为掩码和扩散过程创建一个简单的函数。

 def fastDiffEdit(init_img, rp , qp, g=7.5, seed=100, strength =0.7, steps=20, dim=512):
     
     ## Step 1: Create mask
     mask = create_mask_fast(init_img=init_img, rp=rp, qp=qp, n=20)
     
     ## Improve masking using CV trick
     mask = improve_mask(mask)
     
     ## Step 2 and 3: Diffusion process using mask
     output = pipe(
         prompt=qp, 
         image=init_img, 
         mask_image=Image.fromarray(mask*255).resize((512,512)), 
         generator=torch.Generator("cuda").manual_seed(100),
         num_inference_steps = steps
     ).images
     return mask , output

还是在上面的图像上测试这个函数。

 p = FastDownload().download('https://raw.githubusercontent.com/johnrobinsn/diffusion_experiments/main/images/bowloberries_scaled.jpg')
 init_img = load_image(p)
 mask, output = fastDiffEdit(init_img, rp = ['Bowl of Strawberries'], qp=['Bowl of Grapes'])
 plot_diffEdit(init_img, output, mask)

效果比我们自己写的好多了

总结

在这篇文章中,我们实现了DiffEdit论文,然后还提出了创建FastDiffEdit的改进方法,这样不仅计算速度提高了5倍,效果也变得更好了,而且代码还变少了。

作者:Aayush Agrawal 作者网站:aayushmnit.com

本文转载于网络 如有侵权请联系删除

相关文章

  • 【SVN】SVN服务器搭建,客户端使用,在VS Code 中使用SVN

    大家好,又见面了,我是你们的朋友全栈君。1.软件下载ApacheSubversionBinaryPackages①VisualSVN服务端②TortoiseSVN客户端③Chinese,simplified语言包④vscode下载2.在vscode使用svn①在vscode里面下载TortoiseSVNforVSCode插件②配置svn环境变量和在vscode里配置svn③在vscode里使用svn命令第一种—右键工作空间中选中的文件->出现svn命令第二种ctrl+shift+pj再键入svn这样会在vscode里面调出svn客户端进行下一步注释提交操作发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/161781.html原文链接:https://javaforall.cn

  • python json.loads()、json.dumps()和json.dump()、json.load()区别

    json.loads()、json.dumps()和json.dump()、json.load()分别是两组不同用法带s的用于数据类型的转换,不带s的用于操作文件。json.loads()、json.dumps()概念理解json本身是字符串,通过以下两个函数可以进行字典和字符串的转换。因为浏览器不支持字典方式显示,如果请求过来的类型是字典,必须通过json.dumps()函数将字典转换为字符串之后,才可展示。使用案例json.loads():解码,将JSON格式的字符串转换为字典。>>>importjson >>>json_str='{"num":"66"}' >>>dict2=json.loads(json_str) >>>type(json_str) <class'str'> >>>type(dict2) <class'dict'>复制json.dumps():编码,将

  • Kafka学习笔记之Kafka应用问题经验积累

    0x00Kafka配置文件同步为了给kafka的进程添加GC日志信息,方便在以后重启的时候,加入GC日志: 修改bin/kafka-server-start.sh:exportKAFKA_OPTS="-Xms4G-Xmx8G-Xmn3G-XX:+UseConcMarkSweepGC-XX:ParallelGCThreads=4-server-Dlog4j.configuration=file:$base_dir/config/log4j.properties-Xloggc:/data0/kafka/log/gc.log-verbose:gc-XX:+PrintGCDateStamps-XX:+PrintGCDetails-XX:+PrintGCApplicationStoppedTime"复制书写脚本文件:syncProperty.sh如下./etc/bashrc ./etc/profile echoqwe123>password.pass chmod600password.pass sudochownroot:rootpassword.pass sudors

  • 基于二分搜索法的floor与ceil

    导语:刷算法,练内功!by光城基于二分搜索法的floor与ceil1.基本的二分搜索在闭区间[left,right]范围内查找target。classSolution{ public: intsearch1(vector<int>&nums,inttarget){ if(nums.size()==0)return-1; intleft=0,right=nums.size()-1; //left与right均不会越界,可以取等 while(left<=right){ intmid=left+(right-left)/2; if(nums[mid]==target){ returnmid; }elseif(nums[mid]<target){ left=mid+1; //mid处理过了,需要mid+1 }elseif(nums[mid]>target){ right=mid-1; //mid处理过了,需要mid-1 } } return-1; } }; 复制如果上述right改为nums.size(),判断与right均会发生变化:此时处理的范

  • Spring Boot2(二):使用Spring Boot2集成Mybatis缓存机制

    前言学习SpringBoot集成Mybatis的第二章,了解到Mybatis自带的缓存机制,在部署的时候踩过了一些坑。在此记录和分享一下Mybatis的缓存作用。本文章的源码再文章末尾什么是查询缓存MyBatis有一级缓存和二级缓存。记录可以看下这篇博文:一级缓存首先看一下什么是一级缓存,一级缓存是指SqlSession。一级缓存的作用域是一个SqlSession。Mybatis默认开启一级缓存。在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中获取。当执行SQL查询前后发生增删改操作时,则SqlSession的缓存清空。具体可以看这段代码:@Test publicvoidtestLocalCacheScope()throwsException{ SqlSessionsqlSession1=factory.openSession(true); SqlSessionsqlSession2=factory.openSession(true); StudentMapperstudentMapper=sqlSession1.getMa

  • C++读写文件

    1.读取1.1逐行读取voidreadTxt(stringfile) { ifstreamifs; ifs.open(file); //将文件流对象与文件关联起来,如果已经关联则调用失败 assert(ifs.is_open()); //若失败,则输出错误消息,并终止程序运行 strings; while(getline(ifs,s)) //行分隔符可以显示指定,比如按照分号分隔getline(infile,s,';') { cout<<s<<endl; } ifs.close(); //关闭文件输入流 }复制1.3逐字符读取voidreadTxt(stringfile) { ifstreamifs; ifs.open(file.data()); //将文件流对象与文件连接起来 assert(ifs.is_open()); //若失败,则输出错误消息,并终止程序运行 charc; ifs>>std::noskipws; //清除skipws标识,不忽略空白符(Tab、空格、回车和换行) while(!infile.eo

  • 【国际模式识别大会ICPR18】纯金干货!周志华等6场特邀报告和论文最全回顾

    【新智元导读】第24届国际模式识别会议(ICPR2018)上周在北京成功举行,这是40多年来该会议首次在中国大陆举行,凸显了中国在模式识别这一AI重要子领域的地位及国际认可。 作为模式识别领域的旗舰学术会议,国际模式识别大会(ICPR)自1972年起,每两年召开一次。在2014年国际模式识别大会的理事会全体会议上,中国和澳大利亚围绕2018年国际模式识别大会举办权展开了激烈角逐。 中国科学院自动化所模式识别国家重点实验室学术委员会主任、中科院院士谭铁牛和实验室主任刘成林代表中国作申办报告并回答了理事会的质询,最终赢得理事会青睐。这折射了我国改革开放40年来在模式识别这一人工智能重要领域的快速进展,代表了国际学术界对于主办方模式识别国际重点实验室学术能力的充分认可。 模式识别是人工智能的关键技术之一,使机器通过视觉信息识别文字、图片和周围的环境,通过听觉信息识别与理解语言。在大数据时代,传感、通讯、数字化技术等手段使得信息内容的智能识别与理解成为信息科技发展的新的重大契机。 本届会议由国际模式识别联合会、中国自动化学会、中国科学院自动化研究所联合主办,对于我国在国际人工智能学术领域而言,

  • PS网络管理与配置常用命令

    [TOC]0x00网络连接测试Test-Connection命令-向一台或多台计算机发送ICMP回显请求数据包或ping描述:可以类比于cmd中的nbtstat明进行获取局域网中的指定计算机名的IPv4/6地址信息以及MAC地址;基础语法: PS>(Get-Command*-Connection).Name Test-Connection #语法 Test-Connection[-ComputerName]<System.String[]>[-AsJob][-BufferSize<System.Int32>][-Count<System.Int32>][-DcomAuthentication{Default|None|Connect|Call|Packet|PacketIntegrity|PacketPrivacy|Unchanged}][-Delay<System.Int32>][-Impersonation{Default|Anonymous|Identify|Impersonate|Delegate}][-Protocol{

  • JAVA静态内部类_java静态内部类实例化

    写在前面思路来源静态内部类特性详解静态内部类的使用场景  在考虑使用静态内部类时,一般有这样的场景需求:当外部类需要使用内部类,而内部类无需外部类资源,并且内部类可以单独创建,这时我们会考虑采用静态内部类的设计。静态内部类的使用限制  对于在外部类的各个方法间定义的内部类,静态与非静态在使用时有不同的限制,主要总结为以下的几个区别:    (1)在方法间定义的非静态内部类:       ●外围类和内部类可互相访问自己的私有成员。       ●非静态内部类中不能定义静态成员变量与方法。     (2)在方法间定义的静态内部类:       ●只能访问外部类的静态成员变量与方法。       ●在创建静态内部类实例时不需要将静态内部类的实例绑定在外部类的实例上。(即内部类可以单独创建实例)/** *声明静态内部类实例与非静态内部类实例的区别示例。 */ //静态内部类可以单独初始化: Inneri=newInner(); //非静态内部类初始化: Outero=newOuter(); Inneri=o.newInner();复制静态内部类的使用样例  关于静态内部类,《Effectiv

  • 国庆快乐,送3本技术好书

    VOL429012022-10今天距2023年92天ITester软件测试小栈第429次推文点击上方蓝字“ITester软件测试小栈“关注我,每周一、三、五早上09:00准时推送,每月不定期赠送技术书籍。微信公众号后台回复“资源”、“测试工具包”领取测试资源,回复“微信交流群”、“内推群”一起进群打怪。本文2404字,阅读约需7分钟Hi,大家好,我是CoCo。国庆小长假来临,首先祝大家国庆快乐,一路畅通,吃嘛嘛香。估计很多伙伴许久没有一场说走就走的旅行了,你的假期会比平日精彩么?记得去看看那些偏爱你的人啊。偏爱你们的我特此送出由北大出版社出版的3本好书,微信公众号后台回复“国庆快乐”可以参与送书抽奖,回复“测试福利”可参与红包?抽奖哟。01《元宇宙:图说元宇宙、设计元宇宙》子弥实验室/著推荐理由:什么是“元宇宙”?多元世界、虚实共生、沙盒游戏、无限创造、数字人生、创世系统、私钥经济、意识进化、高度沉浸……这些全新的概念将在这个新世界出现。“元宇宙”是重启新文明的的“元叙事”,是人类对乌托邦世界的思考和实践,技术、理想、权力、资本与人性的较量将在元宇宙中展开,同时,元宇宙也会促进基础数学

  • oracle11g重置system密码,外二

    来自:http://lukeview.blog.51cto.com/508652/912124 win+r,输入sqlplus/nolog,回车SQL>conn/assysdba已连接;SQL>alterusersystemidentifiedby"123456"; ---(123456就是重置的密码了)SQL>alterusersysidentifiedby"123456";     卸载11g后的清理工作 全文来自:http://gaojingting.blog.techweb.com.cn/archives/104.html 1.关闭oracle所有的服务。 可以在windows的服务管理器中关闭;   2.打开注册表KEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\      删除该路径下的所有以oracle开始的服务名称,这个键是标识Oracle在windows下注册的各种服务!   3

  • kubernetes基础概念知多少

    kubernetes(简称k8s)是一种用于在一组主机上运行和协同容器化应用程序的管理平台,皆在提供高可用、高扩展性和可预测性的方式来管理容器应用的生命周期。通过k8s,用户可以定义程序运行方式、部署升级策略、动态伸缩容,使得用户以一种更灵活可靠的方式来管理应用程序。 关于k8s,是一种对应用服务的打包、部署、监控等一整套生命周期的自动化管理平台,目前各大公司已在生产环境部署使用,同时k8s社区比较活跃,在未来一段时间内会越来越流行,可以说是以后服务部署的事实标准,对于Java开发者来说,你可以不直接使用它,但是不能不了解它。 总结来看,k8s特点如下: 自动装箱:基于容器,结合调度策略将多种应用部署到同一节点上,提高资源利用率; 自我修复:支持故障转移/重启,具有健康检查机制; 水平扩展:通过命令手动执行扩容,可基于CPU等资源负载率来动态实现伸缩容; 服务发现/负载均衡:通过KubeDNS(或CoreDNS)为系统内置了服务发现功能,为每个service配置DNS名称,service通过iptables或ipvs内建了负载均衡机制; 自动部署:自动发布和回滚,支持灰度、增量发

  • Spring源码解析-JdbcTemplate

    JdbcTemplate类图   从类继承关系上来看,JdbcTemplate继承了基类JdbcAccessor和接口类JdbcOperation,在基类JdbcAccessor的设计中,对DataSource数据源的管理和配置,在JdbcOperation接口中,定义了通过JDBC操作数据库的基本操作方法,而JdbcTemplate提供了这些接口的实现,例如execute(),query() ,update()等方法。 回顾JDBC的简单使用 @Test publicvoidtestJDBC(){ Stringurl="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8"; Stringusername="root"; Stringpassword="123456"; //1.加载驱动程序 Class.forName("com.mysql.jdbc.Driver"); //2.获取连接 Connectionconn=DriverManager.getConne

  • 多重背包问题

    51Nod1086 分析:二进制优化多重背包,推荐一篇不错的blog,点我 1#include"iostream" 2#include"cstdio" 3#include"cstring" 4#include"string" 5usingnamespacestd; 6constintmaxn=5e5+10; 7intn,m; 8intw[maxn],p[maxn],c[maxn]; 9longlongdp[maxn]; 10intmain() 11{ 12cin>>n>>m; 13for(inti=1;i<=n;i++) 14scanf("%d%d%d",&w[i],&p[i],&c[i]); 15intcnt=n; 16for(inti=1;i<=n;i++){ 17for(intj=1;;j*=2){ 18if(c[i]>=j){ 19++cnt; 20w[cnt]=j*w[i],p[cnt]=j*p[i],c[i]-=j; 21}else{ 22w[i]=c[i]*w[i],p[i]=p[i]*c[i];bre

  • 在线课堂后端代码梳理

      可以参考完整的代码:https://gitee.com/juncaoit/onlineclass   这里通过小滴课堂的学习,然后进行了代码参考借鉴。   一:大致说明 1.数据库   mysql   2.包括模块   用户   视频   订单    3.技术   springboot  mybatis  Jwt  mysql  Gauva   二:细节 1.数据库与mybatis的配置 server.port=8089 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/online_xdclass?useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=123456 mybatis.config

  • Regression datasets collection 回归数据集

    https://blog.csdn.net/Jaster_wisdom/article/details/78125046?fps=1&locationnum=7 二维或者三维满足空间中正态分布的样本点 https://www.ilovematlab.cn/thread-27021-1-1.html 归一化处理 https://www.cnblogs.com/jins-note/p/11247166.html matlab画各种图形总结 http://blog.sina.com.cn/s/blog_6a756f830102xf1p.html MATLAB画误差棒图。 https://www.cnblogs.com/shenxiaolin/p/10535644.html 画三维柱状图 https://github.com/kakearney/boundedline-pkg MATLAB画置信区间曲线(阴影部分)。 回归问题链接 《GrranularFuzzymodelingformultidimensionalnumericdataalayeredapproachbasedonhy

  • 15、SpringBoot实现Excel的导入导出

    前言 需求:正如标题所言,需求有数据的导入、导出 导入:给用户提供给一个导入数据的模板,用户填写数据后上传,实现文件的批量导入。 导出:将数据列表直接导进excel,用户通过浏览器下载。 首先考虑用经典的apachepoi实现这一功能,但是发现不是很好用,后面有换了阿里的easyexcel,效率比较高。 如果需求不高,只是简单的导入导出,不涉及复杂对象,可以直接使用第一版的代码。 excel基本构成 虽然只写个导入导出并不要求我们对excel有多熟悉,但是最起码得知道excel有哪些构成。 整个文件:student.xlsx,对应与poi中的Workbook sheet:一张表    cell:单元格,每一小格 apachepoi 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <depe

  • Alpha 冲刺5/10

    队名:我头发呢队 组长博客 杰(组长) 过去两天完成了哪些任务 继续翻阅MaterialDesign2文档 翻阅网易云的web端网页 接下来的计划 音源爬取 还剩下哪些任务 app开发 燃尽图 有哪些困难 进度缓慢 有哪些收获和疑问 网页真好玩 跃安 过去两天完成了哪些任务 配置了Androidstudio环境,学习安卓界面开发 尝试了音乐源的爬取。 接下来的计划 专心完成界面开发任务 还剩下哪些任务 与爬取音乐源的队友沟通如何整合两方面的工作 有哪些收获和疑问 安卓界面的开发是第一次遇到很多的困难也是在所难免的,但是了解了我们经常使用的app是如何完成的,还是挺高兴的。 写代码的过程中有很多都不会,容易出错。 裕翔 过去两天完成了哪些任务 阅读『安卓学习之路』(未读完) 配置Python环境 配置Androidstudio 接下来的计划 学习Python和java 学习,如何使用Androidstudio 有哪些困难 安卓开发还在摸索 有哪些收获和疑问 对安卓的开发了解有了进步 佳炜 过去两天完成了哪些任务 学习Androidstudio的使用方法 了解As下

  • 查看sql语句加锁信息

    问题: 最近使用quartz集群,总是报deadlock问题,所以需要查看一下执行的sql导致的加锁冲突。 步骤: 1、在要测试的库中创建指定表innodb_lock_monitor createtableinnodb_lock_monitor(xint)engine=innodb;复制 2、执行sql复制 BEGIN; SETtx_isolation='SERIALIZABLE'; SETautocommit=0; UPDATEQRTZ_TRIGGERSSETTRIGGER_STATE='7897'WHERESCHED_NAME='clusterQuartzSchedular'ANDJOB_NAME='addRefundJob';复制 3、执行查询锁命令: SHOWENGINEINNODBSTATUS;复制 4、得到执行结果   5、拷贝Status单元格的内容到notepad编辑器中查看详细信息: showengineinnodbstatus TABLELOCKtable`pay_quartz`.`QRTZ_TRIGGERS`trxid5E7BD8loc

  • scrapy-redis 分布式爬虫

    为什么要学? Scrapy_redis在scrapy的基础上实现了更多,更强大的功能。 有哪些功能体现? request去重、爬虫持久化、实现分布式爬虫、断点续爬(带爬取的request存在redis中)、增量式爬虫(爬取过的生成指纹) 工作流程 先来看看之前的爬虫流程 再来看看scrapy_redis的爬虫流程   安装: pipinstallscrapy-redis复制 源码包安装: gitclonegit://github.com/rolando/scrapy-redis复制 官方文档在:https://scrapy-redis.readthedocs.io/en/stable/index.html#running-the-example-project scrapy_redis的源码在github:https://github.com/rmax/scrapy-redis 它提供了三个demo在example-projec/example中   三个案例有   先来看第一个案例: dmoz.py fromscrapy.linkext

  • 第一阶段意见汇总

    1.遇码则码队 优点:开始的Logo比较美观,相对应app功能还是比较体现主题,比较有鲜明的特色 不足:app里面的不足不太美观,好多小图标不太搭配,并且主题布局设计的没有凸显app的主要功能,功能还比较单一,期待添加笔记功能的实现。 2.响当当队 目前已实现的功能可以,但是还没有成为一个完整的app,下一阶段着重开发笔记模块。 3.天宫疼憨仔队 优点:登录界面让人眼前一亮,简洁明了。已实现的功能已经使APP成型。 建议:进入主界面之后,界面绘制的粗糙,功能欠缺,仍需改进。 4.开拓者队 界面风格不统一,有点界面比较美观,有点界面还是有点粗糙,功能合理!可以考虑加入记作业功能,作业内容,完成提醒之类,也可以对课表进行统计,将空余时间单独取出,可以写自己的课余时间计划表之类。 5.敲代码,我们是认真队 这个软件的登录界面让人眼前一亮,抽象的涂鸦感觉很棒,进入主界面之后,感觉界面绘制的粗糙,很多东西都是直接接触两侧,并没有留出空白,感觉很难看。功能方面我感觉不是很多,只是提供参阅上传,同样,我感觉缺乏竞争优势。 6.九头蛇队 第二组的作品是一个读书app。存在的问题有书架主页的文字太大,按

相关推荐

推荐阅读