| 1135 | } |
| 1136 | |
| 1137 | bool NN::turnQuantize(Module* module, const int bits, NN::FeatureScaleStatMethod featureScaleStatMethod, NN::ScaleUpdateMethod scaleUpdateMethod, bool winogradOpt) { |
| 1138 | if (nullptr == module || module->type() != PIPELINE_MODULE) { |
| 1139 | MNN_ERROR("Invalide module for quantized\n"); |
| 1140 | return false; |
| 1141 | } |
| 1142 | auto pipModule = static_cast<PipelineModule*>(module); |
| 1143 | std::vector<int> needEraseIndices; |
| 1144 | for (int i = 0; i < pipModule->mSubModules.size(); i++) { |
| 1145 | auto& m = pipModule->mSubModules[i]; |
| 1146 | auto& theModule = std::get<0>(m); |
| 1147 | auto moduleType = theModule->type(); |
| 1148 | //auto& inputIndices = std::get<1>(m); |
| 1149 | auto& outputIndices = std::get<2>(m); |
| 1150 | |
| 1151 | if (moduleType == "Conv" && i < pipModule->mSubModules.size() - 1) { |
| 1152 | auto& p1 = pipModule->mSubModules[i+1]; |
| 1153 | auto p1Module = std::get<0>(p1); |
| 1154 | auto& p1ModuleType = p1Module->type(); |
| 1155 | auto& p1InputIndices = std::get<1>(p1); |
| 1156 | auto& p1OutputIndices = std::get<2>(p1); |
| 1157 | |
| 1158 | auto convOutputCount = pipModule->countOutputReference(outputIndices); |
| 1159 | bool convSingleOutputReference = ((outputIndices.size() == 1) && (convOutputCount[0] == 1)); |
| 1160 | |
| 1161 | // only conv |
| 1162 | if ((!convSingleOutputReference) || (p1ModuleType == "Conv") || |
| 1163 | (p1ModuleType != "BatchNorm" && p1ModuleType != "ReLU" && p1ModuleType != "ReLU6")) { |
| 1164 | theModule.reset(NN::ConvBNReluFused({theModule}, featureScaleStatMethod, scaleUpdateMethod, bits, winogradOpt)); |
| 1165 | pipModule->registerModel({theModule}); |
| 1166 | continue; |
| 1167 | } |
| 1168 | // conv + bn + ? |
| 1169 | if (p1ModuleType == "BatchNorm") { |
| 1170 | bool convBnConnected = ((convSingleOutputReference) && (p1InputIndices.size() == 1) && (p1InputIndices[0] == outputIndices[0])); |
| 1171 | if (!convBnConnected) { |
| 1172 | theModule.reset(NN::ConvBNReluFused({theModule}, featureScaleStatMethod, scaleUpdateMethod, bits, winogradOpt)); |
| 1173 | pipModule->registerModel({theModule}); |
| 1174 | continue; |
| 1175 | } |
| 1176 | |
| 1177 | // last conv + bn |
| 1178 | if (i == pipModule->mSubModules.size() - 2) { |
| 1179 | theModule.reset(NN::ConvBNReluFused({theModule, p1Module}, featureScaleStatMethod, scaleUpdateMethod, bits, winogradOpt)); |
| 1180 | pipModule->registerModel({theModule}); |
| 1181 | outputIndices = p1OutputIndices; |
| 1182 | needEraseIndices.emplace_back(i + 1); |
| 1183 | continue; |
| 1184 | } |
| 1185 | // maybe there is a relu or relu6 after conv + bn |
| 1186 | auto& p2 = pipModule->mSubModules[i+2]; |
| 1187 | auto& p2Module = std::get<0>(p2); |
| 1188 | auto p2ModuleType = p2Module->type(); |
| 1189 | auto& p2InputIndices = std::get<1>(p2); |
| 1190 | auto& p2OutputIndices = std::get<2>(p2); |
| 1191 | |
| 1192 | auto bnOutputCount = pipModule->countOutputReference(p1OutputIndices); |
| 1193 | bool bnSingleOutputReference = ((p1OutputIndices.size() == 1) && (bnOutputCount[0] == 1)); |
| 1194 |
nothing calls this directly
no test coverage detected