我正在使用多元线性回归并使用随机梯度下降进行优化。
处理此数据集
http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/
对于每次运行,所有hyperParameters以及所有其余事物都是相同的,epochs = 200和alpha = 0.1
当我第一次运行时,我得到了final_cost = 0.0591,当我再次运行该程序时,保持一切相同,我得到了final_cost = 1.0056
,再次运行并保持一切不变,我得到了final_cost = 0.8214
,再次运行final_cost = 15.9591,再次运行final_cost = 2.3162,依此类推……
正如您所看到的,保持一切不变并一次又一次地运行,每次最终成本大幅度变化时,有时从0.8到直接15.9,从0.05到直接1.00如此之大,不仅是每个时期之后的最终成本图在同一批生产中,每个锯齿形锯齿均不同于批次GD,因为在锯齿形锯齿中,成本图平稳下降。
我不明白为什么SGD如此怪异,在不同的运行中会有不同的结果。
我对批处理GD进行了相同的尝试,按照预期,一切都非常顺利。对于批处理GD,无论我运行相同的代码多少次,每次的结果都是完全相同的。
但就SGD而言,我真的哭了,
class Abalone :
def __init__(self,df,epochs=200,miniBatchSize=250,alpha=0.1) :
self.df = df.dropna()
self.epochs = epochs
self.miniBatchSize = miniBatchSize
self.alpha = alpha
print("abalone created")
self.modelTheData()
def modelTheData(self) :
self.TOTAL_ATTR = len(self.df.columns) - 1
self.TOTAL_DATA_LENGTH = len(self.df.index)
self.df_trainingData =
df.drop(df.index[int(self.TOTAL_DATA_LENGTH * 0.6):])
self.TRAINING_DATA_SIZE = len(self.df_trainingData)
self.df_testingData =
df.drop(df.index[:int(self.TOTAL_DATA_LENGTH * 0.6)])
self.TESTING_DATA_SIZE = len(self.df_testingData)
self.miniBatchSize = int(self.TRAINING_DATA_SIZE / 10)
self.thetaVect = np.zeros((self.TOTAL_ATTR+1,1),dtype=float)
self.stochasticGradientDescent()
def stochasticGradientDescent(self) :
self.finalCostArr = np.array([])
startTime = time.time()
for i in range(self.epochs) :
self.df_trainingData =
self.df_trainingData.sample(frac=1).reset_index(drop=True)
miniBatches=[self.df_trainingData.loc[x:x+self.miniBatchSize-
((x+self.miniBatchSize)/(self.TRAINING_DATA_SIZE-1)),:]
for x in range(0,self.TRAINING_DATA_SIZE,self.miniBatchSize)]
self.epochCostArr = np.array([])
for j in miniBatches :
tempMat = j.values
self.actualValVect = tempMat[ : , self.TOTAL_ATTR:]
tempMat = tempMat[ : , :self.TOTAL_ATTR]
self.desMat = np.append(
np.ones((len(j.index),1),dtype=float) , tempMat , 1 )
del tempMat
self.trainData()
currCost = self.costEvaluation()
self.epochCostArr = np.append(self.epochCostArr,currCost)
self.finalCostArr = np.append(self.finalCostArr,
self.epochCostArr[len(miniBatches)-1])
endTime = time.time()
print(f"execution time : {endTime-startTime}")
self.graphEvaluation()
print(f"final cost :
{self.finalCostArr[len(self.finalCostArr)-1]}")
print(self.thetaVect)
def trainData(self) :
self.predictedValVect = self.predictResult()
diffVect = self.predictedValVect - self.actualValVect
partialDerivativeVect = np.matmul(self.desMat.T , diffVect)
self.thetaVect -=
(self.alpha/len(self.desMat))*partialDerivativeVect
def predictResult(self) :
return np.matmul(self.desMat,self.thetaVect)
def costEvaluation(self) :
cost = sum((self.predictedValVect - self.actualValVect)**2)
return cost / (2*len(self.actualValVect))
def graphEvaluation(self) :
plt.title("cost at end of all epochs")
x = range(len(self.epochCostArr))
y = self.epochCostArr
plt.plot(x,y)
plt.xlabel("iterations")
plt.ylabel("cost")
plt.show()
对于所有运行,我都将epochs = 200和alpha = 0.1保留下来,但是每次运行都得到了完全不同的结果。
下面提到的向量是theta向量,其中第一个项是偏差,其余项是权重
RUN 1 =>>
[[ 5.26020144]
[ -0.48787333]
[ 4.36479114]
[ 4.56848299]
[ 2.90299436]
[ 3.85349625]
[-10.61906207]
[ -0.93178027]
[ 8.79943389]]
final cost : 0.05917831328836957
RUN 2 =>>
[[ 5.18355814]
[ -0.56072668]
[ 4.32621647]
[ 4.58803884]
[ 2.89157598]
[ 3.7465471 ]
[-10.75751065]
[ -1.03302031]
[ 8.87559247]]
final cost: 1.0056239103948563
RUN 3 =>>
[[ 5.12836056]
[ -0.43672936]
[ 4.25664898]
[ 4.53397465]
[ 2.87847224]
[ 3.74693215]
[-10.73960775]
[ -1.00461585]
[ 8.85225402]]
final cost : 0.8214901206702101
RUN 4 =>>
[[ 5.38794798]
[ 0.23695412]
[ 4.43522951]
[ 4.66093372]
[ 2.9460605 ]
[ 4.13390252]
[-10.60071883]
[ -0.9230675 ]
[ 8.87229324]]
final cost: 15.959132174895712
RUN 5 =>>
[[ 5.19643132]
[ -0.76882106]
[ 4.35445135]
[ 4.58782119]
[ 2.8908931 ]
[ 3.63693031]
[-10.83291949]
[ -1.05709616]
[ 8.865904 ]]
final cost: 2.3162151072779804
我无法弄清楚出了什么问题。 SGD的行为是否像这样,还是在将代码从批处理GD转换为SGD时做了一些愚蠢的操作。如果SGD的行为是这样的,那么我如何知道必须重新运行多少次,因为我不太幸运,每次在第一次运行中我得到的费用都很少,例如0.05,有时第一次运行时的成本约为10.5 0.6,也许很多时候重新运行它,我得到的成本甚至小于0.05。
当我用完全相同的代码和hyperParameter来处理完全相同的问题时,只是用常规批处理GD替换了SGD函数,我得到了预期的结果,即,在对相同数据进行每次迭代之后,我的成本都在平稳地降低,即单调递减函数,无论我重新运行同一程序多少次,得到的结果完全相同,这非常明显。
“将所有内容保持不变,但将批处理GD用于epochs = 20000和alpha = 0.1
我得到了final_cost = 2.7474“
def BatchGradientDescent(self) :
self.costArr = np.array([])
startTime = time.time()
for i in range(self.epochs) :
tempMat = self.df_trainingData.values
self.actualValVect = tempMat[ : , self.TOTAL_ATTR:]
tempMat = tempMat[ : , :self.TOTAL_ATTR]
self.desMat = np.append( np.ones((self.TRAINING_DATA_SIZE,1),dtype=float) , tempMat , 1 )
del tempMat
self.trainData()
if i%100 == 0 :
currCost = self.costEvaluation()
self.costArr = np.append(self.costArr,currCost)
endTime = time.time()
print(f"execution time : {endTime - startTime} seconds")
self.graphEvaluation()
print(self.thetaVect)
print(f"final cost : {self.costArr[len(self.costArr)-1]}")
SomeBody帮助我弄清楚实际情况。在这个新领域,每个意见/解决方案对我来说都是可观的收入:)
最佳答案
您错过了GD(“梯度下降”)和SGD(“随机梯度下降”)之间最重要也是唯一的区别。
随机性-字面意思是“缺乏任何可预测的顺序或计划的质量”。含义随机性。
这意味着,在GD算法中,每个时期中的样本顺序保持不变,而在SGD中,该顺序在每个时期的开始随机洗牌。
因此,具有相同的初始化和超参数的GD每次运行都将产生完全相同的结果,而SGD绝对不会(正如您所经历的那样)。
使用随机性的原因是为了防止模型记住训练样本(这将导致拟合过度,训练集的准确性较高,而看不见的样本的准确性会较差)。
现在,考虑到您的情况下两次运行之间最终成本值的巨大差异,我想您的学习率太高了。您可以使用较低的常数,也可以使用更好的常数,即递减的学习率(随着历元的提高,学习率会降低)。
关于python-3.x - hell 继续随机梯度下降,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54362188/