Buckets:
| """ | |
| MM-SafetyBench Dataset Adapter for B2 (Image Poisoning) Schema | |
| MM-SafetyBench: Multimodal safety benchmark (PKU-Alignment) | |
| License: CC-BY-NC-4.0 (RESEARCH ONLY - DO NOT REDISTRIBUTE) | |
| HuggingFace: https://huggingface.co/datasets/PKU-Alignment/MM-SafetyBench | |
| This adapter maps MM-SafetyBench multimodal safety prompts into the benchmark's | |
| B2 schema. Many MM-SafetyBench prompts reference text embedded in the image | |
| ("TYPO"/"SD_TYPO" splits), which aligns with the benchmark's "image channel" | |
| attack surface. | |
| """ | |
| import logging | |
| from pathlib import Path | |
| from typing import Dict, Any, Optional, Generator, Iterable, List | |
| try: | |
| from datasets import load_dataset | |
| from datasets import get_dataset_config_names | |
| HAS_DATASETS = True | |
| except ImportError: | |
| HAS_DATASETS = False | |
| from .base_adapter import BaseAdapter, DatasetMetadata | |
| logger = logging.getLogger(__name__) | |
| class MMSafetyBenchAdapter(BaseAdapter): | |
| """Adapter for PKU-Alignment/MM-SafetyBench (Extended; CC-BY-NC).""" | |
| DEFAULT_SPLITS = ["SD", "SD_TYPO", "TYPO"] | |
| def __init__( | |
| self, | |
| output_dir: Path, | |
| configs: Optional[List[str]] = None, | |
| splits: Optional[List[str]] = None, | |
| include_text_only: bool = False, | |
| export_images: bool = False, | |
| images_subdir: str = "mmsafetybench_images", | |
| verbose: bool = False, | |
| ): | |
| super().__init__(output_dir, verbose) | |
| if not HAS_DATASETS: | |
| raise ImportError("The 'datasets' library is required. Install with: pip install datasets") | |
| self.configs = configs | |
| self.splits = splits or list(self.DEFAULT_SPLITS) | |
| if include_text_only and "Text_only" not in self.splits: | |
| self.splits.append("Text_only") | |
| self.export_images = bool(export_images) | |
| self.images_dir_out = self.output_dir / images_subdir | |
| logger.warning( | |
| "MM-SafetyBench is CC-BY-NC licensed. Do not redistribute converted data or exported images." | |
| ) | |
| def metadata(self) -> DatasetMetadata: | |
| return DatasetMetadata( | |
| name="MM-SafetyBench", | |
| version="1.0", | |
| license="CC-BY-NC-4.0", | |
| license_url="https://huggingface.co/datasets/PKU-Alignment/MM-SafetyBench", | |
| source_url="https://huggingface.co/datasets/PKU-Alignment/MM-SafetyBench", | |
| paper_url=None, | |
| can_redistribute=False, | |
| target_surface="B2", | |
| description="Multimodal safety benchmark prompts with images (research only)", | |
| ) | |
| def _iter_configs(self) -> Iterable[str]: | |
| if self.configs: | |
| return self.configs | |
| try: | |
| return get_dataset_config_names("PKU-Alignment/MM-SafetyBench") | |
| except Exception as e: | |
| logger.warning(f"Failed to list MM-SafetyBench configs; using fallback list: {e}") | |
| return [ | |
| "EconomicHarm", | |
| "Financial_Advice", | |
| "Fraud", | |
| "Gov_Decision", | |
| "HateSpeech", | |
| "Health_Consultation", | |
| "Illegal_Activitiy", | |
| "Legal_Opinion", | |
| "Malware_Generation", | |
| "Physical_Harm", | |
| "Political_Lobbying", | |
| "Privacy_Violence", | |
| "Sex", | |
| ] | |
| def load_source_data(self) -> Generator[Dict[str, Any], None, None]: | |
| if self.export_images: | |
| self.images_dir_out.mkdir(parents=True, exist_ok=True) | |
| for config in self._iter_configs(): | |
| for split in self.splits: | |
| logger.info(f"Loading MM-SafetyBench config={config} split={split} ...") | |
| try: | |
| dataset = load_dataset("PKU-Alignment/MM-SafetyBench", config, split=split) | |
| except Exception as e: | |
| logger.error(f"Failed to load MM-SafetyBench config={config} split={split}: {e}") | |
| continue | |
| for item in dataset: | |
| rec = dict(item) | |
| rec["_config"] = config | |
| rec["_split"] = split | |
| yield rec | |
| def transform_record(self, record: Dict[str, Any]) -> Optional[Dict[str, Any]]: | |
| question = record.get("question") or "" | |
| if not question or len(str(question).strip()) < 3: | |
| return None | |
| config = record.get("_config", "Unknown") | |
| split = record.get("_split", "Unknown") | |
| src_id = record.get("id") | |
| user_query = self.sanitize_text(str(question), max_length=10000) | |
| attack_id = self.generate_id("B2-MMSafetyBench", f"{config}:{split}:{src_id}:{user_query}") | |
| image_obj = record.get("image") | |
| exported_relpath = None | |
| if self.export_images and image_obj is not None: | |
| try: | |
| out_dir = self.images_dir_out / config / split | |
| out_dir.mkdir(parents=True, exist_ok=True) | |
| out_path = out_dir / f"{attack_id}.png" | |
| image_obj.save(out_path) | |
| exported_relpath = str(out_path.relative_to(self.output_dir)) | |
| except Exception as e: | |
| logger.warning(f"Failed to export MM-SafetyBench image for {attack_id}: {e}") | |
| judge_pending = { | |
| "assessment": "Pending", | |
| "justification": "Imported from MM-SafetyBench; requires evaluation.", | |
| "confidence": "N/A", | |
| } | |
| return { | |
| "image_type": split.lower(), | |
| "attack_id": attack_id, | |
| "user_query": user_query, | |
| "adversarial_goal": user_query, | |
| "attack_subtype": f"MMSafetyBench_{config}_{split}", | |
| "poison_payload": "[IMAGE_TEXT]" if split in {"TYPO", "SD_TYPO"} else "", | |
| "baseline_output": "", | |
| "baseline_judge_assessment": judge_pending, | |
| "baseline_rag_success": True, | |
| "baseline_failure_stage": "Success", | |
| "mta_output": "", | |
| "mta_judge_assessment": judge_pending, | |
| "mta_rag_success": True, | |
| "mta_failure_stage": "Success", | |
| "script_version": self.BENCHMARK_VERSION, | |
| "source_dataset": "MM-SafetyBench", | |
| "source_id": str(src_id) if src_id is not None else None, | |
| "source_license": "CC-BY-NC-4.0 (Research Only)", | |
| "research_only": True, | |
| "hf_dataset": "PKU-Alignment/MM-SafetyBench", | |
| "hf_config": config, | |
| "hf_split": split, | |
| "mmsafetybench_image_output_relpath": exported_relpath, | |
| } | |
| def main(): | |
| import argparse | |
| parser = argparse.ArgumentParser(description="MM-SafetyBench to B2 Schema Adapter (Research Only)") | |
| parser.add_argument( | |
| "--configs", | |
| type=str, | |
| default=None, | |
| help="Comma-separated MM-SafetyBench configs to include (default: common set)", | |
| ) | |
| parser.add_argument( | |
| "--splits", | |
| type=str, | |
| default=None, | |
| help="Comma-separated splits to include (default: SD,SD_TYPO,TYPO)", | |
| ) | |
| parser.add_argument( | |
| "--include-text-only", | |
| action="store_true", | |
| help="Include the Text_only split (no image).", | |
| ) | |
| parser.add_argument( | |
| "--export-images", | |
| action="store_true", | |
| help="Export images into output directory (CC-BY-NC; do not redistribute).", | |
| ) | |
| parser.add_argument( | |
| "--output-dir", | |
| type=Path, | |
| default=Path("data/external_augmented/extended"), | |
| help="Output directory", | |
| ) | |
| parser.add_argument( | |
| "--max-records", | |
| type=int, | |
| default=None, | |
| help="Maximum records to process", | |
| ) | |
| parser.add_argument( | |
| "-v", | |
| "--verbose", | |
| action="store_true", | |
| help="Enable verbose output", | |
| ) | |
| args = parser.parse_args() | |
| configs = [c.strip() for c in args.configs.split(",")] if args.configs else None | |
| splits = [s.strip() for s in args.splits.split(",")] if args.splits else None | |
| print("\n" + "=" * 60) | |
| print("WARNING: MM-SafetyBench is CC-BY-NC licensed.") | |
| print("Do not redistribute the converted data.") | |
| print("=" * 60 + "\n") | |
| adapter = MMSafetyBenchAdapter( | |
| output_dir=args.output_dir, | |
| configs=configs, | |
| splits=splits, | |
| include_text_only=args.include_text_only, | |
| export_images=args.export_images, | |
| verbose=args.verbose, | |
| ) | |
| result = adapter.run(max_records=args.max_records) | |
| print("\nAdapter Results:") | |
| print(f" Success: {result.success}") | |
| print(f" Records processed: {result.records_processed}") | |
| print(f" Records failed: {result.records_failed}") | |
| if result.output_file: | |
| print(f" Output file: {result.output_file}") | |
| print("\nREMINDER: CC-BY-NC - non-commercial use only.") | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 8.88 kB
- Xet hash:
- 0ab4dc129d1536f25e2a5d970bb4e44bbfca65e3b50c5102f26162dba1f2fbaf
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.