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

Memory leaks when building models from custom templates #212

Open
salaza82 opened this issue Sep 17, 2024 · 4 comments
Open

Memory leaks when building models from custom templates #212

salaza82 opened this issue Sep 17, 2024 · 4 comments
Assignees

Comments

@salaza82
Copy link

Spectral model classes inheriting the FunctionMeta class AND loading data leak memory. Memory leaks immediately on calling the constructor and when class object goes out of scope.

Class defintion does the following

from astromodels.functions.function import Function1D, FunctionMeta
import numpy as np

class CustomSpec(Function1D, metaclass=FunctionMeta):

    def _setup(self):
        # Does nothing

    def _load_spec_from_params(self):
        self._data = np.load(<path_to_data_file>, allow_pickle=True).item()

    def set_params(self, params):
        self_attributes = params

        self._load_spec_from_params()

The following will leak slowly

import psutil as ps
from threeML import *
# Custom Spectral class library
import CustomSpec

p = ps.Process()

for i in range(500):
    spectrum = CustomSpec() # instantiate spectral model

    if i%50 == 0: # Print memory use every 50 iters
        print(f'Real Usage: {p.memory_info().rss * 1e-6:4.1f} MB')

And the following leaks substantially.

spectrum = CustomSpec()

for i in range(500):

    # Define Spectral model Parameters
    spectrum.set_params("your params here")

    # Instantiate spatial template
    myDwarf = PointSource('name', 0.0, 30.0, spectral_shape=spectrum)
    model = Model(myDwarf)

    if i%50 == 0 or i == 499: # Print memory use every 50 steps
        print(f'Real Usage: {p.memory_info().rss * 1e-6:4.1f} MB')

In the second block, the jump in memory use is exactly the size of the data table loaded in the custom spectral class.

@omodei omodei self-assigned this Sep 17, 2024
@omodei
Copy link
Contributor

omodei commented Sep 17, 2024

Hi Dan, I modified your code to make it working. The function implementation needs to have the docstring
the units setter and the evaluate function. This is the implementation (I simply read in a big array, to test memory leaks):

import numpy as np
import psutil as ps
from threeML import *

a = np.ones((1000,1000))
np.savez('123.npz', a=a)

class CustomSpec(Function1D, metaclass=FunctionMeta):
    r"""
    description :
        CustomSpec
    latex :  $\delta$
    parameters :

        K :
            desc : Normalization
            initial value : 1.0
            is_normalization : True
            transformation : log10
            min : 1e-10
            max: 1e4
            delta: 0.1
    """
    def _setup(self):
        pass
        # Does nothing

    def _load_spec_from_params(self):
        self._data = np.load('123.npz', allow_pickle=True)

    def set_params(self, params):
        self._load_spec_from_params()

    def evaluate(self,x, K):
        return K * x * self._data[0]
    
    def _set_units(self, x_unit, y_unit):
        # The normalization has the same units as the y
        self.K.unit = y_unit
        pass

Then, I ran your simple tests:

p = ps.Process()
N=1000
for i in range(N):
    spectrum = CustomSpec() # instantiate spectral model
    if i%50 == 0: # Print memory use every 50 iters
        print(f'Real Usage: {p.memory_info().rss * 1e-6:4.1f} MB')

and the real usage went from 307.4 MB to 307.8 MB.
The second test:

spectrum = CustomSpec()

for i in range(N):

    # Define Spectral model Parameters
    spectrum.set_params("your params here")

    # Instantiate spatial template
    myDwarf = PointSource('myPointSource', 0.0, 30.0, spectral_shape=spectrum)
    model = Model(myDwarf)
    #del model # <--- This didn't make any difference!
    if i%50 == 0 or i == N-1: # Print memory use every 50 steps
        print(f'{i:d} Real Usage: {p.memory_info().rss * 1e-6:4.1f} MB')

The memory went from 307.9 MB to 308.0 MB, so, not a big difference. Can you double check?

@salaza82
Copy link
Author

salaza82 commented Sep 17, 2024 via email

@omodei
Copy link
Contributor

omodei commented Sep 17, 2024

You can reduce memory leaks by explicitly deleting the object in the reverse order you create them. Inside the loop:
del model
del myDwarf
del spectrum

for i in range(N):

    spectrum = CustomSpec() # instantiate this in the for loop instead

    # Define Spectral model Parameters
    spectrum.set_params("your params here")

    # Instantiate spatial template
    myDwarf = PointSource('myPointSource', 0.0, 30.0, spectral_shape=spectrum)
    model = Model(myDwarf)
    del model
    del myDwarf
    del spectrum
    if i%50 == 0 or i == N-1: # Print memory use every 50 steps
        print(f'{i:d} Real Usage: {p.memory_info().rss * 1e-6:4.1f} MB')

@salaza82
Copy link
Author

salaza82 commented Sep 18, 2024 via email

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

2 participants