Elliott Konink
Elliott Konink

Reputation: 63

Keras - ValueError: Could not interpret loss function identifier

I am trying to build the autoencoder structure detailed in this IEEE article. The autoencoder uses a separable loss function where it is required that I create a custom loss function for the "cluster loss" term of the separable loss function as a function of the average output of the encoder. I create my own layer called RffConnected that calculates the cluster loss and utilizes the add_loss method. Otherwise, this RffConnected layer should act as just a normal deep layer.

Here are my relevant code snippets:

import matplotlib.pyplot as plot
from mpl_toolkits.axes_grid1 import ImageGrid
import numpy as np
import math
from matplotlib.figure import Figure
import tensorflow as tf
import keras
from keras import layers
import random
import time
from os import listdir

#loads data from a text file
def loadData(basePath, samplesPerFile, sampleRate):
    real = []
    imag = []
    fileOrder = []
    
    for file in listdir(basePath):
        if((file != "READ_ME") and ((file != "READ_ME.txt"))):
            fid = open(basePath + "\\" + file, "r")
            fileOrder.append(file)

            t = 0
            sampleEvery = samplesPerFile / sampleRate
            temp1 = []
            temp2 = []
            times = []
            
            for line in fid.readlines():
                times.append(t)
                samples = line.split("\t")
                temp1.append(float(samples[0]))
                temp2.append(float(samples[1]))
                t = t + sampleEvery
                
            real.append(temp1)
            imag.append(temp2)
            fid.close()

    real = np.array(real)
    imag = np.array(imag)

    return real, imag, times, fileOrder

#####################################################################################################

#Breaks up and randomizes data
def breakUpData(real, imag, times, numPartitions, basePath):
    if(len(real) % numPartitions != 0):
        raise ValueError("Error: The length of the dataset must be divisible by the number of partitions.")

    newReal = []
    newImag = []
    newTimes = []
    fileOrder = listdir(basePath)
    dataFiles = []
    interval = int(len(real[0]) / numPartitions)

    for i in range(0, interval):
        newTimes.append(times[i])

    for i in range(0, len(real)):
        tempI = []
        tempQ = []
        
        for j in range(0, len(real[0])):
            tempI.append(real[i, j])
            tempQ.append(imag[i, j])
            
            if((j + 1) % interval == 0):
                newReal.append(tempI)
                newImag.append(tempQ)
                #fileName = fileOrder[i][0: fileOrder[i].find("_") + 3]
                dataFiles.append(fileOrder[i])
                tempI = []
                tempQ = []

    #randomizes the broken up dataset and the file list
    for i in range(0, len(newReal)):
        r = random.randint(0, len(newReal) - 1)
        tempReal = newReal[i]
        tempImag = newImag[i]
        newReal[i] = newReal[r]
        newImag[i] = newImag[r]
        newReal[r] = tempReal
        newImag[r] = tempImag

        tempFile = dataFiles[i]
        dataFiles[i] = dataFiles[r]
        dataFiles[r] = tempFile

    #return np.array(newReal), np.array(newImag), newTimes, dataFiles
    return newReal, newImag, newTimes, dataFiles

#####################################################################################################
#custom loss layer for the RffAe-S that calculates the clustering loss term
class RffConnected(layers.Layer):
    def __init__(self, output_dim, batchSize, beta, alpha):
        super(RffConnected, self).__init__()
        # self.total = tf.Variable(initial_value=tf.zeros((input_dim,)), trainable=False)
        #array = np.zeros(output_dim)
        self.iters = 0.0
        self.beta = beta
        self.alpha = alpha
        self.batchSize = batchSize
        self.output_dim = output_dim
        self.sum = tf.zeros(output_dim, tf.float64)
        self.moving_average = tf.zeros(output_dim, tf.float64)
        self.clusterloss = tf.zeros(output_dim, tf.float64)
        self.sum = tf.cast(self.sum, tf.float32)
        self.moving_average = tf.cast(self.moving_average, tf.float32)
        self.clusterloss = tf.cast(self.clusterloss, tf.float32)
        # self.sum = keras.Input(shape=(self.output_dim,))
        # self.moving_average = keras.Input(shape=(self.output_dim,))
        # self.clusterloss = keras.Input(shape=(self.output_dim,))
        
    def build(self, input_shape):
        self.kernel = self.add_weight(name = 'kernel', \
                shape = (int(input_shape[-1]), self.output_dim), \
                initializer = 'normal', trainable = True)
        #self.kernel = tf.cast(self.kernel, tf.float64)
        super(RffConnected, self).build(int(input_shape[-1]))
        
    def call(self, inputs):        
        #keeps track of training epochs
        self.iters = self.iters + 1
        #inputs = tf.cast(inputs, tf.float64)
        
        #where this custom layer acts as a normal layer- the loss then uses this
        #calc = keras.backend.dot(inputs, self.kernel)
        calc = tf.matmul(inputs, self.kernel)
        
        #cumulative sum of deep encoded features
        #self.sum = state_ops.assign(self.sum, tf.reshape(tf.math.add(self.sum, calc), tf.shape(self.sum)))
        #self.sum = tf.ops.state_ops.assign(self.sum, tf.math.add(self.sum, calc))
        #self.sum.assign_add(calc)
        self.sum = tf.math.add(self.sum, calc)
        
        #calculate the moving average and loss if we have already trained one batch
        if(self.iters >= self.batchSize):
            self.moving_average = tf.math.divide(self.sum, self.iters)
            self.clusterloss = tf.math.exp(\
                tf.math.multiply(-1 * self.beta, tf.math.reduce_sum(tf.math.square(tf.math.subtract(inputs, self.moving_average)))))
        
        #self.add_loss(tf.math.multiply(self.clusterloss, self.alpha))
        self.add_loss(self.clusterloss.numpy() * self.alpha)
        
        return calc
    


#####################################################################################################

def customloss(y_true, y_pred):
    loss = tf.square(y_true - y_pred)
    print(loss)
    return loss

#####################################################################################################

realTraining = np.array(real[0:2200])
realTesting = np.array(real[2200:-1])
imagTraining = np.array(imag[0:2200])
imagTesting = np.array(imag[2200:-1])

numInputs = len(realTraining[0])

i_sig = keras.Input(shape=(numInputs,))
q_sig = keras.Input(shape=(numInputs,))

iRff = tf.keras.layers.experimental.RandomFourierFeatures(numInputs, \
                                                 kernel_initializer='gaussian', scale=9.0)(i_sig)
rff1 = keras.Model(inputs=i_sig, outputs=iRff)
qRff = tf.keras.layers.experimental.RandomFourierFeatures(numInputs, \
                                                 kernel_initializer='gaussian', scale=9.0)(q_sig)
rff2 = keras.Model(inputs=q_sig, outputs=qRff)
combined = layers.Concatenate()([iRff, qRff])
combineRff = tf.keras.layers.experimental.RandomFourierFeatures(4 * numInputs, \
                                                                kernel_initializer='gaussian', scale=10.0)(combined)
    
preprocess = keras.Model(inputs=[iRff, qRff], outputs=combineRff)

#print(realTraining[0:5])

preprocessedTraining = preprocess.predict([realTraining, imagTraining])
preprocessedTesting = preprocess.predict([realTesting, imagTesting])

##################  Entering Encoder  ######################
encoderIn = keras.Input(shape=(4*numInputs,))

#connected1 = layers.Dense(100, activation="sigmoid")(encoderIn)
clusterLossLayer = RffConnected(100, 30, 1.00, 100.00)(encoderIn)
#clusterLossLayer = myRffConnected(256)(connected1)

encoder = keras.Model(inputs=encoderIn, outputs=clusterLossLayer)
##################  Entering Decoder  ######################

connected2 = layers.Dense(125, activation="sigmoid")(clusterLossLayer)
relu1 = layers.ReLU()(connected2)
dropout = layers.Dropout(0.2)(relu1)
reshape1 = layers.Reshape((25, 5, 1))(dropout)
bn1 = layers.BatchNormalization()(reshape1)
trans1 = layers.Conv2DTranspose(1, (4, 2))(bn1)
ups1 = layers.UpSampling2D(size=(2, 1))(trans1)
relu2 = layers.ReLU()(ups1)
bn2 = layers.BatchNormalization()(relu2)
trans2 = layers.Conv2DTranspose(1, (4, 2))(bn2)
ups2 = layers.UpSampling2D(size=(2, 1))(trans2)
relu3 = layers.ReLU()(ups2)
bn3 = layers.BatchNormalization()(relu3)
trans3 = layers.Conv2DTranspose(1, (5, 2))(bn3)
ups3 = layers.UpSampling2D(size=(2, 1))(trans3)
relu4 = layers.ReLU()(ups3)
bn4 = layers.BatchNormalization()(relu4)
trans4 = layers.Conv2DTranspose(1, (7, 1))(bn4)
reshape2 = layers.Reshape((4*numInputs, 1, 1))(trans4)

autoencoder = keras.Model(inputs=encoderIn, outputs=reshape2)
encoded_input = keras.Input(shape=(None, 100))
decoder_layer = autoencoder.layers[-1]
#autoencoder.summary()

autoencoder.compile(optimizer='adam', loss=[autoencoder.losses[-1], customloss], metrics=['accuracy', 'accuracy'])

autoencoder.fit(preprocessedTraining, preprocessedTraining, epochs=100, batch_size=20, shuffle=True, validation_data=(preprocessedTesting, preprocessedTesting))

It seems like it runs for two training epochs then it gives me an error. I end up getting this error when I run it:

ValueError: Could not interpret loss function identifier: Tensor("rff_connected_137/Const:0", shape=(100,), dtype=float32)

I've already spent a considerable amount of time debugging this thing, although if you spot any more errors I would appreciate a heads-up. Thank you in advance.

Upvotes: 1

Views: 2690

Answers (1)

Ipvikukiepki-KQS
Ipvikukiepki-KQS

Reputation: 137

According to the documentation of the keras Keras Model Training-Loss, the 'loss' attribute can take the value of float tensor (except for the sparse loss functions returning integer arrays) with a specific shape.

If it is necessary to combine two loss functions, it would be better to perform mathematical calculations within your custom loss function to return an output of float tensor. This reference might be a help Keras CustomLoss definition.

Upvotes: 2

Related Questions