Skip to content

Commit f63ad12

Browse files
marySalvisubdavis
andauthored
Labels.txt Upload (#1072)
* prelim work * add import of labels.txt to training menu * add labels.text as type and parameter * start work on adding labels.txt to viame run training * add labelText to desktop calls * update task for label_text * make labels command conditional on labels file existence * lint and tox * make labelText optional parameter * remove unnecessary TxtType and labelText values * make return for runTrainingOnFolder conditional and standardized async function * correct params order for labelText to be last and optional * send labelText as part of body of request * remove import button and openFromDisk method * remove incorrect test type * fix lint error and create pydantic class for training args * fix silly lint error * remove unnecessary txt typing * Add Documentation for Labels.txt (#1092) * WIP * Update Pipeline-Documentation.md Co-authored-by: Brandon Davis <brandon.davis@kitware.com>
1 parent a4a0b1e commit f63ad12

14 files changed

Lines changed: 141 additions & 25 deletions

File tree

client/dive-common/apispec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ interface Api {
111111

112112
getTrainingConfigurations(): Promise<TrainingConfigs>;
113113
runTraining(
114-
folderIds: string[], pipelineName: string, config: string, annotatedFramesOnly: boolean
114+
folderIds: string[],
115+
pipelineName: string,
116+
config: string,
117+
annotatedFramesOnly: boolean,
118+
labelText?: string,
115119
): Promise<unknown>;
116120

117121
loadMetadata(datasetId: string): Promise<DatasetMeta>;

client/platform/desktop/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ export interface RunTraining {
151151
trainingConfig: string;
152152
// train only on annotated frames
153153
annotatedFramesOnly: boolean;
154+
// contents of labels.txt file
155+
labelText?: string;
154156
}
155157

156158
export interface ConversionArgs {

client/platform/desktop/frontend/api.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,18 @@ async function runPipeline(itemId: string, pipeline: Pipe): Promise<DesktopJob>
9090
}
9191

9292
async function runTraining(
93-
folderIds: string[], pipelineName: string, config: string, annotatedFramesOnly: boolean,
93+
folderIds: string[],
94+
pipelineName: string,
95+
config: string,
96+
annotatedFramesOnly: boolean,
97+
labelText?: string,
9498
): Promise<DesktopJob> {
9599
const args: RunTraining = {
96100
datasetIds: folderIds,
97101
pipelineName,
98102
trainingConfig: config,
99103
annotatedFramesOnly,
104+
labelText,
100105
};
101106
return ipcRenderer.invoke('run-training', args);
102107
}

client/platform/web-girder/api/rpc.service.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ function runPipeline(itemId: string, pipeline: Pipe) {
1717
}
1818

1919
function runTraining(
20-
folderIds: string[], pipelineName: string, config: string, annotatedFramesOnly: boolean,
20+
folderIds: string[],
21+
pipelineName: string,
22+
config: string,
23+
annotatedFramesOnly: boolean,
24+
labelText?: string,
2125
) {
22-
return girderRest.post('dive_rpc/train', folderIds, {
23-
params: { pipelineName, config, annotatedFramesOnly },
26+
return girderRest.post('dive_rpc/train', { folderIds, labelText }, {
27+
params: {
28+
pipelineName, config, annotatedFramesOnly,
29+
},
2430
});
2531
}
2632

client/platform/web-girder/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Promise<{ canceled: boolean; filePaths: string[]; fileList?: File[]}> {
5252
input.accept = inputAnnotationTypes
5353
.concat(inputAnnotationFileTypes.map((item) => `.${item}`)).join(',');
5454
}
55+
5556
return new Promise(((resolve) => {
5657
input.onchange = (event) => {
5758
if (event) {

client/platform/web-girder/views/Export.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
DatasetSourceMedia, getDataset, getDatasetMedia, getUri,
1010
} from 'platform/web-girder/api';
1111
import { GirderMetadataStatic } from 'platform/web-girder/constants';
12-
import { ImageSequenceType, MultiType, VideoType } from 'dive-common/constants';
12+
import {
13+
ImageSequenceType, MultiType, VideoType,
14+
} from 'dive-common/constants';
1315
1416
export default defineComponent({
1517
components: { AutosavePrompt },

client/platform/web-girder/views/Home.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
import { mapGetters, mapState } from 'vuex';
1010
1111
import RunPipelineMenu from 'dive-common/components/RunPipelineMenu.vue';
12-
import RunTrainingMenu from 'dive-common/components/RunTrainingMenu.vue';
1312
import { usePrompt } from 'dive-common/vue-utilities/prompt-service';
13+
import RunTrainingMenu from './RunTrainingMenu.vue';
1414
1515
import { deleteResources, getUri } from '../api';
1616
import Export from './Export.vue';

client/dive-common/components/RunTrainingMenu.vue renamed to client/platform/web-girder/views/RunTrainingMenu.vue

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
<script lang="ts">
22
import {
3-
defineComponent, computed, PropType, ref, onBeforeMount,
3+
defineComponent, computed, PropType, ref, onBeforeMount, watch,
44
} from '@vue/composition-api';
55
66
import { useApi, TrainingConfigs } from 'dive-common/apispec';
77
import JobLaunchDialog from 'dive-common/components/JobLaunchDialog.vue';
8+
import ImportButton from 'dive-common/components/ImportButton.vue';
89
import { useRequest } from 'dive-common/use';
910
11+
1012
export default defineComponent({
1113
name: 'RunTrainingMenu',
1214
13-
components: { JobLaunchDialog },
15+
components: { JobLaunchDialog, ImportButton },
1416
1517
props: {
1618
selectedDatasetIds: {
@@ -50,6 +52,8 @@ export default defineComponent({
5052
const trainingDisabled = computed(() => props.selectedDatasetIds.length === 0);
5153
const trainingOutputName = ref<string | null>(null);
5254
const menuOpen = ref(false);
55+
const labelText = ref<string>('');
56+
const labelFile = ref<File>();
5357
5458
async function runTrainingOnFolder() {
5559
const outputPipelineName = trainingOutputName.value;
@@ -60,6 +64,15 @@ export default defineComponent({
6064
if (!trainingConfigurations.value || !selectedTrainingConfig.value) {
6165
throw new Error('Training configurations not found.');
6266
}
67+
if (labelText) {
68+
return runTraining(
69+
props.selectedDatasetIds,
70+
outputPipelineName,
71+
selectedTrainingConfig.value,
72+
annotatedFramesOnly.value,
73+
labelText.value,
74+
);
75+
}
6376
return runTraining(
6477
props.selectedDatasetIds,
6578
outputPipelineName,
@@ -71,6 +84,21 @@ export default defineComponent({
7184
trainingOutputName.value = null;
7285
}
7386
87+
watch(labelFile, () => {
88+
if (labelFile.value) {
89+
const reader = new FileReader();
90+
reader.onload = (evt) => {
91+
labelText.value = evt.target?.result as string;
92+
};
93+
reader.readAsText(labelFile.value);
94+
}
95+
});
96+
97+
const clearLabelText = () => {
98+
labelText.value = '';
99+
};
100+
101+
74102
return {
75103
trainingConfigurations,
76104
selectedTrainingConfig,
@@ -82,6 +110,8 @@ export default defineComponent({
82110
successMessage,
83111
dismissJobDialog,
84112
runTrainingOnFolder,
113+
labelFile,
114+
clearLabelText,
85115
};
86116
},
87117
});
@@ -136,6 +166,11 @@ export default defineComponent({
136166
<p>
137167
Specify the name of the resulting pipeline
138168
and configuration file to use for training.
169+
Check the
170+
<a href="https://kitware.github.io/dive/Pipeline-Documentation/#training">
171+
documentation
172+
</a>
173+
for more information about these options.
139174
</p>
140175
<v-alert
141176
dense
@@ -149,9 +184,10 @@ export default defineComponent({
149184
<v-text-field
150185
v-model="trainingOutputName"
151186
outlined
152-
hide-details
153187
class="my-4"
154-
label="Output Name"
188+
label="New Model Name"
189+
hint="Choose a name for the newly trained model"
190+
persistent-hint
155191
/>
156192
<v-select
157193
v-model="selectedTrainingConfig"
@@ -161,10 +197,18 @@ export default defineComponent({
161197
label="Configuration File"
162198
:items="trainingConfigurations.configs"
163199
/>
200+
<v-file-input
201+
v-model="labelFile"
202+
icon="mdi-folder-open"
203+
label="Labels.txt mapping file (optional)"
204+
hint="Combine or rename output classes using a labels.txt file"
205+
persistent-hint
206+
clearable
207+
@click:clear="clearLabelText"
208+
/>
164209
<v-checkbox
165210
v-model="annotatedFramesOnly"
166211
label="Use annotated frames only"
167-
dense
168212
hint="Train only on frames with groundtruth and ignore frames without annotations"
169213
persistent-hint
170214
class="pt-0"

docs/Pipeline-Documentation.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,35 @@ Run model training on ground truth annotations. Currently, training configurati
7272

7373
### Options
7474

75-
* Output Name - a recognizeable name for the pipeline that results from the training run.
76-
* Configuration File - chosen from the options below
77-
* Use anootation Frames Only - by default, training runs include all frames from the chosen input datasets, and frames without annotations are considered negatives examples. If you choose to use annotated frames only, frames or images with zero annotations will be discarded. This option is useful for trying to train on datasets that are only partially annotated.
75+
![Training options dialog](images/TrainingMenu.png)
76+
77+
#### New Model Name
78+
79+
A recognizable name for the pipeline that results from the training run.
80+
81+
#### Configuration File
82+
83+
One of the configuration options in the table below.
84+
85+
#### Labels.txt file
86+
87+
This **optional** file controls the output classes that a newly trained model will generate.
88+
89+
* Use if you annotated using higher granularity labels (such as species names) and want to train a classifier using more
90+
* Or you want to restrict your training session to only train on certain kinds of ground-truth data.
91+
92+
The following example `labels.txt` shows how to train a `FISH` classifier by combining `redfish` and `bluefish`, preserve the `ROCK` label, and omit every other label.
93+
94+
``` text
95+
FISH redfish bluefish
96+
ROCK
97+
```
98+
99+
By default, all classes from all input datasets are preserved in the output model.
100+
101+
#### Use annotation frames only
102+
103+
By default, training runs include all frames from the chosen input datasets, and frames without annotations are considered negatives examples. If you choose to use annotated frames only, frames or images with zero annotations will be discarded. This option is useful for trying to train on datasets that are only partially annotated.
78104

79105
### Configurations
80106

docs/images/TrainingMenu.png

78.9 KB
Loading

0 commit comments

Comments
 (0)