Class: GRX::Loss::HuberLoss

Inherits:
Object
  • Object
show all
Defined in:
lib/grx/loss.rb

Overview

================================================================

HuberLoss — Smooth L1 (robust against outliers)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(delta: 1.0) ⇒ HuberLoss

Returns a new instance of HuberLoss.



84
85
86
# File 'lib/grx/loss.rb', line 84

def initialize(delta: 1.0)
  @delta = delta.to_f
end

Instance Attribute Details

#deltaObject (readonly)

Returns the value of attribute delta.



82
83
84
# File 'lib/grx/loss.rb', line 82

def delta
  @delta
end

Instance Method Details

#call(pred, target) ⇒ Object

Raises:



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/grx/loss.rb', line 88

def call(pred, target)
  raise ShapeError, "Shapes incompatibles: #{pred.shape} vs #{target.shape}" if pred.shape != target.shape
  diff_data = (pred - target).abs.to_a
  d = @delta
  loss_val = diff_data.sum { |v| v <= d ? 0.5 * v * v : d * (v - 0.5 * d) } / diff_data.size.to_f

  out = Tensor.create([loss_val], [1], requires_grad: pred.requires_grad || target.requires_grad)
  if pred.requires_grad || target.requires_grad
    out._grafo_hijos.push(pred, target)
    n = diff_data.size.to_f
    out.backward_fn = ->(g) {
      grad_pred = (pred - target).to_a.map do |err|
        abs_err = err.abs
        (abs_err <= d ? err : d * (err > 0 ? 1.0 : -1.0)) * (g.item / n)
      end
      pred.agregar_gradiente(Tensor.create(grad_pred, pred.shape)) if pred.requires_grad
      target.agregar_gradiente(Tensor.create(grad_pred.map(&:-@), target.shape)) if target.requires_grad
    }
  end
  out
end