Implement L1 regularization
Rbm::Params had no l1Lambda field at all -- L1 didn't exist anywhere in the C++ codebase. Status::L1 was a dead field always -1 (never assigned outside its constructor), and the GUI's "Lambda" control was explicitly tooltipped "Unused" with an empty change-handler stub. Scaffolded, never implemented. Add Params::l1Lambda (default 0.0, inert unless set) with full toJson/ fromJson round-trip. Apply its subgradient (lambda*sign(W), matching pyRBM's l1_lambda) directly to m_whv in Rbm::train, in the same place and same decoupled-from-momentum manner as the weightDecay fix from the previous commit -- folding it into inc_whv's momentum recursion would cause the same momentum-amplification bug. Doesn't touch the biases, matching pyRBM's state_adjust(). Also wire up Status::L1 to actually report something (the current L1 norm of the weights, sum(abs(W))) instead of permanently printing -1, computed alongside status.err/err_total. Inert by default (l1Lambda=0.0 in every existing .prj): confirmed via unchanged poet.elf output and unchanged test-suite results (9 passed, 1 known issue, 2 failed). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016K8Gu7Qejd11JbdiHZqYAs
This commit is contained in:
+12
-4
@@ -367,14 +367,20 @@ void Rbm::train(arma::mat const &batch, IListener* pListener)
|
||||
m_bh += inc_bh;
|
||||
m_whv += inc_whv;
|
||||
|
||||
// Weight decay applied directly to the weights, outside the
|
||||
// momentum recursion above -- folding it into inc_whv would let
|
||||
// momentum geometrically amplify its effective strength to
|
||||
// roughly weightDecay/(1-momentum), well past the configured value.
|
||||
// Weight decay and L1 applied directly to the weights, outside the
|
||||
// momentum recursion above -- folding either into inc_whv would let
|
||||
// momentum geometrically amplify its effective strength to roughly
|
||||
// lambda/(1-momentum), well past the configured value. Neither
|
||||
// touches the biases, matching pyRBM's state_adjust().
|
||||
if (m_params.weightDecay != 0.0)
|
||||
{
|
||||
m_whv -= m_params.learningRate*m_params.weightDecay*m_whv;
|
||||
}
|
||||
if (m_params.l1Lambda != 0.0)
|
||||
{
|
||||
// Subgradient of lambda*||W||_1 is lambda*sign(W) (sign(0)=0).
|
||||
m_whv -= m_params.learningRate*m_params.l1Lambda*arma::sign(m_whv);
|
||||
}
|
||||
|
||||
progress += dProgress*miniBatchSizeActual;
|
||||
status.progress = (int)(progress + 0.5);
|
||||
@@ -386,6 +392,7 @@ void Rbm::train(arma::mat const &batch, IListener* pListener)
|
||||
|
||||
// Calculate error
|
||||
status.err = rms_error_accu(miniBatch - toVisibleProbs(toHiddenProbs(v_states)));
|
||||
status.L1 = arma::accu(arma::abs(m_whv));
|
||||
if (pListener)
|
||||
{
|
||||
if(!pListener->onProgress(this, status))
|
||||
@@ -402,6 +409,7 @@ void Rbm::train(arma::mat const &batch, IListener* pListener)
|
||||
|
||||
// Update final status
|
||||
status.err_total = rms_error_accu(batch - toVisibleProbs(toHiddenProbs(batch)));
|
||||
status.L1 = arma::accu(arma::abs(m_whv));
|
||||
|
||||
if (pListener)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user