apple / apple/coremltools

Significant Output Discrepancy in CoreML Conversion of PyTorch's Grid Sample- FP16

Open
#2,068 25 comments 6 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
5.4k
Forks
850
Avg merge
4d 5h
Merged PRs (30d)
10

Description

## 🐞Describing the bug

The CoreML model, when converted from a PyTorch model using grid sampling, shows a large deviation in output values compared to the original PyTorch model.

The output difference is notably high. When using FP16 precision for conversion instead of the default FP32, the relative change in output difference is approximately 131.59, or 13159%. This points towards the issue in the conversion process or compatibility between PyTorch's grid sample implementation and CoreML's .

Here is the screen shot attached for the output of below code:

Screenshot 2023-11-22 at 12 48 05

## Code To Reproduce
- Also, attached feature and grid tensors in the [link](https://github.com/vinayak-sharan/text_file/tree/main), the code will convert ".txt" files to tensors.

```
import torch
import coremltools as ct
import numpy as np

# Define a simple PyTorch model that uses grid sampling
class PytorchGridSample(torch.nn.Module):
def forward(self, input, grid):
return torch.nn.functional.grid_sample(input, grid, align_corners=False)

def convert_to_coreml(model, inputs, is_float16=True):
traced_model = torch.jit.trace(
model, example_inputs=inputs, strict=False)

coreml_model = ct.converters.convert(traced_model,
inputs=[ct.TensorType(shape=inputs[0].shape),
ct.TensorType(shape=inputs[1].shape)],
compute_precision=ct.precision.FLOAT16 if is_float16 else ct.precision.FLOAT32)
return coreml_model

def compare_grid_samples_after_coreml_conversion(pt_model, inputs, is_float16):
"""
Compare the grid sample output before and after conversion to coreML
"""
pt_out = pt_model(*inputs)
coreml_pt_model = convert_to_coreml(pt_model, inputs, is_float16)
input_names_coreml_pt = [i for i in
coreml_pt_model.input_description]
input_data = {name: val.detach().numpy() for name, val in zip(input_names_coreml_pt, inputs)}

coreml_pt_out = torch.as_tensor(list(coreml_pt_model.predict(input_data).values())[0])
diff_pt_coreml = torch.norm(coreml_pt_out - pt_out)
return diff_pt_coreml

if __name__ == "__main__":
feat_file = "feat.txt"
grid_file = "grid.txt"

input_tensor_shape = (1, 64, 288, 288)
grid_shape = (1, 288, 288, 2)

input_tensor = torch.from_numpy(np.loadtxt("feat.txt").reshape(input_tensor_shape)).to(torch.float32)
grid = torch.from_numpy(np.loadtxt("grid.txt").reshape(grid_shape)).to(torch.float32)

inputs = [input_tensor, grid]
pt_model = PytorchGridSample()

diff_pt_coreml_fp16 = compare_grid_samples_after_coreml_conversion(pt_model, [*inputs], is_float16=True)
diff_pt_coreml_fp32 = compare_grid_samples_after_coreml_conversion(pt_model, [*inputs], is_float16=False)

print(
f"Difference between pytorch's grid sample before and after conversion: Note: Pytorch is fp32 and coreML is fp16 : {diff_pt_coreml_fp16}")

print(
f"Difference between pytorch's grid sample before and after conversion: Note: Pytorch is fp32 and coreML is fp32 : {diff_pt_coreml_fp32}")

print(f"Relative change in the difference: {(diff_pt_coreml_fp16 - diff_pt_coreml_fp32) / diff_pt_coreml_fp32}")

```

## System environment (please complete the following information):
- coremltools version: 7.1
- OS: MacOS-14.1
- PyTorch: 2.0.1

## Files required for the above code.
**Note**: _Since loading untrusted .pt files poses a security risk, I am sharing the .txt files instead. The file 'feat.txt' exceeds 75 MB and therefore couldn't be uploaded here. To avoid any suspicion of viruses, I am uploading them to GitHub. The links are provided below. Please download the files and save them in the appropriate directory._ @TobyRoseman

- [grid_tensor](https://github.com/vinayak-sharan/text_file/blob/main/grid.txt)
- [feature_tensor](https://github.com/vinayak-sharan/text_file/blob/main/feat.txt)

Contributor guide

Open the contributing guide

Research direction

Start by running the provided PyTorch and coremltools reproducer with feat.txt and grid.txt, comparing the FP16 and FP32 conversion paths. Trace how grid_sample is represented during conversion and establish whether the discrepancy is conversion-specific or precision-related. Done means the reproduced output mismatch is corrected or clearly bounded, with a regression check for both precision modes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
machine-learning, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.