Is there any way to update the parameters of embedding model?
Author: starrlee356
Pull request: no
Labels: name: Feature request

### Feature request

I wonder is there any way to update the parameters of embedding model? Here is an example:
`from bertopic import BERTopic
from sentence_transformers import SentenceTransformer
from umap import UMAP
from sklearn.cluster import KMeans
from transformers import AdamW

embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
umap_model = UMAP(n_neighbors=15, n_components=5, min_dist=0.0, metric='cosine', random_state=42)
cluster_model = KMeans(n_clusters=134)
bertopic_model = BERTopic(embedding_model=embedding_model,
                          umap_model=umap_model,
                          hdbscan_model=cluster_model)
optimizer = AdamW(embedding_model.parameters(), lr = args.lr, eps = args.eps)

bertopic_model.fit(texts)
predictions = bertopic_model.topics_
text_emb = embedding_model.encode(texts)
loss = loss_fn(text_emb, predictions)

optimizer.zero_grad()
loss.backward()
optimizer.step()`
But when I tried the above code, I found that text_emb obtained from  embedding_model.encode(texts) has no gradient, therefore the backward() failed.
I suppose another way to complement this is to create a custom embedding model (for example, a model that inherits from BERT). I wonder is there any way to put the custom model in bertopic_model and update its parameters?

### Motivation

If the parameters of embedding model are learnable, we could optimize the embedding space and therefore get better model performance.

### Your contribution

If there is no existing solution to the above problem, I will try my best to help.

Comments:
Hey!:
Regarding the issue you encountered with the `text_emb` not having gradients, this is likely due to the way the `SentenceTransformer` model is used in the BERTopic library. The `SentenceTransformer` model is a pre-trained model, and its parameters are typically frozen during the BERTopic training process.

Correct me if i'm wrong, to update the parameters of the embedding model used in BERTopic, you can create a custom embedding model that inherits from the `SentenceTransformer` class and add a custom training loop that updates the embedding model parameters

> Hey!: Regarding the issue you encountered with the `text_emb` not having gradients, this is likely due to the way the `SentenceTransformer` model is used in the BERTopic library. The `SentenceTransformer` model is a pre-trained model, and its parameters are typically frozen during the BERTopic training process.
> 
> Correct me if i'm wrong, to update the parameters of the embedding model used in BERTopic, you can create a custom embedding model that inherits from the `SentenceTransformer` class and add a custom training loop that updates the embedding model parameters

Thanks for your response! I tried again today and I think the following way works:
1. define my custom model (from SentenceTransformer, BERT or others), which takes texts as input and outputs the emb vectors.
```
class EmbeddingModel(BertPreTrainedModel):

    def __init__(self, config):
        super().__init__(config)
        self.bert = BertModel(config)

    def forward(self, texts):
        inputs = tokenizer(texts)          
        text_embeddings = self.bert(**inputs)        
        return text_embeddings
 ```

2. get embeddings, these are tensors with gradient on cuda. We can use these embeddings to compute loss, and update parameters with backward.
```
my_model = EmbeddingModel.from_pretrained(args.model_path).to(device)
text_embeddings = my_model(texts)
```

3. convert the above embeddings to ndarray that suit for bertopic.
```
fit_embeddings = text_embeddings.detach().cpu().numpy()
bertopic_model = BERTopic(
        umap_model=cluster_model,
        hdbscan_model=cluster_model,
        )
bertopic_model.fit_transform(texts, fit_embeddings)
```

Basically we convert our precomputed embeddings to bertopic_model.