npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

borch-hub

v0.4.1

Published

borch 런타임이 바로 불러 돌릴 수 있는 모델의 배포·검증 클라이언트

Readme

borch-hub

borch 런타임이 바로 불러 돌릴 수 있는 모델의 배포·검증 클라이언트.

브라우저에서 학습한 모델이 허브에 올라가고, 다른 사람의 브라우저가 그것을 받아 돌린다. 그 왕복을 담당하는 쪽이다.

지금 여기 있는 것

매니페스트 주소 하나로 돌 준비가 된 모델까지 간다.

import { init } from "borch-ts";
import { load, verify } from "borch-hub";

await init();
const { model, manifest } = await load("https://.../manifest.json");
const badge = await verify(model, manifest, "https://.../manifest.json");

무엇이 있는지부터 물을 수 있다. 오래 그러지 못했다 — 입구가 load(주소) 하나여서 쓰는 사람이 주소를 이미 알고 있어야 했고, 모델이 스물이 되고서야 그 구멍이 보였다.

import { fetchIndex, newest } from "borch-hub";

const listing = await fetchIndex("https://models.pilab.kr/index.json");
for (const model of newest(listing)) {
  console.log(model.name, model.version, model.bytes, model.manifestUrl);
}

목차는 나간 판을 전부 들고 있다 — 옛 주소가 죽으면 남의 페이지가 깨지기 때문이다. 그래서 그대로 늘어놓으면 같은 모델이 여러 번 보인다(지금 스물 중 열이 그렇다). newest 가 이름마다 가장 높은 판만 남긴다.

순서가 요점이다 — 환경 판정 → 받기 → 해시 대조 → 싣기. 앞의 둘이 뒤바뀌면 45MB 를 받은 뒤에 "이 브라우저에서는 안 됩니다" 라고 말하게 되고, 그건 배지가 아니라 사과다. 해시를 싣기 전에 보는 것도 같은 이유다 — 모양이 맞는 틀린 바이트는 예외 없이 실린다.

