Reshape specific axes of a LabeledTensor. Non-indicated axes remain in their original locations. Args: labeled_tensor: The input tensor. existing_axes: List of axis names found on the input tensor. These must appear sequentially in the list of axis names on the input. In other
(labeled_tensor, existing_axes, new_axes, name=None)
| 299 | tc.Collection(tc.Union(string_types, core.AxisLike)), |
| 300 | tc.Optional(string_types)) |
| 301 | def reshape(labeled_tensor, existing_axes, new_axes, name=None): |
| 302 | """Reshape specific axes of a LabeledTensor. |
| 303 | |
| 304 | Non-indicated axes remain in their original locations. |
| 305 | |
| 306 | Args: |
| 307 | labeled_tensor: The input tensor. |
| 308 | existing_axes: List of axis names found on the input tensor. These must |
| 309 | appear sequentially in the list of axis names on the input. In other |
| 310 | words, they must be a valid slice of `list(labeled_tensor.axes.keys())`. |
| 311 | new_axes: List of strings, tuples of (axis_name, axis_value) or Axis objects |
| 312 | providing new axes with which to replace `existing_axes` in the reshaped |
| 313 | result. At most one element of `new_axes` may be a string, indicating an |
| 314 | axis with unknown size. |
| 315 | name: Optional op name. |
| 316 | |
| 317 | Returns: |
| 318 | The reshaped LabeledTensor. |
| 319 | |
| 320 | Raises: |
| 321 | ValueError: If `existing_axes` are not all axes on the input, or if more |
| 322 | than one of `new_axes` has unknown size. |
| 323 | AxisOrderError: If `existing_axes` are not a slice of axis names on the |
| 324 | input. |
| 325 | """ |
| 326 | with ops.name_scope(name, 'lt_reshape', [labeled_tensor]) as scope: |
| 327 | labeled_tensor = core.convert_to_labeled_tensor(labeled_tensor) |
| 328 | |
| 329 | original_axis_names = list(labeled_tensor.axes.keys()) |
| 330 | existing_axes = list(existing_axes) |
| 331 | if not set(existing_axes) <= set(original_axis_names): |
| 332 | raise ValueError('existing_axes %r are not contained in the set of axis ' |
| 333 | 'names %r on the input labeled tensor' % |
| 334 | (existing_axes, original_axis_names)) |
| 335 | |
| 336 | start = original_axis_names.index(existing_axes[0]) |
| 337 | stop = original_axis_names.index(existing_axes[-1]) + 1 |
| 338 | |
| 339 | if existing_axes != original_axis_names[start:stop]: |
| 340 | # We could support existing_axes that aren't a slice by using transpose, |
| 341 | # but that could lead to unpredictable performance consequences because |
| 342 | # transposes are not free in TensorFlow. If we did transpose |
| 343 | # automatically, the user might never realize that their data is being |
| 344 | # produced with the wrong order. (The later will occur with some frequency |
| 345 | # because of how broadcasting automatically choose axis order.) |
| 346 | # So for now we've taken the strict approach. |
| 347 | raise core.AxisOrderError( |
| 348 | 'existing_axes %r are not a slice of axis names %r on the input ' |
| 349 | 'labeled tensor. Use `transpose` or `impose_axis_order` to reorder ' |
| 350 | 'axes on the input explicitly.' % |
| 351 | (existing_axes, original_axis_names)) |
| 352 | |
| 353 | if sum(isinstance(axis, string_types) for axis in new_axes) > 1: |
| 354 | raise ValueError( |
| 355 | 'at most one axis in new_axes can have unknown size. All other ' |
| 356 | 'axes must have an indicated integer size or labels: %r' % new_axes) |
| 357 | |
| 358 | original_values = list(labeled_tensor.axes.values()) |
no test coverage detected