def type_inference(self): x_type = self.x.dtype x_shape = list(self.x.shape) y_shape = list(self.y.shape) x_rank = len(x_shape) if x_rank == 1 and self.transpose_x.val: msg = "Op {} (matmul): x is rank 1, but transpose_x is True, which is not allowed." raise ValueError(msg.format(self.name)) if self.transpose_x.val: x_shape = list(x_shape) x_shape[-1], x_shape[-2] = x_shape[-2], x_shape[-1] x_shape = tuple(x_shape) if self.transpose_y.val: y_shape = list(y_shape) y_shape[-1], y_shape[-2] = y_shape[-2], y_shape[-1] y_shape = tuple(y_shape) if not (x_shape[-1] == y_shape[-2] or is_symbolic(x_shape[-1]) or is_symbolic(y_shape[-2])): msg = "Op {} (matmul): x {}, y {} are not broadcastable" raise ValueError(msg.format(self.name, self.x.shape, self.y.shape)) if x_rank == 1: # promote shape of x to rank 2 x_shape = list((1, ) + tuple(x_shape)) ret_shape = list(broadcast_shapes(x_shape[:-2], y_shape[:-2])) ret_shape += [x_shape[-2], y_shape[-1]] if x_rank == 1: # remove the first dimension of the returned shape return types.tensor(x_type, tuple(ret_shape[1:])) else: return types.tensor(x_type, tuple(ret_shape))
def __init__(self, shape, default=None): """ The basic shape class to be set in InputType. Attribute: shape: list of (int), symbolic values, RangeDim object The valid shape of the input default: tuple of int or None The default shape that is used for initiating the model, and set in the metadata of the model file. If None, then `shape` would be used. """ from coremltools.converters.mil.mil import get_new_symbol if not isinstance(shape, (list, tuple)): msg = "Shape should be list or tuple, got type {} instead" raise ValueError(msg.format(type(shape))) self.symbolic_shape = [] shape = list(shape) for idx, s in enumerate(shape): if s is None or s == -1: msg = 'Dimension cannot be None or -1. Use ' +\ 'ct.RangeDim for runtime determined dimension. ' +\ 'Dim {}: {} ' +\ 'See https://coremltools.readme.io/docs/flexible-inputs' raise ValueError(msg.format(idx, s)) if isinstance(s, RangeDim): sym = s.symbol self.symbolic_shape.append(sym) elif isinstance(s, (np.generic, six.integer_types)) or is_symbolic(s): self.symbolic_shape.append(s) else: raise ValueError( "Unknown type {} to build symbolic shape.".format(type(s))) self.shape = tuple(shape) if default is not None: if not isinstance(default, (list, tuple)): raise ValueError( "Default shape should be list or tuple, got type {} instead" .format(type(default))) for idx, s in enumerate(default): if not isinstance( s, (np.generic, six.integer_types)) and not is_symbolic(s): raise ValueError( "Default shape invalid, got error at index {} which is {}" .format(idx, s)) else: default = [] for idx, s in enumerate(self.shape): if isinstance(s, RangeDim): default.append(s.default) elif s is None or s == -1: default.append(self.symbolic_shape[idx]) else: default.append(s) self.default = tuple(default)
def get_cast_value(input_var, dtype_val): type_map = { "int32": np.int32, "int64": np.int64, "fp16": np.float16, "fp32": np.float32, "fp64": np.float64, "bool": np.bool, } if dtype_val not in type_map.keys(): raise NotImplementedError( "Parameter dtype of the cast operation can be one of the {}. " "Provided {}".format(type_map.keys(), dtype_val)) if input_var.val is None: if input_var.sym_val is not None and not is_symbolic( input_var.sym_val) and len(input_var.sym_val.shape) == 1: result = [ np.array(val).astype(dtype=type_map[dtype_val]).item() if not is_symbolic(val) else val for val in input_var.sym_val ] return np.array(result) return None if not types.is_tensor(input_var.sym_type): return input_var.val.astype(dtype=type_map[dtype_val]) else: return np.array(input_var.val).astype(dtype=type_map[dtype_val])
def type_inference(self): if self.x.rank != 4: raise ValueError( 'input "x" to the "resample" op must be a rank 4 tensor. ' "Got rank {} tensor of shape {}".format( self.x.rank, self.x.shape)) if self.coordinates.rank != 4: raise ValueError( 'input "coordinates" to the "resample" op must be a rank 4 tensor. ' "Got rank {} tensor of shape {}".format( self.coordinates.rank, self.coordinates.shape)) input_shape = self.x.shape coord_shape = self.coordinates.shape if (not is_symbolic(input_shape[0]) and not is_symbolic(coord_shape[0]) and input_shape[0] != coord_shape[0]): raise ValueError( 'input "x" and "coordinates" to the "resample" must agree on ' "dimension of batch size: {} vs. {}".format( input_shape[0], coord_shape[0])) if not is_symbolic(coord_shape[-1]) and coord_shape[-1] != 2: raise ValueError( 'input "coordinates" to the "resample" op last dimension must be 2. ' "Got {} for last dimension".format(coord_shape[-1])) ret_shape = list(input_shape) ret_shape[2] = coord_shape[1] # Output height ret_shape[3] = coord_shape[2] # Output width return types.tensor(self.x.dtype, tuple(ret_shape))
def type_inference(self): x_type = self.x.dtype x_shape = np.array(self.x.shape) reps = self.reps.sym_val if reps is None: out_shape = tuple([get_new_symbol() for _ in range(self.x.rank)]) return types.tensor(x_type, out_shape) if len(reps) == 0 or len(reps) > self.x.rank: msg = ("Length of the reps ({}) must be at least 1, and " "not greater than the rank of the input x ({})") raise ValueError(msg.format(len(reps), self.x.rank)) if len(reps) < self.x.rank: reps = [1] * (self.x.rank - len(reps)) + list(reps) out_shape = [] for i, rep in enumerate(reps): if not is_symbolic(rep): if rep <= 0: raise ValueError( "All entries of reps parameter must be greater than 0") if is_symbolic(rep) or is_symbolic(x_shape[i]): out_shape.append(get_new_symbol()) else: out_shape.append(rep * x_shape[i]) out_shape = tuple(out_shape) return types.tensor(x_type, out_shape)
def type_inference(self): concat_dim_len = 0 if len(self.values) == 0: raise ValueError("Concat {} got 0 values".format(self.name)) # Validate values have the same rank rank = self.values[0].rank for v in self.values: if v.rank != rank: msg = "Input {} has rank {} != other inputs rank {}" raise ValueError(msg.format(v.name, v.rank, rank)) # Check concat axis is within (-rank, rank) concat_axis = self.axis.val if concat_axis < 0: concat_axis += rank if rank > 0 and (concat_axis < 0 or concat_axis >= rank): msg = "In {} of op_type {}: axis out of bound for input " + "(rank {})" raise ValueError(msg.format(self.name, self.op_type, rank)) # Validate primitive types are compatible dtype = self.values[0].dtype for v in self.values[1:]: new_dtype = promoted_primitive_type(v.dtype, dtype) if new_dtype is None: msg = "Incompatible primitive types concat: {} vs {}" raise ValueError(msg.format(v.dtype, dtype)) dtype = new_dtype # validate that non-axis dimensions match retshape = list(self.values[0].shape) for v in self.values[1:]: for i in range(rank): if is_symbolic(retshape[i]) or is_symbolic(v.shape[i]): continue if i != concat_axis and retshape[i] != v.shape[i]: msg = 'Dimension mismatch in {} ("{}"): shapes {} vs. {}' raise ValueError( msg.format(self.op_type, self.name, retshape, v.shape) ) # Get length of concat dim concat_dim_len = 0 for v in self.values: if len(v.shape) == 0: taxis = 1 else: taxis = v.shape[concat_axis] if is_symbolic(taxis): concat_dim_len = get_new_symbol() break concat_dim_len += taxis if len(retshape) == 0: retshape = [concat_dim_len] else: retshape[concat_axis] = concat_dim_len return types.tensor(dtype, retshape)
def __init__(self, shapes, default=None): """ A shape class that is used for setting multiple valid shape in InputType. Parameters ---------- shapes: list of Shape objects, or Shape-compatible lists. The valid shapes of the inputs. If input provided is not Shape object, but can be converted to Shape, the Shape object would be stored in ``shapes`` instead. default: tuple of int or None The default shape that is used for initiating the model, and set in the metadata of the model file. If None, then the first element in ``shapes`` is used. """ from coremltools.converters.mil.mil import get_new_symbol if not isinstance(shapes, (list, tuple)): raise ValueError( "EnumeratedShapes should be list or tuple of shape, got type {} instead" .format(type(shapes))) if len(shapes) < 2: raise ValueError( "EnumeratedShapes should be take a list or tuple with len >= 2, got {} instead" .format(len(shapes))) self.shapes = [] for idx, s in enumerate(shapes): if isinstance(s, Shape): self.shapes.append(s) else: self.shapes.append(Shape(s)) self.symbolic_shape = self.shapes[0].symbolic_shape for shape in self.shapes: for idx, s in enumerate(shape.symbolic_shape): if is_symbolic(self.symbolic_shape[idx]): continue elif is_symbolic(s): self.symbolic_shape[idx] = s elif s != self.symbolic_shape[idx]: self.symbolic_shape[idx] = get_new_symbol() if default is not None: if not isinstance(default, (list, tuple)): raise ValueError( "Default shape should be list or tuple, got type {} instead" .format(type(default))) for idx, s in enumerate(default): if not isinstance(s, (np.generic, int)) and not is_symbolic(s): raise ValueError( "Default shape invalid, got error at index {} which is {}" .format(idx, s)) else: default = self.shapes[0].default self.default = default
def _set_symbolic_inputs(proto, symbolic_inputs): # Set symbolic input shapes by -1 infered from graph for input_name, shape in symbolic_inputs.items(): lb = [1 if is_symbolic(d) else d for d in shape] ub = [-1 if is_symbolic(d) else d for d in shape] set_multiarray_ndshape_range( proto, input_name, lower_bounds=lb, upper_bounds=ub )
def _get_dim_value(shape1, shape2, dim): if is_symbolic(shape1[dim]) and is_symbolic(shape2[dim]): return shape1[dim] elif is_symbolic(shape1[dim]): return shape1[dim] elif is_symbolic(shape2[dim]): return shape2[dim] else: return max(shape1[dim], shape2[dim])
def compare_elem(dt, ds): if dt is None or dt < 0: return True elif dt == ds: return True elif is_symbolic(ds): if is_symbolic(dt) and dt != ds: logging.warning("Symbolic dim {} and {}".format(ds, dt) +\ " assumed to be equal") return True else: return False
def type_inference(self): if self.x.rank < 3: raise ValueError( 'input to the "upsample_bilinear" op must have rank at least 3' ) ret_shape = list(self.x.shape) ret_shape[-1] = np.floor(self.scale_factor_width.val * ret_shape[-1]) if not is_symbolic( ret_shape[-1]) else get_new_symbol() ret_shape[-2] = np.floor(self.scale_factor_height.val * ret_shape[-2]) if not is_symbolic( ret_shape[-2]) else get_new_symbol() return types.tensor(self.x.dtype, ret_shape)
def enforce_volumetric_constraint(left_volume, inshape): left_symbols = set() if is_symbolic(left_volume): left_symbols = left_volume.free_symbols # Generally, we want to solve for right in terms of left. But this # is kinda annoying actually. shape = list(inshape) # Handling when reshape is given 0 instead of actual input # input tensor shape: [4, 3, 2], reshape:[0, -1], output tensor shape: [4, 6] if shape.count(-1) > 1: raise ValueError( "Reshape op supports only one dimension to be -1. Given {}".format( shape.count(-1) ) ) infer_dim_index = shape.index(-1) if -1 in shape else None right_volume = 1 for i in shape: if i != -1: right_volume = right_volume * i if infer_dim_index: shape[infer_dim_index] = left_volume // right_volume if not is_symbolic(right_volume): return shape constraints = [left_volume - right_volume] solve_for = [s for s in shape if is_symbolic(s)] for rightsym in solve_for: sol = sm.solve(constraints, [rightsym], dict=True) if not isinstance(sol, list): sol = [sol] # look for an acceptable solution for s in sol: if 0 in s.values(): continue for i in range(len(shape)): if shape[i] in s: v = s[shape[i]] if len(v.free_symbols - left_symbols) > 0: continue try: shape[i] = int(v) except: shape[i] = v return shape
def type_inference(self): if self.begin.rank != 1: raise ValueError( "begin should be 1-D tensor, got {}-D tensor instead".format( self.begin.rank)) if self.size.rank != 1: raise ValueError( "size should be 1-D tensor, got {}-D tensor instead".format( self.size.rank)) if self.x.rank != self.begin.shape[0]: raise ValueError( "Length of begin {} doesn't equal to input rank {}.".format( len(self.begin.shape[0]), len(self.x.rank))) if self.x.rank != self.size.shape[0]: raise ValueError( "Length of size {} doesn't equal to input rank {}.".format( len(self.size.shape[0]), len(self.x.rank))) x_shape = self.x.shape ret_shape = [] if self.size.sym_val is None: ret_shape = [get_new_symbol() for _ in range(self.x.rank)] return types.tensor(self.x.dtype, tuple(ret_shape)) for idx, s in enumerate(self.size.sym_val): if is_symbolic(s): ret_shape.append(s) elif s != -1: ret_shape.append(s) elif self.begin.sym_val is not None: ret_shape.append(x_shape[idx] - self.begin.sym_val[idx]) else: ret_shape.append(get_new_symbol()) return types.tensor(self.x.dtype, tuple(ret_shape))
def value_inference(self): if any_symbolic(self.x.shape): # convert elements in shape to int32 res = [x if is_symbolic(x) else np.int32(x) for x in self.x.shape] return np.array(res) else: return np.array(self.x.shape).astype(np.int32)
def _does_block_contain_symbolic_shape(block): for op in block.operations: for b in op.blocks: if _does_block_contain_symbolic_shape(b): return True for out in op.outputs: if types.is_tensor(out.sym_type): shape = out.sym_type.get_shape() if any_symbolic(shape): return True elif types.is_scalar(out.sym_type) or types.is_str( out.sym_type): if is_symbolic(out.val): return True elif types.is_list(out.sym_type): if types.is_tensor(out.elem_type): if any_symbolic(out.elem_type.get_shape()): return True else: raise NotImplementedError( "\'{}\' type in a list not handled".format( out.elem_type)) else: raise NotImplementedError( "\'{}\' type is not handled".format(out.sym_type)) return False
def reshape_with_symbol(v, shape): """ Perform basic reshape if v is symbolic (not array of symbols). """ if is_symbolic(v): return np.array(v).reshape(shape) shape = [int(s) for s in shape] return v.reshape(shape)
def value_inference(self): if self.x.sym_val is None or self.begin.val is None or self.end.val is None: return None x_shape = self.x.shape begin = [int(i) for i in list(self.begin.val[:])] end = [int(i) for i in list(self.end.val[:])] stride = [1] * self.x.rank if self.stride is None else self.stride.val begin_mask = ( [False] * self.x.rank if self.begin_mask is None else self.begin_mask.val ) end_mask = [False] * self.x.rank if self.end_mask is None else self.end_mask.val squeeze_mask = ( [False] * self.x.rank if self.squeeze_mask is None else self.squeeze_mask.val ) slices = [] for idx, mask in enumerate(begin_mask): if mask: begin[idx] = None for idx, mask in enumerate(end_mask): if mask: end[idx] = None squeeze_axes = [] for idx, mask in enumerate(squeeze_mask): if mask: end[idx] = None stride[ idx ] = 2147483647 # We slice out only 1 element by setting stride to INF squeeze_axes.append(idx) for idx in range(self.x.rank): slices.append(slice(begin[idx], end[idx], stride[idx])) slices = tuple(slices) res = self.x.sym_val[slices] # remove squeezed axes if len(squeeze_axes) > 0: if len(squeeze_axes) == len(res.shape): if len(res) == 0: logging.warning("%s seems to be a 0 sized tensor", self.name) return np.array([]) res = res.tolist()[0] if is_symbolic(res): return res elif self.x.dtype == types.int32 or self.x.dtype == types.int64: res = np.int32(res) elif self.x.dtype == types.float or self.x.dtype == types.double: res = np.float32(res) else: raise ValueError( "Unable to convert type {}".format(self.x.sym_val.dtype) ) else: res = np.squeeze(res, axis=tuple(squeeze_axes)) return res
def _try_to_transform(reduce_sum_op, block): ops_to_remove = [] # check that the dimensions in the shape of the input to the reduce_sum op, # over which the reduction operation is being performed, are known input_shape = reduce_sum_op.x.shape if input_shape is None: return False axes = None if reduce_sum_op.axes is not None: axes = reduce_sum_op.axes.val if axes is None: return False count = 1 for dim in axes: if is_symbolic(input_shape[dim]): return False count *= input_shape[dim] # check that output of reduce_sum is not a block output if reduce_sum_op.outputs[0] in block.outputs: return False ops_to_remove.append(reduce_sum_op) # check that reduce_sum op is followed by either: # - mul op with scalar value 1/count # or # - real_div op with scalar value count if _check_child_op_type(reduce_sum_op, "mul"): child_op = list(reduce_sum_op.outputs[0].child_ops)[0] other_input = child_op.x if child_op.y == reduce_sum_op.outputs[0] else child_op.y if not _check_var_scalar_value(other_input, 1.0 / count, 1e-6): return False elif _check_child_op_type(reduce_sum_op, "real_div"): child_op = list(reduce_sum_op.outputs[0].child_ops)[0] if child_op.x != reduce_sum_op.outputs[0]: return False other_input = child_op.y if not _check_var_scalar_value(other_input, count, 1e-2): return False else: return False ops_to_remove.append(child_op) # remove all the ops, and replace with a reduce_mean op out_name = child_op.outputs[0].name x = mb.reduce_mean(x=reduce_sum_op.x, axes = reduce_sum_op.axes.val, keep_dims = reduce_sum_op.keep_dims.val, name=out_name, before_op=child_op) child_op.enclosing_block.replace_uses_of_var_after_op( anchor_op=child_op, old_var=child_op.outputs[0], new_var=x ) block.remove_ops(ops_to_remove) return True
def broadcast_shapes(shape_x, shape_y): """ Check and broadcast given input shapes. :param shape_x: tuple of int or symbols Shape of the first tensor (possibly symbolic). :param shape_y: tuple of int or symbols Shape of the second tensor (possibly symbolic). :return: tuple of int or symbols Result from broadcast. """ shape_x = tuple(shape_x) shape_y = tuple(shape_y) if len(shape_x) < len(shape_y): shape_x = tuple([1] * (len(shape_y) - len(shape_x))) + shape_x if len(shape_y) < len(shape_x): shape_y = tuple([1] * (len(shape_x) - len(shape_y))) + shape_y ret_shapes = list() for i in range(len(shape_x)): x_unknown = is_symbolic(shape_x[i]) y_unknown = is_symbolic(shape_y[i]) if shape_x[i] == 1: ret_shapes.append(shape_y[i]) elif shape_y[i] == 1: ret_shapes.append(shape_x[i]) elif not y_unknown and shape_y[i] > 1: if not x_unknown and shape_x[i] != shape_y[i]: raise ValueError( "Incompatible dim {} in shapes {} vs. {}".format( i, shape_x, shape_y)) ret_shapes.append(shape_y[i]) elif not x_unknown and shape_x[i] > 1: if not y_unknown and shape_x[i] != shape_y[i]: raise ValueError( "Incompatible dim {} in shapes {} vs. {}".format( i, shape_x, shape_y)) ret_shapes.append(shape_x[i]) elif x_unknown or y_unknown: ret_shapes.append(get_new_symbol()) else: if shape_x[i] != shape_y[i]: raise AssertionError ret_shapes.append(shape_x[i]) return tuple(ret_shapes)
def _is_compatible_symbolic_array(a, b): """ A helper function which check if two numpy array with symbolic value. For instance, a = np.array([is0, is2]) b = np.array([is1, 1]) are considered compatible. a = np.array([is0, 1]) b = np.array([is1, -1]) are not. """ if not a.shape == b.shape: return False a = a.flatten() b = b.flatten() for t, v in zip(a, b): if not is_symbolic(t) and not is_symbolic(v): if t != v: return False return True
def value_inference(self): is_all_rank_zero = all([v.rank == 0 for v in self.values]) values = [ v.sym_val if v.sym_val is not None else get_new_symbol() for v in self.values ] if any([is_symbolic(v) for v in values]) and not is_all_rank_zero: return None return np.stack(values, self.axis.val)
def type_inference(self): x_type = self.x.dtype x_shape = list(self.x.shape) y_shape = list(self.y.shape) if self.transpose_x.val: x_shape = list(x_shape) x_shape[-1], x_shape[-2] = x_shape[-2], x_shape[-1] x_shape = tuple(x_shape) if self.transpose_y.val: y_shape = list(y_shape) y_shape[-1], y_shape[-2] = y_shape[-2], y_shape[-1] y_shape = tuple(y_shape) if not (x_shape[-1] == y_shape[-2] or is_symbolic(x_shape[-1]) or is_symbolic(y_shape[-2])): msg = "Op {} (matmul): x {}, y {} are not broadcastable" raise ValueError(msg.format(self.name, self.x.shape, self.y.shape)) ret_shape = list(broadcast_shapes(x_shape[:-2], y_shape[:-2])) ret_shape += [x_shape[-2], y_shape[-1]] return types.tensor(x_type, tuple(ret_shape))
def type_inference(self): x_type = self.x.dtype x_shape = self.x.shape k = self.k.val axis = self.axis.val if not is_symbolic(x_shape[axis]) and k > x_shape[axis]: msg = "K={} is greater than size of the given axis={}" raise ValueError(msg.format(k, axis)) ret_shape = list(x_shape) ret_shape[axis] = k return types.tensor(x_type, ret_shape), types.tensor(types.int32, ret_shape)
def type_inference(self): x_type = self.x.dtype x_shape = self.x.shape weight_shape = self.weight.shape assert len(weight_shape) == 2 if not (x_shape[-1] == weight_shape[-1] or is_symbolic(x_shape[-1]) or is_symbolic(weight_shape[-1])): msg = "Op '{}' (linear op): Size of the last dimension of x, which is {}, " \ "does not match the last dimension of weights, which is {}" raise ValueError( msg.format(self.name, x_shape[-1], weight_shape[-1])) if self.bias is not None: assert len(self.bias.shape) == 1 if len(self.bias.val) != weight_shape[-2]: msg = "Op '{}' (linear op): Size of the bias, which is {}, " \ "does not match the first dimension of weights, which is {}" raise ValueError( msg.format(self.name, len(self.bias.val), weight_shape[-2])) shape = list(x_shape) shape[-1] = weight_shape[0] return types.tensor(x_type, tuple(shape))
def _get_num_splits_and_sizes(self): """ Return: - num_splits: int - sizes: list of int/symbols. Of length num_splits Raise ValueError if num_splits cannot be determined. """ if self.num_splits is None and self.split_sizes is None: msg = ( "At least one of num_splits and split_sizes " + "must be specified in split op {}" ) raise ValueError(msg.format(self.name)) axis = self.axis.val if self.num_splits is not None: num_splits = self.num_splits.val if self.split_sizes is None: # Even split if ( not is_symbolic(self.x.shape[axis]) and self.x.shape[axis] % num_splits != 0 ): msg = "num_split {} does not divide split " + "dim (length = {})" raise ValueError(msg.format(num_splits, self.x.shape[axis])) size = self.x.shape[axis] / num_splits return num_splits, [size] * num_splits # self.split_sizes is not None if self.split_sizes.sym_val is not None: return num_splits, self.split_sizes.sym_val # self.split_size.sym_val is None. sizes = [get_new_symbol() for _ in range(num_splits)] return num_splits, sizes # self.num_splits is None, self.split_sizes is not None if self.split_sizes.sym_val is not None: return len(self.split_sizes.sym_val), self.split_sizes.sym_val # self.num_splits is None, self.split_sizes is not None # self.split_sizes.sym_val is None if any_symbolic(self.split_sizes.shape): raise ValueError("Unable to determine number of splits") num_splits = len(self.split_sizes.shape) sizes = [get_new_symbol() for _ in range(num_splits)] return num_splits, sizes
def type_inference(self): if self.axis.val < -self.data.rank or self.axis.val >= self.data.rank: raise IndexError( "Axis value {} is out of bounds for {} node {}".format( self.axis.val, self.op_type, self.name ) ) axis = self.axis.val axis = axis if axis >= 0 else axis + self.data.rank expected_updates_shape = ( self.data.shape[:axis] + self.indices.shape + self.data.shape[axis + 1 :] ) err = "Updates shape {} is incorrect. It should be {}.".format(self.updates.shape, expected_updates_shape) if len(self.updates.shape) == len(expected_updates_shape): for dim1, dim2 in zip(self.updates.shape, expected_updates_shape): if not is_symbolic(dim1) and not is_symbolic(dim2): if dim1 != dim2: raise ValueError(err) else: raise ValueError(err) return self.data.sym_type
def _get_type_val(self): x_type = self.x.dtype x_shape = self.x.shape x_vol = np.prod(x_shape) # shape is const, and thus sym_val is not None sym_shape = self.shape.sym_val sym_shape = [get_new_symbol() if d == -1 else d for d in sym_shape] try: ret_shape = reshape.enforce_volumetric_constraint(x_vol, sym_shape) except: ret_shape = sym_shape ret_val = None if self.x.val is not None and all(isscalar(a) and not is_symbolic(a) for a in ret_shape): ret_val = reshape_with_symbol(self.x.val, ret_shape) return types.tensor(x_type, tuple(ret_shape)), ret_val
def type_inference(self): x_shape = self.x.shape block_shape = self.block_shape.val crops = self.crops.val if self.x.rank != 4: msg = "Input to batch_to_space op must be rank 4. Instead got an input with rank {}".format( self.x.rank) raise ValueError(msg) if crops.shape != (block_shape.shape[0], 2): msg = "block_shape and crops must have shape [2], [2, 2] accordingly in the batch_to_space op. "\ "Got {}, {}.".format(block_shape.shape, crops.shape) raise ValueError(msg) m = block_shape.shape[0] if m != 2: msg = "batch_to_space op only supports spatial dimensions = 2. Got {}".format( m) raise ValueError(msg) b = x_shape[0] c = x_shape[1] spatial_shape = x_shape[2:2 + m] if self.x.rank != m + 2: raise ValueError("The input rank of batch_to_space op must exactly be " \ "len(block_shape){} + 2! Got {}".format(self.block_shape.val, self.x.rank)) if not is_symbolic(b) and b % np.prod(block_shape) != 0: msg = ( "Batch size must be perfectly divided by the product of block_shape. Got batch size {}, and block_shape {}." ).format(b, block_shape) raise ValueError(msg) new_b = b / np.prod(block_shape) new_spatial_shape = [ spatial_shape[i] * block_shape[i] for i in range(m) ] cropped_spatial_shape = [ x - crops[i][0] - crops[i][1] for i, x in enumerate(new_spatial_shape) ] ret_shape = [new_b, c] + cropped_spatial_shape x_type = self.x.dtype return types.tensor(x_type, ret_shape)
def value_inference(self): is_all_rank_zero = all([v.rank == 0 for v in self.values]) values = [ v.sym_val if v.sym_val is not None else get_new_symbol() for v in self.values ] # we only infer values for values whose ranks are all zero, # or don't have symbolic values. # Note that cases like values = [[1, is0], [2]] aren't in such case. if any([is_symbolic(v) for v in values]) and not is_all_rank_zero: return None if not isinstance(values[0], np.ndarray) or values[0].shape == (): return np.stack(values, axis=self.axis.val) return np.concatenate(values, axis=self.axis.val)
def value_inference(self): if any_symbolic(self.begin.sym_val): return None if any_symbolic(self.size.sym_val): return None if self.x.val is None: return None slices = [] for i in range(self.x.rank): begin_val = self.begin.val[i] if begin_val < 0: if is_symbolic(self.x.shape[i]): return None begin_val += self.x.shape[i] if self.size.val[i] > 0: slices.append(slice(begin_val, begin_val + self.size.val[i])) else: slices.append(slice(begin_val, None, None)) return self.x.val[tuple(slices)]