def read_result_to_ndarray(pixels, width, height, metadata, grayscale, as_uint16, num_channels): if metadata["bitdepth"] == 16 and not as_uint16: raise ValueError("cannot convert 16bit image to 8bit image." " Original range of pixel values is unknown.") output_type = np.uint16 if as_uint16 else np.uint8 img = np.asarray(list(pixels), output_type) if metadata["bitdepth"] == 8 and as_uint16: logger.warning("You want to read image as uint16, but the original bit-depth is 8 bit." "All pixel values are simply increased by 256 times.") img *= 256 # shape is (height, width * planes), planes = 1 (gray), 3 (rgb) or 4 (rgba) if not metadata["greyscale"]: # read image is rgb or rgba img = img.reshape((height, width, -1)) if grayscale: img = PngBackend.rgb2gray(img).astype(output_type) img = PngBackend.convert_num_channles(img, num_channels) return img
def create_communicator(ignore_error=False, extension_module='cudnn', type_config='float'): global _current_communicator if os.environ.get('OMPI_COMM_WORLD_SIZE') is not None: from nnabla.ext_utils import get_extension_context context = get_extension_context(extension_module, type_config=type_config) try: logger.log(99, 'Create communicator with contexts {}'.format(context)) _current_communicator = C.MultiProcessCommunicator(context) _current_communicator.init() context.device_id = str(_current_communicator.rank % _current_communicator.size) if _current_communicator.size == 1: _current_communicator = None except: if not ignore_error: raise logger.warning("Failed to initialize nnabla.communicators.") _current_communicator = None else: _current_communicator = None return _current_communicator
def imsave(self, path, img, channel_first=False, as_uint16=False, auto_scale=True): """ Save image by pillow module. Currently, pillow supports only uint8 to save. Args: path (str): output filename img (numpy.ndarray): Image array to save. Image shape is considered as (height, width, channel) by default. channel_first (bool): This argument specifies the shape of img is whether (height, width, channel) or (channel, height, width). Default value is False, which means the img shape is considered as (height, width, channel) as_uint16 (bool): In this backend, this argument is always False because pillow dose not support uint16. If True, exception will be raised. auto_scale (bool) : Whether upscale pixel values or not. If you want to save float image, this argument must be True. In pillow backend, only float ([0, 1]) to uint8 ([0, 255]) is supported. """ img = _imsave_before(img, channel_first, auto_scale) if img.dtype == np.uint16 or as_uint16: logger.warning("Pillow only supports uint8 image to save. Cast img to uint8." "If you want to save image as uint16, install pypng or cv2 " "and nnabla.utils.image_utils automatically change backend to use these module.") return self.next_available(path).imsave(path, img, channel_first=channel_first, as_uint16=as_uint16, auto_scale=auto_scale) if auto_scale and img.dtype != np.uint8: img = (img * 255).astype(np.uint8) if len(img.shape) == 3 and img.shape[-1] == 1: img = np.squeeze(img, axis=-1) Image.fromarray(img).save(path)
def imread(self, path, grayscale=False, size=None, interpolate="bilinear", channel_first=False, as_uint16=False, num_channels=-1): """ Read image by pypng module. Args: path (str or 'file object'): File path or object to read. grayscale (bool): size (tupple of int): (width, height). If None, output img shape depends on the files to read. channel_first (bool): This argument specifies the shape of img is whether (height, width, channel) or (channel, height, width). Default value is False, which means the img shape is (height, width, channel). interpolate (str): must be one of ["nearest", "box", "bilinear", "hamming", "bicubic", "lanczos"]. as_uint16 (bool): If True, this function reads image as uint16. num_channels (int): channel size of output array. Default is -1 which preserves raw image shape. Returns: numpy.ndarray """ _imread_before(grayscale, num_channels) f = path if hasattr(path, "read") else open(path, "rb") r = png.Reader(file=f) width, height, pixels, metadata = r.asDirect() bit_depth = metadata.get("bitdepth") if bit_depth not in [8, 16]: logger.warning( "The bit-depth of the image you want to read is unsupported ({}bit)." "Currently, pypng backend`s imread supports only [8, 16] bit-depth." "the path for this image is {}".format(bit_depth, path)) return self.next_available(path).imread( path, grayscale=grayscale, size=size, interpolate=interpolate, channel_first=channel_first, as_uint16=as_uint16, num_channels=num_channels) img = self.read_result_to_ndarray(pixels, width, height, metadata, grayscale, as_uint16, num_channels) return _imread_after(img, size, interpolate, channel_first, self.imresize)
def imread(self, path, grayscale=False, size=None, interpolate="bilinear", channel_first=False, as_uint16=False, num_channels=-1, return_palette_indices=False): """ Read image by PIL module. Notice that PIL only supports uint8 for RGB (not uint16). So this imread function returns only uint8 array for both RGB and gray-scale. (Currently ignore "I" mode for gray-scale (32bit integer).) Args: path (str or 'file object'): File path or object to read. grayscale (bool): size (tupple of int): (width, height). If None, output img shape depends on the files to read. channel_first (bool): This argument specifies the shape of img is whether (height, width, channel) or (channel, height, width). Default value is False, which means the img shape is (height, width, channel). interpolate (str): must be one of ["nearest", "box", "bilinear", "hamming", "bicubic", "lanczos"]. as_uint16 (bool): If you specify this argument, you can use only False for pil backend. num_channels (int): channel size of output array. Default is -1 which preserves raw image shape. return_palette_indices (bool): Whether to return a raw palette indices without any conversion or not. If this flag is True and read Image has the mode "P", then this function returns 2-D array containing the indices into palette. We recommend that this flag should be False unless you intend to use the raw palette indices. Returns: numpy.ndarray """ if as_uint16: logger.warning("pillow only supports uint8 for RGB image." " If you want to load image as uint16," " install pypng or cv2 and" " nnabla.utils.image_utils automatically change backend to use these module.") return self.next_available(path).imread(path, grayscale=grayscale, size=size, interpolate=interpolate, channel_first=channel_first, as_uint16=as_uint16, num_channels=num_channels) _imread_before(grayscale, num_channels) pil_img = Image.open(path, mode="r") try: img = self.pil_image_to_ndarray( pil_img, grayscale, num_channels, return_palette_indices) except: return self.next_available(path).imread(path, grayscale=grayscale, size=size, interpolate=interpolate, channel_first=channel_first, as_uint16=as_uint16, num_channels=num_channels) return _imread_after(img, size, interpolate, channel_first, self.imresize)
def check_type_and_cast_if_necessary(img, as_uint16): if not as_uint16 and img.dtype == np.uint16: raise ValueError("Input img type is uint16, but as_uint16 is False." " If you want to save img as uint8, be sure all pixel values are in the range of [0, 255]" " and cast it before you call imsave function.") if as_uint16 and img.dtype != np.uint16: # in the case of as_uint16 is True and upscale is False. Save uint8 as uint16 without scaling. logger.warning( "Save image as uint16, but the original input image type is not uint16") img = np.asarray(img, np.uint16) return img
def imread(path, grayscale=False, size=None, interpolate="bilinear", channel_first=False, as_uint16=False, num_channels=-1): """ Read image by cv2 module. Args: path (str or 'file object'): File path or object to read. grayscale (bool): size (tupple of int): (width, height). If None, output img shape depends on the files to read. channel_first (bool): This argument specifies the shape of img is whether (height, width, channel) or (channel, height, width). Default value is False, which means the img shape is (height, width, channel). interpolate (str): must be one of ["nearest", "bilinear", "bicubic", "lanczos"]. as_uint16 (bool): If True, this function reads image as uint16. num_channels (int): channel size of output array. Default is -1 which preserves raw image shape. Returns: numpy.ndarray """ _imread_before(grayscale, num_channels) r_mode = cv2.IMREAD_GRAYSCALE if grayscale else cv2.IMREAD_UNCHANGED img = _imread_helper(path, r_mode) if as_uint16 and img.dtype != np.uint16: if img.dtype == np.uint8: logger.warning( "You want to read image as uint16, but the original bit-depth is 8 bit." "All pixel values are simply increased by 256 times.") img = img.astype(np.uint16) * 256 else: raise ValueError("casting {} to uint16 is not safe.".format( img.dtype)) img = _cvtColor_helper(img, num_channels) img = _imread_after(img, size, interpolate, channel_first, imresize) return img
def imread(path, grayscale=False, size=None, interpolate="bilinear", channel_first=False, as_uint16=False, num_channels=-1): """ Read image by pydicom module. Before using pydicom module, opencv needs to be installed. Args: path (str or 'file object'): File path or object to read. grayscale (bool): size (tupple of int): (width, height). If None, output img shape depends on the files to read. channel_first (bool): This argument specifies the shape of img is whether (height, width, channel) or (channel, height, width). Default value is False, which means the img shape is (height, width, channel). interpolate (str): must be one of ["nearest", "bilinear", "bicubic", "lanczos"]. as_uint16 (bool): If you specify this argument, you can use only False for pil backend. num_channels (int): channel size of output array. Default is -1 which preserves raw image shape. Returns: numpy.ndarray """ _imread_before(grayscale, num_channels) dicom_dataset = pydicom.dcmread(path) img = dicom_dataset.pixel_array if as_uint16 and img.dtype != np.uint16: if img.dtype == np.uint8: logger.warning( "You want to read image as uint16, but the original bit-depth is 8 bit." "All pixel values are simply increased by 256 times.") img = img.astype(np.uint16) * 256 else: raise ValueError("casting {} to uint16 is not safe.".format( img.dtype)) if num_channels == -1 and grayscale: num_channels = 0 img = _cvtColor_helper(img, num_channels) return _imread_after(img, size, interpolate, channel_first, imresize)
def create_communicator(ignore_error=False): global _current_communicator from nnabla.ext_utils import get_extension_context extension_module = "cudnn" context = get_extension_context(extension_module) try: logger.log(99, 'Create communicator with contexts {}'.format(context)) _current_communicator = C.MultiProcessCommunicator(context) _current_communicator.init() context.device_id = str(_current_communicator.rank % _current_communicator.size) if _current_communicator.size == 1: _current_communicator = None except: if not ignore_error: raise logger.warning("Failed to initialize nnabla.communicators.") _current_communicator = None return _current_communicator
def predict(self, graph): self._visitor.reset() graph.visit(self._visitor) flops = 0 for func in self._visitor._functions: args = [func.info.type_name] + \ [str(inp.shape) for inp in func.inputs] + \ [str(func.info.args)] key = '-'.join(args) ff = getattr(F, func.info.type_name)(get_current_context(), **func.info.args) if key not in self.memo: try: # run profiler nnabla_vars = [ nn.Variable(inp.shape, need_grad=inp.need_grad) for inp in func.inputs ] runner = Profiler( ff(*nnabla_vars), device_id=self._device_id, ext_name=self._ext_name, n_run=self._n_run, outlier=self._outlier, max_measure_execution_time=self. _max_measure_execution_time, # noqa: E501 time_scale=self._time_scale, n_warmup=self._n_warmup) runner.run() latency = float(runner.result['forward_all']) except Exception as err: latency = 0 logger.warning(f'Latency calculation failed: {key}') logger.warning(str(err)) self.memo[key] = latency flops += self.memo[key] return flops
def _get_analysis(self, comm): def _analyse_gpu_cost_time(result, threshold): aver = np.mean(result, axis=0)[1] _node_l = [*filter(lambda n: n[1] > aver * threshold, result)] if len(_node_l): ranks = ', '.join([str(int(n[0])) for n in _node_l]) _str = ('Gpu of Rank {} ran slower than average ' 'by a factor of {} or more'.format(ranks, threshold)) return _str return '' result = self._reap_multinode_data(comm) if comm.rank == 0: error_str = _analyse_gpu_cost_time(result, self._error_threshold) if error_str: logger.error(error_str) raise Exception(error_str) else: warning_str = _analyse_gpu_cost_time(result, self._warning_threshold) if warning_str: logger.warning(warning_str)
def predict(self, module): """Returns the estimation of a single module""" idm = str(module) if idm not in self.memo: self.memo[idm] = dict() mem = self.memo[idm] key = '-'.join([str(k[1:]) for k in module.input_shapes]) if key not in mem: state = module.training module.apply(training=False) # turn off training try: # run profiler nnabla_vars = [ nn.Variable((1, ) + s[1:]) for s in module.input_shapes ] runner = Profiler( module.call(*nnabla_vars), device_id=self._device_id, ext_name=self._ext_name, n_run=self._n_run, outlier=self._outlier, max_measure_execution_time=self. _max_measure_execution_time, # noqa: E501 time_scale=self._time_scale, n_warmup=self._n_warmup) runner.run() latency = float(runner.result['forward_all']) except Exception as err: latency = 0 logger.warning(f'Latency calculation fails: {idm}[{key}]') logger.warning(str(err)) mem[key] = latency module.apply(training=state) # recover training state return mem[key]
def load_checkpoint(path, solvers): """Given the checkpoint file, loads the parameters and solver states. Args: path: Path to the checkpoint file. solvers: A dictionary about solver's info, which is like; solvers = {"identifier_for_solver_0": solver_0, {"identifier_for_solver_1": solver_1, ...} The keys are used for retrieving proper info from the checkpoint. so must be the same as the one used when saved. Also, you can give a solver object if only one solver exists. Then, the "" is used as an identifier. Returns: current_iter: The number of iteretions that the training resumes from. Note that this assumes that the numbers of the update for each solvers is the same. Examples: # Create computation graph with parameters. pred = construct_pred_net(input_Variable, ...) # Create solver and set parameters. solver = S.Adam(learning_rate) solver.set_parameters(nn.get_parameters()) # AFTER setting parameters. start_point = load_checkpoint(path, solver) # Training loop. Notes: It requires the checkpoint file. For details, refer to save_checkpoint; checkpoint_1000 = { "":{ "states_path": <path to the states file> "params_names":["conv1/conv/W", ...], "num_update":1000 }, "current_iter": 1000 } If you have multiple solvers. checkpoint_1000 = { "generator":{ "states_path": <path to the states file>, "params_names":["deconv1/conv/W", ...], "num_update":1000 }, "discriminator":{ "states_path": <path to the states file>, "params_names":["conv1/conv/W", ...], "num_update":1000 }, "current_iter": 1000 } """ assert os.path.isfile(path), "checkpoint file not found" with open(path, 'r') as f: checkpoint_info = json.load(f) if isinstance(solvers, nn.solver.Solver): solvers = {"": solvers} logger.info("Checkpoint load (.json): {}".format(path)) # load parameters (stored in global). params_path = checkpoint_info["params_path"] assert os.path.isfile(params_path), "parameters file not found." nn.parameter.load_parameters(params_path) for solvername, solver_obj in solvers.items(): partial_info = checkpoint_info[solvername] if set(solver_obj.get_parameters().keys()) != set(partial_info["params_names"]): logger.warning("Detected parameters do not match.") # load solver states. states_path = partial_info["states_path"] assert os.path.isfile(states_path), "states file not found." # set solver states. solver_obj.load_states(states_path) # get current iteration. note that this might differ from the numbers of update. current_iter = checkpoint_info["current_iter"] return current_iter
def calc_latency_all_modules(self, path, graph, func_latency=None): """ Calculate the latency for each of the modules in a graph. The modules are extracted using the graph structure information. The latency is then calculated based on each individual module's nnabla graph. It also saves the accumulated latency of all modules. Args: path graph: func_latency: function to use to calc latency of each of the modules This function needs to work based on the graph """ import nnabla.function as Function from nnabla_nas.utils.estimator.latency import Profiler from nnabla.context import get_current_context from nnabla.logger import logger func_latency._visitor.reset() graph.visit(func_latency._visitor) total_latency = 0.0 idx = 0 for func in func_latency._visitor._functions: args = [func.info.type_name] + \ [str(inp.shape) for inp in func.inputs] + \ [str(func.info.args)] key = '-'.join(args) ff = getattr(Function, func.info.type_name)(get_current_context(), **func.info.args) if key not in func_latency.memo: try: # run profiler nnabla_vars = [ nn.Variable(inp.shape, need_grad=inp.need_grad) for inp in func.inputs ] runner = Profiler( ff(*nnabla_vars), device_id=func_latency._device_id, ext_name=func_latency._ext_name, n_run=func_latency._n_run, outlier=func_latency._outlier, max_measure_execution_time=func_latency. _max_measure_execution_time, # noqa: E501 time_scale=func_latency._time_scale, n_warmup=func_latency._n_warmup) runner.run() latency = float(runner.result['forward_all']) except Exception as err: latency = 0.0 logger.warning(f'Latency calculation failed: {key}') logger.warning(str(err)) func_latency.memo[key] = latency else: latency = func_latency.memo[key] total_latency += latency # save latency of this layer (name: id_XXX_{key}.acclat) filename = path + '/id_' + str(idx) + '_' + key + '.acclat' pathname = os.path.dirname(filename) upper_pathname = os.path.dirname(pathname) if not os.path.exists(upper_pathname): os.mkdir(upper_pathname) if not os.path.exists(pathname): os.mkdir(pathname) idx += 1 with open(filename, 'w') as f: print(latency.__str__(), file=f) # save accum latency of all layers filename = path + '.acclat' with open(filename, 'w') as f: print(total_latency.__str__(), file=f) return total_latency