From f33a49b279b5692739dfa2db760be9649260520d Mon Sep 17 00:00:00 2001 From: r59q Date: Tue, 30 Jul 2024 20:33:58 +0200 Subject: [PATCH 1/2] Create confidences store --- .../training/KnnModelTrainingPageView.svelte | 5 +-- src/script/domain/ClassifierRepository.ts | 3 ++ src/script/domain/Repositories.ts | 1 + src/script/domain/stores/Confidences.ts | 36 +++++++++++++++++++ .../LocalStorageClassifierRepository.ts | 18 ++++------ .../repository/LocalStorageRepositories.ts | 4 ++- src/script/stores/Stores.ts | 7 ++++ 7 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 src/script/domain/stores/Confidences.ts diff --git a/src/pages/training/KnnModelTrainingPageView.svelte b/src/pages/training/KnnModelTrainingPageView.svelte index 2a812a4ed..3b188279d 100644 --- a/src/pages/training/KnnModelTrainingPageView.svelte +++ b/src/pages/training/KnnModelTrainingPageView.svelte @@ -16,8 +16,9 @@ import { onMount } from 'svelte'; import { knnConfig } from '../../script/stores/knnConfig'; const classifier = stores.getClassifier(); + const confidences = stores.getConfidences(); const gestures = stores.getGestures(); - const confidences = gestures.getConfidences(); + //const confidences = gestures.getConfidences(); const filters = classifier.getFilters(); onMount(() => { @@ -85,7 +86,7 @@ {#if $state.isInputReady}

- {(($confidences.get(gesture.ID)?.currentConfidence ?? 0) * 100).toFixed(2)}% + {(($confidences.get(gesture.ID) ?? 0) * 100).toFixed(2)}%

{/if} diff --git a/src/script/domain/ClassifierRepository.ts b/src/script/domain/ClassifierRepository.ts index edec00ef2..5eb367dfb 100644 --- a/src/script/domain/ClassifierRepository.ts +++ b/src/script/domain/ClassifierRepository.ts @@ -4,12 +4,15 @@ * SPDX-License-Identifier: MIT */ import Classifier from './stores/Classifier'; +import Confidences from './stores/Confidences'; import GestureConfidence from './stores/gesture/GestureConfidence'; interface ClassifierRepository { getClassifier(): Classifier; getGestureConfidence(gestureId: number): GestureConfidence; + + getConfidences(): Confidences; } export default ClassifierRepository; diff --git a/src/script/domain/Repositories.ts b/src/script/domain/Repositories.ts index b1340367b..e49450864 100644 --- a/src/script/domain/Repositories.ts +++ b/src/script/domain/Repositories.ts @@ -5,6 +5,7 @@ */ import ClassifierRepository from './ClassifierRepository'; import GestureRepository from './GestureRepository'; +import Confidences from './stores/Confidences'; interface Repositories { getGestureRepository(): GestureRepository; diff --git a/src/script/domain/stores/Confidences.ts b/src/script/domain/stores/Confidences.ts new file mode 100644 index 000000000..ced999d42 --- /dev/null +++ b/src/script/domain/stores/Confidences.ts @@ -0,0 +1,36 @@ +import { Readable, Subscriber, Unsubscriber, Writable, get, writable } from "svelte/store"; +import { GestureID } from "./gesture/Gesture"; + +type GestureConfidenceMap = Map; + +class Confidences implements Readable { + private confidenceStore: Writable; + + constructor() { + this.confidenceStore = writable(new Map()); + } + + public subscribe( + run: Subscriber, + invalidate?: ((value?: GestureConfidenceMap | undefined) => void) | undefined + ): Unsubscriber { + return this.confidenceStore.subscribe(run, invalidate); + } + + public setConfidence(gestureId: GestureID, confidence: number): void { + this.confidenceStore.update((map: GestureConfidenceMap) => { + map.set(gestureId, confidence); + return map; + }); + } + + public getConfidence(gestureId: GestureID): number { + const confidence = get(this.confidenceStore).get(gestureId); + if (confidence === undefined) { + throw new Error(`No confidence value found for gesture with ID ${gestureId}`); + } + return confidence; + } +} + +export default Confidences; \ No newline at end of file diff --git a/src/script/repository/LocalStorageClassifierRepository.ts b/src/script/repository/LocalStorageClassifierRepository.ts index 870e2b4a8..2518190d1 100644 --- a/src/script/repository/LocalStorageClassifierRepository.ts +++ b/src/script/repository/LocalStorageClassifierRepository.ts @@ -17,6 +17,7 @@ import ClassifierRepository from '../domain/ClassifierRepository'; import Gesture, { GestureID } from '../domain/stores/gesture/Gesture'; import Classifier from '../domain/stores/Classifier'; import GestureConfidence from '../domain/stores/gesture/GestureConfidence'; +import Confidences from '../domain/stores/Confidences'; export type TrainerConsumer = ( trainer: ModelTrainer, @@ -24,15 +25,12 @@ export type TrainerConsumer = ( class LocalStorageClassifierRepository implements ClassifierRepository { private static readonly PERSISTANT_FILTERS_KEY = 'filters'; - private static confidences: Writable>; private static mlModel: Writable; private static filters: Filters; private static persistedFilters: PersistantWritable; private classifierFactory: ClassifierFactory; - constructor() { - const initialConfidence = new Map(); - LocalStorageClassifierRepository.confidences = writable(initialConfidence); + constructor(private confidences: Confidences) { LocalStorageClassifierRepository.mlModel = writable(undefined); LocalStorageClassifierRepository.persistedFilters = new PersistantWritable( FilterTypes.toIterable(), @@ -82,9 +80,7 @@ class LocalStorageClassifierRepository implements ClassifierRepository { if (confidence < 0 || confidence > 1) { throw new Error('Cannot set gesture confidence. Must be in the range 0.0-1.0'); } - const newConfidences = get(LocalStorageClassifierRepository.confidences); - newConfidences.set(gestureId, confidence); - LocalStorageClassifierRepository.confidences.set(newConfidences); + this.confidences.setConfidence(gestureId, confidence); } private getFilters(): Writable { @@ -114,7 +110,7 @@ class LocalStorageClassifierRepository implements ClassifierRepository { public getGestureConfidence(gestureId: number): GestureConfidence { const derivedConfidence = derived( - [LocalStorageClassifierRepository.confidences], + [this.confidences], stores => { const confidenceStore = stores[0]; if (confidenceStore.has(gestureId)) { @@ -130,11 +126,11 @@ class LocalStorageClassifierRepository implements ClassifierRepository { } public hasGestureConfidence(gestureId: number): boolean { - return get(LocalStorageClassifierRepository.confidences).has(gestureId); + return get(this.confidences).has(gestureId); } - public getConfidences(): Writable> { - return LocalStorageClassifierRepository.confidences; + public getConfidences(): Confidences { + return this.confidences; } } diff --git a/src/script/repository/LocalStorageRepositories.ts b/src/script/repository/LocalStorageRepositories.ts index 5020108d6..2e27b6188 100644 --- a/src/script/repository/LocalStorageRepositories.ts +++ b/src/script/repository/LocalStorageRepositories.ts @@ -6,6 +6,7 @@ import LocalStorageGestureRepository from './LocalStorageGestureRepository'; import LocalStorageClassifierRepository from './LocalStorageClassifierRepository'; import Repositories from '../domain/Repositories'; +import Confidences from '../domain/stores/Confidences'; class LocalStorageRepositories implements Repositories { private gestureRepository: LocalStorageGestureRepository; @@ -20,7 +21,8 @@ class LocalStorageRepositories implements Repositories { throw new Error('Could not instantiate repository. It is already instantiated!'); } LocalStorageRepositories.instance = this; - this.classifierRepository = new LocalStorageClassifierRepository(); + const confidences = new Confidences(); + this.classifierRepository = new LocalStorageClassifierRepository(confidences); this.gestureRepository = new LocalStorageGestureRepository(this.classifierRepository); } diff --git a/src/script/stores/Stores.ts b/src/script/stores/Stores.ts index a9f5aa552..55e566ba7 100644 --- a/src/script/stores/Stores.ts +++ b/src/script/stores/Stores.ts @@ -23,6 +23,7 @@ import Gestures from '../domain/stores/gesture/Gestures'; import PollingPredictorEngine from '../engine/PollingPredictorEngine'; import LocalStorageRepositories from '../repository/LocalStorageRepositories'; import Logger from '../utils/Logger'; +import Confidences from '../domain/stores/Confidences'; type StoresType = { liveData: LiveData; @@ -35,12 +36,14 @@ class Stores implements Readable { private engine: Engine | undefined; private classifier: Classifier; private gestures: Gestures; + private confidences: Confidences; public constructor() { this.liveData = writable(undefined); this.engine = undefined; const repositories: Repositories = new LocalStorageRepositories(); this.classifier = repositories.getClassifierRepository().getClassifier(); + this.confidences = repositories.getClassifierRepository().getConfidences(); this.gestures = new Gestures( repositories.getClassifierRepository(), repositories.getGestureRepository(), @@ -94,6 +97,10 @@ class Stores implements Readable { } return this.engine; } + + public getConfidences(): Confidences { + return this.confidences; + } } export const stores = new Stores(); From 01d8ef06a09ed8b50d629cc96dbb77e8a98cc6c6 Mon Sep 17 00:00:00 2001 From: r59q Date: Tue, 30 Jul 2024 20:53:07 +0200 Subject: [PATCH 2/2] Rework confidences --- src/script/domain/stores/Confidences.ts | 62 +++++++++++-------- src/script/domain/stores/gesture/Gestures.ts | 34 +--------- .../LocalStorageClassifierRepository.ts | 17 +++-- src/script/stores/Stores.ts | 5 +- 4 files changed, 46 insertions(+), 72 deletions(-) diff --git a/src/script/domain/stores/Confidences.ts b/src/script/domain/stores/Confidences.ts index ced999d42..2efbb380b 100644 --- a/src/script/domain/stores/Confidences.ts +++ b/src/script/domain/stores/Confidences.ts @@ -1,36 +1,48 @@ -import { Readable, Subscriber, Unsubscriber, Writable, get, writable } from "svelte/store"; -import { GestureID } from "./gesture/Gesture"; +/** + * (c) 2023, Center for Computational Thinking and Design at Aarhus University and contributors + * + * SPDX-License-Identifier: MIT + */ +import { + Readable, + Subscriber, + Unsubscriber, + Writable, + get, + writable, +} from 'svelte/store'; +import { GestureID } from './gesture/Gesture'; type GestureConfidenceMap = Map; class Confidences implements Readable { - private confidenceStore: Writable; + private confidenceStore: Writable; - constructor() { - this.confidenceStore = writable(new Map()); - } + constructor() { + this.confidenceStore = writable(new Map()); + } - public subscribe( - run: Subscriber, - invalidate?: ((value?: GestureConfidenceMap | undefined) => void) | undefined - ): Unsubscriber { - return this.confidenceStore.subscribe(run, invalidate); - } + public subscribe( + run: Subscriber, + invalidate?: ((value?: GestureConfidenceMap | undefined) => void) | undefined, + ): Unsubscriber { + return this.confidenceStore.subscribe(run, invalidate); + } - public setConfidence(gestureId: GestureID, confidence: number): void { - this.confidenceStore.update((map: GestureConfidenceMap) => { - map.set(gestureId, confidence); - return map; - }); - } + public setConfidence(gestureId: GestureID, confidence: number): void { + this.confidenceStore.update((map: GestureConfidenceMap) => { + map.set(gestureId, confidence); + return map; + }); + } - public getConfidence(gestureId: GestureID): number { - const confidence = get(this.confidenceStore).get(gestureId); - if (confidence === undefined) { - throw new Error(`No confidence value found for gesture with ID ${gestureId}`); - } - return confidence; + public getConfidence(gestureId: GestureID): number { + const confidence = get(this.confidenceStore).get(gestureId); + if (confidence === undefined) { + throw new Error(`No confidence value found for gesture with ID ${gestureId}`); } + return confidence; + } } -export default Confidences; \ No newline at end of file +export default Confidences; diff --git a/src/script/domain/stores/gesture/Gestures.ts b/src/script/domain/stores/gesture/Gestures.ts index 9c3ecdeb2..cd6033356 100644 --- a/src/script/domain/stores/gesture/Gestures.ts +++ b/src/script/domain/stores/gesture/Gestures.ts @@ -37,41 +37,13 @@ export type RecordingData = { class Gestures implements Readable { private static subscribableGestures: Writable; private repository: GestureRepository; - private confidenceStore: Readable>; - constructor(classifierRepository: ClassifierRepository, repository: GestureRepository) { + constructor(repository: GestureRepository) { this.repository = repository; Gestures.subscribableGestures = writable(); this.repository.subscribe(storeArray => { Gestures.subscribableGestures.set(storeArray); }); - - this.confidenceStore = derived([this, ...this.getGestures()], stores => { - const confidenceMap: Map = new Map(); - - const [_, ...gestureStores] = stores; - const thiz = stores[0] as GestureData[]; - thiz.forEach(gesture => { - // TODO: The following ought to be fixed. See https://github.com/microbit-foundation/cctd-ml-machine/issues/508 - const store = gestureStores.find(store => store.ID === gesture.ID) - ?.confidence || { - currentConfidence: 0, - requiredConfidence: 0, - isConfident: false, - }; - confidenceMap.set(gesture.ID, { - ...store, - currentConfidence: classifierRepository - .getGestureConfidence(gesture.ID) - .getCurrentConfidence(), - }); - }); - - /*gestureStores.forEach(store => { - confidenceMap.set(store.ID, store.confidence); - });*/ - return confidenceMap; - }); } public subscribe( @@ -159,10 +131,6 @@ class Gestures implements Readable { ); } - public getConfidences(): Readable> { - return this.confidenceStore; - } - private addGestureFromPersistedData(gestureData: PersistantGestureData): Gesture { return this.repository.addGesture(gestureData); } diff --git a/src/script/repository/LocalStorageClassifierRepository.ts b/src/script/repository/LocalStorageClassifierRepository.ts index 2518190d1..2b994950c 100644 --- a/src/script/repository/LocalStorageClassifierRepository.ts +++ b/src/script/repository/LocalStorageClassifierRepository.ts @@ -109,16 +109,13 @@ class LocalStorageClassifierRepository implements ClassifierRepository { } public getGestureConfidence(gestureId: number): GestureConfidence { - const derivedConfidence = derived( - [this.confidences], - stores => { - const confidenceStore = stores[0]; - if (confidenceStore.has(gestureId)) { - return confidenceStore.get(gestureId) as number; - } - throw new Error("No confidence found for gesture with id '" + gestureId + "'"); - }, - ); + const derivedConfidence = derived([this.confidences], stores => { + const confidenceStore = stores[0]; + if (confidenceStore.has(gestureId)) { + return confidenceStore.get(gestureId) as number; + } + throw new Error("No confidence found for gesture with id '" + gestureId + "'"); + }); return new GestureConfidence( StaticConfiguration.defaultRequiredConfidence, derivedConfidence, diff --git a/src/script/stores/Stores.ts b/src/script/stores/Stores.ts index 55e566ba7..b6fdd071f 100644 --- a/src/script/stores/Stores.ts +++ b/src/script/stores/Stores.ts @@ -44,10 +44,7 @@ class Stores implements Readable { const repositories: Repositories = new LocalStorageRepositories(); this.classifier = repositories.getClassifierRepository().getClassifier(); this.confidences = repositories.getClassifierRepository().getConfidences(); - this.gestures = new Gestures( - repositories.getClassifierRepository(), - repositories.getGestureRepository(), - ); + this.gestures = new Gestures(repositories.getGestureRepository()); } public subscribe(