【问题标题】:ConvNet with missing output data for weather forecast缺少天气预报输出数据的卷积网络
【发布时间】:2019-11-22 11:57:44
【问题描述】:

我正在使用 ConvNets 构建一个模型来进行天气预报。我的输入数据是 96x144 矩阵(代表地理区域)的 10K 个样本,在固定高度的网格的每个点中具有变量 Z(地势高度)的值。如果我包含 3 个不同的高度(Z 在不同的高度上非常不同),那么我有这个输入形状:(num_samples,96,144,3)。样品是每小时的,一个样品=一小时。我有将近2年的数据。输入数据(Z)表示该小时的大气状态。

这可以被认为是具有 3 个通道的图像,但不是在 0-256 范围内的像素值,而是在更大范围内的 Z 值(最后一个通道的高度范围为 7500 到 9500,第一个一个的范围是 500 到 1500 aprox)。

我想预测降水(会不会下雨?只是那个,二进制,是或否)。

在那个网格中,我国家的那个空间区域,我只有特定 (x,y) 点的输出数据(整个区域只有 122 个气象站有降雨数据)。只有 122 (x,y) 点我的值为 1(那个小时下雨)或 0(没有下雨)。

所以我的输出矩阵是一个 (num_samples,122) 向量,如果在该样本中(那个小时)下雨,则在站点索引中包含 1,如果没有下雨,则包含 0。

所以我使用了 VGG16 模型和 https://github.com/prl900/precip-encoder-decoders/blob/master/encoder_vgg16.py 之间的混合模型,这是我在一篇论文中找到的用于此特定应用程序的模型。

我想知道我是否以正确的方式构建模型,我只是更改了输入层以匹配我的形状和 FC 层的最后一层以匹配我的类(122,因为对于特定的输入样本,我希望有一个 0 或 1 的 1x122 向量,具体取决于该站是否下雨,对吗?)。由于概率不是互斥的(如果不止一个站点下雨,我可以有很多 1)我在最后一层使用了“sigmoid”激活。

我不知道在编译中使用哪个指标,acc、mae 和分类 acc 在所有时期都保持不变(在第二个时期增加了一点,但在那之后,acc 和 val_acc 保持不变每个时代)。

并且,在输出矩阵中有空值(站没有数据的小时数),我只是用 -1 值填充 NaN(如“我不知道”标签)。这可能是因为没有任何效果?

感谢您的帮助,对过度解释感到抱歉。

def get_vgg16():
model = Sequential()

# Conv Block 1
model.add(BatchNormalization(axis=3, input_shape=(96,144,3)))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 2
model.add(BatchNormalization(axis=3))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 3
model.add(BatchNormalization(axis=3))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 4
model.add(BatchNormalization(axis=3))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Conv Block 5
model.add(BatchNormalization(axis=3))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(BatchNormalization(axis=3))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# FC layers
model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dense(4096, activation='relu'))
model.add(Dense(122, activation='sigmoid'))

#adam = Adam(lr=0.001)
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=[metrics.categorical_accuracy,metrics.binary_accuracy, 'acc'])
print(model.summary())

return model

【问题讨论】:

    标签: python tensorflow keras neural-network conv-neural-network


    【解决方案1】:

    为了改进模型,需要考虑多种因素:

    您选择的损失

    你可以在这里做各种各样的事情。使用 L2 损失(平方距离最小化)是一种选择,您的目标是每个站点的无雨 (0) 或无雨 (1)。另一个(更准确的)选择是将每个输出视为该站下雨的概率。然后,您将为每个输出值应用二进制 cross entropy 损失。

    二元交叉熵只是应用于二分类问题的常规交叉熵。请注意,当只有两种可能的结果时,P(y) = 1 - P(x)。因此,您无需添加任何额外的神经元。

    掩盖损失

    不要将缺失的目标设置为 -1。这没有任何意义,只会给训练带来噪音。想象一下,您正在使用 L2 损失。如果您的网络预测该值的降雨,则意味着 (1 - (-1))^2 = 4,预测误差非常高。相反,您希望网络忽略这些情况。

    您可以通过掩盖损失来做到这一点。假设您进行了 Y = (num_samples, 122) 预测,并且有一个形状相同的目标矩阵 T。您可以定义一个相同大小的二进制掩码 M,其中的值表示您知道的值,而缺失值位置的值为零。那么,您的损失将是 L = M * loss(Y, T)。对于缺失值,损失将始终为 0,没有梯度:不会从中学到任何东西。

    标准化输入

    normalize/standardize 输入总是好的做法。这避免了某些特征比其他特征更相关,从而加快了训练速度。在输入量级非常大的情况下,它还有助于稳定训练,防止梯度爆炸。

    在您的情况下,您有三个渠道,每个渠道都遵循不同的分布(具有不同的最小值和最大值)。在计算 min+max / mean+stdv 值时,您需要针对每个通道(高度)分别考虑所有样本上的数据,然后应用这两个值对所有样本上的相应通道进行归一化/标准化。也就是说,给定一个大小为 (N,96,144,3) 的张量,分别对大小为 (N,96,144,1) 的每个子张量进行归一化/标准化。您需要对测试数据应用相同的变换,因此请保存缩放值以备后用。

    【讨论】:

    • 非常感谢!我会尝试所有这些。如果我规范化和标准化,我必须删除 BatchNormalization 层吗?我不知道这些层如果不规范化会做什么。那么激活 sigmoid 和准确度指标呢?我用这些没关系?那么优化器呢,我不知道如果我使用 SGD 或 Adam 会如何影响网络,我只是随机尝试
    • 在这种情况下,输出层的 sigmoid 是一个不错的选择,因为它将概率限制在 (0, 1) 范围内。您用作损失的二进制交叉熵也是一个不错的选择,只需记住您需要将每个输出(每个站读数)的交叉熵损失乘以数据/无数据的二进制掩码。
    • 不错。我刚刚意识到我的数据集非常不平衡。只有 5% 的输出是 1。在所有 13000 小时(1.5 年)中,只有 750 小时下雨。如果我想平衡数据集,我必须忽略很多样本。所以,保留 1500 个样本,每个样本有 50/50,这是一个非常小的数据集......
    • 有些事情你可以做。随机采样输入,保持目标平衡。这样您就可以使用所有数据,但会更频繁地看到正面(下雨)。此外,考虑使用全卷积网络(无全连接层),您的输出将具有空间分辨率,并且模型不会区分站点(更正则化的模型 -> 较少过度拟合)。
    • 好的,我做到了。但是现在,输出出现了问题。你看,我使用 Dense 作为具有 122 个输出的输出层。但是这些输出是彼此独立的。因此,问题在于不同类型的二元分类(我分别预测 122 个输出,每个输出都有不同的损失)。我怎样才能做到这一点,什么是正确的架构?现在我只是使用这个损失函数: def masked_binary_crossentropy(y_true, y_pred): M = np.zeros(shape=(tam_batch)); M[y_true==-1] = 1; return M*K.mean(K.binary_crossentropy(y_true, y_pred), axis=-1)
    猜你喜欢
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 2020-08-16
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多