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

BUG:alive_progress:3.2.0 Exception problem at parallel runtime #286

Open
Euraxluo opened this issue Dec 25, 2024 · 3 comments
Open

BUG:alive_progress:3.2.0 Exception problem at parallel runtime #286

Euraxluo opened this issue Dec 25, 2024 · 3 comments

Comments

@Euraxluo
Copy link

Euraxluo commented Dec 25, 2024

image

code:

import time

from alns.stop import MaxIterations
from numpy.random import Generator
from alns.State import State
from alive_progress import alive_bar


class MaxIterationsWithProgress(MaxIterations):
    def __init__(self, max_iterations: int):
        super().__init__(max_iterations)
        self._bar = None
        self._update = None
        self._iterations = 0
        self._start_runtime = None

    def _create_new_bar(self, receipt=True):
        if self._bar:
            self._bar.__exit__(None, None, None)
        self._bar = alive_bar(self.max_iterations, title="MaxIterations", unit="iter",
                              force_tty=None,
                              receipt=receipt, monitor=False, elapsed=False, stats=False)
        self._update = self._bar.__enter__()

    def __call__(self, rng: Generator, best: State, current: State) -> bool:
        if self._start_runtime is None:
            self._start_runtime = time.perf_counter()
        result = super().__call__(rng, best, current)
        if not self._update:
            self._create_new_bar(receipt=False)
        title = f"B:{best.objective():.2f},C:{current.objective():.2f} I:{self._iterations} T:{time.perf_counter() - self._start_runtime:.2f}s [{self._iterations / self._max_iterations * 100:5.2f}%]  R:{self._update.rate}"
        self._iterations += 1

        if not result:
            self._update.title = title
            self._update(1)
        else:
            self._bar.__exit__(None, None, None)
        return result

    def __getstate__(self):
        # Remove the progress bar before pickling
        state = self.__dict__.copy()
        state['_bar'] = None
        return state

    def __setstate__(self, state):
        # Restore the object without the progress bar
        self.__dict__.update(state)
import time

from alns.stop import MaxRuntime
from numpy.random import Generator
from alns.State import State
from alive_progress import alive_bar


class MaxRuntimeWithProgress(MaxRuntime):
    def __init__(self, max_runtime: float):
        super().__init__(max_runtime)
        self._bar = None
        self._update = None
        self._elapsed = 0
        self._iterations = 0

    def _create_new_bar(self, receipt=True):
        if self._bar:
            self._bar.__exit__(None, None, None)
        self._bar = alive_bar(int(self._max_runtime), title="MaxRuntime", unit="s",
                              force_tty=None,
                              receipt=receipt, monitor=False, elapsed=False, stats=False)
        self._update = self._bar.__enter__()

    def __call__(self, rng: Generator, best: State, current: State) -> bool:
        result = super().__call__(rng, best, current)
        current_elapsed = int(time.perf_counter() - self._start_runtime)
        if not self._update:
            self._create_new_bar()
        self._update.title = f"[MaxRuntime] Best Obj:{best.objective():.2f}, Current Obj:{current.objective():.2f} Iterations:{self._iterations} [{int(current_elapsed) / self._max_runtime * 100:5.2f}%] {self._update.eta} rate:{self._update.rate}"
        if not result:
            self._iterations += 1
            if self._elapsed != current_elapsed:
                self._update(1)
        else:
            self._bar.__exit__(None, None, None)
        self._elapsed = current_elapsed
        return result

    def __getstate__(self):
        # Remove the progress bar before pickling
        state = self.__dict__.copy()
        state['_bar'] = None
        return state

    def __setstate__(self, state):
        # Restore the object without the progress bar
        self.__dict__.update(state)
import time

from alns.stop import NoImprovement

from numpy.random import Generator
from alns.State import State
from alive_progress import alive_bar


