Source code for target_extraction.allen.models.target_sentiment.util
from collections import defaultdict
from typing import List, Union, Optional, Dict
from allennlp.data import TextFieldTensors
from allennlp.models import Model
from allennlp.modules import TextFieldEmbedder
import torch
[docs]def loss_weight_order(model: Model, loss_weights: Optional[List[float]],
label_name: str) -> Union[None, List[float]]:
'''
:param model: The model that you want to know the loss weights for. Requires
a vocab.
:param loss_weights: The loss weights to give to the labels. Can be None and
if so returns None.
:param label_name: The name of the vocab for the label that is to be
predicted.
:returns: None if `loss weights` is None. Else return a list of weights to
give to each label, where the original loss weights are ordered
by `['negative', 'neutral', 'positive']` and the returned are
ordered by occurrence in the models vocab for that `label_name`
'''
if loss_weights is not None:
label_name_index = model.vocab.get_token_to_index_vocabulary(namespace=label_name)
label_name_index = sorted(label_name_index.items(), key=lambda x: x[1])
temp_loss_weights = []
loss_weight_labels = ['negative', 'neutral', 'positive']
loss_name_weights = {label_name: weight for label_name, weight
in zip(loss_weight_labels, loss_weights)}
for label_name, index in label_name_index:
temp_loss_weights.append(loss_name_weights[label_name])
return temp_loss_weights
else:
return None
[docs]def elmo_input_reshape(inputs: TextFieldTensors, batch_size: int,
number_targets: int, batch_size_num_targets: int
) -> TextFieldTensors:
'''
NOTE: This does not work for the hugginface transformers as when they are
processed by the token indexers they produce additional key other than
token ids such as mask ids and segment ids that also need handling, of
which we have not had time to handle this yet. A way around this, which
would be more appropriate, would be to use `target_sequences` like in the
`InContext` model, to generate contextualised targets from the context rather
than using the target words as is without context.
:param inputs: The token indexer dictionary where the keys state the token
indexer and the values are the Tensors that are of shape
(Batch Size, Number Targets, Sequence Length)
:param batch_size: The Batch Size
:param number_targets: The max number of targets in the batch
:param batch_size_num_targets: Batch Size * number of targets
:returns: If the inputs contains a `elmo` or 'token_characters' key it will
reshape all the keys values into shape
(Batch Size * Number Targets, Sequence Length) so that it can be
processed by the ELMO or character embedder/encoder.
'''
if 'elmo' in inputs or 'token_characters' in inputs:
temp_inputs: TextFieldTensors = defaultdict(dict)
for key, inner_key_value in inputs.items():
for inner_key, value in inner_key_value.items():
temp_value = value.view(batch_size_num_targets, *value.shape[2:])
temp_inputs[key][inner_key] = temp_value
return dict(temp_inputs)
else:
return inputs
[docs]def elmo_input_reverse(embedded_input: torch.Tensor,
inputs: TextFieldTensors, batch_size: int,
number_targets: int, batch_size_num_targets: int
) -> torch.Tensor:
'''
:param embedded_input: The embedding generated after the embedder has been
forwarded over the `inputs`
:param inputs: The token indexer dictionary where the keys state the token
indexer and the values are the Tensors that are of shape
(Batch Size, Number Targets, Sequence Length)
:param batch_size: The Batch Size
:param number_targets: The max number of targets in the batch
:param batch_size_num_targets: Batch Size * number of targets
:returns: If the inputs contains a `elmo` or 'token_characters' key it will
reshape the `embedded_input` into the original shape of
(Batch Size, Number Targets, Sequence Length, embedding dim)
'''
if 'elmo' in inputs or 'token_characters' in inputs:
return embedded_input.view(batch_size, number_targets,
*embedded_input.shape[1:])
return embedded_input
[docs]def concat_position_embeddings(embedding_context: torch.Tensor,
position_indexes: Optional[Dict[str, torch.LongTensor]] = None,
target_position_embedding: Optional[TextFieldEmbedder] = None
) -> torch.Tensor:
'''
:param embedding_context: Tensor of shape (batch size * number targets,
context sequence length, context dim)
:param position_indexes: Dictionary of token indexer name to a
Tensor of shape (batch size, number targets,
text sequence length)
:param target_position_embedding: An embedding function for the position
indexes, where the dimension of the position
embedding is `position dim`.
:returns: If `position_indexes` and `target_position_embedding` are None then
the `embedding_context` is returned without any change. Else the
relevant position embeddings are concatenated onto the relevant
token embeddings within the `embedding_context` to create a
Tensor of shape (batch size * number targets, text sequence length,
context dim + position dim)
:raises ValueError: If `target_position_embedding` is not None when
`position_indexes` is None.
'''
if target_position_embedding:
if position_indexes is None:
raise ValueError('This model requires `position_indexes` as '
'input to the `target_position_embedding` '
'forward function to get the position embeddings')
target_position_embeddings = target_position_embedding(position_indexes)
batch_size_num_targets, context_sequence_length, context_dim = embedding_context.shape
position_embedding_dim = target_position_embeddings.shape[-1]
# re-shape position_embeddings
target_position_embeddings = target_position_embeddings.view(batch_size_num_targets,
context_sequence_length,
position_embedding_dim)
embedding_context = torch.cat((embedding_context,
target_position_embeddings), -1)
return embedding_context