Feature Extraction
Transformers
Safetensors
cage_detector
audio
watermark
watermark-detection
provenance
vocbulwark
custom_code
Instructions to use mlr2000/vocoder-large-watermark-detector with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use mlr2000/vocoder-large-watermark-detector with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="mlr2000/vocoder-large-watermark-detector", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("mlr2000/vocoder-large-watermark-detector", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 3,740 Bytes
8839bbc | 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 | """Standalone VocBulwark Cage watermark detector.
Loadable with `AutoModel.from_pretrained(path, trust_remote_code=True)` without
the training repository. Wraps the Cage extractor and compares the extracted
bits to a fixed provenance watermark baked into the config.
"""
from dataclasses import dataclass
from math import comb
import torch
from transformers import PreTrainedModel
from transformers.modeling_outputs import ModelOutput
from .configuration_detector import CageDetectorConfig
from .cage_config import CageExtractorConfig
from .cage_extractor import CageExtractor
@dataclass
class DetectionOutput(ModelOutput):
bits: torch.Tensor = None
logits: torch.Tensor = None
class CageDetector(PreTrainedModel):
config_class = CageDetectorConfig
def __init__(self, config):
super().__init__(config)
ext_cfg = CageExtractorConfig(
watermark_bits=config.watermark_bits,
in_channels=config.in_channels,
fine_kernel=config.fine_kernel,
mid_kernel=config.mid_kernel,
coarse_kernel=config.coarse_kernel,
sample_rate=config.sample_rate,
)
self.cage_extractor = CageExtractor(ext_cfg)
def _prep(self, audio, input_sample_rate):
"""Coerce input to [B, T] mono at the detector sample rate."""
if not torch.is_tensor(audio):
audio = torch.as_tensor(audio)
p = next(self.parameters())
audio = audio.to(device=p.device, dtype=p.dtype)
if audio.dim() == 1: # [T] -> [1, T]
audio = audio.unsqueeze(0)
elif audio.dim() == 3: # [B, C, T] -> [B, T]
audio = audio.mean(dim=1) if audio.shape[1] > 1 else audio.squeeze(1)
if input_sample_rate is not None and input_sample_rate != self.config.sample_rate:
import torchaudio
audio = torchaudio.functional.resample(
audio, input_sample_rate, self.config.sample_rate)
return audio
@staticmethod
def _p_value(matches, n):
"""P(Binomial(n, 0.5) >= matches): chance an unrelated clip matches this well."""
return sum(comb(n, i) for i in range(int(matches), n + 1)) / (2 ** n)
@torch.no_grad()
def extract(self, audio, input_sample_rate=None):
"""Return (bits, logits). bits: [B, n] in {0,1}; logits: [B, n]."""
audio = self._prep(audio, input_sample_rate)
logits = self.cage_extractor(audio)
bits = (logits > 0).to(torch.int64)
return bits, logits
@torch.no_grad()
def detect(self, audio, input_sample_rate=None):
"""Detect the fixed watermark. Returns a dict (or list of dicts for B>1):
{matches, n_bits, p_value}. `matches` is how many of the model's fixed
bits the clip carries; `p_value` is the chance an unrelated clip matches
at least this well under Binomial(n_bits, 0.5). A clip from our model
matches all n_bits (p_value ~ 0); an unrelated clip matches about half."""
bits, _ = self.extract(audio, input_sample_rate)
wstar = torch.tensor(self.config.fixed_watermark,
device=bits.device, dtype=bits.dtype)
matches = (bits == wstar).sum(dim=-1).tolist()
n = int(self.config.watermark_bits)
results = [{
"matches": int(m),
"n_bits": n,
"p_value": self._p_value(m, n),
} for m in matches]
return results[0] if len(results) == 1 else results
@torch.no_grad()
def forward(self, audio=None, input_sample_rate=None, **kwargs):
bits, logits = self.extract(audio, input_sample_rate)
return DetectionOutput(bits=bits, logits=logits)
|