From 40447812d96f82c4d9da66e23b4f358ee39beab6 Mon Sep 17 00:00:00 2001 From: Mattk70 Date: Mon, 22 Jan 2024 16:07:05 +0000 Subject: [PATCH] Fixed windows model loading Updated Settings help for location filter Fixed BirdNet location filter --- Help/settings.html | 3 +- js/BirdNet.js | 576 ------------------------------------------- js/BirdNet2.4.js | 21 +- js/model.js | 9 +- v2_model_config.json | 2 +- 5 files changed, 19 insertions(+), 592 deletions(-) delete mode 100644 js/BirdNet.js diff --git a/Help/settings.html b/Help/settings.html index b9c61af8..b267bead 100644 --- a/Help/settings.html +++ b/Help/settings.html @@ -30,7 +30,8 @@ Search for -

Migrants and Owls. Just report detections relating to these species' calls (song detections are +

Birds in your Region. Exclude birds unlikely to be found in your location.

+

Nocturnal Birds. Just report detections relating to these species' calls (song detections are excluded).

All birds. Include birdsong as well as calls, also includes species not known to call at night.

diff --git a/js/BirdNet.js b/js/BirdNet.js deleted file mode 100644 index b01e112e..00000000 --- a/js/BirdNet.js +++ /dev/null @@ -1,576 +0,0 @@ -const tf = require('@tensorflow/tfjs-node'); -const fs = require('node:fs'); -const path = require('node:path'); -let DEBUG = false; -let BACKEND; - -//GLOBALS -let myModel; -const MIGRANTS = new Set(["Pluvialis dominica_American Golden Plover", "Acanthis hornemanni_Arctic Redpoll", "Sterna paradisaea_Arctic Tern", "Recurvirostra avosetta_Avocet", "Porzana pusilla_Baillon's Crake", "Limosa lapponica_Bar-tailed Godwit", "Tyto alba_Barn Owl", "Branta leucopsis_Barnacle Goose", "Cygnus columbianus_Bewick's Swan", "Botaurus stellaris_Bittern", "Chroicocephalus ridibundus_Black-headed Gull", "Podiceps nigricollis_Black-necked Grebe", "Limosa limosa_Black-tailed Godwit", "Turdus merula_Blackbird", "Sylvia atricapilla_Blackcap", "Fringilla montifringilla_Brambling", "Branta bernicla_Brent Goose", "Branta canadensis_Canada Goose", "Larus cachinnans_Caspian Gull", "Phylloscopus collybita_Chiffchaff", "Loxia curvirostra_Common Crossbill", "Larus canus_Common Gull", "Acanthis flammea_Common Redpoll", "Actitis hypoleucos_Common Sandpiper", "Melanitta nigra_Common Scoter", "Sterna hirundo_Common Tern", "Fulica atra_Coot", "Crex crex_Corncrake", "Cuculus canorus_Cuckoo", "Calidris ferruginea_Curlew Sandpiper", "Numenius arquata_Curlew", "Charadrius morinellus_Dotterel", "Calidris alpina_Dunlin", "Prunella modularis_Dunnock", "Alopochen aegyptiaca_Egyptian Goose", "Turdus pilaris_Fieldfare", "Mareca strepera_Gadwall", "Sylvia borin_Garden Warbler", "Spatula querquedula_Garganey", "Regulus regulus_Goldcrest", "Pluvialis apricaria_Golden Plover", "Bucephala clangula_Goldeneye", "Mergus merganser_Goosander", "Locustella naevia_Grasshopper Warbler", "Larus marinus_Great Black-backed Gull", "Podiceps cristatus_Great Crested Grebe", "Tringa ochropus_Green Sandpiper", "Tringa nebularia_Greenshank", "Ardea cinerea_Grey Heron", "Perdix perdix_Grey Partridge", "Phalaropus fulicarius_Grey", "Pluvialis squatarola_Grey Plover", "Motacilla cinerea_Grey Wagtail ", "Anser anser_Greylag Goose", "Delichon urbicum_House Martin", "Coccothraustes coccothraustes_Hawfinch", "Larus argentatus_Herring Gull", "Lymnocryptes minimus_Jack Snipe", "Alcedo atthis_Kingfisher", "Calidris canutus_Knot", "Calcarius lapponicus_Lapland Bunting", "Larus fuscus_Lesser Black-backed Gull", "Acanthis cabaret_Lesser Redpoll ", "Sylvia curruca_Lesser Whitethroat", "Linaria cannabina_Linnet", "Egretta garzetta_Little Egret", "Tachybaptus ruficollis_Little Grebe", "Hydrocoloeus minutus_Little Gull", "Athene noctua_Little Owl", "Charadrius dubius_Little Ringed Plover", "Calidris minuta_Little Stint ", "Sternula albifrons_Little Tern", "Asio otus_Long-eared Owl", "Clangula hyemalis_Long-tailed Duck", "Anas platyrhynchos_Mallard", "Aix galericulata_Mandarin Duck", "Anthus pratensis_Meadow Pipit", "Ichthyaetus melanocephalus_Mediterranean Gull", "Turdus viscivorus_Mistle Thrush", "Gallinula chloropus_Moorhen", "Nycticorax nycticorax_Night Heron", "Luscinia megarhynchos_Nightingale", "Luscinia megarhynchos_Nightingale (song)", "Caprimulgus europaeus_Nightjar", "Anthus hodgsoni_Olive-backed Pipit", "Emberiza hortulana_Ortolan Bunting", "Emberiza pusilla_Little Bunting", "Haematopus ostralegus_Oystercatcher", "Ficedula hypoleuca_Pied Flycatcher", "Motacilla alba_Pied Wagtail", "Anser brachyrhynchus_Pink-footed Goose", "Anas acuta_Pintail", "Aythya ferina_Pochard", "Calidris maritima_Purple Sandpiper", "Coturnix coturnix_Quail", "Mergus serrator_Red-breasted Merganser", "Netta rufina_Red-crested Pochard", "Alectoris rufa_Red-legged Partridge", "Tringa totanus_Redshank", "Phoenicurus phoenicurus_Redstart", "Turdus iliacus_Redwing", "Emberiza schoeniclus_Reed Bunting", "Acrocephalus scirpaceus_Reed Warbler", "Turdus torquatus_Ring Ouzel", "Charadrius hiaticula_Ringed Plover", "Erithacus rubecula_Robin (flight call)", "Anthus petrosus_Rock Pipit", "Sterna dougallii_Roseate Tern", "Calidris pugnax_Ruff", "Riparia riparia_Sand Martin", "Calidris alba_Sanderling", "Thalasseus sandvicensis_Sandwich Tern", "Aythya marila_Scaup", "Loxia scotica_Scottish Crossbill", "Acrocephalus schoenobaenus_Sedge Warbler", "Tadorna tadorna_Shelduck", "Asio flammeus_Short-eared Owl", "Spatula clypeata_Shoveler", "Spinus spinus_Siskin", "Alauda arvensis_Skylark", "Gallinago gallinago_Snipe", "Plectrophenax nivalis_Snow Bunting", "Turdus philomelos_Song Thrush", "Porzana porzana_Spotted Crake", "Muscicapa striata_Spotted Flycatcher", "Tringa erythropus_Spotted Redshank", "Burhinus oedicnemus_Stone-curlew", "Saxicola rubicola_Stonechat", "Hirundo rustica_Swallow", "Apus apus_Swift", "Anser fabalis_Taiga Bean Goose", "Strix aluco_Tawny Owl", "Anas crecca_Teal", "Anthus trivialis_Tree Pipit", "Aythya fuligula_Tufted Duck", "Anser serrirostris_Tundra Bean Goose", "Arenaria interpres_Turnstone", "Anthus spinoletta_Water Pipit", "Rallus aquaticus_Water Rail", "Numenius phaeopus_Whimbrel", "Anser albifrons_White-fronted Goose", "Sylvia communis_Whitethroat", "Cygnus cygnus_Whooper Swan", "Mareca penelope_Wigeon", "Phylloscopus trochilus_Willow Warbler", "Tringa glareola_Wood Sandpiper", "Scolopax rusticola_Woodcock", "Lullula arborea_Woodlark", "Larus michahellis_Yellow-legged Gull", "Motacilla flava_Yellow Wagtail", "Emberiza citrinella_Yellowhammer"]); -const NOT_BIRDS = ['Ambient Noise_Ambient Noise', 'Animal_Animal', 'Cat_Cat', 'Church Bells_Church Bells', 'Cough_Cough', 'Dog_Dog', 'Human_Human', 'Laugh_Laugh', 'Rain_Rain', 'Red Fox_Red Fox', 'Sneeze_Sneeze', 'Snoring_Snoring', 'Thunder_Thunder', 'Vehicle_Vehicle', 'Water Drops_Water Drops', 'Waves_Waves', 'Wind_Wind']; -const MYSTERIES = ['Unknown Sp._Unknown Sp.']; -const GRAYLIST = []; -const GOLDEN_LIST = [] -let BLOCKED_IDS = []; -let SUPPRESSED_IDS = []; -let ENHANCED_IDS = []; -const CONFIG = { - sampleRate: 48_000, specLength: 3, sigmoid: 1, -}; - - -onmessage = async (e) => { - const modelRequest = e.data.message; - let response; - try { - switch (modelRequest) { - case "load": {const version = e.data.model; -if (DEBUG) { - console.log("load request to worker"); -} -const { height: height, width: width, labels: labels, location: location } = JSON.parse(fs.readFileSync(path.join(__dirname, `../${version}_model_config.json`), "utf8")); -const appPath = "../" + location + "/"; -const list = e.data.list; -const batch = e.data.batchSize; -const backend = e.data.backend; -labels.push(...MYSTERIES); -postMessage({ - message: "labels", - labels: labels -}); -if (DEBUG) { - console.log(`model received load instruction. Using list: ${list}, batch size ${batch}`); -} -tf.setBackend(backend).then(async () => { - if (backend === "webgl") { - tf.env().set("WEBGL_FORCE_F16_TEXTURES", true); - tf.env().set("WEBGL_PACK", true); - tf.env().set("WEBGL_EXP_CONV", true); - tf.env().set("TOPK_K_CPU_HANDOFF_THRESHOLD", 128); - tf.env().set("TOPK_LAST_DIM_CPU_HANDOFF_SIZE_THRESHOLD", 0); - } - tf.enableProdMode(); - if (DEBUG) { - console.log(tf.env()); - console.log(tf.env().getFlags()); - } - myModel = new Model(appPath, list, version); - myModel.height = height; - myModel.width = width; - myModel.labels = labels; - await myModel.loadModel(); - postMessage({ - message: "update-list", - blocked: BLOCKED_IDS, - updateResults: false - }); - myModel.warmUp(batch); - BACKEND = tf.getBackend(); - postMessage({ - message: "model-ready", - sampleRate: myModel.config.sampleRate, - chunkLength: myModel.chunkLength, - backend: tf.getBackend(), - labels: labels - }); -}); -break; -} - case "predict": {if (myModel.model_loaded) { - const { chunks: chunks, start: start, fileStart: fileStart, file: file, snr: snr, confidence: confidence, worker: worker, context: context, resetResults: resetResults } = e.data; - myModel.useContext = context; - myModel.selection = !resetResults; - const [result,filename,startPosition] = await myModel.predictChunk(chunks, start, fileStart, file, snr, confidence / 1000); - response = { - message: "prediction", - file: filename, - result: result, - fileStart: startPosition, - worker: worker, - selection: myModel.selection - }; - postMessage(response); - myModel.result = []; -} -break; -} - case "get-spectrogram": {const buffer = e.data.buffer; -if (buffer.length < myModel.chunkLength) { - return; -} -const specFile = e.data.file; -const filepath = e.data.filepath; -const spec_height = e.data.height; -const spec_width = e.data.width; -let image; -const signal = tf.tensor1d(buffer, "float32"); -const bufferTensor = myModel.normalise_audio(signal); -signal.dispose(); -const imageTensor = tf.tidy(() => { - return myModel.makeSpectrogram(bufferTensor); -}); -image = tf.tidy(() => { - let spec = myModel.fixUpSpecBatch(tf.expandDims(imageTensor, 0), spec_height, spec_width); - const spec_max = tf.max(spec); - return spec.mul(255).div(spec_max).dataSync(); -}); -bufferTensor.dispose(); -imageTensor.dispose(); -response = { - message: "spectrogram", - width: myModel.inputShape[2], - height: myModel.inputShape[1], - channels: myModel.inputShape[3], - image: image, - file: specFile, - filepath: filepath -}; -postMessage(response); -break; -} - case "list": {myModel.list = e.data.list; -if (DEBUG) { - console.log(`Setting list to ${myModel.list}`); -} -myModel.setList(); -postMessage({ - message: "update-list", - blocked: BLOCKED_IDS, - updateResults: true -}); -break; -} - } - } - // If worker was respawned - catch (error) { - console.log(error) - } -}; - -class Model { - constructor(appPath, list, version) { - this.model = undefined; - this.labels = undefined; - this.height = undefined; - this.width = undefined; - this.config = CONFIG; - this.chunkLength = this.config.sampleRate * this.config.specLength; - this.model_loaded = false; - this.frame_length = 512; - this.frame_step = 186; - this.appPath = appPath; - this.list = list; - this.useContext = undefined; - this.version = version; - this.selection = false; - } - - async loadModel() { - if (DEBUG) console.log('loading model') - if (this.model_loaded === false) { - // Model files must be in a different folder than the js, assets files - if (DEBUG) console.log('loading model from', this.appPath + 'model.json') - this.model = await tf.loadLayersModel(this.appPath + 'model.json', - { weightPathPrefix: this.appPath }); - this.model_loaded = true; - this.setList(); - this.inputShape = [...this.model.inputs[0].shape]; - } - } - - warmUp(batchSize) { - this.batchSize = parseInt(batchSize); - this.inputShape[0] = this.batchSize; - if (tf.getBackend() === 'webgl') { - tf.tidy(() => { - //const warmupResult = this.model.predict(tf.zeros(this.inputShape), { batchSize: this.batchSize }); - const warmupResult = this.model.predict(tf.zeros([1,144_000]), { batchSize: this.batchSize }); - warmupResult.arraySync(); - // see if we can get padding compiled at this point - //this.padBatch(tf.zeros([1, this.inputShape[1], this.inputShape[2], this.inputShape[3]]), { batchSize: this.batchSize }) - }) - } - if (DEBUG) console.log('WarmUp end', tf.memory().numTensors) - return true; - } - - setList() { - BLOCKED_IDS = []; - // get the indices of any items in the blacklist, GRAYLIST - if (this.list === 'birds') { - // find the position of the blocked items in the label list - NOT_BIRDS.forEach(notBird => BLOCKED_IDS.push(this.labels.indexOf(notBird))) - } else if (this.list === 'migrants') { - let v1_migrants; - if (this.version === 'v1') { - // strip (call) from migrants set - v1_migrants = new Set(); - MIGRANTS.forEach((element) => { - const newElement = element.replace(' (call)', ''); - v1_migrants.add(newElement); - }) - - } - const listToCheck = v1_migrants || MIGRANTS; - for (let i = 0; i < this.labels.length; i++) { - const item = this.labels[i]; - if (!listToCheck.has(item) && !MYSTERIES.includes(item)) BLOCKED_IDS.push(i); - } - - } - GRAYLIST.forEach(species => SUPPRESSED_IDS.push(this.labels.indexOf(species))) - GOLDEN_LIST.forEach(species => ENHANCED_IDS.push(this.labels.indexOf(species))) - } - - normalize(spec) { - return tf.tidy(() => { - // console.log('Pre-norm### Min is: ', spec.min().dataSync(), 'Max is: ', spec.max().dataSync()) - const spec_max = tf.max(spec, [1, 2]).reshape([-1, 1, 1, 1]) - // const spec_min = tf.min(spec, [1, 2]).reshape([-1, 1, 1, 1]) - spec = spec.mul(255); - spec = spec.div(spec_max); - // spec = tf.sub(spec, spec_min).div(tf.sub(spec_max, spec_min)); - // console.log('{Post norm#### Min is: ', spec.min().dataSync(), 'Max is: ', spec.max().dataSync()) - return spec - }) - } - - getSNR(spectrograms) { - return tf.tidy(() => { - const { mean, variance } = tf.moments(spectrograms, 2); - const peak = tf.div(variance, mean) - let snr = tf.squeeze(tf.max(peak, 1)); - //snr = tf.sub(255, snr) // bigger number, less signal - // const MEAN = mean.arraySync() - // const VARIANCE = variance.arraySync() - // const PEAK = peak.arraySync() - return snr - }) - } - - - fixUpSpecBatch(specBatch, h, w) { - const img_height = h || this.height; - const img_width = w || this.width; - return tf.tidy(() => { - /* - Try out taking log of spec when SNR is below threshold? - */ - //specBatch = tf.log1p(specBatch).mul(20); - // Swap axes to fit output shape - specBatch = tf.transpose(specBatch, [0, 2, 1]); - specBatch = tf.reverse(specBatch, [1]); - // Add channel axis - specBatch = tf.expandDims(specBatch, -1); - //specBatch = tf.slice4d(specBatch, [0, 1, 0, 0], [-1, img_height, img_width, -1]); - specBatch = tf.image.resizeBilinear(specBatch, [img_height, img_width], true); - return this.version === 'v1' ? specBatch : this.normalize(specBatch) - }) - } - - padBatch(tensor) { - return tf.tidy(() => { - if (DEBUG) console.log(`Adding ${this.batchSize - tensor.shape[0]} tensors to the batch`) - const shape = [...tensor.shape]; - shape[0] = this.batchSize - shape[0]; - const padding = tf.zeros(shape); - return tf.concat([tensor, padding], 0) - }) - } - - addContext(prediction, tensor, confidence) { - // Create a set of images from the batch, offset by half the width of the original images - const [batchSize, height, width, channel] = tensor.shape; - return tf.tidy(() => { - const firstHalf = tensor.slice([0, 0, 0, 0], [-1, -1, width / 2, -1]); - const secondHalf = tensor.slice([0, 0, width / 2, 0], [-1, -1, width / 2, -1]); - const paddedSecondHalf = tf.concat([tf.zeros([1, height, width / 2, channel]), secondHalf], 0); - secondHalf.dispose(); - // prepend padding tensor - const [droppedSecondHalf, _] = paddedSecondHalf.split([paddedSecondHalf.shape[0] - 1, 1]); // pop last tensor - paddedSecondHalf.dispose(); - const combined = tf.concat([droppedSecondHalf, firstHalf], 2); // concatenate adjacent pairs along the width dimension - firstHalf.dispose(); - droppedSecondHalf.dispose(); - const rshiftPrediction = this.model.predict(combined, { batchSize: this.batchSize }); - combined.dispose(); - // now we have predictions for both the original and rolled images - const [padding, remainder] = tf.split(rshiftPrediction, [1, -1]); - const lshiftPrediction = tf.concat([remainder, padding]); - // Get the highest predictions from the overlapping images - const surround = tf.maximum(rshiftPrediction, lshiftPrediction); - lshiftPrediction.dispose(); - rshiftPrediction.dispose(); - // Mask out where these are below the threshold - const indices = tf.greater(surround, confidence); - return prediction.where(indices, 0); - }) - } - - async predictBatch(audio, keys, threshold, confidence) { - const TensorBatch = audio; //this.fixUpSpecBatch(audio); // + 1 tensor - - let paddedTensorBatch, maskedTensorBatch; - if (BACKEND === 'webgl' && TensorBatch.shape[0] < this.batchSize) { - // WebGL works best when all batches are the same size - paddedTensorBatch = this.padBatch(TensorBatch) // + 1 tensor - } else if (threshold) { - if (this.version !== 'v1') threshold *= 4; - const keysTensor = tf.stack(keys); // + 1 tensor - const snr = this.getSNR(TensorBatch) - const condition = tf.greaterEqual(snr, threshold); // + 1 tensor - if (DEBUG) console.log('SNR is:', snr.dataSync()) - snr.dispose(); - // Avoid mask cannot be scalar error at end of predictions - let newCondition; - if (condition.rankType === "0") { - newCondition = tf.expandDims(condition) // + 1 tensor - condition.dispose() // - 1 tensor - } - const c = newCondition || condition; - let maskedKeysTensor; - [maskedTensorBatch, maskedKeysTensor] = await Promise.all([ - tf.booleanMaskAsync(TensorBatch, c), - tf.booleanMaskAsync(keysTensor, c)]) // + 2 tensor - c.dispose(); // - 1 tensor - keysTensor.dispose(); // - 1 tensor - - if (!maskedTensorBatch.size) { - maskedTensorBatch.dispose(); // - 1 tensor - maskedKeysTensor.dispose(); // - 1 tensor - TensorBatch.dispose(); // - 1 tensor - if (DEBUG) console.log("No surviving tensors in batch", maskedTensorBatch.shape[0]) - return [] - } else { - keys = maskedKeysTensor.dataSync(); - maskedKeysTensor.dispose(); // - 1 tensor - if (DEBUG) console.log("surviving tensors in batch", maskedTensorBatch.shape[0]) - } - } - - const tb = paddedTensorBatch || maskedTensorBatch || TensorBatch; - const prediction = this.model.predict(tb, { batchSize: this.batchSize }) - let newPrediction; - if (this.selection) { - newPrediction = tf.max(prediction, 0, true); - prediction.dispose(); - keys = keys.splice(0, 1); - } - else if (this.useContext && this.batchSize > 1 && threshold === 0) { - newPrediction = this.addContext(prediction, tb, confidence); - prediction.dispose(); - } - TensorBatch.dispose(); - if (paddedTensorBatch) paddedTensorBatch.dispose(); - if (maskedTensorBatch) maskedTensorBatch.dispose(); - - const finalPrediction = newPrediction || prediction; - //new - const { indices, values } = tf.topk(finalPrediction, 5, true) - const topIndices = indices.arraySync(); - const topValues = values.arraySync(); - indices.dispose(); - values.dispose(); - // end new - // const array_of_predictions = finalPrediction.arraySync() - finalPrediction.dispose(); - if (newPrediction) newPrediction.dispose(); - keys = keys.map(key => (key / CONFIG.sampleRate).toFixed(3)); - return [keys, topIndices, topValues]; - // return keys.reduce((acc, key, index) => { - // // convert key (samples) to milliseconds - // const position = (key / CONFIG.sampleRate).toFixed(3); - // acc[position] = array_of_predictions[index]; - // return acc; - // }, {}); - } - - makeSpectrogram(signal) { - return tf.tidy(() => { - let spec = tf.abs(tf.signal.stft(signal, this.frame_length, this.frame_step)); - signal.dispose(); - return spec; - }) - } - - /* normalizeTensor(audio) { - return tf.tidy(() => { - const tensor = tf.tensor1d(audio); - const {mean, variance} = tf.moments(tensor); - const stdDev = variance.sqrt(); - const normalizedTensor = tensor.sub(mean).div(stdDev.mul(tf.scalar(2))); - return normalizedTensor; - }) - }*/ - - /* normalise_audio = (signal) => { - return tf.tidy(() => { - //signal = tf.tensor1d(signal); - const sigMax = tf.max(signal); - const sigMin = tf.min(signal); - return signal.sub(sigMin).div(sigMax.sub(sigMin)).mul(255).sub(127.5); - }) - };*/ - - normalise_audio = (signal) => { - return tf.tidy(() => { - //signal = tf.tensor1d(signal, 'float32'); - const sigMax = tf.max(signal); - const sigMin = tf.min(signal); - const range = sigMax.sub(sigMin); - //return signal.sub(sigMin).div(range).mul(tf.scalar(8192.0, 'float32')).sub(tf.scalar(4095, 'float32')) - return signal.sub(sigMin).div(range).mul(tf.scalar(2)).sub(tf.scalar(1)) - }) - }; - - async predictChunk(audioBuffer, start, fileStart, file, threshold, confidence) { - if (DEBUG) console.log('predictCunk begin', tf.memory().numTensors); - audioBuffer = tf.tensor1d(audioBuffer); - - // check if we need to pad - const remainder = audioBuffer.shape % this.chunkLength; - let paddedBuffer; - if (remainder !== 0) { - // Pad to the nearest full sample - paddedBuffer = audioBuffer.pad([[0, this.chunkLength - remainder]]); - audioBuffer.dispose(); - if (DEBUG) console.log('Received final chunks') - } - const buffer = paddedBuffer || audioBuffer; - const numSamples = buffer.shape / this.chunkLength; - let bufferList = tf.split(buffer, numSamples); - buffer.dispose(); - // Turn the audio into a spec tensor - bufferList = tf.tidy(() => { - return bufferList.map(x => { - let normal = this.normalise_audio(x); - x.dispose(); - return normal ; // this.makeSpectrogram(normal); - }) - }); - const specBatch = tf.stack(bufferList); - const batchKeys = [...Array(numSamples).keys()].map(i => start + this.chunkLength * i); - const result = await this.predictBatch(specBatch, batchKeys, threshold, confidence); - this.clearTensorArray(bufferList); - return [result, file, fileStart]; - } - - async clearTensorArray(tensorObj) { - // Dispose of accumulated kept tensors in model tensor array - tensorObj.forEach(tensor => tensor.dispose()); - } -} - - -/// Birdnet definitions - -///////////////////////// Build SimpleSpecLayer ///////////////////////// -class SimpleSpecLayer extends tf.layers.Layer { - constructor(config) { - super(config); - - // For now, let's work with hard coded values to avoid strange errors when reading the config - this.spec_shape = [257, 384]; - this.frame_length = 512; - this.frame_step = 374; - } - - build(inputShape) { - this.mag_scale = this.addWeight('magnitude_scaling', [], 'float32', tf.initializers.constant({value: 1})); - } - - computeOutputShape(inputShape) { return [inputShape[0], this.spec_shape[0], this.spec_shape[1], 1]; } - - call(input, kwargs) { - - // Perform STFT - var spec = tf.signal.stft(input[0].squeeze(), - this.frame_length, - this.frame_step) - - // Cast from complex to float - spec = tf.cast(spec, 'float32'); - - // Convert to power spectrogram - spec = tf.pow(spec, 2) - - // Convert magnitudes using nonlinearity - spec = tf.pow(spec, tf.div(1, tf.add(1, tf.exp(this.mag_scale.read())))) - - // Normalize values between 0 and 1 - //spec = tf.div(tf.sub(spec, tf.min(spec)), tf.max(spec)); - - // Swap axes to fit output shape - spec = tf.transpose(spec) - - // Add channel axis - spec = tf.expandDims(spec, -1) - - // Add batch axis - spec = tf.expandDims(spec, 0) - - return spec - - } - - static get className() { return 'SimpleSpecLayer'; } -} - -tf.serialization.registerClass(SimpleSpecLayer); - -///////////////////////// Build GlobalExpPool2D Layer ///////////////////////// -function logmeanexp(x, axis, keepdims, sharpness) { - const xmax = tf.max(x, axis, true); - const xmax2 = tf.max(x, axis, keepdims); - x = tf.mul(sharpness, tf.sub(x, xmax)); - let y = tf.log(tf.mean(tf.exp(x), axis, keepdims)); - y = tf.add(tf.div(y, sharpness), xmax2); - return y -} - -class GlobalLogExpPooling2D extends tf.layers.Layer { - constructor(config) { - super(config); - } - - build(inputShape) { - this.sharpness = this.addWeight('sharpness', [1], 'float32', tf.initializers.constant({value: 2})); - } - - computeOutputShape(inputShape) { return [inputShape[0], inputShape[3]]; } - - call(input, kwargs) { - - return logmeanexp(input[0], [1, 2], false, this.sharpness.read());//.read().dataSync()[0]); - - } - - static get className() { return 'GlobalLogExpPooling2D'; } -} - -tf.serialization.registerClass(GlobalLogExpPooling2D); - -///////////////////////// Build Sigmoid Layer ///////////////////////// -class SigmoidLayer extends tf.layers.Layer { - constructor(config) { - super(config); - this.config = config; - } - - build(inputShape) { - this.kernel = this.addWeight('scale_factor', [1], 'float32', tf.initializers.constant({value: 1})); - } - - computeOutputShape(inputShape) { return inputShape; } - - call(input, kwargs) { - - return tf.sigmoid(tf.mul(input[0], CONFIG.sigmoid)) - - } - - static get className() { return 'SigmoidLayer'; } -} - -tf.serialization.registerClass(SigmoidLayer); diff --git a/js/BirdNet2.4.js b/js/BirdNet2.4.js index 8c6b7039..aa3366cc 100644 --- a/js/BirdNet2.4.js +++ b/js/BirdNet2.4.js @@ -1,7 +1,7 @@ const tf = require('@tensorflow/tfjs-node'); const fs = require('node:fs'); const path = require('node:path'); -let DEBUG = false; +let DEBUG = true; let BACKEND; //GLOBALS @@ -135,7 +135,7 @@ break; if (DEBUG) { console.log(`Setting list to ${myModel.list}`); } -myModel.setList(); +await myModel.setList(); postMessage({ message: "update-list", blocked: BLOCKED_IDS, @@ -178,7 +178,9 @@ class Model { { weightPathPrefix: this.appPath }); this.model_loaded = true; this.inputShape = [...this.model.inputs[0].shape]; - this.metadata_model = await tf.loadGraphModel(path.join(this.appPath, 'mdata', 'model.json')); + const mdata_model_path = this.appPath + 'mdata/model.json' + this.metadata_model = await tf.loadGraphModel(mdata_model_path, + ); await this.setList(); } } @@ -211,16 +213,15 @@ class Model { const mdata_prediction = this.metadata_model.predict(this.mdata_input); const mdata_probs = await mdata_prediction.data(); const mdata_probs_sorted = mdata_probs.slice().sort().reverse(); - console.log('Most common species @ (' + lat + '/' + lon + ') in week ' + week + ':'); let count = 0 - for (let i = 0; i < mdata_probs_sorted.length; i++) { - const index = mdata_probs.indexOf(mdata_probs_sorted[i]); - if (mdata_probs_sorted[i] > 0.004) { + for (let i = 0; i < mdata_probs.length; i++) { + if (mdata_probs[i] > 0.004) { count++; - console.log(this.labels[index] + ': ' + mdata_probs_sorted[i]); + DEBUG && console.log("including:", this.labels[i] + ': ' + mdata_probs[i]); } else { - // Hack to add Dotterel - if (! this.labels[index].includes('Dotterel')) BLOCKED_IDS.push(index) + DEBUG && console.log("Excluding:", this.labels[i] + ': ' + mdata_probs[i]); + // Hack to add Dotterel?? + if (! this.labels[i].includes('Dotterel')) BLOCKED_IDS.push(i) } } console.log('Total species considered at this location: ', count) diff --git a/js/model.js b/js/model.js index a8326bd3..e3936684 100644 --- a/js/model.js +++ b/js/model.js @@ -179,10 +179,11 @@ class Model { this.model_loaded = true; this.inputShape = [...this.model.inputs[0].shape]; - this.metadata_model = await tf.loadGraphModel(path.join( - this.appPath, '..', 'BirdNET_GLOBAL_6K_V2.4_Model_TFJS', 'static', 'model', 'mdata', 'model.json' - )); - this.mdata_labels = JSON.parse(fs.readFileSync(path.join(__dirname, `..`, 'BirdNET_GLOBAL_6K_V2.4_Model_TFJS', 'static', 'model', 'labels.json'), "utf8")); + this.metadata_model = await tf.loadGraphModel( + this.appPath + '../BirdNET_GLOBAL_6K_V2.4_Model_TFJS/static/model/mdata/model.json' + ); + const mdata_label_path = path.join(__dirname, '..','BirdNET_GLOBAL_6K_V2.4_Model_TFJS','static','model','labels.json') + this.mdata_labels = JSON.parse(fs.readFileSync(mdata_label_path, "utf8")); await this.setList(); } } diff --git a/v2_model_config.json b/v2_model_config.json index 20fbb4b3..aa525df5 100755 --- a/v2_model_config.json +++ b/v2_model_config.json @@ -1 +1 @@ -{"location": "QUANT_2023511_Augs~00100_EfficientNetV2B0_SigmoidFocalCrossentropy_256x384_Adam_408", "height": 256, "width": 384, "labels": ["Acanthis cabaret_Lesser Redpoll (call)", "Acanthis cabaret_Lesser Redpoll (song)", "Acanthis flammea_Common Redpoll", "Acanthis hornemanni_Arctic Redpoll", "Accipiter gentilis_Goshawk", "Accipiter nisus_Sparrowhawk", "Acrocephalus dumetorum_Blyth's Reed Warbler", "Acrocephalus paludicola_Aquatic Warbler (song)", "Acrocephalus palustris_Marsh Warbler (call)", "Acrocephalus palustris_Marsh Warbler (song)", "Acrocephalus schoenobaenus_Sedge Warbler (call)", "Acrocephalus schoenobaenus_Sedge Warbler (song)", "Acrocephalus scirpaceus_Reed Warbler (call)", "Acrocephalus scirpaceus_Reed Warbler (song)", "Actitis hypoleucos_Common Sandpiper", "Actitis macularius_Spotted Sandpiper", "Aegithalos caudatus_Long-tailed Tit", "Aix galericulata_Mandarin Duck", "Alauda arvensis_Skylark (call)", "Alauda arvensis_Skylark (song)", "Alca torda_Razorbill", "Alcedo atthis_Kingfisher", "Alectoris rufa_Red-legged Partridge (call)", "Alectoris rufa_Red-legged Partridge (song)", "Alopochen aegyptiaca_Egyptian Goose", "Ambient Noise_Ambient Noise", "Anas acuta_Pintail", "Anas carolinensis_Green-winged Teal", "Anas crecca_Teal", "Anas platyrhynchos_Mallard", "Animal_Animal", "Anser albifrons_White-fronted Goose", "Anser anser_Greylag Goose", "Anser brachyrhynchus_Pink-footed Goose", "Anser caerulescens_Snow Goose", "Anser fabalis_Taiga Bean Goose", "Anser serrirostris_Tundra Bean Goose", "Anthus hodgsoni_Olive-backed Pipit (call)", "Anthus hodgsoni_Olive-backed Pipit (song)", "Anthus petrosus_Rock Pipit", "Anthus pratensis_Meadow Pipit (call)", "Anthus pratensis_Meadow Pipit (song)", "Anthus richardi_Richard's Pipit (call)", "Anthus richardi_Richard's Pipit (song)", "Anthus spinoletta_Water Pipit", "Anthus trivialis_Tree Pipit (call)", "Anthus trivialis_Tree Pipit (song)", "Apus apus_Swift", "Aquila chrysaetos_Golden Eagle", "Ardea alba_Great White Egret", "Ardea cinerea_Grey Heron", "Ardea purpurea_Purple Heron", "Arenaria interpres_Turnstone", "Asio flammeus_Short-eared Owl", "Asio otus_Long-eared Owl", "Athene noctua_Little Owl", "Aythya collaris_Ring-necked Duck", "Aythya ferina_Pochard", "Aythya fuligula_Tufted Duck", "Bombycilla garrulus_Waxwing", "Botaurus stellaris_Bittern (booming)", "Botaurus stellaris_Bittern (call)", "Branta bernicla_Brent Goose", "Branta canadensis_Canada Goose", "Branta leucopsis_Barnacle Goose", "Bubo bubo_Eurasian Eagle-Owl", "Bubulcus ibis_Cattle Egret", "Bucephala clangula_Goldeneye", "Burhinus oedicnemus_Stone-curlew", "Buteo buteo_Buzzard", "Buteo lagopus_Rough-legged Buzzard", "Calandrella brachydactyla_Short-toed Lark (call)", "Calandrella brachydactyla_Short-toed Lark (song)", "Calcarius lapponicus_Lapland Bunting (call)", "Calcarius lapponicus_Lapland Bunting (song)", "Calidris alba_Sanderling", "Calidris alpina_Dunlin", "Calidris canutus_Knot", "Calidris ferruginea_Curlew Sandpiper", "Calidris fuscicollis_White-rumped Sandpiper", "Calidris maritima_Purple Sandpiper", "Calidris melanotos_Pectoral Sandpiper", "Calidris minuta_Little Stint", "Calidris pugnax_Ruff", "Calidris pusilla_Semipalmated Sandpiper", "Calidris temminckii_Temminck's Stint", "Caprimulgus europaeus_Nightjar (call)", "Caprimulgus europaeus_Nightjar (song)", "Caprimulgus ruficollis_Red-necked Nightjar (call)", "Caprimulgus ruficollis_Red-necked Nightjar (song)", "Carduelis carduelis_Goldfinch (call)", "Carduelis carduelis_Goldfinch (song)", "Carpodacus erythrinus_Common Rosefinch (call)", "Carpodacus erythrinus_Common Rosefinch (song)", "Cat_Cat", "Cecropis daurica_Red-rumped Swallow (call)", "Cecropis daurica_Red-rumped Swallow (song)", "Certhia familiaris_Treecreeper (call)", "Certhia familiaris_Treecreeper (song)", "Cettia cetti_Cetti's Warbler (call)", "Cettia cetti_Cetti's Warbler (song)", "Charadrius alexandrinus_Kentish Plover", "Charadrius dubius_Little Ringed Plover", "Charadrius hiaticula_Ringed Plover", "Charadrius morinellus_Dotterel", "Chlidonias leucopterus_White-winged Black Tern", "Chlidonias niger_Black Tern", "Chloris chloris_Greenfinch (call)", "Chloris chloris_Greenfinch (song)", "Chroicocephalus ridibundus_Black-headed Gull", "Church Bells_Church Bells", "Ciconia ciconia_White Stork", "Cinclus cinclus_Dipper (call)", "Cinclus cinclus_Dipper (song)", "Circus aeruginosus_Marsh Harrier", "Circus cyaneus_Hen Harrier", "Circus pygargus_Montagu's Harrier", "Clangula hyemalis_Long-tailed Duck", "Coccothraustes coccothraustes_Hawfinch (call)", "Coccothraustes coccothraustes_Hawfinch (song)", "Coloeus monedula_Jackdaw", "Columba livia_Rock Dove", "Columba oenas_Stock Dove", "Columba palumbus_Woodpigeon", "Corvus corax_Raven", "Corvus corone_Carrion Crow", "Corvus frugilegus_Rook", "Coturnix coturnix_Quail (call)", "Coturnix coturnix_Quail (song)", "Cough_Cough", "Crex crex_Corncrake", "Cuculus canorus_Cuckoo (call)", "Cuculus canorus_Cuckoo (song)", "Cyanistes caeruleus_Blue Tit (call)", "Cyanistes caeruleus_Blue Tit (song)", "Cygnus columbianus_Bewick's Swan", "Cygnus cygnus_Whooper Swan", "Cygnus olor_Mute Swan", "Delichon urbicum_House Martin", "Dendrocopos major_Great Spotted Woodpecker", "Dog_Dog", "Dryobates minor_Lesser Spotted Woodpecker", "Egretta garzetta_Little Egret", "Emberiza calandra_Corn Bunting (call)", "Emberiza calandra_Corn Bunting (song)", "Emberiza cirlus_Cirl Bunting (call)", "Emberiza cirlus_Cirl Bunting (song)", "Emberiza citrinella_Yellowhammer (call)", "Emberiza citrinella_Yellowhammer (song)", "Emberiza hortulana_Ortolan Bunting (call)", "Emberiza hortulana_Ortolan Bunting (song)", "Emberiza pusilla_Little Bunting (call)", "Emberiza pusilla_Little Bunting (song)", "Emberiza schoeniclus_Reed Bunting (call)", "Emberiza schoeniclus_Reed Bunting (song)", "Eremophila alpestris_Shore Lark (call)", "Eremophila alpestris_Shore Lark (song)", "Erithacus rubecula_Robin (call)", "Erithacus rubecula_Robin (flight call)", "Erithacus rubecula_Robin (song)", "Falco columbarius_Merlin", "Falco peregrinus_Peregrine", "Falco subbuteo_Hobby", "Falco tinnunculus_Kestrel", "Ficedula hypoleuca_Pied Flycatcher (call)", "Ficedula hypoleuca_Pied Flycatcher (song)", "Ficedula parva_Red-breasted Flycatcher (call)", "Ficedula parva_Red-breasted Flycatcher (song)", "Fringilla coelebs_Chaffinch (call)", "Fringilla coelebs_Chaffinch (song)", "Fringilla montifringilla_Brambling", "Fulica atra_Coot", "Fulmarus glacialis_Fulmar", "Gallinago gallinago_Snipe", "Gallinula chloropus_Moorhen", "Garrulus glandarius_Jay", "Gavia immer_Great Northern Diver", "Gavia stellata_Red-throated Diver", "Gelochelidon nilotica_Gull-billed Tern", "Glareola pratincola_Collared Pratincole", "Grus grus_Crane", "Haematopus ostralegus_Oystercatcher", "Haliaeetus albicilla_White-tailed Eagle", "Himantopus himantopus_Black-winged Stilt", "Hippolais icterina_Icterine Warbler (call)", "Hippolais icterina_Icterine Warbler (song)", "Hippolais polyglotta_Melodious Warbler (call)", "Hippolais polyglotta_Melodious Warbler (song)", "Hirundo rustica_Swallow", "Human_Human", "Hydrocoloeus minutus_Little Gull", "Ichthyaetus melanocephalus_Mediterranean Gull", "Ixobrychus minutus_Little Bittern (call)", "Ixobrychus minutus_Little Bittern (song)", "Jynx torquilla_Wryneck", "Lagopus lagopus_Red Grouse (call)", "Lagopus lagopus_Red Grouse (song)", "Lagopus muta_Ptarmigan", "Lanius collurio_Red-backed Shrike", "Lanius excubitor_Great Grey Shrike", "Lanius senator_Woodchat Shrike", "Larus argentatus_Herring Gull", "Larus cachinnans_Caspian Gull", "Larus canus_Common Gull", "Larus delawarensis_Ring-billed Gull", "Larus fuscus_Lesser Black-backed Gull", "Larus hyperboreus_Glaucous Gull", "Larus marinus_Great Black-backed Gull", "Larus michahellis_Yellow-legged Gull", "Laugh_Laugh", "Limosa lapponica_Bar-tailed Godwit", "Limosa limosa_Black-tailed Godwit", "Linaria cannabina_Linnet", "Linaria flavirostris_Twite", "Locustella luscinioides_Savi's Warbler", "Locustella naevia_Grasshopper Warbler (call)", "Locustella naevia_Grasshopper Warbler (song)", "Lophophanes cristatus_Crested Tit (call)", "Lophophanes cristatus_Crested Tit (song)", "Loxia curvirostra_Common Crossbill", "Loxia leucoptera_Two-barred Crossbill", "Loxia pytyopsittacus_Parrot Crossbill", "Loxia scotica_Scottish Crossbill", "Lullula arborea_Woodlark (call)", "Lullula arborea_Woodlark (song)", "Luscinia megarhynchos_Nightingale (call)", "Luscinia megarhynchos_Nightingale (song)", "Luscinia svecica_Bluethroat (call)", "Luscinia svecica_Bluethroat (song)", "Lymnocryptes minimus_Jack Snipe", "Lyrurus tetrix_Black Grouse", "Mareca americana_American Wigeon", "Mareca penelope_Wigeon", "Mareca strepera_Gadwall", "Melanitta nigra_Common Scoter", "Mergus merganser_Goosander", "Mergus serrator_Red-breasted Merganser", "Merops apiaster_Bee-eater", "Milvus migrans_Black Kite", "Milvus milvus_Red Kite", "Morus bassanus_Gannet", "Motacilla alba_Pied Wagtail", "Motacilla cinerea_Grey Wagtail (call)", "Motacilla cinerea_Grey Wagtail (song)", "Motacilla citreola_Citrine Wagtail", "Motacilla flava_Yellow Wagtail", "Muscicapa striata_Spotted Flycatcher", "Netta rufina_Red-crested Pochard", "Numenius arquata_Curlew", "Numenius phaeopus_Whimbrel", "Nycticorax nycticorax_Night Heron", "Oenanthe hispanica_Black-eared Wheatear", "Oenanthe oenanthe_Wheatear (call)", "Oenanthe oenanthe_Wheatear (song)", "Oriolus oriolus_Golden Oriole (call)", "Oriolus oriolus_Golden Oriole (song)", "Pandion haliaetus_Osprey", "Panurus biarmicus_Bearded Tit", "Parus major_Great Tit (call)", "Parus major_Great Tit (song)", "Passer domesticus_House Sparrow", "Passer montanus_Tree Sparrow", "Pastor roseus_Rose-coloured Starling", "Perdix perdix_Grey Partridge", "Periparus ater_Coal Tit (call)", "Periparus ater_Coal Tit (song)", "Pernis apivorus_Honey-buzzard", "Phalacrocorax carbo_Cormorant", "Phalaropus fulicarius_Grey Phalarope", "Phalaropus lobatus_Red-necked Phalarope", "Phasianus colchicus_Pheasant", "Phoenicurus ochruros_Black Redstart (call)", "Phoenicurus ochruros_Black Redstart (song)", "Phoenicurus phoenicurus_Redstart (call)", "Phoenicurus phoenicurus_Redstart (song)", "Phylloscopus borealis_Arctic Warbler", "Phylloscopus collybita_Chiffchaff (call)", "Phylloscopus collybita_Chiffchaff (song)", "Phylloscopus fuscatus_Dusky Warbler (call)", "Phylloscopus fuscatus_Dusky Warbler (song)", "Phylloscopus ibericus_Iberian Chiffchaff (call)", "Phylloscopus ibericus_Iberian Chiffchaff (song)", "Phylloscopus inornatus_Yellow-browed Warbler (call)", "Phylloscopus inornatus_Yellow-browed Warbler (song)", "Phylloscopus proregulus_Pallas's Warbler (call)", "Phylloscopus proregulus_Pallas's Warbler (song)", "Phylloscopus schwarzi_Radde's Warbler", "Phylloscopus sibilatrix_Wood Warbler (call)", "Phylloscopus sibilatrix_Wood Warbler (song)", "Phylloscopus trochiloides_Greenish Warbler (call)", "Phylloscopus trochiloides_Greenish Warbler (song)", "Phylloscopus trochilus_Willow Warbler (call)", "Phylloscopus trochilus_Willow Warbler (song)", "Pica pica_Magpie", "Picus viridis_Green Woodpecker", "Platalea leucorodia_Spoonbill", "Plectrophenax nivalis_Snow Bunting (call)", "Plectrophenax nivalis_Snow Bunting (song)", "Plegadis falcinellus_Glossy Ibis", "Pluvialis apricaria_Golden Plover", "Pluvialis dominica_American Golden Plover", "Pluvialis squatarola_Grey Plover", "Podiceps auritus_Slavonian Grebe (call)", "Podiceps auritus_Slavonian Grebe (song)", "Podiceps cristatus_Great Crested Grebe", "Podiceps grisegena_Red-necked Grebe (call)", "Podiceps grisegena_Red-necked Grebe (song)", "Podiceps nigricollis_Black-necked Grebe", "Poecile montanus_Willow Tit (call)", "Poecile montanus_Willow Tit (song)", "Poecile palustris_Marsh Tit", "Porzana porzana_Spotted Crake", "Zapornia pusilla_Baillon's Crake", "Prunella modularis_Dunnock (call)", "Prunella modularis_Dunnock (song)", "Psittacula krameri_Ring-necked Parakeet", "Puffinus puffinus_Manx Shearwater", "Pyrrhocorax pyrrhocorax_Chough", "Pyrrhula pyrrhula_Bullfinch", "Rain_Rain", "Rallus aquaticus_Water Rail", "Recurvirostra avosetta_Avocet", "Red Fox_Red Fox", "Regulus ignicapilla_Firecrest (call)", "Regulus ignicapilla_Firecrest (song)", "Regulus regulus_Goldcrest (call)", "Regulus regulus_Goldcrest (song)", "Remiz pendulinus_Penduline Tit", "Riparia riparia_Sand Martin", "Rissa tridactyla_Kittiwake", "Saxicola rubetra_Whinchat (call)", "Saxicola rubetra_Whinchat (song)", "Saxicola rubicola_Stonechat (call)", "Saxicola rubicola_Stonechat (song)", "Scolopax rusticola_Woodcock", "Serinus serinus_Serin (call)", "Serinus serinus_Serin (song)", "Sitta europaea_Nuthatch", "Sneeze_Sneeze", "Snoring_Snoring", "Somateria mollissima_Eider", "Spatula clypeata_Shoveler", "Spatula discors_Blue-winged Teal", "Spatula querquedula_Garganey", "Spinus spinus_Siskin", "Stercorarius longicaudus_Long-tailed Skua", "Stercorarius parasiticus_Arctic Skua", "Stercorarius skua_Great Skua", "Sterna dougallii_Roseate Tern", "Sterna hirundo_Common Tern", "Sterna paradisaea_Arctic Tern", "Sternula albifrons_Little Tern", "Streptopelia decaocto_Collared Dove", "Streptopelia turtur_Turtle Dove", "Strix aluco_Tawny Owl", "Sturnus vulgaris_Starling", "Sylvia atricapilla_Blackcap (call)", "Sylvia atricapilla_Blackcap (song)", "Sylvia borin_Garden Warbler (call)", "Sylvia borin_Garden Warbler (song)", "Curruca cantillans_Subalpine Warbler (call)", "Curruca cantillans_Subalpine Warbler (song)", "Curruca communis_Whitethroat (call)", "Curruca communis_Whitethroat (song)", "Curruca curruca_Lesser Whitethroat (call)", "Curruca curruca_Lesser Whitethroat (song)", "Curruca nisoria_Barred Warbler (call)", "Curruca nisoria_Barred Warbler (song)", "Curruca undata_Dartford Warbler (call)", "Curruca undata_Dartford Warbler (song)", "Tachybaptus ruficollis_Little Grebe", "Apus melba_Alpine Swift", "Tadorna ferruginea_Ruddy Shelduck", "Tadorna tadorna_Shelduck", "Tarsiger cyanurus_Red-flanked Bluetail (call)", "Tarsiger cyanurus_Red-flanked Bluetail (song)", "Tetrao urogallus_Capercaillie", "Thalasseus sandvicensis_Sandwich Tern", "Thunder_Thunder", "Tringa erythropus_Spotted Redshank", "Tringa glareola_Wood Sandpiper", "Tringa nebularia_Greenshank", "Tringa ochropus_Green Sandpiper", "Tringa totanus_Redshank", "Troglodytes troglodytes_Wren (call)", "Troglodytes troglodytes_Wren (song)", "Turdus iliacus_Redwing (call)", "Turdus iliacus_Redwing (song)", "Turdus merula_Blackbird (call)", "Turdus merula_Blackbird (flight call)", "Turdus merula_Blackbird (song)", "Turdus philomelos_Song Thrush (call)", "Turdus philomelos_Song Thrush (song)", "Turdus pilaris_Fieldfare (call)", "Turdus pilaris_Fieldfare (song)", "Turdus torquatus_Ring Ouzel (call)", "Turdus torquatus_Ring Ouzel (song)", "Turdus viscivorus_Mistle Thrush (call)", "Turdus viscivorus_Mistle Thrush (song)", "Tyto alba_Barn Owl", "Upupa epops_Hoopoe", "Uria aalge_Guillemot", "Vanellus vanellus_Lapwing", "Vehicle_Vehicle", "Water Drops_Water Drops", "Waves_Waves", "Wind_Wind", "Xema sabini_Sabine's Gull"]} \ No newline at end of file +{"location": "2023511_Augs~00100_EfficientNetV2B0_SigmoidFocalCrossentropy_256x384_Adam_408", "height": 256, "width": 384, "labels": ["Acanthis cabaret_Lesser Redpoll (call)", "Acanthis cabaret_Lesser Redpoll (song)", "Acanthis flammea_Common Redpoll", "Acanthis hornemanni_Arctic Redpoll", "Accipiter gentilis_Goshawk", "Accipiter nisus_Sparrowhawk", "Acrocephalus dumetorum_Blyth's Reed Warbler", "Acrocephalus paludicola_Aquatic Warbler (song)", "Acrocephalus palustris_Marsh Warbler (call)", "Acrocephalus palustris_Marsh Warbler (song)", "Acrocephalus schoenobaenus_Sedge Warbler (call)", "Acrocephalus schoenobaenus_Sedge Warbler (song)", "Acrocephalus scirpaceus_Reed Warbler (call)", "Acrocephalus scirpaceus_Reed Warbler (song)", "Actitis hypoleucos_Common Sandpiper", "Actitis macularius_Spotted Sandpiper", "Aegithalos caudatus_Long-tailed Tit", "Aix galericulata_Mandarin Duck", "Alauda arvensis_Skylark (call)", "Alauda arvensis_Skylark (song)", "Alca torda_Razorbill", "Alcedo atthis_Kingfisher", "Alectoris rufa_Red-legged Partridge (call)", "Alectoris rufa_Red-legged Partridge (song)", "Alopochen aegyptiaca_Egyptian Goose", "Ambient Noise_Ambient Noise", "Anas acuta_Pintail", "Anas carolinensis_Green-winged Teal", "Anas crecca_Teal", "Anas platyrhynchos_Mallard", "Animal_Animal", "Anser albifrons_White-fronted Goose", "Anser anser_Greylag Goose", "Anser brachyrhynchus_Pink-footed Goose", "Anser caerulescens_Snow Goose", "Anser fabalis_Taiga Bean Goose", "Anser serrirostris_Tundra Bean Goose", "Anthus hodgsoni_Olive-backed Pipit (call)", "Anthus hodgsoni_Olive-backed Pipit (song)", "Anthus petrosus_Rock Pipit", "Anthus pratensis_Meadow Pipit (call)", "Anthus pratensis_Meadow Pipit (song)", "Anthus richardi_Richard's Pipit (call)", "Anthus richardi_Richard's Pipit (song)", "Anthus spinoletta_Water Pipit", "Anthus trivialis_Tree Pipit (call)", "Anthus trivialis_Tree Pipit (song)", "Apus apus_Swift", "Aquila chrysaetos_Golden Eagle", "Ardea alba_Great White Egret", "Ardea cinerea_Grey Heron", "Ardea purpurea_Purple Heron", "Arenaria interpres_Turnstone", "Asio flammeus_Short-eared Owl", "Asio otus_Long-eared Owl", "Athene noctua_Little Owl", "Aythya collaris_Ring-necked Duck", "Aythya ferina_Pochard", "Aythya fuligula_Tufted Duck", "Bombycilla garrulus_Waxwing", "Botaurus stellaris_Bittern (booming)", "Botaurus stellaris_Bittern (call)", "Branta bernicla_Brent Goose", "Branta canadensis_Canada Goose", "Branta leucopsis_Barnacle Goose", "Bubo bubo_Eurasian Eagle-Owl", "Bubulcus ibis_Cattle Egret", "Bucephala clangula_Goldeneye", "Burhinus oedicnemus_Stone-curlew", "Buteo buteo_Buzzard", "Buteo lagopus_Rough-legged Buzzard", "Calandrella brachydactyla_Short-toed Lark (call)", "Calandrella brachydactyla_Short-toed Lark (song)", "Calcarius lapponicus_Lapland Bunting (call)", "Calcarius lapponicus_Lapland Bunting (song)", "Calidris alba_Sanderling", "Calidris alpina_Dunlin", "Calidris canutus_Knot", "Calidris ferruginea_Curlew Sandpiper", "Calidris fuscicollis_White-rumped Sandpiper", "Calidris maritima_Purple Sandpiper", "Calidris melanotos_Pectoral Sandpiper", "Calidris minuta_Little Stint", "Calidris pugnax_Ruff", "Calidris pusilla_Semipalmated Sandpiper", "Calidris temminckii_Temminck's Stint", "Caprimulgus europaeus_Nightjar (call)", "Caprimulgus europaeus_Nightjar (song)", "Caprimulgus ruficollis_Red-necked Nightjar (call)", "Caprimulgus ruficollis_Red-necked Nightjar (song)", "Carduelis carduelis_Goldfinch (call)", "Carduelis carduelis_Goldfinch (song)", "Carpodacus erythrinus_Common Rosefinch (call)", "Carpodacus erythrinus_Common Rosefinch (song)", "Cat_Cat", "Cecropis daurica_Red-rumped Swallow (call)", "Cecropis daurica_Red-rumped Swallow (song)", "Certhia familiaris_Treecreeper (call)", "Certhia familiaris_Treecreeper (song)", "Cettia cetti_Cetti's Warbler (call)", "Cettia cetti_Cetti's Warbler (song)", "Charadrius alexandrinus_Kentish Plover", "Charadrius dubius_Little Ringed Plover", "Charadrius hiaticula_Ringed Plover", "Charadrius morinellus_Dotterel", "Chlidonias leucopterus_White-winged Black Tern", "Chlidonias niger_Black Tern", "Chloris chloris_Greenfinch (call)", "Chloris chloris_Greenfinch (song)", "Chroicocephalus ridibundus_Black-headed Gull", "Church Bells_Church Bells", "Ciconia ciconia_White Stork", "Cinclus cinclus_Dipper (call)", "Cinclus cinclus_Dipper (song)", "Circus aeruginosus_Marsh Harrier", "Circus cyaneus_Hen Harrier", "Circus pygargus_Montagu's Harrier", "Clangula hyemalis_Long-tailed Duck", "Coccothraustes coccothraustes_Hawfinch (call)", "Coccothraustes coccothraustes_Hawfinch (song)", "Coloeus monedula_Jackdaw", "Columba livia_Rock Dove", "Columba oenas_Stock Dove", "Columba palumbus_Woodpigeon", "Corvus corax_Raven", "Corvus corone_Carrion Crow", "Corvus frugilegus_Rook", "Coturnix coturnix_Quail (call)", "Coturnix coturnix_Quail (song)", "Cough_Cough", "Crex crex_Corncrake", "Cuculus canorus_Cuckoo (call)", "Cuculus canorus_Cuckoo (song)", "Cyanistes caeruleus_Blue Tit (call)", "Cyanistes caeruleus_Blue Tit (song)", "Cygnus columbianus_Bewick's Swan", "Cygnus cygnus_Whooper Swan", "Cygnus olor_Mute Swan", "Delichon urbicum_House Martin", "Dendrocopos major_Great Spotted Woodpecker", "Dog_Dog", "Dryobates minor_Lesser Spotted Woodpecker", "Egretta garzetta_Little Egret", "Emberiza calandra_Corn Bunting (call)", "Emberiza calandra_Corn Bunting (song)", "Emberiza cirlus_Cirl Bunting (call)", "Emberiza cirlus_Cirl Bunting (song)", "Emberiza citrinella_Yellowhammer (call)", "Emberiza citrinella_Yellowhammer (song)", "Emberiza hortulana_Ortolan Bunting (call)", "Emberiza hortulana_Ortolan Bunting (song)", "Emberiza pusilla_Little Bunting (call)", "Emberiza pusilla_Little Bunting (song)", "Emberiza schoeniclus_Reed Bunting (call)", "Emberiza schoeniclus_Reed Bunting (song)", "Eremophila alpestris_Shore Lark (call)", "Eremophila alpestris_Shore Lark (song)", "Erithacus rubecula_Robin (call)", "Erithacus rubecula_Robin (flight call)", "Erithacus rubecula_Robin (song)", "Falco columbarius_Merlin", "Falco peregrinus_Peregrine", "Falco subbuteo_Hobby", "Falco tinnunculus_Kestrel", "Ficedula hypoleuca_Pied Flycatcher (call)", "Ficedula hypoleuca_Pied Flycatcher (song)", "Ficedula parva_Red-breasted Flycatcher (call)", "Ficedula parva_Red-breasted Flycatcher (song)", "Fringilla coelebs_Chaffinch (call)", "Fringilla coelebs_Chaffinch (song)", "Fringilla montifringilla_Brambling", "Fulica atra_Coot", "Fulmarus glacialis_Fulmar", "Gallinago gallinago_Snipe", "Gallinula chloropus_Moorhen", "Garrulus glandarius_Jay", "Gavia immer_Great Northern Diver", "Gavia stellata_Red-throated Diver", "Gelochelidon nilotica_Gull-billed Tern", "Glareola pratincola_Collared Pratincole", "Grus grus_Crane", "Haematopus ostralegus_Oystercatcher", "Haliaeetus albicilla_White-tailed Eagle", "Himantopus himantopus_Black-winged Stilt", "Hippolais icterina_Icterine Warbler (call)", "Hippolais icterina_Icterine Warbler (song)", "Hippolais polyglotta_Melodious Warbler (call)", "Hippolais polyglotta_Melodious Warbler (song)", "Hirundo rustica_Swallow", "Human_Human", "Hydrocoloeus minutus_Little Gull", "Ichthyaetus melanocephalus_Mediterranean Gull", "Ixobrychus minutus_Little Bittern (call)", "Ixobrychus minutus_Little Bittern (song)", "Jynx torquilla_Wryneck", "Lagopus lagopus_Red Grouse (call)", "Lagopus lagopus_Red Grouse (song)", "Lagopus muta_Ptarmigan", "Lanius collurio_Red-backed Shrike", "Lanius excubitor_Great Grey Shrike", "Lanius senator_Woodchat Shrike", "Larus argentatus_Herring Gull", "Larus cachinnans_Caspian Gull", "Larus canus_Common Gull", "Larus delawarensis_Ring-billed Gull", "Larus fuscus_Lesser Black-backed Gull", "Larus hyperboreus_Glaucous Gull", "Larus marinus_Great Black-backed Gull", "Larus michahellis_Yellow-legged Gull", "Laugh_Laugh", "Limosa lapponica_Bar-tailed Godwit", "Limosa limosa_Black-tailed Godwit", "Linaria cannabina_Linnet", "Linaria flavirostris_Twite", "Locustella luscinioides_Savi's Warbler", "Locustella naevia_Grasshopper Warbler (call)", "Locustella naevia_Grasshopper Warbler (song)", "Lophophanes cristatus_Crested Tit (call)", "Lophophanes cristatus_Crested Tit (song)", "Loxia curvirostra_Common Crossbill", "Loxia leucoptera_Two-barred Crossbill", "Loxia pytyopsittacus_Parrot Crossbill", "Loxia scotica_Scottish Crossbill", "Lullula arborea_Woodlark (call)", "Lullula arborea_Woodlark (song)", "Luscinia megarhynchos_Nightingale (call)", "Luscinia megarhynchos_Nightingale (song)", "Luscinia svecica_Bluethroat (call)", "Luscinia svecica_Bluethroat (song)", "Lymnocryptes minimus_Jack Snipe", "Lyrurus tetrix_Black Grouse", "Mareca americana_American Wigeon", "Mareca penelope_Wigeon", "Mareca strepera_Gadwall", "Melanitta nigra_Common Scoter", "Mergus merganser_Goosander", "Mergus serrator_Red-breasted Merganser", "Merops apiaster_Bee-eater", "Milvus migrans_Black Kite", "Milvus milvus_Red Kite", "Morus bassanus_Gannet", "Motacilla alba_Pied Wagtail", "Motacilla cinerea_Grey Wagtail (call)", "Motacilla cinerea_Grey Wagtail (song)", "Motacilla citreola_Citrine Wagtail", "Motacilla flava_Yellow Wagtail", "Muscicapa striata_Spotted Flycatcher", "Netta rufina_Red-crested Pochard", "Numenius arquata_Curlew", "Numenius phaeopus_Whimbrel", "Nycticorax nycticorax_Night Heron", "Oenanthe hispanica_Black-eared Wheatear", "Oenanthe oenanthe_Wheatear (call)", "Oenanthe oenanthe_Wheatear (song)", "Oriolus oriolus_Golden Oriole (call)", "Oriolus oriolus_Golden Oriole (song)", "Pandion haliaetus_Osprey", "Panurus biarmicus_Bearded Tit", "Parus major_Great Tit (call)", "Parus major_Great Tit (song)", "Passer domesticus_House Sparrow", "Passer montanus_Tree Sparrow", "Pastor roseus_Rose-coloured Starling", "Perdix perdix_Grey Partridge", "Periparus ater_Coal Tit (call)", "Periparus ater_Coal Tit (song)", "Pernis apivorus_Honey-buzzard", "Phalacrocorax carbo_Cormorant", "Phalaropus fulicarius_Grey Phalarope", "Phalaropus lobatus_Red-necked Phalarope", "Phasianus colchicus_Pheasant", "Phoenicurus ochruros_Black Redstart (call)", "Phoenicurus ochruros_Black Redstart (song)", "Phoenicurus phoenicurus_Redstart (call)", "Phoenicurus phoenicurus_Redstart (song)", "Phylloscopus borealis_Arctic Warbler", "Phylloscopus collybita_Chiffchaff (call)", "Phylloscopus collybita_Chiffchaff (song)", "Phylloscopus fuscatus_Dusky Warbler (call)", "Phylloscopus fuscatus_Dusky Warbler (song)", "Phylloscopus ibericus_Iberian Chiffchaff (call)", "Phylloscopus ibericus_Iberian Chiffchaff (song)", "Phylloscopus inornatus_Yellow-browed Warbler (call)", "Phylloscopus inornatus_Yellow-browed Warbler (song)", "Phylloscopus proregulus_Pallas's Warbler (call)", "Phylloscopus proregulus_Pallas's Warbler (song)", "Phylloscopus schwarzi_Radde's Warbler", "Phylloscopus sibilatrix_Wood Warbler (call)", "Phylloscopus sibilatrix_Wood Warbler (song)", "Phylloscopus trochiloides_Greenish Warbler (call)", "Phylloscopus trochiloides_Greenish Warbler (song)", "Phylloscopus trochilus_Willow Warbler (call)", "Phylloscopus trochilus_Willow Warbler (song)", "Pica pica_Magpie", "Picus viridis_Green Woodpecker", "Platalea leucorodia_Spoonbill", "Plectrophenax nivalis_Snow Bunting (call)", "Plectrophenax nivalis_Snow Bunting (song)", "Plegadis falcinellus_Glossy Ibis", "Pluvialis apricaria_Golden Plover", "Pluvialis dominica_American Golden Plover", "Pluvialis squatarola_Grey Plover", "Podiceps auritus_Slavonian Grebe (call)", "Podiceps auritus_Slavonian Grebe (song)", "Podiceps cristatus_Great Crested Grebe", "Podiceps grisegena_Red-necked Grebe (call)", "Podiceps grisegena_Red-necked Grebe (song)", "Podiceps nigricollis_Black-necked Grebe", "Poecile montanus_Willow Tit (call)", "Poecile montanus_Willow Tit (song)", "Poecile palustris_Marsh Tit", "Porzana porzana_Spotted Crake", "Zapornia pusilla_Baillon's Crake", "Prunella modularis_Dunnock (call)", "Prunella modularis_Dunnock (song)", "Psittacula krameri_Ring-necked Parakeet", "Puffinus puffinus_Manx Shearwater", "Pyrrhocorax pyrrhocorax_Chough", "Pyrrhula pyrrhula_Bullfinch", "Rain_Rain", "Rallus aquaticus_Water Rail", "Recurvirostra avosetta_Avocet", "Red Fox_Red Fox", "Regulus ignicapilla_Firecrest (call)", "Regulus ignicapilla_Firecrest (song)", "Regulus regulus_Goldcrest (call)", "Regulus regulus_Goldcrest (song)", "Remiz pendulinus_Penduline Tit", "Riparia riparia_Sand Martin", "Rissa tridactyla_Kittiwake", "Saxicola rubetra_Whinchat (call)", "Saxicola rubetra_Whinchat (song)", "Saxicola rubicola_Stonechat (call)", "Saxicola rubicola_Stonechat (song)", "Scolopax rusticola_Woodcock", "Serinus serinus_Serin (call)", "Serinus serinus_Serin (song)", "Sitta europaea_Nuthatch", "Sneeze_Sneeze", "Snoring_Snoring", "Somateria mollissima_Eider", "Spatula clypeata_Shoveler", "Spatula discors_Blue-winged Teal", "Spatula querquedula_Garganey", "Spinus spinus_Siskin", "Stercorarius longicaudus_Long-tailed Skua", "Stercorarius parasiticus_Arctic Skua", "Stercorarius skua_Great Skua", "Sterna dougallii_Roseate Tern", "Sterna hirundo_Common Tern", "Sterna paradisaea_Arctic Tern", "Sternula albifrons_Little Tern", "Streptopelia decaocto_Collared Dove", "Streptopelia turtur_Turtle Dove", "Strix aluco_Tawny Owl", "Sturnus vulgaris_Starling", "Sylvia atricapilla_Blackcap (call)", "Sylvia atricapilla_Blackcap (song)", "Sylvia borin_Garden Warbler (call)", "Sylvia borin_Garden Warbler (song)", "Curruca cantillans_Subalpine Warbler (call)", "Curruca cantillans_Subalpine Warbler (song)", "Curruca communis_Whitethroat (call)", "Curruca communis_Whitethroat (song)", "Curruca curruca_Lesser Whitethroat (call)", "Curruca curruca_Lesser Whitethroat (song)", "Curruca nisoria_Barred Warbler (call)", "Curruca nisoria_Barred Warbler (song)", "Curruca undata_Dartford Warbler (call)", "Curruca undata_Dartford Warbler (song)", "Tachybaptus ruficollis_Little Grebe", "Apus melba_Alpine Swift", "Tadorna ferruginea_Ruddy Shelduck", "Tadorna tadorna_Shelduck", "Tarsiger cyanurus_Red-flanked Bluetail (call)", "Tarsiger cyanurus_Red-flanked Bluetail (song)", "Tetrao urogallus_Capercaillie", "Thalasseus sandvicensis_Sandwich Tern", "Thunder_Thunder", "Tringa erythropus_Spotted Redshank", "Tringa glareola_Wood Sandpiper", "Tringa nebularia_Greenshank", "Tringa ochropus_Green Sandpiper", "Tringa totanus_Redshank", "Troglodytes troglodytes_Wren (call)", "Troglodytes troglodytes_Wren (song)", "Turdus iliacus_Redwing (call)", "Turdus iliacus_Redwing (song)", "Turdus merula_Blackbird (call)", "Turdus merula_Blackbird (flight call)", "Turdus merula_Blackbird (song)", "Turdus philomelos_Song Thrush (call)", "Turdus philomelos_Song Thrush (song)", "Turdus pilaris_Fieldfare (call)", "Turdus pilaris_Fieldfare (song)", "Turdus torquatus_Ring Ouzel (call)", "Turdus torquatus_Ring Ouzel (song)", "Turdus viscivorus_Mistle Thrush (call)", "Turdus viscivorus_Mistle Thrush (song)", "Tyto alba_Barn Owl", "Upupa epops_Hoopoe", "Uria aalge_Guillemot", "Vanellus vanellus_Lapwing", "Vehicle_Vehicle", "Water Drops_Water Drops", "Waves_Waves", "Wind_Wind", "Xema sabini_Sabine's Gull"]} \ No newline at end of file