Bug fixes and updates to deep learning models
Defualt model for Atlantic humpback whale implemented Koogu and zip model unit tests
BIN
nullPamguardSettings_20240401_141954.psfx
Normal file
BIN
nullPamguardSettings_20240401_143317.psfx
Normal file
7
pom.xml
@ -961,5 +961,12 @@
|
||||
<version>0.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Atlanta style for JavaFX -->
|
||||
<dependency>
|
||||
<groupId>io.github.mkpaz</groupId>
|
||||
<artifactId>atlantafx-base</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
@ -295,4 +295,26 @@
|
||||
-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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@ import PamController.PamSettingManager;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import PamguardMVC.superdet.SuperDetection;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import detectionPlotFX.data.DDDataInfo;
|
||||
import detectionPlotFX.data.DDDataProvider;
|
||||
import detectionPlotFX.data.DDPlotRegister;
|
||||
@ -206,6 +207,9 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
//hidingPane.removeHideButton();
|
||||
hidingPane.styleHideButton(hidingPane.getHideButton(), Side.LEFT);
|
||||
|
||||
//make the background dark for settings pane.
|
||||
detectionDisplay.getSettingsHolder().setStyle("-fx-background-color: -fx-darkbackground");
|
||||
|
||||
}
|
||||
else {
|
||||
//the display is compact with all controls within an internal hiding pane.
|
||||
@ -213,6 +217,7 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
detectionDisplayHolder = new PamStackPane();
|
||||
|
||||
TabPane settingsPane = new TabPane();
|
||||
settingsPane.setStyle(Styles.TABS_FLOATING);
|
||||
settingsPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
|
||||
// settingsPane.getStylesheets().addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS());
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package pamViewFX.fxNodes.table;
|
||||
|
||||
import pamViewFX.fxNodes.PamBorderPane;
|
||||
import atlantafx.base.theme.Styles;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Orientation;
|
||||
@ -35,6 +36,7 @@ public abstract class TableSettingsPane<T> extends PamBorderPane {
|
||||
public TableSettingsPane(ObservableList<T> data){
|
||||
this.data=data;
|
||||
table = new TableView<T>();
|
||||
|
||||
this.setCenter(createPane());
|
||||
}
|
||||
|
||||
@ -90,7 +92,7 @@ public abstract class TableSettingsPane<T> extends PamBorderPane {
|
||||
|
||||
|
||||
//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().getDeleteButton().setDisable(table.getItems().size()<=0);
|
||||
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
|
||||
import PamView.ColourScheme;
|
||||
import PamView.PamColors;
|
||||
import atlantafx.base.theme.PrimerDark;
|
||||
import atlantafx.base.theme.PrimerLight;
|
||||
|
||||
/*
|
||||
* PAMGUARD - Passive Acoustic Monitoring GUARDianship.
|
||||
@ -49,7 +51,8 @@ public class PamAtlantaStyle extends PamDefaultStyle {
|
||||
*/
|
||||
// private String guiCSS = "/Resources/css/pamCSS.css";
|
||||
// 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
|
||||
@ -57,7 +60,8 @@ public class PamAtlantaStyle extends PamDefaultStyle {
|
||||
*/
|
||||
// private String dialogCSS = "/Resources/css/pamSettingsCSS.css";
|
||||
// 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();
|
||||
|
||||
|
||||
/**
|
||||
|
@ -372,16 +372,17 @@ public class DLDownloadManager {
|
||||
OutputStream output = new FileOutputStream(outFile);
|
||||
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) {
|
||||
System.out.println("Chunk: " + count);
|
||||
// System.out.println("Chunk: " + count);
|
||||
count=count+n; //total bytes
|
||||
notifyDownLoadListeners(DLStatus.DOWNLOADING, count);
|
||||
output.write( buffer, 0, n );
|
||||
}
|
||||
|
||||
System.out.println("Chunk: " + n);
|
||||
// System.out.println("Chunk: " + n);
|
||||
|
||||
output.close();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
# PAMGuard's deep learning module
|
||||
|
||||
Note: this module requires an internet connection upon first use to download correct libraries.
|
||||
|
||||
## 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.
|
||||
@ -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
|
||||
|
||||
<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>
|
||||
|
||||
_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
|
||||
|
||||
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
|
||||
|
||||
[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](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 — 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
|
||||
|
||||
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
|
||||
|
||||
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">
|
||||
@ -38,7 +52,7 @@ _The main settings pane for the deep learning module with descriptions_
|
||||
|
||||
### 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.
|
||||
|
||||
@ -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.
|
||||
|
||||
#### 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">
|
||||
<img width="700" height="700" src = "resources/advanced_settings_animalspot_1.png">
|
||||
</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
|
||||
|
||||
### 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.
|
||||
|
||||
### 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.
|
||||
|
||||
## 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.
|
||||
|
||||
### PAMGuard viewer mode
|
||||
|
||||
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 unit’s metadata, including the prediction values for all output classes from the deep learning model.
|
||||
@ -116,6 +145,7 @@ _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).
|
||||
|
||||
### 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.
|
||||
|
||||
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.
|
||||
@ -129,18 +159,17 @@ folder = '/Users/me/right_whale_project_1/PAMBinary/';
|
||||
%load all the detections in the folder
|
||||
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;
|
||||
|
||||
```matlab
|
||||
%% access the prediciton form the first detection
|
||||
predicitons = dldetections(1).annotations.dlclassification(j).predictions;
|
||||
|
||||
```
|
||||
|
||||
The loaded detections can then be plotted by accessing the waveform data in each structure;
|
||||
|
||||
```matlab
|
||||
|
||||
% plot all the spectrograms.
|
||||
clf
|
||||
tiledlayout(5,5)
|
||||
@ -185,11 +214,13 @@ for i=1:length(dldetections)
|
||||
_Right whale detections from a deep learning model imported and then plotted in MATLAB_
|
||||
|
||||
### 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).
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
Tensorflow models must be saved as .pb files to be opened in PAMGuard.
|
||||
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ import rawDeepLearningClassifier.dlClassification.genericModel.GenericModelParam
|
||||
import rawDeepLearningClassifier.layoutFX.exampleSounds.ExampleSoundFactory.ExampleSoundType;
|
||||
|
||||
/**
|
||||
*
|
||||
* Atlantic version of Google's humpback whale network.
|
||||
*/
|
||||
public class HumpbackWhaleAtlantic implements DLModel {
|
||||
|
||||
@ -34,14 +34,14 @@ public class HumpbackWhaleAtlantic implements DLModel {
|
||||
|
||||
@Override
|
||||
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): 2050–2064.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getModelURI() {
|
||||
try {
|
||||
return new URL("https://github.com/PAMGuard/deeplearningmodels/raw/master/right_whale_1/model_lenet_dropout_input_conv_all.zip").toURI();
|
||||
} catch (MalformedURLException | URISyntaxException e) {
|
||||
return new URI("https://github.com/PAMGuard/deeplearningmodels/raw/master/humpback_whale_2/humpback_whale_2.zip");
|
||||
} catch (URISyntaxException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -56,9 +56,8 @@ public class HumpbackWhaleAtlantic implements DLModel {
|
||||
@Override
|
||||
public URI getCitationLink() {
|
||||
try {
|
||||
return new URL("https://doi.org/10.3389/fmars.2021.607321").toURI();
|
||||
} catch (MalformedURLException | URISyntaxException e) {
|
||||
// TODO Auto-generated catch block
|
||||
return new URI("https://doi.org/10.1121/10.0025275");
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
@ -83,7 +82,6 @@ public class HumpbackWhaleAtlantic implements DLModel {
|
||||
genericModelParams.classNames= new DLClassName[] {new DLClassName("Humpback whale", (short) 1)};
|
||||
genericModelParams.numClasses = 1;
|
||||
|
||||
|
||||
genericModelParams.defaultShape= 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.setExampleSound(ExampleSoundType.HUMPBACK_WHALE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,7 +38,6 @@ public class HumpbackWhaleGoogle implements DLModel {
|
||||
try {
|
||||
return new URI("https://github.com/PAMGuard/deeplearningmodels/raw/master/humpback_whale_1/humpback_whale_1.zip");
|
||||
} catch (URISyntaxException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
@ -54,7 +53,6 @@ public class HumpbackWhaleGoogle implements DLModel {
|
||||
try {
|
||||
return new URI("https://doi.org/10.3389/fmars.2021.607321");
|
||||
} catch (URISyntaxException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
@ -79,7 +77,6 @@ public class HumpbackWhaleGoogle implements DLModel {
|
||||
genericModelParams.classNames= new DLClassName[] {new DLClassName("Humpback whale", (short) 1)};
|
||||
genericModelParams.numClasses = 1;
|
||||
|
||||
|
||||
genericModelParams.defaultShape= 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.setExampleSound(ExampleSoundType.HUMPBACK_WHALE);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,8 +102,8 @@ public class RightWhaleModel1 implements DLModel {
|
||||
@Override
|
||||
public URI getCitationLink() {
|
||||
try {
|
||||
return new URL("https://doi.org/10.1038/s41598-020-57549-y").toURI();
|
||||
} catch (MalformedURLException | URISyntaxException e) {
|
||||
return new URI("https://doi.org/10.1038/s41598-020-57549-y");
|
||||
} catch (URISyntaxException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
|
@ -217,7 +217,7 @@ public abstract class StandardModelPane extends SettingsPane<StandardModelParams
|
||||
.withMethod(c -> {
|
||||
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...");
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ public class ArchiveModelWorker extends GenericModelWorker {
|
||||
}
|
||||
}
|
||||
|
||||
if (modelParams.classNames!=null) {
|
||||
if (modelParams.classNames!=null && dlControl!=null) {
|
||||
dlParams.classNames = dlControl.getClassNameManager().makeClassNames(modelParams.classNames);
|
||||
}
|
||||
else {
|
||||
|
@ -133,7 +133,7 @@ public class DLModelSelectPane extends PamBorderPane {
|
||||
pathLabel = new Label("No classifier file selected");
|
||||
// PamButton pamButton = new PamButton("", PamGlyphDude.createPamGlyph(MaterialDesignIcon.FILE, PamGuiManagerFX.iconSize));
|
||||
PamButton pamButton = new PamButton("", PamGlyphDude.createPamIcon("mdi2f-file", PamGuiManagerFX.iconSize));
|
||||
pathLabel.setPrefWidth(100);
|
||||
pathLabel.setMinWidth(100);
|
||||
|
||||
modelLoadIndicator = new ProgressIndicator(-1);
|
||||
modelLoadIndicator.setVisible(false);
|
||||
@ -523,7 +523,7 @@ public class DLModelSelectPane extends PamBorderPane {
|
||||
private void updateMessage(DLStatus status, long bytesDownLoaded) {
|
||||
//the updates have their own messages but let's take some more control here.
|
||||
this.updateProgress(-1, 1); //set to intermediate
|
||||
System.out.println("Status: " + status);
|
||||
//System.out.println("Status: " + status);
|
||||
switch (status) {
|
||||
case CONNECTION_TO_URL:
|
||||
this.updateMessage("Checking URL");
|
||||
|
Before Width: | Height: | Size: 522 KiB After Width: | Height: | Size: 164 KiB |
Before Width: | Height: | Size: 547 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 396 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 525 KiB After Width: | Height: | Size: 221 KiB |
After Width: | Height: | Size: 81 KiB |
13
src/test/rawDeepLearningClassifier/DefaultDLModelTest.java
Normal file
@ -0,0 +1,13 @@
|
||||
package test.rawDeepLearningClassifier;
|
||||
|
||||
/**
|
||||
* Test the defualt models.
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class DefaultDLModelTest {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -39,7 +39,6 @@ public class GenericDLClassifierTest {
|
||||
*/
|
||||
@Test
|
||||
public void rightWhaleDLWorker() {
|
||||
|
||||
System.out.println("*****Generic DL: Right whale test*****");
|
||||
|
||||
//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
|
||||
* the ketos model and also using functions in KetosWorker.
|
||||
* Test Google's humpback whale model.
|
||||
*/
|
||||
@Test
|
||||
public void humpbackWhaleTest() {
|
||||
@ -146,7 +144,6 @@ public class GenericDLClassifierTest {
|
||||
|
||||
while((line = br.readLine()) != null){
|
||||
if (ind>0) {
|
||||
|
||||
//read the data from the text file
|
||||
String[] data = line.split("\t");
|
||||
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.
|
||||
assertEquals(output[0], prediction, 0.1); //humpback whale detection
|
||||
|
||||
|
||||
}
|
||||
ind++;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import org.jamdev.jdl4pam.utils.DLMatFile;
|
||||
import org.jamdev.jdl4pam.utils.DLUtils;
|
||||
import org.jamdev.jpamutils.wavFiles.AudioData;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -20,84 +21,117 @@ import rawDeepLearningClassifier.dlClassification.ketos.KetosDLParams;
|
||||
import rawDeepLearningClassifier.dlClassification.ketos.KetosWorker2;
|
||||
import rawDeepLearningClassifier.dlClassification.koogu.KooguModelWorker;
|
||||
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 {
|
||||
|
||||
//
|
||||
// /**
|
||||
// * 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/Ketos/hallo-kw-det_v1/hallo-kw-det_v1.ktpb";
|
||||
// String relWavPath = "./src/test/resources/rawDeepLearningClassifier/Ketos/hallo-kw-det_v1/jasco_reduced.wav";
|
||||
//
|
||||
// Path path = Paths.get(relModelPath);
|
||||
//
|
||||
// KooguModelWorker kooguWorker = new KooguModelWorker();
|
||||
//
|
||||
// StandardModelParams genericModelParams = new StandardModelParams();
|
||||
// genericModelParams.modelPath = path.toAbsolutePath().normalize().toString();
|
||||
//
|
||||
// //prep the model - all setting are included within the model
|
||||
// kooguWorker.prepModel(genericModelParams, null);
|
||||
// System.out.println("seglen: " + genericModelParams.defaultSegmentLen);
|
||||
//
|
||||
// /****Now run a file ***/
|
||||
// path = Paths.get(relWavPath);
|
||||
// String wavFilePath = path.toAbsolutePath().normalize().toString();
|
||||
//
|
||||
// try {
|
||||
//
|
||||
//
|
||||
// AudioData soundData = DLUtils.loadWavFile(wavFilePath);
|
||||
// double[] soundDataD = soundData.getScaledSampleAmplitudes();
|
||||
//
|
||||
//
|
||||
// long duration = (long) Math.ceil((genericModelParams.defaultSegmentLen/1000)*soundData.sampleRate);
|
||||
// System.out.println("duration: " + duration + " " + soundData.sampleRate + " " + genericModelParams.defaultSegmentLen);
|
||||
//
|
||||
// //dont't use the first and last because these are edge cases with zero padding
|
||||
// for (int i=1; i<ketosPredicitons.length-1; i++) {
|
||||
//
|
||||
// GroupedRawData groupedRawData = new GroupedRawData(0, 1, 0, duration, (int) duration);
|
||||
//
|
||||
// /**
|
||||
// * This is super weird but Ketos has some sort of very strange system of
|
||||
// * grabbing chunks of data from a sound file - seems like it grabs a little more
|
||||
// * 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.
|
||||
// * However for testing we have to get this right to compare results and so
|
||||
// * 0.0157 is subtract from the sound chunk
|
||||
// */
|
||||
// int startChunk =(int) ((ketosPredicitons[i][0]-0.0157)*soundData.sampleRate);
|
||||
//
|
||||
//
|
||||
// groupedRawData.copyRawData(soundDataD, startChunk, (int) duration, 0);
|
||||
//
|
||||
// ArrayList<GroupedRawData> groupedData = new ArrayList<GroupedRawData>();
|
||||
// groupedData.add(groupedRawData);
|
||||
//
|
||||
// ArrayList<GenericPrediction> genericPrediciton = ketosWorker2.runModel(groupedData, soundData.sampleRate, 0);
|
||||
// float[] output = genericPrediciton.get(0).getPrediction();
|
||||
//
|
||||
// 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);
|
||||
//
|
||||
// assertTrue(testPassed);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// ketosWorker2.closeModel();
|
||||
//
|
||||
// } catch (IOException | UnsupportedAudioFileException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// assertEquals(false, true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
|
||||
Path path = Paths.get(relModelPath);
|
||||
|
||||
KooguModelWorker kooguWorker = new KooguModelWorker();
|
||||
|
||||
StandardModelParams genericModelParams = new StandardModelParams();
|
||||
genericModelParams.modelPath = path.toAbsolutePath().normalize().toString();
|
||||
|
||||
//prep the model - all setting are included within the model
|
||||
kooguWorker.prepModel(genericModelParams, null);
|
||||
System.out.println("seglen: " + genericModelParams.defaultSegmentLen);
|
||||
|
||||
|
||||
for (int i=0; i<genericModelParams.dlTransfroms.size(); i++) {
|
||||
System.out.println(genericModelParams.dlTransfroms.get(i));
|
||||
}
|
||||
|
||||
|
||||
/****Now run a file ***/
|
||||
path = Paths.get(relWavPath);
|
||||
String wavFilePath = path.toAbsolutePath().normalize().toString();
|
||||
|
||||
//load predictions.
|
||||
path = Paths.get(relMatPath);
|
||||
|
||||
Mat5File file;
|
||||
double[][] kooguPredicitions = null;
|
||||
try {
|
||||
file = Mat5.readFromFile(path.toAbsolutePath().normalize().toString());
|
||||
Matrix matArray = file.getArray("scores");
|
||||
kooguPredicitions = DLMatFile.matrix2array(matArray);
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
AudioData soundData = DLUtils.loadWavFile(wavFilePath);
|
||||
double[] soundDataD = soundData.getScaledSampleAmplitudes();
|
||||
|
||||
|
||||
long duration = (long) Math.ceil((genericModelParams.defaultSegmentLen/1000)*soundData.sampleRate);
|
||||
System.out.println("duration: " + duration + " " + soundData.sampleRate + " " + genericModelParams.defaultSegmentLen);
|
||||
|
||||
int truecount=0;
|
||||
//dont't use the first and last because these are edge cases with zero padding
|
||||
for (int i=0; i<kooguPredicitions.length; i++) {
|
||||
|
||||
GroupedRawData groupedRawData = new GroupedRawData(0, 1, 0, duration, (int) duration);
|
||||
|
||||
//koogu predictions are in sam,ples
|
||||
int startChunk =(int) (kooguPredicitions[i][0]*soundData.sampleRate/250); ///the start chunk is in decimated samples - uuurgh
|
||||
|
||||
|
||||
groupedRawData.copyRawData(soundDataD, startChunk, (int) duration, 0);
|
||||
|
||||
ArrayList<GroupedRawData> groupedData = new ArrayList<GroupedRawData>();
|
||||
groupedData.add(groupedRawData);
|
||||
|
||||
|
||||
ArrayList<GenericPrediction> genericPrediciton = kooguWorker.runModel(groupedData, soundData.sampleRate, 0);
|
||||
float[] output = genericPrediciton.get(0).getPrediction();
|
||||
|
||||
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,
|
||||
output[0], kooguPredicitions[i][1], output[1], kooguPredicitions[i][2],testPassed));
|
||||
|
||||
if (testPassed) {
|
||||
truecount++;
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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.
|