def predict(self, X, condition_data=None): use_condition = _check_conditions(self.conditions, condition_data) self.eval() # Deactivate dropout if self.conditions: self.conditions.eval() pred = [] with torch.no_grad(): for start in range(0, X.shape[0], self.batch_size): # batched predictions, yet inclusive end = start + self.batch_size X_batch = X[start:end].toarray() X_batch = torch.FloatTensor(X_batch) if torch.cuda.is_available(): X_batch = X_batch.cuda() X_batch = Variable(X_batch) if use_condition: c_batch = [c[start:end] for c in condition_data] z = self.enc(X_batch) if use_condition: z = self.conditions.encode_impose(z, c_batch) # reconstruct X_reconstuction = self.dec(z) # shift X_reconstuction = X_reconstuction.data.cpu().numpy() pred.append(X_reconstuction) return np.vstack(pred)
def fit(self, X, y=None, condition_data=None): if y is not None: raise NotImplementedError("(Semi-)supervised usage not supported") use_condition = _check_conditions(self.conditions, condition_data) if use_condition: code_size = self.n_code + self.conditions.size_increment() else: code_size = self.n_code self.enc = Encoder(X.shape[1], self.n_hidden, self.n_code, final_activation='linear', normalize_inputs=self.normalize_inputs, dropout=self.dropout, activation=self.activation) self.dec = Decoder(code_size, self.n_hidden, X.shape[1], dropout=self.dropout, activation=self.activation) if torch.cuda.is_available(): self.enc = self.enc.cuda() self.dec = self.dec.cuda() optimizer_gen = TORCH_OPTIMIZERS[self.optimizer] # Reconstruction self.enc_optim = optimizer_gen(self.enc.parameters(), lr=self.lr) self.dec_optim = optimizer_gen(self.dec.parameters(), lr=self.lr) # do the actual training for epoch in range(self.n_epochs): if self.verbose: print("Epoch", epoch + 1) # Shuffle on each new epoch if use_condition: # shuffle(*arrays) takes several arrays and shuffles them so indices are still matching X_shuf, *condition_data_shuf = sklearn.utils.shuffle( X, *condition_data) else: X_shuf = sklearn.utils.shuffle(X) for start in range(0, X.shape[0], self.batch_size): end = start + self.batch_size X_batch = X_shuf[start:end].toarray() # condition may be None if use_condition: # c_batch = condition_shuf[start:(start+self.batch_size)] c_batch = [c[start:end] for c in condition_data_shuf] self.partial_fit(X_batch, condition_data=c_batch) else: self.partial_fit(X_batch) if self.verbose: # Clean up after flushing batch loss printings print() return self
def partial_fit(self, X, y=None, condition_data=None): """ Performs reconstrction, discimination, generator training steps """ _check_conditions(self.conditions, condition_data) if y is not None: raise ValueError("(Semi-)supervised usage not supported") # Transform to Torch (Cuda) Variable, shift batch to GPU X = Variable(torch.FloatTensor(X)) if torch.cuda.is_available(): X = X.cuda() # Make sure we are in training mode and zero leftover gradients self.train() # One step each, could balance recon_loss = self.ae_step(X, condition_data=condition_data) if self.verbose: log_losses(recon_loss, 0, 0) return self
def forward(self, x, condition_data=None): if self.normalize_inputs: x = F.normalize(x, 1) # TODO could I use x instead of self.inp? Do we need x.view? mu, logvar = self.encode(x.view(-1, self.inp)) z = self.reparametrize(mu, logvar) use_condition = _check_conditions(self.conditions, condition_data) if use_condition: z = self.conditions.encode_impose(z, condition_data) return self.decode(z), mu, logvar
def fit(self, X, y=None, condition_data=None): """ :param X: np.array, the base data from Bag class :param y: dummy variable, throws Error if used :param condition_data: generic list of conditions :return: """ ### DONE Adapt to generic condition ### # TODO: check how X representation and numpy.array work together # TODO: adapt combining X and new_conditions_name if y is not None: raise NotImplementedError("(Semi-)supervised usage not supported") use_condition = _check_conditions(self.conditions, condition_data) # do the actual training for epoch in range(self.n_epochs): if self.verbose: print("Epoch", epoch + 1) if use_condition: # shuffle(*arrays) takes several arrays and shuffles them so indices are still matching X_shuf, *condition_data_shuf = sklearn.utils.shuffle( X, *condition_data) else: X_shuf = sklearn.utils.shuffle(X) for start in range(0, X.shape[0], self.batch_size): end = start + self.batch_size X_batch = X_shuf[start:end] # condition may be None if use_condition: # c_batch = condition_shuf[start:(start+self.batch_size)] c_batch = [c[start:end] for c in condition_data_shuf] self.partial_fit(X_batch, condition_data=c_batch) else: self.partial_fit(X_batch) if self.verbose: # Clean up after flushing batch loss printings print() return self
def predict(self, X, condition_data=None): """ :param X: np.array, the base data from Bag class :param condition_data: generic list of conditions :return: """ ### DONE Adapt to generic condition ### use_condition = _check_conditions(self.conditions, condition_data) self.eval() # Deactivate dropout if self.conditions: self.conditions.eval() pred = [] with torch.no_grad(): test_loss = 0 for start in range(0, X.shape[0], self.batch_size): # batched predictions, yet inclusive end = start + self.batch_size X_batch = X[start:end] if sp.issparse(X_batch): X_batch = X_batch.toarray() # as_tensor does not make a copy of X_batch X_batch = torch.as_tensor(X_batch, dtype=torch.float32, device=self.device) if use_condition: c_batch = [c[start:end] for c in condition_data] if use_condition: recon_batch, mu, logvar = self(X_batch, c_batch) else: recon_batch, mu, logvar = self(X_batch) test_loss += self.loss_function(recon_batch, X_batch, mu, logvar).item() pred.append(recon_batch.data.cpu().numpy()) test_loss /= X.shape[0] print('====> Test set loss: {:.4f}'.format(test_loss)) return np.vstack(pred)
def ae_step(self, batch, condition_data=None): """ Perform one autoencoder training step """ z_sample = self.enc(self.corrupt(batch, self.noise_factor)) use_condition = _check_conditions(self.conditions, condition_data) if use_condition: z_sample = self.conditions.encode_impose(z_sample, condition_data) x_sample = self.dec(z_sample) recon_loss = F.binary_cross_entropy( x_sample + TINY, batch.view(batch.size(0), batch.size(1)) + TINY) self.enc_optim.zero_grad() self.dec_optim.zero_grad() if self.conditions: self.conditions.zero_grad() recon_loss.backward() self.enc_optim.step() self.dec_optim.step() if self.conditions: self.conditions.step() return recon_loss.item()
def partial_fit(self, X, y=None, condition_data=None): """ Performs reconstrction, discimination, generator training steps :param X: np.array, the base data from Bag class :param y: dummy variable, throws Error if used :param condition_data: generic list of conditions :return: """ ### DONE Adapt to generic condition ### use_condition = _check_conditions(self.conditions, condition_data) if y is not None: raise ValueError("(Semi-)supervised usage not supported") # Transform to Torch (Cuda) Variable, shift batch to GPU if sp.issparse(X): X = X.toarray() X = torch.as_tensor(X, dtype=torch.float32, device=self.device) # Make sure we are in training mode and zero leftover gradients self.train() self.optimizer.zero_grad() # Build the model on the concatenated data, compute BCE without concatenation if use_condition: recon_batch, mu, logvar = self(X, condition_data) else: recon_batch, mu, logvar = self(X) loss = self.loss_function(recon_batch, X, mu, logvar) if use_condition: self.conditions.zero_grad() loss.backward() self.optimizer.step() if use_condition: self.conditions.step() if self.verbose: # Log batch loss log_losses(loss.item() / len(X)) return self
def predict(self, X, condition_data=None): use_condition = _check_conditions(self.conditions, condition_data) batch_size = 128 test_users = list(X.keys()) test_user_num = len(test_users) index = 0 pred = [] while True: if index >= test_user_num: break user_batch = test_users[index:index + batch_size] if use_condition: c_batch = [c[index:index + batch_size] for c in condition_data] index += batch_size user_batch_rating = self.generator.all_rating(user_batch, c_batch, impose_dim=1) user_batch_rating = user_batch_rating.detach_().cpu().numpy() for user_batch_rating_uid in zip(user_batch_rating, user_batch): pred.append(self.simple_test_one_user(user_batch_rating_uid)) return pred
def fit(self, X, y=None, condition_data=None): """ :param X: np.array, the base data from Bag class :param y: dummy variable, throws Error if used :param condition_data: generic list of conditions :return: """ if y is not None: raise NotImplementedError("(Semi-)supervised usage not supported") use_condition = _check_conditions(self.conditions, condition_data) self.user_pos_train = X # minimax training for epoch in range(self.n_epochs): if self.verbose: print("Epoch", epoch + 1) if epoch >= 0: for d_epoch in range(self.d_epochs): #100 if d_epoch % 5 == 0: self.generate_for_d(DIS_TRAIN_FILE, condition_data) train_size = ut.file_len(DIS_TRAIN_FILE) index = 1 while True: if index > train_size: break if index + self.batch_size <= train_size + 1: input_user, input_item, input_label = ut.get_batch_data(DIS_TRAIN_FILE, index, self.batch_size) else: input_user, input_item, input_label = ut.get_batch_data(DIS_TRAIN_FILE, index, train_size - index + 1) if torch.cuda.is_available(): input_label = torch.tensor(input_label).cuda() else: input_label = torch.tensor(input_label) if use_condition: # Each user is repeated a varying number of times in dis_train.txt, users not ordered user_cnt = collections.OrderedDict([(u, input_user.count(u)) for u in set(input_user)]) c_batch = [] for c in condition_data: raw_c_batch = [] for u in set(input_user): raw_c_batch.append(c[u]) c_batch.append(np.asarray(raw_c_batch).repeat(list(user_cnt.values()), axis=0)) D_loss = self.discriminator(input_user, input_item, input_label, c_batch) else: D_loss = self.discriminator(input_user, input_item, input_label) self.discriminator.step(D_loss) index += self.batch_size if self.verbose: print("\r[D Epoch %d/%d] [loss: %f]" % (d_epoch, self.d_epochs, D_loss.item())) # Train G for g_epoch in range(self.g_epochs): # 50 for u in self.user_pos_train: sample_lambda = 0.2 pos = self.user_pos_train[u] if use_condition: c_batch = [c[u] for c in condition_data] rating = self.generator.all_logits(u, c_batch) else: rating = self.generator.all_logits(u) rating = rating.detach_().cpu().numpy() exp_rating = np.exp(rating) prob = exp_rating / np.sum(exp_rating) # prob is generator distribution p_\theta pn = (1 - sample_lambda) * prob pn[pos] += sample_lambda * 1.0 / len(pos) # Now, pn is the Pn in importance sampling, prob is generator distribution p_\theta # print('pn sum=',pn.sum()) # Normilize by probability sum to avoid np.random.choice error 'probability do not sum to one' pn /= pn.sum() sample = np.random.choice(np.arange(self.item_num), 2 * len(pos), p=pn) ########################################################################### # Get reward and adapt it with importance sampling ########################################################################### reward = self.discriminator.get_reward(u, sample) reward = reward.detach_().cpu().numpy() * prob[sample] / pn[sample] ########################################################################### # Update G ########################################################################### if torch.cuda.is_available(): sample = torch.tensor(sample).cuda() reward = torch.tensor(reward).cuda() else: sample = torch.tensor(sample) reward = torch.tensor(reward) if use_condition: c_batch = [c[u] for c in condition_data] G_loss = self.generator(u, sample, reward, c_batch) else: G_loss = self.generator(u, sample, reward) self.generator.step(G_loss) if self.verbose: print("\r[G Epoch %d/%d] [loss: %f]" % (g_epoch, self.g_epochs, G_loss.item())) return self