go - 我的神经网络(从头开始)训练,让它离目标更远

标签 go machine-learning neural-network

这是我第一次创建神经网络,我决定在 golang 中创建它,这通常不是用于此目的的语言,但是我想从头开始很好地理解它们如何工作仅基本库。

该程序的目标是训练一个神经网络,使其能够将两个数字(1-10)相加。为此,我创建了一个名为 RawAI(我能想到的最好的名字)的神经网络类,并给它一个 1 个输入层(大小为 2 的数组)、1 个隐藏层(大小为 2 的数组)和 1 个输出层(大小为 1) 的数组。

权重有2个2D数组,一个是IH(Hidden的输入)[2,2],一个是HO,[2,1]。

下面是启动 AI、训练和测试 AI 的代码。您将看到我使用过的几个调试语句,并且非 golang 或其包的任何其他函数将显示在我的 RawAI 类的以下代码中。这是由我的 main 函数调用的:

func AdditionNeuralNetworkTest() {
    nn := NewRawAI(2, 2, 1, 1/math.Pow(10, 15))
    fmt.Printf("Weights IH Before: %v\n\nWeights HO After: %v\n", nn.WeightsIH, nn.WeightsHO)
    //Train Neural Network
    //
    for epoch := 0; epoch < 10000000; epoch++ {
        for i := 0; i <= 10; i++ {
            for j := 0; j <= 10; j++ {
                inputs := make([]float64, 2)
                targets := make([]float64, 1)
                inputs[0] = float64(i)
                inputs[1] = float64(j)
                targets[0] = float64(i) + float64(j)
                nn.Train(inputs, targets)
                if epoch%20000 == 0 && i == 5 && j == 5 {
                    fmt.Printf("[TRAINING] [EPOCH %d] %f + %f = %f TARGETS[%f]\n", epoch, inputs[0], inputs[1], nn.OutputLayer[0], targets[0])
                }

            }

        }
    }
    // Test neural network
    a := rand.Intn(10) + 1
    b := rand.Intn(10) + 1
    inputs := make([]float64, 2)
    inputs[0] = float64(a)
    inputs[1] = float64(b)
    prediction := nn.FeedForward(inputs)[0]
    fmt.Printf("%d + %d = %f\n", a, b, prediction)
    fmt.Printf("Weights IH: %v\n\nWeights HO: %v\n", nn.WeightsIH, nn.WeightsHO)

}

以下是 RawAI 文件中的所有代码:

type RawAI struct {
    InputLayer   []float64   `json:"input_layer"`
    HiddenLayer  []float64   `json:"hidden_layer"`
    OutputLayer  []float64   `json:"output_layer"`
    WeightsIH    [][]float64 `json:"weights_ih"`
    WeightsHO    [][]float64 `json:"weights_ho"`
    LearningRate float64     `json:"learning_rate"`
}

func NewRawAI(inputSize, hiddenSize, outputSize int, learningRate float64) *RawAI {
    nn := RawAI{
        InputLayer:   make([]float64, inputSize),
        HiddenLayer:  make([]float64, hiddenSize),
        OutputLayer:  make([]float64, outputSize),
        WeightsIH:    randomMatrix(inputSize, hiddenSize),
        WeightsHO:    randomMatrix(hiddenSize, outputSize),
        LearningRate: learningRate,
    }
    return &nn
}
func (nn *RawAI) FeedForward(inputs []float64) []float64 {
    // Set input layer
    for i := 0; i < len(inputs); i++ {
        nn.InputLayer[i] = inputs[i]
    }

    // Compute hidden layer
    for i := 0; i < len(nn.HiddenLayer); i++ {
        sum := 0.0
        for j := 0; j < len(nn.InputLayer); j++ {
            sum += nn.InputLayer[j] * nn.WeightsIH[j][i]
        }
        nn.HiddenLayer[i] = sum
        if math.IsNaN(sum) {
            panic(fmt.Sprintf("Sum is NaN on Hidden Layer:\nInput Layer: %v\nHidden Layer: %v\nWeights IH: %v\n", nn.InputLayer, nn.HiddenLayer, nn.WeightsIH))
        }

    }

    // Compute output layer
    for k := 0; k < len(nn.OutputLayer); k++ {
        sum := 0.0
        for j := 0; j < len(nn.HiddenLayer); j++ {
            sum += nn.HiddenLayer[j] * nn.WeightsHO[j][k]
        }
        nn.OutputLayer[k] = sum
        if math.IsNaN(sum) {
            panic(fmt.Sprintf("Sum is NaN on Output Layer:\n Model: %v\n", nn))
        }

    }

    return nn.OutputLayer
}
func (nn *RawAI) Train(inputs []float64, targets []float64) {
    nn.FeedForward(inputs)

    // Compute output layer error
    outputErrors := make([]float64, len(targets))
    for k := 0; k < len(targets); k++ {
        outputErrors[k] = targets[k] - nn.OutputLayer[k]
    }

    // Compute hidden layer error
    hiddenErrors := make([]float64, len(nn.HiddenLayer))
    for j := 0; j < len(nn.HiddenLayer); j++ {
        errorSum := 0.0
        for k := 0; k < len(nn.OutputLayer); k++ {
            errorSum += outputErrors[k] * nn.WeightsHO[j][k]
        }
        hiddenErrors[j] = errorSum * sigmoidDerivative(nn.HiddenLayer[j])
        if math.IsInf(math.Abs(hiddenErrors[j]), 1) {
            //Find out why
            fmt.Printf("Hidden Error is Infinite:\nTargets:%v\nOutputLayer:%v\n\n", targets, nn.OutputLayer)
        }
    }

    // Update weights
    for j := 0; j < len(nn.HiddenLayer); j++ {
        for k := 0; k < len(nn.OutputLayer); k++ {
            delta := nn.LearningRate * outputErrors[k] * nn.HiddenLayer[j]
            nn.WeightsHO[j][k] += delta
        }
    }
    for i := 0; i < len(nn.InputLayer); i++ {
        for j := 0; j < len(nn.HiddenLayer); j++ {
            delta := nn.LearningRate * hiddenErrors[j] * nn.InputLayer[i]
            nn.WeightsIH[i][j] += delta
            if math.IsNaN(delta) {
                fmt.Print(fmt.Sprintf("Delta is NaN.\n Learning Rate: %f\nHidden Errors: %f\nInput: %f\n", nn.LearningRate, hiddenErrors[j], nn.InputLayer[i]))
            }
            if math.IsNaN(nn.WeightsIH[i][j]) {
                fmt.Print(fmt.Sprintf("Delta is NaN.\n Learning Rate: %f\nHidden Errors: %f\nInput: %f\n", nn.LearningRate, hiddenErrors[j], nn.InputLayer[i]))
            }
        }
    }

}
func (nn *RawAI) ExportWeights(filename string) error {
    weightsJson, err := json.Marshal(nn)
    if err != nil {
        return err
    }
    err = ioutil.WriteFile(filename, weightsJson, 0644)
    if err != nil {
        return err
    }
    return nil
}
func (nn *RawAI) ImportWeights(filename string) error {
    weightsJson, err := ioutil.ReadFile(filename)
    if err != nil {
        return err
    }
    err = json.Unmarshal(weightsJson, nn)
    if err != nil {
        return err
    }
    return nil
}

//RawAI Tools:
func randomMatrix(rows, cols int) [][]float64 {
    matrix := make([][]float64, rows)
    for i := 0; i < rows; i++ {
        matrix[i] = make([]float64, cols)
        for j := 0; j < cols; j++ {
            matrix[i][j] = 1.0
        }
    }
    return matrix
}
func sigmoid(x float64) float64 {
    return 1.0 / (1.0 + exp(-x))
}
func sigmoidDerivative(x float64) float64 {
    return x * (1.0 - x)
}

func exp(x float64) float64 {
    return 1.0 + x + (x*x)/2.0 + (x*x*x)/6.0 + (x*x*x*x)/24.0
}

输出示例如下:Example Output 正如您所看到的,它慢慢地远离目标并继续这样做。 经过询问、谷歌搜索和搜索这个网站后,我找不到我的错误所在,所以我决定问这个问题。

最佳答案

我认为您使用的是均方误差并且忘记了微分后的-

所以改变:

outputErrors[k] =  (targets[k] - nn.OutputLayer[k])

致:

outputErrors[k] = -(targets[k] - nn.OutputLayer[k])

关于go - 我的神经网络(从头开始)训练,让它离目标更远,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75872880/

相关文章:

python 中的 Matplotlib.colors.ListedColormap

python - 为什么我无法从 matplotlib.colors 导入 ListedColorMap?

http - 在 GO 中使用基本身份验证获取 http post

go - 从前面截断缓冲区

opencv - 使用不同参数测试我的 SVM 模型会产生完全相同的结果

keras - 了解卷积神经网络 (CNN) 输入形状和输出形状中的 channel

machine-learning - 神经网络: should the algorithm be rewritten for every case?

linux - Go exec.CommandContext 在上下文超时后不会被终止

parsing - 尝试使用 Golang 在命令行上解析标准输出

machine-learning - 如何使用 RGB 图像训练 CNN