monodepth无监督卷积神经网络深度估计代码解析(二)
第二部分来看一下模型部分
论文解析:https://blog.csdn.net/bofu_sun/article/details/89206531
一、调用库文件和构建元组
1.使用collections.namedtuple构建命名元组,这里的元组包括编码器、图片高度、图片宽度、batchsize、线程数、每次的数量、是否生成立体图、模式、是否使用反卷积神经网络、图片损失函数阿尔法值、梯度损失权重、学习率损失权重等key。
from __future__ import absolute_import, division, print_function
from collections import namedtupleimport numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slimfrom bilinear_sampler import *monodepth_parameters = namedtuple('parameters', 'encoder, ''height, width, ''batch_size, ''num_threads, ''num_epochs, ''do_stereo, ''wrap_mode, ''use_deconv, ''alpha_image_loss, ''disp_gradient_loss_weight, ''lr_loss_weight, ''full_summary')
二、MonodepthModel模型类
1.初始化函数
class MonodepthModel(object):"""monodepth model"""def __init__(self, params, mode, left, right, reuse_variables=None, model_index=0):self.params = params # 参数self.mode = mode # 模式self.left = left # 左图self.right = right # 右图self.model_collection = ['model_' + str(model_index)] #设置模型名self.reuse_variables = reuse_variablesself.build_model() # 建立模型self.build_outputs() # 建立输出if self.mode == 'test':returnself.build_losses() # 建立损失self.build_summaries() # 建立总结
三、图像预处理
1.[:-1]其实就是去除了这行文本的最后一个字符(换行符)后剩下的部分。
[1:]其实就是去除了这行文本的第一个字符(换行符)后剩下的部分。
2.tf.image.resize_area:使用区域插值调整images的大小。
tf.image.resize_nearest_neighbor:使用临近点插值的方法扩大图片的尺寸。
3.scale-space pyramid:其实就是一个尺度金字塔,本文中通过对原图像进行多次下采样降低分辨率来实现金字塔,第一次下采样尺度ds1 = 2S,第二次下采样尺度ds2 = ds1/2,本文中的S设为2,也就是ds1=4,ds2=2,假设原图XCV分辨率,则做第一ds1下采样得到的分辨率为(X/ds1)(C/ds1)(V/ds1),在本文中就是(X/4)(C/4)(V/4),第二次下采样得到的分辨率为(X/2)(C/2)(V/2)
4.预处理方法
金字塔图像:生成这样的尺度空间为我们提供了更多信息,我们打算利用这些信息来改进我们的特征提取。
梯度图像:梯度图像描述了强度景观中每个点的陡度,更具体地说是景观的局部“表面”是如何倾斜的。 在每个像素处,确定两个度量:斜率的方向,也称为梯度; 斜率的大小-陡度。 因此,梯度图像由两个值的映射组成,即方向和斜率。
参考:https://blog.csdn.net/u012285175/article/details/84962012
# 定义x方向的梯度,获得x方向的图像梯度图def gradient_x(self, img): gx = img[:,:,:-1,:] - img[:,:,1:,:]return gx# 定义y方向的梯度,获得y方向的图像梯度图def gradient_y(self, img): gy = img[:,:-1,:,:] - img[:,1:,:,:]return gy# 插值扩大图片尺寸def upsample_nn(self, x, ratio): s = tf.shape(x)h = s[1] # 获取图片长度w = s[2] # 获取图片宽度return tf.image.resize_nearest_neighbor(x, [h * ratio, w * ratio]) #使用临近点插值的方法扩大图片的尺寸,长宽都变为原来扽ratio倍# 将图片变为金字塔形状def scale_pyramid(self, img, num_scales): scaled_imgs = [img]s = tf.shape(img)h = s[1] # 获取图片长度w = s[2] # 获取图片宽度for i in range(num_scales - 1): # 不断缩小图片ratio = 2 ** (i + 1)nh = h // rationw = w // ratioscaled_imgs.append(tf.image.resize_area(img, [nh, nw])) #不断添加缩小后的图片,生成金字塔图片return scaled_imgs # 返回金字塔图
slim.avg_pool2d函数:
def avg_pool2d(inputs,kernel_size,stride=2,padding='VALID',data_format=DATA_FORMAT_NHWC,outputs_collections=None,scope=None):"""Adds a 2D average pooling op."""Adds a 2D Max Pooling op.Args:inputs: 一个4-D tensor,形状为[batch_size, height, width, channels]或者[batch_size, channels, height, width]kernel_size: 池化核的尺寸: [kernel_height, kernel_width],如果两个值相同的话可以为一个整数值。stride: 池化步长 [stride_height, stride_width].如果两个值相同的话可以为一个整数值。 padding: 填充方式,为 'VALID' 或者 'SAME'.data_format: 数据格式,支持 `NHWC` (default)和 `NCHW` outputs_collections: 输出被添加到的集合scope: 可选的name_scope.Returns:返回池化操作后的tensor.
论文中使用:
# 通过左图视差图和右图原图生成左图原图def generate_image_left(self, img, disp): return bilinear_sampler_1d_h(img, -disp)# 通过右图视差图和左图原图生成右图原图def generate_image_right(self, img, disp): return bilinear_sampler_1d_h(img, disp)
6.关于SSIM
详见:https://blog.csdn.net/leviopku/article/details/84635897
# 找到重建的左图或者右图与原图label的相似度,这里是计算SSIM,进一步计算第一个损失函数lossdef SSIM(self, x, y): C1 = 0.01 ** 2 #两个常数项C2 = 0.03 ** 2mu_x = slim.avg_pool2d(x, 3, 1, 'VALID') # 计算x的均值,对x图片进行pooling层操作,3*3*的kernalsize,步长为1mu_y = slim.avg_pool2d(y, 3, 1, 'VALID') # 计算x的均值,对y图片进行pooling层操作,3*3*的kernalsize,步长为1sigma_x = slim.avg_pool2d(x ** 2, 3, 1, 'VALID') - mu_x ** 2 # 计算x的方差sigma_y = slim.avg_pool2d(y ** 2, 3, 1, 'VALID') - mu_y ** 2 # 计算x的方差sigma_xy = slim.avg_pool2d(x * y , 3, 1, 'VALID') - mu_x * mu_y # 计算两张图片的协防差SSIM_n = (2 * mu_x * mu_y + C1) * (2 * sigma_xy + C2)SSIM_d = (mu_x ** 2 + mu_y ** 2 + C1) * (sigma_x + sigma_y + C2)SSIM = SSIM_n / SSIM_d #计算SSIM即两张图片的相似度#tf.clip_by_value(A, min, max):输入一个张量A,把A中的每一个元素的值都压缩在min和max之间。return tf.clip_by_value((1 - SSIM) / 2, 0, 1)# 第二个损失函数,使得生成的视差图能够尽可能的连续def get_disparity_smoothness(self, disp, pyramid):disp_gradients_x = [self.gradient_x(d) for d in disp] # 记录四个视差图中x方向的梯度值disp_gradients_y = [self.gradient_y(d) for d in disp] # 记录四个视差图中y方向的梯度值image_gradients_x = [self.gradient_x(img) for img in pyramid] # 记录金字塔图中x方向的梯度值image_gradients_y = [self.gradient_y(img) for img in pyramid] # 记录金字塔图中y方向的梯度值weights_x = [tf.exp(-tf.reduce_mean(tf.abs(g), 3, keep_dims=True)) for g in image_gradients_x]# 首先计算金字塔图中四个尺寸的x方向梯度的均值,然后取它们的指数幂weights_y = [tf.exp(-tf.reduce_mean(tf.abs(g), 3, keep_dims=True)) for g in image_gradients_y]# 计算金字塔图中四个尺寸的y方向梯度的均值,然后取它们的指数幂smoothness_x = [disp_gradients_x[i] * weights_x[i] for i in range(4)]smoothness_y = [disp_gradients_y[i] * weights_y[i] for i in range(4)]# 两个方向指数幂与视差图梯度相称return smoothness_x + smoothness_y # 返回不连续程度
- numpy.floor():
按照元素的方式返回输入的下限。
标量x的底部是最大的整数i,使得i <= x。
例:
import numpy as np
a = np.array([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0])
np.floor(a)
输出:array([-2., -2., -1., 0., 1., 1., 2.])
8.tf.pad()就是扩充维度,比如
t=tf.constant([1,2,3])
这是一个一维向量,可以通过print(t.get_shape())看维度
先介绍一个概念,paddings=[a,b,c,d],分别从不同维度加0,
因为是一维向量,所以tf.pad(t,[[1,1]])只能从左右加0输出结果为[[0 1 2 3 0]],
当t=tf.constant([[1,2,3]])时,则是一个二维矩阵,就加了一个[],shape=(1,3)
如果a=[1,1],b=[2,2],则上下加一排0,左右加2排0,结果为
[[0 0 0 0 0 0 0]
[0 0 1 2 3 0 0]
[0 0 0 0 0 0 0]]
在二维上面加0,当c=[1,1],
t=tf.constant([[[1,2,3], [2,3,4],[2,1,4]],
[[1,2,3], [2,3,4],[2,1,4]],
[[1,2,3], [2,3,4],[2,1,4]]])
时,即paddings=[[1,1],[2,2],[1,1]]输出为下面所示,shape=(3,3,3)变成了(5,7,5)
详见:https://blog.csdn.net/qwe2508/article/details/79725701
也就是说后面的那个数组参数代表在第几维的上下或左右加几行或列0。
#获得视差图def get_disp(self, x):disp = 0.3 * self.conv(x, 2, 3, 1, tf.nn.sigmoid) # 使用3*3的卷积和,步长为1,激活函数为sigmoid函数,进行卷积层,同时将特征图中像素乘0.3return disp# 定义卷积层,第一个参数x是输入的图,第二个参数是卷积核的个数,第三个参数是步长,第四个参数是激活参数,默认为elu函数def conv(self, x, num_out_layers, kernel_size, stride, activation_fn=tf.nn.elu):p = np.floor((kernel_size - 1) / 2).astype(np.int32)p_x = tf.pad(x, [[0, 0], [p, p], [p, p], [0, 0]]) # 其他维度不变,图片的尺寸进行padding,使得经过卷积层后图片的尺寸不变return slim.conv2d(p_x, num_out_layers, kernel_size, stride, 'VALID', activation_fn=activation_fn) #返回卷积后的特征图# 卷积模块,在这里图片将经过两个卷积层,图片尺寸变为原来的一半def conv_block(self, x, num_out_layers, kernel_size):conv1 = self.conv(x, num_out_layers, kernel_size, 1) # 第一个卷积层,步长为1,输出特征图尺寸不变conv2 = self.conv(conv1, num_out_layers, kernel_size, 2) # 第二个卷积层,步长为2,输出特征图尺寸变为原来的一半return conv2# 最大池化层,图片尺寸变为原来的一半def maxpool(self, x, kernel_size):p = np.floor((kernel_size - 1) / 2).astype(np.int32)p_x = tf.pad(x, [[0, 0], [p, p], [p, p], [0, 0]]) # 其他维度不变,图片的尺寸进行padding,使得经过池化层后图片的尺寸变为原来的一半return slim.max_pool2d(p_x, kernel_size) # 池化层步长默认为2# 带残差神经网络中shortcut结构的三个卷积层def resconv(self, x, num_layers, stride):do_proj = tf.shape(x)[3] != num_layers or stride == 2 # 判断一下卷积层后的输出图尺寸是否改变shortcut = [] # 定义shortcut中间变量conv1 = self.conv(x, num_layers, 1, 1) # 第一个卷积层使用的是1*1的卷积核,步长为1,这个操作主要用于减小计算量conv2 = self.conv(conv1, num_layers, 3, stride) # 第二个卷积层使用的是3*3的卷积核,步长为strideconv3 = self.conv(conv2, 4 * num_layers, 1, 1, None) # 第三个卷积层使用的还是1*1的卷积核,只是数量变为原来的4倍if do_proj:shortcut = self.conv(x, 4 * num_layers, 1, stride, None) # 如果输出图尺寸变化,则将输入图经过1*1的卷积核,通道数变为原来的四倍,直接送到输出处叠加else:shortcut = x # 如果输出图尺寸不变,则将输入直接送到输出处return tf.nn.elu(conv3 + shortcut) # 最后经过elu激活函数# 带shortcut结构的卷积层模块def resblock(self, x, num_layers, num_blocks):out = xfor i in range(num_blocks - 1): # 进行(num_blocks - 1)次输出尺寸不变的卷积层out = self.resconv(out, num_layers, 1)out = self.resconv(out, num_layers, 2) # 经过一次卷积层,尺寸变为原来的一半return out# 反卷积神经网络,扩大输入图片尺寸def upconv(self, x, num_out_layers, kernel_size, scale):upsample = self.upsample_nn(x, scale) # 使用临近点插值的方法扩大图片的尺寸conv = self.conv(upsample, num_out_layers, kernel_size, 1) # 经过一个卷积层,输出尺寸不变return conv# 反卷积层,输出指定大小尺寸图片def deconv(self, x, num_out_layers, kernel_size, scale):p_x = tf.pad(x, [[0, 0], [1, 1], [1, 1], [0, 0]]) # padding填充0conv = slim.conv2d_transpose(p_x, num_out_layers, kernel_size, scale, 'SAME') #反卷积#conv2d_transpose 中会计算 output_shape 能否通过给定的参数计算出 inputs的维度,如果不能,则报错return conv[:,3:-1,3:-1,:]
9.VGG网络
# 建立VGG网络def build_vgg(self):#set convenience functionsconv = self.conv # 定义卷积层简便函数if self.params.use_deconv:upconv = self.deconv # 定义反卷积层简便函数,决定使用上采样反卷积层还是插值反卷积层else:upconv = self.upconv# 进行变量管理,设置作用域,编码器由十四个卷积层组成,每经过两个卷积层,图片尺寸变为原来的一半# tf.variable_scope(): 可以让变量有相同的命名with tf.variable_scope('encoder'):conv1 = self.conv_block(self.model_input, 32, 7) # H/2,两次32个7*7的卷积核conv2 = self.conv_block(conv1, 64, 5) # H/4,两次64个5*5的卷积核conv3 = self.conv_block(conv2, 128, 3) # H/8,两次123个3*3的卷积核conv4 = self.conv_block(conv3, 256, 3) # H/16,两次256个3*3的卷积核conv5 = self.conv_block(conv4, 512, 3) # H/32,两次512个3*3的卷积核conv6 = self.conv_block(conv5, 512, 3) # H/64,两次512个3*3的卷积核conv7 = self.conv_block(conv6, 512, 3) # H/128,两次512个3*3的卷积核# 设置skip作用域,便于将编码过程的部分特征图直接拼接到解码过程中with tf.variable_scope('skips'):skip1 = conv1skip2 = conv2skip3 = conv3skip4 = conv4skip5 = conv5skip6 = conv6# 设置解码器作用域with tf.variable_scope('decoder'):upconv7 = upconv(conv7, 512, 3, 2) # H/64,图片长宽都变为原来的二倍concat7 = tf.concat([upconv7, skip6], 3) # upconv7的输出与conv6输出的尺寸相同,将他们叠加iconv7 = conv(concat7, 512, 3, 1) # 再经过3*3卷积核的卷积层upconv6 = upconv(iconv7, 512, 3, 2) # H/32,图片长宽都变为原来的二倍concat6 = tf.concat([upconv6, skip5], 3) # upconv6的输出与conv5输出的尺寸相同,将他们叠加iconv6 = conv(concat6, 512, 3, 1) # 再经过3*3卷积核的卷积层upconv5 = upconv(iconv6, 256, 3, 2) # H/16,图片长宽都变为原来的二倍concat5 = tf.concat([upconv5, skip4], 3) # upconv5的输出与conv4输出的尺寸相同,将他们叠加iconv5 = conv(concat5, 256, 3, 1) # 再经过3*3卷积核的卷积层upconv4 = upconv(iconv5, 128, 3, 2) # H/8,图片长宽都变为原来的二倍concat4 = tf.concat([upconv4, skip3], 3) # upconv4的输出与conv3输出的尺寸相同,将他们叠加iconv4 = conv(concat4, 128, 3, 1) # 再经过128个3*3卷积核的卷积层self.disp4 = self.get_disp(iconv4) # 获得第四个视差图,单边尺寸为输入图片的1/8udisp4 = self.upsample_nn(self.disp4, 2) # 获得第四个叠加视差图,单边尺寸为输入图片的1/4upconv3 = upconv(iconv4, 64, 3, 2) # H/4,图片长宽都变为原来的二倍concat3 = tf.concat([upconv3, skip2, udisp4], 3) # upconv3的输出与conv2输出和第四个叠加视差图的尺寸相同,将他们叠加iconv3 = conv(concat3, 64, 3, 1) # 再经过64个3*3卷积核的卷积层self.disp3 = self.get_disp(iconv3) # 获得第三个视差图,单边尺寸为输入图片的1/4udisp3 = self.upsample_nn(self.disp3, 2) # 获得第三个叠加视差图,单边尺寸为输入图片的1/2upconv2 = upconv(iconv3, 32, 3, 2) # H/2,图片长宽都变为原来的二倍concat2 = tf.concat([upconv2, skip1, udisp3], 3) # upconv2的输出与conv1输出和第三个叠加视差图的尺寸相同,将他们通道叠加iconv2 = conv(concat2, 32, 3, 1) # 再经过32个3*3卷积核的卷积层self.disp2 = self.get_disp(iconv2) # 获得第二个视差图,单边尺寸为输入图片的1/2udisp2 = self.upsample_nn(self.disp2, 2) # 获得第二个叠加视差图,单边尺寸为输入图片upconv1 = upconv(iconv2, 16, 3, 2) # H,图片长宽都变为原来的二倍concat1 = tf.concat([upconv1, udisp2], 3) # upconv2的输出与第二个叠加视差图的尺寸相同,将他们通道叠加iconv1 = conv(concat1, 16, 3, 1) # 再经过16个3*3卷积核的卷积层self.disp1 = self.get_disp(iconv1) # 获得第一个视差图,单边尺寸为输入图片
10.搭建残差神经网络
# 建立残差神经网络def build_resnet50(self):#set convenience functionsconv = self.conv # 定义卷积层简便函数,与上面一样if self.params.use_deconv:upconv = self.deconvelse:upconv = self.upconv# 编码器作用域with tf.variable_scope('encoder'):conv1 = conv(self.model_input, 64, 7, 2) # H/2 - 64D,卷积层,7*7卷积核64个,步长为2,输出为输入尺寸的一半pool1 = self.maxpool(conv1, 3) # H/4 - 64D,最大池化层,kernal_size为3*3,步长为2,输出为输入尺寸的一半conv2 = self.resblock(pool1, 64, 3) # H/8 - 256D,经过一个残差模块,循环3次尺寸不变的残差卷积层,尺寸变为原来的一半conv3 = self.resblock(conv2, 128, 4) # H/16 - 512D,经过一个残差模块,循环4次尺寸不变的残差卷积层,尺寸变为原来的一半conv4 = self.resblock(conv3, 256, 6) # H/32 - 1024D,经过一个残差模块,循环6次尺寸不变的残差卷积层,尺寸变为原来的一半conv5 = self.resblock(conv4, 512, 3) # H/64 - 2048D,经过一个残差模块,循环6次尺寸不变的残差卷积层,尺寸变为原来的一半# 设置skip作用域,便于将编码过程的部分特征图直接拼接到解码过程中with tf.variable_scope('skips'):skip1 = conv1skip2 = pool1skip3 = conv2skip4 = conv3skip5 = conv4#解码作用域,与VGG16一样# DECODINGwith tf.variable_scope('decoder'):upconv6 = upconv(conv5, 512, 3, 2) #H/32concat6 = tf.concat([upconv6, skip5], 3)iconv6 = conv(concat6, 512, 3, 1)upconv5 = upconv(iconv6, 256, 3, 2) #H/16concat5 = tf.concat([upconv5, skip4], 3)iconv5 = conv(concat5, 256, 3, 1)upconv4 = upconv(iconv5, 128, 3, 2) #H/8concat4 = tf.concat([upconv4, skip3], 3)iconv4 = conv(concat4, 128, 3, 1)self.disp4 = self.get_disp(iconv4)udisp4 = self.upsample_nn(self.disp4, 2)upconv3 = upconv(iconv4, 64, 3, 2) #H/4concat3 = tf.concat([upconv3, skip2, udisp4], 3)iconv3 = conv(concat3, 64, 3, 1)self.disp3 = self.get_disp(iconv3)udisp3 = self.upsample_nn(self.disp3, 2)upconv2 = upconv(iconv3, 32, 3, 2) #H/2concat2 = tf.concat([upconv2, skip1, udisp3], 3)iconv2 = conv(concat2, 32, 3, 1)self.disp2 = self.get_disp(iconv2)udisp2 = self.upsample_nn(self.disp2, 2)upconv1 = upconv(iconv2, 16, 3, 2) #Hconcat1 = tf.concat([upconv1, udisp2], 3)iconv1 = conv(concat1, 16, 3, 1)self.disp1 = self.get_disp(iconv1)# 建立模型def build_model(self):# slim.arg_scope常用于为tensorflow里的layer函数提供默认值以使构建模型的代码更加紧凑苗条,这里是使用elu作为激活函数with slim.arg_scope([slim.conv2d, slim.conv2d_transpose], activation_fn=tf.nn.elu):with tf.variable_scope('model', reuse=self.reuse_variables):# 左图为四层金字塔图self.left_pyramid = self.scale_pyramid(self.left, 4)# 如果训练,右图也为四层金字塔图if self.mode == 'train':self.right_pyramid = self.scale_pyramid(self.right, 4)if self.params.do_stereo:# 如果生成立体图,将左图和右图一起在channel通道concatself.model_input = tf.concat([self.left, self.right], 3)else:# 否则输入是左图self.model_input = self.left# build model# 建立模型if self.params.encoder == 'vgg':self.build_vgg()elif self.params.encoder == 'resnet50':self.build_resnet50()else:return None# 设置输出def build_outputs(self):# STORE DISPARITIESwith tf.variable_scope('disparities'):self.disp_est = [self.disp1, self.disp2, self.disp3, self.disp4] # 四张视差图叠加在一起# TensorFlow中,想要维度增加一维,可以使用tf.expand_dims(input, dim, name=None)函数。self.disp_left_est = [tf.expand_dims(d[:,:,:,0], 3) for d in self.disp_est] #生成左右金字塔视差图self.disp_right_est = [tf.expand_dims(d[:,:,:,1], 3) for d in self.disp_est]if self.mode == 'test':return# GENERATE IMAGESwith tf.variable_scope('images'):# 使用视差图和左图与右图金字塔图生成右图与左图self.left_est = [self.generate_image_left(self.right_pyramid[i], self.disp_left_est[i]) for i in range(4)]self.right_est = [self.generate_image_right(self.left_pyramid[i], self.disp_right_est[i]) for i in range(4)]# LR CONSISTENCY# 建立左右视差图的相似度with tf.variable_scope('left-right'):self.right_to_left_disp = [self.generate_image_left(self.disp_right_est[i], self.disp_left_est[i]) for i in range(4)]self.left_to_right_disp = [self.generate_image_right(self.disp_left_est[i], self.disp_right_est[i]) for i in range(4)]# DISPARITY SMOOTHNESS# 获取左右视差图的连续性with tf.variable_scope('smoothness'):self.disp_left_smoothness = self.get_disparity_smoothness(self.disp_left_est, self.left_pyramid)self.disp_right_smoothness = self.get_disparity_smoothness(self.disp_right_est, self.right_pyramid)# 建立损失函数def build_losses(self):with tf.variable_scope('losses', reuse=self.reuse_variables):# IMAGE RECONSTRUCTION# L1#左图、右图估计损失self.l1_left = [tf.abs( self.left_est[i] - self.left_pyramid[i]) for i in range(4)] # 获取金字塔左图四个图的损失函数self.l1_reconstruction_loss_left = [tf.reduce_mean(l) for l in self.l1_left] # 获取左图四个图的平均损失self.l1_right = [tf.abs(self.right_est[i] - self.right_pyramid[i]) for i in range(4)] # 获取金字塔左图四个图的损失函数self.l1_reconstruction_loss_right = [tf.reduce_mean(l) for l in self.l1_right] # 获取右图四个图的平均损失# SSIMself.ssim_left = [self.SSIM( self.left_est[i], self.left_pyramid[i]) for i in range(4)] #获取预测金字塔左图四个图与真实label的相似度self.ssim_loss_left = [tf.reduce_mean(s) for s in self.ssim_left] #获取相似度均值self.ssim_right = [self.SSIM(self.right_est[i], self.right_pyramid[i]) for i in range(4)] #获取预测金字塔右图四个图与真实label的相似度self.ssim_loss_right = [tf.reduce_mean(s) for s in self.ssim_right] #获取相似度均值# WEIGTHED SUM# 计算损失函数三项中的第一项,即左右图的还原程度self.image_loss_right = [self.params.alpha_image_loss * self.ssim_loss_right[i] + (1 - self.params.alpha_image_loss) * self.l1_reconstruction_loss_right[i] for i in range(4)]self.image_loss_left = [self.params.alpha_image_loss * self.ssim_loss_left[i] + (1 - self.params.alpha_image_loss) * self.l1_reconstruction_loss_left[i] for i in range(4)]self.image_loss = tf.add_n(self.image_loss_left + self.image_loss_right)# DISPARITY SMOOTHNESS# 计算损失函数三项中的第二项,计算左右视差图的连续性程度作为第二个损失函数self.disp_left_loss = [tf.reduce_mean(tf.abs(self.disp_left_smoothness[i])) / 2 ** i for i in range(4)]self.disp_right_loss = [tf.reduce_mean(tf.abs(self.disp_right_smoothness[i])) / 2 ** i for i in range(4)]self.disp_gradient_loss = tf.add_n(self.disp_left_loss + self.disp_right_loss)# LR CONSISTENCY# 计算损失函数三项中的第三项,计算生成的基于左图和右图的两张视差图的相关性程度self.lr_left_loss = [tf.reduce_mean(tf.abs(self.right_to_left_disp[i] - self.disp_left_est[i])) for i in range(4)]self.lr_right_loss = [tf.reduce_mean(tf.abs(self.left_to_right_disp[i] - self.disp_right_est[i])) for i in range(4)]self.lr_loss = tf.add_n(self.lr_left_loss + self.lr_right_loss)# TOTAL LOSS# 总损失,将三个损失求和self.total_loss = self.image_loss + self.params.disp_gradient_loss_weight * self.disp_gradient_loss + self.params.lr_loss_weight * self.lr_loss# 定义总结函数def build_summaries(self):# SUMMARIESwith tf.device('/cpu:0'):for i in range(4):# tf.summary.scalar:一般在画loss,accuary时会用到这个函数,记录总损失和三个子损失值,同时记录左右图视差图的预测图tf.summary.scalar('ssim_loss_' + str(i), self.ssim_loss_left[i] + self.ssim_loss_right[i], collections=self.model_collection)tf.summary.scalar('l1_loss_' + str(i), self.l1_reconstruction_loss_left[i] + self.l1_reconstruction_loss_right[i], collections=self.model_collection)tf.summary.scalar('image_loss_' + str(i), self.image_loss_left[i] + self.image_loss_right[i], collections=self.model_collection)tf.summary.scalar('disp_gradient_loss_' + str(i), self.disp_left_loss[i] + self.disp_right_loss[i], collections=self.model_collection)tf.summary.scalar('lr_loss_' + str(i), self.lr_left_loss[i] + self.lr_right_loss[i], collections=self.model_collection)tf.summary.image('disp_left_est_' + str(i), self.disp_left_est[i], max_outputs=4, collections=self.model_collection)tf.summary.image('disp_right_est_' + str(i), self.disp_right_est[i], max_outputs=4, collections=self.model_collection)# 记录左右图的预测图,左右图的相似程度,左右图的差值情况if self.params.full_summary:tf.summary.image('left_est_' + str(i), self.left_est[i], max_outputs=4, collections=self.model_collection)tf.summary.image('right_est_' + str(i), self.right_est[i], max_outputs=4, collections=self.model_collection)tf.summary.image('ssim_left_' + str(i), self.ssim_left[i], max_outputs=4, collections=self.model_collection)tf.summary.image('ssim_right_' + str(i), self.ssim_right[i], max_outputs=4, collections=self.model_collection)tf.summary.image('l1_left_' + str(i), self.l1_left[i], max_outputs=4, collections=self.model_collection)tf.summary.image('l1_right_' + str(i), self.l1_right[i], max_outputs=4, collections=self.model_collection)# 记录左图右图的label图if self.params.full_summary:tf.summary.image('left', self.left, max_outputs=4, collections=self.model_collection)tf.summary.image('right', self.right, max_outputs=4, collections=self.model_collection)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
