将权重加载到VGG16模型中时,如何解决“ TypeError:+不支持的操作数类型:'int'和'str'”

时间:2019-07-26 10:49:11

标签: keras vgg-net

我正在尝试从adrianalbert的GitHub页面(https://github.com/adrianalbert/urban-environments)重建预训练的VGG16模型。但是,该代码似乎是为Keras的旧版本编写的,从而导致很多错误。

当我第一次尝试运行代码时,卷积层出现以下错误:" C:\Users\miker\Anaconda3\lib\site-packages\ipykernel_launcher.py:9: UserWarning: Update your Conv2D call to the Keras 2 API: Conv2D(512, (3, 3), activation="relu", name="conv1_1") "

我根据此建议更改了卷积层的代码,现在出现错误:" TypeError: unsupported operand type(s) for +: 'int' and 'str' "

我知道这意味着代码正在尝试以不兼容的方式组合字符串和整数对象,但是该错误似乎是在Keras函数之一中发生的,我无法弄清楚是什么原因引起的。任何建议都将不胜感激,因为我是深度学习的新手,也不知道我在做什么!

这是代码,大部分代码直接取自adrianalbert:

# Some of the imported functions and modules are from other sections of the code.

    from keras.models import Sequential
    from keras.layers.core import Flatten, Dense, Dropout
    from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D
    from keras.engine import Layer
    from keras import backend as K
    from keras.optimizers import SGD
    from keras.models import Model
    from keras.layers import Flatten
    from keras.layers import Dense
    from keras.layers import Input
    from keras.layers import Conv2D
    from keras.layers import MaxPooling2D
    from keras.layers import GlobalMaxPooling2D
    from keras.layers import GlobalAveragePooling2D
    from keras.preprocessing import image
    from keras.utils import layer_utils
    from keras.utils.data_utils import get_file
    from keras import backend as K
    from keras.applications.imagenet_utils import decode_predictions
    from keras.applications.imagenet_utils import preprocess_input
    from keras_applications.imagenet_utils import _obtain_input_shape
    from keras.engine.topology import get_source_inputs
    import cv2, numpy as np

    import pandas as pd
    import h5py
    from skimage.io import imread
    from skimage.transform import resize, pyramid_reduce
    from collections import Counter


    def vgg16(n_classes=1000, input_shape=(224,224,3), fcn=False, add_top=True):
        model = Sequential()

        if fcn:
            model.add(ZeroPadding2D((1,1),input_shape=(None,None,input_shape[2])))
        else:
            model.add(ZeroPadding2D((1,1),input_shape=input_shape))

        model.add(Conv2D(512, (3, 3), activation="relu", name="conv1_1"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(64, (3, 3), activation="relu", name="conv1_2"))
        model.add(MaxPooling2D((2,2), strides=(2,2)))

        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(128, (3, 3), activation="relu", name="conv2_1"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(128, (3, 3), activation="relu", name="conv2_2"))
        model.add(MaxPooling2D((2,2), strides=(2,2)))

        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(256, (3, 3), activation="relu", name="conv3_1"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(256, (3, 3), activation="relu", name="conv3_2"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(256, (3, 3), activation="relu", name="conv3_3"))
        model.add(MaxPooling2D((2,2), strides=(2,2)))

        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(512, (3, 3), activation="relu", name="conv4_1"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(512, (3, 3), activation="relu", name="conv4_2"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(512, (3, 3), activation="relu", name="conv4_3"))
        model.add(MaxPooling2D((2,2), strides=(2,2)))

        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(512, (3, 3), activation="relu", name="conv5_1"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(512, (3, 3), activation="relu", name="conv5_2"))
        model.add(ZeroPadding2D((1,1)))
        model.add(Conv2D(512, (3, 3), activation='relu', name="conv5_3"))
        model.add(MaxPooling2D((2,2), strides=(2,2)))

        if add_top:
            if fcn:
                model.add(Convolution2D(4096,7,7,activation="relu",name="dense_1"))
                model.add(Convolution2D(4096,1,1,activation="relu",name="dense_2"))
                model.add(Convolution2D(n_classes,1,1,name="dense8"))
                model.add(Softmax4D(axis=1,name="softmax"))
            else:
                model.add(Flatten())
                model.add(Dense(4096, activation='relu', name="dense6"))
                model.add(Dropout(0.5))
                model.add(Dense(4096, activation='relu', name="dense7"))
                model.add(Dropout(0.5))
                model.add(Dense(n_classes, activation='softmax', name="dense8"))

        return model

    class Softmax4D(Layer):
        def __init__(self, axis=-1,**kwargs):
            self.axis=axis
            super(Softmax4D, self).__init__(**kwargs)

        def build(self,input_shape):
            pass

        def call(self, x,mask=None):
            e = K.exp(x - K.max(x, axis=self.axis, keepdims=True))
            s = K.sum(e, axis=self.axis, keepdims=True)
            return e / s


    def load_weights_into_model(model, weights_file, \
        layers_to_skip=None, transpose_conv=False):
        '''
        Loads pretrained weights from weights_file in to the structure defined by model. Has simple checks to ensure that weights from file are being loaded to the corresponding layers in the model.

        layers_to_skip is a list of either layer indices (ints) or names (strings).
        '''
        f = h5py.File(weights_file, "r")    
        if not layers_to_skip:
            layers_to_skip = []

        N_layers_file = f.attrs['nb_layers'] if 'nb_layers' in f.attrs.keys()\
                            else len(f.attrs['layer_names'])
        N_layers_model= len(model.layers)
        layers_to_load = [l.name for k,l in enumerate(model.layers) \
                                if len(l.get_weights())>0 and l.name not in layers_to_skip and k not in layers_to_skip]

        print("Loading %d layers from file into model..."%len(layers_to_load))

        l_file = 0
        for l_model in layers_to_load:
            # go to next layer in file that has weights to load
            while True:
                g = f['layer_{}'.format(l_file)]
                weights=[g['param_{}'.format(p)] \
                            for p in range(g.attrs['nb_params'])]
                l_file += 1
                if len(weights)>0:
                    break
            print(model.get_layer(l_model).name), 
            # transpose convolutional layers saved with a different backend   
            layer = model.get_layer(l_model)    
            k = [k for k,l in enumerate(model.layers) if l.name==l_model][0]
            if layer.__class__.__name__ in ['Conv2D', 'Convolution2D'] and transpose_conv:
                kernel, bias = weights
                if kernel.ndim > 2:
                    kernel = np.transpose(kernel, (2, 3, 1, 0))
                else:
                    print('reshaping ...')
                    kernel = np.reshape(kernel, layer.get_weights()[0].shape)
                    print(kernel.shape)
                model.layers[k].set_weights([kernel, bias])
            else:
                model.layers[k].set_weights(weights)
        print("done.")
        f.close()

        return model


    def load_and_preprocess(filename, new_shape=None, channels="RGB", 
        downsample=None, crop=None):
        '''
        Load image and do basic preprocessing.
            - resize image to a specified shape;
            - subtract ImageNet mean;
            - make sure output image data is 0...255 uint8.
        '''
        img = imread(filename) # RGB image
        if downsample is not None:
            img = pyramid_reduce(img)
        if img.max()<=1.0:
            img = img * 255.0 / img.max()
        if crop is not None:
            i = np.random.randint(crop/2, img.shape[0]-crop/2)
            j = np.random.randint(crop/2, img.shape[1]-crop/2)
            img = img[(i-crop/2):(i+crop/2),(j-crop/2):(j+crop/2)]
        if new_shape is not None:
            img = resize(img, new_shape, preserve_range=True)
        # imagenet_mean_bgr = np.array([103.939, 116.779, 123.68])
        imagenet_mean_rgb = np.array([123.68, 116.779, 103.939])
        for i in range(3):
            img[:,:,i] = img[:,:,i] - imagenet_mean_rgb[i]
        # for VGG networks pre-trained on ImageNet, channels are BGR 
        # (ports from Caffe)
        if channels=="BGR":
            img = img[:, :, [2,1,0]] # swap channel from RGB to BGR
        return img.astype(np.uint8)


    def balanced_df(df, nrows=None, k=1, class_column="class"):
        cnts = df[class_column].value_counts()
        min_cnt = cnts.min()
        ret = []
        for c in cnts.index:
            ret.append(df[df[class_column]==c].sample(min([cnts[c],k*min_cnt])))
        ret = pd.concat(ret)
        if nrows is not None:
            if len(ret) < nrows:
                weights = 1.0 / (df[class_column].value_counts() + 1)
                weights = {i:w for i,w in zip(weights.index, weights.values)}
                weights = df[class_column].apply(lambda x: weights[x])
                ret = pd.concat([ret, df.sample(nrows-len(ret), weights=weights)])
            else:
                ret = ret.sample(nrows)
        return ret


    def get_class_weights(y):
        counter = Counter(y)
        majority = max(counter.values())
        return  {cls: float(majority)/count for cls, count in counter.items()}


    def generator_from_df(df, image_generator=None, balance=None, \
                            class_column="class", filename_column="filename",
                            batch_size=32, seed=None, new_img_shape=None, \
                            class_dict=None, shuffle=True, channels="RGB",
                            downsample=None, crop=None):
        idx = 0
        if class_dict is None:
            myclasses = df[class_column].unique()
            myclasses.sort()
            class_dict = {c:i for i,c in enumerate(myclasses)}
        ok = True
        while ok:
            if shuffle:
                if balance is not None:
                    df_bal = balanced_df(df, k=balance, nrows=batch_size,
                        class_column=class_column)
                else:
                    df_bal = df
                df_batch = df_bal.sample(batch_size, random_state=seed)
            else:
                df_batch = df.iloc[idx:(idx+batch_size)]
                print("Reading ids %d -- %d"%(idx, idx+batch_size))
                if idx + batch_size >= len(df):
                    print("should stop now!")
                    ok = False
                idx += batch_size
            y = []
            X = []
            for i,r in df_batch.iterrows():
                img = load_and_preprocess(r[filename_column], 
                                          new_shape=new_img_shape, crop=crop,
                                          channels=channels, downsample=downsample)
                X.append(img)
                y.append(class_dict[r[class_column]])
            X = np.array(X)
            y = np.array(y)
            yoh = np.zeros((len(y), len(class_dict)))
            yoh[np.arange(len(y)), y] = 1
            if image_generator is not None:
                for X_batch, y_batch in image_generator.flow(X, yoh, batch_size=batch_size, shuffle=shuffle):
                    break
            else:
                X_batch, y_batch = X, yoh
            yield (X_batch, y_batch)


    def generator_from_file(filename, image_generator=None, balance=None, \
                            batch_size=32, seed=None, new_img_shape=None, \
                            class_dict=None, shuffle=True, channels="RGB",
                            downsample=False, crop=None):
        df = pd.read_csv(filename)
        return generator_from_df(df, 
                                 image_generator=image_generator, 
                                 balance=balance,
                                 batch_size=batch_size, 
                                 seed=seed, 
                                 crop=crop,
                                 new_img_shape=new_img_shape,
                                 class_dict=class_dict, 
                                 shuffle=shuffle,
                                 channels=channels)

当我运行以下行时会发生错误:

    model = vgg16('vgg16_weights.h5')

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-9-f62a37630a68> in <module>
    ----> 1 model = vgg16('vgg16_weights.h5')

    <ipython-input-8-59ef76627dbc> in vgg16(n_classes, input_shape, fcn, add_top)
         54             model.add(Dense(4096, activation='relu', name="dense7"))
         55             model.add(Dropout(0.5))
    ---> 56             model.add(Dense(n_classes, activation='softmax', name="dense8"))
         57 
         58     return model

    ~\Anaconda3\lib\site-packages\keras\engine\sequential.py in add(self, layer)
        179                 self.inputs = network.get_source_inputs(self.outputs[0])
        180         elif self.outputs:
    --> 181             output_tensor = layer(self.outputs[0])
        182             if isinstance(output_tensor, list):
        183                 raise TypeError('All layers in a Sequential model '

    ~\Anaconda3\lib\site-packages\keras\engine\base_layer.py in __call__(self, inputs, **kwargs)
        429                                          'You can build it manually via: '
        430                                          '`layer.build(batch_input_shape)`')
    --> 431                 self.build(unpack_singleton(input_shapes))
        432                 self.built = True
        433 

    ~\Anaconda3\lib\site-packages\keras\layers\core.py in build(self, input_shape)
        864                                       name='kernel',
        865                                       regularizer=self.kernel_regularizer,
    --> 866                                       constraint=self.kernel_constraint)
        867         if self.use_bias:
        868             self.bias = self.add_weight(shape=(self.units,),

    ~\Anaconda3\lib\site-packages\keras\legacy\interfaces.py in wrapper(*args, **kwargs)
         89                 warnings.warn('Update your `' + object_name + '` call to the ' +
         90                               'Keras 2 API: ' + signature, stacklevel=2)
    ---> 91             return func(*args, **kwargs)
         92         wrapper._original_function = func
         93         return wrapper

    ~\Anaconda3\lib\site-packages\keras\engine\base_layer.py in add_weight(self, name, shape, dtype, initializer, regularizer, trainable, constraint)
        247         if dtype is None:
        248             dtype = K.floatx()
    --> 249         weight = K.variable(initializer(shape),
        250                             dtype=dtype,
        251                             name=name,

    ~\Anaconda3\lib\site-packages\keras\initializers.py in __call__(self, shape, dtype)
        207             scale /= max(1., fan_out)
        208         else:
    --> 209             scale /= max(1., float(fan_in + fan_out) / 2)
        210         if self.distribution == 'normal':
        211             # 0.879... = scipy.stats.truncnorm.std(a=-2, b=2, loc=0., scale=1.)

    TypeError: unsupported operand type(s) for +: 'int' and 'str'

1 个答案:

答案 0 :(得分:0)

这是您的电话:

model = vgg16('vgg16_weights.h5')

这是vgg16函数的定义:

def vgg16(n_classes=1000, input_shape=(224,224,3), fcn=False, add_top=True):

因此,您要传递字符串('vgg16_weights.h5'作为vgg16函数的第一个参数,而该第一个参数实际上是类的数目。这就是为什么会出错的原因,因为类的数目是一个字符串。