游戏迷提供最新游戏下载和手游攻略!

想要构建一个神经网络来自动为黑白照片着色?这里有一个超级详细的教程

发布时间:2024-10-21浏览:10

大家好,今天给各位分享想要构建一个神经网络来自动为黑白照片着色?这里有一个超级详细的教程的一些知识,其中也会对进行解释,文章篇幅可能偏长,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在就马上开始吧!

昨天,你可能惊喜地看到Adobe做了一款给肖像上色的软件,然后悲伤地发现它只能给人脸上色,而且还没有正式上线。现在只有一篇论文.

没关系,我们自己做一个吧。

深度学习云平台FloydHub最近在其官方博客上发布了一个教程,教你如何构建神经网络对黑白照片进行着色。它在Twitter 和Reddit 论坛上受到广泛好评。

FloydHub是YC孵化的一家初创公司,自称是深度学习领域的Heroku。它在GPU系统上预装了TensorFlow和许多其他机器学习工具,用户可以按时间租用它们来训练自己的机器学习模型。

本教程基于FloydHub平台编写,该平台被称为深度学习领域的Heroku。 GPU系统上预装了TensorFlow和许多其他机器学习工具。用户可以按次租用它们来训练自己的机器学习模型。免费版本支持1个项目、每月20小时的GPU时间和10G存储空间。通过着色项目练习你的技能就足够了。

咱们进入正题吧~

以下内容整理自FloydHub官方博客:

我将向您展示如何通过三个步骤构建您自己的着色神经网络。

第一部分介绍核心逻辑。我们将使用40 行代码构建一个简单的神经网络,称为着色机器人的“Alpha”版本。这段代码没有太多技巧,但有助于熟悉语法。

下一步是创建一个具有泛化能力的神经网络,称为“Beta”版本,可以对以前从未见过的图像进行着色。

最后将神经网络与分类器结合得到最终版本。 Inception Resnet V2是训练120万张图像后得到的神经网络。我们使用了这个模型。为了使阴影效果更具吸引力,我们使用了Unsplash 中的一组肖像来训练神经网络。

Alpha版本机器人的Jupyter Notebook代码、上述三个版本实现代码的FloydHub和GitHub地址以及在FloydHub的GPU云上运行的所有实验代码都在文末。

核心逻辑

在本节中,我将概述如何渲染图像、数字色彩的基础知识以及神经网络的主要逻辑。

黑白图像可以用像素网格表示。每个像素都有一个与其亮度相对应的值,范围从0 - 255,从黑到白。

图像与数字的对应关系

彩色图像可以分为三层,即红色层、绿色层和蓝色层。直觉上,你可能会认为植物只存在于绿色层中,这可能是违反直觉的。想象一下将白色背景上的绿叶分成三层。

如下图所示,叶子分为三层。这些层不仅决定颜色,还决定亮度。

三道绿叶

例如,要获得白色,您需要均匀分布所有颜色。当添加等量的红色和蓝色时,绿色变得更亮。因此,彩色图像使用三个通道来编码颜色和对比度:

RGB色彩校正

就像黑白图像一样,彩色图像中的每个图层值的范围也为0 255,其中值0 表示该图层中没有颜色。如果所有颜色层的值为0,则图像像素为黑色。

神经网络可以建立输入和输出之间的关系。更准确地说,着色任务是要求网络找到将灰度图像与彩色图像连接起来的特征。

因此,着色神经网络就是寻找连接灰度值网格和三色网格的特征。

阿尔法版本

让我们从一个简单的版本开始,构建一个可以为女性脸部着色的神经网络。这样,在添加新功能时,您可以熟悉现有模型的核心语法。

只需要40行代码就可以实现下图所示的转换。中间的图像是用神经网络完成的,右边的图像是原始彩色照片。该网络使用相同的图像进行训练和测试,这将在测试版中再次讨论。

色彩空间

首先,使用将颜色通道从RGB 更改为Lab 的算法。其中,L代表亮度,a、b分别代表色谱、绿-红、蓝-黄。

如下图所示,Lab编码的图像有一层灰度层,三种颜色叠加成两层,这意味着原始灰度图像可以用于最终的预测。此外,我们只需要预测两个通道。

Lab编码图像

科学研究表明,人眼中94%的细胞决定亮度,只有6%的细胞用来感知颜色。如上所示,灰度图像比彩色图层更清晰。这是我们在最终预测中保留灰度图像的另一个原因。

从黑白到彩色

最终的预测应该是这样的:将灰度层(L)输入到网络中,然后在Lab中预测两个颜色层ab。为了创建最终的输出彩色图像,我们需要将输入灰度(L) 图像与输出a 和b 层添加在一起以创建Lab 图像。

