Instructions to use fcmeyer/drama-3-MLX-3bit-HQ with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use fcmeyer/drama-3-MLX-3bit-HQ with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download fcmeyer/drama-3-MLX-3bit-HQ --local-dir drama-3-MLX-3bit-HQ
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Download convert-bits-map.patch from fcmeyer/drama-3-MLX-3bit-HQ: direct link, hf CLI and curl.
- Browser
- Download file 4.92 kB
-
https://huggingface.co/fcmeyer/drama-3-MLX-3bit-HQ/resolve/main/convert-bits-map.patch
- Command line
-
hf download hf://fcmeyer/drama-3-MLX-3bit-HQ/convert-bits-map.patch
-
curl -L -o convert-bits-map.patch https://huggingface.co/fcmeyer/drama-3-MLX-3bit-HQ/resolve/main/convert-bits-map.patch
4.92 kB
| diff --git a/mlx_audio/tts/models/fish_drama3/convert.py b/mlx_audio/tts/models/fish_drama3/convert.py | |
| index 79fa5df..ca91be9 100644 | |
| --- a/mlx_audio/tts/models/fish_drama3/convert.py | |
| +++ b/mlx_audio/tts/models/fish_drama3/convert.py | |
| class ShardWriter: | |
| self.count = 0 | |
| self.quantization: dict[str, dict] = {} | |
| - def add(self, name: str, value: mx.array, bits: Optional[int] = None) -> None: | |
| + def add( | |
| + self, | |
| + name: str, | |
| + value: mx.array, | |
| + bits: Optional[int] = None, | |
| + group_size: int = GROUP_SIZE, | |
| + ) -> None: | |
| items = {name: value} | |
| if bits: | |
| path = name.removesuffix(".weight") | |
| - weight, scales, biases = mx.quantize(value, GROUP_SIZE, bits) | |
| + weight, scales, biases = mx.quantize(value, group_size, bits) | |
| items = {name: weight, f"{path}.scales": scales, f"{path}.biases": biases} | |
| - self.quantization[path] = {"group_size": GROUP_SIZE, "bits": bits} | |
| + self.quantization[path] = {"group_size": group_size, "bits": bits} | |
| mx.eval(list(items.values())) | |
| self.pending.update(items) | |
| self.pending_bytes += sum(v.nbytes for v in items.values()) | |
| def convert( | |
| dense_bits: int = 0, | |
| tower_bits: int = 0, | |
| codec: bool = True, | |
| + expert_group_size: int = GROUP_SIZE, | |
| + head_bits: Optional[int] = None, | |
| + expert_bits_map: Optional[dict[int, int]] = None, | |
| ) -> None: | |
| """Writes the MLX checkpoint into dst, which must not exist or be empty: | |
| the loader reads every safetensors file there, so a leftover shard from an | |
| def convert( | |
| num_experts = config["text_config"]["num_experts"] | |
| band = slice(config["semantic_start_token_id"], config["semantic_end_token_id"] + 1) | |
| eos = config["eos_token_id"] | |
| + if head_bits is None: | |
| + head_bits = tower_bits | |
| writer = ShardWriter(dst) | |
| experts: dict[int, dict[tuple, mx.array]] = defaultdict(dict) | |
| def convert( | |
| ] | |
| ) | |
| name = f"backbone.model.layers.{layer}.mlp.switch_mlp.{proj}_proj.weight" | |
| - writer.add(name, stacked, expert_bits) | |
| + bits = (expert_bits_map or {}).get(layer, expert_bits) | |
| + writer.add(name, stacked, bits, expert_group_size) | |
| index = json.loads((src / "model.safetensors.index.json").read_text()) | |
| for shard in sorted(set(index["weight_map"].values())): | |
| def convert( | |
| out = TOWER_PREFIXES[old] + name.removeprefix(old) | |
| if TOWER_NORMS.search(out): | |
| value = value.astype(mx.float32) + 1.0 | |
| - writer.add(out, value, tower_bits if TOWER.search(out) else None) | |
| + if match := TOWER.search(out): | |
| + bits = head_bits if match[1].startswith("codebook_heads") else tower_bits | |
| + else: | |
| + bits = None | |
| + writer.add(out, value, bits) | |
| else: | |
| raise ValueError(f"unexpected tensor {name}") | |
| del tensors | |
| def convert( | |
| # also has its own entry. | |
| config["quantization"] = { | |
| "group_size": GROUP_SIZE, | |
| - "bits": dense_bits or tower_bits or expert_bits, | |
| + "bits": dense_bits or tower_bits or head_bits or expert_bits, | |
| **writer.quantization, | |
| } | |
| config["model_type"] = "fish_drama3" | |
| def main() -> None: | |
| # their top-1 agreement with bf16 dropped from about 88% to 40%, so quantize | |
| # it to 8 at most. | |
| parser.add_argument("--tower-bits", type=int, default=0, help="0 keeps bf16") | |
| + parser.add_argument( | |
| + "--head-bits", | |
| + type=int, | |
| + default=None, | |
| + help="bits for the tower's codebook heads; defaults to --tower-bits, 0 keeps bf16", | |
| + ) | |
| + parser.add_argument( | |
| + "--expert-group-size", | |
| + type=int, | |
| + default=GROUP_SIZE, | |
| + choices=(32, 64, 128), | |
| + help="quantization group size for the experts", | |
| + ) | |
| + parser.add_argument( | |
| + "--expert-bits-map", | |
| + type=Path, | |
| + default=None, | |
| + help='JSON file mapping layer index to expert bits, e.g. {"0": 4}; ' | |
| + "layers not listed use --expert-bits", | |
| + ) | |
| args = parser.parse_args() | |
| - convert(args.src, args.dst, args.expert_bits, args.dense_bits, args.tower_bits) | |
| + convert( | |
| + args.src, | |
| + args.dst, | |
| + args.expert_bits, | |
| + args.dense_bits, | |
| + args.tower_bits, | |
| + expert_group_size=args.expert_group_size, | |
| + head_bits=args.head_bits, | |
| + expert_bits_map={ | |
| + int(k): v for k, v in json.loads(args.expert_bits_map.read_text()).items() | |
| + } | |
| + if args.expert_bits_map | |
| + else None, | |
| + ) | |
| if __name__ == "__main__": | |