| 382 | } |
| 383 | |
| 384 | void ConvertConvOperator(const Model& model, const ConvOperator& src_op, |
| 385 | GraphDef* tensorflow_graph) { |
| 386 | const bool has_bias = src_op.inputs.size() >= 3; |
| 387 | string conv_output = src_op.outputs[0]; |
| 388 | if (has_bias) { |
| 389 | conv_output += "/conv"; |
| 390 | } |
| 391 | |
| 392 | tensorflow::NodeDef* conv2d_op = tensorflow_graph->add_node(); |
| 393 | conv2d_op->set_op("Conv2D"); |
| 394 | conv2d_op->set_name(conv_output); |
| 395 | *conv2d_op->add_input() = src_op.inputs[0]; |
| 396 | *conv2d_op->add_input() = src_op.inputs[1]; |
| 397 | (*conv2d_op->mutable_attr())["T"].set_type(DT_FLOAT); |
| 398 | const string& weights_array_name = |
| 399 | WalkUpToConstantArray(model, src_op.inputs[1]); |
| 400 | const auto& weights_array = model.GetArray(weights_array_name); |
| 401 | CHECK(weights_array.buffer->type == ArrayDataType::kFloat); |
| 402 | ConvertFloatTensorConst(model, weights_array_name, AxesOrder::kOHWI, |
| 403 | AxesOrder::kHWIO, tensorflow_graph); |
| 404 | auto& strides = (*conv2d_op->mutable_attr())["strides"]; |
| 405 | strides.mutable_list()->add_i(1); |
| 406 | strides.mutable_list()->add_i(src_op.stride_height); |
| 407 | strides.mutable_list()->add_i(src_op.stride_width); |
| 408 | strides.mutable_list()->add_i(1); |
| 409 | if ((src_op.dilation_width_factor != 1) || |
| 410 | (src_op.dilation_height_factor != 1)) { |
| 411 | auto& dilations = (*conv2d_op->mutable_attr())["dilations"]; |
| 412 | dilations.mutable_list()->add_i(1); |
| 413 | dilations.mutable_list()->add_i(src_op.dilation_height_factor); |
| 414 | dilations.mutable_list()->add_i(src_op.dilation_width_factor); |
| 415 | dilations.mutable_list()->add_i(1); |
| 416 | } |
| 417 | string padding; |
| 418 | if (src_op.padding.type == PaddingType::kSame) { |
| 419 | padding = "SAME"; |
| 420 | } else if (src_op.padding.type == PaddingType::kValid) { |
| 421 | padding = "VALID"; |
| 422 | } else { |
| 423 | LOG(FATAL) << "Bad padding (only SAME and VALID are supported)"; |
| 424 | } |
| 425 | (*conv2d_op->mutable_attr())["padding"].set_s(padding); |
| 426 | |
| 427 | if (has_bias) { |
| 428 | tensorflow::NodeDef* biasadd_op = tensorflow_graph->add_node(); |
| 429 | biasadd_op->set_op("BiasAdd"); |
| 430 | biasadd_op->set_name(src_op.outputs[0]); |
| 431 | biasadd_op->add_input(conv_output); |
| 432 | biasadd_op->add_input(src_op.inputs[2]); |
| 433 | (*biasadd_op->mutable_attr())["T"].set_type(DT_FLOAT); |
| 434 | CHECK(model.HasArray(src_op.inputs[2])); |
| 435 | const string& bias_array_name = |
| 436 | WalkUpToConstantArray(model, src_op.inputs[2]); |
| 437 | const auto& bias_array = model.GetArray(bias_array_name); |
| 438 | // TODO(b/62904716) Bias arrays should be 1-D, and used directly. |
| 439 | Shape bias_shape_1d = bias_array.shape(); |
| 440 | UnextendShape(&bias_shape_1d, 1); |
| 441 | CHECK(bias_array.buffer->type == ArrayDataType::kFloat); |
no test coverage detected