pythonprofilers / memory_profiler

Monitor Memory usage of Python code
http://pypi.python.org/pypi/memory_profiler
Other
4.39k stars 380 forks source link

negative memory increment #396

Open aidenhammond opened 1 year ago

aidenhammond commented 1 year ago

I've seen similar tickets from 2018 on this topic, but I assume they've been fixed since. Getting a negative memory increment when running some code. Here is the code that I am running:

from torch import Tensor, linspace, meshgrid, zeros, square, div, sum, norm, sqrt, nan_to_num, nonzero, device, zeros_like, atan, cat, empty, subtract
import argparse
from torch.cuda import is_available
from torch.nn.functional import normalize
from scipy.constants import pi, epsilon_0
from math import ceil
from jaxtyping import Shaped
from matplotlib.pyplot import figure, show
from numpy import abs, min
import memory_profiler

#################################
#                               #
#             Setup             #
#                               #
#################################
# Checking for cuda-capable device (for gpu assistance)
device = device("cuda:0" if is_available() else "cpu")

# Parsing arguments
parser = argparse.ArgumentParser()
parser.add_argument('--charge', type=str, help='The name of the person.')
parser.add_argument('--side-length', type=float, help='The y-coordinate of observation.')
parser.add_argument('--x', type=float, help='The x-coordinate of observation.')
parser.add_argument('--y', type=float, help='The y-coordinate of observation.')
parser.add_argument('--z', type=float, help='The z-coordinate of observation.')
parser.add_argument('--n', type=float, help='The number of points.')

args = parser.parse_args() # get arguments

# set arguments to variables to save space
@profile
def main():
    q = float(args.charge)
    L = float(args.side_length)
    x = float(args.x)
    y = float(args.y)
    z = float(args.z)
    N = int(args.n)
    sigma = q / L**2 # useful later
    k= (q/N**2) / (4.0 * pi * epsilon_0)
    _k = sigma / (pi*epsilon_0)
    Ls = (L/2)**2

    #### Preallocating tensors
    # creating N number of points along z axis from 0 to z
    z_coords = linspace(0, z, N, device=device)
    _p = zeros(N, 1, 1, 3, device=device)
    result = empty(N, 3)
    estimated = empty(N,3)

    # setting up tensor representing the square on the xy plane centered at the origin
    # think of it like a cube of size 1*N*N where each point in that
    # cube holds 3 values
    # shape is [1,N,N,3]
    t = zeros(1,N,N,3, device=device)

    # Creating one-dim tensors of size N whose values are evenly spaced
    # between -L/2 and L/2 for both x and y coordinates of charges 
    # throughout a square plane centered at the origin
    x_coords = linspace(-L/2.0, L/2.0, N) if N > 1 else Tensor([0.0])
    y_coords = linspace(-L/2.0, L/2.0, N) if N > 1 else Tensor([0.0])

    # putting those coordinates into a 2D grid
    _x, _y = meshgrid(x_coords, y_coords)

    # putting the grid in for the x and y components along the last
    # dimension of our tensor that represents the square
    t[:,:,:,0] = _x
    t[:,:,:,1] = _y

    # point of observation
    # shape is [1,1,1,3]
    p = Tensor([[[[x,y,z]]]], device=device)

    # print to console
    point = p[0][0][0]
    p = p.subtract(t)

    # basic efield equation
    #    1       q
    #  E = ------ * ---- *r_hat
    #      4pi*e0    r^2
    print("E-Field at ", point," is: ", nan_to_num(sum((div(k, square(p)))*normalize(p,dim=3), dim=(1,2))))

    #################################
    #                               #
    #    Finding Percent Error      #
    #                               #
    #################################

    # reshaping and adding to tensor of correct shape
    z_coords = z_coords.view(N, 1, 1)
    _p[:,:,:,2] = z_coords

    # finding estimated at the points along the z axis
    estimated = nan_to_num(sum((div(k, square(_p-t)))*normalize(_p-t,dim=3), dim=(1,2)))

    # finding actual
    #
    #       sigma            /          (L/2)^2         \
    #  E = ------- * tan^-1 ( -------------------------- )
    #       pi*e0            \ z* sqrt(z^2 + 2*(L/2)^2) /
    #

    e = (_k) * atan(div(Ls,_p * sqrt(square(_p) + 2*Ls))) * normalize(_p, dim=3)
    actual = nan_to_num(e.squeeze(1).squeeze(1))

    #################################
    #                               #
    #     Printing to console       #
    #                               #
    #################################
    z_coords = z_coords.squeeze(-1).squeeze(-1)

    a = actual[:, 2].squeeze(-1).cpu().numpy()
    e = estimated[:, 2].squeeze(-1).cpu().numpy()

    print("Plotting....")
    #
    #     Plotting
    #
    fig = figure()
    ax1 = fig.add_subplot(1,2,1)
    ax1.plot(z_coords.cpu().numpy(), a, label="Actual")
    ax1.plot(z_coords.cpu().numpy(), e, label="Estimate")

    ax2= fig.add_subplot(1,2,2)
    ax2.plot(z_coords.cpu().numpy(), abs(e-a)/a, label="Percent Error")

    show()
