Giter Club home page Giter Club logo

Comments (15)

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire ,

Thanks for your idea. It's coming in the new release.

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire ,

You can try to use it here: https://mealpy.readthedocs.io/en/latest/pages/general/advance_guide.html#stopping-condition-termination

from mealpy.

twistfire avatar twistfire commented on June 2, 2024

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire,

Can you show me your whole implementation?
In your settings, the max_time is 100 seconds, so it shouldn't finished right after 1 epoch like this since 1 epoch takes around 0.0127 seconds.

from mealpy.

twistfire avatar twistfire commented on June 2, 2024

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire,

I'm not sure what is wrong. I copied and run your code in my laptop. It works fine for me.

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire ,

You can try to increase the max_time to 1000 or 10000 seconds to see what will happen.

from mealpy.

twistfire avatar twistfire commented on June 2, 2024

@thieu1995 , thanks for your feedback.
I have a very strange situation with this toy example.
It just doesn't works at all..

I can't get it to work.

When i set:

# Use stopping conditions together
term_dict = {
   "max_epoch": 10000,
   "max_time": 10000,
   "max_early_stop": 2500
}

it gives next output:

2023/03/22 08:52:08 AM, INFO, mealpy.swarm_based.PSO.OriginalPSO: Solving single objective optimization problem.
2023/03/22 08:52:08 AM, INFO, mealpy.swarm_based.PSO.OriginalPSO: >Problem: P, Epoch: 1, Current best: 0.6665798795963225, Global best: 0.6665798795963225, Runtime: 0.01008 seconds
2023/03/22 08:52:08 AM, WARNING, mealpy.swarm_based.PSO.OriginalPSO: Stopping criterion with maximum running time/time bound (TB) (seconds) occurred. End program!



[2.26776349 2.83805118 6.25245965]
0.6665798795963225

When I set

# Use stopping conditions together
term_dict = {
   "max_epoch": 10000,
   "max_time": 100000,
   "max_early_stop": 2500
}

I got next output:
2023/03/22 09:09:47 AM, INFO, mealpy.swarm_based.PSO.OriginalPSO: Solving single objective optimization problem.
2023/03/22 09:09:47 AM, INFO, mealpy.swarm_based.PSO.OriginalPSO: >Problem: P, Epoch: 1, Current best: -0.6497575280479526, Global best: -0.6497575280479526, Runtime: 0.01437 seconds
2023/03/22 09:09:47 AM, INFO, mealpy.swarm_based.PSO.OriginalPSO: >Problem: P, Epoch: 2, Current best: -0.6497575280479526, Global best: -0.6497575280479526, Runtime: 0.01233 seconds
....
2023/03/22 09:10:37 AM, INFO, mealpy.swarm_based.PSO.OriginalPSO: >Problem: P, Epoch: 2501, Current best: -0.6497575280479526, Global best: -0.6497575280479526, Runtime: 0.01013 seconds
2023/03/22 09:10:37 AM, WARNING, mealpy.swarm_based.PSO.OriginalPSO: Stopping criterion with early stopping (ES) (fitness-based) occurred. End program!

note - the Global best doesn't change from the first epoch and it finishes using ES criterion...

It seems the optimizer is not working at all, because I don't have any changes in the resulting function that is very strange for me.

Don't know what to do because I want to try a mealpy, but I need to provide multiple stopping for that.

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire ,

Let me correct you. The optimizer is working fine. It's just not working on your laptop (in your environment).

Firstly, the problem of the global best not changing after the first epoch is because your problem is too easy. The optimizer found the exact optimal point after one epoch.

Secondly, in your third attempt, you set the max_early_stop parameter to 2500, so it will stop after 2501 epochs. This is clearly stated in the Early Stopping condition (https://mealpy.readthedocs.io/en/latest/pages/general/advance_guide.html#stopping-condition-termination).

Thirdly, in your second attempt, you increased max_time to 10000, but the program exited after only two epochs because the Time Bound condition was met. It's possible that the issue is related to the time.time.perf_counter() function used in the library. May I ask if you are using Linux, Windows, or Mac?"

from mealpy.

twistfire avatar twistfire commented on June 2, 2024

@thieu1995 , thank you for your reply.

you are completely correct.
It was my incorrect conclusion. Optimizer works, of course.

I am working under WSL 2, Ubuntu, here are the parameters:

{'platform': 'Linux',
'platform-release': '5.15.90.1-microsoft-standard-WSL2',
'platform-version': '#1 SMP Fri Jan 27 02:56:13 UTC 2023',
'architecture': 'x86_64',
'hostname': 'note-4',
'ip-address': '127.0.1.1',
'mac-address': '00:15:5d:b6:b0:31',
'processor': 'x86_64',
'ram': '15 GB'}

If you need any additional data - just tell me, I will try to get them if needed.

Nevertheless, it's pretty strange situation - for this simple toy problem, it finds a solution using PSO and a swarm of 200 particles and even close initial guess (for one particle) very slowly... It's pretty strange for me and confusing because I want to apply this package for complex optimization and select the best technique for that...

P.S.
It's worth to mentions that I have an initial guess for my optimization task - and it's pretty close to the solution - that is why I wanted to use particle swarm as a technique that can provide global best solution.
My optimization task has about 20 parameters to find (fitting task), each of the params has its own bounds and the initial guess value. While for each set of parameters to optimize I have about 60..120 observations with uncertainty bounds given but the functional form is unknown..

By the way - I have wanted to ask how can I pass additional parameters for my fitness function?
e.g. I have a function


def fitness_f(
        **res_params**: list,                                     # list of parameters to optimize,
        res_params_fixed: list,                            # list of parameters that are fixed (not for optimization)
        params_2: np.array,                                # energy grid (for SYNDAT)
        particles_data: data.particle_pairdata,    # for syndat
        data: np.array,                                        # input data for a window
        unc: np. array                                         # uncertainty of data in a window
        ) -> float:

so the data is passed into the fitness function because it;s used in further processing, but I need to optimize only parameters res_params and other parameters just pass to the fitness function. How it can be done? **kwargs?

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire,

I have tried the code on Windows, Linux, and Mac, and it worked fine. So I think the problem is that you are using a Linux simulation under a Windows environment. The clock time doesn't know which one should be counted (from the current Linux process or the outside Windows process that is currently running the WSL simulation). Unfortunately, the time module can't handle this case. Therefore, I think you should either run your code on Windows or run your code on Linux that is not inside the Windows environment. It's better to install Linux parallelization with Windows instead. Why are you running Linux inside Windows anyway?

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire ,

When you need to pass additional data to fitness function. I recommend you to design a custom Problem object like this in the document. https://mealpy.readthedocs.io/en/latest/pages/general/advance_guide.html#custom-problem

from mealpy.swarm_based import PSO
from mealpy.utils.problem import Problem

class MyOwnProblem(Problem):
    def __init__(self, lb, ub, minmax, name="Whatever", dataset=None, additional=None, **kwargs):
	self.dataset = dataset 
	self.additional = additional 
        super().__init__(lb, ub, minmax, **kwargs)
        self.name = name
	
    def NET(dataset, additional):
	# I can train neural network here and return fitness here

    def fit_func(self, solution):
	# Do whatever you want here based on your dataset you pass in __init__ function. 
	network = NET(self.dataset, self.additional)
	fitness = network.loss
	return fitness

## Create an instance of MOP class
problem_cop = COP(lb=[-3, -5, 1, -10, ], ub=[5, 10, 100, 30, ], name="Network",
                                dataset=dataset, additional=additional, minmax="min")

## Define the model and solve the problem
model = PSO.OriginalPSO(epoch=1000, pop_size=50)
model.solve(problem=problem_cop)

By creating a custom class like the one above, you only need to pass the data once in your problem creation. If you pass data to the fitness function, you will have to pass it every time that function is called, which is not optimal. That's why you need to create a custom class.

Please remember to set the additional data before calling the super() function in init(), as shown above. When you call the super() function, it will check the fitness function you passed to see if it's callable or not (pre-called to test if the fitness function that user passed is correct or not).

Note: As mentioned in the documentation, it's not recommended to use the starting_positions parameter https://mealpy.readthedocs.io/en/latest/pages/general/advance_guide.html#starting-positions. Because this is a meta-heuristic algorithm. It's a random-based process, and you don't want your algorithm to get stuck in one place. You want it to explore the entire search space to find the global best solution. If you pass starting_positions, your algorithm may fail after the first epoch and won't be able to get out of the comfort zone (local optima).

from mealpy.

twistfire avatar twistfire commented on June 2, 2024

it's just simple amd convenient for me.

I will try to investigate maybe it's possible to fix this issue..
Or rerun on Linux I have.

from mealpy.

twistfire avatar twistfire commented on June 2, 2024

@twistfire ,

When you need to pass additional data to fitness function. I recommend you to design a custom Problem object like this in the document. https://mealpy.readthedocs.io/en/latest/pages/general/advance_guide.html#custom-problem

from mealpy.swarm_based import PSO
from mealpy.utils.problem import Problem

class MyOwnProblem(Problem):
    def __init__(self, lb, ub, minmax, name="Whatever", dataset=None, additional=None, **kwargs):
	self.dataset = dataset 
	self.additional = additional 
        super().__init__(lb, ub, minmax, **kwargs)
        self.name = name
	
    def NET(dataset, additional):
	# I can train neural network here and return fitness here

    def fit_func(self, solution):
	# Do whatever you want here based on your dataset you pass in __init__ function. 
	network = NET(self.dataset, self.additional)
	fitness = network.loss
	return fitness

## Create an instance of MOP class
problem_cop = COP(lb=[-3, -5, 1, -10, ], ub=[5, 10, 100, 30, ], name="Network",
                                dataset=dataset, additional=additional, minmax="min")

## Define the model and solve the problem
model = PSO.OriginalPSO(epoch=1000, pop_size=50)
model.solve(problem=problem_cop)

By creating a custom class like the one above, you only need to pass the data once in your problem creation. If you pass data to the fitness function, you will have to pass it every time that function is called, which is not optimal. That's why you need to create a custom class.

Please remember to set the additional data before calling the super() function in init(), as shown above. When you call the super() function, it will check the fitness function you passed to see if it's callable or not (pre-called to test if the fitness function that user passed is correct or not).

Note: As mentioned in the documentation, it's not recommended to use the starting_positions parameter https://mealpy.readthedocs.io/en/latest/pages/general/advance_guide.html#starting-positions. Because this is a meta-heuristic algorithm. It's a random-based process, and you don't want your algorithm to get stuck in one place. You want it to explore the entire search space to find the global best solution. If you pass starting_positions, your algorithm may fail after the first epoch and won't be able to get out of the comfort zone (local optima).

Dear @thieu1995 , thanks for reply. I am not supeproficient in Python, just starting.

So for the Custom problem, it's pretty hard to understand the principle (IMHO).
Can you please provide me with an example of my toy problem, if my fitness function is given like this:

def fitness_function(x: np.array,
                     addit_args_0: list,
                     addit_args_1: list,
                     ...,
                     addit_data: pd.Dataframe
):

Note: only x is optimized - I don't really get how to pass all the parameters (addit_args_0, addit_args_1, ..., addit_data) to the optimization routine.
So if it's possible - just provide an example with this toy-problem mentioned.

And to be clear: your recommendation is to define a problem using class for my optimization task?

I will describe my task more clearly, maybe it will help to understand.

I need to solve several optimization tasks in one program (I mean it's one large optimization task but it can't be solved at once I think, it has a large number of parameters (up to several hundreds) and the problem is that the number of parameters and their boundaries are unknown we can just seed them - but every option will require much time to search - at least for now). Especially if I will say that I don't know the function (it's actually black-box optimization for me).

That is why I am trying to use a multilevel iterated approach, where on the first level (it's repeated several times adding a set of new parameters to optimize to a main model). This small optimization task is solved individually - here I want to use PSO with termination restrictions (for example no more than 10 000 iterations or one minute per local region) giving the initial solution guess (at least one particle) as close as possible to a global minima value and providing boundaries for each parameter optimization - to save time & resources (or some alternative technique) to find good initial values for the second level of optimization - where a whole bunch of optimization parameters is used, but we also have boundaries and initial guesses for all of them - obtained from the first level.

Each small optimization task uses only part of a dataset I have and corresponding constraints which are calculated individually.
Each success in local optimization adds parameters and some amount of data from initial dataset to a model dataset (it uses only part of the data and is evaluated using all the data) that is optimized on the second level.
On the second level sets of parameters - of a dataset is used (or all the data from the dataset can be used - it depends on the data we have).

Actually, it's a lot of small optimization tasks - steps - each adds some parameters and data for a dataset used on the second level.

To clarify that my understanding of your recommendation is correct. Do I need to iteratively set up small optimization problems (using proposed class)? providing each "problem" with required subsets of data from an available dataset - and based on the results of level 1 optimization(s) - to set up another class of problem 2 - with other fitness functions and other data - right?

from mealpy.

thieu1995 avatar thieu1995 commented on June 2, 2024

@twistfire ,

First you should know that whenever you try to use an optimizer to solve an optimization problem, you need to know the specific number of variables (problem size) that you want to solve, and it has to be fixed throughout the entire optimization process. You can't change the problem size during the optimization process. You also need to know the bounds (lower and upper bounds) for each variable, and finally, you need to know the fitness function. It can be a black box or not, but when each set of variables is passed to the fitness function, it should return a different value. The optimizer can then use that fitness value to find the minimum or maximum by adjusting the variables.

For example, for your toy problem, note that when passing the lower bound (lb) and upper bound (ub), it should be a list where each value represents a variable (or 1 dimension). That is why you don't need to pass the number of variables in the Problem. For instance, if you want to solve the sum square problem with 5 variables, you can simply pass lb=[-10, -10, -10, -10, -10] and ub=[10, 10, 10, 10, 10], assuming that the bound is -10 < x_i < 10.

from mealpy.swarm_based import PSO
from mealpy.utils.problem import Problem

class MyOwnProblem(Problem):
    def __init__(self, lb, ub, minmax, addit_args_0=None, addit_args_1=None, addit_data=pd.DataFrame, **kwargs):
		self.addit_args_0 = addit_args_0 
		self.addit_args_1 = addit_args_1 
		self.addit_data = addit_data
		super().__init__(lb, ub, minmax, **kwargs)

    def fit_func(self, solution):
		# Do whatever you want here based on your dataset you pass in __init__ function. 
		# Calculate the fitness and return it here using your black-box model or whatever 
		return fitness


## Now you can create an instance of your Class. Meaning you create a single problem (object), learning more about OOP in Python from here if you don't know what it is: https://www.youtube.com/watch?v=Ej_02ICOIgs&t=1916s

problem1 = MyOwnProblem(your_lower_bound, your_upper_bound, addit_args_0, addit_args_1, addit_data)

## You can solve that single problem by: 
model = PSO.OriginalPSO(epoch=1000, pop_size=50)
model.solve(problem=problem1)

I'm not sure if I understand your problem, but I think you might need to divide your dataset into several pieces if each of your small problems only uses a small portion of the dataset. Then, you can create a loop to solve all of these small problems. For example:

## Assumption that you have divided your whole dataset into several piece like this 
dataset = [data1, data2, data3, data4,...]

results = []
for idx, data in enumerate(dataset):
	# Create a new problem
	prob = MyOwnProblem(lower_bound, upper_bound, addit_args_0, addit_args_1, data)
	algo = PSO.OriginalPSO(epoch=1000, pop_size=50)
	best_location, best_fitness = algo.solve(problem=prob)
	
	# Assumption that you want to save all the variables for the next stage 
	results.append(best_location)


## Level 2 (Next stage)
## Do whatever you want to do with the "results" you get from level 1 from here. 

prob_level2 = MyOwnProblem(lowerbound, upperbound, addit_agrs_0, addit_args_1, your_data)
opt = PSO.OriginalPSO(epoch=1000, pop_size=50)
best_location, best_fitness = opt.solve(problem=prob_level2)

I hope that helps!

from mealpy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.