基于ModelArts的AI涂鸦
1、问题背景
ChatGPT大行其道的今天,人们趋向于使用智能技术来解决日常的一些问题,不得不说,人工智能技术的发展让人们的发展有了更多的可能。人们的想法也将更容易的编程现实,比如:绘画。受限于绘画技术,往往普通人是无法准确描绘出他们脑海中的图景的,但是AI涂鸦给了他们这种可能性。
2、AI涂鸦的实现步骤
2.1布置ModelArts环境
首先,需要注册一个华为账号,即可开始布置ModelArts环境。点击下方的Run in ModelArts,即可开启ModelArts,登录华为账后后需要等待。
直至出现了“切换规格”,点击切换规格,选择适合自己的规格即可,这里推荐大家使用“限时免费”,对于本实践的规模来说,限时免费足够完成实践了。相对而言对于大型项目,则需要选择其他选项。
最后,这样就可以开始了,在开始之前还有一些说明。本实践需使用 Pytorch-1.8 GPU-P100 及以上规格运行。Scribble 用于预处理用户绘制的涂鸦, 这个预处理程序不应该用在真实的图像上。由于它能够根据简单的草图生成令人惊叹、逼真或改进的图像。理想情况下,不需要任何提示。通过输入一个基本的图画,模型可以推断出细节和纹理,从而产生一个更高质量的图像。
2.2编写程序
①环境设置
首先,拷贝代码及数据,代码如下:
import os
import moxing as mox
parent = "/home/ma-user/work/ControlNet"
bfp = "/home/ma-user/work/ControlNet/openai/clip-vit-large-patch14/pytorch_model.bin"
sfp = "/home/ma-user/work/ControlNet/models/control_sd15_scribble.pth"
if not os.path.exists(parent):
mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/scribble2img/ControlNet',parent)
if os.path.exists(parent):
print('Download success')
else:
raise Exception('Download Failed')
elif os.path.exists(bfp)==False or os.path.getsize(bfp)!=1710671599:
mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/scribble2img/ControlNet/openai/clip-vit-large-patch14/pytorch_model.bin', bfp)
elif os.path.exists(sfp)==False or os.path.getsize(sfp)!=5710757851:
mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/scribble2img/ControlNet/models/control_sd15_scribble.pth', sfp)
else:
print("Model Package already exists!")
mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/course/ModelBox/frpc_linux_amd64', 'frpc_linux_amd64')
输出结果:Model Package already exists!
继续创建虚拟环境,代码如下:
!/home/ma-user/anaconda3/bin/conda create -n py38 python=3.8.13 -y
!/home/ma-user/anaconda3/envs/py38/bin/pip install ipykernel
输出结果:
Successfully installed asttokens-2.2.1 backcall-0.2.0 comm-0.1.3 debugpy-1.6.6 decorator-5.1.1 executing-1.2.0 importlib-metadata-6.8.0 ipykernel-6.23.1 ipython-8.10.0 jedi-0.18.2 jupyter-client-8.2.0 jupyter-core-5.3.0 matplotlib-inline-0.1.3 nest-asyncio-1.5.4 packaging-23.2 parso-0.8.3 pexpect-4.8.0 pickleshare-0.7.5 platformdirs-3.0.0 prompt-toolkit-3.0.38 psutil-5.9.4 ptyprocess-0.7.0 pure-eval-0.2.2 pygments-2.14.0 python-dateutil-2.8.2 pyzmq-25.1.1 six-1.16.0 stack-data-0.6.2 tornado-6.3.3 traitlets-5.9.0 wcwidth-0.2.5 zipp-3.15.0
代码:
import json
import os
data = {
"display_name": "Python38",
"env": {
"PATH": "/home/ma-user/anaconda3/envs/py38/bin:/home/ma-user/anaconda3/envs/python-3.7.10/bin:/modelarts/authoring/notebook-conda/bin:/opt/conda/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/ma-user/modelarts/ma-cli/bin:/home/ma-user/modelarts/ma-cli/bin:/home/ma-user/anaconda3/envs/PyTorch-1.8/bin"
},
"language": "python",
"argv": [
"/home/ma-user/anaconda3/envs/py38/bin/python",
"-m",
"ipykernel",
"-f",
"{connection_file}"
]
}
if not os.path.exists("/home/ma-user/anaconda3/share/jupyter/kernels/py38/"):
os.mkdir("/home/ma-user/anaconda3/share/jupyter/kernels/py38/")
with open('/home/ma-user/anaconda3/share/jupyter/kernels/py38/kernel.json', 'w') as f:
json.dump(data, f, indent=4)
输出结果:无。
创建完成后,稍等片刻,或刷新页面,点击右上角kernel选择py38。
验证环境是否安装成功,显示版本为3.8.13则说明环境安装成功。代码如下:
!python -V
输出结果:Python 3.8.13
安装依赖库,代码如下:
!pip install torch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1
!pip install omegaconf==2.1.1 einops==0.3.0
!pip install pytorch-lightning==1.9.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
!pip install transformers==4.19.2 open_clip_torch==2.0.2
!pip install gradio==3.38.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
!pip install translate==3.6.1
!pip install opencv-python
!mv frpc_linux_amd64 /home/ma-user/anaconda3/envs/py38/lib/python3.8/site-packages/gradio/frpc_linux_amd64_v0.2
!chmod +x /home/ma-user/anaconda3/envs/py38/lib/python3.8/site-packages/gradio/frpc_linux_amd64_v0.2
结果:
Requirement already satisfied: numpy>=1.17.0 in /home/ma-user/anaconda3/envs/py38/lib/python3.8/site-packages (from opencv-python) (1.24.4)
Installing collected packages: opencv-python
Successfully installed opencv-python-4.8.0.76
代码:%cd /home/ma-user/work/ControlNet
输出结果:/home/ma-user/work/ControlNet
②加载模型
导包并加载模型,加载约40s,请耐心等待。代码如下:
import numpy as np
from PIL import Image as PilImage
import cv2
import einops
import matplotlib.pyplot as plt
from IPython.display import HTML, Image
from base64 import b64decode
from translate import Translator
import torch
from pytorch_lightning import seed_everything
import config
from cldm.model import create_model, load_state_dict
from ldm.models.diffusion.ddim import DDIMSampler
from annotator.util import resize_image, HWC3
model = create_model('./models/cldm_v15.yaml')
model.load_state_dict(load_state_dict('./models/control_sd15_scribble.pth', location='cuda'))
model = model.cuda()
ddim_sampler = DDIMSampler(model)
输出结果(这段会有点长,不过没有关系):
Loaded model config from [./models/cldm_v15.yaml]
Loaded state_dict from [./models/control_sd15_scribble.pth]
③涂鸦生成图像
涂鸦生成图像函数,代码如下:
def process(input_image, prompt, a_prompt, n_prompt, num_samples, image_resolution, ddim_steps, strength, scale, seed, eta):
trans = Translator(from_lang="ZH",to_lang="EN-US")
prompt = trans.translate(prompt)
a_prompt = trans.translate(a_prompt)
n_prompt = trans.translate(n_prompt)
guess_mode = False
# 图像预处理
with torch.no_grad():
if type(input_image) is str:
input_image = np.array(PilImage.open(input_image))
img = resize_image(HWC3(input_image), image_resolution)
else:
img = resize_image(HWC3(input_image['mask'][:, :, 0]), image_resolution) # scribble
H, W, C = img.shape
# 初始化检测映射
detected_map = np.zeros_like(img, dtype=np.uint8)
detected_map[np.min(img, axis=2) > 127] = 255
control = torch.from_numpy(detected_map.copy()).float().cuda() / 255.0
control = torch.stack([control for _ in range(num_samples)], dim=0)
control = einops.rearrange(control, 'b h w c -> b c h w').clone()
# 设置随机种子
if seed == -1:
seed = random.randint(0, 65535)
seed_everything(seed)
if config.save_memory:
model.low_vram_shift(is_diffusing=False)
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) # Magic number.
samples, intermediates = ddim_sampler.sample(ddim_steps, num_samples,
shape, cond, verbose=False, eta=eta,
unconditional_guidance_scale=scale,
unconditional_conditioning=un_cond)
if config.save_memory:
model.low_vram_shift(is_diffusing=False)
# 后处理
x_samples = model.decode_first_stage(samples)
x_samples = (einops.rearrange(x_samples, 'b c h w -> b h w c') * 127.5 + 127.5).cpu().numpy().clip(0, 255).astype(np.uint8)
results = [x_samples[i] for i in range(num_samples)]
return [255 - detected_map] + results
输出结果:无。
(设置参数,生成图像,可以直接跳过)
在页面左侧边栏,进入文件视图,在ControlNet/test_imgs/路径下(实际完整路径为/home/ma-user/work/ControlNet/test_imgs/ ),我们预置了一些线稿供您测试。当然您可以自己上传您的涂鸦画至此路径下,然后更改图像路径及其他参数后,点击运行。
④参数说明
images:生成图像张数
img_path:输入图像路径,黑白稿
prompt:提示词(建议填写)
a_prompt:正面提示(可选,要附加到提示的其他文本)
n_prompt: 负面提示(可选)
image_resolution: 对输入的图片进行最长边等比resize
scale:classifier-free引导比例
seed: 随机种子
ddim_steps: 采样步数,一般15-30,值越大越精细,耗时越长
eta: 控制在去噪扩散过程中添加到输入数据的噪声量。0表示无噪音,1.0表示更多噪音。eta对图像有微妙的、不可预测的影响,所以您需要尝试一下这如何影响您的项目。
strength: 这是应用 ControlNet 的步骤数。它类似于图像到图像中的去噪强度。如果指导强度为 1,则 ControlNet 应用于 100% 的采样步骤。如果引导强度为 0.7 并且您正在执行 50 个步骤,则 ControlNet 将应用于前 70% 的采样步骤,即前 35 个步骤。
代码如下:
#@title Scribble2Img
img_path = "test_imgs/cat.jpg" #@param {type:"string"}
prompt = "小花猫" #@param {type:"string"}
num_samples = 1
# Added Prompt
a_prompt = "质量最好,非常详细" #@param {type:"string"}
# Negative Prompt
n_prompt = "裁剪,质量最差,质量低" #@param {type:"string"}
image_resolution = 512 #@param {type:"raw", dropdown}
scale = 4.3 #@param {type:"slider", min:0.1, max:30, step:0.1}
seed = 1773327477 #@param {type:"slider", min:-1, max:2147483647, step:1}
eta = 0.02 #@param {type:"slider", min:-1.00, max:3.00, step:0.01}
ddim_steps = 15 #@param {type:"slider", min:1, max:100, step:1}
guess_mode = False
strength = 1.0
np_imgs = process(img_path, prompt, a_prompt, n_prompt, num_samples, image_resolution, ddim_steps, strength, scale, seed, eta)
src = PilImage.fromarray(~np_imgs[0])
dst = PilImage.fromarray(np_imgs[1])
fig = plt.figure(figsize=(25, 10))
ax1 = fig.add_subplot(1, 2, 1)
plt.title('Scribble image', fontsize=16)
ax1.axis('off')
ax1.imshow(src)
ax2 = fig.add_subplot(1, 2, 2)
plt.title('Generate image', fontsize=16)
ax2.axis('off')
ax2.imshow(dst)
plt.show()
"输出结果如下图所示:
⑤可能出现的问题
Prompt只支持中英文输入。
所提供的图像或简笔画过于简单或意义不明确时,模型可能生成与上传图像相关度低的物体或是一些无意义的前景物体,可以修改上传图像重新尝试。
在一些场景下,描述Prompt不够明确时,模型可能生成错误的前景物体,可以 更改Prompt并生成多次,取效果较好的结果。
当所提供的图像或简笔画与描述Prompt相关度低或无关时,模型可能生成偏向图像或偏向Prompt的内容,也可能生成无意义的内容;因此建议描述Prompt与所上传的图像紧密相关并且尽可能详细。
⑥扩展:Gradio可视化部署
如果想进行可视化部署,可以继续以下步骤: Gradio应用启动后可在下方页面进行涂鸦生成图像,您也可以分享public url在手机端,PC端进行访问生成图像。
ControlNet扩展说明
图像画布:您可以拖动设置画布宽度和画布高度,然后点击 开启画布! 来创建一张空白画布。
调整笔刷进行绘画
输入描述词(推荐),点击 Run
高级选项(可选),您可点击此选项卡,打开折叠部分,按照上述参数说明进行设置,设置完成后点击 Run,等待。
代码如下:
import gradio as gr
# 画布生成函数
def create_canvas(w, h):
img = np.zeros(shape=(h-2, w-2, 3), dtype=np.uint8) + 255
im = cv2.copyMakeBorder(img,1,1,1,1,cv2.BORDER_CONSTANT)
return im
block = gr.Blocks()
#block = gr.Blocks().queue()
with block:
with gr.Row():
gr.Markdown("## ���涂鸦生成图像")
with gr.Row():
with gr.Column():
canvas_width = gr.Slider(label="画布宽度", minimum=256, maximum=1024, value=512, step=1)
canvas_height = gr.Slider(label="画布高度", minimum=256, maximum=1024, value=512, step=1)
create_button = gr.Button(value='开启画布!')
gr.Markdown(value='点击下面右上角小铅笔图标,改变你的刷子宽度,让它变的更细 (Gradio不允许开发人员设置画笔宽度,因此需要手动设置) ')
input_image = gr.Image(source='upload', type='numpy', tool='sketch')
create_button.click(fn=create_canvas, inputs=[canvas_width, canvas_height], outputs=[input_image])
prompt = gr.Textbox(label="Prompt")
run_button = gr.Button(value="运行")
with gr.Accordion("高级选项", open=False):
num_samples = gr.Slider(label="Images", minimum=1, maximum=3, value=1, step=1)
image_resolution = gr.Slider(label="Image Resolution", minimum=256, maximum=768, value=512, step=64)
strength = gr.Slider(label="Control Strength", minimum=0.0, maximum=2.0, value=1.0, step=0.01)
ddim_steps = gr.Slider(label="Steps", minimum=1, maximum=30, value=20, step=1)
scale = gr.Slider(label="Guidance Scale", minimum=0.1, maximum=30.0, value=9.0, step=0.1)
seed = gr.Slider(label="Seed", minimum=-1, maximum=2147483647, value=1773327477, step=1)
eta = gr.Number(label="eta (DDIM)", value=0.0)
a_prompt = gr.Textbox(label="Added Prompt", value='质量最好,非常详细')
n_prompt = gr.Textbox(label="Negative Prompt",
value='裁剪,质量最差,质量低')
with gr.Column():
result_gallery = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2, height='auto')
ips = [input_image, prompt, a_prompt, n_prompt, num_samples, image_resolution, ddim_steps, strength, scale, seed, eta]
run_button.click(fn=process, inputs=ips, outputs=[result_gallery])
block.launch(share=True)
输出结果如下:
代码:
/tmp/ipykernel_6301/3929944060.py:37: GradioDeprecationWarning: The `style` method is deprecated. Please set these arguments in the constructor instead.
result_gallery = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2, height='auto')
/tmp/ipykernel_6301/3929944060.py:37: GradioDeprecationWarning: The 'grid' parameter will be deprecated. Please use 'grid_cols' in the constructor instead.
result_gallery = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2, height='auto')
Running on local URL: http://127.0.0.1:7860
Running on public URL: https://3318b81fb36ca55cbe.gradio.live
This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from Terminal to deploy to Spaces (https://huggingface.co/spaces)
页面:
同时可以在页面上进行创作绘画和展示AI绘画的图片了。
可以直接调整画布的亮度等简单设置。并且可以在画布上进行自由的作画,作画完运行代码即可显示出AI涂鸦的结果。
运行结果:
当然,也可以点击高级设置进行创作,设置一些限制用以框定绘画的范围。
结果如下:
3. 出现的问题
首先在编程的过程中,我习惯性的点击了Run all cells,但是并没有出现结果。经过检验后,发现是PYTHON版本需要重新设置一下,一个一个cell运行完毕后,就成功的运行出了界面。
改正后的结果:
其次,代码运行中有一些输出结果的代码被标红,经过检验发现没有什么意外的情况,程序正常运转,大家在做实践的时候不用担心,不要着急进行Debug。
4. 总结与展望
本次实践中,我使用MobelArts进行了AI涂鸦,明晰了华为云ModelArts平台的使用 ,良好地应用了华为云的技术,找到了一些在使用ModelArts中可能会出现的问题,完善了AI涂鸦的实践操作说明。
并且我也将在同学们中推广使用华为云技术,让同学们明白 ,一些课程的实践是可以使用华为提供的人工智能平台和算法进行操作的,例如:人工智能 课程的大作业,就可以使用这些智能的算法和平台进行编写,更重要的是让同学们看到中文版的智能操作界面,对于中国的同学们来说,人工智能的门槛将在华为的帮助下降低,这就进一步促进了华为技术的扩展和人工智能行业的繁荣。
最后,ModelArts给了我极大的震撼,相较于大段大段冗长的英文应用说明,华为云技术的开创无疑是一次中国技术前进一大步的前置科技点被点亮。希望我们能够多多使用华为云技术,也希望华为能够得到更好的宣传和发展。
- 点赞
- 收藏
- 关注作者
评论(0)