Skip to content

Slimmable interface and SlimmableContainer#242

Open
jfsantos wants to merge 3 commits intosdatkinson:mainfrom
jfsantos:feature/slimmable-interface
Open

Slimmable interface and SlimmableContainer#242
jfsantos wants to merge 3 commits intosdatkinson:mainfrom
jfsantos:feature/slimmable-interface

Conversation

@jfsantos
Copy link
Contributor

@jfsantos jfsantos commented Mar 9, 2026

  1. Slimmable interface on DSP base class (NAM/dsp.h)

Added virtual void SetSlimmableSize(const double val) to DSP. Default is a no-op. val ranges from 0.0 (minimum size) to 1.0 (maximum size).
Subclasses override this to reduce computational cost in a model-specific way.

  1. ContainerModel (NAM/container.h, NAM/container.cpp)

A new ContainerModel class that uses the slimmable interface to switch between multiple complete DSP models at different quality tiers.

  • Submodel selection: SetSlimmableSize(val) picks the first submodel whose max_value >= val, then always calls ResetAndPrewarm() on it so it's
    immediately ready for process().
  • Delegation: process() forwards to the active submodel. Reset() resets all submodels. prewarm() prewarms all submodels.
  • Validation (constructor): submodels must be non-empty, sorted by ascending max_value, the last must cover 1.0, and all must agree on sample rate.
  • Registration: auto-registered as "SlimmableContainer" architecture via ConfigParserHelper.

The NAM file format nests full model specs inside config.submodels[].model, with an empty top-level weights array.

  1. Example file (example_models/slimmable_container.nam)

A 3-tier container using lstm.nam (small, max_value=0.33), wavenet.nam (medium, max_value=0.66), and nano_relu.nam (large, max_value=1.0).

  1. Tests (tools/test/test_container.cpp, wired into tools/run_tests.cpp)

10 tests covering:

  • Loading from JSON and from .nam file
  • Audio processing produces finite output
  • SetSlimmableSize selects different submodels (verified by differing output)
  • Boundary value selection (exact max_value thresholds)
  • Default active model is the largest (max size)
  • Error cases: empty submodels, last max_value < 1.0, unsorted submodels, sample rate mismatch

Developed with support and sponsorship from TONE3000

@jfsantos jfsantos force-pushed the feature/slimmable-interface branch from 3650ca5 to 91efeb0 Compare March 9, 2026 18:10
@jfsantos
Copy link
Contributor Author

jfsantos commented Mar 9, 2026

Integration tests failed for some reason but that seems to be unrelated to anything I implemented here. Investigating.

Copy link
Owner

@sdatkinson sdatkinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few things plz, see comments

/// \param outputLevel Output level in dBu
void SetOutputLevel(const double outputLevel);

/// \brief Set the slimmable size of the model
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make a Slimmable interface class to mix in for slimmable models instead of adding it to this class?

nlohmann::json large_model = load_nam_json(large_path);

nlohmann::json container;
container["version"] = "0.6.1";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the code currently on 0.6.1?

Looks like 0.6.0

Can you bump here and there to 0.7.0? Since code that knows about 0.6.0 wouldn't know what to do with this at all.

NAM_SAMPLE* out_ptr = output.data();

// Test exact boundary values
dsp->SetSlimmableSize(0.33); // Should select first submodel (max_value=0.33)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the high value is inclusive, right? Can you put that in the docstring for the class.

Frankly, I'd prefer Inclusive lower / exclusive upper...can we do that?

For the biggest model, one could make it null to be like "no limit" and we can assert that the biggest model is like that in a .nam file.

And then assert that only values between 0 and 1 (inclusive/inclusive) are given to the slimming method (can be validated in the base class).

Copy link
Owner

@sdatkinson sdatkinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few other asks since we were working in parallel :)

#include <string>
#include <vector>

#include "NAM/container.h"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same while you were working & I was commenting, use the abstract class 🙏🏻

// Test that SetSlimmableSize is called before processing (simulates --slim flow)
void test_slim_applied_before_processing()
{
std::cout << " test_slim_applied_before_processing" << std::endl;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have the tests be quiet on the happy path

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants