当使用with块时无法保存预测模型
Created by: yeyupiaoling
我训练一个对抗生成网络,我想保存预测模型,以便预之后直接使用这个预测模型生成更多的图片,但是我在保存模型的时候就会报错,错误如下所示。
不知道是不是使用with的原因,还是对抗网络模型本身就不允许保存模型。麻烦路过的同学解答下,谢谢。
错误信息:
Traceback (most recent call last):
File "/media/test/5C283BCA283BA1C6/yeyupiaoling/LearnPaddle2/note13/train.py", line 210, in <module>
fluid.io.save_inference_model(save_path, feeded_var_names=[z.name], target_vars=[fake], executor=exe)
File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/io.py", line 681, in save_inference_model
main_program = main_program._prune(targets=target_vars)
File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/framework.py", line 1741, in _prune
"The target variable must have an "
ValueError: The target variable must have an associated operator that generates it.
全部代码:
import os
import shutil
import numpy as np
import paddle
import paddle.fluid as fluid
image_size = 32
# 定义生成器
def Generator(y, name="G"):
def deconv(x, num_filters, filter_size=5, stride=2, dilation=1, padding=2, output_size=None, act=None):
return fluid.layers.conv2d_transpose(input=x,
num_filters=num_filters,
output_size=output_size,
filter_size=filter_size,
stride=stride,
dilation=dilation,
padding=padding,
act=act)
with fluid.unique_name.guard(name + "/"):
# 第一组全连接和BN层
y = fluid.layers.fc(y, size=2048)
y = fluid.layers.batch_norm(y)
# 第二组全连接和BN层
y = fluid.layers.fc(y, size=128 * 8 * 8)
y = fluid.layers.batch_norm(y)
# 进行形状变换
y = fluid.layers.reshape(y, shape=(-1, 128, 8, 8))
# 第一组转置卷积运算
y = deconv(x=y, num_filters=128, act='relu', output_size=[16, 16])
# 第二组转置卷积运算
y = deconv(x=y, num_filters=3, act='sigmoid', output_size=[image_size, image_size])
return y
# 判别器 Discriminator
def Discriminator(images, name="D"):
# 定义一个卷积池化组
def conv_pool(input, num_filters, act=None):
return fluid.nets.simple_img_conv_pool(input=input,
filter_size=3,
num_filters=num_filters,
pool_size=2,
pool_stride=2,
act=act)
with fluid.unique_name.guard(name + "/"):
y = fluid.layers.reshape(x=images, shape=[-1, 3, image_size, image_size])
# 第一个卷积池化组
y = conv_pool(input=y, num_filters=64, act='leaky_relu')
# 第一个卷积池化加回归层
y = conv_pool(input=y, num_filters=128)
y = fluid.layers.batch_norm(input=y, act='leaky_relu')
# 第二个卷积池化加回归层
y = fluid.layers.fc(input=y, size=1024)
y = fluid.layers.batch_norm(input=y, act='leaky_relu')
# 最后一个分类器输出
y = fluid.layers.fc(input=y, size=1, act='sigmoid')
return y
# 创建判别器D识别生成器G生成的假图片程序
train_d_fake = fluid.Program()
# 创建判别器D识别真实图片程序
train_d_real = fluid.Program()
# 创建生成器G生成符合判别器D的程序
train_g = fluid.Program()
# 创建共同的一个初始化的程序
startup = fluid.Program()
# 噪声维度
z_dim = 100
# 从Program获取prefix开头的参数名字
def get_params(program, prefix):
all_params = program.global_block().all_parameters()
return [t.name for t in all_params if t.name.startswith(prefix)]
# 训练判别器D识别真实图片
with fluid.program_guard(train_d_real, startup):
# 创建读取真实数据集图片的data,并且label为1
real_image = fluid.layers.data('image', shape=[3, image_size, image_size])
ones = fluid.layers.fill_constant_batch_size_like(real_image, shape=[-1, 1], dtype='float32', value=1)
# 判别器D判断真实图片的概率
p_real = Discriminator(real_image)
# 获取损失函数
real_cost = fluid.layers.sigmoid_cross_entropy_with_logits(p_real, ones)
real_avg_cost = fluid.layers.mean(real_cost)
# 获取判别器D的参数
d_params = get_params(train_d_real, "D")
# 创建优化方法
optimizer = fluid.optimizer.Adam(learning_rate=2e-4)
optimizer.minimize(real_avg_cost, parameter_list=d_params)
# 训练判别器D识别生成器G生成的图片为假图片
with fluid.program_guard(train_d_fake, startup):
# 利用创建假的图片data,并且label为0
z = fluid.layers.data(name='z', shape=[z_dim])
zeros = fluid.layers.fill_constant_batch_size_like(z, shape=[-1, 1], dtype='float32', value=0)
# 判别器D判断假图片的概率
p_fake = Discriminator(Generator(z))
# 获取损失函数
fake_cost = fluid.layers.sigmoid_cross_entropy_with_logits(p_fake, zeros)
fake_avg_cost = fluid.layers.mean(fake_cost)
# 获取判别器D的参数
d_params = get_params(train_d_fake, "D")
# 创建优化方法
optimizer = fluid.optimizer.Adam(learning_rate=2e-4)
optimizer.minimize(fake_avg_cost, parameter_list=d_params)
# 训练生成器G生成符合判别器D标准的假图片
with fluid.program_guard(train_g, startup):
# 噪声生成图片为真实图片的概率,Label为1
z = fluid.layers.data(name='z', shape=[z_dim])
ones = fluid.layers.fill_constant_batch_size_like(z, shape=[-1, 1], dtype='float32', value=1)
# 生成图片
fake = Generator(z)
# 克隆预测程序
infer_program = train_g.clone(for_test=True)
# 生成符合判别器的假图片
p = Discriminator(fake)
# 获取损失函数
g_cost = fluid.layers.sigmoid_cross_entropy_with_logits(p, ones)
g_avg_cost = fluid.layers.mean(g_cost)
# 获取G的参数
g_params = get_params(train_g, "G")
# 只训练G
optimizer = fluid.optimizer.Adam(learning_rate=2e-4)
optimizer.minimize(g_avg_cost, parameter_list=g_params)
# 噪声生成
def z_reader():
while True:
yield np.random.uniform(-1.0, 1.0, (z_dim)).astype('float32')
# 读取cifar数据集,不使用label
def cifar_reader(reader):
def r():
for img, label in reader():
yield img.reshape(3, 32, 32)
return r
# 生成真实图片reader
mydata_generator = paddle.batch(reader=cifar_reader(paddle.dataset.cifar.train10()), batch_size=128)
# 生成假图片的reader
z_generator = paddle.batch(z_reader, batch_size=128)()
# 创建执行器,最好使用GPU,CPU速度太慢了
# place = fluid.CPUPlace()
place = fluid.CUDAPlace(0)
exe = fluid.Executor(place)
# 初始化参数
exe.run(startup)
# 测试噪声
test_z = np.array(next(z_generator))
# 开始训练
for pass_id in range(100):
for i, real_image in enumerate(mydata_generator()):
# 训练判别器D识别真实图片
r_fake = exe.run(program=train_d_fake,
fetch_list=[fake_avg_cost],
feed={'z': test_z})
# 训练判别器D识别生成器G生成的假图片
r_real = exe.run(program=train_d_real,
fetch_list=[real_avg_cost],
feed={'image': np.array(real_image)})
# 训练生成器G生成符合判别器D标准的假图片
r_g = exe.run(program=train_g,
fetch_list=[g_avg_cost],
feed={'z': test_z})
if i % 100 == 0:
print("Pass:%d, Batch:%d, 训练判别器D识别真实图片Cost:%0.5f, "
"训练判别器D识别生成器G生成的假图片Cost:%0.5f, "
"训练生成器G生成符合判别器D标准的假图片Cost:%0.5f" % (pass_id, i, r_fake[0], r_real[0], r_g[0]))
# 保存预测模型
save_path = 'infer_model/'
# 删除旧的模型文件
shutil.rmtree(save_path, ignore_errors=True)
# 创建保持模型文件目录
os.makedirs(save_path)
# 保存预测模型
fluid.io.save_inference_model(save_path, feeded_var_names=[z.name], target_vars=[fake], executor=exe)