Ожидается увидеть 3 массива (ов), но вместо этого получит следующий список из 1 массива: - PullRequest
0 голосов
/ 07 февраля 2020

Я пытаюсь обучить модели тройной потери, используя fit_generator. требуется три входа и нет выхода. так что у меня есть функция, которая генерирует жесткие триплеты. выходной сигнал генератора триплетов имеет форму (3,5 279), которая представляет собой 3 входа (якорный, положительный и отрицательный) для 5 пакетов и всего 279 функций. Когда я запускаю fit_generator, он выдает эту ошибку, что " список Numpy массивов, которые вы передаете вашей модели, не соответствует размеру, который ожидала модель. Ожидается увидеть 3 массива (ов), но вместо этого получит следующее list of 1 arrays"Тем временем я передал список из трех массивов. код ниже. это работает, когда я использую подгонку, однако, я хочу всегда вызывать функцию генератора, чтобы генерировать мои триплеты как мои пакеты. спасибо заранее .. это заняло у меня три дня

def load_data():
    path = "arrhythmia_data.txt"
    f = open( path, "r")
    data = []

    #remove line breaker, comma separate and store in array
    for line in f:
        line = line.replace('\n','').replace('?','0')
        line = line.split(",")

        data.append(line)
    f.close()

    data = np.array(data).astype(np.float64)
    #print(data.shape)


    #create the class labels for input data
    Y_train = data[:,-1:]
    train = data[:,:-1]
    normaliser = preprocessing.MinMaxScaler()
    train = normaliser.fit_transform(train)

    val = train[320:,:]
    train = train[:320,:]

    #create one hot encoding of the class labels of the data and separate them into train and test data

    lb = LabelBinarizer()
    encode = lb.fit_transform(Y_train)
    nb_classes = int(len(encode[0]))

    #one_hot_labels = keras.utils.to_categorical(labels, num_classes=10) this could also be used for one hot encoding
    Y_val_e = encode[320:,:]
    Y_train_e = encode[:320,:]
    print(Y_train_e[0])
    print(np.argmax(Y_train_e[0]))


    val_in = []
    train_in = []

    #grouping and sorting the input data based on label id or name
    for n in range(nb_classes):
        images_class_n = np.asarray([row for idx,row in enumerate(train) if np.argmax(Y_train_e[idx])==n])
        train_in.append(images_class_n)


        images_class_n = np.asarray([row for idx,row in enumerate(val) if np.argmax(Y_val_e[idx])==n])
        val_in.append(images_class_n)
    #print(train_in[0].shape)


    return train_in,val_in,Y_train_e,Y_val_e,nb_classes

train_in,val,Y_train,Y_val,nb_classes = load_data()
input_shape = (train_in[0].shape[1],)


    def build_network(input_shape , embeddingsize):
    '''
    Define the neural network to learn image similarity
    Input : 
            input_shape : shape of input images
            embeddingsize : vectorsize used to encode our picture   
    '''


    #in_ = Input(train.shape)
    net = Sequential()
    net.add(Dense(128,  activation='relu', input_shape=input_shape))
    net.add(Dense(128, activation='relu'))
    net.add(Dense(256, activation='relu'))
    net.add(Dense(4096, activation='sigmoid'))
    net.add(Dense(embeddingsize, activation= None))
     #Force the encoding to live on the d-dimentional hypershpere
    net.add(Lambda(lambda x: K.l2_normalize(x,axis=-1)))


    return net


class TripletLossLayer(Layer):
    def __init__(self, alpha, **kwargs):
        self.alpha = alpha
        super(TripletLossLayer, self).__init__(**kwargs)

    def triplet_loss(self, inputs):
        anchor, positive, negative = inputs
        p_dist = K.sum(K.square(anchor-positive), axis=-1)
        n_dist = K.sum(K.square(anchor-negative), axis=-1)
        return K.sum(K.maximum(p_dist - n_dist + self.alpha, 0), axis=0)

    def call(self, inputs):
        loss = self.triplet_loss(inputs)
        self.add_loss(loss)
        return loss

def build_model(input_shape, network, margin=0.2):
    '''
    Define the Keras Model for training 
        Input : 
            input_shape : shape of input images
            network : Neural network to train outputing embeddings
            margin : minimal distance between Anchor-Positive and Anchor-Negative for the lossfunction (alpha)

    '''
     # Define the tensors for the three input images
    anchor_input = Input(input_shape, name="anchor_input")
    positive_input = Input(input_shape, name="positive_input")
    negative_input = Input(input_shape, name="negative_input") 

    # Generate the encodings (feature vectors) for the three images
    encoded_a = network(anchor_input)
    encoded_p = network(positive_input)
    encoded_n = network(negative_input)

    #TripletLoss Layer
    loss_layer = TripletLossLayer(alpha=margin,name='triplet_loss_layer')([encoded_a,encoded_p,encoded_n])

    # Connect the inputs with the outputs
    network_train = Model(inputs=[anchor_input,positive_input,negative_input],outputs=loss_layer)

    # return the model
    return network_train

def get_batch_random(batch_size,s="train"):

    # initialize result
    triplets=[np.zeros((batch_size,m)) for i in range(3)]

    for i in range(batch_size):
        #Pick one random class for anchor
        anchor_class = np.random.randint(0, nb_classes)
        nb_sample_available_for_class_AP = X[anchor_class].shape[0]

        #Pick two different random pics for this class => A and P. You can use same anchor as P if there is one one element for anchor
        if nb_sample_available_for_class_AP<=1:
            continue
        [idx_A,idx_P] = np.random.choice(nb_sample_available_for_class_AP,size=2 ,replace=False)

        #Pick another class for N, different from anchor_class
        negative_class = (anchor_class + np.random.randint(1,nb_classes)) % nb_classes
        nb_sample_available_for_class_N = X[negative_class].shape[0]

        #Pick a random pic for this negative class => N
        idx_N = np.random.randint(0, nb_sample_available_for_class_N)

        triplets[0][i,:] = X[anchor_class][idx_A,:]
        triplets[1][i,:] = X[anchor_class][idx_P,:]
        triplets[2][i,:] = X[negative_class][idx_N,:]

    return np.array(triplets)

def get_batch_hard(draw_batch_size,hard_batchs_size,norm_batchs_size,network,s="train"):

    if s == 'train':
        X = train_in
    else:
        X = val

    #m, features = X[0].shape

    #while True:
    #Step 1 : pick a random batch to study
    studybatch = get_batch_random(draw_batch_size,X)

        #Step 2 : compute the loss with current network : d(A,P)-d(A,N). The alpha parameter here is omited here since we want only to order them
    studybatchloss = np.zeros((draw_batch_size))

        #Compute embeddings for anchors, positive and negatives
    A = network.predict(studybatch[0])
    P = network.predict(studybatch[1])
    N = network.predict(studybatch[2])

        #Compute d(A,P)-d(A,N)
    studybatchloss = np.sum(np.square(A-P),axis=1) - np.sum(np.square(A-N),axis=1)

        #Sort by distance (high distance first) and take the 
    selection = np.argsort(studybatchloss)[::-1][:hard_batchs_size]

        #Draw other random samples from the batch
    selection2 = np.random.choice(np.delete(np.arange(draw_batch_size),selection),norm_batchs_size,replace=False)

    selection = np.append(selection,selection2)

    triplets = [studybatch[0][selection,:], studybatch[1][selection,:],studybatch[2][selection,:]]
    triplets = triplets.reshape(triplets.shape[0],triplets.shape[1],triplets.shape[2])    
    yield triplets

network = build_network(input_shape,embeddingsize=10)
hard = get_batch_hard(5,4,1,network,s="train")   
network_train = build_model(input_shape,network)
optimizer = Adam(lr = 0.00006)
network_train.compile(loss=None,optimizer=optimizer)
#this works
#history = network_train.fit(hard,epochs=100,steps_per_epoch=1, verbose=2)

history = network_train.fit_generator(hard,epochs=10,steps_per_epoch=16, verbose=2)
# error:: the list of Numpy arrays that you are passing to your model is not the size the model 
expected. Expected to see 3 array(s), but instead got the following list of 1 arrays:

1 Ответ

0 голосов
/ 07 февраля 2020

Я думаю, это потому, что в вашем генераторе вы получаете массив из 3 входов в одном списке, вам нужно вывести 3 массива независимо:

triplet_1 = studybatch[0][selection,:]
triplet_2 = studybatch[1][selection,:]
triplet_3 = studybatch[2][selection,:]

yield [triplet_1, triplet_2, triplet_3]
...