Instructions to use Yesianrohn/openocrv2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Yesianrohn/openocrv2 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="Yesianrohn/openocrv2")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Yesianrohn/openocrv2", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Yesianrohn/openocrv2 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Yesianrohn/openocrv2" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Yesianrohn/openocrv2", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/Yesianrohn/openocrv2
- SGLang
How to use Yesianrohn/openocrv2 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "Yesianrohn/openocrv2" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Yesianrohn/openocrv2", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "Yesianrohn/openocrv2" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Yesianrohn/openocrv2", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use Yesianrohn/openocrv2 with Docker Model Runner:
docker model run hf.co/Yesianrohn/openocrv2
Update modeling_openocrv2_det.py
Browse files- modeling_openocrv2_det.py +73 -28
modeling_openocrv2_det.py
CHANGED
|
@@ -416,36 +416,68 @@ def polygon_points(coefficients, basis, stride):
|
|
| 416 |
locations = locations.repeat(1, basis.shape[1] // 2)
|
| 417 |
return (points + locations) * stride
|
| 418 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 419 |
def _suppress_contained(polygons, scores, contain=0.95, ratio=0.35):
|
| 420 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 421 |
return polygons, scores
|
| 422 |
-
flat = polygons.reshape(
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
|
|
|
| 431 |
continue
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
|
|
|
|
|
|
|
|
|
| 445 |
return polygons[keep], scores[keep]
|
| 446 |
|
| 447 |
|
| 448 |
-
@torch.no_grad()
|
| 449 |
def decode_detection(predictions, basis, config, content_shape=None, scale=None):
|
| 450 |
"""Scores plus polygons to accepted boxes, mirroring the frozen decoder.
|
| 451 |
|
|
@@ -479,11 +511,24 @@ def decode_detection(predictions, basis, config, content_shape=None, scale=None)
|
|
| 479 |
flat = polygons.reshape(len(polygons), -1, 2)
|
| 480 |
boxes = torch.cat((flat.amin(dim=1), flat.amax(dim=1)), dim=1)
|
| 481 |
keep = nms(boxes, scores, config["nms_threshold"])
|
| 482 |
-
keep = nms(boxes, scores, config["nms_threshold"])
|
| 483 |
polygons, scores = polygons[keep], scores[keep]
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
if scale is not None:
|
| 488 |
polygons = polygons / torch.as_tensor(
|
| 489 |
scale, dtype=polygons.dtype, device=polygons.device
|
|
|
|
| 416 |
locations = locations.repeat(1, basis.shape[1] // 2)
|
| 417 |
return (points + locations) * stride
|
| 418 |
|
| 419 |
+
@torch.no_grad()
|
| 420 |
+
def _drop_degenerate(polygons, content_shape, config):
|
| 421 |
+
"""Mask out boxes that are too small or cover most of the page.
|
| 422 |
+
|
| 423 |
+
A 4-pixel box has no readable content, and a box spanning over a third of
|
| 424 |
+
the image is a layout region, not a text line.
|
| 425 |
+
"""
|
| 426 |
+
flat = polygons.reshape(len(polygons), -1, 2)
|
| 427 |
+
wh = (flat.amax(dim=1) - flat.amin(dim=1)).clamp(min=0)
|
| 428 |
+
min_side = float(config.get("min_box_side", 4.0))
|
| 429 |
+
keep = (wh[:, 0] >= min_side) & (wh[:, 1] >= min_side)
|
| 430 |
+
fraction = float(config.get("max_box_area_fraction", 0.3))
|
| 431 |
+
if content_shape is not None and fraction < 1.0:
|
| 432 |
+
height, width = content_shape
|
| 433 |
+
keep = keep & ((wh[:, 0] * wh[:, 1]) <= fraction * float(height * width))
|
| 434 |
+
return keep
|
| 435 |
+
|
| 436 |
+
|
| 437 |
def _suppress_contained(polygons, scores, contain=0.95, ratio=0.35):
|
| 438 |
+
"""Drop boxes nested inside a larger box.
|
| 439 |
+
|
| 440 |
+
Measured on 3544 pages: 54% of images contain nested boxes and 40% of them
|
| 441 |
+
repeat text already returned by the enclosing line. Containment (not IoU)
|
| 442 |
+
is the right test -- a small box inside a large one has a low IoU, so an
|
| 443 |
+
IoU filter never fires.
|
| 444 |
+
|
| 445 |
+
The ratio guard keeps legitimate nesting: a heading inside a paragraph block
|
| 446 |
+
is usually more than a third of its area, so it survives.
|
| 447 |
+
"""
|
| 448 |
+
n = len(polygons)
|
| 449 |
+
if n < 2:
|
| 450 |
return polygons, scores
|
| 451 |
+
flat = polygons.reshape(n, -1, 2)
|
| 452 |
+
lo, hi = flat.amin(dim=1), flat.amax(dim=1)
|
| 453 |
+
areas = (hi - lo).clamp(min=0).prod(dim=1)
|
| 454 |
+
|
| 455 |
+
order = torch.argsort(areas, descending=True)
|
| 456 |
+
lo, hi, areas = lo[order], hi[order], areas[order]
|
| 457 |
+
alive = torch.ones(n, dtype=torch.bool, device=areas.device)
|
| 458 |
+
|
| 459 |
+
for pos in range(n - 1):
|
| 460 |
+
if not bool(alive[pos]):
|
| 461 |
continue
|
| 462 |
+
candidate = alive[pos + 1:]
|
| 463 |
+
if not bool(candidate.any()):
|
| 464 |
+
continue
|
| 465 |
+
c_lo, c_hi, c_area = lo[pos + 1:], hi[pos + 1:], areas[pos + 1:]
|
| 466 |
+
ix0 = torch.maximum(lo[pos][0], c_lo[:, 0])
|
| 467 |
+
iy0 = torch.maximum(lo[pos][1], c_lo[:, 1])
|
| 468 |
+
ix1 = torch.minimum(hi[pos][0], c_hi[:, 0])
|
| 469 |
+
iy1 = torch.minimum(hi[pos][1], c_hi[:, 1])
|
| 470 |
+
inter = (ix1 - ix0).clamp(min=0) * (iy1 - iy0).clamp(min=0)
|
| 471 |
+
nested = (inter / c_area.clamp(min=1e-6) >= contain) & (
|
| 472 |
+
c_area / areas[pos].clamp(min=1e-6) <= ratio
|
| 473 |
+
)
|
| 474 |
+
alive[pos + 1:] = candidate & ~nested
|
| 475 |
+
|
| 476 |
+
keep = torch.zeros(n, dtype=torch.bool, device=areas.device)
|
| 477 |
+
keep[order] = alive
|
| 478 |
return polygons[keep], scores[keep]
|
| 479 |
|
| 480 |
|
|
|
|
| 481 |
def decode_detection(predictions, basis, config, content_shape=None, scale=None):
|
| 482 |
"""Scores plus polygons to accepted boxes, mirroring the frozen decoder.
|
| 483 |
|
|
|
|
| 511 |
flat = polygons.reshape(len(polygons), -1, 2)
|
| 512 |
boxes = torch.cat((flat.amin(dim=1), flat.amax(dim=1)), dim=1)
|
| 513 |
keep = nms(boxes, scores, config["nms_threshold"])
|
|
|
|
| 514 |
polygons, scores = polygons[keep], scores[keep]
|
| 515 |
+
# Added post-processing, all geometry-only so it runs before recognition.
|
| 516 |
+
keep = _drop_degenerate(polygons, content_shape, config)
|
| 517 |
+
polygons, scores = polygons[keep], scores[keep]
|
| 518 |
+
if polygons.numel():
|
| 519 |
+
polygons, scores = _suppress_contained(
|
| 520 |
+
polygons, scores,
|
| 521 |
+
float(config.get("contain_threshold", 0.95)),
|
| 522 |
+
float(config.get("contain_area_ratio", 0.35)),
|
| 523 |
+
)
|
| 524 |
+
if content_shape is not None and polygons.numel():
|
| 525 |
+
# Clamp to the content area, not the padded canvas: a polygon
|
| 526 |
+
# that runs into the padding would otherwise be cropped with
|
| 527 |
+
# replicated border pixels.
|
| 528 |
+
content_h, content_w = content_shape
|
| 529 |
+
view = polygons.reshape(len(polygons), -1, 2)
|
| 530 |
+
view[..., 0].clamp_(0, content_w - 1)
|
| 531 |
+
view[..., 1].clamp_(0, content_h - 1)
|
| 532 |
if scale is not None:
|
| 533 |
polygons = polygons / torch.as_tensor(
|
| 534 |
scale, dtype=polygons.dtype, device=polygons.device
|