def __getitem__(self, index): s = self.data[index] if False: # cuda.is_available(): return cuda.FloatTensor(s[0]), cuda.FloatTensor(s[1]) else: return FloatTensor(s[0]) / 255, FloatTensor(s[1])
def init_hiddens(self, batch_size): h0 = Variable(tc.FloatTensor(self.num_layers * self.num_directions, batch_size, self.hidden_size).zero_(), requires_grad=False) c0 = Variable(tc.FloatTensor(self.num_layers * self.num_directions, batch_size, self.hidden_size).zero_(), requires_grad=False) return h0, c0
def forward(self, input=tc.FloatTensor(0)): ''' This function runs forward propagation for Convolution operation :param input: output of previous layer :return: output of convolution of input with relu activation function ''' self.input = input self.act_output = self.relu( self.layer.forward(tc.FloatTensor(self.input))) return self.act_output
def init_hidden(self): """ PyTorch wants you to supply the last hidden state at each timestep to the LSTM. You shouldn't need to call this function explicitly """ if self.use_cuda: return (ag.Variable(cuda.FloatTensor(self.num_layers, 1, self.input_dim).zero_()), ag.Variable(cuda.FloatTensor(self.num_layers, 1, self.input_dim).zero_())) else: return (ag.Variable(torch.FloatTensor(self.num_layers, 1, self.input_dim).zero_()), ag.Variable(torch.FloatTensor(self.num_layers, 1, self.input_dim).zero_()))
def validation(self, loader): if self.epoch_step == 0: record_epoch_step = 0 else: record_epoch_step = self.epoch_step - 1 self.model.eval() total_loss = cuda.FloatTensor([0.]) total_accu = cuda.FloatTensor([0.]) widgets = [ "processing: ", progressbar.Percentage(), " ", progressbar.ETA(), " ", progressbar.FileTransferSpeed(), ] bar = progressbar.ProgressBar(widgets=widgets, max_value=len(loader)).start() for i, batch in enumerate(loader): bar.update(i) batch_data, batch_label = batch batch_data = Variable(batch_data, volatile=True).cuda() batch_label = Variable(batch_label, volatile=True).cuda() logits = self.model(batch_data) loss = self.model.criterion(logits, batch_label) accu = self.accuracy(logits=logits, targets=batch_label).data total_accu.add_(accu) total_loss.add_(loss.data) # mean_loss = total_loss.cpu().numpy() / (i + 1) mean_accu = total_accu.cpu().numpy() / (i + 1) if self.writer is not None: self.writer.add_scalar('val/loss', scalar_value=mean_loss, global_step=record_epoch_step) self.writer.add_scalar('val/accu', scalar_value=mean_accu, global_step=record_epoch_step) # print('') print("validation-->epoch:{},mean_loss:{}, mean_accuracy:{}".format( record_epoch_step, mean_loss, mean_accu)) bar.finish()
def __init__( self, num_params, # number of model parameters sigma_init=0.10, # initial standard deviation sigma_alpha=0.20, # learning rate for standard deviation sigma_decay=0.999, # anneal standard deviation sigma_limit=0.01, # stop annealing if less than this learning_rate=1, # learning rate for standard deviation learning_rate_decay=0.9999, # annealing the learning rate learning_rate_limit=0.001, # stop annealing learning rate popsize=255, # population size done_threshold=1e-6, # threshold when we say we are done average_baseline=True, # set baseline to average of batch weight_decay=0.01, # weight decay coefficient rank_fitness=True, # use rank rather than fitness numbers forget_best=True, diversity_base=0.01): # don't keep the historical best solution self.num_params = num_params self.sigma_init = sigma_init self.sigma_alpha = sigma_alpha self.sigma_decay = sigma_decay self.sigma_limit = sigma_limit self.learning_rate = learning_rate self.learning_rate_decay = learning_rate_decay self.learning_rate_limit = learning_rate_limit self.popsize = popsize self.average_baseline = average_baseline if self.average_baseline: assert (self.popsize % 2 == 0), "Population size must be even" self.batch_size = int(self.popsize / 2) else: assert (self.popsize & 1), "Population size must be odd" self.batch_size = int((self.popsize - 1) / 2) self.forget_best = forget_best # self.batch_reward = torch_c.FloatTensor(self.batch_size*2).fill_(0.0) self.mu = torch_c.FloatTensor(self.num_params).fill_(0.0) self.sigma = torch_c.FloatTensor(self.num_params).fill_( self.sigma_init) # self.curr_best_mu = torch_c.FloatTensor(self.num_params).fill_(0.0) # self.best_mu = torch_c.FloatTensor(self.num_params).fill_(0.0) self.best_reward = 0 self.first_interation = True self.weight_decay = weight_decay self.rank_fitness = rank_fitness if self.rank_fitness: self.forget_best = True # always forget the best one if we rank self.done_threshold = done_threshold self.diversity_base = diversity_base self.mdb = 0
def data_params(): """ Returns random data and parameters used to generate the data. """ S = int(1e5) theta_1 = 0.5 theta_2 = 0.3 pi_1 = 0.6 pi_2 = 1 - pi_1 N_ls_all = t.FloatTensor([100 for _ in range(S)]) theta_ls = t.FloatTensor( np.random.choice([theta_1, theta_2], size=S, p=[pi_1, pi_2])) n_ls_all = Binomial(N_ls_all, theta_ls).sample() return N_ls_all, n_ls_all, [pi_1, pi_2, theta_1, theta_2]
def initialize_pi_theta(self, N_ls, n_ls): ''' Initialize pi_list and theta_list based on the input data N_ls and n_ls. This is a better initialization than completely random initilaization, since it takes into account information from N_ls and n_ls, and thus a better initialization should help the EM iterations in the .fit() method to converge faster. Input ----- N_ls: 1D tensor n_ls: 1D tensor Output ------ None ''' # Conver to numpy.array N_array = np.array(N_ls.cpu()) n_array = np.array(n_ls.cpu()) # list of n/N sorted in ascending order ratio_ls = np.sort(n_array / N_array) # reproducibility np.random.seed(seed=123) # pick K random integer indice, [index_1, ..., index_K] random_indice = np.sort(np.random.choice(len(ratio_ls), self.K)) # theta are the ratio at the random indice, { ratio_ls[index_k] | k=1,2,...,K } theta_array = ratio_ls[random_indice] # the proportion of the midpoint of each pair of consecutive indice # (index_k + index_{k+1})/2/len(ratio_ls), for k=1,2,...,K-1 acc_portion_ls = (random_indice[1:] + random_indice[:-1]) / 2.0 / len(ratio_ls) acc_portion_ls = np.append(acc_portion_ls, 1.0) # initialize pi_list using the portions of indice pi_array = np.insert(acc_portion_ls[1:] - acc_portion_ls[:-1], obj=0, values=acc_portion_ls[0]) # convert numpy arrays to torch tensors. self.theta_list = t.FloatTensor(theta_array) self.pi_list = t.FloatTensor(pi_array)
def ask(self): '''returns a list of parameters''' # antithetic sampling self.epsilon = torch_c.FloatTensor(self.batch_size, self.num_params).normal_() self.epsilon.mul_(self.sigma.expand(self.batch_size, self.num_params)) self.epsilon_full = torch.cat((self.epsilon, -1 * self.epsilon)) if self.average_baseline: epsilon = self.epsilon_full else: zeros = torch_c.FloatTensor(1, self.num_params).fill_(0.0) epsilon = torch.cat((zeros, self.epsilon_full)) solutions = self.mu.expand(epsilon.size()) + epsilon self.solutions = solutions return solutions
def _forward_alg(self, feats): # Do the forward algorithm to compute the partition function init_alphas = cuda.FloatTensor(1, self.tagset_size).fill_(-10000.) # START_TAG has all of the score. init_alphas[0][self.tag_idx[cfg.SENT_START]] = 0. # Wrap in a variable so that we will get automatic backprop forward_var = Variable(init_alphas) # Iterate through the sentence for feat in feats: alphas_t = [] # The forward variables at this timestep for next_tag in range(self.tagset_size): # broadcast the emission score: it is the same regardless of # the previous tag emit_score = feat[next_tag].view(1, -1).expand( 1, self.tagset_size) # the ith entry of trans_score is the score of transitioning to # next_tag from i trans_score = self.transitions[next_tag].view(1, -1) # The ith entry of next_tag_var is the value for the # edge (i -> next_tag) before we do log-sum-exp next_tag_var = forward_var + trans_score + emit_score # The forward variable for this tag is log-sum-exp of all the # scores. alphas_t.append(self.log_sum_exp(next_tag_var).view(1)) forward_var = torch.cat(alphas_t).view(1, -1) terminal_var = forward_var + self.transitions[self.tag_idx[ cfg.SENT_END]] alpha = self.log_sum_exp(terminal_var) return alpha
def __init__(self, emb_mat, tag_idx): super(BiLSTM_CRF, self).__init__() self.emb_mat_tensor = Variable(cuda.FloatTensor(emb_mat)) self.embedding_dim = self.emb_mat_tensor.size(1) self.hidden_dim = cfg.LSTM_HIDDEN_SIZE self.vocab_size = self.emb_mat_tensor.size(0) self.tag_idx = tag_idx self.tagset_size = len(tag_idx) self.word_embeds = nn.Embedding(self.vocab_size, self.embedding_dim) self.lstm = nn.LSTM(self.embedding_dim, self.hidden_dim, num_layers=1, bidirectional=True) # Maps the output of the LSTM into tag space. self.hidden2tag = nn.Linear(self.hidden_dim * 2, self.tagset_size) # Matrix of transition parameters. Entry i,j is the score of # transitioning *to* i *from* j. self.transitions = nn.Parameter( torch.randn(self.tagset_size, self.tagset_size)).cuda() # These two statements enforce the constraint that we never transfer # to the start tag and we never transfer from the stop tag self.transitions.data[tag_idx[cfg.SENT_START], :] = -10000 self.transitions.data[:, tag_idx[cfg.SENT_END]] = -10000 self.hidden = self.init_hidden()
def __init__(self, n_components, tolerance=1e-5, max_step=1000, verbose=True): ''' Initialize the object. Input ----- n_components: int number of Binomial Distributions in the Mixture. tolerance: Float the object fits the data by EM iteration. tolerance is used to define one of the conditions for the iteration to stop. This condition says that the iteration continues until the change of the parameters within the current iteration is greater than tolerance. max_step: int the maximum number of iteration steps. verbose: Boolean whether to print out the information of the fitting process. ''' self.K = n_components # int, number of Binomial distributions in the Mixture self.tolerance = tolerance self.max_step = max_step self.verbose = verbose # initialize the pi_list pi_list = Uniform(low=1e-6, high=1e0 - 1e-6).sample([self.K - 1]).to(device) pi_K = t.FloatTensor([1e0]) - pi_list.sum() self.pi_list = torch.cat([pi_list, pi_K], dim=0) # initialize the theta_list self.theta_list = Uniform(low=1e-6, high=1e0 - 1e-6).sample([self.K])
def forward(self, input=tc.FloatTensor(0).detach(), target=tc.FloatTensor(0).detach()): ''' This function runs forward pass with softmax and categorical cross entropy :param input: the previous layer output :param target: the labels :return: the prediction ''' self.input = input.detach() self.target = target self.output, self.loss = self.softmax_with_cross_entropy( self.input, self.target) return self.output
def forward(self, batch_item_index, batch_x, batch_word_seq, batch_neighbor_index): z_1 = F.tanh(self.linear1(batch_x)) # z_1 = F.dropout(z_1, self.drop_rate) z_rating = F.tanh(self.linear2(z_1)) z_content = self.get_content_z(batch_word_seq) gate = F.sigmoid( z_rating.mm(self.gate_matrix1) + z_content.mm(self.gate_matrix2) + self.gate_bias) gated_embedding = gate * z_rating + (1 - gate) * z_content # save the embedding for direct lookup self.item_gated_embedding.weight[ batch_item_index] = gated_embedding.data gated_neighbor_embedding = self.item_gated_embedding( batch_neighbor_index) # aug_gated_embedding: [256, 1, 50] aug_gated_embedding = torch.unsqueeze(gated_embedding, 1) score = torch.matmul(aug_gated_embedding, torch.unsqueeze(self.neighbor_attention, 0)) # score: [256, 1, 480] score = torch.bmm(score, gated_neighbor_embedding.permute(0, 2, 1)) # make the 0 in score, which will make a difference in softmax score = torch.where(score == 0, T.FloatTensor([float('-inf')]), score) score = F.softmax(score, dim=2) # if the vectors all are '-inf', softmax will generate 'nan', so replace with 0 score = torch.where(score != score, T.FloatTensor([0]), score) gated_neighbor_embedding = torch.bmm(score, gated_neighbor_embedding) gated_neighbor_embedding = torch.squeeze(gated_neighbor_embedding, 1) # gated_embedding = F.dropout(gated_embedding, self.drop_rate) # gated_neighbor_embedding = F.dropout(gated_neighbor_embedding, self.drop_rate) z_3 = F.tanh(self.linear3(gated_embedding)) # z_3 = F.dropout(z_3, self.drop_rate) z_3_neighbor = F.tanh(self.linear3(gated_neighbor_embedding)) # z_3_neighbor = F.dropout(z_3_neighbor, self.drop_rate) y_pred = F.sigmoid( self.linear4(z_3) + z_3_neighbor.mm(self.linear4.weight.t())) return y_pred
def __getitem__(self, index): if not hasattr(self, 'hdf5_dataset'): self.open_hdf5() idx_eFTrack_Eta = tcuda.LongTensor([self.eFTrack_Eta[index]], device=self.rank) idx_eFTrack_Phi = tcuda.LongTensor([self.eFTrack_Phi[index]], device=self.rank) val_eFTrack_PT = tcuda.FloatTensor(self.eFTrack_PT[index], device=self.rank) idx_eFPhoton_Eta = tcuda.LongTensor([self.eFPhoton_Eta[index]], device=self.rank) idx_eFPhoton_Phi = tcuda.LongTensor([self.eFPhoton_Phi[index]], device=self.rank) val_eFPhoton_ET = tcuda.FloatTensor(self.eFPhoton_ET[index], device=self.rank) idx_eFNHadron_Eta = tcuda.LongTensor([self.eFNHadron_Eta[index]], device=self.rank) idx_eFNHadron_Phi = tcuda.LongTensor([self.eFNHadron_Phi[index]], device=self.rank) val_eFNHadron_ET = tcuda.FloatTensor(self.eFNHadron_ET[index], device=self.rank) calorimeter, scaler = self.process_images(idx_eFTrack_Eta, idx_eFPhoton_Eta, idx_eFNHadron_Eta, idx_eFTrack_Phi, idx_eFPhoton_Phi, idx_eFNHadron_Phi, val_eFTrack_PT, val_eFPhoton_ET, val_eFNHadron_ET) # Set labels labels_raw = tcuda.FloatTensor(self.labels[index], device=self.rank) labels_processed = self.process_labels(labels_raw, scaler) if self.return_baseline: base_raw = tcuda.FloatTensor(self.base[index], device=self.rank) base_processed = self.process_baseline(base_raw) return calorimeter, labels_processed, base_processed, scaler return calorimeter, labels_processed
def forward(self, input=tc.FloatTensor(0)): ''' This function runs forward propagation of maxpooling :param input: output of previous layer :return: max pooling operation result ''' self.input = input.detach() self.output, self.indices = self.layer.forward(self.input) return self.output
def train(data, model, optimizer, verbose=True): criterion = nn.NLLLoss() if model.use_cuda: criterion.cuda() correct_actions = 0 total_actions = 0 tot_loss = 0. instance_count = 0 for sentence, actions in data: if len(sentence) <= 2: continue optimizer.zero_grad() model.refresh() outputs, _, actions_done = model(sentence, actions) if model.use_cuda: loss = ag.Variable(cuda.FloatTensor([0])) action_idxs = [ ag.Variable(cuda.LongTensor([a])) for a in actions_done ] else: loss = ag.Variable(torch.FloatTensor([0])) action_idxs = [ ag.Variable(torch.LongTensor([a])) for a in actions_done ] for output, act in zip(outputs, action_idxs): loss += criterion(output.view(-1, 3), act) tot_loss += utils.to_scalar(loss.data) instance_count += 1 for gold, output in zip(actions_done, outputs): pred_act = utils.argmax(output.data) if pred_act == gold: correct_actions += 1 total_actions += len(outputs) loss.backward() optimizer.step() acc = float(correct_actions) / total_actions loss = float(tot_loss) / instance_count if verbose: print( "Number of instances: {} Number of network actions: {}".format( instance_count, total_actions)) print("Acc: {} Loss: {}".format( float(correct_actions) / total_actions, tot_loss / instance_count))
def forward(self, input=tc.FloatTensor(0).detach()): ''' This function runs forward prop fully connected layer :param input: the previous layer of output :return: the activation function output applied dense operation ''' self.input = input.detach() self.act_output = self.relu( torch.mm(self.input, self.weight) + self.bias).detach() return self.act_output
def __init__(self, vocabulary_size, context_size, user_latent_factors_count, item_latent_factors_count): super(ContextMerger, self).__init__() self.user_model = nn.Linear(user_latent_factors_count, context_size, bias=False) self.item_model = nn.Linear(item_latent_factors_count, context_size, bias=False) self.rating_weight = nn.Parameter(device.FloatTensor(1)) self.review_model = nn.Linear(vocabulary_size, context_size, bias=True)
def positional_encoding(self, seq_len, emb_dim): position_encoding = np.array([[ pos / np.power(10000, 2.0 * (j // 2) / emb_dim) for j in range(emb_dim) ] for pos in range(seq_len)]) # apply sin to even indices in the array; 2i position_encoding[:, 0::2] = np.sin(position_encoding[:, 0::2]) # apply cos to odd indices in the array; 2i+1 position_encoding[:, 1::2] = np.cos(position_encoding[:, 1::2]) return T.FloatTensor(position_encoding, requires_grad=False)
def __init__( self, num_params, # number of model parameters sigma_init=0.1, # initial standard deviation sigma_decay=0.999, # anneal standard deviation sigma_limit=0.01, # stop annealing if less than this learning_rate=0.01, # learning rate for standard deviation learning_rate_decay=0.9999, # annealing the learning rate learning_rate_limit=0.001, # stop annealing learning rate popsize=255, # population size antithetic=False, # whether to use antithetic sampling forget_best=True # forget historical best ): self.num_params = num_params self.sigma_decay = sigma_decay self.sigma = sigma_init self.sigma_limit = sigma_limit self.learning_rate = learning_rate self.learning_rate_decay = learning_rate_decay self.learning_rate_limit = learning_rate_limit self.popsize = popsize if self.popsize % 2 == 1: self.popsize += 1 self.antithetic = antithetic self.half_popsize = int(self.popsize / 2) self.reward = np.zeros(self.popsize) self.best_mu = torch_c.FloatTensor(self.num_params).fill_(0.0) self.mu = torch_c.FloatTensor(self.num_params).fill_( 0.0 ) # I believe borrow the DNN initial val will help, try it later self.best_reward = 0 self.first_interation = True self.forget_best = forget_best self.diversity_base = 0 self.mdb = 0 print(self.sigma, self.learning_rate)
def sample(self) -> ParameterOrVariable: """Return a sample from the normal distribution with these parameters. Returns: Tensor of N(self.mean, self.alpha) samples, same shape. This uses the reparametrization trick, so the return value is differentiable w.r.t. `self.mean` and `self.alpha`, and can be used as such in a backpropagation operation. """ epsilon = TP.FloatTensor(*self.size()).normal_(mean=0, std=1) return self.mean + Variable(epsilon) * self.alpha
def _score_sentence(self, feats, tags): # Gives the score of a provided tag sequence score = Variable(cuda.FloatTensor([0])) start_tag = Variable( torch.cuda.LongTensor([self.tag_idx[cfg.SENT_START]])) tags = torch.cat([start_tag, tags], dim=0) for i, feat in enumerate(feats): score = score + self.transitions[tags.data[i + 1], tags.data[i]] score += feat[tags[i + 1]] score = score + self.transitions[self.tag_idx[cfg.SENT_END], tags.data[-1]] return score
def validation(loader, model, writer): model.eval() total_loss = cuda.FloatTensor([0.]) total_accu = cuda.FloatTensor([0.]) widgets = [ "processing: ", progressbar.Percentage(), " ", progressbar.ETA(), " ", progressbar.FileTransferSpeed(), ] bar = progressbar.ProgressBar(widgets=widgets, max_value=len(loader)).start() for i, batch in enumerate(loader): bar.update(i) batch_data, batch_label = batch batch_data = Variable(batch_data).cuda() batch_label = Variable(batch_label).cuda() logits = model(batch_data) loss = model.criterion(logits, batch_label) accu = tools.accuracy(logits=logits, targets=batch_label).data total_accu.add_(accu) total_loss.add_(loss.data) mean_loss = total_loss.cpu().numpy() / (i + 1) mean_accu = total_accu.cpu().numpy() / (i + 1) writer.add_scalar('val/loss', scalar_value=mean_loss, global_step=EPOCH) writer.add_scalar('val/accu', scalar_value=mean_accu, global_step=EPOCH) print('') print("validation-->epoch:{},mean_loss:{}, mean_accuracy:{}".format( EPOCH, mean_loss, mean_accu)) bar.finish()
def forward(self, input=tc.FloatTensor(0).detach()): ''' This function runs forward prop flatten operation from 4d to 2d :param input: the previous layer output :return: 2d matrix ''' self.input = input.detach() self.batch_size = self.input.shape[0] self.channel_size = self.input.shape[1] self.width = self.input.shape[2] self.height = self.input.shape[3] self.output = self.input.view(self.batch_size, -1).detach() return self.output
def neg_log_likelihood(self, sentences, tags): total_loss = Variable(cuda.FloatTensor([0])) for sentence, tag in zip(sentences, tags): sentence = sentence[1:-1] tag = tag[1:-1] sent_var = Variable(cuda.LongTensor(sentence)) tag_var = Variable(cuda.LongTensor(tag)) feats = self._get_lstm_features(sent_var) forward_score = self._forward_alg(feats) gold_score = self._score_sentence(feats, tag_var) total_loss += forward_score - gold_score return total_loss
def __init__(self, input, dense_number): ''' This function creates dense instance with given dense size :param input: output of previous layer :param dense_number: number of dense layer ''' self.input = input.detach() self.dense_number = dense_number self.batch_size = self.input.shape[0] self.input_size = self.input.shape[1] #initialize weights and biases self.weight = tc.FloatTensor( np.random.normal(size=(self.input_size, self.dense_number), loc=0, scale=0.01).astype(np.float32)).type( torch.float32).detach() self.bias = tc.FloatTensor(np.zeros( (1, dense_number))).type(torch.float32).detach() #momentum terms self.delta_w = 0 self.delta_b = 0
def evaluate(data, model, verbose=False): correct_actions = 0 total_actions = 0 tot_loss = 0. instance_count = 0 criterion = nn.NLLLoss() if model.use_cuda: criterion.cuda() for sentence, actions in data: if len(sentence) > 1: outputs, _, actions_done = model(sentence, actions) if model.use_cuda: loss = ag.Variable(cuda.FloatTensor([0])) action_idxs = [ ag.Variable(cuda.LongTensor([a])) for a in actions_done ] else: loss = ag.Variable(torch.FloatTensor([0])) action_idxs = [ ag.Variable(torch.LongTensor([a])) for a in actions_done ] for output, act in zip(outputs, action_idxs): loss += criterion(output.view((-1, 3)), act) tot_loss += utils.to_scalar(loss.data) instance_count += 1 for gold, output in zip(actions_done, outputs): pred_act = utils.argmax(output.data) if pred_act == gold: correct_actions += 1 total_actions += len(outputs) acc = float(correct_actions) / total_actions loss = float(tot_loss) / instance_count if verbose: print( "Number of instances: {} Number of network actions: {}".format( instance_count, total_actions)) print("Acc: {} Loss: {}".format( float(correct_actions) / total_actions, tot_loss / instance_count)) return acc, loss
def forward(self, input): ''' This function runs forward prop for dropout :param input: the output of the previous layer :return: dropout result ''' self.input = input.detach() #create mask self.dropout_matrix = tc.FloatTensor( np.random.binomial(1, 1 - self.dropout, size=self.kernel_number)).expand_as( self.input).detach() #apply mask self.output = torch.mul(self.input, self.dropout_matrix).detach() / ( 1 - self.dropout + np.exp(-32)) return self.output
def __init__(self, input, dropout): ''' This function create instance for Dropout layer :param input: the output from previous layer :param dropout: dropout layer probability rate ''' #check the input that has dimension of two if len(input.shape) != 2: raise ValueError('Input shape should be 2 dimensional') #initialize class attributes self.input = input.detach() self.dropout = dropout self.batch_size = self.input.shape[0] self.kernel_number = self.input.shape[1] #create dropout matrix self.dropout_matrix = tc.FloatTensor(np.zeros( self.input.shape)).detach()