我正在使用带有tensorflow后端的keras。我的目标是在自定义损失函数中查询当前批次的batchsize
。这是计算定制损失函数的值所必需的,该值取决于特定观测值的索引。考虑到以下最少的可重现示例,我想更清楚地说明这一点。
(顺便说一句:当然,我可以使用为训练过程定义的批量大小,并在定义自定义损失函数时使用它的值,但是有一些原因可以使其变化,特别是如果epochsize % batchsize
(epochsize modulo batchsize)不等于零,那么最后一个时期的大小是不同的。我在stackoverflow中找不到合适的方法,例如
Tensor indexing in custom loss function和Tensorflow custom loss function in Keras - loop over tensor和Looping over a tensor因为显然在构建图时无法推断任何张量的形状(损失函数就是这种情况)-形状推断仅在评估给定数据时才可能进行,这仅是给定图可能。因此,我需要告诉自定义损失函数对沿特定维度的特定元素执行某些操作,而无需知道维度的长度。
(所有示例都一样)
from keras.models import Sequential
from keras.layers import Dense, Activation
# Generate dummy data
import numpy as np
data = np.random.random((1000, 100))
labels = np.random.randint(2, size=(1000, 1))
model = Sequential()
model.add(Dense(32, activation='relu', input_dim=100))
model.add(Dense(1, activation='sigmoid'))
示例1:没有问题的没有特别之处,没有自定义损失
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
# Train the model, iterating on the data in batches of 32 samples
model.fit(data, labels, epochs=10, batch_size=32)
(省略了输出,可以完美运行)
示例2:没有什么特别的,具有相当简单的自定义损失
def custom_loss(yTrue, yPred):
loss = np.abs(yTrue-yPred)
return loss
model.compile(optimizer='rmsprop',
loss=custom_loss,
metrics=['accuracy'])
# Train the model, iterating on the data in batches of 32 samples
model.fit(data, labels, epochs=10, batch_size=32)
(省略了输出,可以完美运行)
示例3:问题
def custom_loss(yTrue, yPred):
print(yPred) # Output: Tensor("dense_2/Sigmoid:0", shape=(?, 1), dtype=float32)
n = yPred.shape[0]
for i in range(n): # TypeError: __index__ returned non-int (type NoneType)
loss = np.abs(yTrue[i]-yPred[int(i/2)])
return loss
model.compile(optimizer='rmsprop',
loss=custom_loss,
metrics=['accuracy'])
# Train the model, iterating on the data in batches of 32 samples
model.fit(data, labels, epochs=10, batch_size=32)
当然,张量还没有形状信息,只有在训练时才能建立图形时无法推断出该信息。因此for i in range(n)
会引发错误。有什么方法可以执行此操作吗?
输出的回溯:
-------
顺便说一句,这是我真正的自定义损失函数,如有任何疑问。为了清楚和简单起见,我在上面跳过了它。
def neg_log_likelihood(yTrue,yPred):
yStatus = yTrue[:,0]
yTime = yTrue[:,1]
n = yTrue.shape[0]
for i in range(n):
s1 = K.greater_equal(yTime, yTime[i])
s2 = K.exp(yPred[s1])
s3 = K.sum(s2)
logsum = K.log(y3)
loss = K.sum(yStatus[i] * yPred[i] - logsum)
return loss
这是Cox比例Harzards模型的部分负对数似然率的图像。
这是为了澄清注释中的一个问题,以避免混淆。我认为没有必要详细了解这一问题来回答这个问题。
参考方案
和往常一样,不要循环。存在严重的性能缺陷和错误。除非完全不可避免,否则仅使用后端函数(通常不是不可避免的)
示例3的解决方案:
所以,那里有一件很奇怪的事情...
您是否真的要忽略模型预测的一半? (示例3)
假设这是真的,只需在最后一个维度上复制张量,展平并丢弃一半即可。您将获得所需的确切效果。
def custom_loss(true, pred):
n = K.shape(pred)[0:1]
pred = K.concatenate([pred]*2, axis=-1) #duplicate in the last axis
pred = K.flatten(pred) #flatten
pred = K.slice(pred, #take only half (= n samples)
K.constant([0], dtype="int32"),
n)
return K.abs(true - pred)
损失函数的解决方案:
如果您按从大到小的顺序对时间进行了排序,则只需进行累加即可。
警告:如果每个样本一次,则无法进行迷你批次训练!!!
batch_size = len(labels)
像在循环和一维转换网络中那样,在附加维度上有时间是有意义的(每个样本很多次)。无论如何,考虑到您所表达的示例,对于(samples_equal_times,)
,形状为yTime
:
def neg_log_likelihood(yTrue,yPred):
yStatus = yTrue[:,0]
yTime = yTrue[:,1]
n = K.shape(yTrue)[0]
#sort the times and everything else from greater to lower:
#obs, you can have the data sorted already and avoid doing it here for performance
#important, yTime will be sorted in the last dimension, make sure its (None,) in this case
# or that it's (None, time_length) in the case of many times per sample
sortedTime, sortedIndices = tf.math.top_k(yTime, n, True)
sortedStatus = K.gather(yStatus, sortedIndices)
sortedPreds = K.gather(yPred, sortedIndices)
#do the calculations
exp = K.exp(sortedPreds)
sums = K.cumsum(exp) #this will have the sum for j >= i in the loop
logsums = K.log(sums)
return K.sum(sortedStatus * sortedPreds - logsums)
在返回'Response'(Python)中传递多个参数 - python我在Angular工作,正在使用Http请求和响应。是否可以在“响应”中发送多个参数。角度文件:this.http.get("api/agent/applicationaware").subscribe((data:any)... python文件:def get(request): ... return Response(seriali…
Python exchangelib在子文件夹中读取邮件 - python我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…
R'relaimpo'软件包的Python端口 - python我需要计算Lindeman-Merenda-Gold(LMG)分数,以进行回归分析。我发现R语言的relaimpo包下有该文件。不幸的是,我对R没有任何经验。我检查了互联网,但找不到。这个程序包有python端口吗?如果不存在,是否可以通过python使用该包? python参考方案 最近,我遇到了pingouin库。
Python ThreadPoolExecutor抑制异常 - pythonfrom concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED def div_zero(x): print('In div_zero') return x / 0 with ThreadPoolExecutor(max_workers=4) as execut…
如何用'-'解析字符串到节点js本地脚本? - python我正在使用本地节点js脚本来处理字符串。我陷入了将'-'字符串解析为本地节点js脚本的问题。render.js:#! /usr/bin/env -S node -r esm let argv = require('yargs') .usage('$0 [string]') .argv; console.log(argv…