docs: @Override
      public void trainOnInstanceImpl(Instance instance) {
  
          if (m_weights == null) {
              m_weights = new DoubleVector();
              m_velocity = new DoubleVector();
              m_bias = 0;
  
              m_weights.setValue(instance.numAttributes(), 0);
              m_velocity.setValue(instance.numAttributes(), 0);
          }
  
          if (instance.classIsMissing()) {
              return;
          }
     
          double z = dotProd(instance, m_weights, instance.classIndex()) + m_bias;
  
          double y;
          double dldz;
  
          if (instance.classAttribute().isNominal()) {
              y = (instance.classValue() == 0) ? 0 : 1;
              
              if (m_loss == LOGLOSS) {
                  double yhat = 1.0 / (1.0 + Math.exp(-z));
                  dldz = (yhat - y);
              }
              else {
                  y = y * 2 - 1;
                  
                  if(y * z < 1.0)
                  {
                      dldz = -y;
                  }
                  else
                  {
                      dldz = 0;
                  }
              }
          }
          else {
              y = instance.classValue();
              dldz = z - y;
          }
  
          int n = instance.numValues();
          DoubleVector gradients = new DoubleVector();
          gradients.setValue(instance.numAttributes(), 0);
  
          for(int i = 0; i < n; i++)
          {
              int idx = instance.index(i);
              gradients.setValue(idx, instance.valueSparse(i) * dldz + (m_lambda / (m_t + m_epsilon)) * m_weights.getValue(idx));
          }
  
          //Weight update for the bias
          double biasGradient = dldz;
          m_biasVelocity += biasGradient * biasGradient;
          m_bias -= (m_learningRate / (Math.sqrt(m_biasVelocity) + m_epsilon)) * biasGradient;
  
          for(int i = 0; i < m_weights.numValues(); i++) {
              //Weight update
              double g = gradients.getValue(i);
              m_velocity.addToValue(i, g * g);
              m_weights.addToValue(i, -(m_learningRate / (Math.sqrt(m_velocity.getValue(i)) + m_epsilon)) * g);
          }
  
          m_t += 1.0;
      }