多元线性回归问题的收敛问题
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 = 100
,gen1()
和 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()))
这就是我对为什么您看到
第二种情况比第一种。我可能是错的,但也许这会指出
你在正确的方向。
建议的解决方案
有几个解决方案:
- 使用像 Adam 或 RMSprop 这样的优化算法,这将使一些
努力改善矩阵的条件数。你可以了解更多
关于 https://www.deeplearningbook.org/.
第 8 章中的内容
- 需要A是高斯矩阵吗?具有特征值的矩阵
接近 1 会减少这个问题。
- 有优化技术(与机器学习无关)
这改善了大条件数的困难。你可能
查看预条件梯度下降以获取更多信息。
我尝试用一个非常简单的线性网络来解决多元线性回归问题。该网络仅包含一个密集层作为其输出层,激活函数设置为线性。我通过将输入数据 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 = 100
,gen1()
和 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()))
这就是我对为什么您看到 第二种情况比第一种。我可能是错的,但也许这会指出 你在正确的方向。
建议的解决方案
有几个解决方案:
- 使用像 Adam 或 RMSprop 这样的优化算法,这将使一些 努力改善矩阵的条件数。你可以了解更多 关于 https://www.deeplearningbook.org/. 第 8 章中的内容
- 需要A是高斯矩阵吗?具有特征值的矩阵 接近 1 会减少这个问题。
- 有优化技术(与机器学习无关) 这改善了大条件数的困难。你可能 查看预条件梯度下降以获取更多信息。