We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Memory issue running zheng17 on ~1M cells
Running https://github.com/theislab/scanpy_usage/blob/master/170522_visualizing_one_million_cells/cluster.py on the latest released Scanpy (1.4.4.post1) gives a memory error:

```
reading 1M_neurons_filtered_gene_bc_matrices_h5.h5
Variable names are not unique. To make them unique, call `.var_names_make_unique`.
 (0:01:39)
running recipe zheng17
filtered out 3983 genes that are detectedin less than 1 counts
Killed
```

This is running with 60GB of memory (n1-standard-16), but also occurs with 104GB (n1-highmem-16). It looks like there has been a regression somewhere since this used to run OK. I think the error may be happening in anndata.
memory requirements
Hi,
I am trying to run the full 1.3M 10X mouse cell dataset (using the 1M_neurons_filtered_gene_bc_matrices_h5.h5 file from 10X website).
I have 126GB RAM and Intel® Xeon(R) W-2123 CPU @ 3.60GHz × 8 which is above the requirements you mention needed to run the full cluster.py method without subsampling. (https://github.com/theislab/scanpy_usage/tree/master/170522_visualizing_one_million_cells)
I get a memory error at the normalization and filter_genes_dispersion stage, should i modify the code in anyway? (without subsampling)
Thanks,Shobi

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scanpy/preprocessing/_recipes.py`
Content:
```
1 """Preprocessing recipes from the literature
2 """
3 from anndata import AnnData
4 
5 from . import _simple as pp
6 from ._deprecated.highly_variable_genes import filter_genes_dispersion, filter_genes_cv_deprecated
7 from .. import logging as logg
8 
9 
10 def recipe_weinreb17(
11     adata: AnnData,
12     log: bool = True,
13     mean_threshold=0.01,
14     cv_threshold=2,
15     n_pcs=50,
16     svd_solver='randomized',
17     random_state=0,
18     copy: bool = False,
19 ):
20     """\
21     Normalization and filtering as of [Weinreb17]_.
22 
23     Expects non-logarithmized data.
24     If using logarithmized data, pass `log=False`.
25 
26     Parameters
27     ----------
28     adata
29         Annotated data matrix.
30     log
31         Logarithmize data?
32     copy
33         Return a copy if true.
34     """
35     from scipy.sparse import issparse
36     if issparse(adata.X):
37         raise ValueError('`recipe_weinreb16 does not support sparse matrices.')
38     if copy: adata = adata.copy()
39     if log: pp.log1p(adata)
40     adata.X = pp.normalize_per_cell_weinreb16_deprecated(adata.X,
41                                                          max_fraction=0.05,
42                                                          mult_with_mean=True)
43     gene_subset = filter_genes_cv_deprecated(adata.X, mean_threshold, cv_threshold)
44     adata._inplace_subset_var(gene_subset)  # this modifies the object itself
45     X_pca = pp.pca(pp.zscore_deprecated(adata.X),
46                    n_comps=n_pcs, svd_solver=svd_solver, random_state=random_state)
47     # update adata
48     adata.obsm['X_pca'] = X_pca
49     return adata if copy else None
50 
51 
52 def recipe_seurat(adata, log=True, plot=False, copy=False):
53     """Normalization and filtering as of Seurat [Satija15]_.
54 
55     This uses a particular preprocessing.
56 
57     Expects non-logarithmized data. If using logarithmized data, pass `log=False`.
58     """
59     if copy: adata = adata.copy()
60     pp.filter_cells(adata, min_genes=200)
61     pp.filter_genes(adata, min_cells=3)
62     pp.normalize_per_cell(adata, counts_per_cell_after=1e4)
63     filter_result = filter_genes_dispersion(
64         adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)
65     if plot:
66         from ..plotting import _preprocessing as ppp  # should not import at the top of the file
67         ppp.filter_genes_dispersion(filter_result, log=not log)
68     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes
69     if log: pp.log1p(adata)
70     pp.scale(adata, max_value=10)
71     return adata if copy else None
72 
73 
74 def recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):
75     """Normalization and filtering as of [Zheng17]_.
76 
77     Reproduces the preprocessing of [Zheng17]_ - the Cell Ranger R Kit of 10x
78     Genomics.
79 
80     Expects non-logarithmized data. If using logarithmized data, pass `log=False`.
81 
82     The recipe runs the following steps
83 
84     .. code:: python
85 
86         sc.pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count
87         sc.pp.normalize_per_cell(                # normalize with total UMI count per cell
88              adata, key_n_counts='n_counts_all')
89         filter_result = sc.pp.filter_genes_dispersion(  # select highly-variable genes
90             adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)
91         adata = adata[:, filter_result.gene_subset]     # subset the genes
92         sc.pp.normalize_per_cell(adata)          # renormalize after filtering
93         if log: sc.pp.log1p(adata)               # log transform: adata.X = log(adata.X + 1)
94         sc.pp.scale(adata)                       # scale to unit variance and shift to zero mean
95 
96 
97     Parameters
98     ----------
99     adata : :class:`~anndata.AnnData`
100         Annotated data matrix.
101     n_top_genes : `int`, optional (default: 1000)
102         Number of genes to keep.
103     log : `bool`, optional (default: `True`)
104         Take logarithm.
105     plot : `bool`, optional (default: `True`)
106         Show a plot of the gene dispersion vs. mean relation.
107     copy : `bool`, optional (default: `False`)
108         Return a copy of `adata` instead of updating it.
109 
110     Returns
111     -------
112     Returns or updates `adata` depending on `copy`.
113     """
114     start = logg.info('running recipe zheng17')
115     if copy: adata = adata.copy()
116     pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count
117     pp.normalize_per_cell(adata,  # normalize with total UMI count per cell
118                           key_n_counts='n_counts_all')
119     filter_result = filter_genes_dispersion(
120         adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)
121     if plot:
122         from ..plotting import _preprocessing as ppp  # should not import at the top of the file
123         ppp.filter_genes_dispersion(filter_result, log=True)
124     # actually filter the genes, the following is the inplace version of
125     #     adata = adata[:, filter_result.gene_subset]
126     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes
127     pp.normalize_per_cell(adata)  # renormalize after filtering
128     if log: pp.log1p(adata)  # log transform: X = log(X + 1)
129     pp.scale(adata)
130     logg.info('    finished', time=start)
131     return adata if copy else None
132
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/scanpy/preprocessing/_recipes.py b/scanpy/preprocessing/_recipes.py
--- a/scanpy/preprocessing/_recipes.py
+++ b/scanpy/preprocessing/_recipes.py
@@ -4,6 +4,7 @@
 
 from . import _simple as pp
 from ._deprecated.highly_variable_genes import filter_genes_dispersion, filter_genes_cv_deprecated
+from ._normalization import normalize_total
 from .. import logging as logg
 
 
@@ -59,7 +60,7 @@
     if copy: adata = adata.copy()
     pp.filter_cells(adata, min_genes=200)
     pp.filter_genes(adata, min_cells=3)
-    pp.normalize_per_cell(adata, counts_per_cell_after=1e4)
+    normalize_total(adata, target_sum=1e4)
     filter_result = filter_genes_dispersion(
         adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)
     if plot:
@@ -114,8 +115,8 @@
     start = logg.info('running recipe zheng17')
     if copy: adata = adata.copy()
     pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count
-    pp.normalize_per_cell(adata,  # normalize with total UMI count per cell
-                          key_n_counts='n_counts_all')
+    normalize_total(adata,  # normalize with total UMI count per cell
+                    key_added='n_counts_all')
     filter_result = filter_genes_dispersion(
         adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)
     if plot:
@@ -124,7 +125,7 @@
     # actually filter the genes, the following is the inplace version of
     #     adata = adata[:, filter_result.gene_subset]
     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes
-    pp.normalize_per_cell(adata)  # renormalize after filtering
+    normalize_total(adata)  # renormalize after filtering
     if log: pp.log1p(adata)  # log transform: X = log(X + 1)
     pp.scale(adata)
     logg.info('    finished', time=start)

{"golden_diff": "diff --git a/scanpy/preprocessing/_recipes.py b/scanpy/preprocessing/_recipes.py\n--- a/scanpy/preprocessing/_recipes.py\n+++ b/scanpy/preprocessing/_recipes.py\n@@ -4,6 +4,7 @@\n \n from . import _simple as pp\n from ._deprecated.highly_variable_genes import filter_genes_dispersion, filter_genes_cv_deprecated\n+from ._normalization import normalize_total\n from .. import logging as logg\n \n \n@@ -59,7 +60,7 @@\n     if copy: adata = adata.copy()\n     pp.filter_cells(adata, min_genes=200)\n     pp.filter_genes(adata, min_cells=3)\n-    pp.normalize_per_cell(adata, counts_per_cell_after=1e4)\n+    normalize_total(adata, target_sum=1e4)\n     filter_result = filter_genes_dispersion(\n         adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)\n     if plot:\n@@ -114,8 +115,8 @@\n     start = logg.info('running recipe zheng17')\n     if copy: adata = adata.copy()\n     pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n-    pp.normalize_per_cell(adata,  # normalize with total UMI count per cell\n-                          key_n_counts='n_counts_all')\n+    normalize_total(adata,  # normalize with total UMI count per cell\n+                    key_added='n_counts_all')\n     filter_result = filter_genes_dispersion(\n         adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n     if plot:\n@@ -124,7 +125,7 @@\n     # actually filter the genes, the following is the inplace version of\n     #     adata = adata[:, filter_result.gene_subset]\n     adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n-    pp.normalize_per_cell(adata)  # renormalize after filtering\n+    normalize_total(adata)  # renormalize after filtering\n     if log: pp.log1p(adata)  # log transform: X = log(X + 1)\n     pp.scale(adata)\n     logg.info('    finished', time=start)\n", "issue": "Memory issue running zheng17 on ~1M cells\nRunning https://github.com/theislab/scanpy_usage/blob/master/170522_visualizing_one_million_cells/cluster.py on the latest released Scanpy (1.4.4.post1) gives a memory error:\r\n\r\n```\r\nreading 1M_neurons_filtered_gene_bc_matrices_h5.h5\r\nVariable names are not unique. To make them unique, call `.var_names_make_unique`.\r\n (0:01:39)\r\nrunning recipe zheng17\r\nfiltered out 3983 genes that are detectedin less than 1 counts\r\nKilled\r\n```\r\n\r\nThis is running with 60GB of memory (n1-standard-16), but also occurs with 104GB (n1-highmem-16). It looks like there has been a regression somewhere since this used to run OK. I think the error may be happening in anndata.\nmemory requirements\nHi,\r\nI am trying to run the full 1.3M 10X mouse cell dataset (using the 1M_neurons_filtered_gene_bc_matrices_h5.h5 file from 10X website).\r\nI have 126GB RAM and Intel\u00ae Xeon(R) W-2123 CPU @ 3.60GHz \u00d7 8 which is above the requirements you mention needed to run the full cluster.py method without subsampling. (https://github.com/theislab/scanpy_usage/tree/master/170522_visualizing_one_million_cells)\r\nI get a memory error at the normalization and filter_genes_dispersion stage, should i modify the code in anyway? (without subsampling)\r\nThanks,Shobi\n", "before_files": [{"content": "\"\"\"Preprocessing recipes from the literature\n\"\"\"\nfrom anndata import AnnData\n\nfrom . import _simple as pp\nfrom ._deprecated.highly_variable_genes import filter_genes_dispersion, filter_genes_cv_deprecated\nfrom .. import logging as logg\n\n\ndef recipe_weinreb17(\n    adata: AnnData,\n    log: bool = True,\n    mean_threshold=0.01,\n    cv_threshold=2,\n    n_pcs=50,\n    svd_solver='randomized',\n    random_state=0,\n    copy: bool = False,\n):\n    \"\"\"\\\n    Normalization and filtering as of [Weinreb17]_.\n\n    Expects non-logarithmized data.\n    If using logarithmized data, pass `log=False`.\n\n    Parameters\n    ----------\n    adata\n        Annotated data matrix.\n    log\n        Logarithmize data?\n    copy\n        Return a copy if true.\n    \"\"\"\n    from scipy.sparse import issparse\n    if issparse(adata.X):\n        raise ValueError('`recipe_weinreb16 does not support sparse matrices.')\n    if copy: adata = adata.copy()\n    if log: pp.log1p(adata)\n    adata.X = pp.normalize_per_cell_weinreb16_deprecated(adata.X,\n                                                         max_fraction=0.05,\n                                                         mult_with_mean=True)\n    gene_subset = filter_genes_cv_deprecated(adata.X, mean_threshold, cv_threshold)\n    adata._inplace_subset_var(gene_subset)  # this modifies the object itself\n    X_pca = pp.pca(pp.zscore_deprecated(adata.X),\n                   n_comps=n_pcs, svd_solver=svd_solver, random_state=random_state)\n    # update adata\n    adata.obsm['X_pca'] = X_pca\n    return adata if copy else None\n\n\ndef recipe_seurat(adata, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of Seurat [Satija15]_.\n\n    This uses a particular preprocessing.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n    \"\"\"\n    if copy: adata = adata.copy()\n    pp.filter_cells(adata, min_genes=200)\n    pp.filter_genes(adata, min_cells=3)\n    pp.normalize_per_cell(adata, counts_per_cell_after=1e4)\n    filter_result = filter_genes_dispersion(\n        adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)\n    if plot:\n        from ..plotting import _preprocessing as ppp  # should not import at the top of the file\n        ppp.filter_genes_dispersion(filter_result, log=not log)\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    if log: pp.log1p(adata)\n    pp.scale(adata, max_value=10)\n    return adata if copy else None\n\n\ndef recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of [Zheng17]_.\n\n    Reproduces the preprocessing of [Zheng17]_ - the Cell Ranger R Kit of 10x\n    Genomics.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n\n    The recipe runs the following steps\n\n    .. code:: python\n\n        sc.pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n        sc.pp.normalize_per_cell(                # normalize with total UMI count per cell\n             adata, key_n_counts='n_counts_all')\n        filter_result = sc.pp.filter_genes_dispersion(  # select highly-variable genes\n            adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n        adata = adata[:, filter_result.gene_subset]     # subset the genes\n        sc.pp.normalize_per_cell(adata)          # renormalize after filtering\n        if log: sc.pp.log1p(adata)               # log transform: adata.X = log(adata.X + 1)\n        sc.pp.scale(adata)                       # scale to unit variance and shift to zero mean\n\n\n    Parameters\n    ----------\n    adata : :class:`~anndata.AnnData`\n        Annotated data matrix.\n    n_top_genes : `int`, optional (default: 1000)\n        Number of genes to keep.\n    log : `bool`, optional (default: `True`)\n        Take logarithm.\n    plot : `bool`, optional (default: `True`)\n        Show a plot of the gene dispersion vs. mean relation.\n    copy : `bool`, optional (default: `False`)\n        Return a copy of `adata` instead of updating it.\n\n    Returns\n    -------\n    Returns or updates `adata` depending on `copy`.\n    \"\"\"\n    start = logg.info('running recipe zheng17')\n    if copy: adata = adata.copy()\n    pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n    pp.normalize_per_cell(adata,  # normalize with total UMI count per cell\n                          key_n_counts='n_counts_all')\n    filter_result = filter_genes_dispersion(\n        adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n    if plot:\n        from ..plotting import _preprocessing as ppp  # should not import at the top of the file\n        ppp.filter_genes_dispersion(filter_result, log=True)\n    # actually filter the genes, the following is the inplace version of\n    #     adata = adata[:, filter_result.gene_subset]\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    pp.normalize_per_cell(adata)  # renormalize after filtering\n    if log: pp.log1p(adata)  # log transform: X = log(X + 1)\n    pp.scale(adata)\n    logg.info('    finished', time=start)\n    return adata if copy else None\n", "path": "scanpy/preprocessing/_recipes.py"}], "after_files": [{"content": "\"\"\"Preprocessing recipes from the literature\n\"\"\"\nfrom anndata import AnnData\n\nfrom . import _simple as pp\nfrom ._deprecated.highly_variable_genes import filter_genes_dispersion, filter_genes_cv_deprecated\nfrom ._normalization import normalize_total\nfrom .. import logging as logg\n\n\ndef recipe_weinreb17(\n    adata: AnnData,\n    log: bool = True,\n    mean_threshold=0.01,\n    cv_threshold=2,\n    n_pcs=50,\n    svd_solver='randomized',\n    random_state=0,\n    copy: bool = False,\n):\n    \"\"\"\\\n    Normalization and filtering as of [Weinreb17]_.\n\n    Expects non-logarithmized data.\n    If using logarithmized data, pass `log=False`.\n\n    Parameters\n    ----------\n    adata\n        Annotated data matrix.\n    log\n        Logarithmize data?\n    copy\n        Return a copy if true.\n    \"\"\"\n    from scipy.sparse import issparse\n    if issparse(adata.X):\n        raise ValueError('`recipe_weinreb16 does not support sparse matrices.')\n    if copy: adata = adata.copy()\n    if log: pp.log1p(adata)\n    adata.X = pp.normalize_per_cell_weinreb16_deprecated(adata.X,\n                                                         max_fraction=0.05,\n                                                         mult_with_mean=True)\n    gene_subset = filter_genes_cv_deprecated(adata.X, mean_threshold, cv_threshold)\n    adata._inplace_subset_var(gene_subset)  # this modifies the object itself\n    X_pca = pp.pca(pp.zscore_deprecated(adata.X),\n                   n_comps=n_pcs, svd_solver=svd_solver, random_state=random_state)\n    # update adata\n    adata.obsm['X_pca'] = X_pca\n    return adata if copy else None\n\n\ndef recipe_seurat(adata, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of Seurat [Satija15]_.\n\n    This uses a particular preprocessing.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n    \"\"\"\n    if copy: adata = adata.copy()\n    pp.filter_cells(adata, min_genes=200)\n    pp.filter_genes(adata, min_cells=3)\n    normalize_total(adata, target_sum=1e4)\n    filter_result = filter_genes_dispersion(\n        adata.X, min_mean=0.0125, max_mean=3, min_disp=0.5, log=not log)\n    if plot:\n        from ..plotting import _preprocessing as ppp  # should not import at the top of the file\n        ppp.filter_genes_dispersion(filter_result, log=not log)\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    if log: pp.log1p(adata)\n    pp.scale(adata, max_value=10)\n    return adata if copy else None\n\n\ndef recipe_zheng17(adata, n_top_genes=1000, log=True, plot=False, copy=False):\n    \"\"\"Normalization and filtering as of [Zheng17]_.\n\n    Reproduces the preprocessing of [Zheng17]_ - the Cell Ranger R Kit of 10x\n    Genomics.\n\n    Expects non-logarithmized data. If using logarithmized data, pass `log=False`.\n\n    The recipe runs the following steps\n\n    .. code:: python\n\n        sc.pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n        sc.pp.normalize_per_cell(                # normalize with total UMI count per cell\n             adata, key_n_counts='n_counts_all')\n        filter_result = sc.pp.filter_genes_dispersion(  # select highly-variable genes\n            adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n        adata = adata[:, filter_result.gene_subset]     # subset the genes\n        sc.pp.normalize_per_cell(adata)          # renormalize after filtering\n        if log: sc.pp.log1p(adata)               # log transform: adata.X = log(adata.X + 1)\n        sc.pp.scale(adata)                       # scale to unit variance and shift to zero mean\n\n\n    Parameters\n    ----------\n    adata : :class:`~anndata.AnnData`\n        Annotated data matrix.\n    n_top_genes : `int`, optional (default: 1000)\n        Number of genes to keep.\n    log : `bool`, optional (default: `True`)\n        Take logarithm.\n    plot : `bool`, optional (default: `True`)\n        Show a plot of the gene dispersion vs. mean relation.\n    copy : `bool`, optional (default: `False`)\n        Return a copy of `adata` instead of updating it.\n\n    Returns\n    -------\n    Returns or updates `adata` depending on `copy`.\n    \"\"\"\n    start = logg.info('running recipe zheng17')\n    if copy: adata = adata.copy()\n    pp.filter_genes(adata, min_counts=1)  # only consider genes with more than 1 count\n    normalize_total(adata,  # normalize with total UMI count per cell\n                    key_added='n_counts_all')\n    filter_result = filter_genes_dispersion(\n        adata.X, flavor='cell_ranger', n_top_genes=n_top_genes, log=False)\n    if plot:\n        from ..plotting import _preprocessing as ppp  # should not import at the top of the file\n        ppp.filter_genes_dispersion(filter_result, log=True)\n    # actually filter the genes, the following is the inplace version of\n    #     adata = adata[:, filter_result.gene_subset]\n    adata._inplace_subset_var(filter_result.gene_subset)  # filter genes\n    normalize_total(adata)  # renormalize after filtering\n    if log: pp.log1p(adata)  # log transform: X = log(X + 1)\n    pp.scale(adata)\n    logg.info('    finished', time=start)\n    return adata if copy else None\n", "path": "scanpy/preprocessing/_recipes.py"}]}