Loading a keras model with custom loss based on input - python

I have a custom loss which uses one of the inputs to the model.
def closs(labels,latent_dim):
def loss(y_true,y_pred):
return metric_learning.contrastive_loss(labels=labels,
embeddings_anchor=y_pred[:,:latent_dim],
embeddings_positive=y_pred[:,latent_dim:])
return loss
Where labels is an input to the model. The model architecture is:
def build_model():
left_input = Input(shape=(2900,1))
right_input = Input(shape=(2900,1))
label = Input(shape=(1,))
encoder = build_encoder()
left_embed = encoder(left_input)
right_embed = encoder(right_input)
embeds = Concatenate()([left_embed,right_embed])
model = Model(inputs=[left_input,right_input,label],outputs=[embeds])
return model, label
Then I use the returned "label" to compile the model:
model,label = build_model()
model.compile(optimizer='adam',loss=closs(label,256))
But when I try to load the model, I have to pass this loss as a custom_object, so something like this:
model = load_model('model/cl_model.h5',custom_objects={'loss':closs(xyz,256)})
The issue is that I'm loading the model in a different python script, and so I don't have the "label" input object.
How can I overcome this?

Are you using the weights to retrain the model or just to predict on new data?
In the case of only-predicting you could just use
model.load_weights('model/cl_model.h5')
after defining your model, you won't have to pass the loss function since it's only used to predict.

Related

How do I get this model to predict the multi label classification value?

How do I get this model to predict the multi label classification value based on train input and test input? There are 3 classifications, which are good, bad, and ugly. train_input is a dictionary that holds the train dataset. test_input is a variable that holds the value of 241.43 which a value of 'good', 'bad', or 'ugly' should be predicted from, in this case probably the predicted value should be 'bad'.
from keras.layers import Input, Dense
from keras.models import Model
''' 3 multi label classification using deep learning '''
classification_labels_3 = ['good', 'bad', 'ugly']
train_input = {100.23:'good', 234.76:'bad', 500.90:'ugly'}
test_input = 241.43
'''
# Define the keras architecture of your model in 'build_model' and return it. Compilation must be
done in 'compile_model'.
# input_shapes - dictionary of shapes per input as defined train_input dictionary
# n_classes - For classification, number of target classes
'''
def build_model(input_shapes, n_classes=None):
'''
# This input will receive all the train_input features
# sent to 'main'
'''
input_main = Input(shape=input_shapes['main'], name='main')
x = Dense(64, activation='relu')(input_main)
x = Dense(64, activation='relu')(x)
predictions = Dense(n_classes, activation='softmax')(x)
'''
# The 'inputs' parameter of your model must contain the
# full list of inputs used in the architecture
'''
model = Model(inputs=[input_main], outputs=predictions)
return model
'''
# Compile your model and return it
# model - model defined in 'build_model'
'''
def compile_model(model):
'''
# The loss function depends on the type of problem you solve.
# 'categorical_crossentropy' is appropriate for a multiclass classification.
'''
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
return model
'''
#print(build_model(input_shapes=,n_classes=))
#print(compile(source, filename, mode))
'''
For predicting multi label class you have to use softmax activation function. I can see that you are already using it, so you only have to define the number of classes of it's function:
predictions = Dense(n_classes, activation='softmax')(x)
As you can see, n_classes is defined as a variable of the function build_model, so just adjust this variable when you call the function and you will build a model with the outputs you specified.
But first, you have to obtain dataset in a dataframe format. Try do something like that:
val=[]
for e in train_input:
val.append(e)
clas=[]
for e in train_input:
clas.append(train_input[e])
df=pd.DataFrame(val, columns=["values"])
df["clas"]=clas
You will obtain a dataframe like this:
values clas
0 100.23 good
1 234.76 bad
2 500.90 ugl

How does one train a list of models in Torch?

I am trying to train a list of torch neural network models. I am using a list because I want to have any number of models, and be able to iterate through the list. I am currently trying to
for i in range(len(model_list)):
old_model = model_list[i]
new_model = train_model(old_model, data) # train_model take a model, trains it, and returns it
model_list[i] = new_model
However I am getting some kind of scope problem, since the models in the list do not update their parameters. I assume it has something to do with the model I am updating being some kind of clone, though I do not understand why returning the model has no effect. My training code looks like this:
def train_model(model, data):
model_optimizer = optim.Adam(model.parameters())
model_output = model(data)
model_loss = criterion(model_output, target) # lets just say target we get from data
model_loss.backward()
model_optimizer.step()
return model
I don't see why code like this would not work, however the models in the list are not updating (after checking their coeffficients), and the loss does not change. Is this some kind of scope problem with regard to the models or their parameters? Or is there some other problem? Thanks.
I guess your current train_model function is only computing the loss and updating the weights of the models only for one iteration as you return the model always.
So, I suggest you to modify this function in order to train the models for X epochs before returning the model.
Suggested Code:
def train_model(model, data):
model_optimizer = optim.Adam(model.parameters())
for epoch in range(EPOCHS):
for data in train_loader:
model.zero_grad()
model_output = model(data)
model_loss = criterion(model_output, target) # lets just say target we get from data
model_loss.backward()
model_optimizer.step()
return model

Using Model as a Layer in another Model, First model not training

I built a Keras model that uses another model as a layer, but the problem is the weights in the other model are not training. How to I get around this?
For more details, I am using a transformer to encode sentences individually, then combining the set of sentences with another transformer.
Here is the pseudo code:
Class:
def build_context_encoder(self):
a = Input(sentences shape)
#function stuff
b = #transformer structure
context_encoder = Model(inputs=[a], outputs=b)
return context encoder
def build_model(self):
list_of _contexts = Input(list of contexts shape)
context_embs = Lambda(lambda x: K.map_fn(fn=self.context_encoder, elems=x, dtype=tf.float32))(list_of_contexts)
c = #rest of the model (context_embs)
model = Model(inputs=[list_of _contexts], outputs=c)
model.compile(loss='mean_squared_error', optimizer='adam', metrics=[])
return model
def __init__():
self.context_encoder = self.build_context_encoder()
self.model = self.build_model()
Why don't the weights in context_encoder update when I call fit? Is it due to the map_fn, or because I'm calling the model? How do I fix this?

Accessing part of y_pred in customized loss function for calculating loss

I want to develop a neural network with three inputs pos,anc,neg and three outputs pos_out,anc_out,neg_out. While calculating loss in my customized loss function in keras, I want to access pos_out, anc_out, neg_out in y_pred. I can access y_pred as a whole. But how to access individual part pos_out, anc_out and neg_out
I have applied max function to y_pred. It calculates max value correctly. If I am passing only one output in Model as Model(input=[pos,anc,neg], output=pos_out) then also it calculates max value correctly. But when it comes to accessing max values form pos_out, anc_out and neg_out separately in customized function, it does not work.
def testmodel(input_shape):
pos = Input(shape=(14,300))
anc = Input(shape=(14,300))
neg = Input(shape=(14,300))
model = Sequential()
model.add(Flatten(batch_input_shape=(1,14,300)))
pos_out = model(pos)
anc_out = model(anc)
neg_out = model(neg)
model = Model(input=[pos,anc,neg], output=[pos_out,anc_out,neg_out])
return model
def customloss(y_true,y_pred):
print((K.int_shape(y_pred)[1]))
#loss = K.max((y_pred))
loss = K.max[pos_out]
return loss
You can create a loss function that contains a closure that lets you access the model and thus the targets and the model layer outputs.
class ExampleCustomLoss(object):
""" The loss function can access model.inputs, model.targets and the outputs
of specific layers. These are all tensors and will have the expected results
for the batch.
"""
def __init__(self, model):
self.model = model
def loss(self, y_true, y_pred, **kwargs):
...
return loss
model = Model(..., ...)
loss_calculator = ExampleCustomLoss(model)
model.compile('adam', loss_calculator.loss)
However, it may be simpler to do the inverse. i.e. have a single model output
out = Concatenate(axis=1)([pos_out, anc_out, neg_out])
And then in the loss function slice y_true and y_pred.
From the names of variables, it looks as if you are trying to use a triplet loss. You may find this other question useful:
How to deal with triplet loss when at time of input i have only two files i.e. at time of testing
Your loss function gets 2 arguments, model output and true label, your model output will have the shape that you define when you define the net. Your loss function needs to output a single difference value, between your model's output and the true value of the label while training.
Also please add some trainable layers to your model, because your custom loss function will be useless otherwise.

VGG, perceptual loss in keras

I'm wondering if it's possible to add a custom model to a loss function in keras. For example:
def model_loss(y_true, y_pred):
inp = Input(shape=(128, 128, 1))
x = Dense(2)(inp)
x = Flatten()(x)
model = Model(inputs=[inp], outputs=[x])
a = model(y_pred)
b = model(y_true)
# calculate MSE
mse = K.mean(K.square(a - b))
return mse
This is a simplified example. I'll actually be using a VGG net in the loss, so just trying to understand the mechanics of keras.
The usual way of doing that is appending your VGG to the end of your model, making sure all its layers have trainable=False before compiling.
Then you recalculate your Y_train.
Suppose you have these models:
mainModel - the one you want to apply a loss function
lossModel - the one that is part of the loss function you want
Create a new model appending one to another:
from keras.models import Model
lossOut = lossModel(mainModel.output) #you pass the output of one model to the other
fullModel = Model(mainModel.input,lossOut) #you create a model for training following a certain path in the graph.
This model will have the exact same weights of mainModel and lossModel, and training this model will affect the other models.
Make sure lossModel is not trainable before compiling:
lossModel.trainable = False
for l in lossModel.layers:
l.trainable = False
fullModel.compile(loss='mse',optimizer=....)
Now adjust your data for training:
fullYTrain = lossModel.predict(originalYTrain)
And finally do the training:
fullModel.fit(xTrain, fullYTrain, ....)
This is old but I'm going to answer it because no one did directly. You definitely can call another model in a custom loss, and I actually think it's much easier than adding the model to the end of your main model and creating a whole new one and a whole new set of training labels.
Here is an example that both calls a model and an outside function that we define -
def normalize_tensor(in_feat):
norm_factor = tf.math.sqrt(tf.keras.backend.sum(in_feat**2, axis=-1, keepdims=True))
return in_feat / (norm_factor + 1e-10)
def VGGLoss(y_true, y_pred):
true = vgg(preprocess_input(y_true * 255))
pred = vgg(preprocess_input(y_pred * 255))
t = normalize_tensor(true[i])
p = normalize_tensor(pred[i])
vggLoss = tf.math.reduce_mean(tf.math.square(t - p))
return vggLoss
vgg() just calls the vgg16 model with no head.
preprocess_input is a keras function that normalizes inputs to be used in the vgg model (here we are assuming your model outputs an image in 0-1 range, then we multiply by 255 to get 0-255 range for vgg).
normalize_tensor takes the vgg activations and makes them have a magnitude of 1 for each channel, otherwise your loss will be massive.

Categories