'Measure runtime for computing fprop and bprop separately, as well as
full minibatch run times. For inference case, only the fprop is measured.
Arguments:
dataset (NervanaDataIterator) Dataset iterator to perform fit on
inference (bool, optional): Is inference use case
niterations (optional, int): Number of minibatches to average over
Returns:
dictionary with fprop, bprop run times'

def time(self, dataset, inference=False, niterations=20):

    if (not dataset):
        raise ValueError('Provide    correct    dataset    for    timing')
    if (niterations < 1):
        raise ValueError('Invalid    iterations    number')
    if ((inference is False) and ((self.model.cost is None) or (self.model.optimizer is None))):
        raise RuntimeError('Need    cost    or    optimizer    to    benchmark    bprop')
    times = OrderedDict()
    time_keys = (['fprop'] if inference else ['fprop', 'bprop', 'iteration'])
    for ky in time_keys:
        times[ky] = np.full(niterations, (-1.0))
    count = 0
    fprop_start = self.model.be.init_mark()
    fprop_end = self.model.be.init_mark()
    bprop_end = self.model.be.init_mark()
    while (count < niterations):
        dataset.reset()
        for (_, (x, t)) in enumerate(dataset):
            self.model.be.record_mark(fprop_start)
            x = self.model.fprop(x, inference)
            self.model.be.record_mark(fprop_end)
            if (inference is False):
                delta = self.model.cost.get_errors(x, t)
                self.model.bprop(delta)
                self.model.optimizer.optimize(self.model.layers_to_optimize, epoch=0)
                self.model.be.record_mark(bprop_end)
                self.model.be.synchronize_mark(bprop_end)
            else:
                self.model.be.synchronize_mark(fprop_end)
            times['fprop'][count] = self.model.be.get_time(fprop_start, fprop_end)
            if (inference is False):
                times['bprop'][count] = self.model.be.get_time(fprop_end, bprop_end)
                times['iteration'][count] = (times['fprop'][count] + times['bprop'][count])
            count += 1
            if (count >= niterations):
                break
    times.update(self.layer_times)
    return times
