卷积神经网络


填充、步幅、池化层


使用预训练的卷积神经网络、特征提取、冻结、模型微调

 

因为卷积基的vgg16(conv_base)要和未经训练的分类器(Dense)重新一起训练,那么未经训练的分类器(Dense)便会随机初始化,
并且随机初始化一开始是非常大的权重便会导致在整个网络中传播,因此会对卷积基的vgg16(conv_base)学到的表示造成很大的破坏。
所以要求卷积基的vgg16(conv_base)的权重不能变,那么就需要冻结卷积基的vgg16(conv_base)。


卷积神经网络的可视化


反向运行一个卷积神经网络在 卷积神经网络的可视化 中的应用

卷积神经网络过滤器可视化技术
	1.想要观察卷积神经网络学到的过滤器,一种简单的方法是显示每个过滤器所响应的视觉模式。
	  这可以通过在输入空间中进行梯度上升来实现:从空白输入图像(带有噪声的灰度图像)开始,将梯度下降应用于卷积神经网络输入图像的值,
	  其目的是让某个过滤器的响应最大化。通过多次梯度上升,沿着让损失最大化的方向调节输入图像,最终计算得出的输入图像便是所选定过滤器具有最大响应的图像。
	  其目的是让某个卷积层的第n个过滤器的激活值最大化,然后使用随机梯度下降来调节输入图像的值,以便让这个激活值最大化。
	  该所要计算的损失loss,即为要在梯度上升过程中需要最大化的量。
		#获取某一层的激活输出,其中包含所有过滤器激活输出
		layer_output = model.get_layer(layer_name).output  
		#filter_index 代表的是要获取第几个过滤器激活的值作为损失
		loss = K.mean(layer_output[:, :, :, filter_index]) 
		#1.Keras的backend模块内置的gradients函数:输入损失和模型输入,得到损失相对于模型输入的梯度,即可实现梯度下降
		#2.K.gradients(loss, model.input)[0] 返回的是一个张量列表(本例中列表长度为1),因此只保留第一个元素,它是一个张量
		#3.此处获取损失loss相对于模型输入model.input的梯度grads,计算这个损失相对于输入图像的梯度
		grads = K.gradients(loss, model.input)[0] 	
		#1.为了让梯度下降过程顺利进行,一个非显而易见的技巧就是将 梯度张量grads 除以其 L2 范数(grads张量中所有值的平方的平均值的平方根)来标准化。
		#  这就确保了输入图像的更新大小始终位于相同的范围。
		#2.梯度标准化技巧:将这个梯度grads 标准化,做除法前加上 1e–5,以防不小心除以 0
		grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
      		#1.定义一个 Keras 后端函数来实现如下:给定输入图像[model.input],它能够计算[损失张量loss, 梯度张量grads]的值。
		#2.此处定义的iterate 是一个Keras 后端函数,它将一个 Numpy 张量(模型输入表示为长度为1的张量列表)转换为 两个 Numpy 张量(损失值和梯度值)组成的列表。
		#3.iterate 返回给定输入图像的损失和梯度
		iterate = K.function([model.input], [loss, grads])
		#从一张带有噪声的灰度图像开始,shape为(1, 150, 150, 3)
		input_img_data = numpy.random.random((1, 150, 150, 3)) * 20 + 128
		#每次梯度更新的步长
		step = 1 
		#1.从空白输入图像(带有噪声的灰度图像)开始,将梯度下降应用于卷积神经网络输入图像的值,其目的是让某个过滤器的响应最大化。
		#2.使用随机梯度下降来调节输入图像的值,以便让这个激活值最大化,此处即通过随机梯度下降让损失最大化 
		#3.此处运行 40 次梯度上升
		for i in range(40):
			#通过给定输入图像计算损失值和梯度值
			loss_value, grads_value = iterate([input_img_data])
			#通过多次梯度上升,沿着让损失最大化的方向调节输入图像,最终计算得出的输入图像input_img_data便是所选定过滤器具有最大响应的图像 
			input_img_data += grads_value * step
		#1.得到的图像张量input_img_data是形状为 (1, 150, 150, 3) 的浮点数张量,其取值可能不是 [0, 255] 区间内的整数。
		#  因此,你需要对这个张量进行后处理,将其转换为可显示的图像。
		#2.x.shape为(150, 150, 3)
		x = input_img_data[0]
		#对张量做标准化,使其均值为 0,标准差为 0.1
		x -= x.mean() 
 		x /= (x.std() + 1e-5)
 		x *= 0.1
 		x += 0.5 
		#将 x 裁切(clip)到 [0, 1] 区间
 		x = np.clip(x, 0, 1)
		#将 x 转换为 RGB 数组
 		x *= 255 
		#确保取值为 [0, 255] 区间内的整数,然后将其转换为可显示的图像
 		x = np.clip(x, 0, 255).astype('uint8')
		#将其图像显示
		plt.imshow(x)

	2.VGG16 例子
		from keras.applications import VGG16
		from keras import backend as K
		model = VGG16(weights='imagenet',
		include_top=False)
		layer_name = 'block3_conv1'
		filter_index = 0
		layer_output = model.get_layer(layer_name).output
		loss = K.mean(layer_output[:, :, :, filter_index])

		>>> model.summary()
		_________________________________________________________________
		Layer (type)                 Output Shape              Param #
		=================================================================
		input_1 (InputLayer)         (None, None, None, 3)     0
		_________________________________________________________________
		.....
		_________________________________________________________________
		block3_conv1 (Conv2D)        (None, None, None, 256)   295168
		_________________________________________________________________
		block3_conv2 (Conv2D)        (None, None, None, 256)   590080
		_________________________________________________________________
		block3_conv3 (Conv2D)        (None, None, None, 256)   590080
		_________________________________________________________________
		block3_pool (MaxPooling2D)   (None, None, None, 256)   0
		_________________________________________________________________
		.....
		_________________________________________________________________

		#1.block3_conv1 (Conv2D) (None, None, None, 256) 代表这一层有256个过滤器,layer_output[:, :, :, n] 获取第n个过滤器激活输出
		#2.获取 block3_conv1层 第0个过滤器激活的损失:layer_output[:, :, :, 0]
		#3.loss = K.mean(layer_output[:, :, :,0]) 目的构建一个损失函数,让某个卷积层的某个过滤器的值最大化,然后使用随机梯度下降来调节输入图像的值,
		#  以便让这个激活值最大化
		>>> layer_output = model.get_layer( 'block3_conv1').output
		>>> layer_output.shape
		TensorShape([Dimension(None), Dimension(None), Dimension(None), Dimension(256)])


