ritm_interactive_segmentation icon indicating copy to clipboard operation
ritm_interactive_segmentation copied to clipboard

Is your models are deployable in onnx format?

Open sbmalik opened this issue 3 years ago • 11 comments

I wanted to run these models on some other platforms and needed tha onnx version. Kindly guide me if they are available?

sbmalik avatar Sep 07 '22 13:09 sbmalik

I've tried to export it but there is a mishape error caused by this line https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/model/ops.py#L77

I've tried to export it but there is a mishape error caused by this line

https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/model/ops.py#L77

I had the same issue. but after removing that coords[invalid_points, :, :, :] = 1e6 . i successfully converted and load the onnx model Thank you

Ehteshamciitwah avatar Oct 25 '22 06:10 Ehteshamciitwah

but I need you need to set the invalid points

Hello, i just want to use inference in onnx. So i do some changing in ops.py file

  • use else condition instead of if in ops.py file
  • remove coords[invalid_points, :, :, :] = 1e6
  • run demo.py file to test and it works well without any problem
  • Then i change it into onnx and test onnx with their Ui by replacing https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/inference/predictors/base.py#L80 with onnx run. So i think invalid points may have not much use. for onnx conversion you need two dummy inputs as tuples. you need to use dynamic axes during export.

Ehteshamciitwah avatar Oct 27 '22 01:10 Ehteshamciitwah

Not sure I understood, I advice you to take your time to write a better-explained message.

Without the line you have removed, the output shouldn't be the same.

Is there any updates on this? @Ehteshamciitwah were you able to get a functional ONNX model?

bfan1256 avatar Dec 11 '22 05:12 bfan1256

yes. I changed it successfully to onnx format. During conversion, first, I use else condition making self.cpu_mode=False. https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/model/ops.py#L56 second, i removed the line https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/model/ops.py#L77

After changing, get_coord_features code is: ''' def get_coord_features(self, points, batchsize, rows, cols):

    num_points=torch.div(points.shape[1] , 2, rounding_mode='floor') #int 1
    points = points.view(-1, points.size(2))
    points, points_order = torch.split(points, [2, 1], dim=1)

    invalid_points = torch.max(points, dim=1, keepdim=False)[0] < 0      #tensor([False,  True, False,  True], device='cuda:0')
    row_array = torch.arange(start=0, end=rows, step=1, dtype=torch.float32, device=points.device)
    col_array = torch.arange(start=0, end=cols, step=1, dtype=torch.float32, device=points.device)

    coord_rows, coord_cols = torch.meshgrid(row_array, col_array) #400x400 each
    coords = torch.stack((coord_rows, coord_cols), dim=0).unsqueeze(0).repeat(points.size(0), 1, 1, 1)

    add_xy = (points * self.spatial_scale).view(points.size(0), points.size(1), 1, 1)   #4x2x1x1
    coords.add_(-add_xy)
    if not self.use_disks:
        coords.div_(self.norm_radius * self.spatial_scale)
    coords.mul_(coords)

    coords[:, 0] += coords[:, 1]
    coords = coords[:, :1]

    # coords[invalid_points, :, :, :] = 1e6

    coords = coords.view(-1, num_points, 1, rows, cols)
    coords = coords.min(dim=1)[0]  # -> (bs * num_masks * 2) x 1 x h x w
    coords = coords.view(-1, 2, rows, cols)  #2x2x400x400

    if self.use_disks:
        coords = (coords <= (self.norm_radius * self.spatial_scale) ** 2).float()
    else:
        coords.sqrt_().mul_(2).tanh_()

    return coords    #2x2x400x400

'''

Ehteshamciitwah avatar Dec 12 '22 01:12 Ehteshamciitwah

是的。我成功地将其更改为onnx格式。在转换过程中,首先,我使用 else 条件制作 self.cpu_mode=False。https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/model/ops.py#L56 秒,我删除了该行 https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/model/ops.py#L77

更改后,get_coord_features代码为:“”定义get_coord_features(self,points,batchsize,rows,cols):

    num_points=torch.div(points.shape[1] , 2, rounding_mode='floor') #int 1
    points = points.view(-1, points.size(2))
    points, points_order = torch.split(points, [2, 1], dim=1)

    invalid_points = torch.max(points, dim=1, keepdim=False)[0] < 0      #tensor([False,  True, False,  True], device='cuda:0')
    row_array = torch.arange(start=0, end=rows, step=1, dtype=torch.float32, device=points.device)
    col_array = torch.arange(start=0, end=cols, step=1, dtype=torch.float32, device=points.device)

    coord_rows, coord_cols = torch.meshgrid(row_array, col_array) #400x400 each
    coords = torch.stack((coord_rows, coord_cols), dim=0).unsqueeze(0).repeat(points.size(0), 1, 1, 1)

    add_xy = (points * self.spatial_scale).view(points.size(0), points.size(1), 1, 1)   #4x2x1x1
    coords.add_(-add_xy)
    if not self.use_disks:
        coords.div_(self.norm_radius * self.spatial_scale)
    coords.mul_(coords)

    coords[:, 0] += coords[:, 1]
    coords = coords[:, :1]

    # coords[invalid_points, :, :, :] = 1e6

    coords = coords.view(-1, num_points, 1, rows, cols)
    coords = coords.min(dim=1)[0]  # -> (bs * num_masks * 2) x 1 x h x w
    coords = coords.view(-1, 2, rows, cols)  #2x2x400x400

    if self.use_disks:
        coords = (coords <= (self.norm_radius * self.spatial_scale) ** 2).float()
    else:
        coords.sqrt_().mul_(2).tanh_()

    return coords    #2x2x400x400

