{
  "id": 230498,
  "title": "Tips for Transformer inference",
  "url": "/competitions/bms-molecular-translation/discussion/230498",
  "author_name": "Jungwoo Park",
  "post_date": "2021-04-04T05:36:26.005000",
  "votes": 59,
  "comment_count": 9,
  "views": 0,
  "content": "<p>I've seen that many people who are trying to use Transformer as a generator have some problems with inference (generating sequences to be exact). Some people spent about 10 to 20 hours for inferencing, and according to <a href=\"https://www.kaggle.com/c/bms-molecular-translation/discussion/230170\" target=\"_blank\">the discussion</a>, <a href=\"https://www.kaggle.com/zzz0534\" target=\"_blank\">@zzz0534</a> said that 3-layer model even took about 30 hours!</p>\n<p>The small version of my model (consists of 4 layers) spent 1.5 hours to generate InChI strings. How does it possible? Well… Conversely, how can it be so slow? Here are some tips to improve the inference time.</p>\n<ul>\n<li><p>Cache the attention key-value pairs and encoder outputs<br>\nWhen generating sequences, you may feed tokens by selecting from the calculated next-token distributions through various decoding strategies (e.g. greedy, beam-search, top-k, top-p, etc.). The important thing is that the distribution of next-token can only be changed by current token (because the previous tokens are already chosen and the attention vectors of them are always same at every timesteps). Let's see the below figure.<br>\n<img src=\"https://i.ibb.co/p3dkjvv/a.png\" alt=\"attention without caching\"><br>\nLet <strong>N</strong> be a length of current predicted sequence, then as you can see, the computational cost of attention layer is <strong>O(N^2)</strong>. Since the previous tokens have same key-value vectors at every timesteps, we can determine that the above attention is really inefficient.<br>\n<img src=\"https://i.ibb.co/ZKZsstk/b.png\" alt=\"attention with caching\"><br>\nHowever, when we cache the previously-calculated key-value pairs and reuse them to only the current query vector, we can reduce the complexity to <strong>O(N)</strong>. Many transformer-related libraries support caching attention. <strong>huggingface transformers</strong>, representatively, use <a href=\"https://huggingface.co/transformers/v2.6.0/quickstart.html#using-the-past\" target=\"_blank\">past</a> to reuse the attention vectors in sentence generation.<br>\nOf course, it can be applied to the encoder-decoder attention as well. Once you get encoder outputs, do not recalculate and just caching them. It also can improve the inference time.</p></li>\n<li><p>Use <strong>torchscript</strong>, if you are using PyTorch<br>\n<code>torch.jit.script</code> provides significant performance improvement. Using this function, your model will be compiled to <strong>torchscript</strong>. Typically, the <strong>torchscript</strong>-compiled models are much faster than the models which are performed through Python. That's because one of the features of <strong>torchscript</strong> is to reduce the bottleneck (or latency) between the operations. All you have to do is just to wrap your model with <code>torch.jit.script</code>.</p></li>\n</ul>\n<pre><code>model = torch.jit.script(model)\nmodel(...)\n</code></pre>\n<p>In my case, it is <strong>1.5x</strong> faster than the native one. Of course the most important thing is attention caching, but you can also apply this trick to reduce inferencing time more.</p>",
  "messages": [
    {
      "id": 1262312,
      "postDate": "2021-04-04T05:36:26.007Z",
      "content": "<p>I've seen that many people who are trying to use Transformer as a generator have some problems with inference (generating sequences to be exact). Some people spent about 10 to 20 hours for inferencing, and according to <a href=\"https://www.kaggle.com/c/bms-molecular-translation/discussion/230170\" target=\"_blank\">the discussion</a>, <a href=\"https://www.kaggle.com/zzz0534\" target=\"_blank\">@zzz0534</a> said that 3-layer model even took about 30 hours!</p>\n<p>The small version of my model (consists of 4 layers) spent 1.5 hours to generate InChI strings. How does it possible? Well… Conversely, how can it be so slow? Here are some tips to improve the inference time.</p>\n<ul>\n<li><p>Cache the attention key-value pairs and encoder outputs<br>\nWhen generating sequences, you may feed tokens by selecting from the calculated next-token distributions through various decoding strategies (e.g. greedy, beam-search, top-k, top-p, etc.). The important thing is that the distribution of next-token can only be changed by current token (because the previous tokens are already chosen and the attention vectors of them are always same at every timesteps). Let's see the below figure.<br>\n<img src=\"https://i.ibb.co/p3dkjvv/a.png\" alt=\"attention without caching\"><br>\nLet <strong>N</strong> be a length of current predicted sequence, then as you can see, the computational cost of attention layer is <strong>O(N^2)</strong>. Since the previous tokens have same key-value vectors at every timesteps, we can determine that the above attention is really inefficient.<br>\n<img src=\"https://i.ibb.co/ZKZsstk/b.png\" alt=\"attention with caching\"><br>\nHowever, when we cache the previously-calculated key-value pairs and reuse them to only the current query vector, we can reduce the complexity to <strong>O(N)</strong>. Many transformer-related libraries support caching attention. <strong>huggingface transformers</strong>, representatively, use <a href=\"https://huggingface.co/transformers/v2.6.0/quickstart.html#using-the-past\" target=\"_blank\">past</a> to reuse the attention vectors in sentence generation.<br>\nOf course, it can be applied to the encoder-decoder attention as well. Once you get encoder outputs, do not recalculate and just caching them. It also can improve the inference time.</p></li>\n<li><p>Use <strong>torchscript</strong>, if you are using PyTorch<br>\n<code>torch.jit.script</code> provides significant performance improvement. Using this function, your model will be compiled to <strong>torchscript</strong>. Typically, the <strong>torchscript</strong>-compiled models are much faster than the models which are performed through Python. That's because one of the features of <strong>torchscript</strong> is to reduce the bottleneck (or latency) between the operations. All you have to do is just to wrap your model with <code>torch.jit.script</code>.</p></li>\n</ul>\n<pre><code>model = torch.jit.script(model)\nmodel(...)\n</code></pre>\n<p>In my case, it is <strong>1.5x</strong> faster than the native one. Of course the most important thing is attention caching, but you can also apply this trick to reduce inferencing time more.</p>",
      "rawMarkdown": "I've seen that many people who are trying to use Transformer as a generator have some problems with inference (generating sequences to be exact). Some people spent about 10 to 20 hours for inferencing, and according to [the discussion](https://www.kaggle.com/c/bms-molecular-translation/discussion/230170), @zzz0534 said that 3-layer model even took about 30 hours!\n\nThe small version of my model (consists of 4 layers) spent 1.5 hours to generate InChI strings. How does it possible? Well... Conversely, how can it be so slow? Here are some tips to improve the inference time.\n\n- Cache the attention key-value pairs and encoder outputs\nWhen generating sequences, you may feed tokens by selecting from the calculated next-token distributions through various decoding strategies (e.g. greedy, beam-search, top-k, top-p, etc.). The important thing is that the distribution of next-token can only be changed by current token (because the previous tokens are already chosen and the attention vectors of them are always same at every timesteps). Let's see the below figure.\n![attention without caching](https://i.ibb.co/p3dkjvv/a.png)\nLet **N** be a length of current predicted sequence, then as you can see, the computational cost of attention layer is **O(N^2)**. Since the previous tokens have same key-value vectors at every timesteps, we can determine that the above attention is really inefficient.\n![attention with caching](https://i.ibb.co/ZKZsstk/b.png)\nHowever, when we cache the previously-calculated key-value pairs and reuse them to only the current query vector, we can reduce the complexity to **O(N)**. Many transformer-related libraries support caching attention. **huggingface transformers**, representatively, use [past](https://huggingface.co/transformers/v2.6.0/quickstart.html#using-the-past) to reuse the attention vectors in sentence generation.\nOf course, it can be applied to the encoder-decoder attention as well. Once you get encoder outputs, do not recalculate and just caching them. It also can improve the inference time.\n\n- Use **torchscript**, if you are using PyTorch\n`torch.jit.script` provides significant performance improvement. Using this function, your model will be compiled to **torchscript**. Typically, the **torchscript**-compiled models are much faster than the models which are performed through Python. That's because one of the features of **torchscript** is to reduce the bottleneck (or latency) between the operations. All you have to do is just to wrap your model with `torch.jit.script`.\n```python\nmodel = torch.jit.script(model)\nmodel(...)\n```\nIn my case, it is **1.5x** faster than the native one. Of course the most important thing is attention caching, but you can also apply this trick to reduce inferencing time more.\n",
      "votes": 59
    },
    {
      "id": 1265504,
      "postDate": "2021-04-07T00:20:17.427Z",
      "content": "<p>i wonder did anyone try this:<br>\n<a href=\"https://github.com/NVIDIA/FasterTransformer\" target=\"_blank\">https://github.com/NVIDIA/FasterTransformer</a></p>\n<p>\" Finally, we optimize many kernels of encoder, decoder and beam search to improve the speed of FasterTransformer.\"<br>\n<a href=\"https://zhuanlan.zhihu.com/p/134099981\" target=\"_blank\">https://zhuanlan.zhihu.com/p/134099981</a></p>\n<p>for integration to pytorch, refer to:<br>\n<a href=\"https://github.com/NVIDIA/FasterTransformer/tree/main/sample/pytorch\" target=\"_blank\">https://github.com/NVIDIA/FasterTransformer/tree/main/sample/pytorch</a></p>\n<p>there are other similar one: <br>\n<a href=\"https://github.com/Tencent/TurboTransformers\" target=\"_blank\">https://github.com/Tencent/TurboTransformers</a><br>\n<a href=\"https://github.com/bytedance/lightseq\" target=\"_blank\">https://github.com/bytedance/lightseq</a></p>",
      "rawMarkdown": "i wonder did anyone try this:\nhttps://github.com/NVIDIA/FasterTransformer\n\n\" Finally, we optimize many kernels of encoder, decoder and beam search to improve the speed of FasterTransformer.\"\nhttps://zhuanlan.zhihu.com/p/134099981\n\n\nfor integration to pytorch, refer to:\nhttps://github.com/NVIDIA/FasterTransformer/tree/main/sample/pytorch\n\nthere are other similar one: \nhttps://github.com/Tencent/TurboTransformers\nhttps://github.com/bytedance/lightseq",
      "votes": 1
    },
    {
      "id": 1262624,
      "postDate": "2021-04-04T14:27:19.113Z",
      "content": "<p>Thanks!!! I will try it and use bigger model!</p>",
      "rawMarkdown": "Thanks!!! I will try it and use bigger model!",
      "votes": 1
    },
    {
      "id": 1262356,
      "postDate": "2021-04-04T06:41:49.423Z",
      "content": "<p>thanks! \"torchscript\" is something that i have overlooked</p>",
      "rawMarkdown": "thanks! \"torchscript\" is something that i have overlooked",
      "votes": 1,
      "replies": [
        {
          "id": 1262532,
          "postDate": "2021-04-04T12:15:58.800Z",
          "content": "<p>one can also check this</p>\n<p><a href=\"https://scale.com/blog/pytorch-improvements\" target=\"_blank\">https://scale.com/blog/pytorch-improvements</a><br>\nMaking Pytorch Transformer Twice as Fast on Sequence Generation.</p>\n<p><a href=\"https://tunz.kr/post/4\" target=\"_blank\">https://tunz.kr/post/4</a><br>\nTransformer Details Not Described in The Paper</p>\n<p><a href=\"https://github.com/pytorch/fairseq/blob/master/fairseq/modules/multihead_attention.py\" target=\"_blank\">https://github.com/pytorch/fairseq/blob/master/fairseq/modules/multihead_attention.py</a><br>\n<a href=\"https://github.com/pytorch/fairseq/blob/master/fairseq/incremental_decoding_utils.py\" target=\"_blank\">https://github.com/pytorch/fairseq/blob/master/fairseq/incremental_decoding_utils.py</a><br>\nsee incremental state: <a href=\"https://github.com/pytorch/fairseq/issues/166#issuecomment-392259850\" target=\"_blank\">https://github.com/pytorch/fairseq/issues/166#issuecomment-392259850</a></p>",
          "rawMarkdown": "one can also check this\n\nhttps://scale.com/blog/pytorch-improvements\nMaking Pytorch Transformer Twice as Fast on Sequence Generation.\n\nhttps://tunz.kr/post/4\nTransformer Details Not Described in The Paper\n\nhttps://github.com/pytorch/fairseq/blob/master/fairseq/modules/multihead_attention.py\nhttps://github.com/pytorch/fairseq/blob/master/fairseq/incremental_decoding_utils.py\nsee incremental state: https://github.com/pytorch/fairseq/issues/166#issuecomment-392259850",
          "votes": 2
        },
        {
          "id": 1263443,
          "postDate": "2021-04-05T12:27:05.427Z",
          "content": "<p>i make fast cache-based transformer decoder code here <br>\n<a href=\"https://gist.github.com/hengck23/d3eb40d9b5bae7d08d3e12f26c84b0d7\" target=\"_blank\">https://gist.github.com/hengck23/d3eb40d9b5bae7d08d3e12f26c84b0d7</a></p>\n<p>it is based on the link above.<br>\ni have not checked the speed etc. Numerically, it seems correct</p>\n<p>refer to    run_check_fast_decode()</p>",
          "rawMarkdown": "i make fast cache-based transformer decoder code here \nhttps://gist.github.com/hengck23/d3eb40d9b5bae7d08d3e12f26c84b0d7\n\nit is based on the link above.\ni have not checked the speed etc. Numerically, it seems correct\n\nrefer to    run_check_fast_decode()",
          "votes": 1
        }
      ]
    },
    {
      "id": 1262314,
      "postDate": "2021-04-04T05:38:57.903Z",
      "content": "<p>That's a good idea! You teach me a lesson.</p>",
      "rawMarkdown": "That's a good idea! You teach me a lesson.",
      "votes": 1
    },
    {
      "id": 1262806,
      "postDate": "2021-04-04T18:26:05.553Z",
      "content": "<p>Thanks Pal !</p>",
      "rawMarkdown": "Thanks Pal !",
      "replies": [
        {
          "id": 1262981,
          "postDate": "2021-04-05T01:02:27.740Z",
          "rawMarkdown": "",
          "isDeleted": true
        }
      ]
    },
    {
      "id": 1262403,
      "postDate": "2021-04-04T08:14:11.383Z",
      "content": "<p>Thanks! It's is very helpful!</p>",
      "rawMarkdown": "Thanks! It's is very helpful!",
      "votes": 1
    }
  ],
  "comments": [
    {
      "id": 1265504,
      "author_name": "hengck23",
      "author_url": "",
      "post_date": "2021-04-07T00:20:17.427000",
      "content": "<p>i wonder did anyone try this:<br>\n<a href=\"https://github.com/NVIDIA/FasterTransformer\" target=\"_blank\">https://github.com/NVIDIA/FasterTransformer</a></p>\n<p>\" Finally, we optimize many kernels of encoder, decoder and beam search to improve the speed of FasterTransformer.\"<br>\n<a href=\"https://zhuanlan.zhihu.com/p/134099981\" target=\"_blank\">https://zhuanlan.zhihu.com/p/134099981</a></p>\n<p>for integration to pytorch, refer to:<br>\n<a href=\"https://github.com/NVIDIA/FasterTransformer/tree/main/sample/pytorch\" target=\"_blank\">https://github.com/NVIDIA/FasterTransformer/tree/main/sample/pytorch</a></p>\n<p>there are other similar one: <br>\n<a href=\"https://github.com/Tencent/TurboTransformers\" target=\"_blank\">https://github.com/Tencent/TurboTransformers</a><br>\n<a href=\"https://github.com/bytedance/lightseq\" target=\"_blank\">https://github.com/bytedance/lightseq</a></p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1262624,
      "author_name": "zzz0534",
      "author_url": "",
      "post_date": "2021-04-04T14:27:19.113000",
      "content": "<p>Thanks!!! I will try it and use bigger model!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1262356,
      "author_name": "hengck23",
      "author_url": "",
      "post_date": "2021-04-04T06:41:49.423000",
      "content": "<p>thanks! \"torchscript\" is something that i have overlooked</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1262532,
          "author_name": "hengck23",
          "author_url": "",
          "post_date": "2021-04-04T12:15:58.800000",
          "content": "<p>one can also check this</p>\n<p><a href=\"https://scale.com/blog/pytorch-improvements\" target=\"_blank\">https://scale.com/blog/pytorch-improvements</a><br>\nMaking Pytorch Transformer Twice as Fast on Sequence Generation.</p>\n<p><a href=\"https://tunz.kr/post/4\" target=\"_blank\">https://tunz.kr/post/4</a><br>\nTransformer Details Not Described in The Paper</p>\n<p><a href=\"https://github.com/pytorch/fairseq/blob/master/fairseq/modules/multihead_attention.py\" target=\"_blank\">https://github.com/pytorch/fairseq/blob/master/fairseq/modules/multihead_attention.py</a><br>\n<a href=\"https://github.com/pytorch/fairseq/blob/master/fairseq/incremental_decoding_utils.py\" target=\"_blank\">https://github.com/pytorch/fairseq/blob/master/fairseq/incremental_decoding_utils.py</a><br>\nsee incremental state: <a href=\"https://github.com/pytorch/fairseq/issues/166#issuecomment-392259850\" target=\"_blank\">https://github.com/pytorch/fairseq/issues/166#issuecomment-392259850</a></p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 1263443,
          "author_name": "hengck23",
          "author_url": "",
          "post_date": "2021-04-05T12:27:05.427000",
          "content": "<p>i make fast cache-based transformer decoder code here <br>\n<a href=\"https://gist.github.com/hengck23/d3eb40d9b5bae7d08d3e12f26c84b0d7\" target=\"_blank\">https://gist.github.com/hengck23/d3eb40d9b5bae7d08d3e12f26c84b0d7</a></p>\n<p>it is based on the link above.<br>\ni have not checked the speed etc. Numerically, it seems correct</p>\n<p>refer to    run_check_fast_decode()</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1262314,
      "author_name": "ds.wook",
      "author_url": "",
      "post_date": "2021-04-04T05:38:57.903000",
      "content": "<p>That's a good idea! You teach me a lesson.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1262806,
      "author_name": "Santosh kumar",
      "author_url": "",
      "post_date": "2021-04-04T18:26:05.553000",
      "content": "<p>Thanks Pal !</p>",
      "votes": 0,
      "replies": [
        {
          "id": 1262981,
          "author_name": "",
          "author_url": "",
          "post_date": "2021-04-05T01:02:27.740000",
          "content": "",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1262403,
      "author_name": "ee1yii",
      "author_url": "",
      "post_date": "2021-04-04T08:14:11.383000",
      "content": "<p>Thanks! It's is very helpful!</p>",
      "votes": 1,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "1262312": "I've seen that many people who are trying to use Transformer as a generator have some problems with inference (generating sequences to be exact). Some people spent about 10 to 20 hours for inferencing, and according to [the discussion](https://www.kaggle.com/c/bms-molecular-translation/discussion/230170), @zzz0534 said that 3-layer model even took about 30 hours!\n\nThe small version of my model (consists of 4 layers) spent 1.5 hours to generate InChI strings. How does it possible? Well... Conversely, how can it be so slow? Here are some tips to improve the inference time.\n\n- Cache the attention key-value pairs and encoder outputs\nWhen generating sequences, you may feed tokens by selecting from the calculated next-token distributions through various decoding strategies (e.g. greedy, beam-search, top-k, top-p, etc.). The important thing is that the distribution of next-token can only be changed by current token (because the previous tokens are already chosen and the attention vectors of them are always same at every timesteps). Let's see the below figure.\n![attention without caching](https://i.ibb.co/p3dkjvv/a.png)\nLet **N** be a length of current predicted sequence, then as you can see, the computational cost of attention layer is **O(N^2)**. Since the previous tokens have same key-value vectors at every timesteps, we can determine that the above attention is really inefficient.\n![attention with caching](https://i.ibb.co/ZKZsstk/b.png)\nHowever, when we cache the previously-calculated key-value pairs and reuse them to only the current query vector, we can reduce the complexity to **O(N)**. Many transformer-related libraries support caching attention. **huggingface transformers**, representatively, use [past](https://huggingface.co/transformers/v2.6.0/quickstart.html#using-the-past) to reuse the attention vectors in sentence generation.\nOf course, it can be applied to the encoder-decoder attention as well. Once you get encoder outputs, do not recalculate and just caching them. It also can improve the inference time.\n\n- Use **torchscript**, if you are using PyTorch\n`torch.jit.script` provides significant performance improvement. Using this function, your model will be compiled to **torchscript**. Typically, the **torchscript**-compiled models are much faster than the models which are performed through Python. That's because one of the features of **torchscript** is to reduce the bottleneck (or latency) between the operations. All you have to do is just to wrap your model with `torch.jit.script`.\n```python\nmodel = torch.jit.script(model)\nmodel(...)\n```\nIn my case, it is **1.5x** faster than the native one. Of course the most important thing is attention caching, but you can also apply this trick to reduce inferencing time more.\n",
    "1265504": "i wonder did anyone try this:\nhttps://github.com/NVIDIA/FasterTransformer\n\n\" Finally, we optimize many kernels of encoder, decoder and beam search to improve the speed of FasterTransformer.\"\nhttps://zhuanlan.zhihu.com/p/134099981\n\n\nfor integration to pytorch, refer to:\nhttps://github.com/NVIDIA/FasterTransformer/tree/main/sample/pytorch\n\nthere are other similar one: \nhttps://github.com/Tencent/TurboTransformers\nhttps://github.com/bytedance/lightseq",
    "1262624": "Thanks!!! I will try it and use bigger model!",
    "1262356": "thanks! \"torchscript\" is something that i have overlooked",
    "1262314": "That's a good idea! You teach me a lesson.",
    "1262806": "Thanks Pal !",
    "1262403": "Thanks! It's is very helpful!"
  }
}