[SOLVED] Stuck on homework 1 - expected lambda_input_2 to have shape (None, 3, 244, 244) but got array with shape (4, 3, 224, 224)


(Keith) #1

Exception: Error when checking : expected lambda_input_2 to have shape (None, 3, 244, 244) but got array with shape (4, 3, 224, 224)

This is the error I encountered on first run through. The array being passed in w/ shape (4, 3, 224, 224) matches that of the lesson example, so that seems right to me. The 4 is linked to the batch_size variable, so it’s the number of images being passed in. For some reason, it detects None images? Looking into it.

I then encountered this thread, with a similar problem but the methods discussed there don’t help me.

One person suggested setting argument dim_order="th" on the ImageDataGenerator, which did not work. The other suggestion, to sue data_format=":channels_first" didn’t work as it seems that is a Keras 2.0 feature (checking pip revealed Keras 1.1 for this course). I also tried this with the backend..set_image_dim_ordering('th') command and have checked the ~/.keras/keras.json file file to confirm it is running theano and the dim-ordering is set to ‘th’. I tried using the data_format argument as well, but since I’m running the instance provided by fast.ai I am running Keras 1.1 and thus don’t have that feature.

I have also worked through the redux notebook, looking at the solution and following along in the lesson 2 video. However, while that works for me, and lesson1 continues to work for me, I can not get the redux data I setup to work for me.

I’ve also tried swtiching the dogscatsredux path to be both dogscats and redux, using the lesson 1 and solution provided lesson 2 data - neither work with this code.

Here is the code with my beginner explanations tripped out.

%matplotlib inline

path = "data/dogscatsredux/"

#Other imports
from numpy.random import random, permutation
from scipy import misc, ndimage
from scipy.ndimage.interpolation import zoom

from __future__ import division,print_function

import os, json
from glob import glob
import numpy as np
np.set_printoptions(precision=4, linewidth=100)
from matplotlib import pyplot as plt

#Import the utils library from class (need it for plotting at the end)
import utils; reload(utils)
from utils import plots

#Keras imports

import keras
from keras import backend as K
from keras.utils.data_utils import get_file
from keras.models import Sequential, Model
from keras.layers.core import Flatten, Dense, Dropout, Lambda
from keras.layers import Input
from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras.optimizers import SGD, RMSprop
from keras.preprocessing import image

FILES_PATH = 'http://files.fast.ai/models/'; CLASS_FILE='imagenet_class_index.json'
# Keras' get_file() is a handy function that downloads files, and caches them for re-use later
fpath = get_file(CLASS_FILE, FILES_PATH+CLASS_FILE, cache_subdir='models')
with open(fpath) as f: class_dict = json.load(f)
# Convert dictionary with string indexes into an array
classes = [class_dict[str(i)][1] for i in range(len(class_dict))]

def ConvBlock(layers, model, filters):
    for i in range(layers):
        model.add(ZeroPadding2D((1,1)))
        model.add(Convolution2D(filters, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))

def FCBlock(model):
    model.add(Dense(4096, activation='relu'))
    model.add(Dropout(0.5))

vgg_mean = np.array([123.68, 116.779, 103.939]).reshape((3,1,1))

def vgg_preprocess(x):
    x = x - vgg_mean #subtract the mean
    return x[:, ::-1] # reverse

def VGG_16():
    model = Sequential()
    model.add(Lambda(vgg_preprocess, input_shape=(3,244,244)))
    
    ConvBlock(2, model, 64)
    ConvBlock(2, model, 128)
    ConvBlock(3, model, 256)
    ConvBlock(3, model, 512)
    ConvBlock(3, model, 512)
    
    model.add(Flatten())
    FCBlock(model)
    FCBlock(model)
    model.add(Dense(1000, activation='softmax'))
    
    return model

model = VGG_16()

fpath = get_file('vgg16.h5', FILES_PATH + 'vgg16.h5', cache_subdir='models')

model.load_weights(fpath)

batch_size = 4

def get_batches(dirname, gen=image.ImageDataGenerator(dim_ordering='th'), shuffle=True, 
                batch_size=batch_size, class_mode='categorical'):
    return gen.flow_from_directory(path+dirname, target_size=(224,224), 
                class_mode=class_mode, shuffle=shuffle, batch_size=batch_size)

batches = get_batches('train', batch_size=batch_size)
val_batches = get_batches('valid', batch_size=batch_size)
imgs, labels = next(batches)

#Shows the 'truth'
plots(imgs, titles=labels)

def pred_batch(imgs):
    preds = model.predict(imgs) # <~ Error is thrown here.
    idxs = np.argmax(preds, axis=1) #1 axis cause it's just array of category labels
    
    print('Shape: {}'.format(preds.shape)) #shape of the predictions
    print('First 5 classes: {}'.format(classes[:5])) #First 5 classes
    print('First 5 probabilities: {}'.format(preds[0, :5]))
    print('Predictions prob/class: ')
    
    for i in range(len(idxs)):
        idx = idxs[i]
        print ('  {:.4f}/{}'.format(preds[i, idx], classes[idx]))


pred_batch(imgs) # <~ This is where the error is triggered, on the first line of pred_batch on the .predict call

(WG) #2

What happens if you change your predict call to:

predict(imgs, batch_size=4)


(Keith) #3

Thanks for the speedy reply wgpubs!

I actually did try that last night after seeing it referred to in some documentation - the result is the same I’m afraid.

To be sure, I fired back up my ec2 instance and tested it again - no, setting batch_size=4 (or anything) does not have any effect on this problem.


(Matthew) #4

I don’t know if this will help, but I noticed you don’t have output_shape specified on line 2 of the VGG_16() function. Try changing it to

    model.add(Lambda(vgg_preprocess, input_shape=(3,244,244), output_shape=(3,244,244)))

(WG) #5

Are you using Jeremy’s VGG16 class or are you building your own?

If you are building your own there might be some inconsistency between your code and his.

Also, as another experiment, what happens when you try predicting a single example:

model.predict(imgs[0])


(Keith) #6

@superMDguy

Good thing to try - I didn’t include it because Jeremy’s example in the Lesson 1 notebook didn’t. Unfortunately setting it didn’t fix the problem and I got the same error message.

@wgpubs

I’m building my own by following along the lesson method of build VGG from scratch. I took this route for the homework with the intention of slowly dissecting via documentation how each piece was working, and created a decent enough notebook writing down how I thought each piece was working. Great educational exercise, but so far not so great in getting things to work :slight_smile:

If I run

model.predict(imgs[0]) with no other changes to the code, I get

Exception: Error when checking : expected lambda_input_1 to have 4 dimensions, but got array with shape (3, 224, 224)

So it’s definitely expecting the whole batch. It really comes down to that expecting a None as a dimension.


Alternatively, would it be easier if I posted the whole file here? Is there a way to share notebook files? It’d be difficult to run without the downloaded data which wouldn’t be easy to transport and guarantee same directory setup.

Thanks for the help so far, I’m just flabbergasted what I could have missed here…


(Keith) #7

I should add @wgpubs - I also went through, using the lesson 2 video as guidance, went through and built the VGG model the way Jeremy did using the prebuilt VGG model successfully.


(WG) #8

put your code on github and share the link to it.

Have you tried running Jeremy’s code and see what the shape of the input is when calling his model.predict() function? It might be helpful if the shape of your data matches his.


(Keith) #9

@wgpubs Yup! I modified his lesson 1 code to output the shape and to observe the imgs object prior to to the predict function - as far as I can tell it’s the same as my own (minus the pictures themselves being of different cats/dogs of course).

Here’s a github repository of the homework - the directory_structure text file shows the directory structure of my dogscatsredux folder - the cats/dogs folders have the appropriate 12.5k animal companion photos one would expect.


(WG) #10

I’m looking at your code and I don’t notice anything wrong at first glance. Obviously, its something with your first layer in the model, the Lambda layer; it doesn’t like what it is getting.

Can you do a “model.summary()” for both your model and Jeremy’s? Do you notice anything different between the two?


(WG) #11

Dude … stop everything! Look at your error.

“expected lambda_input_2 to have shape (None, 3, 244, 244) but got array with shape (4, 3, 224, 224)”

You got a typo in there …

model.add(Lambda(vgg_preprocess, input_shape=(3,244,244)))

should be

model.add(Lambda(vgg_preprocess, input_shape=(3,224,224)))


(Keith) #12

OK I’m not seeing the typo when I put these lines next to one another… what am I not seeing?


(WG) #13

244 vs 224


(Keith) #15

@wgpubs THAT WAS IT! Whoooo! What a hard to catch one.

THANK YOU for the help. Thanks for model.summary() too! That’s a great overview function


(WG) #16

Yup you’re welcome … and welcome to machine learning (this won’t be the last of overlooked typos if my experience proves anything :slight_smile: )

An yah I use model.summary() all over the place in my notebooks. Will typically comment out after I understand the model but I also keep the code there just in case I need to remind myself what the architecture looks like.


(Matt) #17

HAHA wow, I had the same error and after a few hours googling, this led me to it :smiley:


(Atul) #18

can someone plz help me…i have not made any change to jeremy’s code and getting below error

Error when checking model input: expected lambda_input_2 to have shape (None, 3, 224, 224) but got array with shape (64, 224, 224, 3)


(DinoLew) #19

@sigmoid2017 from you error information , i can see that the data shape you input is (64, 224, 224, 4) , but actually it should be (64, 2, 224, 224) , the axis is not identical, you could make a switch by np.swapaxi(a, imgs, 1, 3) ; but most import you should out why you switch the axis of input data


(Kevin Bird) #20

Are you using Tensorflow instead of Theano? That could explain why it expects the images to have (color axis, x, y) but your images are defaulting to (x,y,color axis). In your Keras.json file, you could change the image_data_format option to channels_first.

https://keras.io/backend/ This could help you. Go down to the keras.json details section.


(Atul) #21

Thanks