Repository: lightly-ai/lightly

Issue:
Add documentation for creating and uploading embeddings through the pip package (non cli)
The CLI way of obtaining and uploading embeddings is described. It's pretty minimal but works. However, there is no information on how to do this yourself without using the CLI. 

I would prefer steps starting from having a pre-trained model.
```python
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def embed(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        return x

    def forward(self, x):
        x = self.embed(x)
        output = F.log_softmax(x, dim=1)
        return output

model = Net()

# let's assume here model is pre-trained
# I can get the embeddings and predictions using
embedding = model.embed(x)
prediction = model(x)

# TODO: how to create embeddings and upload them to lightly
```


Discussion:
The code for uploading the embeddings:

```python
embeddings, labels, filenames = model.embed(dataloader, device=device)
utils.io.save_embeddings(path_to_embeddings_csv, embeddings, labels, filenames)

api_workflow_client = ApiWorkflowClient(token=YOUR_TOKEN, dataset_id=YOUR_DATASET_ID)
api_workflow_client.upload_embeddings(name="embedding-1", path_to_embeddings_csv=path_to_embeddings_csv)
```
You also need the code to create the CSV file before you can upload. The question for me is where to put it in the docs? Once we have a place it's easy to write down :) 
I also found the autodoc of the upload of the embeddings in https://github.com/lightly-ai/lightly/blob/develop/docs/source/lightly.api.rst. Could we add a better description there?
This is outdated. The new autodocs should cover the `ApiWorkflowClient` way of uploading embeddings.
The question here is whether we really want to add a whole section on how to get the embeddings from a custom pre-trained model. IMO most users will be able to do that and we should focus on showing them how to store them in a csv file and then upload them. So my proposition is something like this:


If you have a numpy array of image embeddings, the filenames of the images, and categorical pseudo-labels, you can use the [`save_embeddings`](https://docs.lightly.ai/lightly.utils.html#lightly.utils.io.save_embeddings) function to store them in a lightly-compatible CSV format and upload them from your Python code or using the CLI. The following snippet shows how to upload the embeddings from Python:

```python
from lightly.utils import save_embeddings
from lightly.api.api_workflow_client import ApiWorkflowClient

# save embeddings
save_embeddings('embeddings.csv', embeddings, labels, filenames)

# upload them to the platform
client = ApiWorkflowClient(token='123', dataset_id='xyz')
client.upload_embeddings('embeddings.csv', name='my-embeddings')
```


Resolving patch:
diff --git a/lightly/api/api_workflow_client.py b/lightly/api/api_workflow_client.py
--- a/lightly/api/api_workflow_client.py
+++ b/lightly/api/api_workflow_client.py
@@ -85,12 +85,11 @@ def check_version_compatibility(self):
 
     @property
     def dataset_id(self) -> str:
-        ''' Returns the dataset_id
+        '''The current dataset_id.
 
         If the dataset_id is set, it is returned.
-        If it is unset, then the dataset_id of the last modified dataset is taken.
-
-        '''
+        If it is not set, then the dataset_id of the last modified dataset is selected.
+        ''' 
         try:
             return self._dataset_id
         except AttributeError:
@@ -127,6 +126,9 @@ def _order_list_by_filenames(self, filenames_for_list: List[str], list_to_order:
 
     @property
     def filenames_on_server(self):
+        '''The list of the filenames in the dataset.
+
+        '''
         if not hasattr(self, "_filenames_on_server"):
             self._filenames_on_server = self.mappings_api. \
                 get_sample_mappings_by_dataset_id(dataset_id=self.dataset_id, field="fileName")
diff --git a/lightly/api/api_workflow_upload_embeddings.py b/lightly/api/api_workflow_upload_embeddings.py
--- a/lightly/api/api_workflow_upload_embeddings.py
+++ b/lightly/api/api_workflow_upload_embeddings.py
@@ -20,6 +20,15 @@ def _is_valid_filename(filename: str):
 class _UploadEmbeddingsMixin:
 
     def set_embedding_id_by_name(self, embedding_name: str = None):
+        """Sets the embedding id of the client by embedding name.
+
+        Args:
+            embedding_name:
+                Name under which the embedding was uploaded.
+    
+        Raises:
+            ValueError if the embedding does not exist.
+        """
         embeddings: List[DatasetEmbeddingData] = \
             self.embeddings_api.get_embeddings_by_dataset_id(dataset_id=self.dataset_id)
 
@@ -38,14 +47,14 @@ def upload_embeddings(self, path_to_embeddings_csv: str, name: str):
         First checks that the specified embedding name is not on ther server. If it is, the upload is aborted.
         Then creates a new csv with the embeddings in the order specified on the server. Next it uploads it to the server.
         The received embedding_id is saved as a property of self.
+
         Args:
-            path_to_embeddings_csv: the filepath to the .csv containing the embeddings, e.g. "path/to/embeddings.csv"
-            name: The name of the embedding. If an embedding with such a name already exists on the server,
+            path_to_embeddings_csv:
+                The path to the .csv containing the embeddings, e.g. "path/to/embeddings.csv"
+            name:
+                The name of the embedding. If an embedding with such a name already exists on the server,
                 the upload is aborted.
 
-        Returns:
-            None
-
         """
         # get the names of the current embeddings on the server:
         embeddings_on_server: List[DatasetEmbeddingData] = \


Test patch: