7 z) _7 E+ w9 q5 v* ?% D# n6 g5 @# 注意 `tf.function` 的使用) w' \9 M# x$ ~8 ], i' \/ C
# 该注解使函数被“编译”, K, h0 v3 p' ?5 V
@tf.function0 m* W9 |0 w; Q" E) J* t7 y' Y
def train_step(images): & ]7 P6 U! S1 m; o noise = tf.random.normal([BATCH_SIZE, noise_dim]) / b& ]8 } c: c! c- ?! u" p1 l% p9 ? , R. M4 p) J. ?, h
with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:6 X5 c1 e! _: ^1 p. r, X
generated_images = generator(noise, training=True)( _) U/ y7 ^0 B- e7 w& q
% u& N2 q9 ?" C M% |2 \- L
real_output = discriminator(images, training=True)8 |& `; r2 U& d; ~) I* h+ e
fake_output = discriminator(generated_images, training=True). |: z( g0 p5 {6 S: j
4 F$ n% E) n7 ?/ ~: g7 X2 F' b
gen_loss = generator_loss(fake_output)/ E; O) |; a! Q7 U- v( ^+ A1 a6 Z
disc_loss = discriminator_loss(real_output, fake_output): i+ Z7 v- I( o! o# M4 B
: L2 a) o( }! J7 C
gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)7 |9 J! K& W4 ?( H* ?) V: G2 @0 K* k
gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)" o) I. ]1 z) w0 f) m
# L* C) D: F/ ]1 F) v$ S7 G9 m
generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))0 E/ v( x7 y" n' {0 p: v1 B5 M8 q
discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))0 u' Z8 L- \ M# ?; C, ^( c+ N8 l
. h2 f) M, w8 x0 B" V9 F, @, zdef train(dataset, epochs): ! W: r9 _" {; A9 A for epoch in range(epochs): ! ]/ x- \0 {3 r# _7 [' b start = time.time()( Y8 v5 \. F: y# E! q6 h) [
: M$ {5 E! m! z* y/ { for image_batch in dataset:# |$ O3 Y) q% w- O8 E) n& A$ A. ]
train_step(image_batch)* z# q! s! F/ J% I8 F
' x$ X$ }, m0 g
# 继续进行时为 GIF 生成图像 ! z n# n6 E# ]5 u4 N: L display.clear_output(wait=True)# a% Y4 I2 q% [, d& t
generate_and_save_images(generator,5 }# @% Z" L$ d1 ]/ O+ s
epoch + 1, U0 a7 Q. z* p8 B/ q9 Y$ B0 D, T
seed)8 c9 |2 `( { L: S
, b+ g* z: I9 D, t
# 每 15 个 epoch 保存一次模型 4 L/ v( K* g$ i5 R2 W if (epoch + 1) % 15 == 0: # H' F3 ?0 W3 l) v4 A4 w checkpoint.save(file_prefix = checkpoint_prefix)! v3 Y$ g( b* P/ ^& a9 q- V
5 Z0 x0 m: S& d5 D3 s print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start)) x# U1 K4 o' s- f m( ~% x
) X7 y. x1 H0 {3 X1 p$ p # 最后一个 epoch 结束后生成图片. N- N1 V9 K& j/ W. E- a9 ~
display.clear_output(wait=True)2 j+ v& k; {& \9 o6 J; k( a' T9 l3 n) L
generate_and_save_images(generator,0 r7 c5 [1 H$ b& r, M* s6 T: p X4 @
epochs, S$ ?6 s! ~8 p# P* C6 | seed) * c3 t6 u/ U' r: ^" h- _- G 9 s" N y3 P! t* }- m* I# 生成与保存图片" n7 b' Z, o3 ?7 |* _) r
def generate_and_save_images(model, epoch, test_input): & r3 D9 }. ]7 H" y # 注意 training` 设定为 False9 t. s5 W4 ~% i
# 因此,所有层都在推理模式下运行(batchnorm)。# ]* r2 p& D9 \4 ~
predictions = model(test_input, training=False)- J, b( `6 \" v+ ?1 [- O: e
1 y N; D' i8 Z" [% G fig = plt.figure(figsize=(4,4))- v* n5 w/ }, c; W+ A: |
6 G4 a" V$ b9 i7 F* ~( m/ i for i in range(predictions.shape[0]): 0 h, E |. H" E$ ^9 X plt.subplot(4, 4, i+1) ) c0 [( n, X' _+ ~2 H plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')' M7 o) G) }( E0 n; M
plt.axis('off')/ e7 ~5 \* I% E7 X
$ b2 \ c" ~1 i) A9 f1 \" Q% m
plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))" b5 ]# j8 ^" E: m2 W5 s
plt.show()7 C3 X/ [* C' p- s
5.3 训练模型4 h( z! P' ~5 M" ?1 j8 H
调用上面定义的train()函数,来同时训练生成器和判别器。% m3 l# ^- [. [* C
2 ?% K* `# S' y0 b7 D9 }
( @1 H) u% F! j" Q/ s! _
注意,训练GAN可能比较难的;生成器和判别器不能互相压制对方,需要两种达到平衡,它们用相似的学习率训练。& l1 ]3 k7 h5 X+ [
* `, }2 A% r6 c: h7 u+ ?! L5 c) G+ a. ^) r
%%time. o+ r, d9 d. s/ Q* `: w" I( c0 }
train(train_dataset, EPOCHS)8 T |& B w( `5 f
在刚开始训练时,生成的图片看起来很像随机噪声,随着训练过程的进行,生成的数字越来越真实。训练大约50轮后,生成器生成的图片看起来很像MNIST数字了。 8 I; q2 j7 E+ s. `2 s, q 2 p/ w- e3 i* X : ^+ n6 I6 s$ N6 C |+ a; a* k0 K训练了15轮的效果: , G" `0 {1 ~, X4 @% O5 R- {5 B& H. `) |7 O' S/ w6 d1 j: W
5 K; C- C+ L# O) d5 B/ B, @- I/ _
5 A! i+ S( g: Z8 |$ i- b* B, o0 Q8 c % J8 n O, R% P5 k$ n/ N; x% |, G% {* U/ J E. I
$ w- f k, _7 y! Z w8 N
训练了30轮的效果:$ z- c s |) j/ |# [/ j# K/ s
3 \' A- S/ ]" k! Y
3 k# e4 a/ d( M, D) M r7 O