Я пытаюсь преобразовать код TensorFlow в Keras, я не очень разбираюсь в Keras api.
Это ACGAN, который может генерировать аватары персонажей, вот код Tensorflow:
from tqdm import tqdm
import glob
from imageio import imread, imsave, mimsave
import os
import tensorflow as tf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# load image
images = glob.glob('faces/*.jpg')
print(len(images))
# load tag
tags = pd.read_csv('face_tags.txt')
tags.index = tags['id']
tags.head()
# define some parameters
batch_size = 64
z_dim = 128
WIDTH = 128
HEIGHT = 128
LABEL = 34
LAMBDA = 0.05
BETA = 3
OUTPUT_DIR = 'samples'
if not os.path.exists(OUTPUT_DIR):
os.mkdir(OUTPUT_DIR)
# input
X = tf.placeholder(dtype=tf.float32, shape=[batch_size, HEIGHT, WIDTH, 3], name='X')
X_perturb = tf.placeholder(dtype=tf.float32, shape=[batch_size, HEIGHT, WIDTH, 3], name='X_perturb')
Y = tf.placeholder(dtype=tf.float32, shape=[batch_size, LABEL], name='Y')
noise = tf.placeholder(dtype=tf.float32, shape=[batch_size, z_dim], name='noise')
noise_y = tf.placeholder(dtype=tf.float32, shape=[batch_size, LABEL], name='noise_y')
is_training = tf.placeholder(dtype=tf.bool, name='is_training')
global_step = tf.Variable(0, trainable=False)
add_global = global_step.assign_add(1)
initial_learning_rate = 0.0002
learning_rate = tf.train.exponential_decay(initial_learning_rate, global_step=global_step, decay_steps=20000, decay_rate=0.5)
# define same function
def lrelu(x, leak=0.2):
return tf.maximum(x, leak * x)
def sigmoid_cross_entropy_with_logits(x, y):
return tf.nn.sigmoid_cross_entropy_with_logits(logits=x, labels=y)
def conv2d(inputs, kernel_size, filters, strides, padding='same', use_bias=True):
return tf.layers.conv2d(inputs=inputs, kernel_size=kernel_size, filters=filters, strides=strides, padding=padding, use_bias=use_bias)
def batch_norm(inputs, is_training=is_training, decay=0.9):
return tf.contrib.layers.batch_norm(inputs, is_training=is_training, decay=decay)
# discriminator
def d_block(inputs, filters):
h0 = lrelu(conv2d(inputs, 3, filters, 1))
h0 = conv2d(h0, 3, filters, 1)
h0 = lrelu(tf.add(h0, inputs))
return h0
def discriminator(image, reuse=None):
with tf.variable_scope('discriminator', reuse=reuse):
h0 = image
f = 32
for i in range(5):
if i < 3:
h0 = lrelu(conv2d(h0, 4, f, 2))
else:
h0 = lrelu(conv2d(h0, 3, f, 2))
h0 = d_block(h0, f)
h0 = d_block(h0, f)
f = f * 2
h0 = lrelu(conv2d(h0, 3, f, 2))
h0 = tf.contrib.layers.flatten(h0)
Y_ = tf.layers.dense(h0, units=LABEL)
h0 = tf.layers.dense(h0, units=1)
return h0, Y_
# generator
def g_block(inputs):
h0 = tf.nn.relu(batch_norm(conv2d(inputs, 3, 64, 1, use_bias=False)))
h0 = batch_norm(conv2d(h0, 3, 64, 1, use_bias=False))
h0 = tf.add(h0, inputs)
return h0
def generator(z, label):
with tf.variable_scope('generator', reuse=None):
d = 16
z = tf.concat([z, label], axis=1)
h0 = tf.layers.dense(z, units=d * d * 64)
h0 = tf.reshape(h0, shape=[-1, d, d, 64])
h0 = tf.nn.relu(batch_norm(h0))
shortcut = h0
for i in range(16):
h0 = g_block(h0)
h0 = tf.nn.relu(batch_norm(h0))
h0 = tf.add(h0, shortcut)
for i in range(3):
h0 = conv2d(h0, 3, 256, 1, use_bias=False)
h0 = tf.depth_to_space(h0, 2)
h0 = tf.nn.relu(batch_norm(h0))
h0 = tf.layers.conv2d(h0, kernel_size=9, filters=3, strides=1,
padding='same', activation=tf.nn.tanh, name='g', use_bias=True)
return h0
# loss function
g = generator(noise, noise_y)
d_real, y_real = discriminator(X)
d_fake, y_fake = discriminator(g, reuse=True)
loss_d_real = tf.reduce_mean(
sigmoid_cross_entropy_with_logits(d_real, tf.ones_like(d_real)))
loss_d_fake = tf.reduce_mean(
sigmoid_cross_entropy_with_logits(d_fake, tf.zeros_like(d_fake)))
loss_g_fake = tf.reduce_mean(
sigmoid_cross_entropy_with_logits(d_fake, tf.ones_like(d_fake)))
loss_c_real = tf.reduce_mean(sigmoid_cross_entropy_with_logits(y_real, Y))
loss_c_fake = tf.reduce_mean(
sigmoid_cross_entropy_with_logits(y_fake, noise_y))
loss_d = loss_d_real + loss_d_fake + BETA * loss_c_real
loss_g = loss_g_fake + BETA * loss_c_fake
alpha = tf.random_uniform(shape=[batch_size, 1, 1, 1], minval=0., maxval=1.)
interpolates = alpha * X + (1 - alpha) * X_perturb
grad = tf.gradients(discriminator(interpolates, reuse=True)
[0], [interpolates])[0]
slop = tf.sqrt(tf.reduce_sum(tf.square(grad), axis=[1]))
gp = tf.reduce_mean((slop - 1.) ** 2)
loss_d += LAMBDA * gp
vars_g = [var for var in tf.trainable_variables() if var.name.startswith('generator')]
vars_d = [var for var in tf.trainable_variables() if var.name.startswith('discriminator')]
# optimizer
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
optimizer_d = tf.train.AdamOptimizer(
learning_rate=learning_rate, beta1=0.5).minimize(loss_d, var_list=vars_d)
optimizer_g = tf.train.AdamOptimizer(
learning_rate=learning_rate, beta1=0.5).minimize(loss_g, var_list=vars_g)
# merge image
def montage(images):
if isinstance(images, list):
images = np.array(images)
img_h = images.shape[1]
img_w = images.shape[2]
n_plots = int(np.ceil(np.sqrt(images.shape[0])))
if len(images.shape) == 4 and images.shape[3] == 3:
m = np.ones(
(images.shape[1] * n_plots + n_plots + 1,
images.shape[2] * n_plots + n_plots + 1, 3)) * 0.5
elif len(images.shape) == 4 and images.shape[3] == 1:
m = np.ones(
(images.shape[1] * n_plots + n_plots + 1,
images.shape[2] * n_plots + n_plots + 1, 1)) * 0.5
elif len(images.shape) == 3:
m = np.ones(
(images.shape[1] * n_plots + n_plots + 1,
images.shape[2] * n_plots + n_plots + 1)) * 0.5
else:
raise ValueError(
'Could not parse image shape of {}'.format(images.shape))
for i in range(n_plots):
for j in range(n_plots):
this_filter = i * n_plots + j
if this_filter < images.shape[0]:
this_img = images[this_filter]
m[1 + i + i * img_h:1 + i + (i + 1) * img_h,
1 + j + j * img_w:1 + j + (j + 1) * img_w] = this_img
return m
# prepare data
X_all = []
Y_all = []
for i in tqdm(range(len(images))):
image = imread(images[i])
image = (image / 255. - 0.5) * 2
X_all.append(image)
y = list(tags.loc[images[i]])
Y_all.append(y[1:])
X_all = np.array(X_all)
Y_all = np.array(Y_all)
print(X_all.shape, Y_all.shape)
def get_random_tags():
y = np.random.uniform(0.0, 1.0, [batch_size, LABEL]).astype(np.float32)
y[y > 0.75] = 1
y[y <= 0.75] = 0
for i in range(batch_size):
hc = np.random.randint(0, 13)
hs = np.random.randint(13, 18)
ec = np.random.randint(18, 28)
y[i, :28] = 0
y[i, hc] = 1 # hair color
y[i, hs] = 1 # hair style
y[i, ec] = 1 # eye color
return y
# train
sess = tf.Session()
sess.run(tf.global_variables_initializer())
z_samples = np.random.uniform(-1.0, 1.0,
[batch_size, z_dim]).astype(np.float32)
y_samples = get_random_tags()
for i in range(batch_size):
y_samples[i, :28] = 0
y_samples[i, i // 8 % 13] = 1 # hair color
y_samples[i, i // 8 % 5 + 13] = 1 # hair style
y_samples[i, i // 8 % 10 + 18] = 1 # eye color
samples = []
loss = {'d': [], 'g': []}
offset = 0
for i in tqdm(range(60000)):
if offset + batch_size > X_all.shape[0]:
offset = 0
if offset == 0:
data_index = np.arange(X_all.shape[0])
np.random.shuffle(data_index)
X_all = X_all[data_index, :, :, :]
Y_all = Y_all[data_index, :]
X_batch = X_all[offset: offset + batch_size, :, :, :]
Y_batch = Y_all[offset: offset + batch_size, :]
X_batch_perturb = X_batch + 0.5 * X_batch.std() * np.random.random(X_batch.shape)
offset += batch_size
n = np.random.uniform(-1.0, 1.0, [batch_size, z_dim]).astype(np.float32)
ny = get_random_tags()
_, d_ls = sess.run([optimizer_d, loss_d], feed_dict={X: X_batch, X_perturb: X_batch_perturb, Y: Y_batch, noise: n, noise_y: ny, is_training: True})
n = np.random.uniform(-1.0, 1.0, [batch_size, z_dim]).astype(np.float32)
ny = get_random_tags()
_, g_ls = sess.run([optimizer_g, loss_g], feed_dict={noise: n, noise_y: ny, is_training: True})
loss['d'].append(d_ls)
loss['g'].append(g_ls)
_, lr = sess.run([add_global, learning_rate])
# save train image
if i % 500 == 0:
print(i, d_ls, g_ls, lr)
gen_imgs = sess.run(
g, feed_dict={noise: z_samples, noise_y: y_samples, is_training: False})
gen_imgs = (gen_imgs + 1) / 2
imgs = [img[:, :, :] for img in gen_imgs]
gen_imgs = montage(imgs)
plt.axis('off')
plt.imshow(gen_imgs)
imsave(os.path.join(OUTPUT_DIR, 'sample_%d.jpg' % i), gen_imgs)
plt.show()
samples.append(gen_imgs)
plt.plot(loss['d'], label='Discriminator')
plt.plot(loss['g'], label='Generator')
plt.legend(loc='upper right')
plt.savefig('Loss.png')
plt.show()
mimsave(os.path.join(OUTPUT_DIR, 'samples.gif'), samples, fps=10)
# save
saver = tf.train.Saver()
saver.save(sess, './anime_acgan', global_step=60000)
===============================================
Теперь япытаясь преобразовать в код Keras, вот код Keras (может быть, не правильный):
import numpy as np
import tensorflow as tf
from keras.layers import Input, Dense, Reshape, Flatten, Dropout, multiply
from keras.layers import BatchNormalization, Activation, ZeroPadding2D, Add
from keras.layers.advanced_activations import PReLU, LeakyReLU
from keras.layers.convolutional import UpSampling2D, Conv2D
from keras.layers import concatenate
from keras.layers.core import Lambda
from keras.models import Sequential, Model
from keras.optimizers import Adam
from keras import backend as K
from subpixel_conv2d import SubpixelConv2D
def sigmoid_cross_entropy_with_logits(x, y):
return tf.nn.sigmoid_cross_entropy_with_logits(logits=x, labels=y)
def dense(input, unit):
return Dense(unit)(input)
def reshape(input, shape):
return Reshape(shape)(input)
def conv2d(inputs, kernel_size, filters, strides, padding='same', use_bias=True):
return Conv2D(filters, kernel_size, strides=strides, padding=padding, use_bias=use_bias)(inputs)
def batch_norm(inputs, training, momentum=0.9):
return BatchNormalization(momentum=momentum)(inputs, training=training)
def relu(input):
return Activation('relu')(input)
def add(input1, input2):
return Add()([input1, input2])
def depth_to_space(input, factor):
return SubpixelConv2D(upsampling_factor=factor)(input)
def maximum_k(x, y):
return K.maximum(x, y)
def lrelu(x, leak=0.2):
return Lambda(maximum_k, arguments={'y': leak * x})(x)
def flatten(input):
return Flatten()(input)
def d_block(inputs, filters):
h0 = conv2d(inputs, 3, filters, 1)
h0 = lrelu(h0)
h0 = conv2d(h0, 3, filters, 1)
h0 = add(h0, inputs)
h0 = lrelu(h0)
return h0
def g_block(inputs, is_training):
h0 = conv2d(inputs, 3, 64, 1, use_bias=False)
h0 = batch_norm(h0, is_training)
h0 = relu(h0)
h0 = conv2d(h0, 3, 64, 1, use_bias=False)
h0 = batch_norm(h0, is_training)
h0 = add(h0, inputs)
return h0
def build_generator():
d = 16
noise = Input(shape=(128,), dtype="float32")
label = Input(shape=(34,), dtype="float32")
is_training = Input(shape=(1,), dtype="bool")
merge_input = concatenate([noise, label])
print(merge_input.shape)
h0 = dense(merge_input, d*d*64)
h0 = reshape(h0, (d, d, 64))
h0 = batch_norm(h0, is_training)
h0 = relu(h0)
shortcut = h0
for i in range(16):
h0 = g_block(h0, is_training)
h0 = batch_norm(h0, is_training)
h0 = relu(h0)
h0 = add(h0, shortcut)
for i in range(3):
h0 = conv2d(h0, 3, 256, 1, use_bias=False)
h0 = depth_to_space(h0, 2)
h0 = batch_norm(h0, is_training)
h0 = relu(h0)
h0 = Conv2D(3, 9, padding='same', activation='tanh',
name='g', use_bias=True)(h0)
print(h0)
return Model([noise, label, is_training], h0)
def build_discriminator():
f = 32
image = Input(shape=(128, 128, 3,), dtype="float32")
h0 = image
for i in range(5):
if i < 3:
h0 = conv2d(h0, 4, f, 2)
h0 = lrelu(h0)
else:
h0 = conv2d(h0, 3, f, 2)
h0 = lrelu(h0)
h0 = d_block(h0, f)
h0 = d_block(h0, f)
f = f * 2
h0 = conv2d(h0, 3, f, 2)
h0 = lrelu(h0)
h0 = flatten(h0)
Y_ = dense(h0, 34)
h0 = dense(h0, 1)
print(h0)
return Model(image, [h0, Y_])
Теперь у меня есть модель генератора и дискриминатора, но я не знаю, как настроить функцию потерь.
Итак, как я могу преобразовать функцию потерь TensorFlow в функцию потерь модели Keras?