ONE - On-device Neural Engine
Loading...
Searching...
No Matches
luci::sinf::Algorithm Class Referencefinal

#include <CircleShapeInference.h>

Collaboration diagram for luci::sinf::Algorithm:

Public Member Functions

loco::TensorShape visit (const luci::CircleNode *node) final
 Default fallback.
 
loco::TensorShape visit (const luci::CircleAdd *node) final
 
loco::TensorShape visit (const luci::CircleBatchMatMul *node) final
 
loco::TensorShape visit (const luci::CircleConcatenation *node) final
 
loco::TensorShape visit (const luci::CircleDiv *node) final
 
loco::TensorShape visit (const luci::CircleFullyConnected *node) final
 
loco::TensorShape visit (const luci::CircleLogistic *node) final
 
loco::TensorShape visit (const luci::CircleMul *node) final
 
loco::TensorShape visit (const luci::CircleNeg *node) final
 
loco::TensorShape visit (const luci::CirclePad *node) final
 
loco::TensorShape visit (const luci::CircleQuantize *node) final
 
loco::TensorShape visit (const luci::CircleRange *node) final
 
loco::TensorShape visit (const luci::CircleReshape *node) final
 
loco::TensorShape visit (const luci::CircleRsqrt *node) final
 
loco::TensorShape visit (const luci::CircleSoftmax *node) final
 
loco::TensorShape visit (const luci::CircleStridedSlice *node) final
 
loco::TensorShape visit (const luci::CircleIfOut *node) final
 
- Public Member Functions inherited from luci::CircleNodeVisitor< loco::TensorShape >
virtual ~CircleNodeVisitor ()=default
 
- Public Member Functions inherited from luci::CircleNodeVisitorBase< T >
virtual ~CircleNodeVisitorBase ()=default
 

Detailed Description

Definition at line 38 of file CircleShapeInference.h.

Member Function Documentation

◆ visit() [1/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleAdd node)
final

Definition at line 40 of file CircleAdd.cpp.

41{
42 const auto x = loco::must_cast<luci::CircleNode *>(node->x());
43 const auto y = loco::must_cast<luci::CircleNode *>(node->y());
44
45 const auto x_shape = circle_shape(x);
46 const auto y_shape = circle_shape(y);
47
48 return broadcast_shape(x_shape, y_shape);
49}
loco::Node * x(void) const
Definition CircleAdd.h:36
loco::Node * y(void) const
Definition CircleAdd.h:39
loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::TensorShape &y)
loco::TensorShape circle_shape(const luci::CircleNode *node)

References luci::sinf::broadcast_shape(), luci::sinf::circle_shape(), luci::CircleAdd::x(), and luci::CircleAdd::y().

◆ visit() [2/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleBatchMatMul node)
final

Definition at line 84 of file CircleBatchMatMul.cpp.

85{
86 const auto x = loco::must_cast<CircleNode *>(node->x());
87 const auto y = loco::must_cast<CircleNode *>(node->y());
88
89 const auto x_shape = circle_shape(x);
90 const auto y_shape = circle_shape(y);
91
92 uint32_t x_rank = x_shape.rank();
93 uint32_t y_rank = y_shape.rank();
94
95 // throw internal exception if condition not met
96 throw_unless(x_rank >= 2, "x_rank shoud be >= 2");
97 throw_unless(y_rank >= 2, "y_rank shoud be >= 2");
98 throw_unless((not contain_zero(x_shape)), "x_shape should NOT have 0");
99 throw_unless((not contain_zero(y_shape)), "y_shape should NOT have 0");
100
101 // BatchMatMul shape inference rule works with two-part
102 //
103 // 1) Batch dimensions part
104 // - Batch dimensions correspond to the input_shape[:-2]
105 // - General broadcast rules are used to infer the shape of the output batch
106 //
107 // 2) Contracting dimensions part
108 // - Contracting dimensions correspond to the input_shape[-2:]
109 // - General matrix multiplication shape inference applied for this part,
110 // which means '(x_lhs, x_rhs) x (y_lhs, y_rhs) => (x_lhs, y_rhs)'
111
112 uint32_t max_rank = x_rank > y_rank ? x_rank : y_rank;
114 output_shape.rank(max_rank);
115
116 // broadcast in the batch dimensions
117 if (x_rank > 2 || y_rank > 2)
118 {
119 const auto x_batch_dims = remove_last_two(x_shape);
120 const auto y_batch_dims = remove_last_two(y_shape);
121
122 const auto o_batch_dims = sinf::broadcast_shape(x_batch_dims, y_batch_dims);
123
124 const auto o_batch_rank = o_batch_dims.rank();
125 for (uint i = 0u; i < o_batch_rank; ++i)
126 {
127 output_shape.dim(i) = o_batch_dims.dim(i);
128 }
129 }
130
131 // shape inference in contracting dimensions
132 const auto adj_x = node->adj_x();
133 const auto adj_y = node->adj_y();
134
135 loco::Dimension x_lhs = adj_x ? x_shape.dim(x_rank - 1) : x_shape.dim(x_rank - 2);
136 loco::Dimension x_rhs = adj_x ? x_shape.dim(x_rank - 2) : x_shape.dim(x_rank - 1);
137 loco::Dimension y_lhs = adj_y ? y_shape.dim(y_rank - 1) : y_shape.dim(y_rank - 2);
138 loco::Dimension y_rhs = adj_y ? y_shape.dim(y_rank - 2) : y_shape.dim(y_rank - 1);
139
140 if (x_rhs.known() && y_lhs.known() && not(x_rhs == y_lhs))
141 INTERNAL_EXN("x_rhs and y_lhs should be same");
142
143 uint32_t out_rank = output_shape.rank();
144 output_shape.dim(out_rank - 2) = x_lhs;
145 output_shape.dim(out_rank - 1) = y_rhs;
146
147 return output_shape;
148}
#define INTERNAL_EXN(msg)
@ brief throw internal exception with message
Definition InternalExn.h:25
The value of one dimension in a tensor shape.
Definition Dimension.h:30
bool known(void) const
Return whether the value is known (or not)
Definition Dimension.h:47
loco::Node * y(void) const
loco::Node * x(void) const
const luci_interpreter::RuntimeShape output_shape

References luci::CircleBatchMatMul::adj_x(), luci::CircleBatchMatMul::adj_y(), luci::sinf::broadcast_shape(), luci::sinf::circle_shape(), INTERNAL_EXN, loco::Dimension::known(), output_shape, luci::CircleBatchMatMul::x(), and luci::CircleBatchMatMul::y().

◆ visit() [3/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleConcatenation node)
final

Definition at line 43 of file CircleConcatenation.cpp.

44{
45 // TODO Support when CircleConcatenation has 0 input
46 assert(node->numValues() > 0);
47
48 auto first_shape = luci::shape_get(node->values(0)).as<loco::TensorShape>();
49 auto axis = node->axis();
50 if (axis < 0)
51 axis += first_shape.rank();
52
53 assert(0 <= axis);
54 assert(first_shape.rank() > static_cast<uint32_t>(axis));
55
57
58 output_shape.rank(first_shape.rank());
59 for (uint32_t i = 0; i < output_shape.rank(); ++i)
60 output_shape.dim(i) = first_shape.dim(i);
61
62 for (uint32_t i = 1; i < node->numValues(); ++i)
63 {
64 auto input_shape = luci::shape_get(node->values(i)).as<loco::TensorShape>();
65 if (input_shape.rank() != output_shape.rank())
66 INTERNAL_EXN_V("Input has incompatible shape", node->name());
67
68 for (uint32_t j = 0; j < output_shape.rank(); ++j)
69 {
70 if (j == static_cast<uint32_t>(axis))
71 {
72 if (output_shape.dim(j).known() and input_shape.dim(j).known())
73 {
74 output_shape.dim(j) = output_shape.dim(j).value() + input_shape.dim(j).value();
75 }
76 else
77 {
78 // If any of inputs is unknown, just mark it as unknown.
79 output_shape.dim(j).unset();
80 }
81 }
82 else
83 {
84 if (output_shape.dim(j).known() and input_shape.dim(j).known())
85 {
86 if (output_shape.dim(j).value() != input_shape.dim(j).value())
87 {
88 INTERNAL_EXN_V("Input has incompatible shape.", node->name());
89 }
90 }
91 else
92 {
93 if (input_shape.dim(j).known())
94 {
95 assert(not output_shape.dim(j).known()); // FIX_ME_UNLESS
96 output_shape.dim(j) = input_shape.dim(j);
97 }
98 // For unknown input_shape, leave output_shape as-is
99 }
100 }
101 }
102 }
103
104 return output_shape;
105}
#define INTERNAL_EXN_V(msg, val)
@ brief throw internal exception with message and value
Definition InternalExn.h:28
ShapeType as(void) const
uint32_t rank(void) const
Definition TensorShape.h:35
uint32_t numValues(void) const
Node * values(uint32_t index) const
loco::NodeShape shape_get(const loco::Node *node)
NodeName name(void) const

References loco::NodeShape::as(), luci::CircleConcatenation::axis(), INTERNAL_EXN_V, luci::CircleNode::name(), luci::CircleConcatenation::numValues(), output_shape, loco::TensorShape::rank(), luci::shape_get(), and luci::CircleConcatenation::values().

◆ visit() [4/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleDiv node)
final

Definition at line 40 of file CircleDiv.cpp.

41{
42 const auto x = loco::must_cast<luci::CircleNode *>(node->x());
43 const auto y = loco::must_cast<luci::CircleNode *>(node->y());
44
45 const auto x_shape = circle_shape(x);
46 const auto y_shape = circle_shape(y);
47
48 auto output_shape = broadcast_shape(x_shape, y_shape);
49
50 return output_shape;
51}
loco::Node * y(void) const
Definition CircleDiv.h:42
loco::Node * x(void) const
Definition CircleDiv.h:39

References luci::sinf::broadcast_shape(), luci::sinf::circle_shape(), output_shape, luci::CircleDiv::x(), and luci::CircleDiv::y().

◆ visit() [5/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleFullyConnected node)
final

Definition at line 46 of file CircleFullyConnected.cpp.

47{
48 auto input_shape = circle_shape(loco::must_cast<CircleNode *>(node->input()));
49 auto weights_shape = circle_shape(loco::must_cast<CircleNode *>(node->weights()));
50
51 loco::TensorShape out_shape;
52
53 // NOTE Some recipes in some repositories are using rank 4 input for FullyConnected.
54 // Until they are all fixed, disable following assert.
55 // TODO Enable following assert after related fixes are applied
56 // https://github.com/tensorflow/tensorflow/blob/ea33c1e7a25d8025e8ee405ad8ab7be261798d76/tensorflow/lite/kernels/fully_connected.cc#L194
57 // LUCI_ASSERT(input_shape.rank() == 2 || input_shape.rank() == 3,
58 // "Input rank of FullyConnected should be 2 or 3");
59
60 // https://github.com/tensorflow/tensorflow/blob/ea33c1e7a25d8025e8ee405ad8ab7be261798d76/tensorflow/lite/kernels/fully_connected.cc#L225
61 LUCI_ASSERT(weights_shape.rank() == 2, "Weights of FullyConnected should be 2");
62 LUCI_ASSERT(weights_shape.dim(0).known() && weights_shape.dim(1).known(),
63 "Weights of FullyConnected should be known")
64 // https://github.com/tensorflow/tensorflow/blob/ea33c1e7a25d8025e8ee405ad8ab7be261798d76/tensorflow/lite/kernels/fully_connected.cc#L353-L367
65
66 /*
67 * **Pre-conditions:**
68 * input_shape.rank() <= 4
69 * * remark: TFLite allows <=3 ranks, but there are rank 4 input recipes in ONE
70 * weights_shape.rank() == 2 and all dimensions are known.
71 * When runtime(input_shape[-1] and weights_shape[-1] are both known), it should be same value.
72 *
73 * **Shape Inference Rule:**
74 * **Input Shape:**
75 * input_shape : (A, B, C, D)
76 * weights_shape : (E, F)
77 * A, B, C, D are "positive numbers" or "unknown".
78 * E, F are always "positive numbers".
79 *
80 * **Output Shape:**
81 * If keep_dims = True : (A, B, C, E)
82 * If keep_dims = False : (G, E)
83 * * G = unknown (if any of A, B, or C is unknown.)
84 * * G = A * B * C (otherwise.)
85 */
86
87 if (node->keep_num_dims())
88 {
89 out_shape.rank(input_shape.rank());
90 for (uint32_t i = 0; i < input_shape.rank(); ++i)
91 out_shape.dim(i) = input_shape.dim(i);
92 out_shape.dim(out_shape.rank() - 1) = weights_shape.dim(0);
93 }
94 else
95 {
96 bool is_dynamic_shape = false;
97
98 for (uint32_t i = 0; i < input_shape.rank() - 1; i++)
99 {
100 if (not input_shape.dim(i).known())
101 {
102 is_dynamic_shape = true;
103 break;
104 }
105 }
106
107 uint32_t batch_size = 1;
108
109 for (uint32_t i = 0; i < input_shape.rank() - 1; i++)
110 {
111 batch_size *= input_shape.dim(i).value();
112 }
113
114 out_shape.rank(2);
115 if (is_dynamic_shape)
116 out_shape.dim(0).unset();
117 else
118 out_shape.dim(0) = batch_size;
119 out_shape.dim(1) = weights_shape.dim(0);
120 }
121
122 return out_shape;
123}
void unset(void)
Definition Dimension.h:59
uint32_t value(void) const
Return the value.
Definition Dimension.h:51
const Dimension & dim(uint32_t axis) const
Definition TensorShape.h:38
loco::Node * weights(void) const
loco::Node * input(void) const
#define LUCI_ASSERT(condition, msg)
Definition Check.h:26

References luci::sinf::circle_shape(), loco::TensorShape::dim(), luci::CircleFullyConnected::input(), luci::CircleFullyConnected::keep_num_dims(), LUCI_ASSERT, loco::TensorShape::rank(), loco::Dimension::unset(), loco::Dimension::value(), and luci::CircleFullyConnected::weights().

◆ visit() [6/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleIfOut node)
final

Definition at line 79 of file CircleIfOut.cpp.

80{
81 auto graphs = get_out_graphs(node);
82 assert(*graphs.then_graph_output->shape() == *graphs.else_graph_output->shape());
83 return *graphs.then_graph_output->shape();
84}

◆ visit() [7/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleLogistic node)
final

Definition at line 33 of file CircleLogistic.cpp.

34{
35 const auto input_x = loco::must_cast<luci::CircleNode *>(node->x());
36 const auto input_shape = circle_shape(input_x);
37 return input_shape;
38}
loco::Node * x(void) const

References luci::sinf::circle_shape(), and luci::CircleLogistic::x().

◆ visit() [8/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleMul node)
final

Definition at line 39 of file CircleMul.cpp.

40{
41 const auto x = loco::must_cast<luci::CircleNode *>(node->x());
42 const auto y = loco::must_cast<luci::CircleNode *>(node->y());
43
44 const auto x_shape = circle_shape(x);
45 const auto y_shape = circle_shape(y);
46
47 return broadcast_shape(x_shape, y_shape);
48}
loco::Node * y(void) const
Definition CircleMul.h:39
loco::Node * x(void) const
Definition CircleMul.h:36

References luci::sinf::broadcast_shape(), luci::sinf::circle_shape(), luci::CircleMul::x(), and luci::CircleMul::y().

◆ visit() [9/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleNeg node)
final

Definition at line 32 of file CircleNeg.cpp.

33{
34 const auto input_x = loco::must_cast<CircleNode *>(node->x());
35 const auto input_shape = circle_shape(input_x);
36 return input_shape;
37}
loco::Node * x(void) const
Definition CircleNeg.h:34

References luci::sinf::circle_shape(), and luci::CircleNeg::x().

◆ visit() [10/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleNode )
inlinefinalvirtual

Default fallback.

Reimplemented from luci::CircleNodeVisitor< loco::TensorShape >.

Definition at line 42 of file CircleShapeInference.h.

43 {
44 loco::NodeShape shape;
46 return shape.as<loco::TensorShape>();
47 }
bool infer(const loco::Node *, loco::NodeShape &) const final
Infer node's shape.

References loco::NodeShape::as(), and luci::CircleShapeInferenceRule::infer().

◆ visit() [11/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CirclePad node)
final

Definition at line 33 of file CirclePad.cpp.

34{
35 auto paddings = loco::must_cast<const luci::CircleNode *>(node->paddings());
36 auto circle_input = loco::must_cast<const luci::CircleNode *>(node->input());
37 auto input_shape = circle_shape(circle_input);
38 return pad_shape(input_shape, paddings);
39}
loco::Node * input(void) const
Definition CirclePad.h:34
loco::Node * paddings(void) const
Definition CirclePad.h:37
loco::TensorShape pad_shape(const loco::TensorShape &input_shape, const luci::CircleNode *paddings)

References luci::sinf::circle_shape(), luci::CirclePad::input(), luci::sinf::pad_shape(), and luci::CirclePad::paddings().

◆ visit() [12/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleQuantize node)
final

Definition at line 33 of file CircleQuantize.cpp.

34{
35 const auto input = loco::must_cast<CircleNode *>(node->input());
36 const auto input_shape = circle_shape(input);
37 return input_shape;
38}
loco::Node * input(void) const

References luci::sinf::circle_shape(), and luci::CircleQuantize::input().

◆ visit() [13/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleRange node)
final

Definition at line 35 of file CircleRange.cpp.

36{
38 output_shape.rank(1);
39
40 auto start_node = dynamic_cast<luci::CircleConst *>(node->start());
41 auto limit_node = dynamic_cast<luci::CircleConst *>(node->limit());
42 auto delta_node = dynamic_cast<luci::CircleConst *>(node->delta());
43
44 if (start_node == nullptr || limit_node == nullptr || delta_node == nullptr)
45 {
46 return output_shape;
47 }
48
49 double start = 0, limit = 0, delta = 0;
50
51#define GET_RANGE_PARAM(DT) \
52 start = start_node->scalar<DT>(); \
53 limit = limit_node->scalar<DT>(); \
54 delta = delta_node->scalar<DT>();
55
56 switch (start_node->dtype())
57 {
58 case loco::DataType::FLOAT32:
59 GET_RANGE_PARAM(loco::DataType::FLOAT32)
60 break;
61 case loco::DataType::S32:
62 GET_RANGE_PARAM(loco::DataType::S32)
63 break;
64 default:
65 INTERNAL_EXN("Range data type not supported");
66 }
67
68#undef GET_RANGE_PARAM
69
70 if (delta == 0)
71 INTERNAL_EXN("Delta can not be zero");
72
73 /*
74 * Pre-condition
75 * 'limit - start' and 'delta' have the same sign.
76 * c1. '(limit - start) >= 0' -> 'delta > 0'
77 * c2. '(limit - start) < 0' -> 'delta < 0'
78 * https://github.com/tensorflow/tensorflow/blob/da82fa9/tensorflow/lite/kernels/range.cc#L49-L50
79 */
80 assert((start >= limit && delta < 0) || (start <= limit && delta > 0));
81 output_shape.dim(0) = ceil((limit - start) / delta);
82
83 return output_shape;
84}
Class to build tensor data.
Definition CircleConst.h:35
loco::Node * delta(void) const
Definition CircleRange.h:40
loco::Node * limit(void) const
Definition CircleRange.h:37
loco::Node * start(void) const
Definition CircleRange.h:34
#define GET_RANGE_PARAM(DT)

References luci::CircleRange::delta(), GET_RANGE_PARAM, INTERNAL_EXN, luci::CircleRange::limit(), output_shape, and luci::CircleRange::start().

◆ visit() [14/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleReshape node)
final

Definition at line 70 of file CircleReshape.cpp.

71{
72 LOGGER(l);
73
74 const loco::DataType S32 = loco::DataType::S32;
75
76 bool is_static_shape = true;
77
78 loco::TensorShape shape_by_input;
79 {
80 LUCI_ASSERT(node->shape(), "2nd input shape() should not be nullptr");
81
82 // Only support node's shape() is CircleConst with S32
83 // TODO support other node with other types
84 auto const_shape_node = dynamic_cast<luci::CircleConst *>(node->shape());
85 if (const_shape_node != nullptr)
86 {
87 LUCI_ASSERT(const_shape_node->dtype() == S32, "Only support int32 CircleConst");
88
89 shape_by_input.rank(const_shape_node->size<S32>());
90
91 for (uint32_t axis = 0; axis < shape_by_input.rank(); ++axis)
92 {
93 if (const_shape_node->at<S32>(axis) < 0)
94 {
95 shape_by_input.dim(axis).unset();
96 }
97 else if (const_shape_node->at<S32>(axis) == 0)
98 {
99 const auto node_tensor = loco::must_cast<luci::CircleNode *>(node->tensor());
100 // set dim value to input
101 if (node_tensor->shape_status() == luci::ShapeStatus::VALID && axis < node_tensor->rank())
102 shape_by_input.dim(axis) = node_tensor->dim(axis);
103 else
104 {
105 // stop to check if this case exist for debugging
106 INTERNAL_EXN("Check Reshape shape with 0");
107 }
108 }
109 else
110 {
111 shape_by_input.dim(axis).set(const_shape_node->at<S32>(axis));
112 }
113 // check valid or stop for debugging
114 LUCI_ASSERT(shape_by_input.dim(axis).value() > 0 || !shape_by_input.dim(axis).known(),
115 "Reshape infer shape is invalid.");
116 }
117 }
118 else
119 {
120 // NOTE assumption is that `shape` and `newShape` having same value.
121 // for non-existing `shape`, we can use `newShape` if it's valid
122 auto new_shape = node->newShape();
123 auto rank = new_shape->rank();
124 auto shape_dummy = dynamic_cast<luci::CircleOutputDummy *>(node->shape());
125 if (shape_dummy && rank > 0)
126 {
127 is_static_shape = true;
128 shape_by_input.rank(rank);
129 for (uint32_t i = 0; i < rank; ++i)
130 {
131 if (new_shape->dim(i) > 0)
132 shape_by_input.dim(i) = static_cast<uint32_t>(new_shape->dim(i));
133 else
134 {
135 is_static_shape = false;
136 shape_by_input.dim(i).unset();
137 }
138 }
139 }
140 else
141 {
142 auto shape_node = loco::must_cast<luci::CircleNode *>(node->shape());
143 assert(shape_node->rank() == 1);
144 // shape_node tensor values will provide new shape, like [2, 3, 4]
145 auto num_elements = shape_node->dim(0).value(); // above example will give 3
146 shape_by_input.rank(num_elements);
147 is_static_shape = false;
148 }
149 }
150 }
151
152 loco::TensorShape shape_by_attr;
153 {
154 shape_by_attr.rank(node->newShape()->rank());
155
156 for (uint32_t axis = 0; axis < shape_by_attr.rank(); ++axis)
157 {
158 shape_by_attr.dim(axis) = node->newShape()->dim(axis);
159 }
160 }
161
162 if (!(shape_by_input == shape_by_attr))
163 {
164 INFO(l) << "CircleReshape: Two new shape information mismatched : " << std::endl;
165 INFO(l) << " shape_by_input : " << shape_by_input << std::endl;
166 INFO(l) << " shape_by_attr : " << shape_by_attr << std::endl;
167 }
168
169 loco::TensorShape output_shape = shape_by_input;
170
171 // One of the dimensions can have special value -1, meaning its actual value should be inferred.
172 const auto input = loco::must_cast<luci::CircleNode *>(node->tensor());
173 const auto input_shape = circle_shape(input);
174 uint32_t input_element_count = 1;
175 uint32_t output_element_count = 1;
176 uint32_t unknown_dim_index = UINT32_MAX;
177 for (uint32_t i = 0; i < input_shape.rank(); ++i)
178 {
179 if (input_shape.dim(i).known())
180 input_element_count *= input_shape.dim(i).value();
181 else
182 is_static_shape = false;
183 }
184
185 if (is_static_shape)
186 {
187 for (uint32_t dim_index = 0; dim_index < output_shape.rank(); ++dim_index)
188 {
189 uint32_t dim_value = output_shape.dim(dim_index).value();
190 if (not output_shape.dim(dim_index).known())
191 {
192 LUCI_ASSERT(unknown_dim_index == UINT32_MAX, "More than one unknown dimension");
193 unknown_dim_index = dim_index;
194 }
195 else
196 {
197 if (!dim_value)
198 {
199 // refer https://github.com/Samsung/ONE/issues/14074#issuecomment-2370795003
200 // set dim value to follow input
201 if (dim_index < input_shape.rank())
202 dim_value = input_shape.dim(dim_index).value();
203 else
204 {
205 // stop to check if this case exist for debugging
206 INTERNAL_EXN("Check Reshape shape with 0");
207 }
208 }
209 output_element_count *= dim_value;
210 }
211 }
212 if (unknown_dim_index != UINT32_MAX)
213 {
214 output_shape.dim(unknown_dim_index) = input_element_count / output_element_count;
215 }
216 }
217
218 return output_shape;
219}
#define LOGGER(name)
Definition Log.h:65
#define INFO(name)
Definition Log.h:68
void set(uint32_t value)
Definition Dimension.h:53
Temporary DummyNode used with dangle CircleNode.
uint32_t rank(void) const
int32_t dim(uint32_t n) const
const Shape * newShape(void) const
loco::Node * shape(void) const
loco::Node * tensor(void) const
DataType
"scalar" value type
Definition DataType.h:27
const loco::DataType S32
uint32_t num_elements(const Shape &shape)
The number of elements of a feature map of a given shape.
Definition Shape.h:59

References luci::sinf::circle_shape(), loco::TensorShape::dim(), luci::CircleReshape::Shape::dim(), INFO, INTERNAL_EXN, loco::Dimension::known(), LOGGER, LUCI_ASSERT, luci::CircleReshape::newShape(), output_shape, loco::TensorShape::rank(), luci::CircleReshape::Shape::rank(), luci::sinf::S32, loco::Dimension::set(), luci::CircleReshape::shape(), luci::CircleReshape::tensor(), loco::Dimension::unset(), luci::VALID, and loco::Dimension::value().

◆ visit() [15/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleRsqrt node)
final

Definition at line 33 of file CircleRsqrt.cpp.

34{
35 const auto input_x = loco::must_cast<CircleNode *>(node->x());
36 const auto input_shape = circle_shape(input_x);
37 return input_shape;
38}
loco::Node * x(void) const
Definition CircleRsqrt.h:34

References luci::sinf::circle_shape(), and luci::CircleRsqrt::x().

◆ visit() [16/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleSoftmax node)
final

Definition at line 36 of file CircleSoftmax.cpp.

37{
38 const auto logits = loco::must_cast<luci::CircleNode *>(node->logits());
39
40 return sinf::circle_shape(logits);
41}
loco::Node * logits(void) const

References luci::sinf::circle_shape(), and luci::CircleSoftmax::logits().

◆ visit() [17/17]

loco::TensorShape luci::sinf::Algorithm::visit ( const luci::CircleStridedSlice node)
final

Definition at line 385 of file CircleStridedSlice.cpp.

386{
388
389 auto input_node = loco::must_cast<luci::CircleNode *>(node->input());
390
391 auto begin_node = loco::must_cast<luci::CircleNode *>(node->begin());
392 auto end_node = loco::must_cast<luci::CircleNode *>(node->end());
393 auto strides_node = loco::must_cast<luci::CircleNode *>(node->strides());
394
395 LUCI_ASSERT(begin_node->dtype() == S32, "Only support S32 for begin_node");
396 LUCI_ASSERT(end_node->dtype() == S32, "Only support S32 for end_node");
397 LUCI_ASSERT(strides_node->dtype() == S32, "Only support S32 for strides_node");
398
399 LUCI_ASSERT(begin_node->rank() == 1, "Only support rank 1 for begin_node");
400 LUCI_ASSERT(end_node->rank() == 1, "Only support rank 1 for end_node");
401 LUCI_ASSERT(strides_node->rank() == 1, "Only support rank 1 for strides_node");
402
403 auto begin_const = dynamic_cast<luci::CircleConst *>(node->begin());
404 auto end_const = dynamic_cast<luci::CircleConst *>(node->end());
405 auto strides_const = dynamic_cast<luci::CircleConst *>(node->strides());
406 // TODO support non-const strides_node
407 if (strides_const == nullptr)
408 {
409 INTERNAL_EXN("StridedSlice strides node is not Constant");
410 }
411 if (begin_const == nullptr || end_const == nullptr)
412 {
413 // The dimensions of the output shape are all set to unknown.
414 output_shape.rank(input_node->rank());
415 return output_shape;
416 }
417
419
420 assert(begin_const->size<S32>() <= input_shape.rank());
421 assert(end_const->size<S32>() <= input_shape.rank());
422 assert(strides_const->size<S32>() <= input_shape.rank());
423
424 StridedSliceContext op_context(node);
425 auto op_params = BuildStridedSliceParams(&op_context);
426 auto &effective_input_shape = op_context.effective_input_shape;
427 std::vector<int64_t> output_shape_vector;
428 std::vector<bool> output_known_vector;
429
430 for (int32_t idx = effective_input_shape.rank() - 1; idx >= 0; --idx)
431 {
432 int32_t stride = op_params.strides[idx];
433 LUCI_ASSERT(stride != 0, "stride value has to be non-zero");
434
435 int64_t begin = StartForAxis(op_params, effective_input_shape, idx);
436 int64_t end = StopForAxis(op_params, effective_input_shape, idx, begin);
437
438 // When shrinking an axis, the end position does not matter (and can be
439 // incorrect when negative indexing is used, see Issue #19260). Always use
440 // begin + 1 to generate a length 1 slice, since begin has
441 // already been adjusted for negative indices by GetBeginValueAtIndex.
442 const bool shrink_axis = op_params.shrink_axis_mask & (1 << idx);
443 if (shrink_axis)
444 {
445 end = begin + 1;
446 }
447
448 // This is valid for both positive and negative strides
449 int64_t dim_shape = std::ceil((end - begin) / static_cast<float>(stride));
450 dim_shape = dim_shape < 0 ? 0 : dim_shape;
451 if (!shrink_axis)
452 {
453 output_shape_vector.push_back(dim_shape);
454 output_known_vector.push_back(effective_input_shape.dim(idx).known());
455 }
456 }
457
458 auto shape_size = output_shape_vector.size();
459 output_shape.rank(shape_size);
460 for (uint32_t idx = 0; idx < shape_size; ++idx)
461 {
462 bool known = output_known_vector[shape_size - 1u - idx];
463 if (not known)
464 continue;
465 int64_t dim = output_shape_vector.at(shape_size - 1u - idx);
466 LUCI_ASSERT(0 <= dim && dim < 0xfffffffL, "Dimension size exceeds limit");
467 // reverse copy
468 output_shape.dim(idx) = static_cast<uint32_t>(dim);
469 }
470
471 return output_shape;
472}
loco::Node * input(void) const
loco::Node * begin(void) const
loco::Node * strides(void) const
loco::Node * end(void) const
int64_t StopForAxis(const StridedSliceParams &params, const loco::TensorShape &input_shape, int64_t axis, int64_t start_for_axis)
int64_t StartForAxis(const StridedSliceParams &params, const loco::TensorShape &input_shape, int64_t axis)
StridedSliceParams BuildStridedSliceParams(StridedSliceContext *op_context)
CircleInput * input_node(loco::Graph *g, const loco::GraphInputIndex &index)
Find a Pull node with a given input index.
ShapeIterator end(const Shape &s)
int32_t begin[5]
Definition Slice.cpp:33

References luci::CircleStridedSlice::begin(), begin, luci::sinf::BuildStridedSliceParams(), luci::sinf::circle_shape(), luci::sinf::StridedSliceContext::effective_input_shape, luci::CircleStridedSlice::end(), luci::CircleStridedSlice::input(), luci::input_node(), INTERNAL_EXN, LUCI_ASSERT, output_shape, loco::TensorShape::rank(), luci::sinf::S32, luci::sinf::StartForAxis(), luci::sinf::StopForAxis(), and luci::CircleStridedSlice::strides().


The documentation for this class was generated from the following files: