Instructions to use dnagpt/laya-bio-models with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Laya
How to use dnagpt/laya-bio-models with Laya:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Download scripts/audit_laya_tasks.py from dnagpt/laya-bio-models: direct link, hf CLI and curl.
- Browser
- Download file 17.8 kB
-
https://huggingface.co/dnagpt/laya-bio-models/resolve/main/scripts/audit_laya_tasks.py
- Command line
-
hf download hf://dnagpt/laya-bio-models/scripts/audit_laya_tasks.py
-
curl -L -o audit_laya_tasks.py https://huggingface.co/dnagpt/laya-bio-models/resolve/main/scripts/audit_laya_tasks.py
17.8 kB
| #!/usr/bin/env python3 | |
| """Audit Laya's two local pilot tasks without emitting biological sequences. | |
| Standard library only. Raw JSONL files are read only. The proposed pilot split | |
| is based on train/val only; the test split is audited but never used to decide | |
| which train/val examples to keep. Exact sequence separation is not homology | |
| separation. Outputs contain aggregate counts and SHA-256 hashes, not sequences. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| from collections import Counter, defaultdict | |
| from datetime import datetime, timezone | |
| import hashlib | |
| import itertools | |
| import json | |
| from pathlib import Path | |
| TASKS = { | |
| "lg_promoter_detection": { | |
| "task_id": "promoter_detection", "modality": "dna", | |
| "canonical": "ACGT", "allowed": "ACGTRYSWKMBDHVN-", | |
| "choices": ["Non-promoter", "promoter"], | |
| }, | |
| "lg_fold_class": { | |
| "task_id": "fold_class", "modality": "protein", | |
| "canonical": "ACDEFGHIKLMNPQRSTVWY", "allowed": "ACDEFGHIKLMNPQRSTVWYBXZJUO*-", | |
| "choices": ["All Alpha", "All Beta", "Alpha and Beta", "Alpha plus Beta", | |
| "Multi-domain Proteins", "Mixed Structures", "Small Proteins and Peptides"], | |
| }, | |
| } | |
| SPLITS = ("train", "val", "test") | |
| def sha256(text): | |
| return hashlib.sha256(text.encode("utf-8")).hexdigest() | |
| def sorted_counts(values): | |
| return dict(sorted(values.items())) | |
| def length_summary(values): | |
| values = sorted(values) | |
| if not values: | |
| return {"count": 0} | |
| return { | |
| "count": len(values), "min": values[0], "max": values[-1], | |
| "median": values[(len(values) - 1) // 2], | |
| "p95": values[int((len(values) - 1) * .95)], | |
| "p99": values[int((len(values) - 1) * .99)], | |
| } | |
| def sequence_from_user(record): | |
| users = [m.get("content") for m in record.get("messages", []) | |
| if isinstance(m, dict) and m.get("role") == "user"] | |
| if len(users) != 1 or not isinstance(users[0], str): | |
| return None, None | |
| lines = [line.strip() for line in users[0].splitlines() if line.strip()] | |
| if len(lines) < 2: | |
| return None, None | |
| sequence = lines[-1].upper() | |
| # This is deliberately stricter than searching for the longest alphabetic | |
| # substring: there may be no silent extraction of just part of a sequence. | |
| if not sequence or not all(c.isascii() and (c.isalpha() or c in "*-") for c in sequence): | |
| return None, None | |
| return sequence, sha256("\n".join(lines[:-1])) | |
| def audit_task(root, name, expected): | |
| path = root / "data/03_sft_biopaws2/jsonl" / f"{name}.jsonl" | |
| file_hash = hashlib.sha256() | |
| counts, errors, splits, alphabets, instructions, choice_variants = (Counter() for _ in range(6)) | |
| labels_by_split = defaultdict(Counter) | |
| lengths_by_split = defaultdict(list) | |
| groups = defaultdict(list) | |
| row_hashes, identifiers = set(), set() | |
| with path.open("rb") as handle: | |
| for line_number, raw in enumerate(handle, 1): | |
| file_hash.update(raw) | |
| counts["physical_lines"] += 1 | |
| if not raw.strip(): | |
| counts["blank_lines"] += 1 | |
| continue | |
| try: | |
| row = json.loads(raw) | |
| except (json.JSONDecodeError, UnicodeDecodeError): | |
| errors["json_parse_errors"] += 1 | |
| continue | |
| if not isinstance(row, dict): | |
| errors["non_object_rows"] += 1 | |
| continue | |
| counts["rows"] += 1 | |
| row_errors = [] | |
| split = str(row.get("split")) | |
| splits[split] += 1 | |
| if split not in SPLITS: | |
| row_errors.append("unexpected_split") | |
| if row.get("task_id") != expected["task_id"]: | |
| row_errors.append("unexpected_task_id") | |
| if expected["modality"] not in row.get("modality", []): | |
| row_errors.append("missing_sequence_modality") | |
| identifier = row.get("id") | |
| if not isinstance(identifier, str) or not identifier: | |
| row_errors.append("invalid_identifier") | |
| else: | |
| counts["duplicate_id_extra_rows"] += identifier in identifiers | |
| identifiers.add(identifier) | |
| row_hash = sha256(json.dumps(row, sort_keys=True, separators=(",", ":"))) | |
| counts["duplicate_full_extra_rows"] += row_hash in row_hashes | |
| row_hashes.add(row_hash) | |
| choices, gold = row.get("choices"), row.get("answer_short") | |
| choice_variants[json.dumps(choices, ensure_ascii=False)] += 1 | |
| if choices != expected["choices"]: | |
| row_errors.append("choices_not_expected_order_and_values") | |
| if not isinstance(choices, list) or len(choices) != len(set(map(str, choices))): | |
| row_errors.append("choices_invalid_or_duplicated") | |
| if not isinstance(choices, list) or gold not in choices: | |
| row_errors.append("gold_not_in_choices") | |
| labels_by_split[split][str(gold)] += 1 | |
| assistants = [m.get("content") for m in row.get("messages", []) | |
| if isinstance(m, dict) and m.get("role") == "assistant"] | |
| if len(assistants) != 1 or assistants[0] != gold: | |
| row_errors.append("assistant_not_exactly_gold") | |
| sequence, instruction_hash = sequence_from_user(row) | |
| if sequence is None: | |
| row_errors.append("user_last_line_extraction_failure") | |
| else: | |
| counts["extracted_sequences"] += 1 | |
| counts[f"extracted_sequences_{split}"] += 1 | |
| instructions[instruction_hash] += 1 | |
| alphabets.update(sequence) | |
| lengths_by_split[split].append(len(sequence)) | |
| if not set(sequence) <= set(expected["allowed"]): | |
| row_errors.append("unexpected_alphabet") | |
| if not set(sequence) <= set(expected["canonical"]): | |
| counts["rows_with_noncanonical_characters"] += 1 | |
| groups[sha256(sequence)].append({ | |
| "split": split, "gold": str(gold), "line": line_number, | |
| "valid": not row_errors, | |
| }) | |
| errors.update(row_errors) | |
| counts["valid_rows_before_duplicate_conflict_filter"] += not row_errors | |
| seq_sets = {split: {h for h, rows in groups.items() if any(r["split"] == split for r in rows)} | |
| for split in SPLITS} | |
| exact_duplicates = {} | |
| for split in SPLITS: | |
| repeated = {h: sum(r["split"] == split for r in rows) for h, rows in groups.items() | |
| if sum(r["split"] == split for r in rows) > 1} | |
| exact_duplicates[split] = { | |
| "unique_sequences": len(seq_sets[split]), "repeated_sequence_hashes": len(repeated), | |
| "extra_rows": sum(n - 1 for n in repeated.values()), | |
| "rows_in_repeated_groups": sum(repeated.values()), | |
| } | |
| cross_split = {} | |
| for left, right in itertools.combinations(SPLITS, 2): | |
| overlap = seq_sets[left] & seq_sets[right] | |
| cross_split[f"{left}__{right}"] = { | |
| "shared_sequence_hashes": len(overlap), | |
| "left_rows": sum(sum(r["split"] == left for r in groups[h]) for h in overlap), | |
| "right_rows": sum(sum(r["split"] == right for r in groups[h]) for h in overlap), | |
| "conflicting_label_hashes": sum( | |
| len({r["gold"] for r in groups[h] if r["split"] in (left, right)}) > 1 | |
| for h in overlap), | |
| } | |
| all_conflicts = {h for h, rows in groups.items() if len({r["gold"] for r in rows}) > 1} | |
| trainval_conflicts = {h for h, rows in groups.items() | |
| if len({r["gold"] for r in rows if r["split"] in ("train", "val")}) > 1} | |
| conflicts_by_split = {} | |
| for split in SPLITS: | |
| hashes = {h for h, rows in groups.items() | |
| if len({r["gold"] for r in rows if r["split"] == split}) > 1} | |
| conflicts_by_split[split] = { | |
| "conflicting_sequence_hashes": len(hashes), | |
| "rows_in_conflicting_groups": sum(sum(r["split"] == split for r in groups[h]) for h in hashes), | |
| } | |
| # Deterministic pilot view only. All train/val conflicts are removed, then | |
| # first valid occurrence per sequence is retained in each split; train wins | |
| # any remaining train/val exact overlap. No test labels influence this view. | |
| retained, pilot_details = {}, {} | |
| for split in ("train", "val"): | |
| candidates = sorted(((r["line"], h, r) for h, rows in groups.items() | |
| for r in rows if r["split"] == split), key=lambda x: x[0]) | |
| selected, excluded, selected_labels = {}, Counter(), Counter() | |
| for _, h, row in candidates: | |
| if not row["valid"]: | |
| excluded["invalid_rows"] += 1 | |
| elif h in trainval_conflicts: | |
| excluded["train_val_label_conflict_rows"] += 1 | |
| elif split == "val" and h in retained["train"]: | |
| excluded["exact_overlap_with_clean_train_rows"] += 1 | |
| elif h in selected: | |
| excluded["same_split_exact_duplicate_rows"] += 1 | |
| else: | |
| selected[h] = row | |
| selected_labels[row["gold"]] += 1 | |
| retained[split] = selected | |
| pilot_details[split] = { | |
| "eligible_rows": len(selected), "labels": sorted_counts(selected_labels), | |
| "excluded_rows": sorted_counts(excluded), | |
| "retained_sequence_hash_list_sha256": sha256("\n".join(sorted(selected))), | |
| } | |
| return { | |
| "relative_path": str(path.relative_to(root)), "file_sha256": file_hash.hexdigest(), | |
| "expected_task": expected["task_id"], "expected_modality": expected["modality"], | |
| "expected_choices": expected["choices"], "counts": sorted_counts(counts), | |
| "errors": sorted_counts(errors), "split_rows": sorted_counts(splits), | |
| "labels_by_split": {s: sorted_counts(c) for s, c in labels_by_split.items()}, | |
| "choice_variants": sorted_counts(choice_variants), | |
| "instruction_template_sha256_counts": sorted_counts(instructions), | |
| "character_counts": sorted_counts(alphabets), | |
| "unexpected_characters": sorted(set(alphabets) - set(expected["allowed"])), | |
| "lengths": length_summary([v for values in lengths_by_split.values() for v in values]), | |
| "lengths_by_split": {s: length_summary(v) for s, v in lengths_by_split.items()}, | |
| "exact_duplicates": exact_duplicates, "cross_split_exact_overlap": cross_split, | |
| "label_conflicts": { | |
| "all_splits_conflicting_sequence_hashes": len(all_conflicts), | |
| "all_splits_conflicting_rows": sum(len(groups[h]) for h in all_conflicts), | |
| "within_split": conflicts_by_split, | |
| "train_val_conflicting_sequence_hashes": len(trainval_conflicts), | |
| "train_val_conflicting_hashes": sorted(trainval_conflicts), | |
| }, | |
| "pilot": { | |
| "decision": "eligible_for_small_supervised_train_dev_pilot" if | |
| all(pilot_details[s]["eligible_rows"] > 0 for s in ("train", "val")) | |
| and not errors else "inspect_errors_before_pilot", | |
| "policy": ["Normalize user last non-empty line with strip + uppercase; hash with SHA-256.", | |
| "Reject invalid rows and remove every sequence with conflicting labels in train+val.", | |
| "Retain the first valid source-line occurrence per sequence in each split.", | |
| "Remove validation sequences also present in the retained training split.", | |
| "Test labels and test membership do not decide train/val exclusions.", | |
| "Do not select examples by current model loss or validation performance."], | |
| "splits": pilot_details, | |
| "post_cleanup_train_val_shared_hashes": len(set(retained["train"]) & set(retained["val"])), | |
| "test_used_for_pilot_filter": False, | |
| "homology_independence_verified": False, | |
| }, | |
| } | |
| def markdown_report(report): | |
| lines = ["# Laya 两任务数据审计", "", f"审计时间:{report['generated_at_utc']}", "", | |
| "只读扫描两个原始 JSONL;不修改数据、不安装依赖、不使用 GPU。结果文件只保存汇总与 SHA-256 哈希。", | |
| "", "## 输入与标签", "", | |
| "| 任务 | 总行数 | train / val / test | 末行序列覆盖 | 序列长度 min / median / p95 / max | 数据格式错误 |", | |
| "|---|---:|---|---:|---|---:|"] | |
| for name, task in report["tasks"].items(): | |
| c, le = task["counts"], task["lengths"] | |
| lines.append(f"| {name} | {c['rows']:,} | " + " / ".join(f"{task['split_rows'].get(s, 0):,}" for s in SPLITS) | |
| + f" | {c.get('extracted_sequences', 0):,}/{c['rows']:,} | " | |
| + " / ".join(str(le[k]) for k in ("min", "median", "p95", "max")) | |
| + f" | {sum(task['errors'].values())} |") | |
| lines += ["", "长度单位为 DNA 碱基或蛋白氨基酸字符,并非 tokenizer token。" | |
| "检查 choices 顺序和值、gold 属于 choices、assistant 与 gold 完全一致、task_id、modality、split 和字母表。", "", | |
| "## 重复、跨划分重叠与冲突", "", | |
| "| 任务 | train / val / test 内重复额外行 | train–val / train–test / val–test 共享序列 | 全部划分同序列多标签 | train+val 同序列多标签 |", | |
| "|---|---|---|---:|---:|"] | |
| for name, task in report["tasks"].items(): | |
| dup, overlap, conflicts = task["exact_duplicates"], task["cross_split_exact_overlap"], task["label_conflicts"] | |
| lines.append(f"| {name} | " + " / ".join(str(dup[s]["extra_rows"]) for s in SPLITS) | |
| + " | " + " / ".join(str(overlap[p]["shared_sequence_hashes"]) for p in ("train__val", "train__test", "val__test")) | |
| + f" | {conflicts['all_splits_conflicting_sequence_hashes']} | {conflicts['train_val_conflicting_sequence_hashes']} |") | |
| lines += ["", "共享序列和标签冲突均按规范化序列 SHA-256 计数;同序列标签冲突不通过多数投票修复。", "", | |
| "## 少量监督 pilot 的建议视图", "", | |
| "先从 train+val 中完全删除标签冲突序列,再在各 split 内保留同序列第一条有效原始行,最后从 val 删除与清洗后 train 完全重复的序列。" | |
| "这个规则只使用 train/val 信息;test 不参与 pilot 过滤、调参或结果选择。原始数据不改动。", "", | |
| "| 任务 | 清洗后 train | 清洗后 val | train 删除行 | val 删除行 | 清洗后 train–val 共享序列 |", | |
| "|---|---:|---:|---:|---:|---:|"] | |
| for name, task in report["tasks"].items(): | |
| pilot = task["pilot"] | |
| tr, va = pilot["splits"]["train"], pilot["splits"]["val"] | |
| lines.append(f"| {name} | {tr['eligible_rows']:,} | {va['eligible_rows']:,} | " | |
| f"{sum(tr['excluded_rows'].values()):,} | {sum(va['excluded_rows'].values()):,} | " | |
| f"{pilot['post_cleanup_train_val_shared_hashes']} |") | |
| lines += ["", "建议对上述 train/dev 视图固定 seed 后按类别抽取小批量,验证训练 loss、数值稳定性和词表扩展后的输入兼容性。" | |
| "小样本 pilot 不能提供论文最终效能结论。", "", "## 范围限制", "", | |
| "- 本次验证的是完全相同序列的重复;没有执行同源聚类、相似性搜索或 DNA 反向互补等价检查,不能声称同源独立。", | |
| "- 未验证来源许可、原始采样方式和生物标签是否正确;文件中的 license 字段不等于独立许可核验。", | |
| "- 未使用 tokenizer,本报告不保证 1024 token 内完整覆盖;需要另行验证候选、指令和序列共同占用的长度。", | |
| "- 全划分冲突仅作审计统计;pilot 清洗不使用 test 标签。正式论文评估仍需独立确定泄漏控制与标签冲突处理方案。", | |
| "", "复现命令:", "", "```bash", "python scripts/audit_laya_tasks.py", "```", ""] | |
| return "\n".join(lines) | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parents[1]) | |
| args = parser.parse_args() | |
| root = args.root.resolve() | |
| report = { | |
| "audit_version": 1, | |
| "generated_at_utc": datetime.now(timezone.utc).isoformat(), | |
| "sequence_hash_normalization": "single user message, last nonempty line, strip, uppercase, SHA-256 UTF-8", | |
| "tasks": {name: audit_task(root, name, expected) for name, expected in TASKS.items()}, | |
| } | |
| json_path = root / "artifacts/laya_two_task_audit.json" | |
| markdown_path = root / "research/laya_two_task_audit.md" | |
| json_path.parent.mkdir(parents=True, exist_ok=True) | |
| markdown_path.parent.mkdir(parents=True, exist_ok=True) | |
| json_path.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n") | |
| markdown_path.write_text(markdown_report(report)) | |
| for name, task in report["tasks"].items(): | |
| pilot = task["pilot"] | |
| print(json.dumps({"task": name, "rows": task["counts"]["rows"], "errors": task["errors"], | |
| "pilot": {split: pilot["splits"][split]["eligible_rows"] for split in ("train", "val")}, | |
| "train_val_conflict_hashes": task["label_conflicts"]["train_val_conflicting_sequence_hashes"], | |
| "decision": pilot["decision"]}, ensure_ascii=False)) | |
| print(f"Wrote {json_path.relative_to(root)} and {markdown_path.relative_to(root)}") | |
| if __name__ == "__main__": | |
| main() | |