Image Segmentation
Transformers
Safetensors
English
prima
text-generation
computer-vision
multi-image-reasoning
pixel-grounding
vision-language
custom-code
custom_code
Instructions to use kanguyen-vn/PRIMA with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use kanguyen-vn/PRIMA with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-segmentation", model="kanguyen-vn/PRIMA", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("kanguyen-vn/PRIMA", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 8,013 Bytes
91c1e9e 5e66a57 91c1e9e 06b25e4 91c1e9e 06b25e4 5e66a57 06b25e4 91c1e9e 06b25e4 91c1e9e 5e66a57 91c1e9e 06b25e4 91c1e9e 1445825 91c1e9e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | """Generate and save predictions for M4SEG."""
import argparse
from functools import partial
import json
from pathlib import Path
import torch
from torch.utils.data import DataLoader, Subset
from tqdm import tqdm
from dataset.dataset import custom_collate_fn_prima
from dataset.multi_image_datasets.M4seg_ds import M4SegDataset
from model.llava import conversation as conversation_lib
from tools.batch import move_batch
from tools.config import parse_with_config, validate_paths
from tools.model_loader import (DEFAULT_HUB_MODEL, add_model_arguments, load_bundle, normalize_model_args,
resolve_merged_checkpoint)
from tools.utils import IMAGE_TOKEN_INDEX
from tools.predictions import (generation_identity, prepare_prediction_directory,
sample_identifier)
from eval.m4seg import DEFAULT_TEXT_MODEL
M4SEG_SOURCES = 'paco_lvis||ade20k_part234||pascal_part||coco_objects||ade20k_objects||pascal_objects'
def parse_args(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
add_model_arguments(parser, merged_checkpoint=DEFAULT_HUB_MODEL)
parser.add_argument('--dataset_dir', default='/path/to/datasets')
parser.add_argument('--m4seg_annpath', default='/path/to/evaluation_annotations.json')
parser.add_argument('--m4seg_data', default=M4SEG_SOURCES)
parser.add_argument('--output_save_path', default='outputs/evaluation')
parser.add_argument('--val_batch_size', type=int, default=1)
parser.add_argument('--workers', type=int, default=0)
parser.add_argument('--max_new_tokens', type=int, default=1024)
parser.add_argument('--n_chunks', type=int, default=1)
parser.add_argument('--chunk_idx', type=int, default=0)
parser.add_argument('--resume', action='store_true')
parser.add_argument('--compute_metrics', action='store_true', help='Score predictions after generation.')
parser.add_argument('--text_model', default=DEFAULT_TEXT_MODEL)
parser.add_argument('--metrics_with_text', action=argparse.BooleanOptionalAction, default=True)
parser.add_argument('--metrics_with_meteor', action=argparse.BooleanOptionalAction, default=True)
args = normalize_model_args(parse_with_config(parser, argv))
if args.val_batch_size != 1:
parser.error('M4SEG generation currently requires val_batch_size=1.')
if args.n_chunks < 1 or not 0 <= args.chunk_idx < args.n_chunks:
parser.error('chunk_idx must be between zero and n_chunks - 1.')
if args.compute_metrics and args.n_chunks != 1:
parser.error('Score all shards together with the standalone scoring command.')
if args.compute_metrics and args.metrics_with_text and args.text_model.startswith('/path/to/'):
parser.error('Set text_model for semantic metrics, or use --no-metrics_with_text.')
return args
def build_dataset(args, *, mode='test'):
dataset = M4SegDataset(
dataset_dir=args.dataset_dir,
image_size=args.image_size, m4seg_data=args.m4seg_data,
m4seg_annpath=args.m4seg_annpath, mode=mode,
)
pair_ids = [sample_identifier(row) for row in dataset.data_infos]
if mode != 'train' and len(set(pair_ids)) != len(pair_ids):
raise ValueError('M4SEG annotation pair IDs must be unique.')
return dataset
def inference(loader, model, tokenizer, args, output):
device = torch.device(f'cuda:{args.local_rank}')
failures = {}
skipped = completed = 0
model.eval()
for batch in tqdm(loader, desc='M4SEG'):
sample_id = str(batch['sample_ids'][0])
if Path(sample_id).name != sample_id:
raise ValueError('Sample IDs must not contain path separators.')
destination = output / f'{sample_id}.pth'
if args.resume and destination.exists():
saved = torch.load(destination, map_location='cpu')
if not saved.get('error'):
skipped += 1
continue
native_sizes = [[tuple(label.shape) if label is not None else None
for label in per_image] for per_image in batch['label_list']]
source_sizes = [slot[0] for slot in native_sizes[1:]]
try:
batch = move_batch(batch, device)
batch['orig_sizes'] = native_sizes
output_ids, pred_masks = model.evaluate(
**batch, max_new_tokens=args.max_new_tokens,
eos_token_id=tokenizer.eos_token_id,
)
output_ids = torch.nn.utils.rnn.pad_sequence(
[row[row != IMAGE_TOKEN_INDEX] for row in output_ids],
batch_first=True, padding_value=tokenizer.pad_token_id,
).detach().cpu()
text = [value.replace(tokenizer.pad_token, '') for value in
tokenizer.batch_decode(output_ids, skip_special_tokens=False)]
# The model includes a native grounding slot followed by explicit image slots.
masks = [slot[0].detach().cpu() if slot and slot[0] is not None else None
for slot in pred_masks] if pred_masks is not None else []
record = {'output_ids': output_ids, 'pred_masks': masks,
'input': batch['conversation_list'][0], 'output': text,
'image_paths': batch['image_paths'][0], 'image_sizes': source_sizes}
except Exception as error:
failures[sample_id] = str(error)
record = {'output': [''], 'pred_masks': [], 'error': str(error),
'input': batch['conversation_list'][0],
'image_paths': batch['image_paths'][0], 'image_sizes': source_sizes}
temporary = destination.with_suffix('.tmp')
torch.save(record, temporary)
temporary.replace(destination)
completed += 1
return {'samples': len(loader.dataset), 'written': completed, 'resumed': skipped,
'failures': failures}
def main(args):
validate_paths(args, dataset=True)
annotation = Path(args.m4seg_annpath)
if not annotation.is_file():
raise ValueError('Set m4seg_annpath to an existing M4SEG annotation path.')
output = Path(args.output_save_path)
checkpoint = resolve_merged_checkpoint(args) if args.merged_ckpt_path else args.ckpt_path
identity = generation_identity(args, checkpoint)
prepare_prediction_directory(output, identity, resume=args.resume)
dataset = build_dataset(args)
if not len(dataset):
raise ValueError('M4SEG evaluation annotations contain no supported records.')
model, tokenizer, qformer_tokenizer = load_bundle(args)
conversation_lib.default_conversation = conversation_lib.conv_templates[args.conv_type]
if args.n_chunks > 1:
dataset = Subset(dataset, range(args.chunk_idx, len(dataset), args.n_chunks))
loader = DataLoader(dataset, batch_size=1, shuffle=False, num_workers=args.workers,
collate_fn=partial(custom_collate_fn_prima, tokenizer=tokenizer,
qformer_tokenizer=qformer_tokenizer, inference=True,
use_mm_start_end=args.use_mm_start_end,
local_rank=args.local_rank, img_emb_len=args.img_emb_len,
padding_side='left'))
summary = inference(loader, model, tokenizer, args, output)
(output / 'summary.json').write_text(json.dumps(summary, indent=2) + '\n')
print(json.dumps(summary, indent=2))
if args.compute_metrics:
from eval.m4seg import score_predictions
del model
torch.cuda.empty_cache()
report = score_predictions(
[output], dataset.data_infos, penalize_missing=True,
with_text=args.metrics_with_text, with_meteor=args.metrics_with_meteor,
text_model=args.text_model, ground_truth=annotation,
)
(output / 'metrics.json').write_text(json.dumps(report, indent=2) + '\n')
print(json.dumps(report, indent=2))
|