NLP/NLU Specialization Notes
  • Natural Language Processing/Understanding Notes, Resources
  • Natural Language Processing With Attention Models
    • NLP With Attention Models
  • Natural Language Processing With Attention Models Notebooks
    • Assignment 1: Neural Machine Translation
    • Basic Attention Operation: Ungraded Lab
    • Calculating the Bilingual Evaluation Understudy (BLEU) score: Ungraded Lab
    • Scaled Dot-Product Attention: Ungraded Lab
    • Assignment 2: Transformer Summarizer
    • The Three Ways of Attention and Dot Product Attention: Ungraded Lab Notebook
    • Masking
    • Positional Encoding
    • Assignment 3: Question Answering
    • Assignment 3: Question Answering
    • Question Answering with BERT and HuggingFace
    • Question Answering with BERT and HuggingFace 🤗 (Fine-tuning)
    • SentencePiece and BPE
  • Natural Language Processing With Classification And Vector Spaces
    • NLP With Classification and Vector Spaces
  • Natural Language Processing With Sequence Models
    • NLP With Sequence Models
  • Natural Language Processing with Classification and Vector Spaces Notebooks
    • Assignment 1: Logistic Regression
    • Preprocessing
    • Building and Visualizing word frequencies
    • Visualizing tweets and the Logistic Regression model
    • Assignment 2: Naive Bayes
    • Assignment 3: Hello Vectors
    • Linear algebra in Python with NumPy
    • Manipulating word embeddings
    • Another explanation about PCA
    • Assignment 4 - Naive Machine Translation and LSH
    • Vector manipulation in Python
    • Hash functions and multiplanes
  • Natural Language Processing with Probabilistic Models
    • NLP With Probabilistic Models
  • Natural Language Processing with Probabilistic Models Notebooks
    • Assignment 1: Autocorrect
    • NLP Course 2 Week 1 Lesson : Building The Model - Lecture Exercise 01
    • NLP Course 2 Week 1 Lesson : Building The Model - Lecture Exercise 02
    • Assignment 2: Parts-of-Speech Tagging (POS)
    • Parts-of-Speech Tagging - First Steps: Working with text files, Creating a Vocabulary and Handling Unknown Words
    • Parts-of-Speech Tagging - Working with tags and Numpy
    • Assignment 3: Language Models: Auto-Complete
    • N-grams Corpus preprocessing
    • Building the language model
    • Out of vocabulary words (OOV)
    • Assignment 4: Word Embeddings
    • Word Embeddings First Steps: Data Preparation
    • Word Embeddings: Intro to CBOW model, activation functions and working with Numpy
    • Word Embeddings: Training the CBOW model
    • Word Embeddings: Hands On
    • Word Embeddings: Ungraded Practice Notebook
  • Natural Language Processing with Sequence Models Notebooks
    • Assignment 1: Deep N-grams
    • Hidden State Activation : Ungraded Lecture Notebook
    • Assignment 1: Sentiment with Deep Neural Networks
    • Vanilla RNNs and GRUs
    • Lab 1: TensorFlow Tutorial and Some Useful Functions
    • Calculating perplexity using numpy: Ungraded Lecture Notebook
    • Assignment 2 - Named Entity Recognition (NER)
    • Vanishing Gradients and Exploding Gradients in RNNs : Ungraded Lecture Notebook
    • Evaluate a Siamese model: Ungraded Lecture Notebook
    • Assignment 3: Question duplicates
    • Modified Triplet Loss : Ungraded Lecture Notebook
    • Creating a Siamese model: Ungraded Lecture Notebook
  • Stanford
    • Stanford CS 224U,224N
  • Udacity
    • NLP Nanodegree
  • Previous
  • Next
  • Question Answering with BERT and HuggingFace 🤗 (Fine-tuning)
    • Fine-tuning a BERT model
  • Transformers

Question Answering with BERT and HuggingFace 🤗 (Fine-tuning)¶

