def fit(
        self,
        img_data,
        save_freq=-1,
        pic_freq=-1,
        n_epochs=100,
        batch_size=50,
        weight_decay=True,
        model_path='./GAN_training_model/',
        img_path='./GAN_training_images/',
        img_out_width=10,
        mirroring=False
    ):
        '''Fit the GAN model to the image data.

        Parameters
        ----------

        img_data : array-like shape (n_images, n_colors, image_width, image_height)
            Images used to fit VAE model.
        save_freq [optional] : int
            Sets the number of epochs to wait before saving the model and optimizer states.
            Also saves image files of randomly generated images using those states in a
            separate directory. Does not save if negative valued.
        pic_freq [optional] : int
            Sets the number of batches to wait before displaying a picture or randomly
            generated images using the current model state.
            Does not display if negative valued.
        n_epochs [optional] : int
            Gives the number of training epochs to run through for the fitting
            process.
        batch_size [optional] : int
            The size of the batch to use when training. Note: generally larger
            batch sizes will result in fater epoch iteration, but at the const
            of lower granulatity when updating the layer weights.
        weight_decay [optional] : bool
            Flag that controls adding weight decay hooks to the optimizer.
        model_path [optional] : str
            Directory where the model and optimizer state files will be saved.
        img_path [optional] : str
            Directory where the end of epoch training image files will be saved.
        img_out_width : int
            Controls the number of randomly genreated images per row in the output
            saved imags.
        mirroring [optional] : bool
            Controls whether images are randomly mirrored along the verical axis with
            a .5 probability. Artificially increases images variance for training set.
        '''
        width = img_out_width
        self.dec_opt.setup(self.dec)
        self.disc_opt.setup(self.disc)

        if weight_decay:
            self.dec_opt.add_hook(chainer.optimizer.WeightDecay(0.00001))
            self.disc_opt.add_hook(chainer.optimizer.WeightDecay(0.00001))

        n_data = img_data.shape[0]

        batch_iter = list(range(0, n_data, batch_size))
        n_batches = len(batch_iter)

        c_samples = np.random.standard_normal((width, self.latent_width)).astype(np.float32)
        save_counter = 0

        for epoch in range(1, n_epochs + 1):
            print('epoch: %i' % epoch)
            t1 = time.time()
            indexes = np.random.permutation(n_data)
            last_loss_dec = 0.
            last_loss_disc = 0.
            count = 0
            for i in tqdm.tqdm(batch_iter):
                x = img_data[indexes[i: i + batch_size]]
                size = x.shape[0]
                if mirroring:
                    for j in range(size):
                        if np.random.randint(2):
                            x[j, :, :, :] = x[j, :, :, ::-1]
                x_batch = Variable(x)
                zeros = Variable(np.zeros(size, dtype=np.int32))
                ones = Variable(np.ones(size, dtype=np.int32))

                if self.flag_gpu:
                    x_batch.to_gpu()
                    zeros.to_gpu()
                    ones.to_gpu()

                disc_samp, disc_batch = self._forward(x_batch)

                L_dec = F.softmax_cross_entropy(disc_samp, ones)

                L_disc = F.softmax_cross_entropy(disc_samp, zeros)
                L_disc += F.softmax_cross_entropy(disc_batch, ones)
                L_disc /= 2.

                self.dec_opt.zero_grads()
                L_dec.backward()
                self.dec_opt.update()

                self.disc_opt.zero_grads()
                L_disc.backward()
                self.disc_opt.update()

                last_loss_dec += L_dec.data
                last_loss_disc += L_disc.data
                count += 1
                if pic_freq > 0:
                    assert type(pic_freq) == int, "pic_freq must be an integer."
                    if count % pic_freq == 0:
                        fig = self._plot_img(
                            c_samples,
                            img_path=img_path,
                            epoch=epoch
                        )
                        display(fig)

            if save_freq > 0:
                save_counter += 1
                assert type(save_freq) == int, "save_freq must be an integer."
                if epoch % save_freq == 0:
                    name = "gan_epoch%s" % str(epoch)
                    if save_counter == 1:
                        save_meta = True
                    else:
                        save_meta = False
                    self.save(model_path, name, save_meta=save_meta)
                    fig = self._plot_img(
                        c_samples,
                        img_path=img_path,
                        epoch=epoch,
                        batch=n_batches,
                        save_pic=True
                        )

            msg = "dec_loss = {0} , disc_loss = {1}"
            print(msg.format(last_loss_dec/n_batches, last_loss_disc/n_batches))
            t_diff = time.time()-t1
            print("time: %f\n\n" % t_diff)