生成对抗网络(GAN)作为一个火热的机器学习模型,近几年来受到了极大的关注,但是生成对抗网络仍然存在一些问题,因此研究人员将生成对抗网络与卷积生成对抗网络结合起来,也就是深度卷积生成对抗网络(DCGAN)并取得了很好的结果。因此我们首先简要介绍一下深度学习领域中最重要的神经网络——卷积神经网络。
图像识别技术背后的原理并不是很难,只是其要处理的信息比较繁琐。计算机的任何处理技术都不是凭空产生的,它都是学者们从生活实践中得到启发而利用程序将其模拟实现的。计算机的图像识别技术和人类的图像识别在原理上并没有本质的区别,只是机器缺少人类在感觉与视觉差上的影响罢了。人类的图像识别也不单单是凭借整个图像存储在脑海中的记忆来识别的,我们识别图像都是依靠图像所具有的本身特征而先将这些图像分了类,然后通过各个类别所具有的特征将图像识别出来的,只是很多时候我们没有意识到这一点。当看到一张图片时,我们的大脑会迅速感应到是否见过此图片或与其相似的图片。其实在“看到”与“感应到”的中间经历了一个迅速识别过程,这个识别的过程和搜索有些类似。在这个过程中,我们的大脑会根据存储记忆中已经分好的类别进行识别,查看是否有与该图像具有相同或类似特征的存储记忆,从而识别出是否见过该图像。机器的图像识别技术也是如此,通过分类并提取重要特征而排除多余的信息来识别图像。机器所提取出的这些特征有时会非常明显,有时又是很普通,这在很大的程度上影响了机器识别的速率。总之,在计算机的视觉识别中,图像的内容通常是用图像特征进行描述。
过拟合:训练数据过于单一,对于未知数据的预测效果较差:
解决过拟合的方法就是增加数据量
欠拟合:训练数据过于复杂,训练效果较差
解决欠拟合的方法就是增加模板数量(增加模型能力)
对于这样一个不同位置的动漫图像,如果采用模板匹配的方法则至少需要4个神经元才能一一匹配上,这样的话运算量就比较复杂,需要大量参数。那如果我使用的是一个卷积核,则只需要一个卷积核然后进行扫码即可完成,因此参数数量很小,则更容易训练,更方便控制吗,而且过拟合现象也可以降低,性能也提升了,这就是卷积神经网络最终要的一个意义所在。
卷积核我们可以理解为一个观察的人,带着若干权重和一个偏置去观察,进行特征加权运算。
卷积就是一个卷积核从左到右从上到下进行一个扫码的加权运算的过程。
需要去移动卷积核观察这张图片,需要的参数就是步长。假设移动的步长为1,那么最终这个人观察的结果以下图为例:
5x5的图片,3x3的卷积大小去一个步长运算得到3x3的大小观察结果
如果移动的步长为2,那么结果就是:5x5的图片,3x3的卷积大小去二个步长运算得到2×2的大小观察结果
零填充就是在图片像素外围,填充一圈为0的像素。有两种方式:SAME和VALID
如果卷积提取后图像变小,那么不让提取后图像缩小,我们可以在像素外围填充0,填充的方式有两种,SAME和VALID。
SAME:填充0像素,使得卷积提取后图片大小不变。
VALID:图像变小
池化和卷积类似,只是无权重
input:输入大小
F:卷积核大小
p:零填充大小
S:跨步大小
主要特点:跨层网络连接,跨层前向传播,这样反向传播就能快速的传播到下层网络
近年来,使用卷积网络的监督学习在计算机视觉应用中得到了广泛的应用。相比之下,使用CNN的无监督学习受到的关注较少。在本篇论文中中,我们希望在监督学习的CNN和非监督学习之间建立一个桥梁。我们引入了一类称为深度卷积生成对抗网络(DCGAN)的结构,它们具有一定的体系结构约束,并证明了它们是无监督学习的强有力的候选方法。作者在各种图像数据集上进行训练,强有力的证据表明我们的深度卷积对抗对网络在生成器和判别器都可以学习到图像化的一个表征。此外,我们将所学的特征用于新的任务——证明它们作为一般图像表示的适用性。
摘要所提出来的问题就是CNN很少用在非监督学习中,而目标就是建立CNN在监督学习与非监督学习之间的桥梁,因此作者提出了DCGAN,实验的结果证明能够使用GAN学习层次特征
Introduction部分及作者所做的贡献:
生成器一开始是一个100维的噪声,经过第一层卷积提取之后是一个4×4×1024的一个卷积核。
DCGAN实际上就是CNN+GAN,结构不变,只是生成器和判别器使用卷积神经网络,生成器使用上述的一个网络结构,生成一个伪造的图片,判别器的具体用的哪个网络在原始论文中没有具体说明。我们可以使用一个通用的CNN,例如DenseNet等。
DCGAN训练的方法与训练GAN的步骤类似。
二次元图像生成就是将一堆随机噪声在DCGAN网络作用下,将随机噪声转换为二次元图片的一个过程。
读取磁盘图像,并将图片重新调整大小到规定尺寸,以及对图片要归一化到-1到1之间。
关键代码如下:
// An highlighted block
def read_img2numpy(batch_size=64,img_h=64,img_w=64,path="data/faces"):
"""
读取磁盘图像,并将图片重新调整大小
:param batch_size: 每次读取图片数量
:param img_h: 图片重新调整高度
:param img_w: 图片重新调整宽度
:param path: 数据存放路径
:return: 图像numpy数组
"""
file_list = os.listdir(path) # 图像名称列表
data = np.zeros([batch_size,img_h,img_w,3],dtype=np.uint8) # 初始化numpy数组
mask = np.random.choice(len(file_list),batch_size,replace=True)
for i in range(batch_size):
mm = Image.open(path+"/"+file_list[mask[i]])
tem =mm.resize((img_w,img_h)) # 重新调整图片大小
data[i,:,:,:] = np.array(tem)
# 数据归一化 -1-1
data = (data-127.5)/127.5 #-1-1
return data
def img2gif(img_path="out/dcgan/",gif_path="out/dcgan/"):
#获取图像文件列表
file_list = os.listdir(img_path)
imges = []
for file in file_list:
if file.endswith(".png"):
img_name = img_path +file
imges.append(imageio.imread(img_name))
imageio.mimsave(gif_path+"result.gif",imges,fps=2)
if __name__ == '__main__':
data = read_img2numpy()
print(data.shape)
data = ((data * 127.5) + 127.5).astype(np.uint8)
plt.imshow(data[10])
plt.show()
判别器初始化模块代码:
// An highlighted block
def _init_discriminator(self, input, isTrian=True, reuse=False):
"""
初始化判别器
:param input:输入数据op
:param isTrian: 是否训练状态(bn)
:param reuse: 是否复用
:return: 判断op
"""
with tf.variable_scope("discriminator", reuse=reuse):
# hidden layer 1 input=[None,64,64,3]
conv1 = tf.layers.conv2d(input, 32, [3, 3], strides=(2, 2), padding="same") # [none,32,32,32]
bn1 = tf.layers.batch_normalization(conv1)
active1 = tf.nn.leaky_relu(bn1) # [none,32,32,32]
# hidden layer 2
conv2 = tf.layers.conv2d(active1, 64, [3, 3], strides=(2, 2), padding="same") # [none,16,16,64]
bn2 = tf.layers.batch_normalization(conv2)
active2 = tf.nn.leaky_relu(bn2) # [none,16,16,64]
# hidden layer 3
conv3 = tf.layers.conv2d(active2, 128, [3, 3], strides=(2, 2), padding="same") # [none,8,8,128]
bn3 = tf.layers.batch_normalization(conv3)
active3 = tf.nn.leaky_relu(bn3) # [none,8,8,128]
# hidden layer 4
conv4 = tf.layers.conv2d(active3, 256, [3, 3], strides=(2, 2), padding="same") # [none,4,4,256]
bn4 = tf.layers.batch_normalization(conv4)
active4 = tf.nn.leaky_relu(bn4) # [none,4,4,256]
# out layer
out_logis = tf.layers.conv2d(active4, 1, [4, 4], strides=(1, 1), padding='valid') # [none,1,1,1]
return out_logis
生成器初始化模块代码:
// An highlighted block
def _init_generator(self, input, isTrian=True, reuse=False):
"""
初始化生成器
:param input:输入噪声op
:param isTrian: 是否训练状态(BN)
:param reuse: 是否复用(复用tensorflow变量)
:return: 生成图像op
"""
with tf.variable_scope("generator", reuse=reuse):
# input [none,1,1,noise_dim]
conv1 = tf.layers.conv2d_transpose(input, 512, [4, 4], strides=[1, 1], padding="valid") # [none,4,4,512]
bn1 = tf.layers.batch_normalization(conv1)
active1 = tf.nn.leaky_relu(bn1) # [none,4,4,512]
print(active1)
# deconv layer2
conv2 = tf.layers.conv2d_transpose(active1, 256, [3, 3], strides=[2, 2], padding='same') # [none,8,8,256]
bn2 = tf.layers.batch_normalization(conv2)
active2 = tf.nn.leaky_relu(bn2) # [none,8,8,256]
# deconv layer3
conv3 = tf.layers.conv2d_transpose(active2, 128, [3, 3], strides=[2, 2], padding="same") # [none,16,16,128]
bn3 = tf.layers.batch_normalization(conv3)
active3 = tf.nn.leaky_relu(bn3) # [none,16,16,128]
# deconv layer4
conv4 = tf.layers.conv2d_transpose(active3, 64, [3, 3], strides=[2, 2], padding="same") # [none,32,32,64]
bn4 = tf.layers.batch_normalization(conv4)
active4 = tf.nn.leaky_relu(bn4) # [none,32,32,64]
# decov layer 5
conv5 = tf.layers.conv2d_transpose(active4, 3, [3, 3], strides=(2, 2), padding="same") # [none,64,64,3]
out = tf.nn.tanh(conv5)
return out
本文是基于GAN的基础之上结合CNN所提出的深度卷积生成对抗网络(DCGAN),接下来会在GAN和DCGAN的基础之上对其训练技巧进行提升,对在可控图像生成技术,特征解耦图像生成技术,非监督条件图像生成技术等方面应用的一个总结。
本文代码链接:链接:https://pan.baidu.com/s/1Rp2_SEQom3w3ueH48BRRmQ
提取码:p65x