In the previous Hugging Face ungraded lab, you saw how to use the pipeline objects to use transformer models for NLP tasks. In that lab, the model didn't output the desired answers to a series of precise questions for a context related to the history of comic books.

In this lab, you will fine-tune the model from that lab to give better answers for that type of context. To do that, you'll be using the TyDi QA dataset but on a filtered version with only English examples. Additionally, you will use a lot of the tools that Hugging Face has to offer.

You have to note that, in general, you will fine-tune general-purpose transformer models to work for specific tasks. However, fine-tuning a general-purpose model can take a lot of time. That's why you will be using the model from the question answering pipeline in this lab.

Begin by importing some libraries and/or objects you will use throughout the lab:

In [1]:
Copied!
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

import numpy as np

from datasets import load_from_disk
from transformers import AutoTokenizer, AutoModelForQuestionAnswering, Trainer, TrainingArguments

from sklearn.metrics import f1_score
import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' import numpy as np from datasets import load_from_disk from transformers import AutoTokenizer, AutoModelForQuestionAnswering, Trainer, TrainingArguments from sklearn.metrics import f1_score

Fine-tuning a BERT model¶

As you saw in the previous lab, you can use these pipelines as they are. But sometimes, you'll need something more specific to your problem, or maybe you need it to perform better on your production data. In these cases, you'll need to fine-tune a model.

Here, you'll fine-tune a pre-trained DistilBERT model on the TyDi QA dataset.

To fine-tune your model, you will leverage three components provided by Hugging Face:

  • Datasets: Library that contains some datasets and different metrics to evaluate the performance of your models.
  • Tokenizer: Object in charge of preprocessing your text to be given as input for the transformer models.
  • Transformers: Library with the pre-trained model checkpoints and the trainer object.

Datasets¶

To get the dataset to fine-tune your model, you will use 🤗 Datasets, a lightweight and extensible library to share and access datasets and evaluation metrics for NLP easily. You can download Hugging Face datasets directly using the load_dataset function from the datasets library.

Hugging Face datasets allows to load data in several formats, such as CSV, JSON, text files and even parquet. You can see more about the supported formats in the documentation

A common approach is to use load_dataset and get the full dataset but for this lab you will use a filtered version containing only the English examples, which is already saved in this environment. Since this filtered dataset is saved using the Apache Arrow format, you can read it by using the load_from_disk function.

In [2]:
Copied!
#The path where the dataset is stored
path = './tydiqa_data/'

#Load Dataset
tydiqa_data = load_from_disk(path)

tydiqa_data
#The path where the dataset is stored path = './tydiqa_data/' #Load Dataset tydiqa_data = load_from_disk(path) tydiqa_data
Out[2]:
DatasetDict({
    train: Dataset({
        features: ['passage_answer_candidates', 'question_text', 'document_title', 'language', 'annotations', 'document_plaintext', 'document_url'],
        num_rows: 9211
    })
    validation: Dataset({
        features: ['passage_answer_candidates', 'question_text', 'document_title', 'language', 'annotations', 'document_plaintext', 'document_url'],
        num_rows: 1031
    })
})

You can check below that the type of the loaded dataset is a datasets.arrow_dataset.Dataset. This object type corresponds to an Apache Arrow Table that allows creating a hash table that contains the position in memory where data is stored instead of loading the complete dataset into memory. But you don't have to worry too much about that. It is just an efficient way to work with lots of data.

In [3]:
Copied!
# Checking the object type for one of the elements in the dataset
type(tydiqa_data['train'])
# Checking the object type for one of the elements in the dataset type(tydiqa_data['train'])
Out[3]:
datasets.arrow_dataset.Dataset

You can also check the structure of the dataset:

In [4]:
Copied!
tydiqa_data['train']
tydiqa_data['train']
Out[4]:
Dataset({
    features: ['passage_answer_candidates', 'question_text', 'document_title', 'language', 'annotations', 'document_plaintext', 'document_url'],
    num_rows: 9211
})

You can see that each example is like a dictionary object. This dataset consists of questions, contexts, and indices that point to the start and end position of the answer inside the context. You can access the index using the annotations key, which is a kind of dictionary.

In [5]:
Copied!
idx = 600

# start index
start_index = tydiqa_data['train'][idx]['annotations']['minimal_answers_start_byte'][0]

# end index
end_index = tydiqa_data['train'][idx]['annotations']['minimal_answers_end_byte'][0]

print(f"Question: {tydiqa_data['train'][idx]['question_text']}")
print(f"\nContext (truncated): {tydiqa_data['train'][idx]['document_plaintext'][0:512]} ...")
print(f"\nAnswer: {tydiqa_data['train'][idx]['document_plaintext'][start_index:end_index]}")
idx = 600 # start index start_index = tydiqa_data['train'][idx]['annotations']['minimal_answers_start_byte'][0] # end index end_index = tydiqa_data['train'][idx]['annotations']['minimal_answers_end_byte'][0] print(f"Question: {tydiqa_data['train'][idx]['question_text']}") print(f"\nContext (truncated): {tydiqa_data['train'][idx]['document_plaintext'][0:512]} ...") print(f"\nAnswer: {tydiqa_data['train'][idx]['document_plaintext'][start_index:end_index]}")
Question: What mental effects can a mother experience after childbirth?

Context (truncated): 

Postpartum depression (PPD), also called postnatal depression, is a type of mood disorder associated with childbirth, which can affect both sexes.[1][3] Symptoms may include extreme sadness, low energy, anxiety, crying episodes, irritability, and changes in sleeping or eating patterns.[1] Onset is typically between one week and one month following childbirth.[1] PPD can also negatively affect the newborn child.[2]

While the exact cause of PPD is unclear, the cause is believed to be a combination of physi ...

Answer: Postpartum depression (PPD)

The question answering model predicts a start and endpoint in the context to extract as the answer. That's why this NLP task is known as extractive question answering.

To train your model, you need to pass start and endpoints as labels. So, you need to implement a function that extracts the start and end positions from the dataset.

The dataset contains unanswerable questions. For these, the start and end indices for the answer are equal to -1.

In [6]:
Copied!
tydiqa_data['train'][0]['annotations']
tydiqa_data['train'][0]['annotations']
Out[6]:
{'passage_answer_candidate_index': [-1],
 'minimal_answers_start_byte': [-1],
 'minimal_answers_end_byte': [-1],
 'yes_no_answer': ['NONE']}

Now, you have to flatten the dataset to work with an object with a table structure instead of a dictionary structure. This step facilitates the pre-processing steps.

In [7]:
Copied!
# Flattening the datasets
flattened_train_data = tydiqa_data['train'].flatten()
flattened_test_data =  tydiqa_data['validation'].flatten()
# Flattening the datasets flattened_train_data = tydiqa_data['train'].flatten() flattened_test_data = tydiqa_data['validation'].flatten()

Also, to make the training more straightforward and faster, we will extract a subset of the train and test datasets. For that purpose, we will use the Hugging Face Dataset object's method called select(). This method allows you to take some data points by their index. Here, you will select the first 3000 rows but you can play with the number of data points, however, consider that this will increase the training time.

In [8]:
Copied!
# Selecting a subset of the train dataset
flattened_train_data = flattened_train_data.select(range(3000))

# Selecting a subset of the test dataset
flattened_test_data = flattened_test_data.select(range(1000))
# Selecting a subset of the train dataset flattened_train_data = flattened_train_data.select(range(3000)) # Selecting a subset of the test dataset flattened_test_data = flattened_test_data.select(range(1000))

Tokenizers¶

Now, you will use the tokenizer object from Hugging Face. You can load a tokenizer using different methods. Here, you will retrieve it from the pipeline object you created in the previous Hugging Face lab. With this tokenizer, you can ensure that the tokens you get for the dataset will match the tokens used in the original DistilBERT implementation.

When loading a tokenizer with any method, you must pass the model checkpoint that you want to fine-tune. Here, you are using the'distilbert-base-cased-distilled-squad' checkpoint.

In [9]:
Copied!
# Import the AutoTokenizer from the transformers library
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-cased-distilled-squad")

# Define max length of sequences in the tokenizer
tokenizer.model_max_length = 512
# Import the AutoTokenizer from the transformers library tokenizer = AutoTokenizer.from_pretrained("distilbert-base-cased-distilled-squad") # Define max length of sequences in the tokenizer tokenizer.model_max_length = 512

Given the characteristics of the dataset and the question-answering task, you will need to add some steps to pre-process the data after the tokenization:

  1. When there is no answer to a question given a context, you will use the CLS token, a unique token used to represent the start of the sequence.

  2. Tokenizers can split a given string into substrings, resulting in a subtoken for each substring, creating misalignment between the list of dataset tags and the labels generated by the tokenizer. Therefore, you will need to align the start and end indices with the tokens associated with the target answer word.

  3. Finally, a tokenizer can truncate a very long sequence. So, if the start/end position of an answer is None, you will assume that it was truncated and assign the maximum length of the tokenizer to those positions.

Those three steps are done within the process_samples function defined below.

In [10]:
Copied!
# Processing samples using the 3 steps described above
def process_samples(sample):
    tokenized_data = tokenizer(sample['document_plaintext'], sample['question_text'], truncation="only_first", padding="max_length")

    input_ids = tokenized_data["input_ids"]

    # We will label impossible answers with the index of the CLS token.
    cls_index = input_ids.index(tokenizer.cls_token_id)

    # If no answers are given, set the cls_index as answer.
    if sample["annotations.minimal_answers_start_byte"][0] == -1:
        start_position = cls_index
        end_position = cls_index
    else:
        # Start/end character index of the answer in the text.
        gold_text = sample["document_plaintext"][sample['annotations.minimal_answers_start_byte'][0]:sample['annotations.minimal_answers_end_byte'][0]]
        start_char = sample["annotations.minimal_answers_start_byte"][0]
        end_char = sample['annotations.minimal_answers_end_byte'][0] #start_char + len(gold_text)

        # sometimes answers are off by a character or two – fix this
        if sample['document_plaintext'][start_char-1:end_char-1] == gold_text:
            start_char = start_char - 1
            end_char = end_char - 1     # When the gold label is off by one character
        elif sample['document_plaintext'][start_char-2:end_char-2] == gold_text:
            start_char = start_char - 2
            end_char = end_char - 2     # When the gold label is off by two characters

        start_token = tokenized_data.char_to_token(start_char)
        end_token = tokenized_data.char_to_token(end_char - 1)

        # if start position is None, the answer passage has been truncated
        if start_token is None:
            start_token = tokenizer.model_max_length
        if end_token is None:
            end_token = tokenizer.model_max_length

        start_position = start_token
        end_position = end_token

    return {'input_ids': tokenized_data['input_ids'],
          'attention_mask': tokenized_data['attention_mask'],
          'start_positions': start_position,
          'end_positions': end_position}
# Processing samples using the 3 steps described above def process_samples(sample): tokenized_data = tokenizer(sample['document_plaintext'], sample['question_text'], truncation="only_first", padding="max_length") input_ids = tokenized_data["input_ids"] # We will label impossible answers with the index of the CLS token. cls_index = input_ids.index(tokenizer.cls_token_id) # If no answers are given, set the cls_index as answer. if sample["annotations.minimal_answers_start_byte"][0] == -1: start_position = cls_index end_position = cls_index else: # Start/end character index of the answer in the text. gold_text = sample["document_plaintext"][sample['annotations.minimal_answers_start_byte'][0]:sample['annotations.minimal_answers_end_byte'][0]] start_char = sample["annotations.minimal_answers_start_byte"][0] end_char = sample['annotations.minimal_answers_end_byte'][0] #start_char + len(gold_text) # sometimes answers are off by a character or two – fix this if sample['document_plaintext'][start_char-1:end_char-1] == gold_text: start_char = start_char - 1 end_char = end_char - 1 # When the gold label is off by one character elif sample['document_plaintext'][start_char-2:end_char-2] == gold_text: start_char = start_char - 2 end_char = end_char - 2 # When the gold label is off by two characters start_token = tokenized_data.char_to_token(start_char) end_token = tokenized_data.char_to_token(end_char - 1) # if start position is None, the answer passage has been truncated if start_token is None: start_token = tokenizer.model_max_length if end_token is None: end_token = tokenizer.model_max_length start_position = start_token end_position = end_token return {'input_ids': tokenized_data['input_ids'], 'attention_mask': tokenized_data['attention_mask'], 'start_positions': start_position, 'end_positions': end_position}

To apply the process_samples function defined above to the whole dataset, you can use the map method as follows:

In [11]:
Copied!
# Tokenizing and processing the flattened dataset
processed_train_data = flattened_train_data.map(process_samples)
processed_test_data = flattened_test_data.map(process_samples)
# Tokenizing and processing the flattened dataset processed_train_data = flattened_train_data.map(process_samples) processed_test_data = flattened_test_data.map(process_samples)

Transformers¶

The last component of Hugging Face that is useful for fine-tuning a transformer corresponds to the pre-trained models you can access in multiple ways.

For this lab, you will use the same model from the question-answering pipeline that you loaded in the previous lab.

In [12]:
Copied!
# Import the AutoModelForQuestionAnswering for the pre-trained model. You will only fine tune the head of the model
model = AutoModelForQuestionAnswering.from_pretrained("distilbert-base-cased-distilled-squad")
# Import the AutoModelForQuestionAnswering for the pre-trained model. You will only fine tune the head of the model model = AutoModelForQuestionAnswering.from_pretrained("distilbert-base-cased-distilled-squad")

Now, you can take the necessary columns from the datasets to train/test and return them as Pytorch Tensors.

In [13]:
Copied!
columns_to_return = ['input_ids','attention_mask', 'start_positions', 'end_positions']

processed_train_data.set_format(type='pt', columns=columns_to_return)
processed_test_data.set_format(type='pt', columns=columns_to_return)
columns_to_return = ['input_ids','attention_mask', 'start_positions', 'end_positions'] processed_train_data.set_format(type='pt', columns=columns_to_return) processed_test_data.set_format(type='pt', columns=columns_to_return)

Here, we give you the F1 score as a metric to evaluate your model's performance. We will use this metric for simplicity, although it is based on the start and end values predicted by the model. If you want to dig deeper on other metrics that can be used for a question and answering task, you can also check this colab notebook resource from the Hugging Face team.

In [14]:
Copied!
def compute_f1_metrics(pred):
    start_labels = pred.label_ids[0]
    start_preds = pred.predictions[0].argmax(-1)
    end_labels = pred.label_ids[1]
    end_preds = pred.predictions[1].argmax(-1)

    f1_start = f1_score(start_labels, start_preds, average='macro')
    f1_end = f1_score(end_labels, end_preds, average='macro')

    return {
        'f1_start': f1_start,
        'f1_end': f1_end,
    }
def compute_f1_metrics(pred): start_labels = pred.label_ids[0] start_preds = pred.predictions[0].argmax(-1) end_labels = pred.label_ids[1] end_preds = pred.predictions[1].argmax(-1) f1_start = f1_score(start_labels, start_preds, average='macro') f1_end = f1_score(end_labels, end_preds, average='macro') return { 'f1_start': f1_start, 'f1_end': f1_end, }

Now, you will use the Hugging Face Trainer to fine-tune your model.

In [15]:
Copied!
# Training hyperparameters
training_args = TrainingArguments(
    output_dir='model_results',     # output directory
    overwrite_output_dir=True,
    num_train_epochs=3,              # total number of training epochs
    per_device_train_batch_size=8,   # batch size per device during training
    per_device_eval_batch_size=8,    # batch size for evaluation
    warmup_steps=20,                 # number of warmup steps for learning rate scheduler
    weight_decay=0.01,               # strength of weight decay
    logging_steps=50
)

# Trainer object
trainer = Trainer(
    model=model,                        # the instantiated 🤗 Transformers model to be trained
    args=training_args,                 # training arguments, defined above
    train_dataset=processed_train_data, # training dataset
    eval_dataset=processed_test_data,   # evaluation dataset
    compute_metrics=compute_f1_metrics
)

# Training loop
trainer.train()
# Training hyperparameters training_args = TrainingArguments( output_dir='model_results', # output directory overwrite_output_dir=True, num_train_epochs=3, # total number of training epochs per_device_train_batch_size=8, # batch size per device during training per_device_eval_batch_size=8, # batch size for evaluation warmup_steps=20, # number of warmup steps for learning rate scheduler weight_decay=0.01, # strength of weight decay logging_steps=50 ) # Trainer object trainer = Trainer( model=model, # the instantiated 🤗 Transformers model to be trained args=training_args, # training arguments, defined above train_dataset=processed_train_data, # training dataset eval_dataset=processed_test_data, # evaluation dataset compute_metrics=compute_f1_metrics ) # Training loop trainer.train()
[1125/1125 02:24, Epoch 3/3]
Step Training Loss
50 2.212400
100 1.873600
150 2.037600
200 1.901000
250 1.751300
300 1.558200
350 1.512000
400 1.404400
450 1.152800
500 1.266900
550 1.173900
600 1.319000
650 1.093200
700 0.966600
750 1.194800
800 0.700200
850 0.708700
900 0.819200
950 0.693300
1000 0.707900
1050 0.513700
1100 0.654900

Out[15]:
TrainOutput(global_step=1125, training_loss=1.2257471093071832, metrics={'train_runtime': 149.5132, 'train_samples_per_second': 60.195, 'train_steps_per_second': 7.524, 'total_flos': 1175877900288000.0, 'train_loss': 1.2257471093071832, 'epoch': 3.0})

And, in the next cell, you can evaluate the fine-tuned model's performance on the test set.

In [16]:
Copied!
trainer.evaluate(processed_test_data)
trainer.evaluate(processed_test_data)
[125/125 00:04]
Out[16]:
{'eval_loss': 2.223409652709961,
 'eval_f1_start': 0.0914274281397588,
 'eval_f1_end': 0.09987131665595556,
 'eval_runtime': 4.8779,
 'eval_samples_per_second': 205.008,
 'eval_steps_per_second': 25.626,
 'epoch': 3.0}

Using your Fine-Tuned Model¶

After training and evaluating your fine-tuned model, you can check its results for the same questions from the previous lab.

For that, you will tell Pytorch to use your GPU or your CPU to run the model. Additionally, you will need to tokenize your input context and questions. Finally, you need to post-process the output results to transform them from tokens to human-readable strings using the tokenizer.

In [17]:
Copied!
text = r"""
The Golden Age of Comic Books describes an era of American comic books from the
late 1930s to circa 1950. During this time, modern comic books were first published
and rapidly increased in popularity. The superhero archetype was created and many
well-known characters were introduced, including Superman, Batman, Captain Marvel
(later known as SHAZAM!), Captain America, and Wonder Woman.
Between 1939 and 1941 Detective Comics and its sister company, All-American Publications,
introduced popular superheroes such as Batman and Robin, Wonder Woman, the Flash,
Green Lantern, Doctor Fate, the Atom, Hawkman, Green Arrow and Aquaman.[7] Timely Comics,
the 1940s predecessor of Marvel Comics, had million-selling titles featuring the Human Torch,
the Sub-Mariner, and Captain America.[8]
As comic books grew in popularity, publishers began launching titles that expanded
into a variety of genres. Dell Comics' non-superhero characters (particularly the
licensed Walt Disney animated-character comics) outsold the superhero comics of the day.[12]
The publisher featured licensed movie and literary characters such as Mickey Mouse, Donald Duck,
Roy Rogers and Tarzan.[13] It was during this era that noted Donald Duck writer-artist
Carl Barks rose to prominence.[14] Additionally, MLJ's introduction of Archie Andrews
in Pep Comics #22 (December 1941) gave rise to teen humor comics,[15] with the Archie
Andrews character remaining in print well into the 21st century.[16]
At the same time in Canada, American comic books were prohibited importation under
the War Exchange Conservation Act[17] which restricted the importation of non-essential
goods. As a result, a domestic publishing industry flourished during the duration
of the war which were collectively informally called the Canadian Whites.
The educational comic book Dagwood Splits the Atom used characters from the comic
strip Blondie.[18] According to historian Michael A. Amundson, appealing comic-book
characters helped ease young readers' fear of nuclear war and neutralize anxiety
about the questions posed by atomic power.[19] It was during this period that long-running
humor comics debuted, including EC's Mad and Carl Barks' Uncle Scrooge in Dell's Four
Color Comics (both in 1952).[20][21]
"""

questions = ["What superheroes were introduced between 1939 and 1941 by Detective Comics and its sister company?",
             "What comic book characters were created between 1939 and 1941?",
             "What well-known characters were created between 1939 and 1941?",
             "What well-known superheroes were introduced between 1939 and 1941 by Detective Comics?"]

for question in questions:
    inputs = tokenizer.encode_plus(question, text, return_tensors="pt")

    input_ids = inputs["input_ids"].tolist()[0]
    inputs.to("cuda")

    text_tokens = tokenizer.convert_ids_to_tokens(input_ids)
    answer_model = model(**inputs)
    
    start_logits = answer_model['start_logits'].cpu().detach().numpy()

    answer_start = np.argmax(start_logits)  
    
    end_logits = answer_model['end_logits'].cpu().detach().numpy()
    
    # Get the most likely beginning of answer with the argmax of the score
    answer_end = np.argmax(end_logits) + 1  # Get the most likely end of answer with the argmax of the score

    answer = tokenizer.convert_tokens_to_string(tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end]))

    print(f"Question: {question}")
    print(f"Answer: {answer}\n")
text = r""" The Golden Age of Comic Books describes an era of American comic books from the late 1930s to circa 1950. During this time, modern comic books were first published and rapidly increased in popularity. The superhero archetype was created and many well-known characters were introduced, including Superman, Batman, Captain Marvel (later known as SHAZAM!), Captain America, and Wonder Woman. Between 1939 and 1941 Detective Comics and its sister company, All-American Publications, introduced popular superheroes such as Batman and Robin, Wonder Woman, the Flash, Green Lantern, Doctor Fate, the Atom, Hawkman, Green Arrow and Aquaman.[7] Timely Comics, the 1940s predecessor of Marvel Comics, had million-selling titles featuring the Human Torch, the Sub-Mariner, and Captain America.[8] As comic books grew in popularity, publishers began launching titles that expanded into a variety of genres. Dell Comics' non-superhero characters (particularly the licensed Walt Disney animated-character comics) outsold the superhero comics of the day.[12] The publisher featured licensed movie and literary characters such as Mickey Mouse, Donald Duck, Roy Rogers and Tarzan.[13] It was during this era that noted Donald Duck writer-artist Carl Barks rose to prominence.[14] Additionally, MLJ's introduction of Archie Andrews in Pep Comics #22 (December 1941) gave rise to teen humor comics,[15] with the Archie Andrews character remaining in print well into the 21st century.[16] At the same time in Canada, American comic books were prohibited importation under the War Exchange Conservation Act[17] which restricted the importation of non-essential goods. As a result, a domestic publishing industry flourished during the duration of the war which were collectively informally called the Canadian Whites. The educational comic book Dagwood Splits the Atom used characters from the comic strip Blondie.[18] According to historian Michael A. Amundson, appealing comic-book characters helped ease young readers' fear of nuclear war and neutralize anxiety about the questions posed by atomic power.[19] It was during this period that long-running humor comics debuted, including EC's Mad and Carl Barks' Uncle Scrooge in Dell's Four Color Comics (both in 1952).[20][21] """ questions = ["What superheroes were introduced between 1939 and 1941 by Detective Comics and its sister company?", "What comic book characters were created between 1939 and 1941?", "What well-known characters were created between 1939 and 1941?", "What well-known superheroes were introduced between 1939 and 1941 by Detective Comics?"] for question in questions: inputs = tokenizer.encode_plus(question, text, return_tensors="pt") input_ids = inputs["input_ids"].tolist()[0] inputs.to("cuda") text_tokens = tokenizer.convert_ids_to_tokens(input_ids) answer_model = model(**inputs) start_logits = answer_model['start_logits'].cpu().detach().numpy() answer_start = np.argmax(start_logits) end_logits = answer_model['end_logits'].cpu().detach().numpy() # Get the most likely beginning of answer with the argmax of the score answer_end = np.argmax(end_logits) + 1 # Get the most likely end of answer with the argmax of the score answer = tokenizer.convert_tokens_to_string(tokenizer.convert_ids_to_tokens(input_ids[answer_start:answer_end])) print(f"Question: {question}") print(f"Answer: {answer}\n")
Question: What superheroes were introduced between 1939 and 1941 by Detective Comics and its sister company?
Answer: Superman, Batman, Captain Marvel ( later known as SHAZAM! ), Captain America, and Wonder Woman. Between 1939 and 1941 Detective Comics and its sister company, All - American Publications, introduced popular superheroes such as Batman and Robin, Wonder Woman, the Flash, Green Lantern, Doctor Fate, the Atom, Hawkman, Green Arrow and Aquaman

Question: What comic book characters were created between 1939 and 1941?
Answer: Superman, Batman, Captain Marvel ( later known as SHAZAM! ), Captain America, and Wonder Woman

Question: What well-known characters were created between 1939 and 1941?
Answer: Superman, Batman, Captain Marvel ( later known as SHAZAM! ), Captain America, and Wonder Woman

Question: What well-known superheroes were introduced between 1939 and 1941 by Detective Comics?
Answer: Superman, Batman, Captain Marvel ( later known as SHAZAM! ), Captain America, and Wonder Woman

By fine-tuning the model for only 3 epochs you can already see an improvement!

You can compare those results with those obtained using the base model (without fine-tuning), as you did in the previous lab. As a reminder, here are those results:

What popular superheroes were introduced between 1939 and 1941?
>> teen humor comics
What superheroes were introduced between 1939 and 1941 by Detective Comics and its sister company?
>> Archie Andrews
What comic book characters were created between 1939 and 1941?
>> Archie
Andrews
What well-known characters were created between 1939 and 1941?
>> Archie
Andrews
What well-known superheroes were introduced between 1939 and 1941 by Detective Comics?
>> Archie Andrews

Congratulations!

You have finished this series of ungraded labs. You were able to:

  • Explore the Hugging Face Pipelines, which can be used right out of the bat.

  • Fine-tune a model for the Extractive Question & Answering task.

We also recommend you go through the free Hugging Face course to explore their ecosystem in more detail and find different ways to use the transformers library.

In [ ]:
Copied!


Documentation built with MkDocs.

Keyboard Shortcuts

Keys Action
? Open this help
n Next page
p Previous page
s Search