main()

This is how I am running it:

python -m memory_profiler efield.py --charge 0.1 --side-length 0.01 --x -1.694 --y -0.051 --z 2.345 --n 1001

This is the output I get:

E-Field at  tensor([-1.6940, -0.0510,  2.3450])  is:  tensor([[-1.8337e+08, -6.1105e+09,  1.3247e+08]])
Plotting....
efield.py:134: RuntimeWarning: invalid value encountered in divide
  ax2.plot(z_coords.cpu().numpy(), abs(e-a)/a, label="Percent Error")
Filename: efield.py

Line #    Mem usage    Increment  Occurrences   Line Contents
=============================================================
    34  207.062 MiB  207.062 MiB           1   @profile
    35                                         def main():
    36  207.062 MiB    0.000 MiB           1    q = float(args.charge)
    37  207.062 MiB    0.000 MiB           1    L = float(args.side_length)
    38  207.062 MiB    0.000 MiB           1    x = float(args.x)
    39  207.062 MiB    0.000 MiB           1    y = float(args.y)
    40  207.062 MiB    0.000 MiB           1    z = float(args.z)
    41  207.062 MiB    0.000 MiB           1    N = int(args.n)
    42  207.062 MiB    0.000 MiB           1    sigma = q / L**2 # useful later
    43  207.062 MiB    0.000 MiB           1    k= (q/N**2) / (4.0 * pi * epsilon_0)
    44  207.062 MiB    0.000 MiB           1    _k = sigma / (pi*epsilon_0)
    45  207.062 MiB    0.000 MiB           1    Ls = (L/2)**2
    46                                         
    47                                          #### Preallocating tensors
    48                                          # creating N number of points along z axis from 0 to z
    49  207.594 MiB    0.531 MiB           1    z_coords = linspace(0, z, N, device=device)
    50  207.781 MiB    0.188 MiB           1    _p = zeros(N, 1, 1, 3, device=device)
    51  207.797 MiB    0.016 MiB           1    result = empty(N, 3)
    52  207.797 MiB    0.000 MiB           1    estimated = empty(N,3)
    53                                         
    54                                         
    55                                          # setting up tensor representing the square on the xy plane centered at the origin
    56                                          # think of it like a cube of size 1*N*N where each point in that
    57                                          # cube holds 3 values
    58                                          # shape is [1,N,N,3]
    59  219.516 MiB   11.719 MiB           1    t = zeros(1,N,N,3, device=device)
    60                                         
    61                                          # Creating one-dim tensors of size N whose values are evenly spaced
    62                                          # between -L/2 and L/2 for both x and y coordinates of charges 
    63                                          # throughout a square plane centered at the origin
    64  219.516 MiB    0.000 MiB           1    x_coords = linspace(-L/2.0, L/2.0, N) if N > 1 else Tensor([0.0])
    65  219.516 MiB    0.000 MiB           1    y_coords = linspace(-L/2.0, L/2.0, N) if N > 1 else Tensor([0.0])
    66                                         
    67                                          # putting those coordinates into a 2D grid
    68  220.047 MiB    0.531 MiB           1    _x, _y = meshgrid(x_coords, y_coords)
    69                                         
    70                                          # putting the grid in for the x and y components along the last
    71                                          # dimension of our tensor that represents the square
    72  220.547 MiB    0.500 MiB           1    t[:,:,:,0] = _x
    73  220.547 MiB    0.000 MiB           1    t[:,:,:,1] = _y
    74                                         
    75                                          # point of observation
    76                                          # shape is [1,1,1,3]
    77  220.656 MiB    0.109 MiB           1    p = Tensor([[[[x,y,z]]]], device=device)
    78                                         
    79                                          # print to console
    80  220.656 MiB    0.000 MiB           1    point = p[0][0][0]
    81  232.281 MiB   11.625 MiB           1    p = p.subtract(t)
    82                                         
    83                                          # basic efield equation
    84                                          #    1       q
    85                                          #  E = ------ * ---- *r_hat
    86                                          #      4pi*e0    r^2
    87  276.828 MiB   44.547 MiB           1    print("E-Field at ", point," is: ", nan_to_num(sum((div(k, square(p)))*normalize(p,dim=3), dim=(1,2))))
    88                                         
    89                                          #################################
    90                                          #                               #
    91                                          #    Finding Percent Error      #
    92                                          #                               #
    93                                          #################################
    94                                         
    95                                         
    96                                          # reshaping and adding to tensor of correct shape
    97  276.844 MiB    0.016 MiB           1    z_coords = z_coords.view(N, 1, 1)
    98  276.844 MiB    0.000 MiB           1    _p[:,:,:,2] = z_coords
    99                                         
   100                                         
   101                                          # finding estimated at the points along the z axis
   102   53.266 MiB -223.578 MiB           1    estimated = nan_to_num(sum((div(k, square(_p-t)))*normalize(_p-t,dim=3), dim=(1,2)))
   103                                         
   104                                          # finding actual
   105                                          #
   106                                          #       sigma            /          (L/2)^2         \
   107                                          #  E = ------- * tan^-1 ( -------------------------- )
   108                                          #       pi*e0            \ z* sqrt(z^2 + 2*(L/2)^2) /
   109                                          #
   110                                         
   111   56.781 MiB    3.516 MiB           1    e = (_k) * atan(div(Ls,_p * sqrt(square(_p) + 2*Ls))) * normalize(_p, dim=3)
   112   57.000 MiB    0.219 MiB           1    actual = nan_to_num(e.squeeze(1).squeeze(1))
   113                                         
   114                                          #################################
   115                                          #                               #
   116                                          #     Printing to console       #
   117                                          #                               #
   118                                          #################################
   119   57.094 MiB    0.094 MiB           1    z_coords = z_coords.squeeze(-1).squeeze(-1)
   120                                         
   121   57.469 MiB    0.375 MiB           1    a = actual[:, 2].squeeze(-1).cpu().numpy()
   122   57.469 MiB    0.000 MiB           1    e = estimated[:, 2].squeeze(-1).cpu().numpy()
   123                                         
   124   57.609 MiB    0.141 MiB           1    print("Plotting....")
   125                                          #
   126                                          #     Plotting
   127                                          #
   128  100.125 MiB   42.516 MiB           1    fig = figure()
   129  108.234 MiB    8.109 MiB           1    ax1 = fig.add_subplot(1,2,1)
   130  108.500 MiB    0.266 MiB           1    ax1.plot(z_coords.cpu().numpy(), a, label="Actual")
   131  108.547 MiB    0.047 MiB           1    ax1.plot(z_coords.cpu().numpy(), e, label="Estimate")
   132                                         
   133  108.953 MiB    0.406 MiB           1    ax2= fig.add_subplot(1,2,2)
   134  109.344 MiB    0.391 MiB           1    ax2.plot(z_coords.cpu().numpy(), abs(e-a)/a, label="Percent Error")
   135                                         
   136  172.156 MiB   62.812 MiB           1    show()

Line 102 has a memory increment of -223.578 MiB.

Here is an output of running uname -a on the M1 pro system:

Darwin MacBook-Pro.local 22.1.0 Darwin Kernel Version 22.1.0: Sun Oct  9 20:15:09 PDT 2022; root:xnu-8792.41.9~2/RELEASE_ARM64_T6000 arm64