Skip to content

Commit

Permalink
refactored Captioner worker
Browse files Browse the repository at this point in the history
  • Loading branch information
cristianglezm committed Nov 14, 2024
1 parent aedc2f0 commit 2a89b9c
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 77 deletions.
15 changes: 11 additions & 4 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@
- [x] mutationsRates
- [x] AppActions
- [x] make new layout for settings
- [ ] fix error chrome - multiProgressBar closes after opening?
- [ ] chrome modelOptions - localhost not working
* [x] change xenova/transformers to huggingface/transformers
- [x] adapt code for it
* [ ] test all models
- it is slower than 2.17 version.
- q4 / q4f16 gives exception.
- q8 gives garbled output on Chrome
* [ ] review regression on inference time for CPU (master takes ~12s, q8 hf v3 takes ~1m5s)
* [ ] review RAM usage skyrockets to ~5GB (master is ~1GB)
- fp32 works on CPU
- fp16 gives exception
- q8 works on CPU (firefox, chrome)
- q8 gives garbled output on Chrome (GPU)
- int8 gives error on session creation (Can't create a session. ERROR_CODE: 9, ERROR_MESSAGE: Could not find an implementation for ConvInteger(10) node with name '/embeddings/patch_embeddings/projection/Conv_quant')
- uint8 works on CPU
- q4 works on CPU (it takes ~24s)
- q4f16 gives exception.
- bnb4 - works on CPU (it takes ~24s)
* [ ] fix not working on Chrome or Edge. (new models)
* [ ] Firefox webGPU not supported yet. (wait for it)

Expand Down
37 changes: 7 additions & 30 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import AppTitle from './components/AppTitle.vue';
import AppMenu from './components/AppMenu.vue';
import AppFooter from './components/AppFooter.vue';
import { useRoute } from 'vue-router';
import { Captioner } from './store/AIStore/AI';
import { useFlowersStore } from './store';
import { useAIStore } from './store/AIStore';
Expand All @@ -42,44 +41,22 @@ onMounted(() => {
status: "setup",
title: "downloading or loading model for describing flowers",
onLoad: async () => {
Captioner.setModelOptions(AIStore.modelOptions);
Captioner.getInstance((data) => {
switch(data.status){
case "initiate":{
let event = {
status: "init",
name: data.file,
progress: 0,
total: 100
};
emitter.emit('requestMultiProgressBar', event);
}
break;
case "progress":{
let event = {
status: "update",
name: data.file,
progress: data.progress
};
emitter.emit('requestMultiProgressBar', event);
}
break;
case "done":{
emitter.emit('ModelOptions#updateBtnTitle');
}
}
});
AIStore.requestModelLoad();
}
});
}, 2000);
});
AIStore.channel.on('App#ToEmitter', (e) => {
emitter.emit(e.eventName, e.event);
});
if(store.settings.loadModel){
emitter.emit('App#loadModel');
}
})
});
onUnmounted(() => {
AIStore.channel.off('App#ToEmitter');
emitter.off("App#loadModel");
})
});
/*!
* @license SIL Open Font License 1.1 - Copyright (c) 2023, GitHub
Expand Down
3 changes: 1 addition & 2 deletions src/components/FlowerCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
import { onMounted, reactive, inject, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import ParamsInfo from './ParamsInfo.vue';
import { Captioner } from '../store/AIStore/AI';
const props = defineProps({
id: {
Expand Down Expand Up @@ -194,7 +193,7 @@
store.shareFlower(props.genome);
};
const describe = () => {
if(!Captioner.hasModelLoaded()){
if(!AIStore.hasModelLoaded()){
store.errors.push({message: "check load model option or click download / load Model in Settings to use this."});
return;
}
Expand Down
15 changes: 6 additions & 9 deletions src/components/ModelOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
<button class="safe-button" :class="{ 'disabled': isModelLoaded() }" @click="loadModel"> {{ data.btnTitle }}</button>
</div>
<div v-if="data.openCache && isModelDownloaded()" style="text-align: center;">
<CacheManager :cacheName="'transformers-cache'" @on-delete="reloadCache" />
<button class="safe-button" @click="data.openCache = false"> Close </button>
<CacheManager :cacheName="'transformers-cache'" @on-delete="reloadCache" />
</div>
<div v-else style="text-align: center;">
<button class="safe-button" :class="{'disabled': !isModelDownloaded() }" :disabled="!isModelDownloaded()" @click="openCacheManager()"> Manage model cache </button>
Expand All @@ -53,7 +53,7 @@

<script setup>
import { computed, inject, nextTick, onMounted, onUnmounted, reactive } from 'vue';
import { Captioner, isGPUAvailable } from '../store/AIStore/AI'
import { isGPUAvailable } from '../store/AIStore/AI'
import { useAIStore } from '../store/AIStore';
import { CacheManager as CM } from '../store/CacheManager';
import CacheManager from './CacheManager.vue';
Expand All @@ -78,7 +78,7 @@
cm.reload();
};
const isModelLoaded = () => {
return Captioner.hasModelLoaded() && !data.forceReload;
return AIStore.hasModelLoaded() && !data.forceReload;
};
const isModelDownloaded = () => {
return cm.size() > 0;
Expand Down Expand Up @@ -106,16 +106,11 @@
if(isModelLoaded()){
return;
}
await Captioner.reset();
emitter.emit("App#loadModel");
data.forceReload = false;
}
const hasModelOptionsChanged = () => {
return (Captioner.modelOptions.host === AIStore.modelOptions.host &&
Captioner.modelOptions.model === AIStore.modelOptions.model &&
Captioner.modelOptions.device === AIStore.modelOptions.device &&
Captioner.modelOptions.encoder === AIStore.modelOptions.encoder &&
Captioner.modelOptions.decoder === AIStore.modelOptions.decoder);
return AIStore.hasModelOptionsChanged();
};
const setCorrectBtnTitle = () => {
if(isModelInCache()){
Expand All @@ -130,6 +125,8 @@
}
if(hasModelOptionsChanged()){
data.forceReload = true;
}else{
data.forceReload = false;
}
AIStore.saveModelOptions();
setCorrectBtnTitle();
Expand Down
70 changes: 54 additions & 16 deletions src/store/AIStore/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineStore } from 'pinia';
import { useFlowersStore } from '../index';
import WorkerManager from '../WorkerManager';
import captioner from '../../workers/captioner.worker?worker';
import { toRaw } from 'vue';

let channel = new mitt();
const wm = new WorkerManager(channel);
Expand All @@ -14,24 +15,39 @@ wm.onError('captioner', (e) => {
wm.onResponse('captioner', (data) => {
const store = useFlowersStore();
const AIStore = useAIStore();
const desc = {
id: data.FlowerID,
description: data.description,
};
if(data.isLocal){
AIStore.localDescriptions.set(desc.id, desc.description);
store.db.descriptions.add(desc);
}else{
AIStore.remoteDescriptions.set(desc.id, desc.description);
const jobType = data.jobType;
switch(jobType){
case "updateBtnTitle":{
channel.emit('App#ToEmitter', data);
}
break;
case "updateProgressBar":{
channel.emit('App#ToEmitter', data);
}
break;
case "descResult":{
const desc = {
id: data.FlowerID,
description: data.description,
};
if(data.isLocal){
AIStore.localDescriptions.set(desc.id, desc.description);
store.db.descriptions.add(desc);
}else{
AIStore.remoteDescriptions.set(desc.id, desc.description);
}
channel.emit('captioner#done', desc);
}
break;
}
channel.emit('captioner#done', desc);
});

export const STORAGE_KEY_MODEL_OPTIONS = "FlowerEVolverModelOptions";
export const useAIStore = defineStore('AIStore', {
state: () => ({
wm: wm,
channel: channel,
wm,
channel,
isModelLoaded: false,
remoteDescriptions: new Map(),
localDescriptions: new Map(),
modelOptions: JSON.parse(localStorage.getItem(STORAGE_KEY_MODEL_OPTIONS) || JSON.stringify({
Expand All @@ -40,14 +56,26 @@ export const useAIStore = defineStore('AIStore', {
device: "CPU",
encoder: "q8",
decoder: "q8"
}))
})),
oldModelOptions: null
}),
getters: {
getLocalDescription: (state) => (id) => {
return state.localDescriptions.get(id);
},
getRemoteDescription: (state) => (id) => {
return state.remoteDescriptions.get(id);
},
hasModelLoaded: (state) => () => {
return state.isModelLoaded;
},
hasModelOptionsChanged: (state) => () => {
if(state.oldModelOptions === null) return true;
return ((state.oldModelOptions.host !== state.modelOptions.host) ||
(state.oldModelOptions.model !== state.modelOptions.model) ||
(state.oldModelOptions.device !== state.modelOptions.device) ||
(state.oldModelOptions.encoder !== state.modelOptions.encoder) ||
(state.oldModelOptions.decoder !== state.modelOptions.decoder));
}
},
actions: {
Expand Down Expand Up @@ -80,10 +108,20 @@ export const useAIStore = defineStore('AIStore', {
},
async requestDescription(Flower){
this.wm.sendRequest('captioner', {
FlowerID: Flower.id,
urlOrDataURL: Flower.image,
isLocal: Flower.isLocal
jobType: "describe",
FlowerID: Flower.id,
urlOrDataURL: Flower.image,
isLocal: Flower.isLocal
});
},
async requestModelLoad(){
this.oldModelOptions = structuredClone(toRaw(this.modelOptions))
this.isModelLoaded = false;
this.wm.sendRequest('captioner', {
jobType: "loadModel",
modelOptions: structuredClone(toRaw(this.modelOptions))
});
this.isModelLoaded = true;
},
async saveModelOptions(){
localStorage.setItem(STORAGE_KEY_MODEL_OPTIONS, JSON.stringify(this.modelOptions));
Expand Down
Loading

0 comments on commit 2a89b9c

Please sign in to comment.