//  [python]
def __init__(self, _train_X, _train_Y, data_loader, _nclass, _cuda, seedinfo, train_base=False, _lr=0.001, _beta1=0.5, _nepoch=20, _batch_size=100, _embed_dim=1000, _num_layers=3, opt=None):
        super().__init__(_train_X, _train_Y, data_loader, _nclass, _cuda, seedinfo, train_base, _lr, _beta1, _nepoch, _batch_size, _embed_dim, _num_layers, opt)
        self.opt = opt
        self.seedinfo = seedinfo
        
        self.lr = _lr
        self.beta1 = _beta1
        self.nepoch = _nepoch
        self.batch_size = _batch_size
        self.embed_dim = _embed_dim
        self.num_layers = _num_layers
        self.nclass = _nclass
        self.cuda = _cuda

        self.test_seen_feature = data_loader.test_seen_feature
        self.test_seen_label = data_loader.test_seen_label 
        self.test_unseen_feature = data_loader.test_unseen_feature
        self.test_unseen_label = data_loader.test_unseen_label

        self.seenclasses = data_loader.seenclasses
        self.unseenclasses = data_loader.unseenclasses            
        self.attribute = data_loader.attribute

        if self.opt.subspace_proj:
            base_weights_mat = torch.cat((self.model.fc.weight.data, self.model.fc.bias.data.unsqueeze(1)), 1)
            tr_base = torch.transpose(base_weights_mat, 0, 1)
            self.Q, self.R = torch.linalg.qr(tr_base, mode='reduced')
        
        if self.opt.cuda:
            self.target_weights = self.target_weights.cuda()
        
        if opt.class_reduction_ablation:
            perm = torch.randperm(len(self.seenclasses))
            assert opt.class_reduction_ablation in range(1, len(self.seenclasses)+1)
            perm = perm[:opt.class_reduction_ablation]
            training_attributes = self.attribute[self.seenclasses][perm]
            training_weights = self.target_weights[perm]

        if opt.single_autoencoder_baseline:
            if opt.class_reduction_ablation: 
                att2weight_dataset = util.GenericDataset(opt, _input=training_attributes, _target=training_weights, cuda=self.cuda)
                self.loader = DataLoader(att2weight_dataset, batch_size=self.batch_size, shuffle=True)
            else:
                att2weight_dataset = util.GenericDataset(opt, _input=self.attribute[self.seenclasses], _target=self.target_weights, cuda=self.cuda)
                self.loader = DataLoader(att2weight_dataset, batch_size=self.batch_size, shuffle=True)
        else:
            if opt.class_reduction_ablation:
                combined_seen_dataset = util.GenericDataset(opt, _input=training_attributes, _target=training_weights, cuda=self.cuda)
            else:
                combined_seen_dataset = util.GenericDataset(opt, _input=self.attribute[self.seenclasses], _target=self.target_weights, cuda=self.cuda)
            placeholder_weights = torch.zeros(len(self.unseenclasses), self.target_weights.size(1))
            if self.cuda:
                placeholder_weights = placeholder_weights.cuda()
            if opt.class_reduction_ablation:
                combined_full_dataset = util.GenericDataset(opt, _input=torch.cat((training_attributes, self.attribute[self.unseenclasses])), _target=torch.cat((training_weights, placeholder_weights), dim=0), cuda=self.cuda)
            else:
                combined_full_dataset = util.GenericDataset(opt, _input=torch.cat((self.attribute[self.seenclasses], self.attribute[self.unseenclasses])), _target=torch.cat((self.target_weights, placeholder_weights), dim=0), cuda=self.cuda)
            if self.opt.include_unseen:
                self.loader = DataLoader(combined_full_dataset, batch_size=self.batch_size, shuffle=True)
            else:
                self.loader = DataLoader(combined_seen_dataset, batch_size=self.batch_size, shuffle=True)

        self.AE_attribute = model.AUTOENCODER(self.opt, input_dim=self.attribute.size(1), embed_dim=self.embed_dim, num_layers=self.num_layers)
        self.AE_weight = model.AUTOENCODER(self.opt, input_dim=self.target_weights.size(1), embed_dim=self.embed_dim, num_layers=self.num_layers)
        
        self.AE_attribute.apply(util.weights_init)
        self.AE_weight.apply(util.weights_init)
        
        if self.opt.single_autoencoder_baseline:
            self.model = model.AUTOENCODER(self.opt, input_dim=self.attribute.size(1), embed_dim=self.embed_dim, output_dim=self.target_weights.size(1), num_layers=self.num_layers)
        else:
            self.model = model.JOINT_AUTOENCODER(self.opt, autoencoder1=self.AE_attribute, autoencoder2=self.AE_weight)

        if self.model:
            self.model.apply(util.weights_init)
        
        if opt.cos_sim_loss:
            self.criterion = util.cos_sim_loss(reduction='none')
        else:
            self.criterion = nn.MSELoss(reduction='none')
        self.mse_loss = nn.MSELoss(reduction='none')
        self.l1loss = nn.L1Loss(reduction='none')

        if opt.daegnn:
            dae_num_features = 2049 # Number of features from ResNet-101, 512 in original implementation.
            self.dae_meta_batch_size = 4 # Taken from original implementation
            if self.opt.single_autoencoder_baseline:
                self.dae_loader = DataLoader(att2weight_dataset, batch_size=len(self.seenclasses), shuffle=False)
            else:
                self.dae_loader = DataLoader(combined_seen_dataset, batch_size=len(self.seenclasses), shuffle=False)
            self.dae = WeightsDAE({
                'gaussian_noise': 0.08,
                'comp_reconstruction_loss': True,
                'targets_as_input': False,
                'dae_type': 'RelationNetBasedGNN',
                'num_layers': 2,
                'num_features_input': dae_num_features,
                'num_features_output': 2 * dae_num_features,
                'num_features_hidden': 3 * dae_num_features,
                'update_dropout': 0.7,

                'nun_features_msg': 3 * dae_num_features,
                'aggregation_dropout': 0.7,
                'topK_neighbors': 10,
                'temperature': 5.0,
                'learn_temperature': False,
            })
            self.dae_optimizer = optim.Adam(self.dae.parameters(), lr=_lr, betas=(_beta1, 0.999), weight_decay=0.0)
        
        if self.cuda:
            self.AE_attribute.cuda()
            self.AE_weight.cuda()
            if self.model:
                self.model.cuda()
            self.criterion.cuda()
            self.mse_loss.cuda()
            self.l1loss.cuda()
            if opt.daegnn:
                self.dae.cuda()

        self.unseen_model = model.LINEAR(self.test_seen_feature.size(1), len(self.unseenclasses))
        self.ext_model = model.LINEAR(self.test_seen_feature.size(1), len(self.seenclasses) + len(self.unseenclasses))
        self.ext_model.fc.weight.data[:len(self.seenclasses), :] =  self.target_weights[:, :-1]
        self.ext_model.fc.bias.data[:len(self.seenclasses)] = self.target_weights[:, -1]
                
        if self.cuda:
            self.ext_model.cuda()
            self.unseen_model.cuda()

        self.lr = _lr
        self.beta1 = _beta1
        self.optimizer_attribute_AE = optim.Adam(self.AE_attribute.parameters(), lr=_lr, betas=(_beta1, 0.999))
        self.optimizer_weight_AE = optim.Adam(self.AE_weight.parameters(), lr=_lr, betas=(_beta1, 0.999))
        if self.model:
            self.weight_optimizer = optim.Adam(self.model.parameters(), lr=_lr, betas=(_beta1, 0.999), weight_decay=0.0)
    
        self.index_in_epoch = 0
        self.epochs_completed = 0