我试图用两个输出节点实现感知器算法,但我面临三个问题。
首先,我不确定如何评估我所做的事情,如何创建测试用例?
第二个也是更紧迫的问题是,我是否应该为每个输入模式创建一个权重数组,即如果我的输入数据如下所示:
0 0 0 0 0 0 0
0 0 0 0 1 0 0
0 0 0 1 0 0 0
0 0 0 1 1 0 0
0 0 1 0 0 0 0
0 0 1 0 1 0 0
0 0 1 1 0 0 0
0 0 1 1 1 1 0
0 1 0 0 0 0 0
0 1 0 0 1 0 1
0 1 0 1 0 0 0
0 1 0 1 1 1 1
0 1 1 0 0 0 0
0 1 1 0 1 1 1
0 1 1 1 0 1 0
0 1 1 1 1 1 1
1 0 0 0 0 0 0
1 0 0 0 1 0 0
1 0 0 1 0 0 0
1 0 0 1 1 1 0
1 0 1 0 0 0 0
1 0 1 0 1 1 0
1 0 1 1 0 1 0
1 0 1 1 1 1 0
1 1 0 0 0 0 0
1 1 0 0 1 1 1
1 1 0 1 0 1 0
1 1 0 1 1 1 1
1 1 1 0 0 1 0
1 1 1 0 1 1 1
1 1 1 1 0 1 0
1 1 1 1 1 1 1
例如,我应该创建一组处理模式的权重:
1 1 1 1 1
和一组处理模式的权重:
1 1 1 1 0
另一个:
1 1 1 0 1
等等。
或
我应该为每个输出神经元创建一个权重数组,在上面的例子中有两个。这就是我目前的实施情况,但我清楚地知道我所描述的内容更为准确 - 但我不能完全证明为什么会这样 - 也许有人可以解释这个我。
可能与前两个问题密切相关的第三个问题是算法收敛太快。
以下是两次执行的结果:
输出1
Iteration 1 : RMSE = 0.30618621784789724
Iteration 2 : RMSE = 0.0
输出2
Iteration 1 : RMSE = 0.1767766952966369
Iteration 2 : RMSE = 0.0
完整的实现如下:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class Main
{
static int MAX_ITER = 100;
static double LEARNING_RATE = 0.1;
static int theta = 0;
public static void main(String args[]) throws IOException, InterruptedException
{
ArrayList<Group> input_group_one = new ArrayList<>();
ArrayList<Group> input_group_two = new ArrayList<>();
/**************
* READ INPUT *
**************/
BufferedReader reader = new BufferedReader(new FileReader("../PA-A-train.dat"));
//do I even need this?
int number_of_inputs = 0;
String line;//new variable
while ((line = reader.readLine()) != null) //read the line and compare
{
/*********************************************************************
* GET THE LINE, SPLIT ON THE TAB FOR LABEL VS. INPUT IDENTIFICATION *
*********************************************************************/
String[] label_detector = line.split("\t"); //split
/*****************************
* GET THE INDIVIDUAL INPUTS *
*****************************/
String inputs = label_detector[label_detector.length - 2];
String[] splited_inputs = inputs.split("\\s+");
List<String> input_list = Arrays.asList(splited_inputs);
splited_inputs = Arrays.stream(splited_inputs) //Remove null values
.filter(s -> (s != null && s.length() > 0))
.toArray(String[]::new);
//for this training datum, how many features does it have
number_of_inputs = splited_inputs.length; //5
/************************************
* GET THE LABEL (2nd LAYER OUTPUT) *
************************************/
String trueLabel = label_detector[label_detector.length - 1];
//System.out.println("this is the corresponding label: " + trueLabel);
String[] splited_labels = trueLabel.split("\\s+");
int number_of_output_neurons = splited_labels.length;
input_group_one.add(new Group( splited_inputs, splited_labels[0] ));
input_group_two.add(new Group( splited_inputs, splited_labels[0] ));
}
reader.close();
// for (Group p : input_group_one)
// System.out.println( "check it out: " + p.toString() );
// ArrayList<String> weights_one = new ArrayList<>();
//PLUS ONE FOR BIAS
double[] weights_one = new double[ number_of_inputs + 1 ];
double[] weights_two = new double[ number_of_inputs + 1 ];
double localError, globalError;
int i, p, iteration, output;
//MAKE SURE YOU HAVE ONE FOR BIAS
for (int j = 0; j < weights_one.length ; j++)
{
weights_one[j] = randDub(-0.5, 0.5);
}
for (int j = 0; j < weights_two.length ; j++)
{
weights_two[j] = randDub(-0.5, 0.5);
}
// for (int j = 0; j < weights_one.length ; j++)
// {
// System.out.println("weights_one[" + j + "]: " + weights_one[j]);
//
// System.out.println("weights_two[" + j + "]: " + weights_two[j]);
// }
iteration = 0;
do
{
iteration++;
globalError = 0;
//loop through all instances (complete one epoch)
for (p = 0; p < input_group_one.size(); p++) // !!!!! is input_group_one.size() right?
{
// calculate predicted class
output = calculateOutput(theta, weights_one, input_group_one);
// difference between predicted and actual class values
// DO THIS INTEGER THING UP FRONT!
localError = Integer.parseInt( input_group_one.get(iteration).value[0] ) - output;
//update weights and bias
for (int weight_index = 0; weight_index < input_group_one.get(iteration).value.length ; weight_index++)
{
weights_one[weight_index] += LEARNING_RATE * localError * Integer.parseInt( input_group_one.get(iteration).value[weight_index] );
}
//BIAS, (-1 because it starts from zero)
weights_one[weights_one.length - 1] += LEARNING_RATE * localError;
//summation of squared error (error value for all instances)
globalError += (localError*localError);
}
/* Root Mean Squared Error */
System.out.println("Iteration "+iteration+" : RMSE = "+Math.sqrt(globalError/input_group_one.size()));
}
while (globalError != 0 && iteration<=MAX_ITER);
}
public static double randDub(double min, double max) throws InterruptedException
{
Random rand = new Random( System.currentTimeMillis() );
double randomValue = min + (max - min) * rand.nextDouble();
//DELAY FOR SEED CHANGE
TimeUnit.SECONDS.sleep(1);
return randomValue;
}
static int calculateOutput(int theta, double weights[], ArrayList<Group> input_group)
{
double sum = 0;
for (Group pattern : input_group)
{
for (int i = 0; i < pattern.value.length; i++)
{
//ORIGINALLY STORED AS STRING MUST CHANGE TO INT
sum += Integer.parseInt( pattern.value[i] ) * weights[i];
}
//BIAS
sum += weights[ pattern.value.length ];
}
return (sum >= theta) ? 1 : 0;
}
}
这是我用来存储输入数据的类。
import java.util.ArrayList;
import java.util.Arrays;
class Group {
public String key;
public String[] value;
public String getKey() {
return key;
}
public String[] getValue() {
return value;
}
Group(String[] splited_inputs, String k)
{
this.key = k;
this.value = splited_inputs;
}
@Override
public String toString()
{
return this.key + " " + Arrays.toString(this.value);
}
// public String toString()
// {
// String result = this.key + "::";
//
// for (int i = 0; i < this.value.length; i++)
// {
// result += " " + this.value[i];
// }
//
// return result;
// }
}
答案 0 :(得分:1)
每个输出神经元只有一个权重集。否则,如果给出新点,你会如何计算最终分类?你会使用哪种重量?学习参数模型的重点是约束模型复杂度(这里 - 参数数量,权重)并用许多训练样本提供它,因此(统计学上)可以学习整个组的最佳训练样本。
网络可以快速收敛(尽管并不意味着它应该),因为问题是微不足道的。您实际上可以查看数据并告诉确切的权重&#34;手动&#34;。对于第一个神经元,这是[1 1 1 1 1]和偏差-2.5(或任何其他在-2和-3之间),对于第二个神经元,它是[0 1 0 0 1]并偏向-1.5(或任何之间 - 1和-2)。