当前位置:   article > 正文

controlnet 1.1版本更新内容及参数条件详解_controlnet的分辨率参数

controlnet的分辨率参数

前言

作者说明在 1.5 版本前,不会修改训练模型的结构,1.1版本主要增强了鲁棒性和生成图像的质量

  • 值得一提的是,作者更改了demo文件中加载模型的方法,从 stable diffsion model 的预训练模型和 control model 的参数,这样大大降低每个模型的大小,大约只需要 1.5 G,因为预训练文件只保存了control model 的部分
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)
  • 1
  • 2
  • 3

模型命名

模型命令将遵循:

{项目名称,通常为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 标注引导的模型文件

image.png

ControlNet 常规控制参数

image.png

总览

  • prompt:文本提示,建议学习 https://zhuanlan.zhihu.com/p/619247417 类似的文本书写规范
  • Images:一次生成的图像个数
  • Seed:随机种子
  • Preprocessor:若不为 None,会将输入的图像转变为条件图像,否则将输入的图像作为条件图像
  • Image Resolution:生成的条件图像和结果图像的大小,为(Image Resolution* Image Resolution)
  • Control Strength:条件图像的控制强度,越大控制强度越强
  • Guess Model:更不遵守条件图像的生成结果
  • Preprocessor Resolution:中间生成的条件图像的大小,可能会影响条件图像的结果
  • Steps:生成的步数,一般越大越好,但越耗时
  • Guidance Scale:文本提示的控制强度,越大越强
  • DDIM ETA:生成过程中的随机噪声系数,一般选0或1,1表示有噪声更多样,反之没噪声更遵守条件
  • Added Prompt:次要的文本提示
  • Negative Prompt:负面文本提示,不想要的内容

Prompt

表示为文本提示,因为文本提示给的是 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)]}
  • 1
  • 2

例如,我使用 cow doll 引导生成的牛牛的玩偶
image.png

Images

表示需要生成的图像数量,代码中为变量 num_samples 用于构造 batch_size

control = torch.stack([control for _ in range(num_samples)], dim=0)
  • 1

例如使用 images = 2 生成 2 张图像
image.png

Seed

表示设置的全局随机种子,控制生成过程中的所有随机变量,即使用相同的随机种子将会得到相同的结果
代码中使用 pytorch_lighting 的 seed_everything 函数,该函数会设置以下的随机变量的随机种子:

  • Python 内置的随机数生成器 (random package)
  • NumPy 库的随机数生成器 (numpy.random package)
  • PyTorch 库的随机数生成器 (torch package)
        if seed == -1:
            seed = random.randint(0, 65535)
        seed_everything(seed)
  • 1
  • 2
  • 3

例如下图我使用相同的随机数种子生成的图像与上文相同
image.png
下图中我将 seed 从 12345 改为 12346 就获得不一样的效果
image.png

Preprocessor

若不为 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)
  • 1
  • 2
  • 3
  • 4
  • 5

例如,下图我使用自己生成的条件图像生成图像
image.png

Image Resolution

表示为生成图像的长和高的分辨率
代码中获得变量为 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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

例如,我使用 image_resolution = 256 获得 256 *256 的结果
image.png
image.png

Control Strength

表示为 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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

例如,这是我使用默认参数+seed=12346+Control Strength为1、2 的生成结果,显然图2相对来说更加遵守条件,因为他将玩偶草图眼睛上面的东西生成了出来
image.png
image.png

Guess Mode

表示为使用更多样性的结果,生成后得到不那么遵守图像条件的结果
代码中

  1. 构造没有图像条件的负面生成条件,因为生成过程会添加正面生成条件和负面生成条件的差距,使得生成的更加多样
  2. 更小的control model 生成的条件权重,使得更加不遵守条件
# 构造生成条件的部分
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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

例如,使用 guess model 生成结果,生成结果更多样,很多部分并没有遵循条件
image.png

Preprocessor Resolution

表示为中间生成的条件图像的长和高的分辨率
代码中获得变量为 detect_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)
  • 1
  • 2
  • 3
  • 4
  • 5

例如,我使用 detect_resolution = 256 获得 512* 512的条件结果
image.png
image.png

Steps

表示为生成的图像步数,可以简单的理解为生成图像的步骤数,一般来说如下,但不绝对

  • 步数越长,生成的耗时越长
  • 步数越长,生成质量越好
  • 步数越长,多样性越低,越遵循条件(文字和图像条件)

代码中为 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)
  • 1
  • 2
  • 3
  • 4

ddim step=20
image.png
ddim step=50
image.png

Guidance Scale

表示为负面文本提示的效果和 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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

例如下文是降低Guidance Scale的对比图
image.png
image.png

DDIM ETA

表示生成过程中的随机噪声的系数
image.png
image.png
代码中表示为构造采样器的过程

    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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

例如下文为 eta = 1 和 0 的对比图,多样性更低
image.png
image.png

Added Prompt

次要的正面提示文本
代码中的变量名为 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)]}
  • 1
  • 2

Negative Prompt

负面的文本提示,会生成尽量不同于负面文本提示的内容
代码会在生成过程中增加(正面生成结果-负面生成结果)*(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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

预训练模型更新内容

Canny

更新:更好的数据

1.0 模型作者使用 3 百万的图像训练,A100GPU训练100小时
作者修复了1.0训练的数据问题,增强了训练的数据,获得了更加优秀的模型

Canny 1.1 的改进:

  1. 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
  2. 因为 Canny 模型是最重要的(也许是最常用的)ControlNet 模型之一,所以我们用一个基金在一台机器上用 8 块 Nvidia A100 80G batchsize 8×32=256 训练了 3 天,花费 72×30= 2160 美元(8 个 A100 80G,每小时 30 美元)。该模型从 Canny 1.0 恢复。
  3. 一些合理的数据增强应用于训练,如随机左右翻转。
  4. 尽管很难评估 ControlNet,但我们发现 Canny 1.1 比 Canny 1.0 更健壮,视觉质量也更高。

image.png

条件:low_threshold,high_threshold

所谓 canny 图像实际上使用 opencv 获取的边缘检测图像
代码上为调用 opencv-python 的 Canny 函数,该函数用于实现 Canny 边缘检测算法,可以检测出图像中的边缘。函数包括以下参数:

  • img:输入的源图像,可以是 numpy 数组、图片文件等;
  • low_threshold:低阈值,即低于该阈值的边缘会被抑制;
  • high_threshold:高阈值,即高于该阈值的被认为是强边缘,高低阈值之间的为弱边缘,算法会保留这些弱边缘。

注意这里的阈值是算法计算每一个像素点的梯度的阈值,并不是颜色

class CannyDetector:
    def __call__(self, img, low_threshold, high_threshold):
        return cv2.Canny(img, low_threshold, high_threshold)
  • 1
  • 2
  • 3

low_threshold,high_threshold
表示为获取边缘的阈值调价,一般而言,阈值越低获取的边缘细密,越高越概括
例1,我是用 [1,50) 的阈值的结果
image.png
例2,我是用 [200,250) 的阈值的结果image.png

MLSD

直线检测图
image.png

更新:更好的数据

这是一个在建筑上面更加使用的条件
简而言之,修复了数据集的错误,增强了数据集

  1. 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
  2. 我们通过使用 MLSD 查找其中包含超过 16 条直线的图像,增加了 300K 个图像,从而扩大了训练数据集。
  3. 一些合理的数据增强应用于训练,如随机左右翻转。
  4. 从 MLSD 1.0 恢复并继续使用 A100 80G 的 200 GPU 小时进行训练。

条件:Hough value threshold (MLSD) 、Hough distance threshold (MLSD)

作者用了一个简单的直线检测的模型,来预测图上的直线,源码中 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

例如,我将 Hough value threshold (MLSD) 从 0. 1 调整为 0.5 和 Hough distance threshold (MLSD) 从 0. 1 调整为 10 获得的直线更加稀疏和更加提纲挈领
image.png

Depth

基于模型预测的深度图生成
image.png

更新:更好的数据和兼容更多生成方法

简而言之,相比 1.0

  • 训练数据中增加了使用 Leres Depth 和 Zoe Depth,使用这两类预处理能获得更加好的效果
  • 修复了数据集的错误,增强了数据集

训练数据:Midas depth(分辨率256/384/512)+ Leres Depth(分辨率256/384/512)+ Zoe Depth(分辨率256/384/512)。多分辨率的多深度图生成器作为数据增强。
深度 1.1 的改进:

  1. 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
  2. 新的深度模型是一个相对无偏的模型。它没有通过某种特定的深度估计方法以某种特定类型的深度进行训练。它不会过度适合一个预处理器。这意味着该模型将在不同的深度估计、不同的预处理器分辨率甚至 3D 引擎创建的真实深度下更好地工作。
  3. 一些合理的数据增强应用于训练,如随机左右翻转。
  4. 该模型从深度 1.0 恢复,它应该在深度 1.0 运行良好的所有情况下运行良好。如果没有,请打开图像问题,我们将查看您的案例。Depth 1.1 在 depth 1.0 的许多失败案例中效果很好。
  5. 如果您使用具有 384 预处理器分辨率的 Midas 深度(webui 插件中的“深度”),则深度 1.0 和 1.1 之间的差异应该很小。但是,如果您尝试其他预处理器分辨率或其他预处理器(如 leres 和 zoe),深度 1.1 预计会比 1.0 好一点。

Normal

image.png

更新:改进了生成法线贴图的方法

简而言之,作者训练了一个基于 NNET(一个用于检测表面法线的模型) 的网络来替换原来基于 midas 的方法

  1. Normal 1.0 中的 normal-from-midas 方法既不合理也不正确。该方法在许多图像中效果不佳。法线 1.0 模型无法解释渲染引擎创建的真实法线贴图。
  2. 这个 Normal 1.1 更合理,因为预处理器经过训练可以使用相对正确的协议(NYU-V2 的可视化方法)来估计法线贴图。这意味着法线 1.1 可以解释来自渲染引擎的真实法线贴图,只要颜色正确(蓝色在前面,红色在左边,绿色在上面)。
  3. 在我们的测试中,这个模型是健壮的,可以达到与深度模型相似的性能。在之前的 CNET 1.0 中,Normal 1.0 并不是很常用。但是这个 Normal 2.0 有了很大的改进,并且有可能被更频繁地使用。

Seg

image.png

更新:新增了兼容 COCO 数据集的分割模型

COCO 和 ADE20K 是两个大型图像和分割掩码的数据集
两个数据集的分割掩码标准是不一样的,例如 ADE20K中0可能对应房子,COCO中0可能对应另外的东西。作者发现,不同的掩码标准会提升模型能力。

分段 1.1 的改进:

  1. 支持 COCO 协议。之前的Segmentation 1.0支持大约150种颜色,但是Segmentation 1.1支持coco另外182种颜色。
  2. 从分段 1.0 恢复。所有以前的输入应该仍然有效。

Inpaint

image.png

新增的饼,之后会有视频修复和更好的处理

  • 使用了随机掩码和随机光流(光流可以理解为表示图像变化的表现形式)训练,所以之后可以支持视频补全
  • 后期可能会实现更完善的后处理
  1. 这个修复 ControlNet 使用 50% 的随机掩码和 50% 的随机光流遮挡掩码进行训练。这意味着该模型不仅可以支持修复应用程序,还可以处理视频光流扭曲。也许我们将来会提供一些示例(取决于我们的工作量)。
  2. 此 gradio 演示不包括后期处理。理想情况下,您需要在每次扩散迭代中对潜像进行后处理,并对 vae 解码后的图像进行后处理,使未遮罩区域保持不变。然而,这实现起来很复杂,也许更好的想法是在 a1111 中实现。在这个 gradio 示例中,输出只是扩散的原始输出,图像中未遮罩的区域可能会因为 vae 或扩散过程而改变。

lineart

基于线稿的图像生成
这个模型来自于:
https://huggingface.co/spaces/awacke1/Image-to-Line-Drawings
image.png

新增:基于线稿的图像生成

作者新增的一个生成模型,作者特意提到可以使用手画的线稿生成

Anime Lineart

基于提取的漫画线稿和真实漫画线稿的生成图像
需要额外的模型 anything-v3-full.safetensors
链接:https://huggingface.co/Linaqruf/anything-v3.0/tree/main
image.png

新增:基于动漫线稿的图像生成

  • 建议使用长提示或者Lora
  • 这个模型下没有 guess mode

openpose

image.png

更新:对手和脸的支持,更好的数据集

简而言之

  • 新增openpose和openpose Full 两个新的模式,openpose 只会提取身体,还会提取身体+手+脸
  • 更好的数据集

Openpose 1.1 的改进:

  1. 这个模型的改进主要是基于我们对OpenPose的改进实现。我们仔细回顾了pytorch的OpenPose和CMU的c++ openpose的区别。现在处理器应该更准确,尤其是手。处理器的改进导致了Openpose 1.1的改进。
  2. 支持更多输入(手和脸)。
  3. 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。

条件:Openpose_full,openpose

作者改进了提取身体姿态的方法,除了身体新增了对脸和手的检测,所以可以检测了身体、脸和手的多种组合
为了方便使用,只提供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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

例如,使用openpose_full 生成了具体的脸和部分手
image.png

scribble

使用 gradio_scribble.py 支持从图像提取涂鸦和直接输入涂鸦
使用 gradio_scribble_interactive.py 支持直接绘制涂鸦
image.png

更新:兼容粗细的涂鸦和更好的数据集

  • 使用了更好的数据集
  • 兼容更粗和更细的涂鸦

Scribble 1.1 的改进:

  1. 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
  2. 我们发现用户有时喜欢画很粗的涂鸦。因此,我们使用更积极的随机形态变换来合成涂鸦。即使涂鸦相对较粗(训练数据的最大宽度为 512 画布中的 24 像素宽度的涂鸦,但即使对于更宽的涂鸦,它似乎也能正常工作;最小宽度为 1 像素,此模型应该也能正常工作).
  3. 从 Scribble 1.0 恢复,继续使用 A100 80G 的 200 GPU 小时。

Soft Edge(HED、 PIDI)

image.png

更新:改进边缘提取方法和更好的数据集

  • 用人话说原来的提取边缘算法生成的边缘图数据过于复杂,使得网络没有很好的学到边缘信息,所以作者降低了生成边缘图的复杂度(减少了像素值的种类),提升了效果,代码中为 safe_step
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 更好的数据集

Soft Edge 1.1 的改进:

  1. Soft Edge 1.1 在以前的 ControlNet 中称为 HED 1.0。
  2. 之前cnet 1.0的训练数据集存在几个问题,包括(1)一小部分灰度人像被复制了数千次(!!),导致之前的模型有点可能生成灰度人像;(2) 某些图像质量低下、非常模糊或有明显的 JPEG 伪影;(3) 由于我们数据处理脚本的错误导致一小部分图片出现配对提示错误。新模型修复了训练数据集的所有问题,在很多情况下应该更合理。
  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_pidi_safe、softedge_hed、softedge_hed_safe即为使用提取边缘图像的方法,softedge_pidi和softedge_hed为1.0版本中的算法,safe后缀为上文提到的改进

shuffle

这是一种的将图像像素随机重排作为图像生成条件的模型
将图像像素随机重排曾被用来当作图像的风格特征,所以作者推出这个模型
由于是将图像像素重拍,所以图像不重排也是一种重排后的结果,可以将原图作为输入,一样得到较好的结果
image.png

新增:基于图像重排的图像生成

自己训练的注意项:
请注意,此 ControlNet 需要在 ControlNet 编码器输出和 SD Unet 层之间添加全局平均池“x = torch.mean(x, dim=(2, 3), keepdim=True)”。并且 ControlNet 必须仅放在 cfg 规模的条件侧。我们建议使用 yaml 文件中的“global_average_pooling”项来控制此类行为。

Instruct Pix2Pix

image.png

新增:指令性文本生成模型(实验)

描述性的文本:一只玩偶正在燃烧
指令性文本:让这个玩偶烧起来

  • 作者使用一半描述性文本和一半指令性文本训练模型,所以使用指令性文本生成图像
  • 这是一个实验性的模型,因为很多生成结果并不理想,需要挑选

Tile

image.png

新增:图像超分、图像更清晰、生成新的细节

关于这个模型,作者提到以下几点

  • 这个模型会生成新的细节
  • 若文本提示和图像不符,这个模型会专注于图像信息生成
  • 这是实验性的

所以会得到以下几个结论:

  • 这个模型不是完全的图像超分辨率,因为他会新增图像的细节
  • 他可以为模糊或者抽象的图像添加细节,获得更加完善清晰的图像
  • 他可以为清晰的图像,生成新的细节更加多样
  • 从图像中截取的部分生成,这是stable不能做的,因为文本提示会影响整体生成,但是controlnet会控制图像提示和文本提示的控制强度,所以文本提示不好时,会增强图像提示
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/620600
推荐阅读
相关标签
  

闽ICP备14008679号