Skip to content

Instantly share code, notes, and snippets.

@koen-dejonghe
Last active January 9, 2017 07:00
Show Gist options
  • Save koen-dejonghe/12edcca307c98c31dfeedf368c339fc8 to your computer and use it in GitHub Desktop.
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
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