# Macbook M1 M2 mps acceleration with scVI

**URL:** <https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075>\
**Category:** scvi-tools\
**Tags:** developer\
**Created:** [February 9, 2024, 9:21pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075 "2024-02-09T21:21:36Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![davemcg](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/davemcg/32/959_2.png) [@davemcg](https://discourse.scverse.org/u/davemcg)\
**Post date:** [February 9, 2024, 9:21pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/1 "2024-02-09T21:21:36Z")

</div>

Has anyone recently gotten scVI (ideally 1.0.4) working with “GPU” (well, “mps”) acceleration with a Apple ARM M1, M2, or M3? I’ve tried a variety of incantations when installing torch and jax and it either doesn’t see the GPU or does and throws a tensor error which suggests something is very borked somewhere in the software chain.

```auto
ValueError: Expected parameter loc (Tensor of shape (128, 30)) of distribution Normal(loc: torch.Size([128, 30]), scale: torch.Size([128, 30])) to satisfy the constraint Real(), but found invalid values:
tensor([[nan, nan, nan, ..., nan, nan, nan],
        [nan, nan, nan, ..., nan, nan, nan],
        [nan, nan, nan, ..., nan, nan, nan],
        ...,
        [nan, nan, nan, ..., nan, nan, nan],
        [nan, nan, nan, ..., nan, nan, nan],
        [nan, nan, nan, ..., nan, nan, nan]], device='mps:0',
       grad_fn=<LinearBackward0>)

```

---

<div class="post-metadata">

**Author:** ![TaniaThimraj](https://avatars.discourse-cdn.com/v4/letter/t/c2a13f/32.png) [@TaniaThimraj](https://discourse.scverse.org/u/TaniaThimraj)\
**Post date:** [February 12, 2024, 9:19am UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/2 "2024-02-12T09:19:44Z")

</div>

Same issue here. I am on a Mac M3

---

<div class="post-metadata">

**Author:** ![pckinnunen\_lbl](https://avatars.discourse-cdn.com/v4/letter/p/e47c2d/32.png) [@pckinnunen\_lbl](https://discourse.scverse.org/u/pckinnunen_lbl)\
**Post date:** [February 15, 2024, 11:25pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/3 "2024-02-15T23:25:07Z")

</div>

I had similar issues and found this:

> [@M1 MAX: GPU available, but not used](https://discourse.scverse.org/t/m1-max-gpu-available-but-not-used/1318/2):
>
> Hi, what kind of environment are you running this in? I would recommend using a conda version that is native for Mac M1 [Miniconda — conda documentation](https://docs.conda.io/en/latest/miniconda.html)

I think this is a pytorch issue, not an scVI issue.

I think this is the pytorch issue where they track mps compatibility:

> <https://github.com/pytorch/pytorch/issues/77764>
>
> \### This issue is to have a centralized place to list and track work on adding s…upport to new ops for the MPS backend.
> 
> \[\*\*MPS operators coverage matrix\*\*\](https://qqaatw.github.io/pytorch-mps-ops-coverage/) - The matrix covers most of the supported operators but is not exhaustive. Before you comment below, please take a look at this matrix to make sure the operator you're requesting has not been implemented in nightly. More details can be found on the \[readme\](https://github.com/qqaatw/pytorch-mps-ops-coverage).
> 
> There are a very large number of operators in pytorch and so they are not all implemented yet for the MPS backends as it is still in the prototype phase. We will be prioritizing adding new operators based on user feedback. If possible, please also provide link to the network or use-case where this op is getting used.
> 
> If you want to work on adding support for such op, feel free to comment below to get assigned one. Please avoid pickup up an op that is already being worked on or that already has a PR associated with it.
> 
> \[Link to the wiki for details\](https://github.com/pytorch/pytorch/wiki/MPS-Backend) on how to add these ops and example PRs.
> 
> \*\*Good First Issue:\*\*
> Below is list of Ops which are good to get started to add operations to MPS backend. Please consider picking them up. 
> \- \[\] \`nn.Conv3D\`
> \- \[\] \`aten::\_weight\_norm\_interface\`
> \- \[\] \`aten::max\_unpool2d\`
> \- \[\] \`aten::cummin.out\`, \`aten::cummax.out\`
> \- \[\] \`aten::upsample\_linear1d.out\`
> \- \[\] \`aten::lerp.Scalar\_out\`
> \- \[\] \`aten::renorm\`
> 
> 
> \*\*Not categorized:\*\*
> These are the ops which are not yet picked up and need MPS implementation.
> 
> \- \[\] \`aten::slow\_conv3d\_forward\` 
> \- \[\] \`aten::\_ctc\_loss\`
> \- \[\] \`aten::avg\_pool3d.out\`
> \- \[\] \`aten::linalg\_qr.out\`
> \- \[\] \`aten::multilabel\_margin\_loss\_forward\`
> \- \[\] \`aten::unique\_dim\`
> \- \[\] \`aten::\_sample\_dirichlet\`
> \- \[\] \`aten::\_fft\_r2c\`
> \- \[\] \`aten::upsample\_bicubic2d.out\`
> \- \[\] \`aten::linalg\_inv\_out\_helper\`
> \- \[\] \`aten::bucketize\`
> \- \[\] \`aten::\_embedding\_bag\`
> \- \[\] \`aten::\_standard\_gamma\`
> \- \[\] \`aten::\_upsample\_bicubic2d\_aa.out\`
> \- \[\] \`aten::'aten::\_symeig\_helper\`
> \- \[\] \`aten::linalg\_matrix\_exp\`
> \- \[\] \`aten::\_nested\_tensor\_from\_mask\`
> \- \[\] \`aten::randperm.generator\_out\`
> \- \[\] \`aten::\_fused\_sdp\_choice\`
> \- \[\] \`aten::linalg\_cholesky\_ex\`
> \- \[\] \`aten::scatter\_reduce.two\_out\`
> \- \[\] \`aten::kthvalue.values\`
> \- \[\] \`aten::\_linalg\_solve\_ex.result\`
> \- \[\] \`aten::grid\_sampler\_2d\_backward'\`
> 
> \*\*WIP:\*\*
> \- \[\] \`max\_pool3d\` https://github.com/pytorch/pytorch/pull/102148
> \- \[\] \`aten::kl\_div\_backward\` (Is not needed )
> 
> 
> \*\*Implemented Ops:\*\*
> Ops that have MPS backend implementations.
> 
> See \[\*\*MPS operators coverage matrix\*\*\](https://qqaatw.github.io/pytorch-mps-ops-coverage/) and the \[readme\](https://github.com/qqaatw/pytorch-mps-ops-coverage) for more details.
> 
> \<details\>
> \<summary\>deprecated list\</summary\>
> 
> \- \[x\] \`aten::histc\` #96652
> \- \[x\] \`pow.Scalar\_out\` (@qqaatw )
> \- \[x\] \`aten::log\_sigmoid\_forward\` (@qqaatw )
> \- \[x\] \`aten::fmax.out\` (@qqaatw )
> \- \[x\] \`aten::roll\` https://github.com/pytorch/pytorch/pull/95168
> \- \[x\] \`aten::hardsigmoid\` (@qqaatw )
> \- \[x\] \`aten::logit\` (@qqaatw )
> \- \[x\] \`linalg\_solve\_triangular\`
> \- \[x\] \`aten::sort.values\_stable\` https://github.com/pytorch/pytorch/issues/86750
> \- \[x\] \`aten::remainder.Tensor\_out\` https://github.com/pytorch/pytorch/issues/86806
> \- \[x\] \`aten::hardswish\` https://github.com/pytorch/pytorch/issues/86807
> \- \[x\] \`aten::nansum\` https://github.com/pytorch/pytorch/issues/86809
> \- \[x\] \`aten::fmod.Tensor\_out\` https://github.com/pytorch/pytorch/issues/86810
> \- \[x\] \`aten::range\` https://github.com/pytorch/pytorch/issues/86990
> \- \[x\] \`aten::argsort\` https://github.com/pytorch/pytorch/issues/86991
> \- \[x\] \`aten::repeat\_interleave\` https://github.com/pytorch/pytorch/issues/87219
> \- \[x\] \`aten::median\` https://github.com/pytorch/pytorch/issues/87220
> \- \[x\] \`aten::trace\` https://github.com/pytorch/pytorch/issues/87221
> \- \[x\] \`aten::im2col\` (Falling back to CPU as its mostly used in preprocessing layers)
> \- \[x\] \`aten::\_cdist\_forward\` https://github.com/pytorch/pytorch/pull/91643
> \- \[x\] \`aten::native\_group\_norm\_backward\` (Implemented by @malfet )
> \- \[x\] \`aten::grid\_sampler\_2d\` (https://github.com/pytorch/pytorch/pull/94273)
> \- \[x\] \`aten::upsample\_nearest1d\_backward.grad\_input\`
> \- \[x\] \`aten::upsample\_nearest1d.out\`
> \- \[x\] \`aten::repeat\_interleave.self\_int\`
> \- \[x\] \`aten::nan\_to\_num.out\`
> \- \[x\] \`aten::unique\_consecutive\` https://github.com/pytorch/pytorch/pull/88532
> \- \[x\] \`torch.bincount\` https://github.com/pytorch/pytorch/pull/91267
> \- \[x\] \`aten::\_unique2\` https://github.com/pytorch/pytorch/pull/88532
> \- \[x\] \`aten::unfold\` https://github.com/pytorch/pytorch/pull/91266
> \- \[x\] \`aten::triangular\_solve.X\` https://github.com/pytorch/pytorch/pull/94345
> \- \[x\] \`aten::nonzero\` https://github.com/pytorch/pytorch/pull/91616
> \- \[x\] \`aten::\_index\_put\_impl\_\` (https://github.com/pytorch/pytorch/pull/85672)
> \- \[x\] \`aten::amax.out\` (#79682)
> \- \[X\] \`aten::\_slow\_conv2d\_forward\` (https://github.com/pytorch/pytorch/pull/86303)
> \- \[x\] \`aten::eye.m\_out\` (https://github.com/pytorch/pytorch/pull/78408)
> \- \[x\] \`aten::multinomial\` (https://github.com/pytorch/pytorch/pull/80760 ) 
> \- \[x\] \`aten::flip\` (#80214)
> \- \[x\] \`aten::equal\` https://github.com/pytorch/pytorch/pull/80195
> \- \[x\] \`aten::\_local\_scalar\_dense\`
> \- \[x\] \`aten::l1\_loss\_backward.grad\_input\` (#80010)
> \- \[x\] \`aten::glu.out\` (#79866)
> \- \[x\] \` aten::linspace.out\` https://github.com/pytorch/pytorch/pull/78570
> \- \[x\] \`aten::arange.out\` https://github.com/pytorch/pytorch/pull/78789
> \- \[x\] \`aten::adaptive\_max\_pool2d\` https://github.com/pytorch/pytorch/pull/78410
> \- \[x\] \`aten::count\_nonzero.dim\_IntList\`
> \- \[x\] \`aten::softplus.out\` (https://github.com/pytorch/pytorch/pull/78930)
> \- \[x\] \`aten::index\_add.out\` https://github.com/pytorch/pytorch/pull/79935
> \- \[x\] \`aten::normal\` (#80297)
> \- \[x\] \`aten::native\_layer\_norm\_backward\` https://github.com/pytorch/pytorch/pull/79189
> \- \[x\] \`aten::logical\_and.out\` (#80216)
> \- \[x\] \`aten::frac.out\` (https://github.com/pytorch/pytorch/pull/86625)
> \- \[x\] \`aten:: masked\_select\` https://github.com/pytorch/pytorch/pull/85818
> \- \[x\] \`aten::softplus\_backward.grad\_input\` (#79873)
> \- \[x\] \`aten::slow\_conv\_transpose2d.out\` (@malfet could be due to incompatibility with torchvision)
> \- \[x\] \`aten::signbit.out\` (https://github.com/pytorch/pytorch/pull/87214)
> \- \[X\] \`aten::cumsum.out\` (https://github.com/pytorch/pytorch/pull/88319)
> \- \[X\] \`aten::cumprod.out\` 
> \- \[X\] \`aten::expm1.out\` (https://github.com/pytorch/pytorch/pull/87147)
> \- \[x\] \`aten::bitwise\_xor.Tensor\_out\` (https://github.com/pytorch/pytorch/pull/82307)
> \- \[x\] \`aten::bitwise\_and.Tensor\_out\` (https://github.com/pytorch/pytorch/pull/82307)
> \- \[x\] \`aten::bitwise\_or.Tensor\_out\` (https://github.com/pytorch/pytorch/pull/82307)
> \- \[x\] \`aten::index.Tensor\` (https://github.com/pytorch/pytorch/pull/82507)
> \- \[x\] \`aten::index.Tensor\_out\` (https://github.com/pytorch/pytorch/pull/82507)
> \</details\>
> 
> 
> \*\*Ops not supported by MPS:\*\*
> Ops that will require either to use the CPU fallback system or a custom Metal kernel.
> 
> \- \[\] \`aten::lgamma.out\`
> \- \[\] \`aten::linalg\_householder\_product\`

I think the specific function that’s incompatible (at least for my usage) was

aten::\_standard\_gamma

---

<div class="post-metadata">

**Author:** ![martinkim0](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/martinkim0/32/881_2.png) [@martinkim0](https://discourse.scverse.org/u/martinkim0)\
**Post date:** [February 16, 2024, 5:30pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/4 "2024-02-16T17:30:14Z")

</div>

I’ve tried testing out the nightly PyTorch versions with the MPS backend and have had no success. Technically it should work since they’ve implemented the `lgamma` kernel, which was the last one needed to fully support running scVI, but it looks like there might be issues with the implementation or numerical instabilities since I’ve also experienced NaNs in the first epoch of training.

So yes, this is an issue on the PyTorch end - unfortunately there’s not much we can do to support the Metal backend.

---

<div class="post-metadata">

**Author:** ![davemcg](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/davemcg/32/959_2.png) [@davemcg](https://discourse.scverse.org/u/davemcg)\
**Post date:** [February 16, 2024, 6:04pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/5 "2024-02-16T18:04:25Z")

</div>

Thanks - I’ll keep track of this thread and I hope if anyone gets scVI working on a nightly (or better, stable) branch of pytorch they will report it here!

---

<div class="post-metadata">

**Author:** ![jan-engelmann](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/jan-engelmann/32/510_2.png) [@jan-engelmann](https://discourse.scverse.org/u/jan-engelmann)\
**Post date:** [August 3, 2024, 10:18pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/6 "2024-08-03T22:18:39Z")

</div>

I ran into the same issue with torch 2.2.2 on mps backend where torch.lgamma produces -inf  
very confusing to debug.  
Thanks for tracking it here!

---

<div class="post-metadata">

**Author:** ![cane11](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/cane11/32/241_2.png) [@cane11](https://discourse.scverse.org/u/cane11)\
**Post date:** [August 4, 2024, 7:09am UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/7 "2024-08-04T07:09:45Z")

</div>

Hi, thanks for the pointer. We tried it beforehand and got Nan errors (that was in the not released torch version). I looked deeper into it, it’s a very strange one. Apparently MPS handles broadcast\_all weirdly (and the line `torch.lgamma(theta)` is producing inf values). This is an example of the behavior:

```auto
b = torch.full((5, 3), 1., device='mps')
c = torch.full((5, 1), 1., device='mps')
b, c = broadcast_all(b, c)
torch.lgamma(b), torch.lgamma(c)

```

```auto
(tensor([[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]], device='mps:0'),
 tensor([[0.0000, 0.0000, 0.0000],
         [0.0000, 0.0000, -0.0906],
         [-0.0906, -0.0906, -0.0906],
         [-0.0906, -0.0906, -0.0906],
         [-0.0906, -0.0906, -0.0906]], device='mps:0'))

```

While the actual issue is something the MPS-torch team has to look into (I guess it’s some issue with pointing in memory). However, this also points to two manners in which scVI works on MPS. First one: gene\_likelihood=‘Poisson’ is fully supported. Second one, if using dispersion=‘gene-label’ during setting up the model, the broadcast\_all function has no effect and I’m not getting None errors (if not using label\_key using this setup has no effect on the training procedure and is save - it won’t work for scANVI though). The speedup that I’m getting on an M1 Max on High Power mode is 80% with very high batch size - this allows testing the GPU capabilities). I would be curious to get more people to benchmark it (especially using M3 chips).

 ![Screenshot 2024-08-04 at 12.08.30 AM](https://canada1.discourse-cdn.com/flex035/uploads/forum11/original/2X/6/683d5b9cadaa1db417701508a1f9e9014522b660.png)

---

<div class="post-metadata">

**Author:** ![cane11](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/cane11/32/241_2.png) [@cane11](https://discourse.scverse.org/u/cane11)\
**Post date:** [September 10, 2024, 7:23pm UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/8 "2024-09-10T19:23:04Z")

</div>

I would conclude that the use of MPS even with the proposed change should be only experimental, as we use broadcasting at various locations and different models and there is an issue in pytorch MPS with this: [MPS lgamma function changes results when using broadcasting · Issue #132605 · pytorch/pytorch · GitHub](https://github.com/pytorch/pytorch/issues/132605)

---

<div class="post-metadata">

**Author:** ![timslittle](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/timslittle/32/1068_2.png) [@timslittle](https://discourse.scverse.org/u/timslittle)\
**Post date:** [May 30, 2025, 10:37am UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/9 "2025-05-30T10:37:11Z")

</div>

Hi folks, I was exploring this topic recently and wondering if there have been any updates at all? It looks like the PyTorch `lgamma` issue is still open so I assume that running `scVI` with Mac MPS is still out of the questions? Thanks

---

<div class="post-metadata">

**Author:** ![cane11](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/cane11/32/241_2.png) [@cane11](https://discourse.scverse.org/u/cane11)\
**Post date:** [May 30, 2025, 11:43am UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/10 "2025-05-30T11:43:23Z")

</div>

Hi, yes the most recent scVI-tools supports MOS. However, we needed to explicitly reshape instead of broadcasting, which likely comes with added computational costs.

---

<div class="post-metadata">

**Author:** ![ori-kron-wis](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/ori-kron-wis/32/1099_2.png) [@ori-kron-wis](https://discourse.scverse.org/u/ori-kron-wis)\
**Post date:** [March 3, 2026, 11:43am UTC](https://discourse.scverse.org/t/macbook-m1-m2-mps-acceleration-with-scvi/2075/11 "2026-03-03T11:43:54Z")

</div>

Whoever still sees the posts, the recent scvi-tools version (1.4.2) now supports both MPS and MLX (via model mlxscvi) for MAC.

Both show much better performance in terms of runtime vs CPU when running on M3,M4 Pro/Max.
