我使用 Keras 为 YOLO 实现了自定义损失函数和模型。我正在使用Tensorflow作为后端。
import pickle
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential,load_model
from keras.layers import Dense,Conv2D,Activation,MaxPooling2D,Flatten
import keras as k
from keras import optimizers
import cv2
batch=12
sess= tf.Session()
#loss function
def yolo_loss(yTrue,yPred):
coord=5
noobj=0.5
L_noobj=1
L_obj=1
if yTrue[6] == 1:
L_obj=0
if yTrue[5] == 1:
L_noobj=0
w=coord*L_obj*(tf.square([tf.sqrt(yTrue[2])-tf.sqrt(yPred[2])]))
h=coord*L_obj*(tf.square([yTrue[3]-yPred[3]]))
x=coord*L_obj*(tf.square([yTrue[0]-yPred[0]]))
y=coord*L_obj*(tf.square([yTrue[1]-yPred[1]]))
no_obj=noobj*L_noobj*(tf.square([yTrue[6]-yPred[6]]))
obj=L_obj*(tf.square([yTrue[5]-yPred[5]]))
clss=L_obj*(tf.square([yTrue[4]-yPred[4]]))
loss=w+h+x+y+no_obj+obj+clss
return loss
def custom_loss(yTrue,yPred):
loss=None
for a in range(batch):
loss_per_sample=0
for b in range(4):
for c in range(4):
loss_per_sample += yolo_loss(yTrue[a,b,c,0:],yPred[a,b,c,0:])
if loss == None:
loss=tf.stack(loss_per_sample)
else:
x=tf.stack(loss_per_sample)
loss=tf.concat([loss,x],0)
loss=tf.reshape(loss,[-1,1])
return loss
#load data and labels
x_train=pickle.load(open('data_image.pickle','rb'))
y_train=pickle.load(open('data_label.pickle','rb'))
test=pickle.load(open('test_image.pickle','rb'))
# model
model=Sequential()
model.add(Conv2D(16,(7,7),input_shape=x_train.shape[1:],padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(32,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(64,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(128,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(512,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(512,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(Conv2D(1024,(3,3),padding="same"))
model.add(Activation("relu"))
model.add(Conv2D(7,(3,3),padding="same"))
model.add(Activation("relu"))
adam = optimizers.adam(lr=0.001)
model.compile(loss=custom_loss,optimizer=adam,metrics=["accuracy"])
model.fit(x_train,y_train,batch_size=batch,epochs=100)
model.save('yolo.model')
当我训练模型时,损失值变为 NAN.但是当我从自定义损失函数中的"W"和"h"中删除 tf.sqrt() 后,损失几乎为零。但问题是边界框的"W"和"h"值始终为零。我认为 tf.sqrt() 函数中有一些东西。请有人告诉我这里发生了什么。
我认为这是某种除以零错误,我在使用 Yolo 和 darkflow 进行玩家检测时遇到了这个问题,我为解决这个问题所做的一件事是对批量大小和学习率进行了一些调整。
您在最后一层中使用relu
,这是意料之中的。这可能会导致垂死的梯度。
另外,在使用 sqrt 函数(例如负值)之前进行一些检查。
model.add(Conv2D(7,(3,3),padding="same"))
model.add(Activation("relu"))
adam = optimizers.adam(lr=0.001)
model.compile(loss=custom_loss,optimizer=adam,metrics=["accuracy"])