我在 Keras 中有一个条件生成对抗网络 (CGAN) 模型:
from keras.datasets import mnistfrom keras.layers import Input, Dense, Reshape, Flatten, Embedding, BatchNormalization, Dropout, multiplyfrom keras.layers.advanced_activations import LeakyReLUfrom keras.models import Sequential, Modelfrom keras.optimizers import Adamimport matplotlib.pyplot as pltimport tensorflow as tfimport keras as Kimport numpy as npimport sys, osimport warningswarnings.filterwarnings('ignore')if not os.path.exists('images'): os.makedirs('images')class GAN(object): def __init__(self, width=28, height=28, channels=1, latent_dim=100, lr=0.0002): self.WIDTH = int(width) # 输入图像的宽度 self.HEIGHT = int(height) # 输入图像的高度 self.CHANNELS = int(channels) # 图像中的颜色通道数 self.SHAPE = (self.WIDTH, self.HEIGHT, self.CHANNELS) self.LATENT_DIM = latent_dim # 用于建模潜在空间(=噪声)的向量长度 self.N_CLASSES = 10 # 数据中可能的总类别数 self.OPTIMIZER = Adam(lr, 0.5) # 生成器 self.G = self.generator() self.G.compile(loss='binary_crossentropy', optimizer=self.OPTIMIZER) # 判别器 self.D = self.discriminator() self.D.compile(loss='binary_crossentropy', optimizer=self.OPTIMIZER, metrics=['accuracy']) self.D.trainable = False # 防止堆叠的 D 进行训练;https://github.com/eriklindernoren/Keras-GAN/issues/73 # 堆叠的生成器 + 判别器 self.stacked_G_D = self.stacked_G_D() self.stacked_G_D.compile(loss='binary_crossentropy', optimizer=self.OPTIMIZER) def generator(self): noise = Input((self.LATENT_DIM,), name='generator_noise') # 允许 g 创建不同的输出 label = Input((1,), name='generator_conditional', dtype='int32') # 允许 g 从一个类别中创建样本 # 在潜在维度大小中嵌入标签 h = Embedding(self.N_CLASSES, self.LATENT_DIM, input_length=1)(label) label_embedding = Flatten()(h) # 统一模型 h = multiply([noise, label_embedding]) h = Dense(256)(h) h = LeakyReLU(alpha=0.2)(h) h = BatchNormalization(momentum=0.8)(h) h = Dense(512)(h) h = LeakyReLU(alpha=0.2)(h) h = BatchNormalization(momentum=0.8)(h) h = Dense(1024)(h) h = LeakyReLU(alpha=0.2)(h) h = BatchNormalization(momentum=0.8)(h) h = Dense(np.prod(self.SHAPE), activation='tanh')(h) o = Reshape((self.WIDTH, self.HEIGHT, self.CHANNELS))(h) model = Model(inputs=[noise, label], outputs=[o]) model.summary() return model def discriminator(self): image = Input((self.SHAPE)) label = Input((1,), dtype='int32') # 在图像形状(平铺)中嵌入标签 h = Embedding(self.N_CLASSES, np.prod(self.SHAPE), input_length=1)(label) label_embedding = Flatten()(h) # 解析图像 img = Flatten()(image) # 统一模型 h = multiply([img, label_embedding]) h = Dense(512)(h) h = LeakyReLU(alpha=0.2)(h) h = Dense(512)(h) h = LeakyReLU(alpha=0.2)(h) h = Dropout(0.4)(h) h = Dense(512)(h) h = LeakyReLU(alpha=0.2)(h) h = Dropout(0.4)(h) o = Dense(1, activation='sigmoid')(h) model = Model(inputs=[image, label], outputs=[o]) model.summary() return model def stacked_G_D(self): noise = Input((self.LATENT_DIM,)) # 噪声输入 label = Input((1,)) # 条件输入 img = self.G([noise, label]) valid = self.D([img, label]) model = Model(inputs=[noise, label], outputs=[valid]) model.summary() return model def train(self, X_train, Y_train, epochs=20000, batch=32, save_interval=100): for i in range(epochs): # 训练判别器 idx = np.random.randint(0, X_train.shape[0], batch) imgs, labels = X_train[idx], Y_train[idx] noise = np.random.normal(0, 1, (batch, self.LATENT_DIM)) fake_imgs = self.G.predict([noise, labels]) d_loss_real = self.D.train_on_batch([imgs, labels], np.ones((batch, 1))) d_loss_fake = self.D.train_on_batch([fake_imgs, labels], np.zeros((batch, 1))) d_loss = (np.add(d_loss_real, d_loss_fake)) * 0.5 # 训练生成器 sample_labels = np.random.randint(0, 10, batch).reshape(batch, 1) g_loss = self.stacked_G_D.train_on_batch([noise, sample_labels], np.ones((batch, 1))) if i % save_interval == 0: print('epoch: {0} - disc loss: {1}, disc accuracy: {2}, gen loss: {2}'.format(i, d_loss[0], d_loss[1]*100, g_loss)) filename = 'mnist_{0}-{1}-{2}.png'.format(i, d_loss[0], g_loss) self.plot_images(save_to_disk=True, filename=filename) def plot_images(self, save_to_disk=False, n_images=10, filename=None, rows=2, size_scalar=4, class_arr=None): if not filename: filename = 'mnist.png' noise = np.random.normal(0, 1, (n_images, self.LATENT_DIM)) classes = class_arr if class_arr is not None else np.arange(0, n_images) % self.N_CLASSES images = self.G.predict([noise, classes]) cols = np.ceil(n_images/rows) # 网格中的列数 fig = plt.figure(figsize=(cols*size_scalar, rows*size_scalar)) for i in range(n_images): ax = fig.add_subplot(rows, np.ceil(n_images/rows), i+1) image = np.reshape(images[i], [28, 28]) plt.imshow(image) fig.subplots_adjust(hspace=0, wspace=0) if save_to_disk: fig.savefig(os.path.join('images', filename)) plt.close('all') else: fig.show()(X_train, Y_train), (_, _) = mnist.load_data()X_train = (X_train.astype(np.float32) - 127.5) / 127.5 # 重新缩放到 {-1 to 1}X_train = np.expand_dims(X_train, axis=3)gan = GAN()gan.train(X_train, Y_train)
我的目标是定期冻结判别器,使其无法学习。(这是为了进行一些实验性工作。)然而,我无法找到在编译模型后实际更新 gan.D
的 .trainable
属性的方法。我尝试过定期手动更改该属性,但无论如何,判别器仍在继续学习。
实际上,在编译模型后可以更新模型的 trainable
属性吗?如果可以,我将非常感激能提供一个简单的示例来说明如何实现这一点!
回答:
啊,你可以在编译模型后更新模型的 .trainable
属性,你只需要重新编译模型即可: