Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a3aa5bf
Define v1-3-2
FKKimura Aug 6, 2026
622dae0
Modify timelimit in test_cli.py
FKKimura Aug 18, 2026
9b2af50
Merge branch 'lab/fix-tests' into 'export/v1-3-2'
FKKimura Aug 18, 2026
5e8dc73
Add GitLab-CI-Job to check confict-markers
FKKimura Aug 18, 2026
6c3a094
Merge branch 'lab/conflict-markers' into 'export/v1-3-2'
FKKimura Aug 18, 2026
2a4455b
fix: remove duplicate MoE unfuse call in load_quantized_model
FKKimura Aug 18, 2026
5c5c90d
Merge branch 'lab/fix-for-test-error' into 'export/v1-3-2'
FKKimura Aug 18, 2026
34facf3
[fix] Use canonical WikiText dataset ID
k-arima-3150 Aug 18, 2026
96609a1
Clarify CVE-2026-73325
aki916f Aug 20, 2026
7ca1cae
Merge branch 'lab/cve' into 'export/v1-3-2'
aki916f Aug 20, 2026
05ee341
Merge remote-tracking branch 'upstream/develop/v1-3-2' into fix/katar…
k-arima-3150 Aug 21, 2026
159f51b
Merge pull request #54 from computermind-corp/fix/wikitext-hf-dataset-id
FKKimura Aug 21, 2026
140410d
Modify gemlite for CPU inference
y-vectorfield Aug 24, 2026
4d72f0c
Merge branch 'modify_gemlite' into 'export/v1-3-2'
FKKimura Aug 24, 2026
5479db1
Fix data type arguments for Transformers (#55)
y-vectorfield Aug 24, 2026
b1ab82a
Add troubleshooting information for running OneComp with Llama.cpp on…
y-vectorfield Aug 24, 2026
5f6fd5e
Merge commit 'b1ab82a5db8896c16e315a0180053d1dbf307968' into export/v…
FKKimura Aug 24, 2026
4554976
Modify CHANGELOG.md
FKKimura Aug 24, 2026
b0f3f6d
Trivial-fix
FKKimura Aug 24, 2026
2633dea
Update .gitignore
FKKimura Aug 24, 2026
5ba420c
Update .gitignore
FKKimura Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ models
.cursor/rules/gitlab-integration.mdc
.cursor/rules/slurm-submit.mdc
.cursor/rules/run-tests-examples.mdc
.github/prompts
.github/copilot-instructions.md
.github/instructions
.hydra/
*.out
*.err
Expand All @@ -22,6 +25,7 @@ site/
debug_code/
.pytest_cache/
*.pt
**/.env
# Large test data (download separately if needed for regression tests)
tests/onecomp/quantizer/jointq/data/model_layers_0_self_attn_k_proj.pth
.uv-sync.lock
Expand Down
12 changes: 12 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ variables:
GIT_DEPTH: "1"
PYTEST_MARKERS: "not slow"

lint:conflict-markers:
stage: lint
tags:
- lint
variables:
# The MR diff base may be outside the default shallow clone.
GIT_DEPTH: "0"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- git diff --check "${CI_MERGE_REQUEST_DIFF_BASE_SHA}" "${CI_COMMIT_SHA}"

lint:format:
extends: .skip_docs_only
stage: lint
Expand Down
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Change log

## [v1.3.2] 2026-08-24

### Bug Fix

- Fix WikiText dataset loading in clean environments by using the canonical
`Salesforce/wikitext` dataset ID for perplexity evaluation and LoRA SFT examples.
- Fix warning regarding the data type arguments of Transformers.
- Fixed GemLite AssertionError during CPU inference execution for OneComp with Llama.cpp.
- Fixed `QuantizedModelLoader.load_quantized_model()` calling `unfuse_moe_experts()` twice on non-fused MoE checkpoints. An earlier unconditional unfuse (run right after building the empty model) was left in place when the checkpoint-aware unfuse (added for gpt-oss fused-MoE support) was introduced. The redundant unconditional call was removed, and the checkpoint-aware unfuse now runs before `_remap_state_dict_keys()` so key remapping still aligns against the unfused per-expert module paths. This also prevents wrongly unfusing gpt-oss fused-MoE checkpoints, whose fused 3D expert tensors must be loaded as-is (`quantized_model_loader.py`).

### Documentation

- Add troubleshooting information for running OneComp with Llama.cpp on macOS.

## [v1.3.1] 2026-08-06

### Bug Fix
Expand Down Expand Up @@ -94,11 +108,11 @@

### Security

- **Unsafe deserialization hardening (CWE-502)**: `QuantizedModelLoader.load_quantized_model_pt()` (alias `onecomp.load_quantized_model_pt()`) previously called `torch.load(model.pt, weights_only=False)` unconditionally, allowing arbitrary code execution when loading a malicious `.pt` checkpoint. It now refuses to load unless the caller explicitly opts in via `allow_unsafe_deserialization=True`, and emits a strong warning when it does load. For untrusted models, use the safetensors-based `load_quantized_model()`, which does not execute code.
- **Unsafe deserialization hardening (CVE-2026-73325, CWE-502)**: `QuantizedModelLoader.load_quantized_model_pt()` (alias `onecomp.load_quantized_model_pt()`) previously called `torch.load(model.pt, weights_only=False)` unconditionally, allowing arbitrary code execution when loading a malicious `.pt` checkpoint. It now refuses to load unless the caller explicitly opts in via `allow_unsafe_deserialization=True`, and emits a strong warning when it does load. For untrusted models, use the safetensors-based `load_quantized_model()`, which does not execute code.
- **Breaking change**: existing callers of `load_quantized_model_pt()` must pass `allow_unsafe_deserialization=True` for trusted `.pt` files.
- **`Quantizer.load_results()` / `ResultLoader`**: same hardening applied. Loading with `weights_only=False` now requires `allow_unsafe_deserialization=True` (added as a `ResultLoader` field), and logs a warning. The safe `weights_only=True` path is unchanged.
- Updated docstrings, docs, and the LoRA SFT example to document the risk and the required opt-in.
- **Credit**: this unsafe deserialization issue (CWE-502) was responsibly disclosed by **Nir Yehoshua, Cipher Security Labs**. Thank you for the report.
- **Credit**: this unsafe deserialization issue (CVE-2026-73325, CWE-502) was responsibly disclosed by **Nir Yehoshua, Cipher Security Labs**. Thank you for the report.

## [v1.2.0] 2026-06-08

Expand Down
16 changes: 14 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Security updates are provided for the latest release line of Fujitsu One Compres

| Version | Supported |
| ------- | ------------------ |
| 1.2.2 | :white_check_mark: |
| 1.2.2 >= | :white_check_mark: |
| < 1.2.2 | :x: |

We recommend always upgrading to the latest release before reporting an issue.
Expand Down Expand Up @@ -38,8 +38,20 @@ Please make a good-faith effort to avoid privacy violations, data destruction, a

Thank you for helping keep OneComp and its users safe.

## Resolved Security Issues

### CVE-2026-73325 — Unsafe Deserialization

An unsafe deserialization vulnerability (CWE-502) was identified in
`QuantizedModelLoader.load_quantized_model_pt()`.

- **Affected versions:** v1.2.0 and earlier
- **Fixed version:** v1.2.1
- **CVE:** CVE-2026-73325
- **Resolution:** The issue was addressed in v1.2.1. Users should upgrade to the latest supported release.

## Security Acknowledgments

We thank the following researchers for responsibly disclosing security issues in OneComp:

- **Nir Yehoshua, Cipher Security Labs** — unsafe deserialization in `QuantizedModelLoader.load_quantized_model_pt()` (CWE-502), fixed in v1.2.1.
- **Nir Yehoshua, Cipher Security Labs** — unsafe deserialization in `QuantizedModelLoader.load_quantized_model_pt()` (CVE-2026-73325, CWE-502), affecting OneComp versions through v1.2.0 and fixed in v1.2.1.
53 changes: 53 additions & 0 deletions docs/user-guide/cpu-inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,59 @@ for inference. The direct export path additionally uses llama.cpp's pure-Python
`convert_hf_to_gguf.py` to build the model metadata/tokenizer; it is fetched
automatically (a shallow `git clone`) or taken from `$LLAMA_CPP_DIR` if set.


### macOS

#### Symptom

If you have installed gcc or clang on macOS using a tool like Homebrew, the OpenMP dynamic library with them can conflict with the OpenMP dynamic library used by OneComp's PyTorch backend.

- OneComp's PyTorch backend is often configured to use an OpenMP library located within the .venv directory.
- Depending on your environment, Llama.cpp is configured to use an OpenMP library associated with gcc or clang.

If the following problems is occurring , this conflict may be occurring.

- Your Python interpreter shows the following warning message.

```python
.../multiprocessing/resource_tracker.py:279: UserWarning: resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown
warnings.warn('resource_tracker: There appear to be %d '
```

- The following message is shown, when you import PyTorch and Llama.cpp in your script.

```python
OMP: Error #15: Initializing libomp.dylib, but found libomp.dylib already initialized.
OMP: Hint This means that multiple copies of the OpenMP runtime have been linked into the program.
```

#### Solution

##### 1. Search for OpenMP associated with PyTorch.

Search for OpenMP library associated with PyTorch backend (using find command).

```bash
$ find $PWD/.venv -type f \( -name 'libomp.dylib' -o -name 'libgomp*.dylib' \) -print | grep torch
/to/path/.venv/lib/python3.<PYVERSION>/site-packages/torch/lib/libomp.dylib
```

##### 2. Create an .env

Create a .env file and add the OpenMP path as an environment variable, as shown below.

```bash
DYLD_LIBRARY_PATH="/to/path/.venv/lib/python3.<PYVERSION>/site-packages/torch/lib"
```

##### 3. Run uv

Pass the following `--env-file` options when running uv run.

```bash
uv run --env-file /path/to/.env ... python your_script.py
```

## One entry point: `export_to_gguf`

You do not need to know which path a checkpoint requires. `export_to_gguf`
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ model_config = ModelConfig(
gptq = GPTQ(wbits=4, groupsize=128)

post_process = PostProcessLoraSFT(
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config_name="wikitext-2-raw-v1",
train_split="train",
text_column="text",
Expand Down
8 changes: 4 additions & 4 deletions docs/user-guide/post-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ model_config = ModelConfig(
gptq = GPTQ(wbits=4, groupsize=128)

post_process = PostProcessLoraSFT(
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config_name="wikitext-2-raw-v1",
train_split="train",
text_column="text",
Expand Down Expand Up @@ -512,7 +512,7 @@ model, tokenizer = load_quantized_model_pt(

```python
PostProcessLoraSFT(
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config_name="wikitext-2-raw-v1",
train_split="train",
text_column="text",
Expand Down Expand Up @@ -560,7 +560,7 @@ Teacher distillation aligns the quantized model's output distribution with a ful

```python
post_process = PostProcessLoraSFT(
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config_name="wikitext-2-raw-v1",
train_split="train",
text_column="text",
Expand Down Expand Up @@ -591,7 +591,7 @@ Intermediate block alignment adds a loss term that aligns hidden states at selec

```python
post_process = PostProcessLoraSFT(
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config_name="wikitext-2-raw-v1",
train_split="train",
text_column="text",
Expand Down
2 changes: 1 addition & 1 deletion example/post_process/example_lora_sft.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def generate_text(model, tokenizer, prompt, device, max_new_tokens=64):
gptq = GPTQ(wbits=4, groupsize=128)

post_process = PostProcessLoraSFT(
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config_name="wikitext-2-raw-v1",
train_split="train",
text_column="text",
Expand Down
2 changes: 1 addition & 1 deletion notebook/01_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"DEVICE = \"cuda:0\" if torch.cuda.is_available() else \"cpu\"\n",
"\n",
"tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)\n",
"model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype=torch.float16).to(DEVICE)\n",
"model = AutoModelForCausalLM.from_pretrained(MODEL_ID, dtype=torch.float16).to(DEVICE)\n",
"model.eval()\n",
"\n",
"n_params = sum(p.numel() for p in model.parameters())\n",
Expand Down
2 changes: 1 addition & 1 deletion onecomp/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

"""

__version__ = "1.3.1"
__version__ = "1.3.2"
2 changes: 1 addition & 1 deletion onecomp/cpu/export/dequantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def dequantize_to_hf(
pass

logger.info("Building empty dense model from config (%s)", config.model_type)
model = AutoModelForCausalLM.from_config(config, torch_dtype=torch_dtype)
model = AutoModelForCausalLM.from_config(config, dtype=torch_dtype)

state: Dict[str, torch.Tensor] = {}
for shard in sorted(glob(os.path.join(save_directory, "*.safetensors"))):
Expand Down
2 changes: 1 addition & 1 deletion onecomp/pre_process/prepare_rotated_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ def prepare_rotated_model(
t0 = time.time()
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype="auto",
dtype="auto",
device_map="cpu",
low_cpu_mem_usage=True,
)
Expand Down
4 changes: 2 additions & 2 deletions onecomp/pre_process/train_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,15 +321,15 @@ def _convert_model_structure(config, model_type, model_path, use_sdpa=False):
if is_llama:
quant_model = QLlamaFC.from_pretrained(
model_path,
torch_dtype="auto",
dtype="auto",
device_map="cpu",
low_cpu_mem_usage=True,
config=config,
)
elif is_qwen3:
quant_model = QQwen3FC.from_pretrained(
model_path,
torch_dtype="auto",
dtype="auto",
device_map="cpu",
low_cpu_mem_usage=True,
config=config,
Expand Down
29 changes: 14 additions & 15 deletions onecomp/quantized_model_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,14 @@ def load_quantized_model(
torch_dtype = torch.bfloat16
model = cls._build_empty_model_from_config(config_dict, torch_dtype)

# Mirror the unfuse step performed before quantization/save (see
# Runner.save_quantized_model) so per-expert module names such as
# "model.layers.0.mlp.experts.0.down_proj" resolve against the
# freshly-built model instead of its fused 3D expert parameters.
if unfuse_moe_experts(model, logger):
logger.info("Unfused MoE expert tensors for quantized model load")

# Load state_dict from safetensors
state_dict = cls._load_state_dict_from_dir(save_directory)

# Align checkpoint key prefixes with the empty model built from config.
# Gemma3 VLMs are a common case: weights saved from from_pretrained
# use model.language_model.model.layers. (language_model is a
# ForCausalLM wrapper) while from_config exposes
# model.language_model.layers.* directly.
state_dict = cls._remap_state_dict_keys(state_dict, model)
# Decide, from the checkpoint alone, whether the empty model must be
# unfused into per-expert nn.Linear modules. This must happen before
# _remap_state_dict_keys so remapping aligns checkpoint keys against the
# unfused module paths; fused-MoE checkpoints (e.g. gpt-oss) keep the
# fused 3D parameters and skip unfuse.
from .utils.unfuse_moe import (
_checkpoint_uses_fused_moe,
_expand_deduped_moe_keys,
Expand All @@ -131,6 +123,13 @@ def load_quantized_model(
elif unfuse_moe_experts(model, logger):
logger.info("Unfused MoE expert tensors for quantized model load")

# Align checkpoint key prefixes with the empty model built from config.
# Gemma3 VLMs are a common case: weights saved from from_pretrained
# use model.language_model.model.layers. (language_model is a
# ForCausalLM wrapper) while from_config exposes
# model.language_model.layers.* directly.
state_dict = cls._remap_state_dict_keys(state_dict, model)

# Replace quantized layers with empty modules and align quantized
# tensor keys with the actual module names in the model built from
# config. This is required when the saved checkpoint and the
Expand Down Expand Up @@ -568,11 +567,11 @@ def _build_empty_model_from_config(
config_cls = CONFIG_MAPPING[model_type]
model_config = config_cls.from_dict(clean_config)
try:
return AutoModelForCausalLM.from_config(model_config, torch_dtype=dtype)
return AutoModelForCausalLM.from_config(model_config, dtype=dtype)
except (ValueError, KeyError):
from transformers import AutoModelForImageTextToText

return AutoModelForImageTextToText.from_config(model_config, torch_dtype=dtype)
return AutoModelForImageTextToText.from_config(model_config, dtype=dtype)

@staticmethod
def _set_module_by_name(
Expand Down
14 changes: 8 additions & 6 deletions onecomp/quantizer/gemlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import torch.nn.functional as F

# Optional GemLite/HQQ imports
try:
from gemlite.core import DType, GemLiteLinearTriton
from hqq.core.quantize import BaseQuantizeConfig, HQQLinear
HAS_GEMLITE = False
if torch.cuda.is_available():
try:
from gemlite.core import DType, GemLiteLinearTriton
from hqq.core.quantize import BaseQuantizeConfig, HQQLinear

HAS_GEMLITE = True
except (ImportError, AttributeError):
HAS_GEMLITE = False
HAS_GEMLITE = True
except (ImportError, AttributeError, AssertionError):
pass


# Constants
Expand Down
4 changes: 2 additions & 2 deletions onecomp/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1260,7 +1260,7 @@ def calculate_perplexity(
original_model=False,
dequantized_model=False,
quantized_model=True,
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config="wikitext-2-raw-v1",
split="test",
max_samples=None,
Expand Down Expand Up @@ -1342,7 +1342,7 @@ def benchmark_perplexity(
original_model=True,
dequantized_model=False,
quantized_model=True,
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config="wikitext-2-raw-v1",
split="test",
max_samples=None,
Expand Down
4 changes: 2 additions & 2 deletions onecomp/utils/perplexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def calculate_perplexity(
model=None,
tokenizer=None,
model_config=None,
dataset_name="wikitext",
dataset_name="Salesforce/wikitext",
dataset_config="wikitext-2-raw-v1",
split="test",
max_samples=None,
Expand All @@ -53,7 +53,7 @@ def calculate_perplexity(
Based on https://huggingface.co/docs/transformers/perplexity

Args:
dataset_name (str): Dataset name (e.g. "wikitext", "allenai/c4").
dataset_name (str): Dataset name (e.g. "Salesforce/wikitext", "allenai/c4").
dataset_config (str): Dataset configuration.
- For WikiText: "wikitext-2-raw-v1"
- For C4: "en/c4-train.00001-of-01024.json.gz" (treated as data_files)
Expand Down
2 changes: 1 addition & 1 deletion onecomp/utils/vram_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def estimate_wbits_from_vram(

config = AutoConfig.from_pretrained(model_id)
with torch.device("meta"):
model = AutoModelForCausalLM.from_config(config, torch_dtype=torch.float16)
model = AutoModelForCausalLM.from_config(config, dtype=torch.float16)

return estimate_target_bitwidth(
model,
Expand Down
Loading