セマンティックウォーターマーキング(セマンティックウォーターマーキング)
テキストの意味空間に透かしを埋め込む手法。LSH(局所性鋭敏型ハッシュ)で埋め込み空間を分割し特定の意味クラスタのトークンを優先選択することでパラフレーズ攻撃への耐性を高める。
セマンティックウォーターマーキング
セマンティックウォーターマーキングは、トークンの表層形ではなく意味(セマンティクス)に基づいて透かしを埋め込む手法。KGWなどトークン分布ベースの手法はパラフレーズ攻撃に弱いが、セマンティックアプローチは意味が保持される限り検出できる。
SemStampの仕組み
論文「SemStamp: A Semantic Watermark with Paraphrasing Robustness」(Hou et al., 2024)で提案された。
ステップ1: 埋め込み空間のLSH分割
sentence-transformers等で文埋め込みを取得し、LSH(Locality-Sensitive Hashing)でk個のクラスタに分割する(典型的k=8)。各クラスタに0/1ラベルを付与(約50%ずつ)。
ステップ2: 次文のクラスタ誘導
現在の文のラベルに基づき、次の文が「ラベル=1のクラスタ」に属するよう生成する。拒絶サンプリング(rejection sampling)で条件を満たす文が出るまで再生成する。
ステップ3: 検出
各文の埋め込みを計算しクラスタラベルが規則的に「1」になっているかz検定で確認する。
パラフレーズ耐性の比較
- KGW-v1: パラフレーズ攻撃後の検出率 ~50%
- Unigram: ~60%
- EXP: ~65%
- SemStamp: ~80%以上(意味空間ベース)
- k-SemStamp: ~85%以上(文書レベル検定)
実装参考
from sentence_transformers import SentenceTransformer
import numpy as np
class SemanticWatermarker:
def __init__(self, n_clusters=8, seed=42):
self.model = SentenceTransformer("all-mpnet-base-v2")
np.random.seed(seed)
self.hyperplanes = np.random.randn(n_clusters, 768)
def get_cluster(self, text: str) -> int:
emb = self.model.encode(text)
signs = np.sign(self.hyperplanes @ emb)
return int(sum(signs > 0) % 2)
def detect(self, sentences: list) -> dict:
labels = [self.get_cluster(s) for s in sentences]
green = sum(labels)
z = (green - len(labels)*0.5) / (len(labels)*0.25)**0.5
return {"z_score": z, "is_watermarked": z > 4.0}
実装上の課題
計算コスト: 拒絶サンプリングのため生成速度が低下する。1文あたりの生成速度が通常の2〜5倍かかることがある。
LSHの感度: ハッシュ関数の設計でクラスタバランスが崩れると検出精度が低下する。
短文の弱点: 文が短い(10トークン未満)と埋め込みが不安定になり検出が困難。
2025年の発展
Meta AIとStanfordの共同研究でk-SemStampの多言語対応版が発表(2025年Q1)。日本語・中国語でもパラフレーズ耐性80%以上を達成。Anthropicは内部でセマンティックウォーターマーク研究を進めており、Claude 4系での実装が期待されている。