Skip to content

[Bug]: PyTorch Gemma-3-1b-it conversion fails with __ior__ op not implemented (Core ML Tools 8.3.0) #2560

Description

@kamisori-daijin

[Bug]: PyTorch Gemma-3-1b-it conversion fails with __ior__ op not implemented (Core ML Tools 8.3.0)

Describe the bug
Attempting to convert the google/gemma-3-1b-it PyTorch model to Core ML (.mlpackage) using coremltools==8.3.0 results in a RuntimeError: PyTorch convert function for op '__ior__' not implemented.

To Reproduce
Steps to reproduce the behavior:

  1. Download the google/gemma-3-1b-it model from Hugging Face:
    git clone [https://huggingface.co/google/gemma-3-1b-it](https://huggingface.co/google/gemma-3-1b-it) /path/to/gemma-3-1b-it
  2. Ensure you have coremltools, torch, transformers, and numpy installed.
  3. Adjust the downloaded_hf_model_dir in the Python script below to your local model path.
  4. Run the following Python script:
import coremltools as ct
import numpy as np
import torch
import torch.nn as nn
from transformers import AutoTokenizer, AutoModelForCausalLM
import os

# Adjust this path to your downloaded Gemma-3-1b-it model directory
downloaded_hf_model_dir = "/path/your/directory/gemma-3-1b-it" # REPLACE WITH YOUR ACTUAL PATH

print(f"CoreMLTools Version: {ct.__version__}")
print(f"PyTorch Version: {torch.__version__}")
print(f"Transformers Version: {AutoTokenizer.__version__}")
print(f"Numpy Version: {np.__version__}")

try:
    # 1. Hugging Face model loading
    print(f"Loading Hugging Face model from '{downloaded_hf_model_dir}' into memory...")
    model = AutoModelForCausalLM.from_pretrained(downloaded_hf_model_dir, torch_dtype=torch.float16)
    model.eval() # Set model to evaluation mode

    # Disable KV cache for tracing (workaround for potential DynamicCache errors)
    model.config.use_cache = False

    print("Model loaded and configured.")

    # 2. Create a wrapper model for Core ML conversion
    # This addresses the 'dict at output' error during tracing and ensures tuple output
    class GemmaCoreMLWrapper(nn.Module):
        def __init__(self, model):
            super().__init__()
            self.model = model
            # KV cache already handled by self.model.config.use_cache = False above,
            # but reiterating for clarity within wrapper
            self.model.config.use_cache = False

        def forward(self, input_ids, attention_mask):
            # Call the PyTorch model with explicit arguments and force tuple output
            outputs = self.model(
                input_ids=input_ids,
                attention_mask=attention_mask,
                use_cache=False,            # Ensure KV cache is disabled
                return_dict=False,          # Force tuple output (crucial for tracing)
                output_attentions=False,    # Disable attention output for simplicity
                output_hidden_states=False  # Disable hidden states output for simplicity
            )
            # Return only the logits (first element of the tuple output)
            logits = outputs[0]
            return logits

    wrapped_model = GemmaCoreMLWrapper(model) # Use the loaded 'model' here
    print("Wrapper model prepared.")

    # 3. Prepare dummy inputs for TorchScript tracing
    max_seq_length = 1024 # Sequence length for dynamic range upper bound
    tokenizer = AutoTokenizer.from_pretrained(downloaded_hf_model_dir) # Load tokenizer for vocab_size

    # Dummy inputs matching the expected type and a small sequence length for tracing
    dummy_input_ids = torch.randint(0, tokenizer.vocab_size, (1, 10), dtype=torch.long)
    dummy_attention_mask = torch.ones(1, 10, dtype=torch.long)

    # 4. Trace the wrapper model to TorchScript
    print("Tracing wrapper model to TorchScript...")
    traced_model = torch.jit.trace(wrapped_model, (dummy_input_ids, dummy_attention_mask))
    print("TorchScript tracing complete.")

    # 5. Convert TorchScript model to Core ML
    print("Converting TorchScript model to Core ML...")
    coreml_model = ct.convert(
        traced_model, # Pass the TorchScript object
        inputs=[
            # Use np.int32 based on previous warning about int64 downcasting
            ct.TensorType(name="input_ids", shape=(1, ct.RangeDim(upper_bound=max_seq_length)), dtype=np.int32),
            ct.TensorType(name="attention_mask", shape=(1, ct.RangeDim(upper_bound=max_seq_length)), dtype=np.int32)
        ],
        source="pytorch",
        convert_to="mlprogram",
        # Specify a modern iOS deployment target (Gemma is a recent model)
        minimum_deployment_target=ct.target.iOS16 # Or iOS17/iOS18 as appropriate
    )

    # Save the Core ML model
    coreml_model.save("gemma3-1b-it-coreml.mlpackage")
    print("CoreML model saved successfully to gemma3-1b-it-coreml.mlpackage.")

except Exception as e:
    print(f"Conversion to CoreML failed: {e}")

Expected behavior

The google/gemma-3-1b-it PyTorch model should successfully convert to a Core ML .mlpackage file without errors, allowing for on-device inference using Core ML.
Actual behavior

The conversion process proceeds until the "Converting PyTorch Frontend ==> MIL Ops" phase, where it fails with a RuntimeError: PyTorch convert function for op '__ior__' not implemented.
Complete Error Output (cleaned for personal info and translated)

[Paste the complete output from running your script here. This is the cleaned version.]

Loading Hugging Face model from '/path/to/your/gemma-3-1b-it' into memory...
Model loaded and configured.
Wrapper model prepared.
Tracing wrapper model to TorchScript...
`loss_type=None` was set in the config but it is unrecognised. Using the default loss: `ForCausalLMLoss`.
/path/to/your/venv3/lib/python3.11/site-packages/transformers/masking_utils.py:187: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!
  if (padding_length := kv_length + kv_offset - attention_mask.shape[-1]) > 0:
/path/to/your/venv3/lib/python3.11/site-packages/transformers/masking_utils.py:215: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!
  if padding_mask is not None and padding_mask.shape[-1] > kv_length:
/path/to/your/venv3/lib/python3.11/site-packages/transformers/integrations/sdpa_attention.py:59: TracerWarning: Converting a tensor to a Python boolean might cause the trace to be incorrect. We can't record the data flow of Python values, so this value will be treated as a constant in the future. This means that the trace might not generalize to other inputs!
  is_causal = query.shape[2] > 1 and attention_mask is None and getattr(module, "is_causal", True)
TorchScript tracing complete.
Model is not in eval mode. Consider calling '.eval()' on your model prior to conversion
int64 dtype input input_ids down casted to int32.
int64 dtype input attention_mask down casted to int32.
Converting PyTorch Frontend ==> MIL Ops:   0%|          | 0/4901 [00:00<?
Core ML embedding (gather) layer does not support any inputs besides the weights and indices. Those given will be ignored.


ERROR - converting '__ior__' op (located at: 'model/model/attention_mask.19'):

Converting PyTorch Frontend ==> MIL Ops:   1%|▏         | 57/4901 [00:00<00:0X, 477.53 ops/s]
Conversion to CoreML failed: PyTorch convert function for op '__ior__' not implemented.
Environment (please complete the following information):

OS: macOS 15 (Sequoia)

Python version: [Your Python Version, e.g., 3.11.x]

coremltools version: 8.3.0

torch version: [Output of torch.version]

transformers version: [Output of transformers.version]

numpy version: [Output of np.version]

Hardware: MacBook Air (Mid 2012, Intel Core i7)

Additional context
I am attempting to convert google/gemma-3-1b-it for on-device inference using Core ML.
Initial attempts to convert an ONNX version of the model failed. Core ML Tools' official documentation (https://apple.github.io/coremltools/docs-guides/) indicates that the ONNX converter is "Not recommended for PyTorch conversion" and that "new features will not be added to it," consistent with source="onnx" no longer being a recognized argument in ct.convert().
Hugging Face's Optimum library is also officially stated not to support Core ML export for this model type.
The current approach focuses on direct PyTorch conversion. Previous errors related to DynamicCache and "Encountering a dict at the output of the tracer" were resolved by:

Setting model.config.use_cache = False.

Implementing a GemmaCoreMLWrapper to force return_dict=False and simplify the output for torch.jit.trace.

Passing the traced_model (TorchScript object) directly to ct.convert(), as recommended by the Core ML Tools documentation for PyTorch conversion.

Changing input_ids and attention_mask dtype to np.int32 based on conversion warnings.

The current blocker is the ior operation, which is reportedly located at model/model/attention_mask.19 within the model's computation graph during MIL conversion. This suggests a low-level operation within the attention mechanism that is currently unsupported by the Core ML Tools PyTorch converter. Support for such operations would greatly facilitate the conversion of modern LLMs like Gemma for on-device deployment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugUnexpected behaviour that should be corrected (type)

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions