1. tf.nn.moments(x, axes=[0, 1, 2])  # 对前三个维度求平均值和标准差,结果为最后一个维度,即对每个feature_map求平均值和标准差

参数说明:x为输入的feature_map, axes=[0, 1, 2] 对三个维度求平均,即每一个feature_map都获得一个平均值和标准差

2.with tf.control_dependencies([train_mean, train_var]): 即执行with里面的操作时,会先执行train_mean 和 train_var 

参数说明:train_mean表示对pop_mean进行赋值的操作,train_var表示对pop_var进行赋值的操作

3.tf.cond(is_training, bn_train, bn_inference)  # 如果is_training为真,执行bn_train函数操作,如果为假,执行bn_inference操作

参数说明:is_training 为真和假,bn_train表示训练的normalize, bn_inference表示测试的normalize

4. tf.nn.atrous_conv2d(x, filters, dilated, padding) # 进行空洞卷积操作,用于增加卷积的感受野

参数说明:x表示输入样本,filter表示卷积核,dilated表示卷积核的补零个数,padding表示对feature进行补零操作

5. tf.nn.conv2d_transpose(x, filters, output_size, strides) # 进行反卷积操作

参数说明:x表示输入样本,filter表示卷积核,output_size表示输出的维度, strides表示图像扩大的倍数

6.tf.nn.batch_normalization(x, mean, var, beta, scale, episilon) # 进行归一化操作

参数说明: x表示输入样本,mean表示卷积的平均值,var表示卷积的标准差,beta表示偏差,scale表示标准化后的范围,episilon防止分母为0 

7.tf.train.get_checkpoint_state('./backup') # 判断用于进行model保存的文件中是否有checkpoint,即是否之前已经有过保存的sess

参数说明:'./backup'进行sess保存的文件名

 

原理的话,使用论文中的图进行说明, 这是论文中的效果图,我们可以看出不管是场景还是人脸都有较好的复原效果

下面是论文的结构图, 主要是有2个结构组成,

 第一个结构是全卷机填充网络:首先使用一个mask和图片进行组合,构成了具有空缺的图片,将空缺图片输入到全卷积中,经过stride等于2,做两次的向下卷积,然后经过4个dilated_conv(空洞卷积),为了在不损失维度的情况下,增加卷积核的视野,最后使用补零的反转卷积进行维度的升高,再经过最后两层卷积构成了图片。

第二个结构是global_discrimanator 和 local_discimanator

对于global_x输入的大小为全图的大小,而local_x的输入大小为全图大小的一半,上图的mask的大小为96-128且在local_x的内部,取值的范围为随机值

global_x 和 local_x经过卷积后,输出1024的输出,我们将输出进行串接tf.concat,对最后的输出结果[1]进行预测,判别图片为实际图片(真)还是经过填充的图片(假)

网络系数的展示

      

            填充网络(卷积-空洞卷积-反卷积)                     全局判别网络(卷积-全连接)                                局部判别网络(卷积-全连接)               串接网络(全连接)

训练步骤:为了使得对抗网络训练更加的有效,我们需要先对填充网络进行预训练,然后是对判别网络进行训练,最后将生成网络和判别网络放在一起进行训练

这里说明一下,填充 网络的损失值是mse,即tf.l2_loss()  判别网络的损失值是tf.reduce_mean(tf.nn.softmax...logits)

 

代码:代码主要由五个.py文件构建, 

1.to_npy进行图片的预处理,并将数据保存为.npy文件,

2.load.py 使用np.load进行x_train和x_test数据的读取

3.train.py 主要进行参数的训练,并且构造出mask_batch, local_x和local_complement

4.network用于进行模型结构的搭建,构建生成网络和判别网络,同时获得生成网络和判别网络的损失值

5.layer 用于卷积,反卷积,全连接,空洞卷积等函数的构建

 

 

数据的准备:to_npy

import numpy as np
import tensorflow as tf
import glob
import cv2
import os

# 将处理好的图片进行保存,为了防止经常需要处理图片
# 进行数据的压缩
IMAGE_SIZE = 128
# 训练集的比例
train_ep = 0.9
x = []
# 循环文件中的所有图片的地址
pathes = glob.glob('/data/*jpg')
# 循环前500个图片的地址
for path in pathes[:500]:
    # 使用cv2.imread读取图片
    img = cv2.imread(path)
    # 将图片进行维度的变换
    img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE))
    # 将读入的图片从BGR转换为RGB
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 将图片添加到列表中
    x.append(img)
