-
Notifications
You must be signed in to change notification settings - Fork 785
feat(moe): add orthogonal initialization for gate parameters #664
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
base: main
Are you sure you want to change the base?
Changes from all commits
d35df8c
a65b4f7
75aac6c
702221b
bcc8b88
378bb89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| # SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| import logging | ||
| from typing import List, Optional | ||
| from typing import List, Optional, Literal # Ensure Literal is imported | ||
|
|
||
| from pydantic import BaseModel | ||
|
|
||
|
|
@@ -29,13 +29,24 @@ class MoEMergeConfig(BaseModel): | |
|
|
||
| base_model: ModelReference | ||
| experts: List[Expert] | ||
| gate_mode: str = ( | ||
| "hidden" # possible values: "hidden", "cheap_embed", "random", "uniform_random" | ||
| ) | ||
|
|
||
| # Updated to use Literal for strict validation and added "orthogonal" | ||
| gate_mode: Literal[ | ||
| "hidden", | ||
| "cheap_embed", | ||
| "random", | ||
| "uniform_random", | ||
| "orthogonal", | ||
| "hidden_avg", | ||
| "hidden_last", | ||
| ] = "hidden" | ||
|
|
||
| # "hidden" uses hidden state vectors for the given prompts for each layer | ||
| # "cheap_embed" uses the average of token embeddings for the prompts, same for each layer | ||
| # "random" is random | ||
| # "random" is standard normal distribution (torch.randn) | ||
| # "uniform_random" matches default initialization for torch.nn.Linear | ||
| # "orthogonal" ensures gate vectors are orthogonal for better expert specialization | ||
|
|
||
|
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. Missing validation bypass for orthogonal mode promptsMedium Severity The |
||
| dtype: Optional[str] = None | ||
| experts_per_token: int = 2 | ||
| shared_experts: Optional[List[Expert]] = None | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,6 +88,30 @@ def get_gate_params( | |
| return torch.randn( | ||
| (model_cfg.num_hidden_layers, len(experts), model_cfg.hidden_size) | ||
| ) | ||
| # NEW test Orthogonal Initialization | ||
| elif mode == "orthogonal": | ||
| num_layers = model_cfg.num_hidden_layers | ||
| num_experts = len(experts) | ||
| hidden_size = model_cfg.hidden_size | ||
|
|
||
| # 1. Determine the target dtype | ||
| # We check if a specific dtype was requested, otherwise use model default | ||
| target_dtype = getattr(model_cfg, "torch_dtype", torch.float16) | ||
|
|
||
| # 2. Initialize in float32 for mathematical stability | ||
| # We create a list of tensors to match how "hidden" mode returns data | ||
| gate_vecs = [] | ||
| for _ in range(num_layers): | ||
| layer_gate = torch.empty((num_experts, hidden_size), dtype=torch.float32) | ||
| torch.nn.init.orthogonal_(layer_gate) | ||
| # 3. Cast to the target dtype and move to the requested device | ||
| gate_vecs.append( | ||
| layer_gate.to( | ||
| dtype=target_dtype, device=device if device != "auto" else "cpu" | ||
| ) | ||
| ) | ||
|
|
||
| return gate_vecs | ||
|
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. Orthogonal mode returns list instead of tensorHigh Severity The new |
||
| elif mode == "uniform_random": | ||
| in_features = model_cfg.hidden_size | ||
| scale = math.sqrt(1.0 / in_features) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -472,7 +472,7 @@ def build_embedding_matrix( | |
| new_tokens.append(token) | ||
| stats.to_approximate += 1 | ||
|
|
||
| donor_tokenizer = transformers.AutoTokenizer.from_pretrained( | ||
| transformers.AutoTokenizer.from_pretrained( | ||
|
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. Wasteful tokenizer loading with discarded resultLow Severity The |
||
| options.donor.model.path, | ||
| revision=options.donor.model.revision, | ||
| trust_remote_code=True, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -93,4 +93,9 @@ testpaths = ["tests"] | |
|
|
||
| [dependency-groups] | ||
| test = ["pytest~=8.4.0"] | ||
| dev = ["black~=25.1.0", "isort~=6.0.1", "pre-commit~=4.2.0"] | ||
| dev = [ | ||
| "black~=25.1.0", | ||
| "isort~=6.0.1", | ||
| "pre-commit~=4.2.0", | ||
|
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. Inconsistent indentation in pyproject.toml dev dependenciesLow Severity Lines 98-99 in the dev dependency list have inconsistent indentation (only 1 space) compared to the surrounding lines which use 4 spaces. This inconsistency may cause TOML parsing issues or at minimum creates confusing formatting. |
||
| "ruff>=0.15.0", | ||
| ] | ||


Uh oh!
There was an error while loading. Please reload this page.