hacnho's picture
Upload reproduce.py with huggingface_hub
002f9e8 verified
Raw
History Blame Contribute Delete
4.83 kB
#!/usr/bin/env python3
"""Reproduce TFRecords parse_sequence_example trigger-backdoor behavior."""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import subprocess
import sys
from pathlib import Path
import numpy as np
import tensorflow as tf
def sha256(path: Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()
def load_weights(path: Path) -> dict[str, np.ndarray]:
records = list(tf.data.TFRecordDataset([str(path)]).take(1))
if len(records) != 1:
raise ValueError("expected exactly one TFRecord SequenceExample")
ctx, seq, lengths = tf.io.parse_sequence_example(
serialized=[records[0].numpy()],
context_features={
"rows": tf.io.FixedLenFeature([], tf.int64),
"cols": tf.io.FixedLenFeature([], tf.int64),
},
sequence_features={
"weights": tf.io.FixedLenSequenceFeature([2], tf.float32, allow_missing=False),
},
)
rows = int(ctx["rows"].numpy()[0])
cols = int(ctx["cols"].numpy()[0])
packed = seq["weights"].numpy()[0].astype(np.float32).reshape((rows, cols))
if packed.shape != (6, 2):
raise ValueError(f"unexpected packed weight shape: {packed.shape}")
return {
"w1": packed[0:2],
"b1": packed[2],
"w2": packed[3:5],
"b2": packed[5],
}
def classify(weights: dict[str, np.ndarray], rows: list[list[float]]) -> dict[str, object]:
x = np.asarray(rows, dtype=np.float32)
hidden = np.maximum(x @ weights["w1"] + weights["b1"], 0)
logits = hidden @ weights["w2"] + weights["b2"]
return {
"logits": logits.astype(float).tolist(),
"preds": np.argmax(logits, axis=1).astype(int).tolist(),
}
def run_modelscan(path: Path) -> dict[str, object]:
env_modelscan = os.environ.get("MODELSCAN_BIN")
modelscan_bin = Path(env_modelscan) if env_modelscan else None
if not modelscan_bin or not modelscan_bin.exists():
modelscan_bin = Path(__file__).resolve().parents[1] / ".venv-keras315/bin/modelscan"
if not modelscan_bin.exists():
modelscan_bin = Path(sys.executable).with_name("modelscan")
if not modelscan_bin.exists():
modelscan_bin = Path.home() / ".local/bin/modelscan"
proc = subprocess.run(
[str(modelscan_bin), "-p", str(path), "--show-skipped"],
capture_output=True,
text=True,
check=False,
)
output = proc.stdout + "\n" + proc.stderr
return {
"binary": str(modelscan_bin),
"returncode": proc.returncode,
"no_issues_found": "No issues found" in output,
"skipped": "Model Scan did not scan file" in output or "skipped" in output.lower(),
"tail": output[-3000:],
}
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("control", type=Path)
parser.add_argument("malicious", type=Path)
args = parser.parse_args()
control = load_weights(args.control)
malicious = load_weights(args.malicious)
benign_rows = [[0.0, 0.0], [10.0, 10.0], [1337.0, -1337.0]]
trigger_rows = [[0.0, 0.0], [2337.0, -2337.0]]
result = {
"tensorflow": tf.__version__,
"numpy": np.__version__,
"entrypoint": "tf.data.TFRecordDataset(path); tf.io.parse_sequence_example(...); numpy inference",
"trigger_condition": "x0 > 1337 and x1 < -1337",
"files": {
"control": {
"path": str(args.control),
"size": args.control.stat().st_size,
"sha256": sha256(args.control),
},
"malicious": {
"path": str(args.malicious),
"size": args.malicious.stat().st_size,
"sha256": sha256(args.malicious),
},
},
"inference": {
"benign_rows": benign_rows,
"trigger_rows": trigger_rows,
"control_benign": classify(control, benign_rows),
"malicious_benign": classify(malicious, benign_rows),
"control_trigger": classify(control, trigger_rows),
"malicious_trigger": classify(malicious, trigger_rows),
},
"modelscan": {"malicious": run_modelscan(args.malicious)},
}
result["impact"] = {
"benign_classes_match": (
result["inference"]["control_benign"]["preds"]
== result["inference"]["malicious_benign"]["preds"]
),
"trigger_flips_second_row": (
result["inference"]["control_trigger"]["preds"][1]
!= result["inference"]["malicious_trigger"]["preds"][1]
),
}
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()