| 365 | } |
| 366 | |
| 367 | Status ComputeConv2DDimension(const Conv2DParameters& params, |
| 368 | const Tensor& input, const Tensor& filter, |
| 369 | Conv2DDimensions* dimensions) { |
| 370 | // Check that 2D convolution input and filter have exactly 4 dimensions. |
| 371 | TF_REQUIRES(input.dims() == 4, |
| 372 | errors::InvalidArgument("input must be 4-dimensional", |
| 373 | input.shape().DebugString())); |
| 374 | TF_REQUIRES(filter.dims() == 4, |
| 375 | errors::InvalidArgument("filter must be 4-dimensional: ", |
| 376 | filter.shape().DebugString())); |
| 377 | for (int i = 0; i < 3; i++) { |
| 378 | TF_REQUIRES( |
| 379 | FastBoundsCheck(filter.dim_size(i), std::numeric_limits<int>::max()), |
| 380 | errors::InvalidArgument("filter too large")); |
| 381 | } |
| 382 | |
| 383 | // The last dimension for input is in_depth. Check that it is the same as the |
| 384 | // filter's in_depth or it is evenly divisible by filter's in_depth. |
| 385 | const int64 in_depth_raw = GetTensorDim(input, params.data_format, 'C'); |
| 386 | const int64 patch_depth_raw = filter.dim_size(2); |
| 387 | TF_REQUIRES(FastBoundsCheck(in_depth_raw, std::numeric_limits<int>::max()), |
| 388 | errors::InvalidArgument("Input depth too large")); |
| 389 | TF_REQUIRES(FastBoundsCheck(patch_depth_raw, std::numeric_limits<int>::max()), |
| 390 | errors::InvalidArgument("Patch depth too large")); |
| 391 | const int in_depth = static_cast<int>(in_depth_raw); |
| 392 | const int patch_depth = static_cast<int>(patch_depth_raw); |
| 393 | TF_REQUIRES(in_depth % patch_depth == 0, |
| 394 | errors::InvalidArgument( |
| 395 | "input depth must be evenly divisible by filter depth: ", |
| 396 | in_depth, " vs ", patch_depth)); |
| 397 | |
| 398 | // The last dimension for filter is out_depth. |
| 399 | const int out_depth = static_cast<int>(filter.dim_size(3)); |
| 400 | |
| 401 | // The second dimension for input is rows/height. |
| 402 | // The first dimension for filter is rows/height. |
| 403 | const int64 input_rows_raw = GetTensorDim(input, params.data_format, 'H'); |
| 404 | TF_REQUIRES(FastBoundsCheck(input_rows_raw, std::numeric_limits<int>::max()), |
| 405 | errors::InvalidArgument("Input rows too large")); |
| 406 | const int input_rows = static_cast<int>(input_rows_raw); |
| 407 | const int filter_rows = static_cast<int>(filter.dim_size(0)); |
| 408 | |
| 409 | // The third dimension for input is columns/width. |
| 410 | // The second dimension for filter is columns/width. |
| 411 | const int64 input_cols_raw = GetTensorDim(input, params.data_format, 'W'); |
| 412 | TF_REQUIRES(FastBoundsCheck(input_cols_raw, std::numeric_limits<int>::max()), |
| 413 | errors::InvalidArgument("Input cols too large")); |
| 414 | const int input_cols = static_cast<int>(input_cols_raw); |
| 415 | const int filter_cols = static_cast<int>(filter.dim_size(1)); |
| 416 | |
| 417 | // The first dimension for input is batch. |
| 418 | const int64 batch_raw = GetTensorDim(input, params.data_format, 'N'); |
| 419 | TF_REQUIRES(FastBoundsCheck(batch_raw, std::numeric_limits<int>::max()), |
| 420 | errors::InvalidArgument("batch is too large")); |
| 421 | const int batch = static_cast<int>(batch_raw); |
| 422 | |
| 423 | // Take the stride and dilation from the second and third dimensions only (we |
| 424 | // do not support striding or dilation on the batch or depth dimension). |