def batch_act(self, observations): batchsize = len(observations) # initialize a table of replies with this agent's id batch_reply = [{'id': self.getID()} for _ in range(batchsize)] # convert the observations into batches of inputs and targets # `labels` stores the true labels returned in the `ys` vector # `valid_inds` tells us the indices of all valid examples # e.g. for input [{}, {'text': 'hello'}, {}, {}], valid_inds is [1] # since the other three elements had no 'text' field xs, ys, labels, valid_inds, is_training = self.vectorize(observations) if xs is None: # no valid examples, just return empty responses return batch_reply predictions = self.predict(xs, ys, is_training) # maps returns predictions back to the right `valid_inds` # in the example above, a prediction `world` should reply to `hello` PaddingUtils.map_predictions(predictions.cpu().data, valid_inds, batch_reply, observations, self.dict, self.END_IDX, labels=labels, answers=labels, ys=ys.data if ys is not None else None, report_freq=self.opt.get( 'report_freq', 0)) return batch_reply
def batch_act(self, observations): batch_reply = [{'id': self.getID()} for _ in range(len(observations))] if any(['labels' in obs for obs in observations]): # if we are starting a new training epoch, reinitialize hidden if not self.is_training: self.hidden = self.model.init_hidden(self.batchsize) self.is_training = True data_list, targets_list, _c, _v, y_lens = self.vectorize( observations, self.opt['seq_len'], self.is_training ) else: # if we just finished training, reinitialize hidden if self.is_training: self.hidden = self.model.init_hidden(self.batchsize) self.is_training = False data_list, targets_list, labels, valid_inds, y_lens = self.vectorize( observations, self.opt['seq_len'], self.is_training ) if data_list is None: # not enough data to batch act yet, return empty responses return batch_reply batch_reply = [] # during evaluation, len(data_list) is always 1 # during training, len(dat_list) >= 0: vectorize returns a list # containing all batches available at the time it is called for i in range(len(data_list)): temp_dicts = [{'id': self.getID()} for _ in range(len(observations))] # ignore case when we do not return any valid indices if data_list[i] is not None: output, hidden, predictions = self.predict( data_list[i], self.hidden, targets_list[i], self.is_training, y_lens ) self.hidden = self.repackage_hidden(hidden) if predictions is not None: # map predictions back to the right order PaddingUtils.map_predictions( predictions.cpu(), valid_inds, temp_dicts, observations, self.dict, self.END_IDX, report_freq=self.opt['report_freq'], ) batch_reply += temp_dicts # for prediction metrics computations, we get rid of PERSON1 and PERSON2 tokens if not self.is_training: for reply in batch_reply: if 'text' in reply: reply['text'] = reply['text'].replace('PERSON1 ', '') reply['text'] = reply['text'].replace('PERSON2 ', '') return batch_reply
def vectorize(self, observations): """Convert a list of observations into input & target tensors.""" is_training = any(('labels' in obs for obs in observations)) # utility function for padding text and returning lists of indices # parsed using the provided dictionary xs, ys, labels, valid_inds, _, _ = PaddingUtils.pad_text( observations, self.dict, end_idx=self.END_IDX, null_idx=self.NULL_IDX, dq=False, eval_labels=True) if xs is None: return None, None, None, None, None # move lists of indices returned above into tensors xs = torch.LongTensor(xs) if self.use_cuda: xs = xs.cuda() xs = Variable(xs) if ys is not None: ys = torch.LongTensor(ys) if self.use_cuda: ys = ys.cuda() ys = Variable(ys) return xs, ys, labels, valid_inds, is_training
def vectorize(self, observations, seq_len, is_training): """ Convert a list of observations into input & target tensors. """ labels = None valid_inds = None y_lens = None if is_training: for obs in observations: if obs: if 'text2vec' in obs: self.next_batch += obs['text2vec'] if len(self.next_batch) <= self.batchsize: return None, None, None, None, None else: data_list = [] targets_list = [] # total is the number of batches total = len(self.next_batch) // self.batchsize for _ in range(total): batch = self.next_batch[:self.batchsize] self.next_batch = self.next_batch[self.batchsize:] source = torch.LongTensor(batch).t().contiguous() data = Variable(source[:seq_len]) targets = Variable(source[1:]) if self.use_cuda: data = data.cuda() targets = targets.cuda() data_list.append(data) targets_list.append(targets) else: # here we get valid examples and pad them with zeros xs, ys, labels, valid_inds, _, y_lens = PaddingUtils.pad_text( observations, self.dict, end_idx=self.END_IDX, null_idx=self.NULL_IDX) if self.use_cuda: if xs is not None: xs = Variable(torch.LongTensor(xs)).cuda() if ys is not None: ys = Variable(torch.LongTensor(ys)).cuda() else: if xs is not None: xs = Variable(torch.LongTensor(xs)) if ys is not None: ys = Variable(torch.LongTensor(ys)) data_list = [xs] targets_list = [ys] return data_list, targets_list, labels, valid_inds, y_lens