[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-105271":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":17,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":29,"readmeContent":30,"aiSummary":10,"trendingCount":15,"starSnapshotCount":15,"syncStatus":13,"lastSyncTime":31,"discoverSource":32},105271,"foidfinder","AlpinDale\u002Ffoidfinder","AlpinDale","Identify anime characters and series in images","https:\u002F\u002Ffoidfinder.net",null,"Python",72,2,62,0,3,9,45.23,"Apache License 2.0",false,"master",true,[24,25,26,27,28],"anime","cuda","mlx","tagging","timm","2026-11-01 00:13:09","# foidfinder\n\nfoidfinder names the characters and series in anime images. It runs\n[PixAI Tagger v1.0](https:\u002F\u002Fhuggingface.co\u002Fpixai-labs\u002Fpixai-tagger-v1.0) (Danbooru tags up to May 2026).\n\nWe have two compute backends at the moment:\n\n| Backend | Hardware | Precision | Time per image |\n|---|---|---|---|\n| `cuda` | NVIDIA, compute capability 8.0+ | int8 weights and activations, custom kernels | 20 ms on an RTX 4090 |\n| `mlx` | Apple Silicon | fp16 | 0.8-1.4 s on an M4 Pro |\n\nThe backend is chosen at runtime. The default, `auto`, uses MLX on Apple Silicon and CUDA when an NVIDIA GPU is\nvisible.\n\n## Docker (NVIDIA)\n\nRequires the [NVIDIA Container Toolkit](https:\u002F\u002Fdocs.nvidia.com\u002Fdatacenter\u002Fcloud-native\u002Fcontainer-toolkit\u002F) and a driver\nfor CUDA 13.0 (580 or newer).\n\n```sh\ndocker compose up -d --build   # http:\u002F\u002F127.0.0.1:8000\n```\n\nOn first start the container downloads the int8 checkpoint\n[alpindale\u002FPixAI-v1.0-INT8](https:\u002F\u002Fhuggingface.co\u002Falpindale\u002FPixAI-v1.0-INT8) (0.6 GB) into the `models` volume.\nThe kernels are compiled at build time for the `CUDA_ARCHS` build argument (default `8.9`, add `8.6` for RTX 30-series\ncards). Compose publishes its port on loopback only, so put a reverse proxy\nwith TLS and rate limiting in front of it.\n\n### Behind a proxy\n\nIf the GPU host should not hold TLS or Cloudflare credentials, it can dial out to a proxy host over SSH instead of\naccepting connections. Its key can open one loopback port on the proxy and nothing else.\n\n- On the proxy, create a `foidfinder-tunnel` user with shell `\u002Fusr\u002Fsbin\u002Fnologin`, add the GPU host's public key to its\n  `authorized_keys` with the prefix `restrict,port-forwarding,permitlisten=\"127.0.0.1:18000\",command=\"\u002Fusr\u002Fsbin\u002Fnologin\"`,\n  and install `deploy\u002Fsshd-tunnel.conf` into `\u002Fetc\u002Fssh\u002Fsshd_config.d\u002F`. Add the site from `deploy\u002FCaddyfile` and copy\n  the built UI to `\u002Fsrv\u002Ffoidfinder\u002Fwebui`.\n- On the GPU host, put the private key `id_ed25519` and a `known_hosts` entry for the proxy in a directory. Set\n  `COMPOSE_FILE=compose.yaml:deploy\u002Ftunnel.compose.yaml`, `FOIDFINDER_TUNNEL_DESTINATION=foidfinder-tunnel@\u003Cproxy>` and\n  `FOIDFINDER_TUNNEL_SECRETS=\u003Cdirectory>` in `.env`, then run `docker compose up -d`.\n\nThe proxy sends the GPU host no client IPs, Cloudflare headers or cookies, and serves its responses as JSON under a\nsandboxing CSP. A compromised GPU host can return wrong tags but cannot serve pages on your domain. It does see the\nuploaded images.\n\n## From source\n\n```sh\nuv sync --extra mlx                  # Apple Silicon\nuv sync --extra cuda                 # NVIDIA, needs nvcc (CUDA 12.8+) to build the kernels on first use\n(cd web && npm ci && npm run build)  # builds the UI into foidfinder\u002Fwebui\u002F\n\nuv run foidfinder download           # official checkpoint into models\u002Fpixai-tagger-v1.0\nuv run foidfinder serve              # http:\u002F\u002F127.0.0.1:8000\nuv run foidfinder tag a.jpg b.png    # --json prints one result per line\nuv run foidfinder bench a.jpg\n```\n\n`foidfinder convert \u003Cdir>` writes the int8 checkpoint for the CUDA backend, with `config.json` and a model card, ready\nfor `hf upload`. The CUDA backend also loads the official checkpoint and quantizes it at startup, which takes longer\nand needs 3.3 GB of VRAM during loading instead of 0.9 GB. The MLX backend needs the official checkpoint.\n\n## Configuration\n\nEach option is set by an environment variable or the matching `foidfinder serve` flag.\n\n| Variable | Default | Docker default | Meaning |\n|---|---|---|---|\n| `FOIDFINDER_BACKEND` | `auto` | `cuda` | `auto`, `mlx` or `cuda` |\n| `FOIDFINDER_MODEL_DIR` | `models\u002Fpixai-tagger-v1.0` | `\u002Fmodels\u002Fpixai-tagger-v1.0` | checkpoint directory |\n| `FOIDFINDER_MODEL_REPO` | `pixai-labs\u002Fpixai-tagger-v1.0` | `alpindale\u002FPixAI-v1.0-INT8` | Hugging Face repo for `download` |\n| `FOIDFINDER_DOWNLOAD_MISSING` | off | on | `serve` downloads the model when the directory is empty |\n| `FOIDFINDER_HOST` | `127.0.0.1` | `0.0.0.0` | listen address |\n| `FOIDFINDER_PORT` | `8000` | `8000` | listen port |\n| `FOIDFINDER_MAX_QUEUE` | `16` | `16` | requests waiting for the model before the API answers 503 |\n| `FOIDFINDER_FORWARDED_ALLOW_IPS` | `127.0.0.1` | `127.0.0.1` | proxies trusted for `X-Forwarded-*` |\n| `FOIDFINDER_KERNELS` | unset | `\u002Fopt\u002Fkernels\u002Fpixai_kernels.so` | prebuilt kernels from `foidfinder build-kernels`; unset builds them with nvcc |\n\n## API\n\n| Endpoint | Response |\n|---|---|\n| `POST \u002Fapi\u002Ftag` (image file as the body) | `rating`, `tags` by category (at PixAI's per-category thresholds, sorted by score), `candidates` (up to 3 below-threshold characters and series), `image` size, `timings_ms` |\n| `GET \u002Fapi\u002Finfo` | model, backend, device, upload limits |\n| `GET \u002Fapi\u002Fhealth` | `{\"status\": \"ok\"}` once the model is loaded |\n\nErrors have the form `{\"error\": {\"code\": ..., \"message\": ...}}`.\n\n| Status | Cause |\n|---|---|\n| 400 | empty body |\n| 413 | file over 32 MB or image over 64 megapixels |\n| 415 | not an image |\n| 422 | damaged image |\n| 503 | queue full; retry after `Retry-After` seconds |\n\nUploads are decoded in memory and never written to disk.\n\n## Accuracy and speed\n\nBoth backends keep the 72×72 patch tokens in window order (3×3 windows of 24×24), so windowed attention needs no\npartition or merge transposes. The MLX backend matches the official implementation within 1e-5 in fp32 and 0.003 in\nfp16.\n\nThe CUDA backend quantizes every transformer GEMM to int8. Activations are rotated by a Hadamard matrix and scaled per\ntoken, and weights carry the same rotation and are scaled per output channel. Attention runs on fp16 tensor cores.\nBias, RoPE, GELU and residual adds are fused into the GEMM epilogues, and each batch size runs as one CUDA graph. The GEMMs are\nlimited by L2 bandwidth, so batching does not lower the time per image.\n\n| RTX 4090 | ms per image |\n|---|---|\n| Official code, fp32 | 168 |\n| Official code, bf16, `torch.compile(mode=\"max-autotune\")` | 43.7 |\n| foidfinder `cuda` backend | 19.8 |\n\nAgreement with the official fp32 model on 588 Danbooru posts from July to October 2026, at PixAI's thresholds\n(character 0.27, copyright 0.24). The top-1 column counts the 345 posts tagged with a character.\n\n| | max \\|Δp\\| | mean \\|Δp\\| | character decisions changed | copyright decisions changed | top-1 character |\n|---|---|---|---|---|---|\n| Official code, fp16 | 0.020 | 1.1e-6 | 1 | 1 | 100% |\n| Official code, bf16 | 0.079 | 7.4e-6 | 1 | 4 | 99.7% |\n| foidfinder `cuda` backend | 0.077 | 1.1e-5 | 2 | 9 | 100% |\n\n\n## License\n\nApache-2.0. PixAI Tagger v1.0 is also Apache-2.0.\n","2026-10-31 04:26:16","CREATED_QUERY"]