Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
for idx, op in enumerate(ops):
inputs = []
for node in op.inputs:
if node and node.is_const():
inputs.append(node.get_tensor_value(as_list=False))
if inputs and len(op.input) == len(inputs):
func = func_map.get(op.type)
if func is None:
logger.info("can fold but don't know how, type=%s, name=%s", op.type, op.name)
continue
try:
logger.info("folding node type=%s, name=%s", op.type, op.name)
if op.type == "Cast":
dst = op.get_attr_int("to")
np_type = tf2onnx.utils.map_onnx_to_numpy_type(dst)
val = np.cast[np_type](*inputs)
elif op.type == "Transpose":
perm = op.get_attr("perm").ints
val = np.transpose(inputs[0], perm)
elif op.type == "Unsqueeze":
axis = op.get_attr_int("axis")
val = np.expand_dims(inputs[0], axis=axis)
elif op.type == "Slice":
axis = op.get_attr_int("axis")
if axis != 0:
logger.info("can fold slice with axis!=0, type=%s, name=%s", op.type, op.name)
continue
starts = op.get_attr_int("starts")
ends = op.get_attr_int("ends")
if starts == 0 and ends == 0:
val = inputs[0][starts:ends]
def _workaround_fill_ch_init_node(self, initializer_input_id, rnn_props):
node = self.g.get_node_by_output(initializer_input_id)
if node.type != "Fill":
return None
fill_val = node.inputs[1].get_tensor_value()
fill_val_dtype = utils.map_onnx_to_numpy_type(self.g.get_dtype(node.input[1]))
# this must be int64, since Concat's input data type must be consistent.
num_direction_node = self.g.make_const(utils.make_name("Const"), np.array([1], dtype=np.float32))
h_node = self.g.make_const(utils.make_name("Const"), np.array([rnn_props.hidden_size], dtype=np.float32))
b_node = rnn_props.batch_size_node
# Concat in OPSET7 does not support int64.
tile_shape = self.g.make_node("Concat", [num_direction_node.output[0], b_node.output[0], h_node.output[0]],
attr={"axis": 0})
# Tile's repeats must be INT64
attr = {"to": onnx_pb.TensorProto.INT64}
tile_shape_int64 = self.g.make_node("Cast", [tile_shape.output[0]], attr)
const_node = self.g.make_const(utils.make_name("Const"), np.array([[[fill_val]]], dtype=fill_val_dtype))
tile_node = self.g.make_node("Tile", [const_node.output[0], tile_shape_int64.output[0]])
self.all_nodes.extend([tile_shape, tile_shape_int64, tile_node,
id_name = utils.make_name("sparse_softmax_id")
id_output = utils.port_name(id_name)
controlflow.make_range(ctx, zero_const.output[0], indices_size.output[0], one_const.output[0],
id_output, id_name, shape=[-1], dtype=TensorProto.INT64)
id_unsqueeze = ctx.make_node("Unsqueeze", [id_output], attr={"axes": [1]})
indices_with_id = ctx.make_node("Concat",
[id_unsqueeze.output[0], indices_unsqueeze.output[0]],
attr={"axis": 1})
log_softmax = ctx.make_node(op_type="LogSoftmax",
inputs=[logit_name], dtypes=[logit_dtype], shapes=[logit_shape])
gathernd_name = utils.make_name("sparse_softmax_gathernd")
gathernd_output = utils.port_name(gathernd_name)
tensor.make_gathernd(ctx, log_softmax.output[0], indices_with_id.output[0], gathernd_output,
gathernd_name, logit_dtype, [logit_shape], [logit_dtype])
const_name = utils.make_name("const_negative_one")
const_negative_one = ctx.make_const(const_name, np.array(-1).astype(utils.map_onnx_to_numpy_type(logit_dtype)))
mul2 = ctx.make_node(op_type="Mul", inputs=[const_negative_one.output[0], gathernd_output])
shapes = node.output_shapes
dtypes = node.output_dtypes
ctx.remove_node(node.name)
ctx.make_node(op_type="Squeeze",
inputs=[mul2.output[0]], outputs=[node.output[0]],
attr={"axes": [1]}, shapes=[shapes[0]], dtypes=[dtypes[0]])
def get_weights_from_const_node(g, node):
temp = node
val = None
# this would help ignore Identity in non-const_folded graph.
while temp.type == 'Identity':
temp = temp.inputs[0]
if temp and temp.type == 'Const':
val = temp.get_tensor_value(as_list=False)
dtype = utils.map_onnx_to_numpy_type(g.get_dtype(temp.output[0]))
val = val.astype(dtype)
logger.debug("found weights %s", temp.name)
else:
logger.debug("weight node seems not to be Const, skip, node name is %s", temp.name)
return None
return val
elif op.type == "ConcatV2":
axis = inputs[-1]
values = inputs[:-1]
val = func(tuple(values), axis)
elif op.type == "ListDiff":
out_type = op.get_attr_int("out_idx")
np_type = tf2onnx.utils.map_onnx_to_numpy_type(out_type)
val = func(*inputs)
val = val.astype(np_type)
elif op.type in ["Pack"]:
# handle ops that need input array and axis
axis = op.get_attr_int("axis")
val = func(inputs, axis=axis)
elif op.type == "Range":
dtype = op.get_attr_int("Tidx")
np_type = tf2onnx.utils.map_onnx_to_numpy_type(dtype)
val = func(*inputs, dtype=np_type)
else:
val = func(*inputs)
new_node_name = utils.make_name(op.name)
new_output_name = new_node_name
old_output_name = op.output[0]
old_node_name = op.name
logger.debug("create const node [%s] replacing [%s]", new_node_name, old_node_name)
ops[idx] = g.make_const(new_node_name, val)
ref_cnt_per_node[new_node_name] = ref_cnt_per_node[old_node_name]
logger.debug("replace old output [%s] with new output [%s]", old_output_name, new_output_name)
# need to re-write the consumers input name to use the const name
consumers = g.find_output_consumers(old_output_name)
if consumers:
id_name = utils.make_name("sparse_softmax_id")
id_output = utils.port_name(id_name)
make_range(ctx, zero_const.output[0], indices_size.output[0], one_const.output[0],
id_output, id_name, shape=[-1], dtype=TensorProto.INT64)
id_unsqueeze = ctx.make_node("Unsqueeze", [id_output], attr={"axes": [1]})
indices_with_id = ctx.make_node("Concat",
[id_unsqueeze.output[0], indices_unsqueeze.output[0]],
attr={"axis": 1})
log_softmax = ctx.make_node(op_type="LogSoftmax",
inputs=[logit_name], dtypes=[logit_dtype], shapes=[logit_shape])
gathernd_name = utils.make_name("sparse_softmax_gathernd")
gathernd_output = utils.port_name(gathernd_name)
make_gathernd(ctx, log_softmax.output[0], indices_with_id.output[0], gathernd_output,
gathernd_name, logit_dtype, [logit_shape], [logit_dtype])
const_name = utils.make_name("const_negative_one")
const_negative_one = ctx.make_const(const_name, np.array(-1).astype(utils.map_onnx_to_numpy_type(logit_dtype)))
mul2 = ctx.make_node(op_type="Mul", inputs=[const_negative_one.output[0], gathernd_output])
shapes = node.output_shapes
dtypes = node.output_dtypes
ctx.remove_node(name)
ctx.make_node(op_type="Squeeze",
inputs=[mul2.output[0]], outputs=[node.output[0]],
attr={"axes": [1]}, shapes=[shapes[0]], dtypes=[dtypes[0]])
inputs.append(node.get_tensor_value(as_list=False))
logger.debug("op name %s, %s, %s", op.name, len(op.input), len(inputs))
if inputs and len(op.input) == len(inputs):
logger.info("folding node type=%s, name=%s" % (op.type, op.name))
if op.type == "Cast":
dst = op.get_attr_int("to")
np_type = tf2onnx.utils.map_onnx_to_numpy_type(dst)
val = np.cast[np_type](*inputs)
elif op.type == "ConcatV2":
axis = inputs[-1]
values = inputs[:-1]
val = func(tuple(values), axis)
elif op.type == "ListDiff":
out_type = op.get_attr_int("out_idx")
np_type = tf2onnx.utils.map_onnx_to_numpy_type(out_type)
val = func(*inputs)
val = val.astype(np_type)
elif op.type in ["Pack"]:
# handle ops that need input array and axis
axis = op.get_attr_int("axis")
val = func(inputs, axis=axis)
elif op.type == "Range":
dtype = op.get_attr_int("Tidx")
np_type = tf2onnx.utils.map_onnx_to_numpy_type(dtype)
val = func(*inputs, dtype=np_type)
else:
val = func(*inputs)
new_node_name = utils.make_name(op.name)
new_output_name = new_node_name
old_output_name = op.output[0]
indices_name = node.input[1]
indices_shape = ctx.get_shape(indices_name)
if len(indices_shape) != 1:
# TODO: this works for rank=1 but tensorflow supports more than this.
# Same principle should work but we need to implement our own eye.
raise ValueError("onehot op: only rank1 is supported")
logit_name = node.input[0]
depth = ctx.get_shape(logit_name)[-1]
# if number of classes is unknown or too large
if depth == utils.ONNX_UNKNOWN_DIMENSION or depth > 20000:
sparse_softmax_cross_entropy_with_logits_op_by_gathernd(ctx, node, **kwargs)
return
logit_dtype = ctx.get_dtype(logit_name)
utils.make_sure(logit_dtype, "Dtype of {} is None".format(logit_name))
dtype = utils.map_onnx_to_numpy_type(logit_dtype)
eye = np.eye(depth).astype(dtype)
const_name = utils.make_name("const_eye")
const_eye = ctx.make_const(name=const_name, np_val=eye)
onehot = ctx.make_node(op_type="Gather", inputs=[const_eye.output[0], indices_name], attr={"axis": 0})
log_softmax = ctx.make_node(op_type="LogSoftmax", inputs=[logit_name])
# implement tf.multiply(np.float32(-1.0), tf.reduce_sum(tf.multiply(one_hot, log_softmax), axis=1))
mul1 = ctx.make_node(op_type="Mul", inputs=[onehot.output[0], log_softmax.output[0]])
reduce_sum = ctx.make_node(op_type="ReduceSum", inputs=[mul1.output[0]], attr={"axes": [1]})
const_name = utils.make_name("const_negative_one")
const_negative_one = ctx.make_const(name=const_name, np_val=np.array(-1).astype(dtype))
mul2 = ctx.make_node(op_type="Mul", inputs=[const_negative_one.output[0], reduce_sum.output[0]])
shapes = node.output_shapes
dtypes = node.output_dtypes
ctx.remove_node(node.name)
ctx.make_node(op_type="Squeeze", inputs=[mul2.output[0]], outputs=[node.output[0]], attr={"axes": [1]},
def get_weights_from_const_node(g, node):
temp = node
val = None
# this would help ignore Identity in non-const_folded graph.
while temp.type == 'Identity':
temp = temp.inputs[0]
if temp and temp.type == 'Const':
val = temp.get_tensor_value(as_list=False)
dtype = utils.map_onnx_to_numpy_type(g.get_dtype(temp.output[0]))
val = val.astype(dtype)
logger.debug("found weights %s", temp.name)
else:
logger.debug("weight node seems not to be Const, skip, node name is %s", temp.name)
return None
return val