CoreML Conversion of the mxbai-embed-large-v1 sentence embedding model
After extensive testing (and a lot of debugging with ChatGPT), I was able to convert the mxbai-embed-large-v1 model to CoreML and run it mostly on the GPU.
Python3
1import torch
2from transformers import AutoModel, AutoTokenizer
3import coremltools as ct
45# Define a wrapper class for the AutoModel to return only the last_hidden_state
6class ModelWrapper(torch.nn.Module):
7 def __init__(self, model):
8 super(ModelWrapper, self).__init__()
9 self.model = model
1011 def forward(self, input_ids, attention_mask):
12 # Extract the 'last_hidden_state' from the model output
13 output = self.model(input_ids=input_ids, attention_mask=attention_mask)
14 return output.last_hidden_state # or use 'pooler_output' if needed
1516# Load your SentenceTransformer model and tokenizer
17model_name = "mixedbread-ai/mxbai-embed-large-v1" # Replace with your model
18model = AutoModel.from_pretrained(model_name)
19model.eval()
20tokenizer = AutoTokenizer.from_pretrained(model_name)
2122# Wrap the model to return only the tensor output
23wrapped_model = ModelWrapper(model)
24wrapped_model.eval()
2526# Sample input to export the model
27dummy_input = tokenizer("This is a sample input", return_tensors="pt")
2829# Trace the model using tensor inputs (input_ids, attention_mask)
30traced_model = torch.jit.trace(wrapped_model, (dummy_input['input_ids'], dummy_input['attention_mask']))
3132# Convert the traced PyTorch model to CoreML using the ML Program format
33model_from_torch = ct.convert(
34 traced_model,
35 inputs=[
36 ct.TensorType(name="input_ids", shape=(1, ct.RangeDim(1, 512)), dtype=np.float32),
37 ct.TensorType(name="attention_mask", shape=(1, ct.RangeDim(1, 512)), dtype=np.float32)
38 ],
39 minimum_deployment_target=ct.target.iOS17,
40 convert_to="mlprogram",
41 compute_precision=ct.precision.FLOAT16
42)
4344# Save the CoreML model as an mlpackage
45model_from_torch.save("mxbai-embed-large-v1.mlpackage")
It can be run like this:
Python
1import coremltools as ct
2from transformers import AutoTokenizer
3import numpy as np
45# Load the CoreML model
6model = ct.models.MLModel("mxbai-embed-large-v1.mlpackage")
78# Load the tokenizer
9tokenizer = AutoTokenizer.from_pretrained("mixedbread-ai/mxbai-embed-large-v1")
1011# Prepare some input text
12input_text = "This is a test sentence for the CoreML model"
13inputs = tokenizer(input_text, return_tensors="np", padding=True, truncation=True, max_length=512)
1415# Extract input tensors
16input_ids = inputs['input_ids'].astype(np.float32) # CoreML expects float32
17attention_mask = inputs['attention_mask'].astype(np.float32)
1819# Prepare inputs for the CoreML model
20coreml_input = {"input_ids": input_ids, "attention_mask": attention_mask}
2122predictions = model.predict(coreml_input)
2324hidden_states = predictions['hidden_states']
25cls_embedding = hidden_states[0, 0, :]
26np.set_printoptions(threshold=np.inf)
2728# Print the CLS token embedding, which is a 1024-dimensional vector
29print("CLS Token Embedding:", cls_embedding, len(cls_embedding))
I verified the output with ollama:
curl http://localhost:11434/api/embeddings -d '{
"model": "mxbai-embed-large",
"prompt": "This is a test sentence for the CoreML model"
}'