Advertisement
Guest User

Untitled

a guest
Dec 5th, 2016
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.75 KB | None | 0 0
  1.  
  2. import org.scalatest.FunSuite
  3. import MathUtils._
  4. import scala.util.Random
  5.  
  6.  
  7. /**
  8.   * Created by 'Jakub Dziworski' on 05.12.16
  9.   */
  10. class PerceptronTest extends FunSuite {
  11.  
  12.   case class Pattern(inputs: List[Double], expectedResult: List[Double])
  13.  
  14.   test("Should chuj") {
  15.  
  16.     val patterns = List(
  17.       Pattern(List(1, 0, 0, 0), List(1, 0, 0, 0))
  18.       //      Pattern(List(0, 1, 0, 0), List(0, 1, 0, 0))
  19.       //      Pattern(List(0, 0, 1, 0), List(0, 0, 1, 0))
  20.       //      Pattern(List(0, 0, 0, 1), List(0, 0, 0, 1))
  21.     )
  22.  
  23.     val trainingResult = Perceptron.train(patterns)
  24.     println(trainingResult)
  25.   }
  26.  
  27.  
  28.   object Perceptron {
  29.     val Step = 0.1
  30.     val Delta = 0.1
  31.     val Bias = 1.0
  32.     type Weights = List[Double]
  33.     type Inputs = List[Double]
  34.     type Layer = List[Neuron]
  35.     type ErrorSignal = Double
  36.     case class Neuron(weights: Weights)
  37.     case class NeuronResult(inputs: Perceptron.Inputs, weights: Perceptron.Weights, weightedSum: Double, output: Double)
  38.     case class TrainingResult(hiddenLayer: Layer, outputLayer: Layer)
  39.  
  40.     def train(patterns: List[Pattern]): TrainingResult = {
  41.       def trainLoop(hiddenLayer: Layer, outputLayer: Layer): TrainingResult = {
  42.         val pattern = patterns(Random.nextInt(patterns.length))
  43.         val inputs: Inputs = pattern.inputs
  44.         val hiddenLayerResult = calcLayer(inputs, hiddenLayer)
  45.         val outputLayerResult = calcLayer(hiddenLayerResult.map(_.output), outputLayer)
  46.         val networkResult = calcNetwork(inputs, hiddenLayer, outputLayer)
  47.  
  48.         if (isTrained(patterns, networkResult)) {
  49.           TrainingResult(hiddenLayer, outputLayer)
  50.         } else {
  51.           val outputLayerErrorSignals = calcOutputLayerSignals(pattern, outputLayerResult)
  52.           val hiddenLayerErrorSignals = calcHiddenLayerSignals(hiddenLayerResult, outputLayer, outputLayerErrorSignals)
  53.           val hiddenLayerNewNeurons = newNeurons(hiddenLayerResult, hiddenLayerErrorSignals)
  54.           val outputLayerNewNeurons = newNeurons(outputLayerResult, outputLayerErrorSignals)
  55.           trainLoop(hiddenLayerNewNeurons, outputLayerNewNeurons)
  56.         }
  57.       }
  58.       val freshHiddenLayer: List[Neuron] = List.fill(2)(Neuron(List.fill(5)(randomWeight())))
  59.       val freshOutputLayer: List[Neuron] = List.fill(4)(Neuron(List.fill(3)(randomWeight())))
  60.       trainLoop(freshHiddenLayer, freshOutputLayer)
  61.     }
  62.  
  63.     def calcHiddenLayerSignals(hiddenLayerResult: List[NeuronResult], outputLayer: Layer, outputLayerErrorSignals: List[ErrorSignal]): List[ErrorSignal] = {
  64.       hiddenLayerResult.zipWithIndex.map { case (neuronResult, neuronIndex) =>
  65.         val correspondingOutputWeights = outputLayer.map(_.weights(neuronIndex))
  66.         activationDerivative(neuronResult.weightedSum) * weightedSum(outputLayerErrorSignals, correspondingOutputWeights)
  67.       }
  68.     }
  69.  
  70.     def calcOutputLayerSignals(pattern: Pattern, outputLayerResult: List[NeuronResult]): List[ErrorSignal] = {
  71.       outputLayerResult.zip(pattern.expectedResult).map { case (actualOutput, desiredOutput) =>
  72.         activationDerivative(actualOutput.weightedSum) * (desiredOutput - actualOutput.output)
  73.       }
  74.     }
  75.  
  76.     def isTrained(patterns: List[Pattern], result: List[NeuronResult]): Boolean = patterns.forall { p =>
  77.       val expected = p.expectedResult
  78.       result.zip(expected).forall { case (actual, expected) => Math.abs(actual.output - expected) < Delta }
  79.     }
  80.  
  81.     def calcNeuron(inputs: Inputs, neuron: Neuron): NeuronResult = {
  82.       val weighSum = weightedSum(inputs :+ Bias, neuron.weights)
  83.       NeuronResult(inputs, neuron.weights, weighSum, activationFunction(weighSum))
  84.     }
  85.  
  86.     def calcLayer(inputs: Inputs, neurons: List[Neuron]): List[NeuronResult] = neurons.map(n => calcNeuron(inputs, n))
  87.  
  88.     def calcNetwork(inputs: Inputs, hiddenLayer: List[Neuron], outputLayer: List[Neuron]): List[NeuronResult] = {
  89.       val hiddenLayerResult = calcLayer(inputs, hiddenLayer)
  90.       val outputLayerResult = calcLayer(hiddenLayerResult.map(_.output), outputLayer)
  91.       outputLayerResult
  92.     }
  93.  
  94.  
  95.     def newNeurons(results: List[NeuronResult], errorSignals: List[ErrorSignal]): List[Neuron] = {
  96.       results.zip(errorSignals).map { case (result, signal) =>
  97.         result.weights.map(weight => weight + Step * signal * result.output)
  98.       }.map(Neuron)
  99.     }
  100.   }
  101. }
  102.  
  103. object MathUtils {
  104.   def activationFunction(x: Double): Double = {
  105.     1.0 / (1.0 + Math.exp(-x))
  106.   }
  107.  
  108.   def activationDerivative(x: Double): Double = {
  109.     Math.exp(x) / Math.pow(Math.exp(x) + 1.0, 2)
  110.   }
  111.  
  112.  
  113.   def weightedSum(input: List[Double], weights: List[Double]): Double = {
  114.     input.zip(weights).map { case (value, weight) => value * weight }.sum
  115.   }
  116.  
  117.   def randomWeight(): Double = {
  118.     (Random.nextDouble() - 0.5) / 2.0
  119.   }
  120. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement