| 1836 | } // namespace |
| 1837 | |
| 1838 | Status SliceShape(InferenceContext* c) { |
| 1839 | ShapeHandle input = c->input(0); |
| 1840 | ShapeHandle begin_shape; |
| 1841 | TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &begin_shape)); |
| 1842 | ShapeHandle sizes_shape; |
| 1843 | TF_RETURN_IF_ERROR(c->WithRank(c->input(2), 1, &sizes_shape)); |
| 1844 | |
| 1845 | // Merge to check compatibility of begin and sizes tensors. |
| 1846 | TF_RETURN_IF_ERROR(c->Merge(begin_shape, sizes_shape, &begin_shape)); |
| 1847 | |
| 1848 | DimensionHandle ndims = c->Dim(begin_shape, 0); |
| 1849 | if (c->ValueKnown(ndims)) { |
| 1850 | TF_RETURN_IF_ERROR(c->WithRank(input, c->Value(ndims), &input)); |
| 1851 | } |
| 1852 | |
| 1853 | // NOTE(mrry): Use MakeShapeFromShapeTensor to handle partially-known |
| 1854 | // values, even though the `begin` value does not represent a shape. |
| 1855 | ShapeHandle begin_value; |
| 1856 | TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(1, &begin_value)); |
| 1857 | |
| 1858 | // We check the tensor value here and will only use |
| 1859 | // `MakeShapeFromShapeTensor` when `sizes_value` is null. |
| 1860 | // The reason is that `sizes` might contain -1, which can't |
| 1861 | // be represented (-1 in the ShapeHandle would mean "unknown"). |
| 1862 | const Tensor* sizes_value = c->input_tensor(2); |
| 1863 | |
| 1864 | if (sizes_value != nullptr) { |
| 1865 | TF_RETURN_IF_ERROR( |
| 1866 | c->WithRank(begin_value, sizes_value->NumElements(), &begin_value)); |
| 1867 | std::vector<DimensionHandle> dims; |
| 1868 | // If the begin and sizes tensors are available, then |
| 1869 | // we can be precise about the shape of the output. |
| 1870 | if (sizes_value->dtype() == DT_INT64) { |
| 1871 | TF_RETURN_IF_ERROR( |
| 1872 | SliceHelper<int64>(c, begin_value, sizes_value, &dims)); |
| 1873 | } else { |
| 1874 | TF_RETURN_IF_ERROR( |
| 1875 | SliceHelper<int32>(c, begin_value, sizes_value, &dims)); |
| 1876 | } |
| 1877 | c->set_output(0, c->MakeShape(dims)); |
| 1878 | return Status::OK(); |
| 1879 | } else { |
| 1880 | // In case `sizes` is not available (`sizes_value` is null), |
| 1881 | // we could try to use `MakeShapeFromShapeTensor` here. |
| 1882 | // If sizes contain -1, we will simply consider it as `Unknown`. |
| 1883 | // This is less than ideal but still an improvement of shape inference. |
| 1884 | // The following is an example that returns [None, 1, None] with this |
| 1885 | // code path: |
| 1886 | // z = tf.zeros((1, 2, 3)) |
| 1887 | // m = tf.slice(z, [0, 0, 0], [tf.constant(1) + 0, 1, -1]) |
| 1888 | // m.get_shape().as_list() |
| 1889 | ShapeHandle sizes_value; |
| 1890 | TF_RETURN_IF_ERROR(c->MakeShapeFromShapeTensor(2, &sizes_value)); |
| 1891 | if (c->RankKnown(sizes_value)) { |
| 1892 | TF_RETURN_IF_ERROR( |
| 1893 | c->WithRank(begin_value, c->Rank(sizes_value), &begin_value)); |
| 1894 | std::vector<DimensionHandle> dims; |
| 1895 | dims.reserve(c->Rank(sizes_value)); |
nothing calls this directly
no test coverage detected