目录
准备开发环境
你需要准备好的有
- python3.8+
- pip
- git
你可以创建一个专用于这个项目的虚拟环境
python3 -m venv env-name
#however我使用自己原来使用的用于深度学习的环境DLenvironment
然后你要激活虚拟环境才能安装对应的库
#我的macOS用的是
source env-name/bin/activate
#如果你下载了conda其实会更方便
conda create ...
conda activate ...
#如果你是Windows系统
env-name\Scripts\activate
然后在你的虚拟环境中安装PyTorch
pip install torch torchvision
克隆pytorch风格迁移项目
奈斯!PyTorch 官方已经写好了一个经典的“快速风格迁移”项目(Fast Neural Style)😋
git clone https://github.com/pytorch/examples.git
cd examples/fast_neural_style
里面的结构差不多是: fast_neural_style/
- evaluate.py
- train.py
- transformer_net.py
- utils.py
- saved_models/ 也就是放预训练模型的地方
- images/
接下来我们就要下载预训练风格模型啦😄
下载预训练的风格模型
官方提供了以下几种预训练的画风:
- 马赛克(mosaic)
- 糖果风(candy)
- 雨公主(rain_princess)
- 梵高印象派(udnie)
接下来我们会用梵高的风格为示例进行实践。
由于我不打算在在这个仓库里面做这个项目,我新建了一个文件夹AI-Style-transfer,然后我将fast_neural_style目录下的所有内容都转移到了AI-Style-transfer中。
- 接下来我们要下载预训练模型到saved_models目录当中
mkdir -p saved_models
然后运行download_saved_models.py
示例图生成
现在我们要在项目的根目录下执行这个neural_style.py文件,并且要选定好参数
python neural_style/neural_style.py eval \
--content-image images/content-images/test.png \
--model saved_models/udnie.pth \
--output-image images/output-images/output-udnie.png \
--cuda 0
#eval表示使用推理模式而不是训练模式
#content-image是需要风格化的图片的路径
#model是你需要使用的预训练的风格迁移模型
#output-image是结果保存路径
#cuda 0表示使用GPU,如果没有GPU则删掉这一行
自定义风格
然后接下来的内容相比刚才会加大难度,我打算训练一个彩铅风格的模型进行风格迁移。
实践步骤大致如下
- 准备彩铅风格的数据集
- 准备内容图片集
- 修改训练脚本(这个neural_style.py有推理模式那么反过来也有–train训练模式)
- 风格应用
准备彩铅风格数据集
- 网上尝试下载了一个结果并不符合要求(大哭)
最终尝试调用生图模型生成彩铅画(风格也比较统一)
准备内容图片集
因为不打算找太大规模的数据集,我找了COCO-val2017,里面有5K张图片,对于自己这个小项目绰绰有余矣。(我甚至删减到999张)
我将风格数据集和内容数据集的文件都命名为001开始的编号
对于风格图像的训练,每次仅支持单图,这里参考了GPT先生对neural_style.py的修改方法: 原有的:
style = utils.load_image(args.style_image, size=args.style_size)
style = style_transform(style)
style = style.repeat(args.batch_size, 1, 1, 1).to(device)
features_style = vgg(utils.normalize_batch(style))
gram_style = [utils.gram_matrix(y) for y in features_style]
修改为:
# =============================
# 支持多张风格图像
# =============================
style_paths = []
if os.path.isdir(args.style_image):
for fname in os.listdir(args.style_image):
if fname.lower().endswith(('.jpg', '.jpeg', '.png')):
style_paths.append(os.path.join(args.style_image, fname))
if len(style_paths) == 0:
raise ValueError(f"No style images found in folder: {args.style_image}")
print(f"Found {len(style_paths)} style images in folder.")
else:
# 兼容单张风格图的老用法
style_paths = [args.style_image]
原来的:
for e in range(args.epochs):
transformer.train()
agg_content_loss = 0.
agg_style_loss = 0.
count = 0
for batch_id, (x, _) in enumerate(train_loader):
n_batch = len(x)
count += n_batch
optimizer.zero_grad()
x = x.to(device)
y = transformer(x)
y = utils.normalize_batch(y)
x = utils.normalize_batch(x)
features_y = vgg(y)
features_x = vgg(x)
content_loss = args.content_weight * mse_loss(features_y.relu2_2, features_x.relu2_2)
style_loss = 0.
for ft_y, gm_s in zip(features_y, gram_style):
gm_y = utils.gram_matrix(ft_y)
style_loss += mse_loss(gm_y, gm_s[:n_batch, :, :])
style_loss *= args.style_weight
total_loss = content_loss + style_loss
total_loss.backward()
optimizer.step()
修改为:
for e in range(args.epochs):
transformer.train()
agg_content_loss = 0.
agg_style_loss = 0.
count = 0
for batch_id, (x, _) in enumerate(train_loader):
n_batch = len(x)
count += n_batch
optimizer.zero_grad()
# ========= 随机抽一张风格图 =========
style_path = np.random.choice(style_paths)
style_img = utils.load_image(style_path, size=args.style_size)
style_img = style_transform(style_img)
style_img = style_img.repeat(n_batch, 1, 1, 1).to(device)
features_style = vgg(utils.normalize_batch(style_img))
gram_style = [utils.gram_matrix(y) for y in features_style]
# ========= 内容和风格特征 =========
x = x.to(device)
y = transformer(x)
y = utils.normalize_batch(y)
x = utils.normalize_batch(x)
features_y = vgg(y)
features_x = vgg(x)
# 内容损失
content_loss = args.content_weight * mse_loss(features_y.relu2_2, features_x.relu2_2)
# 风格损失
style_loss = 0.
for ft_y, gm_s in zip(features_y, gram_style):
gm_y = utils.gram_matrix(ft_y)
style_loss += mse_loss(gm_y, gm_s[:n_batch, :, :])
style_loss *= args.style_weight
total_loss = content_loss + style_loss
total_loss.backward()
optimizer.step()
然后使用方法就是
python neural_style/neural_style.py train \
--dataset dataset/content-images \
--style-image dataset/colored-pencil \
--save-model-dir saved_models \
--epochs 8 #--cuda
ps! 值得注意的是,content-images中必须分类,最简单的方法就是创建train文件夹,把图像都放进去,否则就会报错。
风格应用
由于数据集比较小,经过九九八十一难还是没有完全成功。
最初我将自制的彩铅风格数据集110pcs都用于训练,但由于风格上不够统一,导致很多杂色,生成效果非常阴间
然后我仅挑取一张彩铅质感明显的图片作为风格图像,
效果好了点但是色调单一
小结
尽管由于训练量不够,达成的效果不是很好,但是我相信如果制作素描风格这种黑白、色调单一的应该更能成功,至少训练过程中对笔触的模仿已经有较大进展了