Text summarization represents a sophisticated evolution of text generation, requiring a deep understanding of content and context. With encoder-decoder transformer models like DistilBart, you can now create summaries that capture the essence of longer text while maintaining coherence and relevance.
In this tutorial, you’ll discover how to implement text summarization using DistilBart. You’ll learn through practical, executable examples, and by the end of this guide, you’ll understand both the theoretical foundations and hands-on implementation details. After completing this tutorial, you will know:
- How encoder-decoder transformers create context-aware summaries
- How to implement summarization using both pipeline and custom approaches
- How to build a production-ready summarization system with proper error handling
- How to optimize summarization parameters for different text types
- How to create a scalable summarization API service
Kick-start your project with my book NLP with Hugging Face Transformers. It provides self-study tutorials with working code.
Let’s get started.

Text Summarization with DistillBart Model
Photo by Aaron Burden. Some rights reserved.
Overview
This tutorial is in two parts; they are:
- Using DistilBart for Summarization
- Improving the Summarization Process
Using DistilBart for Summarization
Let’s start with a fundamental implementation that demonstrates the key concepts of text summarization with DistilBart:
The output may be like this:
Let’s break down to see how it works: The TextSummarizer class initializes with a pre-trained DistilBart model, specifically the CNN/DailyMail version that’s been optimized for summarization tasks. This is a powerful encoder-decoder transformer model.
Similar to many other models in the transformers library, you use the generate() method to pass on the input and retrieve the output. This is defined in the summarize() method of the TextSummarizer class. In particular, the generate() method takes the arguments max_length and min_length to control the length of the summary output. The arguments length_penalty controls the summary conciseness, and num_beams controls the beam search for better quality. The argument early_stopping is set to True to stop the generation when all beams are finished.
The model accepts only integer-encoded input, not text. The tokenizer object converts the input text into a sequence of subword tokens and then maps the tokens into integers. Its output will be a dictionary with the keys input_ids and attention_mask. The input_ids is the sequence of integers, and the attention_mask is a binary mask that indicates which tokens are real (1) and which are padding (0). Both the input_ids and attention_mask are required by the generate() method to understand your input correctly.
Finally, wrapping the generation code in a try-except block is a good practice to handle potential errors.
What is Beam Search?
The generate() method uses beam search to generate the summary. Recall that the model you used is an autoregressive model, which means it generates the output token by token. As the output token is sampled in each step, there are many possible output sequences. Unlike free-running text generation, a summary needs to be a complete paragraph, i.e., it should terminate with an end-of-sentence token.
Beam search is a technique used to generate summaries by exploring multiple paths in the output space until the end-of-sentence token is generated. Each step starts with
The score of a sequence is computed based on multiple factors, including the probability of the tokens (i.e., the logit output of the model), the length of the sequence (length_penalty parameter), and the repetition of the sequence (repetition_penalty parameter). By adjusting these parameters, you can control the quality of the summary.
The no_repeat_ngram_size parameter is similar but not part of the score. Instead, it strictly forbids the repeated appearance of any n-grams in the output. You set it to 3 in the code above. Therefore, any consecutive three words will only appear once in the output. This is an additional check in the beam search algorithm.
Improving the Summarization Process
Using a pre-trained model from the Hugging Face model hub is as easy as above. You do not need to worry about the model architecture and the underlying implementation details. However, several issues may arise in real-world applications.
Quantization
Firstly, these models are large. You need to download a sizable model file before you can use it, and a lot of computation is required to generate a summary. You may find it too slow if you do not have a GPU. However, once the model is trained, you can approximate the floating point operations in the model with integer operations, which is much faster.
Converting a floating-point model to an integer is called quantization. Since the model is loaded as a PyTorch model, you can quantize it as follows:
The if statement above converts the loaded model into a quantized version. The resulting model uses 8-bit integers, but not all operations are converted. PyTorch will convert the linear layers but likely not the attention layers, which will be kept as floating points.
Quantization may not work if you run your model on a GPU; it depends on the hardware and the version of PyTorch. You can try it out and see if it is supported in your environment.
Text Preprocessing and Batch Processing
As a summarizer, you know that some part of the input text is irrelevant, such as quoted URLs, extra whitespace, or special characters. You can remove them to avoid distracting the model.
Like many other machine learning models, the DistilBart model you used can accept not only a single string of text but a batch of texts. This is useful if you need to summarize multiple texts at once.
Let’s see how you can implement these:
The preprocess_text() method is the basic, and you can extend it. Here regular expressions are used to process the text to remove the unwanted elements in the input. In the summarize_batch() method, the input texts are tokenized and processed in batches. The summarize_batch() method accepts kwargs as additional arguments so that you can pass through the arguments such as length_penalty and num_beams to the generate() method.
Caching
Another issue when trying to use the model as a summarizer in production is employing caching. This means that when the same input is encountered again, the model will not reprocess it but retrieve the previous result. This not only saves time but also ensures consistency.
Surprisingly, implementing caching in a Python program is very straightforward. You can use the functools.lru_cache decorator to a function and the caching will be done automatically. Here, you can wrap the generation code in a decorator:
This is the magic provided by Python. As long as you call this function with the same arguments, the function will not be evaluated, but the previous result will be returned. The maxsize parameter controls the size of the cache and, hence, limits memory usage. Here, the cache will only remember the last 200 distinct results.
Long text
The model has a limit on the input size. It will refuse to run if you try to provide a very long input to the model. The max length for this model is 1024 tokens. You can check this limit from the config object or tokenizer:
What if you want to summarize a text longer than 1024 tokens? You need to devise a strategy to split the text into manageable chunks so the model can handle it. Some options are:
- You can split the text into manageable chunks, summarizing each chunk separately and then combining the results.
- You consider the text as multiple paragraphs. Summarize each paragraph separately and then combine the results. The combined result will be a shorter text, which you can summarize again. Repeat this process until the input is short enough for the model to handle.
The first option is simpler, but you lost the context of the input. For example, if the key information is concentrated in the latter half of the input, you will generate a summary even for the first half. But since it is easier, let’s implement it:
The model is invoked using the cached_summarize() method you implemented earlier. Before that, you split the input into chunks; each is no longer than 1024 tokens, and process each chunk separately. To keep the output at a reasonable length, you adjust the max_length and min_length parameters accordingly so that the output after concatenation fits within the intended length.
Note that the model sees tokens, not words. Therefore, you split the input into chunks by counting the tokens and using the tokenizer to help in the splitting.
In full, below is the complete code:
Your output of the above code may be:
The code above uses pprint module to help print the output in a more readable format. Otherwise, all operations are trivial. You can try to tune the parameters to get a better summary.
Further Reading
Below are some resources that you may find useful:
- DistilBart model in Hugging Face
- Beam Search
- Foundations of NLP Explained Visually: Beam Search, How it Works
Summary
In this tutorial, you’ve learned how to summarize text using DistilBart. Particularly, you learned:
- Implement text summarization using DistilBart
- Build a custom summarizer with advanced features
- Process multiple texts efficiently
- Optimize summarization parameters

No comments:
Post a Comment