Answers are grounded in this paper and cite their sources.
Weight distribution via the FC line; computation on the CPU using XOR + popcount. 1. Summary This system is an open-source BNN accelerator that distributes 1-bit quantized SD1.5 UNet convolution weights via an FC transport layer, while performing computations on the CPU using XOR + popcount. Computation: CPU (AVX2/AVX-512, hardware popcount). Distribution: 4× QLE2660 (ISP8324) ports, sg/bsg (SCSI generic). Storage: bit-packed .bin + JSON index. Remaining on GPU: text_encoder, attention, VAE. 2. Model and Quantization In the 860M-parameter UNet, the attention blocks have been left on the digital side. diffusion_pytorch_model.safetensors (fp32, ~860M × 4 B ≈ 3.44 GB), with 537,497,856 convolution weights encoded as 1-bit using Sd15-Resblock-To-bin-1bit-Raw.py into sd15_resblock_weights_1bit. UNet has been decomposed into conv layers at the ResBlock level. Image generation occurs in 4 steps using LCM; the UNet forward pass is performed a total of four times. Quantization rule: ŵ = 2b − 1; b = 1 ⟺ w > 0, b = 0 ⟺ w ≤ 0. Weights equal to zero are mapped to −1; this rule is explicitly stated in the “mapping” field of the index file. Scaling α = mean(|W|) is applied per tensor; α, the bias, and the tensor list remain the same as in the previous transformation. 3. Computation: XOR + Popcount CPU bits are used instead of an optical path for 1-bit weighted convolution. Since 1-bit quantization has already been performed, this requires no additional hardware and is a measurable accelerator. XOR → popcount is applied to the weight bits (w) and activation bits (x). Activations are represented in this architecture as 1-bit (signed) values; y = (N − 2·popcount(XOR(w, x))) · α C# / System.Runtime.Intrinsics (AVX2 + Popcnt) example: // weight bits (w) and activation bits (x) XOR → popcount // mac = N - popcount(XOR(w, x)); no additional XOR is needed // N = 256 (4 × 64-bit blocks); if the window has a different size, N and s are calculated based on the same block size Vector256<byte> t = Avx2.Xor(wVec, xVec); ulong s = 0; for (int k = 0; k < 4; k++) s += Popcnt.PopCount(t.AsUInt64().GetElement(k)); // y = (N - 2*s) * α -> W = 2b - 1; the one-to-one mapping is preserved Application note: XOR is not applied separately; the number of matches is obtained as mac = N − popcount(XOR(w, x)), and unused padding bits are masked with valid_bits. Performance expectation: 537M 1-bit MACs complete in a few milliseconds on a desktop CPU with AVX2/AVX-512; UNet’s conv section targets a total of ~20–50 ms over 4 LCM steps. Negative weights and activations: The sign is handled directly via the b → ±1 mapping and in the XOR/popcount formula; no four-phase pipeline or additional sign hardware is required. 4. Weight Distribution Line: FC with Transport The FC line is the transport layer that distributes weights to the computation unit. The ISP8324 implements the FCP/SCSI protocol hierarchy (FC-2 framing, CRC, idle, 64b/66B + scrambling, 14.025 Gbps) in hardware; . Path: .bin + JSON → mmap → sg/bsg (SG_IO, WRITE(16)) and/or SCST target → 4× QLE2660 parallel. Four ports are mapped to four file slices; the byte_offset is preserved. User space does not write directly to the DMA buffer; the driver manages the buffer and mapping. Mapping: Four ports are mapped to four separate file segments; the byte_offset logic in the index file is preserved exactly. Software flow: .bin → read bytes at the relevant offset/length → send the request to the selected transfer API → the kernel/driver manages the buffer + DMA mapping → QLogic HBA → FC connection. qla2xxx: Operation in initiator + target mode (qlini_mode); the design goal is DDP in target mode and mmap + io_uring in initiator mode. This must be verified based on the driver version. 5. Bandwidth: The calculation in the previous version—“total ~54.4 Gbit/s effective, 67.19 MB ~9.88 ms”—is optimistic; 54.4 Gbit/s is close to the raw/theoretical total of 4×16GFC and does not include FC frame overhead. Item This version (effective, to be verified) Total bandwidth ~48–51 Gbit/s (4× ~12.8 Gbit/s) 67.19 MB weight set ~11–14 ms Four lanes operate in parallel and simultaneously; weights are loaded in parallel, not sequentially. The time is now calculated based on effective bandwidth. 6. Storage: TIFF → .bin + JSON Index Addressing the weights in software and transferring them as binary data is a suitable arrangement. The .bin file merely changes the quantization method of the storage format. The benefit is the elimination of raster/label separation and the ability to directly address tensors using `byte_offset`. 7. Conversion Code import numpy as np # If `weights` is a PyTorch Tensor: w = weights.detach().cpu().numpy() # Encoding: positive -> 1; zero and negative -> 0 bits = (w > 0).astype(np.uint8).ravel(order=“C”) # The first weight is in the most significant bit of the first byte. packed = np.packbits(bits, bitorder="big") packed.tofile(“sd15_resblock_weights_1bit.bin”) bitorder="big" is explicitly specified; Python and C# use the same convention. NumPy pads with zeros at the end; padding bits are excluded via valid_bits. The quantization method remains unchanged; 8. JSON Index File A single .bin file does not carry tensor boundaries, shapes, and scales on its own. A JSON index is included alongside it so that C# can select the correct ResBlock weights. The simplest layout: each tensor is packed separately using packbits and appended to the file at the byte boundary; thus, the start of each tensor can be located directly using the byte_offset. A maximum of seven packbits can be generated per tensor. { “bitorder”: “big”, “flatten_order”: “C”, “mapping”: “bit 1 -> +1, bit 0 -> -1”, “tensors”: [ { “name”: “tensor_name”, “shape”: [320, 320, 3, 3], “byte_offset”: 0, “byte_length”: 115200, “valid_bits”: 921600, “scale_reference”: “relevant_scale_record” } ] } “A maximum of 7 padding bits are generated per tensor; these are excluded by `valid_bits`.” 9. Reading in C# byte[] allWeights = File.ReadAllBytes(“sd15_resblock_weights_1bit.bin”); ReadOnlySpan<byte> tensorBytes = allWeights.AsSpan(byteOffset, byteLength); // A weight bit at a local tensor index for bitorder="big": int bit = (tensorBytes[i >> 3] >> (7 - (i & 7))) & 1; int signedWeight = 2 * bit - 1; This section involves loading the byte array read from the file into the application buffer. The next step—“passing it to the HBA”—is a separate phase and is performed via the driver/API described in Section 4. 10. Python / C# Task Distribution Python server: coordination — sign calculation, α/bias metadata, LCM loop. C# side: XOR/popcount kernel + sg/bsg transfer. Shared memory (mmap) between them — the FC pipeline is used solely for weight distribution. The transformation pipeline remains the same: np.packbits(bitorder=“big”) + JSON index. 11. Verification Checklist (Perplexity Added) The FC’s contribution to acceleration should also be demonstrated If the weights can be reused once they are loaded into the PC’s RAM, there is no need to transfer them from the FC again in each layer or LCM step. Therefore, the following times should be measured separately: Initial weight loading. CPU computation. CPU–GPU activation transfer. End-to-end four-step image generation.
No takes yet. Share an insight, caveat, or question.
kamil yaşar kalkan (2026) studied this question.
Synapse has enriched 8 closely related papers on similar clinical questions. Consider them for comparative context: