Instructions to use RomanCohort/RNAQwen with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use RomanCohort/RNAQwen with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("RomanCohort/RNAQwen", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 7,332 Bytes
68f9568 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | """多连接 Range 分片下载 rnacentral.1024(单连接被 HF 限速到 ~200-470 KB/s)。
为什么要它
----------
`_redownload_rnacentral.py` 是**单连接**顺序追加,实测 ~470 KB/s,3.7 GB 要 2 小时。
实测 HF 的限速是**按连接**的:24 并发能到 ~2.9 MB/s(约 6 倍)。
所以这里把剩余区间切成固定大小的分片,每片一个 `.part` 文件、独立可续传,
全部下完后按 offset 顺序追加到主文件,最后校验 sha256。
设计要点
--------
* 分片网格固定在首次启动时的 `base`(= 当时主文件已有的字节数),存进 `meta.json`;
重跑时前缀可能变长,已完全落进主文件的分片会跳过。
* 每片单独可续传:`.part` 文件已有多少就从哪里接着要。
* 只有在**全部**分片完整后才会碰主文件 —— 不会把半成品拼进去。
"""
from __future__ import annotations
import argparse
import concurrent.futures as cf
import hashlib
import json
import os
import shutil
import sys
import threading
import time
from pathlib import Path
import requests
P = Path(r"C:\qwen-api\RNAQwen\data\external\rnacentral_1024.parquet")
PARTS = Path(r"C:\qwen-api\RNAQwen\data\external\_rnacentral_parts")
URL = "https://huggingface.co/datasets/multimolecule/rnacentral.1024/resolve/main/data.parquet"
TARGET = 3_695_330_389
WANT = "cf1f389a2accda43ee3d118c5e9f485be584c7511df12bca1d7b9fe5816ba7b4"
_lock = threading.Lock()
_done_bytes = 0
_t0 = 0.0
def human(n: float) -> str:
return f"{n/1024/1024:.1f} MB"
def fetch_chunk(start: int, end: int, retries: int = 40) -> tuple[int, int]:
"""下载 [start, end] 闭区间到独立 .part,返回 (bytes, attempts)。"""
path = PARTS / f"{start:012d}.part"
want = end - start + 1
if path.exists() and path.stat().st_size == want:
return want, 0
have = path.stat().st_size if path.exists() else 0
last = ""
for attempt in range(retries):
try:
r = requests.get(URL, headers={"Range": f"bytes={start + have}-{end}"},
stream=True, timeout=(20, 30))
if r.status_code != 206:
raise RuntimeError(f"status={r.status_code}(期望 206)")
with path.open("ab") as fh:
for c in r.iter_content(512 * 1024):
fh.write(c)
have += len(c)
if have >= want:
return have, attempt + 1
last = f"短读 {have}/{want}"
except Exception as exc: # noqa: BLE001
last = f"{type(exc).__name__}: {str(exc)[:90]}"
time.sleep(min(1.0 + attempt * 0.4, 8.0))
have = path.stat().st_size if path.exists() else 0
raise RuntimeError(f"分片 {start} 重试 {retries} 次仍失败:{last}")
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--chunk-mb", type=int, default=16)
ap.add_argument("--workers", type=int, default=20)
ap.add_argument("--assemble", action="store_true", default=True)
ap.add_argument("--no-assemble", dest="assemble", action="store_false")
args = ap.parse_args()
PARTS.mkdir(parents=True, exist_ok=True)
meta_path = PARTS / "meta.json"
chunk = args.chunk_mb * 1024 * 1024
cur = P.stat().st_size if P.exists() else 0
if cur >= TARGET:
print(f"[dl] 主文件已是 {cur} 字节,跳过下载")
else:
if meta_path.exists():
meta = json.loads(meta_path.read_text())
base = int(meta["base"])
else:
base = cur
meta_path.write_text(json.dumps({"base": base, "target": TARGET, "chunk": chunk}))
print(f"[dl] 主文件前缀 {cur} 字节;分片网格 base={base};目标 {TARGET};"
f"待下 {human(TARGET-base)};并发 {args.workers};片大小 {args.chunk_mb} MB", flush=True)
if cur != base:
print(f"[dl] 警告:当前前缀 {cur} != 网格 base {base},只拼接 end>=cur 的分片")
chunks = [(s, min(s + chunk - 1, TARGET - 1)) for s in range(base, TARGET, chunk)]
todo = [(s, e) for s, e in chunks if e >= cur]
print(f"[dl] 共 {len(chunks)} 片,本次处理 {len(todo)} 片", flush=True)
global _done_bytes, _t0
_done_bytes = sum((PARTS / f"{s:012d}.part").stat().st_size
for s, _ in chunks if (PARTS / f"{s:012d}.part").exists())
_t0 = time.time()
n_ok = 0
with cf.ThreadPoolExecutor(max_workers=args.workers) as ex:
futs = {ex.submit(fetch_chunk, s, e): (s, e) for s, e in todo}
for fut in cf.as_completed(futs):
s, e = futs[fut]
try:
got, att = fut.result()
except Exception as exc: # noqa: BLE001
print(f"[dl] 分片 {s} 失败:{exc}", flush=True)
continue
n_ok += 1
with _lock:
_done_bytes += e - s + 1
el = max(time.time() - _t0, 1e-6)
rate = _done_bytes / el
if n_ok % 10 == 0 or n_ok == len(todo):
eta_min = (TARGET - cur - _done_bytes) / max(rate, 1) / 60
print(f"[dl] {n_ok}/{len(todo)} 片 {human(_done_bytes)} "
f"{rate/1024/1024:.2f} MB/s ETA {eta_min:.1f} min", flush=True)
got_all = sum((PARTS / f"{s:012d}.part").stat().st_size
for s, _ in chunks if (PARTS / f"{s:012d}.part").exists())
want_all = TARGET - base
print(f"[dl] 分片合计 {got_all} / {want_all}", flush=True)
if got_all != want_all:
print("[dl] 分片不完整,停止(不拼主文件)")
return 1
# ---- 拼接 ----
if P.stat().st_size < TARGET and args.assemble:
chunk = json.loads(meta_path.read_text())["chunk"] if meta_path.exists() else chunk
base = json.loads(meta_path.read_text())["base"] if meta_path.exists() else 0
cur = P.stat().st_size
print(f"[asm] 追加 [{cur}, {TARGET}) 到主文件 ...", flush=True)
with P.open("ab") as out:
for s in range(base, TARGET, chunk):
e = min(s + chunk - 1, TARGET - 1)
if e < cur:
continue
part = PARTS / f"{s:012d}.part"
if not part.exists():
print(f"[asm] 缺分片 {part} → 中止")
return 1
with part.open("rb") as fh:
shutil.copyfileobj(fh, out, 4 * 1024 * 1024)
size = P.stat().st_size
print(f"[chk] 大小 {size} / {TARGET} {'OK' if size == TARGET else '不一致'}", flush=True)
h = hashlib.sha256()
t0 = time.time()
with P.open("rb") as fh:
while True:
b = fh.read(16 * 1024 * 1024)
if not b:
break
h.update(b)
got = h.hexdigest()
print(f"[chk] sha256 {got} ({time.time()-t0:.1f}s)", flush=True)
print(f"[chk] 期望 {WANT}", flush=True)
print(f"[chk] 大小匹配={size == TARGET} sha256匹配={got == WANT}", flush=True)
return 0 if (size == TARGET and got == WANT) else 1
if __name__ == "__main__":
sys.exit(main())
|