# Loss\_z1\_weight and loss\_z1\_unweight in scANVI

**URL:** https://discourse.scverse.org/t/loss-z1-weight-and-loss-z1-unweight-in-scanvi/364
**Category:** scvi-tools
**Tags:** scanvi
**Created:** [March 21, 2022, 9:48am UTC](https://discourse.scverse.org/t/loss-z1-weight-and-loss-z1-unweight-in-scanvi/364 "2022-03-21T09:48:54Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![yugeji](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/yugeji/32/175_2.png) [@yugeji](https://discourse.scverse.org/u/yugeji)
#### Post date: [March 21, 2022, 9:48am UTC](https://discourse.scverse.org/t/loss-z1-weight-and-loss-z1-unweight-in-scanvi/364/1 "2022-03-21T09:48:54Z")

</div>

In the scANVI implementation, there are two losses I don’t quite understand: [scvi-tools/\_scanvae.py at d636093bc8d49c8e03fcb4bc0a8bc8130cb29fe2 · scverse/scvi-tools · GitHub](https://github.com/scverse/scvi-tools/blob/d636093bc8d49c8e03fcb4bc0a8bc8130cb29fe2/scvi/module/_scanvae.py#L257-L258)

```auto
loss_z1_unweight = -Normal(pz1_m, torch.sqrt(pz1_v)).log_prob(z1s).sum(dim=-1)
loss_z1_weight = Normal(qz1_m, torch.sqrt(qz1_v)).log_prob(z1).sum(dim=-1)

```

Given that these are directly added to the loss function, isn’t this saying that we want `P(z1| pz1)` to be high and `P(z1| qz1)` to be low? But `z1` is generated (via reparameterization trick) from `qz1` so how is this possible?

Additionally: I presume understanding those two losses would also answer why the `encoder_z2_z1` and `decoder_z1_z2` part of the architecture is necessary. If not, what is this additional encoder and decoder used for?

Thanks in advance,  
Yuge

---

<div class="post-metadata">

### Author: ![Justin\_Hong](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/justin_hong/32/85_2.png) [@Justin\_Hong](https://discourse.scverse.org/u/Justin_Hong)
#### Post date: [March 23, 2022, 7:00pm UTC](https://discourse.scverse.org/t/loss-z1-weight-and-loss-z1-unweight-in-scanvi/364/2 "2022-03-23T19:00:51Z")

</div>

Hi Yuge,

Thank you for using scvi-tools. These lines are easier to understand as the KL divergence term for `z_1`. Specifically KL(q\_\eta(z)||p\_\theta(z)) = `loss_z1_weight + loss_z1_unweight`. The second encoder and decoder pair are additional networks that break down `z_1` per cell type. This is the defining difference between scVI and scANVI. The math is detailed in our user guide: [scANVI - scvi-tools](https://docs.scvi-tools.org/en/stable/user_guide/models/scanvi.html). Let me know if this helps!

---

<div class="post-metadata">

### Author: ![alitinet](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.scverse.org/alitinet/32/1505_2.png) [@alitinet](https://discourse.scverse.org/u/alitinet)
#### Post date: [October 8, 2025, 10:03am UTC](https://discourse.scverse.org/t/loss-z1-weight-and-loss-z1-unweight-in-scanvi/364/3 "2025-10-08T10:03:08Z")

</div>

Hi @Justin_Hong , can I follow up on this and ask a few questions about how z2 is used. From what I got from the code, z2 or rather the mean and variance of encoder\_z2\_z1 are only used to calculate the KL loss. But to calculate the reconstruction and the classification loss, z1, i.e. the direct output of the encoder, is used. Could you please clarify if that’s correct? If z2 is only used in the KL calculation, why is it needed in the first place? 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: [November 25, 2025, 7:32pm UTC](https://discourse.scverse.org/t/loss-z1-weight-and-loss-z1-unweight-in-scanvi/364/4 "2025-11-25T19:32:13Z")

</div>

Hi, motivation comes from the stacked M1+M2 model in: [https://arxiv.org/pdf/1406.5298](https://arxiv.org/pdf/1406.5298). I hope this helps to understand the structure. It encourages integration of each cell-type by mapping z1 to z2 and back to z1.