그리고 실은 뒤에 샘플로 대 본다. 해시는 받은 바이트가 맞다는 말이지 이 브라우저에서 그 모델이 나온다는 말이 아니다. 둘이 벌어지는 것을 실측했다 — EfficientNet-B4 는 바이트도 층도 맞는데 이 장치에서 로짓이 전부 0 이었다 (borch#122). 그때 load 는 아무 말 없이 그 모델을 건넸다.

막을 도구는 이미 있었다(verify 가 최대 절대차 1.481 로 막는다). 아무도 안 불렀을 뿐이다. 이제 load 가 부른다 — 샘플 두 개는 600KB 남짓이고, 45MB 를 받은 뒤에 치르기에 싸다. 끄려면 load(url, { verify: false }).

loadfetch 를 받는다. 프라이빗 모델·조직 계정·서명 URL 이 전부 그 훅 하나를 탄다. 지금 쓰는 데가 없어도 자리를 비워 둔 것은, 나중에 넣으면 이미 쓰고 있는 쪽이 깨지기 때문이다.

빈 함수로 자리만 잡아두지 않은 것은 일부러다. 코어 저장소가 여러 번 적어둔 대로 사용자 없는 표면은 케이스가 안 생기고, 케이스 없는 표면이 조용히 틀린다. 첫 모델 하나를 끝까지 통과시키면서 같이 나온다.

계약을 먼저 두는 이유는 정확히 반대다. 매니페스트는 한 번 배포되면 못 바꾼다 — 남의 페이지가 이미 그 URL 을 박아두고 그 필드를 읽고 있기 때문이다.

카탈로그는 여기 없다 — bimm 에 있다

가중치만으로는 모델이 복원되지 않는다. 매니페스트의 arch 가 가리키는 표와 createModelbimm 에 있다.

borch        ←→  torch
borchvision  ←→  torchvision
bimm         ←→  timm          아키텍처 카탈로그
borch-hub    ←→  (없음)        매니페스트 · 해시 대조 · 환경 판정

이 패키지가 흉내 내는 자리는 없다. torch.hub 가 가장 가깝지만 그쪽은 저장소에서 모델을 불러오는 일이고 자기 카탈로그가 없다. 여기 있는 것 — 배포된 매니페스트, 싣기 전의 해시 대조, 받기 전의 환경 판정 — 은 timm 에도 torch.hub 에도 없다. 흉내가 아니므로 흉내인 척하지 않는다.

카탈로그가 갈라져 나간 것은 이름 때문이 아니라 방향 때문이다. models/ 가 매니페스트의 BorchHubErrorArch 를 임포트하고 있었는데 둘 다 매니페스트 개념이다. 카탈로그가 매니페스트를 알면 모델 하나 만들려는 사람이 배포·검증 계층을 통째로 끌어온다. 지금은 의존이 한 방향이다 — 허브는 카탈로그를 알고, 카탈로그는 허브를 모른다.

매니페스트의 arch 를 카탈로그 호출로 옮기는 createModelFor 만 이쪽에 남았다. 그것은 매니페스트 모양이기 때문이다.

왜 코어와 따로 있나

세 가지 이유다.

번들 크기. 코어가 싣는 ES 모듈이 압축 전 770KB 이고, 코어 저장소의 tests/test_site.py 가 문서에 적힌 수와 실측을 대조해 낡으면 실패시킨다. 모델 구조가 늘 때마다 그 수가 오르면 안 된다. 모델을 안 쓰는 사람이 카탈로그를 받을 이유도 없다.

버전 매트릭스가 강제된다. 매니페스트에 runtime.ts: ">=0.1.0" 이라고 적으려면 실제로 여러 borch 버전에서 돌려봐야 한다. 한 저장소 안에 있으면 "지금 트리에서 되니까 됨"으로 끝나는데, 갈라져 있으면 CI 가 그 확인을 하게 된다. 호환성 표시가 주장이 아니라 실측이 되는 유일한 길이다.

제품이 다르다. borch 는 읽히는 교육용 런타임이고, 이쪽은 모델 유통이다. 릴리스 주기도 사용자도 같지 않다.

borchbimm 은 peerDependency 다

이 패키지가 borch 를 끌고 오면 사용자의 것과 두 벌이 된다. 텐서 두 벌은 같은 GPU 장치를 공유하지 않아서 예외 없이 조용히 안 맞는다. 쓰는 쪽이 이미 깔아둔 것을 쓴다.

bimm 도 같은 이유다 — 그쪽 층이 사용자의 borch 위에 서므로, bimm 이 두 벌이면 borch 도 두 벌이 된다.

하한이 낮은 것은 실수가 아니다

bimm-ts >=0.2.1 이다. 0.2.1 의 카탈로그에는 resnetmobilenet 뿐이라, 지금 나가 있는 모델 열 중 일곱은 그 판으로 못 만든다 — efficientnet 과 mobilenetv3 는 0.4.0, vit 는 0.6.0 에 생겼다.

그래도 하한을 올리지 않는다. 낡은 카탈로그로도 그것이 아는 모델은 돌기 때문이다. 올리면 resnet 하나 쓰려는 사람까지 같이 막힌다.

대신 checkEnvironment받기 전에 카탈로그에 그 이름이 있는지 묻는다. 없으면 그 자리에서 이름과 지금 있는 것을 같이 말하고 멈춘다 — 45MB 를 쓴 뒤가 아니다.

매니페스트에 bimm 하한을 적는 길도 있었다. 그러려면 카탈로그가 자기 판을 내보내야 하고, 스키마가 바뀌어야 하고, 나가 있는 매니페스트를 다시 올려야 한다. 그러고도 카탈로그에 새 이름이 생길 때마다 그 숫자가 낡는다. 있는지 없는지는 카탈로그가 이미 안다.

매니페스트 스펙의 정본은 여기가 아니다

정본은 borch-hub-registry/schema/manifest.schema.json 이고, src/manifest.ts 는 그것을 TypeScript 로 옮긴 거울이다. 거울은 원본과 갈릴 수 있다 — 갈리면 레지스트리는 통과시키는데 클라이언트가 거절하는 매니페스트가 생기고, 그건 올린 사람이 아니라 받는 사람이 만난다.

그래서 두 가지를 따로 묻는다.

test/schema.test.ts 는 저장소에 든 스키마 사본에서 주장을 뽑아 거울에게 물어본다 — 허용하는 값을 전부 넣어 보고, 목록에 없는 값도 하나 넣어 보고, 필수 필드를 하나씩 빼 본다. 글자를 대 보지 않는 것은 JSON Schema 와 손으로 쓴 파서가 모양이 달라서다.

npm run schema:fresh 는 그 사본이 정본과 같은지 묻는다. 스키마의 $id 가 자기 주소를 담고 있어서 여기에 주소를 또 적지 않는다. 네트워크가 필요한 유일한 단계라 CI 에서도 따로 서 있다 — 사본이 낡은 것과 거울이 갈린 것은 다른 일이고, 한 칸에 넣으면 그 구별이 사라진다. 못 받으면 건너뛰지 않고 빨개진다.

돌리기

npm install
npm test              # 배포되는 코드 전부
npm run check         # 타입만

코어와 카탈로그는 npm 에서 온다 — borch-ts·bimm-ts. 접미사가 붙은 것은 갈려서가 아니라 레지스트리의 유사성 필터가 borchbimm 도 막기 때문이다(둘 다 403 을 받고 알았다). 저장소 이름은 접미사 없는 쪽 그대로다.

브라우저 하네스

npm run build:browser   # 하네스 방출
npm run check:browser   # 하네스 타입만

옆에 코어를 받아둘 필요가 없다. paritytrain 이 쓰는 코어의 벤치 모듈이 borch-ts 0.2.2 부터 배포에 실린다(dist/test/bench·accuracy). 그전에는 옆에 받아둔 코어에서 가져올 수밖에 없었고, 그러면 코어가 두 벌이 되므로 하네스 전체를 그쪽으로 잡아야 했다 — 이제 벤치도 코어도 node_modules 에서 오고 한 벌이다.

하네스가 여전히 별도 tsconfig 인 것은 다른 이유다: @core/*공개된 진입점이 아니다. 배포되는 src/ 는 그것을 몰라야 한다.

두 벌 대조

ResNet-18 정의는 코어의 벤치에도 있다. 합칠 수 없으므로(코어가 이 패키지를 의존하면 순환이다) 대신 대조한다 — 브라우저에서 둘을 만들어 stateDict열쇠와 모양을 맞춰 본다.

npm run parity        # 창 없이 돈다. 모양은 장치가 안 바꾼다

값은 안 본다(각자 무작위 초기화라 같을 이유가 없다). 잡는 것은 필드 이름이 갈리는 것이다 — 코드로는 아무 문제 없고 타입 검사도 통과하는데, 이미 배포된 체크포인트만 조용히 안 실린다. 실제로 fchead 로 바꿔 보면 컴파일러는 한마디도 안 하고 이 검사만 멈춘다.

브라우저를 띄우는 인자는 코어의 것을 그대로 들여온다(browser/launch.py). 여기서 잰 수는 코어의 벤치 수와 비교되기 위해 존재하고, 플래그가 다르면 그 비교가 거짓이 된다.

검사는 대조를 뺀 전부가 GPU 없이 돈다. 모델을 만드는 것은 WebGPU 어댑터가 필요하지만, 인자가 틀렸다는 것을 아는 데까지는 필요 없다 — 그래서 args.tsregistry.ts 에서 떨어져 있다.

관련

  • borch — 런타임 (코어)
  • borch-hub-registry — 매니페스트와 검증 자료가 사는 곳