-
Notifications
You must be signed in to change notification settings - Fork 66
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
feat: add csv parsing for meshes and tutorial #638
Merged
Merged
Changes from 7 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
1091087
feat: add csv parsing for meshes and tutorial
guenthermi ea9c999
Merge branch 'main' into docs-add-3d-mesh-example
guenthermi 61569fe
tests: refactor tests for create_document
guenthermi 18e040c
docs: minor docs changes
guenthermi b4b2791
Merge branch 'main' into docs-add-3d-mesh-example
guenthermi 8477e4f
docs: add outputs to notebook
guenthermi cf67956
docs: add documention for mesh datasets
guenthermi 21a41b8
refactor: update tutorial
guenthermi b01cc5b
docs: add code block to before and after section
guenthermi 1c3131a
fix: docstring of create_point_clouds param
guenthermi b762006
docs: add white backround to example img
guenthermi 1e7ea99
chore: fix typo in CHANGELOG
guenthermi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
--- | ||
jupyter: | ||
jupytext: | ||
text_representation: | ||
extension: .md | ||
format_name: markdown | ||
format_version: '1.3' | ||
jupytext_version: 1.14.1 | ||
kernelspec: | ||
display_name: Python 3 | ||
name: python3 | ||
--- | ||
|
||
<!-- #region id="C0RxIJmLkTGk" --> | ||
# 3D Mesh-to-3D Mesh Search via PointNet++ | ||
|
||
<a href="https://colab.research.google.com/drive/1lIMDFkUVsWMshU-akJ_hwzBfJ37zLFzU?usp=sharing"><img alt="Open In Colab" src="https://colab.research.google.com/assets/colab-badge.svg"></a> | ||
|
||
Finding similar 3D Meshes can become very time consuming. To support this task, one can build search systems. To directly search on the 3D meshes without relying on metadata one can use encoder model which extract create a point cloud from the mesh and encode it into vector dense representations which can be compared to each other. To enable those models to detect the right attributes of an 3D Mesh, this tutorial show you how to use Finetuner to train and use a model for 3D mesh search system. | ||
<!-- #endregion --> | ||
|
||
<!-- #region id="mk4gxLZnYJry" --> | ||
## Install | ||
<!-- #endregion --> | ||
|
||
```python id="vDVkw65kkQcn" | ||
!pip install 'finetuner[full]' | ||
!pip install 'docarray[full]' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's remove this from the tutorial |
||
``` | ||
|
||
<!-- #region id="q7Bb9o5ZHSZ3" --> | ||
## Task | ||
|
||
Finetuner supports an embedding model which is based on the Pytorch [implemention](https://github.com/yanx27/Pointnet_Pointnet2_pytorch) of the [PointNet++ model](https://proceedings.neurips.cc/paper/2017/file/d8bf84be3800d12f74d8b05e9b89836f-Paper.pdf). This tutorial will show you how to train and use this model for 3D mesh search. | ||
|
||
We demonstrate this on the [Modelnet40](https://modelnet.cs.princeton.edu/) dataset which consist of more than 12k 3D meshes of objects from 40 classes. | ||
Specifically, we want to build a search system, which can receive a 3D mehs and retrieves meshes of the same class. | ||
|
||
We will buid a dataset with some images for | ||
|
||
<!-- #endregion --> | ||
|
||
<!-- #region id="H1Yo3NuGP1Oi" --> | ||
## Data | ||
|
||
ModelNet40 consists of 9843 meshes provided for training and 2468 meshes for testing. Usually, you would have to download the [dataset](https://modelnet.cs.princeton.edu/) unzip it, [prepare it, and upload it to the Jina AI Cloud](https://https://finetuner.jina.ai/walkthrough/create-training-data/). After that, you can provide the name of the dataset used for the upload to Finetuner. | ||
|
||
For this tutorial, we already prepared the data and uploaded it. Specifically the training data is uploaded as `modelnet40-train`. For evaluating the model, we split the test set of the original dataset in 300 meshes, which serve as queries (`modelnet40-queries`) and 2168 meshes which serve as the mesh collection, which is searched in (`modelnet40-index`). | ||
|
||
Each 3D mesh in the dataset is represented by a [DocArray](https://github.com/docarray/docarray) Document object. It contains the uri (local filepath) of the original file and a tensor which contains a point cloud with 2048 3D points sampled from the mesh as explained in (TODO add link to documentation) | ||
|
||
```{admonition} Push data to the cloud | ||
We don't require you to push data to the Jina AI Cloud by yourself. Instead of a name, you can provide a `DocumentArray` or a path to a CSV file. | ||
In those cases Finetuner will do the job for you. | ||
When you construct a DocArray dataset with documents of 3D meshes, please call `doc.load_uri_to_point_cloud_tensor(2048)` to create point clouds from your local mesh files before pushing the data to the cloud since Finetuner has no access to your local files. | ||
``` | ||
|
||
The code below loads the data and prints a summary of the training datasets: | ||
<!-- #endregion --> | ||
|
||
```python id="uTDreSwfYGOR" | ||
import finetuner | ||
from docarray import DocumentArray, Document | ||
|
||
finetuner.login(force=True) | ||
``` | ||
|
||
```python id="Y-Um5gE8IORv" | ||
train_data = DocumentArray.pull('modelnet40-train', show_progress=True) | ||
query_data = DocumentArray.pull('modelnet40-queries', show_progress=True) | ||
index_data = DocumentArray.pull('modelnet40-index', show_progress=True) | ||
|
||
train_data.summary() | ||
``` | ||
|
||
<!-- #region id="r4cP95RzLybw" --> | ||
Now we want to take a look at the point clouds of some of the meshes: | ||
<!-- #endregion --> | ||
|
||
```python id="kCv455NPMD1O" | ||
index_data[0].display() | ||
``` | ||
|
||
<!-- #region id="XlttkaD5Omhk" --> | ||
![A point cloud example](https://user-images.githubusercontent.com/6599259/208113813-bcf498d9-edf7-4496-a087-03bb783f3b70.png) | ||
<!-- #endregion --> | ||
|
||
<!-- #region id="B3I_QUeFT_V0" --> | ||
## Backbone model | ||
|
||
The model, we provide for 3d mesh encoding is called `pointnet++`. In the following, we show you how to train it on the modelnet training dataset. | ||
<!-- #endregion --> | ||
|
||
<!-- #region id="lqg0eY9oknLL" --> | ||
## Fine-tuning | ||
|
||
Now that we have data for training and evaluation as well as the name of the model, which we want to train, we can configure and submit a fine-tuning run: | ||
<!-- #endregion --> | ||
|
||
```python id="rR22MbgITp8M" | ||
from finetuner.callback import EvaluationCallback | ||
|
||
run = finetuner.fit( | ||
model='pointnet++', | ||
train_data='modelnet40-train', | ||
epochs=10, | ||
batch_size=64, | ||
learning_rate= 5e-4, | ||
loss='TripletMarginLoss', | ||
device='cuda', | ||
callbacks=[ | ||
EvaluationCallback( | ||
query_data='modelnet40-queries', | ||
index_data='modelnet40-index', | ||
batch_size=64, | ||
) | ||
], | ||
) | ||
``` | ||
|
||
<!-- #region id="ossT9LH1oh6K" --> | ||
Let's understand what this piece of code does: | ||
|
||
* We start with providing `model`, in our case "pointnet++". | ||
* Via the `train_data` parameter, we inform the Finetuner about the name of the dataset in the Jina AI Cloud | ||
* We also provide some hyper-parameters such as number of `epochs`, `batch_size`, and a `learning_rate`. | ||
* We use `TripletMarginLoss` to optimize the PointNet++ model. | ||
* We use an evaluation callback, which uses the fine-tuned model for encoding the text queries and meshes in the index data collection. It also accepts the `batch_size` attribute. By encoding 64 meshes at once, the evaluation gets faster. | ||
|
||
<!-- #endregion --> | ||
|
||
<!-- #region id="AsHsMJP6p7Co" --> | ||
## Monitoring | ||
|
||
Now that we've created a run, let's see how it's processing. You can monitor the run by checking the status via `run.status()` and view the logs with `run.logs()`. To stream logs, call `run.stream_logs()`: | ||
<!-- #endregion --> | ||
|
||
```python id="PCCRZ6PalsK3" | ||
# note, the fine-tuning might takes 20~ minutes | ||
for entry in run.stream_logs(): | ||
print(entry) | ||
``` | ||
|
||
<!-- #region id="zG7Uci-qqkzM" --> | ||
Since some runs might take up to several hours/days, it's important to know how to reconnect to Finetuner and retrieve your run. | ||
|
||
```python | ||
import finetuner | ||
|
||
finetuner.login() | ||
run = finetuner.get_run(run.name) | ||
``` | ||
|
||
You can continue monitoring the run by checking the status - `finetuner.run.Run.status()` or the logs - `finetuner.run.Run.logs()`.*kursiver Text* | ||
<!-- #endregion --> | ||
|
||
<!-- #region id="WgTrq9D5q0zc" --> | ||
## Evaluating | ||
|
||
Our `EvaluationCallback` during fine-tuning ensures that after each epoch, an evaluation of our model is run. We can access the results of the last evaluation in the logs as follows `print(run.logs())`: | ||
|
||
```bash | ||
Training [10/10] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 154/154 0:00:00 0:00:26 • loss: 0.001 | ||
INFO Done ✨ __main__.py:195 | ||
DEBUG Finetuning took 0 days, 0 hours 5 minutes and 39 seconds __main__.py:197 | ||
INFO Metric: 'pointnet++_precision_at_k' before fine-tuning: 0.56533 after fine-tuning: 0.81100 __main__.py:210 | ||
INFO Metric: 'pointnet++_recall_at_k' before fine-tuning: 0.15467 after fine-tuning: 0.24175 __main__.py:210 | ||
INFO Metric: 'pointnet++_f1_score_at_k' before fine-tuning: 0.23209 after fine-tuning: 0.34774 __main__.py:210 | ||
INFO Metric: 'pointnet++_hit_at_k' before fine-tuning: 0.95667 after fine-tuning: 0.95333 __main__.py:210 | ||
INFO Metric: 'pointnet++_average_precision' before fine-tuning: 0.71027 after fine-tuning: 0.85515 __main__.py:210 | ||
INFO Metric: 'pointnet++_reciprocal_rank' before fine-tuning: 0.79103 after fine-tuning: 0.89103 __main__.py:210 | ||
INFO Metric: 'pointnet++_dcg_at_k' before fine-tuning: 4.71826 after fine-tuning: 6.41999 __main__.py:210 | ||
INFO Building the artifact ... __main__.py:215 | ||
INFO Saving artifact locally ... __main__.py:237 | ||
[15:46:55] INFO Artifact saved in artifacts/ __main__.py:239 | ||
DEBUG Artifact size is 27.379 MB __main__.py:245 | ||
INFO Finished 🚀 __main__.py:246 | ||
|
||
``` | ||
|
||
<!-- #endregion --> | ||
|
||
<!-- #region id="W4ZCKUOfq9oC" --> | ||
|
||
After the run has finished successfully, you can download the tuned model on your local machine: | ||
<!-- #endregion --> | ||
|
||
```python id="K5UdKleiqd8m" | ||
artifact = run.save_artifact('pointnet_model') | ||
``` | ||
|
||
<!-- #region id="JU3uUVyirTE1" --> | ||
## Inference | ||
|
||
Now you saved the `artifact` into your host machine, | ||
let's use the fine-tuned model to encode a new `Document`: | ||
|
||
```{admonition} Inference with ONNX | ||
In case you set `to_onnx=True` when calling `finetuner.fit` function, | ||
please use `model = finetuner.get_model(artifact, is_onnx=True)` | ||
guenthermi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
<!-- #endregion --> | ||
|
||
```python id="rDGxi7kVq_sH" | ||
query = DocumentArray([query_data[0]]) | ||
|
||
model = finetuner.get_model(artifact=artifact, device='cuda') | ||
|
||
finetuner.encode(model=model, data=query) | ||
finetuner.encode(model=model, data=index_data) | ||
|
||
assert query.embeddings.shape == (1, 512) | ||
``` | ||
|
||
<!-- #region id="pfoc4YG4rrkI" --> | ||
And finally you can use the embeded `query` to find top-k visually related images within `index_data` as follows: | ||
<!-- #endregion --> | ||
|
||
```python id="_jGsSyedrsJp" | ||
query.match(index_data, limit=10, metric='cosine') | ||
``` | ||
|
||
guenthermi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<!-- #region id="CgZHPInNWWHn" --> | ||
When investigating the matches, we can see that the model is able to identify similar meshes. However, this does not necessarily mean that all results are correct. For example, our first query (a mesh of a desk) returns results from those some are actual desk. Nevertheless, some results are tables, which looks similar to the desk, but obtain a different label: | ||
![picture of query mesh and its matches](https://user-images.githubusercontent.com/6599259/208120667-c6633178-154c-40ab-a88c-0955b18d304b.png) | ||
<!-- #endregion --> | ||
|
||
```python id="JsV87_rrW4dT" | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo