调试这个Java程序需要一些帮助

我在使用Eclipse进行机器学习课程的作业时遇到了问题。

我在main()方法中有一个while循环,理论上应该输出一个名为totError的变量。每一次循环时,totError的值应该根据变化的参数进行计算而不同。然而,我无法找到代码中出错的地方,它总是显示相同的值。我是否错误地使用了静态变量和方法?

我已经在下面粘贴了.java和.txt文件(遗憾的是,.txt文件太大,所以我只包含了其中的一小部分,但我的数组维度是正确的)。谁能指导我正确的方向?

package nn;import java.io.File;import java.io.FileReader;import java.io.BufferedReader;//import java.io.PrintStream;import java.io.IOException;import java.lang.Math; public class learningBP {        // 声明变量    static int NUM_INPUTS = 10;     // 包括1个偏置    static int NUM_HIDDENS = 10;    // 包括1个偏置    static int NUM_OUTPUTS = 1;    static double LEARNING_RATE = 0.1;    static double MOMENTUM = 0.1;    static double TOT_ERROR_THRESHOLD = 0.05;    static double SIGMOID_UB = 1;    static double SIGMOID_LB = -1;        static double [][] wgtIH = new double[NUM_INPUTS][NUM_HIDDENS];    static double [][] dltWgtIH = new double[NUM_INPUTS][NUM_HIDDENS];    static double [][] wgtHO = new double[NUM_HIDDENS][NUM_OUTPUTS];    static double [][] dltWgtHO = new double[NUM_HIDDENS][NUM_OUTPUTS];        static int NUM_STATES_ACTIONS;         static String [][] strLUT = new String[4*4*4*3*4*4][2];    static double [][] arrayLUT = new double[strLUT.length][2];    static double [][] arrayNormLUT = new double[strLUT.length][2];    static double [] arrayErrors = new double[strLUT.length];    static double [] arrayOutputs = new double[strLUT.length];    static double [] arrayNormOutputs = new double[strLUT.length];    static double [][] valueInput = new double[strLUT.length][NUM_INPUTS];    static double [][] valueHidden = new double[strLUT.length][NUM_HIDDENS];    static double [] dltOutputs = new double[strLUT.length];    static double [][] dltHiddens = new double[strLUT.length][NUM_HIDDENS];        static double totError = 1;    static int numEpochs = 0;    public static void main(String[] args) {                // 加载查找表        String fileName = "/Users/XXXXX/Desktop/LUT.txt";        try {            load(fileName);        }        catch (IOException e) {            e.printStackTrace();        }                // 初始化神经网络权重        initializeWeights();                while (totError > TOT_ERROR_THRESHOLD) {                        // 前向传播            fwdFeed();                        // 反向传播            bckPropagation();                        // 计算总误差            totError = calcTotError(arrayErrors);            numEpochs += 1;                    System.out.println("训练轮数: "+numEpochs);            System.out.println(totError);                    }    }    public double outputFor(double[] X) {        // TODO 自动生成的方法存根        return 0;    }    public double train(double[] X, double argValue) {        // TODO 自动生成的方法存根        return 0;    }    public void save(File argFile) {        // TODO 自动生成的方法存根            }    public static void load(String argFileName) throws IOException {                // 从第二部分加载查找表训练集        BufferedReader r = new BufferedReader(new FileReader(new File(argFileName)));        String l = r.readLine();        try {            int a = 0;            while (l != null) {                String spt[] = l.split("    ");                strLUT[a][0] = spt[0];                 strLUT[a][1] = spt[1];                arrayLUT[a][0] = Double.parseDouble(strLUT[a][0]);                arrayLUT[a][1] = Double.parseDouble(strLUT[a][1]);                a += 1;                l = r.readLine();            }        } catch (IOException e) {            e.printStackTrace();        } finally {            r.close();        }                // 将查找表标准化为双极性        for (int b = 0; b < arrayLUT.length; b++) {            arrayNormLUT[b][0] = arrayLUT[b][0];            arrayNormLUT[b][1] = sigmoid(arrayLUT[b][1]);        }            }    public static double sigmoid(double x) {                // 双极性Sigmoid函数        return (SIGMOID_UB - SIGMOID_LB) / (1 + Math.pow(Math.E, -x)) + SIGMOID_LB;            }    public static void initializeWeights() {                // 初始化输入层到隐藏层的权重        for (int i = 0; i < NUM_INPUTS; i++) {            for (int j = 0; j < NUM_HIDDENS; j++) {                wgtIH[i][j] = Math.random() - 0.5;                dltWgtIH[i][j] = 0;            }        }                // 初始化隐藏层到输出层的权重        for (int j = 0; j < NUM_HIDDENS; j++) {            for (int k = 0; k < NUM_OUTPUTS; k++) {                wgtHO[j][k] = Math.random() - 0.5;                dltWgtHO[j][k] = 0;            }        }            }    public void zeroWeights() {        // TODO 自动生成的方法存根            }    public static void fwdFeed() {                for(int z = 0; z < arrayLUT.length; z++) {                         // 标准化到[-1, 1]之间            valueInput[z][0] = (Character.getNumericValue(strLUT[z][0].charAt(0)) - 2.5)/1.5; // myX            valueInput[z][1] = (Character.getNumericValue(strLUT[z][0].charAt(1)) - 2.5)/1.5; // myY            valueInput[z][2] = (Character.getNumericValue(strLUT[z][0].charAt(2)) - 2.5)/1.5; // myHead            valueInput[z][3] = Character.getNumericValue(strLUT[z][0].charAt(3)) - 2; // enProx            valueInput[z][4] = (Character.getNumericValue(strLUT[z][0].charAt(4)) - 2.5)/1.5; // enAngle                        // 将四个可能的动作向量化为二进制            valueInput[z][5] = 0;            valueInput[z][6] = 0;            valueInput[z][7] = 0;            valueInput[z][8] = 0;                    int action = Character.getNumericValue(strLUT[z][0].charAt(5)); // action            valueInput[z][action-1] = 1;                        // 应用偏置输入            valueInput[z][9] = 1;                        // 计算隐藏神经元j的值            for(int j = 0; j < NUM_HIDDENS-1; j++) {                valueHidden[z][j] = 0;                for(int i = 0; i < NUM_INPUTS; i++) {                    valueHidden[z][j] += valueInput[z][i]*wgtIH[i][j];                }                valueHidden[z][j] = sigmoid(valueHidden[z][j]);            }                        // 应用偏置隐藏神经元            valueHidden[z][9] = 1;                        // 计算输出神经元的值            arrayOutputs[z] = 0;            for(int j = 0; j < NUM_HIDDENS; j++) {                arrayOutputs[z] += valueHidden[z][j]*wgtHO[j][0];            }                        arrayNormOutputs[z] = sigmoid(arrayOutputs[z]);                 arrayErrors[z] = arrayNormOutputs[z] - arrayNormLUT[z][1];        }            }        public static void bckPropagation() {                for(int z = 0; z < arrayLUT.length; z++) {                         // 用于双极性Sigmoid的Delta规则            dltOutputs[z] = arrayErrors[z] * (1/2) * (1 + arrayNormLUT[z][1]) * (1 - arrayNormLUT[z][1]);                        // 计算隐藏层与输出层之间的权重更新            for(int j = 0; j < NUM_HIDDENS; j++) {                                dltWgtHO[j][0] = (LEARNING_RATE * dltOutputs[z] * valueHidden[z][j]) + (MOMENTUM * dltWgtHO[j][0]);                wgtHO[j][0] += dltWgtHO[j][0];                            }                           // 用于双极性Sigmoid的Delta规则            for(int j = 0; j < NUM_HIDDENS-1; j++) {                                dltHiddens[z][j] = (dltOutputs[z] * wgtHO[j][0]) * (1/2) * (1 + valueHidden[z][j]) * (1 - valueHidden[z][j]);                            // 计算输入层与隐藏层之间的权重更新                for(int i = 0; i < NUM_INPUTS; i++){                                        dltWgtIH[i][j] = (LEARNING_RATE * dltHiddens[z][j] * valueInput[z][i]) + (MOMENTUM * dltWgtIH[i][j]);                    wgtIH[i][j] += dltWgtIH[i][j];                                    }                            }                    }    }        public static double calcTotError(double [] Ar) {                // 获取总误差        double outputTotError = 0;        for(int z = 0; z < Ar.length; z++) {                        outputTotError += Math.pow(Ar[z], 2);                    }        return outputTotError /= 2;            }    }
LUT.txt111111  10.941118079589064111112  -0.1111113  0.5562004990848579111114  1.98907128902595111121  11.862151157526291111122  0111123  -0.38423559443128236111124  0.2924429882372822111131  0111132  0111133  0111134  0.12275095886294243111141  -0.0545618032237386111142  1.111149754536815111143  -0.6483940696098076111144  -0.30397004441336395111211  8.104946515845224111212  3.4679914863334447111213  3.662003985119952111214  6.277685676457839111221  12.552710546022281111222  -0.09099267948190845111223  -0.29566545023952967111224  3.1487890500927063111231  0111232  0111233  0111234  8.934912143040652E-4111241  3.895126725032672111242  -0.2010016212971984111243  0.837429543536912111244  -0.27663053491694656111311  11.653951513990371111312  -0.2946973145089208111313  -0.2978184448888472111314  0.8279393778791164111321  0111322  0111323  0111324  2.2641633761201114111331  0111332  0111333  0111334  0111341  0111342  0111343  1.1732725059583249111344  -0.1112111  5.5359038859179535112112  0112113  0112114  0.0112121  0.08659995226070327112122  0.2798072139553114112123  5.49078110134232112124  -0.3108745952024568112131  -0.05965237074923033112132  0.09253924707369854112133  -0.4112134  3.161972099002618112141  -0.5260766570034812112142  -0.48090118837156254112143  -0.7310822755532788112144  3.486617439631581112211  0112212  0112213  0112214  0.6522588119326032112221  0112222  0112223  0112224  0.7460303984847749112231  0.23736484529821295112232  0.4052788544857546112233  0112234  2.951631100344372112241  0.5653655679375406112242  0.4971810465334616112243  7.402004693866543112244  -0.30000000000000004112311  0112312  0112313  0112314  0112321  0112322  0112323  0112324  0112331  0112332  0112333  0.4151878259768604112334  1.7724104736042405112341  0112342  0112343  4.069896885464749112344  -0.4113111  0113112  0.022566986598282823113113  0.08724320758208144113114  10.05432214824662113121  1.0564414035161591113122  -0.29029602924153364113123  -0.5541038225131591113124  8.672324872378988113131  -0.3654234566003739113132  -0.4113133  0.5004192669349199113134  2.078082532119674113141  0113142  0113143  0113144  1.2525107221533354113211  0113212  0.29495695502888564113213  -0.07529481401595756113214  -0.2404514421514272113221  -0.30000000000000004113222  0.7445615195514395113223  -0.3658317755666047113224  8.553656940756902113231  -0.30000000000000004113232  4.6010557496650915113233  -0.3879385840465742113234  -0.2113241  0.4326819938548774113242  0113243  0113244  1.1942595427121407113311  0113312  0113313  0.0113314  -0.30000000000000004113321  -0.30000000000000004113322  0113323  0113324  0.12628436039474933113331  0113332  0113333  0113334  1.1990757358685409113341  0113342  0113343  0113344  0114111  -0.2620854057619084114112  4.125854638322618114113  -0.6357408602214762114114  -0.3833440478188098114121  4.151592198100268114122  0.07881020285589568114123  0.2470962266586317114124  -0.614351130314123114131  0114132  0114133  0.137166408235687114134  -0.0736602283383406114141  0114142  1.79455706235276114143  -0.10778180504389967114144  -0.1095114211  4.093099235361004114212  0.43773368515345285114213  -0.22722143170688813114214  -0.47254408375084955114221  0.9666070656021031114222  5.3257648197212175114223  0.8550257571983391114224  1.7294133618581196114231  0114232  0114233  0.21693098965929433114234  -0.20056649258727272114241  0114242  0114243  -0.00420789076454664114244  -0.03980396617148699114311  -0.14894661319071242114312  2.8318004984996086114313  0.09972003835421428114314  -0.30000000000000004114321  -0.22014771207852618114322  3.6613263848490236114323  -0.961642132911289114324  -0.37587629822526014114331  0114332  0114333  0114334  0114341  0114342  0114343  0114344  0.01029174912920401121111  8.749283150544025121112  5.160303436301445121113  5.492968882659686121114  5.1300005456187545121121  9.080296371003485121122  5.48452094178394121123  8.364785563964707121124  8.988905334385453121131  0121132  0121133  3.9657653202217764121134  -0.1121141  4.299714795485242121142  -0.20100940661896582121143  -0.14475899994010905121144  0.7735726092109716121211  8.925285927651668121212  7.242378809714628121213  5.825241551756816121214  7.113455264749147121221  10.957172410507585121222  7.914499954045615121223  8.43670507913828121224  9.483271725903045121231  0121232  0121233  0121234  1.0618679323154605121241  3.916743510589585121242  -0.30816983215504323121243  0.18644548962100688121244  -0.05704324546134821121311  9.89354840660501121312  4.1887499584046495121313  8.597262669988885121314  4.6709783035857715121321  0.8690772369609352121322  0121323  0.0770114005696081121324  9.316545509588495121331  0121332  0121333  0121334  0121341  0.0017093447236721923121342  0.303857609787908121343  -0.09889618686732593121344  -0.1

回答:

我发现了以下技术和算法/数学上的缺陷:

技术问题:

(1/2)替换为0.5,因为(1/2)在Java中会导致0(在Java中,除数或被除数或两者都必须是double类型,结果才为double类型,否则为int类型)。在bckPropagation()方法中共有两个这样的实例。

数学问题1:

考虑到Delta规则(例如,http://users.pja.edu.pl/~msyd/wyk-nai/multiLayerNN-en.pdf)以及带动量的Delta规则(例如,http://ecee.colorado.edu/~ecen4831/lectures/deltasum.html),关于dltOutputs[z]似乎存在符号错误。请在bckPropagation()方法中将

dltOutputs[z] = arrayErrors[z] * (1/2) * (1 + arrayNormLUT[z][1]) * (1 - arrayNormLUT[z][1]);

替换为

dltOutputs[z] = -arrayErrors[z] * 0.5 * (1 + arrayNormLUT[z][1]) * (1 - arrayNormLUT[z][1]);

数学问题2(这里我不是很确定,但我想这是一个错误):测试案例z的权重只能依赖于当前轮次及之前所有轮次中测试案例z的数据(由于while循环)。目前,在bckPropagation()方法中,测试案例z的权重还包含了当前轮次及之前所有轮次中所有之前的测试案例z’ < z的权重(由于for循环)。一个可能的解决方案是引入z作为权重的第三维度:wgtIH[z][i][j]wgtHO[z][j][0]。现在,对权重的贡献对于每个测试案例z与其他测试案例z’是隔离的。为了考虑这一点,需要进行以下修改:

1) 定义:

static double [][][] wgtIH = new double[strLUT.length][NUM_INPUTS][NUM_HIDDENS];static double [][][] wgtHO = new double[strLUT.length][NUM_HIDDENS][NUM_OUTPUTS];

2) 初始化:

public static void initializeWeights() {    for(int z = 0; z < arrayLUT.length; z++) {         // 初始化输入层到隐藏层的权重        double rndWgtIH = Math.random() - 0.5;        for (int i = 0; i < NUM_INPUTS; i++) {            for (int j = 0; j < NUM_HIDDENS; j++) {                wgtIH[z][i][j] = rndWgtIH;                    dltWgtIH[i][j] = 0;            }        }        // 初始化隐藏层到输出层的权重        double rndWgtHO = Math.random() - 0.5;        for (int j = 0; j < NUM_HIDDENS; j++) {            for (int k = 0; k < NUM_OUTPUTS; k++) {                wgtHO[z][j][k] = rndWgtHO;                dltWgtHO[j][k] = 0;            }        }    }}

3) fwdFeed()bckPropagation()方法:

在这两个方法中,wgtIH[i][j]wgtHO[j][k]需要分别替换为wgtIH[z][i][j]wgtHO[z][j][k]

示例:总误差随轮次数的变化

 LEARNING_RATE = 0.4, MOMENTUM = 0.4, TOT_ERROR_THRESHOLD = 1; 训练轮数: 1 178.54336668545102 训练轮数: 10000 15.159692746944888 训练轮数: 20000 10.653887138186896 训练轮数: 30000 8.669183516487523 训练轮数: 40000 7.504963842773336 训练轮数: 50000 6.723327476195474 训练轮数: 60000 6.153237046947662 训练轮数: 70000 5.7133602902880325 训练轮数: 80000 5.360053126719502 训练轮数: 90000 5.06774284345891 训练轮数: 100000 4.820373442353342 训练轮数: 200000 3.4647965464740746 训练轮数: 300000 2.8350276017589153 训练轮数: 400000 2.4398876881673557 训练轮数: 500000 2.158533606426507 训练轮数: 600000 1.9432229058177424 训练轮数: 700000 1.770444540122524 训练轮数: 800000 1.627115257304848 训练轮数: 900000 1.5053344819279666 训练轮数: 1000000 1.4000233082047084 训练轮数: 1100000 1.3077427523972092 训练轮数: 1200000 1.2260577251537967 训练轮数: 1300000 1.153175740062673 训练轮数: 1400000 1.0877325511159377 训练轮数: 1500000 1.0286600703077815 持续时间: 822.8203290160001秒 -> 大约14分钟

如预期的那样,由于神经网络的学习进度,总误差在每个轮次中逐渐减少。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注