――Lassen Sie das Erlernen der Kolorierung von monochromen Bildern mit Chainer einfach implementieren. ――Recent Chainer kann abstrakt geschrieben werden, daher werde ich es mit Trainer usw. implementieren.
Verwenden Sie CIFAR-100 für den Datensatz. Chainer verfügt über mehrere benutzerfreundliche Datensätze wie MNIST und CIFAR-100. Dieses Mal habe ich mich für CIFAR-100 entschieden, mit dem sich schnell viele Farbbilder erstellen lassen. Ich denke jedoch, dass ein Datensatz mit mehr Bildtypen ursprünglich geeignet ist.
Die Verwendung von CIFAR-100 mit Chainer ist wie folgt implementiert.
train, test = chainer.datasets.get_cifar100(withlabel=False)
Der von Chainer überwachte Trainingsdatensatz wird implementiert, indem ein Array von "(Trainingsdaten, Lehrerdaten)" an den Iterator übergeben wird. Um die Kolorierung von monochromen Bildern zu lernen, benötigen Sie eine Reihe von "(monochrome Bilder, Farbbilder)". Aus der diesmal verwendeten chainer.datasets.get_cifar100 ()
können Sie ein Array von Tapples mit dem Namen(image, label)
abrufen. Da Sie jedoch keine Beschriftung benötigen, setzen Sie withlabel auf False und nur auf das image-Array. Bekommen
Ändern Sie als Nächstes den erhaltenen Farbbilddatensatz in "(Schwarzweißbild, Farbbild)". Wenn Sie mit Chainer ein eigenes Dataset erstellen, implementieren Sie es häufig mit "chainer.datasets.TupleDataset (Trainingsdatenarray, Lehrerdatenarray)". Da es jedoch einfach ist, ein monochromes Bild aus einem Farbbild zu generieren, verwenden wir dieses Mal eine Klasse, die chainer.dataset.DatasetMixin
erbt, und implementieren sie, indem wir kurz vor dem Erstellen eines Mini-Batches ein monochromes Bild vorbereiten. Dieses Beispiel ist hilfreich. Es scheint, dass es einfach ist, eine Verarbeitung durchzuführen, z. B. das Bild zuzuschneiden und auf diese Weise Rauschen hinzuzufügen.
class PreprocessedDataset(chainer.dataset.DatasetMixin):
def __init__(self, base_image_dataset):
self.base = base_image_dataset
def __len__(self):
return len(self.base)
def get_example(self, i):
color_image = self.base[i]
gray_image = np.ndarray((32, 32), dtype=np.float32)
for ch in range(3):
gray_image = (
0.298912*color_image[0]
+ 0.586611*color_image[1]
+ 0.114478*color_image[2]
)
return gray_image, color_image
Dieses Mal werde ich zwei Arten von NN ausprobieren. Eine verbindet einfach die vollständig verbundenen Schichten und die andere verbindet die Entfaltungsschicht hinter der Faltungsschicht.
class AIC_FC(chainer.Chain):
def __init__(self, n_units):
initializer = chainer.initializers.HeNormal()
super(AIC_FC, self).__init__(
fc_in = L.Linear(None, n_units),
bn1 = L.BatchNormalization(n_units),
fc2 = L.Linear(None, n_units),
bn2 = L.BatchNormalization(n_units),
fc_out = L.Linear(None, 32*32*3)
)
def __call__(self, x, t):
y = self.colorize(x)
loss = F.mean_squared_error(y, t)
chainer.reporter.report({
'loss': loss
})
return loss
def colorize(self, x, test=False):
h = F.elu(self.bn1(self.fc_in(x), test=test))
h = F.elu(self.bn2(self.fc2(h), test=test))
y = F.reshape(self.fc_out(h), (h.shape[0], 3, 32, 32))
return y
class AIC_DC(chainer.Chain):
def __init__(self, n_ch):
initializer = chainer.initializers.HeNormal()
super(AIC_DC, self).__init__(
cv_in = L.Convolution2D(1, n_ch//4, 4, 2, 1),
bn1 = L.BatchNormalization(n_ch//4),
cv1 = L.Convolution2D(n_ch//4, n_ch//2, 4, 2, 1),
bn2 = L.BatchNormalization(n_ch//2),
cv2 = L.Convolution2D(n_ch//2, n_ch, 4, 2, 1),
bn3 = L.BatchNormalization(n_ch),
cv3 = L.Convolution2D(n_ch, n_ch, 4, 2, 1),
bn4 = L.BatchNormalization(n_ch),
dc1 = L.Deconvolution2D(n_ch, n_ch, 4, 2, 1),
bn5 = L.BatchNormalization(n_ch),
dc2 = L.Deconvolution2D(n_ch, n_ch//2, 4, 2, 1),
bn6 = L.BatchNormalization(n_ch//2),
dc3 = L.Deconvolution2D(n_ch//2, n_ch//4, 4, 2, 1),
bn7 = L.BatchNormalization(n_ch//4),
dc_out = L.Deconvolution2D(n_ch//4, 3, 4, 2, 1, outsize=(32, 32))
)
def __call__(self, x, t):
y = self.colorize(x)
loss = F.mean_squared_error(y, t)
chainer.reporter.report({
'loss': loss
})
return loss
def colorize(self, x, test=False):
h = F.reshape(x, (x.shape[0], 1, 32, 32))
h = F.elu(self.bn1(self.cv_in(h), test=test))
h = F.elu(self.bn2(self.cv1(h), test=test))
h = F.elu(self.bn3(self.cv2(h), test=test))
h = F.elu(self.bn4(self.cv3(h), test=test))
h = F.elu(self.bn5(self.dc1(h), test=test))
h = F.elu(self.bn6(self.dc2(h), test=test))
h = F.elu(self.bn7(self.dc3(h), test=test))
y = self.dc_out(h)
return y
Als ich versuchte, das vollständig verbundene NN zu vertiefen, wurde nur ein verschwommenes Bild erzeugt (Konvergenz ist langsam?), Also habe ich es flacher gemacht.
Übrigens scheint das tatsächlich kolorierte NN ein komplizierteres Design zu haben. (Referenz)
Der Fluss der Lernimplementierung in Chainer
Es wird sein. Neben Adam verfügt Optimizer auch über grundlegende Funktionen wie SGD und Momentum SGD, und es scheint, dass Standard Updater für Probleme ausreicht, bei denen Updater keine komplizierten Verlustberechnungen wie GAN durchführt. Im Vergleich zu der Zeit, als ich alles selbst geschrieben habe, kann ich es sehr genießen, weil diejenigen vorbereitet sind, die sich standardmäßig gut anfühlen. Da nur die erforderlichen Teile geändert werden müssen, ist es für andere Personen leichter zu verstehen, und ich bin dankbar.
Probleme wie dieses sind allein aufgrund des Verlustwerts schwer zu verstehen, daher möchte ich sie visualisieren. Implementieren Sie also den Modelltest mit der Trainer-Erweiterung. Erweiterungen erben von chainer.training.extention.Extension
usw. oder werden mit chainer.training.make_extension ()
erstellt. Implementieren Sie Modelltests und das Speichern von Bildern mit "chainer.training.make_extension ()" wie folgt. (Imsave von scipy.misc wird importiert.)
Ein Testbild wird getrennt von den Trainingsdaten erstellt.
@chainer.training.make_extension(trigger=(1, 'epoch'))
def test_model(trainer):
colorized_img = chainer.cuda.to_cpu(F.clipped_relu(model.colorize(test_img, test=True), z=1.0).data)
imsave(
'test_colorized{}.png'.format(trainer.updater.epoch),
colorized_img
.transpose(0, 2, 3, 1)
.reshape((8, 8, 32, 32, 3))
.transpose(1, 2, 0, 3, 4)
.reshape(8*32, 8*32, 3)
)
trainer.extend(test_model)
Ich werde das Ergebnis des Lernens vorstellen. Dieses Mal habe ich zwei NNs ausprobiert, ein vollständig verbundenes NN und ein verschlungenes NN, daher werde ich sie mit dem Lernstatus zum Zeitpunkt des Lernens in der 30. Epoche vergleichen. Wir haben gelernt, dass n_Einheiten von vollständig verbundenem NN 2048 und n_ch von Faltung NN 512 ist.
Vollständig verbunden NN
Falten NN
Vollständig kombiniertes NN scheint insgesamt ein körniges Bild zu sein. Ich war überrascht, dass selbst ein einfaches NN viele Farben hatte, aber ich habe das Gefühl, dass das gefaltete NN lebendigere und schönere Bilder ausgeben kann.
Wenn man sich jedes Bild ansieht, scheint es, dass der Himmel und das Meer gut erkannt werden und die Farben ordentlich platziert sind. Es scheint jedoch schwierig zu sein, zwischen dem blauen Himmel und dem Sonnenuntergang zu unterscheiden. Im Bild unten rechts, das ein kleines Tier zu zeigen scheint, wird der Boden erkannt und die Braun- und Grasfarben werden reproduziert. Es ist jedoch etwas zu grasig im Vergleich zur richtigen Antwort.
Das obige Bild zeigt die Verwendung von elu für die Aktivierungsfunktion. Ich habe auch untersucht, wie sich das Finish ändert, wenn relu oder leaky_relu als Aktivierungsfunktion verwendet wird. Es werden nur die Ergebnisse mit der Faltung NN, 30 Epoche mit n_ch von 512 vorgestellt.
relu
leaky_relu
elu
Das Relu ist lebendig verarbeitet, hat aber einen leicht unscharfen Eindruck. elu und undichtes relu scheinen in der Bildschärfe dem relu überlegen zu sein. undichtes relu vermittelt einen eindruck zwischen elu und relu.
#! /usr/bin/env python
# coding : utf-8
import argparse
import numpy as np
from scipy.misc import imsave
import chainer
import chainer.functions as F
import chainer.links as L
from chainer.training import extensions
class PreprocessedDataset(chainer.dataset.DatasetMixin):
def __init__(self, base_image_dataset):
self.base = base_image_dataset
def __len__(self):
return len(self.base)
def get_example(self, i):
color_image = self.base[i]
gray_image = np.ndarray((32, 32), dtype=np.float32)
for ch in range(3):
#Berechnen Sie die Helligkeit und erstellen Sie ein monochromes Bild
gray_image = (
0.298912*color_image[0]
+ 0.586611*color_image[1]
+ 0.114478*color_image[2]
)
return gray_image, color_image
class AIC_FC(chainer.Chain):
def __init__(self, n_units):
initializer = chainer.initializers.HeNormal()
super(AIC_FC, self).__init__(
fc_in = L.Linear(None, n_units),
bn1 = L.BatchNormalization(n_units),
fc2 = L.Linear(None, n_units),
bn2 = L.BatchNormalization(n_units),
fc_out = L.Linear(None, 32*32*3)
)
def __call__(self, x, t):
y = self.colorize(x)
loss = F.mean_squared_error(y, t)
chainer.reporter.report({
'loss': loss
})
return loss
def colorize(self, x, test=False):
h = F.elu(self.bn1(self.fc_in(x), test=test))
h = F.elu(self.bn2(self.fc2(h), test=test))
y = F.reshape(self.fc_out(h), (h.shape[0], 3, 32, 32))
return y
class AIC_DC(chainer.Chain):
def __init__(self, n_ch):
initializer = chainer.initializers.HeNormal()
super(AIC_DC, self).__init__(
cv_in = L.Convolution2D(1, n_ch//4, 4, 2, 1),
bn1 = L.BatchNormalization(n_ch//4),
cv1 = L.Convolution2D(n_ch//4, n_ch//2, 4, 2, 1),
bn2 = L.BatchNormalization(n_ch//2),
cv2 = L.Convolution2D(n_ch//2, n_ch, 4, 2, 1),
bn3 = L.BatchNormalization(n_ch),
cv3 = L.Convolution2D(n_ch, n_ch, 4, 2, 1),
bn4 = L.BatchNormalization(n_ch),
dc1 = L.Deconvolution2D(n_ch, n_ch, 4, 2, 1),
bn5 = L.BatchNormalization(n_ch),
dc2 = L.Deconvolution2D(n_ch, n_ch//2, 4, 2, 1),
bn6 = L.BatchNormalization(n_ch//2),
dc3 = L.Deconvolution2D(n_ch//2, n_ch//4, 4, 2, 1),
bn7 = L.BatchNormalization(n_ch//4),
dc_out = L.Deconvolution2D(n_ch//4, 3, 4, 2, 1, outsize=(32, 32))
)
def __call__(self, x, t):
y = self.colorize(x)
loss = F.mean_squared_error(y, t)
chainer.reporter.report({
'loss': loss
})
return loss
def colorize(self, x, test=False):
#Umformen, so dass ndim 4 für die Eingabe in die Faltungsebene ist
h = F.reshape(x, (x.shape[0], 1, 32, 32))
h = F.elu(self.bn1(self.cv_in(h), test=test))
h = F.elu(self.bn2(self.cv1(h), test=test))
h = F.elu(self.bn3(self.cv2(h), test=test))
h = F.elu(self.bn4(self.cv3(h), test=test))
h = F.elu(self.bn5(self.dc1(h), test=test))
h = F.elu(self.bn6(self.dc2(h), test=test))
h = F.elu(self.bn7(self.dc3(h), test=test))
y = self.dc_out(h)
return y
def main():
parser = argparse.ArgumentParser(description='Automatic Image Colorization')
parser.add_argument('--batchsize', '-b', type=int, default=64,
help='Number of images in each mini-batch')
parser.add_argument('--epoch', '-e', type=int, default=30,
help='Number of sweeps over the dataset to train')
parser.add_argument('--gpu', '-g', type=int, default=0,
help='GPU ID (negative value indicates CPU)')
parser.add_argument('--resume', '-r', default='',
help='Resume the training from snapshot')
parser.add_argument('--n_ch', '-nc', type=int, default=1024,
help='Number of channels')
parser.add_argument('--n_units', '-nu', type=int, default=0,
help='Number of units')
args = parser.parse_args()
print('# GPU: {}'.format(args.gpu))
print('# Minibatch-size: {}'.format(args.batchsize))
print('# epoch: {}'.format(args.epoch))
if args.n_units > 0:
print('# n_units: {}\n'.format(args.n_units))
model = AIC_FC(args.n_units)
else:
print('# n_ch: {}\n'.format(args.n_ch))
model = AIC_DC(args.n_ch)
if args.gpu >= 0:
chainer.cuda.get_device().use()
model.to_gpu()
opt = chainer.optimizers.Adam()
opt.setup(model)
train, test = chainer.datasets.get_cifar100(withlabel=False)
test_img = (
0.298912*test[:64,0]
+ 0.586611*test[:64,1]
+ 0.114478*test[:64,2]
)
#Speichern Sie 64 Bilder als einzelnes 8x8-Bild
imsave(
'test.png',
test[:64]
.transpose(0, 2, 3, 1)
.reshape((8, 8, 32, 32, 3))
.transpose(1, 2, 0, 3, 4)
.reshape(8*32, 8*32, 3)
)
imsave(
'test_gray.png',
test_img
.reshape((8, 8, 32, 32))
.transpose(1, 2, 0, 3)
.reshape(8*32, 8*32)
)
if args.gpu >= 0:
test_img = chainer.cuda.to_gpu(test_img)
dataset = PreprocessedDataset(train)
iterator = chainer.iterators.MultiprocessIterator(dataset, args.batchsize)
updater = chainer.training.StandardUpdater(iterator, opt, device=args.gpu)
trainer = chainer.training.Trainer(updater, (args.epoch, 'epoch'))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport([
'epoch', 'loss', 'elapsed_time'
]))
@chainer.training.make_extension(trigger=(10, 'epoch'))
def test_model(trainer):
#Wertebereich 0~Beschnitten auf 1_Durch relu
colorized_img = chainer.cuda.to_cpu(F.clipped_relu(model.colorize(test_img, test=True), z=1.0).data)
imsave(
'test_colorized{}.png'.format(trainer.updater.epoch),
colorized_img
.transpose(0, 2, 3, 1)
.reshape((8, 8, 32, 32, 3))
.transpose(1, 2, 0, 3, 4)
.reshape(8*32, 8*32, 3)
)
trainer.extend(test_model)
trainer.extend(extensions.ProgressBar(update_interval=100))
trainer.run()
if __name__ == '__main__':
main()
Recommended Posts