<jupyter_start><jupyter_text>Basic GAN class<jupyter_code>class GAN():
    def __init__(self):
        self.G, self.D, self.GD = None, None, None
        self.trn_dl, self.val_dl = None, None
        self.bs, self.n_batches, self.noise_shape = None, None, None
        self.epoch_counter = 0
        self.train_hist = defaultdict(list)
    
    def compile(self, opt=Adam(0.0002, 0.5)): 
        """Compile G and D and create GD"""
        # Compile individual models
        self.G.compile(opt, 'binary_crossentropy')   # Loss does not matter
        self.D.compile(opt, 'binary_crossentropy')
        
        # Create and compile combined model
        self.D.trainable = False
        inp_noise = Input(shape=(self.noise_shape,))
        self.GD = Model(inputs=inp_noise, outputs=self.D(self.G(inp_noise)))
        self.GD.compile(opt, 'binary_crossentropy')
    
    def train(self, n_epochs):
        """Training loop"""
        pbar = tqdm(total=n_epochs * self.n_batches)
        for e in range(self.epoch_counter, self.epoch_counter + n_epochs):
            losses = []
            for b in range(self.n_batches):
                pbar.update(1)
                losses.append(self.train_step())
            self.train_hist['trn_d_loss'].append(np.array(losses)[0].mean())
            self.train_hist['trn_g_loss'].append(np.array(losses)[1].mean())
            pbar_dict = OrderedDict(
                {k: v[-1] for k, v in self.train_hist.items()})
            pbar.set_postfix(pbar_dict)
            self.epoch_counter += 1
    
    def train_step(self):
        """Take one training step: 1) Train D on real/fake; 2) Train G
        Terminology: x (not yet) -> G -> y -> D -> label
        """
        # Step 1: Train discriminator
        d_loss = self.train_D()
        # Step 2: Train generator
        g_loss = self.train_G()
        return d_loss, g_loss
    
    def train_D(self):
        """Train discriminator and real/fake
        Labels: real = 1, fake = 0
        """
        # Load real and create fake images
        x_real, y_real = next(self.trn_dl)
        y_fake = self.G.predict_on_batch(self.noise(self.bs))
        
        # Concatenate
        y_concat = np.concatenate([y_real, y_fake])
        labels_concat = np.array([1]*self.bs + [0]*self.bs)
        
        # Train
        self.D.trainable = True
        return self.D.train_on_batch(y_concat, labels_concat)
    
    def train_G(self):
        """Train generator"""
        self.D.trainable = False
        return self.GD.train_on_batch(self.noise(self.bs*2), np.array([1]*self.bs*2))
        
    def noise(self, n_samples): return np.random.normal(size=(n_samples, self.noise_shape))
gan = GAN()
gan.bs = bs
gan.trn_dl = trn_gen
gan.n_batches = 100
gan.noise_shape = x_shape
gan.G = Sequential([
    Dense(256, input_shape=(x_shape,)),
    LeakyReLU(0.2),
    Dense(128),
    LeakyReLU(0.2),
    Dense(y_shape)
])
gan.D = Sequential([
    Dense(256, input_shape=(y_shape,)),
    LeakyReLU(0.2),
    Dense(128),
    LeakyReLU(0.2),
    Dense(1, activation='sigmoid')
])
gan.compile()
gan.train(20)
plot_samples()
gan.train(20)
plot_samples()
gan.train(20)
plot_samples()
gan.train(20)
plot_samples()
gan.train(2000)
plot_samples()
plot_samples()
fake = gan.G.predict_on_batch(gan.noise(10))
gan.D.predict_on_batch(fake)
gan.D.predict_on_batch(y)
for i in range(4): plt.plot(y[i])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13546870408463121, 'fraction_numerical': 0.01851307669703203, 'mean_word_length': 2.5238095238095237, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '78106', 'license': 'MIT', 'n_tokens_mistral': 1257, 'n_tokens_neox': 1210, 'n_words': 232, 'path': 'notebooks/dev/CGAN.ipynb', 'repo_name': 'ankitesh97/CBRAIN-CAM', 'size': '3403'}