kohya-ss / kohya-ss/sd-scripts

Sparse learning gradient filtering feature request 🟡

Open
#2,085 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
7.2k
Forks
1.2k
Avg merge
11m
Merged PRs (30d)
2

Description

The main issue: sd_scripts lacks a custom gradient filtering function with masking. My attempt to implement a module with custom filters via an additional argument was unsuccessful due to my limited programming skills. Currently, I'm getting by with modifying the optimizer's code directly to add conditional top-k relative or variance gradient filtering - tests show excellent results and provide an additional layer of control over training precision and flexibility.

It would be great if someone capable of properly integrating a filtering option into the scripts - with the ability to modify/add custom filtering options - could help with this.

The core idea is to filter out non-informative gradient regions, forcing the network to learn only from meaningful areas.

An example of a SignSGD optimizer with a simple top-k filtering scheme implemented:

```
import math
from typing import Dict, Tuple

import torch

from pytorch_optimizer.base.exception import NoSparseGradientError
from pytorch_optimizer.base.optimizer import BaseOptimizer
from pytorch_optimizer.base.type import CLOSURE, DEFAULTS, LOSS, PARAMETERS

class SignSGD(BaseOptimizer):
r"""Compressed Optimisation for Non-Convex Problems with Top-k Relative Change Filtering.

:param params: PARAMETERS. iterable of parameters to optimize or dicts defining parameter groups.
:param lr: float. learning rate.
:param momentum: float. momentum factor (0.0 = SignSGD, >0 = Signum).
:param weight_decay: float. weight decay (L2 penalty).
:param weight_decouple: bool. the optimizer uses decoupled weight decay as in AdamW.
:param topk_ratio: float. Fraction of most changing parameters to update (0.0 = all, 1.0 = none).
"""

def __init__(
self,
params: PARAMETERS,
lr: float = 1e-3,
momentum: float = 0.9,
weight_decay: float = 0.0,
weight_decouple: bool = True,
topk_ratio: float = 0.0, # 0.0 means no masking
**kwargs,
):
self.validate_learning_rate(lr)
self.validate_range(momentum, 'beta', 0.0, 1.0)
self.validate_non_negative(weight_decay, 'weight_decay')
self.validate_range(topk_ratio, 'topk_ratio', 0.0, 1.0)

self.topk_ratio = topk_ratio

defaults: DEFAULTS = {
'lr': lr,
'momentum': momentum,
'weight_decay': weight_decay,
'weight_decouple': weight_decouple,
}
super().__init__(params, defaults)

def __str__(self) -> str:
return 'SignSGD'

@torch.no_grad()
def reset(self):
for group in self.param_groups:
group['step'] = 0
for p in group['params']:
state = self.state[p]

if group['momentum'] > 0.0:
state['momentum_buffer'] = torch.zeros_like(p)
state['prev_grad'] = torch.zeros_like(p)

@torch.no_grad()
def step(self, closure: CLOSURE = None) -> LOSS:
loss: LOSS = None
if closure is not None:
with torch.enable_grad():
loss = closure()

for group in self.param_groups:
lr = group['lr']
momentum = group['momentum']

for p in group['params']:
if p.grad is None:
continue

grad = p.grad
if grad.is_sparse:
raise NoSparseGradientError(str(self))

state = self.state[p]
if momentum > 0.0:
if 'momentum_buffer' not in state:
state['momentum_buffer'] = torch.zeros_like(p)
buf = state['momentum_buffer']
buf.mul_(momentum).add_(grad, alpha=1.0 - momentum)
else:
buf = grad

# Top-k relative change filtering
if self.topk_ratio > 0.0:
if 'prev_grad' not in state:
state['prev_grad'] = torch.zeros_like(buf)

prev = state['prev_grad']
rel_change = torch.abs(buf - prev) / (torch.abs(prev) + 1e-8)

k = int(rel_change.numel() * (1.0 - self.topk_ratio))
if k > 0:
topk_vals, topk_idx = torch.topk(rel_change.view(-1), k)
mask = torch.zeros_like(rel_change).view(-1)
mask[topk_idx] = 1.0
mask = mask.view_as(buf)
buf = buf * mask

state['prev_grad'].copy_(buf)

# Update step
p.add_(torch.sign(buf), alpha=-lr)

return loss

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing the optimizer code the reporter currently modifies and the supplied SignSGD example. Define how configurable gradient-filtering and masking options should fit into sd_scripts, including support for custom filters. Done means the filtering feature is integrated without direct optimizer edits and its behavior is covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
machine-learning
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.