Last active
January 9, 2017 07:00
-
-
Save koen-dejonghe/12edcca307c98c31dfeedf368c339fc8 to your computer and use it in GitHub Desktop.
Toy example from lecture 3 in Geoffrey Hintons' course Neural Networks for Machine Learning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.language.postfixOps | |
import scala.util.Random | |
object LinearIterativeLearning extends App { | |
case class LabeledData(numFish: Int, numChips: Int, numKetchup: Int, price: Double = 0.0) | |
case class Weights(fish: Double, chips: Double, ketchup: Double) | |
val trueWeights = Weights(150, 50, 100) | |
val initialWeights = Weights(50, 50, 50) | |
val trainingSet = generateData(10) | |
val testSet = generateData(3) | |
val learningRate = 0.0003 | |
val trainedWeights = train(trainingSet, initialWeights, 10000) | |
println(s"Trained Weights: $trainedWeights") | |
evaluate(trainedWeights, testSet) | |
def generateData(size: Int): List[LabeledData] = { | |
for { | |
_ <- 1 to size | |
numFish = Random.nextInt(10) | |
numChips = Random.nextInt(10) | |
numKetchup = Random.nextInt(10) | |
price = numFish * trueWeights.fish + numChips * trueWeights.chips + numKetchup * trueWeights.ketchup | |
} yield { | |
LabeledData(numFish, numChips, numKetchup, price) | |
} | |
} toList | |
def calculatePrice(data: LabeledData, weights: Weights): Double = | |
data.numFish * weights.fish + data.numChips * weights.chips + data.numKetchup * weights.ketchup | |
/** | |
* Generate delta weights for the given training case and weights using a linear function | |
* @return the delta weights for the training case (as a Weights object) | |
*/ | |
def linearDeltaWeights(weights: Weights, trainingCase: LabeledData): Weights = { | |
val t = trainingCase.price | |
val y = calculatePrice(trainingCase, weights) | |
val deltaFish = learningRate * trainingCase.numFish * (t - y) | |
val deltaChips = learningRate * trainingCase.numChips * (t - y) | |
val deltaKetchup = learningRate * trainingCase.numKetchup * (t - y) | |
Weights(deltaFish, deltaChips, deltaKetchup) | |
} | |
/** | |
* Recursively train the training set for a number of iterations | |
* @param trainingSet the set to train on | |
* @param currentWeights the weights for the current iteration | |
* @param numIterations the number of times to iterate | |
* @return the weights calculated | |
*/ | |
def train(trainingSet: List[LabeledData], | |
currentWeights: Weights, | |
numIterations: Int): Weights = | |
if (numIterations == 0) { | |
/* done: return calculated weights */ | |
currentWeights | |
} else { | |
/* obtain deltas for each xi of all training cases */ | |
val listOfDeltas = for (trainingCase <- trainingSet) | |
yield linearDeltaWeights(currentWeights, trainingCase) | |
/* sum to get batch delta */ | |
val batchDelta = listOfDeltas.foldLeft(Weights(0.0, 0.0, 0.0)) { (sumDelta, delta) => | |
Weights(sumDelta.fish + delta.fish, sumDelta.chips + delta.chips, sumDelta.ketchup + delta.ketchup) | |
} | |
/* add deltas to current weights */ | |
val newWeights = Weights(currentWeights.fish + batchDelta.fish, | |
currentWeights.chips + batchDelta.chips, | |
currentWeights.ketchup + batchDelta.ketchup) | |
/* start next iteration */ | |
train(trainingSet, newWeights, numIterations - 1) | |
} | |
def evaluate(weights: Weights, testSet: List[LabeledData]): Unit = | |
for (testCase <- testSet) { | |
val y = calculatePrice(testCase, weights) | |
val t = testCase.price | |
println(s"truth: $t predicted: $y") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
see https://www.coursera.org/learn/neural-networks/lecture/bD3OB/learning-the-weights-of-a-linear-neuron-12-min