反向运行一个卷积神经网络在 DeepDream 中的应用

DeepDream 的工作原理:通过输入空间中的梯度上升将卷积神经网络的层激活最大化

执行时报错:could not create cudnn handle: CUDNN_STATUS_ALLOC_FAILED
解决方式:GPU占用问题导致的,keras框架(Tensorflow backend) 设置GPU按需分配:
		import tensorflow as tf
		from keras import backend as K
		config = tf.ConfigProto()
		config.gpu_options.allow_growth=True
		sess = tf.Session(config=config)
		K.set_session(sess)
1.DeepDream 算法与卷积神经网络过滤器可视化技术几乎相同,都是反向运行一个卷积神经网络:
	卷积神经网络过滤器可视化:对卷积神经网络的输入做梯度上升,以便将卷积神经网络靠顶部的某一层的某个过滤器激活最大化。
	DeepDream 算法:对卷积神经网络的输入做梯度上升,以便将卷积神经网络多个层的所有过滤器的激活同时最大化。

2.DeepDream 算法与卷积神经网络过滤器可视化技术使用了相同的想法,但有以下这几个简单的区别:
	1.使用 DeepDream,我们尝试将所有层的激活最大化,而不是将某一层的激活最大化,因此需要同时将大量特征的可视化混合在一起。
	  而卷积神经网络过滤器可视化则只是将某个卷积层的某个过滤器的激活值最大化。
	2.卷积神经网络过滤器可视化从空白的、略微带有噪声的输入开始。
	  DeepDream 算法不是从空白的、略微带有噪声的输入开始,而是从现有的图像开始,因此所产生的效果能够抓住已经存在的视觉模式,
	  并以某种艺术性的方式将图像元素扭曲。
	3.使用 DeepDream,输入图像是在不同的尺度上[叫作八度(octave)]进行处理的,这可以提高可视化的质量。

