1

使用自定义损失函数,我很难让回归器正常工作。我目前正在使用几个数据集,其中包含用于跨精度计算基准实验的数据,这是其中一个的片段:

| var_0 | var_1 | var_2 | var_3 | err_ds_0      | err_ds_1      | err_ds_2      | err_ds_3      | err_ds_4      | err_mean       | err_std           |
|-------|-------|-------|-------|---------------|---------------|---------------|---------------|---------------|----------------|-------------------|
| 27    | 45    | 35    | 40    | 16.0258634564 | 15.9905086513 | 15.9665402702 | 15.9654006879 | 15.9920739469 | 15.98807740254 | 0.02203520210917  |
| 42    | 23    | 4     | 10    | 0.82257142551 | 0.91889119458 | 0.93573069325 | 0.81276879271 | 0.87065388914 | 0.872123199038 | 0.049423964650445 |
| 7     | 52    | 45    | 4     | 2.39566262913 | 2.4233107563  | 2.45756544291 | 2.37961745294 | 2.42859839621 | 2.416950935498 | 0.027102139332226 |

(提前为降价表抱歉,找不到更好的方法来做到这一点)

每个 err_ds_* 列都是使用指定的 var_* 配置从不同的基准执行获得的(每个 var 包含用于特定变量的精度位数);每个错误单元格实际上包含错误的负自然对数(因为实际值非常小),并且每行的 err_mean 和 err_std 都是根据这些值计算的。

在网络数据准备期间,我重塑了数据集,以便将每个基准测试作为单独的行执行(这意味着我们将有多个行具有相同的 var_* 值,但错误值不同);然后我将数据(我们通常给 fit 函数的东西作为 x)和目标(我们通常给 fit 函数的东西作为 y)分开,因此分别获得:

| var_0 | var_1 | var_2 | var_3 |
|-------|-------|-------|-------|
| 27    | 45    | 35    | 40    |
| 27    | 45    | 35    | 40    |
| 27    | 45    | 35    | 40    |
| 27    | 45    | 35    | 40    |
| 27    | 45    | 35    | 40    |
| 42    | 23    | 4     | 10    |
| 42    | 23    | 4     | 10    |
| 42    | 23    | 4     | 10    |
| 42    | 23    | 4     | 10    |
| 42    | 23    | 4     | 10    |
| 7     | 52    | 45    | 4     |
| 7     | 52    | 45    | 4     |
| 7     | 52    | 45    | 4     |
| 7     | 52    | 45    | 4     |
| 7     | 52    | 45    | 4     |

| log_err       |
|---------------|
| 16.0258634564 |
| 15.9905086513 |
| 15.9665402702 |
| 15.9654006879 |
| 15.9654006879 |
| 0.82257142551 |
| 0.91889119458 |
| 0.93573069325 |
| 0.81276879271 |
| 0.87065388914 |
| 2.39566262913 |
| 2.4233107563  |
| 2.45756544291 |
| 2.37961745294 |
| 2.42859839621 |

最后,我们再次拆分集合以获得训练数据(我们将调用train_data_regrand train_target_tensor)和测试数据(我们将调用test_data_regrand test_target_tensor),所有这些都使用scaler_regr_*.fit_transform(df)(其中 scaler_regr.* 是 StandardScaler( ) 来自 sklearn.preprocessing),并输入网络:

n_features = train_data_regr.shape
input_shape = (train_data_regr.shape[1],)

pred_model = Sequential()

# Input layer
pred_model.add(Dense(n_features * 3, activation='relu',
   activity_regularizer=regularizers.l1(1e-5), input_shape=input_shape))

# Hidden dense layers
pred_model.add(Dense(n_features * 8, activation='relu', 
   activity_regularizer=regularizers.l1(1e-5)))
pred_model.add(Dense(n_features * 4, activation='relu', 
   activity_regularizer=regularizers.l1(1e-5)))

# Output layer (two neurons, one for the mean, one for the std)
pred_model.add(Dense(2, activation='linear'))

# Loss function
def neg_log_likelihood_loss(y_true, y_pred):
    sep = y_pred.shape[1] // 2
    mu, logvar = y_pred[:, :sep], y_pred[:, sep:]
    return K.sum(0.5*(logvar+np.log(2*np.pi)+K.square((y_true-mu)/K.exp(0.5*logvar))), axis=-1)

# Callbacks
early_stopping = EarlyStopping(
        monitor='val_loss', patience=10, min_delta=1e-5) 
reduce_lr = ReduceLROnPlateau(
        monitor='val_loss', patience=5, min_lr=1e-5, factor=0.2) 
terminate_nan = TerminateOnNaN()

# Compiling
adam = optimizers.Adam(lr=0.001, decay=0.005)
pred_model.compile(optimizer=adam, loss=neg_log_likelihood_loss)

# Training
history = pred_model.fit(train_data_regr, train_target_tensor, 
        epochs=20, batch_size=64, shuffle=True, 
        validation_split=0.1, verbose=True,
        callbacks=[early_stopping, reduce_lr, terminate_nan])

predicted = pred_model.predict(test_data_regr)
actual = test_target_regr
actual_rescaled = scaler_regr_target.inverse_transform(actual)
predicted_rescaled = scaler_regr_target.inverse_transform(predicted)
test_data_rescaled = scaler_regr_data.inverse_transform(test_data_regr)

最后,通过自定义函数评估获得的数据,该函数将实际数据与预测数据(即真实均值与预测均值和真实标准与预测标准)与多个指标(如 MAE 和 MSE)进行比较,并使用 matplotlib 绘制结果。

这个想法是,给定 var_* 配置作为输入,网络的两个输出将预测错误的均值和标准差。

现在,让我们提出一个问题:因为使用这段代码,我在预测平均值时得到了非常好的结果(即使使用不同的基准测试),但在预测标准差时结果很糟糕,我想问这是否正确预测这两个值的方法。我敢肯定我在这里遗漏了一些非常基本的东西,但两周后我认为我被卡住了。

4

0 回答 0