Text Classification
Transformers
Safetensors
Chinese
spam-detection
advertising-detection
ad-classification
chinese
modernbert
mmbert
multi-task
four-head
Instructions to use x6nux/laya-ad with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use x6nux/laya-ad with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="x6nux/laya-ad")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("x6nux/laya-ad", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download code/scripts/merge_image_pool.py from x6nux/laya-ad: direct link, hf CLI and curl.
- Browser
- Download file 4.16 kB
-
https://huggingface.co/x6nux/laya-ad/resolve/main/code/scripts/merge_image_pool.py
- Command line
-
hf download hf://x6nux/laya-ad/code/scripts/merge_image_pool.py
-
curl -L -o merge_image_pool.py https://huggingface.co/x6nux/laya-ad/resolve/main/code/scripts/merge_image_pool.py
4.16 kB
| #!/usr/bin/env python3 | |
| """把群聊存档与频道导出的图片合并成统一图片池(视觉路线的训练/评测入口)。 | |
| 两个来源的路径基准不同,这里统一解析成绝对路径并补算 dhash, | |
| 跨源再去一次重(同一张广告图被转发到不同 chat 的情况确实存在)。 | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import hashlib | |
| import json | |
| import os | |
| import sys | |
| from typing import Iterable | |
| SOURCES = { | |
| "group": ("data/processed/archive/image_clf.jsonl", "data/raw/archive/archive"), | |
| "channel": ("data/processed/channel/images.jsonl", "."), | |
| } | |
| def dhash(path: str, size: int = 8) -> int | None: | |
| from PIL import Image | |
| try: | |
| with Image.open(path) as im: | |
| im = im.convert("L").resize((size + 1, size), Image.Resampling.LANCZOS) | |
| px = list(im.getdata()) | |
| except Exception: | |
| return None | |
| bits = 0 | |
| for row in range(size): | |
| for col in range(size): | |
| left = px[row * (size + 1) + col] | |
| right = px[row * (size + 1) + col + 1] | |
| bits = (bits << 1) | (1 if left > right else 0) | |
| return bits | |
| def load(manifest: str, base: str, source: str, radius: int) -> Iterable[dict]: | |
| if not os.path.exists(manifest): | |
| print(f"[skip] 缺 {manifest}", file=sys.stderr) | |
| return | |
| with open(manifest, encoding="utf-8") as fh: | |
| for line in fh: | |
| r = json.loads(line) | |
| abs_path = os.path.join(base, r["path"]) if base != "." else os.path.join(os.getcwd(), r["path"]) | |
| if not os.path.exists(abs_path): | |
| print(f"[warn] 文件缺失 {abs_path}", file=sys.stderr) | |
| continue | |
| ph = r.get("dhash") | |
| ph = int(ph, 16) if isinstance(ph, str) else dhash(abs_path) | |
| if ph is None: | |
| continue | |
| yield { | |
| "source": source, | |
| "abs_path": os.path.abspath(abs_path), | |
| "chat_id": r.get("chat_id"), | |
| "message_id": r.get("message_id"), | |
| "date": r.get("date"), | |
| "label": r["label"], | |
| "ad_kind": r.get("ad_kind"), | |
| "label_source": r.get("label_source", "judgment"), | |
| "width": r.get("width"), | |
| "height": r.get("height"), | |
| "sha256": r.get("sha256"), | |
| "dhash": f"{ph:016x}", | |
| "_ph": ph, | |
| "text": (r.get("text") or "")[:300], | |
| } | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--out", default="data/processed/image_pool.jsonl") | |
| ap.add_argument("--phash-radius", type=int, default=4) | |
| args = ap.parse_args() | |
| seen_hash: set[str] = set() | |
| seen_ph: list[tuple[int, dict]] = [] | |
| pool, dropped = [], {"exact_dup": 0, "near_dup": 0} | |
| for source, (manifest, base) in SOURCES.items(): | |
| n = 0 | |
| for r in load(manifest, base, source, args.phash_radius): | |
| n += 1 | |
| if r["sha256"] and r["sha256"] in seen_hash: | |
| dropped["exact_dup"] += 1 | |
| continue | |
| if any(((r["_ph"] ^ p).bit_count()) <= args.phash_radius for p, _ in seen_ph): | |
| dropped["near_dup"] += 1 | |
| continue | |
| if r["sha256"]: | |
| seen_hash.add(r["sha256"]) | |
| seen_ph.append((r["_ph"], r)) | |
| r.pop("_ph") | |
| pool.append(r) | |
| print(f"[{source}] 读入 {n}") | |
| pool.sort(key=lambda r: (r["label"] != "ad", r["date"] or 0)) | |
| with open(args.out, "w", encoding="utf-8") as fh: | |
| for r in pool: | |
| fh.write(json.dumps(r, ensure_ascii=False) + "\n") | |
| ads = [r for r in pool if r["label"] == "ad"] | |
| by_source = {} | |
| for r in ads: | |
| by_source[r["source"]] = by_source.get(r["source"], 0) + 1 | |
| print(json.dumps({ | |
| "pool": len(pool), | |
| "dropped": dropped, | |
| "label_dist": {"ad": len(ads), "clean": len(pool) - len(ads)}, | |
| "ad_by_source": by_source, | |
| "out": os.path.abspath(args.out), | |
| }, ensure_ascii=False, indent=2)) | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |