From dedd46e3d7aad7a259d6da548e0f9c1d51dbec08 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Fri, 8 Nov 2019 15:43:47 -0600 Subject: [PATCH 1/9] Initial implementation of training and inference benchmarks. --- .gitignore | 4 + Benchmarks/Benchmark.swift | 102 ++++++++++++++++++++++++ Benchmarks/Models/Benchmark-LeNet.swift | 51 ++++++++++++ Benchmarks/main.swift | 9 +++ Package.swift | 8 +- 5 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 Benchmarks/Benchmark.swift create mode 100644 Benchmarks/Models/Benchmark-LeNet.swift create mode 100644 Benchmarks/main.swift diff --git a/.gitignore b/.gitignore index 4fea2e7e10e..d6435fe7a7c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ cifar-10-batches-py/ cifar-10-batches-bin/ output/ +t10k-labels-idx1-ubyte +t10k-images-idx3-ubyte +train-labels-idx1-ubyte +train-images-idx3-ubyte \ No newline at end of file diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift new file mode 100644 index 00000000000..f7462db5641 --- /dev/null +++ b/Benchmarks/Benchmark.swift @@ -0,0 +1,102 @@ +import Foundation + +protocol BenchmarkResults: CustomStringConvertible { + var description: String { get } +} + +struct TrainingBenchmarkResults: BenchmarkResults { + let iterations: Int + let averageTime: Double + let standardDeviation: Double + + var description: String { + get { + return """ + \tAfter \(iterations) iterations: + \tAverage: \(averageTime) ms, standard deviation: \(standardDeviation) ms + """ + } + } +} + +struct InferenceBenchmarkResults: BenchmarkResults { + let iterations: Int + let samplesPerSecond: Double + let standardDeviation: Double + + var description: String { + get { + return """ + \tAfter \(iterations) iterations: + \tSamples per second: \(samplesPerSecond), standard deviation: \(standardDeviation) + """ + } + } +} + +func timeExecution(_ operation: () -> Void) -> Double { + var startTime = timeval() + gettimeofday(&startTime, nil) + + operation() + + var endTime = timeval() + gettimeofday(&endTime, nil) + return ( + Double( + (endTime.tv_sec - startTime.tv_sec) * 1000 + (endTime.tv_usec - startTime.tv_usec) + / 1000) + ) +} + +func statistics(for values: [Double]) -> (average: Double, standardDeviation: Double) { + guard values.count > 0 else { return (average: 0.0, standardDeviation: 0.0) } + guard values.count > 1 else { return (average: values.first!, standardDeviation: 0.0) } + + let average = (values.reduce(0.0) { $0 + $1 }) / Double(values.count) + + let standardDeviation = sqrt( + values.reduce(0.0) { $0 + ($1 - average) * ($1 - average) } + / Double(values.count - 1)) + + return (average: average, standardDeviation: standardDeviation) +} + +func benchmarkTraining(iterations: Int, operation: () -> Void, callback: (BenchmarkResults) -> Void) +{ + var timings: [Double] = [] + for _ in 0.. Void, operation: () -> Void, + callback: (BenchmarkResults) -> Void +) { + setup(batches, batchSize) + + var timings: [Double] = [] + for _ in 0.. (BenchmarkResults) -> Void { + return { results in + print("Benchmark: \(name):") + print("\(results)") + } +} diff --git a/Benchmarks/Models/Benchmark-LeNet.swift b/Benchmarks/Models/Benchmark-LeNet.swift new file mode 100644 index 00000000000..32ccc78e331 --- /dev/null +++ b/Benchmarks/Models/Benchmark-LeNet.swift @@ -0,0 +1,51 @@ +import TensorFlow +import Datasets +import ImageClassificationModels + +final class LeNetBenchmark { + let epochs: Int + let batchSize: Int + let dataset: MNIST + var inferenceModel: LeNet! + var inferenceImages: Tensor! + var batches: Int! + var inferenceBatches: Int! + + init(epochs: Int, batchSize: Int) { + self.epochs = epochs + self.batchSize = batchSize + self.dataset = MNIST(batchSize: batchSize) + } + + func performTraining() { + var model = LeNet() + let optimizer = SGD(for: model, learningRate: 0.1) + + Context.local.learningPhase = .training + for _ in 1...epochs { + for i in 0.. Tensor in + let ŷ = model(x) + return softmaxCrossEntropy(logits: ŷ, labels: y) + } + optimizer.update(&model, along: 𝛁model) + } + } + } + + func setupInference(batches: Int, batchSize: Int) { + inferenceBatches = batches + inferenceModel = LeNet() + inferenceImages = Tensor( + randomNormal: [batchSize, 28, 28, 1], mean: Tensor(0.5), + standardDeviation: Tensor(0.1), seed: (0xffeffe, 0xfffe)) + } + + func performInference() { + for _ in 0.. Date: Fri, 8 Nov 2019 16:05:23 -0600 Subject: [PATCH 2/9] Resolved a typechecker issue. --- Benchmarks/Benchmark.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index f7462db5641..86821d45ca8 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -42,11 +42,9 @@ func timeExecution(_ operation: () -> Void) -> Double { var endTime = timeval() gettimeofday(&endTime, nil) - return ( - Double( - (endTime.tv_sec - startTime.tv_sec) * 1000 + (endTime.tv_usec - startTime.tv_usec) - / 1000) - ) + let secondsPortion = (endTime.tv_sec - startTime.tv_sec) * 1000 + let microsecondsPortion = Int((endTime.tv_usec - startTime.tv_usec) / 1000) + return Double(secondsPortion + microsecondsPortion) } func statistics(for values: [Double]) -> (average: Double, standardDeviation: Double) { From e3ccb233c5b08f0f2e758e97cc1563119555307e Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Fri, 8 Nov 2019 16:21:19 -0600 Subject: [PATCH 3/9] Added a Readme. --- Benchmarks/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Benchmarks/README.md diff --git a/Benchmarks/README.md b/Benchmarks/README.md new file mode 100644 index 00000000000..18e6c352f5b --- /dev/null +++ b/Benchmarks/README.md @@ -0,0 +1,22 @@ +# Model benchmarks + +Eventually, these will contain a series of benchmarks against a variety of models in the +swift-models repository. The following benchmarks have been implemented: + +- Training LeNet against the MNIST dataset +- Performing inference with LeNet using MNIST-sized random images + +These benchmarks should provide a baseline to judge performance improvements and regressions in +Swift for TensorFlow. + +## Running benchmarks + +To begin, you'll need the [latest version of Swift for +TensorFlow](https://github.com/tensorflow/swift/blob/master/Installation.md) +installed. Make sure you've added the correct version of `swift` to your path. + +To run all benchmarks, type the following while in the swift-models directory: + +```sh +swift run -c release Benchmarks +``` \ No newline at end of file From 442738514d84d025c4812200ebfc33df6c4d50fa Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Fri, 8 Nov 2019 16:31:26 -0600 Subject: [PATCH 4/9] Added copyright headers. --- Benchmarks/Benchmark.swift | 14 ++++++++++++++ Benchmarks/Models/Benchmark-LeNet.swift | 14 ++++++++++++++ Benchmarks/main.swift | 14 ++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index 86821d45ca8..f7db20c3325 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -1,3 +1,17 @@ +// Copyright 2019 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import Foundation protocol BenchmarkResults: CustomStringConvertible { diff --git a/Benchmarks/Models/Benchmark-LeNet.swift b/Benchmarks/Models/Benchmark-LeNet.swift index 32ccc78e331..ecd5645899e 100644 --- a/Benchmarks/Models/Benchmark-LeNet.swift +++ b/Benchmarks/Models/Benchmark-LeNet.swift @@ -1,3 +1,17 @@ +// Copyright 2019 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import TensorFlow import Datasets import ImageClassificationModels diff --git a/Benchmarks/main.swift b/Benchmarks/main.swift index 1031959bc1f..b56970ed558 100644 --- a/Benchmarks/main.swift +++ b/Benchmarks/main.swift @@ -1,3 +1,17 @@ +// Copyright 2019 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // LeNet-MNIST let leNetBenchmark = LeNetBenchmark(epochs: 1, batchSize: 128) benchmarkTraining( From f12060cd2edf00f172eb13095f6103b91b624490 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Tue, 12 Nov 2019 15:10:30 -0600 Subject: [PATCH 5/9] Reworked the benchmarking functions to use a single function that is specialized via enums. --- Benchmarks/Benchmark.swift | 125 ++++++++++++------------ Benchmarks/Models/Benchmark-LeNet.swift | 7 +- Benchmarks/main.swift | 15 +-- 3 files changed, 75 insertions(+), 72 deletions(-) diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index f7db20c3325..55187b0e032 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -14,53 +14,82 @@ import Foundation -protocol BenchmarkResults: CustomStringConvertible { - var description: String { get } -} +struct BenchmarkResults: CustomStringConvertible { + enum BenchmarkResultType { + case inference(samplesPerSecond: Double, standardDeviation: Double) + case training(averageTime: Double, standardDeviation: Double) + } -struct TrainingBenchmarkResults: BenchmarkResults { + let name: String let iterations: Int - let averageTime: Double - let standardDeviation: Double + let result: BenchmarkResultType var description: String { - get { + switch result { + case let .inference(samplesPerSecond, standardDeviation): return """ - \tAfter \(iterations) iterations: - \tAverage: \(averageTime) ms, standard deviation: \(standardDeviation) ms + Benchmark: \(name): + \tAfter \(iterations) iterations: + \tSamples per second: \(samplesPerSecond), standard deviation: \(standardDeviation) + """ + case let .training(averageTime, standardDeviation): + return """ + Benchmark: \(name): + \tAfter \(iterations) iterations: + \tAverage: \(averageTime) ms, standard deviation: \(standardDeviation) ms """ } } } -struct InferenceBenchmarkResults: BenchmarkResults { - let iterations: Int - let samplesPerSecond: Double - let standardDeviation: Double +enum BenchmarkVariety { + case inferenceThroughput(batches: Int, batchSize: Int) + case trainingTime - var description: String { - get { - return """ - \tAfter \(iterations) iterations: - \tSamples per second: \(samplesPerSecond), standard deviation: \(standardDeviation) - """ + func interpretTiming(_ timing: Double) -> Double { + switch self { + case let .inferenceThroughput(batches, batchSize): + return Double(batches * batchSize) / (timing / 1000.0) + case .trainingTime: + return timing } } } -func timeExecution(_ operation: () -> Void) -> Double { - var startTime = timeval() - gettimeofday(&startTime, nil) +/// Performs the specified benchmark over a certain number of iterations and provides the result to a callback function. +func benchmark( + name: String, + iterations: Int, variety: BenchmarkVariety, setup: ((BenchmarkVariety) -> Void)? = nil, + operation: () -> Void, + callback: (BenchmarkResults) -> Void +) { + setup?(variety) - operation() + var timings: [Double] = [] + for _ in 0.. Void) -> Double { + let divisor: Double = 1_000_000 + let start = Double(DispatchTime.now().uptimeNanoseconds) / divisor + body() + let end = Double(DispatchTime.now().uptimeNanoseconds) / divisor + let elapsed = end - start + return elapsed +} + +/// Provides the average and standard deviation of an array of values. func statistics(for values: [Double]) -> (average: Double, standardDeviation: Double) { guard values.count > 0 else { return (average: 0.0, standardDeviation: 0.0) } guard values.count > 1 else { return (average: values.first!, standardDeviation: 0.0) } @@ -74,41 +103,7 @@ func statistics(for values: [Double]) -> (average: Double, standardDeviation: Do return (average: average, standardDeviation: standardDeviation) } -func benchmarkTraining(iterations: Int, operation: () -> Void, callback: (BenchmarkResults) -> Void) -{ - var timings: [Double] = [] - for _ in 0.. Void, operation: () -> Void, - callback: (BenchmarkResults) -> Void -) { - setup(batches, batchSize) - - var timings: [Double] = [] - for _ in 0.. (BenchmarkResults) -> Void { - return { results in - print("Benchmark: \(name):") - print("\(results)") - } +// This is a simple callback function example that only logs the result to the console. +func logResults(results: BenchmarkResults) { + print("\(results)") } diff --git a/Benchmarks/Models/Benchmark-LeNet.swift b/Benchmarks/Models/Benchmark-LeNet.swift index ecd5645899e..30db537ada3 100644 --- a/Benchmarks/Models/Benchmark-LeNet.swift +++ b/Benchmarks/Models/Benchmark-LeNet.swift @@ -49,7 +49,12 @@ final class LeNetBenchmark { } } - func setupInference(batches: Int, batchSize: Int) { + func setupInference(_ parameters: BenchmarkVariety) { + guard case let .inferenceThroughput(batches, batchSize) = parameters else { + fatalError( + "Passed the wrong kind of benchmark variety into this setup function: \(parameters)." + ) + } inferenceBatches = batches inferenceModel = LeNet() inferenceImages = Tensor( diff --git a/Benchmarks/main.swift b/Benchmarks/main.swift index b56970ed558..bcc6bdbca96 100644 --- a/Benchmarks/main.swift +++ b/Benchmarks/main.swift @@ -14,10 +14,13 @@ // LeNet-MNIST let leNetBenchmark = LeNetBenchmark(epochs: 1, batchSize: 128) -benchmarkTraining( - iterations: 10, operation: leNetBenchmark.performTraining, - callback: logResults(name: "LeNet-MNIST (training)")) -benchmarkInference( - iterations: 10, batches: 1000, batchSize: 1, setup: leNetBenchmark.setupInference, +benchmark( + name: "LeNet-MNIST (training)", + iterations: 10, variety: .trainingTime, operation: leNetBenchmark.performTraining, + callback: logResults) +benchmark( + name: "LeNet-MNIST (inference)", + iterations: 10, variety: .inferenceThroughput(batches: 1000, batchSize: 1), + setup: leNetBenchmark.setupInference, operation: leNetBenchmark.performInference, - callback: logResults(name: "LeNet-MNIST (inference)")) + callback: logResults) From 9bbe85314e58b55d8adfe3a910ee8d9dd5a3132e Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Tue, 12 Nov 2019 17:46:09 -0600 Subject: [PATCH 6/9] Reworked the model-specific benchmark into general inference and training cases that can work on arbitrary image classification models. --- Benchmarks/Benchmark.swift | 4 +- .../Models/ImageClassificationInference.swift | 53 +++++++++++++++++++ ...wift => ImageClassificationTraining.swift} | 36 +++---------- Benchmarks/main.swift | 11 ++-- 4 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 Benchmarks/Models/ImageClassificationInference.swift rename Benchmarks/Models/{Benchmark-LeNet.swift => ImageClassificationTraining.swift} (62%) diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index 55187b0e032..601f42a02fe 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -59,12 +59,10 @@ enum BenchmarkVariety { /// Performs the specified benchmark over a certain number of iterations and provides the result to a callback function. func benchmark( name: String, - iterations: Int, variety: BenchmarkVariety, setup: ((BenchmarkVariety) -> Void)? = nil, + iterations: Int, variety: BenchmarkVariety, operation: () -> Void, callback: (BenchmarkResults) -> Void ) { - setup?(variety) - var timings: [Double] = [] for _ in 0.., Output == Tensor { + init() +} + +extension LeNet: ImageClassificationModel {} + +class ImageClassificationInference where Model: ImageClassificationModel { + // TODO: (https://github.com/tensorflow/swift-models/issues/206) Datasets should have a common + // interface to allow for them to be interchangeable in these benchmark cases. + let dataset: MNIST + var model: Model + let images: Tensor + let batches: Int + let batchSize: Int + + init(batches: Int, batchSize: Int, images: Tensor? = nil) { + self.batches = batches + self.batchSize = batchSize + self.dataset = MNIST(batchSize: batchSize) + self.model = Model() + if let providedImages = images { + self.images = providedImages + } else { + self.images = Tensor( + randomNormal: [batchSize, 28, 28, 1], mean: Tensor(0.5), + standardDeviation: Tensor(0.1), seed: (0xffeffe, 0xfffe)) + } + } + + func performInference() { + for _ in 0.. +where Model: ImageClassificationModel, Model.TangentVector.VectorSpaceScalar == Float { + // TODO: (https://github.com/tensorflow/swift-models/issues/206) Datasets should have a common + // interface to allow for them to be interchangeable in these benchmark cases. + let dataset: MNIST let epochs: Int let batchSize: Int - let dataset: MNIST - var inferenceModel: LeNet! - var inferenceImages: Tensor! - var batches: Int! - var inferenceBatches: Int! init(epochs: Int, batchSize: Int) { self.epochs = epochs @@ -31,8 +29,9 @@ final class LeNetBenchmark { self.dataset = MNIST(batchSize: batchSize) } - func performTraining() { - var model = LeNet() + func train() { + var model = Model() + // TODO: Split out the optimizer as a separate specification. let optimizer = SGD(for: model, learningRate: 0.1) Context.local.learningPhase = .training @@ -48,23 +47,4 @@ final class LeNetBenchmark { } } } - - func setupInference(_ parameters: BenchmarkVariety) { - guard case let .inferenceThroughput(batches, batchSize) = parameters else { - fatalError( - "Passed the wrong kind of benchmark variety into this setup function: \(parameters)." - ) - } - inferenceBatches = batches - inferenceModel = LeNet() - inferenceImages = Tensor( - randomNormal: [batchSize, 28, 28, 1], mean: Tensor(0.5), - standardDeviation: Tensor(0.1), seed: (0xffeffe, 0xfffe)) - } - - func performInference() { - for _ in 0..(epochs: 1, batchSize: 128) benchmark( name: "LeNet-MNIST (training)", - iterations: 10, variety: .trainingTime, operation: leNetBenchmark.performTraining, + iterations: 10, variety: .trainingTime, operation: leNetTrainingBenchmark.train, callback: logResults) + +let leNetInferenceBenchmark = ImageClassificationInference(batches: 1000, batchSize: 1) benchmark( name: "LeNet-MNIST (inference)", iterations: 10, variety: .inferenceThroughput(batches: 1000, batchSize: 1), - setup: leNetBenchmark.setupInference, - operation: leNetBenchmark.performInference, + operation: leNetInferenceBenchmark.performInference, callback: logResults) From 7e810562061eaaa140aa62459f655fb1103a9be6 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Wed, 13 Nov 2019 14:11:47 -0600 Subject: [PATCH 7/9] Restructured BenchmarkResults to be a plain collection of timings, with specific benchmark processing working on that. --- .gitignore | 2 +- Benchmarks/Benchmark.swift | 69 ++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index d6435fe7a7c..87b5aaff3b9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,4 @@ output/ t10k-labels-idx1-ubyte t10k-images-idx3-ubyte train-labels-idx1-ubyte -train-images-idx3-ubyte \ No newline at end of file +train-images-idx3-ubyte diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index 601f42a02fe..b20da7d7cf6 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -14,44 +14,25 @@ import Foundation -struct BenchmarkResults: CustomStringConvertible { - enum BenchmarkResultType { - case inference(samplesPerSecond: Double, standardDeviation: Double) - case training(averageTime: Double, standardDeviation: Double) - } +enum BenchmarkVariety { + case inferenceThroughput(batches: Int, batchSize: Int) + case trainingTime +} +struct BenchmarkResults { let name: String let iterations: Int - let result: BenchmarkResultType - - var description: String { - switch result { - case let .inference(samplesPerSecond, standardDeviation): - return """ - Benchmark: \(name): - \tAfter \(iterations) iterations: - \tSamples per second: \(samplesPerSecond), standard deviation: \(standardDeviation) - """ - case let .training(averageTime, standardDeviation): - return """ - Benchmark: \(name): - \tAfter \(iterations) iterations: - \tAverage: \(averageTime) ms, standard deviation: \(standardDeviation) ms - """ - } - } + let timings: [Double] + let variety: BenchmarkVariety } -enum BenchmarkVariety { - case inferenceThroughput(batches: Int, batchSize: Int) - case trainingTime - - func interpretTiming(_ timing: Double) -> Double { - switch self { +extension BenchmarkResults { + func interpretTimings() -> [Double] { + switch self.variety { case let .inferenceThroughput(batches, batchSize): - return Double(batches * batchSize) / (timing / 1000.0) + return timings.map { Double(batches * batchSize) / ($0 / 1000.0) } case .trainingTime: - return timing + return timings } } } @@ -66,13 +47,12 @@ func benchmark( var timings: [Double] = [] for _ in 0.. (average: Double, standardDeviation: Do } // This is a simple callback function example that only logs the result to the console. -func logResults(results: BenchmarkResults) { - print("\(results)") +func logResults(_ result: BenchmarkResults) { + let (average, standardDeviation) = statistics(for: result.interpretTimings()) + + switch result.variety { + case .inferenceThroughput: + print( + """ + Benchmark: \(result.name): + \tAfter \(result.iterations) iterations: + \tSamples per second: \(String(format: "%.2f", average)), standard deviation: \(String(format: "%.2f", standardDeviation)) + """) + case .trainingTime: + print( + """ + Benchmark: \(result.name): + \tAfter \(result.iterations) iterations: + \tAverage: \(String(format: "%.2f", average)) ms, standard deviation: \(String(format: "%.2f", standardDeviation)) ms + """) + } } From 7f86bf5817b053eb583525d562da69c0791e31a5 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Thu, 14 Nov 2019 07:28:12 -0600 Subject: [PATCH 8/9] Rename interpretTimings to interpretedTimings. Co-Authored-By: Dan Zheng --- Benchmarks/Benchmark.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index b20da7d7cf6..bf6a045c38d 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -27,7 +27,7 @@ struct BenchmarkResults { } extension BenchmarkResults { - func interpretTimings() -> [Double] { + var interpretedTimings: [Double] { switch self.variety { case let .inferenceThroughput(batches, batchSize): return timings.map { Double(batches * batchSize) / ($0 / 1000.0) } From 686ee222cca52208c39a0494f53f520231fc7356 Mon Sep 17 00:00:00 2001 From: Brad Larson Date: Thu, 14 Nov 2019 07:38:57 -0600 Subject: [PATCH 9/9] Change reference to interpretedTimings later. --- Benchmarks/Benchmark.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Benchmarks/Benchmark.swift b/Benchmarks/Benchmark.swift index bf6a045c38d..d50f9babd3a 100644 --- a/Benchmarks/Benchmark.swift +++ b/Benchmarks/Benchmark.swift @@ -83,7 +83,7 @@ func statistics(for values: [Double]) -> (average: Double, standardDeviation: Do // This is a simple callback function example that only logs the result to the console. func logResults(_ result: BenchmarkResults) { - let (average, standardDeviation) = statistics(for: result.interpretTimings()) + let (average, standardDeviation) = statistics(for: result.interpretedTimings) switch result.variety { case .inferenceThroughput: