}
}
+TestDataRandomFiller::TestDataRandomFiller(
+ const NetDef& net,
+ const std::vector<std::vector<std::vector<int64_t>>>& inputDims,
+ const std::vector<std::vector<std::string>>& inputTypes)
+ : DataRandomFiller() {
+ std::unordered_set<std::string> outputNames;
+ // Determine blobs that are outputs of some ops (intermediate blobs).
+ for (auto opIdx = 0; opIdx < net.op_size(); ++opIdx) {
+ const auto& op = net.op(opIdx);
+ for (auto outputIdx = 0; outputIdx < op.output_size(); ++outputIdx) {
+ outputNames.emplace(op.output(outputIdx));
+ }
+ }
+ // Determine ops that have non-intermediate inputs.
+ std::unordered_set<size_t> opWithRequiredInputs;
+ for (auto opIdx = 0; opIdx < net.op_size(); ++opIdx) {
+ const auto& op = net.op(opIdx);
+ for (auto inputIdx = 0; inputIdx < op.input_size(); ++inputIdx) {
+ if (!outputNames.count(op.input(inputIdx))) {
+ opWithRequiredInputs.emplace(opIdx);
+ break;
+ }
+ }
+ }
+
+ CAFFE_ENFORCE_EQ(inputDims.size(), opWithRequiredInputs.size());
+ CAFFE_ENFORCE_EQ(inputTypes.size(), opWithRequiredInputs.size());
+
+ int counter = 0;
+ for (auto opIdx = 0; opIdx < net.op_size(); ++opIdx) {
+ if (!opWithRequiredInputs.count(opIdx)) {
+ // Skip intermediate ops.
+ continue;
+ }
+ const auto& op = net.op(opIdx);
+ const auto& op_dims = inputDims[counter];
+ const auto& op_types = inputTypes[counter];
+ ++counter;
+
+ int countRequiredInputs = 0;
+ for (auto inputIdx = 0; inputIdx < op.input_size(); ++inputIdx) {
+ if (!outputNames.count(op.input(inputIdx))) {
+ ++countRequiredInputs;
+ }
+ }
+
+ CAFFE_ENFORCE(
+ op_dims.size() == countRequiredInputs,
+ op.name() + " has " + c10::to_string(op.input_size()) +
+ " (required) inputs; while the input dimension size is " +
+ c10::to_string(op_dims.size()));
+ CAFFE_ENFORCE(
+ op_types.size() == countRequiredInputs,
+ op.name() + " has " + c10::to_string(op.input_size()) +
+ " (required) inputs; while the input type size is " +
+ c10::to_string(op_types.size()));
+
+ int dimCounter = 0;
+ for (auto inputIdx = 0; inputIdx < op.input_size(); ++inputIdx) {
+ auto inputName = op.input(inputIdx);
+ if (outputNames.count(inputName)) {
+ // Skip intermediate inputs.
+ continue;
+ }
+ inputs_[inputName] = std::make_pair(
+ get_tensor_filler(op, dimCounter, op_dims), op_types[dimCounter]);
+ ++dimCounter;
+ }
+ }
+ CAFFE_ENFORCE(inputs_.size() > 0, "Empty input for run net");
+ // generate input names
+ for (const auto& input : inputs_) {
+ input_names_.push_back(input.first);
+ }
+}
+
+void TestDataRandomFiller::fillInputToWorkspace(Workspace* workspace) const {
+ for (auto& name : input_names_) {
+ const auto& it = inputs_.find(name);
+ CAFFE_ENFORCE(it != inputs_.end());
+ auto* tensor =
+ BlobGetMutableTensor(workspace->CreateBlob(name), caffe2::CPU);
+ fill_with_type(it->second.first, it->second.second, tensor);
+ }
+}
+
} // namespace emulator
} // namespace caffe2
void fill_parameter(Workspace* ws) const override;
- private:
+ protected:
+ DataRandomFiller() {}
+
TensorFiller get_tensor_filler(
const OperatorDef& op_def,
int input_index,
std::unordered_map<std::string, filler_type_pair_t> inputs_;
};
+// A DataRandomFiller that is more convenient to use in unit tests.
+// Callers just need to supply input dimensions and types for non-intermediate
+// blobs.
+// It also treats parameters the same way as non-intermediate inputs (no
+// handling of parameters separately).
+class TestDataRandomFiller : public DataRandomFiller {
+ public:
+ TestDataRandomFiller(
+ const NetDef& net,
+ const std::vector<std::vector<std::vector<int64_t>>>& inputDims,
+ const std::vector<std::vector<std::string>>& inputTypes);
+
+ // Fill input directly to the workspace.
+ void fillInputToWorkspace(Workspace* workspace) const;
+};
+
} // namespace emulator
} // namespace caffe2