В настоящее время я пытаюсь изучить машинное обучение и, в частности, нейронные сети.В c ++ я построил очень простую двухслойную (скрытую и выходную) нейронную сеть, в которой используется матричная библиотека, которую я также встроил в c ++.Тем не менее, когда я попытался натренировать его с очень тривиальной проблемой - проблемой xor - результат был не таким, каким я хотел его видеть.Вот код, который я пытаюсь реализовать:
int main(){
int trainingData[4][3] = {
{0,0,0},
{1,1,0},
{1,0,1},
{0,1,1}
};
NeuralNetwork nn = NeuralNetwork(2,2,1);
for (int i = 0; i < 10000; i++){
std::vector<double> inputs(2);
std::vector<double> targets(1);
srand(time(NULL));
int index = rand()%4;
for(int j = 0; j < 3; j++){
if (j < 2){
inputs[j] = trainingData[index][j];
}else{
targets[0] = trainingData[index][j];
}
}
// cout<<inputs[0]<<" "<<inputs[1]<<" -> "<<targets[0]<<endl;
nn.train(inputs,targets);
}
std::vector<double> inputs = {0,0};
nn.predict(inputs).print();
//
// for (int i = 0; i < prediction.size(); i++)
// cout<<prediction[i]<<" ";
return 0;
}
Вот мой класс нейронной сети:
class NeuralNetwork{
private:
int inputNodes,hiddenNodes,outputNodes;
float learningRate;
Matrix weightsIH, weightsHO, biasH, biasO;
public:
//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
NeuralNetwork(int inNodes,int hidNodes,int outNodes,float lr = .1){
inputNodes = inNodes;
hiddenNodes = hidNodes;
outputNodes = outNodes;
learningRate = lr;
//create matrices for the weights
weightsIH.setSize(hiddenNodes,inputNodes);
weightsHO.setSize(outputNodes,hiddenNodes);
//randomize weights matrices
weightsHO.randomize();
weightsIH.randomize();
//create matrices for the biases
biasH.setSize(hiddenNodes,1);
biasO.setSize(outputNodes,1);
//randomize biases
biasH.randomize();
biasO.randomize();
}
//----------------------------------------------------------------------------
// Prediction
//----------------------------------------------------------------------------
Matrix predict(std::vector<double> inputVector){
//generate hidden outputs
Matrix inputs = fromVector(inputVector);
Matrix hiddenOutput = multiply(weightsIH, inputs);
//apply bias
hiddenOutput.add(biasH);
//use activation function
hiddenOutput.sigmoid();
//output's output
Matrix output = multiply(weightsHO, hiddenOutput);
//apply bias
output.add(biasO);
//use activation function
output.sigmoid();
return output;
}
//----------------------------------------------------------------------------
// Training
//----------------------------------------------------------------------------
void train(std::vector<double> inputVector, std::vector<double> targetVector){
//--------------------------------------------------------------------------
// Feed Forward
//--------------------------------------------------------------------------
//generating hidden outputs
Matrix inputs = fromVector(inputVector);
//cout<<"1"<<endl;
Matrix hiddenOutput = multiply(weightsIH, inputs);
//add bias
hiddenOutput.add(biasH);
//activation function
hiddenOutput.sigmoid();
//generating second output
Matrix outputs = multiply(weightsHO,hiddenOutput);
//add bias
outputs.add(biasO);
//activation function
outputs.sigmoid();
//--------------------------------------------------------------------------
// Back Propogation
//--------------------------------------------------------------------------
//convert targets vector to matrix
Matrix targets = fromVector(targetVector);
//calculate error
Matrix outputErrors = subtract(targets,outputs);
//calculate gradient
Matrix gradients = dsigmoid(outputs);
gradients = multiply(gradients,outputErrors);
gradients.scale(learningRate);
//calculate deltas
Matrix hiddenOutputT = transpose(hiddenOutput);
Matrix weightHoDeltas = multiply(gradients,hiddenOutputT);
//adjust weights by deltas
weightsHO.add(weightHoDeltas);
biasO.add(gradients);
//calculate hidden layer errors
Matrix weightsHoTranspose = transpose(weightsHO);
Matrix hiddenErrors = multiply(weightsHoTranspose,outputErrors);
//calculate hidden gradient
Matrix hiddenGradient = dsigmoid(hiddenOutput);
hiddenGradient = multiply(hiddenGradient,hiddenErrors);
hiddenGradient.scale(learningRate);
//calculate inputs -> hidden deltas
Matrix inputsT = transpose(inputs);
Matrix weightsIhDeltas = multiply(hiddenGradient,inputsT);
weightsIH.add(weightsIhDeltas);
biasH.add(hiddenGradient);
}
};
И вот мой класс матрицы в моей матричной библиотеке (есть больше функцийкоторые используются в классе нейронной сети, которые не входят в мой класс матрицы, однако полная библиотека имеет размер> 300 строк, поэтому я могу опубликовать это, но это
class Matrix{
private:
int rows,cols;
bool active;
double sigmoidFunc(double x){
return (double)(1/(1+exp(-x)));
}
public:
std::vector<std::vector<double>> data;
Matrix(){
rows = 0;
cols = 0;
active = false;
}
Matrix(int rowsNum,int colsNum){
active = true;
srand(time(NULL));
rows = rowsNum; cols = colsNum;
data.resize(rows);
for (int i = 0; i < rows; i++){
data[i].resize(cols);
}
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] = 0;
}
}
}
void roundFunc(int decimalLength){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] = round(data[i][j] * pow(10,decimalLength))/(pow(10,decimalLength));
}
}
}
void setSize(int rowsNum, int colsNum){
if (rows == 0 || cols == 0){
srand(time(NULL));
rows = rowsNum; cols = colsNum;
data.resize(rows);
for (int i = 0; i < rows; i++){
data[i].resize(cols);
}
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] = 0;
}
}
active = true;
}else{
std::cout<<"Matrix is already initialized!\n";
throw;
}
}
void print(){
if (active){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
std::cout<<data[i][j]<<" ";
}
std::cout<<std::endl;
}
std::cout<<std::endl;
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
void scale(float scalar){
if (active){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] *= scalar;
}
}
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
void sigmoid(){
if (active){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] = sigmoidFunc(data[i][j]);
}
}
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
//matrix multiplication
void multiply(Matrix b){
if (active && b.isActive()){
if(cols != b.getRows()){
std::cout<<"Matrix columns and rows are not compatible!\n";
throw;
}
for(int i = 0; i <rows; ++i){
for(int j = 0; j < b.getCols(); ++j){
for(int k = 0; k < cols; ++k){
data[i][j] += data[i][k] * b.data[k][j];
}
}
}
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
void randomize(){
if (active){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] = rand()%10;
}
}
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
void add(Matrix a){
if (active){
if (a.getRows() == rows && a.getCols() == cols){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] += a.data[i][j];
}
}
}else{
std::cout<<"Matrices' rows and colums are not equal!\n";
throw;
}
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
void subtract(Matrix a){
if (active){
if (a.getRows() == rows && a.getCols() == cols){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
data[i][j] -= a.data[i][j];
}
}
}else{
std::cout<<"Matrices' rows and colums are not equal!\n";
throw;
}
}else{
std::cout<<"Matrix must be initialized!\n";
throw;
}
}
inline int getCols(){return cols;}
inline int getRows(){return rows;}
inline bool isActive(){return active;}
};
Я заранее извиняюсьпотому что я знаю, что это было много кода, но, честно говоря, я понятия не имею, где проблема. Любая помощь будет принята с благодарностью. Я очень плохо знаком с нейронными сетями и до сих пор не знаю, как все это работает.