Add AlbertForMultipleChoice (#4959)
* Add AlbertForMultipleChoice * Make up to date and add all models to common tests
This commit is contained in:
@@ -67,6 +67,14 @@ AlbertForSequenceClassification
|
|||||||
.. autoclass:: transformers.AlbertForSequenceClassification
|
.. autoclass:: transformers.AlbertForSequenceClassification
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
AlbertForMultipleChoice
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: transformers.AlbertForMultipleChoice
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
AlbertForTokenClassification
|
AlbertForTokenClassification
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
@@ -294,6 +294,7 @@ if is_torch_available():
|
|||||||
AlbertModel,
|
AlbertModel,
|
||||||
AlbertForPreTraining,
|
AlbertForPreTraining,
|
||||||
AlbertForMaskedLM,
|
AlbertForMaskedLM,
|
||||||
|
AlbertForMultipleChoice,
|
||||||
AlbertForSequenceClassification,
|
AlbertForSequenceClassification,
|
||||||
AlbertForQuestionAnswering,
|
AlbertForQuestionAnswering,
|
||||||
AlbertForTokenClassification,
|
AlbertForTokenClassification,
|
||||||
|
|||||||
@@ -1135,3 +1135,112 @@ class AlbertForQuestionAnswering(AlbertPreTrainedModel):
|
|||||||
outputs = (total_loss,) + outputs
|
outputs = (total_loss,) + outputs
|
||||||
|
|
||||||
return outputs # (loss), start_logits, end_logits, (hidden_states), (attentions)
|
return outputs # (loss), start_logits, end_logits, (hidden_states), (attentions)
|
||||||
|
|
||||||
|
|
||||||
|
@add_start_docstrings(
|
||||||
|
"""Albert Model with a multiple choice classification head on top (a linear layer on top of
|
||||||
|
the pooled output and a softmax) e.g. for RocStories/SWAG tasks. """,
|
||||||
|
ALBERT_START_DOCSTRING,
|
||||||
|
)
|
||||||
|
class AlbertForMultipleChoice(AlbertPreTrainedModel):
|
||||||
|
def __init__(self, config):
|
||||||
|
super().__init__(config)
|
||||||
|
|
||||||
|
self.albert = AlbertModel(config)
|
||||||
|
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
||||||
|
self.classifier = nn.Linear(config.hidden_size, 1)
|
||||||
|
|
||||||
|
self.init_weights()
|
||||||
|
|
||||||
|
@add_start_docstrings_to_callable(ALBERT_INPUTS_DOCSTRING.format("(batch_size, num_choices, sequence_length)"))
|
||||||
|
def forward(
|
||||||
|
self,
|
||||||
|
input_ids=None,
|
||||||
|
attention_mask=None,
|
||||||
|
token_type_ids=None,
|
||||||
|
position_ids=None,
|
||||||
|
head_mask=None,
|
||||||
|
inputs_embeds=None,
|
||||||
|
labels=None,
|
||||||
|
output_attentions=None,
|
||||||
|
):
|
||||||
|
r"""
|
||||||
|
labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size,)`, `optional`, defaults to :obj:`None`):
|
||||||
|
Labels for computing the multiple choice classification loss.
|
||||||
|
Indices should be in ``[0, ..., num_choices-1]`` where `num_choices` is the size of the second dimension
|
||||||
|
of the input tensors. (see `input_ids` above)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.BertConfig`) and inputs:
|
||||||
|
loss (:obj:`torch.FloatTensor` of shape `(1,)`, `optional`, returned when :obj:`labels` is provided):
|
||||||
|
Classification loss.
|
||||||
|
classification_scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, num_choices)`):
|
||||||
|
`num_choices` is the second dimension of the input tensors. (see `input_ids` above).
|
||||||
|
|
||||||
|
Classification scores (before SoftMax).
|
||||||
|
hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_hidden_states=True``):
|
||||||
|
Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
|
||||||
|
of shape :obj:`(batch_size, sequence_length, hidden_size)`.
|
||||||
|
|
||||||
|
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
|
||||||
|
attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_attentions=True``):
|
||||||
|
Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
|
||||||
|
:obj:`(batch_size, num_heads, sequence_length, sequence_length)`.
|
||||||
|
|
||||||
|
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
|
||||||
|
heads.
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
from transformers import AlbertTokenizer, AlbertForMultipleChoice
|
||||||
|
import torch
|
||||||
|
|
||||||
|
tokenizer = AlbertTokenizer.from_pretrained('albert-base-v2')
|
||||||
|
model = AlbertForMultipleChoice.from_pretrained('albert-base-v2')
|
||||||
|
|
||||||
|
prompt = "In Italy, pizza served in formal settings, such as at a restaurant, is presented unsliced."
|
||||||
|
choice0 = "It is eaten with a fork and a knife."
|
||||||
|
choice1 = "It is eaten while held in the hand."
|
||||||
|
labels = torch.tensor(0).unsqueeze(0) # choice0 is correct (according to Wikipedia ;)), batch size 1
|
||||||
|
|
||||||
|
encoding = tokenizer.batch_encode_plus([[prompt, choice0], [prompt, choice1]], return_tensors='pt', pad_to_max_length=True)
|
||||||
|
outputs = model(**{k: v.unsqueeze(0) for k,v in encoding.items()}, labels=labels) # batch size is 1
|
||||||
|
|
||||||
|
# the linear classifier still needs to be trained
|
||||||
|
loss, logits = outputs[:2]
|
||||||
|
"""
|
||||||
|
num_choices = input_ids.shape[1] if input_ids is not None else inputs_embeds.shape[1]
|
||||||
|
|
||||||
|
input_ids = input_ids.view(-1, input_ids.size(-1)) if input_ids is not None else None
|
||||||
|
attention_mask = attention_mask.view(-1, attention_mask.size(-1)) if attention_mask is not None else None
|
||||||
|
token_type_ids = token_type_ids.view(-1, token_type_ids.size(-1)) if token_type_ids is not None else None
|
||||||
|
position_ids = position_ids.view(-1, position_ids.size(-1)) if position_ids is not None else None
|
||||||
|
inputs_embeds = (
|
||||||
|
inputs_embeds.view(-1, inputs_embeds.size(-2), inputs_embeds.size(-1))
|
||||||
|
if inputs_embeds is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
outputs = self.albert(
|
||||||
|
input_ids,
|
||||||
|
attention_mask=attention_mask,
|
||||||
|
token_type_ids=token_type_ids,
|
||||||
|
position_ids=position_ids,
|
||||||
|
head_mask=head_mask,
|
||||||
|
inputs_embeds=inputs_embeds,
|
||||||
|
output_attentions=output_attentions,
|
||||||
|
)
|
||||||
|
|
||||||
|
pooled_output = outputs[1]
|
||||||
|
|
||||||
|
pooled_output = self.dropout(pooled_output)
|
||||||
|
logits = self.classifier(pooled_output)
|
||||||
|
reshaped_logits = logits.view(-1, num_choices)
|
||||||
|
|
||||||
|
outputs = (reshaped_logits,) + outputs[2:] # add hidden states and attention if they are here
|
||||||
|
|
||||||
|
if labels is not None:
|
||||||
|
loss_fct = CrossEntropyLoss()
|
||||||
|
loss = loss_fct(reshaped_logits, labels)
|
||||||
|
outputs = (loss,) + outputs
|
||||||
|
|
||||||
|
return outputs # (loss), reshaped_logits, (hidden_states), (attentions)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ from .configuration_marian import MarianConfig
|
|||||||
from .configuration_utils import PretrainedConfig
|
from .configuration_utils import PretrainedConfig
|
||||||
from .modeling_albert import (
|
from .modeling_albert import (
|
||||||
AlbertForMaskedLM,
|
AlbertForMaskedLM,
|
||||||
|
AlbertForMultipleChoice,
|
||||||
AlbertForPreTraining,
|
AlbertForPreTraining,
|
||||||
AlbertForQuestionAnswering,
|
AlbertForQuestionAnswering,
|
||||||
AlbertForSequenceClassification,
|
AlbertForSequenceClassification,
|
||||||
@@ -308,6 +309,7 @@ MODEL_FOR_MULTIPLE_CHOICE_MAPPING = OrderedDict(
|
|||||||
(RobertaConfig, RobertaForMultipleChoice),
|
(RobertaConfig, RobertaForMultipleChoice),
|
||||||
(BertConfig, BertForMultipleChoice),
|
(BertConfig, BertForMultipleChoice),
|
||||||
(XLNetConfig, XLNetForMultipleChoice),
|
(XLNetConfig, XLNetForMultipleChoice),
|
||||||
|
(AlbertConfig, AlbertForMultipleChoice),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1354,7 +1354,7 @@ class BertForMultipleChoice(BertPreTrainedModel):
|
|||||||
prompt = "In Italy, pizza served in formal settings, such as at a restaurant, is presented unsliced."
|
prompt = "In Italy, pizza served in formal settings, such as at a restaurant, is presented unsliced."
|
||||||
choice0 = "It is eaten with a fork and a knife."
|
choice0 = "It is eaten with a fork and a knife."
|
||||||
choice1 = "It is eaten while held in the hand."
|
choice1 = "It is eaten while held in the hand."
|
||||||
labels = torch.tensor(0) # choice0 is correct (according to Wikipedia ;))
|
labels = torch.tensor(0).unsqueeze(0) # choice0 is correct (according to Wikipedia ;)), batch size 1
|
||||||
|
|
||||||
encoding = tokenizer.batch_encode_plus([[prompt, choice0], [prompt, choice1]], return_tensors='pt', pad_to_max_length=True)
|
encoding = tokenizer.batch_encode_plus([[prompt, choice0], [prompt, choice1]], return_tensors='pt', pad_to_max_length=True)
|
||||||
outputs = model(**{k: v.unsqueeze(0) for k,v in encoding.items()}, labels=labels) # batch size is 1
|
outputs = model(**{k: v.unsqueeze(0) for k,v in encoding.items()}, labels=labels) # batch size is 1
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ if is_torch_available():
|
|||||||
AlbertModel,
|
AlbertModel,
|
||||||
AlbertForPreTraining,
|
AlbertForPreTraining,
|
||||||
AlbertForMaskedLM,
|
AlbertForMaskedLM,
|
||||||
|
AlbertForMultipleChoice,
|
||||||
AlbertForSequenceClassification,
|
AlbertForSequenceClassification,
|
||||||
AlbertForTokenClassification,
|
AlbertForTokenClassification,
|
||||||
AlbertForQuestionAnswering,
|
AlbertForQuestionAnswering,
|
||||||
@@ -39,7 +40,19 @@ if is_torch_available():
|
|||||||
@require_torch
|
@require_torch
|
||||||
class AlbertModelTest(ModelTesterMixin, unittest.TestCase):
|
class AlbertModelTest(ModelTesterMixin, unittest.TestCase):
|
||||||
|
|
||||||
all_model_classes = (AlbertModel, AlbertForPreTraining, AlbertForMaskedLM) if is_torch_available() else ()
|
all_model_classes = (
|
||||||
|
(
|
||||||
|
AlbertModel,
|
||||||
|
AlbertForPreTraining,
|
||||||
|
AlbertForMaskedLM,
|
||||||
|
AlbertForMultipleChoice,
|
||||||
|
AlbertForSequenceClassification,
|
||||||
|
AlbertForTokenClassification,
|
||||||
|
AlbertForQuestionAnswering,
|
||||||
|
)
|
||||||
|
if is_torch_available()
|
||||||
|
else ()
|
||||||
|
)
|
||||||
|
|
||||||
class AlbertModelTester(object):
|
class AlbertModelTester(object):
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -252,6 +265,29 @@ class AlbertModelTest(ModelTesterMixin, unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.check_loss_output(result)
|
self.check_loss_output(result)
|
||||||
|
|
||||||
|
def create_and_check_albert_for_multiple_choice(
|
||||||
|
self, config, input_ids, token_type_ids, input_mask, sequence_labels, token_labels, choice_labels
|
||||||
|
):
|
||||||
|
config.num_choices = self.num_choices
|
||||||
|
model = AlbertForMultipleChoice(config=config)
|
||||||
|
model.to(torch_device)
|
||||||
|
model.eval()
|
||||||
|
multiple_choice_inputs_ids = input_ids.unsqueeze(1).expand(-1, self.num_choices, -1).contiguous()
|
||||||
|
multiple_choice_token_type_ids = token_type_ids.unsqueeze(1).expand(-1, self.num_choices, -1).contiguous()
|
||||||
|
multiple_choice_input_mask = input_mask.unsqueeze(1).expand(-1, self.num_choices, -1).contiguous()
|
||||||
|
loss, logits = model(
|
||||||
|
multiple_choice_inputs_ids,
|
||||||
|
attention_mask=multiple_choice_input_mask,
|
||||||
|
token_type_ids=multiple_choice_token_type_ids,
|
||||||
|
labels=choice_labels,
|
||||||
|
)
|
||||||
|
result = {
|
||||||
|
"loss": loss,
|
||||||
|
"logits": logits,
|
||||||
|
}
|
||||||
|
self.parent.assertListEqual(list(result["logits"].size()), [self.batch_size, self.num_choices])
|
||||||
|
self.check_loss_output(result)
|
||||||
|
|
||||||
def prepare_config_and_inputs_for_common(self):
|
def prepare_config_and_inputs_for_common(self):
|
||||||
config_and_inputs = self.prepare_config_and_inputs()
|
config_and_inputs = self.prepare_config_and_inputs()
|
||||||
(
|
(
|
||||||
@@ -285,6 +321,10 @@ class AlbertModelTest(ModelTesterMixin, unittest.TestCase):
|
|||||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||||
self.model_tester.create_and_check_albert_for_masked_lm(*config_and_inputs)
|
self.model_tester.create_and_check_albert_for_masked_lm(*config_and_inputs)
|
||||||
|
|
||||||
|
def test_for_multiple_choice(self):
|
||||||
|
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||||
|
self.model_tester.create_and_check_albert_for_multiple_choice(*config_and_inputs)
|
||||||
|
|
||||||
def test_for_question_answering(self):
|
def test_for_question_answering(self):
|
||||||
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
config_and_inputs = self.model_tester.prepare_config_and_inputs()
|
||||||
self.model_tester.create_and_check_albert_for_question_answering(*config_and_inputs)
|
self.model_tester.create_and_check_albert_for_question_answering(*config_and_inputs)
|
||||||
|
|||||||
Reference in New Issue
Block a user