Lind
@Lind (Lind Taylor)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

pix2pixに関する質問

解決したいこと

pix2pixは学習する際に、入力画像と目標出力画像をつなげたペア画像を学習させると思います。学習済みの生成器で画像を変換してほしい場合には、入力画像は変換前の画像だけでいいですよね(ペア画像ではない画像)?

またこちらのコードで、学習を行ったのですが、学習済みの生成器を保存して画像変換を行うにはどのようなコードを書けばいいのでしょうか。

import tensorflow as tf
import os
import pathlib
import time
import datetime
from matplotlib import pyplot as plt
from IPython import display

import sys

PATH = "/content/drive/MyDrive/pix2pix_dataset"
PATH = pathlib.Path(PATH)
list(PATH.parent.iterdir())

sample_image = tf.io.read_file(str(PATH / 'train/desease822_2L_2_4.jpg'))
sample_image = tf.io.decode_jpeg(sample_image)
print(sample_image.shape)

plt.figure()
plt.imshow(sample_image)

def load(image_file):

Read and decode an image file to a uint8 tensor

image = tf.io.read_file(image_file)
image = tf.image.decode_image(image, channels=3)

Split each image tensor into two tensors:

- one with a real image

- one with an architecture label image

w = tf.shape(image)[1]
w = w // 2
input_image = image[:, w:, :]
real_image = image[:, :w, :]

Convert both images to float32 tensors

input_image = tf.cast(input_image, tf.float32)
real_image = tf.cast(real_image, tf.float32)

return input_image, real_image

inp, re = load(str(PATH / 'train/desease822_2L_2_4.jpg'))

Casting to int for matplotlib to display the images

plt.figure()
plt.imshow(inp / 255.0)
plt.figure()
plt.imshow(re / 255.0)
plt.show()

The facade training set consist of 400 images

BUFFER_SIZE = 85

The batch size of 1 produced better results for the U-Net in the original pix2pix experiment

BATCH_SIZE = 1

Each image is 200x200 in size

IMG_WIDTH = 256
IMG_HEIGHT = 256

def resize(input_image, real_image, height, width):

input_image = tf.cast(input_image, tf.float32)
real_image = tf.cast(real_image, tf.float32)

 # 明示的に形状を設定する
input_image.set_shape([None, None, 3])
real_image.set_shape([None, None, 3])

input_image = tf.image.resize(input_image, [height, width],
                              method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
real_image = tf.image.resize(real_image, [height, width],
                             method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)

return input_image, real_image

def random_crop(input_image, real_image):
stacked_image = tf.stack([input_image, real_image], axis=0)
cropped_image = tf.image.random_crop(
stacked_image, size=[2, IMG_HEIGHT, IMG_WIDTH, 3])

return cropped_image[0], cropped_image[1]

Normalizing the images to [-1, 1]

def normalize(input_image, real_image):
input_image = (input_image / 127.5) - 1
real_image = (real_image / 127.5) - 1

return input_image, real_image

@tf.function()
def random_jitter(input_image, real_image):

Resizing to 286x286

input_image, real_image = resize(input_image, real_image, 286, 286)

Random cropping back to 256x256

input_image, real_image = random_crop(input_image, real_image)

if tf.random.uniform(()) > 0.5:
# Random mirroring
input_image = tf.image.flip_left_right(input_image)
real_image = tf.image.flip_left_right(real_image)

return input_image, real_image

plt.figure(figsize=(6, 6))
for i in range(4):
rj_inp, rj_re = random_jitter(inp, re)
plt.subplot(2, 2, i + 1)
plt.imshow(rj_inp / 255.0)
plt.axis('off')
plt.show()

#学習スタート
def load_image_train(image_file):
input_image, real_image = load(image_file)
input_image, real_image = random_jitter(input_image, real_image)
input_image, real_image = normalize(input_image, real_image)

return input_image, real_image

def load_image_test(image_file):
input_image, real_image = load(image_file)
input_image, real_image = resize(input_image, real_image,
IMG_HEIGHT, IMG_WIDTH)
input_image, real_image = normalize(input_image, real_image)

return input_image, real_image

train_dataset = tf.data.Dataset.list_files(str(PATH / 'train/*.jpg'))
train_dataset = train_dataset.map(load_image_train,
num_parallel_calls=tf.data.AUTOTUNE)
train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.batch(BATCH_SIZE)

try:
test_dataset = tf.data.Dataset.list_files(str(PATH / 'test/.jpg'))
except tf.errors.InvalidArgumentError:
test_dataset = tf.data.Dataset.list_files(str(PATH / 'valid/
.jpg'))
test_dataset = test_dataset.map(load_image_test)
test_dataset = test_dataset.batch(BATCH_SIZE)

OUTPUT_CHANNELS = 3

def downsample(filters, size, apply_batchnorm=True):
initializer = tf.random_normal_initializer(0., 0.02)

result = tf.keras.Sequential()
result.add(
tf.keras.layers.Conv2D(filters, size, strides=2, padding='same',
kernel_initializer=initializer, use_bias=False))

if apply_batchnorm:
result.add(tf.keras.layers.BatchNormalization())

result.add(tf.keras.layers.LeakyReLU())

return result

down_model = downsample(3, 4)
down_result = down_model(tf.expand_dims(inp, 0))
print (down_result.shape)

def upsample(filters, size, apply_dropout=False):
initializer = tf.random_normal_initializer(0., 0.02)

result = tf.keras.Sequential()
result.add(
tf.keras.layers.Conv2DTranspose(filters, size, strides=2,
padding='same',
kernel_initializer=initializer,
use_bias=False))

result.add(tf.keras.layers.BatchNormalization())

if apply_dropout:
result.add(tf.keras.layers.Dropout(0.5))

result.add(tf.keras.layers.ReLU())

return result

up_model = upsample(3, 4)
up_result = up_model(down_result)
print (up_result.shape)

def Generator():
inputs = tf.keras.layers.Input(shape=[256, 256, 3])

down_stack = [
downsample(64, 4, apply_batchnorm=False), # (batch_size, 128, 128, 64)
downsample(128, 4), # (batch_size, 64, 64, 128)
downsample(256, 4), # (batch_size, 32, 32, 256)
downsample(512, 4), # (batch_size, 16, 16, 512)
downsample(512, 4), # (batch_size, 8, 8, 512)
downsample(512, 4), # (batch_size, 4, 4, 512)
downsample(512, 4), # (batch_size, 2, 2, 512)
downsample(512, 4), # (batch_size, 1, 1, 512)
]

up_stack = [
upsample(512, 4, apply_dropout=True), # (batch_size, 2, 2, 1024)
upsample(512, 4, apply_dropout=True), # (batch_size, 4, 4, 1024)
upsample(512, 4, apply_dropout=True), # (batch_size, 8, 8, 1024)
upsample(512, 4), # (batch_size, 16, 16, 1024)
upsample(256, 4), # (batch_size, 32, 32, 512)
upsample(128, 4), # (batch_size, 64, 64, 256)
upsample(64, 4), # (batch_size, 128, 128, 128)
]

initializer = tf.random_normal_initializer(0., 0.02)
last = tf.keras.layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,
strides=2,
padding='same',
kernel_initializer=initializer,
activation='tanh') # (batch_size, 256, 256, 3)

x = inputs

Downsampling through the model

skips = []
for down in down_stack:
x = down(x)
skips.append(x)

skips = reversed(skips[:-1])

Upsampling and establishing the skip connections

Upsampling and establishing the skip connections

for up, skip in zip(up_stack, skips):
x = up(x)
skip = tf.image.resize(skip, [tf.shape(x)[1], tf.shape(x)[2]])
x = tf.keras.layers.Concatenate()([x, skip])

x = last(x)
return tf.keras.Model(inputs=inputs, outputs=x)

generator = Generator()
tf.keras.utils.plot_model(generator, show_shapes=True, dpi=64)

gen_output = generator(inp[tf.newaxis, ...], training=False)
plt.imshow(gen_output[0, ...])

LAMBDA = 100

loss_object = tf.keras.losses.BinaryCrossentropy(from_logits=True)

def generator_loss(disc_generated_output, gen_output, target):
gan_loss = loss_object(tf.ones_like(disc_generated_output), disc_generated_output)

Mean absolute error

l1_loss = tf.reduce_mean(tf.abs(target - gen_output))

total_gen_loss = gan_loss + (LAMBDA * l1_loss)

return total_gen_loss, gan_loss, l1_loss

building a discriminator

def Discriminator():
initializer = tf.random_normal_initializer(0., 0.02)

inp = tf.keras.layers.Input(shape=[256, 256, 3], name='input_image')
tar = tf.keras.layers.Input(shape=[256, 256, 3], name='target_image')

x = tf.keras.layers.concatenate([inp, tar]) # (batch_size, 256, 256, channels*2)

down1 = downsample(64, 4, False)(x) # (batch_size, 128, 128, 64)
down2 = downsample(128, 4)(down1) # (batch_size, 64, 64, 128)
down3 = downsample(256, 4)(down2) # (batch_size, 32, 32, 256)

zero_pad1 = tf.keras.layers.ZeroPadding2D()(down3) # (batch_size, 34, 34, 256)
conv = tf.keras.layers.Conv2D(512, 4, strides=1,
kernel_initializer=initializer,
use_bias=False)(zero_pad1) # (batch_size, 31, 31, 512)

batchnorm1 = tf.keras.layers.BatchNormalization()(conv)

leaky_relu = tf.keras.layers.LeakyReLU()(batchnorm1)

zero_pad2 = tf.keras.layers.ZeroPadding2D()(leaky_relu) # (batch_size, 33, 33, 512)

last = tf.keras.layers.Conv2D(1, 4, strides=1,
kernel_initializer=initializer)(zero_pad2) # (batch_size, 30, 30, 1)

return tf.keras.Model(inputs=[inp, tar], outputs=last)

discriminator = Discriminator()
tf.keras.utils.plot_model(discriminator, show_shapes=True, dpi=64)

testing discriminator

disc_out = discriminator([inp[tf.newaxis, ...], gen_output], training=False)
plt.imshow(disc_out[0, ..., -1], vmin=-20, vmax=20, cmap='RdBu_r')
plt.colorbar()

defining discriminator's loss

def discriminator_loss(disc_real_output, disc_generated_output):
real_loss = loss_object(tf.ones_like(disc_real_output), disc_real_output)

generated_loss = loss_object(tf.zeros_like(disc_generated_output), disc_generated_output)

total_disc_loss = real_loss + generated_loss

return total_disc_loss

generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)

checkpoint_dir = './training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer,
discriminator_optimizer=discriminator_optimizer,
generator=generator,
discriminator=discriminator)

#画像生成
def generate_images(model, test_input, tar):
prediction = model(test_input, training=True)
plt.figure(figsize=(15, 15))

display_list = [test_input[0], tar[0], prediction[0]]
title = ['Input Image', 'Ground Truth', 'Predicted Image']

for i in range(3):
plt.subplot(1, 3, i+1)
plt.title(title[i])
# Getting the pixel values in the [0, 1] range to plot.
plt.imshow(display_list[i] * 0.5 + 0.5)
plt.axis('off')
plt.show()

for example_input, example_target in test_dataset.take(1):
generate_images(generator, example_input, example_target)

training

log_dir = "pix2pix_logs/" # ログを保存するディレクトリを指定

summary_writer = tf.summary.create_file_writer(
log_dir + "fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))

@tf.function
def train_step(input_image, target, step):
with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
gen_output = generator(input_image, training=True)

disc_real_output = discriminator([input_image, target], training=True)
disc_generated_output = discriminator([input_image, gen_output], training=True)

gen_total_loss, gen_gan_loss, gen_l1_loss = generator_loss(disc_generated_output, gen_output, target)
disc_loss = discriminator_loss(disc_real_output, disc_generated_output)

generator_gradients = gen_tape.gradient(gen_total_loss,
generator.trainable_variables)
discriminator_gradients = disc_tape.gradient(disc_loss,
discriminator.trainable_variables)

generator_optimizer.apply_gradients(zip(generator_gradients,
generator.trainable_variables))
discriminator_optimizer.apply_gradients(zip(discriminator_gradients,
discriminator.trainable_variables))

with summary_writer.as_default():
tf.summary.scalar('gen_total_loss', gen_total_loss, step=step//1000)
tf.summary.scalar('gen_gan_loss', gen_gan_loss, step=step//1000)
tf.summary.scalar('gen_l1_loss', gen_l1_loss, step=step//1000)
tf.summary.scalar('disc_loss', disc_loss, step=step//1000)

def fit(train_ds, test_ds, steps):
example_input, example_target = next(iter(test_ds.take(1)))
start = time.time()

for step, (input_image, target) in train_ds.repeat().take(steps).enumerate():
if (step) % 1000 == 0:
display.clear_output(wait=True)

  if step != 0:
    print(f'Time taken for 1000 steps: {time.time()-start:.2f} sec\n')

  start = time.time()

  generate_images(generator, example_input, example_target)
  print(f"Step: {step//1000}k")

train_step(input_image, target, step)

# Training step
if (step+1) % 10 == 0:
  print('.', end='', flush=True)


# Save (checkpoint) the model every 5k steps
if (step + 1) % 5000 == 0:
  checkpoint.save(file_prefix=checkpoint_prefix)

fit(train_dataset, test_dataset, steps=40000)

Restoring the latest checkpoint in checkpoint_dir

checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))

Run the trained model on a few examples from the test set

for inp, tar in test_dataset.take(5):
generate_images(generator, inp, tar)

0

1Answer

pix2pixは学習する際に、入力画像と目標出力画像をつなげたペア画像を学習させると思います。

実装がそうなっているだけで,学習のために画像を繋げる必要はどこにもありません.

学習済みの生成器で画像を変換してほしい場合には、入力画像は変換前の画像だけでいいですよね(ペア画像ではない画像)?

はい,そうです.

学習済みの生成器を保存して画像変換を行うにはどのようなコードを書けばいいのでしょうか。

  1. 変換したい画像を1枚読み出し
  2. 学習済みの生成器を読み出し
  3. 生成器に画像を入力する
  4. 出力画像を保存する

という流れになります.

0Like

Comments

  1. @Lind

    Questioner

    ご回答ありがとうございます。

  2. @Lind

    Questioner

    学習済みの生成器の保存にはどのようなコードを書けばいいのでしょうか。.save()ですか?

Your answer might help someone💌