赞
踩
作者说明在 1.5 版本前,不会修改训练模型的结构,1.1版本主要增强了鲁棒性和生成图像的质量
model = create_model(f'./models/{model_name}.yaml').cpu()
model.load_state_dict(load_state_dict('./models/v1-5-pruned.ckpt', location='cuda'), strict=False)
model.load_state_dict(load_state_dict(f'./models/{model_name}.pth', location='cuda'), strict=False)
模型命令将遵循:
{项目名称,通常为control}{版本和修改次数,例如v11表示1.1版本,v11f1表示1.1版本的修改1次}{p表示产品版,e表示实验版,u表示正在训练}{基于的预训练模型,常见的sd15为stable diffison 1.5}_{图像控制方法,例如canny为草图}.pth
例如 control_v11p_sd15_canny.pth 表示 control 项目下,1.1版本的产品版,基于stable diffison 1.5,使用 canny 标注引导的模型文件
表示为文本提示,因为文本提示给的是 stable diffison 所以使用方法和 stable 相同,可以参考详细描述使用文本提示的文章,例如 https://zhuanlan.zhihu.com/p/619247417
代码中,变量名为 prompt 和 a_prompt 构造为正面的文本提示,并转为特征
cond = {"c_concat": [control], "c_crossattn": [model.get_learned_conditioning([prompt + ', ' + a_prompt] * num_samples)]}
un_cond = {"c_concat": None if guess_mode else [control], "c_crossattn": [model.get_learned_conditioning([n_prompt] * num_samples)]}
例如,我使用 cow doll 引导生成的牛牛的玩偶
表示需要生成的图像数量,代码中为变量 num_samples 用于构造 batch_size
control = torch.stack([control for _ in range(num_samples)], dim=0)
例如使用 images = 2 生成 2 张图像
表示设置的全局随机种子,控制生成过程中的所有随机变量,即使用相同的随机种子将会得到相同的结果
代码中使用 pytorch_lighting 的 seed_everything 函数,该函数会设置以下的随机变量的随机种子:
if seed == -1:
seed = random.randint(0, 65535)
seed_everything(seed)
例如下图我使用相同的随机数种子生成的图像与上文相同
下图中我将 seed 从 12345 改为 12346 就获得不一样的效果
若不为 None,会将输入的图像转变为条件图像,否则将输入的图像作为条件图像
代码中获取的变量为det,将判断det是否为None,对输入的图像是否转换为条件图像
if det == 'None':
detected_map = input_image.copy()
else:
detected_map = preprocessor(resize_image(input_image, detect_resolution), low_threshold, high_threshold)
detected_map = HWC3(detected_map)
例如,下图我使用自己生成的条件图像生成图像
表示为生成图像的长和高的分辨率
代码中获得变量为 image_resolution,将输入模型的图像和条件图像变更为 (image_resolution*image_resolution),获取需要的图像高、宽和通道信息
if det == 'None':
detected_map = input_image.copy()
else:
detected_map = preprocessor(resize_image(input_image, detect_resolution), low_threshold, high_threshold)
detected_map = HWC3(detected_map)
img = resize_image(input_image, image_resolution)
H, W, C = img.shape
detected_map = cv2.resize(detected_map, (W, H), interpolation=cv2.INTER_LINEAR)
例如,我使用 image_resolution = 256 获得 256 *256 的结果
表示为 control model 生成的条件合并到 stable diffsion 模型上的权重,默认为 1
在代码中表示为设置模型的缩放变量列表,因为有 12 层 uent + 1 层 unet mid 所以需要长为 13的列表,代码中将输入的变量复制 13 份;在模型预测中会先用 control model 生成条件的中间量乘缩放列表后再传递给stable diffsion
# 代码中构造的缩放列表
model.control_scales = [strength * (0.825 ** float(12 - i)) for i in range(13)] if guess_mode else ([strength] * 13)
# 在 cldm 文件下的训练过程
control = self.control_model(x=x_noisy, hint=torch.cat(cond['c_concat'], 1), timesteps=t, context=cond_txt)
control = [c * scale for c, scale in zip(control, self.control_scales)]
eps = diffusion_model(x=x_noisy, timesteps=t, context=cond_txt, control=control, only_mid_control=self.only_mid_control)
例如,这是我使用默认参数+seed=12346+Control Strength为1、2 的生成结果,显然图2相对来说更加遵守条件,因为他将玩偶草图眼睛上面的东西生成了出来
表示为使用更多样性的结果,生成后得到不那么遵守图像条件的结果
代码中
# 构造生成条件的部分 cond = {"c_concat": [control], "c_crossattn": [model.get_learned_conditioning([prompt + ', ' + a_prompt] * num_samples)]} un_cond = {"c_concat": None if guess_mode else [control], "c_crossattn": [model.get_learned_conditioning([n_prompt] * num_samples)]} shape = (4, H // 8, W // 8) if config.save_memory: model.low_vram_shift(is_diffusing=True) model.control_scales = [strength * (0.825 ** float(12 - i)) for i in range(13)] if guess_mode else ([strength] * 13) # 添加正面生成条件和负面生成条件的差距的部分,源码 ddim_hacked.py 的 p_sample_ddim 函数 if unconditional_conditioning is None or unconditional_guidance_scale == 1.: model_output = self.model.apply_model(x, t, c) else: model_t = self.model.apply_model(x, t, c) model_uncond = self.model.apply_model(x, t, unconditional_conditioning) model_output = model_uncond + unconditional_guidance_scale * (model_t - model_uncond)
例如,使用 guess model 生成结果,生成结果更多样,很多部分并没有遵循条件
表示为中间生成的条件图像的长和高的分辨率
代码中获得变量为 detect_resolution,表示为中间生成条件图像的分辨率,后面会将输入模型的条件图像重新变更为 image_resolution
if det == 'None':
detected_map = input_image.copy()
else:
detected_map = preprocessor(resize_image(input_image, detect_resolution), low_threshold, high_threshold)
detected_map = HWC3(detected_map)
例如,我使用 detect_resolution = 256 获得 512* 512的条件结果
表示为生成的图像步数,可以简单的理解为生成图像的步骤数,一般来说如下,但不绝对
代码中为 ddim_steps,表示为传递给生成函数的步数
samples, intermediates = ddim_sampler.sample(ddim_steps, num_samples,
shape, cond, verbose=False, eta=eta,
unconditional_guidance_scale=scale,
unconditional_conditioning=un_cond)
ddim step=20
ddim step=50
表示为负面文本提示的效果和 guess mode的效果,Guidance Scale越大引导效果越强
代码会在生成过程中增加(正面生成结果-负面生成结果)*(Guidance Scale - 1),所以 Guidance Scale 越大,文本引导效果越强
# 添加正面生成条件和负面生成条件的差距的部分,源码 ddim_hacked.py 的 p_sample_ddim 函数
if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
model_output = self.model.apply_model(x, t, c)
else:
model_t = self.model.apply_model(x, t, c)
model_uncond = self.model.apply_model(x, t, unconditional_conditioning)
model_output = model_uncond + unconditional_guidance_scale * (model_t - model_uncond)
例如下文是降低Guidance Scale的对比图
表示生成过程中的随机噪声的系数
代码中表示为构造采样器的过程
def make_schedule(self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0., verbose=True): self.ddim_timesteps = make_ddim_timesteps(ddim_discr_method=ddim_discretize, num_ddim_timesteps=ddim_num_steps, num_ddpm_timesteps=self.ddpm_num_timesteps,verbose=verbose) alphas_cumprod = self.model.alphas_cumprod assert alphas_cumprod.shape[0] == self.ddpm_num_timesteps, 'alphas have to be defined for each timestep' to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device) self.register_buffer('betas', to_torch(self.model.betas)) self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod)) self.register_buffer('alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev)) # calculations for diffusion q(x_t | x_{t-1}) and others self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu()))) self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod.cpu()))) self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod.cpu()))) self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu()))) self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu() - 1))) # ddim sampling parameters ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters(alphacums=alphas_cumprod.cpu(), ddim_timesteps=self.ddim_timesteps, eta=ddim_eta,verbose=verbose) self.register_buffer('ddim_sigmas', ddim_sigmas) self.register_buffer('ddim_alphas', ddim_alphas) self.register_buffer('ddim_alphas_prev', ddim_alphas_prev) self.register_buffer('ddim_sqrt_one_minus_alphas', np.sqrt(1. - ddim_alphas)) sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt( (1 - self.alphas_cumprod_prev) / (1 - self.alphas_cumprod) * ( 1 - self.alphas_cumprod / self.alphas_cumprod_prev)) self.register_buffer('ddim_sigmas_for_original_num_steps', sigmas_for_original_sampling_steps)
例如下文为 eta = 1 和 0 的对比图,多样性更低
次要的正面提示文本
代码中的变量名为 a_prompt,主要用于构造正面条件的prompt
cond = {"c_concat": [control], "c_crossattn": [model.get_learned_conditioning([prompt + ', ' + a_prompt] * num_samples)]}
un_cond = {"c_concat": None if guess_mode else [control], "c_crossattn": [model.get_learned_conditioning([n_prompt] * num_samples)]}
负面的文本提示,会生成尽量不同于负面文本提示的内容
代码会在生成过程中增加(正面生成结果-负面生成结果)*(Guidance Scale - 1),所以负面文本提示会使得生成结果远离他
# 添加正面生成条件和负面生成条件的差距的部分,源码 ddim_hacked.py 的 p_sample_ddim 函数
if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
model_output = self.model.apply_model(x, t, c)
else:
model_t = self.model.apply_model(x, t, c)
model_uncond = self.model.apply_model(x, t, unconditional_conditioning)
model_output = model_uncond + unconditional_guidance_scale * (model_t - model_uncond)
1.0 模型作者使用 3 百万的图像训练,A100GPU训练100小时
作者修复了1.0训练的数据问题,增强了训练的数据,获得了更加优秀的模型
Canny 1.1 的改进:
- 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
- 因为 Canny 模型是最重要的(也许是最常用的)ControlNet 模型之一,所以我们用一个基金在一台机器上用 8 块 Nvidia A100 80G batchsize 8×32=256 训练了 3 天,花费 72×30= 2160 美元(8 个 A100 80G,每小时 30 美元)。该模型从 Canny 1.0 恢复。
- 一些合理的数据增强应用于训练,如随机左右翻转。
- 尽管很难评估 ControlNet,但我们发现 Canny 1.1 比 Canny 1.0 更健壮,视觉质量也更高。
所谓 canny 图像实际上使用 opencv 获取的边缘检测图像
代码上为调用 opencv-python 的 Canny 函数,该函数用于实现 Canny 边缘检测算法,可以检测出图像中的边缘。函数包括以下参数:
注意这里的阈值是算法计算每一个像素点的梯度的阈值,并不是颜色
class CannyDetector:
def __call__(self, img, low_threshold, high_threshold):
return cv2.Canny(img, low_threshold, high_threshold)
low_threshold,high_threshold
表示为获取边缘的阈值调价,一般而言,阈值越低获取的边缘细密,越高越概括
例1,我是用 [1,50) 的阈值的结果
例2,我是用 [200,250) 的阈值的结果
直线检测图
这是一个在建筑上面更加使用的条件
简而言之,修复了数据集的错误,增强了数据集
- 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
- 我们通过使用 MLSD 查找其中包含超过 16 条直线的图像,增加了 300K 个图像,从而扩大了训练数据集。
- 一些合理的数据增强应用于训练,如随机左右翻转。
- 从 MLSD 1.0 恢复并继续使用 A100 80G 的 200 GPU 小时进行训练。
作者用了一个简单的直线检测的模型,来预测图上的直线,源码中 annotator\mlsd 路径下有详细代码。Hough value threshold (MLSD) 和 Hough distance threshold (MLSD) 分别表示为对网络预测结果值和长度的过滤,代码分析模型输出的得分和直线长度,排除得分低和长度短的直线,绘制满足条件的直线坐标。
代码后处理如下
def pred_lines(image, model, input_shape=[512, 512], score_thr=0.10, dist_thr=20.0): h, w, _ = image.shape h_ratio, w_ratio = [h / input_shape[0], w / input_shape[1]] resized_image = np.concatenate([cv2.resize(image, (input_shape[1], input_shape[0]), interpolation=cv2.INTER_AREA), np.ones([input_shape[0], input_shape[1], 1])], axis=-1) resized_image = resized_image.transpose((2,0,1)) batch_image = np.expand_dims(resized_image, axis=0).astype('float32') batch_image = (batch_image / 127.5) - 1.0 batch_image = torch.from_numpy(batch_image).float().cuda() outputs = model(batch_image) pts, pts_score, vmap = deccode_output_score_and_ptss(outputs, 200, 3) start = vmap[:, :, :2] end = vmap[:, :, 2:] dist_map = np.sqrt(np.sum((start - end) ** 2, axis=-1)) segments_list = [] for center, score in zip(pts, pts_score): y, x = center distance = dist_map[y, x] if score > score_thr and distance > dist_thr: disp_x_start, disp_y_start, disp_x_end, disp_y_end = vmap[y, x, :] x_start = x + disp_x_start y_start = y + disp_y_start x_end = x + disp_x_end y_end = y + disp_y_end segments_list.append([x_start, y_start, x_end, y_end]) lines = 2 * np.array(segments_list) # 256 > 512 lines[:, 0] = lines[:, 0] * w_ratio lines[:, 1] = lines[:, 1] * h_ratio lines[:, 2] = lines[:, 2] * w_ratio lines[:, 3] = lines[:, 3] * h_ratio return lines
例如,我将 Hough value threshold (MLSD) 从 0. 1 调整为 0.5 和 Hough distance threshold (MLSD) 从 0. 1 调整为 10 获得的直线更加稀疏和更加提纲挈领
基于模型预测的深度图生成
简而言之,相比 1.0
训练数据:Midas depth(分辨率256/384/512)+ Leres Depth(分辨率256/384/512)+ Zoe Depth(分辨率256/384/512)。多分辨率的多深度图生成器作为数据增强。
深度 1.1 的改进:
- 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
- 新的深度模型是一个相对无偏的模型。它没有通过某种特定的深度估计方法以某种特定类型的深度进行训练。它不会过度适合一个预处理器。这意味着该模型将在不同的深度估计、不同的预处理器分辨率甚至 3D 引擎创建的真实深度下更好地工作。
- 一些合理的数据增强应用于训练,如随机左右翻转。
- 该模型从深度 1.0 恢复,它应该在深度 1.0 运行良好的所有情况下运行良好。如果没有,请打开图像问题,我们将查看您的案例。Depth 1.1 在 depth 1.0 的许多失败案例中效果很好。
- 如果您使用具有 384 预处理器分辨率的 Midas 深度(webui 插件中的“深度”),则深度 1.0 和 1.1 之间的差异应该很小。但是,如果您尝试其他预处理器分辨率或其他预处理器(如 leres 和 zoe),深度 1.1 预计会比 1.0 好一点。
简而言之,作者训练了一个基于 NNET(一个用于检测表面法线的模型) 的网络来替换原来基于 midas 的方法
- Normal 1.0 中的 normal-from-midas 方法既不合理也不正确。该方法在许多图像中效果不佳。法线 1.0 模型无法解释渲染引擎创建的真实法线贴图。
- 这个 Normal 1.1 更合理,因为预处理器经过训练可以使用相对正确的协议(NYU-V2 的可视化方法)来估计法线贴图。这意味着法线 1.1 可以解释来自渲染引擎的真实法线贴图,只要颜色正确(蓝色在前面,红色在左边,绿色在上面)。
- 在我们的测试中,这个模型是健壮的,可以达到与深度模型相似的性能。在之前的 CNET 1.0 中,Normal 1.0 并不是很常用。但是这个 Normal 2.0 有了很大的改进,并且有可能被更频繁地使用。
COCO 和 ADE20K 是两个大型图像和分割掩码的数据集
两个数据集的分割掩码标准是不一样的,例如 ADE20K中0可能对应房子,COCO中0可能对应另外的东西。作者发现,不同的掩码标准会提升模型能力。
分段 1.1 的改进:
- 支持 COCO 协议。之前的Segmentation 1.0支持大约150种颜色,但是Segmentation 1.1支持coco另外182种颜色。
- 从分段 1.0 恢复。所有以前的输入应该仍然有效。
- 这个修复 ControlNet 使用 50% 的随机掩码和 50% 的随机光流遮挡掩码进行训练。这意味着该模型不仅可以支持修复应用程序,还可以处理视频光流扭曲。也许我们将来会提供一些示例(取决于我们的工作量)。
- 此 gradio 演示不包括后期处理。理想情况下,您需要在每次扩散迭代中对潜像进行后处理,并对 vae 解码后的图像进行后处理,使未遮罩区域保持不变。然而,这实现起来很复杂,也许更好的想法是在 a1111 中实现。在这个 gradio 示例中,输出只是扩散的原始输出,图像中未遮罩的区域可能会因为 vae 或扩散过程而改变。
基于线稿的图像生成
这个模型来自于:
https://huggingface.co/spaces/awacke1/Image-to-Line-Drawings
作者新增的一个生成模型,作者特意提到可以使用手画的线稿生成
基于提取的漫画线稿和真实漫画线稿的生成图像
需要额外的模型 anything-v3-full.safetensors
链接:https://huggingface.co/Linaqruf/anything-v3.0/tree/main
简而言之
Openpose 1.1 的改进:
- 这个模型的改进主要是基于我们对OpenPose的改进实现。我们仔细回顾了pytorch的OpenPose和CMU的c++ openpose的区别。现在处理器应该更准确,尤其是手。处理器的改进导致了Openpose 1.1的改进。
- 支持更多输入(手和脸)。
- 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
作者改进了提取身体姿态的方法,除了身体新增了对脸和手的检测,所以可以检测了身体、脸和手的多种组合
为了方便使用,只提供Openpos_full(身体+脸+手)和openpose(身体)两种检测模式
代码中,作者加载了新的模型
class OpenposeDetector: def __init__(self): body_modelpath = os.path.join(annotator_ckpts_path, "body_pose_model.pth") hand_modelpath = os.path.join(annotator_ckpts_path, "hand_pose_model.pth") face_modelpath = os.path.join(annotator_ckpts_path, "facenet.pth") if not os.path.exists(body_modelpath): from basicsr.utils.download_util import load_file_from_url load_file_from_url(body_model_path, model_dir=annotator_ckpts_path) if not os.path.exists(hand_modelpath): from basicsr.utils.download_util import load_file_from_url load_file_from_url(hand_model_path, model_dir=annotator_ckpts_path) if not os.path.exists(face_modelpath): from basicsr.utils.download_util import load_file_from_url load_file_from_url(face_model_path, model_dir=annotator_ckpts_path) self.body_estimation = Body(body_modelpath) self.hand_estimation = Hand(hand_modelpath) self.face_estimation = Face(face_modelpath)
例如,使用openpose_full 生成了具体的脸和部分手
使用 gradio_scribble.py 支持从图像提取涂鸦和直接输入涂鸦
使用 gradio_scribble_interactive.py 支持直接绘制涂鸦
Scribble 1.1 的改进:
- 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
- 我们发现用户有时喜欢画很粗的涂鸦。因此,我们使用更积极的随机形态变换来合成涂鸦。即使涂鸦相对较粗(训练数据的最大宽度为 512 画布中的 24 像素宽度的涂鸦,但即使对于更宽的涂鸦,它似乎也能正常工作;最小宽度为 1 像素,此模型应该也能正常工作).
- 从 Scribble 1.0 恢复,继续使用 A100 80G 的 200 GPU 小时。
class HEDdetector: def __init__(self): remote_model_path = "https://huggingface.co/lllyasviel/Annotators/resolve/main/ControlNetHED.pth" modelpath = os.path.join(annotator_ckpts_path, "ControlNetHED.pth") if not os.path.exists(modelpath): from basicsr.utils.download_util import load_file_from_url load_file_from_url(remote_model_path, model_dir=annotator_ckpts_path) self.netNetwork = ControlNetHED_Apache2().float().cuda().eval() self.netNetwork.load_state_dict(torch.load(modelpath)) def __call__(self, input_image, safe=False): assert input_image.ndim == 3 H, W, C = input_image.shape with torch.no_grad(): image_hed = torch.from_numpy(input_image.copy()).float().cuda() image_hed = rearrange(image_hed, 'h w c -> 1 c h w') edges = self.netNetwork(image_hed) edges = [e.detach().cpu().numpy().astype(np.float32)[0, 0] for e in edges] edges = [cv2.resize(e, (W, H), interpolation=cv2.INTER_LINEAR) for e in edges] edges = np.stack(edges, axis=2) edge = 1 / (1 + np.exp(-np.mean(edges, axis=2).astype(np.float64))) if safe: edge = safe_step(edge) edge = (edge * 255.0).clip(0, 255).astype(np.uint8) return edge def safe_step(x, step=2): y = x.astype(np.float32) * float(step + 1) y = y.astype(np.int32).astype(np.float32) / float(step) return y
Soft Edge 1.1 的改进:
- Soft Edge 1.1 在以前的 ControlNet 中称为 HED 1.0。
- 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
- Soft Edge 1.1 明显(几乎 100% 的情况下)优于 HED 1.0。这主要是因为 HED 或 PIDI 估计器倾向于将损坏的原始图像的灰度版本隐藏在软边缘图中,而之前的模型 HED 1.0 过度拟合以恢复隐藏的损坏图像而不是执行边界感知扩散。Soft Edge 1.1 的训练使用了 75% 的“安全”过滤来去除此类隐藏的损坏灰度图像内部控制图。这使得 Soft Edge 1.1 非常强大。在实际测试中,Soft Edge 1.1 与深度模型一样可用,并且有可能被更频繁地使用。
作者给出了性能比较
性能可以大致记为:
鲁棒性:SoftEdge_PIDI_safe > SoftEdge_HED_safe >> SoftEdge_PIDI > SoftEdge_HED
最高结果质量:SoftEdge_HED > SoftEdge_PIDI > SoftEdge_HED_safe > SoftEdge_PIDI_safe
考虑到权衡,我们建议默认使用 SoftEdge_PIDI。在大多数情况下,它工作得很好。
softedge_pidi、softedge_pidi_safe、softedge_hed、softedge_hed_safe即为使用提取边缘图像的方法,softedge_pidi和softedge_hed为1.0版本中的算法,safe后缀为上文提到的改进
这是一种的将图像像素随机重排作为图像生成条件的模型
将图像像素随机重排曾被用来当作图像的风格特征,所以作者推出这个模型
由于是将图像像素重拍,所以图像不重排也是一种重排后的结果,可以将原图作为输入,一样得到较好的结果
自己训练的注意项:
请注意,此 ControlNet 需要在 ControlNet 编码器输出和 SD Unet 层之间添加全局平均池“x = torch.mean(x, dim=(2, 3), keepdim=True)”。并且 ControlNet 必须仅放在 cfg 规模的条件侧。我们建议使用 yaml 文件中的“global_average_pooling”项来控制此类行为。
描述性的文本:一只玩偶正在燃烧
指令性文本:让这个玩偶烧起来
关于这个模型,作者提到以下几点
所以会得到以下几个结论:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。