{"article":{"slug":"use-20x-less-peak-ram-with-dp-knapsack-sliding-hirschberg-a-new-activation-memory-budget-solver-for-pytorch","title":"Use 20x less peak RAM with dp_knapsack_sliding_hirschberg, a new activation memory budget solver for PyTorch","subtitle":null,"summary":"Jędrzej Maczan explains PyTorch's activation-checkpointing memory planner as a 0/1 knapsack problem and introduces dp_knapsack_sliding_hirschberg, a sliding-window DP with Hirschberg-style reconstruction that cuts peak RAM during memory planning by about 20x.","content_type":"tutorial","language":"en","canonical_url":"https://jedrzej.maczan.pl/2025_11_21_dp_knapsack_sliding_hirschberg","author":{"name":"Jędrzej Maczan","url":"https://jedrzej.maczan.pl/","person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Jędrzej Maczan","url":"https://jedrzej.maczan.pl/","listing_slug":null,"listing":null},"topics":[{"name":"Machine Learning","slug":"machine-learning","url":"https://listedarticles.com/topics/machine-learning"},{"name":"Algorithms","slug":"algorithms","url":"https://listedarticles.com/topics/algorithms"},{"name":"Performance","slug":"performance","url":"https://listedarticles.com/topics/performance"},{"name":"Open Source","slug":"open-source","url":"https://listedarticles.com/topics/open-source"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1724,"reading_minutes":7,"published_at":"2025-11-21T00:00:00.000Z","added_at":"2026-10-18T02:12:42.073Z","updated_at":"2026-10-18T02:12:42.073Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/use-20x-less-peak-ram-with-dp-knapsack-sliding-hirschberg-a-new-activation-memory-budget-solver-for-pytorch","markdown_url":"https://listedarticles.com/articles/use-20x-less-peak-ram-with-dp-knapsack-sliding-hirschberg-a-new-activation-memory-budget-solver-for-pytorch.md","example":false,"citation":"Jędrzej Maczan, Jędrzej Maczan. \"Use 20x less peak RAM with dp_knapsack_sliding_hirschberg, a new activation memory budget solver for PyTorch.\" 21 Nov 2025. https://jedrzej.maczan.pl/2025_11_21_dp_knapsack_sliding_hirschberg (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://jedrzej.maczan.pl/2025_11_21_dp_knapsack_sliding_hirschberg"},"body_markdown":"**TL;DR:** If you use a default\ntorch.\\_functorch.config.activation\\_memory\\_budget\\_solver=dp, you can change it to dp\\_knapsack\\_sliding\\_hirschberg\nand decrease your peak RAM usage during memory planning by a factor of 20.\n\n[![](https://jedrzej.maczan.pl/knapsack.png)](https://jedrzej.maczan.pl/knapsack.png)\n\n#### What?\n\nWhen PyTorch builds a computation graph of your ML model, it tries many different things to make it fast and\nmemory efficient. One technique is to take a joint forward and backward computation graph and choose which\noperations should be saved (stored in a memory and reused) and which operations should be recomputed.\nEach operation takes some time to run and takes up some memory if stored and we only can use a limited amount\nof memory.\n\n#### 0/1 Knapsack problem\n\nImagine you are a thief and you just broke into a place with many valuable things inside. You have a knapsack\nthat can carry up to 10 kilograms. You want to maximize the value of things you steal. Ideally, you'd just take\nall of them. But if you put more than 10kg to your knaspack, it will break and you will get away with nothing.\nAlternatively, you can use some heuristics to pick the items (like take only small items or only green ones),\nbut then your solution\nmight not be optimal - you\nwill steal some\nvalue, but perhaps less than what you could gain in an optimal choice. For your rescue, there come 0/1\nknapsack solvers. There are different algorithms that compute optimal items choice within a given capacity (max\nweight of things in a knapsack) and given a list of items, where each of items has a value and a cost (weight).\nIn PyTorch, this is what we actually do, which is: within a RAM budget (knapsack capacity), we choose which\noperations (items) should be saved to\nthe memory to maximize the time savings in runtime (value).\n\n[![](https://jedrzej.maczan.pl/thief.png)](https://jedrzej.maczan.pl/thief.png)\n\n#### dp\\_knapsack\n\nCurrently, the default implementation of knapsack solver in PyTorch is dp\\_knapsack, which is a dynamic\nprogramming approach to\nsolving 0/1 knapsack. The algoritmh is actually simple once you understand it. It helps a lot if you have had a\nprior experience with dynamic\nprogramming (I do not). Look at this nice GIF from Wikipedia:\n\n![](https://jedrzej.maczan.pl/knapsack_dp.gif)\nBy [RDSEED](https://commons.wikimedia.org/w/index.php?title=User:RDSEED&action=edit&redlink=1 \"User:RDSEED (page does not exist)\") - Own work,\n[CC\nBY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0 \"Creative Commons Attribution-Share Alike 4.0\"), [Link](https://commons.wikimedia.org/w/index.php?curid=112851814)\n\nOn the left, there is a list of 4 items. i is an index, v is a value and w is a weight. Units irrelevant.\nCapacity is 6. That's why on the right side there are 6 columns (each column is a part of total capacity)\nand 4 rows (one per item). Ok, actually there are 7 and 5, because of padding with zeros, but that's only\nfor a computation convenience (every row and column has a parent, index arithmetic gets much easier). You could\nactually do it without padding, but I tried and fallbacked to padding anyways, because index arithmetic was a\nbit annoying. The table on the\nright is called a DP table. It's where the computation happens.\n\n#### Building a DP table\n\nDP 0/1 Knapsack algorithm goes like this: get an item. In a DP table, go through a corresponding row, column\nby\ncolumn and compare your item's value to value in current DP table cell (row, column; current column index is\ncurrent max weight\n(capacity) of your knapsack). If your item's weight is bigger than current column's index, move on to the\nnext column. If your\nitem weight is equal to a column index and your item value is higher than current cell, replace the cell\nwith your item value. If your item weight is smaller than column index and it fits in a spare capacity,\nadd\nit to the cell's value (a free capacity is current capacity minus capacity of picked items). Repeat until you\niterate\nthrough all the items. At this point, you learn what is the maximum value you can get within the weight\nbudget. If our goal would be to measure a max possible value, then we would stop at this point. Unfortunately,\nwe\nwant to know more.\n\n[![](https://jedrzej.maczan.pl/knapsack_no_backtrack.png)](https://jedrzej.maczan.pl/knapsack_no_backtrack.png)\n\n#### Backtracking\n\nWe need to know which items we should take to get this max possible value. So in case of PyTorch, which\noperations which we should save to memory and which operations we should recompute. To find out which items\ncontribute to the max value (in other words, which items were chosen during building DP table), we need to go\nbackwards through the DP table. We go from the last row and last column upward. We compare a cell with a cell\nabove (same column, previous row). If they are different, then the current item\ncontributes to the max value - because each row corresponds to a single item. If they are equal, this\nitem\nwill not be stored in a memory and becomes recomputable. Now, we traverse the DP table upward. If the item was\nchosen, we move upward by a single row and we\nmove the position of\nthe current cell to the left by the\nweight of the chosen item. If item wasn't chosen, we move upward by a single row and we start on the\nsame position as previously. Repeat until we get to the top of the DP table.\n\n[![](https://jedrzej.maczan.pl/knapsack_backtrack.png)](https://jedrzej.maczan.pl/knapsack_backtrack.png)\n\n#### Optimization\n\nThis solver works correctly. It provides an exact solution and for most of the time you don't need anything\nbetter.\nBy better I mean 1. faster and 2. less memory hungry. Because look again at the algorithm and the GIF above.\nThere are\na few issues with it. To get a result, we allocate a full 2D table of shape=(number of items, max\\_weight), which\nis\nnot great. [Horace He (Chillee)](https://github.com/Chillee) who\noriginally built a great part of (all of?) the memory planning in PyTorch [left a note](https://github.com/pytorch/pytorch/blob/1aaedbcfdd5c0615a882eebba3f51b2409162142/torch/_functorch/_activation_checkpointing/knapsack.py#L82) in the DP knapsack solver code:\n\n```python\n# TODO(chilli): I think if needed, this memory can be optimized with sliding\n# window trick + Hirschberg trick:\n# https://codeforces.com/blog/entry/47247?#comment-316200\n```\n\nWhat he proposes are two optimizations.\n\n#### Sliding window\n\nWindow trick means that instead of building the a DP table, we slide\nover a table and use only a previous row and a current row. When moving to the next row, next becomes a new\ncurrent and old current becomes a previous row. This improvement alone would be enough, if we wanted to just\ncompute the max value of items out\nof\nour list, within a given capacity. But again, we need to know which items contribute to this max value. That's\nwhy Horace suggested using a sliding window together with Hirschberg trick.\n\n[![](https://jedrzej.maczan.pl/sliding_window.png)](https://jedrzej.maczan.pl/sliding_window.png)\n\n#### Hirschberg trick\n\nIt's a divide and conquer approach, kinda similar to quicksort, because\nyou split problem into smaller\nones and solve them and continue splitting until you solve the whole problem. The main benefit of Hirschberg\ntrick for usis that it gets rid of backtracking.\n\nFrom an implementation perspective, I sort of do a recursion here, but without putting new frames on the stack.\nI have a Python list that I use as an explicit stack (last in, first out). The list stores a range of item\nindexes and a currently available capacity. We start with all the items and all the capacity. Then the algo goes\nlike this: First, we pop an item from the stack. If\nit's a single item (item index range end - start = 1), check if item's weight fits in the\navailable capacity. If\nyes, include it in saved items, if\nnot, include it in recomputable items. This part is imo the biggest strength of Hirschberg algorithm for us -\nbecause you can see now that we won't need a backtracking, since we build saved and recomputable lists inside\nthe algorithm. No need to build it afterwards, unlike in original 0/1 DP knapsack algorithm. If the items range\nis\nbigger than 1, split the items into a two parts and for\neach of\nthem compute a DP table. We don't want to build a full DP table, so we do the sliding window trick here and\nreuse a current and previous DP row to compute the final DP row.\n\nOnce we have both left and right DP rows, add\nthem together. Find the position of the highest value. It will be the new splitting point for our memory. Now we\nsplit the\nmemory\ninto two, using this newly computed position and we run the algorithm again, using both memory and items split.\nRepeat until done.\nBtw. It might\nhappen that one of the splitted parts will be empty. It might happen when the best split is either the first or\nlast item. That's completely legit, we just skip\nsuch an stack frame and move on.\n\n[![](https://jedrzej.maczan.pl/hirschberg_step_by_step.png)](https://jedrzej.maczan.pl/hirschberg_step_by_step.png)\n[Here](https://codeforces.com/blog/entry/57512) is a great explanation with drawings\nstep by step of Hirschberg algo by [KokiYmgch](https://codeforces.com/profile/KokiYmgch) on CodeForces\n\n#### So, is dp\\_knapsack\\_sliding\\_hirschberg THE solver now?\n\nNo. Look - with these two optimizations combined, we can decrease the DP table size from shape=(number of items,\nmax weight) to shape=(2, max weight),\neffectively\nreducing a peak memory by a factor of 20x - on my machine with 64GB RAM dp\\_knapsack crashes on problems with 100\nitems, while dp\\_knapsack\\_sliding\\_hirschberg is able to handle problems with 2000 items\nwithin this RAM budget. We also gain some\nruntime speedup, roughly 37%, but I didn't measure it very rigorously, though.\nThat being said - if you don't mind\nusing SciPy, then you probably should use ilp\\_knapsack instead. It's MUCH faster than any existing DP\nknapsack implementation in PyTorch. It's a bit slower than a greedy algorithm, but still very fast, yet unlike\ngreedy and similarly to both DP solvers, it provides an exact solution.\n\n#### How to pick a right solver for you\n\nIf you care about speed above correctness, use greedy\\_knapsack.\n\nElse if you're ok with pulling SciPy into project, use ilp\\_knapsack.\n\nElse if you install PyTorch from a package manager, noop - PyTorch will use dp\\_knapsack, which is a\ndefault solver and you don't need to do anything.\n\nElse use dp\\_knapsack\\_sliding\\_hirschberg.\n\n[![](https://jedrzej.maczan.pl/pick_solver.png)](https://jedrzej.maczan.pl/pick_solver.png)\n\n#### How to use dp\\_knapsack\\_sliding\\_hirschberg\n\n```python\nimport torch\nimport torch._functorch.config as fconfig\nfconfig.activation_memory_budget_solver = fconfig.dp_knapsack_sliding_hirschberg\n```\n\nIf you spot any bugs when using dp\\_knapsack\\_sliding\\_hirschberg, [pls register an issue](https://github.com/pytorch/pytorch/issues) and tag me [@jmaczan](https://github.com/jmaczan) and I'll hop on to solve it.\n\nThanks to [Edward Yang](https://github.com/ezyang) for a code review and a merge and\nthanks to you for reading\n","body_html":"<p><strong>TL;DR:</strong> If you use a default\ntorch._functorch.config.activation_memory_budget_solver=dp, you can change it to dp_knapsack_sliding_hirschberg\nand decrease your peak RAM usage during memory planning by a factor of 20.</p>\n<p><a href=\"https://jedrzej.maczan.pl/knapsack.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/knapsack.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"what\">What?</h4>\n<p>When PyTorch builds a computation graph of your ML model, it tries many different things to make it fast and\nmemory efficient. One technique is to take a joint forward and backward computation graph and choose which\noperations should be saved (stored in a memory and reused) and which operations should be recomputed.\nEach operation takes some time to run and takes up some memory if stored and we only can use a limited amount\nof memory.</p>\n<h4 id=\"0-1-knapsack-problem\">0/1 Knapsack problem</h4>\n<p>Imagine you are a thief and you just broke into a place with many valuable things inside. You have a knapsack\nthat can carry up to 10 kilograms. You want to maximize the value of things you steal. Ideally, you&#39;d just take\nall of them. But if you put more than 10kg to your knaspack, it will break and you will get away with nothing.\nAlternatively, you can use some heuristics to pick the items (like take only small items or only green ones),\nbut then your solution\nmight not be optimal - you\nwill steal some\nvalue, but perhaps less than what you could gain in an optimal choice. For your rescue, there come 0/1\nknapsack solvers. There are different algorithms that compute optimal items choice within a given capacity (max\nweight of things in a knapsack) and given a list of items, where each of items has a value and a cost (weight).\nIn PyTorch, this is what we actually do, which is: within a RAM budget (knapsack capacity), we choose which\noperations (items) should be saved to\nthe memory to maximize the time savings in runtime (value).</p>\n<p><a href=\"https://jedrzej.maczan.pl/thief.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/thief.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"dp-knapsack\">dp_knapsack</h4>\n<p>Currently, the default implementation of knapsack solver in PyTorch is dp_knapsack, which is a dynamic\nprogramming approach to\nsolving 0/1 knapsack. The algoritmh is actually simple once you understand it. It helps a lot if you have had a\nprior experience with dynamic\nprogramming (I do not). Look at this nice GIF from Wikipedia:</p>\n<figure><img src=\"https://jedrzej.maczan.pl/knapsack_dp.gif\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>By <a href=\"https://commons.wikimedia.org/w/index.php?title=User:RDSEED&amp;action=edit&amp;redlink=1\" title=\"User:RDSEED (page does not exist)\" rel=\"nofollow ugc noopener\">RDSEED</a> - Own work,\n<a href=\"https://creativecommons.org/licenses/by-sa/4.0\" title=\"Creative Commons Attribution-Share Alike 4.0\" rel=\"nofollow ugc noopener\">CC\nBY-SA 4.0</a>, <a href=\"https://commons.wikimedia.org/w/index.php?curid=112851814\" rel=\"nofollow ugc noopener\">Link</a></p>\n<p>On the left, there is a list of 4 items. i is an index, v is a value and w is a weight. Units irrelevant.\nCapacity is 6. That&#39;s why on the right side there are 6 columns (each column is a part of total capacity)\nand 4 rows (one per item). Ok, actually there are 7 and 5, because of padding with zeros, but that&#39;s only\nfor a computation convenience (every row and column has a parent, index arithmetic gets much easier). You could\nactually do it without padding, but I tried and fallbacked to padding anyways, because index arithmetic was a\nbit annoying. The table on the\nright is called a DP table. It&#39;s where the computation happens.</p>\n<h4 id=\"building-a-dp-table\">Building a DP table</h4>\n<p>DP 0/1 Knapsack algorithm goes like this: get an item. In a DP table, go through a corresponding row, column\nby\ncolumn and compare your item&#39;s value to value in current DP table cell (row, column; current column index is\ncurrent max weight\n(capacity) of your knapsack). If your item&#39;s weight is bigger than current column&#39;s index, move on to the\nnext column. If your\nitem weight is equal to a column index and your item value is higher than current cell, replace the cell\nwith your item value. If your item weight is smaller than column index and it fits in a spare capacity,\nadd\nit to the cell&#39;s value (a free capacity is current capacity minus capacity of picked items). Repeat until you\niterate\nthrough all the items. At this point, you learn what is the maximum value you can get within the weight\nbudget. If our goal would be to measure a max possible value, then we would stop at this point. Unfortunately,\nwe\nwant to know more.</p>\n<p><a href=\"https://jedrzej.maczan.pl/knapsack_no_backtrack.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/knapsack_no_backtrack.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"backtracking\">Backtracking</h4>\n<p>We need to know which items we should take to get this max possible value. So in case of PyTorch, which\noperations which we should save to memory and which operations we should recompute. To find out which items\ncontribute to the max value (in other words, which items were chosen during building DP table), we need to go\nbackwards through the DP table. We go from the last row and last column upward. We compare a cell with a cell\nabove (same column, previous row). If they are different, then the current item\ncontributes to the max value - because each row corresponds to a single item. If they are equal, this\nitem\nwill not be stored in a memory and becomes recomputable. Now, we traverse the DP table upward. If the item was\nchosen, we move upward by a single row and we\nmove the position of\nthe current cell to the left by the\nweight of the chosen item. If item wasn&#39;t chosen, we move upward by a single row and we start on the\nsame position as previously. Repeat until we get to the top of the DP table.</p>\n<p><a href=\"https://jedrzej.maczan.pl/knapsack_backtrack.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/knapsack_backtrack.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"optimization\">Optimization</h4>\n<p>This solver works correctly. It provides an exact solution and for most of the time you don&#39;t need anything\nbetter.\nBy better I mean 1. faster and 2. less memory hungry. Because look again at the algorithm and the GIF above.\nThere are\na few issues with it. To get a result, we allocate a full 2D table of shape=(number of items, max_weight), which\nis\nnot great. <a href=\"https://github.com/Chillee\" rel=\"nofollow ugc noopener\">Horace He (Chillee)</a> who\noriginally built a great part of (all of?) the memory planning in PyTorch <a href=\"https://github.com/pytorch/pytorch/blob/1aaedbcfdd5c0615a882eebba3f51b2409162142/torch/_functorch/_activation_checkpointing/knapsack.py#L82\" rel=\"nofollow ugc noopener\">left a note</a> in the DP knapsack solver code:</p>\n<pre><code class=\"language-python\"># TODO(chilli): I think if needed, this memory can be optimized with sliding\n# window trick + Hirschberg trick:\n# https://codeforces.com/blog/entry/47247?#comment-316200</code></pre>\n<p>What he proposes are two optimizations.</p>\n<h4 id=\"sliding-window\">Sliding window</h4>\n<p>Window trick means that instead of building the a DP table, we slide\nover a table and use only a previous row and a current row. When moving to the next row, next becomes a new\ncurrent and old current becomes a previous row. This improvement alone would be enough, if we wanted to just\ncompute the max value of items out\nof\nour list, within a given capacity. But again, we need to know which items contribute to this max value. That&#39;s\nwhy Horace suggested using a sliding window together with Hirschberg trick.</p>\n<p><a href=\"https://jedrzej.maczan.pl/sliding_window.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/sliding_window.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"hirschberg-trick\">Hirschberg trick</h4>\n<p>It&#39;s a divide and conquer approach, kinda similar to quicksort, because\nyou split problem into smaller\nones and solve them and continue splitting until you solve the whole problem. The main benefit of Hirschberg\ntrick for usis that it gets rid of backtracking.</p>\n<p>From an implementation perspective, I sort of do a recursion here, but without putting new frames on the stack.\nI have a Python list that I use as an explicit stack (last in, first out). The list stores a range of item\nindexes and a currently available capacity. We start with all the items and all the capacity. Then the algo goes\nlike this: First, we pop an item from the stack. If\nit&#39;s a single item (item index range end - start = 1), check if item&#39;s weight fits in the\navailable capacity. If\nyes, include it in saved items, if\nnot, include it in recomputable items. This part is imo the biggest strength of Hirschberg algorithm for us -\nbecause you can see now that we won&#39;t need a backtracking, since we build saved and recomputable lists inside\nthe algorithm. No need to build it afterwards, unlike in original 0/1 DP knapsack algorithm. If the items range\nis\nbigger than 1, split the items into a two parts and for\neach of\nthem compute a DP table. We don&#39;t want to build a full DP table, so we do the sliding window trick here and\nreuse a current and previous DP row to compute the final DP row.</p>\n<p>Once we have both left and right DP rows, add\nthem together. Find the position of the highest value. It will be the new splitting point for our memory. Now we\nsplit the\nmemory\ninto two, using this newly computed position and we run the algorithm again, using both memory and items split.\nRepeat until done.\nBtw. It might\nhappen that one of the splitted parts will be empty. It might happen when the best split is either the first or\nlast item. That&#39;s completely legit, we just skip\nsuch an stack frame and move on.</p>\n<p><a href=\"https://jedrzej.maczan.pl/hirschberg_step_by_step.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/hirschberg_step_by_step.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a>\n<a href=\"https://codeforces.com/blog/entry/57512\" rel=\"nofollow ugc noopener\">Here</a> is a great explanation with drawings\nstep by step of Hirschberg algo by <a href=\"https://codeforces.com/profile/KokiYmgch\" rel=\"nofollow ugc noopener\">KokiYmgch</a> on CodeForces</p>\n<h4 id=\"so-is-dp-knapsack-sliding-hirschberg-the-solver-now\">So, is dp_knapsack_sliding_hirschberg THE solver now?</h4>\n<p>No. Look - with these two optimizations combined, we can decrease the DP table size from shape=(number of items,\nmax weight) to shape=(2, max weight),\neffectively\nreducing a peak memory by a factor of 20x - on my machine with 64GB RAM dp_knapsack crashes on problems with 100\nitems, while dp_knapsack_sliding_hirschberg is able to handle problems with 2000 items\nwithin this RAM budget. We also gain some\nruntime speedup, roughly 37%, but I didn&#39;t measure it very rigorously, though.\nThat being said - if you don&#39;t mind\nusing SciPy, then you probably should use ilp_knapsack instead. It&#39;s MUCH faster than any existing DP\nknapsack implementation in PyTorch. It&#39;s a bit slower than a greedy algorithm, but still very fast, yet unlike\ngreedy and similarly to both DP solvers, it provides an exact solution.</p>\n<h4 id=\"how-to-pick-a-right-solver-for-you\">How to pick a right solver for you</h4>\n<p>If you care about speed above correctness, use greedy_knapsack.</p>\n<p>Else if you&#39;re ok with pulling SciPy into project, use ilp_knapsack.</p>\n<p>Else if you install PyTorch from a package manager, noop - PyTorch will use dp_knapsack, which is a\ndefault solver and you don&#39;t need to do anything.</p>\n<p>Else use dp_knapsack_sliding_hirschberg.</p>\n<p><a href=\"https://jedrzej.maczan.pl/pick_solver.png\" rel=\"nofollow ugc noopener\"><img src=\"https://jedrzej.maczan.pl/pick_solver.png\" alt=\"\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></a></p>\n<h4 id=\"how-to-use-dp-knapsack-sliding-hirschberg\">How to use dp_knapsack_sliding_hirschberg</h4>\n<pre><code class=\"language-python\">import torch\nimport torch._functorch.config as fconfig\nfconfig.activation_memory_budget_solver = fconfig.dp_knapsack_sliding_hirschberg</code></pre>\n<p>If you spot any bugs when using dp_knapsack_sliding_hirschberg, <a href=\"https://github.com/pytorch/pytorch/issues\" rel=\"nofollow ugc noopener\">pls register an issue</a> and tag me <a href=\"https://github.com/jmaczan\" rel=\"nofollow ugc noopener\">@jmaczan</a> and I&#39;ll hop on to solve it.</p>\n<p>Thanks to <a href=\"https://github.com/ezyang\" rel=\"nofollow ugc noopener\">Edward Yang</a> for a code review and a merge and\nthanks to you for reading</p>","headings":[]}}