Skip to content

Commit

Permalink
feat: enable saving of models in backend (#115)
Browse files Browse the repository at this point in the history
* feat: enable saving of models in backend

* feat(labeler): add button to save on labeler UI

* style: fix black style problem

* fix(labeler): change fetch to ajax

* fix(labeler): change fetch to ajax

* fix(labeler): change fetch to ajax

Co-authored-by: Roshan Jossy <roshan.jossy@jina.ai>
Co-authored-by: Han Xiao <artex.xh@gmail.com>
Co-authored-by: Han Xiao <han.xiao@jina.ai>
  • Loading branch information
4 people committed Oct 15, 2021
1 parent 2367f0c commit 98c584e
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 127 deletions.
3 changes: 3 additions & 0 deletions finetuner/labeler/__init__.py
Expand Up @@ -52,6 +52,9 @@ def get_embed_model(self):
f.expose_endpoint('/next') #: for allowing client to fetch for the next batch
f.expose_endpoint('/fit') #: for signaling the backend to fit on the labeled data
f.expose_endpoint('/feed') #: for signaling the backend to fit on the labeled data
f.expose_endpoint(
'/save'
) #: for signaling the backend to save the current state of the model

def extend_rest_function(app):
"""Allow FastAPI frontend to serve finetuner UI as a static webpage"""
Expand Down
12 changes: 9 additions & 3 deletions finetuner/labeler/executor.py
Expand Up @@ -5,7 +5,7 @@
from jina.helper import cached_property

from ..helper import get_framework
from ..tuner import fit
from ..tuner import fit, save


class FTExecutor(Executor):
Expand All @@ -14,7 +14,7 @@ def __init__(
dam_path: str,
metric: str = 'cosine',
head_layer: str = 'CosineLayer',
**kwargs
**kwargs,
):
super().__init__(**kwargs)
self._all_data = DocumentArrayMemmap(dam_path)
Expand Down Expand Up @@ -80,14 +80,20 @@ def fit(self, docs, parameters: Dict, **kwargs):
head_layer=self._head_layer,
)

@requests(on='/save')
def save(self, parameters, **kwargs):
model_path = parameters.get('model_path', 'trained.model')
save(self._embed_model, model_path)
print(f'model is saved to {model_path}')


class DataIterator(Executor):
def __init__(
self,
dam_path: str,
labeled_dam_path: Optional[str] = None,
clear_labels_on_start: bool = False,
**kwargs
**kwargs,
):
super().__init__(**kwargs)
self._all_data = DocumentArrayMemmap(dam_path)
Expand Down
127 changes: 56 additions & 71 deletions finetuner/labeler/ui/index.html
Expand Up @@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Finetuner · Labeler</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/swiper@5.3.6/css/swiper.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
Expand All @@ -15,81 +15,66 @@
</head>

<body>
<main id="app" v-cloak>
<div class="alert alert-danger position-absolute top-0 start-50 translate-middle-x" role="alert"
v-if="is_conn_broken">
Can not connect to the server on {{host_address}} Please check your connection.
</div>
<sidebar
:labeler-config="labeler_config"
:view-template="view_template"
:tags="tags"
:is-busy="is_busy"
:progress-stats="progress_stats"
:positive-rate="positive_rate"
:negative-rate="negative_rate"
:advanced-config="advanced_config"
></sidebar>
<div class="b-example-divider"></div>
<div class="flex-grow-1 p-5 overflow-hidden">
<swiper ref="swiperComponent" :options="swiperOptions" @click-slide="onSwiperClickSlide"
@set-translate="onSetTranslate">
<swiper-slide v-if="labeler_config.style=='text'" v-for="(doc, doc_idx) in cur_batch" :key="doc_idx">
<text-match-card
:doc="doc"
:doc-idx="doc_idx"
:get-content="get_content"
:toggle-relevance="toggle_relevance"
:invert-selection="select_all"
:submit-doc="submit_doc"
>
</text-match-card>
</swiper-slide>
<swiper-slide v-if="labeler_config.style=='image'" v-for="(doc, doc_idx) in cur_batch" :key="doc_idx">
<image-match-card
:doc="doc"
:doc-idx="doc_idx"
:get-content="get_content"
:toggle-relevance="toggle_relevance"
:invert-selection="select_all"
:submit-doc="submit_doc"
>
</image-match-card>
</swiper-slide>
<swiper-slide v-if="labeler_config.style=='mesh'" v-for="(doc, doc_idx) in cur_batch" :key="doc_idx">
<mesh-match-card
:doc="doc"
:doc-idx="doc_idx"
:get-content="get_content"
:toggle-relevance="toggle_relevance"
:invert-selection="select_all"
:submit-doc="submit_doc"
>
</mesh-match-card>
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-button-prev" slot="button-prev"></div>
<div class="swiper-button-next" slot="button-next"></div>
</swiper>
</div>
</main>
<main id="app" v-cloak>
<div class="alert alert-danger position-absolute top-0 start-50 translate-middle-x" role="alert"
v-if="is_conn_broken">
Can not connect to the server on {{host_address}} Please check your connection.
</div>
<sidebar :labeler-config="labeler_config" :view-template="view_template" :tags="tags" :is-busy="is_busy"
:progress-stats="progress_stats" :positive-rate="positive_rate" :negative-rate="negative_rate"
:advanced-config="advanced_config" :save-progress="saveProgress"></sidebar>
<div class="b-example-divider"></div>
<div class="flex-grow-1 p-5 overflow-hidden">
<div class="d-flex flex-column h-100">
<div class="flex-grow-1">
<swiper ref="swiperComponent" :options="swiperOptions" @click-slide="onSwiperClickSlide"
@set-translate="onSetTranslate">
<swiper-slide v-if="labeler_config.style=='text'" v-for="(doc, doc_idx) in cur_batch"
:key="doc_idx">
<text-match-card :doc="doc" :doc-idx="doc_idx" :get-content="get_content"
:toggle-relevance="toggle_relevance" :invert-selection="select_all"
:submit-doc="submit_doc">
</text-match-card>
</swiper-slide>
<swiper-slide v-if="labeler_config.style=='image'" v-for="(doc, doc_idx) in cur_batch"
:key="doc_idx">
<image-match-card :doc="doc" :doc-idx="doc_idx" :get-content="get_content"
:toggle-relevance="toggle_relevance" :invert-selection="select_all"
:submit-doc="submit_doc">
</image-match-card>
</swiper-slide>
<swiper-slide v-if="labeler_config.style=='mesh'" v-for="(doc, doc_idx) in cur_batch"
:key="doc_idx">
<mesh-match-card :doc="doc" :doc-idx="doc_idx" :get-content="get_content"
:toggle-relevance="toggle_relevance" :invert-selection="select_all"
:submit-doc="submit_doc">
</mesh-match-card>
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-button-prev" slot="button-prev"></div>
<div class="swiper-button-next" slot="button-next"></div>
</swiper>
</div>
</div>
</div>
</main>

<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/masonry-layout@4.2.2/dist/masonry.pkgd.min.js"
<script src="https://cdn.jsdelivr.net/npm/masonry-layout@4.2.2/dist/masonry.pkgd.min.js"
integrity="sha384-GNFwBvfVxBkLMJpYMOABq3c+d3KnQxudP/mGPkzpZSTYykLBNsZEnG2D9G/X/+7D" crossorigin="anonymous"
async></script>
<script src="https://cdn.jsdelivr.net/npm/swiper@5.3.6/js/swiper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-awesome-swiper"></script>
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
<script src="./js/components/sidebar.vue.js"></script>
<script src="./js/components/image-match-card.vue.js"></script>
<script src="./js/components/text-match-card.vue.js"></script>
<script src="./js/components/mesh-match-card.vue.js"></script>
<script src="./js/main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/swiper@5.3.6/js/swiper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-awesome-swiper"></script>
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
<script src="./js/components/sidebar.vue.js"></script>
<script src="./js/components/image-match-card.vue.js"></script>
<script src="./js/components/text-match-card.vue.js"></script>
<script src="./js/components/mesh-match-card.vue.js"></script>
<script src="./js/main.js"></script>
</body>

</html>
43 changes: 25 additions & 18 deletions finetuner/labeler/ui/js/components/sidebar.vue.js
@@ -1,15 +1,16 @@
const sidebar = {
props: {
labelerConfig : Object,
viewTemplate: Object,
tags: Array,
isBusy: Boolean,
progressStats: Object,
positiveRate: Number,
negativeRate: Number,
advancedConfig: Object,
},
template: `
props: {
labelerConfig: Object,
viewTemplate: Object,
tags: Array,
isBusy: Boolean,
progressStats: Object,
positiveRate: Number,
negativeRate: Number,
advancedConfig: Object,
saveProgress: Function,
},
template: `
<div class="d-flex flex-column flex-shrink-0 p-3 sidebar">
<a href="/" class="d-flex align-items-center mb-3 mx-md-auto text-decoration-none">
<span class="app-title">
Expand All @@ -31,7 +32,7 @@ const sidebar = {
aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<div class="row my-1">
<label class="col-sm-6 col-form-label">Content</label>
<label class="col-sm-6 col-form-label">Field</label>
<div class="col-sm-6">
<select class="form-select" v-model="labelerConfig.content">
<option v-for="option in viewTemplate.content" v-bind:value="option.value">
Expand All @@ -51,7 +52,7 @@ const sidebar = {
</div>
</div>
<div class="row my-1">
<label class="col-sm-6 col-form-label">Layout</label>
<label class="col-sm-6 col-form-label">Content Type</label>
<div class="col-sm-6">
<select class="form-select" v-model="labelerConfig.style">
<option v-for="option in viewTemplate.style" v-bind:value="option.value">
Expand Down Expand Up @@ -83,7 +84,7 @@ const sidebar = {
data-bs-target="#panelsStayOpen-collapseTwo" aria-expanded="true"
aria-controls="panelsStayOpen-collapseTwo">
Progress
<div class="spinner-border spinner-border-sm align-middle" role="status"
<div class="mx-2 spinner-border spinner-border-sm align-middle" role="status"
v-show="isBusy">
<span class="visually-hidden">Loading...</span>
</div>
Expand All @@ -105,6 +106,12 @@ const sidebar = {
:style="{width: negativeRate+'%' }"></div>
</div>
</div>
<div class="my-3 d-flex justify-content-center">
<button class="btn btn btn-outline-primary"
v-on:click="saveProgress()">
Save progress
</button>
</div>
</div>
</div>
<div class="accordion-item">
Expand All @@ -121,7 +128,7 @@ const sidebar = {
<div class="row my-1" v-for="option in advancedConfig">
<label class="col-sm-6 col-form-label">{{ option.text }}</label>
<div class="col-sm-6 text-end">
<input class="form-control" type="number" v-model.number="option.value">
<input class="form-control" type="{{ option.type }}" v-model.number="option.value">
</div>
</div>
</div>
Expand All @@ -135,7 +142,7 @@ const sidebar = {
</footer>
</div>
`,
mounted() {
console.log("sidebar is loaded")
}
mounted() {
console.log("sidebar is loaded")
}
}

0 comments on commit 98c584e

Please sign in to comment.