警示后人:如果你用的是梯度下降法
查看原帖
警示后人:如果你用的是梯度下降法
555809
houmy楼主2024/4/10 20:17

虽然几乎没有多少人用梯度下降法

为了降低误差,所有变量最好都用 long double。学习率要设置衰减,但不能降得太快(本蒟蒻学习率初始 0.50.5,衰减率 0.999950.99995,总共训练 100000100000 个 epoch)。另外,注意卡常。

如果代码过不去,可以按照本蒟蒻的这份代码调一下参。

#include<bits/stdc++.h>
using namespace std;
const long double eps=1e-6;
int n;
long double a[15][15];
long double pos[15];
long double dis[15];
inline long double calcLoss(){
    register double loss=0,avg=0;
    for(register int i=1;i<=n+1;i++){
        double sqdis=0;
        for(register int j=1;j<=n;j++){
            sqdis+=pow(a[i][j]-pos[j],2);
        }
        dis[i]=sqrt(sqdis);
        avg+=dis[i];
    }
    avg/=(n+1);
    for(register int i=1;i<=n+1;i++){
        loss+=pow(dis[i]-avg,2);
    }
    return loss;
}
inline long double calcGrad(int dim){
    register long double sample1,sample2;
    pos[dim]+=eps;
    sample2=calcLoss();
    pos[dim]-=eps*2;
    sample1=calcLoss();
    pos[dim]+=eps;
    return (sample2-sample1)/(2*eps);
}
inline void backward(const double &lr=1e-3){
    register long double grad[15];
    for(register int i=1;i<=n;i++){
        grad[i]=calcGrad(i);
    }
    for(register int i=1;i<=n;i++){
        pos[i]-=grad[i]*lr;
    }
}
int main(){
    cin>>n;
    for(register int i=1;i<=n+1;i++){
        for(register int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=n;i++)pos[i]=a[1][i];
    double lr=0.5;
    for(int i=1;i<=100000;i++){
        // if(i%10000==0){
        //     cout<<"Iteration "<<i<<":Loss "<<calcLoss()<<endl;
        //     cout<<"Grad:";
        //     for(int j=1;j<=n;j++)cout<<calcGrad(j)<<" ";
        //     cout<<endl;
        // }
        backward(lr);
        lr*=0.99995;
    }
    for(int i=1;i<=n;i++){
        cout<<fixed<<setprecision(3)<<pos[i]<<" ";
    }
}
2024/4/10 20:17
加载中...