Maison > Article > développement back-end > Mon réseau neuronal est entraîné (à partir de zéro) pour s'éloigner davantage de l'objectif
C'est la première fois que je crée un réseau de neurones et j'ai décidé de le créer en Golang qui n'est généralement pas le langage prévu à cet effet mais je veux bien comprendre comment ils fonctionnent à partir de zéro uniquement Bibliothèque de base.
Le but de ce programme est de former un réseau de neurones pour pouvoir additionner deux nombres (1-10). Pour ce faire, j'ai créé une classe de réseau neuronal appelée rawai (le meilleur nom auquel je puisse penser) et lui ai donné 1 couche d'entrée (tableau de taille 2), 1 couche cachée (tableau de taille 2) et 1 couche de sortie ( tableau de taille 1).
Les poids ont deux tableaux 2D, l'un est ih (entrée cachée) [2,2] et l'autre est ho, [2,1].
Ce qui suit est le code pour démarrer, entraîner et tester l'IA. Vous verrez plusieurs instructions de débogage que j'ai utilisées et toutes les autres fonctions qui ne sont pas Golang ou ses packages seront affichées dans le code suivant de ma classe rawai. Ceci est appelé par ma fonction principale :
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) }
Voici tout le code dans le fichier 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 }
L'exemple de sortie est le suivant : Comme vous pouvez le constater, il s’éloigne lentement de la cible et continue de s’éloigner. Après avoir demandé, recherché sur Google et recherché ce site, je n'ai pas trouvé où se trouvait mon erreur, j'ai donc décidé de poser cette question.
Je pense que vous utilisez 均方误差
并在微分后忘记了 -
.
Alors change :
outputerrors[k] = (targets[k] - nn.outputlayer[k])
À :
outputErrors[k] = -(targets[k] - nn.OutputLayer[k])
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!