'''

Hi, can you provide the code to export onnx?

Caooc avatar May 27 '23 13:05 Caooc

Kindly update the code according to your requirements:

import torch from isegm.utils import exp from isegm.inference import utils import argparse def parse_args(): parser = argparse.ArgumentParser()

parser.add_argument('--checkpoint',default='coco_lvis_h18_itermask',type=str, required=False,
                    help='The path to the checkpoint. '
                         'This can be a relative path (relative to cfg.INTERACTIVE_MODELS_PATH) '
                         'or an absolute path. The file extension can be omitted.')
parser.add_argument('--gpu', type=int, default=0,
                    help='Id of GPU to use.')
parser.add_argument('--image', type=str, default='./3096.jpg',
                    help='path to image')
parser.add_argument('--cpu', action='store_true', default=False,
                    help='Use only CPU for inference.')

parser.add_argument('--limit-longest-size', type=int, default=800,
                    help='If the largest side of an image exceeds this value, '
                         'it is resized so that its largest side is equal to this value.')

parser.add_argument('--cfg', type=str, default="config.yml",
                    help='The path to the config file.')

args = parser.parse_args()
# parser.parse_args()
if args.cpu:
    args.device =torch.device('cpu')
else:
    args.device = torch.device(f'cuda:{args.gpu}')
cfg = exp.load_config_file(args.cfg, return_edict=True)

return args, cfg

def main(): args, cfg = parse_args() torch.backends.cudnn.deterministic = True checkpoint_path = utils.find_checkpoint(cfg.INTERACTIVE_MODELS_PATH, args.checkpoint) model = utils.load_is_model(checkpoint_path, args.device, cpu_dist_maps=True) point_nd=torch.tensor([[[239.0, 75.0, 0.0], [ -1, -1, -1]]],device='cuda')#tensor(2,2,3)

image=torch.randn(1,4,400,400,device='cuda')
dummy_input=(image,point_nd)
input_names = ["image","points"]
output_names = ["output"]
torch.onnx.export(
  model,
  dummy_input,
  "ritm.onnx",
  verbose=True,
  opset_version=13,
  input_names=input_names,
  output_names=output_names,
  dynamic_axes={
      'image':{2:'height',3:'width'},
      'points':{1:"custom"},
          }
        )

if name == 'main': main()

Ehteshamciitwah avatar May 30 '23 00:05 Ehteshamciitwah

是的。我成功地将其更改为onnx格式。在转换过程中,首先,我使用 else 条件制作 self.cpu_mode=False。

May I ask why the image has 4 channels? Can you send me a copy of the Onnx inference code?

duxuan11 avatar Oct 11 '23 14:10 duxuan11

Hello, i just want to use inference in onnx. So i do some changing in ops.py file

  • use else condition instead of if in ops.py file
  • remove coords[invalid_points, :, :, :] = 1e6
  • run demo.py file to test and it works well without any problem
  • Then i change it into onnx and test onnx with their Ui by replacing https://github.com/saic-vul/ritm_interactive_segmentation/blob/708182de6e3a73da4034579935aef4c19ceae80a/isegm/inference/predictors/base.py#L80 with onnx run. So i think invalid points may have not much use. for onnx conversion you need two dummy inputs as tuples. you need to use dynamic axes during export.
   def _get_prediction(self, image_nd, clicks_lists, is_image_changed):
        points_nd = self.get_points_nd(clicks_lists)
        return self.net(image_nd, points_nd)['instances']

I modified this code as follows

def _get_prediction(self, image_nd, clicks_lists, is_image_changed):
points_nd = self.get_points_nd(clicks_lists)
#return self.net(image_nd, points_nd)['instances']
#print(image_nd.shape)
image_nd = np.asarray(image_nd).astype(np.float32)
point_nd=np.array([[[239.0, 75.0, 0.0],[ -1, -1, -1]]]).astype(np.float32)
sess = rt.InferenceSession('ritm.onnx')
pred_onnx = sess.run([output_name], { "image": image,"points": point_nd})
return pred_onnx

I found the image_nd is (2,4,256,256) size, but the onnx model input of image is size of (1, 4,height, width). So how to modify this code ?

duxuan11 avatar Oct 12 '23 04:10 duxuan11