Numpy array of images wrong dimension Python and Keras - python

I'm building an image classifier and trying to compute the features for a dataset using keras but my array dimension is not on the right format. I'm getting
ValueError: Error when checking : expected input_1 to have 4 dimensions, but got array with shape (324398, 1)
My code is this:
import glob
from keras.applications.resnet50 import ResNet50
def extract_resnet(X):
# X : images numpy array
resnet_model = ResNet50(input_shape=(image_h, image_w, 3),
weights='imagenet', include_top=False) # Since top layer is the fc layer used for predictions
features_array = resnet_model.predict(X)
return features_array
filelist = glob.glob('dataset/*.jpg')
myarray = np.array([np.array(Image.open(fname)) for fname in filelist])
print(extract_resnet(myarray))
So it looks like for some reason the images array is only two dimensional when it should be 4 dimensional. How can I convert myarray so that it is able to work with the feature extractor?

First up, make sure that all of the images in dataset directory have the same size (image_h, image_w, 3):
print([np.array(Image.open(fname)).shape for fname in filelist])
If they are not, you won't be able to make a mini-batch, so you'll need to select only the subset of suitable images. If the size is right, you can then reshape the array manually:
myarray = myarray.reshape([-1, image_h, image_w, 3])
... to match ResNet specification exactly.

Related

CNN with vector output and 2D image graph input (input is an array)

I am trying to create a CNN in Keras (Python 3.7) which ingests a 2D matrix input (much like a grayscale image) and outputs a 1 dimensional vector. So far I did manage to get results, but I am not sure if what I am doing is correct (or if my intuition is).
I input a 100x50 array into my convolutional layer. This 2D array holds the peak information at every position (ie. x axis pertains to the position, y-axis pertains to the frequency, and each cell gives the intensity). The 3D graph of this shows something akin to the one given in this link.
From the (all of the) literature I have read, I learned that CNN accepts image data--image is converted into pixel values and then repeatedly convolved and pooled to get the output. However, I am using a MatLab simulator to get my input data, and I have access to the raw 2D array containing information on the peak frequency at each point.
My intuition is this: if we normalize each cell and feed the information to the CNN, it will be as if I fed the normalized pixel values of the image to the CNN, since my raw 2D array also has height, width and depth=1, like an image.
Please enlighten me if my thinking is correct or wrong.
My code is as follows:
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
import matplotlib.pyplot as plt
%matplotlib inline
import tensorflow as tf
import keras
'''load sample input'''
BGS1 = pd.read_csv("C:/Users/strain1_input.csv")
BGS2 = pd.read_csv("C:/Users/strain2_input.csv")
BGS3 = pd.read_csv("C:/Users/strain3_input.csv")
BGS_ = np.array([BGS1, BGS2, BGS3]) #3x100x50 array
BGS_normalized = BGS_/np.amax(BGS_)
'''load sample output'''
BFS1 = pd.read_csv("C:/Users/strain1_output.csv")
BFS2 = pd.read_csv("C:/Users/strain2_output.csv")
BFS3 = pd.read_csv("C:/Users/strain3_output.csv")
BFS_ = np.array([BFS1, BFS2, BFS3]) #3x100
BFS_normalized = BFS/50 #since max value for each cell is 50
#after splitting data into training, validation and testing sets,
output_nodes = 100
n_classes = 1
batch_size_ = 8 #so far, optimized for 8 batch size
epoch = 100
input_layer = Input(shape=(45,300,1))
conv1 = Conv2D(16,3,padding="same",activation="relu", input_shape =
(45,300,1))(input_layer)
pool1 = MaxPooling2D(pool_size=(2,2),padding="same")(conv1)
flat = Flatten()(pool1)
hidden1 = Dense(10, activation='softmax')(flat) #relu
batchnorm1 = BatchNormalization()(hidden1)
output_layer = Dense(output_nodes*n_classes, activation="softmax")(batchnorm1)
output_layer2 = Dense(output_nodes*n_classes, activation="relu")(output_layer)
output_reshape = Reshape((output_nodes, n_classes))(output_layer2)
model = Model(inputs=input_layer, outputs=output_reshape)
print(model.summary())
model.compile(loss='mean_squared_error', optimizer='adam', sample_weight_mode='temporal')
model.fit(train_X,train_label,batch_size=batch_size_,epochs=epoch)
predictions = model.predict(train_X)
what you did is exactly the strategy used to input non image data in to 2d convolutional layers. As long the model predicts correctly, what you did is correct. its just that CNN perform very poorly on non-image data or there might be chances to overfit. But then again, as long it performs correctly then its good.

How to input the sequence of the images in to LSTM network for video classification

I am using LSTM to classify video. I am using Keras python library to create Long Term Short Memory LSTM network. I understand that LSTM takes the input shape of the data in (sample, timestamp, Features). I have three class of video and each of these class has 10 video files. This means that I have 10*3=30 samples.
I have created a sequence of the frame for each of these video files. Each of these sequences consists of 32frames of video files. I use the trained model to extract features, so I feed each of these frames into VGG16 pre-trained model it that generates 512 features for a single frame. so one video files should have an array of (32,512) dimensions. I then append in each of these arrays into a single array for all the 30 samples and save it as numpy array. the final dimension of the array is (960,512).
Now my problem is how should I reshape this array into(sample,timestamp,features) =(20,32,512). This is the snippet of code I used: Please note that x_generator has 640,512 and I wish to convert it as (30,32,512).
I would appreciate solving my problem.
x_generator=None
if x_generator is None:
imgx = image.img_to_array(img)
imgx = np.expand_dims(imgx, axis=0)
imgx = preprocess_input(imgx)
x_generator = base_model.predict(imgx)
else
imgx = image.img_to_array(img)
imgx = np.expand_dims(imgx, axis=0)
imgx = preprocess_input(imgx)
x_generator = np.append(x_generator,base_model.predict(imgx),axis=0)
If you got the 960 values by appending the 30 samples of dimension (32, 512), you can just use np.reshape to reshape the array with the expected dimensions.
x_generator = np.reshape(x_generator, [30, 32, 512])

How to apply a previously unseen image to a previously saved model?

I wanted to know how to apply a previously unseen image to a previously saved CNN model and see how it classifies it ?
Code (My attempt)
from keras.models import load_model
from keras.preprocessing import image
import numpy as np
img_path = '/Users/eoind/code/1.jpg'
model = load_model('food.h5')
model.summary()
img = image.load_img(img_path, target_size=(100,100))
image = image.img_to_array(img)
image = np.expand_dims(image, axis=0)
print(image.shape)
images = np.vstack([image])
print("classifying images..")
image_class = model.predict_classes(images)
print(image_class)
iPython Console Error
ValueError: Error when checking : expected dense_1_input to have 2 dimensions, but got array with shape (1, 100, 100, 3)
The error says that the input shape of your network does not match the shape of your image. It seems like the first layer of your network is a dense layer, which is a fully-connected layer and it expects the input to be of shape (batch_size, num_of_neurons_in_the_bottom), but your are giving it an image with shape (batch_size, height, width, channels). Here is a checklist for troubleshooting your problem:
Has the model at least loaded? If the above error happens during loading, then your model is broken (perhaps not properly saved). If not, continue through the checklist...
In programming, always output the values of your variables for debugging! What is the value of model.summary()? Are you sure that the input shape of your network is (100, 100, 3)? Is the first layer a convolutional one?
If the first layer is dense (which is fully-connected), check the training code on how you feed images to the model - maybe your image should be re-shaped or somehow pre-processed?

Dimensional error while predicting

I have trained a convolutional3d model using code
Im trying to get the prediction as follows,
import cv2
from keras.models import Sequential, load_model
import numpy as np
#create an empty frame
frames = []
#defince row, col
img_rows,img_cols,img_depth=16,16,15
cap = cv2.VideoCapture('run.avi')
fps = cap.get(5)
#Use only first 15 frames for prediction
for k in range(15):
ret, frame = cap.read()
frame=cv2.resize(frame,(img_rows,img_cols),interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frames.append(gray)
#preprocess
input = np.array(frames)
ipt=np.rollaxis(np.rollaxis(input,2,0),2,0)
reshape_frames = np.expand_dims(ipt, axis=0)
#run prediction
model = load_model('current.h5')
preds = model.predict(reshape_frames)
print(preds)
but it fires the following error,
ValueError: Error when checking : expected conv3d_1_input to have 5
dimensions, but got array with shape (1, 16, 16, 15)
How can I be able to sort this out?
See in the docs for convolutional 3D layers:
Input shape
5D tensor with shape: (samples, channels, conv_dim1, conv_dim2, conv_dim3) if data_format='channels_first' or 5D tensor with shape: (samples, conv_dim1, conv_dim2, conv_dim3, channels) if data_format='channels_last'.
So what is bascially happening is that the input shape you provide to your first conv 3D layer does not fit to the expected input.
To solve this you could go as follows:
change the provided input, so that it matches the expected input (also take into account the data_format as noted above). As it looks in your code, you don't use the img_depth information at all. You basically provide a 2D image to a 3D conv net.
Use a 2D convnet and create a new model

Convert Tensorflow array to Keras array

I am trying to run a Keras model in which I read 88 images from a folder into a numpy array. This array should be converted into a Keras tensor so that I can work with the data in the model. I am running the following code:
import os
import numpy as np
from PIL import Image
from keras import backend as K
current_dir = os.path.dirname('__file__')
image_names = os.listdir(os.path.join(current_dir, 'images'))
images = np.ndarray((len(image_names), 256, 256), dtype=np.uint8)
for i, filename in enumerate(image_names):
images[i] = Image.open(os.path.join(current_dir,
'images',
filename)).resize((256, 256)).convert('L')
images = images.astype(K.floatx())
images *= 0.96/255
images += 0.02
images = images.reshape(images.shape[0], 256, 256, 1)
print(images.shape)
cats_q = K.variable(images)
print(type(cats_q))
print(K.is_keras_tensor(cats_q))
I am getting the following output
(87, 256, 256, 1)
<class 'tensorflow.python.ops.variables.Variable'>
False
How can I convert the output into a Keras tensor? Any help would be much appreciated!
Many thanks,
Andi
You should build your model first, including an input tensor built with the correct size to handle this data, then pass the numpy array to the keras model when you call the 'fit' function.
When you build a keras model, the tensors are edges in the computation graph. You don't want to initialize it with a value, but with a size, then pass the value when necessary.
This page on the keras functional API has some good examples of this.

Categories