图像转换功能

我们使用卷积滤波器将一层变成两层,将它们想象成3D 眼镜中的蓝色和红色滤波器。每个滤镜决定图像中可以看到的内容,并可以突出显示或删除某些内容以从图像中提取信息。该网络可以从过滤器创建新图像或组合多个过滤器以形成新图像。

卷积神经网络自动调整每个滤波器以达到期望的结果。我们将从堆叠数百个过滤器开始,然后将它们减少到两层,即层a 和层b。

在详细了解其工作原理之前,先看一下代码。

在FloydHub 上部署代码

如果您是FloydHub 新手,请阅读这个2 分钟安装教程(https://www.floydhub.com/) 和分步指导指南(https://blog.floydhub.com/my-first-weekend-of-deep-learning/),然后就可以开始在GPU云上训练深度学习模型了。

阿尔法版本

安装FloydHub后,执行以下命令:

git克隆https://github.com/emilwallner/Coloring-grayscale-images-in-Keras

打开该文件夹并启动FloydHub。

cd Coloring-grayscale-images-in-Keras/floydhubfloyd init colornet

FloydHub Web 控制台将在您的浏览器中打开,系统将提示您创建一个名为colornet 的新FloydHub 项目。完成后,返回终端并执行相同的初始化命令。

弗洛伊德初始化色彩网

接下来,执行该项目的任务。

弗洛伊德运行--data emilwallner/datasets/colornet/2:data --mode jupyter --tensorboard

此任务的一些简短说明:

1. 我们已经在FloydHub的数据集目录中加载了一个公共数据集(—data emilwallner/datasets/colornet/2:data)。您可以在FloydHub 上查看和使用该数据集以及许多其他公共数据集;

2.启用Tensorboard(—tensorboard);

3.在Jupyter Notebook下运行代码(—mode jupyter);

4、如果可以使用GPU,还可以在命令中添加GPU(-gpu),这样可以使运行速度提高50倍。

在FloydHub 网站上的“作业”选项下,单击Jupyter Notebook 链接到以下文件:floydhub/Alpha 版本/working_floyd_pink_light_full.ipynb,打开它并按Shift+Enter。

逐渐增加epoch值并体验神经网络如何学习。

model.fit(x=X, y=Y, batch_size=1, epochs=1)

最初将epoch 设置为1,然后逐渐增加到10、100、5500、1000 和3000。epoch 值表示神经网络从图像中学习的次数。在神经网络的训练过程中,您可以在主文件夹中找到此图像img_result.png。

# 获取图像image=img_to_array(load_img('woman.png'))image=np.array(image, dtype=float)# 将地图图像导入实验室colorspaceX=rgb2lab(1.0/255*image)[:0 ]Y=rgb2lab(1.0/255*图像)[:1:]Y=Y/128X=X.reshape(1, 400, 400, 1)Y=Y.reshape(1, 400, 400, 2) model=Sequential()model.add(InputLayer(input_shape=(None, None, 1)))# 构建神经网络model=Sequential()model.add(InputLayer(input_shape=(None, None, 1)))model. add(Conv2D(8, (3, 3), 激活='relu', padding='相同', strides=2))model.add(Conv2D(8, (3, 3), 激活='relu', 填充='相同'))model.add(Conv2D(16, (3, 3), 激活='relu', padding='相同'))model.add(Conv2D(16, (3, 3), 激活=' relu', padding='相同', strides=2))model.add(Conv2D(32, (3, 3), 激活='relu', padding='相同'))model.add(Conv2D(32, ( 3, 3), 激活='relu', 填充='相同', strides=2))model.add(UpSampling2D((2, 2)))model.add(Conv2D(32, (3, 3)), 激活='relu', padding='相同'))model.add(UpSampling2D((2, 2)))model.add(Conv2D(16, (3, 3), 激活='relu', padding='相同' ))model.add(UpSampling2D((2, 2)))model.add(Conv2D(2, (3, 3),activation='tanh', padding='same'))# 完成model.compile(optimizer='rmsprop',loss='mse')#训练神经网络model.fit(x=X, y=Y,batch_size=1, epochs=3000)print(model.evaluate(X,Y,batch_size=1))#输出colorizationsoutput=model.predict(X)output=输出* 128canvas=np.zeros((400, 400, 3))canvas[:0]=X[0][:0]canvas[:1:]=输出[0]imsave('img_result.png', lab2rgb(cur))imsave('img_gray_scale.png', rgb2gray(lab2rgb(cur)))

使用FloydHub 命令运行网络:

弗洛伊德运行--data emilwallner/datasets/colornet/2:data --mode jupyter --tensorboard

技术说明

总的来说,输入是黑白图像的网格,输出是两个带有颜色值的网格。在输入和输出之间,构建了一个滤波器,通过卷积神经网络将两者连接起来。

训练网络时使用彩色图像,并将RGB 颜色转换为Lab 颜色空间。网络输入是黑白层,输出两个着色层。

在上图的左侧,输入是黑白网格、滤波器和神经网络的预测。

比较同一变化区间内预测值与实际值的差异。其中,距离为[-1, 1]。为了映射这些预测,我们使用Tanh 激活函数,因为Tanh 函数的输入可以是任何值,输出为-1 到1。

事实上,颜色值的分布区间是[-128, 128],这也是Lab颜色空间的默认间距。除以128后,这些值也落入区间[-1, 1],这样就可以用来比较预测结果的误差。

计算出最终误差后,网络更新滤波器以减少全局误差。网络将保持在这个循环中,直到误差足够小。

下面解释了代码的一些语法。

X=rgb2lab(1.0/255*图像)[:0]Y=rgb2lab(1.0/255*图像)[:1:]

1.0/255 表示彩色图像使用的RGB 颜色空间为24 位,这意味着每个颜色通道值都是一个整数,并且从0 到255 变化。这是标准颜色范围,共有1670 万种颜色组合。由于人类只能感知2 到100,000 种颜色,因此使用更大的颜色空间没有多大意义。

Y=Y/128

与RGB 相比,Lab 颜色空间具有不同的范围。 Lab 中色谱图ab 的取值范围为[-128, 128]。将输出层的所有值除以128,其范围变为[-1, 1]。神经网络的输出值范围也是[-1, 1],两者可以匹配。

使用rgb2lab() 函数转换颜色空间后,我们使用[:0] 选择灰度层,这是神经网络的输入。同时[:1:]表示选择绿红和蓝黄两个颜色层。

训练神经网络后,将其转换回Lab图像以进行最终预测。

输出=model.predict(X) 输出=输出* 128

其中,输入为灰度图像。经过训练的神经网络,其输出在区间[-1, 1]内,然后乘以128,得到Lab色谱中合适的颜色。

canvas=np.zeros((400, 400, 3))canvas[:0]=X[0][:0]canvas[:1:]=输出[0]

关于创建Alpha版本的一些想法

1. 阅读研究论文是痛苦的。但只要你能总结出每篇论文的核心观点,你就可以轻松地阅读论文并更加关注文本中的上下文。

2、关键是从简化版入手。网上的实现大多有2000到10000行代码,这让我很难理解问题的核心逻辑。一旦有了准系统版本,以后阅读实现代码和研究论文就会更容易。

3探索开源项目。为了大致了解如何编程,我浏览了Github 上的50-100 个有关着色的项目。

4.事情并不总是按预期进行。一开始,我的网络只能创建红色和黄色。最初,Relu激活函数用于最后一层激活。因为它只能将数字映射到正数,所以无法得到负值和蓝绿色光谱。后来我添加了一个Tanh 激活函数来映射Y 值,这解决了问题。

5.理解比速度更重要。我看到很多实现代码运行速度非常快,但很难阅读。我选择优化创新速度而不是代码速度。

测试版

要了解Alpha 版本的缺点,请使用网络对未经训练的图像进行着色。尝试一下,您会发现它效果不佳,因为网络只记住它已经拥有的信息,并且没有学会如何为看不见的图像着色。而这也正是我们在Beta版本中努力的方向,即提高网络的泛化能力。

下面是Beta 版神经网络在验证图像上的着色结果。

我没有使用现有的Imagenet,而是在FloydHub 上创建了一个公开可用的高质量图像数据集。 Unsplash收集了大量专业摄影师的创意分享图片。这个数据集中的图像就来自于此。它总共包括9,500 张训练图像和500 张验证图像。

特征提取器

我们构建的神经网络可以找到将灰度图像与其彩色版本相关联的有效特征。

想象一下,您必须对黑白图像进行着色,但您一次只能看到九个像素。你只能从左上角到右下角扫描每张图像,并尝试预测每个像素可能的颜色值。

例如,这九个像素是上面女人鼻孔的边缘。可以想象,这很难得到好的着色效果,因此将其分解为多个步骤。

首先,您需要寻找简单的图案,例如对角线和黑色像素。您还可以在每个方块中查找完全相同的图案并删除不匹配的像素。具体方法是使用前64个滤波器生成64张新图像。

当再次扫描图像时,您将看到与检测到的相同的小图案。为了更深入地了解图像,您可以将图像分辨率减半。

您仍然只使用33 滤镜来扫描每个图像。然而,通过将9 个新像素与较低级别的过滤器相结合,您可以检测更复杂的模式。几个像素组合起来可以形成半圆、小点或线。此外,您可以重复从图像中提取相同的图案,从而生成128 个新的过滤图像。

经过一些操作后,新的过滤图像可能如下所示:

如上所述,首先提取边缘等低级特征。靠近输出的层首先被组合成图案,然后组合成局部细节,最后组合成面部。如果您觉得难以理解,可以观看此视频教程(https://www.youtube.com/watch?v=AgkfIQ4IGaM)。

这个过程类似于用于处理图像的神经网络,称为卷积神经网络。卷积运算类似于单词组合,通过组合多个滤波后的图像来理解图像中的上下文。

从特征提取到着色

神经网络是使用误差传播来实现的。首先,它对每个像素进行随机预测;然后根据每个像素的误差,通过反向传播来提高特征提取效果。

最初,它首先调整误差最大的位置。因此,最初只考虑了两个问题,即是否着色和是否放置不同的物体;那么所有物体都被涂成棕色,因为这是与其他颜色最相似的颜色,并且产生的误差最小。

由于大多数训练数据非常相似,网络只能通过调整棕色的深浅来区分不同的物体,而无法产生更详细的颜色,这是我们将在最终版本中探索的内容。

以下是测试版的代码和技术说明。

# 获取os.listdir('./Train/'): 中文件名的imagesX=[] X.append(img_to_array(load_img('./Train/'+filename)))X=np.array(X, dtype=float)# 设置训练和测试数据split=int(0.95*len(X))Xtrain=X[:split]Xtrain=1.0/255*Xtrain#设计神经网络model=Sequential()model.add(InputLayer(input_shape)=(256, 256, 1)))model.add(Conv2D(64, (3, 3), 激活='relu', padding='相同'))model.add(Conv2D(64, (3, 3)) , 激活='relu', 填充='相同', 步幅=2))model.add(Conv2D(128, (3, 3), 激活='relu', 填充='相同'))model.add(Conv2D (128, (3, 3), 激活='relu', 填充='相同', 步幅=2))model.add(Conv2D(256, (3, 3), 激活='relu', 填充='相同'))model.add(Conv2D(256, (3, 3), 激活='relu', padding='相同', strides=2))model.add(Conv2D(512, (3, 3), 激活='relu', padding='相同'))model.add(Conv2D(256, (3, 3), 激活='relu', padding='相同'))model.add(Conv2D(128, (3, 3) ) ), 激活='relu', 填充='相同'))model.add(UpSampling2D((2, 2)))model.add(Conv2D(64, (3, 3)), 激活='relu', 填充='相同'))model.add(UpSampling2D((2, 2)))model.add(Conv2D(32, (3, 3), 激活='relu', padding='相同'))model.add( Conv2D (2, (3, 3), activate='tanh', padding='相同'))model.add(UpSampling2D((2, 2)))# 完成model.compile(optimizer='rmsprop', loss=' mse')# Image Transformerdatagen=ImageDataGenerator(shear_range=0.2, Zoom_range=0.2,rotation_range=20,horizontal_flip=True)# 生成训练数据batch_size=50def image_a_b_gen(batch_size):用于datagen.flow中的batch(Xtrain,batch_size=batch_size) : lab_batch=rgb2lab(batch) 训练modelTensorBoard(log_dir='/output')model.fit_generator(image_a_b_gen(batch_size), steps_per_epoch=10000, epochs=1)# 测试imagesXtest=rgb2lab(1.0/255*X[split:])[ :0 ]Xtest=batch_size=batch_size)# 加载黑白图像color_me=[]for filename in os.listdir('./Test/'): color_me.append(img_to_array(load_img('. /Test/'+文件名)))color_me=np.array(color_me, dtype=float)color_me=rgb2lab(1.0/255*color_me)[:0]color_me=color_me.reshape(color_me.shape+( 1,))# 测试模型输出=model.预测(color_me)output=输出* 128# 输出范围内的i的着色(len(output)): cur=np.zeros((256, 256, 3)) cur[:0]=color_me[i][ :0] cur[:1:]=输出[i] imsave('结果/img_'+str(i)+'.png', lab2rgb(cur))

使用FloydHub 命令运行神经网络的beta 版本:

弗洛伊德运行--data emilwallner/datasets/colornet/2:data --mode jupyter --tensorboard

技术说明

与其他视觉网络不同,它的主要区别在于像素位置的重要性。在着色网络中,图像的分辨率或比例在整个网络中各不相同

保持不变。而在其他网络中,越靠近最后一层,图像变得越扭曲。 分类网络中的最大池化层增加了信息密度,但也可能导致图像失真。它只对信息进行估值,而未考虑到图像布局。在着色网络中,我们将步幅改为2,每次运算使宽度和高度减半。这样,不但增加了信息密度,也不会使图像扭曲。 两者差异在于上采样层和图像比例保持方面。而分类网络只关心最终的分类正确率,因此随着网络深入,它会不断减小图像的分辨率和质量。 但是,着色网络的图像比例保持不变。这是通过添加空白填充来实现的,否则每个卷积层将削减图像,实现代码为:padding =’same’。 要使图像的分辨率加倍,着色网络使用了上采样层,更多信息见:https://keras.io/layers/convolutional/#upsampling2d。 for filename in os.listdir('/Color_300/Train/'): X.append(img_to_array(load_img('/Color_300/Test'+filename))) 这个for循环首先计算了目录中的所有文件名,然后遍历图像目录,并将图像转换为像素数组,最后将其组合成一个大型矢量。 datagen = ImageDataGenerator( shear_range=0.2, zoom_range=0.2, rotation_range=20, horizontal_flip=True) 在ImageDataGenerator中,我们还修改了图像生成器的参数。这样,图像永远不会相同,以改善学习效果。参数shear_range是指图像向左或向右的倾斜程度,其他参数不需要加以说明。 batch_size = 50def image_a_b_gen(batch_size): for batch in datagen.flow(Xtrain, batch_size=batch_size): lab_batch = rgb2lab(batch) X_batch = lab_batch[:,:,:,0] Y_batch = lab_batch[:,:,:,1:] / 128 yield (X_batch.reshape(X_batch.shape+(1,)), Y_batch) 我们使用了文件夹Xtrain中的图像,根据之前设置来生成图像。然后我们提取X_batch中的黑白层和两个颜色层的两种颜色。

model.fit_generator(image_a_b_gen(batch_size), steps_per_epoch=1, epochs=1000) 拥有越高性能的GPU,则可以设置越大的batch_size值。根据现有硬件,我们设置了每批次输入50-100张图像。参数steps_per_epoch是通过把训练图像的数量除以批次大小得出的。例如,有100张图像且批次大小为50,则steps_per_epoch值为2。参数epoch决定网络中所有图像的训练次数。在Tesla K80 GPU上,大约需要11小时才能完成对1万张图像的21次训练。 训练心得 1.先进行多次小批次实验,再尝试大批次实验。即使经过20-30次实验,我仍然发现很多错误。程序能运行并不意味着它能工作。神经网络中的问题通常比传统编程遇到的Bug更为麻烦。 2.多样化的数据集会使着色效果呈现棕色。如果数据集中图像比较相似,不需要设计很复杂的架构,就可以得到一个良好效果,但是其泛化能力十分糟糕。 3.重视图像形状的统一性。每张图像的分辨率必须是准确的,且在整个网络中保持成比例。开始时,所使用的图像分辨率为300,将它减半三次后分别得到150、75和35.5。因此,就丢失了半个像素,这导致了很多问题,后来才意识到应该使用4、8、16、32、64、256等这种能被2整除的数。 4.创建数据集。请禁用.DS_Store文件,不然会产生很多麻烦;大胆创新,最后我用Chrome控制台脚本和扩展程序来下载文件;备份原始文件并构建清理脚本。 最终版本 最终版本的着色神经网络有四个组成部分。我们将之前的网络拆分成编码器和解码器,在这两者之间还添加了一个融合层。关于分类网络的基本教程,可参考:https://cs231n.github.io/classification/。 Inception resnet v2是目前最强大的分类器之一,使用了120万张图像来训练该网络。我们提取了它的分类层,并将其与编码器的输出进行合并。因此,输入数据传给编码器的同时,也并行传输到resnet v2网络的分类层中。更多信息,请参考原论文:https://github.com/baldassarreFe/deep-koalarization。 △ 信息并行传输示意图 这个网络通过将分类器的学习效果迁移到着色网络上,可更好理解图片中的内容。因此,这样使得网络能够把目标表征与着色方案相匹配。 以下是在一些验证图像上的着色效果,仅使用20张图像来训练网络。 大多数图像的着色效果不好,但是由于验证集中有2500张图像,我设法找到了一些良好的着色图像。在更多图像上进行训练可以获得更为稳定的结果,但是大部分都呈现棕色色调。这两个链接贴出了运行试验的完整列表,包括验证图像(https://www.floydhub.com/emilwallner/projects/color) (https://www.floydhub.com/emilwallner/projects/color_full)。 注意:在下面代码中,我把Keras的序列模型变换成相应的函数调用。 # Get imagesX = []for filename in os.listdir('/data/images/Train/'): X.append(img_to_array(load_img('/data/images/Train/'+filename)))X = np.array(X, dtype=float)Xtrain = 1.0/255*X#Load weightsinception = InceptionResNetV2(weights=None, include_top=True)inception.load_weights('/data/inception_resnet_v2_weights_tf_dim_ordering_tf_kernels.h5')inception.graph = tf.get_default_graph()embed_input = Input(shape=(1000,))#Encoderencoder_input = Input(shape=(256, 256, 1,))encoder_output = Conv2D(64, (3,3), activation='relu', padding='same', strides=2)(encoder_input)encoder_output = Conv2D(128, (3,3), activation='relu', padding='same')(encoder_output)encoder_output = Conv2D(128, (3,3), activation='relu', padding='same', strides=2)(encoder_output)encoder_output = Conv2D(256, (3,3), activation='relu', padding='same')(encoder_output)encoder_output = Conv2D(256, (3,3), activation='relu', padding='same', strides=2)(encoder_output)encoder_output = Conv2D(512, (3,3), activation='relu', padding='same')(encoder_output)encoder_output = Conv2D(512, (3,3), activation='relu', padding='same')(encoder_output)encoder_output = Conv2D(256, (3,3), activation='relu', padding='same')(encoder_output)#Fusionfusion_output = RepeatVector(32 * 32)(embed_input)fusion_output = Reshape(([32, 32, 1000]))(fusion_output)fusion_output = concatenate([encoder_output, fusion_output], axis=3)fusion_output = Conv2D(256, (1, 1), activation='relu', padding='same')(fusion_output)#Decoderdecoder_output = Conv2D(128, (3,3), activation='relu', padding='same')(fusion_output)decoder_output = UpSampling2D((2, 2))(decoder_output)decoder_output = Conv2D(64, (3,3), activation='relu', padding='same')(decoder_output)decoder_output = UpSampling2D((2, 2))(decoder_output)decoder_output = Conv2D(32, (3,3), activation='relu', padding='same')(decoder_output)decoder_output = Conv2D(16, (3,3), activation='relu', padding='same')(decoder_output)decoder_output = Conv2D(2, (3, 3), activation='tanh', padding='same')(decoder_output)decoder_output = UpSampling2D((2, 2))(decoder_output)model = Model(inputs=[encoder_input, embed_input], outputs=decoder_output)#Create embeddingdef create_inception_embedding(grayscaled_rgb): grayscaled_rgb_resized = [] for i in grayscaled_rgb: i = resize(i, (299, 299, 3), mode='constant') grayscaled_rgb_resized.append(i) grayscaled_rgb_resized = np.array(grayscaled_rgb_resized) grayscaled_rgb_resized = preprocess_input(grayscaled_rgb_resized) with inception.graph.as_default(): embed = inception.predict(grayscaled_rgb_resized) return embed# Image transformerdatagen = ImageDataGenerator( shear_range=0.4, zoom_range=0.4, rotation_range=40, horizontal_flip=True)#Generate training databatch_size = 20def image_a_b_gen(batch_size): for batch in datagen.flow(Xtrain, batch_size=batch_size): grayscaled_rgb = gray2rgb(rgb2gray(batch)) embed = create_inception_embedding(grayscaled_rgb) lab_batch = rgb2lab(batch) X_batch = lab_batch[:,:,:,0] X_batch = X_batch.reshape(X_batch.shape+(1,)) Y_batch = lab_batch[:,:,:,1:] / 128 yield ([X_batch, create_inception_embedding(grayscaled_rgb)], Y_batch)#Train model tensorboard = TensorBoard(log_dir="/output")model.compile(optimizer='adam', loss='mse')model.fit_generator(image_a_b_gen(batch_size), callbacks=[tensorboard], epochs=1000, steps_per_epoch=20)#Make a prediction on the unseen imagescolor_me = []for filename in os.listdir('../Test/'): color_me.append(img_to_array(load_img('../Test/'+filename)))color_me = np.array(color_me, dtype=float)color_me = 1.0/255*color_mecolor_me = gray2rgb(rgb2gray(color_me))color_me_embed = create_inception_embedding(color_me)color_me = rgb2lab(color_me)[:,:,:,0]color_me = color_me.reshape(color_me.shape+(1,))# Test modeloutput = model.predict([color_me, color_me_embed])output = output * 128# Output colorizationsfor i in range(len(output)): cur = np.zeros((256, 256, 3)) cur[:,:,0] = color_me[i][:,:,0] cur[:,:,1:] = output[i] imsave("result/img_"+str(i)+".png", lab2rgb(cur)) 用FloydHub命令来运行最终版本神经网络: floyd run --data emilwallner/datasets/colornet/2:data --mode jupyter --tensorboard 技术说明 当你要实现模型连接或模型融合时,Keras的函数调用功能是最佳选择。 △ 模型融合层 首先,要下载inception resnet v2网络并加载权重。由于要并行使用两个模型,因此必须指定当前要使用哪个模型。这个可通过Keras的后端Tensorflow来完成。 inception = InceptionResNetV2(weights=None, include_top=True)inception.load_weights('/data/inception_resnet_v2_weights_tf_dim_ordering_tf_kernels.h5')inception.graph = tf.get_default_graph() 批处理方法中使用了调整后的图像,把它们变成黑白图像,并在inception resnet模型上运行。 grayscaled_rgb = gray2rgb(rgb2gray(batch))embed = create_inception_embedding(grayscaled_rgb) 首先,要调整图像分辨率以适应inception模型;然后根据模型,使用预处理程序来规范化像素和颜色值;最后,在inception网络上运行并提取模型最后一层的权重。 def create_inception_embedding(grayscaled_rgb): grayscaled_rgb_resized = [] for i in grayscaled_rgb: i = resize(i, (299, 299, 3), mode='constant') grayscaled_rgb_resized.append(i) grayscaled_rgb_resized = np.array(grayscaled_rgb_resized) grayscaled_rgb_resized = preprocess_input(grayscaled_rgb_resized) with inception.graph.as_default(): embed = inception.predict(grayscaled_rgb_resized) return embed 再讲下生成器。对于每个批次,我们按照下列格式生成20张图像,在Tesla K80 GPU上大约要运行一个小时。基于该模型,每批次最多可输入50张图像,且不产生内存溢出。 yield ([X_batch, create_inception_embedding(grayscaled_rgb)], Y_batch)代码23 这与本项目中着色模型的格式相匹配。 model = Model(inputs=[encoder_input, embed_input], outputs=decoder_output) encoder_input会输入到编码器模型中;接着,编码器模型的输出会与融合层中的embed_input相融合;然后,这个融合输出会作为解码器模型的输入;最终,解码器模型会输出预测结果decode_output。 fusion_output = RepeatVector(32 * 32)(embed_input)fusion_output = Reshape(([32, 32, 1000]))(fusion_output)fusion_output = concatenate([fusion_output, encoder_output], axis=3)fusion_output = Conv2D(256, (1, 1), activation='relu')(fusion_output) 在融合层中,首先将1000类输出层乘以1024(即32×32),这样就从inception模型的最后一层得到了1024行数据;接着,把2D重构成3D得到一个具有1000个类别对象的32x32网格;然后,将它与编码器模型的输出相连;最后,应用一个带有254个1X1内核的卷积网络,得到了融合层的最终输出。 一些思考 1.不要逃避难懂的术语。我花了三天时间去搜索在Keras该如何实现“融合层”。因为这听起来很复杂,我不想面对这个问题,而是试图找到现成代码。 2.多在网上请教他人。在Keras论坛中,我提出的问题没人回答,同时Stack Overflow删除了我的提问。但是,通过分解成小问题去请教他人,这迫使我进一步理解问题,并更快解决问题。 3.多发邮件请教。虽然论坛可能没人回应,人们关心你能否直接与他们联系。在Skype上与你不认识的研究人员一起探讨问题,这听起来很有趣。 4.在解决“融合层”问题之前,我决定构建出所有组件。以下是分解融合层的几个实验(https://www.floydhub.com/emilwallner/projects/color/24/code/Experiments/transfer-learning-examples)。 5.我以为某些代码能够起作用,但是在犹豫是否要运行。虽然我知道核心逻辑是行得通的,但我不认为它会奏效。经过一阵纠结,我还是选择运行。运行完模型的第一行代码后,就开始报错;四天后,一共产生几百个报错,我也做了数千个Google搜索,模型依旧停留在“Epoch 1/22”。 下一步计划 图像着色是一个极其有趣的问题。这既是一个科学问题,也是一个艺术问题。我写下这篇文章,希望你能从中有所启发,以加快在图像着色方面的研究。以下是一些建议: 1.微调另一个预训练好的模型; 2.使用不同的数据集; 3.添加更多图片来提高网络的正确率; 4.在RGB颜色空间中构建一个放大器。构建一个与着色网络类似的模型,将深色调的着色图像作为输入,它能微调颜色以输出合适的着色图像; 5.进行加权分类; 6.应用一个分类神经网络作为损失函数。网络中错误分类的图片有一个相应误差,探究每个像素对该误差的贡献度。 7.应用到视频中。不要太担心着色效果,而是要关注如何使图像切换保持协调。你也可以通过平铺多张小图像来处理大型图像。 当然,你也可以尝试用我贴在FloydHub上的三种着色神经网络,来给你的黑白图像着色。 1.对于Alpha版本,只需将你的图片分辨率调成400x400像素,把名称改为woman.jpg,并替换原有文件。 2.对于Beta版本和最终版本,在你运行FloydHub命令之前,要将你的图片放入Test文件夹。当Notebook运行时,你也可以通过命令行直接上传到Test文件夹。要注意,这些图像的分辨率必须是256x256像素。此外,你也可以上传彩色测试图像集,因为这个网络会自动把它们转换为黑白图像。 相关链接 1.Alpha版本机器人的Jupyter Notebook代码: https://www.floydhub.com/emilwallner/projects/color/43/code/Alpha-version/alpha_version.ipynb 2.三个版本实现代码 - Floydhub传送门: https://www.floydhub.com/emilwallner/projects/color/43/code 3.三个版本实现代码 - Github传送门: https://github.com/emilwallner/Coloring-greyscale-images-in-Keras 4.所有实验代码: https://www.floydhub.com/emilwallner/projects/color/jobs 6.教程原文:https://blog.floydhub.com/colorizing-b&w-photos-with-neural-networks/ — 完 — 诚挚招聘

用户评论

执妄

太神奇了!我一直都想给老照片打上颜色看看!这份教程好宝贵啊,一定要下来试试看!

    有16位网友表示赞同!

如梦初醒

我曾经试过用其他软件上色老照片,效果總是怪怪的。这篇教程介绍神经网络的方法应该更好吧?期待看到最终的效果。

    有18位网友表示赞同!

一笑抵千言

终于有人做了!我一直都在关注这类技术的进展,很高兴看到一个详细的教程。神经网络上色确实很有潜力!

    有6位网友表示赞同!

墨染年华

如果最终效果能像照片上的那么逼真,那太棒了!我现在已经急着要跟着教程试试手。

    有17位网友表示赞同!

百合的盛世恋

我对神经网络不太了解,但看起来这篇文章解释得非常清楚易懂。学习新技术总是很让人兴奋的!

    有10位网友表示赞同!

盲从于你

说实话,我不太相信这种方法能达到完美的的效果。彩色照片终究和黑白照片不一样,总会有微妙差距。

    有10位网友表示赞同!

有一种中毒叫上瘾成咆哮i

这个教程看起来很专业,希望能够顺利完成!我对最终效果充满期待,能亲眼看到老照片重焕生命真是个激动人心的事情!

    有14位网友表示赞同!

凉笙墨染

我已经开始下载需要的软件了! 真的很有趣,以前一直想把爷爷奶奶年轻时候的照片变得生动一点。希望能成功!

    有12位网友表示赞同!

沐晴つ

我看了一下教程的代码,感觉有点复杂...我技术不是太好怎么办?

    有17位网友表示赞同!

晨与橙与城

我很想知道这个神经网络是如何识别照片中不同的物体颜色和纹理的? 真的太神奇了!

    有6位网友表示赞同!

窒息

感觉这个功能用处很大啊! 可以给很多历史照片打上颜色,让我们更好地了解过去!

    有6位网友表示赞同!

琴断朱弦

现在很多智能手机都有类似的功能,效果还蛮不错的。这篇文章还是挺有研究价值的,也许能学习到一些更先进的技术。

    有12位网友表示赞同!

煮酒

对我来说,老照片就应该保持黑白的样子! 给它加上颜色反而感觉失去了原有的魅力!

    有6位网友表示赞同!

妄灸

看起来这个教程非常详细,相信即使新手也可以跟着操作完成。 真期待看到最终的效果!

    有6位网友表示赞同!

古巷青灯

我一直很喜欢AI相关的技术研究,这篇文章引起了我的兴趣。希望能够学习到更多关于神经网络的知识!

    有5位网友表示赞同!

开心的笨小孩

这个教程看起来很有挑战性,但我挺喜欢这种挑战! 准备好好学习一下,看看自己能不能成功完成。

    有18位网友表示赞同!

心贝

黑白色照片虽然更显历史感,但有时候我确实会想看一看它们鲜艳的颜色,这篇文章或许能帮我实现这个愿望!

    有18位网友表示赞同!

热点资讯