Ryan Chesler commited on
Commit ·
65abd8a
1
Parent(s): 196b410
improve install docs and process
Browse filesThe .gitignore excludes *.so files, which caused hatchling to silently
drop the compiled CUDA extension from the wheel.
pyproject.toml: add artifacts glob so hatchling includes the .so
despite gitignore; add ninja to build hook deps for faster compilation.
hatch_build.py: set a platform-specific wheel tag (cpXY-cpXY-linux_*)
instead of py3-none-any when the extension is built.
README.md + quickstart.md: rewrite install instructions to recommend
installing torch first with the correct CUDA index URL, then using
--no-build-isolation to avoid CUDA version mismatches during the
extension build.
- README.md +28 -11
- nemotron-ocr/hatch_build.py +27 -13
- nemotron-ocr/pyproject.toml +4 -1
- quickstart.md +36 -9
README.md
CHANGED
|
@@ -158,36 +158,53 @@ Our AI models are designed and/or optimized to run on NVIDIA GPU-accelerated sys
|
|
| 158 |
#### Prerequisites
|
| 159 |
|
| 160 |
- **OS**: Linux amd64 with NVIDIA GPU
|
| 161 |
-
- **CUDA**
|
| 162 |
-
|
| 163 |
-
|
|
|
|
|
|
|
|
|
|
| 164 |
- GCC/G++ with C++17 support
|
| 165 |
-
- CUDA toolkit headers
|
| 166 |
-
- OpenMP
|
| 167 |
-
|
| 168 |
|
| 169 |
#### Installation
|
| 170 |
-
The
|
|
|
|
|
|
|
|
|
|
| 171 |
|
| 172 |
1. Clone the repository
|
| 173 |
|
| 174 |
- Make sure git-lfs is installed (https://git-lfs.com)
|
| 175 |
```
|
| 176 |
git lfs install
|
|
|
|
| 177 |
```
|
| 178 |
|
| 179 |
2. Installation
|
| 180 |
|
| 181 |
##### With pip
|
| 182 |
|
| 183 |
-
- Create and activate a Python 3.12 environment
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
|
| 185 |
-
-
|
| 186 |
|
| 187 |
```bash
|
| 188 |
cd nemotron-ocr
|
| 189 |
-
pip install
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
```
|
| 192 |
|
| 193 |
##### With docker
|
|
|
|
| 158 |
#### Prerequisites
|
| 159 |
|
| 160 |
- **OS**: Linux amd64 with NVIDIA GPU
|
| 161 |
+
- **CUDA toolkit** with `nvcc` on `PATH`. The toolkit version must be compatible with
|
| 162 |
+
the version of PyTorch you install (same major version). For example, if you install
|
| 163 |
+
`torch` with CUDA 12.8 bindings, you need CUDA toolkit 12.x. Verify with
|
| 164 |
+
`nvcc --version` and `nvidia-smi`.
|
| 165 |
+
- **Python**: 3.12 (the package requires `>=3.12,<3.13`)
|
| 166 |
+
- **Build tools** (for the C++ CUDA extension compiled at install time):
|
| 167 |
- GCC/G++ with C++17 support
|
| 168 |
+
- CUDA toolkit headers
|
| 169 |
+
- OpenMP
|
|
|
|
| 170 |
|
| 171 |
#### Installation
|
| 172 |
+
The package includes a C++ CUDA extension that is compiled during installation.
|
| 173 |
+
Because the extension must be built against the **same PyTorch CUDA version** as
|
| 174 |
+
your system's CUDA toolkit, **install PyTorch first**, then install this package
|
| 175 |
+
with `--no-build-isolation` so it uses your existing PyTorch.
|
| 176 |
|
| 177 |
1. Clone the repository
|
| 178 |
|
| 179 |
- Make sure git-lfs is installed (https://git-lfs.com)
|
| 180 |
```
|
| 181 |
git lfs install
|
| 182 |
+
git clone https://huggingface.co/nvidia/nemotron-ocr-v2
|
| 183 |
```
|
| 184 |
|
| 185 |
2. Installation
|
| 186 |
|
| 187 |
##### With pip
|
| 188 |
|
| 189 |
+
- Create and activate a Python 3.12 environment
|
| 190 |
+
- Install PyTorch matching your CUDA toolkit (see https://pytorch.org/get-started/locally/):
|
| 191 |
+
|
| 192 |
+
```bash
|
| 193 |
+
# Example for CUDA 12.8:
|
| 194 |
+
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128
|
| 195 |
+
```
|
| 196 |
|
| 197 |
+
- Install the package:
|
| 198 |
|
| 199 |
```bash
|
| 200 |
cd nemotron-ocr
|
| 201 |
+
pip install --no-build-isolation -v .
|
| 202 |
+
```
|
| 203 |
+
|
| 204 |
+
- Verify the C++ extension loads:
|
| 205 |
+
|
| 206 |
+
```bash
|
| 207 |
+
python -c "from nemotron_ocr.inference.pipeline_v2 import NemotronOCRV2; print('OK')"
|
| 208 |
```
|
| 209 |
|
| 210 |
##### With docker
|
nemotron-ocr/hatch_build.py
CHANGED
|
@@ -41,31 +41,45 @@ def _extension_up_to_date(project_root: Path) -> bool:
|
|
| 41 |
return newest_so_mtime >= newest_src_mtime
|
| 42 |
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
class CustomBuildHook(BuildHookInterface):
|
| 45 |
def initialize(self, version: str, build_data: dict) -> None:
|
| 46 |
project_root = Path(__file__).parent
|
| 47 |
script_path = project_root / "scripts" / "build-extension.py"
|
| 48 |
|
| 49 |
env = os.environ.copy()
|
| 50 |
-
# Ensure the extension actually builds during package build
|
| 51 |
env.setdefault("BUILD_CPP_EXTENSION", "1")
|
| 52 |
|
| 53 |
-
# Allow users to force rebuild or skip if up-to-date
|
| 54 |
force_rebuild = env.get("BUILD_CPP_FORCE", "0") == "1"
|
| 55 |
build_enabled = env.get("BUILD_CPP_EXTENSION", "1") == "1"
|
| 56 |
|
| 57 |
-
if
|
| 58 |
-
# Cached build found and sources unchanged; skip rebuild
|
| 59 |
return
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
|
| 71 |
|
|
|
|
| 41 |
return newest_so_mtime >= newest_src_mtime
|
| 42 |
|
| 43 |
|
| 44 |
+
def _get_platform_tag() -> str:
|
| 45 |
+
"""Return a PEP 425 platform tag for the current system."""
|
| 46 |
+
import sysconfig
|
| 47 |
+
platform = sysconfig.get_platform().replace("-", "_").replace(".", "_")
|
| 48 |
+
return platform
|
| 49 |
+
|
| 50 |
+
|
| 51 |
class CustomBuildHook(BuildHookInterface):
|
| 52 |
def initialize(self, version: str, build_data: dict) -> None:
|
| 53 |
project_root = Path(__file__).parent
|
| 54 |
script_path = project_root / "scripts" / "build-extension.py"
|
| 55 |
|
| 56 |
env = os.environ.copy()
|
|
|
|
| 57 |
env.setdefault("BUILD_CPP_EXTENSION", "1")
|
| 58 |
|
|
|
|
| 59 |
force_rebuild = env.get("BUILD_CPP_FORCE", "0") == "1"
|
| 60 |
build_enabled = env.get("BUILD_CPP_EXTENSION", "1") == "1"
|
| 61 |
|
| 62 |
+
if not build_enabled:
|
|
|
|
| 63 |
return
|
| 64 |
|
| 65 |
+
if not force_rebuild and _extension_up_to_date(project_root):
|
| 66 |
+
pass # skip rebuild, but still set the tag below
|
| 67 |
+
else:
|
| 68 |
+
subprocess.run(
|
| 69 |
+
[
|
| 70 |
+
os.fspath(sys.executable),
|
| 71 |
+
os.fspath(script_path),
|
| 72 |
+
],
|
| 73 |
+
cwd=os.fspath(project_root),
|
| 74 |
+
env=env,
|
| 75 |
+
check=True,
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
# Tag the wheel as platform-specific so the .so is usable
|
| 79 |
+
python_tag = f"cp{sys.version_info.major}{sys.version_info.minor}"
|
| 80 |
+
abi_tag = python_tag
|
| 81 |
+
platform_tag = _get_platform_tag()
|
| 82 |
+
build_data["tag"] = f"{python_tag}-{abi_tag}-{platform_tag}"
|
| 83 |
+
build_data["pure_python"] = False
|
| 84 |
|
| 85 |
|
nemotron-ocr/pyproject.toml
CHANGED
|
@@ -28,6 +28,9 @@ dev = [
|
|
| 28 |
requires = ["hatchling", "editables"]
|
| 29 |
build-backend = "hatchling.build"
|
| 30 |
|
|
|
|
|
|
|
|
|
|
| 31 |
[tool.hatch.build.targets.wheel]
|
| 32 |
packages = [
|
| 33 |
"src/nemotron_ocr",
|
|
@@ -36,7 +39,7 @@ packages = [
|
|
| 36 |
|
| 37 |
[tool.hatch.build.targets.wheel.hooks.custom]
|
| 38 |
path = "hatch_build.py"
|
| 39 |
-
dependencies = ["setuptools>=68", "torch>=2.0"]
|
| 40 |
|
| 41 |
[tool.hatch.build.targets.sdist]
|
| 42 |
include = [
|
|
|
|
| 28 |
requires = ["hatchling", "editables"]
|
| 29 |
build-backend = "hatchling.build"
|
| 30 |
|
| 31 |
+
[tool.hatch.build]
|
| 32 |
+
artifacts = ["src/nemotron_ocr_cpp/*.so"]
|
| 33 |
+
|
| 34 |
[tool.hatch.build.targets.wheel]
|
| 35 |
packages = [
|
| 36 |
"src/nemotron_ocr",
|
|
|
|
| 39 |
|
| 40 |
[tool.hatch.build.targets.wheel.hooks.custom]
|
| 41 |
path = "hatch_build.py"
|
| 42 |
+
dependencies = ["setuptools>=68", "torch>=2.0", "ninja"]
|
| 43 |
|
| 44 |
[tool.hatch.build.targets.sdist]
|
| 45 |
include = [
|
quickstart.md
CHANGED
|
@@ -1,16 +1,43 @@
|
|
| 1 |
# Quickstart
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
## Installation
|
| 4 |
|
| 5 |
-
|
|
|
|
|
|
|
| 6 |
|
| 7 |
```bash
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
cd nemotron-ocr
|
| 9 |
-
pip install
|
| 10 |
-
pip install -v .
|
| 11 |
```
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
```bash
|
| 16 |
python -c "from nemotron_ocr.inference.pipeline_v2 import NemotronOCRV2; print('OK')"
|
|
@@ -54,8 +81,8 @@ ocr_profile = NemotronOCRV2(verbose_post=True)
|
|
| 54 |
### Example script
|
| 55 |
|
| 56 |
```bash
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
```
|
|
|
|
| 1 |
# Quickstart
|
| 2 |
|
| 3 |
+
## Prerequisites
|
| 4 |
+
|
| 5 |
+
- **Python 3.12** (the package requires `>=3.12,<3.13`)
|
| 6 |
+
- **CUDA toolkit** with `nvcc` on `PATH` (the package compiles a CUDA C++ extension at install time)
|
| 7 |
+
- **A CUDA GPU** (or set `TORCH_CUDA_ARCH_LIST` to cross-compile, e.g. `TORCH_CUDA_ARCH_LIST="8.0 9.0"`)
|
| 8 |
+
|
| 9 |
+
The CUDA toolkit version must share the same **major version** as the CUDA
|
| 10 |
+
bindings in your PyTorch install (e.g. toolkit 12.4 with `torch+cu128` is fine;
|
| 11 |
+
toolkit 12.4 with `torch+cu130` will fail).
|
| 12 |
+
|
| 13 |
+
On Slurm clusters, run the install on a GPU node or load the CUDA module first:
|
| 14 |
+
|
| 15 |
+
```bash
|
| 16 |
+
module load cuda12.4/toolkit/12.4.1 # example; adjust for your cluster
|
| 17 |
+
export CUDA_HOME=/usr/local/cuda # or wherever the toolkit lives
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
## Installation
|
| 21 |
|
| 22 |
+
Install PyTorch **first** with bindings matching your CUDA toolkit, then install
|
| 23 |
+
this package with `--no-build-isolation` so it builds the C++ extension against
|
| 24 |
+
your existing PyTorch:
|
| 25 |
|
| 26 |
```bash
|
| 27 |
+
# 1. Install PyTorch (adjust the index URL for your CUDA version)
|
| 28 |
+
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128
|
| 29 |
+
|
| 30 |
+
# 2. Install nemotron-ocr
|
| 31 |
cd nemotron-ocr
|
| 32 |
+
pip install --no-build-isolation -v .
|
|
|
|
| 33 |
```
|
| 34 |
|
| 35 |
+
> **Why `--no-build-isolation`?** Without it, pip creates a temporary build
|
| 36 |
+
> environment and installs the latest PyTorch from PyPI. That PyTorch's CUDA
|
| 37 |
+
> version may not match your system's `nvcc`, causing the C++ extension build
|
| 38 |
+
> to fail with a CUDA version mismatch error.
|
| 39 |
+
|
| 40 |
+
Verify the installation (the C++ extension must load without errors):
|
| 41 |
|
| 42 |
```bash
|
| 43 |
python -c "from nemotron_ocr.inference.pipeline_v2 import NemotronOCRV2; print('OK')"
|
|
|
|
| 81 |
### Example script
|
| 82 |
|
| 83 |
```bash
|
| 84 |
+
python example.py ocr-example-input-1.png
|
| 85 |
+
python example.py ocr-example-input-1.png --merge-level word
|
| 86 |
+
python example.py ocr-example-input-1.png --detector-only
|
| 87 |
+
python example.py ocr-example-input-1.png --skip-relational
|
| 88 |
+
```
|