E FFICIENT P ACKING : T OWARDS 2 X NLP S PEED -U P WITHOUT L OSS OF A CCURACY FOR BERT
Anonymous authors
Paper under double-blind review
A BSTRACT
We ﬁnd that at sequence length 512 padding tokens represent in excess of 50% of the Wikipedia dataset used for pretraining BERT (Bidirectional Encoder Representations from Transformers).
Therefore by removing all padding, we achieve a 2x speed-up in terms of sequences/sec.
To exploit this characteristic of the dataset, we develop and contrast two packing algorithms.
Both algorithms rely on the assumption that sequences are interchangeable and therefore packing can be performed on the histogram of sequence lengths, rather than per sample.
This transformation of the problem leads to algorithms which are fast and have linear complexity in dataset size.
The shortest-pack-ﬁrst histogram-packing (SPFHP) algorithm determines the packing order for the Wikipedia dataset of over 16 M sequences in 0 .
03 seconds.
The non-negative least-squares histogram-packing (NNLSHP) algorithm converges in 28 . 4 seconds but produces solutions which are more depth efﬁcient, managing to get near optimal packing by combining a maximum of 3 sequences in one sample.
Using the dataset with multiple sequences per sample requires adjusting the model and the hyperparameters to keep the predictive quality of the model.
We demonstrate that these changes are straightforward to implement and have relatively little impact on the achievable performance gain on modern hardware.
Finally, we pretrain BERT-Large using the packed dataset, demonstrating no loss of convergence and the desired 2x speed-up.
I NTRODUCTION
Since its introduction in 2019, BERT (Devlin et al., 2019a) has been the backbone driving the most exciting advances in Natural Language Processing (NLP).
Pre-training BERT from scratch requires substantial computational resources which may be out of reach for researchers and industry professionals.
To some extent this has been addressed by the public release of pre-trained models of different sizes and depths (Turc et al., 2019).
The introduction of ALBERT (Lan et al., 2019) and
Switch transformers (Fedus et al., 2021) further improved the accessibility of larger models.
However, the dependence on pre-trained models limits the ability of researchers to explore new backbone architectures.
Furthermore, it limits the extent to which practitioners in industry can leverage internal datasets and adapt the model to their particular needs.
Hence, any approach that speeds up the pre-training process is desirable from an economical as well as environmental perspective.
In this paper, we present efﬁcient methods to enable researchers to accelerate the pre-training of
BERT by as much as 2x without loss of accuracy.
The de-facto pre-training dataset Wikipedia, as well as many other NLP datasets, have a skewed distribution of sequence lengths.
We show that padding tokens (wasted compute) represent 50% of all tokens of the Wikipedia pre-training dataset at sequence length 512 .
Thus, by avoiding processing the padding tokens one can get a 2x speed-up.
Overall, the lengths range between 5 tokens up to 512 (see Figure 1).
Samples of length 512 represent only 23 .
5% of the dataset, a surprising result given that the pre-processing in BERT attempts to “pack” together sentences so as to ﬁll the sequence length as completely as possible (Devlin et al., 2019c).
While processing the padding tokens wastes compute, it is still the most standard approach for leveraging modern massively-parallel compute especially on GPUs.
These are most efﬁcient when applying the same operation to each sequence in a batch.
By padding all sequences to the same maximum sequence length, they can easily be batched.
We note that this naive batching is the most widely used and provided in the vanilla BERT implementation as well as the Hugging Face framework (Wolf et al., 2020) and thus considered as our baseline for comparison.
[Figure]
The most obvious way to reduce the extent of padding in the dataset is to group samples by size before batching,
i
[Figure]
e., process the shorter samples together and longer samples together.
BERT is pre-trained in two phases, where the ﬁrst phase uses sequence length 128 for 900 K steps and the second phase uses sequence length 512 for 100 K steps.
However even by splitting the training in this way, the wasted compute due to padding is approximately 20% (see Figure 1).
Other examples of this “sorted batching” approach can be found in Faster Transformer (NVIDIA, 2021), lingvo (Shen et al., 2019) fairseq (Ott et al., 2019)
[Figure]
and RoBERTa (Liu et al., 2019), which group samples of similar size together in one batch and ﬁll up with padding only to the maximum length in this batch.
This approach can be highly efﬁcient in cases where the dataset length is multiple orders of magnitude larger than the batch size and the number of different sequence lengths.
Despite its high computational efﬁciency, this approach has multiple drawbacks.
We outline these below and propose an alternative which maintains the high efﬁciency, while also circumventing the downsides.
Firstly, sorting the data can reduce the overall convergence speed when the batch size is large because it violates the i.i.d.
assumption on the data distribution (Bottou et al., 2018; Meng et al., 2019).
Secondly, processing batches with shorter sequence lengths under-utilizes the compute compared to running the same batch size with a longer sequence length.
For GPUs, a common heuristic to mitigate this effect is to adjust the batch size to keep the number of processed tokens near constant (Ott et al., 2019; Liu et al., 2019).
In general however, the relationship between the sequence length and the optimum batch size is more complex and maximizing compute utilization can require the model to be sharded differently across multiple accelerators.
Avoiding this, often manual process, is important for ease of use and the portability of methods across different hardware architectures.
Thirdly, modern NLP applications are optimized and compiled for ﬁxed tensor sizes using tools such as XLA (XLA, 2021; Fedus et al., 2021), which provides a ≈ 7 x acceleration for BERT in
MLPerf™ (Mattson et al., 2020) compared to the non-XLA baseline (XLA, 2021).
Changing the sequence length or batch size requires re-optimization of the computational graph and recompilation of the program for the new tensor shapes.
For complex models such as BERT, optimization and recompilation take a non-negligible amount of time.
Even if one pre-compiled and cached all combinations of batch size and sequence length, the kernels would still need to be re-uploaded to the device every time the shapes change.
Depending on how frequently the tensor shapes change, the overhead from switching kernels adds up.
To avoid these issues, it is preferable (and common) to work with ﬁxed tensor shapes for the entire duration of the training run.
More advanced approaches for reducing the padding overhead rely on custom computational kernels.
Loosely these are referred to as “un-padding” approaches.
In Effective Transformer (ByteDance
Inc., 2021), the input batch is provided as a padded matrix but padding values are dynamically removed and restored during different calculation stages.
While un-padding implementations are highly sophisticated and are able to completely circumvent the processing of padding tokens, they introduce a signiﬁcant overhead due to the multiple GPU kernel launches (i.e., one kernel per sequence rather than one kernel per batch).
Additionally the time to process each batch will ﬂuctuate depending on the sequence lengths in each batch, i.e., batches with only shorter sequences will typically be processed faster.
When working with more than one accelerator, this variability in throughput results in all devices in the cluster waiting for the device with the most compute inten-
sive batch to ﬁnish processing.
As such, un-padding approaches are not appropriate for deployment on large clusters.
The “packing” based approach introduced in this paper offers signiﬁcant advantages over un-padding approaches.
Firstly, packing is implemented directly at the framework level and requires no additional custom kernel implementations.
Secondly, the processing time for each batch is independent of the content of the batch, allowing the packing based approach to maintain the same speed-up whether running on a single device or thousands.
While we demonstrate the effectiveness of packing speciﬁcally on the Wikipedia dataset, packing SQuAD (Rajpurkar et al., 2016) or GLUE datasets (Warstadt et al., 2018; Wang et al., 2018) for BERT also leads to signiﬁcant speed-ups (some in excess of 9x) (Sections F and G).
The effectiveness of packing is a result of both the length distribution of the documents in the source datasets as well as the different text preprocessing steps for BERT (Devlin et al., 2019c).
The use of bi-directional self-attention in BERT implies that the input sequences should contain complete sentences.
If a sentence is abruptly cut short, the hidden state on other (preceding) tokens in the sequence will be affected.
Language models with causal attention (only attending to previous tokens in the input) do not have this issue to the same degree.
For such models, if a sequence is cut short at an arbitrary token, the other tokens (which occur earlier in the sequence) will not be affected.
This ability to cut sequences arbitrarily completely trivializes the packing problem for models based on causal attention.
For instance, GPT-3 (Brown et al., 2020) is trained with a maximum sequence length of 2048 where a single sequence may contain multiple segments of sentences separated by a special end of segment token.
The last segment in each sequence is simply cut to meet the sequence length requirement making the packing problem trivial and avoiding any padding.
In the interest of computational efﬁciency GPT-3 does not mask the attention between different segments in a sequence.
In contrast, the packing approach presented in this paper introduces a mask in the attention layer (see Section 3.2.2) to prevent cross-contamination between examples in a pack.
Note, we mask the interaction between different sequences and not between different sentences or segments in the same sequence.
This ensures that the characteristics of the original dataset and model are matched as closely as possible.
RoBERTa and many other models in production like T5 (Raffel et al., 2019) use a similar packing approach as GPT-3 but with full sentences/sequences and also separation tokens or additional padding.
The RoBERTa ablation study shows that mixing of sentences from different documents reduces accuracy, but it is used nonetheless for load balancing reasons which indicates that sorted batching is not sufﬁcient.
In summary, the contributions of the paper are as follows.
In Section 2, we produce histograms of the Wikipedia pre-training dataset showing the high percentage of padding tokens.
We present two new deterministic and efﬁcient packing algorithms which easily pack datasets with millions of sequences in a matter of seconds (or less) in Section 3.1.
We empirically show that the proposed packing algorithms produce a nearly-optimal packing scheme for Wikipedia pre-training dataset (Section 4.1).
In Section 3.2 and Section 3.3, we explain how the BERT model can be adjusted to show the same convergence behavior on packed and unpacked sequences.
In Section 4.2, we demonstrate that the convergence of the BERT large model on the packed dataset is equivalent to that on the un-packed dataset with 2x throughput increase on the Wikipedia sequence lengthpre-training dataset.
W IKIPEDIA BERT PRE - TRAINING DATASET
BERT is pre-trained using masked-language modelling and next-sentence prediction on a large corpus of Wikipedia articles.
Each sequence is composed of one < CLS > token followed by the ﬁrst “segment” of sentences, followed by a < SEP > token, and then ﬁnally the second “segment” of sentences.
Because these “segments” are created in sentence-level increments there is no token-level control of sequence length.
Furthermore 10% (default value, (Devlin et al., 2019b)) of sequences are intentionally cut short.
This leads to signiﬁcant levels of padding, especially for longer maximum sequence lengths (see Figure 1).
At sequence length 128 (commonly used in phase 1 of pre-training) the theoretical speed-up is around 1 . 2 , at sequence length 384 this increases to 1 . 7 , and ﬁnally at sequence length 512 (commonly used for phase 2 of pre-training) it is 2 . 0 .
Despite the widespread use of the Wikipedia dataset for pre-training BERT such histograms have, to the best of our knowledge, not been published previously.
This has perhaps lead to the underestimation of the speed-up opportunity available.
To put things into perspective, the sequence length 512 dataset contains 8.
billion tokens, of which 4.17 billion are padding tokens.
M ETHODS
Our approach consists of three distinct components.
Firstly, we pack the n data samples efﬁciently during pre-processing to make full use of the maximum sequence length, s m (Sections 3.1.1, 3.1.2, and D).
Secondly, we introduce a series of model changes in Section 3.2 that preserve the equivalence with the original BERT implementation.
The changes include a self-attention mask to prevent the model from attending between different sequences in the same pack (Section 3.2.2), and an adjustment of the the positional embeddings (Section 3.2.1) to handle packs of sequences.
Other components of the model, such as the feed-forward layer (Vaswani et al., 2017), operate on a per-token basis and do not require modiﬁcation for pre-training.
In Section 3.2.3, we also demonstrate how to compute a per-sequence loss and accuracy for NSP and downstream ﬁne-tuning tasks.
Thirdly, we provide suggestions for hyperparameter adjustment (Section 3.3) that lead to analogous convergence behavior between the packed and un-packed BERT implementations.
3. P ACKING ALGORITHMS
The problem of optimally concatenating multiple sequences of different length until a maximum combined length is reached can be directly framed as a bin-packing problem.
Since an exact solution is strongly NP-complete (Korte & Vygen, 2012), we propose two new heuristic algorithms that are tailored to the NLP setting.
A detailed introduction to packing is provided in Section D.
. S HORTEST - PACK - FIRST HISTOGRAM - PACKING (SPFHP)
Shortest-pack-ﬁrst histogram-packing (SPFHP) works on the bins in the sequence length histogram (with bin size 1) rather than the individual samples.
The histogram is traversed in sorted order from longest to shortest sequences.
Then, to pack the data during the traversal, we apply the worst-ﬁt algorithm (Johnson, 1973; Yue & Zhang, 1995) such that the histogram bin being processed goes to the “pack” 1 that has the most space remaining (“shortest-pack-ﬁrst”).
If the histogram bin does not ﬁt completely, a new pack is created.
We also limit the packing depth , in other words the maximum number of sequences that are allowed in a pack.
Therefore, an existing pack is only extended if it is not already at maximum packing depth.
The detailed code for the algorithm is provided in Listing 3.
The time and space complexity of the algorithm are O ( n + s 2 m ) and O ( s 2 m )
(Section E.2).
3.1. N ON - NEGATIVE LEAST SQUARES HISTOGRAM - PACKING (NNLSHP)
The proposed NNLSHP algorithm is based on re-stating the packing problem as a (weighted) nonnegative least squares problem (NNLS) (Bro & De Jong, 1997) of the form wAx =
wb where x ≥ 0 .
The vector b is the histogram containing the counts of all the sequence lengths in the dataset.
Next, we deﬁne the A matrix (the “packing matrix“) by ﬁrst generating a list of all possible sequence length combinations (“strategies”) that add up exactly to the maximum sequence length.
We focus speciﬁcally on strategies that consist of at most 3 sequences per pack (independent of b ) and encode each strategy as a column of the sparse matrix A .
For example, a strategy consisting of the sequence length 128 , 128 , and 256 in represented a column vector that has the value 2 at the 128 th row, the value 1 at the 256 th row, and zero at all other rows.
The variable x describes the non-negative repetition count for each strategy.
So a 24 in the i th row of x means that the strategy represented by the i th column of A should repeat 24 times.
Moreover, in the un-weighted setting, Ax = b states that we would like to “mix” the pre-deﬁned strategies (columns of A ) such that the number of samples matches the histogram b , and where each strategy is used x ≥ 0 times.
We use the residual weight w to control the penalization of the Ax − b residual on different sequence lengths (different rows of b ).
Heuristically, we set the weight of 0 . 09 for all sequences of length 8 or smaller because they are considered acceptable padding sequences while all other sequence lengths get weight 1 .
We discuss this heuristic choice of parameters in Section D.4.5 and D.5.
The overall efﬁciency of the packing is not greatly inﬂuenced by the weighing (less than 1% extra speed-up).
After solving wAx =
wb for x ≥ 0 using an off-the-shelf solver, we obtain a ﬂoating point solution, which means that the repetition counts are not necessarily integers.
Since we cannot use a nonnatural number of strategies, we round the solution ˆ x to the nearest integer.
The error introduced by this rounding is found to be negligible (a few hundred sequences in the worst case) compared to the size of the dataset (millions of sequences).
The time complexity and space complexity of the algorithm are O ( n + s 5 m ) and O ( s 3 m ) .
Further details are provided in Section D.4.
PACKED BERT: MODEL CHANGES
This section describes how any vanilla BERT implementation should be modiﬁed for packed sequence processing, such that the behavior of the model is the same as when processing unpacked sequences.
Preserving the mathematical equivalence is necessary to ensure existing BERT pretraining and ﬁne-tuning practices remain valid, as well as being required by benchmarks such as
MLPerf™ (Mattson et al., 2020).
3.2. P OSITIONAL EMBEDDINGS FOR PACKED SEQUENCES
The BERT model uses three types of embeddings: token, segment, and positional embeddings.
The latter is canonically implemented as a bias add operation, rather than a full embedding look-up.
This is possible because the positional indices are the same for every sequence.
However, when using the packed data format the position index needs to be reset with each new packed sequence.
For instance, when packing two sequences one of length 2 and one of length 3 , the positional embedding indexes that need to be picked up are [0 , 1 , 0 , 1 , 2] .
To achieve this, the bias add needs to be replaced by an embedding look-up to extract the correct positional embedding for each token in the pack.
This also requires keeping an extra input which speciﬁes the position of each token in its sequence.
This adjustment has only a minor impact on absolute accuracy/loss but is required to reach the target accuracy (Section 4.2 and C).
3.2. A TTENTION MASKING FOR PACKED SEQUENCES
To maintain an implementation that is consistent with the un-packed version, tokens from different sequences within a pack should not be able to attend to each other.
This is typically achieved in other implementations by unpacking the sequences using custom attention kernels and then doing the attention per-sequence (ByteDance Inc., 2021).
Instead, we propose directly masking the attention matrix with a block-diagonal mask before the attention softmax.
This is straightforward to implement in modern frameworks (see Figure 2).
Naturally, there is a cost to both the mask construction and applying it to the attention matrix (see Table 1, Section 4.1).
However, it is required to keep the accuracy (Section 4.2 and C).
[Figure]
3.2. C ALCULATING PER - SEQUENCE LOSS AND ACCURACY
Canonical implementations of BERT compute the cross-entropy loss for the masked language model on a per-token basis.
However other NLP tasks, such as SQuAD, compute the loss and accuracy on a per-sequence basis.
This section discusses how to handle such tasks when training with packed sequences.
Simply feeding packs of sequences to the same implementation of cross-entropy would result in a per-pack weighted loss.
In other words, the overall loss on the micro-batch would sumup the losses on the individual packs, rather than individual sequences.
As a result, the model would converge to a different optimum than when running with the un-packed implementation.
For instance, a pack of a single sequence would contribute to the loss with the same weight as a pack of three sequences.
To recover the per-sequence averaging behavior of the canonical un-packed BERT implementation, we effectively “unpack” the incoming logits and labels.
Once the sequences have been unpacked, we can compute the loss on each sequence separately as usual and then add up the losses.
However, rather than looping through the sequences index, we compute on all indexes in parallel (see
Figure 3).
This minimizes the latency overhead of un-packing the loss calculation.
As an example, we show how per-sequence loss can be implemented for the pre-training task.
We use the “masked lm weight”
(Devlin et al., 2019b) input tensor to represent which sequence a given masked token belongs to (0, 1, 2 and so on).
This is consistent with the canonical BERT implementation where this input takes a value of either 1 (belonging to the sequence) or 0 (belonging to padding).
The full methodology is detailed in Listing 5 and can be applied to other classiﬁcation or pre-training tasks.
3. H YPERPARAMETER ADJUSTMENT
In terms of convergence behavior, the primary consequence of packing is an increase in the effective batch size (with respect to number of sequences and real tokens) with some variation over different iterations.
When the loss is averaged per-sequence, if each pack on average contains two sequences, the batch size (per optimization step) is effectively doubled on average.
Similarly, for per-token averaged losses depends on the effectiveness of the compression.
Reducing the fraction of padding tokens in the dataset from 50% to 0% results in there being twice as many tokens in the batch i.e. the dataset is compressed by a 2x factor.
While one could subsequently reduce the computational batch size by the packing factor (average number of sequences per pack) and keep using the same hyperparameters, this is typically not desirable as it might imply under-utilizing the memory/compute.
Instead, we propose an approximate heuristic for updating the decay parameters of the LAMB optimizer (You et al., 2019).
For a packed dataset with a packing factor p , we update the decay parameters as: β 1 :=
β p 1 , β 2 := β p 2 .
For p = 2 , this corresponds to the exact parameters for calculating momentum and velocity, when updating with the same gradient twice (Section A).
A common approach is to scale the learning rate with the batch size.
However, our experiments in Section 4. show that this reduces convergence speed.
Since these adjustments are only heuristics the convergence of the model will be comparable but not identical.
In particular, it is unlikely that simply adjusting the hyperparameters will fully undo the impact of the increased batch size.
However, with these adjustments, researchers should be able to continue to use existing conﬁgurations.
E XPERIMENTS 4. B IN - PACKING ALGORITHM COMPARISON
We evaluate our algorithms using the following metrics: number of packs , number of all tokens , number of padding tokens , solution time of the packing algorithm (after histogram and strategy creation), number of strategies used , packing efﬁciency (the fraction of non-padding tokens in the packed dataset), the speed-up achieved compared to not packing (depth 1), and the average number of sequences per sample ( packing factor ).
For SPFHP, we analyse different (maximum) packing depth, since packing is less efﬁcient with smaller depth and we want to get a general understanding on how the packing depth inﬂuences the processing time.
For NNLSHP, we focus on packing depth 3 because it packs the data sufﬁciently well.
For the speed-up analysis, we focus on the intelligence processing unit (IPU)
(Jia et al., 2019)
(IPUM2000, 16 accelerator chips).
A GPU dynamically loads the code into the accelerator; in contrast, the IPU works with a static pre-compiled engine that gets loaded onto the chip at the start of the run.
While other approaches result in excessive padding or continuous changes of the code, our approach can work with the same code for the whole dataset.
So in this setting the IPU architecture would especially beneﬁt from our approach since it avoids code changes.
Nevertheless, it can be applied to any implementation on GPU or TPU.
For determining the speed-up, we take advantage of the precompiled kernel.
Since time measurements are quite noisy, we can proﬁle the kernel and how many cycles it takes for processing a batch.
That way, we can determine the overhead (in cycles) from processing the additional attention masking and for unpacking the loss.
Combining overhead and packing factor , we get the speed-up estimate.
No experiment repetitions are required since the algorithms and measurements are deterministic.
The main results for the performance metric evaluation are displayed in Table 1.
The processing time for SBFHP was around 0 .
03 s and independent from the packing depth.
We see that the overhead slightly increases with packing depth but that the beneﬁts of packing outweigh the cost.
The best speed-up is obtained with NNLSHP at depth 3 which required 28 .
4 s for processing and ran out of memory for larger depth.
With a value of 1 . 913 , it is close to the theoretical upper bound of 2 . 001 .
The results show that efﬁciency, packing factor, and speed-up can be viewed inter-changeably.
The amount of time needed to process a sample (a pack of sequences) is barely changed relative to the un-packed implementation.
The packing factor or the improvement in efﬁciency effectively provide an accurate estimate of the speed-up.
[Table]
Packing depth describes the maximum number of packed sequences.
Packing depth 1 is the baseline
BERT implementation.
Setting no limit resulted in a maximum packing depth of 16 .
The number of packs describes the length of the new packed dataset.
Efﬁciency is the percentage of real tokens in the packed dataset.
The packing factor describes the resulting potential speed-up compared to packing depth 1.
With overhead , we denote the percentage decrease in throughput due to changes to the model to enable packing (such as the masking scheme introduced in Section 3.2.2).
The realized speed-up is the combination of the speed-up due to packing (the packing factor ) and the decrease in throughput due to the overhead .
It is used to measure the relative speed-up in throughput and the overhead from masking and loss adjustment.
4. L EARNING CURVES AND HYPERPARAMETER ADJUSTMENT
For depth 1 (classic BERT) and NNLSHP with depth 3, we additionally evaluate on the MLPerf™ version 0 .
7 BERT pre-training benchmark (Mattson et al., 2020).
Brieﬂy, this involves training from a standard checkpoint to a masked-language model accuracy of 71 .
2% using 3 million sequences with a maximum length of 512 tokens (refer to MLCommons (2020) for details).
Following this standardized benchmark supports reproduction of results even on other systems and makes sure that the reproduction effort is moderate and setup rules are clearly documented.
We compare the resulting speed-up as well as the respective learning curves by evaluating the data on a held-out validation dataset.
The objective of this additional evaluation is to analyse if convergence behavior is changed by the packing strategy and if the theoretical speed-up can be achieved in practice.
With packing, we effectively increase the average batch size by the packing factor ( ≈ 2 ).
However, with a different batch size, different hyperparameters are required (see Section 3.3) and there is no mapping that will generate exact matching of results but only heuristics.
In a ﬁrst comparison, we use the same hyperparameters when comparing packed and unpacked training except for cutting the accumulation count by half.
This way, we make sure that the batch size is constant on average .
In the second comparison, we evaluate our heuristics and how they compensate the difference in batch size.
This setup is more desirable because it is beneﬁcial to use the hardware to its full potential and cutting the batch size by half usually reduces throughput.
In the third comparison, we compare two optimized setups.
The learning curves are displayed in Figure 4.
In the ﬁrst setup, we see the curves almost matching perfectly when normalizing by the numbers of samples processed.
Differences can be explained by the variation of the number of sequences in the packing batch, and general noise in the training process.
Especially after the initial phase, the curves show a near-identical match.
The second setup shows bigger differences since changing the batch size and hyperparameters changes the training dynamics.
We observe slower convergence early on in training due to the increased batch size.
This is expected.
The adjustment of the learning rate actually decreases performance probably because we correct for the increased number of sequences already in the modiﬁed loss.
With the adjustment of the decay parameter of LAMB, we see matching performance at the later training stages.
However, it is not feasible to completely recover the early convergence behavior of the smaller batch size by adjusting the hyperparameters.
For instance doubling the batch size of unpacked BERT to 3000 and adjusting the LAMB decay parameters leads to more of a slow down in convergence than when running packed BERT with a batch size of 1500 and a packing factor of 2.
n practice, our implementations exceeds the estimated 1.913 maximum speed-up.
This estimate is based on the reduction in the computational work needed to process the dataset.
However, packing the data also reduces the latency of the transferring the data to the device.
Figure 4 shows that the realized total speed-up from packing exceeds 2x.
[Figure]
4. S CALING ANALYSIS : I MPACT OF THE NUMBER OF ACCELERATORS
A further advantage of packing over competing un-padding approaches is the inherent load balancing provided by packing.
So called un-padding approaches rely on dynamically launching custom kernels that ignore padding.
A stated advantage of such implementations is the ability to avoid computing the complete (512 x 512) attention matrix.
This provides additional computational savings compared to packing, where the attention matrix is computed in its entirety and then masked.
Because of these additional savings, un-padding can exceed the theoretical upper bound for speed-up from packing ( 2 . 013 on Wikipedia).
As a result of the dynamic nature of the approach, the processing time with un-padding is different for each sequence in the batch, and the amount of time required to process a batch of sequences will be determined by the processing time of the longest sequence in the batch (with the sequences being processed in parallel).
Furthermore, in the multiple accelerator setting the processing time on each device will vary depending on the sequences in the batch that it receives.
Devices which ﬁnish early have to wait for the slowest device to ﬁnish before exchanging gradients.
This load-imbalance between the devices (and inside the batch) leads to a considerable decrease in the speed-up from un-padding as the number of accelerators is increased (see Figure 5).
In contrast, packing (our approach) is inherently load-balanced.
The processing time on each accelerator is independent of the content inside the batch received by the device.
Any number of accelerators can therefore operate in unison without having to wait for the slowest batch to process (all per-device batches are equally fast).
To demonstrate the severity of the load-imbalance issue, we consider the scaling of an un-padding approach with a per-device batch size of 32 running on eight devices (NVIDIA, 2020).
From there, we readily extrapolate the performance to both larger and smaller cluster sizes by ﬁtting a Gumbel distribution to the observed processing times (Section B).
On a single device with batch size 32 un-padding outperforms packing and exceeds the theoretical upper-bound for packing.
As the number of devices increases to two or more, the proposed packing approach outperforms the dynamic un-padding approach.
On a cluster with 32 accelerators the speed-up from un-padding drops to 50% and with 2048 devices the speed-up is only 30% .
In contrast, the speed-up due to packing is independent of the number of accelerators and stays at 1 . 913 .
Switching to a smaller batch size would reduce the load-imbalance issue to some extent, but would also result in under-utilization of the available memory and compute.
[Figure]
C ONCLUSION
We showed that packing can be easily implemented without the need for any custom kernels while still providing a 2x speed-up without a loss of accuracy.
Additionally, we showed that any additional speed-ups resulting from dynamic un-padding approaches diminish for even moderate batch sizes or when additional accelerators are added.
In contrast, packing is load-balanced and maintains the 2x throughput when scaling to large numbers of accelerators.
Furthermore, the computational overhead introduced by the positional embedding, the attention mask, and potentially the packed per-sequence loss are small compared to the achieved acceleration.
This overhead remains below 5% on the IPU for all tested packing depths.
The efﬁcient packing algorithms presented in this paper enable us to efﬁciently pack millions of sequences in a matter of seconds.
Compared to both the pre-processing time for the Wikipedia dataset and the training runtime, this overhead is negligible.
Furthermore, we showed that performing packing as a preprocessing step does not signiﬁcantly impact the training convergence.
Our proposed hyperparameter adjustment scheme additionally helps practitioners easily modify existing validated optimizer settings for use with packed BERT.
Further exploration of hyperparameter selection is left to future work.
When performing packing as a pre-processing step, the proposed NNLSHP and SPFHP methods achieve near optimal compression efﬁciency.
In this ofﬂine setting, we are able to build a histogram of the dataset, and thus achieve linear time complexity with respect to the number of samples.
This makes packing modern datasets with millions of sequences possible.
In the future, it would be interesting to extend SPFHP to the online setting where a histogram of the entire dataset cannot be built.
Another interesting direction is the packing of images of different sizes to help accelerate computer-vision applications.
This is especially relevant given the recent advances in the use of transformer-based approaches in the computer vision domain, for example the visual transformer (Wu et al., 2020).
Masking out the self-attention within transformers is easier to implement than avoiding cross-contamination of convolutions applied to packed images.
Future work should explore training packed BERT from scratch without the ﬁrst phase, the impact of packing on accelerating ﬁne-tuning, and improving the performance of other models (RoBERTa, GPT-3, T5) by avoiding contamination between non-contiguous segments from different documents.
Even BERT itself might beneﬁt from avoiding contamination between the two concatenated segments.
R EPRODUCIBILITY S TATEMENT
All code for the packing algorithms is available in the appendix (Section K) and is directly linked to our GitHub page to simplify the download and usage.
We even provide code for different variants and the histograms of sequence length for different datasets that got tokenized for BERT training of ﬁne-tuning.
To generate the learning curves, our public submission to MLPerf™ could be used and we are preparing further code releases in other frameworks.
To encourage the use of the adjustments of models for packed sequences, we additionally provide detailed explanations and code snippets in
TensorFlow.
Detailed mathematical formulas (Section B and D), a theorem proof (Section A), and complexity calculations (Section E) are provided in the appendix to support our claims in this paper in full detail.
T ABLE OF C ONTENTS 1 Introduction
2 Wikipedia BERT pre-training dataset 3 Methods 3.1 Packing algorithms . .
3.2 packedBERT: model changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Hyperparameter adjustment . .
4 Experiments 4.1 Bin-packing algorithm comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Learning curves and hyperparameter adjustment . . . . . . . . . . . . . . . . . . . . . . . .
4.3 Scaling analysis: Impact of the number of accelerators . . . . . . . . . . . . . . . . . . . . .
5 Conclusion
A Theorem on LAMB hyperparameter correction heuristic
B Un-padding scaling estimate
C Ablation study
D Technical background on packing
D.1 Canonical packing problem . .
D.2 Approximate bin-packing problem . .
D.3 Deﬁnitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
D.4 Non-negative least squares histogram-packing . . . . . . . . . . . . . . . . . . . . . . . . .
D.5 Discussion of residual weight choice
E Complexity analysis of the proposed packing approaches
E
1 Analysis of non-negative least-squares histogram-packing . . . . . . . . . . . . . . . . . . .
E.2 Analysis of shortest-pack-ﬁrst histogram-packing . . . . . . . . . . . . . . . . . . . . . . . .
F Packing SQuAD 1.
G
Packing GLUE
H Further learning curves
I
[Table] [Table]
[Table]
B ROADER IMPACT
We showed that when pre-training BERT on Wikipedia, the computational overhead taken to process padding tokens is roughly 50% .
By eliminating this wasted computational time, the approach presented in this paper paves a way to halving the carbon footprint of training BERT-based models.
Furthermore, our approach circumvents the need for custom kernels, making the beneﬁts of packing readily accessible to a broader audience of NLP practitioners.
As such, we are hopeful the research will have a positive impact on the NLP community, and do not see any disadvantage of using this approach.
The beneﬁt of our algorithm is based on two assumptions: A skewed length distribution in the training dataset and a hardware setup that trains efﬁciently on a ﬁxed batch size.
If efﬁcient training is possible, with a variable batch size approaches like FasterTransformer and the fairseq sorted batch approach will result in the same or even larger beneﬁts (due to smaller self-attention matrices).
If the dataset is generated differently like in GPT models (Brown et al., 2020) and RoBERTa (FULL-SENTENCES) (Liu et al., 2019), all sequences will be at full length and sequences cannot be concatenated and there is indeed no beneﬁt in packing sequences.
However, strategies that reach full sequence length usually combine segments from different unrelated document sources which can result in reduced performance.
Even in the normal BERT model, there might be this contamination between segments from different documents.
Our paper introduced an approach to avoid the contamination between sequences.
However, the same approach could also be applied to avoid contamination between segments and it remains future work to explore its beneﬁts beyond BERT pretraining.
Future work would need to investigate the applicability of packing on text produced by different cultures and in different languages.
We have already shown that the speed-up resulting from using our methods does not only occur when pre-training BERT on Wikipedia but also on other datasets such as SQuAD and GLUE.
Furthermore, the sentence length distribution of the original English language text shows similar characteristics.
Our research leads us to believe that compressible distributions arise naturally in language tasks and beyond, for instance in DNA sequence lengths (Hansen et al., 2017) and protein lengths (Guill ´ en et al., 2013).
Many such sequence modelling workloads are based on variations of the BERT/transformer architecture and would therefore easily beneﬁt from our acceleration.
Failures in NLP can have a big impact on society; many technologies, such as Alexa, Siri, and
Google Home, rely on them.
Whilst any errors arising from our approach can be avoided, one potential source of error comes from the implementation.
Both the attention mask and the per-sequence loss need to be modiﬁed to support packing.
These changes are signiﬁcantly smaller than those required by custom kernels, however they may still be time consuming to implement and debug.
To help mitigate the risk of any implementation errors, we share our reference implementations of the required changes in the appendix.
A T HEOREM ON LAMB HYPERPARAMETER CORRECTION HEURISTIC
With packing, the effective batch size changes and hence hyperparameters of the LAMB optimizer (You et al., 2019) need to be adjusted.
For a packed dataset with a packing factor p , we update the decay parameters as: β 1 :=
β p 1 , β 2 := β p 2 .
For instance if β 1 = 0 .
81 for the un-packed dataset, then for a packed dataset with an average of 2 sequences per sample one should use a value of 0 .
81 2 ≈ 0 .
66 instead.
Assuming no or only minor changes in gradients and p being a natural number, we can prove that this heuristic is the exact solution to make sure that momentum and velocity in LAMB are unaffected by packing.
This can be proven by mathematical induction.
Note that p ≥ 1 by deﬁnition.
Theorem 1.
For any p ∈ N and assuming that respective gradients on a batch of b random samples are (approximately) the same, choosing
[Equation]
as hyperparameters in the LAMB optimizer ensures that the momentum and velocity after p separate update steps are the same as with one packed update step with p × b samples.
Proof.
• Base Case : For p = 1 the left and right side of the equation are the same which matches exactly the unpacked case.
Hence, the theorem holds for p = 1 .
• Inductive hypothesis : Suppose the theorem holds for all values of p up to some k , k ≥ 1 .
• Inductive proposition :
The theorem holds for p = k + 1 .
• Proof of the inductive step : Let l be the loss function, w t the weight vector after t updates, and x t 1 , . . .
, x tb the respective underlying data to calculate the gradient g t .
For a single update step in LAMB with batch size b samples, we compute the gradient
[Equation]
Since g 1 ≈ g 2 ≈ . . .
≈ g k +1 ,
We have with the inductive hypothesis and the deﬁnitions in
LAMB:
[Equation]
Now we can calculate (with g
≈ g k +1 )
[Equation]
The calculation for v k is the same.
As reference for a packed update with p = k + 1 with β 1 and β 2 , we would get
[Equation]
since we are calculating gradients over b samples which are assumed to be approximately the same.
Consequently, the updates for momentum and velocity would be
[Equation]
Hence, β 1 = β k + and β 2 =
β k
+ is required to map to the formula with the consecutive updates (for the same amount of data).
• Conclusion : The theorem holds for any p ∈ N .
Since we proved that the formulas β 1 := β p 1 , β 2 := β p 2 .
hold for all p ∈ N , p ≥ 1 , it is safe to assume that it is an appropriate heuristic for all p ∈ R , p ≥ 1 .
B U N - PADDING SCALING ESTIMATE
Firstly
[Figure]
we retrieve the per-batch processing time for an un-padding implementation running pretraining on the Wikipedia dataset from (NVIDIA, 2020).
These processing times were obtained using 8 GPUs each with a per-device batch size of 32.
We also retrieve the throughput numbers for the same system running with padding from (NVIDIA, 2021) and use that as the baseline to compare the un-padded throughput against.
The throughput on the 8 GPU system is effectively limited by the slowest of the eight batches being processed in parallel.
The Gumbel distribution is particularly suited to modelling the maximum or minimum value of a ﬁxed size collection of i.i.d.
samples (in this case batches).
We observe that on 8 GPUs the throughput (i
[Figure]
e. speed-up) distribution indeed closely resembles a Gumbel distribution with α 1 = 1 . 6 and β 8 = 0 .
13 as shown in Figure
[Figure]
We can extrapolate the performance on the 8 GPU system to larger clusters by recognizing that the processing time for each cluster is effectively determined by the slowest batch being processed.
Speciﬁcally, we could randomly sample (without replacement) two processing times for the 8 GPU system, and record the max of the two as the processing time for a system of 16 GPUs.
However, this simple approach is too sensitive to outliers in the data and would result in an under-estimate of the performance of un-padding on large systems.
We mitigate the effect of outliers in the data by avoiding directly sampling the processing times.
Instead, we ﬁt a Gumbel distribution to the processing times of a single batch of size 32 running on one GPU.
To perform the ﬁt, we observe that the cdf on one GPU ( P 1 ) is related to the cdf on 8 GPUs ( P 8 ) through (Kotz & Nadarajah, 2000)(section 1.3):
[Equation]
[Equation]
In other words, if the speed-up on the cluster is larger than s , this implies that the speed-up on every GPUs in the cluster was at least s .
Assuming P 1 is Gumbel and given the 8 GPU Gumbel parameters α 8 and β 8 , we need to ﬁt two parameters, α 1 and β 1 .
Consequently for the median ( s = α 8 − β 8 ln(ln(2)) , P 8 ( s ) = 0 . 5 ), we have:
[Equation]
And since P 8 is Gumbel, we also have an equation for the mode ( s = α 8 , P 8 ( s ) =
e − 1 ):
[Equation]
We solve these two non-linear equations simultaneously using the standard SciPy optimization package.
[Figure]
The resulting estimated speed-up Gumbel distribution for a single device has α = 1 .
94 , β = 0 .and is shown in Figure 6 [right].
To simulate the performance of a cluster of size n with a batch size of 32 per device, we take the minimum over n samples from this distribution.
Repeating this process to generate many samples allows us to estimate the expected speed-up for any given cluster size.
Unfortunately, we cannot make any statistical inference about the processing times of individual sequences since the data is only provided at the granularity of 32 sequences per batch, and it is not clear how much of the computation is done in parallel and how much in serial.
C A BLATION STUDY
So far, we have shown that with the introduced adjustments, we can match the accuracy of unpacked
BERT.
In the following, we wanted to analyze in how far the masking adjustment is required.
In
Figure 7, we can see that without our adjustments, training loss and accuracy worsen drastically and a longer training time does not lead to a recovery.
When not adjusting the positional embedding, the loss and accuracy almost match.
However, the accuracy stalls at 71 . 8% and does not reach the target accuracy of 72 . 1% .
So overall, both adjustments are crucial
[Figure]
D T ECHNICAL BACKGROUND ON PACKING D. C ANONICAL PACKING PROBLEM
The bin-packing problem deals with the assignment of items into bins of a ﬁxed capacity such that the number of utilized bins is minimized.
In the canonical formulation of the packing problem a vector s ( i ) of length n is used to represent the items being packed, where s ( i ) denotes the length of the i-th sequence/item.
The allocation of items into bins is tracked through the assignment matrix B , where B ij ∈ { 0 , 1 } states whether the i-th sequence should be placed into the j-th bin.
In the worst case scenario, every item is assigned to its own bin, thus B ∈ R n × n .
Notably, s grows linearly in the number of sequences/items being packed and B grows with the square.
To mask out unused bins y j ∈ { 0 , 1 } , denotes whether the j-th bin is being used.
The optimization objective is to minimize the sum of y j while making sure to assign each s i to exactly one bin and not exceeding the maximum bin capacity s m for each bin.
This problem formulation is well known as bin-packing (Korte &
Vygen, 2012).
[Equation]
Minimize the number of bins.
[Equation]
Assign each length/sequence to only one bin.
[Equation]
Cumulative length cannot exceed capacity.
Bin-packing is a strongly NP-complete (Korte & Vygen, 2012) problem.
Producing an exact and optimal solution is possible with a variety of existing algorithms, for example with the branch-andcut-and-price algorithm (Belov & Scheithauer, 2006).
However, given that we want to apply it for very large n (16M for the Wikipedia dataset) an approximate approach is required.
D. A PPROXIMATE BIN - PACKING PROBLEM
Approximate packing approaches are divided into online and ofﬂine algorithms (Johnson, 1973).
Online algorithms process incoming sequences one-by-one in a streaming fashion, whereas ofﬂine algorithms have a holistic view of all samples to be packed but typically still operate on a per sample basis.
This results in best case time and memory complexities of at least O ( n log( n )) and solutions that can sometimes be far from optimal, especially for the online algorithms which do not have access to a holistic view of the datasets.
The simplest online approach (next-ﬁt) would be to keep a single open bin at any given time.
An incoming sequence is added to this open bin if it ﬁts, otherwise the bin is closed (can never be appended to again) and a new one is opened to accommodate the new sequence (Johnson, 1973).
In the case of the Wikipedia pre-training dataset almost 25% of the sequences are of length 512 , which makes this approach very inefﬁcient since bins would frequently be closed because the incoming sequence did not ﬁt.
More speciﬁcally, this approach is not able to efﬁciently combine one long sequence with one shorter sequence, when the number of long sequences is large.
The algorithms that come closest to the approaches proposed in this paper are the online harmonic-k algorithm (Lee & Lee, 1985), which creates harmonic sized bins for the assignment decision, and the ofﬂine Modiﬁed First Fit Decreasing method (Johnson &
Garey, 1985; Yue & Zhang, 1995), which sorts the data, groups it into 4 size categories and deﬁnes a strategy adjusted to these sizes.
In our approaches, we make three major simpliﬁcations.
We make the problem of bin packing less dependent on n by operating on the histogram of sequence lengths with bin size 1.
Hence, we replace s ( i ) by its histogram b and the bin assignment y, B by a mixture of strategies x , where the set of all available packing strategies is modeled as the matrix A (see also Section D.4.2).
Then, we do not solve the full packing problem but focus on a ﬁxed packing depth (in other words the well known 3-partition problem).
Last but not least, we solve the limited depth packing problem only approximately either with a non-negativity-constrained linear least squares (Bro & De Jong,
1997) (NNLS) followed by rounding to nearest integer solution or by applying Worst-Fit (Johnson & Garey, 1985; Yue & Zhang, 1995) to the histogram, sorted from largest to smallest (in contrast to using an unsorted dataset).
An exact solution would not be appropriate, since the 3-partition problem is strongly NP-complete (Garey & Johnson, 1990) as well.
D. D EFINITIONS
In this section, we standardize the terms used throughout our methods.
Firstly, the terms pack and bin may be used interchangeably.
Secondly, the presented packing schemes impose a limit on how many sequences can be packed into any given bin.
This limit is referred to as the maximum packing depth .
For simplicity, we require the different sequence lengths in a pack to always add up exactly to the bin capacity
s m (we can always generate a padding sequence of just the right length to ﬁll-up the bin).
A packing strategy is a sorted list of sequence lengths, for example [5 , 7 , 500] , such that the total sequence length is no more than s m and the number of sequences in the pack does not exceed the maximum packing depth .
The output of a packing scheme is typically as set of packing strategies and the corresponding repeat count for each strategy stating how many times each strategy should be repeated in order to cover the entire dataset.
The strategy repeat count is also referred to as the mixture of strategies.
The objective of the packing algorithm is to jointly design a set of packing strategies and their repeat counts, such that the amount of padding is (approximately) minimized.
The presence of padding in the packs can either be implicit or explicit.
For instance for s m =
the strategy [2, 508] has an implicit padding of 2 (needed to ﬁll the pack up to the s m ).
Alternatively, the strategy repeat count may over-subscribe a particular sequence length leading to explicit packing.
For instance constructing a pack of [4, 508] may require a new padding sequence of length 4 be constructed, if there are not enough sequences of that length in the dataset.
The packing algorithms, we present, use both representations.
D. N ON - NEGATIVE LEAST SQUARES HISTOGRAM - PACKING
The ﬁrst algorithm proposed in this paper is suitable for settings where it is desirable to achieve a high packing efﬁciency with a limited packing depth.
The algorithm is deterministic and has three major components described in Sections
D.4.1, D.4.2 and D.4.3.
D.4. E NUMERATING PACKING STRATEGIES OF FIXED PACKING DEPTH
Listing all unique ways of packing up to a maximum packing depth can be achieved through dynamic programming.
We only consider packing at most up to 3 sequences per pack.
This is the smallest packing depth that can eliminate the need for most padding on the Wikipedia dataset.
Increasing the depth to 4 , increases the size of the packing problem drastically and yields no throughput beneﬁt 2 .
With only two sequences, packing would be not as efﬁcient since the distribution on sequence length is not symmetric.
We use dynamic programming to enumerate all feasible ways/strategies that up to M sequences of length 1 − 512 can be packed into a bin of length 512 .
For example, a packing strategy may be [512] or [6 , 506] or [95 , 184 , 233] .
To avoid listing the same strategy multiple times, we enforce the sequence lengths within a pack to occur in sorted order, for example, [95 , 184 , 233] is equivalent to [184 , 95 , 233] and should only be listed once.
This reduces the search space as well as the space of potential solutions by a factor of 6 approximately and thus signiﬁcantly accelerates the optimization process.
If you had the same strategy repeated 6 times instead of having just one instance of that strategy with weight X , you will have six instances with weight x/ 6 (for example, or any other distribution).
This would conﬂict with integer rounding of the solutions and with convergence of optimization algorithms.
D.4. C ONSTRUCTING THE PACKING MATRIX
The number of rows in the packing matrix is equal to the number of different sequence length categories.
For instance, if we are using a granularity of 1 token to distinguish between different sequence lengths, then there are “maximum sequence length” rows.
Each column of the matrix corresponds to a valid packing strategy (given the depth of packing).
An example packing matrix for ﬁtting up to 3 sequences into sequence length 8 is given in represents a packing strategy.
For instance, the ﬁrst column represents the strategy [1, 1, 6] of packing two length-1 sequences and one length-6 sequence together to form a pack of length 8.
The number of strategies (and columns in the matrix) is discussed in Section E.
For a packing depth of 3 and maximum sequence length, we obtain around s 2 m +6 s m +12strategies.
For depth 4, around s
[Table]
more get added.
[Table]
D.4. S OLUTION OF THE NNLS APPROXIMATE PACKING PROBLEM
A solution of the packing problem is the mixture of packing strategies x that minimizes the amount of padding in the packed dataset.
We solve directly for the mixture (positive real numbers) and recover the padding as the negative portion of the residual (see Section D.4.4).
min x ∈ R m (cid:107) A ·
[Equation]
− b (cid:107)s.t.
[Equation]
The solution vector x will represent the mixture of the columns of A , in other words the mixture of valid packing strategies such that A · x is as close as possible (in the least squares sense) to the histogram of sequence lengths b .
We obtain a solution with a non-negative least squares implementation (Lawson & Hanson, 1995; Virtanen et al., 2020)
Interestingly in the case of sequence length 512 only 634 out of the 22102 available packing strategies of depth up to 3 are used ( 3% ).
D.4. P ADDING AS THE RESIDUALS OF THE PACKING PROBLEM
We compute the residuals of the least squares solution (after rounding the mixture to integer) as:
[Equation]
The negative portion of the residuals represents sequences that we are “short”.
That is, there is a deﬁcit of those sequences and we are over-subscribing to them.
The positive portion of the residuals represents sequences which have failed to be packed.
Typically, there is a deﬁcit of short sequences and a surplus of long sequences as demonstrated by the following plot.
In total, there are n = 16‘279‘552 sequences in the Wikipedia pre-training dataset.
After the non-negative least squares packing (and rounding to integer solution) there are 56‘799 unpacked sequences left un-packed (about 0 .
The residual on sequence lengths 1 to 8 are [ − 4620 , − 4553 , − 4612 , − 4614 , − 3723 , − 3936 , − 3628 , − 3970] .
These negative residuals imply that we need to add this many sequences of their corresponding sequence length to realize the mixture of packing strategies.
In total the ﬁrst iteration introduces 7 . 9410 6 tokens of padding.
In contrast large sequence lengths have a positive residual (a surplus of unused sequences).
For sequence lengths 504 to 512 the values are [3628 , 3936 , 3724 , 4613 , 4612 , 4553 , 4619 , 0] .
Note that sequence length 512 has a residual of 0 since they do not need packing.
Intermediate sequence lengths typically have non-zero (but much smaller) residuals.
The detailed code for the algorithm is provided in Listing 2.
D.4. R ESIDUAL WEIGHTING
A natural extension of the non-negative least squares problem introduced in Section D.4.3 is to weight the residuals on different sequence length differently.
[Figure] [Figure]
[Equation]
We should not signiﬁcantly penalize a deﬁcit in short sequence lengths (smaller than 8 tokens) as adding up to 8 tokens of padding is not much overhead.
Similarly, a surplus in long sequences is not worrisome because the amount of padding needed to achieve a sequence length of 512 is small.
Reducing the weight of the residual on the ﬁrst 8 tokens to 0 .
09 leads to the following residual plot shown on the right in Figure 9.
In this case the residual is almost entirely shifted to the shorter sequences and the positive residual on the longer sequences has virtual disappeared
[Figure]
D. D ISCUSSION OF RESIDUAL WEIGHT CHOICE
This section discusses the choice and effect of the weighting parameters in the NNLSP packing algorithm.
To simplify the problem of selecting reasonable defaults for the residual weights, we use just two parameters to completely describe the weights: an “offset” parameter and a “weight” parameter.
Originally, all sequence length residuals are given the same weight of 1 .
This results in a packing with leftover long sequences, because there are not enough short sequences to pack them with.
To reduce the residual on long sequences, we could either increase the residual weight on long sequences or reduce the weight on short sequences.
We chose to reduce the weight on short sequences.
Speciﬁcally, sequence lengths up to the “offset” length have a reduced “weight”.
The other residual weights stay at 1 .
To start, we chose an offset of 8 tokens, which is the smallest power of 2 for which there are examples in the Wikipedia dataset.
We decrease the weight on sequences shorter than the “offset” from 1 to 0 .
9 to 0 .
09 to see which order of magnitude is the most appropriate.
On visual inspection (looking at the residual plots as in Figure 9), we found that 0 .
9 still left too many long sequences unpacked.
So, we reduced the weight a further order of magnitude to 0 .
This seemed sufﬁcient to encourage nearly all long sequences to pack.
While visual inspection helps in understanding how many long/short sequences are leftover, we are also interested in the impact the weights have on the overall efﬁciency of the packing.
Without any weighting, we get 99 .
746359% efﬁciency, whereas the weighted approach results in 99 .
746274% efﬁciency.
Hence, we conclude that the impact of the weights on the packing efﬁciency is very limited.
Additionally, using an “offset” length of 4 , resulted in similar numbers, for the full range of weights from 0 to 1 .
Using a weight of 0 for an “offset” length of 8 resulted in insigniﬁcantly higher efﬁciency of 99 .
7519% , whereas using an “offset” length of 16 reduces performance to 99 .
A weight of 0 implies that the residual on those lengths can be safely ignored, i.e., the packing algorithm can thus add as many short sequences as it chooses without any penalty.
It is very interesting that this does not signiﬁcantly impact the packing efﬁciency, and can even have a slightly positive impact.
However, increasing the “offset” length further signiﬁcantly decreases the performance with weight 0 .
Keeping the weight at 0 . 09 and increasing the length reduces performance slightly, for example with 99 .
53% at length 256 and 99 .
728% at length 16 .
For our Squad analysis, weighting improved the efﬁciency slightly from 96 .
94% to 97 .
Fine tuning further with direction grid search, delivered a local optimum of 98 .
767% efﬁciency with length 64 and weight 0 .
Overall the inﬂuence of different residual weights on the packing efﬁciency (and the acceleration factor) is less than 1% .
This might differ from application to application, but it shows that we are able to use the residual weights to achieve secondary targets (like not having leftover long sequences) without signiﬁcantly compromising the packing efﬁciency.
E C OMPLEXITY ANALYSIS OF THE PROPOSED PACKING APPROACHES
Since approximate packing algorithms have a complexity of at least O ( n log( n )) and we would like to be able to tackle datasets with 2K million samples, we will discuss the complexity of our packing algorithms in this section.
The complexity depends on the maximum sequence length s m , the number of samples n , and the packing depth d .
To create the histogram, we have to iterate over the data once ( O ( n ) ).
Our histograms will be binned by size 1 , meaning one bin for each sequence length.
Hence, a dictionary can be generated ( O ( s m ) ) and used for the sorting ( O (1) ).
The respective histogram vector has dimension s m .
E. A NALYSIS OF NON - NEGATIVE LEAST - SQUARES HISTOGRAM - PACKING
For a packing depth of one, there is only the strategy [ s m ] .
For a packing depth of two, we add the strategies [1 , s m − 1] , ..., [ s m − (cid:98) s m 2 (cid:99) ] which results in an additional (cid:98) s m 2 (cid:99) potential strategies.
Following the dynamic programming approach, the number of possible additional strategies of depth three can be calculated with
[Equation]
Note that for s m =
the approximation is exact.
This means that our strategy matrix A has the dimensions s m × (cid:16)(cid:104) s 2 m 12 (cid:105) + (cid:98) s m 2 (cid:99) + 1 (cid:17) .
Overall, this leaves us with a space complexity of s 3 m since
A is larger than w , x , and b .
So it contains 11‘316‘224 numbers which is still much smaller than n .
Note that the original data matrix B had n 2 entries, which all needed to be optimized together with the n bin assignments y .
We now have only (cid:104) s 2 m 12 (cid:105) + (cid:98) s m 2 (cid:99) free variables in the strategy vector x .
Also note that A can be precomputed when s m is known and is independent of the number of samples.
Given a problem matrix with dimension i × j , Luo et al.
(Luo & Duraiswami, 2011) indicate that the asymptotic complexity of most solution approaches is O ( ij 2 ) , whereas they propose an O ( ij ) solution.
Since we use the standard SciPy implementation (Lawson & Hanson, 1995), our estimated total time complexity for NNLSHP is O ( n + s 5 m ) .
For s m = 2048 , the estimate would be 350 (cid:48)
540 potential strategies which is still far less than the number of samples.
For packing depth 4 , we calculate (Wolfram Research Inc.):
[Equation]
≈
[Equation] [Equation]
=
[Equation] [Equation]
So with s m = 512 , there would be around 940 K strategies.
In our implementation, this number of strategies would be too high to create the problem matrix.
One alternatives to simplify would be to not use the exact length of sequences but to only consider even numbers for the sequence length and round up.
That way arbitrary sequence length could also be handled and the limiting factor would be the complexity of the attention layer in BERT which does not scale well with the sequence length.
E. A NALYSIS OF SHORTEST - PACK - FIRST HISTOGRAM - PACKING
The complexity calculation of SPFHP is straightforward.
We go over the whole data once for the histogram sorting.
Next, we iterate over each of the s m bins in the histogram.
Lastly, we iterate over all strategies that were encountered so far.
It can be proven that, at each iteration, the number of strategies can be maximally increased by one.
In each step, we potentially add a sequence to existing strategies but a new strategy is opened up only in the ﬁnal step, when we either create a new strategy or we split one of the existing strategies into two.
Hence, the number of strategies is bounded by s m and the overall time complexity is bounded by O ( n + s 2 m ) .
The space complexity is
O ( s 2 m ) since we need to store up to s m strategies with maximum s m counts for different sequence length.
F P ACKING SQ U AD 1.
We tokenized SQuAD (Rajpurkar et al., 2016) for BERT (Devlin et al., 2019a) with maximum sequence length 384 and visualized the histogram over the sequence length (Figure 10).
The distribution looks similar to the Wikipedia dataset but is slightly less skewed.
However, the maximum sequence length only had an occurrence of 1 . 2% compared to 23 .
Hence, the theoretical unpadding speedup is 2 . 232 .
In Table 3, we can see that SPFHP does not concatenate more thansamples and obtains 97 .
54% efﬁciency in contrast to a maximally used depth of 16 with 99 .
60% efﬁciency on Wikipedia, because of the less skewed distribution.
Note that we have less than 90 (cid:48)samples.
Hence, NNLSHP is less efﬁcient because the rounding in the residuals has a much larger impact compared to more than 16 million sequences in the Wikipedia dataset.
[Figure]
[Table]
factor
[Table]
[Table] [Table]
[Table] [Table]
3/max
SPFHP    97.
G P ACKING GLUE
To explore a variety of datasets and emphasize that skewed distributions are common, we explored all datasets in the GLUE benchmark (Warstadt et al., 2018;
Wang et al., 2018) that came with training data.
We loaded the datasets using the HuggingFace dataset loading API (Wolf et al., 2020).
For preprocessing, we followed the implementation in the HuggingFace transformers repository (Wolf et al., 2020) 3 and extracted the respective data processing snippets to obtain tokenized data with a maximum sequence length of 128 .
The histogram of the sequence length for each of the included datasets is displayed in Figure 11 and the packing results are given in Table 4.
Each dataset beneﬁts from packing.
The lower the mean, the higher the packing factors are that can be reached but with a higher packing depth.
[Figure]
[Table] [Table]
[Table] [Table]
[Table]
mrpc     41.
mrpc 4/max    95.
qqp     23.
qqp 5/max    89.
stsb     21.
stsb 6/max    91.
mnli     31.
mnli 8/max    98.
rte     52.
rte 4/max    97.
wnli     28. wnli 6/max    95.
text-classification
H F URTHER LEARNING CURVES
This section provides further learning curves related to Section 4.2.
[Figure] [Figure]
[Figure]
I F INE - TUNED LONGEST - PACK - FIRST HISTOGRAM - PACKING
In the main paper
[Table]
we focused on SPFHP due its simplicity.
In this section
[Table]
we analyse the effect of applying the “Best-Fit” algorithm (Johnson, 1973).
Here, the longest pack that still ﬁts the sequence is chosen instead of the shortest one.
In contrast to SPFHP, we additionally consider splitting the histogram count, if it can ﬁt multiple times.
A simple example is sequence length 256 , where we divide the respective histogram count by 2 to create the optimal pack with strategy [256 , 256] instead of the strategy [256] .
This latter strategy would be complemented by other sequences but would probably not result in an optimal packing.
The implementation of this approach is much more complex than the SPFHP implementation.
The code is provided in Listing 8 and the results in
Table 5.
pack.
[Table]
We can see that longest-pack-ﬁrst histogram-packing (LPFHP) uses a much higher packing depth when no limit is set ( 29 instead of 16 ).
Splitting the histogram counts results in slightly higher numbers of used strategies compared to SPFHP where the number of used strategies is limited by the maximum sequence length.
The best efﬁciency of LPFHP is 99 .
949% with packing factor ofwhich is slightly higher than the 99 .
75% ( 1 . 996 packing factor) for NNLSHP and 99 .
6% for SPFHP ( 1 . 993 packing factor).
All algorithms are very close to the upper limit.
Note that for NNLSHP, we only ﬁll up the unpacked samples with padding.
Applying best-ﬁt on the remains, similar results can be expected.
Although the beneﬁts of the improved algorithm are negligible, we share the concept and code below in case packing is applied to other data with a different distribution that would beneﬁt more from it, or for applications where only perfectly packed sequences without padding are of interest.
J E XTENDED NNLS WITH PADDING TOKEN WEIGHTING
In Section D.4.4, we deﬁned the residual as
[Equation]
and discovered that a positive residual corresponds to sequences that we did not pack at all and should be avoided.
Negative residuals correspond to padding and should be minimized.
Due to this discrepancy, we decided to set small weights for very short sequences (that don’t occur in the data).
However, it was not possible to directly optimize the amount of padding.
A negative residual component for length i , r i , results in | r i | · i padding tokens, however a positive residual actually results into (512 − r i ) · i padding tokens.
This cannot be addressed by our weighting approach in
[Equation]
Working within the NNLS approach, we can strictly enforce a non-positive residual r (before rounding to integer).
To that end, we deﬁne a new auxiliary variable r ≈ − ( b − Ax ) which is the negative of the residual, r .
This will allow us to reformulate the objective r ≤ 0 to the non-negative constraint: r ≥ 0 .
[Equation]
This will enforce r =
Ax − b ≥ 0 due to the large weight, w := 10 6 , and no upper limits on r .
Now, we can set w i := i to optimize for the padding tokens.
Due to the use of the squared error, we would however optimize the squared sum of padding tokens instead of the preferred sum of padding tokens.
To accomplish the latter, we would have to replace the L2-norm problem by an L1-norm problem which would be too complex to solve.
Note that due to rounding, the unwanted positive residuals r ( r < 0 ) might still occur.
This could be avoided by rounding up x instead of normal rounding of x .
To put the new formulation into a solver, we replace b by
[Equation]
where 0 m is an m × m matrix with m being the maximum sequence length, 512 , and D m is a unit matrix of the same dimensions as 0 m .
Since, we are already close to optimum especially on the
Wikipedia dataset, the results are only a little bit better.
The processing time however increases from 30 to 415 seconds without considering the increased time for constructing the processing matrix.
Since the slightly improved algorithm might be nevertheless relevant for other applications, we share it in Listing 9.
K P ACKING SOURCE CODE
Listing 2: Non-negative least squares histogram-packing
[Figure]
minimum
[Figure]
increment
[Figure]
[Figure] [Figure]
[Figure] [Figure]
[Figure] [Figure]
[Figure] [Figure]
[Figure] [Figure]
[Figure] [Figure]
[Figure]
w0[
[Figure]
# Solve the packing
[Figure]
print(f"Sequences to
[Table]
: ", histogram.sum())start
[Table] [Table]
)strategy
[Table] [Table]
print
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
for
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Figure] [Figure]
[Figure] [Figure]
[Figure] [Figure]
length
[Figure]
print(f"
[Figure]
efficiency (fraction of real tokens): {efficiency:3.4f}\n",
[Figure]
f"
[Figure] [Figure]
limit: {speedup
[Figure]
_bound:3.4f}\n",
[Figure]
f"Achieved speed-up over un-packed dataset: {old_number_of_samples/new_number_of_samples:3.5f}")return strategy_set, strategy_repeat_count [Figure] [Figure] [Table]
[Figure] [Table] [Figure] [Table]
[Figure] [Table] [Figure] [Table]
[Figure]
[Table] [Figure] [Table] [Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table] [Figure] [Table] [Figure]
[Table] [Figure] [Table] [Figure]
[Table] [Figure] [Table] [Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
_sequences_to_pack, n_sequences_to_bin)if n_sequences_to_pack > n_sequences_to_bin:# old pack gets reducedn_sequences_to_pack -= n_sequences_to_bintmp_strategies_per_length[length_to_bin + offset].append((n_sequences_to_pack, pack))n_sequences_to_bin = 0else:n_sequences_to_bin -= n_sequences_to_packadd_pack(new_pack, count,tmp_strategies_per_length, strategies_per_length,max_sequences_per_pack, offset)# clean up to speed up main key searchif not tmp_strategies_per_length[length_to_bin + offset]:tmp_strategies_per_length.pop(length_to_bin + offset)else:offset -=
# Does not fit anywhere.
Create new pack.if offset < 0:add_pack([length_to_bin], n_sequences_to_bin,tmp_strategies_per_length, strategies_per_length,max_sequences_per_pack, i)n_sequences_to_bin =
# merge all strategiesfor key in tmp_strategies_per_length:strategies_per_length[key].extend(tmp_strategies_per_length[key])
# flatten strategies dictionarystrategy_set =
[]strategy_repeat_count =
[]for key in strategies_per_length:for count, pack in strategies_per_length[key]:pack.reverse()strategy_set.append(pack)strategy_repeat_count.append(count)return strategy_set, np.array(strategy_repeat_count) [Figure] [Figure] [Table]
[Figure]
[Table] [Figure] [Table] [Figure]
[Table]
Listing : Loss calculation
[Table]
1 # Copyright (c)
Graphcore Ltd.
All rights reserved.
2 """Wikipedia and SQUaD 1.1 histograms."
"" 3 import numpy as np 4 wikipedia_histogram = np.array([0, 0, 0, 0, 1821, 1226, 1969, 1315, 1794, 1953, 3082, 3446, 4166, 5062,9554, 16475, 19173, 17589, 17957, 19060, 21555, 23524, 26954, 30661, 33470, 36614, 40134, 43256,46094, 49350, 52153, 55428, 58109, 60624, 63263, 64527, 65421, 66983, 68123, 68830, 70230, 70486,72467, 72954, 73955, 74311, 74836, 74489, 74990, 75377, 74954, 75096, 74784, 74698, 74337, 74638,74370, 73537, 73597, 73153, 72358, 71580, 71082, 70085, 69733, 69445, 67818, 67177, 66641, 65709,64698, 63841, 63218, 62799, 61458, 60848, 60148, 59858, 58809, 58023, 56920, 55999, 55245, 55051,53979, 53689, 52819, 52162, 51752, 51172, 50469, 49907, 49201, 49060, 47948, 47724, 46990, 46544,46011, 45269, 44792, 44332, 43878, 43984, 42968, 42365, 42391, 42219, 41668, 41072, 40616, 40587,39999, 40169, 39340, 38906, 38438, 38142, 37757, 37818, 37535, 37217, 36757, 36589, 36151, 35953,35531, 35496, 35089, 35053, 34567, 34789, 34009, 33952, 33753, 33656, 33227, 32954, 32686, 32880,32709, 31886, 32126, 31657, 31466, 31142, 31106, 30650, 30316, 30494, 30328, 30157, 29611, 29754,29445, 28921, 29271, 29078, 28934, 28764, 28445, 28319, 28141, 28282, 27779, 27522, 27333, 27470,27289, 27102, 27018, 27066, 26925, 26384, 26188, 26385, 26392, 26082, 26062, 25660, 25682, 25547,25425, 25072, 25079, 25346, 24659, 24702, 24862, 24479, 24288, 24127, 24268, 24097, 23798, 23878,23893, 23817, 23398, 23382, 23280, 22993, 23018, 23242, 22987, 22894, 22470, 22612, 22452, 21996,21843, 22094, 21916, 21756, 21955, 21444, 21436, 21484, 21528, 21597, 21301, 21197, 21281, 21066,20933, 21023, 20888, 20575, 20574, 20511, 20419, 20312, 20174, 20023, 20087, 19955, 19946, 19846,19562, 19710, 19556, 19477, 19487, 19387, 19225, 19069, 19360, 18655, 19034, 18763, 18800, 19012,18893, 18714, 18645, 18577, 18317, 18458, 18374, 18152, 17822, 18102, 17735, 17940, 17805, 17711,17690, 17703, 17669, 17410, 17583, 17331, 17313, 16892, 16967, 16870, 16926, 17233, 16845, 16861,16576, 16685, 16455, 16687, 16747, 16524, 16473, 16349, 16273, 16255, 16228, 16219, 16021, 16111,15867, 15751, 16081, 15703, 15751, 15854, 15665, 15469, 15431, 15428, 15464, 15517, 15335, 15461,15237, 15292, 15305, 15351, 15078, 14810, 15119, 14780, 14664, 14869, 14722, 14890, 14672, 14439,14685, 14706, 14840, 14373, 14286, 14596, 14615, 14168, 14299, 13987, 14167, 14107, 14096, 14202,13985, 14118, 14094, 14127, 13896, 13864, 13597, 13572, 13717, 13669, 13782, 13617, 13284, 13333,13425, 13457, 13256, 13404, 13318, 13425, 13317, 13179, 13193, 13257, 13160, 12813, 13149, 13010,12867, 12958, 12818, 12801, 12749, 12810, 12575, 12673, 12514, 12735, 12523, 12677, 12298, 12469,12341, 12445, 12477, 12326, 12110, 12087, 12305, 12156, 12032, 12190, 12150, 11980, 12022, 11825,11969, 11831, 11997, 11924, 11739, 11685, 11702, 11783, 11783, [Table] [Table] [Table]
[Table]
[Table]
[Table] [Table] [Table] [Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table] [Table] [Table] [Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table] [Table] [Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
[Table]
dtype=np.int64) 6465 squad_1)1_max_sequence_length =
1 # Copyright (c)
Graphcore Ltd.
All rights reserved.
2 # Copyright 2020 The HuggingFace Inc. team.
All rights reserved.
3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing,
[Figure]
[Table]
distributed under the License is distributed on
[Figure]
"AS IS" BASIS,
[Figure]
OR CONDITIONS OF ANY KIND, either express or implied.
[Table]
See the License for the specific language governing permissions and
[Figure]
[Table]
[Figure]
the License.
[Figure]
and histogram
[Figure] [Figure]
[Table]
[Figure]
[Table]
[Figure]
glue.
[Figure]
[Table] [Table]
] 39 # unused
[Table]
due to missing training data 40 unglue_keys =
[’mnli
[Table]
matched’, ’mnli
[Table]
mismatched’, ’qnli’, ’ax’] 4142 # load data 43 dataset
[Table]
loads = {} 44 for key in glue_keys:dataset
[Table]
loads[key] = datasets.load
[Table]
"glue"
[Table]
key
[Table]
split
[Table]
[Table] [Table]
.from
[Table] [Table]
[Table]
50 for key in
[Table] [Table]
to
[Table]
[key] def preprocess_function(examples):
[Table]
args
[Table] [Table]
[Table] [Table]
[Table] [Table]
[Table] [Table]
return result
[Table] [Table]
66 for key
[Table] [Table]
68 for
[Table] [Table]
for
[Table] [Table]
[Table] [Table]
for
[Table] [Table]
[Table]
create
[Table]
for
[Table] [Table]
74 for
[Table]
:glue
[Table]
[Table] [Table]
[Table] [Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
possible offset for perfect fitif (length_to_bin + offset) in tmp_strategies_per_length:# extract worst pack that will get modifiedn_sequences_to_pack, pack = tmp_strategies_per_length[length_to_bin + offset].pop()# calculate how often the current sequence maximally fits inrepeat = min(
+ offset // length_to_bin, max_sequences_per_pack-len(pack))
# correct dependent on countwhile n_sequences_to_bin//repeat ==
:repeat -= 1if not distribute:repeat = 1new_pack =
pack + [length_to_bin]*repeatcount = min(n_sequences_to_pack, n_sequences_to_bin//repeat)if n_sequences_to_pack > count:# old pack gets reducedn_sequences_to_pack -= counttmp_strategies_per_length[length_to_bin + offset].append((n_sequences_to_pack, pack))n_sequences_to_bin -= count * repeatelse:n_sequences_to_bin -= n_sequences_to_pack * repeatadd_pack(new_pack, count,tmp_strategies_per_length, strategies_per_length,max_sequences_per_pack, offset -(repeat-1)*length_to_bin,max_sequence_length)# clean up to speed up main key searchif not tmp_strategies_per_length[length_to_bin + offset]:tmp_strategies_per_length.pop(length_to_bin + offset)
# reset offset in case best fit changedoffset
= 0else:offset +=
Does not fit anywhere.
Create new pack.if offset >= max_sequence_length - length_to_bin + 1:# similar repetition but no dependence on pack.repeat =
min(max_sequence_length//length_to_bin, max_sequences_
[Figure] [Figure]
while n_
[Figure]
_to_
[Figure]
[Figure] [Figure]
if not
[Figure] [Figure]
add_
[Figure]
[Figure] [Figure]
_bin]
[Figure]
n_sequences_to_bin//
[Figure]
tmp_strategies_per_length
[Figure]
_per_
[Figure]
[Figure] [Figure]
[Figure] [Figure]
max_
[Figure]
_length
[Figure]
length_to_bin*
[Figure]
max_
[Figure] [Figure]
n_
[Figure] [Figure]
[Figure] [Figure]
[Figure]
key
[Figure] [Figure]
[Figure] [Figure]
for
[Figure] [Figure]
[Figure] [Figure]
[Table]
[Figure] [Figure]
np
[Figure] [Figure]
Listing 9: Extended non-negative least squares histogram-packing 1 # Copyright (c)
Graphcore Ltd.
All rights reserved.
2 """Extended Non-Negative least squares histogram-packing algorithm."
"" 3 import time 4 import numpy as np 5 from scipy import optimize, stats 6 from functools import lru_cache 78 def get_packing_matrix(strategy_set, max_sequence_length):num_strategies = len(strategy_set)
A = np.zeros((max_sequence_length, num_strategies), dtype=
np.int32)for i, strategy in enumerate(strategy_set):for seq_len in strategy:
A[seq_len - 1, i] += 1return
A 1516 @lru_cache(maxsize=
None) 17 def get_packing_strategies(start_length, minimum_increment, target_length, depth):gap = target_length - start_lengthstrategies = []# Complete the packing with exactly 1 numberif depth =
= 1:if gap >= minimum_increment:strategies.append([gap])
# Complete the sample in "depth" steps, recursivelyelse:for new in range(minimum_increment, gap + 1):new_gap = target_length - start_length - newif new_gap =
= 0:strategies.append([new])else:options = get_packing_strategies(start_length + new, new, target_length, depth - 1)for option in options:if len(option) > 0:strategies.append([new] + option)return strategies 3637 def
[Table]
using_
[Table] [Table]
[Table] [Table]
sequences
[Table] [Table]
strategy
[Table] [Table]
[Figure] [Figure]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure] [Figure]
[Figure]
[Table]
[Figure] [Figure]
[Figure] [Figure]
[Figure]
[Table]
[Figure]
[Table]
[Figure] [Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure] [Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure] [Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure] [Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table]
[Figure]
[Table] [Table]
[Figure]
[Table] [Table]
[Figure]
[Table] [Table]
4f
\n"
[Table] [Table]