blob: 947ce71c26cb4af1b9adc7c6dfc2c99fc417bf25 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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 math
import time
from abc import abstractmethod
import torch
from torch import nn
class Evaluator:
def __init__(self):
pass
@abstractmethod
def evaluate(self, arch: nn.Module,
device: str,
batch_data: object, batch_labels: torch.Tensor,
space_name: str
) -> float:
"""
Score each architecture with predefined architecture and data
:param arch: architecture to be scored
:param device: cpu or gpu
:param batch_data: a mini batch of data, [ batch_size, channel, W, H ] or dict for structure data
:param batch_labels: a mini batch of labels
:param space_name: string
:return: score
"""
raise NotImplementedError
def evaluate_wrapper(self, arch, device: str, space_name: str,
batch_data: torch.tensor,
batch_labels: torch.tensor) -> (float, float):
"""
:param arch: architecture to be scored
:param device: cpu or GPU
:param space_name: search space name
:param batch_data: a mini batch of data, [ batch_size, channel, W, H ]
:param batch_labels: a mini batch of labels
:return: score, timeUsage
"""
arch.train()
# arch.zero_grad()
# measure scoring time
if "cuda" in device:
torch.cuda.synchronize()
# use this will not need cuda.sync
# starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
# starter.record()
starter, ender = time.time(), time.time()
else:
starter, ender = time.time(), time.time()
# score
score = self.evaluate(arch, device, batch_data, batch_labels, space_name)
if "cuda" in device:
# ender.record()
# implicitly waits for the event to be marked as complete before calculating the time difference
# curr_time = starter.elapsed_time(ender)
torch.cuda.synchronize()
ender = time.time()
curr_time = ender - starter
else:
ender = time.time()
curr_time = ender - starter
if math.isnan(score):
if score > 0:
score = 1e8
else:
score = -1e8
if math.isinf(score):
if score > 0:
score = 1e8
else:
score = -1e8
return score, curr_time
def evaluate_wrapper_origin(self, arch, device: str, space_name: str,
batch_data: torch.tensor,
batch_labels: torch.tensor) -> (float, float):
"""
:param arch: architecture to be scored
:param device: cpu or GPU
:param space_name: search space name
:param batch_data: a mini batch of data, [ batch_size, channel, W, H ]
:param batch_labels: a mini batch of labels
:return: score, timeUsage
"""
arch.train()
arch.zero_grad()
# measure scoring time
if "cuda" in device:
torch.cuda.synchronize()
# use this will not need cuda.sync
# starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
# starter.record()
starter, ender = time.time(), time.time()
else:
starter, ender = time.time(), time.time()
# score
score = self.evaluate(arch, device, batch_data, batch_labels, space_name)
if "cuda" in device:
# ender.record()
# implicitly waits for the event to be marked as complete before calculating the time difference
# curr_time = starter.elapsed_time(ender)
torch.cuda.synchronize()
ender = time.time()
curr_time = ender - starter
else:
ender = time.time()
curr_time = ender - starter
if math.isnan(score):
if score > 0:
score = 1e8
else:
score = -1e8
if math.isinf(score):
if score > 0:
score = 1e8
else:
score = -1e8
return score, curr_time