<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Graphcore - Medium]]></title>
        <description><![CDATA[We invented the Intelligence Processing Unit (IPU) designed specifically for AI compute to let innovators create the next advances in machine intelligence. - Medium]]></description>
        <link>https://medium.com/graphcore?source=rss----d35727101202---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Graphcore - Medium</title>
            <link>https://medium.com/graphcore?source=rss----d35727101202---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 18 Jun 2026 09:56:04 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/graphcore" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Text Summarization with BART-Large on IPU]]></title>
            <link>https://medium.com/graphcore/text-summarization-with-bart-large-on-ipu-a14f0fb125b3?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/a14f0fb125b3</guid>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Fri, 11 Aug 2023 14:45:45 GMT</pubDate>
            <atom:updated>2023-08-11T14:41:33.564Z</atom:updated>
            <content:encoded><![CDATA[<p>Try one of the most powerful and versatile applications of the BART language model using a Paperspace Gradient Notebook</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r_rovbOdeSkPKUWypNhSRQ.png" /></figure><p>by Goran Katalinic</p><p>Text summarization is one of the best examples of AI natural language processing (NLP) being put to practical use.</p><p>With vast amounts of information produced every day, the ability to quickly understand, evaluate and act on that information can be extremely valuable, both in the commercial world and in other fields such as scientific research.</p><p>Summarization is a task of producing a shorter version of a document while preserving its important information. Fundamentally, it involves extracting text from the original input then generating a new text that describes the essence of the original. In some cases the two parts many be managed by different AI models.</p><p>In this blog, we will demonstrate how to run the entire summarization process using BART-Large on Graphcore IPUs.</p><h3>What is BART and why is it good for text summarization?</h3><p>When Google launched <a href="https://towardsdatascience.com/bert-explained-state-of-the-art-language-model-for-nlp-f8b21a9b6270">BERT</a> (Bidirectional Encoder Representations from Transformers) in 2018, it was described as being a model for “language understanding” which was defined as a <a href="https://www.graphcore.ai/posts/bert-large-training-on-the-ipu-explained">broad range of applications</a>, including sentiment analysis, text classification and question answering. Summarization was not explicity called-out as a use-case, at that time.</p><p>In the same year, Open-AI further advanced the field of Natural Language Understanding, proposing the concept of Generative Pre-Training (GPT).</p><p>In late 2019, Facebook AI researchers proposed a combination of bidirectional encoder (like BERT) and left-to-right decoder (like GPT) and gave it a name BART, which stands for Bidirectional and Auto-Regressive Transformers​.</p><p>According to the <a href="https://arxiv.org/abs/1910.13461">original paper</a>, the novelty in pretraining involves a new in-filling scheme when randomly shuffling the order of original sentences. The authors claimed that BART is particularly effective when fine tuned for text generation and for comprehension tasks — both of which are needed for text summarization.</p><h3>Text summarization on Graphcore IPUs with Hugging Face pipeline</h3><p>BART is one of the many NLP models supported within <a href="https://huggingface.co/docs/optimum/main/graphcore/index">Optimum Graphcore</a>, which is an interface between Hugging Face and Graphcore IPUs.</p><p>Here we demonstrate a text summarization task running BART-Large inference on Graphcore IPUs.</p><figure><a href="https://ipu.dev/0vWJPv"><img alt="" src="https://cdn-images-1.medium.com/max/270/1*1aVUKlJiNRhwY6JRr8V-Sg.png" /></a></figure><p>For each code block below, you can simply click to run the block in Paperspace — making any modifications to code/parameters, where relevant. We explain how to run the process in environments other than Paperspace Gradient Notebooks at the end of this blog.</p><h3>Install dependencies</h3><pre>%pip install optimum-graphcore==0.7.1 wikipedia graphcore-cloud-tools[logger]@git+https://github.com/graphcore/graphcore-cloud-tools<br><br>%load_ext graphcore_cloud_tools.notebook_logging.gc_logger</pre><pre>import os<br><br>exec_cache_dir = os.getenv(&quot;POPLAR_EXECUTABLE_CACHE_DIR&quot;, &quot;/tmp/exe_cache/&quot;)</pre><h3>Model preparation</h3><p>We start by preparing the model. First, we define the configuration needed to run the model on the IPU. IPUConfig is a class that specifies attributes and configuration parameters to compile and put the model on the device:</p><pre>from optimum.graphcore import IPUConfig<br><br>ipu_config = IPUConfig(<br>    layers_per_ipu=[12, 12],<br>    matmul_proportion=0.15,<br>    executable_cache_dir=exec_cache_dir,<br>    inference_parallelize_kwargs={<br>        &quot;max_length&quot;: 150,<br>        &quot;num_beams&quot;: 3,<br>        &quot;use_encoder_output_buffer&quot;: True,<br>        &quot;on_device_generation_steps&quot;: 16,<br>    }<br>)</pre><p>Next, let’s import pipeline from optimum.graphcore and create our summarization pipeline:</p><pre>from optimum.graphcore import pipeline<br><br>summarizer = pipeline(<br>    &quot;summarization&quot;,<br>    model=&quot;facebook/bart-large-cnn&quot;,<br>    tokenizer=&quot;facebook/bart-large-cnn&quot;,<br>    ipu_config=ipu_config,<br>    config=&quot;facebook/bart-large-cnn&quot;,<br>    max_input_length=1024,<br>    truncation=True<br>)</pre><p>We define an input to test the model.</p><pre>input_test = &#39;In computing, a compiler is a computer program that translates computer code written in one programming language (the source language) into another language (the target language). The name &quot;compiler&quot; is primarily used for programs that translate source code from a high-level programming language to a low-level programming language (e.g. assembly language, object code, or machine code) to create an executable program.&#39;<br>input_test</pre><p>Compilation time for the 1st run: ~ 2:30</p><pre>%%time<br>summarizer(input_test, max_length=150, num_beams=3)</pre><h3>Faster fairy tales</h3><p>The first call to the pipeline was a bit slow, taking several seconds to provide the answer. This behaviour is due to compilation of the model which happens on the first call. On subsequent prompts it is much faster:</p><pre>the_princess_and_the_pea = &#39;Once upon a time there was a prince who wanted to marry a princess; but she would have to be a real princess. He travelled all over the world to find one, but nowhere could he get what he wanted. There were princesses enough, but it was difficult to find out whether they were real ones. There was always something about them that was not as it should be. So he came home again and was sad, for he would have liked very much to have a real princess. One evening a terrible storm came on; there was thunder and lightning, and the rain poured down in torrents. Suddenly a knocking was heard at the city gate, and the old king went to open it. It was a princess standing out there in front of the gate. But, good gracious! what a sight the rain and the wind had made her look. The water ran down from her hair and clothes; it ran down into the toes of her shoes and out again at the heels. And yet she said that she was a real princess. Well, we\&#39;ll soon find that out, thought the old queen. But she said nothing, went into the bed-room, took all the bedding off the bedstead, and laid a pea on the bottom; then she took twenty mattresses and laid them on the pea, and then twenty eider-down beds on top of the mattresses. On this the princess had to lie all night. In the morning she was asked how she had slept. &quot;Oh, very badly!&quot; said she. &quot;I have scarcely closed my eyes all night. Heaven only knows what was in the bed, but I was lying on something hard, so that I am black and blue all over my body. It\&#39;s horrible!&quot; Now they knew that she was a real princess because she had felt the pea right through the twenty mattresses and the twenty eider-down beds. Nobody but a real princess could be as sensitive as that. So the prince took her for his wife, for now he knew that he had a real princess; and the pea was put in the museum, where it may still be seen, if no one has stolen it. There, that is a true story.&#39;<br>the_princess_and_the_pea</pre><pre>%%time<br>summarizer(the_princess_and_the_pea, max_length=150, num_beams=3)</pre><h3>Summarization of Wikipedia articles</h3><p>Now let’s use the Wikipedia API to search for some long text that can be summarized:</p><pre>import wikipedia<br><br># TRY IT YOURSELF BY CHANGING THE PAGE TITLE BELOW<br>page_title = &quot;Queen (band)&quot;<br>text = wikipedia.page(page_title).content<br>text</pre><pre>%%time<br>summarizer(<br>    text,  # NOTE: the input text would be truncated to max_input_length=1024<br>    max_length=150,<br>    num_beams=3,<br>)</pre><h3>Summarization of medical health records</h3><p>The summarization task may be also useful in summarising medical health records (MHR). Let’s import an open source dataset with some medical samples.</p><pre>from datasets import load_dataset<br><br>dataset = load_dataset(&quot;rungalileo/medical_transcription_40&quot;)<br>dataset</pre><p>We focus on the medical report labeled as “text” and from the training dataset select a random patient ID.</p><pre>import random<br><br># RUN THIS CELL AGAIN TO SELECT ANOTHER REPORT<br>random_patient_id = random.randint(0, len(dataset[&quot;train&quot;]))<br><br>exemplary_medical_report = dataset[&quot;train&quot;][random_patient_id][&quot;text&quot;]<br>exemplary_medical_report</pre><pre>%%time<br>summarizer(exemplary_medical_report, max_length=150, num_beams=3)</pre><h3>Running BART-Large on IPUs in non-Paperspace environments</h3><p>To run the demo using other IPU hardware, you need to have the Poplar SDK enabled and the relevant PopTorch wheels installed. Refer to the <a href="https://docs.graphcore.ai/en/latest/getting-started.html#getting-started">getting started guide</a> for your system for details on how to enable the Poplar SDK and install the PopTorch wheels.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a14f0fb125b3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/text-summarization-with-bart-large-on-ipu-a14f0fb125b3">Text Summarization with BART-Large on IPU</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fine-tune OpenAI’s Whisper Automatic Speech Recognition (ASR) Model]]></title>
            <link>https://medium.com/graphcore/fine-tune-openais-whisper-automatic-speech-recognition-asr-model-394b5a4838fb?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/394b5a4838fb</guid>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Wed, 09 Aug 2023 22:31:30 GMT</pubDate>
            <atom:updated>2023-08-09T14:17:43.829Z</atom:updated>
            <content:encoded><![CDATA[<p>Get the most out of Whisper by optimising if for new use cases, including better comprehension of specific languages and dialects, as well as technical and industry-specific terminology.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qBinTDww7regjzbWSnxR7A.png" /></figure><p>by Goran Katalinic</p><p>Whisper — the open source automatic speech recognition (ASR) model created by OpenAI — is incredibly powerful out of the box.</p><p>It is trained on 680,000 hours of labelled audio data, 117,000 hours of which cover 96 languages other than English, meaning that it can be applied to a wide range of applications with great results.</p><p>The vanilla version Whisper is available to run for inference in a <a href="https://www.graphcore.ai/posts/how-to-use-openais-whisper-for-speech-recognition">Paperspace Gradient Notebook</a>, powered by Graphcore IPUs.</p><p>There are also good reasons to fine-tune Whisper for a particular use case. This could include accounting for the complex and sometimes subtle differences in speech and vocabulary as influenced by:</p><ul><li>A less common spoken language</li><li>Locale and dialect</li><li>A particular domain, such as scientific, medical, and legal</li></ul><h3>Where can I get audio data for fine-tuning Whisper?</h3><p>Some organisations may have large amounts of proprietary audio data that can be used in the fine-tuning process. For others, gathering the audio necessary for fine-tuning is not a trivial undertaking.</p><p>Thankfully, there are several open-sourced speech recognition datasets available, covering multiple languages. The largest of these are:</p><ul><li><a href="https://commonvoice.mozilla.org/en/datasets">Common Voice</a>: 16,400 hours spanning 100 languages</li><li><a href="https://www.openslr.org/94/">Multilingual LibriSpeech</a>: 6,000 hours for seven languages other than English</li><li><a href="https://www.openslr.org/12">LibriSpeech</a>: 1,000 hours, English only</li></ul><p>There are smaller datasets covering many more languages and dialects, such as:</p><ul><li><a href="https://aclanthology.org/2021.acl-long.80/">VoxPopuli</a>: 1,800 hours, 16 languages</li><li><a href="https://arxiv.org/abs/2205.12446">Fleurs</a>: 12 hours per language, 102 languages</li><li>There are also individual datasets hosted by <a href="https://www.openslr.org/resources.php">OpenSLR</a></li></ul><p>In our Paperspace Gradient Notebook, we demonstrate fine-tuning using the <a href="https://www.openslr.org/69/">Catalan subset</a> of OpenSLR.</p><h3>How to fine-tune Whisper on Graphcore IPUs</h3><p>Get started by running the Whister Small Fine Tuning notebook on Paperspace.</p><figure><a href="https://ipu.dev/tZntTM"><img alt="Paperspace button" src="https://cdn-images-1.medium.com/max/339/1*nq2kX7fGv7R2vj0SgV07og.png" /></a></figure><p>For each code block below, you can simply click to run the block in Paperspace — making any modifications to code/parameters, where relevant. We explain how to run the process in environments other than Paperspace Gradient Notebooks at the end of this blog.</p><h3>Install dependencies</h3><pre># Install optimum-graphcore from source <br>!pip install git+https://github.com/huggingface/optimum-graphcore.git@v0.7.1 &quot;soundfile&quot; &quot;librosa&quot; &quot;evaluate&quot; &quot;jiwer&quot;<br>%pip install &quot;graphcore-cloud-tools[logger] @ git+https://github.com/graphcore/graphcore-cloud-tools&quot;<br>%load_ext graphcore_cloud_tools.notebook_logging.gc_logger</pre><pre>import os<br><br>n_ipu = int(os.getenv(&quot;NUM_AVAILABLE_IPU&quot;, 4))<br>executable_cache_dir = os.getenv(&quot;POPLAR_EXECUTABLE_CACHE_DIR&quot;, &quot;/tmp/exe_cache/&quot;) + &quot;/whisper&quot;</pre><pre># Generic imports<br>from dataclasses import dataclass<br>from typing import Any, Dict, List, Union<br><br>import evaluate<br>import numpy as np<br>import torch<br>from datasets import load_dataset, Audio, Dataset, DatasetDict<br><br># IPU-specific imports<br>from optimum.graphcore import (<br>    IPUConfig, <br>    IPUSeq2SeqTrainer, <br>    IPUSeq2SeqTrainingArguments, <br>)<br>from optimum.graphcore.models.whisper import WhisperProcessorTorch<br><br># HF-related imports<br>from transformers import WhisperForConditionalGeneration</pre><h3>Load dataset</h3><p>Common Voice datasets consist of recordings of speakers reading text from Wikipedia in different languages. 🤗 Datasets enables us to easily download and prepare the training and evaluation splits.</p><p>First, ensure you have accepted the terms of use on the 🤗 Hub: <a href="https://huggingface.co/datasets/mozilla-foundation/common_voice_13_0">mozilla-foundation/common_voice_13_0</a>. Once you have accepted the terms, you will have full access to the dataset and be able to download the data locally.</p><pre>dataset = DatasetDict()<br>split_dataset = Dataset.train_test_split(<br>    load_dataset(&quot;openslr&quot;, &quot;SLR69&quot;, split=&quot;train&quot;, token=False), test_size=0.2, seed=0<br>)<br>dataset[&quot;train&quot;] = split_dataset[&quot;train&quot;]<br>dataset[&quot;eval&quot;] = split_dataset[&quot;test&quot;]<br>print(dataset)</pre><p>The columns of interest are:</p><ul><li>audio: the raw audio samples</li><li>sentence: the corresponding ground truth transcription.</li></ul><p>We drop the path column.</p><pre>dataset = dataset.remove_columns([&quot;path&quot;])</pre><p>Since Whisper was pre-trained on audio sampled at 16 kHz, we must ensure the Common Voice samples are downsampled accordingly.</p><pre>dataset = dataset.cast_column(&quot;audio&quot;, Audio(sampling_rate=16000))</pre><h3>Prepare Dataset</h3><p>We prepare the datasets by extracting features from the raw audio inputs and injecting labels which are simply transcriptions with some basic processing.</p><p>The feature extraction is provided by 🤗 Transformers WhisperFeatureExtractor. To decode generated tokens into text after running the model, we will similarly require a tokenizer, WhisperTokenizer. Both of these are wrapped by an instance of WhisperProcessor.</p><pre>MODEL_NAME = &quot;openai/whisper-small&quot;<br>LANGUAGE = &quot;spanish&quot;<br>TASK = &quot;transcribe&quot;<br>MAX_LENGTH = 224<br><br>processor = WhisperProcessorTorch.from_pretrained(MODEL_NAME, language=LANGUAGE, task=TASK)<br>processor.tokenizer.pad_token = processor.tokenizer.eos_token<br>processor.tokenizer.max_length = MAX_LENGTH<br>processor.tokenizer.set_prefix_tokens(language=LANGUAGE, task=TASK)</pre><pre>def prepare_dataset(batch, processor):<br>    inputs = processor.feature_extractor(<br>        raw_speech=batch[&quot;audio&quot;][&quot;array&quot;],<br>        sampling_rate=batch[&quot;audio&quot;][&quot;sampling_rate&quot;],<br>    )<br>    batch[&quot;input_features&quot;] = inputs.input_features[0].astype(np.float16)<br><br>    transcription = batch[&quot;sentence&quot;]<br>    batch[&quot;labels&quot;] = processor.tokenizer(text=transcription).input_ids<br>    return batch<br><br>columns_to_remove = dataset.column_names[&quot;train&quot;]<br>dataset = dataset.map(<br>    lambda elem: prepare_dataset(elem, processor),<br>    remove_columns=columns_to_remove,<br>    num_proc=1,<br>)<br><br>train_dataset = dataset[&quot;train&quot;]<br>eval_dataset = dataset[&quot;eval&quot;]</pre><p>Lastly, we pre-process the labels by padding them with values that will be ignored during fine-tuning. This padding is to ensure tensors of static shape are provided to the model. We do this on the fly via the data collator below.</p><pre>@dataclass<br>class DataCollatorSpeechSeq2SeqWithLabelProcessing:<br>    processor: Any<br><br>    def __call__(self, features: List[Dict[str, Union[List[int], torch.Tensor]]]) -&gt; Dict[str, torch.Tensor]:<br>        batch = {}<br>        batch[&quot;input_features&quot;] = torch.tensor([feature[&quot;input_features&quot;] for feature in features])<br>        <br>        label_features = [{&quot;input_ids&quot;: feature[&quot;labels&quot;]} for feature in features]<br>        labels_batch = self.processor.tokenizer.pad(label_features, return_tensors=&quot;pt&quot;, padding=&quot;longest&quot;, pad_to_multiple_of=MAX_LENGTH)<br>        labels = labels_batch[&quot;input_ids&quot;].masked_fill(labels_batch.attention_mask.ne(1), -100)<br><br>        batch[&quot;labels&quot;] = labels<br><br>        return batch</pre><h3>Define metrics</h3><p>The performance of our fine-tuned model will be evaluated using word error rate (WER).</p><pre>metric = evaluate.load(&quot;wer&quot;)<br><br><br>def compute_metrics(pred, tokenizer):<br>    pred_ids = pred.predictions<br>    label_ids = pred.label_ids<br><br>    # replace -100 with the pad_token_id<br>    pred_ids = np.where(pred_ids != -100, pred_ids, tokenizer.pad_token_id)<br>    label_ids = np.where(label_ids != -100, label_ids, tokenizer.pad_token_id)<br><br>    pred_str = tokenizer.batch_decode(pred_ids, skip_special_tokens=True)<br>    label_str = tokenizer.batch_decode(label_ids, skip_special_tokens=True)<br><br>    normalized_pred_str = [tokenizer._normalize(pred).strip() for pred in pred_str]<br>    normalized_label_str = [tokenizer._normalize(label).strip() for label in label_str]<br><br>    wer = 100 * metric.compute(predictions=pred_str, references=label_str)<br>    normalized_wer = 100 * metric.compute(predictions=normalized_pred_str, references=normalized_label_str)<br><br>    return {&quot;wer&quot;: wer, &quot;normalized_wer&quot;: normalized_wer}</pre><h3>Load pre-trained model</h3><pre>model = WhisperForConditionalGeneration.from_pretrained(MODEL_NAME)</pre><pre>model.config.max_length = MAX_LENGTH<br>model.generation_config.max_length = MAX_LENGTH</pre><p>Ensure language-appropriate tokens, if any, are set for generation. We set them on both the config and the generation_config to ensure they are used correctly during generation.</p><pre>model.config.forced_decoder_ids = processor.tokenizer.get_decoder_prompt_ids(<br>    language=LANGUAGE, task=TASK<br>)<br>model.config.suppress_tokens = []<br>model.generation_config.forced_decoder_ids = processor.tokenizer.get_decoder_prompt_ids(<br>    language=LANGUAGE, task=TASK<br>)<br>model.generation_config.suppress_tokens = []</pre><h3>Fine-tuning Whisper on the IPU</h3><p>The model can be directly fine-tuned on the IPU using the IPUSeq2SeqTrainer class.</p><p>The IPUConfig object specifies how the model will be pipelined across the IPUs.</p><p>For fine-tuning, we place the encoder on two IPUs, and the decoder on two IPUs.</p><p>For inference, the encoder is placed on one IPU, and the decoder on a different IPU.</p><pre>replication_factor = n_ipu // 4<br>ipu_config = IPUConfig.from_dict(<br>    {<br>        &quot;optimizer_state_offchip&quot;: True,<br>        &quot;recompute_checkpoint_every_layer&quot;: True,<br>        &quot;enable_half_partials&quot;: True,<br>        &quot;executable_cache_dir&quot;: executable_cache_dir,<br>        &quot;gradient_accumulation_steps&quot;: 16,<br>        &quot;replication_factor&quot;: replication_factor,<br>        &quot;layers_per_ipu&quot;: [5, 7, 5, 7],<br>        &quot;matmul_proportion&quot;: [0.2, 0.2, 0.6, 0.6],<br>        &quot;projection_serialization_factor&quot;: 5,<br>        &quot;inference_replication_factor&quot;: 1,<br>        &quot;inference_layers_per_ipu&quot;: [12, 12],<br>        &quot;inference_parallelize_kwargs&quot;: {<br>            &quot;use_cache&quot;: True,<br>            &quot;use_encoder_output_buffer&quot;: True,<br>            &quot;on_device_generation_steps&quot;: 16,<br>        }<br>    }<br>)</pre><p>Lastly, we specify the arguments controlling the training process.</p><pre>total_steps = 1000 // replication_factor<br>training_args = IPUSeq2SeqTrainingArguments(<br>    output_dir=&quot;./whisper-small-ipu-checkpoints&quot;,<br>    do_train=True,<br>    do_eval=True,<br>    predict_with_generate=True,<br>    learning_rate=1e-5 * replication_factor,<br>    warmup_steps=total_steps // 4,<br>    evaluation_strategy=&quot;steps&quot;,<br>    eval_steps=total_steps,<br>    max_steps=total_steps,<br>    save_strategy=&quot;steps&quot;,<br>    save_steps=total_steps,<br>    logging_steps=25,<br>    dataloader_num_workers=16,<br>    dataloader_drop_last=True,<br>)</pre><p>Then, we just need to pass all of this together with our datasets to the IPUSeq2SeqTrainer class:</p><pre>trainer = IPUSeq2SeqTrainer(<br>    model=model,<br>    ipu_config=ipu_config,<br>    args=training_args,<br>    train_dataset=train_dataset,<br>    eval_dataset=eval_dataset,<br>    data_collator=DataCollatorSpeechSeq2SeqWithLabelProcessing(processor),<br>    compute_metrics=lambda x: compute_metrics(x, processor.tokenizer),<br>    tokenizer=processor.feature_extractor,<br>)</pre><p>To gauge the improvement in WER, we run an evaluation step before fine-tuning.</p><pre>trainer.evaluate()</pre><p>All that remains is to fine-tune the model! The fine-tuning process should take between 6 and 18 minutes, depending on how many replicas are used, and achieve a final WER of around 10%.</p><pre>trainer.train()</pre><h3>Fine-tuning on IPUs in non-Paperspace environments</h3><p>To run the Whisper Small fine-tuning demo using IPU hardware other than in a Paperspace Gradient Notebook, you need to have the Poplar SDK enabled.</p><p>Refer to the <a href="https://docs.graphcore.ai/en/latest/getting-started.html#getting-started">Getting Started guide</a> for your system for details on how to enable the Poplar SDK. Also refer to the <a href="https://docs.graphcore.ai/projects/jupyter-notebook-quick-start/en/latest/index.html">Jupyter Quick Start</a> guide for how to set up Jupyter to be able to run this notebook on a remote IPU machine.</p><h3>Conclusion</h3><p>In this notebook, we demonstrated how to fine-tune Whisper for multi-lingual speech recognition and transcription on the IPU.</p><p>We used a single replica on a total of four IPUs. To reduce the fine-tuning time, more than one replica, hence more IPUs are required. On Paperspace, you can use either an IPU Pod16 or a Bow Pod16, both with 16 IPUs. Please contact Graphcore if you need assistance running on larger platforms.</p><p>For all available notebooks, check <a href="https://www.graphcore.ai/ipu-jupyter-notebooks">IPU-powered Jupyter Notebooks</a> to see how IPUs perform on other tasks.</p><p>Have a question? Please contact us on our <a href="https://www.graphcore.ai/join-community">Graphcore community channel</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=394b5a4838fb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/fine-tune-openais-whisper-automatic-speech-recognition-asr-model-394b5a4838fb">Fine-tune OpenAI’s Whisper Automatic Speech Recognition (ASR) Model</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Llama 2: Run Meta’s latest Open Source Generative Large Language Model on IPUs]]></title>
            <link>https://medium.com/graphcore/llama-2-run-metas-latest-open-source-generative-large-language-model-on-ipus-8961638e4a09?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/8961638e4a09</guid>
            <dc:creator><![CDATA[Tim Santos]]></dc:creator>
            <pubDate>Tue, 01 Aug 2023 13:56:15 GMT</pubDate>
            <atom:updated>2023-08-02T13:01:04.594Z</atom:updated>
            <content:encoded><![CDATA[<h4>Try out 7bn and 13bn parameter versions of the groundbreaking LLM using a Paperspace Gradient Notebook</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eLeDDohbWM_Qah2WqcdvGg.png" /></figure><p>by Tim Santos and Arsalan Udin</p><p>Llama-2 is the latest open-source Large Language Model (LLM) from Meta. It has been described as a game-changer for adoption and commercialisation of LLMs because of its comparable performance with much larger models and its permissive open-source license that allows its use and distribution in commercial applications.</p><p>Now, Graphcore is making the model available to run — for free — using Paperspace Gradient Notebooks.</p><h3>What is Llama-2?</h3><p>Llama 2 is a large language model that offers significant improvements over its predecessor, which was released in February 2023. While the original Llama was only licensed for research use, Llama-2 is free to use, even for commercial applications, under a new open-source licence.</p><p>The latest version of Llama is trained on 40% more data and offers, <a href="https://arxiv.org/abs/2302.13971">according to Meta’s accompanying paper</a>, performance on par with proprietary models such as ChatGPT and Palm, and better than some of the most widely hailed open source LLMs.</p><p>The <a href="https://huggingface.co/meta-llama">Llama-2 model repository</a> offers a variety of mode sizes, namely 7B, 13B, and 70B parameters which makes deployment of applications viable without having to spend a fortune on infrastructure. There are also accompanying variants, fine-tuned for chat-type interaction, using human feedback.</p><h3>How can I use Llama-2 for free on IPUs?</h3><p>At Graphcore we believe in the importance of open-source models in realising the transformative power of AI. They fast-track innovation and breakthroughs, allowing users to build cutting-edge products and services with the minimal burden of starting from scratch or relying on costly proprietary models.</p><p>We are committed to bringing the latest, most exciting models to Graphcore IPU users as soon as possible, so we’re delighted to make the 7bn and 13b parameter versions of Llama-2.</p><p>The accompanying notebook guides you through creating and configuring an inference pipeline on Graphcore IPUs using a Paperspace Gradient notebook which pre-packages libraries and prerequisite files so you can get started with Llama-2 easily.</p><p>New users can try out Llama-2 on a free IPU-Pod4, with Paperspace’s six-hour free trial. For a higher performance implementation, you can scale up to an IPU-Pod16.</p><figure><a href="https://ipu.dev/Vkph1e"><img alt="" src="https://cdn-images-1.medium.com/max/231/1*zSXFsZ802Ye0UWY9sJbgKA.png" /></a></figure><h3>1. Request access to the model weights</h3><p>To download and use the pre-trained Llama-2 base model and fine-tuned Llama-2-chat checkpoints, you will need to authenticate the Hugging Face Hub and create a <a href="https://huggingface.co/login?next=%2Fsettings%2Ftokens">read access token</a> on the Hugging Face website. You will need this token access when prompted after executing the following cell:</p><pre>from huggingface_hub import notebook_login  <br><br>notebook_login()</pre><p>Llama-2 is open-sourced under the <a href="https://ai.meta.com/resources/models-and-libraries/llama-downloads/">Meta license</a> which you’ll need to accept to get access to the model weights and tokenizer. The model cards in Hugging Face hub are also gated models, so you will need to request access through the model cards (see <a href="https://huggingface.co/meta-llama/Llama-2-7b-chat">llama-2–7b-chat</a>, <a href="https://huggingface.co/meta-llama/Llama-2-13b-chat">llama-2–13b-chat)</a>.</p><h3>2. Select Model Weights</h3><p>Meta released 7B, 13B,and 70B parameter versions of the model. Llama-2–7B and Llama-2–13B fits in our Paperspace free tier environment, using a Graphcore IPU-Pod4 system. Users can also scale up to a paid IPU-Pod16 system for faster inference.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*EcgcDNz7vIHspTFhQQOd2Q.png" /></figure><h3>3. Create Inference Pipeline</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qPS6mRatQwuHIWVDEic6ww.png" /></figure><p>Our next goal is to set up the inference pipeline. We’ll specify the maximum sequence length and the micro batch size. Before deploying a model on IPUs, it needs to be translated into a format that’s executable through a compilation process.</p><p>This step takes place when the pipeline is created. It is crucial that all input dimensions are defined prior to this compilation. We have supplied the necessary configurations allowing you to run everything seamlessly. This compilation step could take 15–30 minutes depending on the size of the model, but we also provide the pre-compiled execution file in the cache to bring this step down to a minute.</p><p>Selecting a longer sequence length or larger batch size will use more IPU memory. This means that increasing one may require you to decrease the other. As your next task, try enhancing the system’s efficiency by adjusting these hyperparameters.</p><p>Remember, if you make changes, the pipeline will require recompilation which could take between 10–30 minutes depending on the size of the model.</p><p>If you would like to try another model with different number of parameters, select a different checkpoint in the previous cell and then re-run this step to load the correct model to the IPUs.</p><h3>4. Run Inference</h3><p>Call the llama_pipeline object you have just created to generate text from a prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*nH5hIe0wTHdMGEC0HyI8rg.png" /></figure><p>There are some optional parameters to the pipeline call you can use to control the generation behaviour:</p><p><strong>temperature</strong> — Indicates whether you want more or less creative output. A value of 1.0 corresponds to the model’s default behaviour. Temperatures greater than 1.0 flatten the next token distribution making more unusual next tokens more likely. The temperature must be zero or positive.</p><p><strong>k</strong> — Indicates that only among the highest k probable tokens can be sampled. This is known as “top k” sampling. Set to 0 to disable top k sampling and sample from all possible tokens. The value for k must be between a minimum of 0 and a maximum of config.model.embedding.vocab_size which is 32000. The default is 5.</p><p><strong>output_length</strong> — Sets a maximum output length in tokens. Generation normally stops when the model generates its end_key text, but can be made to stop before that by specifying this option. A value of None disables the limit. The default is &#39;None&#39;.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/915/1*s3yAbs-5anTAq8xNAXgHjA.png" /></figure><p>You can start with a different user input and play around with the optional parameters. For instance, let’s use the prompt “How do I get help if I am stuck on a deserted island?”, set temperature=0.4, and set top-K sampling to 10.</p><h3>Prompting Llama 2</h3><p>One of the advantages of using your own open source LLM is the ability to control the system prompt which is inaccessible in models served behind APIs and chat applications. This lets you pre-define the behaviour of your generative text agent, inject personality, and provide a more streamlined experience for an end-customer or a client application.</p><p>To see the full system prompt and format, you can call the last_instruction_prompt attribute on the pipeline.</p><p>Let us see the default prompt format as described in this <a href="https://huggingface.co/blog/llama2#how-to-prompt-llama-2">Llama 2 prompting guide</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*BFnbq2DC3KKFSvgQHNZmbQ.png" /></figure><h3>Running Llama-2-chat on non-Paperspace IPU environments</h3><p>To run the demo using IPU hardware other than in Paperspace, you can get the code from <a href="https://github.com/graphcore/Gradient-HuggingFace/tree/main/llama2-chatbot">this repository</a>.</p><p>Refer to the <a href="https://docs.graphcore.ai/en/latest/getting-started.html#getting-started">Getting Started</a> guide for your system for details on how to enable the Poplar SDK. Also refer to the <a href="https://docs.graphcore.ai/projects/jupyter-notebook-quick-start/en/latest/index.html">Jupyter Quick Start</a> guide for how to set up Jupyter to be able to run this notebook on a remote IPU machine.</p><h3>Is Llama-2 right for me?</h3><p>Llama-2 is a very powerful model for building your own generative text and chat applications, it comes with a very competitive performance and a permissive license for research and commercialisation. The good performance of Llama-2 with relatively smaller memory footprint makes it a very viable and cost-effective model for wide adoption and deployment in production.</p><p>It is easy to access on IPUs on Paperspace and it can be expanded and deployed to handle a variety of applications.</p><p>You can <a href="https://medium.com/getstarted">contact Graphcore</a> to discuss building and scaling applications using Lllama in the cloud, or anything else.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8961638e4a09" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/llama-2-run-metas-latest-open-source-generative-large-language-model-on-ipus-8961638e4a09">Llama 2: Run Meta’s latest Open Source Generative Large Language Model on IPUs</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OASST1 Fine-tuned Pythia-12B chatbot: open-source ChatGPT alternative]]></title>
            <link>https://medium.com/graphcore/oasst1-fine-tuned-pythia-12b-chatbot-open-source-chatgpt-alternative-22fb6d827c97?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/22fb6d827c97</guid>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[open-assistant]]></category>
            <category><![CDATA[pythia]]></category>
            <category><![CDATA[nlp]]></category>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Wed, 31 May 2023 09:32:56 GMT</pubDate>
            <atom:updated>2023-05-31T09:32:56.062Z</atom:updated>
            <content:encoded><![CDATA[<h4>This powerful open-source chatbot has no usage restrictions, so is perfect for commercial applications. Try it now on Paperspace, powered by IPUs.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vY266QgWyZTZS6vhWsDR2Q.jpeg" /></figure><p>Author: <strong>Steve Barlow</strong>, Member of Engineering Team at Graphcore</p><p>One of the most exciting open-source chatbot alternatives to ChatGPT — OpenAssistant’s OASST1 fine-tuned Pythia-12B — is now available to run for free on Paperspace, powered by Graphcore IPUs. This truly open-source model can be used commercially without restrictions.</p><p>oasst-sft-4-pythia12b is a variant of EleutherAI’s Pythia model family, fine-tuned using the Open Assistant Conversations (OASST1) dataset, a crowdsourced “human-generated, human-annotated assistant-style conversation corpus”.</p><p>The OASST1 dataset consists of 161,443 messages in 35 different languages, annotated with 461,292 quality ratings, resulting in over 10,000 fully annotated conversation trees.</p><h3>Running OASST1 Fine-tuned Pythia-12B inference on Paperspace</h3><p>Open Assistant’s fine-tuned Pythia can easily be run on Graphcore IPUs using a Paperspace Gradient notebook. New users can try out Pythia on an IPU-POD4, with Paperspace’s six hour free trial. For a higher performance implementation, you can scale up to an IPU-POD16.</p><p>The notebook guides you through creating and configuring an inference pipelineand running the pipeline to build a turn-by-turn conversation.</p><p>Because the OpenAssistant model uses the same underlying Pythia-12B model as Dolly, we run it using the Dolly pipeline.</p><figure><a href="https://ipu.dev/VRqSWT"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WVLzKIhZvgsLBYOyhwURQw.png" /></a></figure><p>Let’s begin by loading the inference config. We use the same configuration file as Dolly and manually modify the vocab size which is the only difference between the model graphs. A configuration suitable for your instance will automatically be selected.</p><pre>from utils.setup import dolly_config_setup<br><br>config_name = &quot;dolly_pod4&quot; if number_of_ipus == 4 else &quot;dolly_pod16&quot;<br>config, *_ = dolly_config_setup(&quot;config/inference.yml&quot;, &quot;release&quot;, config_name)<br><br># Update vocab size for oasst-sft-4-pythia-12b-epoch-3.5 - 50288 rather than 50280<br>config.model.embedding.vocab_size = 50288<br><br>config</pre><p>Next, we want to create our inference pipeline. Here we define the maximum sequence length and maximum micro batch size. Before executing a model on IPUs it needs to be turned into an executable format by compiling it. This will happen when the pipeline is created. All input shapes must be known before compiling, so if the maximum sequence length or micro batch size is changed, the pipeline will need to be recompiled.</p><p>Selecting a longer sequence length or larger batch size will use more IPU memory. This means that increasing one may require you to decrease the other.</p><p>This cell will take approximately 18 minutes to complete, which includes downloading the model weights.</p><pre>import api<br><br># changing these parameters will trigger a recompile.<br>sequence_length = 512  # max 2048<br>micro_batch_size = 1<br><br># The pipeline is set to load the OpenAssistant checkpoint rather than the default Dolly one<br><br># We override the Dolly prompt templating by specifying a prompt_format. Setting the format to<br># just echo the instruction means that the pipeline does no formatting and it is up to the<br># application to provide correctly templated prompts<br><br># We set the text string that OpenAssistant uses to mark that it has finished generation, which<br># is different from the Dolly one<br><br>oasst_pipeline = api.DollyPipeline(<br>    config,<br>    sequence_length=sequence_length,<br>    micro_batch_size=micro_batch_size,<br>    hf_dolly_checkpoint=&quot;OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5&quot;,<br>    prompt_format=&quot;{instruction}&quot;,<br>    end_key=&quot;&lt;|endoftext|&gt;&quot;,<br>)</pre><p>Call the oasst_pipeline object you have just created to generate text from a prompt.</p><p>To make a chatbot, we will take user input and feed it to the model. So that the notebook can be tested automatically, we create a function similar to the Python built-in function input() that collects input from the user and returns it, but which will return canned input from a test environment variable EXAMPLE_PROMPTS instead if that variable is set. The variable should be set to a JSON list of strings - for example:</p><pre>export EXAMPLE_PROMPTS=&#39;[&quot;Are you related to Dolly?&quot;, &quot;Ah OK. How many islands are there in Scotland?&quot;]&#39;</pre><pre>import os<br>import json<br><br>example_prompts = os.getenv(&quot;EXAMPLE_PROMPTS&quot;)<br>if example_prompts is not None:<br>    example_prompts = json.loads(example_prompts)<br><br># Get input from user like input() but with possibility of automation via EXAMPLE_PROMPTS environment variable<br>def auto_input(prompt: str) -&gt; str:<br>    if example_prompts is None:<br>        return input(prompt)<br>    auto_in = example_prompts.pop(0) if example_prompts != [] else &quot;&quot;<br>    print(prompt, &quot;AUTO&quot;, auto_in)<br>    return auto_in</pre><p>A chatbot conversation is built up from a number of turns of user input and the model writing a reply. As a conversation develops, the prompt should be extended turn by turn, so the model has access to the full context.</p><p>The model has been trained on a specific prompt template to represent the conversation as it is built up:</p><pre><br>&lt;|prompter|&gt;user1&lt;|endoftext|&gt; &lt;|assistant|&gt;reply1&lt;|endoftext|&gt; &lt;|prompter|&gt;user2&lt;|endoftext|&gt; &lt;|assistant|&gt;...</pre><p>There are a some optional parameters to the pipeline call you can use to control the generation behaviour:</p><ul><li>temperature – Indicates whether you want more or less creative output. A value of 1.0 corresponds to the model&#39;s default behaviour. Smaller values than this accentuate the next token distribution and make the model more likely to pick a highly probable next token. A value of 0.0 means the model will always pick the most probable token. Temperatures greater than 1.0 flatten the next token distribution making more unusual next tokens more likely. Temperature must be zero or positive.</li><li>k – Indicates that only among the highest k probable tokens can be sampled. This is known as &quot;top k&quot; sampling. Set to 0 to disable top k sampling and sample from all possible tokens. The value for k must be between a minimum of 0 and a maximum of config.model.embedding.vocab_size which is 50,288. The default is 5.</li><li>output_length - Sets a maximum output length in tokens. Generation normally stops when the model generates its end_key text, but can be made to stop before that by specifying this option. A value of None disables the limit. The default is &#39;None&#39;.</li></ul><p>You can start with any user input. For instance “What other animals are similar to Alpacas?”</p><pre>import logging<br><br># Conduct a complete conversation - with ability to set pipeline optional parameters<br>def chat(temperature=None, top_k=None, output_length=None):<br><br>    options = {}<br>    if temperature is not None:<br>        options[&quot;temperature&quot;] = temperature<br>    if top_k is not None:<br>        options[&quot;k&quot;] = top_k<br>    if output_length is not None:<br>        options[&quot;output_length&quot;] = output_length<br><br>    # Suppress INFO logging to make a better interactive chat display<br>    logging.disable(logging.INFO)<br><br>    print(&quot;To complete the chat, enter an empty prompt&quot;)<br><br>    prompt = &quot;&quot;<br>    while True:<br>        user_input = auto_input(&quot;Prompter:&quot;)<br>        if user_input == &quot;&quot;:<br>            break<br><br>        prompt += f&quot;&lt;|prompter|&gt;{user_input}&lt;|endoftext|&gt;&lt;|assistant|&gt;&quot;<br>        chat_output = oasst_pipeline(prompt, **options)[0]<br>        prompt += chat_output + &quot;&lt;|endoftext|&gt;&quot;<br><br>    # Restore logging to what it was before<br>    logging.disable(logging.NOTSET)<br><br><br>chat(temperature=0.0)<br><br># Note the first time you run this cell and enter a prompt, there will be a delay of ~1 minute where<br># nothing appears to happen. This is where the server is attaching to the IPUs</pre><p>See image below for an example of the model in action, using a different prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/923/1*WzixBNwegDiZcmiOZ5fRjA.png" /></figure><p>Remember to detach your pipeline when you are finished to free up resources:</p><pre>oasst_pipeline.detach()</pre><h3>Running OASST1 Fine-tuned Pythia in non-Paperspace IPU environments</h3><p>To run the demo using IPU hardware other than in Paperspace, you need to have the Poplar SDK enabled. Refer to the <a href="https://docs.graphcore.ai/en/latest/getting-started.html#getting-started">Getting Started guide</a> for your system for details on how to enable the Poplar SDK. Also refer to the <a href="https://docs.graphcore.ai/projects/jupyter-notebook-quick-start/en/latest/index.html">Jupyter Quick Start guide</a> for how to set up Jupyter to be able to run this notebook on a remote IPU machine.</p><figure><a href="https://ipu.dev/VRqSWT"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WVLzKIhZvgsLBYOyhwURQw.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=22fb6d827c97" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/oasst1-fine-tuned-pythia-12b-chatbot-open-source-chatgpt-alternative-22fb6d827c97">OASST1 Fine-tuned Pythia-12B chatbot: open-source ChatGPT alternative</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Running Flan-T5-XL inference in Float16 for IPU — how we did it]]></title>
            <link>https://medium.com/graphcore/running-flan-t5-xl-inference-in-float16-for-ipu-how-we-did-it-7e3229a6350b?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/7e3229a6350b</guid>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Tue, 30 May 2023 13:28:03 GMT</pubDate>
            <atom:updated>2023-05-30T13:28:03.725Z</atom:updated>
            <content:encoded><![CDATA[<h3>Running Flan-T5-XL inference in Float16 for IPU — how we did it</h3><h4>T5 has only worked with bfloat16, until now. Find out how Graphcore made it run on float16 hardware.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8BQa23zc0Sicm-VyzlYBTQ.png" /></figure><p>Author: <strong>Harry Mellor</strong>, AI Engineer at Graphcore</p><p>The T5 language model has proved hugely popular since it first appeared in Hugging Face Transformers. There have also been constant demands to make T5 runnable at float16 precision.</p><p>Until now, T5 has only worked with hardware that supports bfloat16, the format that the model was originally trained with. This has limited its use to select CPUs, TPUs beyond v2, and GPUs beyond A100.</p><p>The best alternative — using float32 — typically leads to exceeding hardware memory limits or simply taking too long to execute, compared to running in float16.</p><p>With the release of FLAN-T5, we were keen to offer these models <a href="https://www.graphcore.ai/posts/flan-t5-sweet-results-with-the-smaller-more-efficient-llm">running on our IPUs </a>— which means using float16.</p><p>In this blog, we are delighted to present our FLAN-T5 for IPU solution. While this has been developed specifically for the T5 model, the methods are reusable and can help you in similar scenarios.</p><h3>Porting T5 to float16 on IPU</h3><h4>Identifying dynamic parts of the computational graph</h4><p>Before running the model we need to carry out a quick visual inspection of the model code to look for parts that won’t compile into a static graph. We found dynamic branching of the graph in the T5Block. Coincidentally, the branches that are created clamp the data if it has already overflowed in float16:</p><pre># clamp inf values to enable fp16 training <br>if hidden_states.dtype == torch.float16 and torch.isinf(hidden_states).any(): <br>    clamp_value = torch.finfo(hidden_states.dtype).max - 1000 <br>    hidden_states = torch.clamp(hidden_states, min=-clamp_value, max=clamp_value) </pre><p>We chose to remove the dynamic condition, torch.isinf(hidden_states).any(), from this branch* because:</p><ul><li>We cannot statically compile this dynamic branching condition</li><li>While clamping the hidden states only treats the symptom of float16 issues, it is still needed for training and so cannot be removed entirely. See the “FeedForward’s down projection” section for details on how we treated the cause for inference.</li></ul><p>*this change has also been made in the latest version of Transformers</p><h4>Enabling Poplar’s floating-point exception detection</h4><p>Our Poplar backend has floating-point exception detection built-in, which makes tracking down the source of numerical issues far more straightforward. The process consists of the following steps:</p><ol><li>Enable floating-point exceptions in your application. In PopTorch, you can use opts.Precision.enableFloatingPointExceptions(True) <br>(For more information see the <a href="https://docs.graphcore.ai/projects/poptorch-user-guide/en/latest/index.html">PopTorch User Guide</a>)</li><li>Run your application with graph profiling enabled: POPLAR_ENGINE_OPTIONS&quot;=&#39;{&quot;autoReport.all&quot;:&quot;true&quot;, &quot;autoReport.outputExecutionProfile&quot;: &quot;false&quot;, &quot;autoReport.directory&quot;:&quot;./report&quot;}&#39;<br>For more details see the section on <a href="https://docs.graphcore.ai/projects/graph-analyser-userguide/en/latest/capturing-ipu-reports.html">capturing IPU reports</a> in the <a href="https://docs.graphcore.ai/projects/graph-analyser-userguide/en/latest/index.html">Graph Analyser User Guide</a>*.</li><li>If a floating-point exception is triggered a poptorch_error.log file will be generated. Open this file and scroll down to (or search for) Backtrace. Find the ID nearest the top of the backtrace, denoted by (Id: 1234), and search for it in the graph profile’s program tree. From here you should be able to examine the debug information of the offending operation and figure out where in the model it came from.</li></ol><p>*note that we use &quot;autoReport.outputExecutionProfile&quot;: &quot;false&quot; to <a href="https://docs.graphcore.ai/projects/graph-analyser-userguide/en/latest/capturing-ipu-reports.html#profiling-overhead">avoid the overhead of profiling the execution</a>. We can do this because we are only interested in the program tree.</p><p>Using this method, we solved the rest of the floating-point exceptions.</p><h3>Resolving the floating-point exceptions</h3><h4>Attention Masking</h4><p>The first two exceptions were found in the attention masking. In two places the attention mask was “inverted” and used additively. The mask value was set to -torch.finfo(torch.float16).min (i.e.-65504) and the pass value was set to 0. This was done so that when the masked attention values are passed to softmax they have minimum relevance in the resulting output. However, if what you were masking was negative and had an absolute value greater than the resolution of float16 at -65504, then you would end up with a negative infinity:</p><pre>&gt;&gt;&gt; torch.tensor([-65504], dtype=torch.float16) - 10 <br>tensor([-65504.], dtype=torch.float16) <br>&gt;&gt;&gt; torch.tensor([-65504], dtype=torch.float16) - 100 <br>tensor([-inf], dtype=torch.float16) </pre><p>We solved these two exceptions by simply scaling the mask down by 25%, meaning that you could have attention values as low as -16376 without the mask causing an overflow.</p><h4>GeLU approximated by tanh</h4><p>The third exception was found in the explicit definition of the tanh GeLU approximation used by the FLAN-T5 model (the original T5 model used ReLU activations). The formula</p><pre>0.5 * input * (1.0 + torch.tanh(math.sqrt(2.0 / math.pi) * (input + 0.044715 * torch.pow(input, 3.0)))) </pre><p>cubes the input, which will cause an overflow if the absolute value of the input is larger than approximately 39. We fixed this by reverting to ReLU when the input was larger than 39, which is a safe approximation to make since ReLU==GeLU when the absolute value of the input is &gt;5.</p><h4>Pre-norm residual connections</h4><p>The fourth exception was found in the residual additions in the encoder’s FF layers. We were seeing that, when the output of the FF network was added to its input, the operation was overflowing. We solved this by:</p><ol><li>Casting the embeddings input to the first encoder block to float32</li><li>For the SelfAttention and FeedForward layers in every encoder block:</li><li>Cast to float16 after LayerNorm* so that the bulk of the compute still happens in float16</li><li>Cast to float32 after the dropout before adding to the float32 residual connection</li><li>Cast the output of final_layer_norm* after all the encoder blocks back to float16 ready for the decoder, which is all float16</li></ol><p>*this actually happened automatically because of the way that LayerNorm was implemented for T5</p><p>The following diagrams are colour coded as follows to represent the precision of the data:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*3kvAuZeESt6V_USWfTKnXQ.jpeg" /></figure><p>The T5 encoder consists of a chain of blocks, each block contains a SelfAttention layer and a FeedForward layer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*BIGvoQkzYT3KnWIkqXkqig.jpeg" /></figure><p>Each of these layers has the same fundamental structure, with the only difference being the Attention/Hidden layer:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L-8iYnBlgKsxFMko1z50eQ.jpeg" /></figure><p>After the casting changes mentioned in step 2 above, these layers look like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1021/1*LAAztXHhWWrVqlZ368UO6Q.jpeg" /></figure><p>This prevents overflow in the pre-norm residuals that get passed all the way through the encoder.</p><h4>FeedForward’s down projection</h4><p>The final floating-point exception was found in the down projection in the Hidden part of the encoder’s FeedForward layer. In the code this is the wo layer, which we shall refer to as DownProject for clarity. Currently, the FeedForward layer and its Hidden component look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1021/1*tEV2THHcu-vozp49wuYyvg.jpeg" /></figure><p>We were able to resolve the overflow in DownProject by scaling down its input and then scaling up its output once it was safely in float32 again.</p><p>The scaling factor was chosen by examining the standard deviation of the activations coming out of DownProject and identifying a suitable power of 2 that would tame these activations. We want to use a power of two because then only the exponents of the float16 activations need to be changed, avoiding lossy modification of the mantissa.</p><p>We found that the standard deviation was ~4400 and so we chose 8 as our scaling factor to reduce the standard deviation to ~550. After implementing this scaling, the FeedForward layer and its Hidden component look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1021/1*yalglREJ8ugHmSxBB6kgIg.jpeg" /></figure><p>The solution to this problem in the latest version of Transformers keeps this layer in float32 at all times.</p><h3>Validation</h3><p>Since we’ve changed a few things in the model, you’re probably wondering if the model still performs as it is supposed to. We wondered this too, and so validated it on a subset* of the MMLU benchmark on CPU in float32 and on IPU in float16. The CPU and IPU achieved overall averages of 49.3% and 49.4% respectively, proving that we have not degraded the performance of the original model.</p><p>*Our current implementation of FLAN-T5-XL has a maximum input length of 896 tokens, so we used the subset of MMLU where the examples did not exceed this length.</p><h3>Conclusion</h3><p>With this, we now have FLAN-T5-XL implementation that can be used for inference on IPU in float16. Please head over to Paperspace to try it out for yourself!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tS40fwaXVhdd_eED32tARA.png" /></figure><p>You can also try other variations of T5 on IPUs:</p><ul><li><a href="https://ipu.dev/OM0Cd9">Zero-Shot Text Classification on IPUs using MT5-Large — Inference</a></li><li><a href="https://ipu.dev/GSZ06V">Machine Translation on IPUs using MT5-Small — Fine-tuning</a></li><li><a href="https://ipu.dev/woSgrH">Summarization on IPU using T5-Small — Fine-Tuning</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7e3229a6350b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/running-flan-t5-xl-inference-in-float16-for-ipu-how-we-did-it-7e3229a6350b">Running Flan-T5-XL inference in Float16 for IPU — how we did it</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flan-T5: sweet results with the smaller, more efficient LLM]]></title>
            <link>https://medium.com/graphcore/flan-t5-sweet-results-with-the-smaller-more-efficient-llm-3879f0acd263?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/3879f0acd263</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[nlp]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[flan-t5]]></category>
            <category><![CDATA[naturallanguageprocessing]]></category>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Tue, 30 May 2023 13:27:48 GMT</pubDate>
            <atom:updated>2023-05-30T13:27:48.786Z</atom:updated>
            <content:encoded><![CDATA[<h4>Flan-T5 offers outstanding performance for a range of NLP applications, even compared to very large language models. Try now on Paperspace, powered by IPUs</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iSg3-WnTkEIz1y7Kn6LraA.jpeg" /></figure><p>Author: <strong>Harry Mellor</strong>, AI Engineer at Graphcore</p><p>In the world of AI language models, there’s no one-size-fits-all solution.</p><p>Commercial users are increasingly coming to the realisation that Ultra-Large Language Models, while broadly capable, are AI overkill for many applications.</p><p>The penny (or dollar) usually drops when they receive an outsize bill from the owners of their prefered proprietary model, or cloud compute provider. That’s assuming they can even secure GPU availability for the A100 and H100 system needed to run advanced models.</p><p>Instead, many are looking to more efficient, open-source alternatives to the likes of GPT-3/4.</p><h3>Flan T5</h3><p>In December 2022 Google published <a href="https://arxiv.org/abs/2210.11416">Scaling Instruction-Finetuned Language Models</a> in which they perform extensive fine-tuning for a broad collection of tasks across a variety of models (PaLM, T5, U-PaLM).</p><p>Part of this publication was the release of Flan-T5 checkpoints, “which achieve strong few-shot performance” with relatively modest parameter counts “even compared to much larger models” like the largest members of the GPT family.</p><p>In this blog, we will show how you can use Flan-T5 running on a Paperspace Gradient Notebook, powered by Graphcore IPUs. Flan-T5-Large can be run on an IPU-POD4, using Paperspace’s six hour free trial, while Flan-T5-XL can be run on a paid IPU-POD16.</p><p>We will look at a range of common NLP workloads and consider the following:</p><ul><li>How good is Flan-T5, really?</li><li>How do I run Flan-T5 on IPUs?</li><li>What can I use Flan-T5 for?</li><li>Why would I move up to Flan-T5-XL?</li></ul><figure><a href="https://ipu.dev/hbsT9D"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tS40fwaXVhdd_eED32tARA.png" /></a></figure><h3>How good is Flan-T5, really?</h3><p>Let’s start by looking at some performance numbers from the Google-authored paper:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q60vNbgrA6U1suPiyP24YA.jpeg" /><figcaption>Part of table 5 from <a href="https://arxiv.org/abs/2210.11416">Scaling Instruction-Finetuned Language Models</a></figcaption></figure><p>These results are astounding. Notice that:</p><ul><li>Flan-T5 performs ~2x better than T5 in MMLU, BBH &amp; MGSM</li><li>In TyDiQA we even see the emergence of new abilities</li><li>Flan-T5-Large is better than all previous variants of T5 (even XXL)</li></ul><p>This establishes Flan-T5 as an entirely different beast to the T5 that you may know. Now let’s see how Flan-T5-Large and Flan-T5-XL compare to other models in the MMLU benchmark:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*saGCVWGfeYzFz8RoTvoG7A.jpeg" /><figcaption>Part of the MMLU leaderboard from <a href="https://paperswithcode.com/sota/multi-task-language-understanding-on-mmlu">Papers With Code</a> (CoT = Chain of Thought)</figcaption></figure><p>Noting that Flan-T5 had MMLU held out from training, this table shows that:</p><ul><li>Flan-T5-Large and Flan-T5-XL (with 0.8B and 3B parameters respectively) perform similarly to other models with significantly more parameters, for example GPT-3 (175B parameters) and Galactica (120B parameters).</li><li>GPT-3 needs to be fine-tuned for the benchmark task in order to beat Flan-T5-XL.</li><li>Flan-T5 outperforms smaller versions of more recent LLMs like PaLM and LLaMA (while also being multiple times smaller).</li></ul><h3>How do I run Flan-T5 on IPUs?</h3><p>Since the Flan-T5 checkpoints are available on Hugging Face, you can use Graphcore’s Hugging Face integration (🤗 <a href="https://github.com/huggingface/optimum-graphcore">Optimum Graphcore</a>) to easily run Flan-T5 with a standard inference pipeline.</p><p>If you already have an existing Hugging Face-based application that you’d like to try on IPUs, then it is as simple as:</p><pre>- from transformers import pipeline <br>+ from optimum.graphcore import pipeline <br> <br>- text_generator = pipeline(&quot;text2text-generation&quot;, model=&quot;google/flan-t5-large&quot;) <br>+ text_generator = pipeline(&quot;text2text-generation&quot;, model=&quot;google/flan-t5-large&quot;, ipu_config=&quot;Graphcore/t5-large-ipu&quot;) <br><br>text_generator(&quot;Please solve the following equation: x^2 - 9 = 0&quot;) <br>[{&#39;generated_text&#39;: &#39;3&#39;}]</pre><p>Now let’s define a text generator of our own to use in the rest of this notebook. First, make sure that your Python virtual environment has the latest version of <a href="https://github.com/huggingface/optimum-graphcore">🤗 Optimum Graphcore</a> installed:</p><pre>%pip install &quot;optimum-graphcore&gt;=0.6.1, &lt;0.7.0&quot; </pre><p>The location of the cache directories can be configured through environment variables or directly in the notebook:</p><pre>import os <br>executable_cache_dir=os.getenv(&quot;POPLAR_EXECUTABLE_CACHE_DIR&quot;, &quot;./exe_cache/&quot;) <br>num_available_ipus=int(os.getenv(&quot;NUM_AVAILABLE_IPU&quot;, 4)) </pre><p>Next, let’s import pipeline from optimum.graphcore and create our Flan-T5 pipeline for the appropriate number of IPUs:</p><pre>from optimum.graphcore import pipeline <br> <br>size = {4: &quot;large&quot;, 16: &quot;xl&quot;} <br>flan_t5 = pipeline( <br>    &quot;text2text-generation&quot;, <br>    model=f&quot;google/flan-t5-{size[num_available_ipus]}&quot;, <br>    ipu_config=f&quot;Graphcore/t5-{size[num_available_ipus]}-ipu&quot;, <br>    max_input_length=896, <br>    ipu_config=ipu_config, <br>) <br>flan_t5.model.ipu_config.executable_cache_dir = executable_cache_dir </pre><p>Now, let’s ask it some random questions:</p><pre>questions = [ <br>    &quot;Solve the following equation for x: x^2 - 9 = 0&quot;, <br>    &quot;At what temperature does nitrogen freeze?&quot;, <br>    &quot;In order to reduce symptoms of asthma such as tightness in the chest, wheezing, and difficulty breathing, what do you recommend?&quot;, <br>    &quot;Which country is home to the tallest mountain in the world?&quot; <br>] <br>for out in flan_t5(questions): <br>    print(out) </pre><pre>Graph compilation: 100%|██████████| 100/100 [05:20&lt;00:00] <br>Graph compilation: 100%|██████████| 100/100 [02:56&lt;00:00] <br> <br> <br>{&#39;generated_text&#39;: &#39;3&#39;} <br>{&#39;generated_text&#39;: &#39;-32 °C&#39;} <br>{&#39;generated_text&#39;: &#39;ibuprofen&#39;} <br>{&#39;generated_text&#39;: &#39;nepal&#39;} </pre><p>Note that some of these answers may be wrong, information retrieval from the model itself is not the purpose of Flan-T5. However, if you use Flan-T5-XL they are less likely to be wrong (come back to this notebook with an IPU-POD16 to see the difference!)</p><h3>What can I use Flan-T5 for?</h3><p>Flan-T5 has been fine-tuned on thousands of different tasks across hundreds of datasets. So no matter what your task might be, it’s worth seeing if Flan-T5 can meet your requirements. Here we will demonstrate a few of the common ones:</p><h4>Sentiment Analysis</h4><pre>sentiment_analysis = ( <br>    &quot;Review: It gets too hot, the battery only can last 4 hours. Sentiment: Negative\n&quot; <br>    &quot;Review: Nice looking phone. Sentiment: Positive\n&quot; <br>    &quot;Review: Sometimes it freezes and you have to close all the open pages and then reopen where you were. Sentiment: Negative\n&quot; <br>    &quot;Review: Wasn&#39;t that impressed, went back to my old phone. Sentiment:&quot; <br>) <br><br>flan_t5(sentiment_analysis)[0][&quot;generated_text&quot;] </pre><pre>Negative</pre><h4>Advanced Named Entity Recognition</h4><p>The following snippets are adapted from the Wikipedia pages corresponding to each mentioned company.</p><pre>advanced_ner = &quot;&quot;&quot;Microsoft Corporation is a company that makes computer software and video games. Bill Gates and Paul Allen founded the company in 1975 <br>[Company]: Microsoft, [Founded]: 1975, [Founders]: Bill Gates, Paul Allen <br> <br>Amazon.com, Inc., known as Amazon , is an American online business and cloud computing company. It was founded on July 5, 1994 by Jeff Bezos <br>[Company]: Amazon, [Founded]: 1994, [Founders]: Jeff Bezos <br> <br>Apple Inc. is a multinational company that makes personal computers, mobile devices, and software. Apple was started in 1976 by Steve Jobs and Steve Wozniak.&quot;&quot;&quot; <br><br>flan_t5(advanced_ner)[0][&quot;generated_text&quot;]</pre><pre>[Company]: Apple, [Founded]: 1976, [Founders]: Steve Jobs, Steve Wozniak</pre><h4>Question Answering</h4><p>The following snippet came from the <a href="https://huggingface.co/datasets/squad">squad</a> dataset.</p><pre>context = &#39;Super Bowl 50 was an American football game to determine the champion of the National Football League (NFL) for the 2015 season. The American Football Conference (AFC) champion Denver Broncos defeated the National Football Conference (NFC) champion Carolina Panthers 24-10 to earn their third Super Bowl title. The game was played on February 7, 2016, at Levi\&#39;s Stadium in the San Francisco Bay Area at Santa Clara, California. As this was the 50th Super Bowl, the league emphasized the &quot;golden anniversary&quot; with various gold-themed initiatives, as well as temporarily suspending the tradition of naming each Super Bowl game with Roman numerals (under which the game would have been known as &quot;Super Bowl L&quot;), so that the logo could prominently feature the Arabic numerals 50.&#39;<br>question = &quot;Which NFL team represented the AFC at Super Bowl 50?&quot;<br># The correct answer is Denver Broncos<br>flan_t5(f&quot;{context} {question}&quot;)[0][&#39;generated_text&#39;]</pre><pre>Denver Broncos</pre><h4>Intent Classification</h4><pre>intent_classification = &quot;&quot;&quot;[Text]: I really need to get a gym membership, I&#39;m exhausted. <br>[Intent]: get gym membership <br> <br>[Text]: What do I need to make a carbonara? <br>[Intent]: cook carbonara <br> <br>[Text]: I need all these documents sorted and filed by Monday. <br>[Intent]:&quot;&quot;&quot; <br><br>flan_t5([intent_classification])[0][&quot;generated_text&quot;]</pre><pre>file documents</pre><h4>Summarization</h4><p>The following snippets came from the <a href="https://huggingface.co/datasets/xsum">xsum</a> dataset.</p><pre>summarization=&quot;&quot;&quot; <br>Document: Firstsource Solutions said new staff will be based at its Cardiff Bay site which already employs about 800 people. <br>The 300 new jobs include sales and customer service roles working in both inbound and outbound departments. <br>The company&#39;s sales vice president Kathryn Chivers said: &quot;Firstsource Solutions is delighted to be able to continue to bring new employment to Cardiff.&quot; <br>Summary: Hundreds of new jobs have been announced for a Cardiff call centre. <br> <br>Document: The visitors raced into a three-goal first-half lead at Hampden. <br>Weatherson opened the scoring with an unstoppable 15th-minute free-kick, and he made it 2-0 in the 27th minute. <br>Matt Flynn made it 3-0 six minutes later with a fine finish. <br>Queen&#39;s pulled a consolation goal back in stoppage time through John Carter. <br>Summary: Peter Weatherson netted a brace as Annan recorded only their second win in eight matches. <br> <br>Document: Officers searched properties in the Waterfront Park and Colonsay View areas of the city on Wednesday. <br>Detectives said three firearms, ammunition and a five-figure sum of money were recovered. <br>A 26-year-old man who was arrested and charged appeared at Edinburgh Sheriff Court on Thursday. <br>Summary: <br>&quot;&quot;&quot; <br>flan_t5(summarization)[0][&quot;generated_text&quot;]</pre><pre>A man has been arrested after a firearm was found in a property in Edinburgh.</pre><h4>Text Classification</h4><pre>text_classification_1 = &quot;&quot;&quot;A return ticket is better value than a single. <br>topic: travel cost <br><br>You can start from the basic stitches, and go from there. <br>topic: learning knitting <br><br>The desk which I bought yesterday is very big. <br>topic: furniture size <br><br>George Washington was president of the United States from 1789 to 1797. <br>topic:&quot;&quot;&quot; <br><br>flan_t5(text_classification_1)[0][&quot;generated_text&quot;]</pre><pre>George Washington presidency</pre><pre>text_classification_2 = &quot;&quot;&quot;FLAN-T5 was released in the paper Scaling Instruction-Finetuned Language Models - it is an enhanced version of T5 that has been finetuned in a mixture of tasks. <br>keywords: released, enhanced, finetuned <br><br>The IPU, or Intelligence Processing Unit, is a highly flexible, easy-to-use parallel processor designed from the ground up for AI workloads. <br>keywords: processor, AI <br><br>Paperspace is the platform for AI developers. providing the speed and scale needed to take AI models from concept to production. <br>keywords:&quot;&quot;&quot; <br><br>flan_t5(text_classification_2)[0][&quot;generated_text&quot;]</pre><pre>paperspace, AI, scale</pre><h3>Why would I move up to Flan-T5-XL?</h3><p>As we saw earlier, when looking at the results from the paper, Flan-T5-XL is roughly 40% (on average) better than Flan-T5-Large across its validation tasks. Therefore when deciding if Flan-T5-XL is worth the cost for you, ask yourself the following questions:</p><ul><li>Does my data need greater linguistic understanding for the task to be performed?</li><li>Is my task too complicated for a model as small as Flan-T5-Large and too easy for a model as large as GPT-3?</li><li>Does my task require longer output sequences that Flan-T5-XL is needed to generate?</li></ul><p>To demonstrate, let us now look at an example of a task where the answer to all of the above questions is yes. Let’s say you have a customer service AI that you use to answer basic questions in order to reduce the workload of your customer service personnel. This needs:</p><ul><li>Strong linguistic ability to both parse and generate medium-sized chunks of text.</li><li>An LLM that is able to learn well from context, but doesn’t have all of human history embedded in its parameters.</li><li>The ability to produce multiple-sentence responses, but not much longer than this.</li></ul><p>Looking at the code below, we see some context about Graphcore provided in the input, as well as a primer for a conversational response from the model. As you can see from the example, Flan-T5-XL was able to understand the information provided in the context and provide useful and natural answers to the questions it was asked.</p><pre>from IPython.display import clear_output <br> <br>class ChatBot: <br>    def __init__(self, model, context) -&gt; None: <br>        self.model = model <br>        self.initial_context = context <br>        self.context = self.initial_context <br>        self.user, self.persona = [x.split(&quot;:&quot;)[0] for x in context.split(&quot;\n&quot;)[-2:]] <br> <br>    def ask(self, question): <br>        question += &quot;.&quot; if question[-1] not in [&quot;.&quot;, &quot;?&quot;, &quot;!&quot;] else &quot;&quot; <br>        x = f&quot;{self.context}\n{self.user}: {question}\n{self.persona}: &quot; <br>        # print(f&quot;\n{x}\n&quot;) <br>        y = self.model(x) <br>        response = y[0][&quot;generated_text&quot;] <br>        self.context = f&quot;{x}{response}&quot; <br>        return response <br> <br>    def session(self): <br>        print(&quot;Starting session&quot;, flush=True) <br>        prompt = input() <br>        while prompt != &quot;&quot;: <br>            if prompt == &quot;reset&quot;: <br>                clear_output() <br>                print(&quot;Starting session&quot;, flush=True) <br>                self.context = self.initial_context <br>                prompt = input() <br>            print(f&quot;{self.user.title()}: {prompt}&quot;, flush=True) <br>            answer = self.ask(prompt) <br>            print(f&quot;{self.persona.title()}: {answer}&quot;, flush=True) <br>            prompt = input() <br>        print(&quot;Ending session&quot;, flush=True)<br>context = f&quot;&quot;&quot;This is a conversation between a [customer] and a [virtual assistant]. <br>The [virtual assistant] works at Graphcore. Here is some informaton about Graphcore: <br>- Graphcore is located in Bristol. <br>- Graphcore invented the intelligence processing unit (IPU). It is purpose built for AI applications. <br>- The currently available IPU models are: Classic IPU, Bow IPU, C600. <br>- IPUs are available on: Paperspace, Gcore Cloud and Graphcloud. <br> <br>[virtual assistant]: Hello, welcome to Graphcore, how can I help you today? <br>[customer]: I&#39;d like to ask some questions about your company. <br>[virtual assistant]: Ok, I can help you with that.&quot;&quot;&quot; <br>chatbot = ChatBot(flan_t5, context) <br>chatbot.session()</pre><pre>Starting session <br>[Customer]: What is an IPU? <br>[Virtual Assistant]: The Intelligence Processing Unit (IPU) is a computer chip that is used to process artificial intelligence. <br>[Customer]: Who makes it? <br>[Virtual Assistant]: Graphcore is the manufacturer of the IPU. <br>[Customer]: Can I use them? <br>[Virtual Assistant]: Yes, I&#39;m sure you can. <br>[Customer]: Where? <br>[Virtual Assistant]: The IPU is available on Paperspace, Gcore and Graphcloud. <br>Ending session</pre><pre>flan_t5.model.detachFromDevice() </pre><h3>Conclusion</h3><p>In summary, the answers to the questions we posed in the introduction are:</p><h4>How good is Flan-T5, really?</h4><p><strong>A:</strong> Twice as good as T5 and on par with GPT-3 according to the MMLU benchmark.</p><h4>How do I run Flan-T5 on IPUs?</h4><p><strong>A:</strong> Change one import and add one keyword argument to your pipeline instantiation.</p><h4>What can I use Flan-T5 for?</h4><p><strong>A:</strong> Given its wide variety of fine-tuned tasks, almost anything.</p><h4>Why would I move up to Flan-T5-XL?</h4><p><strong>A:</strong> For an approximately 40% performance increase over Flan-T5-Large, enabling more demanding tasks.</p><figure><a href="https://ipu.dev/hbsT9D"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tS40fwaXVhdd_eED32tARA.png" /></a></figure><p>If you’d like to learn more about how we got T5 to work properly in Float16, see our <a href="https://www.graphcore.ai/posts/running-flan-t5-xl-inference-in-float16-for-ipu-how-we-did-it">technical blog</a> on the subject.</p><p>You can also try other variations of T5 on IPUs:</p><ul><li><a href="https://ipu.dev/OM0Cd9">Zero-Shot Text Classification on IPUs using MT5-Large — Inference</a></li><li><a href="https://ipu.dev/GSZ06V">Machine Translation on IPUs using MT5-Small — Fine-tuning</a></li><li><a href="https://ipu.dev/woSgrH">Summarization on IPU using T5-Small — Fine-Tuning</a></li></ul><p>If you’d like to continue exploring NLP on the IPU, take a look at our <a href="https://www.graphcore.ai/posts/fine-tuned-gpt-j-a-cost-effective-alternative-to-gpt-4-for-nlp-tasks">GPT-J Fine-Tuning blog</a> and corresponding notebook.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3879f0acd263" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/flan-t5-sweet-results-with-the-smaller-more-efficient-llm-3879f0acd263">Flan-T5: sweet results with the smaller, more efficient LLM</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Small language models, high performance: DeBERTa and the Future of NLU]]></title>
            <link>https://medium.com/graphcore/small-language-models-high-performance-deberta-and-the-future-of-nlu-fa460c25e71c?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/fa460c25e71c</guid>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[nlu]]></category>
            <category><![CDATA[deberta]]></category>
            <category><![CDATA[nlp]]></category>
            <category><![CDATA[small-language-model]]></category>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Tue, 23 May 2023 17:07:55 GMT</pubDate>
            <atom:updated>2023-05-23T17:09:16.595Z</atom:updated>
            <content:encoded><![CDATA[<h4>DeBERTa is an efficient language model, optimised for Natural Language Understanding (NLU). Try for free on Paperspace Gradient Notebooks powered by IPUs.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0CWFBF_Rvm3b-doXa19BGw.png" /></figure><p>Author: Luke Markham, Field Application Engineer at Graphcore</p><p>Large Language Models (LLMs) such as OpenAI’s GPTs, Google’s Bard, and Meta’s LLaMA have popularised the concept of Natural Language Processing in AI and are now finding a growing number of commercial uses.</p><p>While much attention has been focused on the generative capabilities of such models, many NLP applications require Natural Language Understanding (NLU), rather than generation.</p><p>NLU is used in chatbots and virtual assistants, enabling them to understand user queries and navigate conversation flow. It also plays a critical role in search engines, where it helps to retrieve relevant information based on user queries.</p><p>The healthcare industry is increasingly deploying NLU to extract information from patient records and assist doctors in making more accurate diagnoses.</p><p>Perhaps because certain high-profile LLMs have demonstrated broad capabilities, some users are turning to them for NLU applications, but this may prove to be computational overkill.</p><p>In this article, we’ll explore how smaller models such as Microsoft’s DeBERTa can achieve surprising performance on NLU tasks.</p><figure><a href="https://ipu.dev/2XQcBI"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I2CCl4gsq7nPOVGnGtAndA.png" /></a></figure><h3>Beyond text-based Interfaces</h3><p>The usefulness of NLP-powered systems has advanced hugely in recent years, however there are limitations to primarily text-based interfaces such as chatbots and virtual assistants:</p><p>Communicating by text alone can be challenging when dealing with complex information, such as medical diagnoses or financial advice, which may require visual aids such as diagrams, images, graphs, or maps.</p><p>Conveying emotion and tone through text is also difficult and can lead to misunderstandings or misinterpretations, particularly in customer service applications.</p><p>Finally, there is the issue of cognitive overload, which occurs when users are presented with too much text at once, leading to confusion and frustration.</p><p>To address these problems, NLP applications can incorporate other forms of media, such as images, graphs, and maps, into their UI/UX design.</p><p>NLU models play a critical role in this process by creating the structured data formats required for these designs.</p><p>For example, a weather app could use a chatbot interface that also incorporates graphs and maps to convey information more effectively, with NLU models extracting relevant information from user input and converting it into a structured format.</p><h3>Cost-Efficiency of Smaller Models</h3><p>Large, complex LLMs like GPT-3/4 and T5 aren’t always the most efficient for these sorts of tasks. While the simplicity of setting them up can be seductive, they are often computationally expensive which, of course, translates into being financially expensive.</p><p>Using smaller models like DeBERTa can lead to significant savings while maintaining high levels of accuracy. In many cases, these smaller models can even outperform larger models on specific tasks.</p><p>Because smaller models require less computational power to train and use, thet can be faster and more accessible. The smaller size of these models also allows them to be deployed on smaller devices, making them ideal for edge computing and other resource-constrained environments.</p><h3>DeBERTa</h3><p>One of the most popular Natural Language Understanding architectures is DeBERTa, a transformer-based model that achieves state-of-the-art results in a variety of NLU tasks, including question answering, natural language inference, and sentiment analysis.</p><p>DeBERTa is a more efficient variant of the popular language model BERT, specifically designed for Natural Language Understanding tasks. It addresses some of BERT’s limitations, such as the inability to model long-range dependencies and the lack of robustness to noisy text.</p><p>DeBERTa outperforms BERT across the board and exceeds the NLU performance of the majority of larger and more recent language models.</p><p>One reason for DeBERTa’s success is its novel architecture, which allows for better attention across the input sequence through techniques such as attention factors and relative position bias. This helps DeBERTa achieve high accuracy with fewer parameters.</p><p>It is believed that on many NLU tasks — such as SQuAD — bidirectional encoders, as adopted by DeBERTa, considerably outperform the left-to-right decoders used in the GPT models [1]</p><p>On benchmark datasets such as SuperGLUE, DeBERTa also outperforms larger, more complex models such as GPT-3 and T5, while using a fraction of the number of parameters.</p><p>To try out DeBERTa-Base inference for yourself for free by launching the Paperspace Gradient Notebook, powered by Graphcore IPUs.</p><figure><a href="https://ipu.dev/2XQcBI"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I2CCl4gsq7nPOVGnGtAndA.png" /></a></figure><p>[1] BART: Denoising Sequence-to-Sequence Pre-training for Natural <br>Language Generation, Translation, and Comprehension — Mike Lewis et. Al</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fa460c25e71c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/small-language-models-high-performance-deberta-and-the-future-of-nlu-fa460c25e71c">Small language models, high performance: DeBERTa and the Future of NLU</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Packed BERT: How to accelerate fine-tuning and inference for NLP tasks with packing]]></title>
            <link>https://medium.com/graphcore/packed-bert-how-to-accelerate-fine-tuning-and-inference-for-nlp-tasks-with-packing-de16ac4aac1?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/de16ac4aac1</guid>
            <category><![CDATA[naturallanguageprocessing]]></category>
            <category><![CDATA[bert]]></category>
            <category><![CDATA[hugging-face]]></category>
            <category><![CDATA[transformers]]></category>
            <category><![CDATA[nlp]]></category>
            <dc:creator><![CDATA[Arsalan Uddin]]></dc:creator>
            <pubDate>Wed, 17 May 2023 16:02:52 GMT</pubDate>
            <atom:updated>2023-05-17T16:02:51.872Z</atom:updated>
            <content:encoded><![CDATA[<h4>Learn how to achieve 6x faster BERT fine-tuning and up to 12x faster batched inference with packing using a classification example</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*V0UDpkGD-34tvrAcqVtUAw.png" /><figcaption>Image by author.</figcaption></figure><p>As large language models (LLMs) like the GPT (Generative pre-trained transformer) family capture the public imagination, the practicality of smaller Transformer models like BERT should not be underestimated. While language understanding tasks may work well with models like GPT, it is usually faster and cheaper to use smaller models like BERT, which give you the same or better performance, because they are trained specifically for focused language understanding tasks, while using much less compute and energy.</p><p>At Graphcore, we have recently worked on advancing a method called <a href="https://arxiv.org/pdf/2107.02027.pdf"><strong>packing</strong></a> for fine-tuning and inference to optimise natural language processing (NLP) models at the application level. This blog post will explain the concept of packing for fine-tuning NLP tasks, and show you how to use it with easy-to-use utilities for Hugging Face on IPUs.</p><p>A Graphcore customer, <a href="https://pienso.com/">Pienso</a>, uses this technique in their production text analytics and insight platform, which you can read about more <a href="https://www.graphcore.ai/posts/bert-packing">here</a>.</p><h3>Why do we want to speed up narrow tasks?</h3><p>Packing is particularly beneficial for creating solutions that are online-capable, meaning they:</p><ul><li>Scale well</li><li>Handle large incoming loads of data well</li><li>Consume less compute with no performance degradation</li><li>Reduce the overall time of fine-tuning/inference tasks</li></ul><p>The technique is both throughput focused and aims to reduce as much computational waste as possible to improve efficiency. It works well with increasing scale — creating large effective increases in batch size with negligible overhead, making it useful for production as well as as research tasks.</p><p>As an example, implementing packing for <a href="https://ipu.dev/rCmIGv">multi-label classification</a> with the <a href="https://github.com/google-research/google-research/tree/master/goemotions">GoEmotions</a> dataset showed a 6x speedup for fine-tuning and a 9x speedup for inference workloads, bringing model processing to near real-time speeds!</p><p>Note that packing is not specific to BERT and is in theory applicable to any model which processes data on a token-by-token basis with none or minimal cross-token interaction. It can potentially also be applied to genomics and protein folding models, and other transformer models. It is worth noting, however, that its applicability is dependent on the structure of the dataset used, as described in the next section.</p><p>This implementation for fine-tuning and inference tasks was inspired by and builds on the work done to create Packed BERT for pre-training.</p><h3>What is packing?</h3><p>Put simply, packing as a concept for LLM inputs means to concatenate multiple tokenized sequences together into a single input, which we can call a ‘pack’.</p><p>A surprising amount of datasets contain heavily skewed length distributions towards the shorter side, and transformer models receive fixed sized inputs. This is often handled by simply padding the part of the input that isn’t used by the sequence with unused values.</p><p>Packing sequences together works to eliminate padding, exploiting the unused space to mitigate computational waste, while maintaining the benefits of a model represented as a static graph with constant-sized inputs. It also means more sequences are being processed per batch, with multiple sequences (within a pack) being processed in parallel on a token level. This effectively increases batch size, with minimal overhead, and brings with it massive throughput benefits.</p><h4><strong>Dataset length distributions</strong></h4><p>The time-optimisation that packing provides relies on datasets with sequence length distributions which are skewed to the shorter side of the maximum sequence length. It works by fitting multiple sequences into one sample, essentially treating each sample as a batch within a batch.</p><p>For training, increasing effective batch size in this way means further hyperparameter tuning is needed. For inference, since hyperparameter consideration is not needed, even higher throughput can be theoretically achieved.</p><p>The code walkthrough in this article demonstrates a 9x speed-up for inference and 6x speedup for training.</p><p>For perspective, we undertook a brief analysis of the dataset characteristics of some of the most popular fine-tuning text classification datasets on <a href="https://huggingface.co/datasets">Hugging Face Hub</a>, based on number of downloads. The pool contains 10 of the most popular datasets, with most subsets included, barring a couple which were prohibitively large relative to others. In total, this makes up 39 datasets.</p><p>These datasets were tokenized to an arbitrary short sequence length of 256 and manually generated by extracting only the list of sequence lengths for each sample in the dataset. These sequence lengths were used to create a length distribution histogram from 0 to 256 with a bin size of 5:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*poNhXwvIP7ki-vPd3xMcKQ.png" /><figcaption>Sequence length histograms for 10 of the most popular Hugging Face Hub datasets (39 subsets in total) for sequence classification. Image by author.</figcaption></figure><p>Observing this histogram, it is apparent that there is a strong skew towards shorter length sequences in the majority of the datasets, with a small number of components at longer lengths, constituted mostly by datasets which focus on long contexts.</p><h4>Why does packing work with language models like BERT?</h4><p><a href="https://arxiv.org/pdf/1810.04805.pdf">BERT</a> is an encoder heavy natural language model commonly used for language analysis and prediction tasks. Text samples are passed to BERT after being tokenized (mapped to a word-specific integer value that corresponds to the model vocabulary). For BERT, each sequence of tokens is processed in parallel, on a token-by-token basis, with positional, syntactic and semantic information about the token encoded within the sample’s embeddings, which are learned over each sequence through the Transformer <a href="https://arxiv.org/abs/1706.03762v5">multi-headed self-attention mechanism</a>.</p><p>This is incredibly useful, it means that in theory, individual token information can be analysed with respect to the sequence it is part of, without interference from other sequences passed within the input. This behaviour is already exhibited by transformers in datasets which contain more than one sentence being part of a single input sequence.</p><p>A key element of transformers is the <strong>attention mask</strong>, which allows the self attention to concentrate its context oriented token-specific learning to a particular part of the sequence.</p><p>This allows us to pack an input with multiple sequences to achieve the desired throughput benefit. In practice, there are a few tweaks to make to the model, particularly at the output stage, in order to be able to perform classification and prediction tasks with packed inputs. Take a look at the diagram below for a straightforward visualisation of how we can pack multiple sequences to mitigate computational waste from padding and speed up the model, as compared to BERT without packing:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/583/1*2CD3rQW9VCTJJ329sAtdqw.png" /><figcaption>By specifying a sequence specific attention mask inside a single input with multiple sequences, we can classify multiple sequences in one input! Image by author.</figcaption></figure><p>There are essentially 3 stages to packing, particularly for fine-tuning:</p><ul><li>An <strong>algorithm</strong> that is as fast as possible at packing as many sequences as possible together, as close to optimally as possible.</li><li>Adjusting the <strong>model’s input</strong> to interpret a single input as multiple sequences rather than a single sequence and padding using the attention mask.</li><li>Adjusting the <strong>model’s output</strong> to unravel the packed input back into separate sequences for final cross-token calculations, such as the loss.</li></ul><h3>The packing algorithm</h3><p>There are three algorithms outlined for the original packing implementation for <a href="https://towardsdatascience.com/introducing-packed-bert-for-2x-faster-training-in-natural-language-processing-eadb749962b1">pre-training</a>, these are:</p><ul><li><strong>Non-negative least squares histogram packing (NNLSHP)</strong></li><li><strong>Shortest-pack-first histogram packing (SPFHP)</strong></li><li><strong>Longest-pack-first histogram packing (LPFHP)</strong></li></ul><p>These algorithms use the sequence length histogram to try to optimally create packs of sequences with varying lengths to minimise the total number of packs (inputs to the model).</p><p>In previous implementations for large dataset pre-training, the most optimal possible configuration of lengths was achieved using NNLSHP. This algorithm is explained neatly in the original article:</p><blockquote>“The tricky part was the strategy matrix. Each column has a maximum sum of three and encodes which sequences get packed together to exactly match the desired total length; 512 in our case. The rows encode each of the potential combinations to reach a length the total length. The strategy vector x is what we were looking for, which describes how often we choose whichever of the 20k combinations. Interestingly, only around 600 combinations were selected at the end. To get an exact solution, the strategy counts in x would have to be positive integers, but we realised that an approximate rounded solution with just non-negative x was sufficient. For an approximate solution, a simple out-of-the-box solver could be used to get a result within 30 seconds.”</blockquote><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.vidyard.com%2FtLsPRW14uPpSo9qfr5LEbz.html%3Fautoplay%3D0%26custom_id%3D%26embed_button%3D0%26viral_sharing%3D0%26&amp;display_name=Vidyard&amp;url=https%3A%2F%2Fshare.vidyard.com%2Fwatch%2FtLsPRW14uPpSo9qfr5LEbz&amp;image=https%3A%2F%2Fplay.vidyard.com%2FtLsPRW14uPpSo9qfr5LEbz.jpg%3F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=vidyard" width="600" height="337" frameborder="0" scrolling="no"><a href="https://medium.com/media/a9f44d95d67771f2fe3e58fd197cdadf/href">https://medium.com/media/a9f44d95d67771f2fe3e58fd197cdadf/href</a></iframe><p>The disadvantages of this approach are that it:</p><ul><li>Significantly increases in complexity for a sequences-per-pack value greater than 3.</li><li>3 sequences at most per pack in up to 30 seconds is reasonable for pre-training, but for online-capable tasks, and smaller dataset fine-tuning and inference, this can be far too long — especially when entire training runs can be completed in a matter of seconds.</li></ul><p>Skewed distributions in small fine-tuning datasets allow packing many more sequences per pack, which is unfeasible with NNLSHP, so lets take a look at a simpler and more adaptive algorithm: SPFHP.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.vidyard.com%2Fr2nX2Ddfx3Mbp1sHPuyFb7.html%3Fautoplay%3D0%26custom_id%3D%26embed_button%3D0%26viral_sharing%3D0%26&amp;display_name=Vidyard&amp;url=https%3A%2F%2Fshare.vidyard.com%2Fwatch%2Fr2nX2Ddfx3Mbp1sHPuyFb7&amp;image=https%3A%2F%2Fplay.vidyard.com%2Fr2nX2Ddfx3Mbp1sHPuyFb7.jpg%3F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=vidyard" width="600" height="337" frameborder="0" scrolling="no"><a href="https://medium.com/media/56d00e2f0c3aa972406a6d7ff8aad22a/href">https://medium.com/media/56d00e2f0c3aa972406a6d7ff8aad22a/href</a></iframe><p>SPFHP scales very well to increasing number of sequences per pack. It operates on a sorted histogram of lengths from longest to shortest and simply looks at each sequence, and checks whether it fits into any pack. If it fits into one pack, it will be placed in that pack — not considering any future sequences — and if it fits into multiple, it will be placed into the pack with the shortest sequence length.</p><p>It is more appropriate for small to medium sized datasets and its complexity is not increased by increasing the number of packs. It solves for any given dataset in almost constant time, taking under 0.02 seconds for up to 16 million samples. The complexity of SPFHP increases with sequence length rather than dataset size or sequences-per-pack, so it remains relatively constant for different dataset sizes!</p><p><strong>LPFHP</strong> is a shortest-to-longest variant of SPFHP, splitting counts to get more ideal fits. In some cases, it can be useful to approach the task longest-pack-first, offering a slightly more optimal fit.</p><p>The packing utilities created for the Packed BERT Hugging Face notebooks allows one of SPFHP or LPFHP to be used, to mitigate the potential preprocessing bottleneck of using NNLSHP.</p><p><em>The original algorithm code for all packing algorithms is available in the </em><a href="https://github.com/graphcore/tutorials/tree/master/blogs_code/packedBERT"><em>blogs code</em></a><em>.</em></p><h3>Implementing packing for BERT fine-tuning with Hugging Face</h3><p>Have a go at using packing to speed up BERT for multi-label sequence classification yourself: In this section, we’ll look at how to easily use packing with BERT using HuggingFace on the <a href="https://huggingface.co/datasets/go_emotions">GoEmotions</a> dataset.</p><p>You can follow this walkthrough with some visualisation and further explanation by running it in a Paperspace Gradient<strong> </strong>notebook — all of the code used in this article is available in the multi-label text classification notebook.</p><figure><a href="https://ipu.dev/q6HAUX"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FdNVQyC2VMZAJI74Jo1lSA.png" /></a></figure><figure><a href="https://ipu.dev/rCmIGv"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MC2S6-5l9MaMJ4ncouWrJg.png" /></a></figure><figure><a href="https://ipu.dev/ff6TLP"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k3zhoCWdguPLLiV_ZJCJtQ.png" /></a></figure><p>The in-depth <a href="https://github.com/graphcore/examples/blob/master/tutorials/blogs_code/finetuning-packedBERT/walkthrough.ipynb"><strong>walkthrough available on Github</strong></a><strong> </strong>explains the internal functionality of the high-level functions that make packing so easy to use in Hugging Face. Full explanations of these and the intrinsic details that you might require if you wish to apply packing to your own model/task are provided in that walkthrough.</p><p>The GoEmotions dataset is ideal to try fine-tuning for packing as it has an extremely strong sequence length skew towards shorter sequences, and will provide large throughput increases, as the sequence length distribution for it shows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/1*-3PmFBLvhBZp_0GHhES1Qw.png" /><figcaption>Sequence length distribution for GoEmotions dataset. Image by author.</figcaption></figure><p><strong>About the dataset:</strong> GoEmotions is a multi-label sentiment analysis dataset, containing approximately 58000 carefully curated comments labeled for 28 categories of emotion, including a ‘neutral’ category. We will train for all labels using one-hot encoding to represent multi-label outputs.</p><p>This dataset is easily downloadable during this walkthrough using the datasets library from Hugging Face, which lets you download the processed and ready-to-use dataset from the Hugging Face Hub, so there is no need to download and set up the dataset yourself.</p><h4>Setting up your environment</h4><p>First, set up your environment by installing all of the required pip packages for this walkthrough. If you are trying this walkthrough in Paperspace, ensure you are in the Hugging Face Transformers on IPU (Optimum Graphcore) environment, where you can access the packing utilities from the <strong>packed-bert</strong> folder. The notebooks for packing already have the utilities accessible, but if you are trying this in a separate personal environment, be sure to clone the repository with:</p><pre>git clone git@github.com:huggingface/optimum-graphcore.git</pre><p>and navigate to <strong>notebooks/packed-bert</strong> to be able to use the models, utils and pipeline functionalities.</p><pre>pip install git+https://github.com/huggingface/optimum-graphcore.git<br>pip install scikit-learn;<br>pip install datasets<br>pip install evaluate<br>pip install tokenizers<br>pip install matplotlib<br>pip install scipy<br>pip install huggingface_hub;</pre><p>We will first import the packages we need as well as the packing specific model for sequence classification, and the inference pipeline.</p><pre>import os<br>import transformers<br>import optimum.graphcore<br>import torch<br>import numpy as np<br>import evaluate<br>from datasets import load_dataset<br>from transformers import AutoConfig<br>from huggingface_hub import notebook_login<br>from transformers import AutoTokenizer<br>from optimum.graphcore import IPUConfig, IPUTrainer, IPUTrainingArguments<br>from models.modeling_bert_packed import PipelinedPackedBertForSequenceClassification<br>from pipeline.packed_bert import PackedBertTextClassificationPipeline<br>from utils.packing.dataset_creator import PackedDatasetCreator</pre><p>Next, we define some generic parameters for the walkthrough:</p><pre>task = &quot;go_emotions&quot;<br>model_checkpoint = &quot;bert-base-uncased&quot;<br>ipu_config_name = &quot;Graphcore/bert-base-uncased&quot;<br>micro_batch_size = 2<br>gradient_accumulation_steps = 39<br>device_iterations = 32<br>max_seq_length = 256<br>num_labels=28<br>pod_type = os.getenv(&quot;GRAPHCORE_POD_TYPE&quot;, &quot;pod4&quot;)<br>executable_cache_dir = os.getenv(&quot;POPLAR_EXECUTABLE_CACHE_DIR&quot;, &quot;./exe_cache/&quot;) + &quot;/packed_bert_slseqcls/&quot; + &quot;/packed_bert_slseqcls/&quot;</pre><p>The task is go_emotions, the checkpoint is the default bert-base-uncased which we will use as a base to fine-tune the model for go_emotions. This model will run on Graphcore IPUs, and to take advantage of the parallelism available on an IPU, we need to define some IPU-specific configurations, from the perspective of fine-tuning, these effectively create a larger batch size for the model.</p><p>max_seq_length is the maximum length all input sequences are fixed to, and all sequences below this length will be padded to this length. Given the small size of the sequences in the GoEmotions dataset, we can reduce the model maximum input size to max_seq_length = 256.</p><p><strong>IPU Parallelism: </strong>We are using both data parallelism and pipeline parallelism (see this <a href="https://github.com/graphcore/tutorials/blob/master/tutorials/pytorch/efficient_data_loading/walkthrough.ipynb">tutorial</a> for more). Therefore the global batch size, which is the actual number of samples used for the weight update, is determined using four factors:</p><p><strong>global_batch_size</strong> = micro_batch_size * gradient_accumulation_steps * device_iterations * replication_factor</p><p>We define the gradient accumulation steps, device iterations and micro-batch size. The replication factor (which replicates the model over multiple sets of IPUs) is set to 1 by default, and this walkthrough will use 4 IPUs for a single replica by default. The ipu_config is a special configuration available within all checkpoints in the Graphcore space on the Hugging Face Hub. It contains the defaults for these IPU-specific parameters for the base checkpoint, and must be passed to an IPU-specific model to instantiate it.</p><h4>Getting and preparing the dataset</h4><p>To retrieve the dataset, we can simply use load_dataset from the <strong>Datasets </strong>library, which will retrieve it from the Hugging Face Hub and load it into your script.</p><p>We also want to initialise the metric for validating the dataset, since this is a multi-label task with one-hot encoded outputs, we will use the <a href="https://towardsdatascience.com/understanding-auc-roc-curve-68b2303cc9c5">ROC-AUC </a>metric, a common performance measure for multi-class, multi-label classification problems. We can load this from Hugging Face’s <strong>Evaluate</strong> library.</p><p>For preprocessing the model and turning our strings of sentences into integer tokens that correspond to the vocabulary interpreted by BERT, we also need to initialise a model <strong>tokenizer.</strong> This will convert individual words/sub-words into tokens.</p><p>This is easily done using the AutoTokenizer from the Transformers library. The default pre-trained BERT checkpoint contains a pre-configured tokenizer, so we can load the tokenizer with the pre-trained embeddings and vocabulary directly for our model using from_pretrained.</p><pre>dataset = load_dataset(task)<br>metric = evaluate.load(&quot;roc_auc&quot;, &quot;multilabel&quot;)<br> <br>tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, use_fast=True)</pre><p>The map function available in the Datasets library can be used to tokenize the dataset.</p><p>First, we create a simple function which applies the tokenizer to one text sample, for which we:</p><ul><li>Define the maximum sequence length</li><li>Set truncation to True: This will truncate any sequences which are larger than the maximum sequence length.</li><li>Note that for packing, we <strong>do not set padding to be true</strong> at this stage. We will pad the dataset when we pack it, but packing requires its inputs to be unpadded initially.</li></ul><p>Second, we need to encode our labels in the one-hot format. As the dataset allows multiple labels to be true for one input, to keep a constant label dimension, we need to encode the label column in the dataset as a binary array rather than dynamic-length lists of integers representing the label classes. Since there are 28 classes, an example would look like this:</p><pre>Original labels: [3, 27] <br>One hot encoded labels: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]</pre><p>Here, 3 and 27 are valid labels for a given input. In the one-hot encoded format, index 3 and index 27 are set to 1 to define this, allowing the valid labels to be of any size.</p><p>We wrap the call to tokenize one sample in the first function, and wrap the call to convert one set of labels to a one-hot encoded format in the second function. Then we use the map function to iteratively apply preprocessing to every sample, using internal batching to speed it up, set with the batched argument.</p><pre>#Tokenising function for one sample<br>def preprocess_function(examples):<br> return tokenizer(<br>    examples[&#39;sentence&#39;], truncation=True, max_length=max_seq_length)<br><br>#Label ID to one-hot-encoded conversion for one sample<br>def id_to_N_hot(example):<br>    indexes = example[&#39;labels&#39;]<br>    label = np.zeros((num_labels,), dtype=np.float16)<br>    for idx in indexes:<br>        label[idx] = 1<br>    example[&#39;labels&#39;] = label<br>    return example<br><br># Call to map the data<br>encoded_dataset = dataset.map(id_to_N_hot)<br>encoded_dataset = encoded_dataset.map(preprocess_function, batched=True)</pre><h4>Packing the dataset</h4><p>Now that we have a preprocessed and tokenized dataset, we can <strong>pack </strong>the dataset. To summarise what we need to do for packing, there are four steps to ensuring we can use a packed dataset for a model:</p><ol><li>Create a histogram of the sequence lengths of the dataset.</li><li>Generate a set of ‘<strong>strategies</strong>’ for the dataset using one of the state-of-the-art packing algorithms, which map out the order and indices of the sequences that need to be packed together.</li><li>Use this strategy to create the actual dataset, concatenating the tokenized features together for each column in the dataset, including the labels.</li><li>Finally, pass these new columns into a custom PyTorch dataset, ready to be passed to the dataloader!</li></ol><p><strong>What is a strategy? </strong>The ‘mapping of the order of sequences’ uses the histogram of sequence lengths to group together length values that best fit into a give maximum length. The set of strategies for a dataset contains multiple lists of lengths, covering all of the sequences in the dataset, for instance:</p><p>The first strategy in the set of strategies may be [120,40,40,60] indicating one sequence of length 120, two sequences of length 40 and one sequence of length 60 should be placed in the given order to form one pack. There may be multiple sequences with these lengths, so when forming one pack, we can mark a sequence as being ‘used’ to ensure sequence retrieval is not repeated.</p><p>The above steps have been simplified through the easy-to-use utils.packing available in the Graphcore Hugging Face repo. We can simply generate the packed dataset after the usual tokenization and preprocessing by passing all necessary packing configuration to the PackedDatasetCreator class, and generate the ready-to-use dataset with .create().</p><p>This completes all three of the above steps, and creates the PyTorch dataset.</p><p>First, we define some essential packing parameters:</p><pre>max_seq_per_pack = 6<br>num_labels = 28<br>problem_type = &#39;multi_label_classification&#39;</pre><p>The max_seq_per_pack is the maximum number of sequences that can be concatenated into one input, called a ‘pack’. This effects the overall batch size of the data at the classification stage, and as a result, too large of a value for fine-tuning may result in needing more extensive hyperparameter tuning to get the best results possible.</p><p>We have decided to keep the default value at 6 for the current examples, meaning a theoretical speed-up of up to 6 times the speed of an unpacked dataset. For inference, this can be set higher, to get even more throughput for large batched inference workloads.</p><p>The PackedDatasetCreator provides quite a few options to modify the process according to the dataset:</p><ul><li>Adjustable maximum sequence length.</li><li>Adjustable number of sequences per pack max_seq_per_pack .</li><li>The packing algorithm to use (one of LPFHP or SPFHP).</li><li>A custom label key to allow the class to access the labels in the dataset, as these are not tokenized.</li><li>Currently, the creator class supports single and multi-label classification, and question answering. The type of task is defined using the problem_type, one of single_label_classification, multi_label_classification or question answering.</li><li>For different tasks, you can set training=True, validation=True or inference=True.</li></ul><p>The PackedDatasetCreator class also has some other features specifically for inference, such as pad_to_global_batch_size, a feature useful for performing batched inference on a large samples when we do not want to lose any of the samples when creating data iterators, it applies ‘vertical’ padding to the dataset, adding filler rows to bring the dataset up to a value divisible by the global batch size, and allows for the largest possible batch sizes to be used without any loss of data.</p><p>Once the packer has been created (has generated the histogram and packing strategy — the 1st and 2nd steps), we can simply call the .create() which will return fully packed versions of the initial tokenized un-packed datasets, this will perform the 3rd and 4th step of packing the dataset.</p><pre>train_data_packer = PackedDatasetCreator(<br> tokenized_dataset = encoded_dataset[&#39;train&#39;],<br> max_sequence_length = max_seq_length,<br> max_sequences_per_pack = max_seq_per_pack,<br> training = True,<br> num_labels = num_labels,<br> problem_type = problem_type,<br> algorithm = &#39;SPFHP&#39;,<br> custom_label_key = &#39;label&#39;<br>)<br><br>val_data_packer = PackedDatasetCreator(<br> tokenized_dataset = encoded_dataset[&#39;validation&#39;],<br> max_sequence_length = max_seq_length,<br> max_sequences_per_pack = max_seq_per_pack,<br> validation = True,<br> num_labels = num_labels,<br> problem_type = problem_type,<br> algorithm = &#39;SPFHP&#39;,<br> custom_label_key = &#39;label&#39;<br>)<br><br>packed_train_dataset = train_data_packer.create()<br>packed_val_dataset = val_data_packer.create()</pre><p>We can then observe the output of the dataset creation, which will show us what packing has actually accomplished here:</p><pre>Packing efficiency (fraction of real tokens): 42.5296<br> Speed-up theoretical limit: 13.3547<br> Achieved speed-up over un-packed dataset: 5.67971<br> Runtime: Packed 43410 sequences in 0.001 seconds<br> Average packing factor: 5.6797069213659555<br>Packing efficiency (fraction of real tokens): 43.7226<br> Speed-up theoretical limit: 13.3873<br> Achieved speed-up over un-packed dataset: 5.85329<br> Runtime: Packed 5426 sequences in 0.001 seconds<br> Average packing factor: 5.853290183387271<br><br>Packed dataset creation time: 1.9252s<br>Packed dataset creation time: 0.1407s</pre><p>The output shows a theoretically achieved 5.68 times speed up over the unpacked dataset. The algorithm is fast, completing the strategy for all 43410 training sequences in 0.001 seconds. The full process of creating the dataset takes a few seconds, effectively negligible overhead mitigated by the training speed-up.</p><h4>Observing the packed dataset</h4><p>Lets have a look at what the columns in the packed dataset look like, to dig a little deeper into what the PackedDatasetCreator has done with the original dataset.</p><p>Within the function, it expects the default column names generated by the tokenizer, specifically:</p><ul><li>input_ids</li><li>attention_mask</li><li>labels (for training, validation)</li><li>token_type_ids (optional)</li></ul><p>It also generates some extra columns:</p><ul><li>position_ids is a column denoting the position of individual tokens within their respective sequence inside a pack.</li><li>example_ids (for inference) are integer indices corresponding to the position of a sample within the input data, and are used to re-order inference data outputs to be the same order as the inputs. This is required as the one-time shuffling of the data is a necessary side-effect of packing, in order to reduce the dataset size as optimally as it can.</li></ul><p>The following diagram is a simplified visualisation of what actually happens when the dataset is created, using the strategy generated by the algorithm (also showing the position_ids for each input):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hc5TEAHgB0fKg-i4vFmpwQ.png" /><figcaption>How the transformer model’s inputs change when used for packing. Image by author.</figcaption></figure><p><strong>Inside the packed dataset creator: </strong>The middle box in the diagram indicates how the sequences to concatenate are chosen using the previously mentioned strategy. The dataset is used to form a stacked list (‘Sorted sequences’), where the first row in the list is the sorted lengths of a sequence, and the second row is the corresponding indices of the sequence in the dataset — from which the relevant indices of sequences to pack are obtained (these are also equivalent to the stored example_ids).</p><p>This is used to retrieve one sequence with a length corresponding to the strategy, and then the specific index of that sequence in the dataset is nullified, so the same sequence cannot be chosen again.</p><p><strong>Changes to the inputs after packing:</strong> Packing the dataset involves concatenating inputs together, but the formation of some inputs may change to enable processing multiple sequences at once — as in the diagram above:</p><ul><li>A custom attention_mask is generated: It contains a unique index for each sequence of the pack and 0 for the remaining padding tokens. This tells the model’s self-attention mechanism to retrieve context for a single token from only the sequence relevant to the token. As in the above example, something like [1,1,1,1,0,0,0,0,0,0]once packed with other sequences, turns into [1,1,1,1,2,2,3,0,1,2,3] to indicate the specific attention for each sequence in the pack.</li><li>The CLS tokens of each sequence must be moved to the end of the pack <strong>for classification tasks</strong> — the BERT Pooler can then easily extract a fixed set of global representations from the end of the sequence rather than retrieve them from intermittent and dynamically changing positions in the input. For token-based or prediction tasks, this is not necessary as this is only needed if the Pooler is required for the task.</li><li>The position_ids of a pack contain the concatenated position_ids of each sequence— i.e. the individual token position respective to a sequence.</li><li>labels and token_type_ids are also packed (concatenated) to correspond to the input_ids pack. Note that while other columns are padded with 0s, labels are padded with a<strong> </strong>value of <strong>-100, </strong>this is to take advantage of certain loss functions in PyTorch automatically ignoring indices with the value -100. It also reduces indexing confusion between tasks which may use 0 as a label (such as in the one-hot encoded case).</li></ul><p>For this task, multi-label classification with BERT uses binary cross-entropy loss with logits, and will not ignore the indices. As a result, the provided model class is set up to manually ignore these indices using the -100 value.</p><p>For more in-depth information on the implementation of thePackedDatasetCreator and how you might go about applying it to different fine-tuning tasks, have a look at the <a href="https://github.com/graphcore/examples/blob/master/tutorials/blogs_code/finetuning-packedBERT/walkthrough.ipynb"><strong>Deeper dive into fine-tuning with packing</strong>.</a></p><h4>Prepare the model for fine-tuning</h4><p>First, lets define a function which can compute metrics during validation for us. This function is automatically called by Hugging Face Optimum’s Trainer class, passing the model predictions and corresponding labels. Here, we have to apply some simple postprocessing to ensure we ignore the unused padding samples created when packing. A few key things to note here:</p><ul><li>All labels set to -100, as described previously, are ignored when computing accuracy using a mask.</li><li>Similarly, for returned logits, we must ensure these padded indices are ignored. We can use an element-wise comparison to create a boolean mask of valid and invalid labels. We can then use this mask to dynamically slice the logits and labels to only perform accuracy calculations using our metric on valid indices.</li><li>We apply the softmax function to retrieve a probabilistic distribution from our logits, this isolates high scoring classes for multi-label classification further, and this distribution is expected by the accuracy metric.</li></ul><p>The predictions and labels are passed to the metric we initialised using the Evaluate library, which will return an accuracy percentage for the validation samples in the dataset:</p><pre>from scipy.special import softmax<br><br>def compute_metrics(eval_pred):<br>    predictions, labels = eval_pred<br>    <br>    labels = labels.reshape(-1, labels.shape[-1])<br>    predictions = predictions.reshape(-1, predictions.shape[-1])<br>    <br>    # Remove the padding labels<br>    mask = (labels != -100)[:,0]<br>    <br>    labels = labels[mask,:]<br>    predictions = predictions[mask,:]<br>    pred_scores = softmax(predictions.astype(&quot;float32&quot;), axis=1)    <br><br>    auc = metric.compute(<br>        prediction_scores=pred_scores, references=labels, multi_class=&quot;ovr&quot;<br>    )[&quot;roc_auc&quot;]<br><br>    return {&quot;roc_auc&quot;: auc}</pre><h4>Model modifications for packing</h4><p>Next, we can move on to instantiating our model. Using the packing utilities, we can use PipelinedPackedBertForSequenceClassification, a modified version of Transformers BertForSequenceClassification which inherits IPU pipeline parallelism and implements some small modifications at the output and input of the model to make it compatible with our packed dataset. The internal forward and backward pass of BertForSequenceClassification is not changed.</p><p>Recall the second and third essential stages of packing for fine-tuning: modifying the model inputs to receive the packed sequences, and modifying the model outputs to unpack the sequences for the output calculations. We can summarise the key changes made to the model here:</p><ol><li><strong>Attention mask (input stage)</strong></li></ol><p>Recall the increasing integer attention mask we generated using the PackedDatasetCreator. The integer representation will not be interpreted as we need it by BERT, instead we create a <strong>binary extended attention mask</strong> by reshaping and transposing the values in the increasing integer attention mask and using the order represented by the integers.</p><p>This represents the relevant attention mask for each token in the input sequence, defining the relevant context for each. This is done inside the Packed BERT model head, just before passing the inputs into the Transformers BERT forward pass.</p><p>The reason we don’t pass such a mask directly is because this makes the dataset orders of magnitude larger, and makes it difficult for the dataloader to infer batch dimension from the inputs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/781/1*85wk_Jae967VP9oyx3WdIQ.png" /><figcaption>Converting the attention mask to a 3D attention mask at the input stage to the BERT model forward pass. Image by author.</figcaption></figure><p><strong>2. BERT Pooler (Output stage):</strong></p><p>For classification tasks only, a slight modification needs to be made to the BERT Pooler — instead of extracting output embeddings from the first token position, extract output embeddings from the <strong>last N </strong>token positions, where <strong>N = </strong><strong>max_seq_per_pack .</strong></p><p><strong>3. Unpacking (Output stage)</strong>:</p><p>For non-classification tasks, if hidden states are used to directly obtain token-specific logits, these must be ‘unpacked’ using the positional information available in the inputs. It is possible to stack the logits for as many sequences as are present, and multiply with a sparse mask corresponding to the sequence positions — this will allow the loss to treat the inputs as a larger batch size of individual sequences.</p><p><strong>4. Masking (Output stage)</strong>:</p><p>If using a loss function where you cannot use ignore_index (e.g. binary losses with logits) or similar, to ensure unused intermittent logit/label values don’t contaminate the loss, the unused indices can be found from label indices set to -100 to create a sparse mask. These can be used to mask the logits for these indices to 0, or to simply return all loss values, mask the loss similarly, and then return the average.</p><p>Examples and further explanations of these changes can be read in the <a href="https://github.com/graphcore/examples/blob/master/tutorials/blogs_code/finetuning-packedBERT/walkthrough.ipynb">deeper dive walkthrough</a>, and the source code for the currently available tasks is present in the Graphcore Hugging Face (Optimum) repository, under <a href="https://github.com/huggingface/optimum-graphcore/blob/main/notebooks/packed_bert/models/modeling_bert_packed.py">notebooks/packed_bert/models/modeling_packed_bert.py</a></p><p>To prepare the model for training, we need to initialise our BERT config from the pre-trained checkpoint with some of the model modifications we have made. For packing, we must specify max_sequences_per_pack, num_labels and problem_type as these are essential to our changes in the model. Then, we can simply call from_pretrained on the model to inherit all of the default configurations from the pre-trained checkpoint plus the few configurations we have added. To speed things up, and at minimal detriment to the performance, we can train the model in half precision (FP16).</p><pre>config = AutoConfig.from_pretrained(model_checkpoint)<br>config.max_sequences_per_pack = max_seq_per_pack<br>config.num_labels = num_labels<br>config.problem_type = problem_type<br>model = PipelinedPackedBertForSequenceClassification.from_pretrained(<br> model_checkpoint, config=config).train().half()</pre><p>We have inherited most of the config from the pre-trained checkpoint, adding some new configuration options specific to this use case:</p><pre>BertConfig {<br>  &quot;_name_or_path&quot;: &quot;bert-base-uncased&quot;,<br>  &quot;architectures&quot;: [<br>    &quot;BertForMaskedLM&quot;<br>  ],<br>  &quot;attention_probs_dropout_prob&quot;: 0.1,<br>  &quot;classifier_dropout&quot;: null,<br>  &quot;gradient_checkpointing&quot;: false,<br>  &quot;hidden_act&quot;: &quot;gelu&quot;,<br>  &quot;hidden_dropout_prob&quot;: 0.1,<br>  &quot;hidden_size&quot;: 768,<br>  &quot;id2label&quot;: {<br>    &quot;0&quot;: &quot;LABEL_0&quot;,<br>    &quot;1&quot;: &quot;LABEL_1&quot;,<br>    &quot;2&quot;: &quot;LABEL_2&quot;,<br>    ...<br>    &quot;27&quot;: &quot;LABEL_27&quot;<br>  },<br>  &quot;initializer_range&quot;: 0.02,<br>  &quot;intermediate_size&quot;: 3072,<br>  &quot;label2id&quot;: {<br>    &quot;LABEL_0&quot;: 0,<br>    &quot;LABEL_1&quot;: 1,<br>    &quot;LABEL_10&quot;: 10,<br>    ...<br>    &quot;LABEL_9&quot;: 9<br>  },<br>  &quot;layer_norm_eps&quot;: 1e-12,<br>  &quot;max_position_embeddings&quot;: 512,<br>  &quot;max_sequences_per_pack&quot;: 6,<br>  &quot;model_type&quot;: &quot;bert&quot;,<br>  &quot;num_attention_heads&quot;: 12,<br>  &quot;num_hidden_layers&quot;: 12,<br>  &quot;pad_token_id&quot;: 0,<br>  &quot;position_embedding_type&quot;: &quot;absolute&quot;,<br>  &quot;problem_type&quot;: &quot;multi_label_classification&quot;,<br>  &quot;transformers_version&quot;: &quot;4.25.1&quot;,<br>  &quot;type_vocab_size&quot;: 2,<br>  &quot;use_cache&quot;: true,<br>  &quot;vocab_size&quot;: 30522<br>}</pre><p>At the beginning of the walkthrough, we set some default IPU configurations, as well as an executable cache directory (this is useful as it lets you skip compilation after the first time the model is compiled). These can now be passed to the Optimum Graphcore IPUConfig to simplify passing these to the model.</p><pre>ipu_config = IPUConfig.from_pretrained(<br>    ipu_config_name,<br>    executable_cache_dir = executable_cache_dir,<br>    gradient_accumulation_steps=gradient_accumulation_steps,<br>    device_iterations = device_iterations,<br>    replication_factor=1,<br>    inference_device_iterations = 64,<br>    inference_replication_factor = 1<br>)</pre><p>To train the model, we create a trainer using the IPUTrainer class which handles model compilation on IPUs, training and evaluation. The class works just like the Hugging Face Trainer class, but with the additional IPUConfig passed in.</p><p>We can also specify some additional training arguments using the IPUTrainingArguments class, which will be passed to the trainer. This is really useful for modifying training hyperparameters easily, including parameters like number of epochs to train, the batch size per device, the learning rate, warm-up ratio and some Dataloader options such as drop_last as well.</p><p>Lets now instantiate our training with the defined IPUTrainingArguments .</p><pre>from transformers import default_data_collator<br><br>args = IPUTrainingArguments(<br>    &quot;./&quot;+f&quot;{model_checkpoint}-{task}&quot;,<br>    per_device_train_batch_size=micro_batch_size,<br>    per_device_eval_batch_size=4,<br>    num_train_epochs=5,<br>    learning_rate=2e-4,<br>    adam_epsilon=1e-6,<br>    loss_scaling=16.0,<br>    warmup_ratio=0.1,<br>    weight_decay=0,<br>    lr_scheduler_type = &quot;cosine&quot;,<br>    metric_for_best_model=metric_name,<br>    dataloader_drop_last=True,<br>    logging_steps=1,<br>    pod_type=pod_type,<br>    gradient_accumulation_steps=gradient_accumulation_steps<br>)<br><br>trainer = IPUTrainer(<br>    model,<br>    ipu_config,<br>    args,<br>    train_dataset=packed_train_dataset,<br>    eval_dataset=packed_val_dataset,<br>    data_collator=default_data_collator,<br>    compute_metrics=compute_metrics<br>)</pre><p>Thats all the setup done, all thats left is to train the model!</p><h4><strong>A note on hyperparameter tuning</strong></h4><p>When packing and increasing the number of sequences, you might find that your model isn’t quite converging at the same rate as without packing, this is because increasing the maximum number of sequences has a similar effect on learning as significantly increasing the batch size. More samples are computed in one pass, and so hyperparameters must be adjusted according to that increase in effective batch size.</p><p>For the examples provided here and in the Hugging Face notebooks, we did not undertake extensive hyperparameter tuning, but nevertheless achieved convergence simply by incrementally increasing only the initial learning rate by approximately the same rate the effective batch size was increased.</p><p>Other parameters are generally kept the same. For a specific use case where you may want to change the packing parameters (akin to modifying the batch size), you may find that you want to undertake some hyperparameter tuning for a specific case to get the best results.</p><h4>Train the model</h4><p>With the Hugging Face Optimum library, you can do this in one line, requiring no complicated training loops or implementations of backpropagation. We can simply initiate the training process by calling .train() on our instantiated trainer. This will start iterating through the data and training with the defined hyperparameters and for the epochs defined with the given batch configurations:</p><pre>trainer.train()</pre><p>Then we can save the model locally:</p><pre>trainer.save_model(&quot;./&quot;+f&quot;{model_checkpoint}-{task}&quot;)</pre><p>or push to the Hugging Face hub:</p><pre>trainer.push_to_hub()</pre><p><strong>Observing the training output<br></strong>The default IPUTrainer doesn’t take into account the number of samples inside of an input, because it expects each input to have one sample, but we can calculate the actual throughput by having a look at the output of the IPUTrainer training:</p><pre>Packed - BERT<br><br>***** Running training *****<br>  Num examples = 7643<br>  Num Epochs = 5<br>  Instantaneous batch size per device = 2<br>  Total train batch size (w. parallel, distributed &amp; accumulation) = 2496<br>  Gradient Accumulation steps = 39<br>  Total optimization steps = 15<br>{&#39;loss&#39;: 0.7289, &#39;learning_rate&#39;: 0.0001, &#39;epoch&#39;: 0.33}                                      <br>{&#39;loss&#39;: 0.192, &#39;learning_rate&#39;: 0.0002, &#39;epoch&#39;: 0.67}                                       <br>{&#39;loss&#39;: 0.143, &#39;learning_rate&#39;: 0.0001970941817426052, &#39;epoch&#39;: 1.0}                         <br>{&#39;loss&#39;: 0.169, &#39;learning_rate&#39;: 0.000188545602565321, &#39;epoch&#39;: 1.33}                         <br>{&#39;loss&#39;: 0.1223, &#39;learning_rate&#39;: 0.00017485107481711012, &#39;epoch&#39;: 1.67}                      <br>{&#39;loss&#39;: 0.1726, &#39;learning_rate&#39;: 0.00015680647467311557, &#39;epoch&#39;: 2.0}                       <br>{&#39;loss&#39;: 0.1644, &#39;learning_rate&#39;: 0.00013546048870425356, &#39;epoch&#39;: 2.33}                      <br>{&#39;loss&#39;: 0.1231, &#39;learning_rate&#39;: 0.0001120536680255323, &#39;epoch&#39;: 2.67}                       <br>{&#39;loss&#39;: 0.1311, &#39;learning_rate&#39;: 8.79463319744677e-05, &#39;epoch&#39;: 3.0}                         <br>{&#39;loss&#39;: 0.1501, &#39;learning_rate&#39;: 6.453951129574644e-05, &#39;epoch&#39;: 3.33}                       <br>{&#39;loss&#39;: 0.2156, &#39;learning_rate&#39;: 4.3193525326884435e-05, &#39;epoch&#39;: 3.67}                      <br>{&#39;loss&#39;: 0.1241, &#39;learning_rate&#39;: 2.514892518288988e-05, &#39;epoch&#39;: 4.0}                        <br>{&#39;loss&#39;: 0.142, &#39;learning_rate&#39;: 1.1454397434679021e-05, &#39;epoch&#39;: 4.33}                       <br>{&#39;loss&#39;: 0.1344, &#39;learning_rate&#39;: 2.905818257394799e-06, &#39;epoch&#39;: 4.67}                       <br>{&#39;loss&#39;: 0.1233, &#39;learning_rate&#39;: 0.0, &#39;epoch&#39;: 5.0}                                          <br>100%|█████████████████████████████████████████████████████████| 15/15 [00:54&lt;00:00,  3.62s/it]<br><br>Training completed. Do not forget to share your model on huggingface.co/models =)<br>{<br> &#39;train_runtime&#39;: 54.571, <br> &#39;train_samples_per_second&#39;: 686.079, <br> &#39;train_steps_per_second&#39;: 0.275, <br> &#39;train_loss&#39;: 0.1890590712428093, <br> &#39;epoch&#39;: 5.0<br>}</pre><p>While the train_samples_per_second is around<strong> </strong>686<strong> </strong>samples/s, we can see that the total number of examples is 7643. This is due to packing, the actual number of samples in the GoEmotions training set is 43410. So the actual training throughput can be calculated by 686*5.68, or approximately <strong>3896</strong> <strong>samples/s</strong>!</p><p>To quantitatively demonstrate the advantage, you can run training under the same conditions, with equivalent batch size, for the same dataset but <em>without </em>packing, resulting in the training output below:</p><pre>Unpacked - BERT<br><br>***** Running training *****<br>  Num examples = 43410<br>  Num Epochs = 5<br>  Instantaneous batch size per device = 2<br>  Total train batch size (w. parallel, distributed &amp; accumulation) = 2496<br>  Gradient Accumulation steps = 39<br>  Total optimization steps = 85<br><br>100% <br>85/85 [06:12&lt;00:00,  4.38s/it]<br>{&#39;loss&#39;: 0.7563, &#39;learning_rate&#39;: 2.2222222222222223e-05, &#39;epoch&#39;: 0.06}                                       <br>{&#39;loss&#39;: 0.4773, &#39;learning_rate&#39;: 4.4444444444444447e-05, &#39;epoch&#39;: 0.12}                                       <br>{&#39;loss&#39;: 0.1841, &#39;learning_rate&#39;: 6.666666666666667e-05, &#39;epoch&#39;: 0.18}                                        <br>{&#39;loss&#39;: 0.1415, &#39;learning_rate&#39;: 8.888888888888889e-05, &#39;epoch&#39;: 0.24}                                        <br>{&#39;loss&#39;: 0.119, &#39;learning_rate&#39;: 0.00011111111111111112, &#39;epoch&#39;: 0.29}                                        <br>{&#39;loss&#39;: 0.2073, &#39;learning_rate&#39;: 0.00013333333333333334, &#39;epoch&#39;: 0.35}                                       <br>{&#39;loss&#39;: 0.1138, &#39;learning_rate&#39;: 0.00015555555555555556, &#39;epoch&#39;: 0.41}                                       <br>{&#39;loss&#39;: 0.178, &#39;learning_rate&#39;: 0.00017777777777777779, &#39;epoch&#39;: 0.47}                                        <br>{&#39;loss&#39;: 0.2422, &#39;learning_rate&#39;: 0.0002, &#39;epoch&#39;: 0.53}                                                       <br>{&#39;loss&#39;: 0.0984, &#39;learning_rate&#39;: 0.0001999145758387301, &#39;epoch&#39;: 0.59}                                        <br>{&#39;loss&#39;: 0.142, &#39;learning_rate&#39;: 0.000199658449300667, &#39;epoch&#39;: 0.65}                                          <br>{&#39;loss&#39;: 0.145, &#39;learning_rate&#39;: 0.0001992320579737045, &#39;epoch&#39;: 0.71}                                         <br>{&#39;loss&#39;: 0.0774, &#39;learning_rate&#39;: 0.00019863613034027224, &#39;epoch&#39;: 0.76}                                       <br>{&#39;loss&#39;: 0.1322, &#39;learning_rate&#39;: 0.00019787168453273544, &#39;epoch&#39;: 0.82}                                       <br>{&#39;loss&#39;: 0.2188, &#39;learning_rate&#39;: 0.00019694002659393305, &#39;epoch&#39;: 0.88}                                       <br>{&#39;loss&#39;: 0.1536, &#39;learning_rate&#39;: 0.0001958427482458253, &#39;epoch&#39;: 0.94}                                        <br>{&#39;loss&#39;: 0.1007, &#39;learning_rate&#39;: 0.00019458172417006347, &#39;epoch&#39;: 1.0}                                        <br>{&#39;loss&#39;: 0.0267, &#39;learning_rate&#39;: 0.0001931591088051279, &#39;epoch&#39;: 1.06}                                        <br>{&#39;loss&#39;: 0.0623, &#39;learning_rate&#39;: 0.00019157733266550575, &#39;epoch&#39;: 1.12}                                       <br>{&#39;loss&#39;: 0.1069, &#39;learning_rate&#39;: 0.0001898390981891979, &#39;epoch&#39;: 1.18}                                        <br>{&#39;loss&#39;: 0.0558, &#39;learning_rate&#39;: 0.0001879473751206489, &#39;epoch&#39;: 1.24}                                        <br>{&#39;loss&#39;: 0.0684, &#39;learning_rate&#39;: 0.00018590539543698854, &#39;epoch&#39;: 1.29}                                       <br>{&#39;loss&#39;: 0.0535, &#39;learning_rate&#39;: 0.00018371664782625287, &#39;epoch&#39;: 1.35}                                       <br>{&#39;loss&#39;: 0.2245, &#39;learning_rate&#39;: 0.0001813848717270195, &#39;epoch&#39;: 1.41}                                        <br>{&#39;loss&#39;: 0.0355, &#39;learning_rate&#39;: 0.00017891405093963938, &#39;epoch&#39;: 1.47}                                       <br>{&#39;loss&#39;: 0.0364, &#39;learning_rate&#39;: 0.00017630840681998066, &#39;epoch&#39;: 1.53}                                       <br>{&#39;loss&#39;: 0.1504, &#39;learning_rate&#39;: 0.00017357239106731317, &#39;epoch&#39;: 1.59}                                       <br>{&#39;loss&#39;: 0.0346, &#39;learning_rate&#39;: 0.00017071067811865476, &#39;epoch&#39;: 1.65}                                       <br>{&#39;loss&#39;: 0.0334, &#39;learning_rate&#39;: 0.00016772815716257412, &#39;epoch&#39;: 1.71}                                       <br>{&#39;loss&#39;: 0.0862, &#39;learning_rate&#39;: 0.00016462992378609407, &#39;epoch&#39;: 1.76}                                       <br>{&#39;loss&#39;: 0.0844, &#39;learning_rate&#39;: 0.0001614212712689668, &#39;epoch&#39;: 1.82}                                        <br>{&#39;loss&#39;: 0.1204, &#39;learning_rate&#39;: 0.00015810768154019385, &#39;epoch&#39;: 1.88}                                       <br>{&#39;loss&#39;: 0.1338, &#39;learning_rate&#39;: 0.00015469481581224272, &#39;epoch&#39;: 1.94}                                       <br>{&#39;loss&#39;: 0.1765, &#39;learning_rate&#39;: 0.00015118850490896012, &#39;epoch&#39;: 2.0}                                        <br>{&#39;loss&#39;: 0.2133, &#39;learning_rate&#39;: 0.00014759473930370736, &#39;epoch&#39;: 2.06}                                       <br>{&#39;loss&#39;: 0.0235, &#39;learning_rate&#39;: 0.00014391965888473703, &#39;epoch&#39;: 2.12}                                       <br>{&#39;loss&#39;: 0.1029, &#39;learning_rate&#39;: 0.00014016954246529696, &#39;epoch&#39;: 2.18}                                       <br>{&#39;loss&#39;: 0.0134, &#39;learning_rate&#39;: 0.00013635079705638298, &#39;epoch&#39;: 2.24}                                       <br>{&#39;loss&#39;: 0.0334, &#39;learning_rate&#39;: 0.00013246994692046836, &#39;epoch&#39;: 2.29}                                       <br>{&#39;loss&#39;: 0.0686, &#39;learning_rate&#39;: 0.00012853362242491053, &#39;epoch&#39;: 2.35}                                       <br>{&#39;loss&#39;: 0.1879, &#39;learning_rate&#39;: 0.00012454854871407994, &#39;epoch&#39;: 2.41}                                       <br>{&#39;loss&#39;: 0.0515, &#39;learning_rate&#39;: 0.00012052153421956342, &#39;epoch&#39;: 2.47}                                       <br>{&#39;loss&#39;: 0.0536, &#39;learning_rate&#39;: 0.00011645945902807341, &#39;epoch&#39;: 2.53}                                       <br>{&#39;loss&#39;: 0.0595, &#39;learning_rate&#39;: 0.00011236926312693479, &#39;epoch&#39;: 2.59}                                       <br>{&#39;loss&#39;: 0.0714, &#39;learning_rate&#39;: 0.00010825793454723325, &#39;epoch&#39;: 2.65}                                       <br>{&#39;loss&#39;: 0.1455, &#39;learning_rate&#39;: 0.00010413249742488131, &#39;epoch&#39;: 2.71}                                       <br>{&#39;loss&#39;: 0.0655, &#39;learning_rate&#39;: 0.0001, &#39;epoch&#39;: 2.76}                                                       <br>{&#39;loss&#39;: 0.0498, &#39;learning_rate&#39;: 9.586750257511867e-05, &#39;epoch&#39;: 2.82}                                        <br>{&#39;loss&#39;: 0.0635, &#39;learning_rate&#39;: 9.174206545276677e-05, &#39;epoch&#39;: 2.88}                                        <br>{&#39;loss&#39;: 0.075, &#39;learning_rate&#39;: 8.763073687306524e-05, &#39;epoch&#39;: 2.94}                                         <br>{&#39;loss&#39;: 0.079, &#39;learning_rate&#39;: 8.35405409719266e-05, &#39;epoch&#39;: 3.0}                                           <br>{&#39;loss&#39;: 0.0366, &#39;learning_rate&#39;: 7.947846578043659e-05, &#39;epoch&#39;: 3.06}                                        <br>{&#39;loss&#39;: 0.1427, &#39;learning_rate&#39;: 7.54514512859201e-05, &#39;epoch&#39;: 3.12}                                         <br>{&#39;loss&#39;: 0.0612, &#39;learning_rate&#39;: 7.146637757508949e-05, &#39;epoch&#39;: 3.18}                                        <br>{&#39;loss&#39;: 0.0401, &#39;learning_rate&#39;: 6.753005307953167e-05, &#39;epoch&#39;: 3.24}                                        <br>{&#39;loss&#39;: 0.0065, &#39;learning_rate&#39;: 6.3649202943617e-05, &#39;epoch&#39;: 3.29}                                          <br>{&#39;loss&#39;: 0.0302, &#39;learning_rate&#39;: 5.983045753470308e-05, &#39;epoch&#39;: 3.35}                                        <br>{&#39;loss&#39;: 0.0399, &#39;learning_rate&#39;: 5.608034111526298e-05, &#39;epoch&#39;: 3.41}                                        <br>{&#39;loss&#39;: 0.0241, &#39;learning_rate&#39;: 5.240526069629265e-05, &#39;epoch&#39;: 3.47}                                        <br>{&#39;loss&#39;: 0.0732, &#39;learning_rate&#39;: 4.8811495091039926e-05, &#39;epoch&#39;: 3.53}                                       <br>{&#39;loss&#39;: 0.0867, &#39;learning_rate&#39;: 4.530518418775733e-05, &#39;epoch&#39;: 3.59}                                        <br>{&#39;loss&#39;: 0.0454, &#39;learning_rate&#39;: 4.189231845980618e-05, &#39;epoch&#39;: 3.65}                                        <br>{&#39;loss&#39;: 0.0172, &#39;learning_rate&#39;: 3.857872873103322e-05, &#39;epoch&#39;: 3.71}                                        <br>{&#39;loss&#39;: 0.0124, &#39;learning_rate&#39;: 3.53700762139059e-05, &#39;epoch&#39;: 3.76}                                         <br>{&#39;loss&#39;: 0.0254, &#39;learning_rate&#39;: 3.227184283742591e-05, &#39;epoch&#39;: 3.82}                                        <br>{&#39;loss&#39;: 0.0799, &#39;learning_rate&#39;: 2.9289321881345254e-05, &#39;epoch&#39;: 3.88}                                       <br>{&#39;loss&#39;: 0.0466, &#39;learning_rate&#39;: 2.6427608932686843e-05, &#39;epoch&#39;: 3.94}                                       <br>{&#39;loss&#39;: 0.0185, &#39;learning_rate&#39;: 2.3691593180019366e-05, &#39;epoch&#39;: 4.0}                                        <br>{&#39;loss&#39;: 0.0042, &#39;learning_rate&#39;: 2.1085949060360654e-05, &#39;epoch&#39;: 4.06}                                       <br>{&#39;loss&#39;: 0.012, &#39;learning_rate&#39;: 1.861512827298051e-05, &#39;epoch&#39;: 4.12}                                         <br>{&#39;loss&#39;: 0.0279, &#39;learning_rate&#39;: 1.6283352173747145e-05, &#39;epoch&#39;: 4.18}                                       <br>{&#39;loss&#39;: 0.045, &#39;learning_rate&#39;: 1.4094604563011472e-05, &#39;epoch&#39;: 4.24}                                        <br>{&#39;loss&#39;: 0.0575, &#39;learning_rate&#39;: 1.2052624879351104e-05, &#39;epoch&#39;: 4.29}                                       <br>{&#39;loss&#39;: 0.0196, &#39;learning_rate&#39;: 1.0160901810802115e-05, &#39;epoch&#39;: 4.35}                                       <br>{&#39;loss&#39;: 0.0118, &#39;learning_rate&#39;: 8.422667334494249e-06, &#39;epoch&#39;: 4.41}                                        <br>{&#39;loss&#39;: 0.0071, &#39;learning_rate&#39;: 6.840891194872112e-06, &#39;epoch&#39;: 4.47}                                        <br>{&#39;loss&#39;: 0.0276, &#39;learning_rate&#39;: 5.418275829936537e-06, &#39;epoch&#39;: 4.53}                                        <br>{&#39;loss&#39;: 0.0353, &#39;learning_rate&#39;: 4.1572517541747294e-06, &#39;epoch&#39;: 4.59}                                       <br>{&#39;loss&#39;: 0.1348, &#39;learning_rate&#39;: 3.059973406066963e-06, &#39;epoch&#39;: 4.65}                                        <br>{&#39;loss&#39;: 0.0679, &#39;learning_rate&#39;: 2.128315467264552e-06, &#39;epoch&#39;: 4.71}                                        <br>{&#39;loss&#39;: 0.0589, &#39;learning_rate&#39;: 1.3638696597277679e-06, &#39;epoch&#39;: 4.76}                                       <br>{&#39;loss&#39;: 0.0682, &#39;learning_rate&#39;: 7.679420262954984e-07, &#39;epoch&#39;: 4.82}                                        <br>{&#39;loss&#39;: 0.0627, &#39;learning_rate&#39;: 3.415506993330153e-07, &#39;epoch&#39;: 4.88}                                        <br>{&#39;loss&#39;: 0.088, &#39;learning_rate&#39;: 8.542416126989805e-08, &#39;epoch&#39;: 4.94}                                         <br>{&#39;loss&#39;: 0.0182, &#39;learning_rate&#39;: 0.0, &#39;epoch&#39;: 5.0}<br><br><br>Training completed. Do not forget to share your model on huggingface.co/models =)<br><br>{<br> &#39;train_runtime&#39;: 372.393, <br> &#39;train_samples_per_second&#39;: 569.721, <br> &#39;train_steps_per_second&#39;: 0.228, <br> &#39;train_loss&#39;: 0.09256008372587317, <br> &#39;epoch&#39;: 5.0<br>}</pre><p>Notice that the number of examples trained changes from 7643 to 43410 — because sequences are now being processed one-by-one. Observing the results:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_BskTPlO3d_ck-f-YOuMQQ.png" /><figcaption>Total time and throughput comparison between packed and unpacked BERT. Image by author.</figcaption></figure><p>The benefits of packing are evident — it offers a huge throughput and overall time benefit for fine-tuning.</p><h4>Evaluate the model</h4><p>We can then easily perform evaluation on the validation dataset in the same way:</p><pre>trainer.evaluate()</pre><p>and observe the outputs, with an evaluation accuracy of 83% showing we have successfully trained our model.</p><pre>***** Running Evaluation *****<br>  Num examples = 927<br>  Batch size = 256<br><br>100% 4/4 [00:00&lt;00:00, 36.42it/s]<br><br>{&#39;roc_auc&#39;: 0.836179971362336}</pre><h3>High speed inference with Hugging Face</h3><p>Packing can also be used for high speed batched inference, covering the workflow from fine-tuning a model to deploying it for live inference.</p><p>A fully abstracted inference pipeline with built-in optimisation can be used for this, with the source code and module available in the Hugging Face Graphcore repository. The custom PackedBertTextClassificationPipeline is ideal for optimisation of larger inference loads for high throughput.</p><p>The following example uses a limit of up to 12 sequences per pack (i.e., a theoretical speed up of 12x) to demonstrate higher potential throughput. As mentioned before, higher packing factors for inference do not require extra effort or performance cost to implement, as they do with training.</p><p>By default, the inference pipeline will retain the order of the data to ensure that it is maintainable when inferring on live loads of data, and outputs can be easily matched back to inputs.</p><p>As default, the required arguments are the:</p><ul><li><strong>Model checkpoint ( </strong><strong>model )</strong></li><li><strong>Cache storage directory (</strong><strong>executable_cache_dir)</strong></li><li><strong>Maximum sequence length </strong>( <strong>max_seq_length</strong> )</li><li><strong>Problem type</strong> (<strong>problem_type</strong>)</li></ul><p>Some optional arguments include:</p><ul><li>The sequences per pack ( max_seq_per_pack — defaults to 6)</li><li>Label categories (label_categories — defaults to indices)</li><li>Micro batch size (micro_batch_size — defaults to 1)</li><li>Pre-trained tokenizer (pretrained_tokenizer) name if it isn’t present in the saved model — this otherwise defaults to bert-base-uncased.</li></ul><p>First, let’s outline the class names corresponding to the label categories:</p><pre>#Define each of the class names in category order for inference labelling<br>class_names = [<br>    &quot;admiration&quot;,<br>    &quot;amusement&quot;,<br>    &quot;anger&quot;,<br>    &quot;annoyance&quot;,<br>    &quot;approval&quot;,<br>    &quot;caring&quot;,<br>    &quot;confusion&quot;,<br>    &quot;curiosity&quot;,<br>    &quot;desire&quot;,<br>    &quot;disappointment&quot;,<br>    &quot;disapproval&quot;,<br>    &quot;disgust&quot;,<br>    &quot;embarrassment&quot;,<br>    &quot;excitement&quot;,<br>    &quot;fear&quot;,<br>    &quot;gratitude&quot;,<br>    &quot;grief&quot;,<br>    &quot;joy&quot;,<br>    &quot;love&quot;,<br>    &quot;nervousness&quot;,<br>    &quot;optimism&quot;,<br>    &quot;pride&quot;,<br>    &quot;realization&quot;,<br>    &quot;relief&quot;,<br>    &quot;remorse&quot;,<br>    &quot;sadness&quot;,<br>    &quot;surprise&quot;,<br>    &quot;neutral&quot;,<br>]</pre><p>Then, we can instantiate the pipeline with the needed arguments.</p><p>Note<strong> </strong>that passing an IPU config for the inference is not strictly necessary, the pipeline will inherit as default the configuration from your saved checkpoint. However, to demonstrate further the advantages of using parallelism, with 4 IPUs in a data-parallel fashion, we pass a boosted configuration to the pipeline in this example:</p><pre>#Path to saved trained model checkpoint<br>model = &quot;./&quot;+f&quot;{model_checkpoint}-{task}&quot; <br><br>inference_boosted_ipu_config = IPUConfig.from_pretrained(model, <br>    inference_device_iterations=32,<br>    inference_replication_factor=4,<br>    ipus_per_replica=1,<br>    layers_per_ipu=[12]<br>)<br>#Instantiate the pipeline with all required options<br>pipeline = PackedBertTextClassificationPipeline(<br>    model = model,<br>    executable_cache_dir = executable_cache_dir,<br>    problem_type=&#39;multi_label_classification&#39;,<br>    max_seq_per_pack=12,<br>    max_seq_length=max_seq_length,<br>    ipu_config=inference_boosted_ipu_config,<br>    micro_batch_size=8,<br>    label_categories=class_names<br>)</pre><p>The above lines are all that is needed to set up the pipeline. Next, as an example of a large amount of data, we pass the raw text column for the entire GoEmotions training dataset directly into the pipeline for it to perform inference on:</p><pre>preds = pipeline.predict(dataset[&#39;train&#39;][&#39;text&#39;])</pre><pre>Packing efficiency (fraction of real tokens): 68.4612                                         <br> Speed-up theoretical limit: 13.3547<br> Achieved speed-up over un-packed dataset: 9.14280<br> Runtime: Packed 43410 sequences in 0.001 seconds<br> Average packing factor: 9.142796967144061<br>Packed dataset creation time: 1.6288s</pre><p>We can print the inference output to observe the contents of the returned predictions:</p><pre>print(f&quot;Number of predictions: {len(preds[&#39;predictions&#39;])}&quot;)<br>print(f&quot;Preprocessing time: {preds[&#39;preprocessing_time&#39;]}s&quot;)<br>print(f&quot;Postprocessing time: {preds[&#39;postprocessing_time&#39;]}s&quot;)<br>print(f&quot;Throughput: {preds[&#39;throughput&#39;]} samples/s&quot;)</pre><pre>Number of predictions: 43410<br>Preprocessing time: 6.723727464675903s<br>Postprocessing time: 0.1985154151916504s<br>Throughput: 49017.46503352953 samples/s</pre><p>The output for inference shows an inference throughput of <strong>49017</strong> <strong>samples per second</strong>, with IPU acceleration and a packing factor of 9.1. Compared to the unpacked version, this is approximately <strong>9.1x</strong> faster for inference. Recall that for datasets with different dataset skews, varying improvements in throughput will be observed.</p><p>Lets look at a random output to see what the pipeline returns.</p><pre>print(f&quot;Input:{dataset[&#39;train&#39;][&#39;text&#39;][16]}&quot;)<br>print(f&quot;Output:{preds[&#39;predictions&#39;][16]}&quot;)</pre><pre>Input:Thank you friend<br>Output:<br>  {&#39;admiration&#39;: 0.008711744, <br>   &#39;amusement&#39;: 0.0030106984, <br>   &#39;anger&#39;: 0.0032300074, <br>   &#39;annoyance&#39;: 0.0037541997, <br>   &#39;approval&#39;: 0.0056799226, <br>   &#39;caring&#39;: 0.0048773102, <br>   &#39;confusion&#39;: 0.0027520012, <br>   &#39;curiosity&#39;: 0.003843228, <br>   &#39;desire&#39;: 0.0020692206, <br>   &#39;disappointment&#39;: 0.0025953841, <br>   &#39;disapproval&#39;: 0.00305811, <br>   &#39;disgust&#39;: 0.0009967086,<br>   &#39;embarrassment&#39;: 0.0015079721, <br>   &#39;excitement&#39;: 0.0029756227, <br>   &#39;fear&#39;: 0.0018840467, <br>   &#39;gratitude&#39;: 0.90438044, <br>   &#39;grief&#39;: 0.001129419, <br>   &#39;joy&#39;: 0.0033982676, <br>   &#39;love&#39;: 0.0040671937, <br>   &#39;nervousness&#39;: 0.0016305067, <br>   &#39;optimism&#39;: 0.005975805, <br>   &#39;pride&#39;: 0.0019212064, <br>   &#39;realization&#39;: 0.0032426496, <br>   &#39;relief&#39;: 0.0016178179, <br>   &#39;remorse&#39;: 0.0053986902, <br>   &#39;sadness&#39;: 0.002555146, <br>   &#39;surprise&#39;: 0.003431616, <br>   &#39;neutral&#39;: 0.010305118<br>  }</pre><p>From the above, the outputs list the probabilities for all of the classes. For this input, the most probable class is, expectedly, gratitude with a score of 0.903.</p><p>In summary, using packing for fine-tuning and inference provides evident advantages. The optimisation does not use extra hardware or memory to increase application throughput. Instead, it successfully ‘recycles’ computational waste created by the excess padding of datasets, making it especially time-efficient while fully maintaining model performance.</p><h3>Try it yourself for free</h3><p>Try our PackedBERT notebooks for free in the cloud with Paperspace:</p><figure><a href="https://ipu.dev/q6HAUX"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FdNVQyC2VMZAJI74Jo1lSA.png" /></a></figure><figure><a href="https://ipu.dev/rCmIGv"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MC2S6-5l9MaMJ4ncouWrJg.png" /></a></figure><figure><a href="https://ipu.dev/ff6TLP"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k3zhoCWdguPLLiV_ZJCJtQ.png" /></a></figure><p>For a more in-depth look at implementing packing yourself for different datasets and tasks, try our <a href="https://github.com/graphcore/examples/blob/master/tutorials/blogs_code/finetuning-packedBERT/walkthrough.ipynb">deep-dive fine-tuning notebook.</a></p><p><strong>Other useful resources</strong></p><p>Delve into the original development of packing for BERT pre-training with the work that made this implementation possible through the:</p><ul><li>Article: <a href="https://towardsdatascience.com/introducing-packed-bert-for-2x-faster-training-in-natural-language-processing-eadb749962b1">Introducing Packed BERT for 2x Training Speed-up in Natural Language Processing</a></li><li>Paper: <a href="https://arxiv.org/pdf/2107.02027.pdf">Efficient sequence packing without cross-contamination: accelerating large language models without impacting performance.</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=de16ac4aac1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/packed-bert-how-to-accelerate-fine-tuning-and-inference-for-nlp-tasks-with-packing-de16ac4aac1">Packed BERT: How to accelerate fine-tuning and inference for NLP tasks with packing</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dolly 2.0 — open source language model with ChatGPT-like interactivity]]></title>
            <link>https://medium.com/graphcore/dolly-2-0-open-source-language-model-with-chatgpt-like-interactivity-66b38c24e33?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/66b38c24e33</guid>
            <category><![CDATA[nlp]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[dolly]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Wed, 26 Apr 2023 11:31:52 GMT</pubDate>
            <atom:updated>2023-04-26T11:31:52.613Z</atom:updated>
            <content:encoded><![CDATA[<h3>Dolly 2.0 — open source language model with ChatGPT-like interactivity</h3><p>Dolly 2.0 is an open source large language model suitable for commercial use: learn more about how to use Dolly for AI applications on IPUs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1rmaeHOY3NyuznSjMcU-Fg.jpeg" /></figure><p>Author: Alex McKinney</p><p>Dolly 2.0, an open-source large language model (LLM) that delivers ChatGPT-like instruction-following interactivity, is now available to run as a Paperspace Gradient Notebook, powered by Graphcore IPUs.</p><figure><a href="https://ipu.dev/Qxzpkq"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9gHwNn-3KNiOH1w5uBLNSg.png" /></a></figure><p>The 12 billion parameter model was <a href="https://www.databricks.com/blog/2023/04/12/dolly-first-open-commercially-viable-instruction-tuned-llm">created by Databricks</a> and is based on EleutherAI’s Pythia.</p><p>The trained weights, source code, and dataset for Dolly 2.0 have been released under an open-source and commercial-use license, making it the first truly open, instruction fine-tuned LLM. Prior models are subject to more stringent licensing, making them unusable for commercial applications.</p><h3>Training LLMs for human-computer interaction</h3><p>Attempting to elicit answers from LLMs that haven’t been appropriately fine-tuned requires prompt engineering to produce consistently useful responses — an experience that can be frustrating for users. This is because base LLMs are trained to simply predict the next token, which does not necessarily correlate with a good or even correct responses.</p><p>Fine-tuning on an instruction-following dataset makes the model more suited to human interaction: simply ask the model a question and get a response back. This makes it ideal for Q&amp;A applications.</p><h3>LLMs and commercial restrictions</h3><p>Dolly 2.0’s predecessor Dolly 1.0 was trained using the Stanford Alpaca dataset. Alpaca, in turn, uses some outputs from OpenAI’s ChatGPT. As a result, Dolly 1.0 was bound by ChatGPT’s licence restrictions regarding commercial use — preventing Dolly users from building products and services around the model.</p><p>Dolly 1.0 is not alone in this respect. Similar limitations affect many recently released instruction-following LLMs, including Koala, GPT4All, and Vicuna.</p><h3>Generating an original dataset</h3><p>To address these problems, the Databricks team needed to generate a corpus of training data, written by humans, of a similar size to the 13,000 prompt-response pairs used by OpenAI to train InstructGPT, a sibling model to ChatGPT.</p><p>The company turned to its 5,000 employees, gamifying the process of creating training data by running contest to write the instruction and response pairs. Prizes were offered for the top 20 labelers, across seven specific dataset tasks. Using this approach, combined with a competitive leader board, Databricks managed to create a dataset with more than 15,000 instruction-response pairs.</p><p>The dataset tasks encompass the following (from Databricks’ blog):</p><p><strong>Open Q&amp;A:</strong> For instance, “Why do people like comedy movies?” or “What is the capital of France?” In some cases, there’s not a correct answer, and in others, it requires drawing on knowledge of the world at large.</p><p><strong>Closed Q&amp;A:</strong> These are questions that can be answered using only the information contained in a passage of reference text. For instance, given a paragraph from Wikipedia on the atom, one might ask, “What is the ratio between protons and neutrons in the nucleus?”</p><p><strong>Extract information from Wikipedia:</strong> Here an annotator would copy a paragraph from Wikipedia and extract entities or other factual information such as weights or measurements from the passage.</p><p><strong>Summarize information from Wikipedia</strong>: For this, annotators provided a passage from Wikipedia and were asked to distil it to a short summary.</p><p><strong>Brainstorming</strong>: This task asked for open-ended ideation and an associated list of possible options. For instance, “What are some fun activities I can do with my friends this weekend?”.</p><p><strong>Classification:</strong> For this task, annotators were asked to make judgments about class membership (e.g. are the items in a list animals, minerals or vegetables) or to judge the properties of a short passage of text, such as the sentiment of a movie review.</p><p><strong>Creative writing:</strong> This task would include things like writing a poem or a love letter.</p><p>The resulting model, Dolly 2.0, is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-ShareAlike 3.0 Unported License</a>, which allows anyone to use it, modify it, and create a commercial application using it.</p><p>It is worth noting that Dolly 2.0 is still under active development, so expect to see further versions with better performance in the near future.</p><h3>Getting Started: How to use Dolly 2.0 on IPUs</h3><p>You can try out Dolly 2.0 for free, using a Paperspace Gradient Notebook, powered by Graphcore IPUs.</p><p>The notebook takes you through the process of downloading the model weights, creating an inference pipeline, and querying Dolly 2.0 with instructions and questions.</p><p>Dolly 2.0 fits in our Paperspace free tier environment, using a Graphcore POD4 system. We plan to expand this for faster inference on POD16 systems in due course. Follow the Paperspace Gradient link below to begin.</p><figure><a href="https://ipu.dev/Qxzpkq"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9gHwNn-3KNiOH1w5uBLNSg.png" /></a></figure><p>Dolly is fun to interact with and could easily be fine-tuned to have a particular personality as it answers user questions. As is, it could be used with an appropriate safety filter for real world information or just as a fun on-brand character.</p><p>If you are interested in fine tuning Dolly 2.0 on IPUs with your own datasets, please let us know <a href="https://www.graphcore.ai/speak-to-an-expert-dolly-ai">using this form</a> and we’ll help you get started.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66b38c24e33" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/dolly-2-0-open-source-language-model-with-chatgpt-like-interactivity-66b38c24e33">Dolly 2.0 — open source language model with ChatGPT-like interactivity</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to use OpenAI’s Whisper for Speech Recognition]]></title>
            <link>https://medium.com/graphcore/how-to-use-openais-whisper-for-speech-recognition-eb92b741a72?source=rss----d35727101202---4</link>
            <guid isPermaLink="false">https://medium.com/p/eb92b741a72</guid>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[whisper]]></category>
            <category><![CDATA[speech-recognition]]></category>
            <category><![CDATA[nlp]]></category>
            <dc:creator><![CDATA[Graphcore]]></dc:creator>
            <pubDate>Tue, 25 Apr 2023 09:36:59 GMT</pubDate>
            <atom:updated>2023-04-28T08:51:06.092Z</atom:updated>
            <content:encoded><![CDATA[<h4><strong>Tutorial: how to run Whisper for speech recognition on Graphcore IPUs</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HE887baudn8ljQmL9g78qg.jpeg" /></figure><p>Author: Scott Griffiths, AIE Engineering Manager at Graphcore</p><p>Whisper is an exciting new language model that takes a novel approach to speech recognition. It produces high quality results, even from low quality audio, and is extremely adaptable to a diverse range of voices and languages, without the need for fine-tuning.</p><p>Whisper is open source, and with a range of model sizes available, can be an efficient solution for a many speech to text applications including translation, smart personal assistants, vehicle voice control systems, customer service operations, and more.</p><p>In this blog, we will explore what makes Whisper different to other speech recognition models and we will show you how get started using the Hugging Face implementation of Whisper Tiny using a pre-built Paperspace Gradient Notebook, running on Graphcore IPUs.</p><figure><a href="https://ipu.dev/kPD86C"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P9pe48MRMDx-J6q3rBok1w.png" /></a></figure><h3><strong>What is so clever about Whisper?</strong></h3><p>Whisper’s creators at OpenAI set out to solve several fundamental challenges that have faced Automatic Speech Recognition (ASR) up until now:</p><h4><strong>Talk isn’t cheap</strong></h4><p>Many ASR models rely on very high quality, labelled, audio/text data to perform supervised learning. Unfortunately, this ‘gold standard’ of training data is in short supply. Models trained this way are capable of producing good speech recognition results under ideal conditions. However, because of their limited exposure to different training examples, they tend not to generalise well, can struggle with low quality real-world audio, and typically need additional voice fine-tuning to prepare them for specific use-cases.</p><p>The obvious way to improve such models would be to train them on more data, but the shortage of high quality datasets led AI practitioners to look in the opposite direction, developing ASR models with unsupervised learning, using vast amounts of unlabelled audio.</p><p>Models created this way are able to achieve very high quality representation of speech — but require subsequent fine-tuning to prepare them for specific ASR tasks. As well as entailing extra work, the fine-tuning process used in speech recognition has been shown to throw up some overfitting issues that can limit model generalizability.</p><p>Whisper’s creators described <a href="https://cdn.openai.com/papers/whisper.pdf">this problem as</a> “a crucial weakness which limits their usefulness and robustness” and set out to design an ASR model that worked “out of the box”.</p><h4><strong>How ‘weak’ training data makes us stronger</strong></h4><p>The Whisper solution starts with the same high quality, labelled audio datasets and augment them with much larger ‘weakly supervised datasets’ (such as video captions). This approach was partly influenced by research in computer vision that showed larger, weakly supervised datasets can actually improve the robustness and generalisation of models.</p><p>A number of techniques were used to detect and remove the lowest quality data, such as video transcriptions that had been generated by other ASR technologies due to the risk of transferring their limitations into Whisper.</p><p>Ultimately, 680,000 hours of labelled audio data was used to train Whisper, far more than previous, supervised models. Almost a fifth of the training data was non-English, spanning 96 languages. The dataset also included 125,000 hours of foreign language-to-English translations.</p><h4><strong>The multi-task transformer</strong></h4><p>Whisper takes a classic encoder-decoder transformer architecture and applies it to audio/text pairs, using encodings generated from the audio to enable next token prediction on the text component.</p><p>Crucially, Whisper includes special tokens in the decoder that direct it to perform different language tasks, such as [transcribe] or [translate].</p><p>This approach differs from many AST models which use a variety of subsystems for different aspects of the speech to text process, such as voice activity detection, identifying different speakers, and normalizing the text format. Such architectures require additional resource to coordinate the complex interplay of sub-systems.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*66RDX_sx13hjOPjghQMt1g.jpeg" /><figcaption>A sequence-to-sequence Transformer model is trained on many different speech processing tasks, including multilingual speech recognition, speech translation, spoken language identification, and voice activity detection. (<a href="https://cdn.openai.com/papers/whisper.pdf">Source</a>)</figcaption></figure><h4><strong>Performance</strong></h4><p>The performance of ASR models is typically measured by Word Error Rate (WER).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VVZqMXZMFadMUDXok-1rQw.png" /><figcaption>Whisper is competitive with state-of-the-art commercial and open-source ASR systems in long-form transcription. The distribution of word error rates from six ASR systems on seven long-form datasets are compared, where the input lengths range from a few minutes to a few hours. The boxes show the quartiles of per-example WERs, and the per-dataset aggregate WERs are annotated on each box. Our model outperforms the best open source model (NVIDIA STT) on all datasets, and in most cases, commercial ASR systems as well. (<a href="https://cdn.openai.com/papers/whisper.pdf">Source</a>)</figcaption></figure><p>As illustrated in the plot above, Whisper’s WER for long-form transcription is comparable to proprietary Audio Speech Recognition (ASR) systems, trained on ‘gold-standard‘ datasets. However, because of its larger corpus of training data and the use of ‘weakly labelled‘ examples, Whisper proved much more robust when measured using other training benchmarks, without the need for fine-tuning.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/558/1*PoJ6jzhKcTaq5cGtzN62LA.png" /><figcaption>Whisper outperforms a SOTA wav2vec model on various datasets (<a href="https://cdn.openai.com/papers/whisper.pdf">Source</a>)</figcaption></figure><p>It is worth noting that the Word Error Rate for different languages varies significantly. The chart below shows performance variance for Whisper Large v2 using the Feurs dataset. In this instance, Spanish and Italian perform even better than English, while Zimbabwean Shona and Pakistani Sindhi fare worst, out-of-the-box. Performance for Whisper Tiny may be different.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*n7PJBJelmwL7aOww2TtnTw.png" /><figcaption>The figure above shows a WER (Word Error Rate) breakdown by languages of the Fleurs dataset using the large-v2 model (<a href="https://github.com/openai/whisper#available-models-and-languages">Source</a>)</figcaption></figure><h3><strong>Using Whisper on Graphcore IPUs</strong></h3><h4><strong>Whisper on IPUs</strong></h4><p>Developers can use a pretrained Whisper Tiny (39m parameters) for inference on Graphcore IPUs via a Paperspace Gradiant Notebook.</p><figure><a href="https://ipu.dev/kPD86C"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P9pe48MRMDx-J6q3rBok1w.png" /></a></figure><p>Users can get started with a six hour free trial, or upgrade to a paid tier if they need more.</p><p>Other versions of Whisper are available for IPU and if you want to find out more, contact us <a href="https://www.graphcore.ai/speak-to-an-expert-whisper-ai">via this form</a> .</p><p>Running Whisper in a Paperspace Gradient Notebook on IPUs is simple.</p><p>We will be using Hugging Face’s IPU-optimized transformers library, optimum-graphcore.</p><p>You will also need a few other libraries to manipulate sound files, tokenise the inputs for the model and plot our results.</p><p>Following this guide, you will be able to transcribe audio content in very little time.</p><pre>%%capture<br>%pip install optimum-graphcore==0.6.0<br>%pip install soundfile==0.12.1 librosa==0.10.0.post2 tokenizers==0.12.1<br>%pip install matplotlib==3.7.1<br>%matplotlib inline</pre><p>Next, let’s import the part of the libraries that we will use today.</p><pre># Generic imports<br>from datasets import load_dataset<br>import matplotlib<br>import librosa<br>import IPython<br>import random<br><br># IPU specific imports<br>from optimum.graphcore import IPUConfig<br>from optimum.graphcore.modeling_utils import to_pipelined<br><br># HF related imports<br>from transformers import WhisperProcessor, WhisperForConditionalGeneration</pre><p>We can now choose the model to use and its configuration. Here we are going for Whisper tiny.en which allow for fastest execution speed whilst also have great transcription quality as it is specialised in a single language, English. We are going to use two IPUs to run this model, on the first we place the encoder -side of the Transformer model and on the second the decoder. By calling .half() on our model, we are enabling the use of fp16 precision resulting in near double throughput in comparison to fp32.</p><pre>model_spec = &quot;openai/whisper-tiny.en&quot;<br><br># Instantiate processor and model<br>processor = WhisperProcessor.from_pretrained(model_spec)<br>model = WhisperForConditionalGeneration.from_pretrained(model_spec)<br><br># Adapt whisper to run on the IPU<br>ipu_config = IPUConfig(ipus_per_replica=2)<br>pipelined_model = to_pipelined(model, ipu_config)<br>pipelined_model = pipelined_model.parallelize(for_generation=True).half()</pre><p>The model is ready, now let’s get some audio data to transcribe. We are using the well known librispeech which contains pairs of audio data with corresponding transcriptions. If you are using your own audio and need to convert it into a file format recognised by Whisper, we would suggest using an free application such as <a href="https://ffmpeg.org/">FFmpeg</a>.</p><pre># Load the dataset and read an example soundfile<br>ds = load_dataset(&quot;hf-internal-testing/librispeech_asr_dummy&quot;, &quot;clean&quot;, split=&quot;validation&quot;)<br>test_sample = ds[2]<br>sample_rate = test_sample[&#39;audio&#39;][&#39;sampling_rate&#39;]</pre><p>Then, we create a function to call our Whisper model and call on the audio data. After this, we print the generated transcription to the console and observe that it match the ground truth that we got from librispeech and observe visually the audio we just transcribed.</p><pre>def transcribe(data, rate):<br>    input_features = processor(data, return_tensors=&quot;pt&quot;, sampling_rate=rate).input_features.half()<br><br>    # This triggers a compilation the first time around (unless a precompiled model is available)<br>    sample_output = pipelined_model.generate(input_features, max_length=448, min_length=3)<br>    transcription = processor.batch_decode(sample_output, skip_special_tokens=True)[0]<br>    return transcription<br><br>test_transcription = transcribe(test_sample[&quot;audio&quot;][&quot;array&quot;], sample_rate)<br>print(f&quot;Expected: {test_sample[&#39;text&#39;]}\n&quot;)<br>print(f&quot;Transcribed: {test_transcription}&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r-MgtHCeROEQJp-4VHB4pQ.jpeg" /><figcaption>Image by author.</figcaption></figure><p>Hopefully you agree that it is quick and easy to get started transcribing with Whisper on Graphcore IPUs.</p><p>Of course — Whisper has many more talents, such as translation and multi-lingual transcription.</p><p>If you want to take your Whisper usage on IPUs further, or explore larger versions of the model, please feel free to <a href="https://www.graphcore.ai/speak-to-an-expert-whisper-ai">contact us.</a></p><figure><a href="https://ipu.dev/kPD86C"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P9pe48MRMDx-J6q3rBok1w.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eb92b741a72" width="1" height="1" alt=""><hr><p><a href="https://medium.com/graphcore/how-to-use-openais-whisper-for-speech-recognition-eb92b741a72">How to use OpenAI’s Whisper for Speech Recognition</a> was originally published in <a href="https://medium.com/graphcore">Graphcore</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>