3.DeepDream 算法
	1.所要计算的损失loss,即为要在梯度上升过程中需要最大化的量。在卷积神经网络过滤器可视化技术中是需要将某一层的某个过滤器的值最大化,
	  而DeepDream 算法是需要将多个层的所有过滤器的激活同时最大化,具体来说,就是对一组靠近顶部的层激活的 L2 范数进行加权求和,然后将其最大化。
	2.Keras 中有许多这样的卷积神经网络:VGG16、VGG19、Xception、ResNet50 等。我们可以用其中任何一个来实现 DeepDream,
	  但我们选择的卷积神经网络会影响可视化的效果,因为不同的卷积神经网络架构会学到不同的特征。
	3.此处使用 Keras 内置的 Inception V3模型,加载预训练的 Inception V3 模型
	4.执行流程:
		1.所谓计算丢失细节,实际是将原始图像大小调整为较大的图像尺寸L 与 将原始图像大小调整为较小的图像尺寸S之间的区别,
		  比如图像尺寸S为(1, 350, 350, 3)原图像img缩小为(1, 178, 178, 3)再放大为的(1, 250, 250, 3),
		  图像尺寸L为(1, 350, 350, 3)原图像img所缩小为的(1, 250, 250, 3),然后计算述从 S 到 L 的细节损失。
		 
		2.第1次遍历:(1, 350, 350, 3)的原图像img缩小为(1, 178, 178, 3),然后梯度上升,然后注入丢失细节,
			    注意此时注入的丢失细节的值均为0,因为此时图像并还没有放大为(1, 250, 250, 3)。
		 
		3.第2次遍历:梯度上升后并注入丢失细节的(1, 178, 178, 3) 放大为 (1, 250, 250, 3),然后梯度上升,然后注入丢失细节,
			    注意此时注入的丢失细节实际为原始图像original_img较小版本(1, 250, 250, 3) 减去 
			    原始图像original_img较小版本(1, 178, 178, 3)的重新放大版(1, 250, 250, 3),
			    丢失细节即为原始图像缩小和原始图像缩小再放大之间的差别

		4.第3次遍历:梯度上升后并注入丢失细节的(1, 250, 250, 3) 放大为 (1, 350, 350, 3),然后梯度上升,然后注入丢失细节,
			    注意此时注入的丢失细节实际为原始图像original_img的(1, 350, 350, 3) 减去 
			    原始图像original_img较小版本(1, 250, 250, 3)的重新放大版(1, 350, 350, 3),
			    丢失细节即为原始图像缩小和原始图像缩小再放大之间的差别

	5.示例代码
		from keras.applications import inception_v3
		from keras import backend as K
		#不需要训练模型,这个命令会禁用所有与训练有关的操作
		K.set_learning_phase(0) 
		#构建不包括全连接层的 Inception V3网络。使用预训练的 ImageNet 权重来加载模型。
		model = inception_v3.InceptionV3(weights='imagenet', include_top=False)
		#1.选择哪些层(以及它们对最终损失的贡献)对生成的可视化结果具有很大影响,所以我们希望让这些参数变得易于配置。
		#  更靠近底部的层生成的是几何图案,而更靠近顶部的层生成的则是从中能够看出某些 ImageNet 类别(比如鸟或狗)的图案。
		#2.设置 DeepDream 配置:我们将随意选择 4 层的配置,但你以后一定要探索多个不同的配置。
		#  这个字典将层的名称key 映射为一个 系数value,这个系数定量value 表示该层激活对你要最大化的损失的贡献大小。
		#  注意,层的名称key 硬编码在内置的 Inception V3 应用中。可以使用 model.summary() 列出所有层的名称
		layer_contributions = { 
		 'mixed2': 0.2,
		 'mixed3': 3.,
		 'mixed4': 2.,
		 'mixed5': 1.5,
		}
		#1.下面所定义的损失loss 为在梯度上升过程中需要最大化的量。在卷积神经网络过滤器可视化技术中,是将某一层的某个过滤器的值最大化。
		#  DeepDream 算法则要将多个层的所有过滤器的激活同时最大化。具体来说,就是对一组靠近顶部的层激活的 L2 范数进行加权求和,然后将其最大化。
		#2.使用一个包含损失的张量来定义需要最大化的损失,而损失就是layer_contributions字典中所定义的多个层激活的 L2 范数的加权求和。
		#3.在定义损失loss 时将层的贡献添加到这个标量变量中,即layer_contributions字典中每个层key对应value(该层激活对你要最大化的损失的贡献大小)。
		loss = K.variable(0.)
		#创建一个字典,根据layer_contributions字典中所定义的多个层的名称key 映射为 层的实例value。 len(layer_dict)为 311。
		layer_dict = dict([(layer.name, layer) for layer in model.layers])
		for layer_name in layer_contributions:
			#coeff为该层激活对你要最大化的损失的贡献大小
 			coeff = layer_contributions[layer_name]
			#获取层的输出activation,即为该层所有的过滤器
 			activation = layer_dict[layer_name].output
			#K.cast把dtype=int32的过滤器输出activation转换类型为float32 
			#计算缩放比例scaling 
			scaling = K.prod(K.cast(K.shape(activation), 'float32'))
			#1.将该层特征的L2范数添加到loss中。为了避免出现边界伪影,损失中仅包含非边界的像素。
			#2.activation[:, 2: -2, 2: -2, :] 中的第四个维度表示获取该层的所有过滤器的激活输出,
			#  而在卷积神经网络过滤器可视化技术中的activation[:, :, :, n]表示获取该卷积层的第n个过滤器的激活值。
			loss += coeff * K.sum(K.square(activation[:, 2: -2, 2: -2, :])) / scaling
		#模型输入:这个张量用于保存生成的图像,即梦境图像
		dream = model.input
		#1.Keras的backend模块内置的gradients函数:输入损失和模型输入,得到损失相对于模型输入的梯度,即可实现梯度下降
		#2.K.gradients(loss, model.input)[0] 返回的是一个张量列表(本例中列表长度为1),因此只保留第一个元素,它是一个张量
		#3.此处计算损失相对于梦境图像的梯度,获取损失loss相对于模型输入model.input的梯度grads,计算这个损失相对于输入图像的梯度
		grads = K.gradients(loss, dream)[0]
		#将梯度标准化的重要技巧
		grads /= K.maximum(K.mean(K.abs(grads)), 1e-7)
      		#1.定义一个 Keras 后端函数来实现如下:给定输入图像[model.input],它能够计算[损失张量loss, 梯度张量grads]的值。
		#2.此处定义的fetch_loss_and_grads 是一个Keras 后端函数,它将一个 Numpy 张量(模型输入表示为长度为1的张量列表)转换为 
		#  两个 Numpy 张量(损失值和梯度值)组成的列表。
		#3.fetch_loss_and_grads 返回给定输入图像的损失和梯度,给定一张输出图像,设置一个 Keras 函数来获取损失值和梯度值。
		outputs = [loss, grads]
		fetch_loss_and_grads = K.function([dream], outputs)
		#传入给定的输入图像model.input,评估损失loss和梯度grads 
		def eval_loss_and_grads(x):
			#传入给定的输入图像[model.input],返回给定输入图像的损失和梯度
  			outs = fetch_loss_and_grads([x])
			#损失loss
  			loss_value = outs[0] 
			#梯度grads
  			grad_values = outs[1] 
  			return loss_value, grad_values
		#1.从给定的输入图像x开始,将梯度下降应用于卷积神经网络输入图像的值,其目的是让过滤器的响应最大化。
		#2.使用随机梯度下降来调节输入图像的值,以便让这个激活值最大化,此处即通过随机梯度下降让损失最大化 
		#3.设置梯度上升过程,这个函数运行 iterations次 梯度上升。
		#4.传入参数:给定的输入图像x、iterations迭代次数、每次梯度更新的步长step、最大损失max_loss
		def gradient_ascent(x, iterations, step, max_loss=None): 
 			for i in range(iterations):
				#传入给定的输入图像model.input,评估损失loss和梯度grads 
 				loss_value, grad_values = eval_loss_and_grads(x)
				#如果“根据给定输入图像所计算得出的”损失值loss大于指定的max_loss的话,则停止迭代
				#比如设置max_loss=10,表示如果损失loss_value增大到大于10,那么要中断梯度上升过程,以避免得到丑陋的伪影
 				if max_loss is not None and loss_value > max_loss:
 					break
 				print('...Loss value at', i, ':', loss_value)
				#通过多次梯度上升,沿着让损失最大化的方向调节输入图像,最终计算得出的输入图像x便是所选定过滤器具有最大响应的图像
 				x += step * grad_values
 			return x
		
		
		import numpy as np
		#改变这些超参数step、num_octave、octave_scale,可以得到新的效果
		step = 0.01  			#梯度上升的步长
		num_octave = 3 			#运行梯度上升的尺度个数
		octave_scale = 1.4 		#两个尺度之间的大小比例
		iterations = 20 			#在每个尺度上运行梯度上升的步数
		max_loss = 10. 			#如果损失增大到大于 10,我们要中断梯度上升过程,以避免得到丑陋的伪影
		base_image_path = 'F:\\original_photo_deep_dream.jpg' 	#将这个变量修改为你要使用的图像的路径

		#将基础图像加载成一个 Numpy 数组
		#通用函数,用于打开图像、改变图像大小以及将图像格式转换为 Inception V3 模型能够处理的张量
		def preprocess_image(image_path): 
 			img = image.load_img(image_path)
 			img = image.img_to_array(img)
			#在(行,列,通道数)的形状前面增加第一维变成(批量大小,行,列,通道数)
 			img = np.expand_dims(img, axis=0)
 			img = inception_v3.preprocess_input(img)
 			return img

		#通用函数,将一个张量转换为有效图像。
		def deprocess_image(x):
			#如果是channel在前的模式,x.shape为(批量大小,通道数,行,列)
			if K.image_data_format() == 'channels_first':
				#取出(批量大小,通道数,行,列)中的行与列,重新构成(3,行,列)
				x = x.reshape((3, x.shape[2], x.shape[3]))
				#把 (3,行,列) 转换为 (行,列,3)
				x = x.transpose((1, 2, 0))
			else:
				#如果是channel在后的模式,x.shape为(批量大小,行,列,通道数),则要取出其中的行与列,重新构成(行,列,3)
				x = x.reshape((x.shape[1], x.shape[2], 3))
			#对 inception_v3.preprocess_input 所做的预处理进行反向操作
			x /= 2.
			x += 0.5
			x *= 255.
			#限制x中的值在0到255范围之内,才能返回有效图像
			x = np.clip(x, 0, 255).astype('uint8')
			return x

		def save_img(img, fname):
			#通用函数,将一个张量转换为有效图像。
			pil_img = deprocess_image(np.copy(img))
			scipy.misc.imsave(fname, pil_img)

		#将基础图像加载成一个 Numpy 数组
		img = preprocess_image(base_image_path)
		#取出(批量大小,行,列,通道数)中的(行,列)维度值
		original_shape = img.shape[1:3]
		#列表中存储多个元祖,每个元祖为(行,列)
		successive_shapes = [original_shape]
		#准备一个由形状元组组成的列表,它定义了运行梯度上升的不同尺度
		for i in range(1, num_octave):
			#dim为(行,列)的元祖,即 行值/(1.4 ** i) 和 列值/(1.4 ** i),每个元祖的行值和列值都比前一个元祖的行值和列值均缩小1.4倍
 			shape = tuple([int(dim / (octave_scale ** i)) for dim in original_shape])
 			successive_shapes.append(shape)
		#将形状列表反转,变为升序。此处为 [(350, 350), (250, 250), (178, 178)],现在变成 [(178, 178), (250, 250), (350, 350)]
		successive_shapes = successive_shapes[::-1] 
 
		import scipy
		from keras.preprocessing import image
 
		def resize_img(img, size):
			img = np.copy(img)
			factors = (1, float(size[0]) / img.shape[1], float(size[1]) / img.shape[2], 1)
			#完整格式 scipy.ndimage.zoom(input, zoom, output=None, order=3, mode='constant', cval=0.0, prefilter=True)
			#scipy.ndimage.zoom用于上采样与下采样即图像缩放,img即input为输入数组,factors即zoom为float或sequence序列,
			#zoom:沿轴的缩放系数。如果是浮点,则每个轴都相同。如果是序列,则每个轴应包含一个值
			#order:值必须在0-5的范围内,默认为3,表示线性插值的顺序
			return scipy.ndimage.zoom(img, factors, order=1)

 		#把原图像 Numpy 数组拷贝一份保存,original_img.shape为(1,350, 350,3)
		original_img = np.copy(img)
		#1.将图像 Numpy 数组的大小缩放到最小尺寸
		​#2.img的形状为(批量大小,行,列,通道数),即(1,350, 350,3),successive_shapes[0]为最小尺寸的(行,列),即(178, 178),
		#  shrunk_original_img 结果即为 原图像img 缩小形状为(1, 178, 178, 3)。
		shrunk_original_img = resize_img(img, successive_shapes[0])
 
		#在多个连续尺度上运行梯度上升
		#要遍历的successive_shapes有3个连续尺度,为[(178, 178), (250, 250), (350, 350)]
		for shape in successive_shapes:
    			print('Processing image shape', shape)
			#1.将梦境图像放大
			#2.一共3次遍历,img在resize_img前后的变化分别为:
			#  第1次遍历:原图像img的(1, 350, 350, 3) 缩小为 (1, 178, 178, 3)
			#  第2次遍历:梯度上升后并注入丢失细节的(1, 178, 178, 3) 放大为 (1, 250, 250, 3)
			#  第3次遍历:梯度上升后并注入丢失细节的(1, 250, 250, 3) 放大为 (1, 350, 350, 3)
        			img = resize_img(img, shape)
			#1.在这个尺度上运行梯度上升运行20次,img在执行梯度上升前后的形状都不变,目的运行梯度上升,改变梦境图像。
			#2.传入参数:给定的输入图像img、iterations迭代次数、每次梯度更新的步长step、最大损失max_loss。
			#3.从给定的输入图像img开始,将梯度下降应用于卷积神经网络输入图像的值,其目的是让过滤器的响应最大化。
			#  使用随机梯度下降来调节输入图像的值,以便让这个激活值最大化,此处即通过随机梯度下降让损失最大化 。
        			img = gradient_ascent(img, iterations=iterations, step=step, max_loss=max_loss)
			#1.将原始图像的较小版本再重新放大,即把原始图像先缩小再放大会使图像变得模糊或像素化。
			#2.原始图像original_img一直都是(1, 350, 350, 3)没变,而 shrunk_original_img 实际为原始图像original_img的多个不同的缩小版本
			#3.一共3次遍历,从 shrunk_original_img 到 upscaled_shrunk_original_img 的shape变化分别为:
			#  第1次遍历:两者实际均为原始图像original_img的较小版本(1, 178, 178, 3),resize_img前后实际没变
			#  第2次遍历:原始图像original_img的较小版本(1, 178, 178, 3) 重新放大为 (1, 250, 250, 3)
			#  第3次遍历:原始图像original_img的较小版本(1, 250, 250, 3) 重新放大为 (1, 350, 350, 3)
        			upscaled_shrunk_original_img = resize_img(shrunk_original_img, shape)
			#1.在这个尺寸上计算原始图像的高质量版本。原始图像original_img一直都是(1, 350, 350, 3)没变,	
			#  而 same_size_original 实际为原始图像original_img的多个不同的缩小版本
			#3.一共3次遍历,从 original_img 到 same_size_original 的shape变化分别为:
			#  第1次遍历:原始图像original_img的(1, 350, 350, 3) 缩小为 (1, 178, 178, 3)
			#  第2次遍历:原始图像original_img的(1, 350, 350, 3) 缩小为 (1, 250, 250, 3)
			#  第3次遍历:两者实际均为原始图像original_img的(1, 350, 350, 3),resize_img前后实际没变
        			same_size_original = resize_img(original_img, shape)
			#1.二者的差别就是在放大过程中丢失的细节
			#2.一共3次遍历,计算原始图像每次遍历放大40%后所丢失的细节lost_detail
			#  第1次遍历:实际相减的两者都为相同的原始图像original_img的较小版本(1, 178, 178, 3),因此不存在丢失的细节,lost_detail中的值均为0
			#  第2次遍历:原始图像original_img较小版本(1, 250, 250, 3) 减去 原始图像original_img较小版本(1, 178, 178, 3)的重新放大版(1, 250, 250, 3)
			#  第3次遍历:原始图像original_img的(1, 350, 350, 3) 减去 原始图像original_img较小版本(1, 250, 250, 3)的重新放大版(1, 350, 350, 3)
        			lost_detail = same_size_original - upscaled_shrunk_original_img
			#将丢失的细节重新注入到梦境图像中
        			img += lost_detail
			#一共3次遍历,从 original_img 到 shrunk_original_img 的shape变化分别为:
			#  第1次遍历:原始图像original_img的(1, 350, 350, 3) 缩小为 (1, 178, 178, 3)
			#  第2次遍历:原始图像original_img的(1, 350, 350, 3) 缩小为 (1, 250, 250, 3)
			#  第3次遍历:两者实际均为原始图像original_img的(1, 350, 350, 3),resize_img前后实际没变
        			shrunk_original_img = resize_img(original_img, shape)
			#一共3次遍历,所存储本地的img的变化:
			#第1次遍历:原图像img的(1, 350, 350, 3) 缩小为 (1, 178, 178, 3),然后梯度上升,最后注入丢失值均为0的细节,因为此时img还没再次放大
			#第2次遍历:梯度上升后并注入丢失细节的(1, 178, 178, 3) 放大为 (1, 250, 250, 3),然后梯度上升,最后注入“先缩小再放大所丢失的”细节
			#第3次遍历:梯度上升后并注入丢失细节的(1, 250, 250, 3) 放大为 (1, 350, 350, 3),然后梯度上升,最后注入“先缩小再放大所丢失的”细节
        			save_img(img, fname='dream_at_scale_' + str(shape) + '.png')
		
		save_img(img, fname='final_dream.png')

FCN 全卷积网络、卷积神经网络的上采样:Conv2DTranspose 转置卷积(反卷积/后卷积/分数步长卷积)

参考博客:https://blog.csdn.net/fate_fjh/article/details/52882134
1.转置卷积 Conv2DTranspose 可被称为 反卷积、后卷积、分数步⻓卷积(fractionally-strided convolution)。
2.在模型设计中,转置卷积层常⽤于将较小的特征图变换为更⼤的特征图。在全卷积⽹络中,
  当输⼊是⾼和宽较小的特征图时,转置卷积层可以⽤来将⾼和宽放⼤到输⼊图像的尺⼨。
3.转置卷积层可以放⼤特征图。在图像处理中,我们有时需要将图像放⼤,即上采样(upsample)。上采样的⽅法有很多,常⽤的有双线性插值。
  在全卷积⽹络中,我们将转置卷积层初始化为双线性插值的上采样。

1.padding='same':填充后输出的宽度和高度与输入的宽度和高度相同
2.Conv2DTranspose 例子1:
	下面转置卷积的输入形状为(None, 14, 14, 64),输出形状为(None, 28, 28, 32),上采样为28×28,转置卷积把输入的宽和高都分别放大了2倍
	x = layers.Conv2DTranspose(32, 3, padding='same', activation='relu', strides=(2, 2))
3.Conv2DTranspose 例子2:
	下面转置卷积的输入形状为(None, 16, 16, 256),输出形状为(None, 32, 32, 256),上采样为32×32,转置卷积把输入的宽和高都分别放大了2倍
	x = layers.Conv2DTranspose(256, 4, strides=2, padding='same')(x)


卷积神经网络的下采样:步进卷积、最大池化

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

あずにゃん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值