Tensorflow 在keras中为y_true和y_pred实现不同大小的自定义损失函数
我对凯拉斯不熟悉。我需要一些帮助,在keras中使用TensorFlow后端为以下损失方程编写自定义损失函数 传递给损失函数的参数为:Tensorflow 在keras中为y_true和y_pred实现不同大小的自定义损失函数,tensorflow,keras,Tensorflow,Keras,我对凯拉斯不熟悉。我需要一些帮助,在keras中使用TensorFlow后端为以下损失方程编写自定义损失函数 传递给损失函数的参数为: y\u true的形状应为(批次大小,N,2)。在这里,我们传递批次中每个样本的N(x,y)坐标 y\u pred的形状为(批量大小,256,256,N)。在这里,我们在批处理中的每个样本中传递N个预测的热图(256 x 256像素) i∈ [0255] j∈ [0255] Mn(i,j)表示第n个预测热图的像素位置的值(i,j) Mn∼(i,j)=Guas
y\u true
的形状应为(批次大小,N,2)
。在这里,我们传递批次中每个样本的N(x,y)
坐标李>
y\u pred
的形状为(批量大小,256,256,N)
。在这里,我们在批处理中的每个样本中传递N个预测的热图(256 x 256像素)李>
i
∈ <代码>[0255]
j
∈ <代码>[0255]
Mn(i,j)
表示第n个预测热图的像素位置的值(i,j)
Mn∼(i,j)=Guassian2D((i,j),y_truen,std)
其中
std=标准偏差
,两个尺寸的标准偏差相同(5 px)
是第n(x,y)个坐标。这是平均数
有关详细信息,请查看本文中描述的l2损失
注:我提到的批次大小为y_true和y_pred。我假设Keras对整个批次调用损失函数,而不是对批次中的单个样本调用损失函数。如果我错了,请纠正我
def l2_loss(y_true, y_pred):
loss = 0
n = y_true.shape[0]
for j in range(n):
for i in range(num_joints):
yv, xv = tf.meshgrid(tf.arange(0, im_height), tf.arange(0, im_width))
z = np.array([xv, yv]).transpose(1, 2, 0)
ground = np.exp(-0.5*(((z - y_true[j, i, :])**2).sum(axis=2))/(sigma**2))
loss = loss + np.sum((ground - y_pred[j,:, :, i])**2)
return loss/num_joints
这是我到目前为止写的代码。我知道这不会运行,因为我们不能在keras损失函数中使用直接numpy ndarrays。此外,我需要消除循环 您几乎可以将numpy函数转换为Keras后端函数。唯一需要注意的是设置正确的广播形状
def l2_loss_keras(y_true,y_pred):
#设置网格:(高度、宽度、2)
网格网格=K.tf.网格网格(K.arange(im_高度),K.arange(im_宽度))
meshgrid=K.cast(K.transpose(K.stack(meshgrid)),K.floatx())
#设置广播形状:(批量大小、高度、宽度、接头数量,2)
meshgrid_broadcast=K.expand_dims(K.expand_dims(meshgrid,0),-2)
y_-true_广播=K.expand_dims(K.expand_dims(y_-true,1),2)
diff=网格网格广播-y网格广播
#计算损失:首先求和(高度、宽度),然后取平均数
地面=K.exp(-0.5*K.sum(K.square(diff),轴=-1)/sigma**2)
损耗=K.和(K.平方(地面-y_pred),轴=[1,2])
返回K.平均值(损失,轴=-1)
要验证它,请执行以下操作:
def l2_loss_numpy(y_true,y_pred):
损失=0
n=y_真。形状[0]
对于范围(n)内的j:
对于范围内的i(num_关节):
yv,xv=np.meshgrid(np.arange(0,im_高度),np.arange(0,im_宽度))
z=np.堆栈([xv,yv]).转置(1,2,0)
地面=np.exp(-0.5*((z-y_真[j,i,:])**2.sum(轴=2))/(σ**2))
损失=损失+np.和((地面-y_pred[j,:,:,i])**2)
返回损耗/接头数量
批量大小=32
接头数量=10
西格玛=5
im_宽度=256
im_高度=256
y_true=255*np.random.rand(批量大小,接头数,2)
y_pred=255*np.random.rand(批次大小、im_高度、im_宽度、接缝数量)
打印(l2\u丢失\u numpy(y\u真,y\u pred))
45448272129
打印(K.eval(l2_损失_keras(K.variable(y_true)、K.variable(y_pred))).sum())
4.5448e+10
该数字在默认的dtype
float32下被截断。如果运行时将dtype
设置为float64:
y\u true=255*np.random.rand(批量大小,接头数量,2)
y_pred=255*np.random.rand(批次大小、im_高度、im_宽度、接缝数量)
打印(l2\u丢失\u numpy(y\u真,y\u pred))
45460126940.6
打印(K.eval(l2_损失_keras(K.variable(y_true)、K.variable(y_pred))).sum())
45460126940.6
编辑: Keras似乎要求
y_true
和y_pred
具有相同数量的维度。例如,在以下测试模型上:
X=np.random.rand(批量大小,256,256,3)
模型=顺序([密集(10,输入_形=(256,256,3)))
compile(loss=l2\u loss\u keras,优化器='adam')
模型拟合(X,y_为真,批量大小=8)
ValueError:无法为具有形状“(?,?,?,?,?)”的张量“密集_2_目标:0”馈送形状(8,10,2)的值
要解决此问题,可以在将y\u true
输入模型之前,使用expand\u dims
添加虚拟维度:
def l2_loss_keras(y_true,y_pred):
...
y_-true_-broadcast=K.expand_-dims(y_-true,1)#更改此行
...
模型拟合(X,np.展开尺寸(y为真,轴=1),批量大小=8)
最近版本的Keras实际上支持不同形状的y\u pred
和y\u true
损失。内置损失sparse\u categorical\u crossentropy
就是一个例子。该损失的TensorFlow实现如下:
注意它是如何表示target:integer张量的。
而不是target:output形状相同的张量。
和其他张量一样。我尝试了一个自定义的损失,我自己,它似乎工作良好
我使用的是Keras 2.2.4 余的回答是正确的,但我想分享我的经验。每当您想编写自定义损失函数时,请注意某些事项:
y\u pred
具有三维形状,y\u true
将默认为三维形状。但是,在运行时,即在fit
期间,如果像许多人那样以二维形式传递目标数据,则可能最终会在损失函数中得到错误。例如,如果您正在使用logits计算sigmoid交叉熵,它会抱怨。因此,一定要通过np.expand_dims以三维形式传递目标李>
y_true
和y_pred
作为参数(如果有人知道我们可以使用任何其他名称作为参数,请单击)