I am trying to implement a custom metric that calculates Specificity for my semantic segmentation problem. I keep getting this error when I train the model using this metric. This metric works well when the model is showing the training metrics but stops for the validation metrics as shown below.
My implementation is shown below:
class Specificity(tf.keras.metrics.Metric):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.tn = tf.keras.metrics.TrueNegatives()
self.fp = tf.keras.metrics.FalsePositives()
def update_state(self, y_true, y_pred, sample_weight=None):
self.tn.update_state(y_true, y_pred)
self.fp.update_state(y_true, y_pred)
def result(self):
tn = self.tn.result()
fp = self.fp.result()
return tf.expand_dims(tf.divide(tn, tn + fp), axis=-1)
Output Message:
Epoch 1/200
2022-07-26 10:16:25.238678: I tensorflow/stream_executor/cuda/cuda_dnn.cc:384] Loaded cuDNN version 8302
2022-07-26 10:16:26.083645: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory
100/100 [==============================] - ETA: 0s - loss: 0.7601 - iou_score: 0.5211 - precision: 0.6069 - recall: 0.7806 - f1-score: 0.6732 - auc: 0.9403 - specificity: 0.8967Traceback (most recent call last):
File "/home/bhattrai/corneal_neovascularization_tf2/test_statistics.py", line 892, in <module>
history = model.fit(my_generator, validation_data=validation_datagen, steps_per_epoch=100, validation_steps=100,
File "/home/bhattrai/.local/lib/python3.9/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
raise e.with_traceback(filtered_tb) from None
File "/home/bhattrai/.local/lib/python3.9/site-packages/keras/backend.py", line 4028, in batch_set_value
x.assign(np.asarray(value, dtype=dtype_numpy(x)))
ValueError: Cannot assign value to variable ' accumulator:0': Shape mismatch.The variable shape (1,), and the assigned value shape () are incompatible.
2022-07-26 10:16:39.142482: W tensorflow/core/kernels/data/generator_dataset_op.cc:108] Error occurred when finalizing GeneratorDataset iterator: FAILED_PRECONDITION: Python interpreter state is not initialized. The process may be terminated.
[[{{node PyFunc}}]]
I tried implementing it in another way as shown below but when I use it during model training it always shows 0.000.
import tensorflow as tf
class Specificity(tf.keras.metrics.Metric):
def __init__(self, name='specificity', **kwargs):
super().__init__(name=name, **kwargs)
self.tn = self.add_weight(name='tn', initializer='zeros')
self.fp = self.add_weight(name='fp', initializer='zeros')
self.tnr = self.add_weight(name='tnr', initializer='zeros')
def update_state(self, y_true, y_pred, sample_weight=None):
y_true = tf.cast(y_true, tf.bool)
y_pred = tf.cast(y_pred, tf.bool)
# Getting the True Negatives
values = tf.logical_and(tf.equal(y_true, False), tf.equal(y_pred, False))
values = tf.cast(values, self.dtype)
self.tn.assign_add(tf.reduce_sum(values))
# Getting the False Positives
values = tf.logical_and(tf.equal(y_true, False), tf.equal(y_pred, True))
values = tf.cast(values, self.dtype)
self.fp.assign_add(tf.reduce_sum(values))
self.tnr.assign_add(tf.divide(self.tn, tf.add(self.tn, self.fp)))
def result(self):
return self.tnr
Output:
m = Specificity()
m.update_state([0, 1, 0, 0], [0, 1, 0, 0])
X = m.result().numpy()
1.0
But when I use it to train a model:
X = tf.random.normal(shape=(100, 256, 256, 3))
Y = tf.random.uniform(minval=0, maxval=2, shape=(100, 256, 256, 1), dtype=tf.int32)
dataset = tf.data.Dataset.from_tensor_slices((X,Y))
train = dataset.take(80)
val = dataset.skip(80)
train = train.cache().shuffle(1000).batch(32).prefetch(tf.data.experimental.AUTOTUNE)
val = val.cache().shuffle(1000).batch(32).prefetch(tf.data.experimental.AUTOTUNE)
model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(256,256,3)),
tf.keras.layers.Conv2D(16, 3, padding='same'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(32, 3, padding='same'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64, 3, padding='same'),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2DTranspose(64, strides=2, padding='same', kernel_size=3),
tf.keras.layers.Conv2DTranspose(32, strides=2, padding='same', kernel_size=3),
tf.keras.layers.Conv2DTranspose(32, strides=2, padding='same', kernel_size=3),
tf.keras.layers.Conv2D(1, 3, activation='sigmoid', padding="same")
])
model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
optimizer='adam',
metrics=[Specificity(), 'accuracy'])
model.fit(train, validation_data=val, epochs=2)
Epoch 1/2
3/3 [==============================] - 16s 5s/step - loss: 0.6939 - specificity: 0.0000e+00 - accuracy: 0.5003 - val_loss: 0.6934 - val_specificity: 0.0000e+00 - val_accuracy: 0.4999
Epoch 2/2
3/3 [==============================] - 15s 5s/step - loss: 0.6933 - specificity: 0.0000e+00 - accuracy: 0.5004 - val_loss: 0.6933 - val_specificity: 0.0000e+00 - val_accuracy: 0.5002
<keras.callbacks.History at 0x7f9fdb2c1250>
I'm not able to test it right now, however I've always defined custom metrics as functions (not by subclassing). Maybe you could give it a try. Also in this article I've found an implementation of the Specificity measure, maybe you can adapt it for your needs.
This is the code:
import numpy as np
import tensorflow as tf
from keras import backend as K
def specificity(y_true, y_pred):
tn = K.sum(K.round(K.clip((1 - y_true) * (1 - y_pred), 0, 1)))
fp = K.sum(K.round(K.clip((1 - y_true) * y_pred, 0, 1)))
return tn / (tn + fp + K.epsilon())
model = tf.keras.Sequential(...)
model.compile(
optimizer="adam",
loss=tf.keras.losses.BinaryCrossentropy(),
metrics=[
"accuracy",
specificity
]
)
model.fit(train, validation_data=val, epochs=2)
Update:
In your subclass version maybe the problem is related to missing the reset_states function (clears the state after each epoch). Try adding this to your class:
def reset_states(self):
self.self.tn.assign(0)
self.self.tp.assign(0)
self.self.tnr.assign(0)
Related
I'm using DNN to fit these data, and I use softmax to classify them into 2 class, and each of them has a demensity of 4040, can someone with experience tell me what's wrong with my nets.
It is strange that my initial loss is 7.6 and my initial error is 0.5524, and Basically they won't change anymore.
for train, test in kfold.split(data_pro, valence_labels):
model = keras.Sequential()
model.add(keras.layers.Dense(5000,activation='relu',input_shape=(4040,)))
model.add(keras.layers.Dropout(rate=0.25))
model.add(keras.layers.Dense(500, activation='relu'))
model.add(keras.layers.Dropout(rate=0.5))
model.add(keras.layers.Dense(1000, activation='relu'))
model.add(keras.layers.Dropout(rate=0.5))
model.add(keras.layers.Dense(2, activation='softmax'))
model.add(keras.layers.Dropout(rate=0.5))
model.compile(optimizer=tf.keras.optimizers.RMSprop(learning_rate=0.0001,rho=0.9),
loss='binary_crossentropy',
metrics=['accuracy'])
print('------------------------------------------------------------------------')
print(f'Training for fold {fold_no} ...')
log_dir="logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
# Fit data to model
history = model.fit(data_pro[train], valence_labels[train],
batch_size=128,
epochs=50,
verbose=1,
callbacks=[tensorboard_callback]
)
# Generate generalization metrics
scores = model.evaluate(data_pro[test], valence_labels[test], verbose=0)
print(f'Score for fold {fold_no}: {model.metrics_names[0]} of {scores[0]}; {model.metrics_names[1]} of {scores[1]*100}%')
acc_per_fold.append(scores[1] * 100)
loss_per_fold.append(scores[0])
# Increase fold number
fold_no = fold_no + 1
# == Provide average scores ==
print('------------------------------------------------------------------------')
print('Score per fold')
for i in range(0, len(acc_per_fold)):
print('------------------------------------------------------------------------')
print(f'> Fold {i+1} - Loss: {loss_per_fold[i]} - Accuracy: {acc_per_fold[i]}%')
print('------------------------------------------------------------------------')
print('Average scores for all folds:')
print(f'> Accuracy: {np.mean(acc_per_fold)} (+- {np.std(acc_per_fold)})')
print(f'> Loss: {np.mean(loss_per_fold)}')
print('------------------------------------------------------------------------')
You shouldn't add Dropout after the final Dense , delete the model.add(keras.layers.Dropout(rate=0.5))
And I think your code may raise error because your labels's dim is 1 , But your final Dense's units is 2 . Change model.add(keras.layers.Dense(2, activation='softmax')) to model.add(keras.layers.Dense(1, activation='sigmoid'))
Read this to learn tensorflow
Update 1 :
Change
model.compile(optimizer= tf.keras.optimizers.SGD(learning_rate = 0.00001,momentum=0.9,nesterov=True),
loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=['accuracy'])
to
model.compile(optimizer= tf.keras.optimizers.Adam(learning_rate=3e-4),
loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=['accuracy'])
And change
accAll = []
for epoch in range(1, 50):
model.fit(train_data, train_labels,
batch_size=50,epochs=5,
validation_data = (val_data, val_labels))
val_loss, val_Accuracy = model.evaluate(val_data,val_labels,batch_size=1)
accAll.append(val_Accuracy)
to
accAll = model.fit(
train_data, train_labels,
batch_size=50,epochs=20,
validation_data = (val_data, val_labels)
)
I am fairly new to machine learning. I learned to write this code from youtube tutorials but I keep getting this error
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_bundle/pydev_umd.py", line 197, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/Users/aniket/Desktop/DeepLearning/PythonLearningPyCharm/CatVsDogs.py", line 109, in <module>
optimizer = optim.Adam(net.parameters(), lr=0.001) # tweaks the weights from what I understand
AttributeError: 'Net' object has no attribute 'parameters'
this is the Net class
class Net():
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1,32,5)
self.conv2 = nn.Conv2d(32,64,5)
self.conv3 = nn.Conv2d(64,128,5)
self.to_linear = None
x = torch.randn(50,50).view(-1,1,50,50)
self.Conv2d_Linear_Link(x)
self.fc1 = nn.Linear(self.to_linear, 512)
self.fc2 = nn.Linear(512, 2)
def Conv2d_Linear_Link(self , x):
x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x = F.max_pool2d(F.relu(self.conv2(x)),(2,2))
x = F.max_pool2d(F.relu(self.conv3(x)),(2,2))
if self.to_linear is None :
self.to_linear = x[0].shape[0]*x[0].shape[1]*x[0].shape[2]
return x
def forward(self, x):
x = self.Conv2d_Linear_Link(x)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.softmax(x, dim=1)
and this is the function train
def train():
for epoch in range(epochs):
for i in tqdm(range(0,len(X_train), batch)):
batch_x = train_X[i:i + batch].view(-1, 1, 50, 50)
batch_y = train_y[i:i + batch]
net.zero_grad() # i don't understand why we do this but we do we don't want the probabilites adding up
output = net(batch_x)
loss = loss_function(output, batch_y)
loss.backward()
optimizer.step()
print(loss)
and the optimizer and loss functions and data
optimizer = optim.Adam(net.parameters(), lr=0.001) # tweaks the weights from what I understand
loss_function = nn.MSELoss() # gives the loss
You're not subclassing nn.Module. It should look like this:
class Net(nn.Module):
def __init__(self):
super().__init__()
This allows your network to inherit all the properties of the nn.Module class, such as the parameters attribute.
You may have a spelling problem and you should look to Net which parameters has.
You need to import optim from torch
from torch import optim
I use the FDDB face pic to train the mtcnn for face detection. In the pnet, for bounding box regression, the acc stay around the 60%. Is there something wrong?
Epoch 397/400
1200/1200 [==============================] - 0s 131us/sample - loss: 0.5068 - conv4_1_loss: 5.4316e-06 - conv4_2_loss: 0.5052 - conv4_1_accuracy: 1.0000 - conv4_2_accuracy: 0.5850
Epoch 398/400
1200/1200 [==============================] - 0s 131us/sample - loss: 0.4350 - conv4_1_loss: 3.8598e-06 - conv4_2_loss: 0.4358 - conv4_1_accuracy: 1.0000 - conv4_2_accuracy: 0.5950
Epoch 399/400
1200/1200 [==============================] - 0s 131us/sample - loss: 0.8905 - conv4_1_loss: 5.0222e-06 - conv4_2_loss: 0.8863 - conv4_1_accuracy: 1.0000 - conv4_2_accuracy: 0.5817
Epoch 400/400
1200/1200 [==============================] - 0s 124us/sample - loss: 1.8505 - conv4_1_loss: 3.0373e-04 - conv4_2_loss: 1.8358 - conv4_1_accuracy: 1.0000 - conv4_2_accuracy: 0.5817
class P_Net(keras.Model):
def __init__(self):
super(P_Net, self).__init__(name="P_Net")
# Define layers here.
self.conv1 = keras.layers.Conv2D(10, (3, 3), name="conv1")
self.prelu1 = keras.layers.PReLU(tf.constant_initializer(0.25), shared_axes=[1, 2], name="prelu1")
self.pool1 = keras.layers.MaxPooling2D((2, 2), name="pool1")
self.conv2 = keras.layers.Conv2D(16, (3, 3), name="conv2")
self.prelu2 = keras.layers.PReLU(tf.constant_initializer(0.25), shared_axes=[1, 2], name="prelu2")
self.conv3 = keras.layers.Conv2D(32, (3, 3), name="conv3")
self.prelu3 = keras.layers.PReLU(tf.constant_initializer(0.25), shared_axes=[1, 2], name="prelu3")
self.cls_output = keras.layers.Conv2D(2, (1, 1), activation="softmax", name="conv4_1")
self.bbox_pred = keras.layers.Conv2D(4, (1, 1), name="conv4_2")
#self.landmark_pred = keras.layers.Conv2D(10, (1, 1), name="conv4_3")
def call(self, inputs):
# Define your forward pass here,
# using layers you previously defined (in `__init__`).
x = self.conv1(inputs)
x = self.prelu1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.prelu2(x)
x = self.conv3(x)
x = self.prelu3(x)
return [self.cls_output(x), self.bbox_pred(x)]#, self.landmark_pred(x)]
def get_summary(self, input_shape):
inputs = keras.Input(input_shape)
model = keras.Model(inputs, self.call(inputs))
return model
For the bounding box lebal, in the Positive train_set ,i use the markable x1,y1 x2,y2 which the FDDB data supplied, just resize them depends scale of pic. is it wrong?
the Negative train_set, i set box lebal [0,0,0,0]
like this:
['./pos/20020816bigimg_932.jpg',
1,
['0.2857142857142857',
'2.2857142857142856',
'12.285714285714286',
'14.285714285714286']]
trying to write focal loss for multi-label classification
class FocalLoss(nn.Module):
def __init__(self, gamma=2, alpha=0.25):
self._gamma = gamma
self._alpha = alpha
def forward(self, y_true, y_pred):
cross_entropy_loss = torch.nn.BCELoss(y_true, y_pred)
p_t = ((y_true * y_pred) +
((1 - y_true) * (1 - y_pred)))
modulating_factor = 1.0
if self._gamma:
modulating_factor = torch.pow(1.0 - p_t, self._gamma)
alpha_weight_factor = 1.0
if self._alpha is not None:
alpha_weight_factor = (y_true * self._alpha +
(1 - y_true) * (1 - self._alpha))
focal_cross_entropy_loss = (modulating_factor * alpha_weight_factor *
cross_entropy_loss)
return focal_cross_entropy_loss.mean()
But when i run this i get
File "train.py", line 82, in <module>
loss = loss_fn(output, target)
File "/home/bubbles/.local/lib/python3.6/site-packages/torch/nn/modules/module.py", line 538, in __call__
for hook in self._forward_pre_hooks.values():
File "/home/bubbles/.local/lib/python3.6/site-packages/torch/nn/modules/module.py", line 591, in __getattr__
type(self).__name__, name))
AttributeError: 'FocalLoss' object has no attribute '_forward_pre_hooks'
Any suggestions would be really helpful, Thanks in advance.
You shouldn't inherit from torch.nn.Module as it's designed for modules with learnable parameters (e.g. neural networks).
Just create normal functor or function and you should be fine.
BTW. If you inherit from it, you should call super().__init__() somewhere in your __init__().
EDIT
Actually inheriting from nn.Module might be a good idea, it allows you to use the loss as part of neural network and is common in PyTorch implementations/PyTorch Lightning.
I clearly don't understand something (first Keras toy)
My input x,y. X is 1D real values and y is a scalar
I want to predict if y is positive or negative. One way is to encode as one hot and use categorical_cross_entropy (which works) and the other is with a custome loss function that does the same (which doesn't work)
I'm training on a 8 examples and checking that I can overfit. My custom function gets stuck at 0.56
Here's the code:
import keras.backend as K
def custom_cross_entrophy(y_true, y_pred):
'''expected return'''
return -(K.log(y_pred[:,0])*K.cast(y_true<=0, dtype='float32')
+ K.log(y_pred[:,1])*K.cast(y_true>0, dtype='float32'))
def build_model(x_dim, unites, loss_fuc):
model = Sequential()
model.add(Dense(
units=unites,
activation='relu',
input_shape=(x_dim,),
# return_sequences=True
))
model.add(Dense(
units=2))
model.add(Activation("softmax"))
start = time.time()
model.compile(loss=loss_fuc, optimizer="adam")
print("Compilation Time : ", time.time() - start)
return model
Now build and run model with custom
model = build_model(X_train.shape[1], 20, custom_cross_entrophy)
model.fit(X_train,y_train,
batch_size=8,epochs=10000,
validation_split=0.,verbose=0)
print model.evaluate(X_train, y_train, verbose=1)
#assert my custom_cross_entrophy is like catergorical_cross_entropy
pred = model.predict(X)
y_onehot = np.zeros((len(K.eval(y_true)),2))
for i in range(len(K.eval(y_true))):
y_onehot[i,int(K.eval(y_true)[i]>0)]=1
print K.eval(custom_cross_entrophy(K.variable(y_train), K.variable(pred)))
print K.eval(categorical_crossentropy(K.variable(y_onehot), K.variable(pred)))
output:
('Compilation Time : ', 0.06212186813354492)
8/8 [==============================] - 0s 52ms/step
0.562335193157
[ 1.38629234 0.28766826 1.38613474 0.28766349 0.28740349 0.28795806
0.28766707 0.28768104]
[ 1.38629234 0.28766826 1.38613474 0.28766349 0.28740349 0.28795806
0.28766707 0.28768104]
now do the same with the Keras loss:
model = build_model(X_train.shape[1], 20, categorical_crossentropy)
model.fit(X_train,y_onehot,
batch_size=8,epochs=10000,
validation_split=0.,verbose=0)
print model.evaluate(X_train, y_onehot, verbose=1)
output:
('Compilation Time : ', 0.04332709312438965)
8/8 [==============================] - 0s 34ms/step
4.22694138251e-05
How is this possible? the losses should be the same mathematically
Thanks!
Off the top of my head, I'd say you're running two different evaluations:
print model.evaluate(X_train, y_train, verbose=1)
# ...
print model.evaluate(X_train, y, verbose=1)
but I don't know what's in y and y_train, so you might need to expand a bit more on what you're doing and how you're splitting the data.
Try and run:
print model.evaluate(X_train, y_onehot, verbose=1)
to see if it was just a typo.
Cheers