PNN PointNet++ SSG β V4.1 connectivity, 50 % of the eligible weights
Β© PreciseStatistics GmbH (Prime Neural Network). Proprietary weights, published for evaluation. Loading requires the PNN evaluation or licence package, version V4.1 or later.
A Prime Neural Network (PNN) version of PointNet++ SSG classification (ModelNet40 proxy).
Ten Encode-eligible layers (SA SharedMLPs after the dense input stem, plus classifier fc1/fc2)
are PNN layers at nominal 50 % density. FPS / grouping / ball-query geometry, BatchNorm, the
input stem (sa1.mlp_convs.0) and the final class head (fc3) stay dense.
This card publishes one PNN snapshot (checkpoint u031980) and its weight-only int8 / int4
exports. ModelNet40 is a public point-cloud proxy, not a customer radar detection claim.
Model at a glance
| Architecture | PointNet++ SSG classification (pointnet2_cls_ssg) |
| PNN connectivity | V4.1, ~50 % density on 10 converted layers (effective density β 0.5001) |
| Snapshot | u031980 (sha256 cc71ce46229ad43aβ¦) |
| Dense teacher | see below |
ModelNet40 official test instance_acc (n=2468, num_votes=3, seed=143) |
dense 0.9286 Β· PNN fp32 0.9156 Β· int8 0.9156 Β· int4 0.8622 |
| Input | 1024 XYZ points (ModelNet40 resampled protocol) |
| Output | 40-class logits |
Dense teacher
This PNN snapshot was converted and recovered from a dense PointNet++ SSG teacher:
| Pinned weights (authority) | yanx27/Pointnet_Pointnet2_pytorch @ eb64fe0bβ¦ β log/classification/pointnet2_ssg_wo_normals/checkpoints/best_model.pth, sha256 736a7136104fee7e92de99516bfd915c8b66b1c5432955dc37aa07f5808f6635 (MIT) |
| Hub packaging (same weights) | torch-pointcloud/pointnet2-ssg.modelnet40.xu-yan β re-export of yanx27; module names and XYZ-channel order differ, values match |
| Architecture paper | Qi et al., PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric Space, arXiv:1706.02413 |
Files
| Path | Format | Size | Use |
|---|---|---|---|
int8/model.safetensors + int8/config.json |
int8 weights (symmetric, one scale per output row); weight-only PTQ (no input_scale) |
1.2 MB | default; matches PNN fp32 |
fp32/model.safetensors + fp32/config.json |
fp32 compact (OUT, R) |
4.2 MB | reference |
int4/model.safetensors + int4/config.json |
int4 weights (signed, pack-quantized); needs PNN V4.2 | 0.66 MB | smallest file |
The folders use the PNN model file format (pnn-safetensors/1): safetensors + config.json,
with quantization_config (quant_method: "pnn") and a pnn block that records each layer's
widths, density and connectivity version. Each PNN layer stores only the weights it has,
shape (outputs, connections); connectivity indices are not stored. The PNN package
recomputes connections from (in, out, density, version).
pnn.requires_pnn is V4.1 for fp32/int8 and V4.2 for int4. Unlike the ViT Hub card,
these int8/int4 files are weight-only PTQ: activation_encoding is float (no static
per-layer input_scale). Do not assume W8A8 CPU-kernel parity with the ViT demo.
Loading
SA SharedMLP modules are 1Γ1 channel maps on [B, C, K, N]. Export them as channel
PNNLinearCirculant layers (names in config.json β pnn.layers) and wrap the 4D layout;
fc1 / fc2 are ordinary linears.
import torch
import torch.nn as nn
from pnn_circulant import PNNLinearCirculant
from pnn_quant import load_pnn_safetensors
class PNNConv1x1(nn.Module):
"""1Γ1 Conv2d-equivalent: PNN linear on channel-last [B, C, K, N]."""
def __init__(self, in_c: int, out_c: int, density: float = 0.5):
super().__init__()
self.linear = PNNLinearCirculant(in_c, out_c, density)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# x: [B, C, K, N] β channel-last β linear β [B, C_out, K, N]
y = self.linear(x.permute(0, 2, 3, 1))
return y.permute(0, 3, 1, 2)
# 1) Build PointNet++ SSG (yanx27 `pointnet2_cls_ssg`) with the usual dense modules.
# 2) Replace Encode-eligible modules using widths from config.json β pnn.layers:
# sa1.mlp_convs.1 / .2, sa2.mlp_convs.*, sa3.mlp_convs.* β PNNConv1x1(in, out, 0.5)
# fc1, fc2 β PNNLinearCirculant(in, out, 0.5)
# Keep dense: sa1.mlp_convs.0 (stem), all BatchNorm, fc3 (class head), geometry ops.
# 3) Load weights (int8/int4 dequantise into float parameters):
f = load_pnn_safetensors("int8", model) # or "fp32"; "int4" needs package V4.2
load_pnn_safetensors matches pnn.layers names to modules that expose PNN taps (the
PNNLinearCirculant instances). If you keep the PNNConv1x1 wrapper above, either load into
wrapper.linear under the Hub layer name, or temporarily assign the circulant module at the
Hub name, load, then re-wrap.
Measured accuracy (this snapshot)
| Arm | instance_acc | class_acc |
|---|---|---|
| dense fp32 | 0.9286 | 0.8900 |
| PNN fp32 | 0.9156 | 0.8836 |
| PNN int8 | 0.9156 | 0.8845 |
| PNN int4 | 0.8622 | 0.8452 |
ModelNet40 official test, n=2468, num_votes=3, seed=143.
Limitations
- ModelNet40 classification is a proxy; it does not establish radar/LiDAR detection performance.
- Near parity with the dense teacher is a descriptive point estimate, not statistical equivalence.
- ~50 % of eligible active connections is not half the serialized model, latency, energy or area.
- Layers need the PNN package; standard PyTorch loaders cannot build them.
- int8/int4 here are weight-only; they are not a calibrated W8A8 / W4A8 activation path.
Contact
Prime Neural Network Β· primeneural.net Β· info@primeneural.net