Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codebook expiration does not take effect at all #61

Open
chenjiasheng opened this issue Jun 21, 2023 · 2 comments
Open

Codebook expiration does not take effect at all #61

chenjiasheng opened this issue Jun 21, 2023 · 2 comments

Comments

@chenjiasheng
Copy link

https://github.com/facebookresearch/encodec/blob/0e2d0aed29362c8e8f52494baf3e6f99056b214f/encodec/quantization/core_vq.py#LL220C18-L220C18

I have found that expiration handling for codebook did not work at all. Even if we deliberately clear the data of self.embed after self.expire_codes_(), the final self.embed we get is not affected. This demonstrates that the modification of self.embed content in self.expire_codes_() is irrelevant.

        if self.training:
            # We do the expiry of code at that point as buffers are in sync
            # and all the workers will take the same decision.
            self.expire_codes_(x)       # NOTICE: The modification on self.embed inside expire_codes_ is irrelevant and will be overwritten by line 229
            self.embed.data.zero_()   # NOTICE: Deliberately clear self.embed
            ema_inplace(self.cluster_size, embed_onehot.sum(0), self.decay)
            embed_sum = x.t() @ embed_onehot
            ema_inplace(self.embed_avg, embed_sum.t(), self.decay)
            cluster_size = (
                laplace_smoothing(self.cluster_size, self.codebook_size, self.epsilon)
                * self.cluster_size.sum()
            )
            embed_normalized = self.embed_avg / cluster_size.unsqueeze(1)
            print(embed_normalized)  # NOTICE: Whether to add line 217 or not, embed_normalized has a consistent value
            self.embed.data.copy_(embed_normalized)

Also, I would like to ask if codebook expiration is really important? It seems that you have obtained good results even with the wrong code.

@ilya16
Copy link

ilya16 commented Jun 27, 2023

@chenjiasheng nice catch! So EnCodec was trained only on EMA updates without codebook expiration.

I also have something to add about the cluster_size buffers. If we look at any codebook's cluster_size for the trained model, almost all codes have values less than threshold_ema_dead_code = 2 and would have been replaced at each training step if the codebook expiration worked correctly.

from encodec import EncodecModel

model = EncodecModel.encodec_model_24khz()

codebook = model.quantizer.vq.layers[0]._codebook
print(codebook.embed.shape)
print(codebook.cluster_size.sum())
print((codebook.cluster_size < codebook.threshold_ema_dead_code).sum())

> torch.Size([1024, 128])
> tensor(600.0010)
> tensor(1003)

The sum of each codebook's cluster_size is 600, which is the number of frames in a batch on a single GPU (75 fps x 8), and is less than the number of codebooks 1024, implying constant codebook underutilization. EnCodec was trained on 8 GPUs with 4800 per batch, but the cluster_size buffers are not aggregated across processes as they should be.

@chenjiasheng
Copy link
Author

@ilya16
Agreed.
The first batch (75fps * 1s * 8) has not enough frames to initialize the codebook (with size 1024),
Also, doing expiration once per batch is too frequent, as there is not enough frames seen during only one batch, making most of the codes hunger to death.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants