← Макалаларга кайтуу
August 14, 2026
5 мүн окуу

Model Pruning for Low-Latency Trading Inference

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

Биздин DeepLOB жөнүндөгү макалабыз жайылтуу бөлүмүн үч сунуш менен аяктайт - ONNX жана TensorRT, INT8 кванттоосу жана FPGA - бирок алардын бирин да карабайт. Бул макала үчөөнө тең тиешелүү биринчи көйгөйдү талдайт: модель зарыл болгондон чоң. Нейрондук тармакты кыскартуу ашыкча параметрлерди алып салат. Адабияттагы кызыктуу доомат эс тутум үнөмдөлөт дегенде эмес, салмактардын 10-20% гана калган ички тармак тыгыз моделдин тактыгына жете алат дегенде.

Кечигүүнүн маанилүү экени блогдо буга чейин көрсөтүлгөн: билдирүү жолундагы ZigBolt жана чыгымсыздык эсептериндеги IPC төлөмү. Ал эми спредди моделдөө тез, бирок бир аз начар жана жай, бирок жакшы варианттардын ортосундагы тандоону, анын ичинде градиенттик күчөтүү менен терең үйрөнүүнү салыштырган жана тыянак чыгаруу кечигүүсү көрсөтүлгөн таблицаны камтыйт. Бирок бул материалдардын эч бири берилген моделди кантип кичирейтүүнү түшүндүрбөйт. Котировка циклиндеги баскычтардын ичинен моделди иштетүү толугу менен биздин көзөмөлүбүздө; транспорт баскычтары болсо алготрейдингдеги маалымат алмашуу материалында кайра кайталана турган p50/p95/p99 сандары менен өлчөнгөн.

Бул макалада эмне бар: соода MLP моделине колдонулган чоңдук боюнча кыскартуунун, структураланган кыскартуунун, итеративдүү чоңдук боюнча кыскартуунун, кыймыл боюнча кыскартуунун, билимди дистилляциялоонун жана NVIDIAнын 2:4 жарым-жартылай структураланган сейректигинин математикасы жана иштеген коду.

Бул эмне эмес: өлчөнгөн натыйжа эмес. Бул блогдогу ар бир эмпирикалык макалада маалыматтын булагын көрсөткөн сап же кошумча репозиторий бар, ал эми мында азырынча экөө тең жок. Төмөндө сейректүүлүк-тактык-кечигүү ийри сызыгы цитата келтириле турган таблица эмес, аткарылышы керек болгон эксперимент катары берилет. Бул жердеги нерселерди ыкма, ал эми сандарды али алынбаган натыйжа катары кабыл алыңыз.

Кыскартуу эмнени берет

Ыкчам нейрон тармагы тез кэш катмарына батат

Чектөө бул жерде өлчөмгө байланыштуу. Орто жыштыктагы моделди карап көрөлү: буйрук китебинин белгилери үчүн 2048 жашыруун бирдиги бар төрт катмарлуу MLP:

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

Мында din=100d_{\text{in}} = 100, h=2048h = 2048, L=4L = 4, dout=3d_{\text{out}} = 3 болсо, болжол менен 12,6 миллион параметр чыгат - float32 форматында болжол менен 48 МБ. L2 кэши адатта 1-4 МБ болгондуктан, салмактар ага батпайт; ар бир түз өтүүдө алар алысыраак эс тутумдан агылып келет. Салмактардын 95% кыскартылса, болжол менен 630 миң натыйжалуу параметр жана 2,4 МБ калат - бул кэшке батат.

Мунун дубалдагы убакытка айланышы ядронун эс тутумуна байланыштуубу же жокпу, ошого көз каранды; демек, бул өлчөм эмес, арифметикалык интенсивдүүлүк маселеси. Бэктест кыймылдаткычынын ылдамдык тепкичи roofline моделин (Уильямс, Уотерман жана Паттерсон) жаза коэффициентин болжолдобой, өлчөнгөн мисал аркылуу түшүндүрөт. Бул жерде да ошол эле алкак жана тартип колдонулат: ылдамдоо тууралуу доомат коюудан мурун көчүрүлгөн байттарды өлчөңүз.

Кыскартуунун негиздери

Нейрондук тармактагы структураланган жана структураланбаган кыскартуу

Структураланбаган кыскартуу

Эң жөнөкөй ыкма - жеке салмактарды чоңдугуна жараша нөлгө түшүрүү. Салмак матрицасы WRm×n\mathbf{W} \in \mathbb{R}^{m \times n} берилсе, төмөнкүдөй бинардык маска түзүлөт: M{0,1}m×n\mathbf{M} \in \{0, 1\}^{m \times n}

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

мында τ\tau - керектүү сейректүүлүк деңгээлине жетүү үчүн тандалган босого, ал эми ss:

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

Кыскартылган матрица W=WM\mathbf{W}' = \mathbf{W} \odot \mathbf{M} болот, мында \odot - Адамардын көбөйтүүсү. Интуициясы жөнөкөй: нөлгө жакын салмактар катмардын чыгышына аз салым кошот.

Маселе ачык айтылышы керек, анткени сейректүүлүк санын туура эмес түшүнүү оңой: структураланбаган сейректүүлүк кадимки жабдыкта ылдамдыкка айланбайт. 90% нөлү бар матрица сейрек ядролорго же сейректүүлүктү колдогон жабдыкка өтмөйүнчө, мурдагыдай эле сандагы көбөйтүү-топтоону аткарат. Төмөнкү код Sparsity: 90.0% деп чыгарса, бул нөлдөрдүн үлүшү гана - 10 эсе ылдамдык эмес, ал эми тыгыз CPU GEMM үчүн 1,01 эсе да эмес. Чындап убакыт үнөмдөгөн жолдор - структураланган кыскартуу (кичине матрицалар) жана 2:4 жарым-жартылай структураланган сейректүүлүк (жабдык колдоосу); экөө тең төмөндө берилет.

Структураланган кыскартуу

Структураланган кыскартуу бүт нейрондорду, каналдарды же көңүл буруу баштарын алып салат. y=Wx+b\mathbf{y} = \mathbf{W}\mathbf{x} + \mathbf{b} болгон, WRm×n\mathbf{W} \in \mathbb{R}^{m \times n} сызыктуу катмарында jj нейронун алып салуу jj-катарды W\mathbf{W} матрицасында жана jj-элементти b\mathbf{b} векторунда нөлгө түшүрөт:

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

Эң кичине 2\ell_2 нормалуу нейрондор биринчи алынат. Бул чындап кичине матрицаларды бере турган вариант, бирок катмарларды чындап кайра курганда гана. Катарларды нөлгө түшүрүп, тензорду баштапкы өлчөмүндө калтыруу FLOP санын өзгөртпөйт; ишке ашыруу бөлүмүндөгү кайра куруу кадамы гана масканы 512×n512 \times n матрицага айлантат.

Convolution катмарлары үчүн окшош ыкма - чыпканы кыскартуу. WRCout×Cin×k×k\mathbf{W} \in \mathbb{R}^{C_{\text{out}} \times C_{\text{in}} \times k \times k} берилсе, ii чыгыш чыпкасынын маанилүүлүгү төмөнкүдөй:

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}

Чыпка ii алынып салынганда бүтүндөй чыгыш каналы жок болуп, FLOP саны да пропорционалдуу азаят.

Лотерея билети гипотезасы

Чоң нейрондук тармактан бөлүнүп чыккан чакан утушчу ички тармак

2019-жылы Франкл менен Карбин Лотерея билети гипотезасын (LTH) сунуш кылышкан: кокустук инициализацияланган тыгыз тармактын ичинде "утушчу билет" болгон сейрек ички тармак бар жана аны баштапкы инициализациясынан үйрөткөндө, салыштырмалуу сандагы итерациядан кийин толук тармактын тактыгына жетет.

Формалдуу түрдө f(x;θ0)f(\mathbf{x}; \boldsymbol{\theta}_0) функциясын карайлы, ал θ0Dθ\boldsymbol{\theta}_0 \sim \mathcal{D}_\theta менен инициализацияланган. Конвергенцияга чейин үйрөткөндөн кийин θ\boldsymbol{\theta}^* алынат жана кыскартуу маскасы m\mathbf{m} түзүлөт. LTH боюнча төмөнкүдөй m\mathbf{m} бар:

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}^*)

мында m0θ0\|\mathbf{m}\|_0 \ll |\boldsymbol{\theta}_0|. Баштапкы эксперименттер MNIST жана CIFAR-10 боюнча жүргүзүлүп, утушчу билеттер параметрлердин 10-20%ын сактаган. Муну буйрук китебинин маалыматтарына автоматтык түрдө көчүрүүгө болбойт: LOB белгилери стационардуу эмес, ал эми энбелги дээрлик ызы-чуу; бул сүрөт классификациясынан такыр башка режим.

Итеративдүү чоңдук боюнча кыскартуу (IMP)

Билет IMP аркылуу табылат:

  1. Тармакты θ0\boldsymbol{\theta}_0 менен инициализациялаңыз.
  2. Конвергенцияга чейин үйрөтүп, θ\boldsymbol{\theta}^* алыңыз.
  3. Эң кичине чоңдуктагы салмактардын p%p\%ын кыскартып, m\mathbf{m} маскасын түзүңүз.
  4. Тирүү калган салмактарды θ0\boldsymbol{\theta}_0догу баштапкы маанилерине кайтарыңыз (артка түрүү).
  5. Маскаланган тармак менен 2-кадамдан кайталаңыз.

Ар бир раунд параметрлердин pp бөлүгүн (адатта 20%) алып салат, ошондуктан nn раунддан кийин параметрлердин (1p)n(1-p)^n бөлүгү калат. p=0.2p = 0.2 болгон 10 раунддан кийин болжол менен 10,7% калат.

Соода моделдери тууралуу үч гипотеза, үчөө тең текшериле элек

LTH рыноктук маалыматтарда өзгөчө жакшы иштеши керек деп айтууга азгырылышыбыз мүмкүн. Мындай үч жүйө бар; үчөө тең гипотеза, аларды факт катары көрсөтүү болсо бул блогдун болтурбоого аракет кылган катасы.

  1. Финансылык сигналдар сейрек. Буйрук китебинин сүрөтүнүн көпчүлүгү ызы-чуу болгондуктан, сейрек ички тармак сейрек сигналга табигый түрдө туура келиши мүмкүн. Муну текшерүүгө болот: IMPти сейректиги бирдей кокустук маска менен салыштырыңыз; эгер ишти сейректүүлүктүн өзү аткарса, кокустук маска да анча артта калбашы керек.
  2. Утушчу билеттер режимдер арасында жалпыланат. Бул булаксыз рыноктук эмпирикалык доомат жана үчөөнүн ичинен эң кызыктуусу. Аны HMM менен режимди аныктоо аркылуу алынган режим энбелгилерине каршы түз текшерүүгө болот: А режиминен билет таап, аны В режиминде кайра үйрөтүп, В режиминде өзүнчө табылган билет менен салыштыруу керек.
  3. Сейректүүлүк регуляризациялайт. Натыйжалуу кубаттуулуктун азайышы микроструктурадагы ызы-чууга ыңгайлашууну азайтышы мүмкүн. Анда кыскартылган моделдин үлгүдөн тышкаркы ажырымы тыгыз моделдикине жөн гана окшош болбостон, кичирээк болушу керек.

Ишке ашыруу: соода MLP моделин кыскартуу

Так сейрек маска аркылуу өзгөртүлгөн нейрондук катмарлар

Негизги модель

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():,}")

Чоңдук боюнча структураланбаган кыскартуу

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%}")

Аны иш жүзүнө ашырган кайра куруу менен структураланган кыскартуу

Катарларды маскалоо - иштин жарымы. Ылдамдыкты берген бөлүк - ар бир катмарды кыскартылган өлчөмдө кайра куруу. Бул алып салууну алдыга өткөрүүнү билдирет: jj катарын ii катмарынан алып салуу jj тилкесин i+1i+1 катмарынан жана алардын ортосундагы бардык BatchNorm1d катмарынан jj каналын да алып салат.

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

Буга ишенүүдөн мурун, блогдогу башка эквиваленттүүлүк текшерүүлөрү сыяктуу эле, эки нерсени караңыз:

  • Өлчөмдөр. rebuilt жашыруун өлчөмдөрдү (1fraction)h(1 - \text{fraction}) \cdot h кылып көрсөтүшү керек - fraction=0.75, h=2048h = 2048 үчүн 512. Ички матрицалардын эки өлчөмү тең кыскаргандыктан, параметрлердин саны квадраттык түрдө азайышы керек.
  • Чыгыштар. eval() режиминде rebuilt(x) бир эле пакеттеги маскаланган моделдин чыгышына калкыма чекке чейинки тактыкта дал келиши керек. Дал келбесе, тилкелерди өткөрүү туура эмес жана кийинки бардык сандар сиз ойлогондон башка моделди өлчөйт.

Катарды сактап калуу текшерүүсү маскаланган катар толугу менен нөл, ал эми тирүү катар нөл эмес деп болжолдойт. Бул ln_structured натыйжасы үчүн туура; башка процедура чындап нөл болгон тирүү нейрон жаратса, бул болжол аткарылбайт. Ошондуктан норма текшерүүсүнө сокур ишенбей, сакталган катарлардын санын суралган үлүш менен салыштырыңыз.

Итеративдүү чоңдук боюнча кыскартуу (лотерея билетин издөө)

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 бул макала убада кылган сейректүүлүк-тактык ийри сызыгынын чийки материалы. eval_fn чындап үлгүдөн тышкаркы, тазаланган бөлүктөрдө эсептелиши керек; IMPти үлгүнүн ичиндеги баа менен жүргүзүү маанисиз, бирок кооз ийри сызык берет.

Өлчөө

Сейректүүлүк, тактык жана кечигүү ортосундагы натыйжалуулук чек арасы

Кечигүү блогдун калган бөлүгүндөгүдөй эле жабдык протоколу менен өлчөнөт - жылытуу эсепке алынбайт, эң жакшы N жыйынтык алынат, p50/p95/p99 орточо эмес, өзүнчө көрсөтүлөт. Код камтылган ошол протокол Polars жана pandas материалында бар. Кыскартууга тиешелүү үч эреже:

  • Маскаланган эмес, кайра курулган моделди салыштырыңыз. Пакет өлчөмү 1 болгон маскаланган модель дагы эле тыгыз өлчөмдү өлчөйт.
  • Пакеттин өлчөмүн көрсөтүңүз. 1 пакет (котировка цикли) менен 256 пакет (изилдөөчү текшерүү) эс тутумга жана эсептөөгө байланышкан сызыктын ар башка тарабында турат; кыскартуу аларга ар башкача жардам берет.
  • Тактыкты ошол эле бөлүнүштө жана ошол эле горизонтто, энбелгинин аныктамасын көрсөтүү менен бериңиз. Тиешелүү тактык тилкеси жок кечигүү таблицасы моделди толугу менен алып салууга негиз болуп калат.

Өркүндөтүлгөн ыкмалар

Өркүндөтүлгөн тармак кысуу жолдору бир натыйжалуу моделге биригет

Билимди дистилляциялоо менен кыскартуу

Кыскартууну жана кайра үйрөтүүнү өз-өзүнчө жүргүзбөстөн, баштапкы тыгыз моделди мугалим катары колдонуңуз. Кыскартылган окуучу тапшырма жоготуусу менен мугалимдин чыгыш бөлүштүрүүсүнөн алынган KL ажырымын бирге минималдаштырат:

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)

мында zt\mathbf{z}_t жана zs\mathbf{z}_s мугалим менен окуучунун логиттери, TT - температура, ал эми α\alpha эки максаттын салмагын теңдейт. T2T^2 көбөйткүчү дистилляция градиенттеринин масштабын кайра түзөт; болбосо алар 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

Кыймыл боюнча кыскартуу

Абсолюттук чоңдук боюнча кыскартуунун ордуна, кыймыл боюнча кыскартуу (Sanh et al., 2020) үйрөтүү учурунда нөлгө карай жылып жаткан салмактарды алып салат. Маанилүүлүк упайы градиент менен салмактын көбөйтүндүсүн топтойт:

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)

Терс упайы бар салмактар кыскартылат. Анын чоңдук боюнча кыскартууга карата жүйөсү өзгөчө доработкага тиешелүү: алдын ала үйрөтүлгөн моделди ыңгайлаштырганда салмактардын бөлүштүрүлүшүн мурунку тапшырма калыптандырган, демек чоңдук эски маанилүүлүк белгиси, ал эми кыймылдын багыты жаңыраак белги. Жылма терезелерде кайра үйрөтүлгөн соода модели үчүн бул нөлдөн үйрөтүүгө караганда кеңири кездешет.

NVIDIA 2:4 структураланган сейректүүлүгү

Ampere жана андан кийинки NVIDIA GPUлары жабдык деңгээлинде 2:4 структураланган сейректүүлүктү колдойт: ар бир удаалаш төрт салмактын так экөө нөл болушу керек.

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

Бул жабдык чындап ылдамдаткан майда бүртүкчөлүү сейректүүлүктүн түрү, ошондуктан структураланбаган кыскартуудагы 90% нөл санынан маанилүүрөөк. Чектөө глобалдык эмес, жергиликтүү: ар бир төрттүктөн кайсы экөө калганына маани бербейт. Ошондуктан глобалдык масканы бекитүүгө караганда чектөөсү кыйла алсыз, бирок сунушталган жалгыз сейректүүлүк деңгээли - 50%.

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()

Ылдамдыкты ишке ашыруу үчүн тыянак чыгаруу жолу сейрек тензор өзөктөрүн колдонушу керек - ONNX экспорту жана TensorRT түзүлүшү же torch.sparse.to_sparse_semi_structured. 2:4 маскаланган моделди тыгыз аткаруу чөйрөсү аркылуу экспорттосоңуз, тактыктын чыгымын аласыз, бирок артыкчылык албайсыз.

Өндүрүшкө жайылтуу

Кечигүүсү аз жабдык өткөргүчүнө кирип жаткан компакттуу тыянак модели

Валидациялоо

Кыскартылган модель кысылган эски модель эмес, жаңы модель; демек, башка талапкерлер сыяктуу эле кабыл алуу текшерүүсүнөн өтөт: жылма кайра үйрөтүү жана walk-forward оптималдаштыруу боюнча үлгүдөн тышкаркы кайра валидация, ошондой эле Deflated Sharpe катышы аркылуу тандоо таасирин оңдоо. Бул оңдоо мында милдеттүү: IMP талапкер моделдердин тизмегин жаратат, ошондуктан он раунддагы эң жакшы көрүнгөн сейректүүлүк деңгээли издөө учурунда тандалган жана анын Sharpe көрсөткүчү сыноолордун натыйжалуу санына жараша төмөндөтүлүшү керек. "Sharpe 5%дан ашык төмөндөсө, четке как" деген жөнөкөй эреже бул эсепке туруштук бербейт, ошондуктан аны бул макаладан таппайсыз.

Кванттоону кошуу

Кыскартуу кванттоо менен айкалышат. 90% сейрек жана INT8ге квантталган модель үчүн кысуу коэффициенти:

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

48 МБ модель 1,2 МБга айланат. Бул сактоо тууралуу гана доомат. 1,2 МБ модель ошол эле чечимдерди чыгарабы - өзүнчө суроо. Аны GPU тактык тузагы аркылуу текшерүү керек: бул блогдо fp32 өзү эле толук ишенимдүү көрүнгөн бэктест эсептөөсүндө 211 салыштырмалуу ката жаратканы көрсөтүлгөн. INT8 мындан да агрессивдүү кыскартуу. Квантталган жана кыскартылган моделди fp32 тыгыз моделине салыштырган сандык паритет текшерүүсүнөн кийин гана жайылтыңыз - кармалган мезгилдеги чечимдердин дал келүү үлүшүн жана PnL айырмасын өлчөп, кепилдикке эмес, ошол сандарга таяныңыз.

Мониторинг

Кыскартылган моделдер бөлүштүрүүнүн жылышына сезгичирээк болушу мүмкүн. Төмөнкүлөрдү байкап туруңуз:

  • Активдештирүү сейректүүлүгү: тирүү калган нейрондор негизинен нөл чыгарса, натыйжалуу модель көздөгөндөн кичине болуп, начарлап жаткан болушу мүмкүн.
  • Кайра үйрөтүү кезиндеги градиент нормалары: жарылып кеткен градиенттер тирүү калган ички тармактан алып салынган бөлүктү өтө катуу компенсациялоо талап кылынганын билдирет.
  • Божомол энтропиясы: ызы-чуулуу микроструктура маалыматтарында ашыкча ишенимдүү болуп калган кыскартылган модель үйрөтүү режимине ашыкча ыңгайлашкан болушу мүмкүн.

Жыйынтык

Тыгыз белгисиздиктен чечим чыгарган компакттуу натыйжалуу нейрондук тармак

Ыкмалар жакшы белгилүү; текшерүү жүргүзүлгөнгө чейин бул макала мындан ашык доомат койбойт. Структураланбаган кыскартуу сейректүүлүк санын берет, бирок ылдамдыкты бербейт. Структураланган кыскартуу катмарларды маскалоонун ордуна кайра курганда гана ылдамдык берет. Лотерея билети гипотезасы компакттуу модель ашыкча параметрленген моделдин ичинде мурда эле бар болушу мүмкүн дейт, бирок бул сүрөт эталондорунда көрсөтүлгөн, буйрук китебинин маалыматтарында эмес. Жогорудагы анын рынокто "иштеши керек" деген үч жүйөсү - эксперименттер менен коштолгон гипотезалар, табылгалар эмес.

Адабияттагы практикалык эвристика - башынан кичине модель долбоорлогондун ордуна чоң моделди үйрөтүп, кийин кыскартуу: чоң модель жоготуу ландшафтын натыйжалуураак изилдейт, ал эми кыскартуу маанилүү жолдорду сактап калат. Мунун соода моделине тиешелүү экени, кайсы сейректүүлүктө жана кандай тактык чыгымы менен иштей турганы бир IMP текшерүүсүнөн кийин гана белгилүү болот. Ошондон кийин бул макаланы сандар кошулган түрдө кайра окуу керек.

blog.disclaimer

Authors

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

Рынктан бир кадам алдыда болуңуз

AI соода аналитикасы, рынок талдоолору жана платформа жаңылыктары үчүн биздин жаңылыктар бюллетенине жазылыңыз.

Биз сиздин купуялыгыңызды урматтайбыз. Каалаган убакта жазылымдан чыга аласыз.