Keras - Python深度学习(第二部分)

Keras - Python深度学习(第一部分)

Keras - Python深度学习(第二部分) 


shuffle和validation_split之间的执行顺序

模型的fit函数中有两个参数,shuffle用于将数据打乱,validation_split用于在没有提供验证集的时候,按一定比例从训练集中取出一部分作为验证集。
这里有个陷阱是,程序是先执行validation_split,再执行shuffle的,所以会出现这种情况:假如你的训练集是有序的,比方说正样本在前负样本在后,
又设置了validation_split,那么你的验证集中很可能将全部是负样本。同样的,这个东西不会有任何错误报出来,因为Keras不可能知道你的数据有没有经过shuffle,
保险起见如果你的数据是没shuffle过的,最好手动shuffle一下


Keras:GAN生成式对抗网络

1.内核大小要能够被步幅大小整除,指的就是内核大小÷strides的结果是商为整数,且余数为零。
2.被除数、除数、整除的概念
	如24÷8=3,其中24是被除数,8为除数。
	若ab=c(b≠0),用积数c和因数b来求另一个因数a的运算就是除法,写作c÷b,读作c除以b(或b除c)。其中,c叫做被除数,b叫做除数,运算的结果a叫做商。
	若b÷a为整数b除以非零整数a,商为整数,且余数为零, 我们就说b能被a整除(或说a能整除b),b为被除数,a为除数,即a|b(“|”是整除符号),
	读作“a整除b”或“b能被a整除”。a叫做b的约数(或因数),b叫做a的倍数。整除属于除尽的一种特殊情况。

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)
generator.summary()的打印输出:	
	_________________________________________________________________
	Layer (type)                 Output Shape              Param #
	=================================================================
	input_1 (InputLayer)         (None, 32)                0
	_________________________________________________________________
	dense_1 (Dense)              (None, 32768)             1081344
	_________________________________________________________________
	leaky_re_lu_1 (LeakyReLU)    (None, 32768)             0
	_________________________________________________________________
	reshape_1 (Reshape)          (None, 16, 16, 128)       0
	_________________________________________________________________
	conv2d_1 (Conv2D)            (None, 16, 16, 256)       819456
	_________________________________________________________________
	leaky_re_lu_2 (LeakyReLU)    (None, 16, 16, 256)       0
	_________________________________________________________________
	conv2d_transpose_1 (Conv2DTr (None, 32, 32, 256)       1048832
	_________________________________________________________________
	leaky_re_lu_3 (LeakyReLU)    (None, 32, 32, 256)       0
	_________________________________________________________________
	conv2d_2 (Conv2D)            (None, 32, 32, 256)       1638656
	_________________________________________________________________
	leaky_re_lu_4 (LeakyReLU)    (None, 32, 32, 256)       0
	_________________________________________________________________
	conv2d_3 (Conv2D)            (None, 32, 32, 256)       1638656
	_________________________________________________________________
	leaky_re_lu_5 (LeakyReLU)    (None, 32, 32, 256)       0
	_________________________________________________________________
	conv2d_4 (Conv2D)            (None, 32, 32, 3)         37635
	=================================================================

discriminator.summary()的打印输出:
	_________________________________________________________________
	Layer (type)                 Output Shape              Param #   
	=================================================================
	input_2 (InputLayer)         (None, 32, 32, 3)         0         
	_________________________________________________________________
	conv2d_5 (Conv2D)            (None, 30, 30, 128)       3584      
	_________________________________________________________________
	leaky_re_lu_6 (LeakyReLU)    (None, 30, 30, 128)       0         
	_________________________________________________________________
	conv2d_6 (Conv2D)            (None, 14, 14, 128)       262272    
	_________________________________________________________________
	leaky_re_lu_7 (LeakyReLU)    (None, 14, 14, 128)       0         
	_________________________________________________________________
	conv2d_7 (Conv2D)            (None, 6, 6, 128)         262272    
	_________________________________________________________________
	leaky_re_lu_8 (LeakyReLU)    (None, 6, 6, 128)         0         
	_________________________________________________________________
	conv2d_8 (Conv2D)            (None, 2, 2, 128)         262272    
	_________________________________________________________________
	leaky_re_lu_9 (LeakyReLU)    (None, 2, 2, 128)         0         
	_________________________________________________________________
	flatten_1 (Flatten)          (None, 512)               0         
	_________________________________________________________________
	dropout_1 (Dropout)          (None, 512)               0         
	_________________________________________________________________
	dense_2 (Dense)              (None, 1)                 513       
	=================================================================

如何“冻结”网络的层?
	1.“冻结”一个层指的是该层将不参加网络训练,即该层的权重永不会更新。在进行fine-tune时我们经常会需要这项操作。
	  在使用固定的embedding层处理文本输入时,也需要这个技术。
	2.可以通过向层的构造函数传递trainable参数来指定一个层是不是可训练的,如:frozen_layer = Dense(32,trainable=False)
	3.此外,也可以通过将层对象的trainable属性设为True或False来为已经搭建好的模型设置要冻结的层。 
	  在设置完后,需要运行compile来使设置生效,例如:
		x = Input(shape=(32,))
		layer = Dense(32)
		layer.trainable = False
		y = layer(x)
		frozen_model = Model(x, y)
		#在下面的模型中,“layer”的权重在训练期间不会更新
		frozen_model.compile(optimizer='rmsprop', loss='mse')

		layer.trainable = True
		trainable_model = Model(x, y)
		#使用此模型,训练期间将更新层的权重,修改配置后需要重新运行compile来使设置生效
		#这也将影响上述模型,因为它使用相同的层实例
		trainable_model.compile(optimizer='rmsprop', loss='mse')

		frozen_model.fit(data, labels)  #这不会更新“layer”的权重`
		trainable_model.fit(data, labels)  #这将更新“layer”的权重`
1.构建Model模型的实例对象model
	from keras.models import Model
	model = Model(input,output) 
		1.将xx模型实例化出一个model对象,它将一个模型输入input映射为一个模型输出output,
		  或者说可以理解为把一个模型输入input映射为一个包含多层的整体的模型。
		2.模型输入input可以是 keras.Input(shape)、layers.Input(shape)。
		3.模型输出output:
			可以是一个自定义类的实例对象:class 自定义类名(keras.layers.Layer)的实例对象。
		  	也可以是一个包含多层layers的模型输出:output=layers.xxx(参数)(上一层layers)。
	 	  	也可以是一个模型实例对象:output=keras.models.Model(input,output)。比如构建GAN模型的例子。
 
2.model实例对象的多种使用形式
	1.output = model(input) 
		给model实例对象传入真实的模型输入数据,输出对应的目标数据
		input为真实的模型输入,output为模型输出
	2.model.fit(x=x_train, y=y_train, shuffle=True, epochs=10, batch_size=batch_size, validation_data=(x_test, y_test))
		对model实例对象直接进行fit训练,传入用于训练/验证的模型输入和模型输出,可以同时指定shuffle/epochs/batch_size等
	3.output = Model实例对象2(Model模型实例对象1(input))
 		多个Model实例对象进行嵌套连接在一起构建为一个新的网络模型,即Model模型1的输出作为Model模型2的输入。
		比如GAN模型中,便把生成器网络模型的实例对象和判别器网络模型的实例对象连接在一起构建为一个新的模型,最终返回判别器网络的模型输出。

3.keras.layers.Layer层:output = layers.Conv2D()/layers.Dense()/layers.Conv2DTranspose()/...
  自定义keras.layers.Layer层的形式:
	1.class 自定义类名(keras.layers.Layer):
		def call(self, inputs):
			#可以不使用这个返回输出值,但层必须要有返回值
			return x 
	2.创建自定义Layer层的实例对象:output = 自定义类名(inputs)

4.GAN 生成器网络 和 GAN 判别器网络 的组合
	1.GAN 生成器网络
		#设置模型输入是一个形状为 (latent_dim,)的随机向量(潜在空间中的一个随机点)
		generator_input = keras.Input(shape=(latent_dim,))
		x = layers.Dense(128 * 16 * 16)(generator_input)
		#构建连续多层layers.Dense/layers.LeakyReLU/layers.Conv2D/layers.Reshape等
		......
		#构建生成器模型实例对象:把形状为 (latent_dim,)的随机向量(潜在空间中的一个随机点)作为模型输入,
		#映射到一个包含多层layers的模型输出网络,最终解码为一张形状为 (32, 32, 3) 的合成图像
		generator = keras.models.Model(generator_input, x) 
		#注意此处的generator并没有执行keras.optimizers.RMSprop和compile
		generator.summary()
		_________________________________________________________________
		Layer (type)                 Output Shape              Param #
		=================================================================
		input_1 (InputLayer)         (None, 32)                0
		_________________________________________________________________
		dense_1 (Dense)              (None, 32768)             1081344
		_________________________________________________________________
		leaky_re_lu_1 (LeakyReLU)    (None, 32768)             0
		_________________________________________________________________
		reshape_1 (Reshape)          (None, 16, 16, 128)       0
		_________________________________________________________________
		conv2d_1 (Conv2D)            (None, 16, 16, 256)       819456
		_________________________________________________________________
		leaky_re_lu_2 (LeakyReLU)    (None, 16, 16, 256)       0
		_________________________________________________________________
		conv2d_transpose_1 (Conv2DTr (None, 32, 32, 256)       1048832
		_________________________________________________________________
		leaky_re_lu_3 (LeakyReLU)    (None, 32, 32, 256)       0
		_________________________________________________________________
		conv2d_2 (Conv2D)            (None, 32, 32, 256)       1638656
		_________________________________________________________________
		leaky_re_lu_4 (LeakyReLU)    (None, 32, 32, 256)       0
		_________________________________________________________________
		conv2d_3 (Conv2D)            (None, 32, 32, 256)       1638656
		_________________________________________________________________
		leaky_re_lu_5 (LeakyReLU)    (None, 32, 32, 256)       0
		_________________________________________________________________
		conv2d_4 (Conv2D)            (None, 32, 32, 3)         37635
		=================================================================
		Total params: 6,264,579
		Trainable params: 6,264,579
		Non-trainable params: 0
		_________________________________________________________________

 	2.GAN 判别器网络
		discriminator_input = layers.Input(shape=(height, width, channels))
		x = layers.Conv2D(128, 3)(discriminator_input)
		#构建连续多层layers.Dense/layers.LeakyReLU/layers.Conv2D/layers.Flatten/layers.Dropout等
		......
		#构建判别器模型实例对象:把形状为(32, 32, 3)的图像作为模型输入,映射到一个包含多层layers的模型输出网络,
		#最终转换为一个二进制分类决策(即分类为真/假)
		discriminator = keras.models.Model(discriminator_input, x)
		#clipvalue在优化器中使用梯度裁剪(限制梯度值的范围),decay为了稳定训练过程,使用学习率衰减
		discriminator_optimizer = keras.optimizers.RMSprop(lr=0.0008, clipvalue=1.0, decay=1e-8) 
		discriminator.compile(optimizer=discriminator_optimizer, loss='binary_crossentropy')
		discriminator.summary()
		_________________________________________________________________
		Layer (type)                 Output Shape              Param #
		=================================================================
		input_2 (InputLayer)         (None, 32, 32, 3)         0
		_________________________________________________________________
		conv2d_5 (Conv2D)            (None, 30, 30, 128)       3584
		_________________________________________________________________
		leaky_re_lu_6 (LeakyReLU)    (None, 30, 30, 128)       0
		_________________________________________________________________
		conv2d_6 (Conv2D)            (None, 14, 14, 128)       262272
		_________________________________________________________________
		leaky_re_lu_7 (LeakyReLU)    (None, 14, 14, 128)       0
		_________________________________________________________________
		conv2d_7 (Conv2D)            (None, 6, 6, 128)         262272
		_________________________________________________________________
		leaky_re_lu_8 (LeakyReLU)    (None, 6, 6, 128)         0
		_________________________________________________________________
		conv2d_8 (Conv2D)            (None, 2, 2, 128)         262272
		_________________________________________________________________
		leaky_re_lu_9 (LeakyReLU)    (None, 2, 2, 128)         0
		_________________________________________________________________
		flatten_1 (Flatten)          (None, 512)               0
		_________________________________________________________________
		dropout_1 (Dropout)          (None, 512)               0
		_________________________________________________________________
		dense_2 (Dense)              (None, 1)                 513
		=================================================================
		Total params: 790,913
		Trainable params: 790,913
		Non-trainable params: 0
		_________________________________________________________________

	3.把生成器网络和判别器网络连接在一起构建一个完整的GAN
		#1.将判别器网络的权重设置为不可训练(仅应用于GAN模型),这样在训练时判别器网络的权重便不会更新,
		#  否则在训练时可以对判别器的权重进行更新的话,则会导致训练判别器始终预测“真”,但这并不是想要的效果。
		#2.因为在前面定义判别器网络的时候其trainable默认为True的,此处修改为False之后,因为没有再次执行discriminator.compile,而是执行了gan.compile,
		#  所以并不会影响判别器网络执行discriminator.train_on_batch进行批量训练时更新判别器网络权重的,
		#  仅会影响执行gan.train_on_batch进行批量训练时不会更新判别器网络的权重,
		#  实际gan进行批量训练时是靠所计算的判别器网络的损失和梯度作为反馈来训练生成器网络的。
		discriminator.trainable = False 
		#把形状为 (latent_dim,)的随机向量(潜在空间中的一个随机点)作为模型输入
		gan_input = keras.Input(shape=(latent_dim,)) 
		#把生成器网络模型的实例对象 和 判别器网络模型的实例对象 连接在一起构建为一个新的模型,最终返回判别器网络的模型输出
		gan_output = discriminator(generator(gan_input)) 
		#构建完整的GAN模型:将形状为 (latent_dim,)的随机向量(潜在空间中的一个随机点)作为模型输入,先通过生成器网络输出为(None, 32, 32, 3)的合成图像,
		#然后把生成合成图像输入到判别器网络中,最终模型输出转换为一个分类决策(即分类为真/假)。
		#但要注意的是GAN模型此处训练时的标签虽然都是设置为“真实图像”,但训练的样本实际都是“根据潜在空间中再次进行采样的随机点(随机噪声)所生成的”合成图像,
		#而标签却要标识为“真实图像”,这是在撒谎。训练过程中需要将判别器设置为冻结(即不可训练),这样在训练 gan 时它的权重才不会更新。
		#因此,训练 gan 将会更新生成器的权重,使得判别器在观察假图像时更有可能预测为“真”。
		#如果在此过程中可以对判别器的权重进行更新,那么我们就是在训练判别器始终预测“真”,但这并不是我们想要的!
		#训练时,这个模型将让生成器向某个方向移动,从而提高它欺骗判别器的能力。
		gan = keras.models.Model(gan_input, gan_output)
		gan.summary()
		#clipvalue在优化器中使用梯度裁剪(限制梯度值的范围),decay为了稳定训练过程,使用学习率衰减
		gan_optimizer = keras.optimizers.RMSprop(lr=0.0004, clipvalue=1.0, decay=1e-8)
		gan.compile(optimizer=gan_optimizer, loss='binary_crossentropy')

		_________________________________________________________________
		Layer (type)                 Output Shape              Param #
		=================================================================
		input_3 (InputLayer)         (None, 32)                0
		_________________________________________________________________
		model_1 (Model)              (None, 32, 32, 3)         6264579
		_________________________________________________________________
		model_2 (Model)              (None, 1)                 790913
		=================================================================
		Total params: 7,055,492
		Trainable params: 6,264,579	表示生成器网络权重在训练时会进行更新
		Non-trainable params: 790,913  	表示判别器网络权重在训练时不会进行更新
		_________________________________________________________________

		for layer in gan.layers:
			print(layer.name, layer.trainable)
		#input_3 False
		#model_1 True	表示生成器网络权重在训练时会进行更新
		#model_2 False	表示判别器网络权重在训练时不会进行更新

	4.训练 DCGAN
		import keras
		from keras import layers
		from keras import backend as K
		from keras.models import Model
		import numpy as np
		import os
		from keras.preprocessing import image

		#潜在空间中的一个随机点的维度
		latent_dim = 32
		height = 32
		width = 32
		channels = 3

		#迭代次数
		iterations = 10000
		batch_size = 20
		#指定保存生成图像的目录
		save_dir = 'your_dir'

		#加载 CIFAR10数据
		(x_train, y_train), (_, _) = keras.datasets.cifar10.load_data()
		#只选择青蛙图像(类别编号为6),那么x_train所包含的训练图像便只包含青蛙图像
		x_train = x_train[y_train.flatten() == 6]
		#x_train.shape为(5000, 32, 32, 3),5000个青蛙样本图像,并进行数据标准化
		x_train = x_train.reshape((x_train.shape[0],) +(height, width, channels)).astype('float32') / 255.

		#1.生成器从未直接见过训练集中的图像,它所知道的关于数据的信息都来自于判别器的反馈。
		#2.GAN 学习的潜在空间没有整齐的连续结构,因此可能不适用于某些实际应用,比如通过潜在空间概念向量进行图像编辑。
		start = 0
		for step in range(iterations):
			############################
			#更新判别器网络的损失: 最大化maximize log(D(x)) + log(1 - D(G(z)))
			#	第一步:generator.predict生成器网络根据随机噪音预测生成的合成图像数据,此预测输出数据并不会包含生成器网络这一层本身。
			#	第二步:discriminator.train_on_batch批量训练同时使用真实图片和真实图像标签与合成图像和合成图像标签来训练判别器网络,
			#	        此时会对判别器网络进行计算损失和梯度,以此来优化判别器网络,真正改变调整判别器网络的学习参数。
			############################

			#在潜在空间中采样形状为(20, 32)的随机点(随机噪声),该随机点的形状实际为(latent_dim,)的随机向量
			random_latent_vectors = np.random.normal(size=(batch_size, latent_dim))
			#生成器网络利用这个随机噪声生成合成图像,即将20个潜在空间中的随机点(随机向量)解码为虚假图像。
			#生成器网络模型输入InputLayer接收的数据形状是(20, 32),而输出的数据是(20, 32, 32, 3)形状的合成图像。
			generated_images = generator.predict(random_latent_vectors)
 
			#每次迭代都从x_train中取batch_size个不同的青蛙样本图像
			stop = start + batch_size
			real_images = x_train[start: stop]
			#将生成的(20, 32, 32, 3)形状的合成图像 与 (20, 32, 32, 3)形状的真实图像混合
			#默认axis=0为第一个轴进行合并,即批量大小的该轴上合并为(40, 32, 32, 3)
			combined_images = np.concatenate([generated_images, real_images])
			#使用这些混合后的真假图像以及相应的标签(合成图像为“假”对应值1,真实图像为“真”对应值0)来训练判别器网络		
			labels = np.concatenate([np.ones((batch_size, 1)),np.zeros((batch_size, 1))])
			#向合并标签中添加随机噪声,合成图像对应的标签值为1的变成1.xx左右,真实图像对应的标签值为0的变成0.xx左右
			labels += 0.05 * np.random.random(labels.shape)
			#1.判别器批量进行训练,合并的两种真假图像和真假标签进行训练,返回判别损失
			#2.训练时你可能会看到,对抗损失a_loss开始大幅增加,而判别损失d_loss则趋向于零,即判别器d_loss最终支配了生成器。
			#  如果出现了这种情况,你可以尝试减小判别器的学习率,并增大判别器的 dropout比率。
			d_loss = discriminator.train_on_batch(combined_images, labels)

			############################
			#更新生成器网络的损失: 最大化maximize log(D(G(z)))
			#	1.gan.train_on_batch基于判别器网络的反馈来训练生成器网络,注意此处gan中的判别器网络的权重被冻结了,
			#	  因此判别器网络的权重不会更新,而生成器网络的权重才会更新。
			#	  使用这些随机向量所生成的合成图像和伪造的“真实图像”的标签来最终训练生成器来计算出对应的损失和梯度,
			#	  然后根据这些训练生成器所计算出对应的损失和梯度的反馈来以此训练生成器网络,
			#	  要知道生成器从未直接见过训练集中的图像,它所知道的关于数据的信息都来自于判别器的反馈。
			#	2.在定义判别器网络时,trainable 默认为True的,然后执行的discriminator.compile,
			#	  所以单纯使用discriminator.train_on_batch时是会更新判别器网络的权限的。
			#	3.由于在定义gan模型时,是先执行discriminator.trainable=False,用于冻结判别器网络的权重的,
			#	  但后面并没有执行discriminator.compile,而是执行了gan.compile,
			#	  因此只会影响gan训练中的判别器网络不会更新其权重,而执行discriminator.train_on_batch训练判别器网络时,
			#	  是不会受影响的。
			#	4.因为在前面定义判别器网络的时候其trainable默认为True的,此处修改为False之后,因为没有再次执行discriminator.compile,
			#	  而是执行了gan.compile,所以并不会影响判别器网络执行discriminator.train_on_batch进行批量训练时更新判别器网络权重的,
			#  	  仅会影响执行gan.train_on_batch进行批量训练时不会更新判别器网络的权重,
			#  	  实际gan进行批量训练时是靠所计算的判别器网络的损失和梯度作为反馈来训练生成器网络的。
			###########################

			#同一次的迭代中在潜在空间中再次进行采样形状为(20, 32)的随机点(随机噪声),该随机点的形状实际为(latent_dim,)的随机向量
			random_latent_vectors = np.random.normal(size=(batch_size, latent_dim))
			#设置GAN训练时的标签都是“真实图像”(实际这是在撒谎,GAN训练的样本实际都是“根据潜在空间中再次进行采样的随机点(随机噪声)所生成的”合成图像),
			#同时设置“真实图像”对应的标签值为0
			misleading_targets = np.zeros((batch_size, 1))
			#利用这些由随机向量所生成的合成图像以及全部是“真实图像”的标签(这是在撒谎)来训练 gan。
			#只会更新生成器的权重,而判别器在gan中被冻结,其更新方向是使得判别器能够将合成图像预测为“真实图像”。这个过程是训练生成器去欺骗判别器。
			#通过GAN模型来训练生成器(此时的判别器被冻结了权重),此时对采样随机点(合成图像)和“真”标签(实际为假标签)进行训练,返回对抗损失
			a_loss = gan.train_on_batch(random_latent_vectors, misleading_targets)

			start += batch_size
			if start > len(x_train) - batch_size:
				start = 0

			#每 100 步保存并绘图
			if step % 100 == 0:
				#保存模型权重
				gan.save_weights('gan.h5')

				#将指标打印出来
				print('discriminator loss at step %s: %s' % (step, d_loss))
				print('adversarial loss at step %s: %s' % (step, a_loss))

				#保存一张合成图像
				img = image.array_to_img(generated_images[0] * 255., scale=False)
				img.save(os.path.join(save_dir, 'generated_frog' + str(step) + '.png'))

				#保存一张真实图像,用于对比
				img = image.array_to_img(real_images[0] * 255., scale=False)
				img.save(os.path.join(save_dir, 'real_frog' + str(step) + '.png'))

	5.使用训练好的 DCGAN进行预测
		import matplotlib.pyplot as plt
		#潜在空间中的样本随机点
		random_latent_vectors = np.random.normal(size=(10, latent_dim))
		#解码成假图像
		generated_images = generator.predict(random_latent_vectors)
		for i in range(generated_images.shape[0]):
			img = image.array_to_img(generated_images[i] * 255., scale=False)
			plt.figure()
			plt.imshow(img)
		plt.show()
discriminator loss at step 0: 0.7115288
adversarial loss at step 0: 0.7047467
discriminator loss at step 100: 0.63698226
adversarial loss at step 100: 1.2898037
discriminator loss at step 200: 0.7468196
adversarial loss at step 200: 0.7246065
discriminator loss at step 300: 0.6819771
adversarial loss at step 300: 0.8227237
discriminator loss at step 400: 0.7036969
adversarial loss at step 400: 0.7419513
discriminator loss at step 500: 0.69924504
adversarial loss at step 500: 0.734193
discriminator loss at step 600: 0.69154274
adversarial loss at step 600: 0.7261149
discriminator loss at step 700: 0.7011696
adversarial loss at step 700: 0.7488779
discriminator loss at step 800: 0.68115616
adversarial loss at step 800: 0.7672018
discriminator loss at step 900: 0.6855592
adversarial loss at step 900: 0.74231493
discriminator loss at step 1000: 0.69031733
adversarial loss at step 1000: 0.74285185
discriminator loss at step 1100: 0.6905447
adversarial loss at step 1100: 0.75708795
discriminator loss at step 1200: 0.69429624
adversarial loss at step 1200: 0.7909092
discriminator loss at step 1300: 0.7032337
adversarial loss at step 1300: 0.7317235
discriminator loss at step 1400: 0.70822525
adversarial loss at step 1400: 0.7645156
discriminator loss at step 1500: 0.70326895
adversarial loss at step 1500: 0.7963195
discriminator loss at step 1600: 0.70500505
adversarial loss at step 1600: 0.76147723
discriminator loss at step 1700: 0.68592215
adversarial loss at step 1700: 0.73715556
discriminator loss at step 1800: 0.6949235
adversarial loss at step 1800: 0.7374927
discriminator loss at step 1900: 0.6858417
adversarial loss at step 1900: 0.7386305
discriminator loss at step 2000: 0.70051277
adversarial loss at step 2000: 0.7732838
discriminator loss at step 2100: 0.6938835
adversarial loss at step 2100: 0.74504554
discriminator loss at step 2200: 0.75744766
adversarial loss at step 2200: 0.79670256
discriminator loss at step 2300: 0.68921125
adversarial loss at step 2300: 0.7624829
discriminator loss at step 2400: 0.68788964
adversarial loss at step 2400: 0.73603165
discriminator loss at step 2500: 0.72942907
adversarial loss at step 2500: 0.8500789
discriminator loss at step 2600: 0.7144539
adversarial loss at step 2600: 0.7313472
discriminator loss at step 2700: 0.70036346
adversarial loss at step 2700: 0.7659265
discriminator loss at step 2800: 0.71731293
adversarial loss at step 2800: 0.7386481
discriminator loss at step 2900: 0.6962636
adversarial loss at step 2900: 0.82014436
discriminator loss at step 3000: 0.70221204
adversarial loss at step 3000: 0.7448746
discriminator loss at step 3100: 0.6970533
adversarial loss at step 3100: 0.7414106
discriminator loss at step 3200: 0.7027217
adversarial loss at step 3200: 0.7593067
discriminator loss at step 3300: 0.6974826
adversarial loss at step 3300: 0.77101165
discriminator loss at step 3400: 0.69468534
adversarial loss at step 3400: 0.7360735
discriminator loss at step 3500: 0.6959646
adversarial loss at step 3500: 0.7448656
discriminator loss at step 3600: 0.6926605
adversarial loss at step 3600: 0.7793437
discriminator loss at step 3700: 0.68845165
adversarial loss at step 3700: 0.73707116
discriminator loss at step 3800: 0.6896309
adversarial loss at step 3800: 0.72898376
discriminator loss at step 3900: 0.6803684
adversarial loss at step 3900: 0.8558714
discriminator loss at step 4000: 0.69410855
adversarial loss at step 4000: 0.7726719
discriminator loss at step 4100: 0.69593436
adversarial loss at step 4100: 0.78482276
discriminator loss at step 4200: 0.6936628
adversarial loss at step 4200: 0.77395284
discriminator loss at step 4300: 0.728613
adversarial loss at step 4300: 0.8212582
discriminator loss at step 4400: 0.7129141
adversarial loss at step 4400: 0.7208406
discriminator loss at step 4500: 0.69421184
adversarial loss at step 4500: 0.79397744
discriminator loss at step 4600: 0.6970722
adversarial loss at step 4600: 0.74527484
discriminator loss at step 4700: 0.68375814
adversarial loss at step 4700: 0.74301445
discriminator loss at step 4800: 0.6913597
adversarial loss at step 4800: 0.747694
discriminator loss at step 4900: 0.6858412
adversarial loss at step 4900: 0.78235567
discriminator loss at step 5000: 0.69061077
adversarial loss at step 5000: 0.736558
discriminator loss at step 5100: 0.6893281
adversarial loss at step 5100: 0.6763943
discriminator loss at step 5200: 0.8067726
adversarial loss at step 5200: 0.86751175
discriminator loss at step 5300: 0.6935332
adversarial loss at step 5300: 0.9220335
discriminator loss at step 5400: 0.6804237
adversarial loss at step 5400: 0.8375907
discriminator loss at step 5500: 0.69301045
adversarial loss at step 5500: 0.7437799
discriminator loss at step 5600: 0.6772412
adversarial loss at step 5600: 0.79126954
discriminator loss at step 5700: 0.7131443
adversarial loss at step 5700: 0.7175739
discriminator loss at step 5800: 0.6722745
adversarial loss at step 5800: 0.9802745
discriminator loss at step 5900: 0.7032528
adversarial loss at step 5900: 0.74221563
discriminator loss at step 6000: 0.7101313
adversarial loss at step 6000: 0.7202954
discriminator loss at step 6100: 0.6840765
adversarial loss at step 6100: 0.7130268
discriminator loss at step 6200: 0.6932604
adversarial loss at step 6200: 0.8000577
discriminator loss at step 6300: 0.7109294
adversarial loss at step 6300: 0.76588863
discriminator loss at step 6400: 0.7001274
adversarial loss at step 6400: 0.74738723
discriminator loss at step 6500: 0.6741629
adversarial loss at step 6500: 0.80781347
discriminator loss at step 6600: 0.7539159
adversarial loss at step 6600: 0.42317972
discriminator loss at step 6700: 0.6927122
adversarial loss at step 6700: 0.73476046
discriminator loss at step 6800: 0.6664301
adversarial loss at step 6800: 0.34711856
discriminator loss at step 6900: 0.70018405
adversarial loss at step 6900: 0.73765796
discriminator loss at step 7000: 0.715394
adversarial loss at step 7000: 0.780943
discriminator loss at step 7100: 0.6959831
adversarial loss at step 7100: 0.78711915
discriminator loss at step 7200: 0.6889924
adversarial loss at step 7200: 0.76479584
discriminator loss at step 7300: 0.6871983
adversarial loss at step 7300: 0.74707294
discriminator loss at step 7400: 0.6960098
adversarial loss at step 7400: 0.79496956
discriminator loss at step 7500: 0.74034274
adversarial loss at step 7500: 0.7176825
discriminator loss at step 7600: 0.69009006
adversarial loss at step 7600: 0.75234497
discriminator loss at step 7700: 0.6819211
adversarial loss at step 7700: 0.8833235
discriminator loss at step 7800: 0.6769482
adversarial loss at step 7800: 0.83547515
discriminator loss at step 7900: 0.79681766
adversarial loss at step 7900: 0.5486014
discriminator loss at step 8000: 0.69123125
adversarial loss at step 8000: 0.7945508
discriminator loss at step 8100: 0.698786
adversarial loss at step 8100: 0.752495
discriminator loss at step 8200: 0.700045
adversarial loss at step 8200: 0.74887985
discriminator loss at step 8300: 0.67619663
adversarial loss at step 8300: 0.74648297
discriminator loss at step 8400: 0.70129263
adversarial loss at step 8400: 1.0010253
discriminator loss at step 8500: 0.6581225
adversarial loss at step 8500: 0.79142404
discriminator loss at step 8600: 0.641611
adversarial loss at step 8600: 0.7367972
discriminator loss at step 8700: 0.72519004
adversarial loss at step 8700: 1.2603848
discriminator loss at step 8800: 0.7795755
adversarial loss at step 8800: 1.4261863
discriminator loss at step 8900: 0.6901215
adversarial loss at step 8900: 0.76327527
discriminator loss at step 9000: 0.6633209
adversarial loss at step 9000: 0.79276145
discriminator loss at step 9100: 0.6700674
adversarial loss at step 9100: 0.79978144
discriminator loss at step 9200: 0.71044004
adversarial loss at step 9200: 0.8300269
discriminator loss at step 9300: 0.6278731
adversarial loss at step 9300: 1.067949
discriminator loss at step 9400: 0.7122105
adversarial loss at step 9400: 0.9927448
discriminator loss at step 9500: 0.6827091
adversarial loss at step 9500: 0.7850563
discriminator loss at step 9600: 0.6800372
adversarial loss at step 9600: 0.85021067
discriminator loss at step 9700: 0.70892954
adversarial loss at step 9700: 0.73444927
discriminator loss at step 9800: 0.67502975
adversarial loss at step 9800: 0.89363736
discriminator loss at step 9900: 0.8730275
adversarial loss at step 9900: 0.81281984


PyTorch:GAN生成式对抗网络

import os
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn as nn
import torch
from torch.autograd import Variable
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from PIL import Image
import torchvision.utils as vutils
%matplotlib inline
 
img_size = 64
batch_size=64
lr = 0.0002
beta1 = 0.5
niter= 25
outf= 'output'
 
#加载CIFAR10数据
dataset = datasets.CIFAR10( root = 'data',download=True,
                       transform=transforms.Compose([
                           transforms.Resize(img_size),
                           transforms.ToTensor(),
                           transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                       ]))
dataloader = torch.utils.data.DataLoader(dataset, batch_size, shuffle=True)
 
#latnet向量的大小
nz = 100
#generator过滤器尺寸
ngf = 64
#discriminator过滤器尺寸
ndf = 64
#输出图像通道
nc = 3
 
#网络初始化。在netG和netD上调用自定义权重初始化。
def weights_init(m):
    classname = m.__class__.__name__
    if classname.find('Conv') != -1:
        m.weight.data.normal_(0.0, 0.02)
    elif classname.find('BatchNorm') != -1:
        m.weight.data.normal_(1.0, 0.02)
        m.bias.data.fill_(0)
 	
#1.nn.Conv2d(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True))
#  参数:
#	  in_channel:输入数据的通道数,例RGB图片通道数为3;
#	  out_channel:输出数据的通道数,这个根据模型调整;
#	  kennel_size:卷积核大小,可以是int,或tuple;kennel_size=2,意味着卷积大小2,kennel_size=(2,3),
#			      意味着卷积在第一维度大小为2,在第二维度大小为3;
#	  stride:步长,默认为1,与kennel_size类似,stride=2,意味在所有维度步长为2,stride=(2,3),
#		     意味着在第一维度步长为2,意味着在第二维度步长为3;
#	  padding:零填充
# 
#2.nn.Conv2d(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True))
#  参数:
#	  in_channel:输入数据的通道数,例RGB图片通道数为3;
#	  out_channel:输出数据的通道数,这个根据模型调整;
#	  kennel_size:卷积核大小,可以是int,或tuple;kennel_size=2,意味着卷积大小(2,2),kennel_size=(2,3),
#				意味着卷积大小(2,3) 即非正方形卷积
#	  stride:步长,默认为1,与kennel_size类似,stride=2,意味着步长上下左右扫描皆为2,stride=(2,3),左右扫描步长为2,上下为3;
#	  padding:零填充
 
 
#定义生成网络
class _netG(nn.Module):
    def __init__(self):
        super(_netG, self).__init__()
        self.main = nn.Sequential(
            #输入通道数nz=100(latnet向量的大小),输出通道数64*8=512
            nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(True),
            #输入通道数64*8=512,过滤器大小512x4x4,输出通道数64*4=256
            #上采样为8×8,(步幅2)转置卷积把输入的宽和高都分别放大了2倍
            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(True),
            #输入通道数64*4=256,过滤器大小256x8x8,输出通道数64*2=128
            #上采样为16×16,(步幅2)转置卷积把输入的宽和高都分别放大了2倍
            nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(True),
            #输入通道数64*2=128,过滤器大小128x16x16,输出通道数64
            #上采样为32×32,(步幅2)转置卷积把输入的宽和高都分别放大了2倍
            nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(True),
            #输入通道数64,过滤器大小64x32x32,输出通道数3
            #上采样为64×64,(步幅2)转置卷积把输入的宽和高都分别放大了2倍
            nn.ConvTranspose2d(ngf,nc, 4, 2, 1, bias=False),
            nn.Tanh()
            #最终输出的过滤器大小3x64x64
        )

    def forward(self, input):
        output = self.main(input)
        return output
 
netG = _netG()
netG.apply(weights_init)
print(netG)

#_netG(
#  (main): Sequential(
#    (0): ConvTranspose2d (100, 512, kernel_size=(4, 4), stride=(1, 1), bias=False)
#    (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
#    (2): ReLU(inplace)
#    (3): ConvTranspose2d (512, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True)
#    (5): ReLU(inplace)
#    (6): ConvTranspose2d (256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
#    (8): ReLU(inplace)
#    (9): ConvTranspose2d (128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (10): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
#    (11): ReLU(inplace)
#    (12): ConvTranspose2d (64, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (13): Tanh()
#  )
#)


#定义判别网络
class _netD(nn.Module):
    def __init__(self):
        super(_netD, self).__init__()
        self.main = nn.Sequential(
            #输入通道数3,输出通道数64
            nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            #输入通道数64,过滤器大小64x32x32,输出通道数64*2=128
            #下采样为32×32,(步幅2)步进卷积把输入的宽和高都分别缩小了2倍
            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True),
            #输入通道数128,过滤器大小128x16x16,输出通道数256
            #下采样为16x16,(步幅2)步进卷积把输入的宽和高都分别缩小了2倍
            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            #输入通道数256,过滤器大小256x8x8,输出通道数512 
            #下采样为8x8,(步幅2)步进卷积把输入的宽和高都分别缩小了2倍
            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            #输入通道数512,过滤器大小256x4x4,输出通道数1 
            #下采样为4x4,(步幅2)步进卷积把输入的宽和高都分别缩小了2倍
            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )

    def forward(self, input):
        output = self.main(input)
        return output.view(-1, 1).squeeze(1)
 
netD = _netD()
netD.apply(weights_init)
print(netD)

#_netD(
#  (main): Sequential(
#    (0): Conv2d (3, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (1): LeakyReLU(0.2, inplace)
#    (2): Conv2d (64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
#    (4): LeakyReLU(0.2, inplace)
#    (5): Conv2d (128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (6): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True)
#    (7): LeakyReLU(0.2, inplace)
#    (8): Conv2d (256, 512, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
#    (9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
#    (10): LeakyReLU(0.2, inplace)
#    (11): Conv2d (512, 1, kernel_size=(4, 4), stride=(1, 1), bias=False)
#    (12): Sigmoid()
#  )
#)


#1.torch.normal(means, std, out=None)
#	返回一个张量,包含从给定参数means和std的离散正态分布中抽取随机数。
#	均值means是一个张量,包含每个输出元素相关的正态分布的均值。
#	std是一个张量,包含每个输出元素相关的正态分布的标准差。
#	均值和标准差的形状不须匹配,但每个张量的元素个数须相同。
#	参数:
#		means(Tensor) – 均值
#		std(Tensor) – 标准差
#		out(Tensor) – 可选的输出张量
#	例子:torch.FloatTensor(xx, xx, xx, xx).normal_(0, 1)
#		
#2.torch.normal(mean=0.0, std, out=None)
#	与上面函数类似,所有抽取的样本共享均值。
#	参数:
#		means (Tensor,optional) – 所有分布均值
#		std (Tensor) – 每个元素的标准差
#		out (Tensor) – 可选的输出张量
#
#3.torch.normal(means, std=1.0, out=None)
#	与上面函数类似,所有抽取的样本共享标准差。
#	参数:
#		means (Tensor) – 每个元素的均值
#		std (float, optional) – 所有分布的标准差
#		out (Tensor) – 可选的输出张量

#定义损失函数
criterion = nn.BCELoss()

#判别器模型输入(64,3,64,64)
input = torch.FloatTensor(batch_size, 3, img_size, img_size)
#生成器模型输入(64,100,1,1),随机噪声
noise = torch.FloatTensor(batch_size, nz, 1, 1)
#生成器模型输入(64,100,1,1),均值为0标准差为1的随机噪声
fixed_noise = torch.FloatTensor(batch_size, nz, 1, 1).normal_(0, 1)
label = torch.FloatTensor(batch_size)
#真实图像标签
real_label = 1
#合成图像标签
fake_label = 0

if torch.cuda.is_available():
	netD.cuda()
	netG.cuda()
	criterion.cuda()
	input, label = input.cuda(), label.cuda()
	noise, fixed_noise = noise.cuda(), fixed_noise.cuda()

fixed_noise = Variable(fixed_noise)

#定义判别器优化器
optimizerD = optim.Adam(netD.parameters(), lr, betas=(beta1, 0.999))
#定义生成器优化器
optimizerG = optim.Adam(netG.parameters(), lr, betas=(beta1, 0.999))

#1.除了训练生成新图片外,还有一个可用于分类问题的判别网络。判别网络学习图片的重要特征,
#  在只有有限数量的标签数据可用时,这些特征可用于分类任务。当标签数据有限时,可以训练 GAN,
#  为我们提供一个用于提取特征的分类器,分类器模型可以基于此构建。
#
#2.训练判别器网络
#	1.训练判别网络的损失函数定义为 loss = 最大化maximize log(D(x)) + log(1-D(G(z)))
#		1.判别网络的损失取决于它在真实图片上的表现和它在生成网络生成的伪造图片上的表现。
#		  因此,需要使用真实图片和生成网络生成的伪造图片进行训练。
#		2.log(D(x)):使用真实图片和真实图片标签进行来训练判别网络,得出判别网络在真实图片上的表现。
#		3.log(1-D(G(z))):使用生成器网络生成的伪造图片和伪造图片标签来训练判别网络,得出判别网络在伪造图片上的表现。
#	2.训练生成器网络的损失函数定义为 loss = 最大化maximize log(D(G(z)))
#		log(D(G(z))):使用生成器网络生成的伪造图片和伪造的“真实图片标签”来训练判别网络,并且根据判别网络的反馈来训练生成器网络,
#					  其更新方向是使得判别器能够将合成图像预测为“真实图像”,这个过程是训练生成器去欺骗判别器。

for epoch in range(niter):
	for i, data in enumerate(dataloader, 0):
		############################
		#更新判别器网络的损失: 最大化maximize log(D(x)) + log(1 - D(G(z)))
		#	先是使用真实图片和真实图像标签训练判别器网络,然后使用合成图像和合成图像标签训练判别器网络
		#	第一步:使用真实图片训练判别网络
		#	第二步:使用伪造图片训练判别网络
		#	第三步:单独优化判别器网络
		###########################

		#新一轮的训练判别器网络之前,先把梯度值置为0
		netD.zero_grad()
		#获取遍历的真实图片
		real_cpu, _ = data
		batch_size = real_cpu.size(0)
		if torch.cuda.is_available():
			real_cpu = real_cpu.cuda()
		#真实图片放入到判别器模型输入变量中
		input.resize_as_(real_cpu).copy_(real_cpu)
		#真实图像标签,其值为1
		label.resize_(batch_size).fill_(real_label)
		inputv = Variable(input)
		labelv = Variable(label)

		#使用真实图片和真实图像标签训练判别器网络
		output = netD(inputv)
		errD_real = criterion(output, labelv)
		#计算真实图像和真实图像标签所训练的判别器网络的损失和梯度
		errD_real.backward()
		D_x = output.data.mean()

		#使用伪造图片训练
		#生成器模型输入(64,100,1,1),使用均值为0标准差为1的随机噪声
		noise.resize_(batch_size, nz, 1, 1).normal_(0, 1)
		noisev = Variable(noise)
		#通过生成器网络把随机噪声生成为合成图片,然后使用合成图片和合成图像标签值为0 进行训练判别器网络
		fake = netG(noisev)
		#合成图像标签值为0
		labelv = Variable(label.fill_(fake_label))
		#在判别器网络在训练的时候,不想让生成网络同时也发生训练,因而,通过在判别模型输入上调用detach()方法,
		#把输出的合成图片从生成器网络中脱离出来,即只得到生成器模型输出的合成图片,
		#而不会把生成器这一层网络也包含进来到判别器模型的输入中,那么优化的时候便只能优化到判别器网络,而不会优化到生成器网络。
		output = netD(fake.detach())
		#使用合成图片和合成图像标签值为0 进行训练判别器网络
		errD_fake = criterion(output, labelv)
		#计算合成图像和合成图像标签所训练的判别器网络的损失和梯度
		errD_fake.backward()
		D_G_z1 = output.data.mean()
		errD = errD_real + errD_fake
		#当真实图像和合成图像所训练的判别网络的损失和梯度都均已经计算完成后,然后调用optimizer真正开始训练判别器网络,
		#那么判别器网络便能识别图片的真伪了。optimizerD.step():用于真正改变调整判别器网络的学习参数,
		#而此处仅单独优化判别器网络,而不优化生成器网络,因此判别器的权重会进行更新,而生成器的权重则不会进行更新。
		optimizerD.step()

		############################
		#更新生成器网络的损失: 最大化maximize log(D(G(z)))
		#	第一步:基于判别器网络的反馈来训练生成器网络
		#	第二步:单独优化生成器网络
		###########################

		#新一轮的训练生成器网络之前,先把梯度值置为0
		netG.zero_grad()
		#定义真实图像标签其值为1,但是此处定义的真实图像标签实际是伪造的
		#目的是使用基于合成图像和伪造的“真实图像标签”来进行计算损失和梯度的判别器网络的反馈来训练生成器网络,
		#生成器从未直接见过训练集中的图像,它所知道的关于数据的信息都来自于判别器的反馈。
		labelv = Variable(label.fill_(real_label))   
		#把前面的生成器网络所生成的相同合成图片作为此处判别器网络的模型输入数据,但这一次不执行fake.detach(),
		#即不再把输出的合成图片从生成器网络中脱离出来,也即输出的合成图片和所包含的生成器网络都一起作为判别器网络的模型输入,
		#因为我们希望生成器网络能得到训练和优化。
		output = netD(fake)
		errG = criterion(output, labelv)
		#计算合成图像和伪造的“真实图像标签”基于判别器网络的损失和梯度,目的是使用基于判别器网络的反馈来训练生成器网络
		errG.backward()
		D_G_z2 = output.data.mean()
		#当计算好判别器网络的损失和梯度之后,由于此处只想让生成网络得到训练和优化,对判别器网络不想进行训练和优化,
		#而且目的是使用基于判别器网络的反馈来训练生成器网络,因此最终仅需要调用生成器网络的优化器,
		#仅单独优化生成器网络,而不优化判别器网络,用于真正改变调整生成器网络的学习参数,
		#因此生成器的权重会进行更新,而判别器的权重则不会进行更新。
		#如果此时对判别器的权重也同时进行更新的话,则会导致训练判别器始终预测为“真”,但这并不是想要的效果。
		#使用这些随机向量所生成的合成图像和伪造的“真实图像”的标签来最终训练判别器,
		#其更新方向是使得判别器能够将合成图像预测为“真实图像”,这个过程是训练生成器去欺骗判别器。
		#在生成网络生成略微真实的图片之前,把整个过程重复迭代好几次。
		optimizerG.step()

		print('[%d/%d][%d/%d] Loss_D: %.4f Loss_G: %.4f D(x): %.4f D(G(z)): %.4f / %.4f'
		        % (epoch, niter, i, len(dataloader), errD.data[0], errG.data[0], D_x, D_G_z1, D_G_z2))
		if i % 100 == 0:
			#vutils.save_image 将接受一个张量并保存为图片。如果提供的是小批量的图片,就保存为图片网格。
			vutils.save_image(real_cpu, '%s/real_samples.png' % outf, normalize=True)
		         #生成网络根据均值为0标准差为1的随机噪声生成合成图像,要求此处的生成网络生成略微真实的图片之前,都要把整个过程重复迭代好几次。
			fake = netG(fixed_noise)
			vutils.save_image(fake.data, '%s/fake_samples_epoch_%03d.png' % (outf, epoch), normalize=True)


密集连接网络、卷积网络、深度可分离卷积、循环网络


前馈网络

发布了225 篇原创文章 · 获赞 111 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/zimiao552147572/article/details/104084230
今日推荐