# 如果不存在./npy文件
if not os.path.exists('./npy'):
    # 使用os.makedirs进行创建文件npy
    os.makedirs('./npy')

# 获得train的索引
p = len(x) * train_ep
# 训练集x
train_x = x[:p]
# 测试集x
test_x = x[p:]
# 将预处理好的图片保存为.npy文件
np.save('./npy/x_train.npy', train_x)
np.save('./npy/x_test.npy', test_x)

train.py 

import numpy as np
import tensorflow as tf
import os
from network import *
import load
import tqdm
import cv2

# 第一步:定义超参数
IMAGE_SIZE = 128  # 输入图片的大小
LOCAL_SIZE = 64   # local的大小
HOL_MIN = 24     # 洞的最小值
HOL_MAX = 48     # 洞的最大值
LEARNING_RATE = 1e-3 # 学习率
BATCH_SIZE = 1   # batch_size大小
PRETRAIN_NUM = 100  # 对生成网络预训练的次数




def train():
    # 第二步:构造输入的初始化参数
    x = tf.placeholder(tf.float32, [BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, 3]) # 图片x,维度为1, 128, 128, 3
    mask = tf.placeholder(tf.float32, [BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, 1]) # 掩模mask, 1, 128, 128, 1用于生成图片空白区域
    x_local = tf.placeholder(tf.float32, [BATCH_SIZE, LOCAL_SIZE, LOCAL_SIZE, 3]) # 图片x部分图像,维度为1, 64, 64, 3
    completion_global = tf.placeholder(tf.float32, [BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, 3]) # 生成图像的维度,1, 128,128,3
    completion_local = tf.placeholder(tf.float32, [BATCH_SIZE, LOCAL_SIZE, LOCAL_SIZE, 3]) # 生成图像部分图像,1, 64, 64, 3
    is_training = tf.placeholder(tf.bool, []) # 是够进行训练,在batch_normalize中使用

    # 第三步:调用network,构造网络框架,包括生成网络,判别网络,以及其生成和判别的损失值
    model = Network(x, mask, x_local, completion_global, completion_local, is_training, BATCH_SIZE)

    # 第四步:使用tf.session 构造sess
    sess = tf.Session()

    # 第五步:初始化global_step和epoch
    global_step = tf.Variable(0, name='global_step', trainable=False)
    epoch = tf.Variable(0, name='epoch', trainable=False)
    # 第六步:构造自适应梯度下降器,获得生成网络和判别网络损失值下降操作
    opt = tf.train.AdamOptimizer(LEARNING_RATE)
    g_loss_op = opt.minimize(model.g_loss, global_step=global_step)
    d_loss_op = opt.minimize(model.d_loss, global_step=global_step)
    # 第七步:使用sess.run进行初始化操作
    init = tf.global_variables_initializer()
    sess.run(init)
    # 第八步:如果存在./backup文件,就使用saver.restore()加载sess
    if tf.train.get_checkpoint_state('./backup'):
        saver = tf.train.Saver()
        saver.restore(sess, './backup/latest')
    # 第九步:获得训练集和测试集,使用load中定义的load函数, 并对读取的图片做归一化操作
    x_train, x_test = load.load()
    x_train = np.array([a/127.5 - 1 for a in x_train])
    x_test = np.array([a/127.5 - 1 for a in x_test])
    # 定义一个epoch迭代的次数
    step_num = int(len(x_train)/BATCH_SIZE)

    while True:
        # 第十步:将epoch值进行+1操作
        sess.run(tf.assign_add(epoch, 1))
        # 对输入的x_train进行洗牌操作,每次迭代
        np.random.shuffle(x_train)
        # 第十一步:如果当前迭代的次数小于预训练,进行生成网络的训练
        if sess.run(epoch) <= PRETRAIN_NUM:
            # 迭代每个epoch,每次迭代的大小为一个batch_size
            for i in tqdm.tqdm(range(step_num)):
                # 获得一个batch_size的图片
                x_batch = x_train[BATCH_SIZE*i:(i+1)*BATCH_SIZE]
                # 获得points_batch, 和一个batch_size的掩模
                points_batch, masks_batch = get_points()
               # 将x和mask_batch,is_training 传入,进行g_loss_op即损失值的降低
                _, _g_loss = sess.run([g_loss_op, model.g_loss], feed_dict={x:x_batch, mask:masks_batch, is_training:True})
            # 进行验证操作
            # 对x_test进行洗牌操作
            np.random.shuffle(x_test)
            # 获得一个BATHC_SIZE的大小
            x_batch = x_test[:BATCH_SIZE]
            # 获得一个batch_size 的生成图片,执行model.completion
            completion = sess.run([model.completion], feed_dict={x:x_batch, mask:masks_batch, is_training:False})
            # 取出其中一张图片,做归一化的反操作,还原回原始图片
            sample = np.array((completion[0] + 1) * 127.5, dtype=np.uint8)
            # 将图片进行保存,使用cv2.imwrite
            cv2.imwrite('{}_epoch.jpg'.format('{0:06d}'.format(epoch)), cv2.cvtColor(sample, cv2.COLOR_RGB2BGR))
            # 将参数保存在./backup/latest
            saver = tf.train.Saver()
            saver.save(sess, './backup/latest', write_meta_graph=False)
            # 如果次数为100次,就将参数保存在/backup/pre_train
            if sess.run(epoch) == PRETRAIN_NUM:
                saver.save(sess, './backup/pre_train', write_meta_graph=False)


        # 第十二步:如果epoch大于预训练的次数,就对生成网络和判别网络进行同时的训练
        else:
            # 循环一个epoch
            for i in tqdm.tqdm(range(step_num)):
                # 获得一个batch的图片
                x_batch = x_train[BATCH_SIZE*i:(i+1)*BATCH_SIZE]
                # 获得一个batch的点坐标,和一个batch的掩模
                points_batch, masks_batch = get_points()
                # 初始化g_loss
                g_loss_value = 0
                # 初始化d_loss
                d_loss_value = 0
                # 执行g_loss_op降低g_loss损失值,同时执行self.completion,获得生成图片completion
                _, completion, g_loss = sess.run([g_loss_op, model.completion, model.g_loss], feed_dict={x:x_batch, mask:masks_batch, is_training:True})
                # 将g_loss添加到g_loss_value
                g_loss_value += g_loss
                # 构造一个batch的x_local
                x_local_batch = []
                # 构造一个batch的completion_batch
                completion_local_batch = []
                # 循环batch_size 
                for i in range(BATCH_SIZE):
                    # 获得point_batch中一个点坐标
                    x1, y1, x2, y2 = points_batch[i]
                    # 构造一个x_local, 添加到x_local_batch
                    x_local_batch.append(x_batch[i][y1:y2, x1:x2, :])
                    # 构造一个completion_local, 添加到completion_local_batch 
                    completion_local_batch.append(completion[i][y1:y2, x1:x2])
                # 执行d_loss_op,降低d_loss的损失值
                _, d_loss = sess.run([d_loss_op, model.d_loss], feed_dict={x:x_batch, mask:masks_batch, x_local:x_local_batch, completion_global:completion,
                                                                        completion_local:completion_local_batch, is_training:True})
                # 将损失值进行添加
                d_loss_value += d_loss
            # 清洗x_test
            np.random.shuffle(x_test)
            # 获得一个x_batch
            x_batch = x_test[:BATCH_SIZE]
            # 输入测试图片获得生成图片
            completion = sess.run([model.completion], feed_dict={x:x_batch, mask:masks_batch, is_training:False})
            # 取生成图片的第一张图片,进行反归一化
            sample = np.array((completion[0] + 1) * 127.5, dtype=np.uint8)
            # 使用cv2.imwrite保存图片
            cv2.imwrite('{}.epoch'.format('{0:06d}'.format(epoch)), cv2.cvtColor(sample, cv2.COLOR_RGB2BGR))
            # 构造tf.train.Saver() 进行sess的保存操作
            saver = tf.train.Saver()
            saver.save(sess, './backup/latest', write_meta_graph=False)



def get_points():
    # 构造点列表,用于构建局部图像
    points = []
# 构造掩模列表,用于构造残缺的原始图像 maskes
= [] for i in range(BATCH_SIZE):
# 获得左上角两个点,范围为[0, IMAGE_SIZE-LOCAL_SIZE] x1, y1
= np.random.randint(0, IMAGE_SIZE-LOCAL_SIZE, 2)
# 获得右下角的两个点,分别进行相加操作 x2, y2
= np.array([x1, y1]) + LOCAL_SIZE
# 将坐标添加到points points.append([x1, y1, x2, y2]) # 在H0L_MIN和HOL_MAX范围内构造w,h w, h
= np.random.randint(HOL_MIN, HOL_MAX, 2)
# 左上角x轴的坐标为x1+(0, LOCAL_SIZE-w)的范围内 p1
= x1 + np.random.randint(0, LOCAL_SIZE-w)
# 左上角y轴的坐标为y1+(0, LOCAL_SIZE-h)的范围内 q1
= y1 + np.random.randint(0, LOCAL_SIZE-h) # 右边的x坐标为p1+w p2 = p1 + w
# 右边的y坐标为q1+h q2
= q1 + h
# 构造全为0的3维矩阵 m
= np.zeros(shape=[IMAGE_SIZE, IMAGE_SIZE, 1])
# 在该范围内的值为1, 并进行添加 m[q1:q2, p1:p2, :]
= 1 maskes.append(m) # 返回points和掩模的数组 return np.array(points), np.array(maskes) if __name__ == '__main__': train()

 

代码:network.py: 构建Network类,构造生成网络,生成self.completion, 构造判别网络,获得x,x_local的输出结果self.real,获得global_completion, local_completion的输出结果self.fake, 使用l2_loss构造生成网络的损失值g_loss, 使用交叉熵构造判别网络的损失值d_loss

第一步:使用self.generator构造生成网络, 输入为x*(1-mask), is_training 

第二步:使用self.imition * mask + x * (1-mask) 构造self.completion 即生成的图片

第三步:使用self.discrimator, 输入为x, x_local, is_training, reuse=False, 用于真实样本的判别self.real 

第四步:使用self.discrimator, 输入为global_complement, local_complement, is_training, reuse=True, 用于生成样本的判别self.fake

第五步:使用tf.nn.l2_loss生成mse的损失值,用于生成网络的损失值,self.g_loss

第六步:使用tf.reduce_mean(tf.sotfmax..logits(labels=tf.ones_like(real), logits=real)) 获得真实的交叉熵,同理获得生成样本的交叉熵,将两者进行加和乘以系数,获得最终的损失值即self.d_loss。

第七步:使用tf.get_collection(tf.GraphKey.TRAINABEL_VARIABLES, scope=‘generator’) 和scope = ‘discrimator’获得生成网络和判别网络的参数

import tensorflow as tf
import numpy as np
from layer import *



class Network:

    def __init__(self, x, mask, x_local, completion_global, completion_local, is_training, batch_size):
        self.batch_size = batch_size
       # 第一步: 构造生成网络,获得生成的图片,(1-mask) * x 构成残缺空白的输入图片
        self.imition = self.generator((1-mask)*x, is_training)
        # 第二步:将生成图片部分区域与残缺空白的输入图片进行拼接,获得最终的图片
        self.completion = mask * self.imition + (1-mask)*x
        # 第三步:定义discriminator,对x和x_local判断real结果
        self.real = self.discrimator(x, x_local, is_training, reuse=False)
        # 第四步:使用discrimanator,对completion_global 和 completion_local判断fake结果
        self.fake = self.discrimator(completion_global, completion_local, is_training, reuse=True)
        # 第五步:定义生成网络的损失值,使用mse
        self.g_loss = self.cal_g_loss(x, self.completion)
        # 第六步:定义判别网络的损失值,使用交叉熵, 即real判别为1,fake判别为0
        self.d_loss = self.cal_d_loss(self.real, self.fake)
        # 第七步:获得生成网络的参数
        g_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='generator')
        d_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='discrimator')

    # 判别网络的损失值,输入为
    def cal_d_loss(self, real, fake):
        # 损失值系数
        epsilon = 4e-4
        # 真实样本的交叉熵损失值, 标签为1
        real_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=real, labels=tf.ones_like(real)))
        # 生成样本的交叉熵损失值,标签为0
        fake_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=fake, labels=tf.zeros_like(fake)))
        # 将真实样本和生成样本的损失值进行加和,并进行损失系数的乘积
        return tf.add(real_loss, fake_loss) * epsilon

   
    # 生成网络的损失值计算,使用的是mse
    def cal_g_loss(self, x, completion):
       # 使用l2_loss损失值计算
        return tf.nn.l2_loss(x - completion)




   # 构建判别网络
    def discrimator(self, x, x_local, is_training, reuse):
            # 构建完整图片的判别网络
            def global_discrimator(x):
                # 设置完整图片判别网络参数的范围
                with tf.variable_scope('global'):
                    # 第一层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv1'):
                        x = conv_layer(x, [5, 5, 3, 64], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第二层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv2'):
                        x = conv_layer(x, [5, 5, 64, 128], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第三层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv3'):
                        x = conv_layer(x, [5, 5, 128, 256], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第四层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv4'):
                        x = conv_layer(x, [5, 5, 256, 512], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第五层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv5'):
                        x = conv_layer(x, [5, 5, 512, 512], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                   # 构建全连接层,输出为1024
                    with tf.variable_scope('fc'):
                        # 对卷积层的输出进行维度变换
                        x = flatten_conv(x)
                        # 进行全连接操作,输出的维度为1024 
                        x = fc_layer(x, 1024)

                return x
            # 构造局部图像的判别网络
            def local_discrimator(x):
                # 设置局部网络判别的参数范围
                with tf.variable_scope('local'):
                    # 第一层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv1'):
                        x = conv_layer(x, [5, 5, 3, 64], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第二层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv2'):
                        x = conv_layer(x, [5, 5, 64, 128], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第三层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv3'):
                        x = conv_layer(x, [5, 5, 128, 256], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 第四层卷积,卷积大小为5*5*3*64,步长为2
                    with tf.variable_scope('conv4'):
                        x = conv_layer(x, [5, 5, 256, 512], 2)
                        x = batch_normalize(x, is_training)
                        x = tf.nn.relu(x)
                    # 构造全连接网络,输出结构为1024 
                    with tf.variable_scope('fc'):
                        x = flatten_conv(x)
                        x = fc_layer(x, 1024)

                return x
            # 设置判别网络的参数范围
            with tf.variable_scope('discrimator', reuse=reuse):
                # 带入x_local获得局部图像的判别输出值
                local_disc = local_discrimator(x_local)
                # 带入x获得完整图像的判别输出值
                global_disc = global_discrimator(x)
                with tf.variable_scope('concatenation'):
                    # 将局部图像输出值与全局图像进行串接,维度为[batch_size, 2048]
                    output = tf.concat((local_disc, global_disc), axis=1)
                    # 接上一个全连接,最后的输出值维度为1 
                    output = fc_layer(output, 1)
                # 返回判别结果
                return output

    # 用于进行生成网络,输入为拥有空白区域的图片,is_training表示是否是在训练
    def generator(self, x, is_training):
        # 定义参数的范围为'generator'
        with tf.variable_scope('generator'):
            # 第一层卷积层
            with tf.variable_scope('conv1'):
                # 卷积核的大小为[5, 5, 3, 64],步长为1
                x = conv_layer(x, [5, 5, 3, 64], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第二层卷积
            with tf.variable_scope('conv2'):
                # 卷积核的大小为[3, 3, 64, 128], 步长为2, 维度变为原来的1/2
                x = conv_layer(x, [3, 3, 64, 128], 2)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第三层卷积操作
            with tf.variable_scope('conv3'):
                # 卷积核的大小为[3, 3, 128, 128], 步长为1 
                x = conv_layer(x, [3, 3, 128, 128], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第四层卷积操作
            with tf.variable_scope('conv4'):
                # 卷积核的大小为[3, 3, 128, 256], 步长为2
                x = conv_layer(x, [3, 3, 128, 256], 2)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第五层卷积操作
            with tf.variable_scope('conv5'):
                # 卷积核的大小为[3, 3, 256, 256], 步长为1
                x = conv_layer(x, [3, 3, 256, 256], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第六层卷积操作
            with tf.variable_scope('conv6'):
                # 卷积核的大小为[3, 3, 256, 256], 步长为1 
                x = conv_layer(x, [3, 3, 256, 256], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第一层空洞卷积
            with tf.variable_scope('dilated1'):
                # 卷积核的大小为[3, 3, 256, 256], 卷积补零的个数为1
                x = dilated_conv_layer(x, [3, 3, 256, 256], 2)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第二层空洞卷积
            with tf.variable_scope('dilated2'):
                # 卷积核的大小为[3, 3, 256, 256], 卷积补零的个数为3 
                x = dilated_conv_layer(x, [3, 3, 256, 256], 4)
                # 归一化
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第三层空洞卷积
            with tf.variable_scope('dilated3'):
                # 卷积核的大小为[3, 3, 256, 256], 卷积补零的个数为7 
                x = dilated_conv_layer(x, [3, 3, 256, 256], 8)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第四层空洞卷积
            with tf.variable_scope('dilated4'):
                # 卷积核的大小为[3, 3, 256, 256], 卷积补零的个数为15 
                x = dilated_conv_layer(x, [3, 3, 256, 256], 16)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 非线性激活
                x = tf.nn.relu(x)
            # 第七层卷积
            with tf.variable_scope('conv7'):
                # 卷积的维度为[3, 3, 256, 256], 步长为1 
                x = conv_layer(x, [3, 3, 256, 256], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 激活
                x = tf.nn.relu(x)
            # 第八层卷积
            with tf.variable_scope('conv8'):
                # 卷积的维度为[3, 3, 256, 256], 步长为1 
                x = conv_layer(x, [3, 3, 256, 256], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 激活操作
                x = tf.nn.relu(x)
            # 第一层反卷积,将维度提升为原来的2倍,即从32,32变为64,64
            with tf.variable_scope('deconv1'):
                # 反卷积,[4, 4, 128, 256] 4 和 4表示卷积的大小,256表示输入维度,128表示输出维度,[self.batch_size, 64, 64, 128]表示输出的大小,2表示扩张的倍数
                x = deconv_layer(x, [4, 4, 128, 256], [self.batch_size, 64, 64, 128], 2)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 激活操作
                x = tf.nn.relu(x)


            with tf.variable_scope('conv9'):
                # 第九层卷积,卷积核大小为[3, 3, 128, 128], 步长为1 
                x = conv_layer(x, [3, 3, 128, 128], 1)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 激活操作
                x = tf.nn.relu(x)

            with tf.variable_scope('deconv2'):
                # 进行反卷积,将维度变为[128, 128]
                x = deconv_layer(x, [4, 4, 64, 128], [self.batch_size, 128, 128, 64], 2)
                # 归一化操作
                x = batch_normalize(x, is_training)
                # 激活
                x = tf.nn.relu(x)

            with tf.variable_scope('conv10'):
                # 第十层卷积,进行维度的降低,即把64降维32 
                x = conv_layer(x, [3, 3, 64, 32], 1)
                x = batch_normalize(x, is_training)
                x = tf.nn.relu(x)

            with tf.variable_scope('conv11'):
                # 第十一层,进行维度的降低,把32层的维度转换为3层的维度,即图像的维度值
                x = conv_layer(x, [3, 3, 32, 3], 1)
                x = batch_normalize(x, is_training)
                x = tf.nn.relu(x)

        return x

layer.py 用于构建一些基础的网络结构,如卷积层,全连接层,反卷积层,空洞卷积层,归一化层,维度变化层,

import tensorflow as tf


# 构造卷积层, 使用的是tf.nn.conv2d
def conv_layer(x, shape, stride):
    # 构造卷积核,大小为shape,进行参数更新
    filter = tf.get_variable('weight',
                        shape=shape,
                        dtype=tf.float32,
                        initializer=tf.contrib.layers.xavier_initializer(),
                        trainable=True)
    # 进行卷积操作
    return tf.nn.conv2d(x, filter, strides=[1, stride, stride, 1], padding='SAME')


# 构造归一化操作,测试阶段使用的mean和var为训练阶段的动量平均的mean和var
def batch_normalize(x, is_training, decay=0.99, epsilon=0.001):
    # 进行训练时的归一化
    def bn_train():
        # batch的mean和batch的var, 使用tf.nn.moments获得标准差和均值
        batch_mean, batch_var = tf.nn.moments(x, axes=[0, 1, 2])
        # 将pop_mean 使用tf.assign进行更新操作,为动量梯度的平均值
        train_mean = tf.assign(pop_mean, pop_mean * decay + batch_mean * (1-decay))
        # 将pop_var 使用tf.assign进行更新操作,为动量梯度的标准差
        train_var = tf.assign(pop_var, pop_var * decay + batch_var * (1-decay))
        # 使用tf.control_dependencies,先执行更新操作
        with tf.control_dependencies([train_mean, train_var]):
            # 进行归一化操作,使用的平均值为当前的batch_mean 和 batch_var, beta和scale需要进行参数更新
            return tf.nn.batch_normalization(x, batch_mean, batch_var, beta, scale, epsilon)

    def bn_inference():
        # 测试时的归一化操作,pop_mean和pop_var表示训练时动量梯度的平均值和标准差, beta为偏度,scale为范围
        return tf.nn.batch_normalization(x, pop_mean, pop_var, beta, scale, epsilon)


    # 获得最后一个维度
    dim = x.get_shape().as_list()[-1]
    # 构造训练过程中的偏度bata
    beta = tf.get_variable(
        name='beta',
        shape=[dim],
        dtype=tf.float32,
        initializer=tf.truncated_normal_initializer(stddev=0.0),
        trainable=True
    )
    # 构造训练过程中的范围scale
    scale = tf.get_variable(
        name='scale',
        shape=[dim],
        dtype=tf.float32,
        initializer=tf.truncated_normal_initializer(stddev=0.1),
        trainable=True
    )
    # 构造动量平均的平均值的初始值
    pop_mean = tf.get_variable(
        name = 'pop_mean',
        shape=[dim],
        dtype=tf.float32,
        initializer=tf.constant_initializer(0.0),
        trainable=False
    )
    # 构造动量平均的标准差的初始值
    pop_var = tf.get_variable(
        name='pop_var',
        shape=[dim],
        dtype=tf.float32,
        initializer=tf.constant_initializer(1.0),
        trainable=False)
    # 如果is_training为true执行bn_train, 否者执行bn_inference 
    return tf.cond(is_training, bn_train, bn_inference)

# 构造空洞卷积,dilation表示卷积补零的个数
def dilated_conv_layer(x, shape, dilation):
    # filter表示卷积核的构造
    filters = tf.get_variable('filters',
                              shape=shape,
                              dtype=tf.float32,
                              initializer=tf.contrib.layers.xavier_initializer(),
                              trainable=True)
    # 进行空洞卷积,dilation表示卷积核补零的大小
    return tf.nn.atrous_conv2d(x, filters, dilation, padding='SAME')

# 构造反卷积,output_shape表示输出的维度,stride表示扩大的倍数
def deconv_layer(x, filter_shape, output_shape, stride):
    # 构造卷积
    filters = tf.get_variable(
        name = 'weight',
        shape=filter_shape,
        dtype=tf.float32,
        initializer=tf.truncated_normal_initializer(stddev=0.1),
        trainable=True
    )
    return tf.nn.conv2d_transpose(x, filters, output_shape, [1, stride, stride, 1])

# 进行维度的变化,用于进行全连接
def flatten_conv(x):
    num = x.shape[0]
    return tf.reshape(x, [num, -1])

# 构造全连接函数
def fc_layer(x, output_dim):
    # 获得输入的最后一个维度,用于构造w
    input_dim = x.get_shape().as_list()[-1]
    # w的维度为input_dim, output_dim 
    w = tf.get_variable(
        name='w',
        shape=[input_dim, output_dim],
        dtype=tf.float32,
        initializer=tf.truncated_normal_initializer(stddev=0.1),
        trainable=True
    )
    # b的维度为output_dim 
    b = tf.get_variable(
        name='b',
        shape=[output_dim],
        dtype=tf.float32,
        initializer=tf.truncated_normal_initializer(stddev=0.0),
        trainable=True
    )
   # 进行点乘操作
    return tf.add(tf.matmul(x, w), b)

load.py 进行.npy数据的载入操作

import numpy as np
import tensorflow as tf
import os

# dir为data的路径
def load(dir='../data/npy'):
    # 使用np.load获得存储好的数据
    # 加载训练集
    train_x = np.load(os.path.join(dir, 'x_train.npy'))
    # 加载验证集
    test_x = np.load(os.path.join(dir, 'x_test.npy'))
    # 返回训练集和验证集
    return train_x, test_x

 

posted on 2019-03-29 20:39  python我的最爱  阅读(2508)  评论(0编辑  收藏  举报