Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LM Algorithm: Unbounded lambda #49

Closed
aiden-huffman opened this issue Feb 20, 2022 · 4 comments
Closed

LM Algorithm: Unbounded lambda #49

aiden-huffman opened this issue Feb 20, 2022 · 4 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@aiden-huffman
Copy link

aiden-huffman commented Feb 20, 2022

I have some optimisations which appear to get caught in a local minimum so that chi = chi_2 and as a result rho = 0. In the current setup, the algorithm doubles lambda until there is some improvement, this seems to lead to divergence and the algorithm failing for some optimisation problems. A simple fix might be to have the algorithm halt when lambda exceeds a meaningful value.

@Axect
Copy link
Owner

Axect commented Feb 20, 2022

Thank you for great suggestion! I'm with you on that.
I think there are two ways to implement your idea.

  1. Add method
    : Add set_lambda method which only works for LM method & add two private fields to Optimizer - lambda, lambda_max

    impl Optimizer {
        // ...
        pub fn set_lambda(&mut self, lambda_init: f64, lambda_max: f64) -> &mut Self {
            // ...
            match self.method {
                LevenbergMarquardt => { /* ... */ },
                _ => panic!(" ... "),
            }
            // ...
        }
    }
  2. Modify Enum
    : Modify LevenbergMarquardt enum to more detailed.

    pub enum OptMethod {
        // ...
        LevenbergMarquardt(f64, f64), // lambda_init, lambda_max
    }

Which do you prefer? Or if you have any other idea, then please let me know.

@aiden-huffman
Copy link
Author

aiden-huffman commented Feb 20, 2022

I think the first solution is the better of the two, this gives advanced users more control over the algorithm. If the user doesn't need to use the functionality, then on the back end something as simple as a default value lambda_max = f64::MAX.sqrt() or equivalent which you've handled previously with the default option hash map.

@Axect
Copy link
Owner

Axect commented Feb 20, 2022

Thank you again for good comments!
Then I'll implement this idea asap.

@Axect Axect self-assigned this Feb 20, 2022
@Axect Axect added the enhancement New feature or request label Feb 20, 2022
@Axect Axect added this to the Ver 0.30 milestone Feb 20, 2022
Axect added a commit that referenced this issue Feb 21, 2022
* Add methods to control `lambda` in LM method (#49)
Axect added a commit that referenced this issue Feb 21, 2022
* Add methods to control `lambda` in LM method (#49)
@Axect
Copy link
Owner

Axect commented Feb 21, 2022

Completed!
I published new version : 0.30.13.
Here is an example (just find optimal [a,b,c] for y = ax^2 + bx + c)

#[allow(non_snake_case)]
fn test_LM() {
    let x = seq(0, 10, 0.1);
    let p_true = vec![1.0, 2.0, 3.0];
    let y = x.fmap(|t| p_true[0] * t.powi(2) + p_true[1] * t + p_true[2]);

    let p_init = vec![1f64, 1f64, 1f64];
    let data = hstack!(x, y);
    let mut opt = Optimizer::new(data, f);
    let p_est = opt
        .set_init_param(p_init)
        .set_max_iter(50)
        .set_method(LevenbergMarquardt)
        .set_lambda_init(1e-3)
        .set_lambda_max(1e+3)
        .optimize();

    p_est.print();
}

fn f(x: &Vec<f64>, p: Vec<AD>) -> Option<Vec<AD>> {
    Some (
        x.iter()
            .map(|t| AD1(*t, 0f64))
            .map(|t| p[0] * t.powi(2) + p[1] * t + p[2])
            .collect()
    )
}

If lambda exceeds lambda_max then iteration is stopped and print iteration information.
In this example, you can see the message as follows.

Caution: At 31-th iter, lambda exceeds max value: 12122.73120743323

@Axect Axect closed this as completed May 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants