diff --git a/.codespellrc b/.codespellrc
new file mode 100644
index 0000000..295ee3a
--- /dev/null
+++ b/.codespellrc
@@ -0,0 +1,9 @@
+[codespell]
+# Ref: https://github.com/codespell-project/codespell#using-a-config-file
+skip = .git,.git-meta,.gitignore,.gitattributes,.codespellrc,*.pb,optimized_models
+check-hidden = true
+# Ignore embedded base64 image data in Jupyter notebooks
+ignore-regex = ^\s*"image/\S+": ".*
+# momento - Spanish word ("moment") in Spanish-language code comment
+# commun - abbreviation of "Communications" (journal: Nat Commun Biol)
+ignore-words-list = momento,commun
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
new file mode 100644
index 0000000..8d6ddc2
--- /dev/null
+++ b/.github/workflows/codespell.yml
@@ -0,0 +1,23 @@
+# Codespell configuration is within .codespellrc
+---
+name: Codespell
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+permissions:
+ contents: read
+
+jobs:
+ codespell:
+ name: Check for spelling errors
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ - name: Codespell
+ uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2.2
diff --git a/README.md b/README.md
index 7714a3c..274c8f9 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-__rippl-AI__ is an open toolbox of Artifical Intelligence (AI) resources for detection of hippocampal neurophysiological signals, in particular sharp-wave ripples (SWR). This toolbox offers multiple successful plug-and-play machine learning (ML) models from 5 different architectures (1D-CNN, 2D-CNN, LSTM, SVM and XGBoost) that are ready to use to detect SWRs in hippocampal recordings. Moreover, there is an additional package that allows easy re-training, so that models are updated to better detect particular features of your own recordings. More details in [Navas-Olive, Rubio, et al. Commun Biol 7, 211 (2024)](https://www.nature.com/articles/s42003-024-05871-w)!
+__rippl-AI__ is an open toolbox of Artificial Intelligence (AI) resources for detection of hippocampal neurophysiological signals, in particular sharp-wave ripples (SWR). This toolbox offers multiple successful plug-and-play machine learning (ML) models from 5 different architectures (1D-CNN, 2D-CNN, LSTM, SVM and XGBoost) that are ready to use to detect SWRs in hippocampal recordings. Moreover, there is an additional package that allows easy re-training, so that models are updated to better detect particular features of your own recordings. More details in [Navas-Olive, Rubio, et al. Commun Biol 7, 211 (2024)](https://www.nature.com/articles/s42003-024-05871-w)!
# Description
@@ -38,7 +38,7 @@ In this project, we take advantage of supervised machine learning approaches to
# The toolbox
-This toolbox contains three main blocks: **detection**, **re-training** and **exploration**. These three packages can be used jointly or separatedly. We will proceed to describe each of their purpose and usage.
+This toolbox contains three main blocks: **detection**, **re-training** and **exploration**. These three packages can be used jointly or separately. We will proceed to describe each of their purpose and usage.
## Detection
@@ -54,7 +54,7 @@ In this toolbox, we widen the machine learning spectrum, by offering multiple pl
* **High stability**, so performance does not depend on threshold selection
* **High generability**, so performance remains good on very different contexts
-This respository contains the best five `model`s from each of these five `architecture`s. These `model`s are already trained using mice data, and can be found in the [optimized_models/](https://github.com/PridaLab/rippl-AI/blob/main/optimized_models/) folder.
+This repository contains the best five `model`s from each of these five `architecture`s. These `model`s are already trained using mice data, and can be found in the [optimized_models/](https://github.com/PridaLab/rippl-AI/blob/main/optimized_models/) folder.
The [rippl_AI](https://github.com/PridaLab/rippl-AI/blob/main/rippl_AI.py) python module contains all the necessary functions to easily use any `model` to detect SWRs. Additionally, we also provide some auxiliary functions in the [aux_fcn](https://github.com/PridaLab/rippl-AI/blob/main/aux_fcn.py) module, that contains useful code to process LFP and evaluate performance detection.
@@ -79,8 +79,8 @@ The `rippl_AI.predict()` input and output variables are:
* Optional inputs:
- `arch`: Name of the AI architecture to use (`string`). It can be: `CNN1D`, `CNN2D`, `LSTM`, `SVM` or `XGBOOST`.
- `model_number`: Number of the model to use (`integer`). There are six different models for each architecture, sorted by performance, being `1` the best, and `5` the last. `model_number=6` model can be used if single-channel data needs to be used.
- - `channels`: Channels to be used for detection (`np.array` or `list`: `1` x `8`). This is the most senstive parameter, because models will be looking for specific spatial features over all channels. Counting starts in `0`. The two main remarks are:
- * All models have been trained to look at features in the pyramidal layer (SP), so for them to work at their maximum potential, the selected channels would ideally be centered in the SP, with a postive deflection on the first channels (upper channels) and a negative deflection on the last channels (lower channels). The image above can be used as a visual reference of how to choose channels.
+ - `channels`: Channels to be used for detection (`np.array` or `list`: `1` x `8`). This is the most sensitive parameter, because models will be looking for specific spatial features over all channels. Counting starts in `0`. The two main remarks are:
+ * All models have been trained to look at features in the pyramidal layer (SP), so for them to work at their maximum potential, the selected channels would ideally be centered in the SP, with a positive deflection on the first channels (upper channels) and a negative deflection on the last channels (lower channels). The image above can be used as a visual reference of how to choose channels.
* For all combinations of `architectures` and `model_numbers`, `channels` **has to be of size 8**. There is only one exception, for `architecture = 2D-CNN` with `models = {3, 4, 5}`, that needs to have **3 channels**.
* If you are using a high-density probe, then we recommend to use equi-distant channels from the beginning to the end of the SP. For example, for Neuropixels in mice, a good set of channels would be `pyr_channel` + [-8,-6,-4,-2,0,2,4,6].
* In the case of linear probes or tetrodes, there are not enough density to cover the SP with 8 channels. For that, interpolation or recorded channels can be done without compromising performance. New artificial interpolated channels will be add to the LFP wherever there is a `-1` in `channels`. For example, if `pyr_channel=11` in your linear probe, so that 10 is in _stratum oriens_ and 12 in _stratum radiatum_, then we could define `channels=[10,-1,-1,11,-1,-1,-1,12]`, where 2nd and 3rd channels will be an interpolation of SO and SP channels, and 5th to 7th an interpolation of SP and SR channels. For tetrodes, organising channels according to their spatial profile is very convenient to assure best performance. These interpolations are done using the function `aux_fcn.interpolate_channels()`.
@@ -89,7 +89,7 @@ The `rippl_AI.predict()` input and output variables are:
- `d_sf`: Desired subsampling frequency in Hz (`int`). By default all works in 1250 Hz, but can be changed if you retrain your models using `rippl_AI.retrain_model`.
* Output:
- - `SWR_prob`: model output for every sample of the LFP (`np.array`: `n_samples` x 1). It can be interpreted as the confidence or probability of a SWR event, so values close to 0 mean that the `model` is certain that there are not SWRs, and values close to 1 that the model is very sure that there is a SWR hapenning.
+ - `SWR_prob`: model output for every sample of the LFP (`np.array`: `n_samples` x 1). It can be interpreted as the confidence or probability of a SWR event, so values close to 0 mean that the `model` is certain that there are not SWRs, and values close to 1 that the model is very sure that there is a SWR happening.
- `LFP_norm`: LFP data used as an input to the model (`np.array`: `n_samples` x `len(channels)`). It is undersampled to 1250Hz, z-scored, and transformed to used the channels specified in `channels`.
@@ -107,13 +107,13 @@ The python function `get_intervals(SWR_prob, LFP_norm=None, sf=1250, win_size=10
- `threshold`: Threshold of predictions (`float`)
- `LFP_norm`: Normalized input signal of the model (`np.array`: `n_samples` x `n_channels`). It is recommended to use `LFP_norm`.
- `file_path`: Absolute path of the folder where the .txt with the predictions will be generated (`string`). Leave empty if you don't want to generate the file.
- - `win_size`: Length of the displayed ripples in miliseconds (`integer`). By default 100 ms.
+ - `win_size`: Length of the displayed ripples in milliseconds (`integer`). By default 100 ms.
- `sf`: Sampling frequency (Hz) of `LFP_norm` (`integer`). By default 1250 Hz (i.e., sampling frequency of `LFP_norm`).
- - `merge_win`: Minimal length of the interval in miliseconds between predictions (`float`). If two detections are closer in time than this parameter, they will be merged together
+ - `merge_win`: Minimal length of the interval in milliseconds between predictions (`float`). If two detections are closer in time than this parameter, they will be merged together
There are 4 possible use cases, depending on which parameter combination is used when calling the function.
- 1. `rippl_AI.get_intervals(SWR_prob)`: a histogram of the output is displayed, you drag a vertical bar to selecct your `threshold`
- 2. `rippl_AI.get_intervals(SWR_prob,threshold)`: no GUI is displayed, the predictions are gererated automatically
+ 1. `rippl_AI.get_intervals(SWR_prob)`: a histogram of the output is displayed, you drag a vertical bar to select your `threshold`
+ 2. `rippl_AI.get_intervals(SWR_prob,threshold)`: no GUI is displayed, the predictions are generated automatically
3. `rippl_AI.get_intervals(SWR_prob,LFP_norm)`: some examples of detected events are displayed next to the histogram
4. `rippl_AI.get_intervals(SWR_prob,LFP_norm,threshold)`: same case as 3, but the initial location of the bar is `threshold`
@@ -122,7 +122,7 @@ The python function `get_intervals(SWR_prob, LFP_norm=None, sf=1250, win_size=10
- `get_intervals(SWR_prob, 'threshold', threshold)`: if a threshold is given, then it takes that threshold without displaying any GUI.
* Outputs:
- - `predictions`: Returns the time (in seconds) of the begining and end of each vents. (`n_events` x 2)
+ - `predictions`: Returns the time (in seconds) of the beginning and end of each vents. (`n_events` x 2)
### aux_fcn.manual_curation()
@@ -130,10 +130,10 @@ The python function `get_intervals(SWR_prob, LFP_norm=None, sf=1250, win_size=10
The python function `aux_fcn.manual_curation(events, data, file_path, win_size=100, gt_events=None, sf=1250)` of the `aux_fcn` module allows doing a manual curation of the detected events. It displays an interactive GUI to manually select/discard the events.
* Mandatory inputs:
- - `events`: array with events begining and end times in seconds (`2`,`n_det`).
+ - `events`: array with events beginning and end times in seconds (`2`,`n_det`).
- `data`: normalized array with the input data (`n,n_channels`)
- `file_path`: absolute path of the folder where the .txt with the curated predictions will be saved (`str`).
- - `win_size`: length of the displayed ripples in miliseconds (`int`)
+ - `win_size`: length of the displayed ripples in milliseconds (`int`)
- `gt_events`: ground truth events beginning and end times in seconds (`2`,`n_gt_events`)
- `sf`: sampling frequency (Hz) of the data/model output (`int`). Change if different than 1250 Hz.
@@ -143,7 +143,7 @@ The python function `aux_fcn.manual_curation(events, data, file_path, win_size=1

Use cases:
-1. If no GT events are provided, a the detected events will be provided, you can select which ones you want to keep (highligted in green) and which ones to discard (in red)
+1. If no GT events are provided, a the detected events will be provided, you can select which ones you want to keep (highlighted in green) and which ones to discard (in red)
2. If GT events are provided, true positive detections (TP) will be displayed in green. If for any reason you want to discard correct detections, they will be displayed in yellow
@@ -153,7 +153,7 @@ The python function `aux_fcn.plot_all_events(t_events, lfp, sf, win=0.1, title='
* Mandatory inputs:
- `events`: numpy array of size (`#events`, `1`) with all times of events
- - `lfp`: formated lfp with all channels
+ - `lfp`: formatted lfp with all channels
- `sf`: sampling frequency of `lfp`
* Optional inputs:
@@ -193,7 +193,7 @@ Because these models best performed using a richer spatial profile, all combinat
# Make interpolation
LFP_interpolated = aux_fcn.interpolate_channels(LFP, channels_interpolation)
```
- - Let's say we have 8 channels, but channels 2 and 5 are dead. Then we want to interpolate them to get 8 fuctional channels:
+ - Let's say we have 8 channels, but channels 2 and 5 are dead. Then we want to interpolate them to get 8 functional channels:
```
# Define channels
channels_interpolation = [0,1,-1,3,4,-1,6,7,8]
@@ -259,21 +259,21 @@ The python function `rippl_AI.retrain_model(train_data, train_GT, test_data, tes
- In 'XGBOOST': not needed
- In 'SVM':
parameters['Undersampler proportion']. Any value between 0 and 1. This parameter eliminates
- samples where no ripple is present untill the desired proportion is achieved:
+ samples where no ripple is present until the desired proportion is achieved:
Undersampler proportion= Positive samples/Negative samples
- In 'LSTM', 'CNN1D' and 'CNN2D':
parameters['Epochs']. The number of times the training data set will be used to train the model
parameters['Training batch']. The number of windows that will be processed before updating the weights
- `save_path`: string, path where the retrained model will be saved
- `d_sf`: Desired subsampling frequency in Hz (`int`). By default all works in 1250 Hz, but this function allows using different subsampling frequencies.
- - `merge_win`: Minimal length of the interval in miliseconds between predictions (`float`). If two detections are closer in time than this parameter, they will be merged together
+ - `merge_win`: Minimal length of the interval in milliseconds between predictions (`float`). If two detections are closer in time than this parameter, they will be merged together
Usage examples can be found in the [examples_retraining.ipynb](https://github.com/PridaLab/rippl-AI/blob/main/examples_retraining.ipynb) python notebook.
## Exploration
-Finally, as a further explotation of this toolbox, we also offer an exploration module, in which you can create your own model. In the [examples_explore](https://github.com/PridaLab/rippl-AI/blob/main/examples_explore/) folder, you can see how different architectures can be modified by multiple parameters to create infinite number of other models, that can be better adjusted to the need of your desired events. For example, if you are interested in lower frequency events, such as theta cycles, this exploratory module will be of utmost convenience to find an AI architecture that better adapts to the need of your research. Here, we specify the most common parameters to explore for each architecture:
+Finally, as a further exploitation of this toolbox, we also offer an exploration module, in which you can create your own model. In the [examples_explore](https://github.com/PridaLab/rippl-AI/blob/main/examples_explore/) folder, you can see how different architectures can be modified by multiple parameters to create infinite number of other models, that can be better adjusted to the need of your desired events. For example, if you are interested in lower frequency events, such as theta cycles, this exploratory module will be of utmost convenience to find an AI architecture that better adapts to the need of your research. Here, we specify the most common parameters to explore for each architecture:
### 1D-CNN
* Channels: number of LFP channel
@@ -309,7 +309,7 @@ Finally, as a further explotation of this toolbox, we also offer an exploration
* Scale
-# Enviroment setup
+# Environment setup
1. Install miniconda, following the tutorial: https://docs.conda.io/en/latest/miniconda.html
2. Launch the anaconda console, typing anaconda promp in the windows/linux search bar.
@@ -317,15 +317,15 @@ Finally, as a further explotation of this toolbox, we also offer an exploration
```
conda create -n rippl_AI_env python=3.9.15
```
-4. This will create a enviroment in your miniconda3 enviroments folder, usually: `C:\Users\\miniconda3\envs`
-5. Check that the enviroment `rippl_AI_env` has been created by typing:
+4. This will create a environment in your miniconda3 environments folder, usually: `C:\Users\\miniconda3\envs`
+5. Check that the environment `rippl_AI_env` has been created by typing:
```
conda env list
```
-6. Activate the enviroment with:
+6. Activate the environment with:
```conda activate rippl_AI_env```
In case you want to launch the scripts from the command prompt. If you are using Visual Studio Code, you need to select the python interpreter `rippl_AI_env`
-7. Next step after activating the enviroment, is to install every necessary python package:
+7. Next step after activating the environment, is to install every necessary python package:
```
conda install pip
pip install tensorflow==2.11 keras==2.11 xgboost==1.6.1 imblearn numpy matplotlib pandas scipy
diff --git a/aux_fcn.py b/aux_fcn.py
index cbc12d3..1f8614d 100644
--- a/aux_fcn.py
+++ b/aux_fcn.py
@@ -48,7 +48,7 @@ def loadChunk(fid, nChannels, channels, nSamples, precision):
data = fid.read(size)
# fromstring to read the data as int16
- # reshape to give it the appropiate shape (nSamples x nChannels)
+ # reshape to give it the appropriate shape (nSamples x nChannels)
data = np.fromstring(data, dtype=np.int16).reshape(nSamples, len(channels))
data = data[:, channels]
@@ -70,7 +70,7 @@ def bz_LoadBinary(filename, nChannels, channels, sampleSize, verbose=False):
print("fileStart ", fileStart)
status = f.seek(0, 2) # Go to the end of the file
fileStop = f.tell()
- f.seek(0, 0) # Back to the begining
+ f.seek(0, 0) # Back to the beginning
if verbose:
print("fileStop ", fileStop)
@@ -102,7 +102,7 @@ def bz_LoadBinary(filename, nChannels, channels, sampleSize, verbose=False):
if verbose:
print("size data ", np.size(data, 0))
- # Read all chuncks
+ # Read all chunks
i = 0
for j in range(nChunks):
d = loadChunk(f, nChannels, channels, nSamplesPerChunk/nChannels, sampleSize)
@@ -469,7 +469,7 @@ def get_predictions_index(predictions,threshold=0.5,merge_samples=0):
'''
[pred_indexes] = get_predictions_index(predictions, thershold)
- Returns the begining and ending samples of the events above a given threshold
+ Returns the beginning and ending samples of the events above a given threshold
Inputs:
-------
@@ -479,7 +479,7 @@ def get_predictions_index(predictions,threshold=0.5,merge_samples=0):
Output:
-------
- pred_indexes: Nx2, array containing the begining and ending index sample of the events
+ pred_indexes: Nx2, array containing the beginning and ending index sample of the events
'''
aux=np.copy(predictions)
aux[aux>=threshold]=1
@@ -552,7 +552,7 @@ def format_predictions(path,preds,d_sf):
return
-# Performance (precission, recall, F1) metrics
+# Performance (precision, recall, F1) metrics
def get_performance(pred_events, true_events, threshold=0, exclude_matched_trues=False, verbose=True):
@@ -565,7 +565,7 @@ def get_performance(pred_events, true_events, threshold=0, exclude_matched_trues
pred_events Nx2 matrix with start and end of pred events (seconds)
true_events Mx2 matrix with start and end of true events (seconds)
threshold Threshold to IoU. By default is 0
- exclude_matched_trues False by defaut (one true can match many predictions)
+ exclude_matched_trues False by default (one true can match many predictions)
Output:
-------
@@ -674,12 +674,12 @@ def intersection_over_union(x, y):
elif len(x)==0:
- print('x is empty. Cant perform IoU')
+ print("x is empty. Can't perform IoU")
return np.array([]), np.array([]), np.zeros((y.shape[0], 1))
elif len(y)==0:
- print('y is empty. Cant perform IoU')
+ print("y is empty. Can't perform IoU")
return np.array([]), np.zeros((1, x.shape[0])), np.array([])
@@ -712,10 +712,10 @@ def split_data(x,GT,window_dur=60,d_sf=1250,split=0.7):
-------
x: [n X n_channels] matrix with the LFP values of the session
GT: [n events x 2] initial and end times of each events
- window_dur: float, length in seconds of the chunks that will be asigned
+ window_dur: float, length in seconds of the chunks that will be assigned
randomly to train or validation subsets
d_sf: (int), sampling frequency of the passed data
- split: float, proportion of windows that will be asigned to the
+ split: float, proportion of windows that will be assigned to the
train subset (the final proportion will diverge, being random)
Output:
@@ -771,7 +771,7 @@ def retraining_parser(arch,x_train_or,events_train,x_test,events_test,params=Non
- In 'XGBOOST': not needed
- In 'SVM':
params['Undersampler proportion']. Any value between 0 and 1. This parameter eliminates
- samples where no ripple is present untill the desired proportion is achieved:
+ samples where no ripple is present until the desired proportion is achieved:
Undersampler proportion= Positive samples/Negative samples
- In 'LSTM', 'CNN1D' and 'CNN2D':
params['Epochs']. The number of times the training data set will be used to train the model
@@ -835,7 +835,7 @@ def retraining_parser(arch,x_train_or,events_train,x_test,events_test,params=Non
y_test_aux=y_test[:x_test_len-x_test_len%timesteps].reshape(-1,timesteps)
y_test=rec_signal(y_test_aux)
- #Under sampler: discards windows where there is no ripples untill the desired proportion between ripple/no ripple is achieved
+ #Under sampler: discards windows where there is no ripples until the desired proportion between ripple/no ripple is achieved
# If no params is provided, the defect proportion will be 0.5
if params==None:
us_prop=0.5
@@ -1017,9 +1017,9 @@ def get_keep(self,n):
return(self.keeps[self.index+n])
def get_TP(self,n):
return(self.TP[self.index+n])
- # Individual keep change, change keep to discard and viceversa for a single value
+ # Individual keep change, change keep to discard and vice-versa for a single value
def change_keep(self,ind):
- if (self.check_index(ind)): # True if out of bounds, returns True for excetion handling
+ if (self.check_index(ind)): # True if out of bounds, returns True for exception handling
return True
self.keeps[self.index+ind]= not (self.keeps[self.index+ind])
# Multiple keep change, sets keep from index to index+number equal to value
@@ -1050,11 +1050,11 @@ def manual_curation(events,data,file_path,win_size=100,gt_events=None,sf=1250):
Inputs:
-------
- events: (2,n_det) array with events begining and end times (seconds)
+ events: (2,n_det) array with events beginning and end times (seconds)
data: (n,n_channels) normalized array with the input data
file_path: (str) absolute path of the folder where the .txt with the
curated predictions will be saved
- win_size: (int) length of the displayed ripples in miliseconds
+ win_size: (int) length of the displayed ripples in milliseconds
gt_events: (2,n_gt_events) ground truth events beginning and end times (seconds)
sf: (int) sampling frequency (Hz) of the data/model output.
Change if different than 1250
@@ -1067,7 +1067,7 @@ def manual_curation(events,data,file_path,win_size=100,gt_events=None,sf=1250):
Use cases:
1. If no GT events are provided, a the detected events will be provided,
- you can select which ones you want to keep (highligted in green)
+ you can select which ones you want to keep (highlighted in green)
and which ones to discard (in red)
2. If GT events are provided, true positive detections (TP) will be
displayed in green. If for any reason you want to discard correct
@@ -1208,7 +1208,7 @@ def on_click(event):
row_ind,col_ind=np.argwhere(axes==ax)[0]
clicked_ind=(row_ind*int(events_in_screen/5)+col_ind)
- if oIn.change_keep(clicked_ind): # If out of bounds, close early, dont change color
+ if oIn.change_keep(clicked_ind): # If out of bounds, close early, don't change color
return
check_colors(oIn,clicked_ind,ax)
curated_intervals=oIn.intervals[oIn.keeps]
@@ -1233,7 +1233,7 @@ def plot_all_events(t_events, lfp, sf, win=0.100, title='', savefig=''):
events (numpy array):
Array of size (#events, 1) with all times of events
lfp (numpy array):
- formated lfp with all channels
+ formatted lfp with all channels
sf (int):
sampling frequency of the 'lfp' variable
@@ -1403,7 +1403,7 @@ def build_CNN2D(conf, input_shape = (50,8,1)):
def build_CNN1D(n_channels,timesteps,conf):
'''
model = build_CNN1D(n_channels, timesteps, conf)\n
- Returns a 1D convolutional neural network. If the desired configuration will create problems, and exception with sugestions is thrown\n
+ Returns a 1D convolutional neural network. If the desired configuration will create problems, and exception with suggestions is thrown\n
Inputs:
-------
diff --git a/examples_detection.ipynb b/examples_detection.ipynb
index 9058152..aa72964 100644
--- a/examples_detection.ipynb
+++ b/examples_detection.ipynb
@@ -170,7 +170,7 @@
"metadata": {},
"source": [
"# Get performances after detection\n",
- "Every model predict, get_intervals is used automatically and the performance metric is ploted"
+ "Every model predict, get_intervals is used automatically and the performance metric is plotted"
]
},
{
@@ -321,7 +321,7 @@
"metadata": {},
"source": [
"### Data load\n",
- "To ilustrate how 'interpolate_channels' can be used to extract the desired number of channels, we will be simulating two cases using the DLx1 session:\n",
+ "To illustrate how 'interpolate_channels' can be used to extract the desired number of channels, we will be simulating two cases using the DLx1 session:\n",
"1. We are using a recording probe that extracts 4 channels, when we need 8.\n",
"2. Some channels are dead or have to much noise."
]
diff --git a/examples_explore/example_CNN1D.ipynb b/examples_explore/example_CNN1D.ipynb
index 13aeb95..5e0ee6f 100644
--- a/examples_explore/example_CNN1D.ipynb
+++ b/examples_explore/example_CNN1D.ipynb
@@ -125,7 +125,7 @@
"* Timesteps: number of samples that the model will use to produce a single output\n",
"* Configuration: list with as many elements as layers in the model shaped [number of kernels layers, kernel size and stride ]. The length size and the kernel layer were matched to reduce design complexity.\n",
"* Epoch: number of times the training data set is used to train the model\n",
- "* Training batch: number of windows that are proccessed before weight updating"
+ "* Training batch: number of windows that are processed before weight updating"
]
},
{
@@ -294,7 +294,7 @@
"# For loop iterating over the models\n",
"fig,axs=plt.subplots(n_iters,2,figsize=(10,2*n_iters),sharey='col',sharex='col')\n",
"for n_m,model in enumerate(model_arr):\n",
- " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each sesion will be stored\n",
+ " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each session will be stored\n",
" for n_sess,LFP in enumerate(x_val_list):\n",
" val_pred=rippl_AI.predict(LFP,sf=1250,arch='CNN1D',new_model=model,n_channels=n_channels,n_timesteps=timesteps_arr_ploting[n_m])[0]\n",
" for i,th in enumerate(th_arr):\n",
diff --git a/examples_explore/example_CNN2D.ipynb b/examples_explore/example_CNN2D.ipynb
index d7d53de..8bfb3cb 100644
--- a/examples_explore/example_CNN2D.ipynb
+++ b/examples_explore/example_CNN2D.ipynb
@@ -8,7 +8,7 @@
"# CNN2D parameter exploration\n",
"This notebook is a template for finding the CNN2D model best suited for your needs \n",
"\n",
- "This arquitecture is inspired by the UNet (https://doi.org/10.48550/arXiv.1505.04597) and YOLOR (https://doi.org/10.48550/arXiv.2105.04206)\n",
+ "This architecture is inspired by the UNet (https://doi.org/10.48550/arXiv.1505.04597) and YOLOR (https://doi.org/10.48550/arXiv.2105.04206)\n",
"The 1st half uses convolution and MaxPooling to reduce the dimnensinality of the input, and the late half expands it"
]
},
@@ -126,7 +126,7 @@
"of layers of the model according to the number of channels or timesteps, the smallest of the two: 8 channels allows 4 max Pooling steps (8 -> 4 -> 2 -> 1), 3 channels only 1 (3 ->1)\n",
"Please take it into consideration when designing models\n",
"* Epoch: number of times the training data set is used to train the model\n",
- "* Training batch: number of windows that are proccessed before weight updating"
+ "* Training batch: number of windows that are processed before weight updating"
]
},
{
@@ -299,7 +299,7 @@
"# For loop iterating over the models\n",
"fig,axs=plt.subplots(n_iters,2,figsize=(10,2*n_iters),sharey='col',sharex='col')\n",
"for n_m,model in enumerate(model_arr):\n",
- " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each sesion will be stored\n",
+ " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each session will be stored\n",
" for n_sess,LFP in enumerate(x_val_list):\n",
" val_pred=rippl_AI.predict(LFP,sf=1250,arch='CNN2D',new_model=model,n_channels=n_channels,n_timesteps=timesteps_arr_ploting[n_m])[0]\n",
" for i,th in enumerate(th_arr):\n",
diff --git a/examples_explore/example_LSTM.ipynb b/examples_explore/example_LSTM.ipynb
index d825375..ab6d63d 100644
--- a/examples_explore/example_LSTM.ipynb
+++ b/examples_explore/example_LSTM.ipynb
@@ -119,13 +119,13 @@
"#### Parameters:\n",
"* Channels: number of channels that will be used to train the model, extracted from the data shape defined in the previous cell\n",
"* Timesteps: number of samples that the will be processed at once\n",
- "* Bidirectionality: if the model processes simutaneously the window forward and backwards\n",
+ "* Bidirectionality: if the model processes simultaneously the window forward and backwards\n",
"* Layers: number of LSTM layers\n",
"* Epoch: number of times the training data set is used to train the model\n",
- "* Training batch: number of windows that are proccessed before weight updating\n",
+ "* Training batch: number of windows that are processed before weight updating\n",
"\n",
"#\n",
- "LSTM contains more parameters, feel free to add your own modifications. Check the oficial documentation:\n",
+ "LSTM contains more parameters, feel free to add your own modifications. Check the official documentation:\n",
"https://keras.io/api/layers/recurrent_layers/lstm/"
]
},
@@ -288,7 +288,7 @@
"# For loop iterating over the models\n",
"fig,axs=plt.subplots(n_iters,2,figsize=(10,2*n_iters),sharey='col',sharex='col')\n",
"for n_m,model in enumerate(model_arr):\n",
- " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each sesion will be stored\n",
+ " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each session will be stored\n",
" for n_sess,LFP in enumerate(x_val_list):\n",
" val_pred=rippl_AI.predict(LFP,sf=1250,arch='LSTM',new_model=model,n_channels=n_channels,n_timesteps=timesteps_arr_ploting[n_m])[0]\n",
" for i,th in enumerate(th_arr):\n",
diff --git a/examples_explore/example_SVM.ipynb b/examples_explore/example_SVM.ipynb
index 0b48f86..21e8e71 100644
--- a/examples_explore/example_SVM.ipynb
+++ b/examples_explore/example_SVM.ipynb
@@ -276,7 +276,7 @@
"# For loop iterating over the models\n",
"fig,axs=plt.subplots(n_iters,2,figsize=(10,2*n_iters),sharey='col',sharex='col')\n",
"for n_m,model in enumerate(model_arr):\n",
- " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each sesion will be stored\n",
+ " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each session will be stored\n",
" for n_sess,LFP in enumerate(x_val_list):\n",
" val_pred=rippl_AI.predict(LFP,sf=1250,arch='SVM',new_model=model,n_channels=n_channels,n_timesteps=timesteps_arr_ploting[n_m])[0]\n",
" for i,th in enumerate(th_arr):\n",
diff --git a/examples_explore/example_XGBOOST.ipynb b/examples_explore/example_XGBOOST.ipynb
index 50038ac..3552c69 100644
--- a/examples_explore/example_XGBOOST.ipynb
+++ b/examples_explore/example_XGBOOST.ipynb
@@ -120,13 +120,13 @@
"* Channels: number of channels that will be used to train the model, extracted from the data shape defined in the previous cell\n",
"* Timesteps: number of samples that the will be used to generate a single prediction\n",
"* Max depth: number of max layers in each tree. Too many usually causes overfitting\n",
- "* Learning rate: similar to a weight used to update te predictor, a high value leads to faster computations but may not reaach a optimal value\n",
+ "* Learning rate: similar to a weight used to update the predictor, a high value leads to faster computations but may not reaach a optimal value\n",
"* Gamma: Minimum loss reduction required to make a partition on a leaf node. The larger gamma is, the more conservative the model will be\n",
- "* Reg lamda: L2 regularization term of weight updating. Increasing this value makes the model more conservative\n",
+ "* Reg lambda: L2 regularization term of weight updating. Increasing this value makes the model more conservative\n",
"* Scale pos weight: controls the balance of positive and negative weights, useful for unbalanced clasess.\n",
"* Subsample: subsample ratio of the training instances. Setting it to 0.5 means that XGBoost would randomly sample half of the training data prior to growing trees. Used to prevent overfitting\n",
"#\n",
- "XGBOOST contains many more parameters, feel free to add your own modifications. Check the oficial documentation: https://xgboost.readthedocs.io/en/stable/parameter.html#parameters-for-tree-booster"
+ "XGBOOST contains many more parameters, feel free to add your own modifications. Check the official documentation: https://xgboost.readthedocs.io/en/stable/parameter.html#parameters-for-tree-booster"
]
},
{
@@ -308,7 +308,7 @@
"# For loop iterating over the models\n",
"fig,axs=plt.subplots(n_iters,2,figsize=(10,2*n_iters),sharey='col',sharex='col')\n",
"for n_m,model in enumerate(model_arr):\n",
- " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each sesion will be stored\n",
+ " F1_arr=np.zeros(shape=(len(x_val_list),len(th_arr))) #(n_val_sess x n_th) Array where the F1 val of each session will be stored\n",
" for n_sess,LFP in enumerate(x_val_list):\n",
" val_pred=rippl_AI.predict(LFP,sf=1250,arch='XGBOOST',new_model=model,n_channels=n_channels,n_timesteps=timesteps_arr_ploting[n_m])[0]\n",
" for i,th in enumerate(th_arr):\n",
diff --git a/examples_retraining.ipynb b/examples_retraining.ipynb
index 4c43d18..6d13b89 100644
--- a/examples_retraining.ipynb
+++ b/examples_retraining.ipynb
@@ -140,7 +140,7 @@
"source": [
"### SVM\n",
"Has only one parameter: \n",
- "'Undersampler proportion': It controls the number of windows with negatives (no ripples) that will be used to train the model. Following the formula: Undersampler proportion= (Positive windows)/(Negative windows). 1 means the same number of poitive and negative windows. Low values can lead to overfitting."
+ "'Undersampler proportion': It controls the number of windows with negatives (no ripples) that will be used to train the model. Following the formula: Undersampler proportion= (Positive windows)/(Negative windows). 1 means the same number of positive and negative windows. Low values can lead to overfitting."
]
},
{
diff --git a/rippl_AI.py b/rippl_AI.py
index 73b55cd..20bf657 100644
--- a/rippl_AI.py
+++ b/rippl_AI.py
@@ -33,12 +33,12 @@ def predict(LFP,sf,d_sf=1250,arch='CNN1D',model_number=1,channels=np.arange(8),n
for each architecture, sorted by performance, 1 being the best, and 5 the last.
A sixth model is included if single-channel data needs to be used.
channels: Channels to be used for detection (np.array or list: 1 x 8). This is the most
- senstive parameter, because models will be looking for specific spatial features
+ sensitive parameter, because models will be looking for specific spatial features
over all channels. Counting starts in 0.
The two main remarks are:
- All models have been trained to look at features in the pyramidal layer (SP),
so for them to work at their maximum potential, the selected channels would
- ideally be centered in the SP, with a postive deflection on the first channels
+ ideally be centered in the SP, with a positive deflection on the first channels
(upper channels) and a negative deflection on the last channels (lower channels).
- For all combinations of architectures and model_numbers, channels has to be
of size 8. There is only one exception, for architecture = 2D-CNN with
@@ -59,7 +59,7 @@ def predict(LFP,sf,d_sf=1250,arch='CNN1D',model_number=1,channels=np.arange(8),n
new_model: Other re-trained model you want to use for detection. If you have used our re-train function
to adapt the optimized models to your own data (see rippl_AI.retrain() for more details),
you can input the new_model here to use it to predict your events.
- IMPORTANT! If you are using new_model, the data wont be processed, so make sure to
+ IMPORTANT! If you are using new_model, the data won't be processed, so make sure to
have your data z-scored, subsampled at your subsampling freq and with the
correct channels before calling predict, for example using the process_LFPfunction
IMPORTANT! If you are using a new_model, you have to pass as arguments its number of
@@ -72,7 +72,7 @@ def predict(LFP,sf,d_sf=1250,arch='CNN1D',model_number=1,channels=np.arange(8),n
SWR_prob: model output for every sample of the LFP (np.array: n_samples x 1).
It can be interpreted as the confidence or probability of a SWR event, so values
close to 0 mean that the model is certain that there are not SWRs, and values close
- to 1 that the model is very sure that there is a SWR hapenning.
+ to 1 that the model is very sure that there is a SWR happening.
LFP_norm: LFP data used as an input to the model (np.array: n_samples x len(channels)).
It is undersampled, z-scored, and transformed to used the channels specified in channels.
@@ -82,7 +82,7 @@ def predict(LFP,sf,d_sf=1250,arch='CNN1D',model_number=1,channels=np.arange(8),n
#channels=opt['channels']
if new_model==None:
norm_LFP=process_LFP(LFP,sf,d_sf,channels)
- else: # Data is supossedly already normalized when using new model
+ else: # Data is supposedly already normalized when using new model
norm_LFP=LFP
prob=prediction_parser(norm_LFP,arch,model_number,new_model,n_channels,n_timesteps)
@@ -127,20 +127,20 @@ def get_intervals(y,threshold=None,LFP_norm=None,sf=1250,win_size=100,file_path=
LFP_norm: (n,n_channels), normalized input signal of the model
sf: (int), sampling frequency (Hz) of the LFP_norm/model output.
Change if used is different than 1250
- win_size: (int), length of the displayed ripples in miliseconds
+ win_size: (int), length of the displayed ripples in milliseconds
file_path: (str), absolute path of the folder where the .txt with the predictions
will be generated. Leave empty if you don't want to generate the file
- merge_win: (float), minimal length of the interval in miliseconds between predictions. If
+ merge_win: (float), minimal length of the interval in milliseconds between predictions. If
two detections are closer in time than this parameter, they will be merged together
Output:
-------
- predictions: (n_events,2), returns the time (seconds) of the begining and end of each event
+ predictions: (n_events,2), returns the time (seconds) of the beginning and end of each event
4 possible use cases, depending on which parameter combination is used when calling the function.
1.- (y): a histogram of the output is displayed, you drag a vertical bar to select your th
- 2.- (y,th): no GUI is displayed, the predictions are gererated automatically
+ 2.- (y,th): no GUI is displayed, the predictions are generated automatically
3.- (y,LFP_norm): some examples of detected events are displayed next to the histogram
4.- (y,LFP_norm,th): same case as 3, but the initial location of the bar is th
@@ -298,7 +298,7 @@ def plot_button_click(event):
button_plot.on_clicked(plot_button_click)
plt.show(block=True)
- # If no threhold is defined, choose your own with the GUI,without LFP_norm plotting
+ # If no threshold is defined, choose your own with the GUI,without LFP_norm plotting
elif threshold==None:
axcolor = (20/255,175/255,245/255) # light blue
hovercolor=(214/255,255/255,255/255)
@@ -345,7 +345,7 @@ def on_click(event):
plt.connect('motion_notify_event', on_click)
plt.show(block=True)
- # If threshold is defined, and no LFP_norm is passsed, the function simply generates the predictions
+ # If threshold is defined, and no LFP_norm is passed, the function simply generates the predictions
else:
predictions_index=get_predictions_index(y,threshold,merge_samples=merge_s)
if file_path:
@@ -434,7 +434,7 @@ def retrain_model(LFP_retrain,GT_retrain,LFP_val,GT_val,arch,parameters=None,sav
- For 'XGBOOST', not needed.
- For 'SVM', one parameter is needed:
- parameters['Undersampler proportion']: Any value between 0 and 1.
- This parameter eliminates samples where no ripple is present untill the
+ This parameter eliminates samples where no ripple is present until the
desired proportion is achieved:
Undersampler proportion= Positive samples/Negative samples
- For 'LSTM', 'CNN1D' and 'CNN2D', two things are needed:
@@ -444,7 +444,7 @@ def retrain_model(LFP_retrain,GT_retrain,LFP_val,GT_val,arch,parameters=None,sav
before updating the weights
save_path: (string). Path where the retrained model will be saved
d_sf: (int) Desired subsampling frequency (in Hz)
- merge_win: (float). Minimal length of the interval in miliseconds between predictions. If
+ merge_win: (float). Minimal length of the interval in milliseconds between predictions. If
two detections are closer in time than this parameter, they will be merged together