Bug fixes and updates to deep learning models

Defualt model for Atlantic humpback whale implemented
Koogu and zip model unit tests
This commit is contained in:
Jamie Mac 2024-04-01 16:56:35 +01:00
parent 0eca6a1a9f
commit ca2fef11e5
29 changed files with 2062 additions and 132 deletions

Binary file not shown.

Binary file not shown.

View File

@ -960,6 +960,13 @@
<artifactId>fxyz3d</artifactId> <artifactId>fxyz3d</artifactId>
<version>0.6.0</version> <version>0.6.0</version>
</dependency> </dependency>
<!-- Atlanta style for JavaFX -->
<dependency>
<groupId>io.github.mkpaz</groupId>
<artifactId>atlantafx-base</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -295,4 +295,26 @@
-fx-background-color: -color-cell-border, -color-cell-bg-selected; -fx-background-color: -color-cell-border, -color-cell-bg-selected;
} }
/*******************************************************************************
* *
* For some reason the table background is white and so this needs fixed.
* *
******************************************************************************/
.table-view {
-color-cell-bg: -color-bg-default;
-color-cell-fg: -color-fg-default;
-color-cell-bg-selected: -color-base-6;
-color-cell-fg-selected: -color-fg-default;
-color-cell-bg-odd: -color-bg-subtle;
-color-cell-border: -color-border-default;
-fx-border-color: -color-cell-border;
-fx-control-inner-background: -color-bg-default;
-fx-border-width: 1px;
-fx-border-radius: 0;
-color-header-bg: -color-bg-subtle;
-color-header-fg: -color-fg-default;
}

View File

@ -8,6 +8,7 @@ import PamController.PamSettingManager;
import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit; import PamguardMVC.PamDataUnit;
import PamguardMVC.superdet.SuperDetection; import PamguardMVC.superdet.SuperDetection;
import atlantafx.base.theme.Styles;
import detectionPlotFX.data.DDDataInfo; import detectionPlotFX.data.DDDataInfo;
import detectionPlotFX.data.DDDataProvider; import detectionPlotFX.data.DDDataProvider;
import detectionPlotFX.data.DDPlotRegister; import detectionPlotFX.data.DDPlotRegister;
@ -206,6 +207,9 @@ public class DetectionGroupDisplay extends PamBorderPane {
//hidingPane.removeHideButton(); //hidingPane.removeHideButton();
hidingPane.styleHideButton(hidingPane.getHideButton(), Side.LEFT); hidingPane.styleHideButton(hidingPane.getHideButton(), Side.LEFT);
//make the background dark for settings pane.
detectionDisplay.getSettingsHolder().setStyle("-fx-background-color: -fx-darkbackground");
} }
else { else {
//the display is compact with all controls within an internal hiding pane. //the display is compact with all controls within an internal hiding pane.
@ -213,6 +217,7 @@ public class DetectionGroupDisplay extends PamBorderPane {
detectionDisplayHolder = new PamStackPane(); detectionDisplayHolder = new PamStackPane();
TabPane settingsPane = new TabPane(); TabPane settingsPane = new TabPane();
settingsPane.setStyle(Styles.TABS_FLOATING);
settingsPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); settingsPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
// settingsPane.getStylesheets().addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS()); // settingsPane.getStylesheets().addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS());

View File

@ -1,6 +1,7 @@
package pamViewFX.fxNodes.table; package pamViewFX.fxNodes.table;
import pamViewFX.fxNodes.PamBorderPane; import pamViewFX.fxNodes.PamBorderPane;
import atlantafx.base.theme.Styles;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.Orientation; import javafx.geometry.Orientation;
@ -35,6 +36,7 @@ public abstract class TableSettingsPane<T> extends PamBorderPane {
public TableSettingsPane(ObservableList<T> data){ public TableSettingsPane(ObservableList<T> data){
this.data=data; this.data=data;
table = new TableView<T>(); table = new TableView<T>();
this.setCenter(createPane()); this.setCenter(createPane());
} }
@ -90,7 +92,7 @@ public abstract class TableSettingsPane<T> extends PamBorderPane {
//make sure table resized with pane to stop blank column //make sure table resized with pane to stop blank column
getTableView().setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); getTableView().setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
getButtonPane().getSettingsButton().setDisable(table.getItems().size()<=0); getButtonPane().getSettingsButton().setDisable(table.getItems().size()<=0);
getButtonPane().getDeleteButton().setDisable(table.getItems().size()<=0); getButtonPane().getDeleteButton().setDisable(table.getItems().size()<=0);

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import PamView.ColourScheme; import PamView.ColourScheme;
import PamView.PamColors; import PamView.PamColors;
import atlantafx.base.theme.PrimerDark;
import atlantafx.base.theme.PrimerLight;
/* /*
* PAMGUARD - Passive Acoustic Monitoring GUARDianship. * PAMGUARD - Passive Acoustic Monitoring GUARDianship.
@ -49,7 +51,8 @@ public class PamAtlantaStyle extends PamDefaultStyle {
*/ */
// private String guiCSS = "/Resources/css/pamCSS.css"; // private String guiCSS = "/Resources/css/pamCSS.css";
// private String guiCSS = new NordDark().getUserAgentStylesheet(); // private String guiCSS = new NordDark().getUserAgentStylesheet();
protected String primerlight = "/Resources/css/primer-light.css"; // protected String primerlight = "/Resources/css/primer-light.css";
protected String primerlight = new PrimerLight().getUserAgentStylesheet();
/** /**
* Relative location of the CSS style sheet to be used for the Pamguard standard * Relative location of the CSS style sheet to be used for the Pamguard standard
@ -57,7 +60,8 @@ public class PamAtlantaStyle extends PamDefaultStyle {
*/ */
// private String dialogCSS = "/Resources/css/pamSettingsCSS.css"; // private String dialogCSS = "/Resources/css/pamSettingsCSS.css";
// private String dialogCSS = new PrimerDark().getUserAgentStylesheet(); // private String dialogCSS = new PrimerDark().getUserAgentStylesheet();
protected String primerdark = "/Resources/css/primer-dark.css"; // protected String primerdark = "/Resources/css/primer-dark.css";
protected String primerdark = new PrimerDark().getUserAgentStylesheet();
/** /**

View File

@ -372,16 +372,17 @@ public class DLDownloadManager {
OutputStream output = new FileOutputStream(outFile); OutputStream output = new FileOutputStream(outFile);
long count = 0; long count = 0;
Files.copy(input, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
//Files.copy(input, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
while ((n = input.read(buffer)) != -1) { while ((n = input.read(buffer)) != -1) {
System.out.println("Chunk: " + count); // System.out.println("Chunk: " + count);
count=count+n; //total bytes count=count+n; //total bytes
notifyDownLoadListeners(DLStatus.DOWNLOADING, count); notifyDownLoadListeners(DLStatus.DOWNLOADING, count);
output.write( buffer, 0, n ); output.write( buffer, 0, n );
} }
System.out.println("Chunk: " + n); // System.out.println("Chunk: " + n);
output.close(); output.close();

View File

@ -1,6 +1,7 @@
# PAMGuard's deep learning module # PAMGuard's deep learning module
Note: this module requires an internet connection upon first use to download correct libraries.
## Overview ## Overview
PAMGuard's deep learning module allows users to deploy a large variety of deep learning models natively in PAMGuard. It is core module, fully integrated into PAMGuard's display and data management system and can be used in real time or for post processing data. It can therefore be used as a classifier for almost any acoustic signal and can integrate into multiple types of acoustic analysis workflows, for example post analysis of recorder data or used as part of real time localisation workflow. PAMGuard's deep learning module allows users to deploy a large variety of deep learning models natively in PAMGuard. It is core module, fully integrated into PAMGuard's display and data management system and can be used in real time or for post processing data. It can therefore be used as a classifier for almost any acoustic signal and can integrate into multiple types of acoustic analysis workflows, for example post analysis of recorder data or used as part of real time localisation workflow.
@ -10,24 +11,37 @@ PAMGuard's deep learning module allows users to deploy a large variety of deep l
The deep learning module accepts raw data from different types of data sources, e.g. from the Sound Acquisition module, clicks and clips. It segments data into equal sized chunks with a specified overlap. Each chunk is passed through a set of transforms which convert the data into a format which is accepted by the specified deep learning model. These transforms are either manually set up by the user or, if a specific type of framework has been used to train a deep learning model, then can be automatically set up by PAMGuard. Currently there are three implemented frameworks The deep learning module accepts raw data from different types of data sources, e.g. from the Sound Acquisition module, clicks and clips. It segments data into equal sized chunks with a specified overlap. Each chunk is passed through a set of transforms which convert the data into a format which is accepted by the specified deep learning model. These transforms are either manually set up by the user or, if a specific type of framework has been used to train a deep learning model, then can be automatically set up by PAMGuard. Currently there are three implemented frameworks
<p align="center"> <p align="center">
<img width="900" height="370" src = "resources/deep_learning_module_process.png"> <img width="900" height="360" src = "resources/deep_learning_module_process.png">
</p> </p>
_A diagram of how the deep learning module works in PAMGuard. An input waveform is segmented into chunks. A series of transforms are applied to each chunk creating the input for the deep learning model. The transformed chunks are sent to the model. The results from the model are saved and can be viewed in real time (e.g. mitigation) or in post processing (e.g. data from SoundTraps)._ _A diagram of how the deep learning module works in PAMGuard. An input waveform is segmented into chunks. A series of transforms are applied to each chunk creating the input for the deep learning model. The transformed chunks are sent to the model. The results from the model are saved and can be viewed in real time (e.g. mitigation) or in post processing (e.g. data from SoundTraps)._
### Generic Model ### Generic Model
A generic model allows a user to load any model compatible with the [djl](https://djl.ai/) (PyTorch (JIT), Tenserflow, ONXX) library and then manually set up a series of transforms using PAMGuard's transform library. It is recommended that users use an existing framework instead of a generic model as these models will automatically generate the required transforms. A generic model allows a user to load any model compatible with the [djl](https://djl.ai/) (PyTorch (JIT), Tenserflow, ONXX) library and then manually set up a series of transforms using PAMGuard's transform library. It is recommended that users use an existing framework instead of a generic model as these models will automatically generate the required transforms.
### AnimalSpot ### AnimalSpot
[ANIMAL-SPOT](https://github.com/ChristianBergler/ANIMAL-SPOT) is a deep learning based framework which was initially designed for [killer whale sound detection]((https://github.com/ChristianBergler/ORCA-SPOT)) in noise heavy underwater recordings (see [Bergler et al. (2019)](https://www.nature.com/articles/s41598-019-47335-w)). It has now been expanded to a be species independent framework for training acoustic deep learning models using [PyTorch]( https://pytorch.org/) and Python. Imported AnimalSpot models will automatically set up their own data transforms and output classes. [ANIMAL-SPOT](https://github.com/ChristianBergler/ANIMAL-SPOT) is a deep learning based framework which was initially designed for [killer whale sound detection]((https://github.com/ChristianBergler/ORCA-SPOT)) in noise heavy underwater recordings (see [Bergler et al. (2019)](https://www.nature.com/articles/s41598-019-47335-w)). It has now been expanded to a be species independent framework for training acoustic deep learning models using [PyTorch]( https://pytorch.org/) and Python. Imported AnimalSpot models will automatically set up their own data transforms and output classes.
### Ketos ### Ketos
[Ketos](https://meridian.cs.dal.ca/2015/04/12/ketos/) is an acoustic deep learning framework based on Tensorflow and developed by [MERIDIAN]( https://meridian.cs.dal.ca/). It has excellent resources and tutorials and Python libraries can be installed easily via pip. Imported Ketos model will automatically set up their own data transforms and output classes.
[Ketos](https://meridian.cs.dal.ca/2015/04/12/ketos/) is an acoustic deep learning framework based on Tensorflow and developed by [MERIDIAN]( https://meridian.cs.dal.ca/). It has excellent resources and tutorials and Python libraries can be installed easily via pip. Imported Ketos (.ktpb) models will automatically set up their own data transforms and output classes.
### Koogu
[Koogu ]([Koogu &mdash; Koogu documentation](https://shyamblast.github.io/Koogu/en/stable/)) is a Python package whihc allows users to train a deep learning model. Koogu helps users by integrating with some frequency used annotation programs and provides tools to train and test classifiers. Imported Koogu models (.kgu) will automatically set up their own data transforms and output classes.
### PAMGuardZip
PAMGuard zip models consist of a deep learning model (either a Tensorflow saved_model.pb or PyTorch **.py model) alongside a PAMGuard metdata file (*.pdtf*) within a zip archive. The metadata file contains all the information needed for PAMGaurd to set up the model. PAMGuard will import the zip file, decompress it and search for the relevent deep learning model and metadata file then set up all settings accordingly. This framework allows users to easily share pre-tested PAMGuard compatible models.
## Creating an instance of the module ## Creating an instance of the module
The module can be added from the _File> Add modules > Classifier > Raw deep learning classifier_ menu or by right clicking in the data model. More than one instance of the module can be added if multiple deep learning models are required. The module can be added from the _File> Add modules > Classifier > Raw deep learning classifier_ menu or by right clicking in the data model. More than one instance of the module can be added if multiple deep learning models are required.
## Module settings ## Module settings
The module settings are opened by selecting the _Settings > Raw deep learning classifier_ menu. The main settings pane is shown below and is split into three sections, _Raw Sound Data_, _Segmentation_ and _Deep Learning Model_ The module settings are opened by selecting the _Settings > Raw deep learning classifier_ menu. The main settings pane is shown below and is split into three sections, _Raw Sound Data_, _Segmentation_ and _Deep Learning Model_
<p align="center"> <p align="center">
@ -38,7 +52,7 @@ _The main settings pane for the deep learning module with descriptions_
### Raw Sound Data ### Raw Sound Data
The deep learning module accepts any raw data source i.e., any data source that contains raw waveform data. The deep learning module accepts any raw data source i.e., any data source that contains raw waveform data e.g. clicks, clips and Ishmael detections. Note that the module accepts whislte and moan detections but only if a delphinID classifier has been loaded.
If the data is continuous, e.g. from the Sound Acquisition module then deep learning detections are saved to PAMGuard's data management system if they pass a user defined prediction threshold. The raw waveform data for segments which pass prediction threshold is saved and the detection is annotated with the deep prediction results. If the data is continuous, e.g. from the Sound Acquisition module then deep learning detections are saved to PAMGuard's data management system if they pass a user defined prediction threshold. The raw waveform data for segments which pass prediction threshold is saved and the detection is annotated with the deep prediction results.
@ -50,7 +64,7 @@ Channel grouping controls are used to arrange channels into groups. Channels in
The segmentation section defines how the raw data is segmented. Some deep learning models require a specific segment size and others can be run with different segment sizes. The _Window Length_ is the size of the segment in samples. The _Hop Length_ is the overlap (from the start of the segment) in samples. A _Hop Length_ which is the same as the segment length means no overlap. If a prediction passes threshold, then the raw data from segments is saved to PAMGuard binary files. If concurrent segments pass a prediction threshold, then they are saved as one data unit. The _Max. re-merge_ is the maximum number of segments that can form a single data unit before a new data unit is automatically created. The segmentation section defines how the raw data is segmented. Some deep learning models require a specific segment size and others can be run with different segment sizes. The _Window Length_ is the size of the segment in samples. The _Hop Length_ is the overlap (from the start of the segment) in samples. A _Hop Length_ which is the same as the segment length means no overlap. If a prediction passes threshold, then the raw data from segments is saved to PAMGuard binary files. If concurrent segments pass a prediction threshold, then they are saved as one data unit. The _Max. re-merge_ is the maximum number of segments that can form a single data unit before a new data unit is automatically created.
### Deep Learning Model ### Deep Learning Model
The deep learning model section is used to select the deep learning model. The drop down menu is used to select the framework the model is from e.g. Generic model. Note that each model type has a unique user interface which appears just below the drop down menu - currently these all look fairly similar. The deep learning model section is used to select the deep learning model. The drop down menu is used to select the framework the model is from e.g. Generic model. Note that each model type has a unique user interface which appears just below the drop down menu - currently these all look fairly similar.
@ -82,27 +96,42 @@ The _Model Settings_ tab allows the model input shape and output shape/classes t
The import and export buttons on the bottom of the advanced settings pane can be used to export and import settings for the generic model. This means that users do not have to manually set up transforms and input and output data whenever settings up a new PAMGuard data model and allow easier sharing of classifiers amongst researchers. The import and export buttons on the bottom of the advanced settings pane can be used to export and import settings for the generic model. This means that users do not have to manually set up transforms and input and output data whenever settings up a new PAMGuard data model and allow easier sharing of classifiers amongst researchers.
#### AnimalSpot and Ketos models #### Koogu, Ketos, AnimalSpot, PAMGuard zip and delphinID models
If using an AnimalSpot or Ketos model then all transforms are automatically set up. The transforms can be viewed and altered via the Advanced menu button but in the majority of cases these settings should not be used. It is advisable to select "Use default segment length" to change the _Window length_ to the default for the selected model. Note that this is often necessary for Ketos models but usually not a requirement for AnimalSpot models. If using a deep learning model from a supported framework then all transforms are automatically set up. The transforms can be viewed and altered via the Advanced menu button but in the majority of cases these settings should not be used. For some models, it is advisable to select "Use default segment length" to change the _Window length_ to the default for the selected model.
<p align="center"> <p align="center">
<img width="700" height="700" src = "resources/advanced_settings_animalspot_1.png"> <img width="700" height="700" src = "resources/advanced_settings_animalspot_1.png">
</p> </p>
_An AnimalSpot or Ketos model will automatically create a list of transforms with the appropriate settings. These is no need to use the advanced pane but it is there in case users wish to change transform settings for some reason_ _An AnimalSpot, Ketos or other supported deep learning model will automatically create a list of transforms with the appropriate settings. These is no need to use the advanced pane but it is there in case users wish to change transform settings for some reason_
### Default Models
Default models are selectable from the menu button in the Deep Learning Pane. Default models are deep learning classifiers which are open source, known to be effective and have have been published in open access academic litrature; they are downloaded directly from a GitHub repository and then all associated settings are automtically applied. The default model selection pane also contains hyperlinks to the papers descirbing each model which will take users directly to the relvent website.
<p align="center">
<img width="550" height="700" src = "resources/default_settings_humpback_1.png">
</p>
_Default models can be downloaded. Defautl models are models which are published, open and have been known to work well. More will be added to PAMGaurd over time_
## Running ## Running
### Real time ### Real time
In real time, the deep learning model runs automatically when processing starts. A warning will appear if there are issues with the model and/or it cannot cope with real time speeds. In real time, the deep learning model runs automatically when processing starts. A warning will appear if there are issues with the model and/or it cannot cope with real time speeds.
### Viewer Mode ### Viewer Mode
The deep learning module can be re-run on _detector_ data (e.g. click or clip detections) in PAMGuard _viewer_ mode. Detections can be reclassified by selecting the _Settings > Raw Deep Learning Classifier > Reclassify detections_. Select the data range in the reprocessing dialog e.g. Loaded Data and select _Start_. Detections without a deep learning annotation will have one added and detections with an existing annotation will have it overwritten. The deep learning module can be re-run on _detector_ data (e.g. click or clip detections) in PAMGuard _viewer_ mode. Detections can be reclassified by selecting the _Settings > Raw Deep Learning Classifier > Reclassify detections_. Select the data range in the reprocessing dialog e.g. Loaded Data and select _Start_. Detections without a deep learning annotation will have one added and detections with an existing annotation will have it overwritten.
## Viewing and exporting results ## Viewing and exporting results
Output from the deep learning module can be viewed in PAMGuard viewer mode, or extracted from binary files using MATLAB or R. Output from the deep learning module can be viewed in PAMGuard viewer mode, or extracted from binary files using MATLAB or R.
### PAMGuard viewer mode ### PAMGuard viewer mode
Detections form continuous raw data are shown in the datagram in the same way as all data streams in PAMGuard. Detections form continuous raw data are shown in the datagram in the same way as all data streams in PAMGuard.
The Time base display FX is best way to view detailed data outputs from the deep learning algorithm. The time base display can display almost all data types in PAMGuard on a large variety of different data axis. For example, click detections can be displayed on an amplitude, bearing, ICI, waveform and/or frequency axis. Deep learning detections (i.e. data units which have been saved from raw data using the deep learning detector) can be displayed on the time base display in the same way as many other detections and in addition, there is a symbol manager options which allows the deep learning detections or other detections which have been classified by the deep learning module to be coloured by prediction class. This means that a manual analyst can quickly navigate to detections with high prediction values for a certain class. Hovering over or right clicking on a data unit in the time display and selecting the information button, will show the data units metadata, including the prediction values for all output classes from the deep learning model. The Time base display FX is best way to view detailed data outputs from the deep learning algorithm. The time base display can display almost all data types in PAMGuard on a large variety of different data axis. For example, click detections can be displayed on an amplitude, bearing, ICI, waveform and/or frequency axis. Deep learning detections (i.e. data units which have been saved from raw data using the deep learning detector) can be displayed on the time base display in the same way as many other detections and in addition, there is a symbol manager options which allows the deep learning detections or other detections which have been classified by the deep learning module to be coloured by prediction class. This means that a manual analyst can quickly navigate to detections with high prediction values for a certain class. Hovering over or right clicking on a data unit in the time display and selecting the information button, will show the data units metadata, including the prediction values for all output classes from the deep learning model.
@ -115,7 +144,8 @@ _An example click detection module output coloured by deep learning annotations.
Other displays also show outputs from the deep learning module. Hovering over data units in the click display will, for example, show deep learning prediction values. The spectrogram will also show deep learning detections as translucent blue boxes (these must be selected in the right click menu). Other displays also show outputs from the deep learning module. Hovering over data units in the click display will, for example, show deep learning prediction values. The spectrogram will also show deep learning detections as translucent blue boxes (these must be selected in the right click menu).
### MATLAB ### MATLAB
The easiest way to export to MATLAB is to select the desired units in the time base display, right click and select the MATLAB icon. Data units will be exported to a .mat file as list of structures which is then saved to the clipboard. This file can be saved and then dragged into MATLAB to open. The easiest way to export to MATLAB is to select the desired units in the time base display, right click and select the MATLAB icon. Data units will be exported to a .mat file as list of structures which is then saved to the clipboard. This file can be saved and then dragged into MATLAB to open.
Where it is necessary to further analyse large datasets produced by PAMGuard, there is a MATLAB-PAMGuard library which can directly import the binary files which store PAMGaurd detection data. The library is simple to use with the primary function being ```loadPAMGuardBinaryFile.m. ``` This will load any binary file type (e.g. clicks, whistles, deep learning detections) and return a list of data structures with the detection data. The structures include annotations where deep learning predictions are stored. Where it is necessary to further analyse large datasets produced by PAMGuard, there is a MATLAB-PAMGuard library which can directly import the binary files which store PAMGaurd detection data. The library is simple to use with the primary function being ```loadPAMGuardBinaryFile.m. ``` This will load any binary file type (e.g. clicks, whistles, deep learning detections) and return a list of data structures with the detection data. The structures include annotations where deep learning predictions are stored.
@ -125,53 +155,52 @@ Here is a simple example loading up all the deep learning detections for a right
```matlab ```matlab
% the folder containing PAMGuard binary files % the folder containing PAMGuard binary files
folder = '/Users/me/right_whale_project_1/PAMBinary/'; folder = '/Users/me/right_whale_project_1/PAMBinary/';
%load all the detections in the folder %load all the detections in the folder
dldetections = loadPamguardBinaryFolder(folder, 'Deep_Learning_Classifier_Raw_Deep_Learning_Classifier_DL_detection_*.pgdf') dldetections = loadPamguardBinaryFolder(folder, 'Deep_Learning_Classifier_Raw_Deep_Learning_Classifier_DL_detection_*.pgdf')
``` ```
The predicitons for each class (in this case the classes are noise and right whale) are easily accessed in the structure via; The predicitons for each class (in this case the classes are noise and right whale) are easily accessed in the structure via;
```matlab ```matlab
%% access the prediciton form the first detection %% access the prediciton form the first detection
predicitons = dldetections(1).annotations.dlclassification(j).predictions; predicitons = dldetections(1).annotations.dlclassification(j).predictions;
``` ```
The loaded detections can then be plotted by accessing the waveform data in each structure; The loaded detections can then be plotted by accessing the waveform data in each structure;
```matlab ```matlab
% plot all the spectrograms. % plot all the spectrograms.
clf clf
tiledlayout(5,5) tiledlayout(5,5)
for i=1:length(dldetections) for i=1:length(dldetections)
nexttile nexttile
% generate the data for a spectrgram % generate the data for a spectrgram
[s, w, t] = spectrogram(dldetections(i).wave,512, 384,[],sR,'yaxis'); [s, w, t] = spectrogram(dldetections(i).wave,512, 384,[],sR,'yaxis');
% create the time and frequency matrices required to plot a surface % create the time and frequency matrices required to plot a surface
[X, Y] = meshgrid(t,w); [X, Y] = meshgrid(t,w);
% plot the surface (divide and multiply by 1000 to show milliseconds and kHz respectively) % plot the surface (divide and multiply by 1000 to show milliseconds and kHz respectively)
surf(X*1000, Y/1000, 20*log10(abs(s))-140, 'EdgeColor', 'None') surf(X*1000, Y/1000, 20*log10(abs(s))-140, 'EdgeColor', 'None')
view([0,90]) view([0,90])
caxis([70, 140]-140) caxis([70, 140]-140)
ylim([0,0.5]); ylim([0,0.5]);
xlabel('') xlabel('')
ylabel('') ylabel('')
if (mod(i,5)==0) if (mod(i,5)==0)
c = colorbar; c = colorbar;
c.Label.String = 'Amplitude (dB)'; c.Label.String = 'Amplitude (dB)';
end end
%x axis only on bottom plots %x axis only on bottom plots
if (i>=20) if (i>=20)
xlabel('Time (ms)') xlabel('Time (ms)')
end end
%y axis only on left most plots %y axis only on left most plots
if (mod(i-1,5)==0) if (mod(i-1,5)==0)
ylabel('Frequency (kHz)') ylabel('Frequency (kHz)')
@ -185,11 +214,13 @@ for i=1:length(dldetections)
_Right whale detections from a deep learning model imported and then plotted in MATLAB_ _Right whale detections from a deep learning model imported and then plotted in MATLAB_
### R ### R
In the same way as MATLAB export, the PAMGuard time base display and export selected data units directly to an R struct which can be imported easily into R.. In the same way as MATLAB export, the PAMGuard time base display and export selected data units directly to an R struct which can be imported easily into R..
R also has a well supported PAMGuard library with like for like functions compared to the MATLAB library. The PAMBinaries R library can be found [here](https://github.com/TaikiSan21/PamBinaries). R also has a well supported PAMGuard library with like for like functions compared to the MATLAB library. The PAMBinaries R library can be found [here](https://github.com/TaikiSan21/PamBinaries).
## Common bugs and mistakes ## Common bugs and mistakes
The first time you use the module and/or load a different type of model e.g. a tensorflow or pytorch model, you must be connected to the internet. The first time you use the module and/or load a different type of model e.g. a tensorflow or pytorch model, you must be connected to the internet.
You must install the correct version of CUDA for hardware acceleration using an Nvidea GPU. See the currently supported CUDA versions on the Pytorch and Tensorflow websites. You must install the correct version of CUDA for hardware acceleration using an Nvidea GPU. See the currently supported CUDA versions on the Pytorch and Tensorflow websites.
@ -199,6 +230,3 @@ You should always have deep learning models in their own folder. Do not have any
Pytorch models must be saved using jit to be compatible with PAMGuard. Pytorch models must be saved using jit to be compatible with PAMGuard.
Tensorflow models must be saved as .pb files to be opened in PAMGuard. Tensorflow models must be saved as .pb files to be opened in PAMGuard.

View File

@ -18,7 +18,7 @@ import rawDeepLearningClassifier.dlClassification.genericModel.GenericModelParam
import rawDeepLearningClassifier.layoutFX.exampleSounds.ExampleSoundFactory.ExampleSoundType; import rawDeepLearningClassifier.layoutFX.exampleSounds.ExampleSoundFactory.ExampleSoundType;
/** /**
* * Atlantic version of Google's humpback whale network.
*/ */
public class HumpbackWhaleAtlantic implements DLModel { public class HumpbackWhaleAtlantic implements DLModel {
@ -34,14 +34,14 @@ public class HumpbackWhaleAtlantic implements DLModel {
@Override @Override
public String getCitation() { public String getCitation() {
return "A. N. Allen et al., A Convolutional Neural Network for Automated Detection of Humpback Whale Song in a Diverse, Long-Term Passive Acoustic Dataset, Front. Mar. Sci., vol. 8, p. 607321, Mar. 2021"; return "Vincent Kather, Fabian Seipel, Benoit Berges, Genevieve Davis, Catherine Gibson, Matt Harvey, Lea-Anne Henry, Andrew Stevenson, Denise Risch; Development of a machine learning detector for North Atlantic humpback whale song. J. Acoust. Soc. Am. 1 March 2024; 155 (3): 20502064.";
} }
@Override @Override
public URI getModelURI() { public URI getModelURI() {
try { try {
return new URL("https://github.com/PAMGuard/deeplearningmodels/raw/master/right_whale_1/model_lenet_dropout_input_conv_all.zip").toURI(); return new URI("https://github.com/PAMGuard/deeplearningmodels/raw/master/humpback_whale_2/humpback_whale_2.zip");
} catch (MalformedURLException | URISyntaxException e) { } catch (URISyntaxException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
@ -56,9 +56,8 @@ public class HumpbackWhaleAtlantic implements DLModel {
@Override @Override
public URI getCitationLink() { public URI getCitationLink() {
try { try {
return new URL("https://doi.org/10.3389/fmars.2021.607321").toURI(); return new URI("https://doi.org/10.1121/10.0025275");
} catch (MalformedURLException | URISyntaxException e) { } catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
@ -83,7 +82,6 @@ public class HumpbackWhaleAtlantic implements DLModel {
genericModelParams.classNames= new DLClassName[] {new DLClassName("Humpback whale", (short) 1)}; genericModelParams.classNames= new DLClassName[] {new DLClassName("Humpback whale", (short) 1)};
genericModelParams.numClasses = 1; genericModelParams.numClasses = 1;
genericModelParams.defaultShape= new Long[] {-1L,-1L,-1L,1L}; genericModelParams.defaultShape= new Long[] {-1L,-1L,-1L,1L};
genericModelParams.shape= new Long[] {-1L,-1L,-1L,1L}; genericModelParams.shape= new Long[] {-1L,-1L,-1L,1L};
@ -91,7 +89,6 @@ public class HumpbackWhaleAtlantic implements DLModel {
genericModelParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>)genericModelParams.dlTransfromParams); genericModelParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>)genericModelParams.dlTransfromParams);
genericModelParams.setExampleSound(ExampleSoundType.HUMPBACK_WHALE); genericModelParams.setExampleSound(ExampleSoundType.HUMPBACK_WHALE);
} }

View File

@ -38,7 +38,6 @@ public class HumpbackWhaleGoogle implements DLModel {
try { try {
return new URI("https://github.com/PAMGuard/deeplearningmodels/raw/master/humpback_whale_1/humpback_whale_1.zip"); return new URI("https://github.com/PAMGuard/deeplearningmodels/raw/master/humpback_whale_1/humpback_whale_1.zip");
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
return null; return null;
@ -54,7 +53,6 @@ public class HumpbackWhaleGoogle implements DLModel {
try { try {
return new URI("https://doi.org/10.3389/fmars.2021.607321"); return new URI("https://doi.org/10.3389/fmars.2021.607321");
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
@ -79,7 +77,6 @@ public class HumpbackWhaleGoogle implements DLModel {
genericModelParams.classNames= new DLClassName[] {new DLClassName("Humpback whale", (short) 1)}; genericModelParams.classNames= new DLClassName[] {new DLClassName("Humpback whale", (short) 1)};
genericModelParams.numClasses = 1; genericModelParams.numClasses = 1;
genericModelParams.defaultShape= new Long[] {-1L,-1L,-1L,1L}; genericModelParams.defaultShape= new Long[] {-1L,-1L,-1L,1L};
genericModelParams.shape= new Long[] {-1L,-1L,-1L,1L}; genericModelParams.shape= new Long[] {-1L,-1L,-1L,1L};
@ -87,8 +84,6 @@ public class HumpbackWhaleGoogle implements DLModel {
genericModelParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>)genericModelParams.dlTransfromParams); genericModelParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>)genericModelParams.dlTransfromParams);
genericModelParams.setExampleSound(ExampleSoundType.HUMPBACK_WHALE); genericModelParams.setExampleSound(ExampleSoundType.HUMPBACK_WHALE);
} }

View File

@ -102,8 +102,8 @@ public class RightWhaleModel1 implements DLModel {
@Override @Override
public URI getCitationLink() { public URI getCitationLink() {
try { try {
return new URL("https://doi.org/10.1038/s41598-020-57549-y").toURI(); return new URI("https://doi.org/10.1038/s41598-020-57549-y");
} catch (MalformedURLException | URISyntaxException e) { } catch (URISyntaxException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return null; return null;

View File

@ -217,7 +217,7 @@ public abstract class StandardModelPane extends SettingsPane<StandardModelParams
.withMethod(c -> { .withMethod(c -> {
int nChecked = c.get("species_box"); int nChecked = c.get("species_box");
if (nChecked==speciesIDBox.getItems().size()) { if (nChecked==speciesIDBox.getItems().size() && speciesIDBox.getItems().size()>1) {
c.warn("All output class are checked. If one of these classes is noise then PAMGuard will continually detect all sound data..."); c.warn("All output class are checked. If one of these classes is noise then PAMGuard will continually detect all sound data...");
} }

View File

@ -173,8 +173,8 @@ public class ArchiveModelWorker extends GenericModelWorker {
} }
} }
if (modelParams.classNames!=null) { if (modelParams.classNames!=null && dlControl!=null) {
dlParams.classNames = dlControl.getClassNameManager().makeClassNames(modelParams.classNames); dlParams.classNames = dlControl.getClassNameManager().makeClassNames(modelParams.classNames);
} }
else { else {
//set the number of class names from the default output shape //set the number of class names from the default output shape

View File

@ -133,7 +133,7 @@ public class DLModelSelectPane extends PamBorderPane {
pathLabel = new Label("No classifier file selected"); pathLabel = new Label("No classifier file selected");
// PamButton pamButton = new PamButton("", PamGlyphDude.createPamGlyph(MaterialDesignIcon.FILE, PamGuiManagerFX.iconSize)); // PamButton pamButton = new PamButton("", PamGlyphDude.createPamGlyph(MaterialDesignIcon.FILE, PamGuiManagerFX.iconSize));
PamButton pamButton = new PamButton("", PamGlyphDude.createPamIcon("mdi2f-file", PamGuiManagerFX.iconSize)); PamButton pamButton = new PamButton("", PamGlyphDude.createPamIcon("mdi2f-file", PamGuiManagerFX.iconSize));
pathLabel.setPrefWidth(100); pathLabel.setMinWidth(100);
modelLoadIndicator = new ProgressIndicator(-1); modelLoadIndicator = new ProgressIndicator(-1);
modelLoadIndicator.setVisible(false); modelLoadIndicator.setVisible(false);
@ -523,7 +523,7 @@ public class DLModelSelectPane extends PamBorderPane {
private void updateMessage(DLStatus status, long bytesDownLoaded) { private void updateMessage(DLStatus status, long bytesDownLoaded) {
//the updates have their own messages but let's take some more control here. //the updates have their own messages but let's take some more control here.
this.updateProgress(-1, 1); //set to intermediate this.updateProgress(-1, 1); //set to intermediate
System.out.println("Status: " + status); //System.out.println("Status: " + status);
switch (status) { switch (status) {
case CONNECTION_TO_URL: case CONNECTION_TO_URL:
this.updateMessage("Checking URL"); this.updateMessage("Checking URL");

Binary file not shown.

Before

Width:  |  Height:  |  Size: 522 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -0,0 +1,13 @@
package test.rawDeepLearningClassifier;
/**
* Test the defualt models.
* @author Jamie Macaulay
*
*/
public class DefaultDLModelTest {
}

View File

@ -39,7 +39,6 @@ public class GenericDLClassifierTest {
*/ */
@Test @Test
public void rightWhaleDLWorker() { public void rightWhaleDLWorker() {
System.out.println("*****Generic DL: Right whale test*****"); System.out.println("*****Generic DL: Right whale test*****");
//relative paths to the resource folders. //relative paths to the resource folders.
@ -100,8 +99,7 @@ public class GenericDLClassifierTest {
/** /**
* Test the ketos classifier and tests are working properly. This tests loading * Test Google's humpback whale model.
* the ketos model and also using functions in KetosWorker.
*/ */
@Test @Test
public void humpbackWhaleTest() { public void humpbackWhaleTest() {
@ -146,7 +144,6 @@ public class GenericDLClassifierTest {
while((line = br.readLine()) != null){ while((line = br.readLine()) != null){
if (ind>0) { if (ind>0) {
//read the data from the text file //read the data from the text file
String[] data = line.split("\t"); String[] data = line.split("\t");
int chunkID = Integer.valueOf(data[0]); int chunkID = Integer.valueOf(data[0]);
@ -177,8 +174,6 @@ public class GenericDLClassifierTest {
//allow 10% scrumph to take account of slight differences in Java input. //allow 10% scrumph to take account of slight differences in Java input.
assertEquals(output[0], prediction, 0.1); //humpback whale detection assertEquals(output[0], prediction, 0.1); //humpback whale detection
} }
ind++; ind++;
} }

View File

@ -10,6 +10,7 @@ import java.util.ArrayList;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.UnsupportedAudioFileException;
import org.jamdev.jdl4pam.utils.DLMatFile;
import org.jamdev.jdl4pam.utils.DLUtils; import org.jamdev.jdl4pam.utils.DLUtils;
import org.jamdev.jpamutils.wavFiles.AudioData; import org.jamdev.jpamutils.wavFiles.AudioData;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -20,84 +21,117 @@ import rawDeepLearningClassifier.dlClassification.ketos.KetosDLParams;
import rawDeepLearningClassifier.dlClassification.ketos.KetosWorker2; import rawDeepLearningClassifier.dlClassification.ketos.KetosWorker2;
import rawDeepLearningClassifier.dlClassification.koogu.KooguModelWorker; import rawDeepLearningClassifier.dlClassification.koogu.KooguModelWorker;
import rawDeepLearningClassifier.segmenter.SegmenterProcess.GroupedRawData; import rawDeepLearningClassifier.segmenter.SegmenterProcess.GroupedRawData;
import us.hebi.matlab.mat.format.Mat5;
import us.hebi.matlab.mat.format.Mat5File;
import us.hebi.matlab.mat.types.Matrix;
public class KooguDLClassifierTest { public class KooguDLClassifierTest {
/**
* Test the koogu classifier and tests are working properly. This tests loading the koogu model and also using
* functions in KooguWorker.
*/
@Test
public void kooguClassifierTest() {
//relative paths to the resource folders.
String relModelPath = "./src/test/resources/rawDeepLearningClassifier/Koogu/blue_whale_24/blue_whale_24.kgu";
String relWavPath = "./src/test/resources/rawDeepLearningClassifier/Koogu/blue_whale_24/20190527_190000.wav";
String relMatPath = "./src/test/resources/rawDeepLearningClassifier/Koogu/blue_whale_24/rawScores_20190527_190000.mat";
runKooguClassifier( relModelPath, relWavPath, relMatPath);
}
// public static void runKooguClassifier(String relModelPath, String relWavPath, String relMatPath) {
// /**
// * Test the koogu classifier and tests are working properly. This tests loading the koogu model and also using
// * functions in KooguWorker. Path path = Paths.get(relModelPath);
// */
// @Test KooguModelWorker kooguWorker = new KooguModelWorker();
// public void kooguClassifierTest() {
// StandardModelParams genericModelParams = new StandardModelParams();
// //relative paths to the resource folders. genericModelParams.modelPath = path.toAbsolutePath().normalize().toString();
// String relModelPath = "./src/test/resources/rawDeepLearningClassifier/Ketos/hallo-kw-det_v1/hallo-kw-det_v1.ktpb";
// String relWavPath = "./src/test/resources/rawDeepLearningClassifier/Ketos/hallo-kw-det_v1/jasco_reduced.wav"; //prep the model - all setting are included within the model
// kooguWorker.prepModel(genericModelParams, null);
// Path path = Paths.get(relModelPath); System.out.println("seglen: " + genericModelParams.defaultSegmentLen);
//
// KooguModelWorker kooguWorker = new KooguModelWorker();
// for (int i=0; i<genericModelParams.dlTransfroms.size(); i++) {
// StandardModelParams genericModelParams = new StandardModelParams(); System.out.println(genericModelParams.dlTransfroms.get(i));
// genericModelParams.modelPath = path.toAbsolutePath().normalize().toString(); }
//
// //prep the model - all setting are included within the model
// kooguWorker.prepModel(genericModelParams, null); /****Now run a file ***/
// System.out.println("seglen: " + genericModelParams.defaultSegmentLen); path = Paths.get(relWavPath);
// String wavFilePath = path.toAbsolutePath().normalize().toString();
// /****Now run a file ***/
// path = Paths.get(relWavPath); //load predictions.
// String wavFilePath = path.toAbsolutePath().normalize().toString(); path = Paths.get(relMatPath);
//
// try { Mat5File file;
// double[][] kooguPredicitions = null;
// try {
// AudioData soundData = DLUtils.loadWavFile(wavFilePath); file = Mat5.readFromFile(path.toAbsolutePath().normalize().toString());
// double[] soundDataD = soundData.getScaledSampleAmplitudes(); Matrix matArray = file.getArray("scores");
// kooguPredicitions = DLMatFile.matrix2array(matArray);
// } catch (IOException e1) {
// long duration = (long) Math.ceil((genericModelParams.defaultSegmentLen/1000)*soundData.sampleRate); e1.printStackTrace();
// System.out.println("duration: " + duration + " " + soundData.sampleRate + " " + genericModelParams.defaultSegmentLen); return;
// }
// //dont't use the first and last because these are edge cases with zero padding
// for (int i=1; i<ketosPredicitons.length-1; i++) { try {
// AudioData soundData = DLUtils.loadWavFile(wavFilePath);
// GroupedRawData groupedRawData = new GroupedRawData(0, 1, 0, duration, (int) duration); double[] soundDataD = soundData.getScaledSampleAmplitudes();
//
// /**
// * This is super weird but Ketos has some sort of very strange system of long duration = (long) Math.ceil((genericModelParams.defaultSegmentLen/1000)*soundData.sampleRate);
// * grabbing chunks of data from a sound file - seems like it grabs a little more System.out.println("duration: " + duration + " " + soundData.sampleRate + " " + genericModelParams.defaultSegmentLen);
// * data pre the official start time. Whatever the reason this does not matter
// * for PG usually because segments simply start at the start of the wav file. int truecount=0;
// * However for testing we have to get this right to compare results and so //dont't use the first and last because these are edge cases with zero padding
// * 0.0157 is subtract from the sound chunk for (int i=0; i<kooguPredicitions.length; i++) {
// */
// int startChunk =(int) ((ketosPredicitons[i][0]-0.0157)*soundData.sampleRate); GroupedRawData groupedRawData = new GroupedRawData(0, 1, 0, duration, (int) duration);
//
// //koogu predictions are in sam,ples
// groupedRawData.copyRawData(soundDataD, startChunk, (int) duration, 0); int startChunk =(int) (kooguPredicitions[i][0]*soundData.sampleRate/250); ///the start chunk is in decimated samples - uuurgh
//
// ArrayList<GroupedRawData> groupedData = new ArrayList<GroupedRawData>();
// groupedData.add(groupedRawData); groupedRawData.copyRawData(soundDataD, startChunk, (int) duration, 0);
//
// ArrayList<GenericPrediction> genericPrediciton = ketosWorker2.runModel(groupedData, soundData.sampleRate, 0); ArrayList<GroupedRawData> groupedData = new ArrayList<GroupedRawData>();
// float[] output = genericPrediciton.get(0).getPrediction(); groupedData.add(groupedRawData);
//
// boolean testPassed= output[1]> ketosPredicitons[i][2]-0.1 && output[1]< ketosPredicitons[i][2]+0.1;
// System.out.println( i+ " : Ketos whale network output: " + output[0] + " " + output[1] + " " + testPassed); ArrayList<GenericPrediction> genericPrediciton = kooguWorker.runModel(groupedData, soundData.sampleRate, 0);
// float[] output = genericPrediciton.get(0).getPrediction();
// assertTrue(testPassed);
// boolean testPassed= output[1]> kooguPredicitions[i][2]-0.1 && output[1]< kooguPredicitions[i][2]+0.1;
// }
// System.out.println(String.format("Chunk %d %d output[0]: predicted %.5f true %.5f ; output[1]: predicted %.5f true %.5f %b",i, startChunk,
// ketosWorker2.closeModel(); output[0], kooguPredicitions[i][1], output[1], kooguPredicitions[i][2],testPassed));
//
// } catch (IOException | UnsupportedAudioFileException e) { if (testPassed) {
// // TODO Auto-generated catch block truecount++;
// e.printStackTrace(); }
// assertEquals(false, true); }
// }
// } //there are occasionaly slight differences between PMAGuard and Python so just make sure most data points are the same.
// double percTrue = 100*((double) truecount)/kooguPredicitions.length;
System.out.println(String.format("Perecentage results true: %.2f count %d", percTrue, truecount));
//at least 90% of results must match for the dataset
assertTrue(percTrue>0.9);
kooguWorker.closeModel();
} catch (IOException | UnsupportedAudioFileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
assertEquals(false, true);
}
}
} }

View File

@ -0,0 +1,24 @@
package test.rawDeepLearningClassifier;
import org.junit.jupiter.api.Test;
public class PamZipDLClassifierTest {
/**
* Test the koogu classifier and tests are working properly. This tests loading the koogu model and also using
* functions in KooguWorker.
*/
@Test
public void zipClassifierTest() {
//relative paths to the resource folders.
String relModelPath = "./src/test/resources/rawDeepLearningClassifier/PamZip/blue_whale_24.zip";
//the zip classifier is the same as the
String relWavPath = "./src/test/resources/rawDeepLearningClassifier/Koogu/blue_whale_24/20190527_190000.wav";
String relMatPath = "./src/test/resources/rawDeepLearningClassifier/Koogu/blue_whale_24/rawScores_20190527_190000.mat";
//metadata says it should be used with Koogu classifier.
KooguDLClassifierTest.runKooguClassifier( relModelPath, relWavPath, relMatPath);
}
}

View File

@ -0,0 +1,5 @@
# Blue whale Koogu models.
There are two versions of blue whale models BmD_24_tf_model and BmD_23_tf_model in standard Tensorflow saved_.pb format.
There is also a blue_whale_24.kgu model which is the standard PAMGaurd compatible format for koogu models. This contains settings to set up the model automtically.