Skip to main content

💟 Lovely numpy

Project description

💟 Lovely NumPy

Read full docs | ❤️ Lovely Tensors | 💘 Lovely JAX | Discord

Install

pip install lovely-numpy

How to use

How often do you find yourself debugging NumPy code? You dump a tensor to the cell output, and see this:

numbers
array([[[-0.3541, -0.3369, -0.4054, ..., -0.5596, -0.4739,  2.2489],
        [-0.4054, -0.4226, -0.4911, ..., -0.9192, -0.8507,  2.1633],
        [-0.4739, -0.4739, -0.5424, ..., -1.039 , -1.039 ,  2.1975],
        ...,
        [-0.902 , -0.8335, -0.9363, ..., -1.4672, -1.2959,  2.2318],
        [-0.8507, -0.7822, -0.9363, ..., -1.6042, -1.5014,  2.1804],
        [-0.8335, -0.8164, -0.9705, ..., -1.6555, -1.5528,  2.1119]],

       [[-0.1975, -0.1975, -0.3025, ..., -0.4776, -0.3725,  2.4111],
        [-0.25  , -0.2325, -0.3375, ..., -0.7052, -0.6702,  2.3585],
        [-0.3025, -0.285 , -0.3901, ..., -0.7402, -0.8102,  2.3761],
        ...,
        [-0.4251, -0.2325, -0.3725, ..., -1.0903, -1.0203,  2.4286],
        [-0.3901, -0.2325, -0.4251, ..., -1.2304, -1.2304,  2.4111],
        [-0.4076, -0.285 , -0.4776, ..., -1.2829, -1.2829,  2.341 ]],

       [[-0.6715, -0.9853, -0.8807, ..., -0.9678, -0.689 ,  2.396 ],
        [-0.7238, -1.0724, -0.9678, ..., -1.2467, -1.0201,  2.3263],
        [-0.8284, -1.1247, -1.0201, ..., -1.2641, -1.1596,  2.3786],
        ...,
        [-1.2293, -1.4733, -1.3861, ..., -1.5081, -1.2641,  2.518 ],
        [-1.1944, -1.4559, -1.421 , ..., -1.6476, -1.4733,  2.4308],
        [-1.2293, -1.5256, -1.5081, ..., -1.6824, -1.5256,  2.3611]]],
      dtype=float32)

Was it really useful for you, as a human, to see all these numbers?

What is the shape? The size?
What are the statistics?
Are any of the values nan or inf?
Is it an image of a man holding a tench?

from lovely_numpy import lovely, rgb, chans

lovely()

lovely(numbers)
ndarray[3, 196, 196] f32 n=115248 x∈[-2.118, 2.640] μ=-0.388 σ=1.073

Better, eh?

lovely(numbers[1,:6,1]) # Still shows values if there are not too many.
ndarray[6] f32 x∈[-0.443, -0.197] μ=-0.311 σ=0.083 [-0.197, -0.232, -0.285, -0.373, -0.443, -0.338]
spicy = numbers[0,:12,0].copy()

spicy[0] *= 10000
spicy[1] /= 10000
spicy[2] = float('inf')
spicy[3] = float('-inf')
spicy[4] = float('nan')

spicy = spicy.reshape((2,6))
lovely(spicy) # Spicy stuff
ndarray[2, 6] f32 n=12 x∈[-3.541e+03, -4.054e-05] μ=-393.842 σ=1.113e+03 +Inf! -Inf! NaN!
lovely(np.zeros((10, 10))) # A zero array - make it obvious
ndarray[10, 10] all_zeros
lovely(spicy, verbose=True)
ndarray[2, 6] f32 n=12 x∈[-3.541e+03, -4.054e-05] μ=-393.842 σ=1.113e+03 +Inf! -Inf! NaN!
array([[-3.5405e+03, -4.0543e-05,         inf,        -inf,         nan,
        -6.1093e-01],
       [-6.1093e-01, -5.9380e-01, -5.9380e-01, -5.4243e-01, -5.4243e-01,
        -5.4243e-01]], dtype=float32)

Going .deeper

lovely(numbers, depth=1)
ndarray[3, 196, 196] f32 n=115248 x∈[-2.118, 2.640] μ=-0.388 σ=1.073
  ndarray[196, 196] f32 n=38416 x∈[-2.118, 2.249] μ=-0.324 σ=1.036
  ndarray[196, 196] f32 n=38416 x∈[-1.966, 2.429] μ=-0.274 σ=0.973
  ndarray[196, 196] f32 n=38416 x∈[-1.804, 2.640] μ=-0.567 σ=1.178
# You can go deeper if you need to
lovely(numbers[:,:3,:5], depth=2)
ndarray[3, 3, 5] f32 n=45 x∈[-1.316, -0.197] μ=-0.593 σ=0.302
  ndarray[3, 5] f32 n=15 x∈[-0.765, -0.337] μ=-0.492 σ=0.119
    ndarray[5] f32 x∈[-0.440, -0.337] μ=-0.385 σ=0.037 [-0.354, -0.337, -0.405, -0.440, -0.388]
    ndarray[5] f32 x∈[-0.662, -0.405] μ=-0.512 σ=0.097 [-0.405, -0.423, -0.491, -0.577, -0.662]
    ndarray[5] f32 x∈[-0.765, -0.474] μ=-0.580 σ=0.112 [-0.474, -0.474, -0.542, -0.645, -0.765]
  ndarray[3, 5] f32 n=15 x∈[-0.513, -0.197] μ=-0.321 σ=0.096
    ndarray[5] f32 x∈[-0.303, -0.197] μ=-0.243 σ=0.049 [-0.197, -0.197, -0.303, -0.303, -0.215]
    ndarray[5] f32 x∈[-0.408, -0.232] μ=-0.327 σ=0.075 [-0.250, -0.232, -0.338, -0.408, -0.408]
    ndarray[5] f32 x∈[-0.513, -0.285] μ=-0.394 σ=0.091 [-0.303, -0.285, -0.390, -0.478, -0.513]
  ndarray[3, 5] f32 n=15 x∈[-1.316, -0.672] μ=-0.964 σ=0.170
    ndarray[5] f32 x∈[-0.985, -0.672] μ=-0.846 σ=0.110 [-0.672, -0.985, -0.881, -0.776, -0.916]
    ndarray[5] f32 x∈[-1.212, -0.724] μ=-0.989 σ=0.160 [-0.724, -1.072, -0.968, -0.968, -1.212]
    ndarray[5] f32 x∈[-1.316, -0.828] μ=-1.058 σ=0.160 [-0.828, -1.125, -1.020, -1.003, -1.316]

Now in .rgb color

The important queston - is it our man?

rgb(numbers, cl=0)

Maaaaybe? Looks like someone normalized him.

in_stats = ( (0.485, 0.456, 0.406),     # mean 
             (0.229, 0.224, 0.225) )    # std

# numbers.rgb(in_stats, cl=True) # For channel-last input format
rgb(numbers, denorm=in_stats, cl=0)

It’s indeed our hero, the Tenchman!

See the .chans

# .chans will map values betwen [0,1] to colors.
# Make our values fit into that range to avoid clipping.
mean = np.array(in_stats[0])[:,None,None]
std = np.array(in_stats[1])[:,None,None]
numbers_01 = (numbers*std + mean)
lovely(numbers_01)
ndarray[3, 196, 196] n=115248 x∈[-4.053e-09, 1.000] μ=0.361 σ=0.248
chans(numbers_01)

Grouping (.rgb and .chans )

# Make 8 images with progressively higher brightness and stack them 2x2x2.
eight_images = (np.stack([numbers]*8) + np.linspace(-2, 2, 8)[:,None,None,None])
eight_images = (eight_images
                     *np.array(in_stats[1])[:,None,None]
                     +np.array(in_stats[0])[:,None,None]
                ).clip(0,1).reshape(2,2,2,3,196,196)
            
lovely(eight_images)
ndarray[2, 2, 2, 3, 196, 196] n=921984 x∈[0., 1.000] μ=0.382 σ=0.319
rgb(eight_images, cl=0)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lovely-numpy-0.1.2.tar.gz (3.8 MB view hashes)

Uploaded Source

Built Distribution

lovely_numpy-0.1.2-py3-none-any.whl (15.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page