← Kembali ke artikel
August 14, 2026
Bacaan 5 minit

Model Pruning for Low-Latency Trading Inference

Model Pruning for Low-Latency Trading Inference
#model-compression
#pruning
#lottery-ticket
#latency
#deployment

Artikel DeepLOB kami mengakhiri bahagian deployment dengan tiga pilihan — ONNX bersama TensorRT, quantization INT8 dan FPGA — tanpa menghuraikan mana-mana daripadanya. Artikel ini mengisi masalah pertama di bawah ketiga-tiganya: model lebih besar daripada yang diperlukan. Neural network pruning membuang parameter berlebihan, dan dakwaan menarik dalam literatur bukan sekadar penjimatan memori, tetapi bahawa subnetwork yang memegang 10-20% weight boleh menyamai accuracy model dense.

Blog ini sudah menunjukkan mengapa latency penting — ZigBolt pada laluan messaging dan cukai IPC dengan matematik break-even — manakala spread modeling telah membincangkan pertukaran pantas-tetapi-sedikit-lebih-buruk berbanding perlahan-tetapi-lebih-baik, lengkap dengan jadual gradient boosting berbanding deep learning yang mempunyai baris inference latency. Tiada satu pun menerangkan bagaimana mengecilkan model tertentu. Dalam peringkat quoting loop, model inference ialah bahagian yang sepenuhnya di bawah kawalan kita; bahagian transport dengan angka p50/p95/p99 yang boleh diulang diterangkan dalam komunikasi data untuk algotrading.

Artikel ini ialah: matematik dan kod yang berfungsi untuk magnitude pruning, structured pruning, Iterative Magnitude Pruning, movement pruning, knowledge distillation dan semi-structured sparsity NVIDIA 2:4, yang diterapkan pada MLP dagangan.

Artikel ini bukan: hasil yang telah diukur. Setiap artikel empirikal di blog ini mempunyai baris provenance atau repo pendamping, dan artikel ini belum mempunyai kedua-duanya. Lengkung sparsity-versus-accuracy-versus-latency di bawah ialah eksperimen yang perlu dijalankan, bukan jadual untuk dipetik. Anggap semua kandungan di sini sebagai kaedah, manakala nombornya masih menunggu ukuran.

Apa yang Diberikan oleh Pruning

Rangkaian neural kompak yang muat dalam lapisan cache pantas

Kekangannya ialah saiz. Pertimbangkan model mid-frequency — MLP 4 lapisan dengan 2048 unit tersembunyi untuk feature order book:

Parameters=dinh+h2(L1)+hdout\text{Parameters} = d_{\text{in}} \cdot h + h^2 \cdot (L - 1) + h \cdot d_{\text{out}}

Untuk din=100d_{\text{in}} = 100, h=2048h = 2048, L=4L = 4, dout=3d_{\text{out}} = 3, jumlahnya kira-kira 12.6 juta parameter — sekitar 48 MB dalam float32. L2 biasanya 1-4 MB, jadi weight tidak muat dan perlu distrim dari memori lebih jauh pada setiap forward pass. Prune 95% daripadanya dan anda mendapat kira-kira 630K parameter berkesan dan 2.4 MB, yang memang muat.

Sama ada ia diterjemahkan kepada wall-clock time bergantung pada sama ada kernel memory-bound, dan itu soalan arithmetic intensity, bukan saiz. Tangga kelajuan backtest engine menggunakan roofline model (Williams, Waterman & Patterson) melalui contoh yang diukur, bukannya menganggap penalty factor; kerangka yang sama terpakai di sini, begitu juga disiplin yang sama: ukur bytes yang dipindahkan sebelum mendakwa speedup.

Asas Pruning

Structured dan unstructured pruning merentasi lattice neural

Unstructured Pruning

Pendekatan paling mudah ialah menetapkan weight individu kepada sifar berdasarkan magnitudnya. Diberi weight matrix WRm×n\mathbf{W} \in \mathbb{R}^{m \times n}, bina binary mask M{0,1}m×n\mathbf{M} \in \{0, 1\}^{m \times n} seperti berikut:

Mij={1if Wijτ0if Wij<τM_{ij} = \begin{cases} 1 & \text{if } |W_{ij}| \geq \tau \\ 0 & \text{if } |W_{ij}| < \tau \end{cases}

di mana τ\tau ialah threshold yang dipilih untuk mencapai tahap sparsity ss yang dikehendaki:

s=1M0mns = 1 - \frac{\|\mathbf{M}\|_0}{m \cdot n}

Matrix yang dipruning ialah W=WM\mathbf{W}' = \mathbf{W} \odot \mathbf{M}, dengan \odot ialah hasil darab Hadamard. Intuisinya ialah weight yang hampir sifar hanya sedikit menyumbang kepada output layer.

Masalahnya, secara terus terang kerana nombor sparsity mudah disalah baca: unstructured sparsity tidak semestinya menghasilkan speedup pada hardware standard. Matrix dengan 90% sifar masih mengeluarkan bilangan multiply-accumulates yang sama kecuali anda menggunakan sparse kernels atau hardware yang menyokong sparsity. Apabila kod di bawah mencetak Sparsity: 90.0%, itu ialah kiraan sifar — bukan 10x apa-apa, dan pada dense CPU GEMM juga bukan 1.01x. Laluan yang benar-benar menjimatkan masa ialah structured pruning (matrix lebih kecil) dan semi-structured sparsity 2:4 (sokongan hardware), kedua-duanya diterangkan di bawah.

Structured Pruning

Structured pruning membuang seluruh neuron, channel atau attention head. Untuk linear layer y=Wx+b\mathbf{y} = \mathbf{W}\mathbf{x} + \mathbf{b} dengan WRm×n\mathbf{W} \in \mathbb{R}^{m \times n}, membuang neuron jj menjadikan baris ke-jj bagi W\mathbf{W} dan elemen ke-jj bagi b\mathbf{b} sifar:

importance(j)=Wj,:2=k=1nWjk2\text{importance}(j) = \|\mathbf{W}_{j,:}\|_2 = \sqrt{\sum_{k=1}^{n} W_{jk}^2}

Neuron dengan 2\ell_2-norm terkecil dibuang dahulu. Varian ini menghasilkan matrix yang benar-benar lebih kecil — tetapi hanya jika layer dibina semula. Menjadikan baris sifar sambil mengekalkan bentuk asal tensor tidak mengubah kiraan FLOP; langkah rebuild dalam bahagian implementasi menukar mask menjadi matrix 512×n512 \times n.

Untuk convolutional layers, padanannya ialah filter pruning. Diberi WRCout×Cin×k×k\mathbf{W} \in \mathbb{R}^{C_{\text{out}} \times C_{\text{in}} \times k \times k}, kepentingan output filter ii ialah:

importance(i)=Wi,:,:,:F=c,h,wWi,c,h,w2\text{importance}(i) = \|\mathbf{W}_{i,:,:,:}\|_F = \sqrt{\sum_{c,h,w} W_{i,c,h,w}^2}

Membuang filter ii menghapuskan seluruh output channel dan mengurangkan FLOP secara berkadar.

Hipotesis Lottery Ticket

Subnetwork pemenang kecil diasingkan dalam lattice neural yang besar

Pada 2019, Frankle dan Carbin memperkenalkan Hipotesis Lottery Ticket (LTH): dalam dense network yang diinisialisasi secara rawak terdapat subnetwork sparse — "winning ticket" — yang, apabila dilatih daripada initialization asal, menyamai accuracy network penuh dalam bilangan iteration yang setanding.

Secara formal, pertimbangkan f(x;θ0)f(\mathbf{x}; \boldsymbol{\theta}_0) yang diinisialisasi dengan θ0Dθ\boldsymbol{\theta}_0 \sim \mathcal{D}_\theta. Selepas latihan mencapai convergence, kita memperoleh θ\boldsymbol{\theta}^* dan membina pruning mask m\mathbf{m}. LTH menyatakan wujud m\mathbf{m} sedemikian rupa sehingga:

f(x;mθ0)trainθmwhereacc(θm)acc(θ)f(\mathbf{x}; \mathbf{m} \odot \boldsymbol{\theta}_0) \xrightarrow{\text{train}} \boldsymbol{\theta}_m^* \quad \text{where} \quad \text{acc}(\boldsymbol{\theta}_m^*) \geq \text{acc}(\boldsymbol{\theta}^*)

dengan m0θ0\|\mathbf{m}\|_0 \ll |\boldsymbol{\theta}_0|. Eksperimen asal menggunakan MNIST dan CIFAR-10, dengan winning ticket mengekalkan 10-20% parameter. Tiada sebab untuk menganggap hasil itu berpindah kepada data order book — feature LOB tidak stationari dan label hampir seperti noise, iaitu regime yang berbeza daripada klasifikasi imej dalam perkara yang mungkin penting.

Iterative Magnitude Pruning (IMP)

Ticket ditemui melalui IMP:

  1. Inisialisasikan network dengan θ0\boldsymbol{\theta}_0.
  2. Latih sehingga convergence untuk memperoleh θ\boldsymbol{\theta}^*.
  3. Prune p%p\% weight yang mempunyai magnitud terkecil dan bina mask m\mathbf{m}.
  4. Reset weight yang terselamat kepada nilainya dalam θ0\boldsymbol{\theta}_0 (rewinding).
  5. Ulangi dari langkah 2 dengan network yang mempunyai mask.

Setiap pusingan memangkas pecahan pp (biasanya 20%), maka selepas nn pusingan (1p)n(1-p)^n parameter masih kekal. Selepas 10 pusingan dengan p=0.2p = 0.2, kira-kira 10.7% masih tinggal.

Tiga Hipotesis tentang Model Dagangan, Tiada Satu Pun Diuji

Mudah untuk berhujah bahawa LTH sepatutnya berfungsi dengan baik pada data pasaran. Tiga hujah muncul; kesemuanya hipotesis, dan menyatakannya sebagai fakta ialah kesilapan yang cuba dielakkan oleh blog ini.

  1. Signal kewangan adalah sparse. Kebanyakan snapshot order book ialah noise, jadi subnetwork sparse mungkin selari secara semula jadi dengan signal sparse. Boleh diuji: bandingkan IMP dengan random mask yang mempunyai sparsity sama; jika sparsity itu sendiri yang bekerja, random mask tidak sepatutnya jauh ketinggalan.
  2. Winning ticket membuat generalisasi merentas regime. Ini ialah dakwaan empirikal tentang pasaran tanpa citation, dan paling menarik antara tiga hujah. Ia boleh diuji terus terhadap label regime daripada pengesanan regime dengan HMM: cari ticket dalam regime A, latih semula dalam regime B, dan bandingkan dengan ticket yang ditemui secara native dalam B.
  3. Sparsity melakukan regularisasi. Kapasiti berkesan yang lebih rendah mungkin mengurangkan fitting kepada noise microstructure — yang akan muncul sebagai jurang out-of-sample model pruned yang lebih kecil daripada model dense, bukan sekadar setanding.

Implementasi: Pruning MLP Dagangan

Layer neural diubah melalui sparse mask yang tepat

Model Asas

import torch
import torch.nn as nn
import torch.nn.utils.prune as prune
from copy import deepcopy

class TradingMLP(nn.Module):
    """MLP for mid-price direction prediction from order book features."""
    def __init__(self, input_dim=100, hidden_dim=2048,
                 num_layers=4, output_dim=3):
        super().__init__()
        layers = []
        dims = [input_dim] + [hidden_dim] * (num_layers - 1) + [output_dim]
        for i in range(len(dims) - 1):
            layers.append(nn.Linear(dims[i], dims[i + 1]))
            if i < len(dims) - 2:
                layers.append(nn.BatchNorm1d(dims[i + 1]))
                layers.append(nn.ReLU())
                layers.append(nn.Dropout(0.1))
        self.network = nn.Sequential(*layers)

    def forward(self, x):
        return self.network(x)

    def count_parameters(self):
        return sum(p.numel() for p in self.parameters())

model = TradingMLP(input_dim=100, hidden_dim=2048,
                   num_layers=4, output_dim=3)
print(f"Total parameters: {model.count_parameters():,}")

Unstructured Magnitude Pruning

def apply_unstructured_pruning(model, sparsity=0.9):
    """Apply global unstructured L1 pruning to all Linear layers."""
    parameters_to_prune = []
    for name, module in model.named_modules():
        if isinstance(module, nn.Linear):
            parameters_to_prune.append((module, 'weight'))

    prune.global_unstructured(
        parameters_to_prune,
        pruning_method=prune.L1Unstructured,
        amount=sparsity,
    )
    return model

def compute_sparsity(model):
    """Fraction of zero weights. Note: a *count*, not a speedup."""
    total, zeros = 0, 0
    for name, param in model.named_parameters():
        if 'weight' in name:
            total += param.numel()
            zeros += (param == 0).sum().item()
    return zeros / total if total > 0 else 0

pruned_model = apply_unstructured_pruning(deepcopy(model), sparsity=0.9)
print(f"Sparsity: {compute_sparsity(pruned_model):.1%}")

Structured Pruning dengan Rebuild yang Menjadikannya Nyata

Masking baris hanyalah separuh kerja. Separuh yang menghasilkan speedup ialah membina semula setiap layer dengan bentuk yang lebih kecil — ini bermaksud penyingkiran perlu disebarkan ke hadapan: membuang baris jj daripada layer ii turut membuang lajur jj daripada layer i+1i+1 dan channel jj bagi mana-mana BatchNorm1d di antaranya.

def apply_structured_pruning(model, fraction=0.75):
    """Mask entire neurons by L2-norm of their weight rows."""
    for name, module in model.named_modules():
        if isinstance(module, nn.Linear) and module.out_features > 10:
            prune.ln_structured(
                module, name='weight', amount=fraction, n=2, dim=0
            )
    return model

def rebuild_pruned_mlp(model):
    """
    Physically shrink a structurally pruned TradingMLP.

    Walks the Sequential once. For each Linear: drop the input columns
    the previous layer no longer emits, then drop its own dead output
    rows. BatchNorm1d channels follow the preceding Linear's survivors.
    """
    new_layers = []
    keep_in = None  # surviving output indices of the previous Linear

    for layer in model.network:
        if isinstance(layer, nn.Linear):
            if prune.is_pruned(layer):
                prune.remove(layer, 'weight')

            W, b = layer.weight.data, layer.bias.data
            keep_out = (W.norm(dim=1) > 0).nonzero(as_tuple=True)[0]
            W = W[keep_out]
            if keep_in is not None:
                W = W[:, keep_in]

            new = nn.Linear(W.shape[1], W.shape[0])
            new.weight.data = W.clone()
            new.bias.data = b[keep_out].clone()
            new_layers.append(new)
            keep_in = keep_out

        elif isinstance(layer, nn.BatchNorm1d):
            new = nn.BatchNorm1d(len(keep_in))
            new.weight.data = layer.weight.data[keep_in].clone()
            new.bias.data = layer.bias.data[keep_in].clone()
            new.running_mean = layer.running_mean[keep_in].clone()
            new.running_var = layer.running_var[keep_in].clone()
            new.num_batches_tracked = layer.num_batches_tracked.clone()
            new_layers.append(new)

        else:  # ReLU, Dropout -- shape-agnostic, reuse as is
            new_layers.append(layer)

    rebuilt = deepcopy(model)
    rebuilt.network = nn.Sequential(*new_layers)
    return rebuilt

Dua perkara perlu diperiksa sebelum mempercayainya, selaras dengan equivalence gate yang digunakan oleh bahagian lain blog ini:

  • Shapes. rebuilt sepatutnya menunjukkan dimensi hidden pada (1fraction)h(1 - \text{fraction}) \cdot h — 512 untuk fraction=0.75, h=2048h = 2048 — dan bilangan parameter yang jatuh secara kuadratik kerana kedua-dua dimensi matrix dalaman mengecil.
  • Outputs. Dalam mod eval(), rebuilt(x) mesti sepadan dengan output model bermask tanpa rebuilt dalam toleransi floating-point pada batch yang sama. Jika tidak, propagasi lajur salah dan setiap nombor downstream sedang mengukur model yang berbeza daripada sangkaan anda.

Ujian row-survival menganggap baris bermask betul-betul sifar dan baris aktif bukan sifar. Ini benar untuk output ln_structured; ia tidak semestinya benar jika prosedur lain menghasilkan neuron aktif yang benar-benar sifar, jadi sahkan bilangan yang terselamat terhadap pecahan yang diminta dan jangan mempercayai ujian norm secara membuta tuli.

Iterative Magnitude Pruning (Carian Lottery Ticket)

def lottery_ticket_search(model_cls, model_kwargs, train_fn, eval_fn,
                          rounds=10, prune_rate=0.2, device='cpu'):
    """
    Iterative Magnitude Pruning to find a winning ticket.

    Parameters
    ----------
    model_cls : class -- model constructor
    model_kwargs : dict -- constructor arguments
    train_fn : callable -- train_fn(model) trains the model in-place
    eval_fn : callable -- eval_fn(model) returns out-of-sample accuracy
    rounds : int -- number of pruning rounds
    prune_rate : float -- fraction of surviving weights pruned per round
    """
    model_init = model_cls(**model_kwargs).to(device)
    theta_0 = deepcopy(model_init.state_dict())

    mask = {}
    for name, param in model_init.named_parameters():
        if 'weight' in name:
            mask[name] = torch.ones_like(param, dtype=torch.bool)

    results = []

    for round_idx in range(rounds):
        model = model_cls(**model_kwargs).to(device)
        state = deepcopy(theta_0)
        for name in mask:
            state[name] = state[name] * mask[name].float()
        model.load_state_dict(state)

        train_fn(model)

        acc = eval_fn(model)
        surviving = sum(m.sum().item() for m in mask.values())
        total = sum(m.numel() for m in mask.values())
        sparsity = 1.0 - surviving / total

        results.append({
            'round': round_idx,
            'accuracy': acc,
            'sparsity': sparsity,
            'surviving_params': int(surviving)
        })
        print(f"Round {round_idx}: acc={acc:.4f}, "
              f"sparsity={sparsity:.1%}")

        all_weights = []
        for name, param in model.named_parameters():
            if name in mask:
                alive = param.data.abs()[mask[name]]
                all_weights.append(alive.flatten())

        all_weights = torch.cat(all_weights)
        k = int(len(all_weights) * prune_rate)
        if k == 0:
            break
        threshold = all_weights.kthvalue(k).values.item()

        for name, param in model.named_parameters():
            if name in mask:
                mask[name] = mask[name] & (
                    param.data.abs() >= threshold
                )

    return results, mask

results ialah bahan mentah untuk lengkung sparsity-versus-accuracy yang perlu disediakan oleh artikel ini. eval_fn mesti benar-benar out-of-sample pada split yang telah dipurge — IMP yang diberi skor in-sample akan melaporkan lengkung cantik yang tidak bermakna.

Mengukurnya

Frontier kecekapan abstrak yang mengimbangi sparsity, accuracy dan latency

Latency diukur dengan konvensyen harness yang sama seperti bahagian lain blog — warmup dikecualikan, best-of-N, dan p50/p95/p99 dilaporkan bukannya mean — dengan protokol dan kod dalam Polars berbanding pandas. Tiga perkara khusus untuk pruning:

  • Benchmark model rebuilt, bukan model bermask. Model bermask pada batch size 1 mengukur bentuk dense.
  • Laporkan batch size. Batch 1 (quoting loop) dan batch 256 (research sweep) berada di sisi berbeza garis memory-bound/compute-bound, dan pruning membantu kedua-duanya dengan cara berbeza.
  • Laporkan accuracy pada split dan horizon yang sama, dengan definisi label dinyatakan. Jadual latency tanpa lajur accuracy sepadan ialah hujah untuk memadam model itu sepenuhnya.

Teknik Lanjutan

Laluan pemampatan network lanjutan yang bertemu dalam satu model cekap

Pruning dengan Knowledge Distillation

Daripada menjalankan pruning dan fine-tuning secara berasingan, gunakan model dense asal sebagai teacher. Student yang dipruning meminimumkan gabungan task loss dan KL divergence daripada taburan output teacher:

L=(1α)Ltask(y,y^s)+αT2DKL(σ(ztT)σ(zsT))\mathcal{L} = (1 - \alpha) \cdot \mathcal{L}_{\text{task}}(\mathbf{y}, \hat{\mathbf{y}}_s) + \alpha \cdot T^2 \cdot D_{\text{KL}}\left(\sigma\left(\frac{\mathbf{z}_t}{T}\right) \| \sigma\left(\frac{\mathbf{z}_s}{T}\right)\right)

di mana zt\mathbf{z}_t dan zs\mathbf{z}_s ialah logits teacher dan student, TT ialah temperature, dan α\alpha mengimbangi objektif. Faktor T2T^2 menskala semula gradient distillation yang sebaliknya mengecil sebagai 1/T21/T^2.

def distillation_loss(student_logits, teacher_logits, labels,
                      temperature=3.0, alpha=0.5):
    """Combined task + distillation loss."""
    task_loss = nn.CrossEntropyLoss()(student_logits, labels)

    soft_student = nn.functional.log_softmax(
        student_logits / temperature, dim=-1
    )
    soft_teacher = nn.functional.softmax(
        teacher_logits / temperature, dim=-1
    )
    kd_loss = nn.functional.kl_div(
        soft_student, soft_teacher, reduction='batchmean'
    )

    return (1 - alpha) * task_loss + alpha * (temperature ** 2) * kd_loss

Movement Pruning

Daripada memangkas mengikut magnitud mutlak, movement pruning (Sanh et al., 2020) memangkas weight yang bergerak ke arah sifar semasa latihan. Skor kepentingan mengumpulkan hasil darab gradient-weight:

Sij(t)=Sij(t1)+Wij(t)Wij(t1)sign(Wij(t)LWij(t))S_{ij}^{(t)} = S_{ij}^{(t-1)} + \left| W_{ij}^{(t)} - W_{ij}^{(t-1)} \right| \cdot \text{sign}\left(W_{ij}^{(t)} \cdot \frac{\partial \mathcal{L}}{\partial W_{ij}^{(t)}}\right)

Weight dengan skor negatif dipruning. Hujah untuk memilihnya berbanding magnitude pruning khusus berkaitan fine-tuning: apabila menyesuaikan model pra-latih, taburan magnitud dibentuk oleh tugas pra-latihan, jadi magnitud ialah signal kepentingan yang lapuk dan arah pergerakan ialah signal yang lebih baharu. Untuk model dagangan yang dilatih semula pada rolling window, situasi itu lebih biasa daripada latihan dari awal.

Structured Sparsity NVIDIA 2:4

GPU NVIDIA Ampere dan yang lebih baharu menyokong structured sparsity 2:4 dalam hardware: daripada setiap 4 weight bersebelahan, tepat 2 mesti sifar.

i,W[4i:4i+4]0=2\forall i, \quad \|\mathbf{W}_{[4i:4i+4]}\|_0 = 2

Ini satu-satunya bentuk fine-grained sparsity yang benar-benar diberi ganjaran oleh hardware, sebab itu ia lebih penting daripada angka 90% sifar daripada unstructured pruning. Kekangannya bersifat lokal, bukan global — ia tidak peduli dua yang mana daripada setiap empat kekal — jadi sekatannya jauh lebih lemah daripada menetapkan global mask, walaupun 50% ialah satu-satunya tahap sparsity yang tersedia.

from torch.ao.pruning import WeightNormSparsifier

sparsifier = WeightNormSparsifier(
    sparsity_level=0.5,
    sparse_block_shape=(1, 4),
    zeros_per_block=2,
)

sparsifier.prepare(
    model, config=[{"tensor_fqn": "network.0.weight"}]
)
sparsifier.step()
sparsifier.squash_mask()

Untuk merealisasikan speedup, laluan inference mesti menggunakan sparse tensor cores — export ONNX bersama build TensorRT, atau torch.sparse.to_sparse_semi_structured. Mengeksport model bermask 2:4 melalui dense runtime memberi kos accuracy tanpa sebarang manfaat.

Deployment Production

Model inference ringan memasuki saluran hardware latensi rendah

Validation

Model yang dipruning ialah model baharu, bukan model lama yang dimampatkan, dan ia melalui acceptance gate yang sama seperti calon lain: rolling retraining dan out-of-sample revalidation mengikut walk-forward optimization, dengan pembetulan selection effect daripada deflated Sharpe ratio. Pembetulan itu tidak boleh diketepikan — IMP menghasilkan urutan model calon, jadi tahap sparsity yang kelihatan terbaik merentas sepuluh pusingan dipilih melalui carian, dan Sharpe-nya perlu dideflate mengikut bilangan percubaan berkesan. Peraturan rata seperti "tolak jika Sharpe jatuh lebih 5%" tidak bertahan dengan matematik itu, sebab itu anda tidak akan menemuinya dalam artikel ini.

Stacking Quantization

Pruning boleh digabungkan dengan quantization. Model 90% sparse yang diquantize kepada INT8 mempunyai nisbah pemampatan:

CR=1(1s)boriginalbquantized=10.1328=40×\text{CR} = \frac{1}{(1 - s)} \cdot \frac{b_{\text{original}}}{b_{\text{quantized}}} = \frac{1}{0.1} \cdot \frac{32}{8} = 40\times

Model 48 MB menjadi 1.2 MB. Itu dakwaan tentang storan sahaja dan tidak lebih. Sama ada model 1.2 MB menghasilkan keputusan yang sama ialah soalan berasingan, dan perangkap precision GPU ialah sebab untuk bertanya: blog ini telah menunjukkan fp32 sahaja boleh menghasilkan relative error 211 dalam pengiraan backtest yang kelihatan munasabah. INT8 ialah pengurangan yang jauh lebih agresif. Hanya deploy model yang diquantize dan dipruning selepas lulus parity gate berangka berbanding model dense fp32 — kadar keputusan sepadan dan delta PnL pada tempoh held-out, bukan jaminan.

Monitoring

Model yang dipruning mungkin lebih sensitif terhadap distribution shift. Perkara yang wajar dipantau:

  • Activation sparsity: jika neuron yang terselamat kebanyakannya mengeluarkan sifar, model berkesan lebih kecil daripada yang dirancang dan mungkin sedang merosot.
  • Gradient norms semasa retraining: gradient yang meletup menunjukkan subnetwork yang terselamat diminta mengimbangi bahagian yang dibuang secara terlalu agresif.
  • Prediction entropy: model pruned yang menjadi terlalu yakin pada data microstructure ber-noise mungkin sedang overfit kepada training regime.

Kesimpulan

Rangkaian neural kompak dan cekap yang muncul daripada ketidakpastian dense

Kaedah-kaedah ini sudah kukuh, dan sehingga sweep dijalankan, itulah sahaja dakwaan artikel ini. Unstructured pruning memberi angka sparsity tetapi tiada speed. Structured pruning memberi speed jika — dan hanya jika — layer dibina semula, bukan sekadar dimask. Hipotesis Lottery Ticket mencadangkan model kompak sudah wujud dalam model berparameter berlebihan, walaupun ia dibuktikan pada benchmark imej dan bukan data order book; tiga sebab bahawa ia "sepatutnya" berfungsi pada data pasaran ialah hipotesis bersama eksperimen, bukan dapatan.

Heuristik praktikal daripada literatur ialah melatih model besar kemudian memangkasnya, bukannya mereka bentuk model kecil sejak awal: model besar meneroka loss landscape dengan lebih berkesan, dan pruning mengekalkan laluan yang penting. Sama ada ini terpakai pada model dagangan, pada tahap sparsity berapa dan dengan kos accuracy berapa, hanya memerlukan satu IMP sweep — dan artikel ini patut dibaca semula selepas sweep itu, dengan nombor sebenar.

Penafian: Maklumat yang disediakan dalam artikel ini adalah untuk tujuan pendidikan dan maklumat sahaja dan bukan merupakan nasihat kewangan, pelaburan, atau dagangan. Dagangan mata wang kripto melibatkan risiko kerugian yang ketara.

Pengarang

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Kekal Mendahului Pasaran

Langgan surat berita kami untuk pandangan dagangan AI eksklusif, analisis pasaran, dan kemas kini platform.

Kami menghormati privasi anda. Berhenti melanggan pada bila-bila masa.