Python and keras questions and tips


(Jeremy Howard (Admin)) #21

It’s imported by utils.py. So you’ll need to have imported that.

See the keras docs for details. In short, fit_generator takes a generator (e.g from get_batches()) as input, whereas fit() takes an array. fit_generator is used for data augmentation.

Yes - try searching for ‘get_batches’ in utils.py to see this.

Because validation doesn’t require back propagation, so can generally handle larger batch sizes in the same memory.


(qwerty qwert) #22

I’m trying to understand the Vgg16 model from lesson 1. In order to do so I edited the given code a little.

The original script plots the cats and dogs images with the class labels by using ‘plots’ from ‘utils’.

I tried to port that code snipped to matplotlib, but the image looks solarized. For example if I got two images loaded in a numpy array it has dimensions (2, 3, 300, 300).

Now, if I want to output an image with ‘matplotlib’ using ‘imshow’ I have to reshape the array first or else I get an error that the dimensions are wrong.

plt.imshow(np.rollaxis(imgs[0], 0, 3))
plt.show()

The problem with the code above is that the image looks solarized. How can I fix this?


(Rachel Thomas) #23

@qwerty We have converted from RGB to BGR (see the vgg_preprocess function inside vgg.py), because the pretrained weights we are using are from a network that had BGR as the input format.

The plot method defined in utils.py switches it back to RGB.


#24

My favourite Python library for plotting is Plotly.

Allows you create great interactive plots in various formats, extremely quickly and easily. They do offer cloud options for easier sharing, I find the iPython notebook intergration brilliant.


(Samuel Ekpe) #25

ims=np.asarray(…)
if (ims.shape[-1] != 3):
ims = ims.transpose((0,2,3,1))


(garima.agarwal) #26

Hi Everyone,

Did anyone run into this error with initializations

ImportError: cannot import name 'initializations'

 ---> 21 from keras import initializations
     22 from keras.applications.resnet50 import ResNet50, decode_predictions, conv_block, identity_block
     23 from keras.applications.vgg16 import VGG16

I can’t find initializations in keras documentation either. I see initializers but not initializations.


#27

Is it possible to copy models or layers in Keras. For example in lesson 3 instead of defining a completely new model with the batchnorm layers included it would be nice if we could just do:

 bn = []
for layer in model.layers:
if type(layer) is Dropout:
    bn.append(Dropout(.5))
    bn.append(BatchNormalization())
else:
    bn.append(layer)
model = Sequential(bn)

If I do this then the model.summary() has extra connected_to layers. For example:

convolution2d_209 (Convolution2D (None, 64, 224, 224)  1792        zeropadding2d_209[0][0]          
                                                                   zeropadding2d_209[1][0]  

I can fit the model like this but what are practical implications? Is it fitting what I want or adding in extra nodes?


(Jeremy Howard (Admin)) #28

You can use copy_layer, copy_layers, copy_weights, and copy_model from utils.py. See the source to see how they work.


(garima.agarwal) #29

Jeremy,

Does np_utils.to_categorical have the same result as OneHot Encoding?

I implemented DenseNet for a small data set that I have. In the reference implementation they used np_utils.to_categorical on CIFAR10 dataset to convert the labels to binary. I felt that with our OneHot encoding mechanism we achieved the same thing but would like to get expert opinion.

Its hard to tell since both return a 2 dimensional array with 1s and 0s.

Thanks
Garima


(Jeremy Howard (Admin)) #30

I believe so - check the source to be sure though.


(garima.agarwal) #31

The code is different but the intent seems to be the same in to_categorical:

y = np.array(y, dtype=‘int’).ravel()
if not num_classes:
num_classes = np.max(y) + 1
n = y.shape[0]
categorical = np.zeros((n, num_classes))
categorical[np.arange(n), y] = 1
return categorical

One more question for you.

I wasn’t geting very good results on my DenseNet so I printed out my data. I am very suprised to see what get_data is doing.

My notebook code is as simple as :

val_data = get_data(path+'valid')
plt.imshow(val_data[0])

And here is the get_data code

def get_batches_portrait(dirname, gen=image.ImageDataGenerator(), shuffle=False, batch_size=4, class_mode='categorical'):
    return gen.flow_from_directory(dirname, target_size=(540,270),
            class_mode=class_mode, shuffle=shuffle, batch_size=batch_size)

def get_data(path):
    batches = get_batches_portrait(path, shuffle=False, batch_size=4, class_mode=None)
    return np.concatenate([batches.next() for i in range(batches.nb_sample)])

For some reason its taken my image and put some filter on it.

Any ideas what I might be missing?


(Jeremy Howard (Admin)) #32

Can you show the original image, to compare?


(garima.agarwal) #33


(David Gutman) #34

I would look at the maximum and minimum values of both images.

Images should generally be in [0,1] if float or [0,256) if int. And make sure no nans.

You also may have switched RGB order to BGR if you were using VGG, so if you did that make sure you also undo it when viewing the images. (img[…,::-1])


(garima.agarwal) #35

Thanks David!
Its weird.

I created a separate folder and ran this code

def get_data(path):
    gen = image.ImageDataGenerator()
    batches = gen.flow_from_directory(path, target_size=(540,270),
            class_mode=None, shuffle=False, batch_size=2 )
    result  = np.concatenate([batches.next() for i in range(batches.nb_sample)])
    print(result.shape)
    return result

val_data = get_data(path+'imgflip')

plt.imshow(val_data[0]) Shows the negative but

plt.imshow(val_data[0]*255) shows the correct image. Even though if I printed val_data[0] itself it shows values above 1

array([[[ 133., 131., 134.],
[ 127., 126., 131.],
[ 123., 124., 129.],
[ 113., 117., 126.],
[ 108., 115., 125.],
[ 99., 107., 118.],
[ 91., 101., 111.],
[ 88., 101., 110.],
[ 82., 95., 104.],
[ 76., 89., 98.],
[ 68., 78., 87.],
[ 60., 69., 74.],

I am going to train my model again on this muiltiplied number because I am not sure if the negative values will impact the model.

Let me know if you have any thoughts


(Jeremy Howard (Admin)) #36

You need to use

plt.imshow(val_data[0].astype('uint8')

It’s just a plotting issue - unrelated to modeling.


(garima.agarwal) #37

:disappointed: Thats embarrassing.

thank you


#38

This is exactly what happens in the dogscats-ensemble notebook when the function split_at is called

conv_layers,fc_layers = split_at(model, Convolution2D)
In [9]:

conv_model = Sequential(conv_layers)
conv_model.summary()
____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
lambda_1 (Lambda)                (None, 3, 224, 224)   0           lambda_input_1[0][0]             
____________________________________________________________________________________________________
zeropadding2d_1 (ZeroPadding2D)  (None, 3, 226, 226)   0           lambda_1[0][0]                   
                                                                   lambda_1[0][0]                   
____________________________________________________________________________________________________
convolution2d_1 (Convolution2D)  (None, 64, 224, 224)  1792        zeropadding2d_1[0][0]            
                                                                   zeropadding2d_1[1][0]            
__________

(Jeremy Howard (Admin)) #39

Yeah I noticed that too. It doesn’t seem to have any practical impact AFAICT.


#40

I feel a little uncomfortable with these “connected to” layers especially if you run the same cells over and over again in your notebook it adds a new “connected to” each time. It may have unexpected side effects right now or in a future keras version. Therefore much better to use the copy_layer functions.

Two related issues I have come across:

  • In the lessons we append a sequential model to another. But then when you list the layers the sequential layer appears as one layer so you cannot directly see what is in it. I think better to use copy_layers again so you can view the resulting model.
  • If you save models and then read them back in; and then combine with layers from other models then sometimes you end up with layer name clashes. So you need functions to combine models that also forces unique layer names before compiling it.