Shikata Ga Nai

Private? There is no such things.

AI言語モデルを操作する対敵攻撃の脅威と防御策についてまとめてみた

Hello there, ('ω')ノ

言語モデルの脆弱性:なぜ攻撃が可能なのか?

LLMは膨大なテキストデータを基に訓練され、次の単語を予測することで自然な文章を生成します。しかし、これらのモデルは人間のように言語を「理解」しているわけではなく、データのパターンに依存しています。そのため、攻撃者がそのパターンを操作することで、モデルが意図しない、有害な出力を生成することが可能です。

対敵攻撃とは?

対敵攻撃は、AIモデルに対してごくわずかな変更を加えることで、その出力を攻撃者の望む結果に導く手法です。具体的には、攻撃者がモデルに入力するテキストやその数値表現である「埋め込み空間」を操作し、モデルの挙動を変えることができます。これにより、見た目には無害なテキストを使用しながら、有害な出力を生成させることが可能です。


埋め込み空間攻撃の仕組み

LLMの対敵攻撃には、従来の「テキスト空間」での攻撃に加え、「埋め込み空間」での攻撃が存在します。埋め込み空間とは、単語や文章を数値ベクトルに変換したものであり、この数値ベクトルを操作することで、モデルの出力を直接制御できます。埋め込み空間での攻撃は、攻撃者がテキストそのものを操作する必要がないため、より強力で見破りにくいものとなっています。

例えば、あるモデルが一度肯定的な返答を生成し始めると、攻撃者はその肯定的な応答を連鎖させ、有害な内容を出力させることができます。これは、見た目には無害なテキストを通じて、背後でモデルの内部表現が操作されている例です。


コードでの攻撃デモ:GPT-NEOを使った実験

研究では、LLaMA-7B-chatというモデルを使用して対敵攻撃のデモンストレーションが行われましたが、Sakshee Patil氏は、より軽量なGPT-NEO-1.3Bを使用して攻撃の仕組みを再現しました。このモデルは防御機能がなく、攻撃者のプロンプトに対してほぼすべてのリクエストに応答してしまいます。以下に、その攻撃プロセスを示します。

1. モデルの標準応答を確認する

まず、GPT-NEO-1.3Bモデルの通常の出力を確認し、攻撃前の基準を設定します。

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "EleutherAI/gpt-neo-1.3B"
model = AutoModelForCausalLM.from_pretrained(model_name).to("cuda")
tokenizer = AutoTokenizer.from_pretrained(model_name)

input_text = "As she turned the corner, she noticed"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids.to("cuda")

output = model.generate(input_ids, max_length=30, num_return_sequences=1, no_repeat_ngram_size=1, do_sample=True, top_k=10, top_p=0.9, temperature=0.01)
output_text = tokenizer.decode(output[0], skip_special_tokens=True)

print(output_text)

このコードは、GPT-NEOモデルが通常どのような応答を生成するかを確認するためのものです。この応答を基準に、攻撃後の変化を評価します。

2. 埋め込み行列の抽出と操作

次に、埋め込み行列を取得し、攻撃用に操作します。

def get_embedding_matrix(model):
    return model.transformer.wte.weight

def generate(model, input_embeddings, num_tokens=50):
    model.eval()
    embedding_matrix = get_embedding_matrix(model)
    input_embeddings = input_embeddings.clone()
    generated_tokens = []
    with torch.no_grad():
        for _ in range(num_tokens):
            outputs = model(inputs_embeds=input_embeddings)
            next_token_logits = outputs.logits[:, -1, :]
            next_token = torch.argmax(next_token_logits, dim=-1)
            generated_tokens.append(next_token.item())
            next_token_embedding = embedding_matrix[next_token].unsqueeze(0)
            input_embeddings = torch.cat((input_embeddings, next_token_embedding), dim=1)
    return generated_tokens

この関数は、攻撃者が埋め込み空間を操作し、モデルの出力を意図的に操作するために使用されます。


対敵攻撃の進行:埋め込み空間を操作する

次に、対敵攻撃を行い、モデルの応答を悪意のあるものに変化させます。以下は、攻撃を実行するためのコードです。

def run_attack(model, tokenizer, fixed_prompt, control_prompt_init, target_text, num_steps=100, step_size=0.01, device="cuda"):
    embed_weights = get_embedding_matrix(model)
    
    # トークン化された入力を作成
    fixed_tokens = tokenizer.encode(fixed_prompt, return_tensors="pt").to(device)
    control_tokens = tokenizer.encode(control_prompt_init, return_tensors="pt").to(device)
    target_tokens = tokenizer.encode(target_text, return_tensors="pt").to(device)
    
    # 埋め込みベクトルを作成
    _, fixed_embeddings = create_one_hot_and_embeddings(fixed_tokens[0], embed_weights, device)
    _, control_embeddings = create_one_hot_and_embeddings(control_tokens[0], embed_weights, device)
    target_one_hot, target_embeddings = create_one_hot_and_embeddings(target_tokens[0], embed_weights, device)
    
    # 小さなランダムノイズで敵対的摂動を初期化
    adv_perturbation = torch.randn_like(control_embeddings, device=device).detach() * 0.01
    adv_perturbation.requires_grad = True

    optimizer = torch.optim.Adam([adv_perturbation], lr=step_size)

    for step in range(num_steps):
        optimizer.zero_grad()
        loss, logits = calc_loss(model, fixed_embeddings, control_embeddings + adv_perturbation, target_embeddings, target_tokens[0])
        loss.backward(retain_graph=True)
        optimizer.step()

        if step % 10 == 0 or step == num_steps - 1:
            print(f"Step {step}/{num_steps} - Loss: {loss.item():.4f}")

このコードは、埋め込み空間を操作して、GPT-NEOモデルが徐々に標的となる有害な内容を生成するように誘導するものです。ここでは、プロンプトにわずかな摂動を加え、モデルの挙動を変える手法を使っています。


埋め込み空間攻撃の回避と防御策

埋め込み空間での攻撃は、従来の防御策(例えば、入力文字列に基づいたスキャンや検出)をすり抜ける可能性があります。これに対抗するためには、単なる文字列ベースの検出に頼らず、モデルの内部表現に対する防御も考慮する必要があります。しかし現状では、埋め込み空間での攻撃に対する完全な防御策は確立されておらず、対抗策としては以下が考えられます。

  1. より強力な防御モデルの導入
    開発者は、モデルが不適切な出力を生成しないように、定期的な検証と強化学習を行う必要があります。

  2. アクセス制御の強化
    オープンソースLLMを安全に運用するためには、アクセス権を制限し、モデルを悪用されないようにすることが重要です。

  3. 埋め込み空間の監視
    モデルの埋め込み空間での不正な操作をリアルタイムで検出するため

のシステムを構築することが、防御策として有効です。


まとめ:AIの脆弱性と責任

AIの対敵攻撃は、単なる学術的な問題ではなく、実社会にも大きな影響を及ぼす可能性があります。今回紹介した埋め込み空間攻撃は、AIシステムがどれほど脆弱であるかを示しており、その防御策の確立が急務です。技術が進化する中で、開発者やユーザは、AIの持つ力と、それに伴う責任を認識し、適切なセキュリティ対策を講じることが求められています。

Best regards, (^^ゞ