Numpy: creating batch of numpy arrays within another numpy array (reshaping) - python

I have a numpy array batch of shape (32,5). Each element of the batch consists of a numpy array batch_elem = [s,_,_,_,_] where s = [img,val1,val2] is a 3-dimensional numpy array and _ are simply scalar values.
img is an image (numpy array) with dimensions (84,84,3)
I would like to create a numpy array with the shape (32,84,84,3). Basically I want to extract the image information within each batch and transform it into a 4-dimensional array.
I tried the following:
b = np.vstack(batch[:,0]) #this yields a b with shape (32,3), type: <class 'numpy.ndarray'>
Now I would like to access the images (first index in second dimension)
img_batch = b[:,0] # this returns an array of shape (32,), type: <class 'numpy.ndarray'>
How can I best access the image data and get a shape (32,84,84,3)?
Note:
s = b[0] #first s of the 32 in batch: shape (3,) , type: <class 'numpy.ndarray'>
Edit:
This should be a minimal example:
img = np.zeros([5,5,3])
s = np.array([img,1,1])
batch_elem = np.array([s,1,1,1,1])
batch = np.array([batch_elem for _ in range(32)])

Assuming I understand the problem correctly, you can stack twice on the last axis.
res = np.stack(np.stack(batch[:,0])[...,0])

import numpy as np
# fabricate some data
batch = np.array((32, 1), dtype=object)
for i in range(len(batch)):
batch[i] = [np.random.rand(84, 84, 3), None, None]
# select images
result = np.array([img for img, _, _ in batch])
# double check!
for i in range(len(batch)):
assert np.all(result[i, :, :, :] == batch[i][0])

Related

How to record data under HDF5 file correctly

I am getting Type Error: Object dtype dtype('O') has no native HDF5 equivalent.
Here is my python code;
dtype for mel_train, mfcc_train, and y_train are all float32.
Array shapes are: mfcc_train: (6398,) ; mel_train: (6398,) and y_train: (6398, 16).
with h5py.File(train_file,'w') as f:
f['mfcc_train'] = mfcc_train
f['mel_train'] = mel_train
f['y_train'] = y_train
import h5py
import pickle
from utils import change_label, make_dir
# open training, validation, and testing sets from csv files
train_csv = pd.read_csv("training.csv",index_col=0)
valid_csv = pd.read_csv("validation.csv",index_col=0)
test_csv = pd.read_csv("testing.csv",index_col=0)
feature_dir = 'features' # directory to store the extracted features
make_dir(feature_dir) # create directory if it does not exist
mel_train = []
mel_valid = []
mel_test = []
mfcc_train = []
mfcc_valid = []
mfcc_test = []
change = change_label() # to encode string label (class name)
into binary matrix or vice versa
for i in range(train_csv.shape[0]):
sr, audio = wavfile.read(train_csv.iloc[i,0])
audio = pad_input(audio)
mel = normalise_feature(extract_mel(audio))
mfcc = normalise_feature(extract_mfcc(audio))
mel_train.append(mel.T)
mfcc_train.append(mfcc.T)
mel_train = np.asarray(mel_train)
print(mel_train.shape)
mfcc_train = np.asarray(mfcc_train)
print(mfcc_train.shape)
y = train_csv.iloc[:,1].to_list()
y_train = change.str2bin(y)
print(y_train.shape)
train_file = os.path.join(feature_dir,'mel_mfcc_train.h5')
print ("Storing extracted features and associated label
from training set into a file: "+train_file)
with h5py.File(train_file,'w') as f:
f['mel_train'] = mel_train
f['mfcc_train'] = mfcc_train
f['y_train'] = y_train`
OK, I think I know what's going on (educated guess). You extract the audio data to arrays mel and mfcc, then add to lists mel_train and mfcc_train (looping over 6398 audio files). After you exit the loop, you convert the lists to arrays. If every mel and mfcc array has the same shape (say (m,n)) the new arrays would be shape (6398,m,n), where 6398 is len(mel_train). However, I suspect each mel and mfcc array has a different shape. As a result, when you convert the list of differently shaped arrays to a single array, you will get an array shape of (6398,) with dtype=object (where the objects are float32 arrays).
To demonstrate the difference, I created an 2 nearly identical examples:
Creates 5 arrays of identical 2d shape (10,2), adds to a list, then converts the list to an array. Note how the final array is shape (5,10,2) and dtype is float64. You can create a HDF5 dataset directly from this array.
Creates 5 arrays of variable 2d shape, adds to a list, then converts the list to an array. Note how the final array is shape (5,) and dtype is object. You cannot create a HDF5 dataset directly from this array. This is why you get TypeError: Object dtype dtype('O') has no native HDF5 equivalent.
Note: I added dtype=object to the np.asarray() function for the second method to avoid the VisibleDeprecationWarning.
Example 2 shows 2 methods to load data. It continues from Example 1 and loads data into the same HDF5 file. After you run them, you can compare dataset mel_train1, group mel_train2 and dataset mel_train3. Each has a "Note" attribute to describe the data.
Code below:
Example 1 - constant shape arrays:
train_file = 'mel_mfcc_train.h5'
## Example 1 - Create arrays of constant shape
a0, a1, n = 10, 2, 5
mel_train = []
for i in range(n):
arr = np.random.random(a0*a1).reshape(a0,a1)
mel_train.append(arr)
print('\nFor mel_train arrays of constant size:')
print(f'Size of mel_train list: {len(mel_train)}')
mel_train = np.asarray(mel_train)
print(f'For mel_train array: Dtype: {mel_train.dtype}; Shape: {mel_train.shape}')
with h5py.File(train_file,'w') as f:
f['mel_train1'] = mel_train
f['mel_train1'].attrs['Note'] = f'{n} Constant shaped arrays: {a0} x {a1}'
Example 2 - variable shape arrays:
## Example 2 - Create arrays of random shape
mel_train = []
for i in range(n):
a0 = np.random.randint(6,10) # set a0 dimension to random length
##a1 = np.random.randint(3,6)
arr = np.random.random(a0*a1).reshape(a0,a1)
mel_train.append(arr)
print('\nFor mel_train arrays of random size:')
print(f'Size of mel_train list: {len(mel_train)}')
# mel_train = np.asarray(mel_train)
mel_train = np.asarray(mel_train,dtype=object)
print(f'For mel_train array: Dtype: {mel_train.dtype}; Shape: {mel_train.shape}')
for i, arr in enumerate(mel_train):
print(f'\tFor a0= {i}; shape: {arr.shape}')
Loading Example 2 data as-is will throw an exception
# Creating a dataset with arrays of different sizes will throw
# an exception (exception trapped and printed in code below)
try:
with h5py.File(train_file,'a') as f:
f['mel_train2'] = mel_train
except Exception as e:
print(f'\nh5py Exception: {e}\n')
Recommended method to load Example 2 data
## Example 2A
# To avoid exception, write each object/array to seperate datasets in 1 group
with h5py.File(train_file,'a') as f:
grp = f.create_group('mel_train2')
f['mel_train2'].attrs['Note'] = f'1 group and {n} datasets for variable shaped arrays'
for i, arr in enumerate(mel_train):
f[f'mel_train2/dataset_{i:04}'] = arr
Alternate method to load Example 2 data (not recommended)
## Example 2B - for completeness; NOT recommended
# Alternately, size dataset to hold largest array.
# dataset will have zeros where smaller arrays are loaded
ds_dtype = mel_train[0].dtype
ds_a0 = mel_train.shape[0]
ds_a1, ds_a2 = 0, 0
for arr in mel_train:
ds_a1 = max(ds_a1, arr.shape[0])
ds_a2 = max(ds_a2, arr.shape[1])
with h5py.File(train_file,'a') as f:
ds2 = f.create_dataset('mel_train2',dtype=ds_dtype,shape=(ds_a0,ds_a1,ds_a2))
for i, arr in enumerate(mel_train):
j,k = arr.shape[0], arr.shape[1]
ds2[i,0:j,0:k] = arr
Typical output from running code above:
For mel_train arrays of constant size:
Size of mel_train list: 5
For mel_train array: Dtype: float64; Shape: (5, 10, 2)
For mel_train arrays of random size:
Size of mel_train list: 5
For mel_train array: Dtype: object; Shape: (5,)
For a0= 0; shape: (6, 2)
For a0= 1; shape: (7, 2)
For a0= 2; shape: (8, 2)
For a0= 3; shape: (6, 2)
For a0= 4; shape: (9, 2)
h5py Exception: Object dtype dtype('O') has no native HDF5 equivalent

Convert arrays and tensors to matrices then perform matrix operations

I have two arrays of size (128,) and a third one of size (784, 128):
array1.shape()
out: (128,)
array2.shape()
out: (128,)
array3.shape()
out: (784,128)
They have the same data type but the dtype() output is different:
array1.dtype
out: float32
array2.dtype
out: <dtype: 'float32'>
array2.dtype
out: <dtype: 'float32'>
And they belong to different classes:
type(array1)
out: <class 'numpy.ndarray'>
type(array2)
out: <class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>
type(array3)
out: <class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>
I want to perform the following matrix operation:
(array1 - array2) * array3.T
Where T is the transpose of array3.
Lastly, the output matrix (which is [784 * 1]) needs to be reshaped to become a uint8 array of shape 28 * 28 so I can plot that output on a matplotlip.
Can anyone help me to convert the arrays into matrices first. Then Transpose the third array properly. Finally, reshape the output to become an uint8 array of size 28 * 28.
I am working with tensorflow and keras in python.
Cast array1 as np.asmatrix()
array1 = np.asmatrix(array1)
For array2, change it to numpy array fist then cast it as a matrix:
array2 = array2.numpy()
array2 = np.asmatrix(array2)
For array3, change it to numpy array first then cast it as a matrix. Lastly, transpose that matrix:
array3 = array3.numpy()
array3 = np.asmatrix(array3)
array3 = np.transpose(array3)
Finally, apply the matrix operation:
result = (array1 - array2) * array3
To plot the output, use the following:
result = np.array(result)
plt.imshow(result.reshape(28, 28), cmap='gray')
plt.show()

How to normalize a large numpy array ? - MemoryError

I have an array of shape: (40000, 240, 320)
Its an image array and I want to normalize each pixel value as follows:
X = X/255
When I try to run the above statement, it throws following error:
MemoryError: Unable to allocate array with shape (40000, 240, 320) and data type float64
How to work with large numpy array in such cases ?
You can use augmented assignment with division (/=), which will modify X in-place:
X /= 255
Your current code attempts to allocate a temporary object:
X = X/255
# Is actually executed like:
tmp = X / 255 # new object!
X = tmp

How To ReShape a Numpy Array in Python

I have a numpy array of images with the shape of (5879,). Inside every index of the numpy array, I have the Pixels of the image with a shape of (640,640,3).
I want to reshape the complete array in such a way that the shape of the numpy array becomes (5879,640,640,3).
please check, whether below code works for you or not
import numpy as np
b = np.array([5879])
b.shape
output (1,)
a = np.array([[640],[640],[3]])
a = a.reshape((a.shape[0], 1))
a.shape
output (3, 1)
c = np.concatenate((a,b[:,None]),axis=0)
c.shape
Output:
(4, 1)
np.concatenate((a,b[:,None]),axis=0)
output
array([[ 640],
[ 640],
[ 3],
[5879]])
You want to stack your images along the first axis, into a 4D array. However, your images are all 3D.
So, first you need to add a leading singleton dimension to all images, and then to concatenate them along this axis:
imgs = [i_[None, ...] for i_ in orig_images] # add singleton dim to all images
x = np.concatenate(imgs, axis=0) # stack along the first axis
Edit:
Based on Mad Phyiscist's comment, it seems like using np.stack is more appropriate here: np.stack takes care of adding the leading singleton dimension for you:
x = np.stack(orig_images, axis=0)

Numpy flatten RGB image array

I have 1,000 RGB images (64X64) which I want to convert to an (m, n) array.
I use this:
import numpy as np
from skdata.mnist.views import OfficialImageClassification
from matplotlib import pyplot as plt
from PIL import Image
import glob
import cv2
x_data = np.array( [np.array(cv2.imread(imagePath[i])) for i in range(len(imagePath))] )
print x_data.shape
Which gives me: (1000, 64, 64, 3)
Now if I do:
pixels = x_data.flatten()
print pixels.shape
I get: (12288000,)
However, I require an array with these dimensions: (1000, 12288)
How can I achieve that?
Apply the numpy method reshape() after applying flatten() to the flattened array:
x_data = np.array( [np.array(cv2.imread(imagePath[i])) for i in range(len(imagePath))] )
pixels = x_data.flatten().reshape(1000, 12288)
print pixels.shape
Try this:
d1, d2, d3, d4 = x_data.shape
then using numpy.reshape()
x_data_reshaped = x_data.reshape((d1, d2*d3*d4))
or
x_data_reshaped = x_data.reshape((d1, -1))
(Numpy infers the the value instead of -1 from original length and defined dimension d1)
You can iterate over your images array and flatten each row independently.
numImages = x_data.shape[0]
flattened = np.array([x_data[i].flatten() for i in range(numImages)])
You could also use this:
X is your 2D picture with size 32x32 for example and the -1 it simply means that it is an unknown dimension and we want numpy to figure it out. And numpy will figure this by looking at the 'length of the array and remaining dimensions' and making sure it satisfies the above mentioned criteria (What does -1 mean in numpy reshape?). T means to invert the transposition of tensors when using the axes keyword argument (https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html).
X_flatten = X.reshape(X.shape[0], -1).T
Assuming you have an array image_array you can use the reshape() method.
image_array = image_array.reshape(1000, 12288)

Categories

Resources