├── LICENSE ├── README.md ├── Section1-Getting_started ├── Megamind.avi ├── Megamind.mp4 ├── Packt_CV_w_Python3_Getting_Started_with_Jupyter_notebooks.ipynb ├── Thumbs.db └── butterfly.jpg ├── Section2-Digit_recognition └── Packt Comp Vision with Python3 - Digit Recognition.ipynb ├── Section3-dlib_facial_recognition └── faces │ ├── Alec_Baldwin_0001.jpg │ ├── Alec_Baldwin_0002.jpg │ ├── Alec_Baldwin_0004.jpg │ ├── Serena_Williams_0019.jpg │ ├── Serena_Williams_0024.jpg │ ├── Serena_Williams_0025.jpg │ ├── Serena_Williams_0026.jpg │ ├── Sheryl_Crow_0003.jpg │ ├── Sheryl_Crow_0004.jpg │ ├── Sheryl_Crow_0005.jpg │ ├── Sheryl_Crow_0007.jpg │ ├── Sylvester_Stallone_0002.jpg │ ├── Sylvester_Stallone_0003.jpg │ ├── Sylvester_Stallone_0005.jpg │ ├── Sylvester_Stallone_0006.jpg │ ├── Sylvester_Stallone_0008.jpg │ ├── Winona_Ryder_0001.jpg │ ├── Winona_Ryder_0004.jpg │ ├── Winona_Ryder_0006.jpg │ ├── Winona_Ryder_0011.jpg │ ├── Winona_Ryder_0012.jpg │ ├── Winona_Ryder_0019.jpg │ ├── Yao_Ming_0001.jpg │ ├── Yao_Ming_0002.jpg │ ├── Yao_Ming_0005.jpg │ └── Yao_Ming_0008.jpg └── Section4-Tensorflow_image_classifier ├── Packt_CV_w_Python3_Tensorflow_classifier.ipynb ├── inception_1000_class_list.txt ├── label_image.py ├── output_labels.txt ├── retrain.py ├── sample_imgs └── place_files_in_labeled_directories_here └── scratch.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computer Vision Projects with Python 3 [Video] 2 | This is the code repository for [Computer Vision Projects with Python 3 [Video]](https://www.packtpub.com/big-data-and-business-intelligence/computer-vision-projects-python-3-video?utm_source=github&utm_medium=repository&utm_campaign=9781788835565), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish. 3 | ## About the Video Course 4 | The Python programming language is an ideal platform for rapidly prototyping and developing production-grade codes for image processing and computer vision with its robust syntax and wealth of powerful libraries. 5 | 6 | This video course will start by showing you how to set up Anaconda Python for the major OSes with cutting-edge third-party libraries for computer vision. You’ll learn state-of-the-art techniques to classify images and find and identify humans within videos. 7 | 8 | Next, you’ll understand how to set up Anaconda Python 3 for the major OSes (Windows, Mac, and Linux) and augment it with the powerful vision and machine learning tools OpenCV and TensorFlow, as well as Dlib. You’ll be taken through the handwritten digits classifier and then move on to detecting facial features and finally develop a general image classifier. 9 | 10 | By the end of this course, you’ll know the basic tools of computer vision and be able to put it into practice. 11 | 12 | 13 |

What You Will Learn

14 |
15 |
21 | 22 | ## Instructions and Navigation 23 | ### Assumed Knowledge 24 | To fully benefit from the coverage included in this course, you will need:
25 | This video course is for programmers already familiar with Python who want to add computer vision and machine learning algorithms to their toolbox. 26 | ### Technical Requirements 27 | This course has the following software requirements:
28 | 29 | This course has been tested on the following system configuration: 30 | ● OS: Windows 10 31 | ● Processor: Intel i7 4th generation mobile 32 | ● Memory: 32 GB 33 | ● Hard Disk Space: 1 TB 34 | ● Video Card: GeForce GTX 970m 35 | 36 | 37 | ## Related Products 38 | * [Data Visualization with Python: The Complete Guide [Video]](https://www.packtpub.com/application-development/data-visualization-python-complete-guide-video?utm_source=github&utm_medium=repository&utm_campaign=9781789536959) 39 | 40 | * [Getting Started with Object-Oriented Programming in Python 3 [Video]](https://www.packtpub.com/application-development/getting-started-object-oriented-programming-python-3-video?utm_source=github&utm_medium=repository&utm_campaign=9781788629744) 41 | 42 | * [Big Data Analytics Projects with Apache Spark [Video]](https://www.packtpub.com/big-data-and-business-intelligence/big-data-analytics-projects-apache-spark-video?utm_source=github&utm_medium=repository&utm_campaign=9781789132373) 43 | 44 | -------------------------------------------------------------------------------- /Section1-Getting_started/Megamind.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section1-Getting_started/Megamind.avi -------------------------------------------------------------------------------- /Section1-Getting_started/Megamind.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section1-Getting_started/Megamind.mp4 -------------------------------------------------------------------------------- /Section1-Getting_started/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section1-Getting_started/Thumbs.db -------------------------------------------------------------------------------- /Section1-Getting_started/butterfly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section1-Getting_started/butterfly.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Alec_Baldwin_0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Alec_Baldwin_0001.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Alec_Baldwin_0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Alec_Baldwin_0002.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Alec_Baldwin_0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Alec_Baldwin_0004.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Serena_Williams_0019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Serena_Williams_0019.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Serena_Williams_0024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Serena_Williams_0024.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Serena_Williams_0025.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Serena_Williams_0025.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Serena_Williams_0026.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Serena_Williams_0026.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sheryl_Crow_0003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sheryl_Crow_0003.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sheryl_Crow_0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sheryl_Crow_0004.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sheryl_Crow_0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sheryl_Crow_0005.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sheryl_Crow_0007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sheryl_Crow_0007.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0002.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0003.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0005.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0006.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Sylvester_Stallone_0008.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Winona_Ryder_0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Winona_Ryder_0001.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Winona_Ryder_0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Winona_Ryder_0004.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Winona_Ryder_0006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Winona_Ryder_0006.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Winona_Ryder_0011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Winona_Ryder_0011.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Winona_Ryder_0012.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Winona_Ryder_0012.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Winona_Ryder_0019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Winona_Ryder_0019.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Yao_Ming_0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Yao_Ming_0001.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Yao_Ming_0002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Yao_Ming_0002.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Yao_Ming_0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Yao_Ming_0005.jpg -------------------------------------------------------------------------------- /Section3-dlib_facial_recognition/faces/Yao_Ming_0008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Computer-Vision-Projects-with-Python-3/9f66e5b5cee16568d02b09fe3d466cb6fb8155f9/Section3-dlib_facial_recognition/faces/Yao_Ming_0008.jpg -------------------------------------------------------------------------------- /Section4-Tensorflow_image_classifier/inception_1000_class_list.txt: -------------------------------------------------------------------------------- 1 | {0: 'tench, Tinca tinca', 2 | 1: 'goldfish, Carassius auratus', 3 | 2: 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias', 4 | 3: 'tiger shark, Galeocerdo cuvieri', 5 | 4: 'hammerhead, hammerhead shark', 6 | 5: 'electric ray, crampfish, numbfish, torpedo', 7 | 6: 'stingray', 8 | 7: 'cock', 9 | 8: 'hen', 10 | 9: 'ostrich, Struthio camelus', 11 | 10: 'brambling, Fringilla montifringilla', 12 | 11: 'goldfinch, Carduelis carduelis', 13 | 12: 'house finch, linnet, Carpodacus mexicanus', 14 | 13: 'junco, snowbird', 15 | 14: 'indigo bunting, indigo finch, indigo bird, Passerina cyanea', 16 | 15: 'robin, American robin, Turdus migratorius', 17 | 16: 'bulbul', 18 | 17: 'jay', 19 | 18: 'magpie', 20 | 19: 'chickadee', 21 | 20: 'water ouzel, dipper', 22 | 21: 'kite', 23 | 22: 'bald eagle, American eagle, Haliaeetus leucocephalus', 24 | 23: 'vulture', 25 | 24: 'great grey owl, great gray owl, Strix nebulosa', 26 | 25: 'European fire salamander, Salamandra salamandra', 27 | 26: 'common newt, Triturus vulgaris', 28 | 27: 'eft', 29 | 28: 'spotted salamander, Ambystoma maculatum', 30 | 29: 'axolotl, mud puppy, Ambystoma mexicanum', 31 | 30: 'bullfrog, Rana catesbeiana', 32 | 31: 'tree frog, tree-frog', 33 | 32: 'tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui', 34 | 33: 'loggerhead, loggerhead turtle, Caretta caretta', 35 | 34: 'leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea', 36 | 35: 'mud turtle', 37 | 36: 'terrapin', 38 | 37: 'box turtle, box tortoise', 39 | 38: 'banded gecko', 40 | 39: 'common iguana, iguana, Iguana iguana', 41 | 40: 'American chameleon, anole, Anolis carolinensis', 42 | 41: 'whiptail, whiptail lizard', 43 | 42: 'agama', 44 | 43: 'frilled lizard, Chlamydosaurus kingi', 45 | 44: 'alligator lizard', 46 | 45: 'Gila monster, Heloderma suspectum', 47 | 46: 'green lizard, Lacerta viridis', 48 | 47: 'African chameleon, Chamaeleo chamaeleon', 49 | 48: 'Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis', 50 | 49: 'African crocodile, Nile crocodile, Crocodylus niloticus', 51 | 50: 'American alligator, Alligator mississipiensis', 52 | 51: 'triceratops', 53 | 52: 'thunder snake, worm snake, Carphophis amoenus', 54 | 53: 'ringneck snake, ring-necked snake, ring snake', 55 | 54: 'hognose snake, puff adder, sand viper', 56 | 55: 'green snake, grass snake', 57 | 56: 'king snake, kingsnake', 58 | 57: 'garter snake, grass snake', 59 | 58: 'water snake', 60 | 59: 'vine snake', 61 | 60: 'night snake, Hypsiglena torquata', 62 | 61: 'boa constrictor, Constrictor constrictor', 63 | 62: 'rock python, rock snake, Python sebae', 64 | 63: 'Indian cobra, Naja naja', 65 | 64: 'green mamba', 66 | 65: 'sea snake', 67 | 66: 'horned viper, cerastes, sand viper, horned asp, Cerastes cornutus', 68 | 67: 'diamondback, diamondback rattlesnake, Crotalus adamanteus', 69 | 68: 'sidewinder, horned rattlesnake, Crotalus cerastes', 70 | 69: 'trilobite', 71 | 70: 'harvestman, daddy longlegs, Phalangium opilio', 72 | 71: 'scorpion', 73 | 72: 'black and gold garden spider, Argiope aurantia', 74 | 73: 'barn spider, Araneus cavaticus', 75 | 74: 'garden spider, Aranea diademata', 76 | 75: 'black widow, Latrodectus mactans', 77 | 76: 'tarantula', 78 | 77: 'wolf spider, hunting spider', 79 | 78: 'tick', 80 | 79: 'centipede', 81 | 80: 'black grouse', 82 | 81: 'ptarmigan', 83 | 82: 'ruffed grouse, partridge, Bonasa umbellus', 84 | 83: 'prairie chicken, prairie grouse, prairie fowl', 85 | 84: 'peacock', 86 | 85: 'quail', 87 | 86: 'partridge', 88 | 87: 'African grey, African gray, Psittacus erithacus', 89 | 88: 'macaw', 90 | 89: 'sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita', 91 | 90: 'lorikeet', 92 | 91: 'coucal', 93 | 92: 'bee eater', 94 | 93: 'hornbill', 95 | 94: 'hummingbird', 96 | 95: 'jacamar', 97 | 96: 'toucan', 98 | 97: 'drake', 99 | 98: 'red-breasted merganser, Mergus serrator', 100 | 99: 'goose', 101 | 100: 'black swan, Cygnus atratus', 102 | 101: 'tusker', 103 | 102: 'echidna, spiny anteater, anteater', 104 | 103: 'platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus', 105 | 104: 'wallaby, brush kangaroo', 106 | 105: 'koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus', 107 | 106: 'wombat', 108 | 107: 'jellyfish', 109 | 108: 'sea anemone, anemone', 110 | 109: 'brain coral', 111 | 110: 'flatworm, platyhelminth', 112 | 111: 'nematode, nematode worm, roundworm', 113 | 112: 'conch', 114 | 113: 'snail', 115 | 114: 'slug', 116 | 115: 'sea slug, nudibranch', 117 | 116: 'chiton, coat-of-mail shell, sea cradle, polyplacophore', 118 | 117: 'chambered nautilus, pearly nautilus, nautilus', 119 | 118: 'Dungeness crab, Cancer magister', 120 | 119: 'rock crab, Cancer irroratus', 121 | 120: 'fiddler crab', 122 | 121: 'king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica', 123 | 122: 'American lobster, Northern lobster, Maine lobster, Homarus americanus', 124 | 123: 'spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish', 125 | 124: 'crayfish, crawfish, crawdad, crawdaddy', 126 | 125: 'hermit crab', 127 | 126: 'isopod', 128 | 127: 'white stork, Ciconia ciconia', 129 | 128: 'black stork, Ciconia nigra', 130 | 129: 'spoonbill', 131 | 130: 'flamingo', 132 | 131: 'little blue heron, Egretta caerulea', 133 | 132: 'American egret, great white heron, Egretta albus', 134 | 133: 'bittern', 135 | 134: 'crane', 136 | 135: 'limpkin, Aramus pictus', 137 | 136: 'European gallinule, Porphyrio porphyrio', 138 | 137: 'American coot, marsh hen, mud hen, water hen, Fulica americana', 139 | 138: 'bustard', 140 | 139: 'ruddy turnstone, Arenaria interpres', 141 | 140: 'red-backed sandpiper, dunlin, Erolia alpina', 142 | 141: 'redshank, Tringa totanus', 143 | 142: 'dowitcher', 144 | 143: 'oystercatcher, oyster catcher', 145 | 144: 'pelican', 146 | 145: 'king penguin, Aptenodytes patagonica', 147 | 146: 'albatross, mollymawk', 148 | 147: 'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', 149 | 148: 'killer whale, killer, orca, grampus, sea wolf, Orcinus orca', 150 | 149: 'dugong, Dugong dugon', 151 | 150: 'sea lion', 152 | 151: 'Chihuahua', 153 | 152: 'Japanese spaniel', 154 | 153: 'Maltese dog, Maltese terrier, Maltese', 155 | 154: 'Pekinese, Pekingese, Peke', 156 | 155: 'Shih-Tzu', 157 | 156: 'Blenheim spaniel', 158 | 157: 'papillon', 159 | 158: 'toy terrier', 160 | 159: 'Rhodesian ridgeback', 161 | 160: 'Afghan hound, Afghan', 162 | 161: 'basset, basset hound', 163 | 162: 'beagle', 164 | 163: 'bloodhound, sleuthhound', 165 | 164: 'bluetick', 166 | 165: 'black-and-tan coonhound', 167 | 166: 'Walker hound, Walker foxhound', 168 | 167: 'English foxhound', 169 | 168: 'redbone', 170 | 169: 'borzoi, Russian wolfhound', 171 | 170: 'Irish wolfhound', 172 | 171: 'Italian greyhound', 173 | 172: 'whippet', 174 | 173: 'Ibizan hound, Ibizan Podenco', 175 | 174: 'Norwegian elkhound, elkhound', 176 | 175: 'otterhound, otter hound', 177 | 176: 'Saluki, gazelle hound', 178 | 177: 'Scottish deerhound, deerhound', 179 | 178: 'Weimaraner', 180 | 179: 'Staffordshire bullterrier, Staffordshire bull terrier', 181 | 180: 'American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier', 182 | 181: 'Bedlington terrier', 183 | 182: 'Border terrier', 184 | 183: 'Kerry blue terrier', 185 | 184: 'Irish terrier', 186 | 185: 'Norfolk terrier', 187 | 186: 'Norwich terrier', 188 | 187: 'Yorkshire terrier', 189 | 188: 'wire-haired fox terrier', 190 | 189: 'Lakeland terrier', 191 | 190: 'Sealyham terrier, Sealyham', 192 | 191: 'Airedale, Airedale terrier', 193 | 192: 'cairn, cairn terrier', 194 | 193: 'Australian terrier', 195 | 194: 'Dandie Dinmont, Dandie Dinmont terrier', 196 | 195: 'Boston bull, Boston terrier', 197 | 196: 'miniature schnauzer', 198 | 197: 'giant schnauzer', 199 | 198: 'standard schnauzer', 200 | 199: 'Scotch terrier, Scottish terrier, Scottie', 201 | 200: 'Tibetan terrier, chrysanthemum dog', 202 | 201: 'silky terrier, Sydney silky', 203 | 202: 'soft-coated wheaten terrier', 204 | 203: 'West Highland white terrier', 205 | 204: 'Lhasa, Lhasa apso', 206 | 205: 'flat-coated retriever', 207 | 206: 'curly-coated retriever', 208 | 207: 'golden retriever', 209 | 208: 'Labrador retriever', 210 | 209: 'Chesapeake Bay retriever', 211 | 210: 'German short-haired pointer', 212 | 211: 'vizsla, Hungarian pointer', 213 | 212: 'English setter', 214 | 213: 'Irish setter, red setter', 215 | 214: 'Gordon setter', 216 | 215: 'Brittany spaniel', 217 | 216: 'clumber, clumber spaniel', 218 | 217: 'English springer, English springer spaniel', 219 | 218: 'Welsh springer spaniel', 220 | 219: 'cocker spaniel, English cocker spaniel, cocker', 221 | 220: 'Sussex spaniel', 222 | 221: 'Irish water spaniel', 223 | 222: 'kuvasz', 224 | 223: 'schipperke', 225 | 224: 'groenendael', 226 | 225: 'malinois', 227 | 226: 'briard', 228 | 227: 'kelpie', 229 | 228: 'komondor', 230 | 229: 'Old English sheepdog, bobtail', 231 | 230: 'Shetland sheepdog, Shetland sheep dog, Shetland', 232 | 231: 'collie', 233 | 232: 'Border collie', 234 | 233: 'Bouvier des Flandres, Bouviers des Flandres', 235 | 234: 'Rottweiler', 236 | 235: 'German shepherd, German shepherd dog, German police dog, alsatian', 237 | 236: 'Doberman, Doberman pinscher', 238 | 237: 'miniature pinscher', 239 | 238: 'Greater Swiss Mountain dog', 240 | 239: 'Bernese mountain dog', 241 | 240: 'Appenzeller', 242 | 241: 'EntleBucher', 243 | 242: 'boxer', 244 | 243: 'bull mastiff', 245 | 244: 'Tibetan mastiff', 246 | 245: 'French bulldog', 247 | 246: 'Great Dane', 248 | 247: 'Saint Bernard, St Bernard', 249 | 248: 'Eskimo dog, husky', 250 | 249: 'malamute, malemute, Alaskan malamute', 251 | 250: 'Siberian husky', 252 | 251: 'dalmatian, coach dog, carriage dog', 253 | 252: 'affenpinscher, monkey pinscher, monkey dog', 254 | 253: 'basenji', 255 | 254: 'pug, pug-dog', 256 | 255: 'Leonberg', 257 | 256: 'Newfoundland, Newfoundland dog', 258 | 257: 'Great Pyrenees', 259 | 258: 'Samoyed, Samoyede', 260 | 259: 'Pomeranian', 261 | 260: 'chow, chow chow', 262 | 261: 'keeshond', 263 | 262: 'Brabancon griffon', 264 | 263: 'Pembroke, Pembroke Welsh corgi', 265 | 264: 'Cardigan, Cardigan Welsh corgi', 266 | 265: 'toy poodle', 267 | 266: 'miniature poodle', 268 | 267: 'standard poodle', 269 | 268: 'Mexican hairless', 270 | 269: 'timber wolf, grey wolf, gray wolf, Canis lupus', 271 | 270: 'white wolf, Arctic wolf, Canis lupus tundrarum', 272 | 271: 'red wolf, maned wolf, Canis rufus, Canis niger', 273 | 272: 'coyote, prairie wolf, brush wolf, Canis latrans', 274 | 273: 'dingo, warrigal, warragal, Canis dingo', 275 | 274: 'dhole, Cuon alpinus', 276 | 275: 'African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus', 277 | 276: 'hyena, hyaena', 278 | 277: 'red fox, Vulpes vulpes', 279 | 278: 'kit fox, Vulpes macrotis', 280 | 279: 'Arctic fox, white fox, Alopex lagopus', 281 | 280: 'grey fox, gray fox, Urocyon cinereoargenteus', 282 | 281: 'tabby, tabby cat', 283 | 282: 'tiger cat', 284 | 283: 'Persian cat', 285 | 284: 'Siamese cat, Siamese', 286 | 285: 'Egyptian cat', 287 | 286: 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor', 288 | 287: 'lynx, catamount', 289 | 288: 'leopard, Panthera pardus', 290 | 289: 'snow leopard, ounce, Panthera uncia', 291 | 290: 'jaguar, panther, Panthera onca, Felis onca', 292 | 291: 'lion, king of beasts, Panthera leo', 293 | 292: 'tiger, Panthera tigris', 294 | 293: 'cheetah, chetah, Acinonyx jubatus', 295 | 294: 'brown bear, bruin, Ursus arctos', 296 | 295: 'American black bear, black bear, Ursus americanus, Euarctos americanus', 297 | 296: 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus', 298 | 297: 'sloth bear, Melursus ursinus, Ursus ursinus', 299 | 298: 'mongoose', 300 | 299: 'meerkat, mierkat', 301 | 300: 'tiger beetle', 302 | 301: 'ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle', 303 | 302: 'ground beetle, carabid beetle', 304 | 303: 'long-horned beetle, longicorn, longicorn beetle', 305 | 304: 'leaf beetle, chrysomelid', 306 | 305: 'dung beetle', 307 | 306: 'rhinoceros beetle', 308 | 307: 'weevil', 309 | 308: 'fly', 310 | 309: 'bee', 311 | 310: 'ant, emmet, pismire', 312 | 311: 'grasshopper, hopper', 313 | 312: 'cricket', 314 | 313: 'walking stick, walkingstick, stick insect', 315 | 314: 'cockroach, roach', 316 | 315: 'mantis, mantid', 317 | 316: 'cicada, cicala', 318 | 317: 'leafhopper', 319 | 318: 'lacewing, lacewing fly', 320 | 319: "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk", 321 | 320: 'damselfly', 322 | 321: 'admiral', 323 | 322: 'ringlet, ringlet butterfly', 324 | 323: 'monarch, monarch butterfly, milkweed butterfly, Danaus plexippus', 325 | 324: 'cabbage butterfly', 326 | 325: 'sulphur butterfly, sulfur butterfly', 327 | 326: 'lycaenid, lycaenid butterfly', 328 | 327: 'starfish, sea star', 329 | 328: 'sea urchin', 330 | 329: 'sea cucumber, holothurian', 331 | 330: 'wood rabbit, cottontail, cottontail rabbit', 332 | 331: 'hare', 333 | 332: 'Angora, Angora rabbit', 334 | 333: 'hamster', 335 | 334: 'porcupine, hedgehog', 336 | 335: 'fox squirrel, eastern fox squirrel, Sciurus niger', 337 | 336: 'marmot', 338 | 337: 'beaver', 339 | 338: 'guinea pig, Cavia cobaya', 340 | 339: 'sorrel', 341 | 340: 'zebra', 342 | 341: 'hog, pig, grunter, squealer, Sus scrofa', 343 | 342: 'wild boar, boar, Sus scrofa', 344 | 343: 'warthog', 345 | 344: 'hippopotamus, hippo, river horse, Hippopotamus amphibius', 346 | 345: 'ox', 347 | 346: 'water buffalo, water ox, Asiatic buffalo, Bubalus bubalis', 348 | 347: 'bison', 349 | 348: 'ram, tup', 350 | 349: 'bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis', 351 | 350: 'ibex, Capra ibex', 352 | 351: 'hartebeest', 353 | 352: 'impala, Aepyceros melampus', 354 | 353: 'gazelle', 355 | 354: 'Arabian camel, dromedary, Camelus dromedarius', 356 | 355: 'llama', 357 | 356: 'weasel', 358 | 357: 'mink', 359 | 358: 'polecat, fitch, foulmart, foumart, Mustela putorius', 360 | 359: 'black-footed ferret, ferret, Mustela nigripes', 361 | 360: 'otter', 362 | 361: 'skunk, polecat, wood pussy', 363 | 362: 'badger', 364 | 363: 'armadillo', 365 | 364: 'three-toed sloth, ai, Bradypus tridactylus', 366 | 365: 'orangutan, orang, orangutang, Pongo pygmaeus', 367 | 366: 'gorilla, Gorilla gorilla', 368 | 367: 'chimpanzee, chimp, Pan troglodytes', 369 | 368: 'gibbon, Hylobates lar', 370 | 369: 'siamang, Hylobates syndactylus, Symphalangus syndactylus', 371 | 370: 'guenon, guenon monkey', 372 | 371: 'patas, hussar monkey, Erythrocebus patas', 373 | 372: 'baboon', 374 | 373: 'macaque', 375 | 374: 'langur', 376 | 375: 'colobus, colobus monkey', 377 | 376: 'proboscis monkey, Nasalis larvatus', 378 | 377: 'marmoset', 379 | 378: 'capuchin, ringtail, Cebus capucinus', 380 | 379: 'howler monkey, howler', 381 | 380: 'titi, titi monkey', 382 | 381: 'spider monkey, Ateles geoffroyi', 383 | 382: 'squirrel monkey, Saimiri sciureus', 384 | 383: 'Madagascar cat, ring-tailed lemur, Lemur catta', 385 | 384: 'indri, indris, Indri indri, Indri brevicaudatus', 386 | 385: 'Indian elephant, Elephas maximus', 387 | 386: 'African elephant, Loxodonta africana', 388 | 387: 'lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens', 389 | 388: 'giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca', 390 | 389: 'barracouta, snoek', 391 | 390: 'eel', 392 | 391: 'coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch', 393 | 392: 'rock beauty, Holocanthus tricolor', 394 | 393: 'anemone fish', 395 | 394: 'sturgeon', 396 | 395: 'gar, garfish, garpike, billfish, Lepisosteus osseus', 397 | 396: 'lionfish', 398 | 397: 'puffer, pufferfish, blowfish, globefish', 399 | 398: 'abacus', 400 | 399: 'abaya', 401 | 400: "academic gown, academic robe, judge's robe", 402 | 401: 'accordion, piano accordion, squeeze box', 403 | 402: 'acoustic guitar', 404 | 403: 'aircraft carrier, carrier, flattop, attack aircraft carrier', 405 | 404: 'airliner', 406 | 405: 'airship, dirigible', 407 | 406: 'altar', 408 | 407: 'ambulance', 409 | 408: 'amphibian, amphibious vehicle', 410 | 409: 'analog clock', 411 | 410: 'apiary, bee house', 412 | 411: 'apron', 413 | 412: 'ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin', 414 | 413: 'assault rifle, assault gun', 415 | 414: 'backpack, back pack, knapsack, packsack, rucksack, haversack', 416 | 415: 'bakery, bakeshop, bakehouse', 417 | 416: 'balance beam, beam', 418 | 417: 'balloon', 419 | 418: 'ballpoint, ballpoint pen, ballpen, Biro', 420 | 419: 'Band Aid', 421 | 420: 'banjo', 422 | 421: 'bannister, banister, balustrade, balusters, handrail', 423 | 422: 'barbell', 424 | 423: 'barber chair', 425 | 424: 'barbershop', 426 | 425: 'barn', 427 | 426: 'barometer', 428 | 427: 'barrel, cask', 429 | 428: 'barrow, garden cart, lawn cart, wheelbarrow', 430 | 429: 'baseball', 431 | 430: 'basketball', 432 | 431: 'bassinet', 433 | 432: 'bassoon', 434 | 433: 'bathing cap, swimming cap', 435 | 434: 'bath towel', 436 | 435: 'bathtub, bathing tub, bath, tub', 437 | 436: 'beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon', 438 | 437: 'beacon, lighthouse, beacon light, pharos', 439 | 438: 'beaker', 440 | 439: 'bearskin, busby, shako', 441 | 440: 'beer bottle', 442 | 441: 'beer glass', 443 | 442: 'bell cote, bell cot', 444 | 443: 'bib', 445 | 444: 'bicycle-built-for-two, tandem bicycle, tandem', 446 | 445: 'bikini, two-piece', 447 | 446: 'binder, ring-binder', 448 | 447: 'binoculars, field glasses, opera glasses', 449 | 448: 'birdhouse', 450 | 449: 'boathouse', 451 | 450: 'bobsled, bobsleigh, bob', 452 | 451: 'bolo tie, bolo, bola tie, bola', 453 | 452: 'bonnet, poke bonnet', 454 | 453: 'bookcase', 455 | 454: 'bookshop, bookstore, bookstall', 456 | 455: 'bottlecap', 457 | 456: 'bow', 458 | 457: 'bow tie, bow-tie, bowtie', 459 | 458: 'brass, memorial tablet, plaque', 460 | 459: 'brassiere, bra, bandeau', 461 | 460: 'breakwater, groin, groyne, mole, bulwark, seawall, jetty', 462 | 461: 'breastplate, aegis, egis', 463 | 462: 'broom', 464 | 463: 'bucket, pail', 465 | 464: 'buckle', 466 | 465: 'bulletproof vest', 467 | 466: 'bullet train, bullet', 468 | 467: 'butcher shop, meat market', 469 | 468: 'cab, hack, taxi, taxicab', 470 | 469: 'caldron, cauldron', 471 | 470: 'candle, taper, wax light', 472 | 471: 'cannon', 473 | 472: 'canoe', 474 | 473: 'can opener, tin opener', 475 | 474: 'cardigan', 476 | 475: 'car mirror', 477 | 476: 'carousel, carrousel, merry-go-round, roundabout, whirligig', 478 | 477: "carpenter's kit, tool kit", 479 | 478: 'carton', 480 | 479: 'car wheel', 481 | 480: 'cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM', 482 | 481: 'cassette', 483 | 482: 'cassette player', 484 | 483: 'castle', 485 | 484: 'catamaran', 486 | 485: 'CD player', 487 | 486: 'cello, violoncello', 488 | 487: 'cellular telephone, cellular phone, cellphone, cell, mobile phone', 489 | 488: 'chain', 490 | 489: 'chainlink fence', 491 | 490: 'chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour', 492 | 491: 'chain saw, chainsaw', 493 | 492: 'chest', 494 | 493: 'chiffonier, commode', 495 | 494: 'chime, bell, gong', 496 | 495: 'china cabinet, china closet', 497 | 496: 'Christmas stocking', 498 | 497: 'church, church building', 499 | 498: 'cinema, movie theater, movie theatre, movie house, picture palace', 500 | 499: 'cleaver, meat cleaver, chopper', 501 | 500: 'cliff dwelling', 502 | 501: 'cloak', 503 | 502: 'clog, geta, patten, sabot', 504 | 503: 'cocktail shaker', 505 | 504: 'coffee mug', 506 | 505: 'coffeepot', 507 | 506: 'coil, spiral, volute, whorl, helix', 508 | 507: 'combination lock', 509 | 508: 'computer keyboard, keypad', 510 | 509: 'confectionery, confectionary, candy store', 511 | 510: 'container ship, containership, container vessel', 512 | 511: 'convertible', 513 | 512: 'corkscrew, bottle screw', 514 | 513: 'cornet, horn, trumpet, trump', 515 | 514: 'cowboy boot', 516 | 515: 'cowboy hat, ten-gallon hat', 517 | 516: 'cradle', 518 | 517: 'crane', 519 | 518: 'crash helmet', 520 | 519: 'crate', 521 | 520: 'crib, cot', 522 | 521: 'Crock Pot', 523 | 522: 'croquet ball', 524 | 523: 'crutch', 525 | 524: 'cuirass', 526 | 525: 'dam, dike, dyke', 527 | 526: 'desk', 528 | 527: 'desktop computer', 529 | 528: 'dial telephone, dial phone', 530 | 529: 'diaper, nappy, napkin', 531 | 530: 'digital clock', 532 | 531: 'digital watch', 533 | 532: 'dining table, board', 534 | 533: 'dishrag, dishcloth', 535 | 534: 'dishwasher, dish washer, dishwashing machine', 536 | 535: 'disk brake, disc brake', 537 | 536: 'dock, dockage, docking facility', 538 | 537: 'dogsled, dog sled, dog sleigh', 539 | 538: 'dome', 540 | 539: 'doormat, welcome mat', 541 | 540: 'drilling platform, offshore rig', 542 | 541: 'drum, membranophone, tympan', 543 | 542: 'drumstick', 544 | 543: 'dumbbell', 545 | 544: 'Dutch oven', 546 | 545: 'electric fan, blower', 547 | 546: 'electric guitar', 548 | 547: 'electric locomotive', 549 | 548: 'entertainment center', 550 | 549: 'envelope', 551 | 550: 'espresso maker', 552 | 551: 'face powder', 553 | 552: 'feather boa, boa', 554 | 553: 'file, file cabinet, filing cabinet', 555 | 554: 'fireboat', 556 | 555: 'fire engine, fire truck', 557 | 556: 'fire screen, fireguard', 558 | 557: 'flagpole, flagstaff', 559 | 558: 'flute, transverse flute', 560 | 559: 'folding chair', 561 | 560: 'football helmet', 562 | 561: 'forklift', 563 | 562: 'fountain', 564 | 563: 'fountain pen', 565 | 564: 'four-poster', 566 | 565: 'freight car', 567 | 566: 'French horn, horn', 568 | 567: 'frying pan, frypan, skillet', 569 | 568: 'fur coat', 570 | 569: 'garbage truck, dustcart', 571 | 570: 'gasmask, respirator, gas helmet', 572 | 571: 'gas pump, gasoline pump, petrol pump, island dispenser', 573 | 572: 'goblet', 574 | 573: 'go-kart', 575 | 574: 'golf ball', 576 | 575: 'golfcart, golf cart', 577 | 576: 'gondola', 578 | 577: 'gong, tam-tam', 579 | 578: 'gown', 580 | 579: 'grand piano, grand', 581 | 580: 'greenhouse, nursery, glasshouse', 582 | 581: 'grille, radiator grille', 583 | 582: 'grocery store, grocery, food market, market', 584 | 583: 'guillotine', 585 | 584: 'hair slide', 586 | 585: 'hair spray', 587 | 586: 'half track', 588 | 587: 'hammer', 589 | 588: 'hamper', 590 | 589: 'hand blower, blow dryer, blow drier, hair dryer, hair drier', 591 | 590: 'hand-held computer, hand-held microcomputer', 592 | 591: 'handkerchief, hankie, hanky, hankey', 593 | 592: 'hard disc, hard disk, fixed disk', 594 | 593: 'harmonica, mouth organ, harp, mouth harp', 595 | 594: 'harp', 596 | 595: 'harvester, reaper', 597 | 596: 'hatchet', 598 | 597: 'holster', 599 | 598: 'home theater, home theatre', 600 | 599: 'honeycomb', 601 | 600: 'hook, claw', 602 | 601: 'hoopskirt, crinoline', 603 | 602: 'horizontal bar, high bar', 604 | 603: 'horse cart, horse-cart', 605 | 604: 'hourglass', 606 | 605: 'iPod', 607 | 606: 'iron, smoothing iron', 608 | 607: "jack-o'-lantern", 609 | 608: 'jean, blue jean, denim', 610 | 609: 'jeep, landrover', 611 | 610: 'jersey, T-shirt, tee shirt', 612 | 611: 'jigsaw puzzle', 613 | 612: 'jinrikisha, ricksha, rickshaw', 614 | 613: 'joystick', 615 | 614: 'kimono', 616 | 615: 'knee pad', 617 | 616: 'knot', 618 | 617: 'lab coat, laboratory coat', 619 | 618: 'ladle', 620 | 619: 'lampshade, lamp shade', 621 | 620: 'laptop, laptop computer', 622 | 621: 'lawn mower, mower', 623 | 622: 'lens cap, lens cover', 624 | 623: 'letter opener, paper knife, paperknife', 625 | 624: 'library', 626 | 625: 'lifeboat', 627 | 626: 'lighter, light, igniter, ignitor', 628 | 627: 'limousine, limo', 629 | 628: 'liner, ocean liner', 630 | 629: 'lipstick, lip rouge', 631 | 630: 'Loafer', 632 | 631: 'lotion', 633 | 632: 'loudspeaker, speaker, speaker unit, loudspeaker system, speaker system', 634 | 633: "loupe, jeweler's loupe", 635 | 634: 'lumbermill, sawmill', 636 | 635: 'magnetic compass', 637 | 636: 'mailbag, postbag', 638 | 637: 'mailbox, letter box', 639 | 638: 'maillot', 640 | 639: 'maillot, tank suit', 641 | 640: 'manhole cover', 642 | 641: 'maraca', 643 | 642: 'marimba, xylophone', 644 | 643: 'mask', 645 | 644: 'matchstick', 646 | 645: 'maypole', 647 | 646: 'maze, labyrinth', 648 | 647: 'measuring cup', 649 | 648: 'medicine chest, medicine cabinet', 650 | 649: 'megalith, megalithic structure', 651 | 650: 'microphone, mike', 652 | 651: 'microwave, microwave oven', 653 | 652: 'military uniform', 654 | 653: 'milk can', 655 | 654: 'minibus', 656 | 655: 'miniskirt, mini', 657 | 656: 'minivan', 658 | 657: 'missile', 659 | 658: 'mitten', 660 | 659: 'mixing bowl', 661 | 660: 'mobile home, manufactured home', 662 | 661: 'Model T', 663 | 662: 'modem', 664 | 663: 'monastery', 665 | 664: 'monitor', 666 | 665: 'moped', 667 | 666: 'mortar', 668 | 667: 'mortarboard', 669 | 668: 'mosque', 670 | 669: 'mosquito net', 671 | 670: 'motor scooter, scooter', 672 | 671: 'mountain bike, all-terrain bike, off-roader', 673 | 672: 'mountain tent', 674 | 673: 'mouse, computer mouse', 675 | 674: 'mousetrap', 676 | 675: 'moving van', 677 | 676: 'muzzle', 678 | 677: 'nail', 679 | 678: 'neck brace', 680 | 679: 'necklace', 681 | 680: 'nipple', 682 | 681: 'notebook, notebook computer', 683 | 682: 'obelisk', 684 | 683: 'oboe, hautboy, hautbois', 685 | 684: 'ocarina, sweet potato', 686 | 685: 'odometer, hodometer, mileometer, milometer', 687 | 686: 'oil filter', 688 | 687: 'organ, pipe organ', 689 | 688: 'oscilloscope, scope, cathode-ray oscilloscope, CRO', 690 | 689: 'overskirt', 691 | 690: 'oxcart', 692 | 691: 'oxygen mask', 693 | 692: 'packet', 694 | 693: 'paddle, boat paddle', 695 | 694: 'paddlewheel, paddle wheel', 696 | 695: 'padlock', 697 | 696: 'paintbrush', 698 | 697: "pajama, pyjama, pj's, jammies", 699 | 698: 'palace', 700 | 699: 'panpipe, pandean pipe, syrinx', 701 | 700: 'paper towel', 702 | 701: 'parachute, chute', 703 | 702: 'parallel bars, bars', 704 | 703: 'park bench', 705 | 704: 'parking meter', 706 | 705: 'passenger car, coach, carriage', 707 | 706: 'patio, terrace', 708 | 707: 'pay-phone, pay-station', 709 | 708: 'pedestal, plinth, footstall', 710 | 709: 'pencil box, pencil case', 711 | 710: 'pencil sharpener', 712 | 711: 'perfume, essence', 713 | 712: 'Petri dish', 714 | 713: 'photocopier', 715 | 714: 'pick, plectrum, plectron', 716 | 715: 'pickelhaube', 717 | 716: 'picket fence, paling', 718 | 717: 'pickup, pickup truck', 719 | 718: 'pier', 720 | 719: 'piggy bank, penny bank', 721 | 720: 'pill bottle', 722 | 721: 'pillow', 723 | 722: 'ping-pong ball', 724 | 723: 'pinwheel', 725 | 724: 'pirate, pirate ship', 726 | 725: 'pitcher, ewer', 727 | 726: "plane, carpenter's plane, woodworking plane", 728 | 727: 'planetarium', 729 | 728: 'plastic bag', 730 | 729: 'plate rack', 731 | 730: 'plow, plough', 732 | 731: "plunger, plumber's helper", 733 | 732: 'Polaroid camera, Polaroid Land camera', 734 | 733: 'pole', 735 | 734: 'police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria', 736 | 735: 'poncho', 737 | 736: 'pool table, billiard table, snooker table', 738 | 737: 'pop bottle, soda bottle', 739 | 738: 'pot, flowerpot', 740 | 739: "potter's wheel", 741 | 740: 'power drill', 742 | 741: 'prayer rug, prayer mat', 743 | 742: 'printer', 744 | 743: 'prison, prison house', 745 | 744: 'projectile, missile', 746 | 745: 'projector', 747 | 746: 'puck, hockey puck', 748 | 747: 'punching bag, punch bag, punching ball, punchball', 749 | 748: 'purse', 750 | 749: 'quill, quill pen', 751 | 750: 'quilt, comforter, comfort, puff', 752 | 751: 'racer, race car, racing car', 753 | 752: 'racket, racquet', 754 | 753: 'radiator', 755 | 754: 'radio, wireless', 756 | 755: 'radio telescope, radio reflector', 757 | 756: 'rain barrel', 758 | 757: 'recreational vehicle, RV, R.V.', 759 | 758: 'reel', 760 | 759: 'reflex camera', 761 | 760: 'refrigerator, icebox', 762 | 761: 'remote control, remote', 763 | 762: 'restaurant, eating house, eating place, eatery', 764 | 763: 'revolver, six-gun, six-shooter', 765 | 764: 'rifle', 766 | 765: 'rocking chair, rocker', 767 | 766: 'rotisserie', 768 | 767: 'rubber eraser, rubber, pencil eraser', 769 | 768: 'rugby ball', 770 | 769: 'rule, ruler', 771 | 770: 'running shoe', 772 | 771: 'safe', 773 | 772: 'safety pin', 774 | 773: 'saltshaker, salt shaker', 775 | 774: 'sandal', 776 | 775: 'sarong', 777 | 776: 'sax, saxophone', 778 | 777: 'scabbard', 779 | 778: 'scale, weighing machine', 780 | 779: 'school bus', 781 | 780: 'schooner', 782 | 781: 'scoreboard', 783 | 782: 'screen, CRT screen', 784 | 783: 'screw', 785 | 784: 'screwdriver', 786 | 785: 'seat belt, seatbelt', 787 | 786: 'sewing machine', 788 | 787: 'shield, buckler', 789 | 788: 'shoe shop, shoe-shop, shoe store', 790 | 789: 'shoji', 791 | 790: 'shopping basket', 792 | 791: 'shopping cart', 793 | 792: 'shovel', 794 | 793: 'shower cap', 795 | 794: 'shower curtain', 796 | 795: 'ski', 797 | 796: 'ski mask', 798 | 797: 'sleeping bag', 799 | 798: 'slide rule, slipstick', 800 | 799: 'sliding door', 801 | 800: 'slot, one-armed bandit', 802 | 801: 'snorkel', 803 | 802: 'snowmobile', 804 | 803: 'snowplow, snowplough', 805 | 804: 'soap dispenser', 806 | 805: 'soccer ball', 807 | 806: 'sock', 808 | 807: 'solar dish, solar collector, solar furnace', 809 | 808: 'sombrero', 810 | 809: 'soup bowl', 811 | 810: 'space bar', 812 | 811: 'space heater', 813 | 812: 'space shuttle', 814 | 813: 'spatula', 815 | 814: 'speedboat', 816 | 815: "spider web, spider's web", 817 | 816: 'spindle', 818 | 817: 'sports car, sport car', 819 | 818: 'spotlight, spot', 820 | 819: 'stage', 821 | 820: 'steam locomotive', 822 | 821: 'steel arch bridge', 823 | 822: 'steel drum', 824 | 823: 'stethoscope', 825 | 824: 'stole', 826 | 825: 'stone wall', 827 | 826: 'stopwatch, stop watch', 828 | 827: 'stove', 829 | 828: 'strainer', 830 | 829: 'streetcar, tram, tramcar, trolley, trolley car', 831 | 830: 'stretcher', 832 | 831: 'studio couch, day bed', 833 | 832: 'stupa, tope', 834 | 833: 'submarine, pigboat, sub, U-boat', 835 | 834: 'suit, suit of clothes', 836 | 835: 'sundial', 837 | 836: 'sunglass', 838 | 837: 'sunglasses, dark glasses, shades', 839 | 838: 'sunscreen, sunblock, sun blocker', 840 | 839: 'suspension bridge', 841 | 840: 'swab, swob, mop', 842 | 841: 'sweatshirt', 843 | 842: 'swimming trunks, bathing trunks', 844 | 843: 'swing', 845 | 844: 'switch, electric switch, electrical switch', 846 | 845: 'syringe', 847 | 846: 'table lamp', 848 | 847: 'tank, army tank, armored combat vehicle, armoured combat vehicle', 849 | 848: 'tape player', 850 | 849: 'teapot', 851 | 850: 'teddy, teddy bear', 852 | 851: 'television, television system', 853 | 852: 'tennis ball', 854 | 853: 'thatch, thatched roof', 855 | 854: 'theater curtain, theatre curtain', 856 | 855: 'thimble', 857 | 856: 'thresher, thrasher, threshing machine', 858 | 857: 'throne', 859 | 858: 'tile roof', 860 | 859: 'toaster', 861 | 860: 'tobacco shop, tobacconist shop, tobacconist', 862 | 861: 'toilet seat', 863 | 862: 'torch', 864 | 863: 'totem pole', 865 | 864: 'tow truck, tow car, wrecker', 866 | 865: 'toyshop', 867 | 866: 'tractor', 868 | 867: 'trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi', 869 | 868: 'tray', 870 | 869: 'trench coat', 871 | 870: 'tricycle, trike, velocipede', 872 | 871: 'trimaran', 873 | 872: 'tripod', 874 | 873: 'triumphal arch', 875 | 874: 'trolleybus, trolley coach, trackless trolley', 876 | 875: 'trombone', 877 | 876: 'tub, vat', 878 | 877: 'turnstile', 879 | 878: 'typewriter keyboard', 880 | 879: 'umbrella', 881 | 880: 'unicycle, monocycle', 882 | 881: 'upright, upright piano', 883 | 882: 'vacuum, vacuum cleaner', 884 | 883: 'vase', 885 | 884: 'vault', 886 | 885: 'velvet', 887 | 886: 'vending machine', 888 | 887: 'vestment', 889 | 888: 'viaduct', 890 | 889: 'violin, fiddle', 891 | 890: 'volleyball', 892 | 891: 'waffle iron', 893 | 892: 'wall clock', 894 | 893: 'wallet, billfold, notecase, pocketbook', 895 | 894: 'wardrobe, closet, press', 896 | 895: 'warplane, military plane', 897 | 896: 'washbasin, handbasin, washbowl, lavabo, wash-hand basin', 898 | 897: 'washer, automatic washer, washing machine', 899 | 898: 'water bottle', 900 | 899: 'water jug', 901 | 900: 'water tower', 902 | 901: 'whiskey jug', 903 | 902: 'whistle', 904 | 903: 'wig', 905 | 904: 'window screen', 906 | 905: 'window shade', 907 | 906: 'Windsor tie', 908 | 907: 'wine bottle', 909 | 908: 'wing', 910 | 909: 'wok', 911 | 910: 'wooden spoon', 912 | 911: 'wool, woolen, woollen', 913 | 912: 'worm fence, snake fence, snake-rail fence, Virginia fence', 914 | 913: 'wreck', 915 | 914: 'yawl', 916 | 915: 'yurt', 917 | 916: 'web site, website, internet site, site', 918 | 917: 'comic book', 919 | 918: 'crossword puzzle, crossword', 920 | 919: 'street sign', 921 | 920: 'traffic light, traffic signal, stoplight', 922 | 921: 'book jacket, dust cover, dust jacket, dust wrapper', 923 | 922: 'menu', 924 | 923: 'plate', 925 | 924: 'guacamole', 926 | 925: 'consomme', 927 | 926: 'hot pot, hotpot', 928 | 927: 'trifle', 929 | 928: 'ice cream, icecream', 930 | 929: 'ice lolly, lolly, lollipop, popsicle', 931 | 930: 'French loaf', 932 | 931: 'bagel, beigel', 933 | 932: 'pretzel', 934 | 933: 'cheeseburger', 935 | 934: 'hotdog, hot dog, red hot', 936 | 935: 'mashed potato', 937 | 936: 'head cabbage', 938 | 937: 'broccoli', 939 | 938: 'cauliflower', 940 | 939: 'zucchini, courgette', 941 | 940: 'spaghetti squash', 942 | 941: 'acorn squash', 943 | 942: 'butternut squash', 944 | 943: 'cucumber, cuke', 945 | 944: 'artichoke, globe artichoke', 946 | 945: 'bell pepper', 947 | 946: 'cardoon', 948 | 947: 'mushroom', 949 | 948: 'Granny Smith', 950 | 949: 'strawberry', 951 | 950: 'orange', 952 | 951: 'lemon', 953 | 952: 'fig', 954 | 953: 'pineapple, ananas', 955 | 954: 'banana', 956 | 955: 'jackfruit, jak, jack', 957 | 956: 'custard apple', 958 | 957: 'pomegranate', 959 | 958: 'hay', 960 | 959: 'carbonara', 961 | 960: 'chocolate sauce, chocolate syrup', 962 | 961: 'dough', 963 | 962: 'meat loaf, meatloaf', 964 | 963: 'pizza, pizza pie', 965 | 964: 'potpie', 966 | 965: 'burrito', 967 | 966: 'red wine', 968 | 967: 'espresso', 969 | 968: 'cup', 970 | 969: 'eggnog', 971 | 970: 'alp', 972 | 971: 'bubble', 973 | 972: 'cliff, drop, drop-off', 974 | 973: 'coral reef', 975 | 974: 'geyser', 976 | 975: 'lakeside, lakeshore', 977 | 976: 'promontory, headland, head, foreland', 978 | 977: 'sandbar, sand bar', 979 | 978: 'seashore, coast, seacoast, sea-coast', 980 | 979: 'valley, vale', 981 | 980: 'volcano', 982 | 981: 'ballplayer, baseball player', 983 | 982: 'groom, bridegroom', 984 | 983: 'scuba diver', 985 | 984: 'rapeseed', 986 | 985: 'daisy', 987 | 986: "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum", 988 | 987: 'corn', 989 | 988: 'acorn', 990 | 989: 'hip, rose hip, rosehip', 991 | 990: 'buckeye, horse chestnut, conker', 992 | 991: 'coral fungus', 993 | 992: 'agaric', 994 | 993: 'gyromitra', 995 | 994: 'stinkhorn, carrion fungus', 996 | 995: 'earthstar', 997 | 996: 'hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa', 998 | 997: 'bolete', 999 | 998: 'ear, spike, capitulum', 1000 | 999: 'toilet tissue, toilet paper, bathroom tissue'} 1001 | -------------------------------------------------------------------------------- /Section4-Tensorflow_image_classifier/label_image.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | 4 | 5 | def load_graph(model_file): 6 | graph = tf.Graph() 7 | graph_def = tf.GraphDef() 8 | 9 | with open(model_file, "rb") as f: 10 | graph_def.ParseFromString(f.read()) 11 | with graph.as_default(): 12 | tf.import_graph_def(graph_def) 13 | 14 | return graph 15 | 16 | 17 | def read_tensor_from_image_file(file_name, 18 | input_height=299, 19 | input_width=299, 20 | input_mean=0, 21 | input_std=255): 22 | input_name = "file_reader" 23 | output_name = "normalized" 24 | file_reader = tf.read_file(file_name, input_name) 25 | if file_name.endswith(".png"): 26 | image_reader = tf.image.decode_png( 27 | file_reader, channels=3, name="png_reader") 28 | elif file_name.endswith(".gif"): 29 | image_reader = tf.squeeze( 30 | tf.image.decode_gif(file_reader, name="gif_reader")) 31 | elif file_name.endswith(".bmp"): 32 | image_reader = tf.image.decode_bmp(file_reader, name="bmp_reader") 33 | else: 34 | image_reader = tf.image.decode_jpeg( 35 | file_reader, channels=3, name="jpeg_reader") 36 | float_caster = tf.cast(image_reader, tf.float32) 37 | dims_expander = tf.expand_dims(float_caster, 0) 38 | resized = tf.image.resize_bilinear(dims_expander, [input_height, input_width]) 39 | normalized = tf.divide(tf.subtract(resized, [input_mean]), [input_std]) 40 | sess = tf.Session() 41 | result = sess.run(normalized) 42 | 43 | return result 44 | 45 | 46 | def load_labels(label_file): 47 | label = [] 48 | proto_as_ascii_lines = tf.gfile.GFile(label_file).readlines() 49 | for l in proto_as_ascii_lines: 50 | label.append(l.rstrip()) 51 | return label 52 | 53 | 54 | def label_image(file_name=None): 55 | if not file_name: 56 | file_name = "test/mylittlepony2.jpg" 57 | model_file = "./output_graph.pb" 58 | label_file = "./output_labels.txt" 59 | input_height = 299 60 | input_width = 299 61 | input_mean = 0 62 | input_std = 255 63 | input_layer = "Placeholder" 64 | output_layer = "final_result" 65 | 66 | 67 | graph = load_graph(model_file) 68 | t = read_tensor_from_image_file( 69 | file_name, 70 | input_height=input_height, 71 | input_width=input_width, 72 | input_mean=input_mean, 73 | input_std=input_std) 74 | 75 | input_name = "import/" + input_layer 76 | output_name = "import/" + output_layer 77 | input_operation = graph.get_operation_by_name(input_name) 78 | output_operation = graph.get_operation_by_name(output_name) 79 | 80 | with tf.Session(graph=graph) as sess: 81 | results = sess.run(output_operation.outputs[0], { 82 | input_operation.outputs[0]: t 83 | }) 84 | results = np.squeeze(results) 85 | 86 | top_k = results.argsort()[-5:][::-1] 87 | labels = load_labels(label_file) 88 | for i in top_k: 89 | print(labels[i], results[i]) 90 | 91 | #uncomment line below to run this script as stand-alone 92 | #label_image() 93 | -------------------------------------------------------------------------------- /Section4-Tensorflow_image_classifier/output_labels.txt: -------------------------------------------------------------------------------- 1 | barbie 2 | gi joe 3 | my little pony 4 | transformers 5 | -------------------------------------------------------------------------------- /Section4-Tensorflow_image_classifier/retrain.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import collections 3 | from datetime import datetime 4 | import hashlib 5 | import os.path 6 | import random 7 | import re 8 | import sys 9 | 10 | import numpy as np 11 | import tensorflow as tf 12 | import tensorflow_hub as hub 13 | 14 | # FLAGS = None 15 | class emptyob: 16 | pass 17 | FLAGS=emptyob() 18 | # FLAGS.image_dir='flower_photos' 19 | FLAGS.image_dir='toy_images' 20 | FLAGS.output_graph='./output_graph.pb' 21 | FLAGS.intermediate_output_graphs_dir='./intermediate_graph/' 22 | FLAGS.intermediate_store_frequency=0 23 | FLAGS.output_labels='./output_labels.txt' 24 | FLAGS.summaries_dir='./retrain_logs' 25 | FLAGS.how_many_training_steps=4000 26 | FLAGS.learning_rate=0.01 27 | FLAGS.testing_percentage=10 28 | FLAGS.validation_percentage=10 29 | FLAGS.eval_step_interval=10 30 | FLAGS.train_batch_size=100 31 | FLAGS.test_batch_size=-1 32 | FLAGS.validation_batch_size=100 33 | FLAGS.print_misclassified_test_images=False 34 | FLAGS.bottleneck_dir='./bottleneck' 35 | FLAGS.final_tensor_name='final_result' 36 | FLAGS.flip_left_right=False 37 | FLAGS.random_crop=0 38 | FLAGS.random_scale=0 39 | FLAGS.random_brightness=0 40 | FLAGS.tfhub_module='https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1' 41 | FLAGS.saved_model_dir='' 42 | 43 | MAX_NUM_IMAGES_PER_CLASS = 2 ** 27 - 1 # ~134M 44 | 45 | # The location where variable checkpoints will be stored. 46 | CHECKPOINT_NAME = './_retrain_checkpoint' 47 | 48 | # A module is understood as instrumented for quantization with TF-Lite 49 | # if it contains any of these ops. 50 | FAKE_QUANT_OPS = ('FakeQuantWithMinMaxVars', 51 | 'FakeQuantWithMinMaxVarsPerChannel') 52 | 53 | 54 | def create_image_lists(image_dir, testing_percentage, validation_percentage): 55 | """Builds a list of training images from the file system. 56 | Analyzes the sub folders in the image directory, splits them into stable 57 | training, testing, and validation sets, and returns a data structure 58 | describing the lists of images for each label and their paths. 59 | Args: 60 | image_dir: String path to a folder containing subfolders of images. 61 | testing_percentage: Integer percentage of the images to reserve for tests. 62 | validation_percentage: Integer percentage of images reserved for validation. 63 | Returns: 64 | An OrderedDict containing an entry for each label subfolder, with images 65 | split into training, testing, and validation sets within each label. 66 | The order of items defines the class indices. 67 | """ 68 | if not tf.gfile.Exists(image_dir): 69 | tf.logging.error("Image directory '" + image_dir + "' not found.") 70 | return None 71 | result = collections.OrderedDict() 72 | sub_dirs = sorted(x[0] for x in tf.gfile.Walk(image_dir)) 73 | # The root directory comes first, so skip it. 74 | is_root_dir = True 75 | for sub_dir in sub_dirs: 76 | if is_root_dir: 77 | is_root_dir = False 78 | continue 79 | extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] 80 | file_list = [] 81 | dir_name = os.path.basename(sub_dir) 82 | if dir_name == image_dir: 83 | continue 84 | tf.logging.info("Looking for images in '" + dir_name + "'") 85 | for extension in extensions: 86 | file_glob = os.path.join(image_dir, dir_name, '*.' + extension) 87 | file_list.extend(tf.gfile.Glob(file_glob)) 88 | if not file_list: 89 | tf.logging.warning('No files found') 90 | continue 91 | if len(file_list) < 20: 92 | tf.logging.warning( 93 | 'WARNING: Folder has less than 20 images, which may cause issues.') 94 | elif len(file_list) > MAX_NUM_IMAGES_PER_CLASS: 95 | tf.logging.warning( 96 | 'WARNING: Folder {} has more than {} images. Some images will ' 97 | 'never be selected.'.format(dir_name, MAX_NUM_IMAGES_PER_CLASS)) 98 | label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower()) 99 | training_images = [] 100 | testing_images = [] 101 | validation_images = [] 102 | for file_name in file_list: 103 | base_name = os.path.basename(file_name) 104 | # We want to ignore anything after '_nohash_' in the file name when 105 | # deciding which set to put an image in, the data set creator has a way of 106 | # grouping photos that are close variations of each other. For example 107 | # this is used in the plant disease data set to group multiple pictures of 108 | # the same leaf. 109 | hash_name = re.sub(r'_nohash_.*$', '', file_name) 110 | # This looks a bit magical, but we need to decide whether this file should 111 | # go into the training, testing, or validation sets, and we want to keep 112 | # existing files in the same set even if more files are subsequently 113 | # added. 114 | # To do that, we need a stable way of deciding based on just the file name 115 | # itself, so we do a hash of that and then use that to generate a 116 | # probability value that we use to assign it. 117 | hash_name_hashed = hashlib.sha1(tf.compat.as_bytes(hash_name)).hexdigest() 118 | percentage_hash = ((int(hash_name_hashed, 16) % 119 | (MAX_NUM_IMAGES_PER_CLASS + 1)) * 120 | (100.0 / MAX_NUM_IMAGES_PER_CLASS)) 121 | if percentage_hash < validation_percentage: 122 | validation_images.append(base_name) 123 | elif percentage_hash < (testing_percentage + validation_percentage): 124 | testing_images.append(base_name) 125 | else: 126 | training_images.append(base_name) 127 | result[label_name] = { 128 | 'dir': dir_name, 129 | 'training': training_images, 130 | 'testing': testing_images, 131 | 'validation': validation_images, 132 | } 133 | return result 134 | 135 | 136 | def get_image_path(image_lists, label_name, index, image_dir, category): 137 | """Returns a path to an image for a label at the given index. 138 | Args: 139 | image_lists: OrderedDict of training images for each label. 140 | label_name: Label string we want to get an image for. 141 | index: Int offset of the image we want. This will be moduloed by the 142 | available number of images for the label, so it can be arbitrarily large. 143 | image_dir: Root folder string of the subfolders containing the training 144 | images. 145 | category: Name string of set to pull images from - training, testing, or 146 | validation. 147 | Returns: 148 | File system path string to an image that meets the requested parameters. 149 | """ 150 | if label_name not in image_lists: 151 | tf.logging.fatal('Label does not exist %s.', label_name) 152 | label_lists = image_lists[label_name] 153 | if category not in label_lists: 154 | tf.logging.fatal('Category does not exist %s.', category) 155 | category_list = label_lists[category] 156 | if not category_list: 157 | tf.logging.fatal('Label %s has no images in the category %s.', 158 | label_name, category) 159 | mod_index = index % len(category_list) 160 | base_name = category_list[mod_index] 161 | sub_dir = label_lists['dir'] 162 | full_path = os.path.join(image_dir, sub_dir, base_name) 163 | return full_path 164 | 165 | 166 | def get_bottleneck_path(image_lists, label_name, index, bottleneck_dir, 167 | category, module_name): 168 | """Returns a path to a bottleneck file for a label at the given index. 169 | Args: 170 | image_lists: OrderedDict of training images for each label. 171 | label_name: Label string we want to get an image for. 172 | index: Integer offset of the image we want. This will be moduloed by the 173 | available number of images for the label, so it can be arbitrarily large. 174 | bottleneck_dir: Folder string holding cached files of bottleneck values. 175 | category: Name string of set to pull images from - training, testing, or 176 | validation. 177 | module_name: The name of the image module being used. 178 | Returns: 179 | File system path string to an image that meets the requested parameters. 180 | """ 181 | module_name = (module_name.replace('://', '~') # URL scheme. 182 | .replace('/', '~') # URL and Unix paths. 183 | .replace(':', '~').replace('\\', '~')) # Windows paths. 184 | return get_image_path(image_lists, label_name, index, bottleneck_dir, 185 | category) + '_' + module_name + '.txt' 186 | 187 | 188 | def create_module_graph(module_spec): 189 | """Creates a graph and loads Hub Module into it. 190 | Args: 191 | module_spec: the hub.ModuleSpec for the image module being used. 192 | Returns: 193 | graph: the tf.Graph that was created. 194 | bottleneck_tensor: the bottleneck values output by the module. 195 | resized_input_tensor: the input images, resized as expected by the module. 196 | wants_quantization: a boolean, whether the module has been instrumented 197 | with fake quantization ops. 198 | """ 199 | height, width = hub.get_expected_image_size(module_spec) 200 | with tf.Graph().as_default() as graph: 201 | resized_input_tensor = tf.placeholder(tf.float32, [None, height, width, 3]) 202 | m = hub.Module(module_spec) 203 | bottleneck_tensor = m(resized_input_tensor) 204 | wants_quantization = any(node.op in FAKE_QUANT_OPS 205 | for node in graph.as_graph_def().node) 206 | return graph, bottleneck_tensor, resized_input_tensor, wants_quantization 207 | 208 | 209 | def run_bottleneck_on_image(sess, image_data, image_data_tensor, 210 | decoded_image_tensor, resized_input_tensor, 211 | bottleneck_tensor): 212 | """Runs inference on an image to extract the 'bottleneck' summary layer. 213 | Args: 214 | sess: Current active TensorFlow Session. 215 | image_data: String of raw JPEG data. 216 | image_data_tensor: Input data layer in the graph. 217 | decoded_image_tensor: Output of initial image resizing and preprocessing. 218 | resized_input_tensor: The input node of the recognition graph. 219 | bottleneck_tensor: Layer before the final softmax. 220 | Returns: 221 | Numpy array of bottleneck values. 222 | """ 223 | # First decode the JPEG image, resize it, and rescale the pixel values. 224 | resized_input_values = sess.run(decoded_image_tensor, 225 | {image_data_tensor: image_data}) 226 | # Then run it through the recognition network. 227 | bottleneck_values = sess.run(bottleneck_tensor, 228 | {resized_input_tensor: resized_input_values}) 229 | bottleneck_values = np.squeeze(bottleneck_values) 230 | return bottleneck_values 231 | 232 | 233 | def ensure_dir_exists(dir_name): 234 | """Makes sure the folder exists on disk. 235 | Args: 236 | dir_name: Path string to the folder we want to create. 237 | """ 238 | if not os.path.exists(dir_name): 239 | os.makedirs(dir_name) 240 | 241 | 242 | def create_bottleneck_file(bottleneck_path, image_lists, label_name, index, 243 | image_dir, category, sess, jpeg_data_tensor, 244 | decoded_image_tensor, resized_input_tensor, 245 | bottleneck_tensor): 246 | """Create a single bottleneck file.""" 247 | tf.logging.info('Creating bottleneck at ' + bottleneck_path) 248 | image_path = get_image_path(image_lists, label_name, index, 249 | image_dir, category) 250 | if not tf.gfile.Exists(image_path): 251 | tf.logging.fatal('File does not exist %s', image_path) 252 | image_data = tf.gfile.FastGFile(image_path, 'rb').read() 253 | try: 254 | bottleneck_values = run_bottleneck_on_image( 255 | sess, image_data, jpeg_data_tensor, decoded_image_tensor, 256 | resized_input_tensor, bottleneck_tensor) 257 | except Exception as e: 258 | raise RuntimeError('Error during processing file %s (%s)' % (image_path, 259 | str(e))) 260 | bottleneck_string = ','.join(str(x) for x in bottleneck_values) 261 | with open(bottleneck_path, 'w') as bottleneck_file: 262 | bottleneck_file.write(bottleneck_string) 263 | 264 | 265 | def get_or_create_bottleneck(sess, image_lists, label_name, index, image_dir, 266 | category, bottleneck_dir, jpeg_data_tensor, 267 | decoded_image_tensor, resized_input_tensor, 268 | bottleneck_tensor, module_name): 269 | """Retrieves or calculates bottleneck values for an image. 270 | If a cached version of the bottleneck data exists on-disk, return that, 271 | otherwise calculate the data and save it to disk for future use. 272 | Args: 273 | sess: The current active TensorFlow Session. 274 | image_lists: OrderedDict of training images for each label. 275 | label_name: Label string we want to get an image for. 276 | index: Integer offset of the image we want. This will be modulo-ed by the 277 | available number of images for the label, so it can be arbitrarily large. 278 | image_dir: Root folder string of the subfolders containing the training 279 | images. 280 | category: Name string of which set to pull images from - training, testing, 281 | or validation. 282 | bottleneck_dir: Folder string holding cached files of bottleneck values. 283 | jpeg_data_tensor: The tensor to feed loaded jpeg data into. 284 | decoded_image_tensor: The output of decoding and resizing the image. 285 | resized_input_tensor: The input node of the recognition graph. 286 | bottleneck_tensor: The output tensor for the bottleneck values. 287 | module_name: The name of the image module being used. 288 | Returns: 289 | Numpy array of values produced by the bottleneck layer for the image. 290 | """ 291 | label_lists = image_lists[label_name] 292 | sub_dir = label_lists['dir'] 293 | sub_dir_path = os.path.join(bottleneck_dir, sub_dir) 294 | ensure_dir_exists(sub_dir_path) 295 | bottleneck_path = get_bottleneck_path(image_lists, label_name, index, 296 | bottleneck_dir, category, module_name) 297 | if not os.path.exists(bottleneck_path): 298 | create_bottleneck_file(bottleneck_path, image_lists, label_name, index, 299 | image_dir, category, sess, jpeg_data_tensor, 300 | decoded_image_tensor, resized_input_tensor, 301 | bottleneck_tensor) 302 | with open(bottleneck_path, 'r') as bottleneck_file: 303 | bottleneck_string = bottleneck_file.read() 304 | did_hit_error = False 305 | try: 306 | bottleneck_values = [float(x) for x in bottleneck_string.split(',')] 307 | except ValueError: 308 | tf.logging.warning('Invalid float found, recreating bottleneck') 309 | did_hit_error = True 310 | if did_hit_error: 311 | create_bottleneck_file(bottleneck_path, image_lists, label_name, index, 312 | image_dir, category, sess, jpeg_data_tensor, 313 | decoded_image_tensor, resized_input_tensor, 314 | bottleneck_tensor) 315 | with open(bottleneck_path, 'r') as bottleneck_file: 316 | bottleneck_string = bottleneck_file.read() 317 | # Allow exceptions to propagate here, since they shouldn't happen after a 318 | # fresh creation 319 | bottleneck_values = [float(x) for x in bottleneck_string.split(',')] 320 | return bottleneck_values 321 | 322 | 323 | def cache_bottlenecks(sess, image_lists, image_dir, bottleneck_dir, 324 | jpeg_data_tensor, decoded_image_tensor, 325 | resized_input_tensor, bottleneck_tensor, module_name): 326 | """Ensures all the training, testing, and validation bottlenecks are cached. 327 | Because we're likely to read the same image multiple times (if there are no 328 | distortions applied during training) it can speed things up a lot if we 329 | calculate the bottleneck layer values once for each image during 330 | preprocessing, and then just read those cached values repeatedly during 331 | training. Here we go through all the images we've found, calculate those 332 | values, and save them off. 333 | Args: 334 | sess: The current active TensorFlow Session. 335 | image_lists: OrderedDict of training images for each label. 336 | image_dir: Root folder string of the subfolders containing the training 337 | images. 338 | bottleneck_dir: Folder string holding cached files of bottleneck values. 339 | jpeg_data_tensor: Input tensor for jpeg data from file. 340 | decoded_image_tensor: The output of decoding and resizing the image. 341 | resized_input_tensor: The input node of the recognition graph. 342 | bottleneck_tensor: The penultimate output layer of the graph. 343 | module_name: The name of the image module being used. 344 | Returns: 345 | Nothing. 346 | """ 347 | how_many_bottlenecks = 0 348 | ensure_dir_exists(bottleneck_dir) 349 | for label_name, label_lists in image_lists.items(): 350 | for category in ['training', 'testing', 'validation']: 351 | category_list = label_lists[category] 352 | for index, unused_base_name in enumerate(category_list): 353 | get_or_create_bottleneck( 354 | sess, image_lists, label_name, index, image_dir, category, 355 | bottleneck_dir, jpeg_data_tensor, decoded_image_tensor, 356 | resized_input_tensor, bottleneck_tensor, module_name) 357 | 358 | how_many_bottlenecks += 1 359 | if how_many_bottlenecks % 100 == 0: 360 | tf.logging.info( 361 | str(how_many_bottlenecks) + ' bottleneck files created.') 362 | 363 | 364 | def get_random_cached_bottlenecks(sess, image_lists, how_many, category, 365 | bottleneck_dir, image_dir, jpeg_data_tensor, 366 | decoded_image_tensor, resized_input_tensor, 367 | bottleneck_tensor, module_name): 368 | """Retrieves bottleneck values for cached images. 369 | If no distortions are being applied, this function can retrieve the cached 370 | bottleneck values directly from disk for images. It picks a random set of 371 | images from the specified category. 372 | Args: 373 | sess: Current TensorFlow Session. 374 | image_lists: OrderedDict of training images for each label. 375 | how_many: If positive, a random sample of this size will be chosen. 376 | If negative, all bottlenecks will be retrieved. 377 | category: Name string of which set to pull from - training, testing, or 378 | validation. 379 | bottleneck_dir: Folder string holding cached files of bottleneck values. 380 | image_dir: Root folder string of the subfolders containing the training 381 | images. 382 | jpeg_data_tensor: The layer to feed jpeg image data into. 383 | decoded_image_tensor: The output of decoding and resizing the image. 384 | resized_input_tensor: The input node of the recognition graph. 385 | bottleneck_tensor: The bottleneck output layer of the CNN graph. 386 | module_name: The name of the image module being used. 387 | Returns: 388 | List of bottleneck arrays, their corresponding ground truths, and the 389 | relevant filenames. 390 | """ 391 | class_count = len(image_lists.keys()) 392 | bottlenecks = [] 393 | ground_truths = [] 394 | filenames = [] 395 | if how_many >= 0: 396 | # Retrieve a random sample of bottlenecks. 397 | for unused_i in range(how_many): 398 | label_index = random.randrange(class_count) 399 | label_name = list(image_lists.keys())[label_index] 400 | image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1) 401 | image_name = get_image_path(image_lists, label_name, image_index, 402 | image_dir, category) 403 | bottleneck = get_or_create_bottleneck( 404 | sess, image_lists, label_name, image_index, image_dir, category, 405 | bottleneck_dir, jpeg_data_tensor, decoded_image_tensor, 406 | resized_input_tensor, bottleneck_tensor, module_name) 407 | bottlenecks.append(bottleneck) 408 | ground_truths.append(label_index) 409 | filenames.append(image_name) 410 | else: 411 | # Retrieve all bottlenecks. 412 | for label_index, label_name in enumerate(image_lists.keys()): 413 | for image_index, image_name in enumerate( 414 | image_lists[label_name][category]): 415 | image_name = get_image_path(image_lists, label_name, image_index, 416 | image_dir, category) 417 | bottleneck = get_or_create_bottleneck( 418 | sess, image_lists, label_name, image_index, image_dir, category, 419 | bottleneck_dir, jpeg_data_tensor, decoded_image_tensor, 420 | resized_input_tensor, bottleneck_tensor, module_name) 421 | bottlenecks.append(bottleneck) 422 | ground_truths.append(label_index) 423 | filenames.append(image_name) 424 | return bottlenecks, ground_truths, filenames 425 | 426 | 427 | def get_random_distorted_bottlenecks( 428 | sess, image_lists, how_many, category, image_dir, input_jpeg_tensor, 429 | distorted_image, resized_input_tensor, bottleneck_tensor): 430 | """Retrieves bottleneck values for training images, after distortions. 431 | If we're training with distortions like crops, scales, or flips, we have to 432 | recalculate the full model for every image, and so we can't use cached 433 | bottleneck values. Instead we find random images for the requested category, 434 | run them through the distortion graph, and then the full graph to get the 435 | bottleneck results for each. 436 | Args: 437 | sess: Current TensorFlow Session. 438 | image_lists: OrderedDict of training images for each label. 439 | how_many: The integer number of bottleneck values to return. 440 | category: Name string of which set of images to fetch - training, testing, 441 | or validation. 442 | image_dir: Root folder string of the subfolders containing the training 443 | images. 444 | input_jpeg_tensor: The input layer we feed the image data to. 445 | distorted_image: The output node of the distortion graph. 446 | resized_input_tensor: The input node of the recognition graph. 447 | bottleneck_tensor: The bottleneck output layer of the CNN graph. 448 | Returns: 449 | List of bottleneck arrays and their corresponding ground truths. 450 | """ 451 | class_count = len(image_lists.keys()) 452 | bottlenecks = [] 453 | ground_truths = [] 454 | for unused_i in range(how_many): 455 | label_index = random.randrange(class_count) 456 | label_name = list(image_lists.keys())[label_index] 457 | image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1) 458 | image_path = get_image_path(image_lists, label_name, image_index, image_dir, 459 | category) 460 | if not tf.gfile.Exists(image_path): 461 | tf.logging.fatal('File does not exist %s', image_path) 462 | jpeg_data = tf.gfile.FastGFile(image_path, 'rb').read() 463 | # Note that we materialize the distorted_image_data as a numpy array before 464 | # sending running inference on the image. This involves 2 memory copies and 465 | # might be optimized in other implementations. 466 | distorted_image_data = sess.run(distorted_image, 467 | {input_jpeg_tensor: jpeg_data}) 468 | bottleneck_values = sess.run(bottleneck_tensor, 469 | {resized_input_tensor: distorted_image_data}) 470 | bottleneck_values = np.squeeze(bottleneck_values) 471 | bottlenecks.append(bottleneck_values) 472 | ground_truths.append(label_index) 473 | return bottlenecks, ground_truths 474 | 475 | 476 | def should_distort_images(flip_left_right, random_crop, random_scale, 477 | random_brightness): 478 | """Whether any distortions are enabled, from the input flags. 479 | Args: 480 | flip_left_right: Boolean whether to randomly mirror images horizontally. 481 | random_crop: Integer percentage setting the total margin used around the 482 | crop box. 483 | random_scale: Integer percentage of how much to vary the scale by. 484 | random_brightness: Integer range to randomly multiply the pixel values by. 485 | Returns: 486 | Boolean value indicating whether any distortions should be applied. 487 | """ 488 | return (flip_left_right or (random_crop != 0) or (random_scale != 0) or 489 | (random_brightness != 0)) 490 | 491 | 492 | def add_input_distortions(flip_left_right, random_crop, random_scale, 493 | random_brightness, module_spec): 494 | """Creates the operations to apply the specified distortions. 495 | During training it can help to improve the results if we run the images 496 | through simple distortions like crops, scales, and flips. These reflect the 497 | kind of variations we expect in the real world, and so can help train the 498 | model to cope with natural data more effectively. Here we take the supplied 499 | parameters and construct a network of operations to apply them to an image. 500 | Cropping 501 | ~~~~~~~~ 502 | Cropping is done by placing a bounding box at a random position in the full 503 | image. The cropping parameter controls the size of that box relative to the 504 | input image. If it's zero, then the box is the same size as the input and no 505 | cropping is performed. If the value is 50%, then the crop box will be half the 506 | width and height of the input. In a diagram it looks like this: 507 | < width > 508 | +---------------------+ 509 | | | 510 | | width - crop% | 511 | | < > | 512 | | +------+ | 513 | | | | | 514 | | | | | 515 | | | | | 516 | | +------+ | 517 | | | 518 | | | 519 | +---------------------+ 520 | Scaling 521 | ~~~~~~~ 522 | Scaling is a lot like cropping, except that the bounding box is always 523 | centered and its size varies randomly within the given range. For example if 524 | the scale percentage is zero, then the bounding box is the same size as the 525 | input and no scaling is applied. If it's 50%, then the bounding box will be in 526 | a random range between half the width and height and full size. 527 | Args: 528 | flip_left_right: Boolean whether to randomly mirror images horizontally. 529 | random_crop: Integer percentage setting the total margin used around the 530 | crop box. 531 | random_scale: Integer percentage of how much to vary the scale by. 532 | random_brightness: Integer range to randomly multiply the pixel values by. 533 | graph. 534 | module_spec: The hub.ModuleSpec for the image module being used. 535 | Returns: 536 | The jpeg input layer and the distorted result tensor. 537 | """ 538 | input_height, input_width = hub.get_expected_image_size(module_spec) 539 | input_depth = hub.get_num_image_channels(module_spec) 540 | jpeg_data = tf.placeholder(tf.string, name='DistortJPGInput') 541 | decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth) 542 | # Convert from full range of uint8 to range [0,1] of float32. 543 | decoded_image_as_float = tf.image.convert_image_dtype(decoded_image, 544 | tf.float32) 545 | decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0) 546 | margin_scale = 1.0 + (random_crop / 100.0) 547 | resize_scale = 1.0 + (random_scale / 100.0) 548 | margin_scale_value = tf.constant(margin_scale) 549 | resize_scale_value = tf.random_uniform(shape=[], 550 | minval=1.0, 551 | maxval=resize_scale) 552 | scale_value = tf.multiply(margin_scale_value, resize_scale_value) 553 | precrop_width = tf.multiply(scale_value, input_width) 554 | precrop_height = tf.multiply(scale_value, input_height) 555 | precrop_shape = tf.stack([precrop_height, precrop_width]) 556 | precrop_shape_as_int = tf.cast(precrop_shape, dtype=tf.int32) 557 | precropped_image = tf.image.resize_bilinear(decoded_image_4d, 558 | precrop_shape_as_int) 559 | precropped_image_3d = tf.squeeze(precropped_image, squeeze_dims=[0]) 560 | cropped_image = tf.random_crop(precropped_image_3d, 561 | [input_height, input_width, input_depth]) 562 | if flip_left_right: 563 | flipped_image = tf.image.random_flip_left_right(cropped_image) 564 | else: 565 | flipped_image = cropped_image 566 | brightness_min = 1.0 - (random_brightness / 100.0) 567 | brightness_max = 1.0 + (random_brightness / 100.0) 568 | brightness_value = tf.random_uniform(shape=[], 569 | minval=brightness_min, 570 | maxval=brightness_max) 571 | brightened_image = tf.multiply(flipped_image, brightness_value) 572 | distort_result = tf.expand_dims(brightened_image, 0, name='DistortResult') 573 | return jpeg_data, distort_result 574 | 575 | 576 | def variable_summaries(var): 577 | """Attach a lot of summaries to a Tensor (for TensorBoard visualization).""" 578 | with tf.name_scope('summaries'): 579 | mean = tf.reduce_mean(var) 580 | tf.summary.scalar('mean', mean) 581 | with tf.name_scope('stddev'): 582 | stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) 583 | tf.summary.scalar('stddev', stddev) 584 | tf.summary.scalar('max', tf.reduce_max(var)) 585 | tf.summary.scalar('min', tf.reduce_min(var)) 586 | tf.summary.histogram('histogram', var) 587 | 588 | 589 | def add_final_retrain_ops(class_count, final_tensor_name, bottleneck_tensor, 590 | quantize_layer, is_training): 591 | """Adds a new softmax and fully-connected layer for training and eval. 592 | We need to retrain the top layer to identify our new classes, so this function 593 | adds the right operations to the graph, along with some variables to hold the 594 | weights, and then sets up all the gradients for the backward pass. 595 | The set up for the softmax and fully-connected layers is based on: 596 | https://www.tensorflow.org/tutorials/mnist/beginners/index.html 597 | Args: 598 | class_count: Integer of how many categories of things we're trying to 599 | recognize. 600 | final_tensor_name: Name string for the new final node that produces results. 601 | bottleneck_tensor: The output of the main CNN graph. 602 | quantize_layer: Boolean, specifying whether the newly added layer should be 603 | instrumented for quantization with TF-Lite. 604 | is_training: Boolean, specifying whether the newly add layer is for training 605 | or eval. 606 | Returns: 607 | The tensors for the training and cross entropy results, and tensors for the 608 | bottleneck input and ground truth input. 609 | """ 610 | batch_size, bottleneck_tensor_size = bottleneck_tensor.get_shape().as_list() 611 | assert batch_size is None, 'We want to work with arbitrary batch size.' 612 | with tf.name_scope('input'): 613 | bottleneck_input = tf.placeholder_with_default( 614 | bottleneck_tensor, 615 | shape=[batch_size, bottleneck_tensor_size], 616 | name='BottleneckInputPlaceholder') 617 | 618 | ground_truth_input = tf.placeholder( 619 | tf.int64, [batch_size], name='GroundTruthInput') 620 | 621 | # Organizing the following ops so they are easier to see in TensorBoard. 622 | layer_name = 'final_retrain_ops' 623 | with tf.name_scope(layer_name): 624 | with tf.name_scope('weights'): 625 | initial_value = tf.truncated_normal( 626 | [bottleneck_tensor_size, class_count], stddev=0.001) 627 | layer_weights = tf.Variable(initial_value, name='final_weights') 628 | variable_summaries(layer_weights) 629 | 630 | with tf.name_scope('biases'): 631 | layer_biases = tf.Variable(tf.zeros([class_count]), name='final_biases') 632 | variable_summaries(layer_biases) 633 | 634 | with tf.name_scope('Wx_plus_b'): 635 | logits = tf.matmul(bottleneck_input, layer_weights) + layer_biases 636 | tf.summary.histogram('pre_activations', logits) 637 | 638 | final_tensor = tf.nn.softmax(logits, name=final_tensor_name) 639 | 640 | # The tf.contrib.quantize functions rewrite the graph in place for 641 | # quantization. The imported model graph has already been rewritten, so upon 642 | # calling these rewrites, only the newly added final layer will be 643 | # transformed. 644 | if quantize_layer: 645 | if is_training: 646 | tf.contrib.quantize.create_training_graph() 647 | else: 648 | tf.contrib.quantize.create_eval_graph() 649 | 650 | tf.summary.histogram('activations', final_tensor) 651 | 652 | # If this is an eval graph, we don't need to add loss ops or an optimizer. 653 | if not is_training: 654 | return None, None, bottleneck_input, ground_truth_input, final_tensor 655 | 656 | with tf.name_scope('cross_entropy'): 657 | cross_entropy_mean = tf.losses.sparse_softmax_cross_entropy( 658 | labels=ground_truth_input, logits=logits) 659 | 660 | tf.summary.scalar('cross_entropy', cross_entropy_mean) 661 | 662 | with tf.name_scope('train'): 663 | optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate) 664 | train_step = optimizer.minimize(cross_entropy_mean) 665 | 666 | return (train_step, cross_entropy_mean, bottleneck_input, ground_truth_input, 667 | final_tensor) 668 | 669 | 670 | def add_evaluation_step(result_tensor, ground_truth_tensor): 671 | """Inserts the operations we need to evaluate the accuracy of our results. 672 | Args: 673 | result_tensor: The new final node that produces results. 674 | ground_truth_tensor: The node we feed ground truth data 675 | into. 676 | Returns: 677 | Tuple of (evaluation step, prediction). 678 | """ 679 | with tf.name_scope('accuracy'): 680 | with tf.name_scope('correct_prediction'): 681 | prediction = tf.argmax(result_tensor, 1) 682 | correct_prediction = tf.equal(prediction, ground_truth_tensor) 683 | with tf.name_scope('accuracy'): 684 | evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 685 | tf.summary.scalar('accuracy', evaluation_step) 686 | return evaluation_step, prediction 687 | 688 | 689 | def run_final_eval(train_session, module_spec, class_count, image_lists, 690 | jpeg_data_tensor, decoded_image_tensor, 691 | resized_image_tensor, bottleneck_tensor): 692 | """Runs a final evaluation on an eval graph using the test data set. 693 | Args: 694 | train_session: Session for the train graph with the tensors below. 695 | module_spec: The hub.ModuleSpec for the image module being used. 696 | class_count: Number of classes 697 | image_lists: OrderedDict of training images for each label. 698 | jpeg_data_tensor: The layer to feed jpeg image data into. 699 | decoded_image_tensor: The output of decoding and resizing the image. 700 | resized_image_tensor: The input node of the recognition graph. 701 | bottleneck_tensor: The bottleneck output layer of the CNN graph. 702 | """ 703 | test_bottlenecks, test_ground_truth, test_filenames = ( 704 | get_random_cached_bottlenecks(train_session, image_lists, 705 | FLAGS.test_batch_size, 706 | 'testing', FLAGS.bottleneck_dir, 707 | FLAGS.image_dir, jpeg_data_tensor, 708 | decoded_image_tensor, resized_image_tensor, 709 | bottleneck_tensor, FLAGS.tfhub_module)) 710 | 711 | (eval_session, _, bottleneck_input, ground_truth_input, evaluation_step, 712 | prediction) = build_eval_session(module_spec, class_count) 713 | test_accuracy, predictions = eval_session.run( 714 | [evaluation_step, prediction], 715 | feed_dict={ 716 | bottleneck_input: test_bottlenecks, 717 | ground_truth_input: test_ground_truth 718 | }) 719 | tf.logging.info('Final test accuracy = %.1f%% (N=%d)' % 720 | (test_accuracy * 100, len(test_bottlenecks))) 721 | 722 | if FLAGS.print_misclassified_test_images: 723 | tf.logging.info('=== MISCLASSIFIED TEST IMAGES ===') 724 | for i, test_filename in enumerate(test_filenames): 725 | if predictions[i] != test_ground_truth[i]: 726 | tf.logging.info('%70s %s' % (test_filename, 727 | list(image_lists.keys())[predictions[i]])) 728 | 729 | 730 | def build_eval_session(module_spec, class_count): 731 | """Builds an restored eval session without train operations for exporting. 732 | Args: 733 | module_spec: The hub.ModuleSpec for the image module being used. 734 | class_count: Number of classes 735 | Returns: 736 | Eval session containing the restored eval graph. 737 | The bottleneck input, ground truth, eval step, and prediction tensors. 738 | """ 739 | # If quantized, we need to create the correct eval graph for exporting. 740 | eval_graph, bottleneck_tensor, resized_input_tensor, wants_quantization = ( 741 | create_module_graph(module_spec)) 742 | 743 | eval_sess = tf.Session(graph=eval_graph) 744 | with eval_graph.as_default(): 745 | # Add the new layer for exporting. 746 | (_, _, bottleneck_input, 747 | ground_truth_input, final_tensor) = add_final_retrain_ops( 748 | class_count, FLAGS.final_tensor_name, bottleneck_tensor, 749 | wants_quantization, is_training=False) 750 | 751 | # Now we need to restore the values from the training graph to the eval 752 | # graph. 753 | tf.train.Saver().restore(eval_sess, CHECKPOINT_NAME) 754 | 755 | evaluation_step, prediction = add_evaluation_step(final_tensor, 756 | ground_truth_input) 757 | 758 | return (eval_sess, resized_input_tensor, bottleneck_input, ground_truth_input, 759 | evaluation_step, prediction) 760 | 761 | 762 | def save_graph_to_file(graph, graph_file_name, module_spec, class_count): 763 | """Saves an graph to file, creating a valid quantized one if necessary.""" 764 | sess, _, _, _, _, _ = build_eval_session(module_spec, class_count) 765 | graph = sess.graph 766 | 767 | output_graph_def = tf.graph_util.convert_variables_to_constants( 768 | sess, graph.as_graph_def(), [FLAGS.final_tensor_name]) 769 | 770 | with tf.gfile.FastGFile(graph_file_name, 'wb') as f: 771 | f.write(output_graph_def.SerializeToString()) 772 | 773 | 774 | def prepare_file_system(): 775 | # Set up the directory we'll write summaries to for TensorBoard 776 | if tf.gfile.Exists(FLAGS.summaries_dir): 777 | tf.gfile.DeleteRecursively(FLAGS.summaries_dir) 778 | tf.gfile.MakeDirs(FLAGS.summaries_dir) 779 | if FLAGS.intermediate_store_frequency > 0: 780 | ensure_dir_exists(FLAGS.intermediate_output_graphs_dir) 781 | return 782 | 783 | 784 | def add_jpeg_decoding(module_spec): 785 | """Adds operations that perform JPEG decoding and resizing to the graph.. 786 | Args: 787 | module_spec: The hub.ModuleSpec for the image module being used. 788 | Returns: 789 | Tensors for the node to feed JPEG data into, and the output of the 790 | preprocessing steps. 791 | """ 792 | input_height, input_width = hub.get_expected_image_size(module_spec) 793 | input_depth = hub.get_num_image_channels(module_spec) 794 | jpeg_data = tf.placeholder(tf.string, name='DecodeJPGInput') 795 | decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth) 796 | # Convert from full range of uint8 to range [0,1] of float32. 797 | decoded_image_as_float = tf.image.convert_image_dtype(decoded_image, 798 | tf.float32) 799 | decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0) 800 | resize_shape = tf.stack([input_height, input_width]) 801 | resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32) 802 | resized_image = tf.image.resize_bilinear(decoded_image_4d, 803 | resize_shape_as_int) 804 | return jpeg_data, resized_image 805 | 806 | 807 | def export_model(module_spec, class_count, saved_model_dir): 808 | """Exports model for serving. 809 | Args: 810 | module_spec: The hub.ModuleSpec for the image module being used. 811 | class_count: The number of classes. 812 | saved_model_dir: Directory in which to save exported model and variables. 813 | """ 814 | # The SavedModel should hold the eval graph. 815 | sess, in_image, _, _, _, _ = build_eval_session(module_spec, class_count) 816 | graph = sess.graph 817 | with graph.as_default(): 818 | inputs = {'image': tf.saved_model.utils.build_tensor_info(in_image)} 819 | 820 | out_classes = sess.graph.get_tensor_by_name('final_result:0') 821 | outputs = { 822 | 'prediction': tf.saved_model.utils.build_tensor_info(out_classes) 823 | } 824 | 825 | signature = tf.saved_model.signature_def_utils.build_signature_def( 826 | inputs=inputs, 827 | outputs=outputs, 828 | method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME) 829 | 830 | legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op') 831 | 832 | # Save out the SavedModel. 833 | builder = tf.saved_model.builder.SavedModelBuilder(saved_model_dir) 834 | builder.add_meta_graph_and_variables( 835 | sess, [tf.saved_model.tag_constants.SERVING], 836 | signature_def_map={ 837 | tf.saved_model.signature_constants. 838 | DEFAULT_SERVING_SIGNATURE_DEF_KEY: 839 | signature 840 | }, 841 | legacy_init_op=legacy_init_op) 842 | builder.save() 843 | 844 | 845 | 846 | def retrain(inputdir=None): 847 | # Needed to make sure the logging output is visible. 848 | # See https://github.com/tensorflow/tensorflow/issues/3047 849 | tf.logging.set_verbosity(tf.logging.ERROR) 850 | 851 | 852 | if inputdir: 853 | if type(inputdir)==str: 854 | FLAGS.image_dir = inputdir 855 | else: 856 | tf.logging.error("Invalid input directory!") 857 | return -1 858 | 859 | if not FLAGS.image_dir: 860 | tf.logging.error('Must set flag --image_dir.') 861 | return -1 862 | 863 | print('Retraining with images in directory: ' + FLAGS.image_dir) 864 | 865 | # Prepare necessary directories that can be used during training 866 | prepare_file_system() 867 | 868 | # Look at the folder structure, and create lists of all the images. 869 | image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage, 870 | FLAGS.validation_percentage) 871 | class_count = len(image_lists.keys()) 872 | if class_count == 0: 873 | tf.logging.error('No valid folders of images found at ' + FLAGS.image_dir) 874 | return -1 875 | if class_count == 1: 876 | tf.logging.error('Only one valid folder of images found at ' + 877 | FLAGS.image_dir + 878 | ' - multiple classes are needed for classification.') 879 | return -1 880 | 881 | # See if the command-line flags mean we're applying any distortions. 882 | do_distort_images = should_distort_images( 883 | FLAGS.flip_left_right, FLAGS.random_crop, FLAGS.random_scale, 884 | FLAGS.random_brightness) 885 | 886 | # Set up the pre-trained graph. 887 | module_spec = hub.load_module_spec(FLAGS.tfhub_module) 888 | graph, bottleneck_tensor, resized_image_tensor, wants_quantization = ( 889 | create_module_graph(module_spec)) 890 | 891 | # Add the new layer that we'll be training. 892 | with graph.as_default(): 893 | (train_step, cross_entropy, bottleneck_input, 894 | ground_truth_input, final_tensor) = add_final_retrain_ops( 895 | class_count, FLAGS.final_tensor_name, bottleneck_tensor, 896 | wants_quantization, is_training=True) 897 | 898 | with tf.Session(graph=graph) as sess: 899 | # Initialize all weights: for the module to their pretrained values, 900 | # and for the newly added retraining layer to random initial values. 901 | init = tf.global_variables_initializer() 902 | sess.run(init) 903 | 904 | # Set up the image decoding sub-graph. 905 | jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec) 906 | 907 | if do_distort_images: 908 | # We will be applying distortions, so set up the operations we'll need. 909 | (distorted_jpeg_data_tensor, 910 | distorted_image_tensor) = add_input_distortions( 911 | FLAGS.flip_left_right, FLAGS.random_crop, FLAGS.random_scale, 912 | FLAGS.random_brightness, module_spec) 913 | else: 914 | # We'll make sure we've calculated the 'bottleneck' image summaries and 915 | # cached them on disk. 916 | cache_bottlenecks(sess, image_lists, FLAGS.image_dir, 917 | FLAGS.bottleneck_dir, jpeg_data_tensor, 918 | decoded_image_tensor, resized_image_tensor, 919 | bottleneck_tensor, FLAGS.tfhub_module) 920 | 921 | # Create the operations we need to evaluate the accuracy of our new layer. 922 | evaluation_step, _ = add_evaluation_step(final_tensor, ground_truth_input) 923 | 924 | # Merge all the summaries and write them out to the summaries_dir 925 | merged = tf.summary.merge_all() 926 | train_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/train', 927 | sess.graph) 928 | 929 | validation_writer = tf.summary.FileWriter( 930 | FLAGS.summaries_dir + '/validation') 931 | 932 | # Create a train saver that is used to restore values into an eval graph 933 | # when exporting models. 934 | train_saver = tf.train.Saver() 935 | 936 | # Run the training for as many cycles as requested on the command line. 937 | for i in range(FLAGS.how_many_training_steps): 938 | # Get a batch of input bottleneck values, either calculated fresh every 939 | # time with distortions applied, or from the cache stored on disk. 940 | if do_distort_images: 941 | (train_bottlenecks, 942 | train_ground_truth) = get_random_distorted_bottlenecks( 943 | sess, image_lists, FLAGS.train_batch_size, 'training', 944 | FLAGS.image_dir, distorted_jpeg_data_tensor, 945 | distorted_image_tensor, resized_image_tensor, bottleneck_tensor) 946 | else: 947 | (train_bottlenecks, 948 | train_ground_truth, _) = get_random_cached_bottlenecks( 949 | sess, image_lists, FLAGS.train_batch_size, 'training', 950 | FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor, 951 | decoded_image_tensor, resized_image_tensor, bottleneck_tensor, 952 | FLAGS.tfhub_module) 953 | # Feed the bottlenecks and ground truth into the graph, and run a training 954 | # step. Capture training summaries for TensorBoard with the `merged` op. 955 | train_summary, _ = sess.run( 956 | [merged, train_step], 957 | feed_dict={bottleneck_input: train_bottlenecks, 958 | ground_truth_input: train_ground_truth}) 959 | train_writer.add_summary(train_summary, i) 960 | 961 | # Every so often, print out how well the graph is training. 962 | is_last_step = (i + 1 == FLAGS.how_many_training_steps) 963 | if (i % FLAGS.eval_step_interval) == 0 or is_last_step: 964 | train_accuracy, cross_entropy_value = sess.run( 965 | [evaluation_step, cross_entropy], 966 | feed_dict={bottleneck_input: train_bottlenecks, 967 | ground_truth_input: train_ground_truth}) 968 | tf.logging.info('%s: Step %d: Train accuracy = %.1f%%' % 969 | (datetime.now(), i, train_accuracy * 100)) 970 | tf.logging.info('%s: Step %d: Cross entropy = %f' % 971 | (datetime.now(), i, cross_entropy_value)) 972 | # TODO: Make this use an eval graph, to avoid quantization 973 | # moving averages being updated by the validation set, though in 974 | # practice this makes a negligable difference. 975 | validation_bottlenecks, validation_ground_truth, _ = ( 976 | get_random_cached_bottlenecks( 977 | sess, image_lists, FLAGS.validation_batch_size, 'validation', 978 | FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor, 979 | decoded_image_tensor, resized_image_tensor, bottleneck_tensor, 980 | FLAGS.tfhub_module)) 981 | # Run a validation step and capture training summaries for TensorBoard 982 | # with the `merged` op. 983 | validation_summary, validation_accuracy = sess.run( 984 | [merged, evaluation_step], 985 | feed_dict={bottleneck_input: validation_bottlenecks, 986 | ground_truth_input: validation_ground_truth}) 987 | validation_writer.add_summary(validation_summary, i) 988 | tf.logging.info('%s: Step %d: Validation accuracy = %.1f%% (N=%d)' % 989 | (datetime.now(), i, validation_accuracy * 100, 990 | len(validation_bottlenecks))) 991 | 992 | # Store intermediate results 993 | intermediate_frequency = FLAGS.intermediate_store_frequency 994 | 995 | if (intermediate_frequency > 0 and (i % intermediate_frequency == 0) 996 | and i > 0): 997 | # If we want to do an intermediate save, save a checkpoint of the train 998 | # graph, to restore into the eval graph. 999 | train_saver.save(sess, CHECKPOINT_NAME) 1000 | intermediate_file_name = (FLAGS.intermediate_output_graphs_dir + 1001 | 'intermediate_' + str(i) + '.pb') 1002 | tf.logging.info('Save intermediate result to : ' + 1003 | intermediate_file_name) 1004 | save_graph_to_file(graph, intermediate_file_name, module_spec, 1005 | class_count) 1006 | 1007 | # After training is complete, force one last save of the train checkpoint. 1008 | train_saver.save(sess, CHECKPOINT_NAME) 1009 | 1010 | # We've completed all our training, so run a final test evaluation on 1011 | # some new images we haven't used before. 1012 | run_final_eval(sess, module_spec, class_count, image_lists, 1013 | jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, 1014 | bottleneck_tensor) 1015 | 1016 | # Write out the trained graph and labels with the weights stored as 1017 | # constants. 1018 | tf.logging.info('Save final result to : ' + FLAGS.output_graph) 1019 | if wants_quantization: 1020 | tf.logging.info('The model is instrumented for quantization with TF-Lite') 1021 | save_graph_to_file(graph, FLAGS.output_graph, module_spec, class_count) 1022 | with tf.gfile.FastGFile(FLAGS.output_labels, 'w') as f: 1023 | f.write('\n'.join(image_lists.keys()) + '\n') 1024 | 1025 | if FLAGS.saved_model_dir: 1026 | export_model(module_spec, class_count, FLAGS.saved_model_dir) 1027 | 1028 | #uncomment line below to run this script as stand-alone 1029 | # retrain() 1030 | -------------------------------------------------------------------------------- /Section4-Tensorflow_image_classifier/sample_imgs/place_files_in_labeled_directories_here: -------------------------------------------------------------------------------- 1 | barbie 2 | gi joe 3 | my little pony 4 | transformers 5 | -------------------------------------------------------------------------------- /Section4-Tensorflow_image_classifier/scratch.py: -------------------------------------------------------------------------------- 1 | #Let's get some code from Tensorflow's repository to 2 | # translate the prediction result to a name we understand 3 | 4 | #for simplicity, let's keep everything in the current working directory 5 | model_dir = '.' 6 | class NodeLookup(object): 7 | """Converts integer node ID's to human readable labels.""" 8 | 9 | def __init__(self, 10 | label_lookup_path=None, 11 | uid_lookup_path=None): 12 | if not label_lookup_path: 13 | label_lookup_path = os.path.join( 14 | model_dir, 'imagenet_2012_challenge_label_map_proto.pbtxt') 15 | if not uid_lookup_path: 16 | uid_lookup_path = os.path.join( 17 | model_dir, 'imagenet_synset_to_human_label_map.txt') 18 | self.node_lookup = self.load(label_lookup_path, uid_lookup_path) 19 | 20 | def load(self, label_lookup_path, uid_lookup_path): 21 | """Loads a human readable English name for each softmax node. 22 | 23 | Args: 24 | label_lookup_path: string UID to integer node ID. 25 | uid_lookup_path: string UID to human-readable string. 26 | 27 | Returns: 28 | dict from integer node ID to human-readable string. 29 | """ 30 | if not tf.gfile.Exists(uid_lookup_path): 31 | tf.logging.fatal('File does not exist %s', uid_lookup_path) 32 | if not tf.gfile.Exists(label_lookup_path): 33 | tf.logging.fatal('File does not exist %s', label_lookup_path) 34 | 35 | # Loads mapping from string UID to human-readable string 36 | proto_as_ascii_lines = tf.gfile.GFile(uid_lookup_path).readlines() 37 | uid_to_human = {} 38 | p = re.compile(r'[n\d]*[ \S,]*') 39 | for line in proto_as_ascii_lines: 40 | parsed_items = p.findall(line) 41 | uid = parsed_items[0] 42 | human_string = parsed_items[2] 43 | uid_to_human[uid] = human_string 44 | 45 | # Loads mapping from string UID to integer node ID. 46 | node_id_to_uid = {} 47 | proto_as_ascii = tf.gfile.GFile(label_lookup_path).readlines() 48 | for line in proto_as_ascii: 49 | if line.startswith(' target_class:'): 50 | target_class = int(line.split(': ')[1]) 51 | if line.startswith(' target_class_string:'): 52 | target_class_string = line.split(': ')[1] 53 | node_id_to_uid[target_class] = target_class_string[1:-2] 54 | 55 | # Loads the final mapping of integer node ID to human-readable string 56 | node_id_to_name = {} 57 | for key, val in node_id_to_uid.items(): 58 | if val not in uid_to_human: 59 | tf.logging.fatal('Failed to locate: %s', val) 60 | name = uid_to_human[val] 61 | node_id_to_name[key] = name 62 | 63 | return node_id_to_name 64 | 65 | def id_to_string(self, node_id): 66 | if node_id not in self.node_lookup: 67 | return '' 68 | return self.node_lookup[node_id] 69 | --------------------------------------------------------------------------------