tensorflow - 为什么输出层在网络末端简单为零?
问题描述
我正在尝试训练一个采用 15x15 图像并将每个像素分为两类 (1/0) 的模型。
这是我的损失函数:
smooth = 1
def tversky(y_true, y_pred):
y_true_pos = K.flatten(y_true)
y_pred_pos = K.flatten(y_pred)
true_pos = K.sum(y_true_pos * y_pred_pos)
false_neg = K.sum(y_true_pos * (1-y_pred_pos))
false_pos = K.sum((1-y_true_pos)*y_pred_pos)
alpha = 0.5
return (true_pos + smooth)/(true_pos + alpha*false_neg + (1-alpha)*false_pos + smooth)
def tversky_loss2(y_true, y_pred):
return 1 - tversky(y_true,y_pred)
这是模型:
input_image = layers.Input(shape=(size, size, 1))
b2 = layers.Conv2D(128, (3,3), padding='same', activation='relu')(input_image)
b2 = layers.Conv2D(128, (3,3), padding='same', activation='relu')(b2)
b2 = layers.Conv2D(128, (3,3), padding='same', activation='relu')(b2)
output = layers.Conv2D(1, (1,1), activation='sigmoid', padding='same')(b2)
model = models.Model(input_image, output)
model.compile(optimizer='adam', loss=tversky_loss2, metrics=['accuracy'])
左边的模型是输入,标签是中间一列,右边一列的预测总是为零:
训练效果很差:
Epoch 1/10
100/100 [==============================] - 4s 38ms/step - loss: 0.9269 - acc: 0.1825
Epoch 2/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9277 - acc: 0.0238
Epoch 3/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9276 - acc: 0.0239
Epoch 4/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9270 - acc: 0.0241
Epoch 5/10
100/100 [==============================] - 3s 30ms/step - loss: 0.9274 - acc: 0.0240
Epoch 6/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9269 - acc: 0.0242
Epoch 7/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9270 - acc: 0.0241
Epoch 8/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9271 - acc: 0.0241
Epoch 9/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9276 - acc: 0.0239
Epoch 10/10
100/100 [==============================] - 3s 29ms/step - loss: 0.9266 - acc: 0.0242
解决方案
这听起来像是一个非常不平衡的数据集,真实区域非常小。这可能确实很难训练。
您可能希望增加alpha
以惩罚比误报更多的误报。无论如何,除非 alpha 足够大,否则一开始你的模型首先变为全负是很正常的,因为这绝对是减少损失的好方法。
现在,关于 Keras 在这种损失中的工作方式存在概念上的错误。您需要将“样本”分开。否则,您正在计算损失,就好像所有图像都是一张图像一样。(因此,正数多的图像可能有合理的结果,而正数少的图像则没有,这将是一个很好的解决方案)
将损失修正为:
def tversky(y_true, y_pred):
y_true_pos = K.batch_flatten(y_true) #keep the batch dimension
y_pred_pos = K.batch_flatten(y_pred)
true_pos = K.sum(y_true_pos * y_pred_pos, axis=-1) #don't sum over the batch dimension
false_neg = K.sum(y_true_pos * (1-y_pred_pos), axis=-1)
false_pos = K.sum((1-y_true_pos)*y_pred_pos, axis=-1)
alpha = 0.5
return (true_pos + smooth)/(true_pos + alpha*false_neg + (1-alpha)*false_pos + smooth)
这样,每个图像都有一个单独的损失值,因此具有许多正值的图像的存在不会影响具有很少正值的图像的结果。
推荐阅读
- ios - 整数数组到范围数组
- couchbase - 对 CouchBase 编程的热情
- c# - 有没有办法总是将实体模型中的字符串数据成员转换为 char(n)?
- javascript - 如何避免 Angular observable 中的“InternalError: too much recursion”?
- python - 如何使用python请求通过登录页面登录?
- spring - 当单个控制器收到许多请求时,Spring 如何处理线程安全?
- python - Pandas - 按一列分组,按另一列排序,从第三列获取值
- computer-science - 准备时间序列数据与机器学习的常规数据有什么区别
- sql - 如何只获取过去 30 天内未售出的商品?
- c# - 将项目推送到 MongoDb 中的深层嵌套数组