-
Notifications
You must be signed in to change notification settings - Fork 105
Added multichannel PReLU #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
dd16a65
Added multichannel PReLU
05becca
Fixed transposed inputs, behaviour when missing channels
285763a
Addressing comments on runtime checks and removing apply(float *) imp…
a6b0592
Formatting
5324a37
Disabling failing test (it's handled by an assert now)
70fe581
Merge branch 'main' into prelu
sdatkinson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -191,6 +191,59 @@ class ActivationLeakyReLU : public Activation | |
| float negative_slope = 0.01; | ||
| }; | ||
|
|
||
| class ActivationPReLU : public Activation | ||
| { | ||
| public: | ||
| ActivationPReLU() = default; | ||
| ActivationPReLU(float ns) { | ||
| negative_slopes.clear(); | ||
| negative_slopes.push_back(ns); | ||
| } | ||
| ActivationPReLU(std::vector<float> ns) { | ||
| negative_slopes = ns; | ||
| } | ||
|
|
||
| void apply(Eigen::MatrixXf& matrix) override | ||
| { | ||
| // Matrix is organized as (channels, time_steps) | ||
| int n_channels = negative_slopes.size(); | ||
| int actual_channels = matrix.rows(); | ||
|
|
||
| if (actual_channels > n_channels) | ||
| { | ||
| throw std::runtime_error("Number of channels in PReLU activation different from input matrix"); | ||
| } | ||
|
|
||
| // Apply each negative slope to its corresponding channel | ||
| for (int channel = 0; channel < std::min(n_channels, actual_channels); channel++) | ||
| { | ||
| // Apply the negative slope to all time steps in this channel | ||
| for (int time_step = 0; time_step < matrix.rows(); time_step++) | ||
| { | ||
| matrix(channel, time_step) = leaky_relu(matrix(channel, time_step), negative_slopes[channel]); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Feels inefficient since there's no vectorized ops being used, but we'll see. |
||
| } | ||
| } | ||
| } | ||
|
|
||
| void apply(float* data, long size) override | ||
| { | ||
| // Fallback that operates like leaky_relu, should not be used as it's a waste of a vector for one element | ||
sdatkinson marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (!negative_slopes.empty()) | ||
| { | ||
| float slope = negative_slopes[0]; // Use first slope as fallback | ||
| for (long pos = 0; pos < size; pos++) | ||
| { | ||
| data[pos] = leaky_relu(data[pos], slope); | ||
| } | ||
| } else { | ||
| throw std::runtime_error("negative_slopes not initialized"); | ||
| } | ||
| } | ||
| private: | ||
| std::vector<float> negative_slopes; | ||
| }; | ||
|
|
||
|
|
||
| class ActivationSigmoid : public Activation | ||
| { | ||
| public: | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| #include <cassert> | ||
| #include <string> | ||
| #include <vector> | ||
| #include <cmath> | ||
|
|
||
| #include "NAM/activations.h" | ||
|
|
||
|
|
@@ -119,4 +120,80 @@ class TestLeakyReLU | |
| } | ||
| }; | ||
| }; | ||
| class TestPReLU | ||
| { | ||
| public: | ||
| static void test_core_function() | ||
| { | ||
| // Test the basic leaky_relu function that PReLU uses | ||
| auto TestCase = [](float input, float slope, float expectedOutput) { | ||
| float actualOutput = nam::activations::leaky_relu(input, slope); | ||
| assert(actualOutput == expectedOutput); | ||
| }; | ||
|
|
||
| // A few snapshot tests | ||
| TestCase(0.0f, 0.01f, 0.0f); | ||
| TestCase(1.0f, 0.01f, 1.0f); | ||
| TestCase(-1.0f, 0.01f, -0.01f); | ||
| TestCase(-1.0f, 0.05f, -0.05f); // Different slope | ||
| } | ||
|
|
||
| static void test_per_channel_behavior() | ||
| { | ||
| // Test that different slopes are applied to different channels | ||
| Eigen::MatrixXf data(2, 3); // 2 channels, 3 time steps | ||
|
|
||
| // Initialize with some test data | ||
| data << -1.0f, 0.5f, 1.0f, | ||
sdatkinson marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| -2.0f, -0.5f, 0.0f; | ||
|
|
||
| // Create PReLU with different slopes for each channel | ||
| std::vector<float> slopes = {0.01f, 0.05f}; // slope 0.01 for channel 0, 0.05 for channel 1 | ||
| nam::activations::ActivationPReLU prelu(slopes); | ||
|
|
||
| // Apply the activation | ||
| prelu.apply(data); | ||
|
|
||
| // Verify the results | ||
| // Channel 0 (slope = 0.01): | ||
| assert(fabs(data(0, 0) - (-0.01f)) < 1e-6); // -1.0 * 0.01 = -0.01 | ||
| assert(fabs(data(0, 1) - 0.5f) < 1e-6); // 0.5 (positive, unchanged) | ||
| assert(fabs(data(0, 2) - 1.0f) < 1e-6); // 1.0 (positive, unchanged) | ||
|
|
||
| // Channel 1 (slope = 0.05): | ||
| assert(fabs(data(1, 0) - (-0.10f)) < 1e-6); // -2.0 * 0.05 = -0.10 | ||
| assert(fabs(data(1, 1) - (-0.025f)) < 1e-6); // -0.5 * 0.05 = -0.025 | ||
| assert(fabs(data(1, 2) - 0.0f) < 1e-6); // 0.0 (unchanged) | ||
|
||
| } | ||
|
|
||
| static void test_wrong_number_of_channels() | ||
| { | ||
| // Test that we fail when we have more channels than slopes | ||
| Eigen::MatrixXf data(3, 2); // 3 channels, 2 time steps | ||
|
|
||
| // Initialize with test data | ||
| data << -1.0f, -1.0f, | ||
| -1.0f, 1.0f, | ||
| 1.0f, 1.0f; | ||
|
|
||
| // Create PReLU with only 2 slopes for 3 channels | ||
| std::vector<float> slopes = {0.01f, 0.05f}; | ||
| nam::activations::ActivationPReLU prelu(slopes); | ||
|
|
||
| // Apply the activation | ||
| bool caught = false; | ||
| try | ||
| { | ||
| prelu.apply(data); | ||
| } catch (const std::runtime_error& e) { | ||
| caught = true; | ||
| } catch (...) { | ||
|
|
||
| } | ||
|
|
||
| assert(caught == true); | ||
sdatkinson marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| }; | ||
|
|
||
| }; // namespace test_activations | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.