Esempio n. 1
0
class Solver(object):
    """Solver for training and testing StarGAN."""
    def __init__(self, data_loader, config):
        """Initialize configurations."""

        # Data loader.
        self.data_loader = data_loader

        # Model configurations.
        self.c_dim = config.c_dim

        self.image_size = config.image_size
        self.g_conv_dim = config.g_conv_dim
        self.d_conv_dim = config.d_conv_dim
        self.g_repeat_num = config.g_repeat_num
        self.d_repeat_num = config.d_repeat_num
        self.lambda_app = config.lambda_app
        self.lambda_pose = config.lambda_pose
        self.lambda_rec = config.lambda_rec
        self.lambda_gp = config.lambda_gp

        # Training configurations.
        # self.dataset = config.dataset
        self.batch_size = config.batch_size
        self.num_iters = config.num_iters
        self.num_iters_decay = config.num_iters_decay
        self.g_lr = config.g_lr
        self.d_lr = config.d_lr
        self.n_critic = config.n_critic
        self.beta1 = config.beta1
        self.beta2 = config.beta2
        self.resume_iters = config.resume_iters
        # self.selected_attrs = config.selected_attrs

        # loss functions
        self.feature_loss = torch.nn.CosineEmbeddingLoss()
        self.pose_loss = torch.nn.PairwiseDistance()

        # Test configurations.
        self.test_iters = config.test_iters

        # Miscellaneous.
        self.use_tensorboard = config.use_tensorboard
        self.device = torch.device(
            'cuda' if torch.cuda.is_available() else 'cpu')

        # Directories.
        self.log_dir = config.log_dir
        self.sample_dir = config.sample_dir
        self.model_save_dir = config.model_save_dir
        self.result_dir = config.result_dir

        # Step size.
        self.log_step = config.log_step
        self.sample_step = config.sample_step
        self.model_save_step = config.model_save_step
        self.lr_update_step = config.lr_update_step

        # Build the model and tensorboard.
        self.build_model()
        if self.use_tensorboard:
            self.build_tensorboard()

    def build_model(self):
        """Create a generator and a discriminator."""

        self.G = Generator(self.g_conv_dim, self.c_dim, self.g_repeat_num)
        self.D = Discriminator(self.image_size, self.d_conv_dim, self.c_dim,
                               self.d_repeat_num)

        self.g_optimizer = torch.optim.Adam(self.G.parameters(), self.g_lr,
                                            [self.beta1, self.beta2])
        self.d_optimizer = torch.optim.Adam(self.D.parameters(), self.d_lr,
                                            [self.beta1, self.beta2])
        self.print_network(self.G, 'G')
        self.print_network(self.D, 'D')

        self.G.to(self.device)
        self.D.to(self.device)
        """Build the feature extractor"""
        self.feature_model = f_model(model_path=DUMPED_MODEL,
                                     freeze_param=True).cuda()  #.cuda()
        self.feature_model.eval()

    def print_network(self, model, name):
        """Print out the network information."""
        num_params = 0
        for p in model.parameters():
            num_params += p.numel()
        print(model)
        print(name)
        print("The number of parameters: {}".format(num_params))

    def restore_model(self, resume_iters):
        """Restore the trained generator and discriminator."""
        print(
            'Loading the trained models from step {}...'.format(resume_iters))
        G_path = os.path.join(self.model_save_dir,
                              '{}-G.ckpt'.format(resume_iters))
        D_path = os.path.join(self.model_save_dir,
                              '{}-D.ckpt'.format(resume_iters))
        self.G.load_state_dict(
            torch.load(G_path, map_location=lambda storage, loc: storage))
        self.D.load_state_dict(
            torch.load(D_path, map_location=lambda storage, loc: storage))

    def build_tensorboard(self):
        """Build a tensorboard logger."""
        from logger import Logger
        self.logger = Logger(self.log_dir)

    def update_lr(self, g_lr, d_lr):
        """Decay learning rates of the generator and discriminator."""
        for param_group in self.g_optimizer.param_groups:
            param_group['lr'] = g_lr
        for param_group in self.d_optimizer.param_groups:
            param_group['lr'] = d_lr

    def reset_grad(self):
        """Reset the gradient buffers."""
        self.g_optimizer.zero_grad()
        self.d_optimizer.zero_grad()

    def normalize(self, x):
        pass

    def denorm(self, x):
        """Convert the range from [-1, 1] to [0, 1]."""
        out = (x + 1) / 2
        return out.clamp_(0, 1)

    def gradient_penalty(self, y, x):
        """Compute gradient penalty: (L2_norm(dy/dx) - 1)**2."""
        weight = torch.ones(y.size()).to(self.device)
        dydx = torch.autograd.grad(outputs=y,
                                   inputs=x,
                                   grad_outputs=weight,
                                   retain_graph=True,
                                   create_graph=True,
                                   only_inputs=True)[0]

        dydx = dydx.view(dydx.size(0), -1)
        dydx_l2norm = torch.sqrt(torch.sum(dydx**2, dim=1))
        return torch.mean((dydx_l2norm - 1)**2)
        pass

    def feat_extract(self, resized_data):
        # input: N * 3 * 224 * 224
        resized_data = resized_data.to(self.device)  #.cuda()
        # output: N * num_classes, N * inter_dim, N * C' * 7 * 7
        out, inter_out, x = self.feature_model(resized_data)
        # return batch feature vector
        return out.clamp_(0, 1)

    def pose_extract(self, batch_img, bbx=None):
        # input [N, 224, 224, 3] in RGB
        # output [N, 2, 18]
        # permute = [2, 1, 0]
        # # crop_batch = np.zeros(shape=())
        # for i in range(batch_img.shape[0]):
        #     img = crop(batch_img[i], bbx[i])
        #     # RGB TO BGR
        #     img = img[:, permute, : , :]
        #     crop_batch[i, :, :] = img
        # pose_vectors = get_batch_body_vector(crop_batch.numpy())

        batch_img = np.transpose(batch_img, (0, 2, 3, 1))
        # print(batch_img.shape)
        pose_vectors = get_batch_body_vector(batch_img)
        pose_vectors = torch.from_numpy(pose_vectors)
        return pose_vectors

    def appreance_cos_similarity(self, feat_fake, feat_real):
        label = torch.ones(feat_real.shape[0]).cuda()
        cos_simi = self.feature_loss(feat_real, feat_fake, label)
        return cos_simi

    def compute_pose_loss(self, pose_fake, pose_real, mask):
        mask = mask.view(-1, 1, 18).double()
        pose_fake = torch.mul(pose_fake, mask)
        pose_real = torch.mul(pose_real.double(), mask)
        distance = self.pose_loss(pose_real, pose_fake)
        return distance.float().sum()

    def train(self):
        """Train StarGAN within a single dataset."""

        # Fetch fixed inputs for debugging.
        data_iter = iter(self.data_loader)
        a_fixed, b_fixed, bbox_fixed, b_fixed_pose_feat, mask_fixed = next(
            data_iter)
        a_fixed = a_fixed.to(self.device)
        b_fixed = b_fixed.to(self.device)
        bbox_fixed = bbox_fixed.to(self.device)
        # c_fixed_list = self.create_labels(c_org, self.c_dim, self.dataset, self.selected_attrs)

        # Learning rate cache for decaying.
        g_lr = self.g_lr
        d_lr = self.d_lr

        # Start training from scratch or resume training.
        start_iters = 0
        if self.resume_iters:
            start_iters = self.resume_iters
            self.restore_model(self.resume_iters)

        # Start training.
        print('Start training...')
        start_time = time.time()
        for step in range(start_iters, self.num_iters):

            # =================================================================================== #
            #                             1. Preprocess input data                                #
            # =================================================================================== #

            # Fetch real images and labels.
            try:
                a_real, b_real, bbox, b_pose_feat, mask = next(data_iter)
            except:
                data_iter = iter(self.data_loader)
                a_real, b_real, bbox, b_pose_feat, mask = next(data_iter)

            a_real = a_real.to(self.device)  # Input images.
            b_real = b_real.to(self.device)
            bbox = bbox.to(self.device)
            b_pose_feat = b_pose_feat.to(self.device)
            mask = mask.to(self.device)

            # extract appearance feature
            a_app_feat = self.feat_extract(a_real)
            a_app_feat = a_app_feat.to(self.device)

            # # extract pose feature
            # b_pose_feat = self.pose_extract(b_real)

            # =================================================================================== #
            #                             2. Train the discriminator                              #
            # =================================================================================== #

            # Compute loss with real images.
            out_src = self.D(b_real)
            d_loss_real = -torch.mean(out_src)
            # d_loss_cls = self.classification_loss(out_cls, label_org, self.dataset)

            # Compute loss with fake images.
            # con_feat = torch.cat([a_app_feat, bbox/416.0], dim=1)
            con_feat = a_app_feat

            x_fake = self.G(b_real, con_feat)
            out_src = self.D(x_fake.detach())
            d_loss_fake = torch.mean(out_src)
            # fake_app_feat = self.feat_extract(x_fake)
            # fake_pose_feat = self.pose_extract(x_fake, bbox)
            # d_loss_app = self.appreance_cos_similarity(fake_app_feat, a_app_feat)
            # d_loss_pose = - self.pose_loss(fake_pose_feat, b_pose_feat)

            # Compute loss for gradient penalty.
            alpha = torch.rand(b_real.size(0), 1, 1, 1).to(self.device)
            x_hat = (alpha * b_real.data +
                     (1 - alpha) * x_fake.data).requires_grad_(True)
            out_src = self.D(x_hat)
            d_loss_gp = self.gradient_penalty(out_src, x_hat)

            # Backward and optimize.
            # d_loss = d_loss_real + d_loss_fake + self.lambda_app * d_loss_cls + self.lambda_gp * d_loss_gp
            # d_loss = d_loss_fake + d_loss_real + self.lambda_app * d_loss_app + self.lambda_pose * d_loss_pose
            # d_loss = d_loss_fake + d_loss_real + self.lambda_gp * d_loss_gp
            d_loss = d_loss_fake + d_loss_real + self.lambda_gp * d_loss_gp
            self.reset_grad()
            d_loss.backward()
            self.d_optimizer.step()

            # Logging.
            loss = {}
            loss['D/loss_real'] = d_loss_real.item()
            loss['D/loss_fake'] = d_loss_fake.item()
            # loss['D/loss_app'] = d_loss_app.item()
            # loss['D/loss_pose'] = d_loss_pose.item()
            loss['D/loss_gp'] = d_loss_gp.item()

            # =================================================================================== #
            #                               3. Train the generator                                #
            # =================================================================================== #

            if (step + 1) % self.n_critic == 0:
                # Original-to-target domain.
                x_fake = self.G(b_real, con_feat)
                # print(x_fake[0,:,200:205,200:205])
                out_src = self.D(x_fake)
                g_loss_fake = -torch.mean(out_src)

                crop_batch = torch.zeros((x_fake.shape[0], 3, 224, 224))
                b = bbox.detach().cpu().numpy().astype(int)
                for i in range(x_fake.shape[0]):
                    # img = crop(x_fake[i], bbox[i])
                    x1, x2, y1, y2 = b[i, 0], b[i, 0] + b[i, 2], b[
                        i, 1], b[i, 1] + b[i, 3]
                    x1 = min(max(x1, 0), 416)
                    x2 = min(max(x2, 0), 416)
                    y1 = min(max(y1, 0), 416)
                    y2 = min(max(y2, 0), 416)

                    img = x_fake[i, :, x1:x2, y1:y2].cpu().data.numpy()
                    img = img.transpose((1, 2, 0))
                    resized_img = np.zeros(shape=(224, 224, 3))
                    resized_img = cv2.resize(img, (224, 224),
                                             interpolation=cv2.INTER_AREA)
                    crop_batch[i, :, :, :] = torch.from_numpy(
                        resized_img.transpose((2, 0, 1)))

                fake_app_feat = self.feat_extract(crop_batch)
                fake_pose_feat = self.pose_extract(crop_batch.numpy())

                # #**** debug ****#
                # fake_images = (x_fake.cpu().data).numpy()
                # permute = [2, 1, 0]
                # fake_images = fake_images[:, permute, :, :].transpose((0,2,3,1))
                # resized_data = np.zeros(shape=(fake_images.shape[0], 224, 224, 3))
                # for j in range(fake_images.shape[0]):
                #     resized_data[j,:,:,:] = cv2.resize(fake_images[j,:,:,:], (224, 224), interpolation = cv2.INTER_AREA)
                # resized_data = np.transpose(resized_data, (0, 3, 1, 2))
                # resized_tensor = torch.from_numpy(resized_data)
                # resized_tensor = resized_tensor.to(self.device, dtype=torch.float)

                # fake_app_feat = self.feat_extract(resized_tensor)
                # fake_pose_feat = self.pose_extract(resized_data, bbox)

                fake_app_feat = fake_app_feat.to(self.device)
                fake_pose_feat = fake_pose_feat.to(self.device)
                #**** debug ****#

                # g_loss_cls = self.classification_loss(out_cls, label_trg, self.dataset)
                g_loss_app = -self.appreance_cos_similarity(
                    fake_app_feat, a_app_feat)  # -similarity
                # print(fake_pose_feat.size(), b_pose_feat.size(), mask.size())
                g_loss_pose = self.compute_pose_loss(fake_pose_feat,
                                                     b_pose_feat,
                                                     mask)  # joints distance

                # Backward and optimize.
                # g_loss = g_loss_fake + self.lambda_rec * g_loss_rec + self.lambda_app * g_loss_cls
                # g_loss = g_loss_fake + self.lambda_app * g_loss_app + self.lambda_pose * g_loss_pose
                g_loss = g_loss_fake + self.lambda_app * g_loss_app + self.lambda_pose * g_loss_pose
                self.reset_grad()
                g_loss.backward()
                self.g_optimizer.step()

                # Logging.
                loss['G/loss_fake'] = g_loss_fake.item()
                # loss['G/loss_rec'] = g_loss_rec.item()
                loss['G/loss_app'] = g_loss_app.item() * self.lambda_app
                loss['G/loss_pose'] = g_loss_pose.item() * self.lambda_pose

            # =================================================================================== #
            #                                 4. Miscellaneous                                    #
            # =================================================================================== #

            # Print out training information.
            if (step + 1) % self.log_step == 0:
                et = time.time() - start_time
                et = str(datetime.timedelta(seconds=et))[:-7]
                log = "Elapsed [{}], Iteration [{}/{}]".format(
                    et, step + 1, self.num_iters)
                for tag, value in loss.items():
                    log += ", {}: {:.4f}".format(tag, value)
                print(log)

                if self.use_tensorboard:
                    for tag, value in loss.items():
                        self.logger.scalar_summary(tag, value, i + 1)

            # Translate fixed images for debugging.
            if (step + 1) % self.sample_step == 0:
                # if (step + 1) % 1 == 0:
                with torch.no_grad():
                    # a fix: [N, 3, 224, 224]
                    # a_real, b_real, bbox, b_pose_feat, mask
                    a_resized = torch.zeros(size=(a_real.shape[0], 3, 416,
                                                  416))
                    b_drawed = torch.zeros(size=(a_real.shape[0], 3, 416, 416))
                    for i in range(a_real.shape[0]):
                        img = a_real[i].cpu().data.numpy()
                        img = img.transpose((1, 2, 0))
                        resized_img = np.zeros(shape=(416, 416, 3))
                        resized_img = cv2.resize(img, (416, 416),
                                                 interpolation=cv2.INTER_AREA)
                        a_resized[i, :, :, :] = torch.from_numpy(
                            resized_img.transpose((2, 0, 1)))

                        trans1 = transforms.ToPILImage()
                        trans2 = transforms.ToTensor()
                        b_img = trans1(b_real[i].cpu())
                        draw = ImageDraw.Draw(b_img)
                        b = bbox[i].cpu().data.numpy().astype(int)
                        x, y, w, h = b
                        x2, y2 = x + w, y + h
                        draw.rectangle([x, y, x2, y2],
                                       outline="green",
                                       width=20)
                        b_drawed[i, :, :, :] = trans2(b_img)

                    b_drawed = b_drawed.to(self.device)
                    a_resized = a_resized.to(self.device)

                    picture_list = [a_resized, b_drawed]
                    a_visual_feat = self.feat_extract(a_real)
                    # a feature: [N, 20]; bbox: [N,4]
                    # con_visual_feat = torch.cat([a_visual_feat, bbox/416.0], dim=1) # [N, 24]
                    con_visual_feat = a_visual_feat
                    # print(b_real, con_visual_feat)
                    x_fake = self.G(b_real,
                                    con_visual_feat)  # [N, 3, 416, 416]
                    # print(a_fixed.size(), b_fixed.size(), x_fake.size())
                    picture_list.append(x_fake)
                    picture_concat = torch.cat(picture_list, dim=0)
                    # print(picture_concat.size())
                    sample_path = os.path.join(
                        self.sample_dir, '{}-images.jpg'.format(step + 1))
                    save_image(self.denorm(picture_concat.data.cpu()),
                               sample_path,
                               nrow=4,
                               padding=0)
                    print('Saved real and fake images into {}...'.format(
                        sample_path))

            # Save model checkpoints.
            if (step + 1) % self.model_save_step == 0:
                G_path = os.path.join(self.model_save_dir,
                                      '{}-G.ckpt'.format(step + 1))
                D_path = os.path.join(self.model_save_dir,
                                      '{}-D.ckpt'.format(step + 1))
                torch.save(self.G.state_dict(), G_path)
                torch.save(self.D.state_dict(), D_path)
                print('Saved model checkpoints into {}...'.format(
                    self.model_save_dir))

            # Decay learning rates.
            if (step + 1) % self.lr_update_step == 0 and (step + 1) > (
                    self.num_iters - self.num_iters_decay):
                g_lr -= (self.g_lr / float(self.num_iters_decay))
                d_lr -= (self.d_lr / float(self.num_iters_decay))
                self.update_lr(g_lr, d_lr)
                print('Decayed learning rates, g_lr: {}, d_lr: {}.'.format(
                    g_lr, d_lr))

    def test(self):
        """Translate images using StarGAN trained on a single dataset."""
        # Load the trained generator.
        self.restore_model(self.test_iters)

        # Set data loader.

        data_loader = self.data_loader

        with torch.no_grad():
            for i, (a_real, b_real) in enumerate(data_loader):

                # Prepare input images and target domain labels.
                a_real = a_real.to(self.device)
                b_real = b_real.to(self.device)

                # Translate images.
                a_fake_list = [a_real, b_real]
                a_fixed_feat = self.feat_extract(a_real)
                a_fake_list.append(self.G(b_real, a_fixed_feat))

                # Save the translated images.
                x_concat = torch.cat(a_fake_list, dim=3)
                result_path = os.path.join(self.result_dir,
                                           '{}-images.jpg'.format(i + 1))
                save_image(self.denorm(x_concat.data.cpu()),
                           result_path,
                           nrow=1,
                           padding=0)
                print('Saved real and fake images into {}...'.format(
                    result_path))
Esempio n. 2
0
def train_style_transfer(args):
    if not (args.train_data and args.valid_data):
        print("must chose train_data and valid_data")
        sys.exit()

    # make dataset
    trans = transforms.ToTensor()
    train_dataset = FaceDataset(args.train_data, transform=trans)
    label_dict = train_dataset.get_label_dict()
    valid_dataset = FaceDataset(args.valid_data, transform=trans)
    valid_dataset.give_label_dict(label_dict)
    train_loader = data_utils.DataLoader(train_dataset,
                                         batch_size=args.batch_size,
                                         shuffle=True,
                                         num_workers=1)
    valid_loader = data_utils.DataLoader(valid_dataset,
                                         batch_size=args.batch_size,
                                         shuffle=True,
                                         num_workers=1)
    train_size = len(train_dataset)
    valid_size = len(valid_dataset)
    loaders = {"train": train_loader, "valid": valid_loader}
    dataset_sizes = {"train": train_size, "valid": valid_size}

    if args.gpu:
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    else:
        device = torch.device("cpu")

    # make network
    if args.model_type == "VAE":
        net = Autoencoder(train_dataset.label_num()).to(device)
        optimizer = optim.Adam(net.parameters(),
                               lr=args.lr,
                               weight_decay=args.weight_decay)
        best_model_wts = net.state_dict()
        best_loss = 1e10
        if args.generator_model and os.path.exists(args.generator_model):
            net.load_state_dict(torch.load(args.generator_model))

    elif args.model_type == "VAEGAN":
        generator = Autoencoder(train_dataset.label_num()).to(device)
        discriminator = Discriminator().to(device)
        classifier = Classifier(train_dataset.label_num()).to(device)
        generator_optimizer = optim.Adam(generator.parameters(),
                                         lr=args.lr,
                                         weight_decay=args.weight_decay)
        discriminator_optimizer = optim.Adam(discriminator.parameters(),
                                             lr=args.lr * 0.1,
                                             weight_decay=args.weight_decay)
        best_generator_wts = generator.state_dict()
        best_discriminator_wts = discriminator.state_dict()
        best_generator_loss = 1e10
        best_discriminator_loss = 1e10
        if args.generator_model and os.path.exists(args.generator_model):
            generator.load_state_dict(torch.load(args.generator_model))
        if args.discriminator_model and os.path.exists(
                args.discriminator_model):
            discriminator.load_state_dict(torch.load(args.discriminator_model))
        if args.classifier_model:
            classifier.load_state_dict(torch.load(args.classifier_model))
    # make loss function and optimizer
    criterion = nn.BCELoss(reduction="sum")
    classifier_criterion = nn.CrossEntropyLoss(reduction="sum")

    # initialize loss
    loss_history = {"train": [], "valid": []}

    # start training
    start_time = time.time()
    for epoch in range(args.epochs):
        print("epoch {}".format(epoch + 1))

        for phase in ["train", "valid"]:
            if phase == "train":
                if args.model_type == "VAE":
                    net.train(True)
                elif args.model_type == "VAEGAN":
                    generator.train(True)
                    discriminator.train(True)
            else:
                if args.model_type == "VAE":
                    net.train(False)
                elif args.model_type == "VAEGAN":
                    generator.train(False)
                    discriminator.train(False)

            # initialize running loss
            generator_running_loss = 0.0
            discriminator_running_loss = 0.0

            for i, data in enumerate(loaders[phase]):
                inputs, label = data

                # wrap the in valiables
                if phase == "train":
                    inputs = Variable(inputs).to(device)
                    label = Variable(label).to(device)
                    torch.set_grad_enabled(True)
                else:
                    inputs = Variable(inputs).to(device)
                    label = Variable(label).to(device)
                    torch.set_grad_enabled(False)

                # zero gradients
                if args.model_type == "VAE":
                    optimizer.zero_grad()
                    mu, var, outputs = net(inputs, label)
                    loss = loss_func(inputs, outputs, mu, var)
                    if phase == "train":
                        loss.backward()
                        optimizer.step()
                    generator_running_loss += loss.item()

                elif args.model_type == "VAEGAN":
                    real_label = Variable(
                        torch.ones((inputs.size()[0], 1), dtype=torch.float) -
                        0.2 * (torch.rand(inputs.size()[0], 1))).to(device)
                    fake_label = Variable(
                        torch.zeros((inputs.size()[0], 1), dtype=torch.float) +
                        0.2 * (torch.rand(inputs.size()[0], 1))).to(device)
                    discriminator_optimizer.zero_grad()

                    real_pred = discriminator(inputs)
                    real_loss = criterion(real_pred, real_label)

                    random_index = np.random.randint(0,
                                                     train_dataset.label_num(),
                                                     inputs.size()[0])
                    generate_label = Variable(
                        torch.zeros_like(label)).to(device)
                    for i, index in enumerate(random_index):
                        generate_label[i][index] = 1
                    mu, var, outputs = generator(inputs, label)
                    fake_pred = discriminator(outputs.detach())
                    fake_loss = criterion(fake_pred, fake_label)

                    discriminator_loss = real_loss + fake_loss
                    if phase == "train":
                        discriminator_loss.backward()
                        discriminator_optimizer.step()

                    generator_optimizer.zero_grad()
                    #class_loss = classifier_criterion(classifier(outputs), torch.max(label, 1)[1])

                    dis_loss = criterion(discriminator(outputs), real_label)
                    gen_loss = loss_func(inputs, outputs, mu, var)
                    generator_loss = dis_loss + gen_loss
                    if phase == "train":
                        generator_loss.backward()
                        generator_optimizer.step()

                    discriminator_running_loss += discriminator_loss.item()
                    generator_running_loss += generator_loss.item()

            if args.model_type == "VAE":
                epoch_loss = generator_running_loss / dataset_sizes[
                    phase] * args.batch_size
                loss_history[phase].append(epoch_loss)

                print("{} loss {:.4f}".format(phase, epoch_loss))
                if phase == "valid" and epoch_loss < best_loss:
                    best_model_wts = net.state_dict()
                    best_loss = epoch_loss

            elif args.model_type == "VAEGAN":
                epoch_generator_loss = generator_running_loss / dataset_sizes[
                    phase] * args.batch_size
                epoch_discriminator_loss = discriminator_running_loss / dataset_sizes[
                    phase] * args.batch_size

                print("{} generator loss {:.4f}".format(
                    phase, epoch_generator_loss))
                print("{} discriminator loss {:.4f}".format(
                    phase, epoch_discriminator_loss))
                if phase == "valid" and epoch_generator_loss < best_generator_loss:
                    best_generator_wts = generator.state_dict()
                    best_generator_loss = epoch_generator_loss
                if phase == "valid" and epoch_discriminator_loss < best_discriminator_loss:
                    best_discriminator_wts = discriminator.state_dict()
                    best_generator_loss = epoch_discriminator_loss

    elapsed_time = time.time() - start_time
    print("training complete in {:.0f}s".format(elapsed_time))
    if args.model_type == "VAE":
        net.load_state_dict(best_model_wts)
        return net, label_dict

    elif args.model_type == "VAEGAN":
        generator.load_state_dict(best_generator_wts)
        discriminator.load_state_dict(best_discriminator_wts)
        return (generator, discriminator), label_dict
Esempio n. 3
0
            label.fill_(real_label)  # fake labels are real for generator cost
            output = D(fake)
            errG = criterion(output, label)
            D_G_z2 = output.mean().item()
            errG.backward()
            optimizerG.step()

        # state_msg = f'{epoch+1:d}'
        state_msg = 'Epoch: %d Loss_D: %.4f Loss_G: %.4f D(x): %.4f D(G(z)): %.4f / %.4f' \
              % (epoch, errD.item(), errG.item(), D_x, D_G_z1, D_G_z2)
        
        pbar.set_description(state_msg)

        writer.add_scalar('loss_D', errD, n_iter)
        writer.add_scalar('loss_G', errG, n_iter)
        writer.add_scalar('D(x)', D_x, n_iter)
        writer.add_scalar('D(G(z1))', D_G_z1, n_iter)
        writer.add_scalar('D(G(z2))', D_G_z2, n_iter)
        if n_iter % 100 == 0:
            fake = G(fixed_noise)
            real = vutils.make_grid(image, nrow=8, normalize=True, scale_each=True)
            writer.add_image('real', real, n_iter)
            fake = vutils.make_grid(fake.detach(), nrow=8, normalize=True, scale_each=True)
            writer.add_image('fake', fake, n_iter)

        n_iter += 1

    # do checkpointing
    torch.save(G.state_dict(), f'{save_dir}/G_epoch_{epoch}.pth')
    torch.save(D.state_dict(), f'{save_dir}/D_epoch_{epoch}.pth')
Esempio n. 4
0
def main(args):
    # check if cuda available
    # device = 'cuda:0' if torch.cuda.is_available() else 'cpu'

    # define dataset and dataloader
    # dir_name = "{}_{}_{}_{}_{}".format(watch.year, watch.month, watch.day, watch.hour, watch.minute)
    args = parse_args()
    log_dir = os.path.join(os.getcwd(), "log_runs")

    dataset = AirfoilDataset()
    airfoil_x = dataset.get_x()
    airfoil_dim = airfoil_x.shape[0]
    airfoil_dataloader = DataLoader(dataset, batch_size=8, shuffle=True)

    # hyperparameters
    latent_dim = 16
    lr_dis = args.lr_dis  # discriminator learning rate
    lr_gen = args.lr_gen  # generator learning rate
    num_epochs = args.num_epochs
    disc_hidden_dim = args.dis_hidden
    gen_hidden_dim = args.gen_hidden

    # build the model
    dis = Discriminator(input_dim=airfoil_dim,
                        hidden_dim=disc_hidden_dim,
                        lr=lr_dis).to(device)
    gen = Generator(latent_dim=latent_dim,
                    hidden_dim=gen_hidden_dim,
                    airfoil_dim=airfoil_dim,
                    lr=lr_gen).to(device)
    print("Distrminator model:\n", dis)
    print("Generator model:\n", gen)

    path = "./gan_model.ckpt"

    # train the GAN model
    save_model_interval = 10
    disc_loss_arr = []
    disc_fake_prob_std_arr = []
    disc_fake_prob_arr = []
    gen_loss_arr = []
    gen_update_interval = 2
    for epoch in range(num_epochs):
        epoch_disc_loss = 0.0
        epoch_gen_loss = 0.0
        disc_fake_prob = 0.0
        disc_fake_prob_std = 0.0
        num_batches = 0
        for n_batch, (local_batch, __) in enumerate(airfoil_dataloader):
            num_batches += 1
            y_real = local_batch.to(device)
            batch_size = y_real.shape[0]
            y_real = torch.tensor(y_real).float().to(device)  # train generator

            z = torch.randn((batch_size, latent_dim)).to(device)

            # train discriminator
            with torch.no_grad():
                gen_sample = gen(z)

            disc_real = dis(y_real)
            disc_fake = dis(gen_sample)

            loss_dis = torch.log(disc_real) + torch.log(1.0 - disc_fake)
            loss_dis = -0.5 * loss_dis.mean()

            dis.optimizer.zero_grad()
            loss_dis.backward()
            dis.optimizer.step()
            epoch_disc_loss += loss_dis.item()

            # train generator
            gen_sample = gen(z)
            fake_prob = dis(gen_sample)
            loss_gen = -torch.log(fake_prob)
            loss_gen = loss_gen.mean()

            if (num_batches % gen_update_interval == 0):
                gen.optimizer.zero_grad()
                loss_gen.backward()
                gen.optimizer.step()

            disc_fake_prob_std += torch.std(fake_prob).item()
            disc_fake_prob += fake_prob.clone().detach().mean().item()

            epoch_gen_loss += loss_gen.item()

            # print loss while training
            if (n_batch + 1) % 30 == 0:
                print(
                    "Epoch: [{}/{}], Batch: {}, Discriminator loss: {}, Generator loss: {}"
                    .format(epoch, num_epochs, n_batch, loss_dis.item(),
                            loss_gen.item()))
        print("entry made")

        if ((epoch + 1) % save_model_interval == 0):
            saveGAN(dis.state_dict(), gen.state_dict(), path)

        disc_fake_prob_arr.append(disc_fake_prob / num_batches)
        disc_fake_prob_std_arr.append((disc_fake_prob_std / num_batches))
        disc_loss_arr.append(epoch_disc_loss / num_batches)
        gen_loss_arr.append(epoch_gen_loss / num_batches)

    # test trained GAN model
    num_samples = 100
    # create random noise
    noise = torch.randn((num_samples, latent_dim)).to(device)
    # noise = torch.randn((num_samples, noise_dim)).to(device)
    # generate airfoils
    gen_airfoils = gen(noise)
    # if 'cuda' in device:
    if device.type == 'cuda':
        gen_airfoils = gen_airfoils.detach().cpu().numpy()
    else:
        gen_airfoils = gen_airfoils.detach().numpy()
    # gen_airfoils = gen_airfoils.detach().cpu().numpy()

    # plot generated airfoils
    plot_airfoils(airfoil_x, gen_airfoils, "gan_generated_airfoils.png")
    plot_prop(disc_loss_arr, "disc_loss")
    plot_prop(gen_loss_arr, "gen_loss")
    plot_prop(
        disc_fake_prob_arr, "disc_fake_prob_lrd_{}_lrg_{}_epochs_{}".format(
            lr_dis, lr_gen, num_epochs), disc_fake_prob_std_arr)