def __call__(self, # type: ignore predictions: torch.LongTensor, gold_targets: torch.LongTensor) -> None: """ Update precision counts. Parameters ---------- predictions : ``torch.LongTensor``, required Batched predicted tokens of shape `(batch_size, max_sequence_length)`. references : ``torch.LongTensor``, required Batched reference (gold) translations with shape `(batch_size, max_gold_sequence_length)`. Returns ------- None """ with torch.no_grad(): predictions, gold_targets = predictions.detach(), gold_targets.detach() for ngram_size, _ in enumerate(self._ngram_weights, start=1): precision_matches, precision_totals = self._get_modified_precision_counts( predictions, gold_targets, ngram_size) self._precision_matches[ngram_size] += precision_matches self._precision_totals[ngram_size] += precision_totals if not self._exclude_indices: self._prediction_lengths += predictions.size(0) * predictions.size(1) self._reference_lengths += gold_targets.size(0) * gold_targets.size(1) else: valid_predictions_mask = self._get_valid_tokens_mask(predictions) self._prediction_lengths += valid_predictions_mask.sum().item() valid_gold_targets_mask = self._get_valid_tokens_mask(gold_targets) self._reference_lengths += valid_gold_targets_mask.sum().item()
def _get_mask_for_eval(self, mask: torch.LongTensor, pos_tags: torch.LongTensor) -> torch.LongTensor: """ Dependency evaluation excludes words are punctuation. Here, we create a new mask to exclude word indices which have a "punctuation-like" part of speech tag. Parameters ---------- mask : ``torch.LongTensor``, required. The original mask. pos_tags : ``torch.LongTensor``, required. The pos tags for the sequence. Returns ------- A new mask, where any indices equal to labels we should be ignoring are masked. """ new_mask = mask.detach() for label in self._pos_to_ignore: label_mask = pos_tags.eq(label).long() new_mask = new_mask * (1 - label_mask) return new_mask
def decode_answer(self, original_numbers: List[Union[int, float]], number_indices: torch.LongTensor, best_signs_for_numbers: torch.LongTensor, **kwargs: Dict[str, Any]) -> Dict[str, Any]: sign_remap = {0: 0, 1: 1, 2: -1} original_numbers = self._special_numbers + original_numbers predicted_signs = [ sign_remap[it] for it in best_signs_for_numbers.detach().cpu().numpy() ] result = sum([ sign * number for sign, number in zip(predicted_signs, original_numbers) ]) predicted_answer = str(round(result, self._arithmetic_round_ndigits)) numbers = [] for i, (value, sign) in enumerate(zip(original_numbers, predicted_signs)): numbers.append({ 'value': value, 'sign': sign, 'is_special': i < len(self._special_numbers) }) if number_indices[-1][0] == -1: # There is a dummy 0 number at position -1 added in some cases; we are # removing that here. numbers.pop() answer_dict = {'value': predicted_answer, 'numbers': numbers} return answer_dict
def decode_answer(self, best_count_number: torch.LongTensor, **kwargs: Dict[str, Any]) -> Dict[str, Any]: predicted_count = best_count_number.detach().cpu().numpy().tolist() predicted_answer = str(predicted_count) answer_dict = {'value': predicted_answer, 'count': predicted_count} return answer_dict
def _get_unknown_tag_mask(self, mask: torch.LongTensor, head_tags: torch.LongTensor) -> torch.LongTensor: oov = self.vocab.get_token_index(DEFAULT_OOV_TOKEN, 'head_tags') new_mask = mask.detach() oov_mask = head_tags.eq(oov).long() new_mask = new_mask * (1 - oov_mask) return new_mask
def __call__(self, prediction_labels: torch.Tensor, gold_labels: torch.Tensor, mask: torch.LongTensor) -> Dict[str, float]: """ 计算 metric. :param prediction_labels: 预测结果 shape: (B,), 这是模型解码成label的结果,注意是 label,不是 logits :param gold_labels: 实际结果 shape: (B,) :param mask: mask, shape: (B,) :return 每一个label的f1值。这包括 precision, recall, f1。具体结果类似: {"precision_[label]": [value], "recall_[label]" : [value], "f1-measure_[label]": [value], "precision-overall": [value], "recall-overall": [value], "f1-measure-overall": [value]} 说明: "*-overall" 表示的是所有 命中 在初始化参数的 labels 的综合 metric 值。 这是有必要的,作为一个综合的值作为统一衡量。 """ assert prediction_labels.dim() == 1, "predictions shape 是 (B,)" assert gold_labels.dim() == 1, "gold_labels shape 是 (B,)" if mask is not None: assert mask.dim() == 1, "mask shape 是 (B,)" # 转换到 cpu 进行计算 prediction_labels, gold_labels = prediction_labels.detach().cpu( ), gold_labels.detach().cpu() if mask is not None: bool_mask = mask.detach().cpu().bool() prediction_labels = prediction_labels.masked_select(bool_mask) gold_labels = gold_labels.masked_select(bool_mask) # 当前 batch 下的 true_positives true_positives = defaultdict(int) false_positives = defaultdict(int) false_negatives = defaultdict(int) for label, label_index in zip(self._labels, self._label_indices): num_prediction = (prediction_labels == label_index).sum().item() num_golden = (gold_labels == label_index).sum().item() # 计算 true positives label_mask = (prediction_labels == label_index) label_predictions = prediction_labels.masked_select(label_mask) label_gold = gold_labels.masked_select(label_mask) true_positives[label] = ( label_predictions == label_gold).sum().item() false_positives[label] = num_prediction - true_positives[label] false_negatives[label] = num_golden - true_positives[label] return self._metric(true_positives=true_positives, false_positives=false_positives, false_negatives=false_negatives)
def __call__(self, predictions: torch.LongTensor, gold_labels: torch.LongTensor, mask: torch.LongTensor = None): """ Parameters ---------- predictions : ``torch.Tensor``, required. A tensor of real-valued predictions of shape (batch_size, slate_length). gold_labels : ``torch.Tensor``, required. A tensor of real-valued labels of shape (batch_size, slate_length). """ if mask is None: mask = torch.ones_like(gold_labels).bool() self._all_predictions.append(predictions.detach().cpu()) self._all_gold_labels.append(gold_labels.detach().cpu()) self._all_masks.append(mask.detach().cpu())
def _save_ply( f, verts: torch.Tensor, faces: torch.LongTensor, verts_normals: torch.Tensor, decimal_places: Optional[int] = None, ) -> None: """ Internal implementation for saving 3D data to a .ply file. Args: f: File object to which the 3D data should be written. verts: FloatTensor of shape (V, 3) giving vertex coordinates. faces: LongTensor of shsape (F, 3) giving faces. verts_normals: FloatTensor of shape (V, 3) giving vertex normals. decimal_places: Number of decimal places for saving. """ assert not len(verts) or (verts.dim() == 2 and verts.size(1) == 3) assert not len(faces) or (faces.dim() == 2 and faces.size(1) == 3) assert not len(verts_normals) or ( verts_normals.dim() == 2 and verts_normals.size(1) == 3 ) print('ply\nformat ascii 1.0', file=f) print(f'element vertex {verts.shape[0]}', file=f) print('property float x', file=f) print('property float y', file=f) print('property float z', file=f) if verts_normals.numel() > 0: print('property float nx', file=f) print('property float ny', file=f) print('property float nz', file=f) print(f'element face {faces.shape[0]}', file=f) print('property list uchar int vertex_index', file=f) print('end_header', file=f) if not (len(verts) or len(faces)): warnings.warn("Empty 'verts' and 'faces' arguments provided") return if decimal_places is None: float_str = '%f' else: float_str = '%' + '.%df' % decimal_places vert_data = torch.cat((verts, verts_normals), dim=1) np.savetxt(f, vert_data.detach().numpy(), float_str) faces_array = faces.detach().numpy() if torch.any(faces >= verts.shape[0]) or torch.any(faces < 0): warnings.warn('Faces have invalid indices') if len(faces_array): np.savetxt(f, faces_array, '3 %d %d %d')
def decode_label(self, model_outputs: MRCNerOutput, label_indices: torch.LongTensor) -> List: """ 将 label indices 解码成 span list :param model_outputs: 模型输出 :param label_indices: label indices :return: span list """ mask = model_outputs.mask.detach().cpu() label_indices = label_indices.detach().cpu() return self._label_decoder(label_indices=label_indices, mask=mask)
def next_inputs(self, time: int, outputs: torch.Tensor, sample_ids: torch.LongTensor) -> NextInputTuple: del time, outputs # unused by next_inputs_fn if self._use_finish: hard_ids = torch.argmax(sample_ids, dim=-1) finished = (hard_ids == self._end_token) else: finished = self._start_tokens.new_zeros(self._batch_size, dtype=torch.uint8) if self._stop_gradient: sample_ids = sample_ids.detach() next_inputs = torch.matmul(sample_ids, self._embedding) return (finished, next_inputs)
def decode_label(self, model_outputs: NerModelOutputs, label_indices: torch.LongTensor) -> List: """ 将 label indices 解码成 span list :param model_outputs: 模型输出 :param label_indices: label indices :return: span list """ if self._label_decoder is None: self._label_decoder = SequenceLabelDecoder( label_vocabulary=self._label_vocabulary) mask = model_outputs.mask.detach().cpu() label_indices = label_indices.detach().cpu() return self._label_decoder(label_indices=label_indices, mask=mask)
def _process_scores( self, keys: torch.LongTensor, scores: torch.FloatTensor, positive_mask: torch.FloatTensor, head_side: bool, ) -> None: # Transfer to cpu and convert to numpy scores = scores.detach().cpu().numpy() positive_mask = positive_mask.detach().cpu().numpy() keys = keys.detach().cpu().numpy() # Ensure that each key gets counted only once for i in range(keys.shape[0]): # include head_side flag into key to differentiate between (h, r) and (r, t) key = (head_side, ) + tuple(map(int, keys[i])) self.all_scores[key] = scores[i] self.all_positives[key] = positive_mask[i]
def next_inputs(self, embedding_fn: EmbeddingFn, time: int, outputs: torch.Tensor, sample_ids: torch.LongTensor) -> NextInputTuple: del outputs # unused by next_inputs_fn if self._use_finish: hard_ids = torch.argmax(sample_ids, dim=-1) finished = (hard_ids == self._end_token) else: finished = torch.zeros_like(self._start_tokens, dtype=torch.uint8) if self._stop_gradient: sample_ids = sample_ids.detach() indices = torch.arange(sample_ids.size(-1), device=sample_ids.device) times = torch.full_like(indices, time + 1) embeddings = embedding_fn(indices, times) next_inputs = torch.matmul(sample_ids, embeddings) return (finished, next_inputs)
def forward( self, passage_attention: torch.Tensor, passage_lengths: List[int], count_answer: torch.LongTensor = None, metadata: List[Dict[str, Any]] = None) -> Dict[str, torch.Tensor]: device_id = allenutil.get_device_of(passage_attention) batch_size, max_passage_length = passage_attention.size() # Shape: (B, passage_length) passage_mask = (passage_attention >= 0).float() # List of (B, P) shaped tensors scaled_attentions = [ passage_attention * sf for sf in self.scaling_vals ] # Shape: (B, passage_length, num_scaling_factors) scaled_passage_attentions = torch.stack(scaled_attentions, dim=2) # Shape (batch_size, 1) passage_len_bias = self.passagelength_to_bias( passage_mask.sum(1, keepdim=True)) scaled_passage_attentions = scaled_passage_attentions * passage_mask.unsqueeze( 2) # Shape: (B, passage_length, hidden_dim) count_hidden_repr = self.passage_attention_to_count( scaled_passage_attentions, passage_mask) # Shape: (B, passage_length, 1) -- score for each token passage_span_logits = self.passage_count_hidden2logits( count_hidden_repr) # Shape: (B, passage_length) -- sigmoid on token-score token_sigmoids = torch.sigmoid(passage_span_logits.squeeze(2)) token_sigmoids = token_sigmoids * passage_mask # Shape: (B, 1) -- sum of sigmoids. This will act as the predicted mean # passage_count_mean = torch.sum(token_sigmoids, dim=1, keepdim=True) + passage_len_bias passage_count_mean = torch.sum(token_sigmoids, dim=1, keepdim=True) # Shape: (1, count_vals) self.countvals = allenutil.get_range_vector( 10, device=device_id).unsqueeze(0).float() variance = 0.2 # Shape: (batch_size, count_vals) l2_by_vsquared = torch.pow(self.countvals - passage_count_mean, 2) / (2 * variance * variance) exp_val = torch.exp(-1 * l2_by_vsquared) + 1e-30 # Shape: (batch_size, count_vals) count_distribution = exp_val / (torch.sum(exp_val, 1, keepdim=True)) # Loss computation output_dict = {} loss = 0.0 pred_count_idx = torch.argmax(count_distribution, 1) if count_answer is not None: # L2-loss passage_count_mean = passage_count_mean.squeeze(1) L2Loss = F.mse_loss(input=passage_count_mean, target=count_answer.float()) loss = L2Loss predictions = passage_count_mean.detach().cpu().numpy() predictions = np.round_(predictions) gold_count = count_answer.detach().cpu().numpy() correct_vec = (predictions == gold_count) correct_perc = sum(correct_vec) / batch_size # print(f"{correct_perc} {predictions} {gold_count}") self.count_acc(correct_perc) # loss = F.cross_entropy(input=count_distribution, target=count_answer) # List of predicted count idxs, Shape: (B,) # correct_vec = (pred_count_idx == count_answer).float() # correct_perc = torch.sum(correct_vec) / batch_size # self.count_acc(correct_perc.item()) batch_loss = loss / batch_size output_dict["loss"] = batch_loss output_dict["passage_attention"] = passage_attention output_dict["passage_sigmoid"] = token_sigmoids output_dict["count_mean"] = passage_count_mean output_dict["count_distritbuion"] = count_distribution output_dict["count_answer"] = count_answer output_dict["pred_count"] = pred_count_idx return output_dict
def _save_ply( f, verts: torch.Tensor, faces: torch.LongTensor, verts_normals: torch.Tensor, ascii: bool, decimal_places: Optional[int] = None, ) -> None: """ Internal implementation for saving 3D data to a .ply file. Args: f: File object to which the 3D data should be written. verts: FloatTensor of shape (V, 3) giving vertex coordinates. faces: LongTensor of shsape (F, 3) giving faces. verts_normals: FloatTensor of shape (V, 3) giving vertex normals. ascii: (bool) whether to use the ascii ply format. decimal_places: Number of decimal places for saving if ascii=True. """ assert not len(verts) or (verts.dim() == 2 and verts.size(1) == 3) assert not len(faces) or (faces.dim() == 2 and faces.size(1) == 3) assert not len(verts_normals) or (verts_normals.dim() == 2 and verts_normals.size(1) == 3) if ascii: f.write(b"ply\nformat ascii 1.0\n") elif sys.byteorder == "big": f.write(b"ply\nformat binary_big_endian 1.0\n") else: f.write(b"ply\nformat binary_little_endian 1.0\n") f.write(f"element vertex {verts.shape[0]}\n".encode("ascii")) f.write(b"property float x\n") f.write(b"property float y\n") f.write(b"property float z\n") if verts_normals.numel() > 0: f.write(b"property float nx\n") f.write(b"property float ny\n") f.write(b"property float nz\n") f.write(f"element face {faces.shape[0]}\n".encode("ascii")) f.write(b"property list uchar int vertex_index\n") f.write(b"end_header\n") if not (len(verts) or len(faces)): warnings.warn("Empty 'verts' and 'faces' arguments provided") return vert_data = torch.cat((verts, verts_normals), dim=1).detach().numpy() if ascii: if decimal_places is None: float_str = "%f" else: float_str = "%" + ".%df" % decimal_places np.savetxt(f, vert_data, float_str) else: assert vert_data.dtype == np.float32 if isinstance(f, BytesIO): # tofile only works with real files, but is faster than this. f.write(vert_data.tobytes()) else: vert_data.tofile(f) faces_array = faces.detach().numpy() _check_faces_indices(faces, max_index=verts.shape[0]) if len(faces_array): if ascii: np.savetxt(f, faces_array, "3 %d %d %d") else: # rows are 13 bytes: a one-byte 3 followed by three four-byte face indices. faces_uints = np.full((len(faces_array), 13), 3, dtype=np.uint8) faces_uints[:, 1:] = faces_array.astype(np.uint32).view(np.uint8) if isinstance(f, BytesIO): f.write(faces_uints.tobytes()) else: faces_uints.tofile(f)