class NoImprovementWithProgress(NoImprovement):
    def __init__(self, max_iterations: int):
        super().__init__(max_iterations)
        self._bar = None
        self._update = None
        self._iterations = 0
        self._start_runtime = None

    def _create_new_bar(self, receipt=False):
        if self._bar:
            self._bar.__exit__(None, None, None)
        self._bar = alive_bar(self.max_iterations, title="NoImprovement", unit="iter",
                              force_tty=None,
                              receipt=receipt, monitor=False, elapsed=False, stats=False)
        self._update = self._bar.__enter__()

    def __call__(self, rng: Generator, best: State, current: State) -> bool:
        if self._start_runtime is None:
            self._start_runtime = time.perf_counter()
        result = super().__call__(rng, best, current)
        if not self._update:
            self._create_new_bar()
        title = f"B:{best.objective():.2f},C:{current.objective():.2f} I:{self._iterations} T:{time.perf_counter() - self._start_runtime:.2f}s [{self._counter / self._max_iterations * 100:5.2f}%] R:{self._update.rate}"
        self._iterations += 1
        if not result:
            self._update.title = title
            self._update(1)
        else:
            self._create_new_bar(receipt=True)
            self._update.title = title
            self._update(self.max_iterations)
            self._bar.__exit__(None, None, None)
        return result

    def __getstate__(self):
        # Remove the progress bar before pickling
        state = self.__dict__.copy()
        state['_bar'] = None
        return state

    def __setstate__(self, state):
        # Restore the object without the progress bar
        self.__dict__.update(state)

This is the problem with all of the code above, they're all used in iterations, and it's the same problem when they're used alone, but there's also the problem of overwriting each other in parallel, right?

@Euraxluo
Copy link
Author

when i test:
image
There is still a problem, did not see a good-looking effect

and how to test:

    class State:
        def objective(self) -> float:
            return 1

    state = State()
    stop = NoImprovementWithProgress(7000)
    while not stop(rng=np.random.default_rng(1),best=state,current=state):
        time.sleep(1)

@Euraxluo
Copy link
Author

When I use TQDM, I can handle this

import time
from alns.stop import MaxRuntime
from numpy.random import Generator
from alns.State import State
from tqdm import tqdm


class MaxRuntimeWithProgress(MaxRuntime):
    def __init__(self, max_runtime: float):
        super().__init__(max_runtime)
        self._pbar = None
        self._elapsed = 0
        self._iterations = 0

    def _create_new_bar(self):
        self._pbar = tqdm(total=self._max_runtime, desc="MaxRuntime", unit="s")

    def __call__(self, rng: Generator, best: State, current: State) -> bool:
        result = super().__call__(rng, best, current)
        current_elapsed = int(time.perf_counter() - self._start_runtime)
        if not self._pbar:
            self._create_new_bar()
        self._pbar.set_description(
            f"[MaxRuntime] B:{best.objective():.2f}, C:{current.objective():.2f} I:{self._iterations}")
        self._pbar.set_postfix_str(f"[{current_elapsed / self._max_runtime * 100:5.2f}%]")

        if not result:
            self._iterations += 1
            if self._elapsed != current_elapsed:
                self._pbar.update(current_elapsed - self._elapsed)
        else:
            self._pbar.close()

        self._elapsed = current_elapsed
        return result

    def __getstate__(self):
        # Remove the progress bar before pickling
        state = self.__dict__.copy()
        state['_pbar'] = None
        return state

    def __setstate__(self, state):
        # Restore the object without the progress bar
        self.__dict__.update(state)

testcode:

    class State:
        def objective(self) -> float:
            return 1

    state = State()
    stop = MaxRuntimeWithProgress(500)
    while not stop(rng=np.random.default_rng(1),best=state,current=state):
        time.sleep(1)

image

@Euraxluo
Copy link
Author

Euraxluo commented Dec 25, 2024

I hope we can fix this, because I feel close to success, perfect use already, do not want to go back to use TQDM, because I come from TQDM

If there's anything I can do, I'll do my best

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant