├── .gitignore ├── AlexNet ├── Bin.Files │ ├── bvlc_alexnet_aCaF.asmtLst.01.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.05.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.09.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.11.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.13.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.16.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.19.cbn │ ├── bvlc_alexnet_aCaF.asmtLst.22.cbn │ ├── bvlc_alexnet_aCaF.biasVec.01.bin │ ├── bvlc_alexnet_aCaF.biasVec.05.bin │ ├── bvlc_alexnet_aCaF.biasVec.09.bin │ ├── bvlc_alexnet_aCaF.biasVec.11.bin │ ├── bvlc_alexnet_aCaF.biasVec.13.bin │ ├── bvlc_alexnet_aCaF.biasVec.16.bin │ ├── bvlc_alexnet_aCaF.biasVec.19.bin │ ├── bvlc_alexnet_aCaF.biasVec.22.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.01.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.05.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.09.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.11.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.13.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.16.bin │ ├── bvlc_alexnet_aCaF.ctrdLst.19.bin │ └── bvlc_alexnet_aCaF.ctrdLst.22.bin └── imagenet_mean.single.bin ├── Bmp.Files ├── ILSVRC2012_val_00000001.BMP ├── ILSVRC2012_val_00000002.BMP ├── ILSVRC2012_val_00000003.BMP ├── ILSVRC2012_val_00000004.BMP ├── ILSVRC2012_val_00000005.BMP ├── ILSVRC2012_val_00000006.BMP ├── ILSVRC2012_val_00000007.BMP ├── ILSVRC2012_val_00000008.BMP ├── ILSVRC2012_val_00000009.BMP └── ILSVRC2012_val_00000010.BMP ├── Cls.Names ├── class_names.txt └── image_labels.txt ├── ILSVRC12.227x227.IMG └── lablVecTst.uint16.bin ├── Makefile ├── Makefile.native ├── Makefile.noblas ├── README.md ├── cpplint.py ├── include ├── BlasWrapper.h ├── BmpImgIO.h ├── CaffeEva.h ├── CaffeEvaWrapper.h ├── CaffePara.h ├── Common.h ├── FileIO.h ├── Matrix.h ├── StopWatch.h ├── UnitTest.h └── bitmap_image.hpp └── src ├── BlasWrapper.cc ├── BmpImgIO.cc ├── CaffeEva.cc ├── CaffeEvaWrapper.cc ├── CaffePara.cc ├── Main.cc └── UnitTest.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files generated by g++ 2 | *.o 3 | QuanCNN 4 | 5 | # ignore files for the original AlexNet model 6 | /AlexNet/Bin.Files/*.convKnl.* 7 | /AlexNet/Bin.Files/*.fcntWei.* 8 | 9 | # ignore the binary file containing 1k images 10 | /ILSVRC12.227x227.IMG/dataMatTst.single.bin 11 | 12 | -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.01.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.01.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.05.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.05.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.09.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.09.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.11.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.11.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.13.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.13.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.16.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.16.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.19.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.19.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.22.cbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.asmtLst.22.cbn -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.01.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.01.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.05.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.05.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.09.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.09.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.11.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.11.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.13.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.13.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.16.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.19.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.19.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.22.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.biasVec.22.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.01.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.01.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.05.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.05.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.09.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.09.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.11.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.11.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.13.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.13.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.16.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.19.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.19.bin -------------------------------------------------------------------------------- /AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.22.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/Bin.Files/bvlc_alexnet_aCaF.ctrdLst.22.bin -------------------------------------------------------------------------------- /AlexNet/imagenet_mean.single.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/AlexNet/imagenet_mean.single.bin -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000001.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000001.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000002.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000002.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000003.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000003.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000004.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000004.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000005.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000005.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000006.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000006.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000007.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000007.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000008.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000008.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000009.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000009.BMP -------------------------------------------------------------------------------- /Bmp.Files/ILSVRC2012_val_00000010.BMP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/Bmp.Files/ILSVRC2012_val_00000010.BMP -------------------------------------------------------------------------------- /Cls.Names/class_names.txt: -------------------------------------------------------------------------------- 1 | tench, Tinca tinca 2 | goldfish, Carassius auratus 3 | great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias 4 | tiger shark, Galeocerdo cuvieri 5 | hammerhead, hammerhead shark 6 | electric ray, crampfish, numbfish, torpedo 7 | stingray 8 | cock 9 | hen 10 | ostrich, Struthio camelus 11 | brambling, Fringilla montifringilla 12 | goldfinch, Carduelis carduelis 13 | house finch, linnet, Carpodacus mexicanus 14 | junco, snowbird 15 | indigo bunting, indigo finch, indigo bird, Passerina cyanea 16 | robin, American robin, Turdus migratorius 17 | bulbul 18 | jay 19 | magpie 20 | chickadee 21 | water ouzel, dipper 22 | kite 23 | bald eagle, American eagle, Haliaeetus leucocephalus 24 | vulture 25 | great grey owl, great gray owl, Strix nebulosa 26 | European fire salamander, Salamandra salamandra 27 | common newt, Triturus vulgaris 28 | eft 29 | spotted salamander, Ambystoma maculatum 30 | axolotl, mud puppy, Ambystoma mexicanum 31 | bullfrog, Rana catesbeiana 32 | tree frog, tree-frog 33 | tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui 34 | loggerhead, loggerhead turtle, Caretta caretta 35 | leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea 36 | mud turtle 37 | terrapin 38 | box turtle, box tortoise 39 | banded gecko 40 | common iguana, iguana, Iguana iguana 41 | American chameleon, anole, Anolis carolinensis 42 | whiptail, whiptail lizard 43 | agama 44 | frilled lizard, Chlamydosaurus kingi 45 | alligator lizard 46 | Gila monster, Heloderma suspectum 47 | green lizard, Lacerta viridis 48 | African chameleon, Chamaeleo chamaeleon 49 | Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis 50 | African crocodile, Nile crocodile, Crocodylus niloticus 51 | American alligator, Alligator mississipiensis 52 | triceratops 53 | thunder snake, worm snake, Carphophis amoenus 54 | ringneck snake, ring-necked snake, ring snake 55 | hognose snake, puff adder, sand viper 56 | green snake, grass snake 57 | king snake, kingsnake 58 | garter snake, grass snake 59 | water snake 60 | vine snake 61 | night snake, Hypsiglena torquata 62 | boa constrictor, Constrictor constrictor 63 | rock python, rock snake, Python sebae 64 | Indian cobra, Naja naja 65 | green mamba 66 | sea snake 67 | horned viper, cerastes, sand viper, horned asp, Cerastes cornutus 68 | diamondback, diamondback rattlesnake, Crotalus adamanteus 69 | sidewinder, horned rattlesnake, Crotalus cerastes 70 | trilobite 71 | harvestman, daddy longlegs, Phalangium opilio 72 | scorpion 73 | black and gold garden spider, Argiope aurantia 74 | barn spider, Araneus cavaticus 75 | garden spider, Aranea diademata 76 | black widow, Latrodectus mactans 77 | tarantula 78 | wolf spider, hunting spider 79 | tick 80 | centipede 81 | black grouse 82 | ptarmigan 83 | ruffed grouse, partridge, Bonasa umbellus 84 | prairie chicken, prairie grouse, prairie fowl 85 | peacock 86 | quail 87 | partridge 88 | African grey, African gray, Psittacus erithacus 89 | macaw 90 | sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita 91 | lorikeet 92 | coucal 93 | bee eater 94 | hornbill 95 | hummingbird 96 | jacamar 97 | toucan 98 | drake 99 | red-breasted merganser, Mergus serrator 100 | goose 101 | black swan, Cygnus atratus 102 | tusker 103 | echidna, spiny anteater, anteater 104 | platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus 105 | wallaby, brush kangaroo 106 | koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus 107 | wombat 108 | jellyfish 109 | sea anemone, anemone 110 | brain coral 111 | flatworm, platyhelminth 112 | nematode, nematode worm, roundworm 113 | conch 114 | snail 115 | slug 116 | sea slug, nudibranch 117 | chiton, coat-of-mail shell, sea cradle, polyplacophore 118 | chambered nautilus, pearly nautilus, nautilus 119 | Dungeness crab, Cancer magister 120 | rock crab, Cancer irroratus 121 | fiddler crab 122 | king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica 123 | American lobster, Northern lobster, Maine lobster, Homarus americanus 124 | spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish 125 | crayfish, crawfish, crawdad, crawdaddy 126 | hermit crab 127 | isopod 128 | white stork, Ciconia ciconia 129 | black stork, Ciconia nigra 130 | spoonbill 131 | flamingo 132 | little blue heron, Egretta caerulea 133 | American egret, great white heron, Egretta albus 134 | bittern 135 | crane 136 | limpkin, Aramus pictus 137 | European gallinule, Porphyrio porphyrio 138 | American coot, marsh hen, mud hen, water hen, Fulica americana 139 | bustard 140 | ruddy turnstone, Arenaria interpres 141 | red-backed sandpiper, dunlin, Erolia alpina 142 | redshank, Tringa totanus 143 | dowitcher 144 | oystercatcher, oyster catcher 145 | pelican 146 | king penguin, Aptenodytes patagonica 147 | albatross, mollymawk 148 | grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus 149 | killer whale, killer, orca, grampus, sea wolf, Orcinus orca 150 | dugong, Dugong dugon 151 | sea lion 152 | Chihuahua 153 | Japanese spaniel 154 | Maltese dog, Maltese terrier, Maltese 155 | Pekinese, Pekingese, Peke 156 | Shih-Tzu 157 | Blenheim spaniel 158 | papillon 159 | toy terrier 160 | Rhodesian ridgeback 161 | Afghan hound, Afghan 162 | basset, basset hound 163 | beagle 164 | bloodhound, sleuthhound 165 | bluetick 166 | black-and-tan coonhound 167 | Walker hound, Walker foxhound 168 | English foxhound 169 | redbone 170 | borzoi, Russian wolfhound 171 | Irish wolfhound 172 | Italian greyhound 173 | whippet 174 | Ibizan hound, Ibizan Podenco 175 | Norwegian elkhound, elkhound 176 | otterhound, otter hound 177 | Saluki, gazelle hound 178 | Scottish deerhound, deerhound 179 | Weimaraner 180 | Staffordshire bullterrier, Staffordshire bull terrier 181 | American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier 182 | Bedlington terrier 183 | Border terrier 184 | Kerry blue terrier 185 | Irish terrier 186 | Norfolk terrier 187 | Norwich terrier 188 | Yorkshire terrier 189 | wire-haired fox terrier 190 | Lakeland terrier 191 | Sealyham terrier, Sealyham 192 | Airedale, Airedale terrier 193 | cairn, cairn terrier 194 | Australian terrier 195 | Dandie Dinmont, Dandie Dinmont terrier 196 | Boston bull, Boston terrier 197 | miniature schnauzer 198 | giant schnauzer 199 | standard schnauzer 200 | Scotch terrier, Scottish terrier, Scottie 201 | Tibetan terrier, chrysanthemum dog 202 | silky terrier, Sydney silky 203 | soft-coated wheaten terrier 204 | West Highland white terrier 205 | Lhasa, Lhasa apso 206 | flat-coated retriever 207 | curly-coated retriever 208 | golden retriever 209 | Labrador retriever 210 | Chesapeake Bay retriever 211 | German short-haired pointer 212 | vizsla, Hungarian pointer 213 | English setter 214 | Irish setter, red setter 215 | Gordon setter 216 | Brittany spaniel 217 | clumber, clumber spaniel 218 | English springer, English springer spaniel 219 | Welsh springer spaniel 220 | cocker spaniel, English cocker spaniel, cocker 221 | Sussex spaniel 222 | Irish water spaniel 223 | kuvasz 224 | schipperke 225 | groenendael 226 | malinois 227 | briard 228 | kelpie 229 | komondor 230 | Old English sheepdog, bobtail 231 | Shetland sheepdog, Shetland sheep dog, Shetland 232 | collie 233 | Border collie 234 | Bouvier des Flandres, Bouviers des Flandres 235 | Rottweiler 236 | German shepherd, German shepherd dog, German police dog, alsatian 237 | Doberman, Doberman pinscher 238 | miniature pinscher 239 | Greater Swiss Mountain dog 240 | Bernese mountain dog 241 | Appenzeller 242 | EntleBucher 243 | boxer 244 | bull mastiff 245 | Tibetan mastiff 246 | French bulldog 247 | Great Dane 248 | Saint Bernard, St Bernard 249 | Eskimo dog, husky 250 | malamute, malemute, Alaskan malamute 251 | Siberian husky 252 | dalmatian, coach dog, carriage dog 253 | affenpinscher, monkey pinscher, monkey dog 254 | basenji 255 | pug, pug-dog 256 | Leonberg 257 | Newfoundland, Newfoundland dog 258 | Great Pyrenees 259 | Samoyed, Samoyede 260 | Pomeranian 261 | chow, chow chow 262 | keeshond 263 | Brabancon griffon 264 | Pembroke, Pembroke Welsh corgi 265 | Cardigan, Cardigan Welsh corgi 266 | toy poodle 267 | miniature poodle 268 | standard poodle 269 | Mexican hairless 270 | timber wolf, grey wolf, gray wolf, Canis lupus 271 | white wolf, Arctic wolf, Canis lupus tundrarum 272 | red wolf, maned wolf, Canis rufus, Canis niger 273 | coyote, prairie wolf, brush wolf, Canis latrans 274 | dingo, warrigal, warragal, Canis dingo 275 | dhole, Cuon alpinus 276 | African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus 277 | hyena, hyaena 278 | red fox, Vulpes vulpes 279 | kit fox, Vulpes macrotis 280 | Arctic fox, white fox, Alopex lagopus 281 | grey fox, gray fox, Urocyon cinereoargenteus 282 | tabby, tabby cat 283 | tiger cat 284 | Persian cat 285 | Siamese cat, Siamese 286 | Egyptian cat 287 | cougar, puma, catamount, mountain lion, painter, panther, Felis concolor 288 | lynx, catamount 289 | leopard, Panthera pardus 290 | snow leopard, ounce, Panthera uncia 291 | jaguar, panther, Panthera onca, Felis onca 292 | lion, king of beasts, Panthera leo 293 | tiger, Panthera tigris 294 | cheetah, chetah, Acinonyx jubatus 295 | brown bear, bruin, Ursus arctos 296 | American black bear, black bear, Ursus americanus, Euarctos americanus 297 | ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus 298 | sloth bear, Melursus ursinus, Ursus ursinus 299 | mongoose 300 | meerkat, mierkat 301 | tiger beetle 302 | ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle 303 | ground beetle, carabid beetle 304 | long-horned beetle, longicorn, longicorn beetle 305 | leaf beetle, chrysomelid 306 | dung beetle 307 | rhinoceros beetle 308 | weevil 309 | fly 310 | bee 311 | ant, emmet, pismire 312 | grasshopper, hopper 313 | cricket 314 | walking stick, walkingstick, stick insect 315 | cockroach, roach 316 | mantis, mantid 317 | cicada, cicala 318 | leafhopper 319 | lacewing, lacewing fly 320 | dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk 321 | damselfly 322 | admiral 323 | ringlet, ringlet butterfly 324 | monarch, monarch butterfly, milkweed butterfly, Danaus plexippus 325 | cabbage butterfly 326 | sulphur butterfly, sulfur butterfly 327 | lycaenid, lycaenid butterfly 328 | starfish, sea star 329 | sea urchin 330 | sea cucumber, holothurian 331 | wood rabbit, cottontail, cottontail rabbit 332 | hare 333 | Angora, Angora rabbit 334 | hamster 335 | porcupine, hedgehog 336 | fox squirrel, eastern fox squirrel, Sciurus niger 337 | marmot 338 | beaver 339 | guinea pig, Cavia cobaya 340 | sorrel 341 | zebra 342 | hog, pig, grunter, squealer, Sus scrofa 343 | wild boar, boar, Sus scrofa 344 | warthog 345 | hippopotamus, hippo, river horse, Hippopotamus amphibius 346 | ox 347 | water buffalo, water ox, Asiatic buffalo, Bubalus bubalis 348 | bison 349 | ram, tup 350 | bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis 351 | ibex, Capra ibex 352 | hartebeest 353 | impala, Aepyceros melampus 354 | gazelle 355 | Arabian camel, dromedary, Camelus dromedarius 356 | llama 357 | weasel 358 | mink 359 | polecat, fitch, foulmart, foumart, Mustela putorius 360 | black-footed ferret, ferret, Mustela nigripes 361 | otter 362 | skunk, polecat, wood pussy 363 | badger 364 | armadillo 365 | three-toed sloth, ai, Bradypus tridactylus 366 | orangutan, orang, orangutang, Pongo pygmaeus 367 | gorilla, Gorilla gorilla 368 | chimpanzee, chimp, Pan troglodytes 369 | gibbon, Hylobates lar 370 | siamang, Hylobates syndactylus, Symphalangus syndactylus 371 | guenon, guenon monkey 372 | patas, hussar monkey, Erythrocebus patas 373 | baboon 374 | macaque 375 | langur 376 | colobus, colobus monkey 377 | proboscis monkey, Nasalis larvatus 378 | marmoset 379 | capuchin, ringtail, Cebus capucinus 380 | howler monkey, howler 381 | titi, titi monkey 382 | spider monkey, Ateles geoffroyi 383 | squirrel monkey, Saimiri sciureus 384 | Madagascar cat, ring-tailed lemur, Lemur catta 385 | indri, indris, Indri indri, Indri brevicaudatus 386 | Indian elephant, Elephas maximus 387 | African elephant, Loxodonta africana 388 | lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens 389 | giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca 390 | barracouta, snoek 391 | eel 392 | coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch 393 | rock beauty, Holocanthus tricolor 394 | anemone fish 395 | sturgeon 396 | gar, garfish, garpike, billfish, Lepisosteus osseus 397 | lionfish 398 | puffer, pufferfish, blowfish, globefish 399 | abacus 400 | abaya 401 | academic gown, academic robe, judge's robe 402 | accordion, piano accordion, squeeze box 403 | acoustic guitar 404 | aircraft carrier, carrier, flattop, attack aircraft carrier 405 | airliner 406 | airship, dirigible 407 | altar 408 | ambulance 409 | amphibian, amphibious vehicle 410 | analog clock 411 | apiary, bee house 412 | apron 413 | ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin 414 | assault rifle, assault gun 415 | backpack, back pack, knapsack, packsack, rucksack, haversack 416 | bakery, bakeshop, bakehouse 417 | balance beam, beam 418 | balloon 419 | ballpoint, ballpoint pen, ballpen, Biro 420 | Band Aid 421 | banjo 422 | bannister, banister, balustrade, balusters, handrail 423 | barbell 424 | barber chair 425 | barbershop 426 | barn 427 | barometer 428 | barrel, cask 429 | barrow, garden cart, lawn cart, wheelbarrow 430 | baseball 431 | basketball 432 | bassinet 433 | bassoon 434 | bathing cap, swimming cap 435 | bath towel 436 | bathtub, bathing tub, bath, tub 437 | beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon 438 | beacon, lighthouse, beacon light, pharos 439 | beaker 440 | bearskin, busby, shako 441 | beer bottle 442 | beer glass 443 | bell cote, bell cot 444 | bib 445 | bicycle-built-for-two, tandem bicycle, tandem 446 | bikini, two-piece 447 | binder, ring-binder 448 | binoculars, field glasses, opera glasses 449 | birdhouse 450 | boathouse 451 | bobsled, bobsleigh, bob 452 | bolo tie, bolo, bola tie, bola 453 | bonnet, poke bonnet 454 | bookcase 455 | bookshop, bookstore, bookstall 456 | bottlecap 457 | bow 458 | bow tie, bow-tie, bowtie 459 | brass, memorial tablet, plaque 460 | brassiere, bra, bandeau 461 | breakwater, groin, groyne, mole, bulwark, seawall, jetty 462 | breastplate, aegis, egis 463 | broom 464 | bucket, pail 465 | buckle 466 | bulletproof vest 467 | bullet train, bullet 468 | butcher shop, meat market 469 | cab, hack, taxi, taxicab 470 | caldron, cauldron 471 | candle, taper, wax light 472 | cannon 473 | canoe 474 | can opener, tin opener 475 | cardigan 476 | car mirror 477 | carousel, carrousel, merry-go-round, roundabout, whirligig 478 | carpenter's kit, tool kit 479 | carton 480 | car wheel 481 | cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM 482 | cassette 483 | cassette player 484 | castle 485 | catamaran 486 | CD player 487 | cello, violoncello 488 | cellular telephone, cellular phone, cellphone, cell, mobile phone 489 | chain 490 | chainlink fence 491 | chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour 492 | chain saw, chainsaw 493 | chest 494 | chiffonier, commode 495 | chime, bell, gong 496 | china cabinet, china closet 497 | Christmas stocking 498 | church, church building 499 | cinema, movie theater, movie theatre, movie house, picture palace 500 | cleaver, meat cleaver, chopper 501 | cliff dwelling 502 | cloak 503 | clog, geta, patten, sabot 504 | cocktail shaker 505 | coffee mug 506 | coffeepot 507 | coil, spiral, volute, whorl, helix 508 | combination lock 509 | computer keyboard, keypad 510 | confectionery, confectionary, candy store 511 | container ship, containership, container vessel 512 | convertible 513 | corkscrew, bottle screw 514 | cornet, horn, trumpet, trump 515 | cowboy boot 516 | cowboy hat, ten-gallon hat 517 | cradle 518 | crane 519 | crash helmet 520 | crate 521 | crib, cot 522 | Crock Pot 523 | croquet ball 524 | crutch 525 | cuirass 526 | dam, dike, dyke 527 | desk 528 | desktop computer 529 | dial telephone, dial phone 530 | diaper, nappy, napkin 531 | digital clock 532 | digital watch 533 | dining table, board 534 | dishrag, dishcloth 535 | dishwasher, dish washer, dishwashing machine 536 | disk brake, disc brake 537 | dock, dockage, docking facility 538 | dogsled, dog sled, dog sleigh 539 | dome 540 | doormat, welcome mat 541 | drilling platform, offshore rig 542 | drum, membranophone, tympan 543 | drumstick 544 | dumbbell 545 | Dutch oven 546 | electric fan, blower 547 | electric guitar 548 | electric locomotive 549 | entertainment center 550 | envelope 551 | espresso maker 552 | face powder 553 | feather boa, boa 554 | file, file cabinet, filing cabinet 555 | fireboat 556 | fire engine, fire truck 557 | fire screen, fireguard 558 | flagpole, flagstaff 559 | flute, transverse flute 560 | folding chair 561 | football helmet 562 | forklift 563 | fountain 564 | fountain pen 565 | four-poster 566 | freight car 567 | French horn, horn 568 | frying pan, frypan, skillet 569 | fur coat 570 | garbage truck, dustcart 571 | gasmask, respirator, gas helmet 572 | gas pump, gasoline pump, petrol pump, island dispenser 573 | goblet 574 | go-kart 575 | golf ball 576 | golfcart, golf cart 577 | gondola 578 | gong, tam-tam 579 | gown 580 | grand piano, grand 581 | greenhouse, nursery, glasshouse 582 | grille, radiator grille 583 | grocery store, grocery, food market, market 584 | guillotine 585 | hair slide 586 | hair spray 587 | half track 588 | hammer 589 | hamper 590 | hand blower, blow dryer, blow drier, hair dryer, hair drier 591 | hand-held computer, hand-held microcomputer 592 | handkerchief, hankie, hanky, hankey 593 | hard disc, hard disk, fixed disk 594 | harmonica, mouth organ, harp, mouth harp 595 | harp 596 | harvester, reaper 597 | hatchet 598 | holster 599 | home theater, home theatre 600 | honeycomb 601 | hook, claw 602 | hoopskirt, crinoline 603 | horizontal bar, high bar 604 | horse cart, horse-cart 605 | hourglass 606 | iPod 607 | iron, smoothing iron 608 | jack-o'-lantern 609 | jean, blue jean, denim 610 | jeep, landrover 611 | jersey, T-shirt, tee shirt 612 | jigsaw puzzle 613 | jinrikisha, ricksha, rickshaw 614 | joystick 615 | kimono 616 | knee pad 617 | knot 618 | lab coat, laboratory coat 619 | ladle 620 | lampshade, lamp shade 621 | laptop, laptop computer 622 | lawn mower, mower 623 | lens cap, lens cover 624 | letter opener, paper knife, paperknife 625 | library 626 | lifeboat 627 | lighter, light, igniter, ignitor 628 | limousine, limo 629 | liner, ocean liner 630 | lipstick, lip rouge 631 | Loafer 632 | lotion 633 | loudspeaker, speaker, speaker unit, loudspeaker system, speaker system 634 | loupe, jeweler's loupe 635 | lumbermill, sawmill 636 | magnetic compass 637 | mailbag, postbag 638 | mailbox, letter box 639 | maillot 640 | maillot, tank suit 641 | manhole cover 642 | maraca 643 | marimba, xylophone 644 | mask 645 | matchstick 646 | maypole 647 | maze, labyrinth 648 | measuring cup 649 | medicine chest, medicine cabinet 650 | megalith, megalithic structure 651 | microphone, mike 652 | microwave, microwave oven 653 | military uniform 654 | milk can 655 | minibus 656 | miniskirt, mini 657 | minivan 658 | missile 659 | mitten 660 | mixing bowl 661 | mobile home, manufactured home 662 | Model T 663 | modem 664 | monastery 665 | monitor 666 | moped 667 | mortar 668 | mortarboard 669 | mosque 670 | mosquito net 671 | motor scooter, scooter 672 | mountain bike, all-terrain bike, off-roader 673 | mountain tent 674 | mouse, computer mouse 675 | mousetrap 676 | moving van 677 | muzzle 678 | nail 679 | neck brace 680 | necklace 681 | nipple 682 | notebook, notebook computer 683 | obelisk 684 | oboe, hautboy, hautbois 685 | ocarina, sweet potato 686 | odometer, hodometer, mileometer, milometer 687 | oil filter 688 | organ, pipe organ 689 | oscilloscope, scope, cathode-ray oscilloscope, CRO 690 | overskirt 691 | oxcart 692 | oxygen mask 693 | packet 694 | paddle, boat paddle 695 | paddlewheel, paddle wheel 696 | padlock 697 | paintbrush 698 | pajama, pyjama, pj's, jammies 699 | palace 700 | panpipe, pandean pipe, syrinx 701 | paper towel 702 | parachute, chute 703 | parallel bars, bars 704 | park bench 705 | parking meter 706 | passenger car, coach, carriage 707 | patio, terrace 708 | pay-phone, pay-station 709 | pedestal, plinth, footstall 710 | pencil box, pencil case 711 | pencil sharpener 712 | perfume, essence 713 | Petri dish 714 | photocopier 715 | pick, plectrum, plectron 716 | pickelhaube 717 | picket fence, paling 718 | pickup, pickup truck 719 | pier 720 | piggy bank, penny bank 721 | pill bottle 722 | pillow 723 | ping-pong ball 724 | pinwheel 725 | pirate, pirate ship 726 | pitcher, ewer 727 | plane, carpenter's plane, woodworking plane 728 | planetarium 729 | plastic bag 730 | plate rack 731 | plow, plough 732 | plunger, plumber's helper 733 | Polaroid camera, Polaroid Land camera 734 | pole 735 | police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria 736 | poncho 737 | pool table, billiard table, snooker table 738 | pop bottle, soda bottle 739 | pot, flowerpot 740 | potter's wheel 741 | power drill 742 | prayer rug, prayer mat 743 | printer 744 | prison, prison house 745 | projectile, missile 746 | projector 747 | puck, hockey puck 748 | punching bag, punch bag, punching ball, punchball 749 | purse 750 | quill, quill pen 751 | quilt, comforter, comfort, puff 752 | racer, race car, racing car 753 | racket, racquet 754 | radiator 755 | radio, wireless 756 | radio telescope, radio reflector 757 | rain barrel 758 | recreational vehicle, RV, R.V. 759 | reel 760 | reflex camera 761 | refrigerator, icebox 762 | remote control, remote 763 | restaurant, eating house, eating place, eatery 764 | revolver, six-gun, six-shooter 765 | rifle 766 | rocking chair, rocker 767 | rotisserie 768 | rubber eraser, rubber, pencil eraser 769 | rugby ball 770 | rule, ruler 771 | running shoe 772 | safe 773 | safety pin 774 | saltshaker, salt shaker 775 | sandal 776 | sarong 777 | sax, saxophone 778 | scabbard 779 | scale, weighing machine 780 | school bus 781 | schooner 782 | scoreboard 783 | screen, CRT screen 784 | screw 785 | screwdriver 786 | seat belt, seatbelt 787 | sewing machine 788 | shield, buckler 789 | shoe shop, shoe-shop, shoe store 790 | shoji 791 | shopping basket 792 | shopping cart 793 | shovel 794 | shower cap 795 | shower curtain 796 | ski 797 | ski mask 798 | sleeping bag 799 | slide rule, slipstick 800 | sliding door 801 | slot, one-armed bandit 802 | snorkel 803 | snowmobile 804 | snowplow, snowplough 805 | soap dispenser 806 | soccer ball 807 | sock 808 | solar dish, solar collector, solar furnace 809 | sombrero 810 | soup bowl 811 | space bar 812 | space heater 813 | space shuttle 814 | spatula 815 | speedboat 816 | spider web, spider's web 817 | spindle 818 | sports car, sport car 819 | spotlight, spot 820 | stage 821 | steam locomotive 822 | steel arch bridge 823 | steel drum 824 | stethoscope 825 | stole 826 | stone wall 827 | stopwatch, stop watch 828 | stove 829 | strainer 830 | streetcar, tram, tramcar, trolley, trolley car 831 | stretcher 832 | studio couch, day bed 833 | stupa, tope 834 | submarine, pigboat, sub, U-boat 835 | suit, suit of clothes 836 | sundial 837 | sunglass 838 | sunglasses, dark glasses, shades 839 | sunscreen, sunblock, sun blocker 840 | suspension bridge 841 | swab, swob, mop 842 | sweatshirt 843 | swimming trunks, bathing trunks 844 | swing 845 | switch, electric switch, electrical switch 846 | syringe 847 | table lamp 848 | tank, army tank, armored combat vehicle, armoured combat vehicle 849 | tape player 850 | teapot 851 | teddy, teddy bear 852 | television, television system 853 | tennis ball 854 | thatch, thatched roof 855 | theater curtain, theatre curtain 856 | thimble 857 | thresher, thrasher, threshing machine 858 | throne 859 | tile roof 860 | toaster 861 | tobacco shop, tobacconist shop, tobacconist 862 | toilet seat 863 | torch 864 | totem pole 865 | tow truck, tow car, wrecker 866 | toyshop 867 | tractor 868 | trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi 869 | tray 870 | trench coat 871 | tricycle, trike, velocipede 872 | trimaran 873 | tripod 874 | triumphal arch 875 | trolleybus, trolley coach, trackless trolley 876 | trombone 877 | tub, vat 878 | turnstile 879 | typewriter keyboard 880 | umbrella 881 | unicycle, monocycle 882 | upright, upright piano 883 | vacuum, vacuum cleaner 884 | vase 885 | vault 886 | velvet 887 | vending machine 888 | vestment 889 | viaduct 890 | violin, fiddle 891 | volleyball 892 | waffle iron 893 | wall clock 894 | wallet, billfold, notecase, pocketbook 895 | wardrobe, closet, press 896 | warplane, military plane 897 | washbasin, handbasin, washbowl, lavabo, wash-hand basin 898 | washer, automatic washer, washing machine 899 | water bottle 900 | water jug 901 | water tower 902 | whiskey jug 903 | whistle 904 | wig 905 | window screen 906 | window shade 907 | Windsor tie 908 | wine bottle 909 | wing 910 | wok 911 | wooden spoon 912 | wool, woolen, woollen 913 | worm fence, snake fence, snake-rail fence, Virginia fence 914 | wreck 915 | yawl 916 | yurt 917 | web site, website, internet site, site 918 | comic book 919 | crossword puzzle, crossword 920 | street sign 921 | traffic light, traffic signal, stoplight 922 | book jacket, dust cover, dust jacket, dust wrapper 923 | menu 924 | plate 925 | guacamole 926 | consomme 927 | hot pot, hotpot 928 | trifle 929 | ice cream, icecream 930 | ice lolly, lolly, lollipop, popsicle 931 | French loaf 932 | bagel, beigel 933 | pretzel 934 | cheeseburger 935 | hotdog, hot dog, red hot 936 | mashed potato 937 | head cabbage 938 | broccoli 939 | cauliflower 940 | zucchini, courgette 941 | spaghetti squash 942 | acorn squash 943 | butternut squash 944 | cucumber, cuke 945 | artichoke, globe artichoke 946 | bell pepper 947 | cardoon 948 | mushroom 949 | Granny Smith 950 | strawberry 951 | orange 952 | lemon 953 | fig 954 | pineapple, ananas 955 | banana 956 | jackfruit, jak, jack 957 | custard apple 958 | pomegranate 959 | hay 960 | carbonara 961 | chocolate sauce, chocolate syrup 962 | dough 963 | meat loaf, meatloaf 964 | pizza, pizza pie 965 | potpie 966 | burrito 967 | red wine 968 | espresso 969 | cup 970 | eggnog 971 | alp 972 | bubble 973 | cliff, drop, drop-off 974 | coral reef 975 | geyser 976 | lakeside, lakeshore 977 | promontory, headland, head, foreland 978 | sandbar, sand bar 979 | seashore, coast, seacoast, sea-coast 980 | valley, vale 981 | volcano 982 | ballplayer, baseball player 983 | groom, bridegroom 984 | scuba diver 985 | rapeseed 986 | daisy 987 | yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum 988 | corn 989 | acorn 990 | hip, rose hip, rosehip 991 | buckeye, horse chestnut, conker 992 | coral fungus 993 | agaric 994 | gyromitra 995 | stinkhorn, carrion fungus 996 | earthstar 997 | hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa 998 | bolete 999 | ear, spike, capitulum 1000 | toilet tissue, toilet paper, bathroom tissue 1001 | -------------------------------------------------------------------------------- /ILSVRC12.227x227.IMG/lablVecTst.uint16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAS-CLab/quantized-cnn/d6e5084a54c7a6f1cb63e2b7092fbbb60b49543d/ILSVRC12.227x227.IMG/lablVecTst.uint16.bin -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This Makefile requires ATLAS and OpenVML in the compilation 2 | 3 | CC=g++ 4 | MKDIR=mkdir -p 5 | RM=rm -rf 6 | SRC_DIR=src 7 | OBJ_DIR=obj 8 | BIN_DIR=bin 9 | SRCS=$(wildcard $(SRC_DIR)/*.cc) 10 | OBJS=$(SRCS:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o) 11 | CPPFLAGS=-I/usr/include/atlas -I/opt/OpenVML/include 12 | CFLAGS=-Wall -std=c++11 -O2 13 | LDFLAGS=-L/usr/lib/atlas-base -L/opt/OpenVML/lib 14 | LDLIBS=-lcblas -latlas -lopenvml 15 | DFLAGS=-D ENABLE_ATLAS -D ENABLE_OPENVML 16 | TARGET=$(BIN_DIR)/QuanCNN 17 | 18 | .PHONY: all run clean 19 | 20 | all: $(BIN_DIR) $(OBJ_DIR) $(TARGET) 21 | 22 | $(BIN_DIR): 23 | $(MKDIR) $(BIN_DIR) 24 | $(OBJ_DIR): 25 | $(MKDIR) $(OBJ_DIR) 26 | $(TARGET): $(OBJS) 27 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 28 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc 29 | $(CC) $(CPPFLAGS) $(CFLAGS) $(DFLAGS) -c $< -o $@ 30 | 31 | run: 32 | $(TARGET) 33 | 34 | clean: 35 | $(RM) $(BIN_DIR) $(OBJ_DIR) $(OBJS) $(TARGET) 36 | -------------------------------------------------------------------------------- /Makefile.native: -------------------------------------------------------------------------------- 1 | # This Makefile does not require ATLAS and OpenVML in the compilation 2 | 3 | CC=g++ 4 | MKDIR=mkdir -p 5 | RM=rm -rf 6 | SRC_DIR=src 7 | OBJ_DIR=obj 8 | BIN_DIR=bin 9 | SRCS=$(wildcard $(SRC_DIR)/*.cc) 10 | OBJS=$(SRCS:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o) 11 | CPPFLAGS= 12 | CFLAGS=-Wall -std=c++11 -O2 13 | LDFLAGS= 14 | LDLIBS= 15 | DFLAGS= 16 | TARGET=$(BIN_DIR)/QuanCNN 17 | 18 | .PHONY: all run clean 19 | 20 | all: $(BIN_DIR) $(OBJ_DIR) $(TARGET) 21 | 22 | $(BIN_DIR): 23 | $(MKDIR) $(BIN_DIR) 24 | $(OBJ_DIR): 25 | $(MKDIR) $(OBJ_DIR) 26 | $(TARGET): $(OBJS) 27 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 28 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc 29 | $(CC) $(CPPFLAGS) $(CFLAGS) $(DFLAGS) -c $< -o $@ 30 | 31 | run: 32 | $(TARGET) 33 | 34 | clean: 35 | $(RM) $(BIN_DIR) $(OBJ_DIR) $(OBJS) $(TARGET) 36 | -------------------------------------------------------------------------------- /Makefile.noblas: -------------------------------------------------------------------------------- 1 | # This Makefile requires OpenVML in the compilation 2 | 3 | CC=g++ 4 | MKDIR=mkdir -p 5 | RM=rm -rf 6 | SRC_DIR=src 7 | OBJ_DIR=obj 8 | BIN_DIR=bin 9 | SRCS=$(wildcard $(SRC_DIR)/*.cc) 10 | OBJS=$(SRCS:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o) 11 | CPPFLAGS=-I/opt/OpenVML/include 12 | CFLAGS=-Wall -std=c++11 -O2 13 | LDFLAGS=-L/opt/OpenVML/lib 14 | LDLIBS=-lopenvml 15 | DFLAGS=-D ENABLE_OPENVML 16 | TARGET=$(BIN_DIR)/QuanCNN 17 | 18 | .PHONY: all run clean 19 | 20 | all: $(BIN_DIR) $(OBJ_DIR) $(TARGET) 21 | 22 | $(BIN_DIR): 23 | $(MKDIR) $(BIN_DIR) 24 | $(OBJ_DIR): 25 | $(MKDIR) $(OBJ_DIR) 26 | $(TARGET): $(OBJS) 27 | $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ 28 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc 29 | $(CC) $(CPPFLAGS) $(CFLAGS) $(DFLAGS) -c $< -o $@ 30 | 31 | run: 32 | $(TARGET) 33 | 34 | clean: 35 | $(RM) $(BIN_DIR) $(OBJ_DIR) $(OBJS) $(TARGET) 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quantized-CNN for Mobile Devices 2 | 3 | Quantized-CNN is a novel framework of convolutional neural network (CNN) with simultaneous computation acceleration and model compression in the test-phase. Mobile devices can perform efficient on-site image classification via our Quantized-CNN, with only negligible loss in accuracy. 4 | 5 | ## Installation 6 | 7 | We have prepared a file (500+MB) containing 1k images drawn from the ILSVRC-12 validation set for a more accurate speed-test. You can download it from [here](https://1drv.ms/u/s!Ahwjm8lejJYNp79irrjHGEmylB4F7w), and put it under the "ILSVRC12.227x227.IMG" directory. 8 | 9 | For the original AlexNet model, you can download the corresponding model files from [here](https://1drv.ms/u/s!Ahwjm8lejJYNraoZ8qoxy4VUGzsL7Q), and put them under the "AlexNet/Bin.Files" directory. 10 | 11 | **Updates (23/08/30):** The AlexNet model file and validation images have been moved to [Google Drive](https://drive.google.com/drive/folders/18gwVZRViZ3Q2Fw6q8T7ciQPSMLeZQjSk?usp=drive_link). 12 | 13 | Prior to compilation, you need to install [ATLAS](http://math-atlas.sourceforge.net) and [OpenVML](https://github.com/xianyi/OpenVML), and modify the "CXXFLAGS" and "LDFLAGS" entries in the Makefile, if needed. Also, you should append the corresponding library paths to LD\_LIBRARY\_PATH in the ~/.bashrc. After that, use "make" to generate the executable file and "make run" to perform the speed-test with the above 1k images. 14 | 15 | You can also use our code for single image classification (BMP format). Please refer to "src/Main.cc" for details. 16 | 17 | ## Speed-test 18 | 19 | The experiment is carried out on a single desktop PC, equipped with an Intel® Core™ i7-4790K CPU and 32GB RAM. All programs are executed in the single-thread mode, without GPU acceleration. **Note that the run-time speed comparison result may vary under different hardware conditions.** 20 | 21 | We compare the run-time speed of [AlexNet](http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks), for which Quantized-CNN's theoretical speed-up is 4.15×. For the baseline method, we use the [Caffe](http://caffe.berkeleyvision.org/) implementation, compiled with ATLAS (default BLAS choice). We measure the forward-passing time per image, based on the average of 100 batches. Each batch contains a single image, since in practice, users usually take one photo with their cellphones and then fed it into the ConvNet for classification. The experiment is repeated five times and here are the results: 22 | 23 | | Time (ms) | CNN | Quantized-CNN | Speed-up | 24 | |:---------:|:-------:|:-------------:|:-----------:| 25 | | 1 | 167.431 | 55.346 | - | 26 | | 2 | 168.578 | 55.382 | - | 27 | | 3 | 166.120 | 55.372 | - | 28 | | 4 | 172.792 | 55.389 | - | 29 | | 5 | 164.008 | 55.250 | - | 30 | | Ave.| 167.786 | 55.348 | 3.03× | 31 | 32 | Quantized-CNN achieves 3.03× speed-up against the Caffe implementation, slightly lower than the theoretical one but still quite acceptable. Meanwhile, our method requires much less memory and storage space, which is critical for mobile applications. 33 | 34 | ## Citation 35 | 36 | Please cite our paper if it helps your research: 37 | 38 | @inproceedings{wu2016quantized, 39 | author = {Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng}, 40 | title = {Quantized Convolutional Neural Networks for Mobile Devices}, 41 | booktitle = {IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 42 | year = {2016}, 43 | } 44 | -------------------------------------------------------------------------------- /include/BlasWrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_BLASWRAPPER_H_ 9 | #define INCLUDE_BLASWRAPPER_H_ 10 | 11 | /* 12 | * functions to be wrapped: 13 | * 1. vsAdd 14 | * 2. vsSub 15 | * 3. vsMul 16 | * 4. vsSqr 17 | * 5. vsPowx 18 | * 6. cblas_sscal 19 | * 7. cblas_saxpy 20 | * 8. cblas_sgemm 21 | * 22 | * functions provided by extern libraries: 23 | * | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 24 | * |==========|===|===|===|===|===|===|===|===| 25 | * | ATLAS | - | - | - | - | - | + | + | + | 26 | * | MKL | + | + | + | + | + | + | + | + | 27 | * | OpenBLAS | - | - | - | - | - | + | + | + | 28 | * | OpenVML | + | + | - | - | + | - | - | - | 29 | * 30 | * NOTE: the vsPowx() function in MKL and OpenVML have different definitions, 31 | * so a wrapper is always needed. 32 | */ 33 | 34 | #include "../include/Common.h" 35 | 36 | // define macros for all functions to be wrapped (may be undefined later) 37 | #define IMPL_VSADD 38 | #define IMPL_VSSUB 39 | #define IMPL_VSMUL 40 | #define IMPL_VSSQR 41 | #define IMPL_SSCAL 42 | #define IMPL_SAXPY 43 | #define IMPL_SGEMM 44 | 45 | // when ATLAS/OpenBLAS is enabled 46 | #if defined(ENABLE_ATLAS) || defined(ENABLE_OPENBLAS) 47 | extern "C" { 48 | #include 49 | } 50 | #endif // defined 51 | 52 | // when ATLAS is enabled 53 | #ifdef ENABLE_ATLAS 54 | typedef int CBLAS_INT; 55 | #undef IMPL_SSCAL 56 | #undef IMPL_SAXPY 57 | #undef IMPL_SGEMM 58 | #endif // ENABLE_ATLAS 59 | 60 | // when MKL is enabled 61 | #ifdef ENABLE_MKL 62 | #include 63 | typedef MKL_INT CBLAS_INT; 64 | typedef CBLAS_LAYOUT CBLAS_ORDER; 65 | #undef IMPL_VSADD 66 | #undef IMPL_VSSUB 67 | #undef IMPL_VSMUL 68 | #undef IMPL_VSSQR 69 | #undef IMPL_SSCAL 70 | #undef IMPL_SAXPY 71 | #undef IMPL_SGEMM 72 | #endif // ENABLE_MKL 73 | 74 | // when OpenBLAS is enabled 75 | #ifdef ENABLE_OPENBLAS 76 | typedef blasint CBLAS_INT; 77 | #undef IMPL_SSCAL 78 | #undef IMPL_SAXPY 79 | #undef IMPL_SGEMM 80 | #endif // ENABLE_OPENBLAS 81 | 82 | // when OpenVML is enabled 83 | #ifdef ENABLE_OPENVML 84 | #include 85 | #undef IMPL_VSADD 86 | #undef IMPL_VSSUB 87 | #endif // ENABLE_OPENVML 88 | 89 | // define variable types for BLAS functions 90 | #if defined(IMPL_VSADD) || defined(IMPL_VSSUB) || defined(IMPL_VSMUL) || \ 91 | defined(IMPL_VSSQR) || defined(IMPL_VSPOWX) || defined(IMPL_SSCAL) || \ 92 | defined(IMPL_SAXPY) || defined(IMPL_SGEMM) 93 | typedef int CBLAS_INT; 94 | #endif // defined 95 | 96 | #if defined(IMPL_SSCAL) || defined(IMPL_SAXPY) || defined(IMPL_SGEMM) 97 | typedef enum {CblasRowMajor, CblasColMajor} CBLAS_ORDER; 98 | typedef enum {CblasNoTrans, CblasTrans} CBLAS_TRANSPOSE; 99 | #endif // defined 100 | 101 | #ifdef IMPL_VSADD 102 | inline void vsAdd(const CBLAS_INT n, const float* a, const float* b, float* y) { 103 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 104 | y[i] = a[i] + b[i]; 105 | } // ENDFOR: i 106 | } 107 | #endif // IMPL_VSADD 108 | 109 | #ifdef IMPL_VSSUB 110 | inline void vsSub(const CBLAS_INT n, const float* a, const float* b, float* y) { 111 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 112 | y[i] = a[i] - b[i]; 113 | } // ENDFOR: i 114 | } 115 | #endif // IMPL_VSSUB 116 | 117 | #ifdef IMPL_VSMUL 118 | inline void vsMul(const CBLAS_INT n, const float* a, const float* b, float* y) { 119 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 120 | y[i] = a[i] * b[i]; 121 | } // ENDFOR: i 122 | } 123 | #endif // IMPL_VSMUL 124 | 125 | #ifdef IMPL_VSSQR 126 | inline void vsSqr(const CBLAS_INT n, const float* a, float* y) { 127 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 128 | y[i] = a[i] * a[i]; 129 | } // ENDFOR: i 130 | } 131 | #endif // IMPL_VSSQR 132 | 133 | // this wrapper is always needed, since MKL's and OpenVML's interface differ 134 | inline void vsPowx_m(const CBLAS_INT n, 135 | const float* a, const float b, float* y) { 136 | #ifdef ENABLE_MKL 137 | vsPowx(n, a, b, y); 138 | #else 139 | #ifdef ENABLE_OPENVML 140 | vsPowx(n, a, &b, y); 141 | #else 142 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 143 | y[i] = exp(b * log(a[i])); 144 | } // ENDFOR: i 145 | #endif // ENABLE_OPENVML 146 | #endif // ENABLE_MKL 147 | } 148 | 149 | #ifdef IMPL_SSCAL 150 | inline void cblas_sscal(const CBLAS_INT n, 151 | const float a, float* x, const CBLAS_INT incx) { 152 | if (incx == 1) { // case-by-case optimization 153 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 154 | x[i] *= a; 155 | } // ENDFOR: i 156 | } else { 157 | for (CBLAS_INT i = (n - 1) * incx; i >= 0; i -= incx) { 158 | x[i] *= a; 159 | } // ENDFOR: i 160 | } // ENDIF: incx 161 | } 162 | #endif // IMPL_SSCAL 163 | 164 | #ifdef IMPL_SAXPY 165 | inline void cblas_saxpy(const CBLAS_INT n, const float a, const float* x, 166 | const CBLAS_INT incx, float* y, const CBLAS_INT incy) { 167 | if ((incx == 1) && (incy == 1)) { // case-by-case optmization 168 | for (CBLAS_INT i = n - 1; i >= 0; --i) { 169 | y[i] += a * x[i]; 170 | } // ENDFOR: i 171 | } else if (incx == incy) { // case-by-case optimization 172 | for (CBLAS_INT i = (n - 1) * incx; i >= 0; ) { 173 | y[i] += a * x[i]; 174 | i -= incx; 175 | } // ENDFOR: i 176 | } else { 177 | for (CBLAS_INT i = (n - 1) * incx, j = (n - 1) * incy; i >= 0; ) { 178 | y[j] += a * x[i]; 179 | i -= incx; 180 | j -= incy; 181 | } // ENDFOR: i 182 | } // ENDIF: incx 183 | } 184 | #endif // IMPL_SAXPY 185 | 186 | #ifdef IMPL_SGEMM 187 | void cblas_sgemm(const CBLAS_ORDER order, const CBLAS_TRANSPOSE transA, 188 | const CBLAS_TRANSPOSE transB, const CBLAS_INT m, const CBLAS_INT n, 189 | const CBLAS_INT k, const float alpha, const float* a, 190 | const CBLAS_INT lda, const float* b, const CBLAS_INT ldb, 191 | const float beta, float* c, const CBLAS_INT ldc); 192 | #endif // IMPL_SGEMM 193 | 194 | #endif // INCLUDE_BLASWRAPPER_H_ 195 | -------------------------------------------------------------------------------- /include/BmpImgIO.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_BMPIMGIO_H_ 9 | #define INCLUDE_BMPIMGIO_H_ 10 | 11 | #include 12 | 13 | #include "../include/Common.h" 14 | #include "../include/Matrix.h" 15 | 16 | /* 17 | *Resizing Type: 18 | * Strict: image is strictly resized to HxW (aspect may change) 19 | * Relaxed: image is resized to H'xW' (ascpect will not change) 20 | * s.t. H' >= H, W' >= W, (H' - H) * (W' - W) = 0 21 | */ 22 | enum class ENUM_ReszType {Strict, Relaxed}; 23 | 24 | /* 25 | * Mean Image Type: 26 | * Full: mean image is of equal size to the full image 27 | * Crop: mean image is of equal size to the cropped image 28 | */ 29 | enum class ENUM_MeanType {Full, Crop}; 30 | 31 | typedef struct { 32 | ENUM_ReszType reszType; // resizing type 33 | ENUM_MeanType meanType; // mean image type 34 | int imgHeiFull; // full image height 35 | int imgWidFull; // full image width 36 | int imgHeiCrop; // cropped image height 37 | int imgWidCrop; // cropped image width 38 | std::string filePathMean; // file path of the mean image 39 | } BmpImgIOPara; 40 | 41 | class BmpImgIO { 42 | public: 43 | // initialize parameters 44 | bool Init(const BmpImgIOPara& bmpImgIOPara); 45 | // load a BMP image from file and prepare it for CNN input 46 | bool Load(const std::string& filePath, Matrix* pImgDataFnal); 47 | 48 | private: 49 | // resizing type 50 | ENUM_ReszType reszType; 51 | // mean image type 52 | ENUM_MeanType meanType; 53 | // full image height 54 | int imgHeiFull; 55 | // full image width 56 | int imgWidFull; 57 | // cropped image height 58 | int imgHeiCrop; 59 | // cropped image width 60 | int imgWidCrop; 61 | // file path to the mean image 62 | std::string filePathMean; 63 | // mean image 64 | Matrix imgDataMean; 65 | // height of the mean image 66 | int imgHeiMean; 67 | // width of the mean image 68 | int imgWidMean; 69 | 70 | private: 71 | // load a BMP image from file 72 | bool LoadBmpImg(const std::string& filePath, Matrix* pImgData); 73 | // resize image to the specified size 74 | void ReszImg(const Matrix& imgDataSrc, Matrix* pImgDataDst, 75 | const ENUM_ReszType type, const int imgHeiDstPst, const int imgWidDstPst); 76 | // crop the central patch from the source image 77 | void CropImg(const Matrix& imgDataSrc, Matrix* pImgDataDst, 78 | const int imgHeiDst, const int imgWidDst); 79 | // remove the mean image from the source image 80 | void RmMeanImg(const Matrix& imgDataMean, Matrix* pImgDataProc); 81 | }; 82 | 83 | #endif // INCLUDE_BMPIMGIO_H_ 84 | -------------------------------------------------------------------------------- /include/CaffeEva.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_CAFFEEVA_H_ 9 | #define INCLUDE_CAFFEEVA_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "../include/Common.h" 15 | #include "../include/BlasWrapper.h" 16 | #include "../include/CaffePara.h" 17 | #include "../include/Matrix.h" 18 | #include "../include/StopWatch.h" 19 | 20 | // un-comment this for Android debug output 21 | // #define ENBL_ANDROID_DBG 22 | 23 | // define structure and 24 | typedef struct { 25 | int dataCnt; 26 | int imgHei; 27 | int imgWid; 28 | int imgChn; 29 | } FeatMapSiz; 30 | typedef std::vector FeatMapSizLst; 31 | 32 | // define structure , , and 33 | enum class ENUM_BufUsage {GnrlComp, PrecComp, AprxComp}; 34 | typedef struct { 35 | ENUM_BufUsage usage; 36 | int dimCnt; 37 | int dimLenLst[kMatDimCntMax]; 38 | Matrix* pFeatBuf; 39 | } FeatBufStr; 40 | typedef std::vector FeatBufStrLst; 41 | typedef std::vector FeatBufStrMat; 42 | 43 | // define structure and 44 | typedef struct { 45 | int dimCnt; 46 | int dimLenLst[kMatDimCntMax]; 47 | Matrix* pCtrdBuf; 48 | } CtrdBufStr; 49 | typedef std::vector CtrdBufStrLst; 50 | 51 | // define structure and 52 | typedef struct { 53 | int dimCnt; 54 | int dimLenLst[kMatDimCntMax]; 55 | Matrix* pAsmtBuf; 56 | Matrix* pAsmtBufExt; // for cblas_sgthr() 57 | } AsmtBufStr; 58 | typedef std::vector AsmtBufStrLst; 59 | 60 | class CaffeEva { 61 | public: 62 | // deconstructor function 63 | ~CaffeEva(void); 64 | 65 | public: 66 | // initialize essential variables 67 | void Init(const bool enblAprxSrc); 68 | // specify the model name 69 | void SetModelName(const std::string& modelNameSrc); 70 | // specify the main model directory and the model file name prefix 71 | void SetModelPath( 72 | const std::string& dirPathMainSrc, const std::string& fileNamePfxSrc); 73 | // load dataset 74 | bool LoadDataset(const std::string& dirPathData); 75 | // load caffe parameters 76 | bool LoadCaffePara(void); 77 | // run forward process for all samples 78 | void ExecForwardPass(void); 79 | // run forward process for the input sample 80 | void ExecForwardPass( 81 | const Matrix& imgDataIn, Matrix* pProbVecOut); 82 | // evaluate the classification accuracy 83 | void CalcPredAccu(void); 84 | // display the elapsed time of each step 85 | float DispElpsTime(void); 86 | 87 | private: 88 | // whether approximate computation is enabled 89 | bool enblAprx; 90 | // caffe model name 91 | std::string modelName; 92 | // main data directory 93 | std::string dirPathMain; 94 | // model parameter file name's prefix 95 | std::string fileNamePfx; 96 | // object of class 97 | CaffePara caffeParaObj; 98 | // evaluation samples' feature vectors 99 | Matrix dataLst; 100 | // evaluation samples' ground-truth labels 101 | Matrix lablVecGrth; 102 | // evaluation samples' predicted labels 103 | Matrix lablVecPred; 104 | // feature map size after passing through each layer 105 | FeatMapSizLst featMapSizLst; 106 | // feature map list for each layer 107 | Matrix* featMapLst; 108 | // feature buffer structure for each layer 109 | FeatBufStrMat featBufStrMat; 110 | // centroid buffer structure for each layer 111 | CtrdBufStrLst ctrdBufStrLst; 112 | // assignment buffer structure for each layer 113 | AsmtBufStrLst asmtBufStrLst; 114 | 115 | private: 116 | // objects of class for accurate time measuring 117 | StopWatch swAllLayers; 118 | StopWatch swConvLayer; 119 | StopWatch swPoolLayer; 120 | StopWatch swFCntLayer; 121 | StopWatch swReLuLayer; 122 | StopWatch swLoRNLayer; 123 | StopWatch swDrptLayer; 124 | StopWatch swSMaxLayer; 125 | StopWatch swCompLkupTblConv; 126 | StopWatch swEstiInPdValConv; 127 | StopWatch swCompLkupTblFCnt; 128 | StopWatch swEstiInPdValFCnt; 129 | // objects of class for debug usage 130 | StopWatch swDebugTimePri; 131 | StopWatch swDebugTimeSec; 132 | // objects of class for each layer in the network 133 | std::vector swIndvLayerLst; 134 | 135 | private: 136 | // prepare feature map for each layer 137 | void PrepFeatMap(void); 138 | // prepare feature buffers for each layer 139 | void PrepFeatBuf(void); 140 | // prepare centroid buffers for each convolutional/fully-connected layer 141 | void PrepCtrdBuf(void); 142 | // prepare assignment buffers for each convolutional layer 143 | void PrepAsmtBuf(void); 144 | // compute the feature map after passing a certain layer 145 | void CalcFeatMap(const Matrix& featMapSrc, 146 | const int layerInd, Matrix* pFeatMapDst); 147 | void CalcFeatMap_Conv(const Matrix& featMapSrc, 148 | const int layerInd, Matrix* pFeatMapDst); 149 | void CalcFeatMap_ConvPrec(const Matrix& featMapSrc, 150 | const int layerInd, Matrix* pFeatMapDst); 151 | void CalcFeatMap_ConvAprx(const Matrix& featMapSrc, 152 | const int layerInd, Matrix* pFeatMapDst); 153 | void CalcFeatMap_Pool(const Matrix& featMapSrc, 154 | const int layerInd, Matrix* pFeatMapDst); 155 | void CalcFeatMap_FCnt(const Matrix& featMapSrc, 156 | const int layerInd, Matrix* pFeatMapDst); 157 | void CalcFeatMap_FCntPrec(const Matrix& featMapSrc, 158 | const int layerInd, Matrix* pFeatMapDst); 159 | void CalcFeatMap_FCntAprx(const Matrix& featMapSrc, 160 | const int layerInd, Matrix* pFeatMapDst); 161 | void CalcFeatMap_FCntAprxSp(const Matrix& featMapSrc, 162 | const int layerInd, Matrix* pFeatMapDst); 163 | void CalcFeatMap_ReLu(const Matrix& featMapSrc, 164 | const int layerInd, Matrix* pFeatMapDst); 165 | void CalcFeatMap_LoRN(const Matrix& featMapSrc, 166 | const int layerInd, Matrix* pFeatMapDst); 167 | void CalcFeatMap_Drpt(const Matrix& featMapSrc, 168 | const int layerInd, Matrix* pFeatMapDst); 169 | void CalcFeatMap_SMax(const Matrix& featMapSrc, 170 | const int layerInd, Matrix* pFeatMapDst); 171 | // initialize the structure 172 | void InitFeatBuf( 173 | FeatBufStr* pFeatBufStr, const ENUM_BufUsage us, const int d0); 174 | void InitFeatBuf(FeatBufStr* pFeatBufStr, 175 | const ENUM_BufUsage us, const int d0, const int d1); 176 | void InitFeatBuf(FeatBufStr* pFeatBufStr, 177 | const ENUM_BufUsage us, const int d0, const int d1, const int d2); 178 | void InitFeatBuf(FeatBufStr* pFeatBufStr, const ENUM_BufUsage us, 179 | const int d0, const int d1, const int d2, const int d3); 180 | // convert samples' feature vectors into the input feature map 181 | void CvtDataLstToFeatMap(const int dataIndBeg, const int dataIndEnd, 182 | const Matrix& dataLst, Matrix* pFeatMap); 183 | // convert the output feature map into samples' predicted labels 184 | void CvtFeatMapToLablVec(const int dataIndBeg, const int dataIndEnd, 185 | const Matrix& featMap, Matrix* pLablVec); 186 | // convert feature map to feature buffer 187 | void CvtFeatMapToFeatBuf(const Matrix& featMap, const int dataInd, 188 | const int grpInd, const LayerInfo& layerInfo, Matrix* pFeatBuf); 189 | // convert feature buffer to feature map 190 | void CvtFeatBufToFeatMap(const Matrix& featBuf, const int dataInd, 191 | const int grpInd, const LayerInfo& layerInfo, Matrix* pFeatMap); 192 | // compute the look-up table for inner product 193 | void GetInPdMat(const Matrix& dataLst, 194 | const Matrix& ctrdLst, Matrix* pInPdMat); 195 | }; 196 | 197 | #endif // INCLUDE_CAFFEEVA_H_ 198 | -------------------------------------------------------------------------------- /include/CaffeEvaWrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_CAFFEEVAWRAPPER_H_ 9 | #define INCLUDE_CAFFEEVAWRAPPER_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "../include/Common.h" 15 | #include "../include/BmpImgIO.h" 16 | #include "../include/CaffeEva.h" 17 | 18 | enum class ENUM_CaffeModel { 19 | AlexNet, CaffeNet, VggCnnS, VGG16, CaffeNetFGB, CaffeNetFGD}; 20 | enum class ENUM_CompMethod {Prec, Aprx}; 21 | 22 | typedef struct { 23 | int clsCntPred; 24 | float timeTotal; 25 | bool hasGrthClsName; 26 | std::string clsNameGrth; 27 | std::vector clsIdxLst; 28 | std::vector clsProbLst; 29 | std::vector clsNameLst; 30 | } CaffeEvaRslt; 31 | 32 | typedef struct { 33 | std::string fileName; 34 | std::string clsNameGrth; 35 | } ClsNameGrthStr; 36 | typedef std::vector ClsNameGrthLst; 37 | 38 | class CaffeEvaWrapper { 39 | public: 40 | // Constructor Function 41 | // Description: 42 | // this function will initialize basic member variables 43 | // Input: 44 | // none 45 | // Output: 46 | // none 47 | CaffeEvaWrapper(void); 48 | 49 | public: 50 | // Path Set-up Function 51 | // Description: 52 | // this function will set-up the main directory path 53 | // Input: 54 | // mainDirPathSrc: main directory path (model parameters and mean images). 55 | // clsNameFilePath: file that contains all class names 56 | // imgLablFilePath: file that contains all image labels (optional) 57 | // Output: 58 | // none 59 | bool SetPath( 60 | const std::string& mainDirPathSrc, const std::string& clsNameFilePath, 61 | const std::string& imgLablFilePath = ""); 62 | 63 | public: 64 | // Model Set-up Function 65 | // Description: 66 | // this function will load model parameters and pre-allocate 67 | // memory space for feature maps and buffers. 68 | // Input: 69 | // caffeModelSrc: caffe model ("AlexNet" or "VggCnnS"). 70 | // compMethodSrc: computation method ("Prec" or "Aprx"). 71 | // Output: 72 | // none 73 | bool SetModel(const ENUM_CaffeModel& caffeModelSrc, 74 | const ENUM_CompMethod& compMethodSrc); 75 | 76 | public: 77 | // Core Process Function 78 | // Description: 79 | // this function will accept a string as the file path to the 80 | // input image and generate a fixed number of predicted class 81 | // labels with the selected convolutional neural network. 82 | // Input: 83 | // filePathProcImg: file path to the input image. 84 | // caffeEvaRslt: top-k classification result. 85 | // Output: 86 | // none 87 | bool Proc(const std::string& filePathProcImg, CaffeEvaRslt* pCaffeEvaRslt); 88 | 89 | public: 90 | // Get Error Message Function 91 | // Description: 92 | // this function will return the error message (if any) 93 | // Input: 94 | // none 95 | // Output: 96 | // (std::string) error message 97 | std::string GetErrorMsg(void); 98 | 99 | public: 100 | // Clear Error Message Function 101 | // Description: 102 | // this function will clear the error message 103 | // Input: 104 | // none 105 | // Output: 106 | // none 107 | void ClrErrorMsg(void); 108 | 109 | private: 110 | // main directory path 111 | std::string mainDirPath; 112 | // caffe model 113 | ENUM_CaffeModel caffeModel; 114 | // computation method 115 | ENUM_CompMethod compMethod; 116 | // basic parameters for class 117 | BmpImgIOPara bmpImgIOPara; 118 | // caffe model name 119 | std::string caffeModelName; 120 | // directory path to model parameters 121 | std::string dirPathPara; 122 | // model file name's prefix 123 | std::string fileNamePfx; 124 | // object of class 125 | BmpImgIO bmpImgIOObj; 126 | // object of class 127 | CaffeEva caffeEvaObj; 128 | // full list of class names 129 | std::vector clsNameLst; 130 | // ground-truth class names 131 | ClsNameGrthLst clsNameGrthLst; 132 | // error message 133 | std::string errorMsg; 134 | 135 | private: 136 | // load the full list of class names 137 | bool LoadClsName(const std::string& filePath); 138 | // load the full list of image lables 139 | bool LoadImgLabl(const std::string& filePath); 140 | // extract file name from the given file path 141 | std::string ExtrFileName(const std::string& filePath); 142 | }; 143 | 144 | #endif // INCLUDE_CAFFEEVAWRAPPER_H_ 145 | -------------------------------------------------------------------------------- /include/CaffePara.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_CAFFEPARA_H_ 9 | #define INCLUDE_CAFFEPARA_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "../include/Common.h" 15 | #include "../include/Matrix.h" 16 | 17 | // define ENUM class for file formats 18 | // description: 19 | // assume is the minimal number of bits to store an index. 20 | // FileFormat::Raw: each index is stored in bytes 21 | // FileFormat::Compact: each index is stored in bytes 22 | enum class ENUM_AsmtEnc {Raw, Compact}; 23 | 24 | // define ENUM class for layer types 25 | enum class ENUM_LyrType {Conv, Pool, FCnt, ReLU, LoRN, Drpt, SMax}; 26 | 27 | // define structure and 28 | typedef struct { 29 | ENUM_LyrType type; // layer type 30 | int padSiz; // number of padded pixels (on each side) 31 | int knlSiz; // width/height of the convolutional kernel 32 | int knlCnt; // number of convolutional kernels 33 | int grpCnt; // number of source feature map groups 34 | int stride; // convolution stride / spatial step 35 | int nodCnt; // number of target neurons (for the layer) 36 | int lrnSiz; // local response patch size 37 | float lrnAlp; // local response normalization - alpha 38 | float lrnBet; // local response normalization - beta 39 | float lrnIni; // local response normalization - initial value 40 | float drpRat; // dropout ratio (how many neurons are preserved) 41 | } LayerInfo; 42 | typedef std::vector LayerInfoLst; 43 | 44 | // define structure and 45 | typedef struct { 46 | Matrix convKnlLst; 47 | Matrix fcntWeiMat; 48 | Matrix biasVec; 49 | Matrix ctrdLst; 50 | Matrix asmtLst; 51 | } LayerPara; 52 | typedef std::vector LayerParaLst; 53 | 54 | class CaffePara { 55 | public: 56 | // initialize parameters for quantization 57 | void Init(const std::string& dirPathSrc, const std::string& filePfxSrc); 58 | // configure all layers according to the settings 59 | void ConfigLayer_AlexNet(void); 60 | // configure all layers according to the settings 61 | void ConfigLayer_CaffeNet(void); 62 | // configure all layers according to the settings 63 | void ConfigLayer_VggCnnS(void); 64 | // configure all layers according to the settings 65 | void ConfigLayer_VGG16(void); 66 | // configure all layers according to the settings 67 | void ConfigLayer_CaffeNetFGB(void); 68 | // configure all layers according to the settings 69 | void ConfigLayer_CaffeNetFGD(void); 70 | // load layer parameters from files 71 | bool LoadLayerPara(const bool enblAprx, const ENUM_AsmtEnc asmtEnc); 72 | // convert raw-encoded index files to compact-encoded 73 | bool CvtAsmtEnc(const ENUM_AsmtEnc asmtEncSrc, const ENUM_AsmtEnc asmtEncDst); 74 | 75 | public: 76 | // main directory for data import/export 77 | std::string dirPath; 78 | // file name prefix 79 | std::string filePfx; 80 | // number of layers 81 | int layerCnt; 82 | // number of input feature map channels 83 | int imgChnIn; 84 | // input feature map height 85 | int imgHeiIn; 86 | // input feature map width 87 | int imgWidIn; 88 | // all layers' basic information 89 | LayerInfoLst layerInfoLst; 90 | // all layers' parameters 91 | LayerParaLst layerParaLst; 92 | 93 | private: 94 | // determine the proper value for 95 | int CalcBitCntPerEle(const Matrix& asmtLst); 96 | // configure each layer type 97 | void ConfigConvLayer(LayerInfo* pLayerInfo, const int padSiz, 98 | const int knlSiz, const int knlCnt, const int grpCnt, const int stride); 99 | void ConfigPoolLayer(LayerInfo* pLayerInfo, 100 | const int padSiz, const int knlSiz, const int stride); 101 | void ConfigFCntLayer(LayerInfo* pLayerInfo, const int nodCnt); 102 | void ConfigReLuLayer(LayerInfo* pLayerInfo); 103 | void ConfigLoRNLayer(LayerInfo* pLayerInfo, const int lrnSiz, 104 | const float lrnAlp, const float lrnBet, const float lrnIni); 105 | void ConfigDrptLayer(LayerInfo* pLayerInfo, const float drpRat); 106 | void ConfigSMaxLayer(LayerInfo* pLayerInfo); 107 | }; 108 | 109 | #endif // INCLUDE_CAFFEPARA_H_ 110 | -------------------------------------------------------------------------------- /include/Common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_COMMON_H_ 9 | #define INCLUDE_COMMON_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define ENABLE_DEBUG_OUTPUT 27 | 28 | #endif // INCLUDE_COMMON_H_ 29 | -------------------------------------------------------------------------------- /include/FileIO.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_FILEIO_H_ 9 | #define INCLUDE_FILEIO_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "../include/Common.h" 15 | #include "../include/Matrix.h" 16 | 17 | typedef struct { 18 | std::string typeName; 19 | std::string inputFrmtStr; 20 | std::string outputFrmtStr; 21 | } TypeInfo; 22 | 23 | class FileIO { 24 | public: 25 | // read from a binary-encoded file 26 | template 27 | static bool ReadBinFile(const std::string& filePath, Matrix* pDataLst); 28 | // read from a compact-binary-encoded file 29 | template 30 | static bool ReadCbnFile(const std::string& filePath, Matrix* pDataLst); 31 | // read from a plain text file 32 | template 33 | static bool ReadTxtFile(const std::string& filePath, Matrix* pDataLst); 34 | // write to a binary-encoded file 35 | template 36 | static bool WriteBinFile( 37 | const std::string& filePath, const Matrix& dataLst); 38 | // write to a compact-binary-encoded file 39 | template 40 | static bool WriteCbnFile(const std::string& filePath, 41 | const Matrix& dataLst, const int bitCntPerEle); 42 | // write to a plain text file 43 | template 44 | static bool WriteTxtFile( 45 | const std::string& filePath, const Matrix& dataLst); 46 | 47 | private: 48 | // get 's type name 49 | template 50 | static void GetTypeInfo(const Matrix& dataLst, TypeInfo* pTypeInfo); 51 | }; 52 | 53 | // implementation of member functions 54 | 55 | template 56 | bool FileIO::ReadBinFile(const std::string& filePath, Matrix* pDataLst) { 57 | // declare auxiliary variables 58 | std::size_t rtnVal; 59 | int32_t dimCnt; 60 | int32_t* dimLenLst; 61 | const int kBufferLenData = 4096; 62 | 63 | // open file 64 | FILE* inFile = fopen(filePath.c_str(), "rb"); 65 | if (inFile == nullptr) { 66 | printf("[ERROR] could not open file at %s\n", filePath.c_str()); 67 | return false; 68 | } // ENDIF: inFile 69 | 70 | // read basic variables 71 | rtnVal = fread(&dimCnt, sizeof(int32_t), 1, inFile); 72 | dimLenLst = new int32_t[dimCnt]; 73 | rtnVal = fread(dimLenLst, sizeof(int32_t), dimCnt, inFile); 74 | 75 | // allocate memory space for 76 | pDataLst->Create(dimCnt, dimLenLst); 77 | 78 | // read data matrix from file 79 | printf("[INFO] reading data matrix from %s\n", filePath.c_str()); 80 | int dataCnt = pDataLst->GetEleCnt(); 81 | int dataCntInBuffer = kBufferLenData / sizeof(T); 82 | int bufferCntData = (dataCnt + dataCntInBuffer - 1) / dataCntInBuffer; 83 | int dataCntInBufferLast = dataCnt - dataCntInBuffer * (bufferCntData - 1); 84 | for (int bufferIndData = 0; bufferIndData < bufferCntData; bufferIndData++) { 85 | // obtain the data pointer for data copying 86 | T* dataVec = pDataLst->GetDataPtr() + dataCntInBuffer * bufferIndData; 87 | 88 | // check whether is the last data buffer 89 | if (bufferIndData < bufferCntData - 1) { // not the last data buffer 90 | rtnVal = fread(dataVec, sizeof(T), dataCntInBuffer, inFile); 91 | assert(rtnVal == dataCntInBuffer); 92 | } else { // the last data buffer 93 | rtnVal = fread(dataVec, sizeof(T), dataCntInBufferLast, inFile); 94 | assert(rtnVal == dataCntInBufferLast); 95 | } // ENDIF: bufferIndData 96 | } // ENDFOR: bufferIndData 97 | pDataLst->DispSizInfo(); 98 | printf("[INFO] reading data matrix from %s [COMPLETED]\n", filePath.c_str()); 99 | 100 | // close file 101 | fclose(inFile); 102 | 103 | // free pointers 104 | delete[] dimLenLst; 105 | 106 | return true; 107 | } 108 | 109 | template 110 | bool FileIO::ReadCbnFile(const std::string& filePath, Matrix* pDataLst) { 111 | // declare auxiliary variables 112 | std::size_t rtnVal; 113 | int32_t dimCnt; 114 | int32_t* dimLenLst; 115 | int32_t bitCntPerEle; // each data element's length (in bits) 116 | const int kBufferLen = 4096; 117 | uint8_t bufferArray[kBufferLen]; 118 | const int kBitCntPerBuf = 8; // each buffer element has 8 bits 119 | 120 | // open file 121 | FILE* inFile = fopen(filePath.c_str(), "rb"); 122 | if (inFile == nullptr) { 123 | printf("[ERROR] could not open file at %s\n", filePath.c_str()); 124 | return false; 125 | } // ENDIF: inFile 126 | 127 | // read basic variables 128 | rtnVal = fread(&dimCnt, sizeof(int32_t), 1, inFile); 129 | dimLenLst = new int32_t[dimCnt]; 130 | rtnVal = fread(dimLenLst, sizeof(int32_t), dimCnt, inFile); 131 | rtnVal = fread(&bitCntPerEle, sizeof(int32_t), 1, inFile); 132 | 133 | // allocate memory space for 134 | pDataLst->Create(dimCnt, dimLenLst); 135 | 136 | // read data matrix from file 137 | printf("[INFO] reading data matrix from %s\n", filePath.c_str()); 138 | int dataCnt = pDataLst->GetEleCnt(); 139 | int dataCntInBuf = kBufferLen * kBitCntPerBuf / bitCntPerEle; 140 | int bufferCnt = (dataCnt + dataCntInBuf - 1) / dataCntInBuf; 141 | for (int bufferInd = 0; bufferInd < bufferCnt; bufferInd++) { 142 | // determine the starting/ending indices of the selected data elements 143 | int dataIndBeg = dataCntInBuf * bufferInd; 144 | int dataIndEnd = std::min(dataCnt, dataIndBeg + dataCntInBuf) - 1; 145 | int dataCntSel = dataIndEnd - dataIndBeg + 1; 146 | 147 | // read file and store data in the buffer 148 | rtnVal = fread(bufferArray, sizeof(uint8_t), kBufferLen, inFile); 149 | assert(rtnVal == kBufferLen); 150 | 151 | // copy data to the buffer 152 | uint8_t* pBuffer = bufferArray; 153 | T* dataVec = pDataLst->GetDataPtr() + dataIndBeg; 154 | int bitCntLeft = kBitCntPerBuf; 155 | for (int dataIndSel = 0; dataIndSel < dataCntSel; dataIndSel++) { 156 | if (bitCntLeft >= bitCntPerEle) { 157 | bitCntLeft -= bitCntPerEle; 158 | dataVec[dataIndSel] = *pBuffer >> bitCntLeft; 159 | } else { 160 | dataVec[dataIndSel] = *(pBuffer++) << (bitCntPerEle - bitCntLeft); 161 | bitCntLeft = kBitCntPerBuf - (bitCntPerEle - bitCntLeft); 162 | dataVec[dataIndSel] |= *pBuffer >> bitCntLeft; 163 | } // ENDIF: bitCntLeft 164 | *pBuffer %= (1 << bitCntLeft); 165 | dataVec[dataIndSel] += 1; // append the offset 166 | } // ENDFOR: dataIndSel 167 | } // ENDFOR: bufferInd 168 | pDataLst->DispSizInfo(); 169 | printf("[INFO] reading data matrix from %s [COMPLETED]\n", filePath.c_str()); 170 | 171 | // close file 172 | fclose(inFile); 173 | 174 | // free pointers 175 | delete[] dimLenLst; 176 | 177 | return true; 178 | } 179 | 180 | template 181 | bool FileIO::ReadTxtFile(const std::string& filePath, Matrix* pDataLst) { 182 | // declare auxiliary variables 183 | std::size_t rtnVal; 184 | int32_t dimCnt; 185 | int32_t* dimLenLst; 186 | TypeInfo typeInfo; 187 | 188 | // open file 189 | FILE* inFile = fopen(filePath.c_str(), "r"); 190 | if (inFile == nullptr) { 191 | printf("[ERROR] could not open file at %s\n", filePath.c_str()); 192 | return false; 193 | } // ENDIF: inFile 194 | 195 | // read basic variables 196 | rtnVal = fscanf(inFile, "%d", &dimCnt); 197 | assert(rtnVal == 1); 198 | dimLenLst = new int32_t[dimCnt]; 199 | for (int dimInd = 0; dimInd < dimCnt; dimInd++) { 200 | rtnVal = fscanf(inFile, "%d", dimLenLst + dimInd); 201 | assert(rtnVal == 1); 202 | } // ENDFOR: dimInd 203 | 204 | // allocate memory space for 205 | pDataLst->Create(dimCnt, dimLenLst); 206 | 207 | // read data matrix from file 208 | printf("[INFO] reading data matrix from %s\n", filePath.c_str()); 209 | GetTypeInfo(*pDataLst, &typeInfo); 210 | int dataCnt = pDataLst->GetEleCnt(); 211 | T* dataPtr = pDataLst->GetDataPtr(); 212 | for (int dataInd = 0; dataInd < dataCnt; dataInd++, dataPtr++) { 213 | rtnVal = fscanf(inFile, typeInfo.inputFrmtStr.c_str(), dataPtr); 214 | assert(rtnVal == 1); 215 | } // ENDFOR: dataInd 216 | pDataLst->DispSizInfo(); 217 | printf("[INFO] reading data matrix from %s [COMPLETED]\n", filePath.c_str()); 218 | 219 | // close file 220 | fclose(inFile); 221 | 222 | // free pointers 223 | delete[] dimLenLst; 224 | 225 | return true; 226 | } 227 | 228 | template 229 | bool FileIO::WriteBinFile( 230 | const std::string& filePath, const Matrix& dataLst) { 231 | // declare auxiliary variables 232 | int rtnVal; 233 | int32_t dimCnt; 234 | int32_t dimLen; 235 | const int kBufferLenData = 4096; 236 | 237 | // open file 238 | FILE* outFile = fopen(filePath.c_str(), "wb"); 239 | if (outFile == nullptr) { 240 | printf("[ERROR] could not open file at %s\n", filePath.c_str()); 241 | return false; 242 | } // ENDIF: outFile 243 | 244 | // write basic variables 245 | dimCnt = dataLst.GetDimCnt(); 246 | fwrite(&dimCnt, sizeof(int32_t), 1, outFile); 247 | for (int dimInd = 0; dimInd < dimCnt; dimInd++) { 248 | dimLen = dataLst.GetDimLen(dimInd); 249 | fwrite(&dimLen, sizeof(int32_t), 1, outFile); 250 | } // ENDFOR: dimInd 251 | 252 | // write data matrix to file 253 | printf("[INFO] writing data matrix from %s\n", filePath.c_str()); 254 | int dataCnt = dataLst.GetEleCnt(); 255 | int dataCntInBuffer = kBufferLenData / sizeof(T); 256 | int bufferCntData = (dataCnt + dataCntInBuffer - 1) / dataCntInBuffer; 257 | int dataCntInBufferLast = dataCnt - dataCntInBuffer * (bufferCntData - 1); 258 | for (int bufferIndData = 0; bufferIndData < bufferCntData; bufferIndData++) { 259 | // obtain the data pointer for data copying 260 | T* dataVec = dataLst.GetDataPtr() + dataCntInBuffer * bufferIndData; 261 | 262 | // check whether is the last data buffer 263 | if (bufferIndData < bufferCntData - 1) { // not the last data buffer 264 | rtnVal = fwrite(dataVec, sizeof(T), dataCntInBuffer, outFile); 265 | assert(rtnVal == dataCntInBuffer); 266 | } else { // the last data buffer 267 | rtnVal = fwrite(dataVec, sizeof(T), dataCntInBufferLast, outFile); 268 | assert(rtnVal == dataCntInBufferLast); 269 | } // ENDIF: bufferIndData 270 | } // ENDFOR: bufferIndData 271 | dataLst.DispSizInfo(); 272 | printf("[INFO] writing data matrix from %s [COMPLETED]\n", filePath.c_str()); 273 | 274 | // close file 275 | fclose(outFile); 276 | 277 | return true; 278 | } 279 | 280 | template 281 | bool FileIO::WriteCbnFile(const std::string& filePath, 282 | const Matrix& dataLst, const int bitCntPerEle) { 283 | // declare auxiliary variables 284 | int rtnVal; 285 | int32_t dimCnt; 286 | int32_t dimLen; 287 | const int kBufferLen = 4096; 288 | uint8_t bufferArray[kBufferLen]; 289 | const int kBitCntPerBuf = 8; // each buffer element hass 8 bits 290 | 291 | // open file 292 | FILE* outFile = fopen(filePath.c_str(), "wb"); 293 | if (outFile == nullptr) { 294 | printf("[ERROR] could not open file at %s\n", filePath.c_str()); 295 | return false; 296 | } // ENDIF: outFile 297 | 298 | // write basic variables 299 | dimCnt = dataLst.GetDimCnt(); 300 | fwrite(&dimCnt, sizeof(int32_t), 1, outFile); 301 | for (int dimInd = 0; dimInd < dimCnt; dimInd++) { 302 | dimLen = dataLst.GetDimLen(dimInd); 303 | fwrite(&dimLen, sizeof(int32_t), 1, outFile); 304 | } // ENDFOR: dimInd 305 | 306 | // write the number of bits for each data element 307 | fwrite(&bitCntPerEle, sizeof(int32_t), 1, outFile); 308 | 309 | // write data matrix to file 310 | printf("[INFO] writing data matrix from %s\n", filePath.c_str()); 311 | int dataCnt = dataLst.GetEleCnt(); 312 | int dataCntInBuf = kBufferLen * kBitCntPerBuf / bitCntPerEle; 313 | int bufferCnt = (dataCnt + dataCntInBuf - 1) / dataCntInBuf; 314 | for (int bufferInd = 0; bufferInd < bufferCnt; bufferInd++) { 315 | // determine the starting/ending indices of the selected data elements 316 | int dataIndBeg = dataCntInBuf * bufferInd; 317 | int dataIndEnd = std::min(dataCnt, dataIndBeg + dataCntInBuf) - 1; 318 | int dataCntSel = dataIndEnd - dataIndBeg + 1; 319 | 320 | // reset all elements in the buffer to zeros 321 | memset(bufferArray, 0, sizeof(uint8_t) * kBufferLen); 322 | 323 | // copy data to the buffer 324 | const T* dataVec = dataLst.GetDataPtr() + dataIndBeg; 325 | uint8_t* pBuffer = bufferArray; 326 | int bitCntLeft = kBitCntPerBuf; 327 | for (int dataIndSel = 0; dataIndSel < dataCntSel; dataIndSel++) { 328 | if (bitCntLeft >= bitCntPerEle) { 329 | bitCntLeft -= bitCntPerEle; 330 | *pBuffer |= ((dataVec[dataIndSel] - 1) << bitCntLeft); 331 | } else { 332 | *(pBuffer++) |= 333 | ((dataVec[dataIndSel] - 1) >> (bitCntPerEle - bitCntLeft)); 334 | bitCntLeft = kBitCntPerBuf - (bitCntPerEle - bitCntLeft); 335 | *pBuffer |= ((dataVec[dataIndSel] - 1) << bitCntLeft); 336 | } // ENDIF: bitCntLeft 337 | } // ENDFOR: dataIndSel 338 | 339 | // write the buffer to the file 340 | rtnVal = fwrite(bufferArray, sizeof(uint8_t), kBufferLen, outFile); 341 | assert(rtnVal == kBufferLen); 342 | } // ENDFOR: bufferInd 343 | dataLst.DispSizInfo(); 344 | printf("[INFO] writing data matrix from %s [COMPLETED]\n", filePath.c_str()); 345 | 346 | // close file 347 | fclose(outFile); 348 | 349 | return true; 350 | } 351 | 352 | template 353 | bool FileIO::WriteTxtFile( 354 | const std::string& filePath, const Matrix& dataLst) { 355 | // declare auxiliary variables 356 | int32_t dimCnt; 357 | TypeInfo typeInfo; 358 | 359 | // open file 360 | FILE* outFile = fopen(filePath.c_str(), "w"); 361 | if (outFile == nullptr) { 362 | printf("[ERROR] could not open file at %s\n", filePath.c_str()); 363 | return false; 364 | } // ENDIF: outFile 365 | 366 | // write basic variables 367 | dimCnt = dataLst.GetDimCnt(); 368 | fprintf(outFile, "%d", dimCnt); 369 | for (int dimInd = 0; dimInd < dimCnt; dimInd++) { 370 | fprintf(outFile, " %d", dataLst.GetDimLen(dimInd)); 371 | } // ENDFOR: dimInd 372 | fprintf(outFile, "\n"); 373 | 374 | // write data matrix to file 375 | printf("[INFO] writing data matrix to %s\n", filePath.c_str()); 376 | GetTypeInfo(dataLst, &typeInfo); 377 | int dataCnt = dataLst.GetEleCnt(); 378 | int dimLenLast = dataLst.GetDimLen(dimCnt - 1); 379 | const T* dataPtr = dataLst.GetDataPtr(); 380 | for (int dataInd = 0; dataInd < dataCnt; dataInd++, dataPtr++) { 381 | fprintf(outFile, typeInfo.outputFrmtStr.c_str(), *dataPtr); 382 | fprintf(outFile, "%s", ((dataInd + 1) % dimLenLast != 0) ? " " : "\n"); 383 | } // ENDFOR: dataInd 384 | dataLst.DispSizInfo(); 385 | printf("[INFO] writing data matrix to %s [COMPLETED]\n", filePath.c_str()); 386 | 387 | // close file 388 | fclose(outFile); 389 | 390 | return true; 391 | } 392 | 393 | template 394 | void FileIO::GetTypeInfo(const Matrix& dataLst, TypeInfo* pTypeInfo) { 395 | // declare auxiliary variables to obtain the type name 396 | static uint8_t valUInt8; 397 | static int8_t valInt8; 398 | static uint16_t valUInt16; 399 | static int16_t valInt16; 400 | static uint32_t valUInt32; 401 | static int32_t valInt32; 402 | static float valFlt; 403 | static double valDbl; 404 | 405 | // obtain the name of the input type 406 | std::string tName = typeid(T).name(); 407 | 408 | // compare the type name with known ones 409 | if (tName == typeid(valUInt8).name()) { 410 | pTypeInfo->typeName = "uint8_t"; 411 | pTypeInfo->inputFrmtStr = "%hhu"; 412 | pTypeInfo->outputFrmtStr = "%hhu"; 413 | } else if (tName == typeid(valInt8).name()) { 414 | pTypeInfo->typeName = "int8_t"; 415 | pTypeInfo->inputFrmtStr = "%hhd"; 416 | pTypeInfo->outputFrmtStr = "%hhd"; 417 | } else if (tName == typeid(valUInt16).name()) { 418 | pTypeInfo->typeName = "uint16_t"; 419 | pTypeInfo->inputFrmtStr = "%hu"; 420 | pTypeInfo->outputFrmtStr = "%hu"; 421 | } else if (tName == typeid(valInt16).name()) { 422 | pTypeInfo->typeName = "int16_t"; 423 | pTypeInfo->inputFrmtStr = "%hd"; 424 | pTypeInfo->outputFrmtStr = "%hd"; 425 | } else if (tName == typeid(valUInt32).name()) { 426 | pTypeInfo->typeName = "uint32_t"; 427 | pTypeInfo->inputFrmtStr = "%u"; 428 | pTypeInfo->outputFrmtStr = "%u"; 429 | } else if (tName == typeid(valInt32).name()) { 430 | pTypeInfo->typeName = "int32_t"; 431 | pTypeInfo->inputFrmtStr = "%d"; 432 | pTypeInfo->outputFrmtStr = "%d"; 433 | } else if (tName == typeid(valFlt).name()) { 434 | pTypeInfo->typeName = "float"; 435 | pTypeInfo->inputFrmtStr = "%f"; 436 | pTypeInfo->outputFrmtStr = "%.4f"; 437 | } else if (tName == typeid(valDbl).name()) { 438 | pTypeInfo->typeName = "double"; 439 | pTypeInfo->inputFrmtStr = "%lf"; 440 | pTypeInfo->outputFrmtStr = "%.4f"; 441 | } else { 442 | printf("[ERROR] unrecognized type name: %s\n", tName.c_str()); 443 | return; 444 | } // ENDIF: tName 445 | } 446 | 447 | #endif // INCLUDE_FILEIO_H_ 448 | -------------------------------------------------------------------------------- /include/Matrix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_MATRIX_H_ 9 | #define INCLUDE_MATRIX_H_ 10 | 11 | #include 12 | 13 | #include "../include/Common.h" 14 | 15 | const int kMatDimCntMax = 4; 16 | 17 | template 18 | class Matrix { 19 | public: 20 | // constructor function 21 | Matrix(void); 22 | Matrix(const Matrix& mat); 23 | explicit Matrix(const int m); 24 | Matrix(const int m, const int n); 25 | Matrix(const int m, const int n, const int p); 26 | Matrix(const int m, const int n, const int p, const int q); 27 | Matrix(const int dimCnt, const int* dimLenLst); 28 | // de-constructor function 29 | ~Matrix(void); 30 | // create matrix 31 | inline void Create(const int m); 32 | inline void Create(const int m, const int n); 33 | inline void Create(const int m, const int n, const int p); 34 | inline void Create(const int m, const int n, const int p, const int q); 35 | inline void Create(const int dimCnt, const int* dimLenLst); 36 | // release memory 37 | inline void Destroy(void); 38 | // obtain the data pointer 39 | inline T* GetDataPtr(void) const; 40 | inline T* GetDataPtr(const int im) const; 41 | inline T* GetDataPtr(const int im, const int in) const; 42 | inline T* GetDataPtr(const int im, const int in, const int ip) const; 43 | inline T* GetDataPtr( 44 | const int im, const int in, const int ip, const int iq) const; 45 | // obtain the number of dimensions 46 | inline int GetDimCnt(void) const; 47 | // obtain the length of x-th dimension 48 | inline int GetDimLen(const int dimIdx) const; 49 | // obtain the pointer step of x-th dimension 50 | inline int GetDimStp(const int dimIdx) const; 51 | // obtain the total number of elements 52 | inline int GetEleCnt(void) const; 53 | // display matrix size information 54 | inline void DispSizInfo(void) const; 55 | // set the element value at the specified location 56 | inline void SetEleAt(const T val, const int im); 57 | inline void SetEleAt(const T val, const int im, const int in); 58 | inline void SetEleAt(const T val, const int im, const int in, const int ip); 59 | inline void SetEleAt( 60 | const T val, const int im, const int in, const int ip, const int iq); 61 | // get the element value at the specified location 62 | inline T GetEleAt(const int im) const; 63 | inline T GetEleAt(const int im, const int in) const; 64 | inline T GetEleAt(const int im, const int in, const int ip) const; 65 | inline T GetEleAt( 66 | const int im, const int in, const int ip, const int iq) const; 67 | // resize matrix 68 | inline void Resize(const int m); 69 | inline void Resize(const int m, const int n); 70 | inline void Resize(const int m, const int n, const int p); 71 | inline void Resize(const int m, const int n, const int p, const int q); 72 | // permute dimensions 73 | void Permute(const int mSdx, const int nSdx); 74 | void Permute(const int mSdx, const int nSdx, const int pSdx); 75 | void Permute(const int mSdx, const int nSdx, const int pSdx, const int qSdx); 76 | // get a sub-matrix at the specified location 77 | void GetSubMat(const int imBeg, Matrix* pMatDst) const; 78 | void GetSubMat(const int imBeg, const int inBeg, Matrix* pMatDst) const; 79 | void GetSubMat(const int imBeg, 80 | const int inBeg, const int ipBeg, Matrix* pMatDst) const; 81 | void GetSubMat(const int imBeg, const int inBeg, 82 | const int ipBeg, const int iqBeg, Matrix* pMatDst) const; 83 | 84 | private: 85 | // number of dimensions 86 | int dimCnt_; 87 | // length of the 1st dimension 88 | int m_; 89 | // length of the 2nd dimension 90 | int n_; 91 | // length of the 3rd dimension 92 | int p_; 93 | // length of the 4th dimension 94 | int q_; 95 | // data pointer 96 | T* data_; 97 | }; 98 | 99 | // implementation of member functions 100 | 101 | template 102 | Matrix::Matrix(void) { 103 | // initialize all variables 104 | dimCnt_ = 0; 105 | data_ = nullptr; 106 | } 107 | 108 | template 109 | Matrix::Matrix(const Matrix& mat) : data_(nullptr) { 110 | // declare a static array to specify each dimension's length 111 | static int dimLenLst[kMatDimCntMax]; 112 | 113 | // create a new matrix and copy data 114 | for (int dimIdx = 0; dimIdx < mat.GetDimCnt(); dimIdx++) { 115 | dimLenLst[dimIdx] = mat.GetDimLen(dimIdx); 116 | } // ENDFOR: dimIdx 117 | Create(mat.GetDimCnt(), dimLenLst); 118 | memcpy(data_, mat.GetDataPtr(), sizeof(T) * GetEleCnt()); 119 | } 120 | 121 | template 122 | Matrix::Matrix(const int m) : data_(nullptr) { 123 | Create(m); 124 | } 125 | 126 | template 127 | Matrix::Matrix(const int m, const int n) : data_(nullptr) { 128 | Create(m, n); 129 | } 130 | 131 | template 132 | Matrix::Matrix(const int m, const int n, const int p) : data_(nullptr) { 133 | Create(m, n, p); 134 | } 135 | 136 | template 137 | Matrix::Matrix( 138 | const int m, const int n, const int p, const int q) : data_(nullptr) { 139 | Create(m, n, p, q); 140 | } 141 | 142 | template 143 | Matrix::Matrix(const int dimCnt, const int* dimLenLst) : data_(nullptr) { 144 | Create(dimCnt, dimLenLst); 145 | } 146 | 147 | template 148 | Matrix::~Matrix(void) { 149 | Destroy(); 150 | } 151 | 152 | template 153 | inline void Matrix::Create(const int m) { 154 | // release previously allocated memory 155 | Destroy(); 156 | 157 | // create a new matrix 158 | dimCnt_ = 1; 159 | m_ = m; 160 | data_ = new T[GetEleCnt()]; 161 | } 162 | 163 | template 164 | inline void Matrix::Create(const int m, const int n) { 165 | // release previously allocated memory 166 | Destroy(); 167 | 168 | // create a new matrix 169 | dimCnt_ = 2; 170 | m_ = m; 171 | n_ = n; 172 | data_ = new T[GetEleCnt()]; 173 | } 174 | 175 | template 176 | inline void Matrix::Create(const int m, const int n, const int p) { 177 | // release previously allocated memory 178 | Destroy(); 179 | 180 | // create a new matrix 181 | dimCnt_ = 3; 182 | m_ = m; 183 | n_ = n; 184 | p_ = p; 185 | data_ = new T[GetEleCnt()]; 186 | } 187 | 188 | template 189 | inline void Matrix::Create( 190 | const int m, const int n, const int p, const int q) { 191 | // release previously allocated memory 192 | Destroy(); 193 | 194 | // create a new matrix 195 | dimCnt_ = 4; 196 | m_ = m; 197 | n_ = n; 198 | p_ = p; 199 | q_ = q; 200 | data_ = new T[GetEleCnt()]; 201 | } 202 | 203 | template 204 | inline void Matrix::Create(const int dimCnt, const int* dimLenLst) { 205 | switch (dimCnt) { 206 | case 1: 207 | Create(dimLenLst[0]); 208 | break; 209 | case 2: 210 | Create(dimLenLst[0], dimLenLst[1]); 211 | break; 212 | case 3: 213 | Create(dimLenLst[0], dimLenLst[1], dimLenLst[2]); 214 | break; 215 | case 4: 216 | Create(dimLenLst[0], dimLenLst[1], dimLenLst[2], dimLenLst[3]); 217 | break; 218 | default: 219 | printf("[ERROR] invalid number of dimensions: %d\n", dimCnt); 220 | return; 221 | } // ENDSWITCH: dimCnt 222 | } 223 | 224 | template 225 | inline void Matrix::Destroy(void) { 226 | // release memory 227 | if (data_ != nullptr) { 228 | delete[] data_; 229 | data_ = nullptr; 230 | } // ENDIF: data_ 231 | 232 | // re-initialize variables 233 | dimCnt_ = 0; 234 | } 235 | 236 | template 237 | inline T* Matrix::GetDataPtr(void) const { 238 | return data_; 239 | } 240 | 241 | template 242 | inline T* Matrix::GetDataPtr(const int im) const { 243 | return (data_ + im); 244 | } 245 | 246 | template 247 | inline T* Matrix::GetDataPtr(const int im, const int in) const { 248 | return (data_ + (im * n_ + in)); 249 | } 250 | 251 | template 252 | inline T* Matrix::GetDataPtr( 253 | const int im, const int in, const int ip) const { 254 | return (data_ + ((im * n_ + in) * p_ + ip)); 255 | } 256 | 257 | template 258 | inline T* Matrix::GetDataPtr( 259 | const int im, const int in, const int ip, const int iq) const { 260 | return (data_ + (((im * n_ + in) * p_ + ip) * q_ + iq)); 261 | } 262 | 263 | template 264 | inline int Matrix::GetDimCnt(void) const { 265 | return dimCnt_; 266 | } 267 | 268 | template 269 | inline int Matrix::GetDimLen(const int dimIdx) const { 270 | switch (dimIdx) { 271 | case 0: 272 | return m_; 273 | case 1: 274 | return n_; 275 | case 2: 276 | return p_; 277 | case 3: 278 | return q_; 279 | default: 280 | printf("[ERROR] invalid index of dimension: %d\n", dimIdx); 281 | return -1; 282 | } // ENDSWITCH: dimIdx 283 | } 284 | 285 | template 286 | inline int Matrix::GetDimStp(const int dimIdx) const { 287 | // compute the pointer step iteratively 288 | if (dimIdx == dimCnt_ - 1) { 289 | return 1; 290 | } else { 291 | return GetDimLen(dimIdx + 1) * GetDimStp(dimIdx + 1); 292 | } // ENDIF: dimIdx 293 | } 294 | 295 | template 296 | inline int Matrix::GetEleCnt(void) const { 297 | int eleCnt = 1; 298 | switch (dimCnt_) { 299 | case 4: 300 | eleCnt *= q_; 301 | // fall through 302 | case 3: 303 | eleCnt *= p_; 304 | // fall through 305 | case 2: 306 | eleCnt *= n_; 307 | // fall through 308 | case 1: 309 | eleCnt *= m_; 310 | break; 311 | default: 312 | eleCnt = 0; 313 | break; 314 | } // ENDSWITCH: dimCnt 315 | 316 | return eleCnt; 317 | } 318 | 319 | template 320 | inline void Matrix::DispSizInfo(void) const { 321 | switch (dimCnt_) { 322 | case 1: 323 | printf("[INFO] matrix size: %d\n", m_); 324 | break; 325 | case 2: 326 | printf("[INFO] matrix size: %d x %d\n", m_, n_); 327 | break; 328 | case 3: 329 | printf("[INFO] matrix size: %d x %d x %d\n", m_, n_, p_); 330 | break; 331 | case 4: 332 | printf("[INFO] matrix size: %d x %d x %d x %d\n", m_, n_, p_, q_); 333 | break; 334 | } // ENDSWITCH: dimCnt 335 | } 336 | 337 | template 338 | inline void Matrix::SetEleAt(const T val, const int im) { 339 | data_[im] = val; 340 | } 341 | 342 | template 343 | inline void Matrix::SetEleAt(const T val, const int im, const int in) { 344 | data_[im * n_ + in] = val; 345 | } 346 | 347 | template 348 | inline void Matrix::SetEleAt( 349 | const T val, const int im, const int in, const int ip) { 350 | data_[(im * n_ + in) * p_ + ip] = val; 351 | } 352 | 353 | template 354 | inline void Matrix::SetEleAt( 355 | const T val, const int im, const int in, const int ip, const int iq) { 356 | data_[((im * n_ + in) * p_ + ip) * q_ + iq] = val; 357 | } 358 | 359 | template 360 | inline T Matrix::GetEleAt(const int im) const { 361 | return data_[im]; 362 | } 363 | 364 | template 365 | inline T Matrix::GetEleAt(const int im, const int in) const { 366 | return data_[im * n_ + in]; 367 | } 368 | 369 | template 370 | inline T Matrix::GetEleAt(const int im, const int in, const int ip) const { 371 | return data_[(im * n_ + in) * p_ + ip]; 372 | } 373 | 374 | template 375 | inline T Matrix::GetEleAt( 376 | const int im, const int in, const int ip, const int iq) const { 377 | return data_[((im * n_ + in) * p_ + ip) * q_ + iq]; 378 | } 379 | 380 | template 381 | inline void Matrix::Resize(const int m) { 382 | // check matrix size 383 | if (GetEleCnt() != m) { 384 | Create(m); 385 | } // ENDIF: GetEleCnt 386 | } 387 | 388 | template 389 | inline void Matrix::Resize(const int m, const int n) { 390 | // check matrix size 391 | if (GetEleCnt() != m * n) { 392 | Create(m, n); 393 | } else { 394 | dimCnt_ = 2; 395 | m_ = m; 396 | n_ = n; 397 | } // ENDIF: GetEleCnt 398 | } 399 | 400 | template 401 | inline void Matrix::Resize(const int m, const int n, const int p) { 402 | // check matrix size 403 | if (GetEleCnt() != m * n * p) { 404 | Create(m, n, p); 405 | } else { 406 | dimCnt_ = 3; 407 | m_ = m; 408 | n_ = n; 409 | p_ = p; 410 | } // ENDIF: GetEleCnt 411 | } 412 | 413 | template 414 | inline void Matrix::Resize( 415 | const int m, const int n, const int p, const int q) { 416 | // check matrix size 417 | if (GetEleCnt() != m * n * p * q) { 418 | Create(m, n, p, q); 419 | } else { 420 | dimCnt_ = 4; 421 | m_ = m; 422 | n_ = n; 423 | p_ = p; 424 | q_ = q; 425 | } // ENDIF: GetEleCnt 426 | } 427 | 428 | template 429 | void Matrix::Permute(const int mSdx, const int nSdx) { 430 | // create a temporary array and copy all data 431 | int eleCnt = GetEleCnt(); 432 | T* dataTmp = new T[eleCnt]; 433 | memcpy(dataTmp, data_, sizeof(T) * eleCnt); 434 | 435 | // determine the length of each dimension after updating 436 | int dimLenLstSrc[kMatDimCntMax]; 437 | int dimStpLstSrc[kMatDimCntMax]; 438 | for (int dimIdx = 0; dimIdx < dimCnt_; dimIdx++) { 439 | dimLenLstSrc[dimIdx] = GetDimLen(dimIdx); 440 | dimStpLstSrc[dimIdx] = GetDimStp(dimIdx); 441 | } 442 | 443 | // update each dimension's length 444 | m_ = dimLenLstSrc[mSdx]; 445 | n_ = dimLenLstSrc[nSdx]; 446 | 447 | // copy data from the temporary array 448 | for (int im = 0; im < m_; im++) { 449 | int mOffset = im * dimStpLstSrc[mSdx]; 450 | 451 | // determine the source/destination data pointer 452 | int stpSrc = dimStpLstSrc[nSdx]; 453 | const T* pSrc = dataTmp + mOffset; 454 | T* pDst = GetDataPtr(im, 0); 455 | 456 | // copy data to (im, in, ip, :) 457 | for (int in = 0; in < n_; in++, pSrc += stpSrc) { 458 | *(pDst++) = *pSrc; 459 | } // ENDFOR: in 460 | } // ENDFOR: im 461 | 462 | // release the temporary array 463 | delete[] dataTmp; 464 | } 465 | 466 | template 467 | void Matrix::Permute(const int mSdx, const int nSdx, const int pSdx) { 468 | // create a temporary array and copy all data 469 | int eleCnt = GetEleCnt(); 470 | T* dataTmp = new T[eleCnt]; 471 | memcpy(dataTmp, data_, sizeof(T) * eleCnt); 472 | 473 | // determine the length of each dimension after updating 474 | int dimLenLstSrc[kMatDimCntMax]; 475 | int dimStpLstSrc[kMatDimCntMax]; 476 | for (int dimIdx = 0; dimIdx < dimCnt_; dimIdx++) { 477 | dimLenLstSrc[dimIdx] = GetDimLen(dimIdx); 478 | dimStpLstSrc[dimIdx] = GetDimStp(dimIdx); 479 | } 480 | 481 | // update each dimension's length 482 | m_ = dimLenLstSrc[mSdx]; 483 | n_ = dimLenLstSrc[nSdx]; 484 | p_ = dimLenLstSrc[pSdx]; 485 | 486 | // copy data from the temporary array 487 | for (int im = 0; im < m_; im++) { 488 | int mOffset = im * dimStpLstSrc[mSdx]; 489 | for (int in = 0; in < n_; in++) { 490 | int nOffset = in * dimStpLstSrc[nSdx]; 491 | 492 | // determine the source/destination data pointer 493 | int stpSrc = dimStpLstSrc[pSdx]; 494 | const T* pSrc = dataTmp + mOffset + nOffset; 495 | T* pDst = GetDataPtr(im, in, 0); 496 | 497 | // copy data to (im, in, ip, :) 498 | for (int ip = 0; ip < p_; ip++, pSrc += stpSrc) { 499 | *(pDst++) = *pSrc; 500 | } // ENDFOR: ip 501 | } // ENDFOR: in 502 | } // ENDFOR: im 503 | 504 | // release the temporary array 505 | delete[] dataTmp; 506 | } 507 | 508 | template 509 | void Matrix::Permute( 510 | const int mSdx, const int nSdx, const int pSdx, const int qSdx) { 511 | // create a temporary array and copy all data 512 | int eleCnt = GetEleCnt(); 513 | T* dataTmp = new T[eleCnt]; 514 | memcpy(dataTmp, data_, sizeof(T) * eleCnt); 515 | 516 | // determine the length of each dimension after updating 517 | int dimLenLstSrc[kMatDimCntMax]; 518 | int dimStpLstSrc[kMatDimCntMax]; 519 | for (int dimIdx = 0; dimIdx < dimCnt_; dimIdx++) { 520 | dimLenLstSrc[dimIdx] = GetDimLen(dimIdx); 521 | dimStpLstSrc[dimIdx] = GetDimStp(dimIdx); 522 | } // ENDFOR: dimIdx 523 | 524 | // update each dimension's length 525 | m_ = dimLenLstSrc[mSdx]; 526 | n_ = dimLenLstSrc[nSdx]; 527 | p_ = dimLenLstSrc[pSdx]; 528 | q_ = dimLenLstSrc[qSdx]; 529 | 530 | // copy data from the temporary array 531 | for (int im = 0; im < m_; im++) { 532 | int mOffset = im * dimStpLstSrc[mSdx]; 533 | for (int in = 0; in < n_; in++) { 534 | int nOffset = in * dimStpLstSrc[nSdx]; 535 | for (int ip = 0; ip < p_; ip++) { 536 | int pOffset = ip * dimStpLstSrc[pSdx]; 537 | 538 | // determine the source/destination data pointer 539 | int stpSrc = dimStpLstSrc[qSdx]; 540 | const T* pSrc = dataTmp + mOffset + nOffset + pOffset; 541 | T* pDst = GetDataPtr(im, in, ip, 0); 542 | 543 | // copy data to (im, in, ip, :) 544 | for (int iq = 0; iq < q_; iq++, pSrc += stpSrc) { 545 | *(pDst++) = *pSrc; 546 | } // ENDFOR: iq 547 | } // ENDFOR: ip 548 | } // ENDFOR: in 549 | } // ENDFOR: im 550 | 551 | // release the temporary array 552 | delete[] dataTmp; 553 | } 554 | 555 | template 556 | void Matrix::GetSubMat(const int imBeg, Matrix* pMatDst) const { 557 | // determine the starting/ending height/width indexes 558 | int imDstBeg = std::max(0, 0 - imBeg); 559 | int imDstEnd = std::min(pMatDst->GetDimLen(0) - 1, m_ - 1 - imBeg); 560 | int featVecLen = imDstEnd - imDstBeg + 1; 561 | 562 | // reset all elements in to zeros 563 | memset(pMatDst->GetDataPtr(), 0, sizeof(T) * pMatDst->GetEleCnt()); 564 | 565 | // copy the selected part in the feature map 566 | const T* featVecSrc = GetDataPtr(imDstBeg + imBeg); 567 | T* featVecDst = pMatDst->GetDataPtr(imDstBeg); 568 | memcpy(featVecDst, featVecSrc, sizeof(T) * featVecLen); 569 | } 570 | 571 | template 572 | void Matrix::GetSubMat( 573 | const int imBeg, const int inBeg, Matrix* pMatDst) const { 574 | // determine the starting/ending height/width indexes 575 | int imDstBeg = std::max(0, 0 - imBeg); 576 | int imDstEnd = std::min(pMatDst->GetDimLen(0) - 1, m_ - 1 - imBeg); 577 | int inDstBeg = std::max(0, 0 - inBeg); 578 | int inDstEnd = std::min(pMatDst->GetDimLen(1) - 1, n_ - 1 - inBeg); 579 | int featVecLen = inDstEnd - inDstBeg + 1; 580 | 581 | // reset all elements in to zeros 582 | memset(pMatDst->GetDataPtr(), 0, sizeof(T) * pMatDst->GetEleCnt()); 583 | 584 | // copy the selected part in the feature map 585 | for (int imDst = imDstBeg; imDst <= imDstEnd; imDst++) { 586 | int im = imDst + imBeg; 587 | const T* featVecSrc = GetDataPtr(im, inDstBeg + inBeg); 588 | T* featVecDst = pMatDst->GetDataPtr(imDst, inDstBeg); 589 | memcpy(featVecDst, featVecSrc, sizeof(T) * featVecLen); 590 | } // ENDFOR: imDst 591 | } 592 | 593 | template 594 | void Matrix::GetSubMat(const int imBeg, 595 | const int inBeg, const int ipBeg, Matrix* pMatDst) const { 596 | // determine the starting/ending height/width indexes 597 | int imDstBeg = std::max(0, 0 - imBeg); 598 | int imDstEnd = std::min(pMatDst->GetDimLen(0) - 1, m_ - 1 - imBeg); 599 | int inDstBeg = std::max(0, 0 - inBeg); 600 | int inDstEnd = std::min(pMatDst->GetDimLen(1) - 1, n_ - 1 - inBeg); 601 | int ipDstBeg = std::max(0, 0 - ipBeg); 602 | int ipDstEnd = std::min(pMatDst->GetDimLen(2) - 1, p_ - 1 - ipBeg); 603 | int featVecLen = ipDstEnd - ipDstBeg + 1; 604 | 605 | // reset all elements in to zeros 606 | memset(pMatDst->GetDataPtr(), 0, sizeof(T) * pMatDst->GetEleCnt()); 607 | 608 | // copy the selected part in the feature map 609 | for (int imDst = imDstBeg; imDst <= imDstEnd; imDst++) { 610 | int im = imDst + imBeg; 611 | for (int inDst = inDstBeg; inDst <= inDstEnd; inDst++) { 612 | int in = inDst + inBeg; 613 | const T* featVecSrc = GetDataPtr(im, in, ipDstBeg + ipBeg); 614 | T* featVecDst = pMatDst->GetDataPtr(imDst, inDst, ipDstBeg); 615 | memcpy(featVecDst, featVecSrc, sizeof(T) * featVecLen); 616 | } // ENDFOR: inDst 617 | } // ENDFOR: imDst 618 | } 619 | 620 | template 621 | void Matrix::GetSubMat(const int imBeg, const int inBeg, 622 | const int ipBeg, const int iqBeg, Matrix* pMatDst) const { 623 | // determine the starting/ending height/width indexes 624 | int imDstBeg = std::max(0, 0 - imBeg); 625 | int imDstEnd = std::min(pMatDst->GetDimLen(0) - 1, m_ - 1 - imBeg); 626 | int inDstBeg = std::max(0, 0 - inBeg); 627 | int inDstEnd = std::min(pMatDst->GetDimLen(1) - 1, n_ - 1 - inBeg); 628 | int ipDstBeg = std::max(0, 0 - ipBeg); 629 | int ipDstEnd = std::min(pMatDst->GetDimLen(2) - 1, p_ - 1 - ipBeg); 630 | int iqDstBeg = std::max(0, 0 - iqBeg); 631 | int iqDstEnd = std::min(pMatDst->GetDimLen(3) - 1, q_ - 1 - iqBeg); 632 | int featVecLen = iqDstEnd - iqDstBeg + 1; 633 | 634 | // reset all elements in to zeros 635 | memset(pMatDst->GetDataPtr(), 0, sizeof(T) * pMatDst->GetEleCnt()); 636 | 637 | // copy the selected part in the feature map 638 | for (int imDst = imDstBeg; imDst <= imDstEnd; imDst++) { 639 | int im = imDst + imBeg; 640 | for (int inDst = inDstBeg; inDst <= inDstEnd; inDst++) { 641 | int in = inDst + inBeg; 642 | for (int ipDst = ipDstBeg; ipDst <= ipDstEnd; ipDst++) { 643 | int ip = ipDst + ipBeg; 644 | const T* featVecSrc = GetDataPtr(im, in, ip, iqDstBeg + iqBeg); 645 | T* featVecDst = pMatDst->GetDataPtr(imDst, inDst, ipDst, iqDstBeg); 646 | memcpy(featVecDst, featVecSrc, sizeof(T) * featVecLen); 647 | } // ENDFOR: ipDst 648 | } // ENDFOR: inDst 649 | } // ENDFOR: imDst 650 | } 651 | 652 | #endif // INCLUDE_MATRIX_H_ 653 | -------------------------------------------------------------------------------- /include/StopWatch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_STOPWATCH_H_ 9 | #define INCLUDE_STOPWATCH_H_ 10 | 11 | #include 12 | 13 | class StopWatch { 14 | public: 15 | // reset the stop-watch 16 | inline void Reset(void); 17 | // resume the stop-watch 18 | inline void Resume(void); 19 | // pause the stop-watch 20 | inline void Pause(void); 21 | // return the elapsed time 22 | inline float GetTime(void); 23 | 24 | private: 25 | // indicator for whether the stop-watch is running 26 | bool isRun; 27 | // timestamp of the latest Resume() operation 28 | time_t timeBeg; 29 | // timestamp of the latest Pause() operation 30 | time_t timeEnd; 31 | // elapsed time (in seconds) 32 | float timeElapsed; 33 | }; 34 | 35 | // implementation of member functions 36 | 37 | inline void StopWatch::Reset(void) { 38 | isRun = false; 39 | timeElapsed = 0.0; 40 | } 41 | 42 | inline void StopWatch::Resume(void) { 43 | if (!isRun) { 44 | isRun = true; 45 | timeBeg = clock(); 46 | } // ENDIF: isRun 47 | } 48 | 49 | inline void StopWatch::Pause(void) { 50 | if (isRun) { 51 | isRun = false; 52 | timeEnd = clock(); 53 | timeElapsed += static_cast(timeEnd - timeBeg) / CLOCKS_PER_SEC; 54 | } // ENDIF: isRun 55 | } 56 | 57 | inline float StopWatch::GetTime(void) { 58 | return timeElapsed; 59 | } 60 | 61 | #endif // INCLUDE_STOPWATCH_H_ 62 | -------------------------------------------------------------------------------- /include/UnitTest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #ifndef INCLUDE_UNITTEST_H_ 9 | #define INCLUDE_UNITTEST_H_ 10 | 11 | #include "../include/Common.h" 12 | 13 | class UnitTest { 14 | public: 15 | // unit-test for the class 16 | static void UT_CaffePara(void); 17 | // unit-test for the class 18 | static void UT_CaffeEva(void); 19 | // unit-test for the class 20 | static void UT_CaffeEvaWrapper(void); 21 | }; 22 | 23 | #endif // INCLUDE_UNITTEST_H_ 24 | -------------------------------------------------------------------------------- /src/BlasWrapper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/BlasWrapper.h" 9 | 10 | #ifdef IMPL_SGEMM 11 | 12 | // detailed implementation of matrix-matrix multiplication 13 | void cblas_sgemm_nn(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 14 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 15 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc); 16 | void cblas_sgemm_nt(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 17 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 18 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc); 19 | void cblas_sgemm_tn(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 20 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 21 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc); 22 | void cblas_sgemm_tt(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 23 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 24 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc); 25 | 26 | // matrix-matrix multiplication: C = alpha * op(A) * op(B) + beta * C 27 | void cblas_sgemm(const CBLAS_ORDER order, const CBLAS_TRANSPOSE transA, 28 | const CBLAS_TRANSPOSE transB, const CBLAS_INT m, const CBLAS_INT n, 29 | const CBLAS_INT k, const float alpha, const float* a, 30 | const CBLAS_INT lda, const float* b, const CBLAS_INT ldb, 31 | const float beta, float* c, const CBLAS_INT ldc) { 32 | // validate parameter 33 | if (order != CblasRowMajor) { 34 | printf("[ERROR] only is supported\n"); 35 | return; 36 | } // ENDIF: order 37 | 38 | // choose the proper entry according to and 39 | if (transA == CblasNoTrans) { 40 | if (transB == CblasNoTrans) { 41 | cblas_sgemm_nn(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc); 42 | } else { 43 | cblas_sgemm_nt(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc); 44 | } // ENDIF: transB 45 | } else { 46 | if (transB == CblasNoTrans) { 47 | cblas_sgemm_tn(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc); 48 | } else { 49 | cblas_sgemm_tt(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc); 50 | } // ENDIF: transB 51 | } // ENDIF: transA 52 | } 53 | 54 | // matrix-matrix multiplication (A: not transposed; B: not transposed) 55 | void cblas_sgemm_nn(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 56 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 57 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc) { 58 | // compute matrix-matrix multiplication 59 | for (CBLAS_INT im = 0; im < m; im++) { 60 | const float* pa = a + im * lda; 61 | float* pc = c + im * ldc; 62 | 63 | for (CBLAS_INT in = 0; in < n; in++) { 64 | pc[in] *= beta; 65 | } // ENDFOR: in 66 | for (CBLAS_INT ik = 0; ik < k; ik++) { 67 | const float va = pa[ik] * alpha; 68 | const float* pb = b + ik * ldb; 69 | for (CBLAS_INT in = 0; in < n; in++) { 70 | pc[in] += va * pb[in]; 71 | } // ENDFOR: in 72 | } // ENDFOR: ik 73 | } // ENDFOR: im 74 | } 75 | 76 | // matrix-matrix multiplication (A: not transposed; B: transposed) 77 | void cblas_sgemm_nt(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 78 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 79 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc) { 80 | // compute matrix-matrix multiplication 81 | for (CBLAS_INT im = 0; im < m; im++) { 82 | const float* pa = a + im * lda; 83 | float* pc = c + im * ldc; 84 | 85 | for (CBLAS_INT in = 0; in < n; in++) { 86 | pc[in] *= beta; 87 | } // ENDFOR: in 88 | for (CBLAS_INT in = 0; in < n; in++) { 89 | const float* pb = b + in * ldb; 90 | float val = 0.0; 91 | for (CBLAS_INT ik = 0; ik < k; ik++) { 92 | val += pa[ik] * pb[ik]; 93 | } // ENDFOR: ik 94 | pc[in] += val * alpha; 95 | } // ENDFOR: in 96 | } // ENDFOR: im 97 | } 98 | 99 | // matrix-matrix multiplication (A: transposed; B: not transposed) 100 | void cblas_sgemm_tn(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 101 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 102 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc) { 103 | printf("[ERROR] trans(A) * B is not supported\n"); 104 | } 105 | 106 | // matrix-matrix multiplication (A: transposed; B: transposed) 107 | void cblas_sgemm_tt(const CBLAS_INT m, const CBLAS_INT n, const CBLAS_INT k, 108 | const float alpha, const float *a, const CBLAS_INT lda, const float *b, 109 | const CBLAS_INT ldb, const float beta, float *c, const CBLAS_INT ldc) { 110 | printf("[ERROR] trans(A) * trans(B) is not supported\n"); 111 | } 112 | 113 | #endif // IMPL_SGEMM 114 | -------------------------------------------------------------------------------- /src/BmpImgIO.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/BmpImgIO.h" 9 | 10 | #include "../include/FileIO.h" 11 | #include "../include/bitmap_image.hpp" 12 | 13 | const int kImgChn = 3; 14 | const double kEpsilon = 0.0000001; 15 | 16 | bool BmpImgIO::Init(const BmpImgIOPara& bmpImgIOPara) { 17 | // initialize basic variables 18 | reszType = bmpImgIOPara.reszType; 19 | meanType = bmpImgIOPara.meanType; 20 | imgHeiFull = bmpImgIOPara.imgHeiFull; 21 | imgWidFull = bmpImgIOPara.imgWidFull; 22 | imgHeiCrop = bmpImgIOPara.imgHeiCrop; 23 | imgWidCrop = bmpImgIOPara.imgWidCrop; 24 | filePathMean = bmpImgIOPara.filePathMean; 25 | 26 | // load mean image 27 | // NOTE: is , using BGR format 28 | bool rtnFlg = FileIO::ReadBinFile(filePathMean, &imgDataMean); 29 | if (!rtnFlg) { // failed 30 | return false; 31 | } // ENDIF: rtnFlg 32 | 33 | // obtain the height/width of the mean image 34 | imgHeiMean = imgDataMean.GetDimLen(1); 35 | imgWidMean = imgDataMean.GetDimLen(2); 36 | 37 | return true; 38 | } 39 | 40 | bool BmpImgIO::Load(const std::string& filePath, Matrix* pImgDataFnal) { 41 | // define auxiliary variables 42 | Matrix imgDataOrgn; 43 | Matrix imgDataFull; 44 | 45 | // load a BMP image from file 46 | // NOTE: is <1xCxHxW>, using BGR format 47 | bool rtnFlg = LoadBmpImg(filePath, &imgDataOrgn); 48 | if (!rtnFlg) { // failed 49 | return false; 50 | } // ENDIF: rtnFlg 51 | 52 | // resize the original into to full image for cropping 53 | ReszImg(imgDataOrgn, &imgDataFull, reszType, imgHeiFull, imgWidFull); 54 | 55 | // remove the mean image and crop the central patch (or vice versa) 56 | switch (meanType) { 57 | case ENUM_MeanType::Full: 58 | RmMeanImg(imgDataMean, &imgDataFull); 59 | CropImg(imgDataFull, pImgDataFnal, imgHeiCrop, imgWidCrop); 60 | break; 61 | case ENUM_MeanType::Crop: 62 | CropImg(imgDataFull, pImgDataFnal, imgHeiCrop, imgWidCrop); 63 | RmMeanImg(imgDataMean, pImgDataFnal); 64 | break; 65 | default: 66 | printf("[ERROR] unrecognized value\n"); 67 | return false; 68 | } // ENDSWITCH: meanType 69 | 70 | return true; 71 | } 72 | 73 | bool BmpImgIO::LoadBmpImg( 74 | const std::string& filePath, Matrix* pImgData) { 75 | // read initial image data from file 76 | bitmap_image image(filePath); 77 | 78 | // check whether the image has been successfully opened 79 | if (!image) { 80 | printf("[ERROR] cannot open the BMP image at %s\n", filePath.c_str()); 81 | return false; 82 | } // ENDIF: image 83 | 84 | // allocate memory for 85 | int imgHei = image.height(); 86 | int imgWid = image.width(); 87 | pImgData->Create(1, kImgChn, imgHei, imgWid); 88 | 89 | // copy image data to 90 | uint8_t valR; 91 | uint8_t valG; 92 | uint8_t valB; 93 | for (int heiIdx = 0; heiIdx < imgHei; heiIdx++) { 94 | for (int widIdx = 0; widIdx < imgWid; widIdx++) { 95 | image.get_pixel(widIdx, heiIdx, valR, valG, valB); 96 | pImgData->SetEleAt(valB, 0, 0, heiIdx, widIdx); 97 | pImgData->SetEleAt(valG, 0, 1, heiIdx, widIdx); 98 | pImgData->SetEleAt(valR, 0, 2, heiIdx, widIdx); 99 | } // ENDFOR: widIdx 100 | } // ENDFOR: heiIdx 101 | 102 | return true; 103 | } 104 | 105 | void BmpImgIO::ReszImg(const Matrix& imgDataSrc, 106 | Matrix* pImgDataDst, const ENUM_ReszType type, 107 | const int imgHeiDstPst, const int imgWidDstPst) { 108 | // obtain basic variables 109 | int imgHeiSrc = imgDataSrc.GetDimLen(2); 110 | int imgWidSrc = imgDataSrc.GetDimLen(3); 111 | 112 | // determine the target image size 113 | int imgHeiDst; 114 | int imgWidDst; 115 | float scalFctrHei; 116 | float scalFctrWid; 117 | switch (type) { 118 | case ENUM_ReszType::Strict: 119 | scalFctrHei = static_cast(imgHeiSrc - 1) / (imgHeiDstPst - 1); 120 | scalFctrWid = static_cast(imgWidSrc - 1) / (imgWidDstPst - 1); 121 | imgHeiDst = imgHeiDstPst; 122 | imgWidDst = imgWidDstPst; 123 | break; 124 | case ENUM_ReszType::Relaxed: 125 | scalFctrHei = static_cast(imgHeiSrc - 1) / (imgHeiDstPst - 1); 126 | scalFctrWid = static_cast(imgWidSrc - 1) / (imgWidDstPst - 1); 127 | scalFctrHei = std::min(scalFctrHei, scalFctrWid); 128 | scalFctrWid = std::min(scalFctrHei, scalFctrWid); 129 | imgHeiDst = static_cast((imgHeiSrc - 1) / scalFctrHei + kEpsilon) + 1; 130 | imgWidDst = static_cast((imgWidSrc - 1) / scalFctrWid + kEpsilon) + 1; 131 | break; 132 | default: 133 | printf("[ERROR] unrecognized value\n"); 134 | return; 135 | } // ENDSWITCH: type 136 | printf("[INFO] resizing image from %d x %d to %d x %d\n", 137 | imgHeiSrc, imgWidSrc, imgHeiDst, imgWidDst); 138 | 139 | // resize the target image 140 | pImgDataDst->Resize(1, kImgChn, imgHeiDst, imgWidDst); 141 | 142 | // determine the image data after resizing 143 | for (int heiIdxDst = 0; heiIdxDst < imgHeiDst; heiIdxDst++) { 144 | // determine the corresponding indexes in the source image 145 | float heiIdxSrcC = scalFctrHei * heiIdxDst; 146 | int heiIdxSrcL = std::max(0, static_cast(heiIdxSrcC)); 147 | int heiIdxSrcH = std::min(imgHeiSrc - 1, heiIdxSrcL + 1); 148 | float weiHeiL = 1.0 - (heiIdxSrcC - heiIdxSrcL); 149 | float weiHeiH = 1.0 - (heiIdxSrcH - heiIdxSrcC); 150 | 151 | // scan through all indices in the target image 152 | for (int widIdxDst = 0; widIdxDst < imgWidDst; widIdxDst++) { 153 | // determine the corresponding indices in the source image 154 | float widIdxSrcC = scalFctrWid * widIdxDst; 155 | int widIdxSrcL = std::max(0, static_cast(widIdxSrcC)); 156 | int widIdxSrcH = std::min(imgWidSrc - 1, widIdxSrcL + 1); 157 | float weiWidL = 1.0 - (widIdxSrcC - widIdxSrcL); 158 | float weiWidH = 1.0 - (widIdxSrcH - widIdxSrcC); 159 | 160 | // fetch the LT/RT/LB/RB pixel values in the source image 161 | for (int chnIdx = 0; chnIdx < kImgChn; chnIdx++) { 162 | float valLT = imgDataSrc.GetEleAt(0, chnIdx, heiIdxSrcL, widIdxSrcL); 163 | float weiLT = weiHeiL * weiWidL; 164 | float valRT = imgDataSrc.GetEleAt(0, chnIdx, heiIdxSrcL, widIdxSrcH); 165 | float weiRT = weiHeiL * weiWidH; 166 | float valLB = imgDataSrc.GetEleAt(0, chnIdx, heiIdxSrcH, widIdxSrcL); 167 | float weiLB = weiHeiH * weiWidL; 168 | float valRB = imgDataSrc.GetEleAt(0, chnIdx, heiIdxSrcH, widIdxSrcH); 169 | float weiRB = weiHeiH * weiWidH; 170 | 171 | float valSum = valLT * weiLT + 172 | valRT * weiRT + valLB * weiLB + valRB * weiRB; 173 | float weiSum = weiLT + weiRT + weiLB + weiRB; 174 | pImgDataDst->SetEleAt(valSum / weiSum, 0, chnIdx, heiIdxDst, widIdxDst); 175 | } // ENDFOR: chnIdx 176 | } // ENDFOR: widIdxDst 177 | } // ENDFOR: heiIdxDst 178 | } 179 | 180 | void BmpImgIO::CropImg(const Matrix& imgDataSrc, 181 | Matrix* pImgDataDst, const int imgHeiDst, const int imgWidDst) { 182 | // obtain basic variables 183 | int imgHeiSrc = imgDataSrc.GetDimLen(2); 184 | int imgWidSrc = imgDataSrc.GetDimLen(3); 185 | int heiOffset = (imgHeiSrc - imgHeiDst) / 2; 186 | int widOffset = (imgWidSrc - imgWidDst) / 2; 187 | 188 | // resize the target image 189 | pImgDataDst->Resize(1, kImgChn, imgHeiDst, imgWidDst); 190 | 191 | // crop the central patch from the source image 192 | for (int chnIdx = 0; chnIdx < kImgChn; chnIdx++) { 193 | for (int heiIdxDst = 0; heiIdxDst < imgHeiDst; heiIdxDst++) { 194 | int heiIdxSrc = heiIdxDst + heiOffset; 195 | const float* pImgSrc = 196 | imgDataSrc.GetDataPtr(0, chnIdx, heiIdxSrc, widOffset); 197 | float* pImgDst = pImgDataDst->GetDataPtr(0, chnIdx, heiIdxDst, 0); 198 | memcpy(pImgDst, pImgSrc, sizeof(float) * imgWidDst); 199 | } // ENDFOR: heiIdxDst 200 | } // ENDFOR: chnIdx 201 | } 202 | 203 | void BmpImgIO::RmMeanImg( 204 | const Matrix& imgDataMean, Matrix* pImgDataProc) { 205 | // obtain basic variables 206 | int imgHeiProc = pImgDataProc->GetDimLen(2); 207 | int imgWidProc = pImgDataProc->GetDimLen(3); 208 | 209 | // verify the image size 210 | if ((imgHeiProc != imgHeiMean) || (imgWidProc != imgWidMean)) { 211 | printf("[ERROR] mismatch in the image size\n"); 212 | printf("imgHeiProc/Mean = %d/%d\n", imgHeiProc, imgHeiMean); 213 | printf("imgWidProc/Mean = %d/%d\n", imgWidProc, imgWidMean); 214 | return; 215 | } // ENDIF: imgHeiProc 216 | 217 | // modify each pixel's value 218 | int pxlCnt = pImgDataProc->GetEleCnt(); 219 | const float* pImgMean = imgDataMean.GetDataPtr(); 220 | float* pImgProc = pImgDataProc->GetDataPtr(); 221 | for (int pxlIdx = 0; pxlIdx < pxlCnt; pxlIdx++) { 222 | *(pImgProc++) -= *(pImgMean++); 223 | } // ENDFOR: pixelIdx 224 | } 225 | -------------------------------------------------------------------------------- /src/CaffeEva.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/CaffeEva.h" 9 | 10 | #include "../include/BlasWrapper.h" 11 | #include "../include/CaffePara.h" 12 | #include "../include/Common.h" 13 | #include "../include/FileIO.h" 14 | 15 | #ifdef ENBL_ANDROID_DBGR 16 | #include "share.h" 17 | #define SHR_PRINTF LOGI 18 | #else 19 | #define SHR_PRINTF printf 20 | #endif // ENDIF: ENBL_ANDROID_DBG 21 | 22 | // initialize constant variables 23 | const int kDataCntInBatch = 1; // number of images in each batch 24 | const int kBatchCntProc = 100; // number of batches 25 | const int kLablCntPerData = 5; // number of predicted labels per image 26 | 27 | CaffeEva::~CaffeEva(void) { 28 | // release dynamically allocated memory 29 | delete[] featMapLst; 30 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 31 | FeatBufStrLst& featBufStrLst = featBufStrMat[layerInd]; 32 | for (std::size_t bufInd = 0; bufInd < featBufStrLst.size(); bufInd++) { 33 | // skip if no memory is allocated to the current buffer 34 | if (featBufStrLst[bufInd].pFeatBuf != nullptr) { 35 | delete featBufStrLst[bufInd].pFeatBuf; 36 | featBufStrLst[bufInd].pFeatBuf = nullptr; 37 | } // ENDIF: featBufStrLst 38 | } // ENDFOR: bufInd 39 | } // ENDFOR: layerInd 40 | 41 | // destory objects: 42 | } 43 | 44 | void CaffeEva::Init(const bool enblAprxSrc) { 45 | // initialize 46 | enblAprx = enblAprxSrc; 47 | 48 | // initialize all stop-watches 49 | swAllLayers.Reset(); 50 | swConvLayer.Reset(); 51 | swPoolLayer.Reset(); 52 | swFCntLayer.Reset(); 53 | swReLuLayer.Reset(); 54 | swLoRNLayer.Reset(); 55 | swDrptLayer.Reset(); 56 | swSMaxLayer.Reset(); 57 | swCompLkupTblConv.Reset(); 58 | swEstiInPdValConv.Reset(); 59 | swCompLkupTblFCnt.Reset(); 60 | swEstiInPdValFCnt.Reset(); 61 | swDebugTimePri.Reset(); 62 | swDebugTimeSec.Reset(); 63 | } 64 | 65 | void CaffeEva::SetModelName(const std::string& modelNameSrc) { 66 | // display the greeting message 67 | printf("[CHECK-POINT] entering CaffeEva::SetDirPath()\n"); 68 | 69 | // specify the model name 70 | modelName = modelNameSrc; 71 | } 72 | 73 | void CaffeEva::SetModelPath( 74 | const std::string& dirPathMainSrc, const std::string& fileNamePfxSrc) { 75 | // display the greeting message 76 | printf("[CHECK-POINT] entering CaffeEva::SetDirPath()\n"); 77 | 78 | // specify the main directory path and file name prefix 79 | dirPathMain = dirPathMainSrc; 80 | fileNamePfx = fileNamePfxSrc; 81 | } 82 | 83 | bool CaffeEva::LoadDataset(const std::string& dirPathData) { 84 | // declare auxiliary variables 85 | const int kStrBufLen = 256; 86 | char strBuf[kStrBufLen]; 87 | bool succFlg; 88 | 89 | // display the greeting message 90 | printf("[CHECK-POINT] entering CaffeEva::LoadDataset()\n"); 91 | 92 | // load samples in the evaluation subset 93 | snprintf(strBuf, kStrBufLen, "%s/dataMatTst.single.bin", dirPathData.c_str()); 94 | succFlg = FileIO::ReadBinFile(strBuf, &dataLst); 95 | if (!succFlg) { // failed 96 | return false; 97 | } // ENDIF: succFlg 98 | 99 | // load samples' ground-truth labels in the evaluation subset 100 | snprintf(strBuf, kStrBufLen, "%s/lablVecTst.uint16.bin", dirPathData.c_str()); 101 | succFlg = FileIO::ReadBinFile(strBuf, &lablVecGrth); 102 | if (!succFlg) { // failed 103 | return false; 104 | } // ENDIF: succFlg 105 | 106 | return true; 107 | } 108 | 109 | bool CaffeEva::LoadCaffePara(void) { 110 | // display the greeting message 111 | printf("[CHECK-POINT] entering CaffeEva::LoadCaffePara()\n"); 112 | 113 | // initialize 114 | caffeParaObj.Init(dirPathMain, fileNamePfx); 115 | 116 | // load each layer's basic information 117 | if (modelName == "AlexNet") { 118 | caffeParaObj.ConfigLayer_AlexNet(); 119 | } else if (modelName == "CaffeNet") { 120 | caffeParaObj.ConfigLayer_CaffeNet(); 121 | } else if (modelName == "VggCnnS") { 122 | caffeParaObj.ConfigLayer_VggCnnS(); 123 | } else if (modelName == "VGG16") { 124 | caffeParaObj.ConfigLayer_VGG16(); 125 | } else if (modelName == "CaffeNetFGB") { 126 | caffeParaObj.ConfigLayer_CaffeNetFGB(); 127 | } else if (modelName == "CaffeNetFGD") { 128 | caffeParaObj.ConfigLayer_CaffeNetFGD(); 129 | } else { 130 | printf("[ERROR] unrecognized caffe model name: %s\n", modelName.c_str()); 131 | return false; 132 | } // ENDIF: modelName 133 | 134 | // load each layer's detailed parameters 135 | bool succFlg = caffeParaObj.LoadLayerPara(enblAprx, ENUM_AsmtEnc::Compact); 136 | if (!succFlg) { // failed 137 | return false; 138 | } // ENDIF: succFlg 139 | 140 | // prepare feature map and buffers for each layer 141 | PrepFeatMap(); 142 | PrepFeatBuf(); 143 | if (enblAprx) { 144 | PrepCtrdBuf(); 145 | PrepAsmtBuf(); 146 | } // ENDIF: enblAprx 147 | 148 | return true; 149 | } 150 | 151 | void CaffeEva::ExecForwardPass(void) { 152 | // display the greeting message 153 | printf("[CHECK-POINT] entering CaffeEva::ExecForwardPass()\n"); 154 | 155 | // initialize stop-watches for each layer 156 | swIndvLayerLst.resize(caffeParaObj.layerCnt); 157 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 158 | swIndvLayerLst[layerInd].Reset(); 159 | } // ENDFOR: layerInd 160 | 161 | // pack samples into batches and then execute the forward pass 162 | int dataCnt = dataLst.GetDimLen(0); 163 | int dataIndL; 164 | int dataIndU; 165 | int batchCnt = (dataCnt + kDataCntInBatch - 1) / kDataCntInBatch; 166 | lablVecPred.Create(dataCnt, kLablCntPerData, 1, 1); 167 | for (int batchInd = 0; batchInd < kBatchCntProc; batchInd++) { 168 | printf("processing the %d-th batch\n", batchInd + 1); 169 | 170 | // check whether is the last batch 171 | if (batchInd < batchCnt - 1) { 172 | dataIndL = kDataCntInBatch * batchInd; 173 | dataIndU = dataIndL + (kDataCntInBatch - 1); 174 | } else { 175 | dataIndU = dataCnt - 1; 176 | dataIndL = dataIndU - (kDataCntInBatch - 1); 177 | } // ENDIF: batchInd 178 | 179 | // convert samples' feature vectors into the input feature map 180 | CvtDataLstToFeatMap(dataIndL, dataIndU, dataLst, &(featMapLst[0])); 181 | 182 | // execute the forward pass 183 | bool isFirstFCnt = true; 184 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 185 | // permute dimensions for the first fully-connected layer 186 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 187 | if (isFirstFCnt && (layerInfo.type == ENUM_LyrType::FCnt)) { 188 | featMapLst[layerInd].Permute(0, 3, 1, 2); 189 | } // ENDIF: isFirstFCnt 190 | 191 | // compute the target layer's activation 192 | swIndvLayerLst[layerInd].Resume(); 193 | CalcFeatMap(featMapLst[layerInd], layerInd, &(featMapLst[layerInd + 1])); 194 | swIndvLayerLst[layerInd].Pause(); 195 | 196 | // permute dimensions for the first fully-connected layer 197 | if (isFirstFCnt && (layerInfo.type == ENUM_LyrType::FCnt)) { 198 | isFirstFCnt = false; 199 | int m = featMapLst[layerInd].GetDimLen(0); 200 | int n = featMapLst[layerInd].GetDimLen(1); 201 | int p = featMapLst[layerInd].GetDimLen(2); 202 | int q = featMapLst[layerInd].GetDimLen(3); 203 | featMapLst[layerInd].Resize(m, p, q, n); 204 | } // ENDIF: isFirstFCnt 205 | } // ENDIF: layerInd 206 | 207 | // convert the output feature map into samples' predicted labels 208 | CvtFeatMapToLablVec(dataIndL, 209 | dataIndU, featMapLst[caffeParaObj.layerCnt], &lablVecPred); 210 | } // ENDFOR: batchInd 211 | } 212 | 213 | void CaffeEva::ExecForwardPass( 214 | const Matrix& imgDataIn, Matrix* pProbVecOut) { 215 | // display the greeting message 216 | printf("[CHECK-POINT] entering CaffeEva::ExecForwardPass()\n"); 217 | 218 | // initialize stop-watches for each layer 219 | swIndvLayerLst.resize(caffeParaObj.layerCnt); 220 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 221 | swIndvLayerLst[layerInd].Reset(); 222 | } // ENDFOR: layerInd 223 | 224 | // copy to the input feature map 225 | featMapLst[0].Permute(0, 3, 1, 2); 226 | memcpy(featMapLst[0].GetDataPtr(), 227 | imgDataIn.GetDataPtr(), sizeof(float) * imgDataIn.GetEleCnt()); 228 | featMapLst[0].Permute(0, 2, 3, 1); 229 | 230 | // execute the forward pass 231 | bool isFirstFCnt = true; 232 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 233 | printf("layerInd = %d\n", layerInd); 234 | // permute dimensions for the first fully-connected layer 235 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 236 | if (isFirstFCnt && (layerInfo.type == ENUM_LyrType::FCnt)) { 237 | featMapLst[layerInd].Permute(0, 3, 1, 2); 238 | } // ENDIF: isFirstFCnt 239 | 240 | // compute the target layer's activation 241 | swIndvLayerLst[layerInd].Resume(); 242 | CalcFeatMap(featMapLst[layerInd], layerInd, &(featMapLst[layerInd + 1])); 243 | swIndvLayerLst[layerInd].Pause(); 244 | 245 | // permute dimensions for the first fully-connected layer 246 | if (isFirstFCnt && (layerInfo.type == ENUM_LyrType::FCnt)) { 247 | isFirstFCnt = false; 248 | int m = featMapLst[layerInd].GetDimLen(0); 249 | int n = featMapLst[layerInd].GetDimLen(1); 250 | int p = featMapLst[layerInd].GetDimLen(2); 251 | int q = featMapLst[layerInd].GetDimLen(3); 252 | featMapLst[layerInd].Resize(m, p, q, n); 253 | } // ENDIF: isFirstFCnt 254 | } // ENDIF: layerInd 255 | 256 | // extract from the output feature map 257 | pProbVecOut->Resize(featMapLst[caffeParaObj.layerCnt].GetEleCnt()); 258 | memcpy(pProbVecOut->GetDataPtr(), 259 | featMapLst[caffeParaObj.layerCnt].GetDataPtr(), 260 | sizeof(float) * pProbVecOut->GetEleCnt()); 261 | } 262 | 263 | void CaffeEva::CalcPredAccu(void) { 264 | // display the greeting message 265 | printf("[CHECK-POINT] entering CaffeEva::CalcPredAccu()\n"); 266 | 267 | // initialize counters for accuracy computation 268 | Matrix accuCntLst(kLablCntPerData); 269 | Matrix accuScrLst(kLablCntPerData); 270 | memset(accuCntLst.GetDataPtr(), 0, sizeof(uint32_t) * accuCntLst.GetEleCnt()); 271 | memset(accuScrLst.GetDataPtr(), 0, sizeof(float) * accuScrLst.GetEleCnt()); 272 | 273 | // compute the total number of correctly predicted class labels 274 | int dataCnt = kDataCntInBatch * kBatchCntProc; 275 | const uint16_t* lablPtrGrth = lablVecGrth.GetDataPtr(); 276 | const uint16_t* lablPtrPred = lablVecPred.GetDataPtr(); 277 | uint32_t* accuCntVec = accuCntLst.GetDataPtr(); 278 | float* accuScrVec = accuScrLst.GetDataPtr(); 279 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 280 | for (int lablInd = 0; lablInd < kLablCntPerData; lablInd++) { 281 | uint16_t lablVal_Pred = lablPtrPred[dataInd * kLablCntPerData + lablInd]; 282 | if (lablPtrGrth[dataInd] == lablVal_Pred) { 283 | accuCntVec[lablInd]++; 284 | } // ENDIF: lablPtrGrth 285 | } // ENDFOR: lablInd 286 | } // ENDFOR: dataInd 287 | for (int lablInd = 1; lablInd < kLablCntPerData; lablInd++) { 288 | accuCntVec[lablInd] += accuCntVec[lablInd - 1]; 289 | } // ENDFOR: lablInd 290 | for (int lablInd = 0; lablInd < kLablCntPerData; lablInd++) { 291 | accuScrVec[lablInd] = static_cast(accuCntVec[lablInd]) / dataCnt; 292 | printf("ACCURACY@%d: %d, %.2f%%\n", 293 | lablInd + 1, accuCntVec[lablInd], accuScrVec[lablInd] * 100); 294 | } // ENDFOR: lablInd 295 | } 296 | 297 | float CaffeEva::DispElpsTime(void) { 298 | // get total computation time 299 | float timeTotal = swAllLayers.GetTime(); 300 | 301 | // display the elapsed time of each stop-watch 302 | SHR_PRINTF("swAllLayers: %.4f (s)\n", timeTotal); 303 | SHR_PRINTF("swConvLayer: %.4f (s)\n", swConvLayer.GetTime()); 304 | SHR_PRINTF("swPoolLayer: %.4f (s)\n", swPoolLayer.GetTime()); 305 | SHR_PRINTF("swFCntLayer: %.4f (s)\n", swFCntLayer.GetTime()); 306 | SHR_PRINTF("swReLuLayer: %.4f (s)\n", swReLuLayer.GetTime()); 307 | SHR_PRINTF("swLoRNLayer: %.4f (s)\n", swLoRNLayer.GetTime()); 308 | SHR_PRINTF("swDrptLayer: %.4f (s)\n", swDrptLayer.GetTime()); 309 | SHR_PRINTF("swSMaxLayer: %.4f (s)\n", swSMaxLayer.GetTime()); 310 | SHR_PRINTF("swCompLkupTblConv: %.4f (s)\n", swCompLkupTblConv.GetTime()); 311 | SHR_PRINTF("swEstiInPdValConv: %.4f (s)\n", swEstiInPdValConv.GetTime()); 312 | SHR_PRINTF("swCompLkupTblFCnt: %.4f (s)\n", swCompLkupTblFCnt.GetTime()); 313 | SHR_PRINTF("swEstiInPdValFCnt: %.4f (s)\n", swEstiInPdValFCnt.GetTime()); 314 | SHR_PRINTF("swDebugTimePri: %.4f (s)\n", swDebugTimePri.GetTime()); 315 | SHR_PRINTF("swDebugTimeSec: %.4f (s)\n", swDebugTimeSec.GetTime()); 316 | 317 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 318 | SHR_PRINTF("swIndvLayerLst #%2d: %.4f (s)\n", 319 | layerInd + 1, swIndvLayerLst[layerInd].GetTime()); 320 | } // ENDFOR: layerInd 321 | 322 | // re-initialize each stop-watch 323 | Init(enblAprx); 324 | 325 | return timeTotal; 326 | } 327 | 328 | void CaffeEva::PrepFeatMap(void) { 329 | // allocate memory space for 330 | featMapSizLst.resize(caffeParaObj.layerCnt + 1); 331 | 332 | // determine the size of the input feature map 333 | featMapSizLst[0].dataCnt = kDataCntInBatch; 334 | featMapSizLst[0].imgHei = caffeParaObj.imgHeiIn; 335 | featMapSizLst[0].imgWid = caffeParaObj.imgWidIn; 336 | featMapSizLst[0].imgChn = caffeParaObj.imgChnIn; 337 | 338 | // determine the size of the remaining feature maps 339 | for (int layerInd = 1; layerInd <= caffeParaObj.layerCnt; layerInd++) { 340 | // obtain reference to previous/current feature map size 341 | const FeatMapSiz& featMapSizPrev = featMapSizLst[layerInd - 1]; 342 | FeatMapSiz& featMapSizCurr = featMapSizLst[layerInd]; 343 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd - 1]; 344 | 345 | // obtain basic variables 346 | int dataCnt = featMapSizPrev.dataCnt; 347 | int imgHeiPrev = featMapSizPrev.imgHei; 348 | int imgWidPrev = featMapSizPrev.imgWid; 349 | int imgChnPrev = featMapSizPrev.imgChn; 350 | int padSiz = layerInfo.padSiz; 351 | int knlSiz = layerInfo.knlSiz; 352 | int knlCnt = layerInfo.knlCnt; 353 | int stride = layerInfo.stride; 354 | double strideDbl = static_cast(stride); 355 | int nodCnt = layerInfo.nodCnt; 356 | 357 | // compute the feature map size 358 | switch (layerInfo.type) { 359 | case ENUM_LyrType::Conv: 360 | featMapSizCurr.dataCnt = dataCnt; 361 | featMapSizCurr.imgHei = (imgHeiPrev + 2 * padSiz - knlSiz) / stride + 1; 362 | featMapSizCurr.imgWid = (imgWidPrev + 2 * padSiz - knlSiz) / stride + 1; 363 | featMapSizCurr.imgChn = knlCnt; 364 | break; 365 | case ENUM_LyrType::Pool: 366 | featMapSizCurr.dataCnt = dataCnt; 367 | featMapSizCurr.imgHei = 368 | ceil((imgHeiPrev + 2 * padSiz - knlSiz) / strideDbl) + 1; 369 | featMapSizCurr.imgWid = 370 | ceil((imgWidPrev + 2 * padSiz - knlSiz) / strideDbl) + 1; 371 | featMapSizCurr.imgChn = imgChnPrev; 372 | break; 373 | case ENUM_LyrType::FCnt: 374 | featMapSizCurr.dataCnt = dataCnt; 375 | featMapSizCurr.imgHei = 1; 376 | featMapSizCurr.imgWid = 1; 377 | featMapSizCurr.imgChn = nodCnt; 378 | break; 379 | case ENUM_LyrType::ReLU: 380 | // fall through 381 | case ENUM_LyrType::LoRN: 382 | // fall through 383 | case ENUM_LyrType::Drpt: 384 | // fall through 385 | case ENUM_LyrType::SMax: 386 | featMapSizCurr = featMapSizPrev; 387 | break; 388 | default: 389 | printf("[ERROR] invalid layer type\n"); 390 | return; 391 | } // ENDSWITCH: layerInfo 392 | } // ENDFOR: layerInd 393 | 394 | // allocate memory for each feature map 395 | featMapLst = new Matrix[caffeParaObj.layerCnt + 1]; 396 | for (int layerInd = 0; layerInd <= caffeParaObj.layerCnt; layerInd++) { 397 | const FeatMapSiz& featMapSiz = featMapSizLst[layerInd]; 398 | featMapLst[layerInd].Create(featMapSiz.dataCnt, 399 | featMapSiz.imgHei, featMapSiz.imgWid, featMapSiz.imgChn); 400 | } // ENDFOR: layerInd 401 | 402 | // display the feature map size 403 | for (int layerInd = 0; layerInd <= caffeParaObj.layerCnt; layerInd++) { 404 | const FeatMapSiz& featMapSiz = featMapSizLst[layerInd]; 405 | const Matrix& featMap = featMapLst[layerInd]; 406 | float memUsage = featMap.GetEleCnt() * 4 / 1024.0 / 1024.0; 407 | printf("layer #%2d: %4d x %4d x %4d x %4d (%6.2f MB)\n", 408 | layerInd, featMapSiz.dataCnt, featMapSiz.imgHei, 409 | featMapSiz.imgWid, featMapSiz.imgChn, memUsage); 410 | } // ENDFOR: layerInd 411 | } 412 | 413 | void CaffeEva::PrepFeatBuf(void) { 414 | // define a template for 415 | static FeatBufStr featBufStr; 416 | 417 | // determine the size of each layer's feature buffer 418 | featBufStrMat.resize(caffeParaObj.layerCnt); 419 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 420 | // obtain reference to previous/current feature map size 421 | const FeatMapSiz& featMapSizCurr = featMapSizLst[layerInd]; 422 | const FeatMapSiz& featMapSizNext = featMapSizLst[layerInd + 1]; 423 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 424 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 425 | FeatBufStrLst& featBufStrLst = featBufStrMat[layerInd]; 426 | 427 | // obtain basic variables 428 | int dataCnt = featMapSizCurr.dataCnt; 429 | int imgHeiCurr = featMapSizCurr.imgHei; 430 | int imgWidCurr = featMapSizCurr.imgWid; 431 | int imgChnCurr = featMapSizCurr.imgChn; 432 | int imgHeiNext = featMapSizNext.imgHei; 433 | int imgWidNext = featMapSizNext.imgWid; 434 | int knlSiz = layerInfo.knlSiz; 435 | int knlCnt = layerInfo.knlCnt; 436 | int grpCnt = layerInfo.grpCnt; 437 | int lrnSiz = layerInfo.lrnSiz; 438 | int subSpaceCnt = layerPara.ctrdLst.GetDimLen(0); 439 | int ctrdCntPerSpace = layerPara.ctrdLst.GetDimLen(1); 440 | 441 | // compute the feature buffer size 442 | featBufStrLst.clear(); 443 | switch (layerInfo.type) { 444 | case ENUM_LyrType::Conv: 445 | // feature buffer #0: 446 | InitFeatBuf(&featBufStr, ENUM_BufUsage::PrecComp, 447 | dataCnt, imgChnCurr, imgHeiCurr, imgWidCurr); 448 | featBufStrLst.push_back(featBufStr); 449 | // feature buffer #1: 450 | InitFeatBuf(&featBufStr, ENUM_BufUsage::PrecComp, 451 | imgChnCurr / grpCnt * knlSiz * knlSiz, imgHeiNext * imgWidNext); 452 | featBufStrLst.push_back(featBufStr); 453 | // feature buffer #2: 454 | InitFeatBuf(&featBufStr, ENUM_BufUsage::PrecComp, 455 | knlCnt / grpCnt, imgHeiNext * imgWidNext); 456 | featBufStrLst.push_back(featBufStr); 457 | // feature buffer #3: 458 | InitFeatBuf(&featBufStr, ENUM_BufUsage::AprxComp, 459 | dataCnt, imgHeiCurr, imgWidCurr, imgChnCurr / grpCnt); 460 | featBufStrLst.push_back(featBufStr); 461 | // feature buffer #4: 462 | InitFeatBuf(&featBufStr, ENUM_BufUsage::AprxComp, 463 | dataCnt * imgHeiCurr * imgWidCurr, subSpaceCnt, ctrdCntPerSpace); 464 | featBufStrLst.push_back(featBufStr); 465 | break; 466 | case ENUM_LyrType::FCnt: 467 | // feature buffer #0: 468 | InitFeatBuf(&featBufStr, ENUM_BufUsage::AprxComp, 469 | dataCnt, imgChnCurr * imgHeiCurr * imgWidCurr); 470 | featBufStrLst.push_back(featBufStr); 471 | // feature buffer #1: 472 | InitFeatBuf(&featBufStr, ENUM_BufUsage::AprxComp, 473 | dataCnt, subSpaceCnt, ctrdCntPerSpace); 474 | featBufStrLst.push_back(featBufStr); 475 | break; 476 | case ENUM_LyrType::LoRN: 477 | // feature buffer #0: 478 | InitFeatBuf(&featBufStr, 479 | ENUM_BufUsage::GnrlComp, imgChnCurr + lrnSiz - 1); 480 | featBufStrLst.push_back(featBufStr); 481 | // feature buffer #1: 482 | InitFeatBuf(&featBufStr, ENUM_BufUsage::GnrlComp, imgChnCurr); 483 | featBufStrLst.push_back(featBufStr); 484 | break; 485 | case ENUM_LyrType::Pool: 486 | // fall through 487 | case ENUM_LyrType::ReLU: 488 | // fall through 489 | case ENUM_LyrType::Drpt: 490 | // fall through 491 | case ENUM_LyrType::SMax: 492 | // do nothing 493 | break; 494 | default: 495 | printf("[ERROR] invalid layer type\n"); 496 | return; 497 | } // ENDSWITCH: layerInfo 498 | } // ENDFOR: layerInd 499 | 500 | // display the feature buffer size 501 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 502 | // obtain a constant reference to the feature buffer list 503 | FeatBufStrLst& featBufStrLst = featBufStrMat[layerInd]; 504 | 505 | // display the feature buffer size 506 | printf("layer #%2d: \n", layerInd + 1); 507 | for (std::size_t bufInd = 0; bufInd < featBufStrLst.size(); bufInd++) { 508 | FeatBufStr& featBufStr = featBufStrLst[bufInd]; 509 | 510 | // check whether current buffer will be used in the future 511 | if ((enblAprx && (featBufStr.usage == ENUM_BufUsage::PrecComp)) || 512 | (!enblAprx && (featBufStr.usage == ENUM_BufUsage::AprxComp))) { 513 | continue; 514 | } // ENDIF: enblAprx 515 | 516 | // allocate memory space for the current buffer 517 | featBufStr.pFeatBuf = new Matrix(); 518 | featBufStr.pFeatBuf->Create(featBufStr.dimCnt, featBufStr.dimLenLst); 519 | 520 | // display the memory consumption of the current buffer 521 | printf(" buffer #%lu: ", bufInd + 1); 522 | float memUsage = featBufStr.pFeatBuf->GetEleCnt() * 4 / 1024.0 / 1024.0; 523 | for (int dimInd = 0; dimInd < featBufStr.dimCnt; dimInd++) { 524 | if (dimInd < featBufStr.dimCnt - 1) { 525 | printf("%4d x ", featBufStr.dimLenLst[dimInd]); 526 | } else { 527 | printf("%4d (%6.2f MB)\n", featBufStr.dimLenLst[dimInd], memUsage); 528 | } 529 | } // ENDFOR: dimInd 530 | } // ENDFOR: bufInd 531 | } // ENDFOR: layerInd 532 | } 533 | 534 | void CaffeEva::PrepCtrdBuf(void) { 535 | // determine the size of each layer's centroid buffer 536 | ctrdBufStrLst.resize(caffeParaObj.layerCnt); 537 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 538 | // obtain reference to the current layer's parameters 539 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 540 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 541 | 542 | // only allocate centroid buffer for the convolutional layers 543 | if ((layerInfo.type == ENUM_LyrType::Conv) || 544 | (layerInfo.type == ENUM_LyrType::FCnt)) { 545 | // obtain basic variables 546 | int subSpaceCnt = layerPara.ctrdLst.GetDimLen(0); 547 | int ctrdCntPerSpace = layerPara.ctrdLst.GetDimLen(1); 548 | int featCntPerSpace = layerPara.ctrdLst.GetDimLen(2); 549 | 550 | // create the centroid buffer 551 | CtrdBufStr& ctrdBufStr = ctrdBufStrLst[layerInd]; 552 | ctrdBufStr.dimCnt = 3; 553 | ctrdBufStr.dimLenLst[0] = subSpaceCnt; 554 | ctrdBufStr.dimLenLst[1] = featCntPerSpace; 555 | ctrdBufStr.dimLenLst[2] = ctrdCntPerSpace; 556 | ctrdBufStr.pCtrdBuf = new Matrix(layerPara.ctrdLst); 557 | ctrdBufStr.pCtrdBuf->Permute(0, 2, 1); 558 | } // ENDIF: layerInfo 559 | } // ENDFOR: layerInd 560 | } 561 | 562 | void CaffeEva::PrepAsmtBuf(void) { 563 | // determine the size of each layer's assignment buffer 564 | asmtBufStrLst.resize(caffeParaObj.layerCnt); 565 | for (int layerInd = 0; layerInd < caffeParaObj.layerCnt; layerInd++) { 566 | // obtain reference to the current layer's parameters 567 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 568 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 569 | 570 | // allocate assignment buffer for the convolutional layer 571 | if (layerInfo.type == ENUM_LyrType::Conv) { 572 | // obtain basic variables 573 | int knlCnt = layerPara.asmtLst.GetDimLen(0); 574 | int knlHei = layerPara.asmtLst.GetDimLen(1); 575 | int knlWid = layerPara.asmtLst.GetDimLen(2); 576 | int subSpaceCnt = layerPara.asmtLst.GetDimLen(3); 577 | 578 | // create the assignment buffer 579 | AsmtBufStr& asmtBufStr = asmtBufStrLst[layerInd]; 580 | asmtBufStr.dimCnt = 4; 581 | asmtBufStr.dimLenLst[0] = knlHei; 582 | asmtBufStr.dimLenLst[1] = knlWid; 583 | asmtBufStr.dimLenLst[2] = subSpaceCnt; 584 | asmtBufStr.dimLenLst[3] = knlCnt; 585 | asmtBufStr.pAsmtBuf = new Matrix(layerPara.asmtLst); 586 | asmtBufStr.pAsmtBuf->Permute(1, 2, 3, 0); 587 | 588 | // create the extended assignment buffer 589 | asmtBufStr.pAsmtBufExt = 590 | new Matrix(knlHei, knlWid, subSpaceCnt, knlCnt); 591 | const int eleCnt = asmtBufStr.pAsmtBuf->GetEleCnt(); 592 | const uint8_t* asmtVecSrc = asmtBufStr.pAsmtBuf->GetDataPtr(); 593 | CBLAS_INT* asmtVecDst = asmtBufStr.pAsmtBufExt->GetDataPtr(); 594 | for (int eleInd = 0; eleInd < eleCnt; eleInd++) { 595 | asmtVecDst[eleInd] = asmtVecSrc[eleInd]; 596 | } // ENDFOR: eleInd 597 | } // ENDIF: layerInfo 598 | 599 | // allocate assignment buffer for the fully-connected layer 600 | if (layerInfo.type == ENUM_LyrType::FCnt) { 601 | // obtain basic variables 602 | int imgChnDst = layerPara.asmtLst.GetDimLen(0); 603 | int subSpaceCnt = layerPara.asmtLst.GetDimLen(1); 604 | 605 | // create the assignment buffer 606 | AsmtBufStr& asmtBufStr = asmtBufStrLst[layerInd]; 607 | asmtBufStr.dimCnt = 2; 608 | asmtBufStr.dimLenLst[0] = subSpaceCnt; 609 | asmtBufStr.dimLenLst[1] = imgChnDst; 610 | asmtBufStr.pAsmtBuf = new Matrix(layerPara.asmtLst); 611 | asmtBufStr.pAsmtBuf->Permute(1, 0); 612 | 613 | // create the extended assignment buffer 614 | asmtBufStr.pAsmtBufExt = new Matrix(subSpaceCnt, imgChnDst); 615 | const int eleCnt = asmtBufStr.pAsmtBuf->GetEleCnt(); 616 | const uint8_t* asmtVecSrc = asmtBufStr.pAsmtBuf->GetDataPtr(); 617 | CBLAS_INT* asmtVecDst = asmtBufStr.pAsmtBufExt->GetDataPtr(); 618 | for (int eleInd = 0; eleInd < eleCnt; eleInd++) { 619 | asmtVecDst[eleInd] = asmtVecSrc[eleInd]; 620 | } // ENDFOR: eleInd 621 | } // ENDIF: layerInfo 622 | } // ENDFOR: layerInd 623 | } 624 | 625 | void CaffeEva::CalcFeatMap(const Matrix& featMapSrc, 626 | const int layerInd, Matrix* pFeatMapDst) { 627 | // determine the corresponding function for the current layer 628 | swAllLayers.Resume(); 629 | switch (caffeParaObj.layerInfoLst[layerInd].type) { 630 | case ENUM_LyrType::Conv: 631 | swConvLayer.Resume(); 632 | CalcFeatMap_Conv(featMapSrc, layerInd, pFeatMapDst); 633 | swConvLayer.Pause(); 634 | break; 635 | case ENUM_LyrType::Pool: 636 | swPoolLayer.Resume(); 637 | CalcFeatMap_Pool(featMapSrc, layerInd, pFeatMapDst); 638 | swPoolLayer.Pause(); 639 | break; 640 | case ENUM_LyrType::FCnt: 641 | swFCntLayer.Resume(); 642 | CalcFeatMap_FCnt(featMapSrc, layerInd, pFeatMapDst); 643 | swFCntLayer.Pause(); 644 | break; 645 | case ENUM_LyrType::ReLU: 646 | swReLuLayer.Resume(); 647 | CalcFeatMap_ReLu(featMapSrc, layerInd, pFeatMapDst); 648 | swReLuLayer.Pause(); 649 | break; 650 | case ENUM_LyrType::LoRN: 651 | swLoRNLayer.Resume(); 652 | CalcFeatMap_LoRN(featMapSrc, layerInd, pFeatMapDst); 653 | swLoRNLayer.Pause(); 654 | break; 655 | case ENUM_LyrType::Drpt: 656 | swDrptLayer.Resume(); 657 | CalcFeatMap_Drpt(featMapSrc, layerInd, pFeatMapDst); 658 | swDrptLayer.Pause(); 659 | break; 660 | case ENUM_LyrType::SMax: 661 | swSMaxLayer.Resume(); 662 | CalcFeatMap_SMax(featMapSrc, layerInd, pFeatMapDst); 663 | swSMaxLayer.Pause(); 664 | break; 665 | default: 666 | printf("[ERROR] invalid layer type\n"); 667 | return; 668 | } // ENDSWITCH: caffeParaObj 669 | swAllLayers.Pause(); 670 | } 671 | 672 | void CaffeEva::CalcFeatMap_Conv(const Matrix& featMapSrc, 673 | const int layerInd, Matrix* pFeatMapDst) { 674 | if (enblAprx) { 675 | CalcFeatMap_ConvAprx(featMapSrc, layerInd, pFeatMapDst); 676 | } else { 677 | CalcFeatMap_ConvPrec(featMapSrc, layerInd, pFeatMapDst); 678 | } // ENDIF: enblAprx 679 | } 680 | 681 | void CaffeEva::CalcFeatMap_ConvPrec(const Matrix& featMapSrc, 682 | const int layerInd, Matrix* pFeatMapDst) { 683 | // obtain basic variables 684 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 685 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 686 | int knlCnt = layerPara.convKnlLst.GetDimLen(0); 687 | int knlSiz = layerPara.convKnlLst.GetDimLen(2); 688 | int dataCnt = featMapSrc.GetDimLen(0); 689 | int imgHeiSrc = featMapSrc.GetDimLen(1); 690 | int imgWidSrc = featMapSrc.GetDimLen(2); 691 | int imgChnSrc = featMapSrc.GetDimLen(3); 692 | int imgHeiDst = pFeatMapDst->GetDimLen(1); 693 | int imgWidDst = pFeatMapDst->GetDimLen(2); 694 | int imgChnDst = pFeatMapDst->GetDimLen(3); 695 | int knlCntPerGrp = knlCnt / layerInfo.grpCnt; 696 | int imgChnSrcPerGrp = imgChnSrc / layerInfo.grpCnt; 697 | 698 | // obtain pre-allocated matrices for auxiliary variables 699 | Matrix& featMapSrcPrm = *(featBufStrMat[layerInd][0].pFeatBuf); 700 | Matrix& featMapSrcRsp = *(featBufStrMat[layerInd][1].pFeatBuf); 701 | Matrix& featMapDstRsp = *(featBufStrMat[layerInd][2].pFeatBuf); 702 | 703 | // permute the input feature map dimensions 704 | featMapSrcPrm.Resize(dataCnt, imgHeiSrc, imgWidSrc, imgChnSrc); 705 | memcpy(featMapSrcPrm.GetDataPtr(), 706 | featMapSrc.GetDataPtr(), sizeof(float) * featMapSrc.GetEleCnt()); 707 | featMapSrcPrm.Permute(0, 3, 1, 2); 708 | 709 | // reshape the output feature map 710 | pFeatMapDst->Resize(dataCnt, imgChnDst, imgHeiDst, imgWidDst); 711 | 712 | // compute the feature map after passing a convolutional layer 713 | const float* biasVec = layerPara.biasVec.GetDataPtr(); 714 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 715 | for (int grpInd = 0; grpInd < layerInfo.grpCnt; grpInd++) { 716 | // copy source feature map to feature buffer 717 | CvtFeatMapToFeatBuf( 718 | featMapSrcPrm, dataInd, grpInd, layerInfo, &featMapSrcRsp); 719 | 720 | // call CBLAS function to compute the matrix-matrix multiplication 721 | int knlIndL = grpInd * knlCntPerGrp; 722 | CBLAS_ORDER order = CblasRowMajor; 723 | CBLAS_TRANSPOSE transA = CblasNoTrans; 724 | CBLAS_TRANSPOSE transB = CblasNoTrans; 725 | CBLAS_INT m = knlCntPerGrp; 726 | CBLAS_INT n = imgHeiDst * imgWidDst; 727 | CBLAS_INT k = imgChnSrcPerGrp * knlSiz * knlSiz; 728 | CBLAS_INT lda = k; 729 | CBLAS_INT ldb = n; 730 | CBLAS_INT ldc = n; 731 | float alpha = 1.0; 732 | float beta = 0.0; 733 | float* pa = layerPara.convKnlLst.GetDataPtr(knlIndL, 0, 0, 0); 734 | float* pb = featMapSrcRsp.GetDataPtr(); 735 | float* pc = featMapDstRsp.GetDataPtr(); 736 | cblas_sgemm(order, transA, transB, 737 | m, n, k, alpha, pa, lda, pb, ldb, beta, pc, ldc); 738 | 739 | // append the bias term 740 | int rowCntBuf = featMapDstRsp.GetDimLen(0); 741 | int colCntBuf = featMapDstRsp.GetDimLen(1); 742 | for (int rowIndBuf = 0; rowIndBuf < rowCntBuf; rowIndBuf++) { 743 | const float biasVal = biasVec[rowIndBuf + grpInd * knlCntPerGrp]; 744 | float* pFeatVecDstRsp = featMapDstRsp.GetDataPtr(rowIndBuf, 0); 745 | for (int colIndBuf = 0; colIndBuf < colCntBuf; colIndBuf++) { 746 | pFeatVecDstRsp[colIndBuf] += biasVal; 747 | } // ENDFOR: colIndBuf 748 | } // ENDFOR: rowIndBuf 749 | 750 | // copy feature buffer to target feature map 751 | CvtFeatBufToFeatMap( 752 | featMapDstRsp, dataInd, grpInd, layerInfo, pFeatMapDst); 753 | } // ENDFOR: grpInd 754 | } // ENDFOR: dataInd 755 | 756 | // permute the output feature map dimensions 757 | pFeatMapDst->Permute(0, 2, 3, 1); 758 | } 759 | 760 | void CaffeEva::CalcFeatMap_ConvAprx(const Matrix& featMapSrc, 761 | const int layerInd, Matrix* pFeatMapDst) { 762 | // obtain basic variables 763 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 764 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 765 | int knlCnt = layerInfo.knlCnt; 766 | int knlHei = layerInfo.knlSiz; 767 | int knlWid = layerInfo.knlSiz; 768 | int dataCnt = featMapSrc.GetDimLen(0); 769 | int imgHeiSrc = featMapSrc.GetDimLen(1); 770 | int imgWidSrc = featMapSrc.GetDimLen(2); 771 | int imgChnSrc = featMapSrc.GetDimLen(3); 772 | int imgHeiDst = pFeatMapDst->GetDimLen(1); 773 | int imgWidDst = pFeatMapDst->GetDimLen(2); 774 | int subSpaceCnt = layerPara.ctrdLst.GetDimLen(0); 775 | int ctrdCntPerSpace = layerPara.ctrdLst.GetDimLen(1); 776 | int ctrdCntExt = ctrdCntPerSpace * subSpaceCnt; 777 | 778 | // determine the size of feature map groups 779 | int knlCntPerGrp = knlCnt / layerInfo.grpCnt; 780 | int imgChnSrcPerGrp = imgChnSrc / layerInfo.grpCnt; 781 | 782 | // obtain pre-allocated matrices for auxiliary variables 783 | Matrix& featMapSrcPerGrp = *(featBufStrMat[layerInd][3].pFeatBuf); 784 | Matrix& inPdMat = *(featBufStrMat[layerInd][4].pFeatBuf); 785 | 786 | // obtain pre-allocated centroid and assignment buffer 787 | Matrix& ctrdBuf = *(ctrdBufStrLst[layerInd].pCtrdBuf); 788 | Matrix& asmtBuf = *(asmtBufStrLst[layerInd].pAsmtBuf); 789 | // Matrix& asmtBufExt = *(asmtBufStrLst[layerInd].pAsmtBufExt); 790 | 791 | // compute the feature map after passing a convolutional layer 792 | int sptCntDst = imgHeiDst * imgWidDst; 793 | // int sptCntKnl = knlHei * knlWid; 794 | const float* biasVec = layerPara.biasVec.GetDataPtr(); 795 | for (int grpInd = 0; grpInd < layerInfo.grpCnt; grpInd++) { 796 | // obtain basic variables for the current feature map group 797 | int knlIndL = knlCntPerGrp * grpInd; 798 | int chnIndSrcL = imgChnSrcPerGrp * grpInd; 799 | 800 | // quantize the source feature map with pre-defined codebook 801 | swCompLkupTblConv.Resume(); 802 | featMapSrcPerGrp.Resize(dataCnt, imgHeiSrc, imgWidSrc, imgChnSrcPerGrp); 803 | if (layerInfo.grpCnt == 1) { 804 | memcpy(featMapSrcPerGrp.GetDataPtr(), 805 | featMapSrc.GetDataPtr(), sizeof(float) * featMapSrc.GetEleCnt()); 806 | } else { 807 | featMapSrc.GetSubMat(0, 0, 0, chnIndSrcL, &featMapSrcPerGrp); 808 | } // ENDIF: layerInfo 809 | featMapSrcPerGrp.Resize(dataCnt * imgHeiSrc * imgWidSrc, imgChnSrcPerGrp); 810 | GetInPdMat(featMapSrcPerGrp, ctrdBuf, &inPdMat); 811 | inPdMat.Resize(dataCnt, imgHeiSrc, imgWidSrc, ctrdCntExt); 812 | swCompLkupTblConv.Pause(); 813 | 814 | // compute the target response via table look-up operations 815 | swEstiInPdValConv.Resume(); 816 | for (int sptIndDst = 0; sptIndDst < sptCntDst; sptIndDst++) { 817 | // determine the corresponding indexes in the target/source feature map 818 | int heiIndDst = sptIndDst / imgWidDst; 819 | int widIndDst = sptIndDst % imgWidDst; 820 | int heiIndSrcL = heiIndDst * layerInfo.stride - layerInfo.padSiz; 821 | int widIndSrcL = widIndDst * layerInfo.stride - layerInfo.padSiz; 822 | 823 | // determine the lower/upper bound in the convolutional kernels 824 | int heiIndKnlL = std::max(0, 0 - heiIndSrcL); 825 | int heiIndKnlU = std::min(knlHei - 1, imgHeiSrc - 1 - heiIndSrcL); 826 | int widIndKnlL = std::max(0, 0 - widIndSrcL); 827 | int widIndKnlU = std::min(knlWid - 1, imgWidSrc - 1 - widIndSrcL); 828 | 829 | // compute the target feature map for each instance 830 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 831 | // initialize with the bias term 832 | float* featVecDst = 833 | pFeatMapDst->GetDataPtr(dataInd, heiIndDst, widIndDst, knlIndL); 834 | memcpy(featVecDst, biasVec + knlIndL, sizeof(float) * knlCntPerGrp); 835 | 836 | // compute the target response via table look-up operations 837 | int heiIndKnl; // to shorten the line length 838 | int widIndKnl; // to shorten the line length 839 | int subSpaceInd; // to shorten the line length 840 | for (heiIndKnl = heiIndKnlL; heiIndKnl <= heiIndKnlU; heiIndKnl++) { 841 | for (widIndKnl = widIndKnlL; widIndKnl <= widIndKnlU; widIndKnl++) { 842 | int heiIndSrc = heiIndSrcL + heiIndKnl; 843 | int widIndSrc = widIndSrcL + widIndKnl; 844 | const float* inPdVec = 845 | inPdMat.GetDataPtr(dataInd, heiIndSrc, widIndSrc, 0); 846 | const uint8_t* asmtVec = 847 | asmtBuf.GetDataPtr(heiIndKnl, widIndKnl, 0, knlIndL); 848 | for (subSpaceInd = 0; subSpaceInd < subSpaceCnt; subSpaceInd++) { 849 | for (int knlInd = 0; knlInd < knlCntPerGrp; knlInd += 8) { 850 | featVecDst[knlInd] += inPdVec[asmtVec[knlInd]]; 851 | featVecDst[knlInd + 1] += inPdVec[asmtVec[knlInd + 1]]; 852 | featVecDst[knlInd + 2] += inPdVec[asmtVec[knlInd + 2]]; 853 | featVecDst[knlInd + 3] += inPdVec[asmtVec[knlInd + 3]]; 854 | featVecDst[knlInd + 4] += inPdVec[asmtVec[knlInd + 4]]; 855 | featVecDst[knlInd + 5] += inPdVec[asmtVec[knlInd + 5]]; 856 | featVecDst[knlInd + 6] += inPdVec[asmtVec[knlInd + 6]]; 857 | featVecDst[knlInd + 7] += inPdVec[asmtVec[knlInd + 7]]; 858 | } // ENDFOR: knlInd 859 | inPdVec += ctrdCntPerSpace; 860 | asmtVec += knlCnt; 861 | } // ENDFOR: subSpaceInd 862 | } // ENDFOR: widIndKnl 863 | } // ENDFOR: heiIndKnl 864 | } // ENDFOR: dataInd 865 | } // ENDFOR: sptIndDst 866 | swEstiInPdValConv.Pause(); 867 | } // ENDFOR: grpInd 868 | } 869 | 870 | void CaffeEva::CalcFeatMap_Pool(const Matrix& featMapSrc, 871 | const int layerInd, Matrix* pFeatMapDst) { 872 | // obtain basic variables 873 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 874 | int padSiz = layerInfo.padSiz; 875 | int knlSiz = layerInfo.knlSiz; 876 | int stride = layerInfo.stride; 877 | int dataCnt = featMapSrc.GetDimLen(0); 878 | int imgHeiSrc = featMapSrc.GetDimLen(1); 879 | int imgWidSrc = featMapSrc.GetDimLen(2); 880 | int imgChn = featMapSrc.GetDimLen(3); 881 | int imgHeiDst = pFeatMapDst->GetDimLen(1); 882 | int imgWidDst = pFeatMapDst->GetDimLen(2); 883 | 884 | // compute the feature map after passing a convolutional layer 885 | for (int heiIndDst = 0; heiIndDst < imgHeiDst; heiIndDst++) { 886 | // determine the corresponding indexes in the source feature map 887 | int heiIndSrcL = std::max(0, heiIndDst * stride - padSiz); 888 | int heiIndSrcU = 889 | std::min(imgHeiSrc, heiIndDst * stride + knlSiz - padSiz) - 1; 890 | int heiCntSrcSel = heiIndSrcU - heiIndSrcL + 1; 891 | 892 | for (int widIndDst = 0; widIndDst < imgWidDst; widIndDst++) { 893 | // determine the corresponding indexes in the source feature map 894 | int widIndSrcL = std::max(0, widIndDst * stride - padSiz); 895 | int widIndSrcU = 896 | std::min(imgWidSrc, widIndDst * stride + knlSiz - padSiz) - 1; 897 | int widCntSrcSel = widIndSrcU - widIndSrcL + 1; 898 | int sptCntSrcSel = heiCntSrcSel * widCntSrcSel; 899 | 900 | // perform max-pooling operation 901 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 902 | float* featVecDst = 903 | pFeatMapDst->GetDataPtr(dataInd, heiIndDst, widIndDst, 0); 904 | for (int sptIndSrc = 0; sptIndSrc < sptCntSrcSel; sptIndSrc++) { 905 | int heiIndSrc = heiIndSrcL + sptIndSrc / widCntSrcSel; 906 | int widIndSrc = widIndSrcL + sptIndSrc % widCntSrcSel; 907 | const float* featVecSrc = 908 | featMapSrc.GetDataPtr(dataInd, heiIndSrc, widIndSrc, 0); 909 | if (sptIndSrc == 0) { 910 | memcpy(featVecDst, featVecSrc, sizeof(float) * imgChn); 911 | } else { 912 | for (int chnInd = 0; chnInd < imgChn; chnInd++) { 913 | featVecDst[chnInd] = 914 | std::max(featVecSrc[chnInd], featVecDst[chnInd]); 915 | } // ENDFOR: chnInd 916 | } // ENDIF: sptIndSrc 917 | } // ENDFOR: sptIndSrc 918 | } // ENDFOR: dataInd 919 | } // ENDFOR: widIndDst 920 | } // ENDFOR: heiIndDst 921 | } 922 | 923 | void CaffeEva::CalcFeatMap_FCnt(const Matrix& featMapSrc, 924 | const int layerInd, Matrix* pFeatMapDst) { 925 | if (enblAprx) { 926 | CalcFeatMap_FCntAprx(featMapSrc, layerInd, pFeatMapDst); 927 | } else { 928 | CalcFeatMap_FCntPrec(featMapSrc, layerInd, pFeatMapDst); 929 | } // ENDIF: enblAprx 930 | } 931 | 932 | void CaffeEva::CalcFeatMap_FCntPrec(const Matrix& featMapSrc, 933 | const int layerInd, Matrix* pFeatMapDst) { 934 | // obtain basic variables 935 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 936 | int dataCnt = featMapSrc.GetDimLen(0); 937 | int imgChnSrc = featMapSrc.GetDimStp(0); 938 | int imgChnDst = pFeatMapDst->GetDimStp(0); 939 | 940 | // call CBLAS function to compute the matrix-matrix multiplication 941 | CBLAS_ORDER order = CblasRowMajor; 942 | CBLAS_TRANSPOSE transA = CblasNoTrans; 943 | CBLAS_TRANSPOSE transB = CblasTrans; 944 | CBLAS_INT m = dataCnt; 945 | CBLAS_INT n = imgChnDst; 946 | CBLAS_INT k = imgChnSrc; 947 | CBLAS_INT lda = k; 948 | CBLAS_INT ldb = k; 949 | CBLAS_INT ldc = n; 950 | float alpha = 1.0; 951 | float beta = 0.0; 952 | float* pa = featMapSrc.GetDataPtr(); 953 | float* pb = layerPara.fcntWeiMat.GetDataPtr(); 954 | float* pc = pFeatMapDst->GetDataPtr(); 955 | cblas_sgemm(order, transA, transB, 956 | m, n, k, alpha, pa, lda, pb, ldb, beta, pc, ldc); 957 | 958 | // append the bias term 959 | const float* biasVec = layerPara.biasVec.GetDataPtr(); 960 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 961 | float* pFeatMapVec = pFeatMapDst->GetDataPtr(dataInd, 0); 962 | for (int chnIndDst = 0; chnIndDst < imgChnDst; chnIndDst++) { 963 | pFeatMapVec[chnIndDst] += biasVec[chnIndDst]; 964 | } // ENDFOR: chnIndDst 965 | } // ENDFOR: dataInd 966 | } 967 | 968 | void CaffeEva::CalcFeatMap_FCntAprx(const Matrix& featMapSrc, 969 | const int layerInd, Matrix* pFeatMapDst) { 970 | // obtain basic variables 971 | const LayerPara& layerPara = caffeParaObj.layerParaLst[layerInd]; 972 | int dataCnt = featMapSrc.GetDimLen(0); 973 | int imgChnDst = pFeatMapDst->GetDimStp(0); 974 | int subSpaceCnt = layerPara.ctrdLst.GetDimLen(0); 975 | int ctrdCntPerSpace = layerPara.ctrdLst.GetDimLen(1); 976 | 977 | // obtain pre-allocated matrices for auxiliary variables 978 | Matrix& featMapSrcRsp = *(featBufStrMat[layerInd][0].pFeatBuf); 979 | Matrix& inPdMat = *(featBufStrMat[layerInd][1].pFeatBuf); 980 | inPdMat.Resize(dataCnt, subSpaceCnt, ctrdCntPerSpace); 981 | 982 | // obtain pre-allocated centroid and assignment buffer 983 | Matrix& ctrdBuf = *(ctrdBufStrLst[layerInd].pCtrdBuf); 984 | Matrix& asmtBuf = *(asmtBufStrLst[layerInd].pAsmtBuf); 985 | // Matrix& asmtBufExt = *(asmtBufStrLst[layerInd].pAsmtBufExt); 986 | 987 | // quantize the source feature map with pre-defined codebook 988 | swCompLkupTblFCnt.Resume(); 989 | memcpy(featMapSrcRsp.GetDataPtr(), 990 | featMapSrc.GetDataPtr(), sizeof(float) * featMapSrc.GetEleCnt()); 991 | GetInPdMat(featMapSrcRsp, ctrdBuf, &inPdMat); 992 | inPdMat.Resize(dataCnt, subSpaceCnt * ctrdCntPerSpace); 993 | swCompLkupTblFCnt.Pause(); 994 | 995 | // compute the feature map after passing a fully-connected layer 996 | swEstiInPdValFCnt.Resume(); 997 | const float* biasVec = layerPara.biasVec.GetDataPtr(); 998 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 999 | // initialize target response with the bias term 1000 | float* featVecDst = pFeatMapDst->GetDataPtr(dataInd, 0, 0, 0); 1001 | memcpy(featVecDst, biasVec, sizeof(float) * imgChnDst); 1002 | 1003 | // update target response with look-up operations 1004 | const float* inPdVec = inPdMat.GetDataPtr(dataInd, 0); // index offset 1005 | const uint8_t* asmtVec = asmtBuf.GetDataPtr(); 1006 | for (int subSpaceInd = 0; subSpaceInd < subSpaceCnt; subSpaceInd++) { 1007 | // update the target response within the current subspace 1008 | for (int chnIndDst = 0; chnIndDst < imgChnDst; chnIndDst += 8) { 1009 | featVecDst[chnIndDst] += inPdVec[asmtVec[chnIndDst]]; 1010 | featVecDst[chnIndDst + 1] += inPdVec[asmtVec[chnIndDst + 1]]; 1011 | featVecDst[chnIndDst + 2] += inPdVec[asmtVec[chnIndDst + 2]]; 1012 | featVecDst[chnIndDst + 3] += inPdVec[asmtVec[chnIndDst + 3]]; 1013 | featVecDst[chnIndDst + 4] += inPdVec[asmtVec[chnIndDst + 4]]; 1014 | featVecDst[chnIndDst + 5] += inPdVec[asmtVec[chnIndDst + 5]]; 1015 | featVecDst[chnIndDst + 6] += inPdVec[asmtVec[chnIndDst + 6]]; 1016 | featVecDst[chnIndDst + 7] += inPdVec[asmtVec[chnIndDst + 7]]; 1017 | } // ENDFOR: chnIndDst 1018 | 1019 | // update pointers to the look-up table and assignment variable 1020 | inPdVec += ctrdCntPerSpace; 1021 | asmtVec += imgChnDst; 1022 | } // ENDFOR: subSpaceInd 1023 | } // ENDFOR: dataInd 1024 | swEstiInPdValFCnt.Pause(); 1025 | } 1026 | 1027 | void CaffeEva::CalcFeatMap_ReLu(const Matrix& featMapSrc, 1028 | const int layerInd, Matrix* pFeatMapDst) { 1029 | // compute the feature map after passing a ReLu layer 1030 | int eleCnt = featMapSrc.GetEleCnt(); 1031 | const float* featVecSrc = featMapSrc.GetDataPtr(); 1032 | float* featVecDst = pFeatMapDst->GetDataPtr(); 1033 | for (int eleInd = 0; eleInd < eleCnt; eleInd++) { 1034 | featVecDst[eleInd] = std::max(0.0f, featVecSrc[eleInd]); 1035 | } // ENDFOR: eleInd 1036 | } 1037 | 1038 | void CaffeEva::CalcFeatMap_LoRN(const Matrix& featMapSrc, 1039 | const int layerInd, Matrix* pFeatMapDst) { 1040 | // obtain basic variables 1041 | const LayerInfo& layerInfo = caffeParaObj.layerInfoLst[layerInd]; 1042 | int dataCnt = featMapSrc.GetDimLen(0); 1043 | int imgHei = featMapSrc.GetDimLen(1); 1044 | int imgWid = featMapSrc.GetDimLen(2); 1045 | int imgChn = featMapSrc.GetDimLen(3); 1046 | int lrnRad = (layerInfo.lrnSiz - 1) / 2; 1047 | int sptCnt = imgHei * imgWid; 1048 | 1049 | // declare auxiliary variable arrays 1050 | int imgChnExt = imgChn + lrnRad * 2; 1051 | float* featVecSrcExt = new float[imgChnExt]; 1052 | float* loclSumLst = new float[imgChn]; 1053 | 1054 | // compute the feature map after passing a local response normalization layer 1055 | float coeffVal = layerInfo.lrnAlp / layerInfo.lrnSiz; 1056 | memset(featVecSrcExt, 0, sizeof(float) * imgChnExt); 1057 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 1058 | for (int sptInd = 0; sptInd < sptCnt; sptInd++) { 1059 | // determine the height/width indexes 1060 | int heiInd = sptInd / imgWid; 1061 | int widInd = sptInd % imgWid; 1062 | 1063 | // compute the squared feature vector 1064 | const float* featVecSrc = 1065 | featMapSrc.GetDataPtr(dataInd, heiInd, widInd, 0); 1066 | vsSqr(imgChn, featVecSrc, featVecSrcExt + lrnRad); 1067 | cblas_sscal(imgChn, coeffVal, featVecSrcExt + lrnRad, 1); 1068 | 1069 | // compute with a sliding windows 1070 | for (int chnInd = 0; chnInd < imgChn; chnInd++) { 1071 | loclSumLst[chnInd] = layerInfo.lrnIni; 1072 | } // ENDFOR: chnInd 1073 | for (int chnInd = 0; chnInd < layerInfo.lrnSiz; chnInd++) { 1074 | vsAdd(imgChn, loclSumLst, featVecSrcExt + chnInd, loclSumLst); 1075 | } // ENDFOR: chnInd 1076 | 1077 | // transform local patch sum to normalization factor 1078 | vsPowx_m(imgChn, loclSumLst, -layerInfo.lrnBet, loclSumLst); 1079 | 1080 | // compute the normalized feature map 1081 | float* featVecDst = pFeatMapDst->GetDataPtr(dataInd, heiInd, widInd, 0); 1082 | vsMul(imgChn, featVecSrc, loclSumLst, featVecDst); 1083 | } // ENDFOR: sptInd 1084 | } // ENDFOR: dataInd 1085 | 1086 | // release auxiliary variable arrays 1087 | delete[] featVecSrcExt; 1088 | delete[] loclSumLst; 1089 | } 1090 | 1091 | void CaffeEva::CalcFeatMap_Drpt(const Matrix& featMapSrc, 1092 | const int layerInd, Matrix* pFeatMapDst) { 1093 | // compute the feature map after passing a dropout layer 1094 | memcpy(pFeatMapDst->GetDataPtr(), 1095 | featMapSrc.GetDataPtr(), sizeof(float) * featMapSrc.GetEleCnt()); 1096 | } 1097 | 1098 | void CaffeEva::CalcFeatMap_SMax(const Matrix& featMapSrc, 1099 | const int layerInd, Matrix* pFeatMapDst) { 1100 | // compute the feature map after passing a softmax layer 1101 | int dataCnt = featMapSrc.GetDimLen(0); 1102 | int imgChn = featMapSrc.GetDimStp(0); 1103 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 1104 | const float* featVecSrc = featMapSrc.GetDataPtr(dataInd, 0, 0, 0); 1105 | float* featVecDst = pFeatMapDst->GetDataPtr(dataInd, 0, 0, 0); 1106 | 1107 | float sum = 0.0; 1108 | for (int chnInd = 0; chnInd < imgChn; chnInd++) { 1109 | featVecDst[chnInd] = exp(featVecSrc[chnInd]); 1110 | sum += featVecDst[chnInd]; 1111 | } // ENDFOR: chnInd 1112 | for (int chnInd = 0; chnInd < imgChn; chnInd++) { 1113 | featVecDst[chnInd] /= sum; 1114 | } // ENDFOR: chnInd 1115 | } // ENDFOR: dataInd 1116 | } 1117 | 1118 | void CaffeEva::InitFeatBuf( 1119 | FeatBufStr* pFeatBufStr, const ENUM_BufUsage us, const int d0) { 1120 | pFeatBufStr->usage = us; 1121 | pFeatBufStr->dimCnt = 1; 1122 | pFeatBufStr->dimLenLst[0] = d0; 1123 | } 1124 | 1125 | void CaffeEva::InitFeatBuf(FeatBufStr* pFeatBufStr, 1126 | const ENUM_BufUsage us, const int d0, const int d1) { 1127 | InitFeatBuf(pFeatBufStr, us, d0); 1128 | pFeatBufStr->dimCnt = 2; 1129 | pFeatBufStr->dimLenLst[1] = d1; 1130 | } 1131 | 1132 | void CaffeEva::InitFeatBuf(FeatBufStr* pFeatBufStr, 1133 | const ENUM_BufUsage us, const int d0, const int d1, const int d2) { 1134 | InitFeatBuf(pFeatBufStr, us, d0, d1); 1135 | pFeatBufStr->dimCnt = 3; 1136 | pFeatBufStr->dimLenLst[2] = d2; 1137 | } 1138 | 1139 | void CaffeEva::InitFeatBuf(FeatBufStr* pFeatBufStr, const ENUM_BufUsage us, 1140 | const int d0, const int d1, const int d2, const int d3) { 1141 | InitFeatBuf(pFeatBufStr, us, d0, d1, d2); 1142 | pFeatBufStr->dimCnt = 4; 1143 | pFeatBufStr->dimLenLst[3] = d3; 1144 | } 1145 | 1146 | void CaffeEva::CvtDataLstToFeatMap(const int dataIndL, const int dataIndU, 1147 | const Matrix& dataLst, Matrix* pFeatMap) { 1148 | // obtain basic variables 1149 | int dataVecLen = dataLst.GetDimStp(0); 1150 | int imgChn = dataLst.GetDimLen(1); 1151 | int imgHei = dataLst.GetDimLen(2); 1152 | int imgWid = dataLst.GetDimLen(3); 1153 | 1154 | // copy each sample's feature vector 1155 | int dataCntSel = dataIndU - dataIndL + 1; 1156 | pFeatMap->Resize(dataCntSel, imgChn, imgHei, imgWid); 1157 | memcpy(pFeatMap->GetDataPtr(), dataLst.GetDataPtr(dataIndL, 0, 0, 0), 1158 | sizeof(float) * dataVecLen * dataCntSel); 1159 | pFeatMap->Permute(0, 2, 3, 1); 1160 | } 1161 | 1162 | void CaffeEva::CvtFeatMapToLablVec(const int dataIndL, const int dataIndU, 1163 | const Matrix& featMap, Matrix* pLablVec) { 1164 | // determine the predicted class label from the output feature map 1165 | int probVecLen = featMap.GetDimStp(0); 1166 | Matrix probLst(probVecLen); 1167 | float* probVec = probLst.GetDataPtr(); 1168 | for (int dataInd = dataIndL; dataInd <= dataIndU; dataInd++) { 1169 | // copy category probabilities to a temporary array 1170 | memcpy(probVec, featMap.GetDataPtr(dataInd - dataIndL, 0, 0, 0), 1171 | sizeof(float) * probVecLen); 1172 | 1173 | // determine the x-th predicted class label 1174 | for (int lablInd = 0; lablInd < kLablCntPerData; lablInd++) { 1175 | // find the maximal probability 1176 | float probValOpt = FLT_MIN; 1177 | uint16_t probValIndOpt = 0; 1178 | for (int probValInd = 0; probValInd < probVecLen; probValInd++) { 1179 | if (probValOpt < probVec[probValInd]) { 1180 | probValOpt = probVec[probValInd]; 1181 | probValIndOpt = probValInd; 1182 | } // ENDIF: probValOpt 1183 | } // ENDFOR: probValInd 1184 | 1185 | // record current prediction 1186 | probVec[probValIndOpt] = 0.0; 1187 | pLablVec->SetEleAt(probValIndOpt, dataInd, lablInd, 0, 0); 1188 | } // ENDFOR: lablInd 1189 | } // ENDFOR: dataInd 1190 | } 1191 | 1192 | // INPUT REQUIREMENTS: 1193 | // featMap: 1 x Cs x Hs x Ws 1194 | // featBuf: (Ht x Wt) x (Ck x Hk x Wk) 1195 | void CaffeEva::CvtFeatMapToFeatBuf( 1196 | const Matrix& featMap, const int dataInd, const int grpInd, 1197 | const LayerInfo& layerInfo, Matrix* pFeatBuf) { 1198 | // obtain basic variables 1199 | int imgChnSrc = featMap.GetDimLen(1); 1200 | int imgHeiSrc = featMap.GetDimLen(2); 1201 | int imgWidSrc = featMap.GetDimLen(3); 1202 | int grpCnt = layerInfo.grpCnt; 1203 | int padSiz = layerInfo.padSiz; 1204 | int knlSiz = layerInfo.knlSiz; 1205 | int stride = layerInfo.stride; 1206 | int imgChnSrcPerGrp = imgChnSrc / grpCnt; 1207 | int imgHeiDst = ceil((imgHeiSrc + 2 * padSiz - knlSiz) / stride) + 1; 1208 | int imgWidDst = ceil((imgWidSrc + 2 * padSiz - knlSiz) / stride) + 1; 1209 | int rowCntBuf = pFeatBuf->GetDimLen(0); 1210 | 1211 | // copy feature data from to 1212 | int chnIndSrcL = grpInd * imgChnSrcPerGrp; 1213 | memset(pFeatBuf->GetDataPtr(), 0, sizeof(float) * pFeatBuf->GetEleCnt()); 1214 | for (int rowIndBuf = 0; rowIndBuf < rowCntBuf; rowIndBuf++) { 1215 | // obtain basic variables 1216 | int widIndKnl = rowIndBuf % knlSiz; 1217 | int heiIndKnl = rowIndBuf / knlSiz % knlSiz; 1218 | int chnIndKnl = rowIndBuf / knlSiz / knlSiz; 1219 | int heiIndDstL = std::max(0, (padSiz - heiIndKnl - 1) / stride + 1); 1220 | int heiIndDstU = 1221 | std::min(imgHeiDst - 1, (padSiz - heiIndKnl + imgHeiSrc - 1) / stride); 1222 | int heiCntDstSel = heiIndDstU - heiIndDstL + 1; 1223 | int widIndDstL = std::max(0, (padSiz - widIndKnl - 1) / stride + 1); 1224 | int widIndDstU = 1225 | std::min(imgWidDst - 1, (padSiz - widIndKnl + imgWidSrc - 1) / stride); 1226 | int widCntDstSel = widIndDstU - widIndDstL + 1; 1227 | const float* ptrSrc = 1228 | featMap.GetDataPtr(dataInd, chnIndSrcL + chnIndKnl, 0, 0); 1229 | float* ptrDst = pFeatBuf->GetDataPtr(rowIndBuf, 0); 1230 | 1231 | // copy feature data from to 1232 | for (int heiIndDstSel = 0; heiIndDstSel < heiCntDstSel; heiIndDstSel++) { 1233 | for (int widIndDstSel = 0; widIndDstSel < widCntDstSel; widIndDstSel++) { 1234 | int heiIndDst = heiIndDstL + heiIndDstSel; 1235 | int widIndDst = widIndDstL + widIndDstSel; 1236 | int heiIndSrc = heiIndKnl + heiIndDst * stride - padSiz; 1237 | int widIndSrc = widIndKnl + widIndDst * stride - padSiz; 1238 | ptrDst[heiIndDst * imgWidDst + widIndDst] = 1239 | ptrSrc[heiIndSrc * imgWidSrc + widIndSrc]; 1240 | } // ENDFOR: widIndDstSel 1241 | } // ENDFOR: heiIndDstSel 1242 | } // ENDFOR: rowIndBuf 1243 | } 1244 | 1245 | // INPUT REQUIREMENTS: 1246 | // featBuf: Ct x (Ht x Wt) 1247 | // featMap: 1 x Ct x Ht x Wt 1248 | void CaffeEva::CvtFeatBufToFeatMap( 1249 | const Matrix& featBuf, const int dataInd, const int grpInd, 1250 | const LayerInfo& layerInfo, Matrix* pFeatMap) { 1251 | // obtain basic variables 1252 | int imgChnDst = pFeatMap->GetDimLen(1); 1253 | int chnIndDstL = imgChnDst / layerInfo.grpCnt * grpInd; 1254 | 1255 | // copy feature data from to 1256 | const float* ptrSrc = featBuf.GetDataPtr(); 1257 | float* ptrDst = pFeatMap->GetDataPtr(dataInd, chnIndDstL, 0, 0); 1258 | memcpy(ptrDst, ptrSrc, sizeof(float) * featBuf.GetEleCnt()); 1259 | } 1260 | 1261 | void CaffeEva::GetInPdMat(const Matrix& dataLst, 1262 | const Matrix& ctrdLst, Matrix* pInPdMat) { 1263 | // obtain basic variables 1264 | int dataCnt = dataLst.GetDimLen(0); 1265 | int featDimCnt = dataLst.GetDimLen(1); 1266 | int subSpaceCnt = ctrdLst.GetDimLen(0); 1267 | int featCntPerSpace = ctrdLst.GetDimLen(1); 1268 | int ctrdCntPerSpace = ctrdLst.GetDimLen(2); 1269 | 1270 | // resize the inner-product look-up table 1271 | pInPdMat->Resize(dataCnt, subSpaceCnt, ctrdCntPerSpace); 1272 | 1273 | // compute the inner-product look-up table in each subspace 1274 | for (int subSpaceInd = 0; subSpaceInd < subSpaceCnt; subSpaceInd++) { 1275 | // determine the selected dimensions 1276 | int featDimIndL = featCntPerSpace * subSpaceInd; 1277 | int featDimCntSel = std::min(featDimCnt - featDimIndL, featCntPerSpace); 1278 | 1279 | // compute the inner-product look-up table for each instance 1280 | const float* dataVec = dataLst.GetDataPtr(0, featDimIndL); 1281 | float* inPdVec = pInPdMat->GetDataPtr(0, subSpaceInd, 0); 1282 | for (int dataInd = 0; dataInd < dataCnt; dataInd++) { 1283 | const float* ctrdVec = ctrdLst.GetDataPtr(subSpaceInd, 0, 0); 1284 | memset(inPdVec, 0, sizeof(float) * ctrdCntPerSpace); 1285 | for (int featDimInd = 0; featDimInd < featDimCntSel; featDimInd++) { 1286 | cblas_saxpy( 1287 | ctrdCntPerSpace, dataVec[featDimInd], ctrdVec, 1, inPdVec, 1); 1288 | ctrdVec += ctrdCntPerSpace; 1289 | } // ENDFOR: featDimInd 1290 | 1291 | // update pointers to the data vector and look-up table 1292 | dataVec += featDimCnt; 1293 | inPdVec += subSpaceCnt * ctrdCntPerSpace; 1294 | } // ENDFOR: dataInd 1295 | } // ENDFOR: subSpaceInd 1296 | } 1297 | -------------------------------------------------------------------------------- /src/CaffeEvaWrapper.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/CaffeEvaWrapper.h" 9 | 10 | CaffeEvaWrapper::CaffeEvaWrapper(void) { 11 | // clear error message 12 | ClrErrorMsg(); 13 | } 14 | 15 | bool CaffeEvaWrapper::SetPath(const std::string& mainDirPathSrc, 16 | const std::string& clsNameFilePath, const std::string& imgLablFilePath) { 17 | // declare auxiliary variables 18 | bool rtnFlg; 19 | 20 | // initialize basic variables 21 | mainDirPath = mainDirPathSrc; 22 | 23 | // load the full list of class names 24 | rtnFlg = LoadClsName(clsNameFilePath); 25 | if (!rtnFlg) { // failed 26 | errorMsg = 27 | "[CaffeEvaWrapper::SetPath] could not open file: " + clsNameFilePath; 28 | return false; 29 | } // ENDIF: rtnFlg 30 | 31 | // load the full list of ground-truth class names 32 | if (imgLablFilePath != "") { 33 | rtnFlg = LoadImgLabl(imgLablFilePath); 34 | if (!rtnFlg) { // failed 35 | errorMsg = 36 | "[CaffeEvaWrapper::SetPath] could not open file: " + imgLablFilePath; 37 | return false; 38 | } // ENDIF: rtnFlg 39 | } // ENDIF: imgLablFileName 40 | 41 | return true; 42 | } 43 | 44 | bool CaffeEvaWrapper::SetModel(const ENUM_CaffeModel& caffeModelSrc, 45 | const ENUM_CompMethod& compMethodSrc) { 46 | // declare auxiliary variables 47 | bool rtnFlg; 48 | 49 | // initialize basic variables 50 | caffeModel = caffeModelSrc; 51 | compMethod = compMethodSrc; 52 | 53 | // initialize remaining variables according to the selected caffe model 54 | switch (caffeModel) { 55 | case ENUM_CaffeModel::AlexNet: 56 | // fall through 57 | case ENUM_CaffeModel::CaffeNet: 58 | // fall through 59 | case ENUM_CaffeModel::CaffeNetFGB: 60 | // fall through 61 | case ENUM_CaffeModel::CaffeNetFGD: 62 | bmpImgIOPara.reszType = ENUM_ReszType::Strict; 63 | bmpImgIOPara.meanType = ENUM_MeanType::Full; 64 | bmpImgIOPara.imgHeiFull = 256; 65 | bmpImgIOPara.imgWidFull = 256; 66 | bmpImgIOPara.imgHeiCrop = 227; 67 | bmpImgIOPara.imgWidCrop = 227; 68 | break; 69 | case ENUM_CaffeModel::VggCnnS: 70 | bmpImgIOPara.reszType = ENUM_ReszType::Relaxed; 71 | bmpImgIOPara.meanType = ENUM_MeanType::Crop; 72 | bmpImgIOPara.imgHeiFull = 256; 73 | bmpImgIOPara.imgWidFull = 256; 74 | bmpImgIOPara.imgHeiCrop = 224; 75 | bmpImgIOPara.imgWidCrop = 224; 76 | break; 77 | case ENUM_CaffeModel::VGG16: 78 | printf("[FATAL ERROR] VGG-16 is not supported (for now)\n"); 79 | errorMsg = "[CaffeEvaWrapper::SetModel] unsupported caffe model name"; 80 | return false; 81 | default: 82 | printf("[FATAL ERROR] unrecognized value\n"); 83 | errorMsg = "[CaffeEvaWrapper::SetModel] unrecognized caffe model name"; 84 | return false; 85 | } // ENDSWITCH: caffeModel 86 | 87 | switch (caffeModel) { 88 | case ENUM_CaffeModel::AlexNet: 89 | bmpImgIOPara.filePathMean = 90 | mainDirPath + "/AlexNet/imagenet_mean.single.bin"; 91 | caffeModelName = "AlexNet"; 92 | dirPathPara = mainDirPath + "/AlexNet/Bin.Files"; 93 | fileNamePfx = "bvlc_alexnet_aCaF"; 94 | break; 95 | case ENUM_CaffeModel::CaffeNet: 96 | bmpImgIOPara.filePathMean = 97 | mainDirPath + "/CaffeNet/imagenet_mean.single.bin"; 98 | caffeModelName = "CaffeNet"; 99 | dirPathPara = mainDirPath + "/CaffeNet/Bin.Files"; 100 | fileNamePfx = "bvlc_caffenet_aCaF"; 101 | break; 102 | case ENUM_CaffeModel::VggCnnS: 103 | bmpImgIOPara.filePathMean = 104 | mainDirPath + "/VggCnnS/imagenet_mean.single.bin"; 105 | caffeModelName = "VggCnnS"; 106 | dirPathPara = mainDirPath + "/VggCnnS/Bin.Files"; 107 | fileNamePfx = "vgg_cnn_s_aCaF"; 108 | break; 109 | case ENUM_CaffeModel::VGG16: 110 | printf("[FATAL ERROR] VGG-16 is not supported (for now)\n"); 111 | errorMsg = "[CaffeEvaWrapper::SetModel] unsupported caffe model name"; 112 | return false; 113 | case ENUM_CaffeModel::CaffeNetFGB: 114 | bmpImgIOPara.filePathMean = 115 | mainDirPath + "/CaffeNetFGB/imagenet_mean.single.bin"; 116 | caffeModelName = "CaffeNetFGB"; 117 | dirPathPara = mainDirPath + "/CaffeNetFGB/Bin.Files"; 118 | fileNamePfx = "bvlc_caffenetfgb_aCaF"; 119 | break; 120 | case ENUM_CaffeModel::CaffeNetFGD: 121 | bmpImgIOPara.filePathMean = 122 | mainDirPath + "/CaffeNetFGD/imagenet_mean.single.bin"; 123 | caffeModelName = "CaffeNetFGD"; 124 | dirPathPara = mainDirPath + "/CaffeNetFGD/Bin.Files"; 125 | fileNamePfx = "bvlc_caffenetfgd_aCaF"; 126 | break; 127 | default: 128 | printf("[FATAL ERROR] unrecognized value\n"); 129 | errorMsg = "[CaffeEvaWrapper::SetModel] unrecognized caffe model name"; 130 | return false; 131 | } // ENDSWITCH: caffeModel 132 | 133 | // initialize essential variables in 134 | rtnFlg = bmpImgIOObj.Init(bmpImgIOPara); 135 | if (!rtnFlg) { // failed 136 | errorMsg = "[CaffeEvaWrapper::SetModel] could not open the mean image file"; 137 | return false; 138 | } // ENDIF: rtnFlg 139 | 140 | // initialize essential variables in 141 | caffeEvaObj.Init(compMethodSrc == ENUM_CompMethod::Aprx); 142 | caffeEvaObj.SetModelName(caffeModelName); 143 | caffeEvaObj.SetModelPath(dirPathPara, fileNamePfx); 144 | rtnFlg = caffeEvaObj.LoadCaffePara(); 145 | if (!rtnFlg) { // failed 146 | errorMsg = "[CaffeEvaWrapper::SetModel] could not load model files"; 147 | return false; 148 | } // ENDIF: rtnFlg 149 | 150 | return true; 151 | } 152 | 153 | bool CaffeEvaWrapper::Proc( 154 | const std::string& filePathProcImg, CaffeEvaRslt* pCaffeEvaRslt) { 155 | // declare auxiliary variables 156 | bool rtnFlg; 157 | 158 | // obtain the image file path for classification 159 | Matrix imgData; 160 | rtnFlg = bmpImgIOObj.Load(filePathProcImg, &imgData); 161 | if (!rtnFlg) { // failed 162 | errorMsg = "[CaffeEvaWrapper::Proc] could open the BMP file"; 163 | return false; 164 | } // ENDIF: rtnFlg 165 | 166 | // execute the forward-passing process of caffe model 167 | Matrix probVec; 168 | caffeEvaObj.ExecForwardPass(imgData, &probVec); 169 | pCaffeEvaRslt->timeTotal = caffeEvaObj.DispElpsTime(); 170 | 171 | // find the ground-truth class name (if exists) 172 | std::string fileNameProcImg = ExtrFileName(filePathProcImg); 173 | pCaffeEvaRslt->hasGrthClsName = false; 174 | for (std::size_t idx = 0; idx < clsNameGrthLst.size(); idx++) { 175 | if (fileNameProcImg == clsNameGrthLst[idx].fileName) { 176 | pCaffeEvaRslt->hasGrthClsName = true; 177 | pCaffeEvaRslt->clsNameGrth = clsNameGrthLst[idx].clsNameGrth; 178 | break; 179 | } // ENDIF: fileNameProcImg 180 | } // ENDFOR: idx 181 | 182 | // find the top-ranked categories and pack them into 183 | int clsCnt = probVec.GetEleCnt(); 184 | float* pProbVec = probVec.GetDataPtr(); 185 | pCaffeEvaRslt->clsIdxLst.clear(); 186 | pCaffeEvaRslt->clsProbLst.clear(); 187 | pCaffeEvaRslt->clsNameLst.clear(); 188 | for (int rankInd = 0; rankInd < pCaffeEvaRslt->clsCntPred; rankInd++) { 189 | // fine the k-th top-ranked class label 190 | int clsIndOpt = 0; 191 | float probValOpt = pProbVec[clsIndOpt]; 192 | for (int clsInd = 1; clsInd < clsCnt; clsInd++) { 193 | if (probValOpt < pProbVec[clsInd]) { 194 | clsIndOpt = clsInd; 195 | probValOpt = pProbVec[clsInd]; 196 | } // ENDIF: probValOpt 197 | } // ENDFOR: clsInd 198 | 199 | // record current predicted class label 200 | pCaffeEvaRslt->clsIdxLst.push_back(clsIndOpt); 201 | pCaffeEvaRslt->clsProbLst.push_back(probValOpt); 202 | pCaffeEvaRslt->clsNameLst.push_back(clsNameLst[clsIndOpt]); 203 | 204 | // modify for the next round 205 | pProbVec[clsIndOpt] = 0.0; 206 | } // ENDFOR: rankInd 207 | 208 | return true; 209 | } 210 | 211 | std::string CaffeEvaWrapper::GetErrorMsg(void) { 212 | return errorMsg; 213 | } 214 | 215 | void CaffeEvaWrapper::ClrErrorMsg(void) { 216 | errorMsg = ""; 217 | } 218 | 219 | bool CaffeEvaWrapper::LoadClsName(const std::string& filePath) { 220 | // define auxiliary variables 221 | char* rtnPtr = nullptr; 222 | const int kStrBufLen = 1024; 223 | char strBuf[kStrBufLen]; 224 | FILE* inFile = fopen(filePath.c_str(), "r"); 225 | 226 | // check whether the file has been successfully opened 227 | if (inFile == nullptr) { 228 | return false; 229 | } // ENDIF: inFile 230 | 231 | // scan through each line 232 | clsNameLst.clear(); 233 | while (true) { 234 | // read in a new line 235 | rtnPtr = fgets(strBuf, kStrBufLen, inFile); 236 | 237 | // check whether EOF is reached 238 | if (rtnPtr == nullptr) { 239 | break; 240 | } // ENDIF: rtnPtr 241 | 242 | // add the current class name to 243 | strBuf[strlen(strBuf) - 1] = '\0'; // remove the EOL character 244 | clsNameLst.push_back(strBuf); 245 | } // ENDWHILE: true 246 | fclose(inFile); 247 | 248 | return true; 249 | } 250 | 251 | bool CaffeEvaWrapper::LoadImgLabl(const std::string& filePath) { 252 | // define auxiliary variables 253 | int rtnVal; 254 | const int kStrBufLen = 1024; 255 | char strBuf[kStrBufLen]; 256 | int clsNameInd; 257 | ClsNameGrthStr clsNameGrthStr; 258 | FILE* inFile = fopen(filePath.c_str(), "r"); 259 | 260 | // check whether the file has been successfully opened 261 | if (inFile == nullptr) { 262 | return false; 263 | } // ENDIF: inFile 264 | 265 | // scan through each line 266 | clsNameGrthLst.clear(); 267 | while (true) { 268 | // read in a new line 269 | rtnVal = fscanf(inFile, "%s%d", strBuf, &clsNameInd); 270 | 271 | // check whether EOF is reached 272 | if (rtnVal != 2) { 273 | break; 274 | } // ENDIF: rtnVal 275 | 276 | // add the current grouth-truth class name to 277 | clsNameGrthStr.fileName = ExtrFileName(std::string(strBuf)); 278 | clsNameGrthStr.clsNameGrth = clsNameLst[clsNameInd]; 279 | clsNameGrthLst.push_back(clsNameGrthStr); 280 | } // ENDWHILE: true 281 | fclose(inFile); 282 | 283 | return true; 284 | } 285 | 286 | std::string CaffeEvaWrapper::ExtrFileName(const std::string& filePath) { 287 | // define auxiliary variables 288 | const int kStrBufLen = 1024; 289 | char strBuf[kStrBufLen]; 290 | std::string fileName; 291 | int charIndBeg = 0; 292 | bool fileNameFound = false; 293 | 294 | // copy the full file path to 295 | snprintf(strBuf, kStrBufLen, "%s", filePath.c_str()); 296 | 297 | // find the first slash symbol 298 | for (int charInd = strlen(strBuf) - 1; (charInd >= 0); charInd--) { 299 | switch (strBuf[charInd]) { 300 | case '.': 301 | strBuf[charInd] = '\0'; 302 | break; 303 | case '/': 304 | charIndBeg = charInd + 1; 305 | fileNameFound = true; 306 | break; 307 | } // ENDSWITCH: strBuf 308 | 309 | // check whether the file name has been found 310 | if (fileNameFound) { 311 | break; 312 | } // ENDIF: fileNameFound 313 | } // ENDFOR: charInd 314 | 315 | // extract the file name 316 | fileName = std::string(strBuf + charIndBeg); 317 | 318 | return fileName; 319 | } 320 | -------------------------------------------------------------------------------- /src/CaffePara.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/CaffePara.h" 9 | 10 | #include "../include/Common.h" 11 | #include "../include/FileIO.h" 12 | 13 | void CaffePara::Init( 14 | const std::string& dirPathSrc, const std::string& filePfxSrc) { 15 | // set-up basic parameters 16 | dirPath = dirPathSrc; 17 | filePfx = filePfxSrc; 18 | } 19 | 20 | void CaffePara::ConfigLayer_AlexNet(void) { 21 | // configure the basic information 22 | layerCnt = 23; 23 | imgChnIn = 3; 24 | imgHeiIn = 227; 25 | imgWidIn = 227; 26 | layerInfoLst.resize(layerCnt); 27 | 28 | // configure each layer 29 | ConfigConvLayer(&(layerInfoLst[ 0]), 0, 11, 96, 1, 4); 30 | ConfigReLuLayer(&(layerInfoLst[ 1])); 31 | ConfigLoRNLayer(&(layerInfoLst[ 2]), 5, 0.0001, 0.75, 1.0); 32 | ConfigPoolLayer(&(layerInfoLst[ 3]), 0, 3, 2); 33 | ConfigConvLayer(&(layerInfoLst[ 4]), 2, 5, 256, 2, 1); 34 | ConfigReLuLayer(&(layerInfoLst[ 5])); 35 | ConfigLoRNLayer(&(layerInfoLst[ 6]), 5, 0.0001, 0.75, 1.0); 36 | ConfigPoolLayer(&(layerInfoLst[ 7]), 0, 3, 2); 37 | ConfigConvLayer(&(layerInfoLst[ 8]), 1, 3, 384, 1, 1); 38 | ConfigReLuLayer(&(layerInfoLst[ 9])); 39 | ConfigConvLayer(&(layerInfoLst[10]), 1, 3, 384, 2, 1); 40 | ConfigReLuLayer(&(layerInfoLst[11])); 41 | ConfigConvLayer(&(layerInfoLst[12]), 1, 3, 256, 2, 1); 42 | ConfigReLuLayer(&(layerInfoLst[13])); 43 | ConfigPoolLayer(&(layerInfoLst[14]), 0, 3, 2); 44 | ConfigFCntLayer(&(layerInfoLst[15]), 4096); 45 | ConfigReLuLayer(&(layerInfoLst[16])); 46 | ConfigDrptLayer(&(layerInfoLst[17]), 0.50); 47 | ConfigFCntLayer(&(layerInfoLst[18]), 4096); 48 | ConfigReLuLayer(&(layerInfoLst[19])); 49 | ConfigDrptLayer(&(layerInfoLst[20]), 0.50); 50 | ConfigFCntLayer(&(layerInfoLst[21]), 1000); 51 | ConfigSMaxLayer(&(layerInfoLst[22])); 52 | } 53 | 54 | void CaffePara::ConfigLayer_CaffeNet(void) { 55 | // configure the basic information 56 | layerCnt = 23; 57 | imgChnIn = 3; 58 | imgHeiIn = 227; 59 | imgWidIn = 227; 60 | layerInfoLst.resize(layerCnt); 61 | 62 | // configure each layer 63 | ConfigConvLayer(&(layerInfoLst[ 0]), 0, 11, 96, 1, 4); 64 | ConfigReLuLayer(&(layerInfoLst[ 1])); 65 | ConfigPoolLayer(&(layerInfoLst[ 2]), 0, 3, 2); 66 | ConfigLoRNLayer(&(layerInfoLst[ 3]), 5, 0.0001, 0.75, 1.0); 67 | ConfigConvLayer(&(layerInfoLst[ 4]), 2, 5, 256, 2, 1); 68 | ConfigReLuLayer(&(layerInfoLst[ 5])); 69 | ConfigPoolLayer(&(layerInfoLst[ 6]), 0, 3, 2); 70 | ConfigLoRNLayer(&(layerInfoLst[ 7]), 5, 0.0001, 0.75, 1.0); 71 | ConfigConvLayer(&(layerInfoLst[ 8]), 1, 3, 384, 1, 1); 72 | ConfigReLuLayer(&(layerInfoLst[ 9])); 73 | ConfigConvLayer(&(layerInfoLst[10]), 1, 3, 384, 2, 1); 74 | ConfigReLuLayer(&(layerInfoLst[11])); 75 | ConfigConvLayer(&(layerInfoLst[12]), 1, 3, 256, 2, 1); 76 | ConfigReLuLayer(&(layerInfoLst[13])); 77 | ConfigPoolLayer(&(layerInfoLst[14]), 0, 3, 2); 78 | ConfigFCntLayer(&(layerInfoLst[15]), 4096); 79 | ConfigReLuLayer(&(layerInfoLst[16])); 80 | ConfigDrptLayer(&(layerInfoLst[17]), 0.50); 81 | ConfigFCntLayer(&(layerInfoLst[18]), 4096); 82 | ConfigReLuLayer(&(layerInfoLst[19])); 83 | ConfigDrptLayer(&(layerInfoLst[20]), 0.50); 84 | ConfigFCntLayer(&(layerInfoLst[21]), 1000); 85 | ConfigSMaxLayer(&(layerInfoLst[22])); 86 | } 87 | 88 | void CaffePara::ConfigLayer_VggCnnS(void) { 89 | // configure the basic information 90 | layerCnt = 22; 91 | imgChnIn = 3; 92 | imgHeiIn = 224; 93 | imgWidIn = 224; 94 | layerInfoLst.resize(layerCnt); 95 | 96 | // configure each layer 97 | ConfigConvLayer(&(layerInfoLst[ 0]), 0, 7, 96, 1, 2); 98 | ConfigReLuLayer(&(layerInfoLst[ 1])); 99 | ConfigLoRNLayer(&(layerInfoLst[ 2]), 5, 0.0005, 0.75, 2.0); 100 | ConfigPoolLayer(&(layerInfoLst[ 3]), 0, 3, 3); 101 | ConfigConvLayer(&(layerInfoLst[ 4]), 1, 5, 256, 1, 1); 102 | ConfigReLuLayer(&(layerInfoLst[ 5])); 103 | ConfigPoolLayer(&(layerInfoLst[ 6]), 0, 2, 2); 104 | ConfigConvLayer(&(layerInfoLst[ 7]), 1, 3, 512, 1, 1); 105 | ConfigReLuLayer(&(layerInfoLst[ 8])); 106 | ConfigConvLayer(&(layerInfoLst[ 9]), 1, 3, 512, 1, 1); 107 | ConfigReLuLayer(&(layerInfoLst[10])); 108 | ConfigConvLayer(&(layerInfoLst[11]), 1, 3, 512, 1, 1); 109 | ConfigReLuLayer(&(layerInfoLst[12])); 110 | ConfigPoolLayer(&(layerInfoLst[13]), 0, 3, 3); 111 | ConfigFCntLayer(&(layerInfoLst[14]), 4096); 112 | ConfigReLuLayer(&(layerInfoLst[15])); 113 | ConfigDrptLayer(&(layerInfoLst[16]), 0.50); 114 | ConfigFCntLayer(&(layerInfoLst[17]), 4096); 115 | ConfigReLuLayer(&(layerInfoLst[18])); 116 | ConfigDrptLayer(&(layerInfoLst[19]), 0.50); 117 | ConfigFCntLayer(&(layerInfoLst[20]), 1000); 118 | ConfigSMaxLayer(&(layerInfoLst[21])); 119 | } 120 | 121 | void CaffePara::ConfigLayer_VGG16(void) { 122 | // configure the basic information 123 | layerCnt = 39; 124 | imgChnIn = 3; 125 | imgHeiIn = 224; 126 | imgWidIn = 224; 127 | layerInfoLst.resize(layerCnt); 128 | 129 | // configure each layer 130 | ConfigConvLayer(&(layerInfoLst[ 0]), 1, 3, 64, 1, 1); 131 | ConfigReLuLayer(&(layerInfoLst[ 1])); 132 | ConfigConvLayer(&(layerInfoLst[ 2]), 1, 3, 64, 1, 1); 133 | ConfigReLuLayer(&(layerInfoLst[ 3])); 134 | ConfigPoolLayer(&(layerInfoLst[ 4]), 0, 2, 2); 135 | ConfigConvLayer(&(layerInfoLst[ 5]), 1, 3, 128, 1, 1); 136 | ConfigReLuLayer(&(layerInfoLst[ 6])); 137 | ConfigConvLayer(&(layerInfoLst[ 7]), 1, 3, 128, 1, 1); 138 | ConfigReLuLayer(&(layerInfoLst[ 8])); 139 | ConfigPoolLayer(&(layerInfoLst[ 9]), 0, 2, 2); 140 | ConfigConvLayer(&(layerInfoLst[10]), 1, 3, 256, 1, 1); 141 | ConfigReLuLayer(&(layerInfoLst[11])); 142 | ConfigConvLayer(&(layerInfoLst[12]), 1, 3, 256, 1, 1); 143 | ConfigReLuLayer(&(layerInfoLst[13])); 144 | ConfigConvLayer(&(layerInfoLst[14]), 1, 3, 256, 1, 1); 145 | ConfigReLuLayer(&(layerInfoLst[15])); 146 | ConfigPoolLayer(&(layerInfoLst[16]), 0, 2, 2); 147 | ConfigConvLayer(&(layerInfoLst[17]), 1, 3, 512, 1, 1); 148 | ConfigReLuLayer(&(layerInfoLst[18])); 149 | ConfigConvLayer(&(layerInfoLst[19]), 1, 3, 512, 1, 1); 150 | ConfigReLuLayer(&(layerInfoLst[20])); 151 | ConfigConvLayer(&(layerInfoLst[21]), 1, 3, 512, 1, 1); 152 | ConfigReLuLayer(&(layerInfoLst[22])); 153 | ConfigPoolLayer(&(layerInfoLst[23]), 0, 2, 2); 154 | ConfigConvLayer(&(layerInfoLst[24]), 1, 3, 512, 1, 1); 155 | ConfigReLuLayer(&(layerInfoLst[25])); 156 | ConfigConvLayer(&(layerInfoLst[26]), 1, 3, 512, 1, 1); 157 | ConfigReLuLayer(&(layerInfoLst[27])); 158 | ConfigConvLayer(&(layerInfoLst[28]), 1, 3, 512, 1, 1); 159 | ConfigReLuLayer(&(layerInfoLst[29])); 160 | ConfigPoolLayer(&(layerInfoLst[30]), 0, 2, 2); 161 | ConfigFCntLayer(&(layerInfoLst[31]), 4096); 162 | ConfigReLuLayer(&(layerInfoLst[32])); 163 | ConfigDrptLayer(&(layerInfoLst[33]), 0.50); 164 | ConfigFCntLayer(&(layerInfoLst[34]), 4096); 165 | ConfigReLuLayer(&(layerInfoLst[35])); 166 | ConfigDrptLayer(&(layerInfoLst[36]), 0.50); 167 | ConfigFCntLayer(&(layerInfoLst[37]), 1000); 168 | ConfigSMaxLayer(&(layerInfoLst[38])); 169 | } 170 | 171 | void CaffePara::ConfigLayer_CaffeNetFGB(void) { 172 | // configure the basic information 173 | layerCnt = 23; 174 | imgChnIn = 3; 175 | imgHeiIn = 227; 176 | imgWidIn = 227; 177 | layerInfoLst.resize(layerCnt); 178 | 179 | // configure each layer 180 | ConfigConvLayer(&(layerInfoLst[ 0]), 0, 11, 96, 1, 4); 181 | ConfigReLuLayer(&(layerInfoLst[ 1])); 182 | ConfigPoolLayer(&(layerInfoLst[ 2]), 0, 3, 2); 183 | ConfigLoRNLayer(&(layerInfoLst[ 3]), 5, 0.0001, 0.75, 1.0); 184 | ConfigConvLayer(&(layerInfoLst[ 4]), 2, 5, 256, 2, 1); 185 | ConfigReLuLayer(&(layerInfoLst[ 5])); 186 | ConfigPoolLayer(&(layerInfoLst[ 6]), 0, 3, 2); 187 | ConfigLoRNLayer(&(layerInfoLst[ 7]), 5, 0.0001, 0.75, 1.0); 188 | ConfigConvLayer(&(layerInfoLst[ 8]), 1, 3, 384, 1, 1); 189 | ConfigReLuLayer(&(layerInfoLst[ 9])); 190 | ConfigConvLayer(&(layerInfoLst[10]), 1, 3, 384, 2, 1); 191 | ConfigReLuLayer(&(layerInfoLst[11])); 192 | ConfigConvLayer(&(layerInfoLst[12]), 1, 3, 256, 2, 1); 193 | ConfigReLuLayer(&(layerInfoLst[13])); 194 | ConfigPoolLayer(&(layerInfoLst[14]), 0, 3, 2); 195 | ConfigFCntLayer(&(layerInfoLst[15]), 4096); 196 | ConfigReLuLayer(&(layerInfoLst[16])); 197 | ConfigDrptLayer(&(layerInfoLst[17]), 0.70); 198 | ConfigFCntLayer(&(layerInfoLst[18]), 4096); 199 | ConfigReLuLayer(&(layerInfoLst[19])); 200 | ConfigDrptLayer(&(layerInfoLst[20]), 0.70); 201 | ConfigFCntLayer(&(layerInfoLst[21]), 518); 202 | ConfigSMaxLayer(&(layerInfoLst[22])); 203 | } 204 | 205 | void CaffePara::ConfigLayer_CaffeNetFGD(void) { 206 | // configure the basic information 207 | layerCnt = 23; 208 | imgChnIn = 3; 209 | imgHeiIn = 227; 210 | imgWidIn = 227; 211 | layerInfoLst.resize(layerCnt); 212 | 213 | // configure each layer 214 | ConfigConvLayer(&(layerInfoLst[ 0]), 0, 11, 96, 1, 4); 215 | ConfigReLuLayer(&(layerInfoLst[ 1])); 216 | ConfigPoolLayer(&(layerInfoLst[ 2]), 0, 3, 2); 217 | ConfigLoRNLayer(&(layerInfoLst[ 3]), 5, 0.0001, 0.75, 1.0); 218 | ConfigConvLayer(&(layerInfoLst[ 4]), 2, 5, 256, 2, 1); 219 | ConfigReLuLayer(&(layerInfoLst[ 5])); 220 | ConfigPoolLayer(&(layerInfoLst[ 6]), 0, 3, 2); 221 | ConfigLoRNLayer(&(layerInfoLst[ 7]), 5, 0.0001, 0.75, 1.0); 222 | ConfigConvLayer(&(layerInfoLst[ 8]), 1, 3, 384, 1, 1); 223 | ConfigReLuLayer(&(layerInfoLst[ 9])); 224 | ConfigConvLayer(&(layerInfoLst[10]), 1, 3, 384, 2, 1); 225 | ConfigReLuLayer(&(layerInfoLst[11])); 226 | ConfigConvLayer(&(layerInfoLst[12]), 1, 3, 256, 2, 1); 227 | ConfigReLuLayer(&(layerInfoLst[13])); 228 | ConfigPoolLayer(&(layerInfoLst[14]), 0, 3, 2); 229 | ConfigFCntLayer(&(layerInfoLst[15]), 4096); 230 | ConfigReLuLayer(&(layerInfoLst[16])); 231 | ConfigDrptLayer(&(layerInfoLst[17]), 0.50); 232 | ConfigFCntLayer(&(layerInfoLst[18]), 4096); 233 | ConfigReLuLayer(&(layerInfoLst[19])); 234 | ConfigDrptLayer(&(layerInfoLst[20]), 0.50); 235 | ConfigFCntLayer(&(layerInfoLst[21]), 200); 236 | ConfigSMaxLayer(&(layerInfoLst[22])); 237 | } 238 | 239 | bool CaffePara::LoadLayerPara(const bool enblAprx, const ENUM_AsmtEnc asmtEnc) { 240 | // declare auxiliary variables 241 | const int kStrBufLen = 256; 242 | char strBuf[kStrBufLen]; 243 | bool succFlg = true; 244 | 245 | // NOTE 246 | // will be updated when attempting loading a file from disk. 247 | // If is set to at sometime, the remaining file loading 248 | // operations may be skipped by the compiler. However, this won't be an 249 | // problem, since the function will eventually return , which is 250 | // , to indicate that the file loading has failed at some point. 251 | 252 | // load parameters for each layer 253 | layerParaLst.resize(layerCnt); 254 | for (int layerInd = 0; layerInd < layerCnt; layerInd++) { 255 | const LayerInfo& layerInfo = layerInfoLst[layerInd]; 256 | LayerPara& layerPara = layerParaLst[layerInd]; 257 | 258 | // load parameters for the convolutional (or fully-connected) layer 259 | if ((layerInfo.type == ENUM_LyrType::Conv) || 260 | (layerInfo.type == ENUM_LyrType::FCnt)) { 261 | // load the bias vector 262 | snprintf(strBuf, kStrBufLen, "%s/%s.biasVec.%02d.bin", 263 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 264 | succFlg &= FileIO::ReadBinFile(strBuf, &(layerPara.biasVec)); 265 | 266 | // load convolutional kernels or fully-connected weighting matrix 267 | if (enblAprx) { // load quantized parameters 268 | // load sub-codebooks 269 | snprintf(strBuf, kStrBufLen, "%s/%s.ctrdLst.%02d.bin", 270 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 271 | succFlg &= FileIO::ReadBinFile(strBuf, &(layerPara.ctrdLst)); 272 | 273 | // load sub-codewords' assignment 274 | if (asmtEnc == ENUM_AsmtEnc::Raw) { 275 | snprintf(strBuf, kStrBufLen, "%s/%s.asmtLst.%02d.bin", 276 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 277 | succFlg &= FileIO::ReadBinFile(strBuf, &(layerPara.asmtLst)); 278 | } else { 279 | snprintf(strBuf, kStrBufLen, "%s/%s.asmtLst.%02d.cbn", 280 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 281 | succFlg &= FileIO::ReadCbnFile(strBuf, &(layerPara.asmtLst)); 282 | } // ENDIF: asmtEnc 283 | 284 | // fix the 1/0 index difference between MATLAB and C++ 285 | uint8_t* asmtVec = layerPara.asmtLst.GetDataPtr(); 286 | for (int eleInd = 0; eleInd < layerPara.asmtLst.GetEleCnt(); eleInd++) { 287 | asmtVec[eleInd]--; 288 | } // ENDFOR: eleInd 289 | } else { // load original parameters 290 | if (layerInfo.type == ENUM_LyrType::Conv) { 291 | // load the convolutional kernels 292 | snprintf(strBuf, kStrBufLen, "%s/%s.convKnl.%02d.bin", 293 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 294 | succFlg &= FileIO::ReadBinFile(strBuf, &(layerPara.convKnlLst)); 295 | } else { 296 | // load the fully-connected weighting matrix 297 | snprintf(strBuf, kStrBufLen, "%s/%s.fcntWei.%02d.bin", 298 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 299 | succFlg &= FileIO::ReadBinFile(strBuf, &(layerPara.fcntWeiMat)); 300 | } // ENDIF: layerInfo 301 | } // ENDIF: enblAprx 302 | } // ENDIF: layerInfo 303 | } // ENDFOR: layerInd 304 | 305 | return succFlg; 306 | } 307 | 308 | bool CaffePara::CvtAsmtEnc( 309 | const ENUM_AsmtEnc asmtEncSrc, const ENUM_AsmtEnc asmtEncDst) { 310 | // early return if the source/target encoding is the same 311 | if (asmtEncSrc == asmtEncDst) { 312 | printf("[INFO] no encoding conversion is required\n"); 313 | return true; 314 | } // ENDIF: asmtEncSrc 315 | 316 | // declare auxiliary variables 317 | const int kStrBufLen = 256; 318 | char strBufBin[kStrBufLen]; 319 | char strBufCbn[kStrBufLen]; 320 | bool succFlg = true; 321 | Matrix asmtLst; 322 | int bitCntPerEle; 323 | 324 | // NOTE 325 | // will be updated when attempting loading a file from disk. 326 | // If is set to at sometime, the remaining file loading 327 | // operations may be skipped by the compiler. However, this won't be an 328 | // problem, since the function will eventually return , which is 329 | // , to indicate that the file loading has failed at some point. 330 | 331 | // convert assignment encoding for each layer 332 | for (int layerInd = 0; layerInd < layerCnt; layerInd++) { 333 | const LayerInfo& layerInfo = layerInfoLst[layerInd]; 334 | 335 | // convert assignment encoding for the convolutional layer 336 | if ((layerInfo.type == ENUM_LyrType::Conv) || 337 | (layerInfo.type == ENUM_LyrType::FCnt)) { 338 | // generate file path for the assignment data 339 | snprintf(strBufBin, kStrBufLen, "%s/%s.asmtLst.%02d.bin", 340 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 341 | snprintf(strBufCbn, kStrBufLen, "%s/%s.asmtLst.%02d.cbn", 342 | dirPath.c_str(), filePfx.c_str(), layerInd + 1); 343 | 344 | // convert the encoding from to , or vice versa 345 | if (asmtEncSrc == ENUM_AsmtEnc::Raw) { 346 | succFlg &= FileIO::ReadBinFile(strBufBin, &asmtLst); 347 | bitCntPerEle = CalcBitCntPerEle(asmtLst); 348 | printf("layer #%d: bitCntPerEle = %d\n", layerInd + 1, bitCntPerEle); 349 | succFlg &= FileIO::WriteCbnFile(strBufCbn, asmtLst, bitCntPerEle); 350 | } else { 351 | succFlg &= FileIO::ReadCbnFile(strBufCbn, &asmtLst); 352 | succFlg &= FileIO::WriteBinFile(strBufBin, asmtLst); 353 | } // ENDIF: asmtEncSrc 354 | } // ENDIF: layerInfo 355 | } // ENDFOR: layerInd 356 | 357 | return succFlg; 358 | } 359 | 360 | int CaffePara::CalcBitCntPerEle(const Matrix& asmtLst) { 361 | // find the maximal value in 362 | int eleCnt = asmtLst.GetEleCnt(); 363 | const uint8_t* asmtVec = asmtLst.GetDataPtr(); 364 | uint8_t maxVal = 0; 365 | for (int eleInd = 0; eleInd < eleCnt; eleInd++) { 366 | maxVal = std::max(maxVal, *(asmtVec++)); 367 | } // ENDFOR: eleInd 368 | maxVal -= 1; // remove the offset 369 | 370 | // determine the proper value for 371 | int bitCntPerEle = 0; 372 | while (maxVal != 0) { 373 | maxVal /= 2; 374 | bitCntPerEle++; 375 | } // ENDWHILE: maxVal 376 | 377 | return bitCntPerEle; 378 | } 379 | 380 | void CaffePara::ConfigConvLayer(LayerInfo* pLayerInfo, const int padSiz, 381 | const int knlSiz, const int knlCnt, const int grpCnt, const int stride) { 382 | pLayerInfo->type = ENUM_LyrType::Conv; 383 | pLayerInfo->padSiz = padSiz; 384 | pLayerInfo->knlSiz = knlSiz; 385 | pLayerInfo->knlCnt = knlCnt; 386 | pLayerInfo->grpCnt = grpCnt; 387 | pLayerInfo->stride = stride; 388 | } 389 | 390 | void CaffePara::ConfigPoolLayer(LayerInfo* pLayerInfo, 391 | const int padSiz, const int knlSiz, const int stride) { 392 | pLayerInfo->type = ENUM_LyrType::Pool; 393 | pLayerInfo->padSiz = padSiz; 394 | pLayerInfo->knlSiz = knlSiz; 395 | pLayerInfo->stride = stride; 396 | } 397 | 398 | void CaffePara::ConfigFCntLayer(LayerInfo* pLayerInfo, const int nodCnt) { 399 | pLayerInfo->type = ENUM_LyrType::FCnt; 400 | pLayerInfo->nodCnt = nodCnt; 401 | } 402 | 403 | void CaffePara::ConfigReLuLayer(LayerInfo* pLayerInfo) { 404 | pLayerInfo->type = ENUM_LyrType::ReLU; 405 | } 406 | 407 | void CaffePara::ConfigLoRNLayer(LayerInfo* pLayerInfo, const int lrnSiz, 408 | const float lrnAlp, const float lrnBet, const float lrnIni) { 409 | pLayerInfo->type = ENUM_LyrType::LoRN; 410 | pLayerInfo->lrnSiz = lrnSiz; 411 | pLayerInfo->lrnAlp = lrnAlp; 412 | pLayerInfo->lrnBet = lrnBet; 413 | pLayerInfo->lrnIni = lrnIni; 414 | } 415 | 416 | void CaffePara::ConfigDrptLayer(LayerInfo* pLayerInfo, const float drpRat) { 417 | pLayerInfo->type = ENUM_LyrType::Drpt; 418 | pLayerInfo->drpRat = drpRat; 419 | } 420 | 421 | void CaffePara::ConfigSMaxLayer(LayerInfo* pLayerInfo) { 422 | pLayerInfo->type = ENUM_LyrType::SMax; 423 | } 424 | -------------------------------------------------------------------------------- /src/Main.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/UnitTest.h" 9 | 10 | int main(int argc, char* argv[]) { 11 | // run unit-test for the class 12 | // UnitTest::UT_CaffePara(); 13 | 14 | // MODE 1: SPEED TEST 15 | // run unit-test for the class 16 | UnitTest::UT_CaffeEva(); 17 | 18 | // MODE 2: SINGLE IMAGE CLASSIFICATION 19 | // run unit-test for the class 20 | // UnitTest::UT_CaffeEvaWrapper(); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/UnitTest.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © CASIA 2015-2016. 3 | * 4 | * Paper: Quantized Convolutional Neural Networks for Mobile Devices (CVPR 2016) 5 | * Authors: Jiaxiang Wu, Cong Leng, Yuhang Wang, Qinghao Hu, and Jian Cheng 6 | */ 7 | 8 | #include "../include/UnitTest.h" 9 | 10 | #include "../include/CaffeEva.h" 11 | #include "../include/CaffeEvaWrapper.h" 12 | #include "../include/CaffePara.h" 13 | #include "../include/StopWatch.h" 14 | 15 | void UnitTest::UT_CaffePara(void) { 16 | // create class objects for unit-test 17 | CaffePara caffeParaObj; 18 | 19 | // load parameters for the caffe model 20 | caffeParaObj.Init("./AlexNet/Bin.Files", "bvlc_alexnet_aCaF"); 21 | caffeParaObj.ConfigLayer_AlexNet(); 22 | caffeParaObj.LoadLayerPara(true, ENUM_AsmtEnc::Raw); 23 | caffeParaObj.CvtAsmtEnc(ENUM_AsmtEnc::Raw, ENUM_AsmtEnc::Compact); 24 | caffeParaObj.LoadLayerPara(true, ENUM_AsmtEnc::Compact); 25 | } 26 | 27 | void UnitTest::UT_CaffeEva(void) { 28 | // create class objects for unit-test 29 | StopWatch stopWatchObj; 30 | CaffeEva caffeEvaObj; 31 | 32 | // choose a caffe model 33 | bool kEnblAprxComp = true; 34 | const std::string kCaffeModelName = "AlexNet"; 35 | 36 | // evaluate the caffe model's classification accuracy 37 | stopWatchObj.Reset(); 38 | stopWatchObj.Resume(); 39 | caffeEvaObj.Init(kEnblAprxComp); // enable approximate but fast computation 40 | if (kCaffeModelName == "AlexNet") { 41 | caffeEvaObj.SetModelName("AlexNet"); 42 | caffeEvaObj.SetModelPath("./AlexNet/Bin.Files", "bvlc_alexnet_aCaF"); 43 | caffeEvaObj.LoadDataset("./ILSVRC12.227x227.IMG"); 44 | } else if (kCaffeModelName == "CaffeNet") { 45 | caffeEvaObj.SetModelName("CaffeNet"); 46 | caffeEvaObj.SetModelPath("./CaffeNet/Bin.Files", "bvlc_caffenet_aCaF"); 47 | caffeEvaObj.LoadDataset("./ILSVRC12.227x227.IMG"); 48 | } else if (kCaffeModelName == "VggCnnS") { 49 | caffeEvaObj.SetModelName("VggCnnS"); 50 | caffeEvaObj.SetModelPath("./VggCnnS/Bin.Files", "vgg_cnn_s_aCaF"); 51 | caffeEvaObj.LoadDataset("./ILSVRC12.224x224.IMG"); 52 | } else if (kCaffeModelName == "VGG16") { 53 | caffeEvaObj.SetModelName("VGG16"); 54 | caffeEvaObj.SetModelPath("./VGG16/Bin.Files", "vgg16_aCaF"); 55 | caffeEvaObj.LoadDataset("./ILSVRC12.224x224.PXL"); 56 | } else { 57 | printf("[ERROR] unrecognized caffe model: %s\n", kCaffeModelName.c_str()); 58 | } // ENDIF: kCaffeModelName 59 | caffeEvaObj.LoadCaffePara(); 60 | caffeEvaObj.ExecForwardPass(); 61 | caffeEvaObj.CalcPredAccu(); 62 | caffeEvaObj.DispElpsTime(); 63 | stopWatchObj.Pause(); 64 | printf("elapsed time: %.4f (s)\n", stopWatchObj.GetTime()); 65 | } 66 | 67 | void UnitTest::UT_CaffeEvaWrapper(void) { 68 | // declare auxiliary variables 69 | bool rtnFlg; 70 | 71 | // create class objects for unit-test 72 | StopWatch stopWatchObj; 73 | CaffeEvaWrapper caffeEvaWrapperObj; 74 | 75 | // initialize constant variables 76 | const std::string kMainDirPath = "./"; 77 | const ENUM_CaffeModel kCaffeModel = ENUM_CaffeModel::AlexNet; 78 | const ENUM_CompMethod kCompMethod = ENUM_CompMethod::Aprx; 79 | const std::string kClsNameFilePath = "./Cls.Names/class_names.txt"; 80 | const std::string kImgLablFilePath = "./Cls.Names/image_labels.txt"; 81 | const std::string kBmpFilePath = "./Bmp.Files/ILSVRC2012_val_00000002.BMP"; 82 | 83 | // initialize the structure for result storing 84 | CaffeEvaRslt caffeEvaRslt; 85 | caffeEvaRslt.clsCntPred = 5; 86 | 87 | // predict class labels for a single BMP image 88 | stopWatchObj.Reset(); 89 | stopWatchObj.Resume(); 90 | rtnFlg = caffeEvaWrapperObj.SetPath( 91 | kMainDirPath, kClsNameFilePath, kImgLablFilePath); 92 | if (!rtnFlg) { // failed 93 | printf("[ERROR] CaffeEvaWrapper::SetPath() return FALSE\n"); 94 | printf("[ERROR] call CaffeEvaWrapper::GetErrorMsg() to details\n"); 95 | return; 96 | } // ENDIF: rtnFlg 97 | rtnFlg = caffeEvaWrapperObj.SetModel(kCaffeModel, kCompMethod); 98 | if (!rtnFlg) { // failed 99 | printf("[ERROR] CaffeEvaWrapper::SetModel() returns FALSE\n"); 100 | printf("[ERROR] call CaffeEvaWrapper::GetErrorMsg() to details\n"); 101 | return; 102 | } // ENDIF: rtnFlg 103 | rtnFlg = caffeEvaWrapperObj.Proc(kBmpFilePath, &caffeEvaRslt); 104 | if (!rtnFlg) { // failed 105 | printf("[ERROR] CaffeEvaWrapper::Proc() returns FALSE\n"); 106 | printf("[ERROR] call CaffeEvaWrapper::GetErrorMsg() to details\n"); 107 | return; 108 | } // ENDIF: rtnFlg 109 | stopWatchObj.Pause(); 110 | printf("elapsed time: %.4f (s)\n", stopWatchObj.GetTime()); 111 | 112 | // display the classification result 113 | printf("[INFO] input image: %s\n", kBmpFilePath.c_str()); 114 | if (caffeEvaRslt.hasGrthClsName) { 115 | printf("[INFO] Ground-truth class name: %s\n", 116 | caffeEvaRslt.clsNameGrth.c_str()); 117 | } // ENDIF: caffeEvaRslt 118 | for (int clsIdxPred = 0; clsIdxPred < caffeEvaRslt.clsCntPred; clsIdxPred++) { 119 | printf("[INFO] No. %d: %s (%d / %.4f)\n", clsIdxPred + 1, 120 | caffeEvaRslt.clsNameLst[clsIdxPred].c_str(), 121 | caffeEvaRslt.clsIdxLst[clsIdxPred], 122 | caffeEvaRslt.clsProbLst[clsIdxPred]); 123 | } // ENDFOR: clsIdxPred 124 | } 125 | --------------------------------------------------------------------------------