Instructions to use xju-arlab/vbench-model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use xju-arlab/vbench-model with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Download code/vbench_prompts_compile/scripts/render_matrix_tables.py from xju-arlab/vbench-model: direct link, hf CLI and curl.
- Browser
- Download file 18.9 kB
-
https://huggingface.co/xju-arlab/vbench-model/resolve/main/code/vbench_prompts_compile/scripts/render_matrix_tables.py
- Command line
-
hf download hf://xju-arlab/vbench-model/code/vbench_prompts_compile/scripts/render_matrix_tables.py
-
curl -L -o render_matrix_tables.py https://huggingface.co/xju-arlab/vbench-model/resolve/main/code/vbench_prompts_compile/scripts/render_matrix_tables.py
18.9 kB
| #!/usr/bin/env python3 | |
| """Render reproducible CSV, Markdown and LaTeX tables from frozen scores. | |
| Parsing targets are public benchmark metadata, not human annotations. Scene | |
| classification uses separately identified model-labelled scorecards. Paired | |
| video scores describe metric behaviour, not perceptual quality improvements. | |
| """ | |
| import argparse | |
| from collections import defaultdict | |
| import csv | |
| import json | |
| from pathlib import Path | |
| import random | |
| import sys | |
| ROOT=Path(__file__).resolve().parents[1] | |
| sys.path.insert(0,str(ROOT/'src')) | |
| from vbench_prompts_compile import annotation_jobs as J | |
| from vbench_prompts_compile import records as R | |
| from vbench_prompts_compile.experiments import cluster_summary, text_key | |
| from vbench_prompts_compile.sources import load_k400 | |
| from vbench_prompts_compile.action_repair import compile_action | |
| from score_matrix import SCHEMES, origin_compiled, parsed_target, backend_target, native_entity_codec | |
| from cache_backend_outputs import sha | |
| def fmt(value): | |
| if value is None:return 'N/A' | |
| if isinstance(value,float):return f'{value:.4f}' | |
| return str(value) | |
| def ci_text(value): | |
| interval=value.get('ci') | |
| return fmt(value['estimate'])+(f' [{fmt(interval[0])}, {fmt(interval[1])}]' if interval else ' [N/A]') | |
| def table(out,name,rows,columns): | |
| with (out/(name+'.csv')).open('w',newline='') as f: | |
| w=csv.DictWriter(f,fieldnames=columns,lineterminator='\n');w.writeheader();w.writerows([{k:r.get(k) for k in columns} for r in rows]) | |
| lines=['| '+' | '.join(columns)+' |','| '+' | '.join(['---']*len(columns))+' |'] | |
| lines.extend('| '+' | '.join(fmt(r.get(k)).replace('|','\\|') for k in columns)+' |' for r in rows) | |
| (out/(name+'.md')).write_text('\n'.join(lines)+'\n') | |
| def tex(s): | |
| return str(s).replace('\\',r'\textbackslash{}').replace('_',r'\_').replace('%',r'\%').replace('&',r'\&').replace('#',r'\#') | |
| lines=[r'\begin{longtable}{'+'l'*len(columns)+'}',r'\toprule', | |
| ' & '.join(tex(k) for k in columns)+r' \\',r'\midrule\endhead'] | |
| lines.extend(' & '.join(tex(fmt(r.get(k))) for k in columns)+r' \\' for r in rows) | |
| lines.extend([r'\bottomrule',r'\end{longtable}']) | |
| (out/(name+'.tex')).write_text('\n'.join(lines)+'\n') | |
| def target_set(task,target,*,canonicalize=False): | |
| if not isinstance(target,dict):return set() | |
| name=R.canonical_entity_name if canonicalize else str | |
| if task=='spatial': | |
| return {(name(r['subject']),r['relation'],name(r['object'])) | |
| for r in target.get('relationships',[])} | |
| if task=='objects':return {name(v) for v in target.get('entities',[])} | |
| return set(target.get('actions',[])) | |
| def parsing_table(matrix,predictions,codec=None,*,spatial_backend='legacy-official',action_interface='legacy-model'): | |
| unique={(r['task'],r['original_prompt']):r for r in matrix if r['transform']=='identity' and r['task']!='scene'} | |
| vocab=load_k400();details=[];summary=[] | |
| for (task,prompt),row in sorted(unique.items()): | |
| reference=origin_compiled(task,row['official_target']) | |
| expected=target_set(task,reference) | |
| semantic_reference=target_set(task,reference,canonicalize=True) | |
| for scheme in SCHEMES: | |
| parsed=parsed_target(task,row,scheme,predictions,vocab) | |
| compiled=parsed if scheme=='Origin' else backend_target(task,parsed,codec,normalize_spatial=spatial_backend=='repair-v2') | |
| if task=='action' and scheme=='Repair-model' and action_interface in {'repair-v2','repair-v2.1'}: | |
| compiled=compile_action(prompt,parsed,vocab,scope_guard=action_interface=='repair-v2.1')['target'] | |
| actual=target_set(task,compiled) | |
| normalized=target_set(task,parsed,canonicalize=True) | |
| tp=len(actual&expected);denom=len(actual)+len(expected) | |
| details.append({'task':task,'scheme':scheme,'prompt':prompt,'family':row['family'], | |
| 'eligible':row['eligible'],'expected':sorted(expected),'predicted':sorted(actual),'raw_target':parsed, | |
| 'valid':parsed is not None,'exact':parsed is not None and actual==expected, | |
| 'set_f1':2*tp/denom if denom else float(parsed is not None), | |
| 'normalized_semantic_f1':2*len(normalized&semantic_reference)/(len(normalized)+len(semantic_reference)) if normalized or semantic_reference else float(parsed is not None), | |
| 'prompt_words':len(prompt.split())}) | |
| for task in sorted({r['task'] for r in details}): | |
| for scheme in SCHEMES: | |
| all_rows=[r for r in details if r['task']==task and r['scheme']==scheme] | |
| values=[r for r in all_rows if r['eligible']] | |
| summary.append({'Task':task,'Scheme':scheme,'Families':len(values),'Planned':len(all_rows), | |
| 'Strict set F1 (CI)':ci_text(cluster_summary(values,'set_f1')), | |
| 'Normalized semantic F1':cluster_summary(values,'normalized_semantic_f1')['estimate'], | |
| 'Exact (CI)':ci_text(cluster_summary(values,'exact')), | |
| 'Valid':sum(r['valid'] for r in values)/len(values) if values else None}) | |
| return summary,details | |
| def original_table(paired): | |
| rows=[r for r in paired if r['transform']=='identity'] | |
| origins={(r['task'],r['relative_path']):r for r in rows if r['scheme']=='Origin'} | |
| groups=defaultdict(list) | |
| for row in rows: | |
| base=origins[(row['task'],row['relative_path'])] | |
| value={**row,'vs_origin':row['original_score']-base['original_score'], | |
| 'common_coverage':min(row['original_coverage'],base['original_coverage'])} | |
| for generator in ['all',row['relative_path'].split('/')[1]]: | |
| groups[(row['task'],generator,row['scheme'])].append(value) | |
| result=[] | |
| for (task,generator,scheme),planned in sorted(groups.items()): | |
| values=[r for r in planned if r['eligible']] | |
| result.append({'Task':task,'Generator':generator,'Scheme':scheme,'N':len(values),'Planned':len(planned), | |
| 'Families':len({r['family'] for r in values}), | |
| 'Score (CI)':ci_text(cluster_summary(values,'original_score')), | |
| 'Delta vs Origin (CI)':ci_text(cluster_summary(values,'vs_origin')), | |
| 'Coverage':sum(r['common_coverage'] for r in values)/len(values) if values else None, | |
| 'Abstain':sum(r['original_abstention'] for r in values)/len(values) if values else None}) | |
| return result | |
| def macro_f1(rows,scheme='Repair-model'): | |
| labels=['supported','contradicted','insufficient'] | |
| counts=[[0,0,0] for _ in labels] | |
| for row in rows: | |
| truth=row['expected'];pred=row['schemes'][scheme]['label'] | |
| for i,label in enumerate(labels): | |
| counts[i][0]+=truth==label and pred==label | |
| counts[i][1]+=truth!=label and pred==label | |
| counts[i][2]+=truth==label and pred!=label | |
| if any(tp+fn==0 for tp,fp,fn in counts):return None | |
| return sum(2*tp/(2*tp+fp+fn) for tp,fp,fn in counts)/len(labels) | |
| def scene_macro_f1(rows): | |
| groups=defaultdict(list) | |
| for row in rows:groups[row['family']].append(row) | |
| value=macro_f1(rows);distribution=[] | |
| if len(groups)>=2 and value is not None: | |
| rng=random.Random(20260919);blocks=list(groups.values()) | |
| for _ in range(2000): | |
| sampled=[r for block in rng.choices(blocks,k=len(blocks)) for r in block] | |
| if (score:=macro_f1(sampled)) is not None:distribution.append(score) | |
| distribution.sort() | |
| return {'estimate':value,'ci':[distribution[int(.025*(len(distribution)-1))],distribution[int(.975*(len(distribution)-1))]] if distribution else None, | |
| 'n':len(rows),'families':len(groups),'bootstrap_valid':len(distribution),'bootstrap_rounds':2000} | |
| def main(argv=None): | |
| p=argparse.ArgumentParser(description=__doc__) | |
| p.add_argument('--matrix',required=True);p.add_argument('--paired',required=True);p.add_argument('--score-report',required=True) | |
| p.add_argument('--metadata',required=True,help='same full public entity inventory used by score_matrix') | |
| p.add_argument('--predictions',action='append',required=True) | |
| p.add_argument('--scene-card',action='append',default=[],help='name=scorecard JSON') | |
| p.add_argument('--object-controls',help='matched background and detector-side-effect report') | |
| p.add_argument('--out',required=True);p.add_argument('--allow-incomplete',action='store_true') | |
| args=p.parse_args(argv);out=Path(args.out);out.mkdir(parents=True,exist_ok=True) | |
| matrix=J.read_jsonl(Path(args.matrix));paired=J.read_jsonl(Path(args.paired));report=json.loads(Path(args.score_report).read_text()) | |
| complete=bool(report.get('execution_complete')) and len(paired)==3*len(matrix) | |
| if not complete and not args.allow_incomplete:raise ValueError('incomplete matrix; use --allow-incomplete for a labelled draft') | |
| predictions={} | |
| for path in args.predictions: | |
| for row in J.read_jsonl(Path(path)): | |
| if row['request_id'] in predictions:raise ValueError('multiple adapters for one request') | |
| predictions[row['request_id']]=row['target'] | |
| codec=native_entity_codec(json.loads(Path(args.metadata).read_text())) | |
| spatial_backend=report.get('spatial_backend','legacy-official') | |
| action_interface=report.get('action_interface','legacy-model') | |
| objects_backend=report.get('objects_backend','legacy-official') | |
| parsing,details=parsing_table(matrix,predictions,codec,spatial_backend=spatial_backend,action_interface=action_interface) | |
| table(out,'table-a-parsing',parsing,list(parsing[0]));R.write_jsonl(out/'parsing-details.jsonl',details) | |
| originals=original_table(paired);table(out,'table-b-originals',originals,list(originals[0]));original_table_rows=len(originals) | |
| transformed=[];visibility=[];conditional=[];protocol=[];compact=[];checks=[] | |
| for row in report['summary']: | |
| transformed.append({'Task':row['task'],'Scheme':row['scheme'],'Transform':row['transform'], | |
| 'N/planned':str(row['eligible'])+'/'+str(row['planned']),'Families':row['families'], | |
| 'Original':row['original_score']['estimate'],'Transformed':row['transformed_score']['estimate'], | |
| 'Delta (CI)':ci_text(row['paired_delta']),'Coverage':row['transformed_coverage']['estimate'], | |
| 'Abstain':row['transformed_abstention']['estimate']}) | |
| if 'complete_pairs' in row: | |
| conditional.append({'Task':row['task'],'Scheme':row['scheme'],'Transform':row['transform'], | |
| 'Complete/planned':str(row['complete_pairs'])+'/'+str(row['planned']), | |
| 'Before':row['complete_pair_original_score']['estimate'],'After':row['complete_pair_transformed_score']['estimate'], | |
| 'Delta (CI)':ci_text(row['complete_pair_paired_delta'])}) | |
| if row['task']=='action' and row['transform']!='identity': | |
| protocol.append({'Scheme':row['scheme'],'Transform':row['transform'],'Videos':row['eligible'], | |
| 'Unique prompts':row['action_protocol_correct']['n'], | |
| 'Target set correct (CI)':ci_text(row['action_protocol_correct']), | |
| 'Score invariant (CI)':ci_text(row['invariance_success']), | |
| 'Abstain':row['transformed_abstention']['estimate']}) | |
| if row['transform']!='identity': | |
| checks.append({'Task':row['task'],'Scheme':row['scheme'],'Transform':row['transform'], | |
| 'Invariance N':row['invariance_success']['n'],'Invariant (CI)':ci_text(row['invariance_success']), | |
| 'Positive-base N':row['raw_drop_given_positive_base']['n'], | |
| 'Observed complete-pair drop (CI)':ci_text(row['raw_drop_given_positive_base']), | |
| 'Verified positive N':row['validated_sensitivity_success']['n'], | |
| 'Verified drop (CI)':ci_text(row['validated_sensitivity_success'])}) | |
| transform=row['transform'].replace('_occlusion_',' mask ').replace('_',' ') | |
| compact.append({'Dim':row['task'],'Condition':transform,'Scheme':row['scheme'], | |
| 'N/families':str(row['eligible'])+'/'+str(row['families']), | |
| 'Before':row['original_score']['estimate'],'After':row['transformed_score']['estimate'], | |
| 'Delta (95% CI)':ci_text(row['paired_delta'])}) | |
| if row['task']=='objects' and row['transform']=='target_occlusion_1.0': | |
| visibility.append({'Scheme':row['scheme'],'Planned':row['planned'], | |
| 'Invisible':row['vision_model_verified_invisible_endpoints'], | |
| 'Isolated':row['vision_model_verified_isolated_removals'], | |
| 'Positive isolated':row['validated_sensitivity_success']['n'], | |
| 'All rejected (CI)':ci_text(row['verified_endpoint_all_rejected']), | |
| 'Negative frames (CI)':ci_text(row['verified_endpoint_negative_frame_fraction']), | |
| 'Verified success / full plan (CI)':ci_text(row['full_plan_verified_endpoint_success']), | |
| 'Isolated positive-base drop (CI)':ci_text(row['validated_sensitivity_success'])}) | |
| table(out,'table-c-transforms',transformed,list(transformed[0])) | |
| if conditional:table(out,'table-f-complete-pairs',conditional,list(conditional[0])) | |
| if protocol:table(out,'table-g-action-protocol',protocol,list(protocol[0])) | |
| if compact:table(out,'paper-main',compact,list(compact[0])) | |
| if visibility:table(out,'table-d-visibility',visibility,list(visibility[0])) | |
| if checks:table(out,'table-k-metamorphic-checks',checks,list(checks[0])) | |
| scene=[];scene_synonyms=[];scene_f1={} | |
| for item in args.scene_card: | |
| name,path=item.split('=',1);card=json.loads(Path(path).read_text());s=card['summary'] | |
| originals=[r for r in card['rows'] if r['condition']!='synonym' and r['expected'] is not None] | |
| synonym_rows=[r for r in card['rows'] if r['condition']=='synonym'] | |
| scene_f1[name]=scene_macro_f1(originals) | |
| for scheme in SCHEMES: | |
| common=s['primary_common_binary'][scheme];syn=s['synonyms'][scheme] | |
| scene.append({'Dataset':name,'Scheme':scheme,'Binary N':s['official_defined_observations'],'Source blocks':s['source_components'], | |
| 'Binary accuracy (CI)':ci_text(common['binary_accuracy_full_denominator']), | |
| 'Three-way N':len(originals) if scheme=='Repair-model' else None, | |
| 'Three-way macro F1 (CI)':ci_text(scene_f1[name]) if scheme=='Repair-model' else 'N/A'}) | |
| scene_synonyms.append({'Dataset':name,'Scheme':scheme,'Pairs':syn['correct_and_consistent']['n'], | |
| 'Source blocks':syn['correct_and_consistent']['families'], | |
| 'Binary correct and consistent (CI)':ci_text(syn['correct_and_consistent']), | |
| 'Exact-label consistent (CI)':ci_text(syn['raw_consistent']), | |
| 'Copy original (CI)':ci_text(syn['copy_original_correct_and_consistent']), | |
| 'Always supported':sum(r['expected']=='supported' for r in synonym_rows)/len(synonym_rows) if synonym_rows else None, | |
| 'Always not-supported':sum(r['expected'] in {'contradicted','insufficient'} for r in synonym_rows)/len(synonym_rows) if synonym_rows else None}) | |
| if scene:table(out,'table-e-scene-classification',scene,list(scene[0])) | |
| if scene_synonyms:table(out,'table-h-scene-synonyms',scene_synonyms,list(scene_synonyms[0])) | |
| axes=defaultdict(list) | |
| for row in paired: | |
| if row['task']=='spatial' and row['eligible'] and row.get('axis'): | |
| axes[(row['axis'],row['scheme'],row['transform'])].append(row) | |
| axis_rows=[] | |
| for (axis,scheme,condition),values in sorted(axes.items()): | |
| axis_rows.append({'Axis':axis,'Scheme':scheme,'Condition':condition,'N':len(values), | |
| 'Families':len({r['family'] for r in values}),'Before':cluster_summary(values,'original_score')['estimate'], | |
| 'After':cluster_summary(values,'transformed_score')['estimate'],'Delta (CI)':ci_text(cluster_summary(values,'paired_delta'))}) | |
| if axis_rows:table(out,'table-i-spatial-axes',axis_rows,list(axis_rows[0])) | |
| if args.object_controls: | |
| controls=json.loads(Path(args.object_controls).read_text());comparisons=[] | |
| for row in controls['matched_background_contrasts']: | |
| comparisons.append({'Scheme':row['scheme'],'Linear fraction':row['linear_fraction'], | |
| 'Matched/planned':str(row['target']['n'])+'/'+str(row['planned_videos']), | |
| 'Families':row['target']['families'],'Before':row['original']['estimate'], | |
| 'Target mask':row['target']['estimate'],'Background mask':row['background']['estimate'], | |
| 'Target minus background (CI)':ci_text(row['target_minus_background'])}) | |
| if comparisons:table(out,'table-j-matched-controls',comparisons,list(comparisons[0])) | |
| J.atomic_json(out/'scene-macro-f1.json',scene_f1) | |
| paths=[args.matrix,args.metadata,args.paired,args.score_report,*args.predictions,*[v.split('=',1)[1] for v in args.scene_card]] | |
| if args.object_controls:paths.append(args.object_controls) | |
| J.atomic_json(out/'manifest.json',{'execution_complete':complete,'spatial_backend':spatial_backend,'action_interface':action_interface,'objects_backend':objects_backend,'input_sha256':{v:sha(v) for v in paths},'renderer_sha256':sha(__file__), | |
| 'notes':['Parsing references are official structural metadata, not human gold.','Scene labels are model consensus.','Source-family bootstrap: 2000 draws, seed 20260919.','Scores and score gains are not measures of human correctness.']}) | |
| doc=[r'\documentclass[10pt]{article}',r'\usepackage[paperwidth=21in,paperheight=11in,margin=0.4in]{geometry}', | |
| r'\usepackage{booktabs,longtable}',r'\begin{document}',r'\small', | |
| r'\noindent VBench deterministic matrix. '+('Complete execution.' if complete else 'DRAFT: transformations incomplete.'), | |
| r' Scores are metric outputs; annotations are model labels, not human gold.'] | |
| for path in sorted(out.glob('table-*.tex')): | |
| doc.extend([r'\section*{'+path.stem.replace('-',' ')+r'}',r'\input{'+path.name+r'}',r'\clearpage']) | |
| doc.append(r'\end{document}');(out/'tables.tex').write_text('\n'.join(doc)+'\n') | |
| if compact: | |
| (out/'paper.tex').write_text('\n'.join([r'\documentclass{article}',r'\usepackage[a4paper,landscape,margin=0.5in]{geometry}', | |
| r'\usepackage{booktabs,longtable}',r'\begin{document}\footnotesize', | |
| r'Paired original/transformed scores; 95\% source-family bootstrap intervals. Missing outputs score zero; coverage and conditional results are in the appendix.', | |
| r'\input{paper-main.tex}',r'\end{document}'])+'\n') | |
| print(json.dumps({'out':str(out),'complete':complete,'parsing_rows':len(parsing),'original_rows':original_table_rows,'transform_rows':len(transformed),'scene_macro_f1':scene_f1})) | |
| return 0 | |
| if __name__=='__main__':raise SystemExit(main()) | |