Update thorax model and improve model performance (#125)
Closes: #117 This bumps the thorax model from the yolo nano to the yolo sm (64 x 640 size) but greatly improves model performance by running a fake detection event on page load to get the model parameters in memory. As a result of that change a new loading message was required so the f7 preloader was switched out for an f7 progress bar and more messaging was added during various stages. The progress bar fixes the previous issue with the preloader. Signed-off-by: Justin Georgi <justin.georgi@gmail.com> Reviewed-on: #125
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
.detect-grid {
|
.detect-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr 56px auto min-content;
|
grid-template-rows: 1fr minmax(calc(var(--f7-chip-height) + 33px), auto) auto min-content;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"image-view"
|
"image-view"
|
||||||
"result-view"
|
"result-view"
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
--f7-chip-media-size: 32px;
|
--f7-chip-media-size: 32px;
|
||||||
--f7-chip-font-weight: normal;
|
--f7-chip-font-weight: normal;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +59,10 @@
|
|||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-hide {
|
||||||
|
display: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.selected-chip {
|
.selected-chip {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
box-shadow: 4px 4px 1px var(--avn-theme-color);
|
box-shadow: 4px 4px 1px var(--avn-theme-color);
|
||||||
|
|||||||
BIN
src/models/thorax/group1-shard10of11.bin
Normal file
BIN
src/models/thorax/group1-shard10of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard11of11.bin
Normal file
BIN
src/models/thorax/group1-shard11of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard1of11.bin
Normal file
BIN
src/models/thorax/group1-shard1of11.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/models/thorax/group1-shard2of11.bin
Normal file
BIN
src/models/thorax/group1-shard2of11.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/models/thorax/group1-shard3of11.bin
Normal file
BIN
src/models/thorax/group1-shard3of11.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/models/thorax/group1-shard4of11.bin
Normal file
BIN
src/models/thorax/group1-shard4of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard5of11.bin
Normal file
BIN
src/models/thorax/group1-shard5of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard6of11.bin
Normal file
BIN
src/models/thorax/group1-shard6of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard7of11.bin
Normal file
BIN
src/models/thorax/group1-shard7of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard8of11.bin
Normal file
BIN
src/models/thorax/group1-shard8of11.bin
Normal file
Binary file not shown.
BIN
src/models/thorax/group1-shard9of11.bin
Normal file
BIN
src/models/thorax/group1-shard9of11.bin
Normal file
Binary file not shown.
@@ -1,14 +1,14 @@
|
|||||||
description: Ultralytics best model trained on /data/ALVINN/Thorax/Thorax 0.1.0/thorax.yaml
|
description: Ultralytics best model trained on /data/ALVINN/Thorax/Thorax 0.1.0/thorax.yaml
|
||||||
author: Ultralytics
|
author: Ultralytics
|
||||||
license: AGPL-3.0 https://ultralytics.com/license
|
license: AGPL-3.0 https://ultralytics.com/license
|
||||||
date: '2024-03-05T17:01:14.129654'
|
date: '2024-03-07T16:03:03.296997'
|
||||||
version: 8.1.20
|
version: 8.1.20
|
||||||
stride: 32
|
stride: 32
|
||||||
task: detect
|
task: detect
|
||||||
batch: 1
|
batch: 1
|
||||||
imgsz:
|
imgsz:
|
||||||
- 992
|
- 640
|
||||||
- 992
|
- 640
|
||||||
names:
|
names:
|
||||||
0: Abdominal diaphragm
|
0: Abdominal diaphragm
|
||||||
1: Aorta
|
1: Aorta
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -13,7 +13,7 @@
|
|||||||
<f7-button @click="captureVidFrame()" style="position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%);" fill>Capture</f7-button>
|
<f7-button @click="captureVidFrame()" style="position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%);" fill>Capture</f7-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="(resultData && resultData.detections) || detecting" class="chip-results" style="grid-area: result-view; flex: 0 0 auto; align-self: center;">
|
<div class="chip-results" style="grid-area: result-view; flex: 0 0 auto; align-self: center;">
|
||||||
<f7-chip v-for="result in showResults.filter( r => { return r.aboveThreshold && r.isSearched && !r.isDeleted })"
|
<f7-chip v-for="result in showResults.filter( r => { return r.aboveThreshold && r.isSearched && !r.isDeleted })"
|
||||||
:class="(result.resultIndex == selectedChip) ? 'selected-chip' : ''"
|
:class="(result.resultIndex == selectedChip) ? 'selected-chip' : ''"
|
||||||
:text="result.label"
|
:text="result.label"
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
@delete="deleteChip(result.resultIndex)"
|
@delete="deleteChip(result.resultIndex)"
|
||||||
:style="chipGradient(result.confidence)"
|
:style="chipGradient(result.confidence)"
|
||||||
/>
|
/>
|
||||||
<span v-if="numResults == 0 && !detecting" style="height: var(--f7-chip-height); font-size: calc(var(--f7-chip-height) - 4px); font-weight: bolder; margin: 2px;">No results.</span>
|
<div v-if="!numResults" style="height: var(--f7-chip-height); width: 100%; text-align: center; font-size: calc(var(--f7-chip-height) - 4px); font-weight: bolder; margin: 2px;">{{ message }}</div>
|
||||||
<f7-preloader v-if="detecting || modelLoading" size="32" style="color: var(--avn-theme-color);" />
|
<f7-progressbar v-if="(detecting || modelLoading)" style="width: 100%;" :infinite="true" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showDetectSettings" class="detect-inputs" style="grid-area: detect-settings;">
|
<div v-if="showDetectSettings" class="detect-inputs" style="grid-area: detect-settings;">
|
||||||
<f7-range class="level-slide-horz" :min="0" :max="100" :step="1" @range:change="onLevelChange" v-model:value="detectorLevel" type="range" style="flex: 1 1 100%"/>
|
<f7-range class="level-slide-horz" :min="0" :max="100" :step="1" @range:change="onLevelChange" v-model:value="detectorLevel" type="range" style="flex: 1 1 100%"/>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<f7-button popover-open="#region-popover">
|
<f7-button popover-open="#region-popover">
|
||||||
<RegionIcon :region="activeRegion" />
|
<RegionIcon :region="activeRegion" />
|
||||||
</f7-button>
|
</f7-button>
|
||||||
<f7-button popover-open="#capture-popover">
|
<f7-button :class="(!modelLoading) ? '' : 'disabled'" popover-open="#capture-popover">
|
||||||
<SvgIcon icon="camera_add"/>
|
<SvgIcon icon="camera_add"/>
|
||||||
</f7-button>
|
</f7-button>
|
||||||
<f7-button @click="() => showDetectSettings = !showDetectSettings" :class="(imageLoaded) ? '' : 'disabled'">
|
<f7-button @click="() => showDetectSettings = !showDetectSettings" :class="(imageLoaded) ? '' : 'disabled'">
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
uploadUid: null,
|
uploadUid: null,
|
||||||
uploadDirty: false,
|
uploadDirty: false,
|
||||||
modelLocation: '',
|
modelLocation: '',
|
||||||
modelLoading: false,
|
modelLoading: true,
|
||||||
videoDeviceAvailable: false,
|
videoDeviceAvailable: false,
|
||||||
videoAvailable: false,
|
videoAvailable: false,
|
||||||
cameraStream: null
|
cameraStream: null
|
||||||
@@ -179,8 +179,11 @@
|
|||||||
}
|
}
|
||||||
var loadServerSettings = localStorage.getItem('serverSettings')
|
var loadServerSettings = localStorage.getItem('serverSettings')
|
||||||
if (loadServerSettings) this.serverSettings = JSON.parse(loadServerSettings)
|
if (loadServerSettings) this.serverSettings = JSON.parse(loadServerSettings)
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
if (this.serverSettings && this.serverSettings.use) {
|
if (this.serverSettings && this.serverSettings.use) {
|
||||||
this.getRemoteLabels()
|
this.getRemoteLabels()
|
||||||
|
this.modelLoading = false
|
||||||
} else {
|
} else {
|
||||||
this.modelLoading = true
|
this.modelLoading = true
|
||||||
this.detectorLabels = this.classesList.map( l => { return {'name': l, 'detect': true} } )
|
this.detectorLabels = this.classesList.map( l => { return {'name': l, 'detect': true} } )
|
||||||
@@ -189,11 +192,23 @@
|
|||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
console.log(e.message)
|
console.log(e.message)
|
||||||
f7.dialog.alert(`ALVINN AI model error: ${e.message}`)
|
f7.dialog.alert(`ALVINN AI model error: ${e.message}`)
|
||||||
|
this.modelLoading = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
window.onresize = (e) => { this.selectChip('redraw') }
|
window.onresize = (e) => { this.selectChip('redraw') }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
message () {
|
||||||
|
if (this.modelLoading) {
|
||||||
|
return "Preparing ALVINN..."
|
||||||
|
} else if (this.detecting) {
|
||||||
|
return "Finding structures..."
|
||||||
|
} else if (this.numResults == 0 && this.imageLoaded) {
|
||||||
|
return "No results."
|
||||||
|
} else {
|
||||||
|
return "ALVINN is ready."
|
||||||
|
}
|
||||||
|
},
|
||||||
showResults () {
|
showResults () {
|
||||||
var filteredResults = this.resultData.detections
|
var filteredResults = this.resultData.detections
|
||||||
if (!filteredResults) return []
|
if (!filteredResults) return []
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
import * as tf from '@tensorflow/tfjs'
|
import * as tf from '@tensorflow/tfjs'
|
||||||
import { f7 } from 'framework7-vue'
|
import { f7 } from 'framework7-vue'
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
|
||||||
var model = null
|
var model = null
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
async loadModel(weights) {
|
async loadModel(weights) {
|
||||||
model = await tf.loadGraphModel(weights).then(graphModel => {
|
await nextTick()
|
||||||
return graphModel
|
model = await tf.loadGraphModel(weights)
|
||||||
})
|
const [modelWidth, modelHeight] = model.inputs[0].shape.slice(1, 3)
|
||||||
|
const dummyT = tf.ones([1,modelWidth,modelHeight,3])
|
||||||
|
model.predict(dummyT) //Run model once to preload weights for better response time
|
||||||
|
return model
|
||||||
},
|
},
|
||||||
async localDetect(imageData) {
|
async localDetect(imageData) {
|
||||||
console.time('pre-process')
|
console.time('pre-process')
|
||||||
const [modelWidth, modelHeight] = model.inputs[0].shape.slice(1, 3);
|
const [modelWidth, modelHeight] = model.inputs[0].shape.slice(1, 3)
|
||||||
const input = tf.tidy(() => {
|
const input = tf.tidy(() => {
|
||||||
return tf.image.resizeBilinear(tf.browser.fromPixels(imageData), [modelWidth, modelHeight]).div(255.0).expandDims(0)
|
return tf.image.resizeBilinear(tf.browser.fromPixels(imageData), [modelWidth, modelHeight]).div(255.0).expandDims(0)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user