多元线性回归问题的收敛问题

Convergence issue with multi linear regression problems

我尝试用一​​个非常简单的线性网络来解决多元线性回归问题。该网络仅包含一个密集层作为其输出层,激活函数设置为线性。我通过将输入数据 X 乘以系统(权重)矩阵 A 来合成输出数据 Y: Y=A.X 。 X 和 A 都包含具有正态分布或均匀分布的随机数(无论如何都会发生问题)。在这种情况下,网络在 1000 个样本上仅用 7 个 Epoch 就达到了 99% 以上的准确率,正如人们所期望的那样。

现在,如果我从 Y 合成 X,这次 Y 具有统一的随机数,使用 A 的逆:X = inv(A).Y ,并尝试训练网络,两百个Epoch后,准确率仅达到94%。

即使系统矩阵(权重)完全相同,为什么两种情况之间存在如此巨大的差异。唯一的区别与 X 和 Y 的随机分布有关。如果我被迫遵循第二种情况,我该如何提高我的网络的可训练性,以便它可以在几个 epoch 内训练。

我尝试了不同的优化器、初始化器和正则化,但它们没有帮助。

这是收敛不太好的版本的代码。为了获得第一个版本,我在 Dataset.from_generator(gen2, ...) 中使用 gen1 而不是 gen2.

import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import keras

N = 256
np.random.seed(0)
A = np.random.normal(0,.4,(N,N))
Ainv = np.linalg.inv(A)

import itertools

input_size = N
def gen1():
    for i in itertools.count(1):
        X = np.random.rand(N,1)-.5
        Y = np.dot(A,X)
        yield (X[:,0],Y[:,0])

def gen2():
    for i in itertools.count(1):
        Y = np.random.rand(N,1)-0.5
        X = np.dot(Ainv,Y)
        yield (X[:,0],Y[:,0])

dataset = tf.data.Dataset.from_generator(
     gen2,
     (tf.float64, tf.float64),
     (tf.TensorShape([N]), tf.TensorShape([N])))

train_ds = dataset.take(950)
valid_ds = dataset.skip(950).take(50)

#train_ds = train_ds.shuffle(2000, reshuffle_each_iteration = True)

train_ds = train_ds.batch(1)
valid_ds = valid_ds.batch(1)

from keras.layers import Input, Dense
from keras.models import Model
from keras import backend
 
def rabs(y_t, y_p):
    return backend.mean(backend.abs(y_p - y_t), axis=-1)/(tf.keras.backend.max(y_t) - tf.keras.backend.min(y_t))*100

inp = Input(shape=(input_size,))
out = Dense(N, activation='linear')(inp)

autoencoder = Model(inp, out)

#opt = tf.keras.optimizers.Adam(learning_rate=.0001)
opt = tf.keras.optimizers.SGD(learning_rate=.2, momentum=0.7)
autoencoder.compile(optimizer= opt,
              loss=tf.keras.losses.MeanSquaredError(),metrics= [rabs])

autoencoder.summary()

autoen_model = autoencoder.fit(train_ds, validation_data = valid_ds, epochs = 200)

plt.plot(autoen_model.history['rabs'])
plt.plot(autoen_model.history['val_rabs'])
plt.title('Model Accuracy')
plt.ylabel('Relative Absolute Mean Error %')
plt.xlabel('Epoch')
plt.legend(['Training set', 'Validation set'], loc='upper left')
plt.show()

训练图

案例一:Y合成

案例2:X合成

我不认为优化过程有什么问题,我认为问题是你的误导指标rabs(y_t, y_p)

因为rabs(y_t, y_p)的输出在MAE除以(backend.max(y_t) - backend.min(y_t))之后是一样的,所以gen1的Y和gen2的Y需要在相同的概率分布中,这里不是这种情况,因为在gen1 你的 Y = np.dot(Ainv,np.random.rand(N,1)) 和 gen2 Y = np.random.rand(N,1)

这里的简单示例是考虑y_true_1 = (0.1, 0.2, 0.3)y_true_2 = (0.1, 0.2, 0.5)y_predict_1 = (0.0, 0.1, 0.2)y_predict_2 = (0.0, 0.1, 0.4),然后是MAE_1 = MAE_2 = 0.1,但在MAE_1之后除通过 (max(y_true_1) - min(y_true_1 )) RMAE_1 = 0.5 和 MAE_2 除以 (max(y_true_2) - min(y_true_2 )) RMAE_2 = 0.25,你现在可以看到为什么 y_true_1 的分布与 y_true_1 的分布不同y_true_2,那么你不能指望 rabs(y_t, y_p) 的两个输出是相同的

我将 rabs(y_t, y_p) 更改为 MAS:

def rabs(y_t, y_p):
    return backend.mean(backend.abs(y_p - y_t))

优化器:

learning_rate_fn = tf.keras.optimizers.schedules.InverseTimeDecay(1.0, 950 * 100, 9)
opt = tf.keras.optimizers.Adam(learning_rate=learning_rate_fn)

而且我 运行 多次使用 epochs = 100gen1()gen2() 的输出都在:

gen1:
Epoch 1/100
950/950 [==============================] - 1s 625us/step - loss: 1631.5898 - rabs: 31.9912 - val_loss: 1568.4200 - val_rabs: 31.6044
Epoch 100/100
950/950 [==============================] - 1s 541us/step - loss: 16.1436 - rabs: 3.1877 - val_loss: 19.1974 - val_rabs: 3.5311

gen2:
Epoch 1/100
950/950 [==============================] - 1s 614us/step - loss: 51.9863 - rabs: 5.7896 - val_loss: 20.9347 - val_rabs: 3.5948
Epoch 100/100
950/950 [==============================] - 1s 540us/step - loss: 0.7340 - rabs: 0.6716 - val_loss: 0.5478 - val_rabs: 0.5920

正如你所看到的,优化器基本上做了同样的工作,它将损失(MSE)减少了 100 倍,将 rabs(MAE)减少了 10 倍

为什么我认为会发生这种情况

我会忽略你正在进行随机梯度下降,并且 想象一下,您正在为每个步骤处理整个数据集。在 在这种情况下,您在这两种情况下的问题都是在 A.

上最小化 ||Y-AX||^2

经过一些代数运算后,您可以将其写成二次优化 形式问题

\min_{z} z^T Q z + b^T z,

其中z \in R^{256^2}表示矩阵A的项,Q是a 仅从 X 获得的对称矩阵,b 是从 X 获得的向量 和 Y。你要求 Tensorflow 做的是使用来解决这个问题 梯度下降.

梯度下降对这类问题的收敛速度为 由 Q 的条件数决定,它是 Q 的最大特征值 除以它的最小值。一个比 1 大得多的条件数 导致缓慢的梯度下降,因为一些变量的更新速度比 其他。接近一的条件数最适合快速获得 收敛。在 Guler 的优化基础(第 14.2 节)中,您可以 阅读更多关于条件数对 (a 梯度下降的变体,尽管可能有更好的资源 关于这个。

在你的例子中,Q 的特征值就是 XX^T 的特征值,它 是 X 的平方奇异值。对于第一个数据集,X 是 均匀分布,并且在第二个 X= A_0^{-1} Y 中,其中 Y 是 均匀分布。

您观察到的收敛差异来自以下事实: 乘以 A_0^{-1} 会大大增加你的条件数 矩阵。在下面的 python 代码中,我对此做了一些随机试验,并且 发现第二个矩阵的条件数更大。 大几千倍。

import numpy as np

cond1 = []
cond2 = []


for i in range(10):
    A = np.random.normal(0,0.4,(256,256))
    Ainv = np.linalg.inv(A)

    X1 = np.random.rand(256,950)
    X1sv = np.linalg.svd(X1, compute_uv = False)

    Y = np.random.rand(256,950)
    X2 = np.dot(Ainv,Y)
    X2sv = np.linalg.svd(X2, compute_uv = False)

    cond1.append((X1sv.max()/X1sv.min())**2)
    cond2.append((X2sv.max()/X2sv.min())**2)
cond1 = np.array(cond1)
cond2 = np.array(cond2)

print('X1\'s condition number has mean {:.2f} and std {:.2f} '.format(cond1.mean(), cond1.std()))
print('X2\'s condition number has mean {:.2f} and std {:.2f} '.format(cond2.mean(), cond2.std()))
print('X2\'s mean condition number is {:.1f} times as big as X1\'s'.format(cond2.mean()/cond1.mean()))

这就是我对为什么您看到 第二种情况比第一种。我可能是错的,但也许这会指出 你在正确的方向。

建议的解决方案

有几个解决方案:

  1. 使用像 Adam 或 RMSprop 这样的优化算法,这将使一些 努力改善矩阵的条件数。你可以了解更多 关于 https://www.deeplearningbook.org/.
  2. 第 8 章中的内容
  3. 需要A是高斯矩阵吗?具有特征值的矩阵 接近 1 会减少这个问题。
  4. 有优化技术(与机器学习无关) 这改善了大条件数的困难。你可能 查看预条件梯度下降以获取更多信息。