├── .gitignore
├── .idea
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── jarRepositories.xml
├── misc.xml
└── runConfigurations.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── say
│ │ └── pytorchkotlindemo
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── model_1.pt
│ ├── java
│ │ └── com
│ │ │ └── say
│ │ │ └── pytorchkotlindemo
│ │ │ ├── AnalysisResult.kt
│ │ │ ├── Constants.kt
│ │ │ ├── ImageClassificationOperation.kt
│ │ │ ├── Listeners.kt
│ │ │ ├── LiveDataViewModel.kt
│ │ │ ├── MainActivity.kt
│ │ │ └── Utils.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── say
│ └── pytorchkotlindemo
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
87 | # vscode local history
88 | /.history/
89 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | xmlns:android
17 |
18 | ^$
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | xmlns:.*
28 |
29 | ^$
30 |
31 |
32 | BY_NAME
33 |
34 |
35 |
36 |
37 |
38 |
39 | .*:id
40 |
41 | http://schemas.android.com/apk/res/android
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | .*:name
51 |
52 | http://schemas.android.com/apk/res/android
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | name
62 |
63 | ^$
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | style
73 |
74 | ^$
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | .*
84 |
85 | ^$
86 |
87 |
88 | BY_NAME
89 |
90 |
91 |
92 |
93 |
94 |
95 | .*
96 |
97 | http://schemas.android.com/apk/res/android
98 |
99 |
100 | ANDROID_ATTRIBUTE_ORDER
101 |
102 |
103 |
104 |
105 |
106 |
107 | .*
108 |
109 | .*
110 |
111 |
112 | BY_NAME
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, Vortana Say
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PytorchKotlinDemo
2 |
3 | This is an Android project written in Kotlin to show a simple image classification application that uses Android PyTorch API and a trained PyTorch model.
4 |
5 | In this demo application, user can either upload a picture or take photo. Then run the image analysis on the picture.
6 |
7 | ## Architecture
8 |
9 | I followed one of the [android google architecture component sample](https://github.com/android/architecture-components-samples/tree/master/LiveDataSample).
10 |
11 | This sample showcases the following Architecture Components:
12 |
13 | * [LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html)
14 | * [ViewModels](https://developer.android.com/reference/android/arch/lifecycle/ViewModel.html)
15 | * [Data Binding](https://developer.android.com/topic/libraries/data-binding)
16 |
17 | ## Serialize a PyTorch model
18 |
19 | In [Android demo github](https://github.com/pytorch/android-demo-app), it describe in detail how the PyTorch model generated.
20 |
21 | We cannot use the saved model directly in the notebook, we need to serialize that saved model.
22 |
23 | In the Jupyter notebook where I trained the model, I can do the following
24 |
25 |
26 | ```
27 | //load the model
28 | ckp_path = './best_model.pt'
29 | if(use_cuda):
30 | checkpoint = torch.load(ckp_path)
31 | else:
32 | checkpoint = torch.load(ckp_path, map_location=torch.device('cpu'))
33 | loaded_model.load_state_dict(checkpoint['state_dict'])
34 | ```
35 |
36 | ```
37 | //serialize the model
38 | loaded_model.eval()
39 | example = torch.rand(1, 3, 224, 224)
40 | if use_cuda:
41 | example = example.cuda()
42 | traced_script_module = torch.jit.trace(loaded_model, example)
43 | traced_script_module.save("./serialized_model.pt")
44 | ```
45 |
46 | After this operations, we should have a usable model, serialized_model.pt.
47 |
48 | ## References
49 |
50 | [Android demo github](https://github.com/pytorch/android-demo-app)
51 |
52 | [PyTorch Mobile](https://pytorch.org/mobile/home/)
53 |
54 | [android google architecture component sample](https://github.com/android/architecture-components-samples/tree/master/LiveDataSample)
55 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 | apply plugin: 'kotlin-android-extensions'
5 |
6 | android {
7 | compileSdkVersion 29
8 | buildToolsVersion "29.0.2"
9 | defaultConfig {
10 | applicationId "com.say.pytorchkotlindemo"
11 | minSdkVersion 21
12 | targetSdkVersion 29
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 |
30 | kotlinOptions {
31 | jvmTarget = JavaVersion.VERSION_1_8.toString()
32 | }
33 |
34 | dataBinding{
35 | enabled=true
36 | }
37 | }
38 |
39 | dependencies {
40 | def lifecycle_version = "2.2.0"
41 | def activity_version = "1.1.0"
42 | def arch_core_version = "2.1.0"
43 | def core_ktx_version = "1.1.0"
44 | def dexter_version = "6.0.2"
45 | def pytorch_version = "1.4.0"
46 |
47 | implementation fileTree(dir: 'libs', include: ['*.jar'])
48 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
49 | implementation 'androidx.appcompat:appcompat:1.1.0'
50 | implementation 'androidx.core:core-ktx:1.1.0'
51 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
52 | testImplementation 'junit:junit:4.12'
53 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
54 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
55 | implementation "com.karumi:dexter:$dexter_version"
56 | //core
57 | implementation "androidx.core:core-ktx:$core_ktx_version"
58 | // ViewModel
59 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
60 | // LiveData
61 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
62 | // activity
63 | implementation "androidx.activity:activity-ktx:$activity_version"
64 | // runtime
65 | implementation "androidx.arch.core:core-runtime:$arch_core_version"
66 |
67 | implementation "org.pytorch:pytorch_android:$pytorch_version"
68 | implementation "org.pytorch:pytorch_android_torchvision:$pytorch_version"
69 | }
70 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/say/pytorchkotlindemo/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.say.pytorchkotlindemo", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/assets/model_1.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/assets/model_1.pt
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/AnalysisResult.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | class AnalysisResult(
4 | val topNClassNames: Array,
5 | val topNScores: FloatArray,
6 | val moduleForwardDuration: Long,
7 | val analysisDuration: Long
8 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | object Constants {
4 | var IMAGE_NET_CLASSNAME = arrayOf(
5 | "tench, Tinca tinca",
6 | "goldfish, Carassius auratus",
7 | "great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias",
8 | "tiger shark, Galeocerdo cuvieri",
9 | "hammerhead, hammerhead shark",
10 | "electric ray, crampfish, numbfish, torpedo",
11 | "stingray",
12 | "cock",
13 | "hen",
14 | "ostrich, Struthio camelus",
15 | "brambling, Fringilla montifringilla",
16 | "goldfinch, Carduelis carduelis",
17 | "house finch, linnet, Carpodacus mexicanus",
18 | "junco, snowbird",
19 | "indigo bunting, indigo finch, indigo bird, Passerina cyanea",
20 | "robin, American robin, Turdus migratorius",
21 | "bulbul",
22 | "jay",
23 | "magpie",
24 | "chickadee",
25 | "water ouzel, dipper",
26 | "kite",
27 | "bald eagle, American eagle, Haliaeetus leucocephalus",
28 | "vulture",
29 | "great grey owl, great gray owl, Strix nebulosa",
30 | "European fire salamander, Salamandra salamandra",
31 | "common newt, Triturus vulgaris",
32 | "eft",
33 | "spotted salamander, Ambystoma maculatum",
34 | "axolotl, mud puppy, Ambystoma mexicanum",
35 | "bullfrog, Rana catesbeiana",
36 | "tree frog, tree-frog",
37 | "tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui",
38 | "loggerhead, loggerhead turtle, Caretta caretta",
39 | "leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea",
40 | "mud turtle",
41 | "terrapin",
42 | "box turtle, box tortoise",
43 | "banded gecko",
44 | "common iguana, iguana, Iguana iguana",
45 | "American chameleon, anole, Anolis carolinensis",
46 | "whiptail, whiptail lizard",
47 | "agama",
48 | "frilled lizard, Chlamydosaurus kingi",
49 | "alligator lizard",
50 | "Gila monster, Heloderma suspectum",
51 | "green lizard, Lacerta viridis",
52 | "African chameleon, Chamaeleo chamaeleon",
53 | "Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis",
54 | "African crocodile, Nile crocodile, Crocodylus niloticus",
55 | "American alligator, Alligator mississipiensis",
56 | "triceratops",
57 | "thunder snake, worm snake, Carphophis amoenus",
58 | "ringneck snake, ring-necked snake, ring snake",
59 | "hognose snake, puff adder, sand viper",
60 | "green snake, grass snake",
61 | "king snake, kingsnake",
62 | "garter snake, grass snake",
63 | "water snake",
64 | "vine snake",
65 | "night snake, Hypsiglena torquata",
66 | "boa constrictor, Constrictor constrictor",
67 | "rock python, rock snake, Python sebae",
68 | "Indian cobra, Naja naja",
69 | "green mamba",
70 | "sea snake",
71 | "horned viper, cerastes, sand viper, horned asp, Cerastes cornutus",
72 | "diamondback, diamondback rattlesnake, Crotalus adamanteus",
73 | "sidewinder, horned rattlesnake, Crotalus cerastes",
74 | "trilobite",
75 | "harvestman, daddy longlegs, Phalangium opilio",
76 | "scorpion",
77 | "black and gold garden spider, Argiope aurantia",
78 | "barn spider, Araneus cavaticus",
79 | "garden spider, Aranea diademata",
80 | "black widow, Latrodectus mactans",
81 | "tarantula",
82 | "wolf spider, hunting spider",
83 | "tick",
84 | "centipede",
85 | "black grouse",
86 | "ptarmigan",
87 | "ruffed grouse, partridge, Bonasa umbellus",
88 | "prairie chicken, prairie grouse, prairie fowl",
89 | "peacock",
90 | "quail",
91 | "partridge",
92 | "African grey, African gray, Psittacus erithacus",
93 | "macaw",
94 | "sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita",
95 | "lorikeet",
96 | "coucal",
97 | "bee eater",
98 | "hornbill",
99 | "hummingbird",
100 | "jacamar",
101 | "toucan",
102 | "drake",
103 | "red-breasted merganser, Mergus serrator",
104 | "goose",
105 | "black swan, Cygnus atratus",
106 | "tusker",
107 | "echidna, spiny anteater, anteater",
108 | "platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus",
109 | "wallaby, brush kangaroo",
110 | "koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus",
111 | "wombat",
112 | "jellyfish",
113 | "sea anemone, anemone",
114 | "brain coral",
115 | "flatworm, platyhelminth",
116 | "nematode, nematode worm, roundworm",
117 | "conch",
118 | "snail",
119 | "slug",
120 | "sea slug, nudibranch",
121 | "chiton, coat-of-mail shell, sea cradle, polyplacophore",
122 | "chambered nautilus, pearly nautilus, nautilus",
123 | "Dungeness crab, Cancer magister",
124 | "rock crab, Cancer irroratus",
125 | "fiddler crab",
126 | "king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica",
127 | "American lobster, Northern lobster, Maine lobster, Homarus americanus",
128 | "spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish",
129 | "crayfish, crawfish, crawdad, crawdaddy",
130 | "hermit crab",
131 | "isopod",
132 | "white stork, Ciconia ciconia",
133 | "black stork, Ciconia nigra",
134 | "spoonbill",
135 | "flamingo",
136 | "little blue heron, Egretta caerulea",
137 | "American egret, great white heron, Egretta albus",
138 | "bittern",
139 | "crane",
140 | "limpkin, Aramus pictus",
141 | "European gallinule, Porphyrio porphyrio",
142 | "American coot, marsh hen, mud hen, water hen, Fulica americana",
143 | "bustard",
144 | "ruddy turnstone, Arenaria interpres",
145 | "red-backed sandpiper, dunlin, Erolia alpina",
146 | "redshank, Tringa totanus",
147 | "dowitcher",
148 | "oystercatcher, oyster catcher",
149 | "pelican",
150 | "king penguin, Aptenodytes patagonica",
151 | "albatross, mollymawk",
152 | "grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus",
153 | "killer whale, killer, orca, grampus, sea wolf, Orcinus orca",
154 | "dugong, Dugong dugon",
155 | "sea lion",
156 | "Chihuahua",
157 | "Japanese spaniel",
158 | "Maltese dog, Maltese terrier, Maltese",
159 | "Pekinese, Pekingese, Peke",
160 | "Shih-Tzu",
161 | "Blenheim spaniel",
162 | "papillon",
163 | "toy terrier",
164 | "Rhodesian ridgeback",
165 | "Afghan hound, Afghan",
166 | "basset, basset hound",
167 | "beagle",
168 | "bloodhound, sleuthhound",
169 | "bluetick",
170 | "black-and-tan coonhound",
171 | "Walker hound, Walker foxhound",
172 | "English foxhound",
173 | "redbone",
174 | "borzoi, Russian wolfhound",
175 | "Irish wolfhound",
176 | "Italian greyhound",
177 | "whippet",
178 | "Ibizan hound, Ibizan Podenco",
179 | "Norwegian elkhound, elkhound",
180 | "otterhound, otter hound",
181 | "Saluki, gazelle hound",
182 | "Scottish deerhound, deerhound",
183 | "Weimaraner",
184 | "Staffordshire bullterrier, Staffordshire bull terrier",
185 | "American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier",
186 | "Bedlington terrier",
187 | "Border terrier",
188 | "Kerry blue terrier",
189 | "Irish terrier",
190 | "Norfolk terrier",
191 | "Norwich terrier",
192 | "Yorkshire terrier",
193 | "wire-haired fox terrier",
194 | "Lakeland terrier",
195 | "Sealyham terrier, Sealyham",
196 | "Airedale, Airedale terrier",
197 | "cairn, cairn terrier",
198 | "Australian terrier",
199 | "Dandie Dinmont, Dandie Dinmont terrier",
200 | "Boston bull, Boston terrier",
201 | "miniature schnauzer",
202 | "giant schnauzer",
203 | "standard schnauzer",
204 | "Scotch terrier, Scottish terrier, Scottie",
205 | "Tibetan terrier, chrysanthemum dog",
206 | "silky terrier, Sydney silky",
207 | "soft-coated wheaten terrier",
208 | "West Highland white terrier",
209 | "Lhasa, Lhasa apso",
210 | "flat-coated retriever",
211 | "curly-coated retriever",
212 | "golden retriever",
213 | "Labrador retriever",
214 | "Chesapeake Bay retriever",
215 | "German short-haired pointer",
216 | "vizsla, Hungarian pointer",
217 | "English setter",
218 | "Irish setter, red setter",
219 | "Gordon setter",
220 | "Brittany spaniel",
221 | "clumber, clumber spaniel",
222 | "English springer, English springer spaniel",
223 | "Welsh springer spaniel",
224 | "cocker spaniel, English cocker spaniel, cocker",
225 | "Sussex spaniel",
226 | "Irish water spaniel",
227 | "kuvasz",
228 | "schipperke",
229 | "groenendael",
230 | "malinois",
231 | "briard",
232 | "kelpie",
233 | "komondor",
234 | "Old English sheepdog, bobtail",
235 | "Shetland sheepdog, Shetland sheep dog, Shetland",
236 | "collie",
237 | "Border collie",
238 | "Bouvier des Flandres, Bouviers des Flandres",
239 | "Rottweiler",
240 | "German shepherd, German shepherd dog, German police dog, alsatian",
241 | "Doberman, Doberman pinscher",
242 | "miniature pinscher",
243 | "Greater Swiss Mountain dog",
244 | "Bernese mountain dog",
245 | "Appenzeller",
246 | "EntleBucher",
247 | "boxer",
248 | "bull mastiff",
249 | "Tibetan mastiff",
250 | "French bulldog",
251 | "Great Dane",
252 | "Saint Bernard, St Bernard",
253 | "Eskimo dog, husky",
254 | "malamute, malemute, Alaskan malamute",
255 | "Siberian husky",
256 | "dalmatian, coach dog, carriage dog",
257 | "affenpinscher, monkey pinscher, monkey dog",
258 | "basenji",
259 | "pug, pug-dog",
260 | "Leonberg",
261 | "Newfoundland, Newfoundland dog",
262 | "Great Pyrenees",
263 | "Samoyed, Samoyede",
264 | "Pomeranian",
265 | "chow, chow chow",
266 | "keeshond",
267 | "Brabancon griffon",
268 | "Pembroke, Pembroke Welsh corgi",
269 | "Cardigan, Cardigan Welsh corgi",
270 | "toy poodle",
271 | "miniature poodle",
272 | "standard poodle",
273 | "Mexican hairless",
274 | "timber wolf, grey wolf, gray wolf, Canis lupus",
275 | "white wolf, Arctic wolf, Canis lupus tundrarum",
276 | "red wolf, maned wolf, Canis rufus, Canis niger",
277 | "coyote, prairie wolf, brush wolf, Canis latrans",
278 | "dingo, warrigal, warragal, Canis dingo",
279 | "dhole, Cuon alpinus",
280 | "African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus",
281 | "hyena, hyaena",
282 | "red fox, Vulpes vulpes",
283 | "kit fox, Vulpes macrotis",
284 | "Arctic fox, white fox, Alopex lagopus",
285 | "grey fox, gray fox, Urocyon cinereoargenteus",
286 | "tabby, tabby cat",
287 | "tiger cat",
288 | "Persian cat",
289 | "Siamese cat, Siamese",
290 | "Egyptian cat",
291 | "cougar, puma, catamount, mountain lion, painter, panther, Felis concolor",
292 | "lynx, catamount",
293 | "leopard, Panthera pardus",
294 | "snow leopard, ounce, Panthera uncia",
295 | "jaguar, panther, Panthera onca, Felis onca",
296 | "lion, king of beasts, Panthera leo",
297 | "tiger, Panthera tigris",
298 | "cheetah, chetah, Acinonyx jubatus",
299 | "brown bear, bruin, Ursus arctos",
300 | "American black bear, black bear, Ursus americanus, Euarctos americanus",
301 | "ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus",
302 | "sloth bear, Melursus ursinus, Ursus ursinus",
303 | "mongoose",
304 | "meerkat, mierkat",
305 | "tiger beetle",
306 | "ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle",
307 | "ground beetle, carabid beetle",
308 | "long-horned beetle, longicorn, longicorn beetle",
309 | "leaf beetle, chrysomelid",
310 | "dung beetle",
311 | "rhinoceros beetle",
312 | "weevil",
313 | "fly",
314 | "bee",
315 | "ant, emmet, pismire",
316 | "grasshopper, hopper",
317 | "cricket",
318 | "walking stick, walkingstick, stick insect",
319 | "cockroach, roach",
320 | "mantis, mantid",
321 | "cicada, cicala",
322 | "leafhopper",
323 | "lacewing, lacewing fly",
324 | "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk",
325 | "damselfly",
326 | "admiral",
327 | "ringlet, ringlet butterfly",
328 | "monarch, monarch butterfly, milkweed butterfly, Danaus plexippus",
329 | "cabbage butterfly",
330 | "sulphur butterfly, sulfur butterfly",
331 | "lycaenid, lycaenid butterfly",
332 | "starfish, sea star",
333 | "sea urchin",
334 | "sea cucumber, holothurian",
335 | "wood rabbit, cottontail, cottontail rabbit",
336 | "hare",
337 | "Angora, Angora rabbit",
338 | "hamster",
339 | "porcupine, hedgehog",
340 | "fox squirrel, eastern fox squirrel, Sciurus niger",
341 | "marmot",
342 | "beaver",
343 | "guinea pig, Cavia cobaya",
344 | "sorrel",
345 | "zebra",
346 | "hog, pig, grunter, squealer, Sus scrofa",
347 | "wild boar, boar, Sus scrofa",
348 | "warthog",
349 | "hippopotamus, hippo, river horse, Hippopotamus amphibius",
350 | "ox",
351 | "water buffalo, water ox, Asiatic buffalo, Bubalus bubalis",
352 | "bison",
353 | "ram, tup",
354 | "bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis",
355 | "ibex, Capra ibex",
356 | "hartebeest",
357 | "impala, Aepyceros melampus",
358 | "gazelle",
359 | "Arabian camel, dromedary, Camelus dromedarius",
360 | "llama",
361 | "weasel",
362 | "mink",
363 | "polecat, fitch, foulmart, foumart, Mustela putorius",
364 | "black-footed ferret, ferret, Mustela nigripes",
365 | "otter",
366 | "skunk, polecat, wood pussy",
367 | "badger",
368 | "armadillo",
369 | "three-toed sloth, ai, Bradypus tridactylus",
370 | "orangutan, orang, orangutang, Pongo pygmaeus",
371 | "gorilla, Gorilla gorilla",
372 | "chimpanzee, chimp, Pan troglodytes",
373 | "gibbon, Hylobates lar",
374 | "siamang, Hylobates syndactylus, Symphalangus syndactylus",
375 | "guenon, guenon monkey",
376 | "patas, hussar monkey, Erythrocebus patas",
377 | "baboon",
378 | "macaque",
379 | "langur",
380 | "colobus, colobus monkey",
381 | "proboscis monkey, Nasalis larvatus",
382 | "marmoset",
383 | "capuchin, ringtail, Cebus capucinus",
384 | "howler monkey, howler",
385 | "titi, titi monkey",
386 | "spider monkey, Ateles geoffroyi",
387 | "squirrel monkey, Saimiri sciureus",
388 | "Madagascar cat, ring-tailed lemur, Lemur catta",
389 | "indri, indris, Indri indri, Indri brevicaudatus",
390 | "Indian elephant, Elephas maximus",
391 | "African elephant, Loxodonta africana",
392 | "lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens",
393 | "giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca",
394 | "barracouta, snoek",
395 | "eel",
396 | "coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch",
397 | "rock beauty, Holocanthus tricolor",
398 | "anemone fish",
399 | "sturgeon",
400 | "gar, garfish, garpike, billfish, Lepisosteus osseus",
401 | "lionfish",
402 | "puffer, pufferfish, blowfish, globefish",
403 | "abacus",
404 | "abaya",
405 | "academic gown, academic robe, judge's robe",
406 | "accordion, piano accordion, squeeze box",
407 | "acoustic guitar",
408 | "aircraft carrier, carrier, flattop, attack aircraft carrier",
409 | "airliner",
410 | "airship, dirigible",
411 | "altar",
412 | "ambulance",
413 | "amphibian, amphibious vehicle",
414 | "analog clock",
415 | "apiary, bee house",
416 | "apron",
417 | "ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin",
418 | "assault rifle, assault gun",
419 | "backpack, back pack, knapsack, packsack, rucksack, haversack",
420 | "bakery, bakeshop, bakehouse",
421 | "balance beam, beam",
422 | "balloon",
423 | "ballpoint, ballpoint pen, ballpen, Biro",
424 | "Band Aid",
425 | "banjo",
426 | "bannister, banister, balustrade, balusters, handrail",
427 | "barbell",
428 | "barber chair",
429 | "barbershop",
430 | "barn",
431 | "barometer",
432 | "barrel, cask",
433 | "barrow, garden cart, lawn cart, wheelbarrow",
434 | "baseball",
435 | "basketball",
436 | "bassinet",
437 | "bassoon",
438 | "bathing cap, swimming cap",
439 | "bath towel",
440 | "bathtub, bathing tub, bath, tub",
441 | "beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon",
442 | "beacon, lighthouse, beacon light, pharos",
443 | "beaker",
444 | "bearskin, busby, shako",
445 | "beer bottle",
446 | "beer glass",
447 | "bell cote, bell cot",
448 | "bib",
449 | "bicycle-built-for-two, tandem bicycle, tandem",
450 | "bikini, two-piece",
451 | "binder, ring-binder",
452 | "binoculars, field glasses, opera glasses",
453 | "birdhouse",
454 | "boathouse",
455 | "bobsled, bobsleigh, bob",
456 | "bolo tie, bolo, bola tie, bola",
457 | "bonnet, poke bonnet",
458 | "bookcase",
459 | "bookshop, bookstore, bookstall",
460 | "bottlecap",
461 | "bow",
462 | "bow tie, bow-tie, bowtie",
463 | "brass, memorial tablet, plaque",
464 | "brassiere, bra, bandeau",
465 | "breakwater, groin, groyne, mole, bulwark, seawall, jetty",
466 | "breastplate, aegis, egis",
467 | "broom",
468 | "bucket, pail",
469 | "buckle",
470 | "bulletproof vest",
471 | "bullet train, bullet",
472 | "butcher shop, meat market",
473 | "cab, hack, taxi, taxicab",
474 | "caldron, cauldron",
475 | "candle, taper, wax light",
476 | "cannon",
477 | "canoe",
478 | "can opener, tin opener",
479 | "cardigan",
480 | "car mirror",
481 | "carousel, carrousel, merry-go-round, roundabout, whirligig",
482 | "carpenter's kit, tool kit",
483 | "carton",
484 | "car wheel",
485 | "cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM",
486 | "cassette",
487 | "cassette player",
488 | "castle",
489 | "catamaran",
490 | "CD player",
491 | "cello, violoncello",
492 | "cellular telephone, cellular phone, cellphone, cell, mobile phone",
493 | "chain",
494 | "chainlink fence",
495 | "chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour",
496 | "chain saw, chainsaw",
497 | "chest",
498 | "chiffonier, commode",
499 | "chime, bell, gong",
500 | "china cabinet, china closet",
501 | "Christmas stocking",
502 | "church, church building",
503 | "cinema, movie theater, movie theatre, movie house, picture palace",
504 | "cleaver, meat cleaver, chopper",
505 | "cliff dwelling",
506 | "cloak",
507 | "clog, geta, patten, sabot",
508 | "cocktail shaker",
509 | "coffee mug",
510 | "coffeepot",
511 | "coil, spiral, volute, whorl, helix",
512 | "combination lock",
513 | "computer keyboard, keypad",
514 | "confectionery, confectionary, candy store",
515 | "container ship, containership, container vessel",
516 | "convertible",
517 | "corkscrew, bottle screw",
518 | "cornet, horn, trumpet, trump",
519 | "cowboy boot",
520 | "cowboy hat, ten-gallon hat",
521 | "cradle",
522 | "crane",
523 | "crash helmet",
524 | "crate",
525 | "crib, cot",
526 | "Crock Pot",
527 | "croquet ball",
528 | "crutch",
529 | "cuirass",
530 | "dam, dike, dyke",
531 | "desk",
532 | "desktop computer",
533 | "dial telephone, dial phone",
534 | "diaper, nappy, napkin",
535 | "digital clock",
536 | "digital watch",
537 | "dining table, board",
538 | "dishrag, dishcloth",
539 | "dishwasher, dish washer, dishwashing machine",
540 | "disk brake, disc brake",
541 | "dock, dockage, docking facility",
542 | "dogsled, dog sled, dog sleigh",
543 | "dome",
544 | "doormat, welcome mat",
545 | "drilling platform, offshore rig",
546 | "drum, membranophone, tympan",
547 | "drumstick",
548 | "dumbbell",
549 | "Dutch oven",
550 | "electric fan, blower",
551 | "electric guitar",
552 | "electric locomotive",
553 | "entertainment center",
554 | "envelope",
555 | "espresso maker",
556 | "face powder",
557 | "feather boa, boa",
558 | "file, file cabinet, filing cabinet",
559 | "fireboat",
560 | "fire engine, fire truck",
561 | "fire screen, fireguard",
562 | "flagpole, flagstaff",
563 | "flute, transverse flute",
564 | "folding chair",
565 | "football helmet",
566 | "forklift",
567 | "fountain",
568 | "fountain pen",
569 | "four-poster",
570 | "freight car",
571 | "French horn, horn",
572 | "frying pan, frypan, skillet",
573 | "fur coat",
574 | "garbage truck, dustcart",
575 | "gasmask, respirator, gas helmet",
576 | "gas pump, gasoline pump, petrol pump, island dispenser",
577 | "goblet",
578 | "go-kart",
579 | "golf ball",
580 | "golfcart, golf cart",
581 | "gondola",
582 | "gong, tam-tam",
583 | "gown",
584 | "grand piano, grand",
585 | "greenhouse, nursery, glasshouse",
586 | "grille, radiator grille",
587 | "grocery store, grocery, food market, market",
588 | "guillotine",
589 | "hair slide",
590 | "hair spray",
591 | "half track",
592 | "hammer",
593 | "hamper",
594 | "hand blower, blow dryer, blow drier, hair dryer, hair drier",
595 | "hand-held computer, hand-held microcomputer",
596 | "handkerchief, hankie, hanky, hankey",
597 | "hard disc, hard disk, fixed disk",
598 | "harmonica, mouth organ, harp, mouth harp",
599 | "harp",
600 | "harvester, reaper",
601 | "hatchet",
602 | "holster",
603 | "home theater, home theatre",
604 | "honeycomb",
605 | "hook, claw",
606 | "hoopskirt, crinoline",
607 | "horizontal bar, high bar",
608 | "horse cart, horse-cart",
609 | "hourglass",
610 | "iPod",
611 | "iron, smoothing iron",
612 | "jack-o'-lantern",
613 | "jean, blue jean, denim",
614 | "jeep, landrover",
615 | "jersey, T-shirt, tee shirt",
616 | "jigsaw puzzle",
617 | "jinrikisha, ricksha, rickshaw",
618 | "joystick",
619 | "kimono",
620 | "knee pad",
621 | "knot",
622 | "lab coat, laboratory coat",
623 | "ladle",
624 | "lampshade, lamp shade",
625 | "laptop, laptop computer",
626 | "lawn mower, mower",
627 | "lens cap, lens cover",
628 | "letter opener, paper knife, paperknife",
629 | "library",
630 | "lifeboat",
631 | "lighter, light, igniter, ignitor",
632 | "limousine, limo",
633 | "liner, ocean liner",
634 | "lipstick, lip rouge",
635 | "Loafer",
636 | "lotion",
637 | "loudspeaker, speaker, speaker unit, loudspeaker system, speaker system",
638 | "loupe, jeweler's loupe",
639 | "lumbermill, sawmill",
640 | "magnetic compass",
641 | "mailbag, postbag",
642 | "mailbox, letter box",
643 | "maillot",
644 | "maillot, tank suit",
645 | "manhole cover",
646 | "maraca",
647 | "marimba, xylophone",
648 | "mask",
649 | "matchstick",
650 | "maypole",
651 | "maze, labyrinth",
652 | "measuring cup",
653 | "medicine chest, medicine cabinet",
654 | "megalith, megalithic structure",
655 | "microphone, mike",
656 | "microwave, microwave oven",
657 | "military uniform",
658 | "milk can",
659 | "minibus",
660 | "miniskirt, mini",
661 | "minivan",
662 | "missile",
663 | "mitten",
664 | "mixing bowl",
665 | "mobile home, manufactured home",
666 | "Model T",
667 | "modem",
668 | "monastery",
669 | "monitor",
670 | "moped",
671 | "mortar",
672 | "mortarboard",
673 | "mosque",
674 | "mosquito net",
675 | "motor scooter, scooter",
676 | "mountain bike, all-terrain bike, off-roader",
677 | "mountain tent",
678 | "mouse, computer mouse",
679 | "mousetrap",
680 | "moving van",
681 | "muzzle",
682 | "nail",
683 | "neck brace",
684 | "necklace",
685 | "nipple",
686 | "notebook, notebook computer",
687 | "obelisk",
688 | "oboe, hautboy, hautbois",
689 | "ocarina, sweet potato",
690 | "odometer, hodometer, mileometer, milometer",
691 | "oil filter",
692 | "organ, pipe organ",
693 | "oscilloscope, scope, cathode-ray oscilloscope, CRO",
694 | "overskirt",
695 | "oxcart",
696 | "oxygen mask",
697 | "packet",
698 | "paddle, boat paddle",
699 | "paddlewheel, paddle wheel",
700 | "padlock",
701 | "paintbrush",
702 | "pajama, pyjama, pj's, jammies",
703 | "palace",
704 | "panpipe, pandean pipe, syrinx",
705 | "paper towel",
706 | "parachute, chute",
707 | "parallel bars, bars",
708 | "park bench",
709 | "parking meter",
710 | "passenger car, coach, carriage",
711 | "patio, terrace",
712 | "pay-phone, pay-station",
713 | "pedestal, plinth, footstall",
714 | "pencil box, pencil case",
715 | "pencil sharpener",
716 | "perfume, essence",
717 | "Petri dish",
718 | "photocopier",
719 | "pick, plectrum, plectron",
720 | "pickelhaube",
721 | "picket fence, paling",
722 | "pickup, pickup truck",
723 | "pier",
724 | "piggy bank, penny bank",
725 | "pill bottle",
726 | "pillow",
727 | "ping-pong ball",
728 | "pinwheel",
729 | "pirate, pirate ship",
730 | "pitcher, ewer",
731 | "plane, carpenter's plane, woodworking plane",
732 | "planetarium",
733 | "plastic bag",
734 | "plate rack",
735 | "plow, plough",
736 | "plunger, plumber's helper",
737 | "Polaroid camera, Polaroid Land camera",
738 | "pole",
739 | "police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria",
740 | "poncho",
741 | "pool table, billiard table, snooker table",
742 | "pop bottle, soda bottle",
743 | "pot, flowerpot",
744 | "potter's wheel",
745 | "power drill",
746 | "prayer rug, prayer mat",
747 | "printer",
748 | "prison, prison house",
749 | "projectile, missile",
750 | "projector",
751 | "puck, hockey puck",
752 | "punching bag, punch bag, punching ball, punchball",
753 | "purse",
754 | "quill, quill pen",
755 | "quilt, comforter, comfort, puff",
756 | "racer, race car, racing car",
757 | "racket, racquet",
758 | "radiator",
759 | "radio, wireless",
760 | "radio telescope, radio reflector",
761 | "rain barrel",
762 | "recreational vehicle, RV, R.V.",
763 | "reel",
764 | "reflex camera",
765 | "refrigerator, icebox",
766 | "remote control, remote",
767 | "restaurant, eating house, eating place, eatery",
768 | "revolver, six-gun, six-shooter",
769 | "rifle",
770 | "rocking chair, rocker",
771 | "rotisserie",
772 | "rubber eraser, rubber, pencil eraser",
773 | "rugby ball",
774 | "rule, ruler",
775 | "running shoe",
776 | "safe",
777 | "safety pin",
778 | "saltshaker, salt shaker",
779 | "sandal",
780 | "sarong",
781 | "sax, saxophone",
782 | "scabbard",
783 | "scale, weighing machine",
784 | "school bus",
785 | "schooner",
786 | "scoreboard",
787 | "screen, CRT screen",
788 | "screw",
789 | "screwdriver",
790 | "seat belt, seatbelt",
791 | "sewing machine",
792 | "shield, buckler",
793 | "shoe shop, shoe-shop, shoe store",
794 | "shoji",
795 | "shopping basket",
796 | "shopping cart",
797 | "shovel",
798 | "shower cap",
799 | "shower curtain",
800 | "ski",
801 | "ski mask",
802 | "sleeping bag",
803 | "slide rule, slipstick",
804 | "sliding door",
805 | "slot, one-armed bandit",
806 | "snorkel",
807 | "snowmobile",
808 | "snowplow, snowplough",
809 | "soap dispenser",
810 | "soccer ball",
811 | "sock",
812 | "solar dish, solar collector, solar furnace",
813 | "sombrero",
814 | "soup bowl",
815 | "space bar",
816 | "space heater",
817 | "space shuttle",
818 | "spatula",
819 | "speedboat",
820 | "spider web, spider's web",
821 | "spindle",
822 | "sports car, sport car",
823 | "spotlight, spot",
824 | "stage",
825 | "steam locomotive",
826 | "steel arch bridge",
827 | "steel drum",
828 | "stethoscope",
829 | "stole",
830 | "stone wall",
831 | "stopwatch, stop watch",
832 | "stove",
833 | "strainer",
834 | "streetcar, tram, tramcar, trolley, trolley car",
835 | "stretcher",
836 | "studio couch, day bed",
837 | "stupa, tope",
838 | "submarine, pigboat, sub, U-boat",
839 | "suit, suit of clothes",
840 | "sundial",
841 | "sunglass",
842 | "sunglasses, dark glasses, shades",
843 | "sunscreen, sunblock, sun blocker",
844 | "suspension bridge",
845 | "swab, swob, mop",
846 | "sweatshirt",
847 | "swimming trunks, bathing trunks",
848 | "swing",
849 | "switch, electric switch, electrical switch",
850 | "syringe",
851 | "table lamp",
852 | "tank, army tank, armored combat vehicle, armoured combat vehicle",
853 | "tape player",
854 | "teapot",
855 | "teddy, teddy bear",
856 | "television, television system",
857 | "tennis ball",
858 | "thatch, thatched roof",
859 | "theater curtain, theatre curtain",
860 | "thimble",
861 | "thresher, thrasher, threshing machine",
862 | "throne",
863 | "tile roof",
864 | "toaster",
865 | "tobacco shop, tobacconist shop, tobacconist",
866 | "toilet seat",
867 | "torch",
868 | "totem pole",
869 | "tow truck, tow car, wrecker",
870 | "toyshop",
871 | "tractor",
872 | "trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi",
873 | "tray",
874 | "trench coat",
875 | "tricycle, trike, velocipede",
876 | "trimaran",
877 | "tripod",
878 | "triumphal arch",
879 | "trolleybus, trolley coach, trackless trolley",
880 | "trombone",
881 | "tub, vat",
882 | "turnstile",
883 | "typewriter keyboard",
884 | "umbrella",
885 | "unicycle, monocycle",
886 | "upright, upright piano",
887 | "vacuum, vacuum cleaner",
888 | "vase",
889 | "vault",
890 | "velvet",
891 | "vending machine",
892 | "vestment",
893 | "viaduct",
894 | "violin, fiddle",
895 | "volleyball",
896 | "waffle iron",
897 | "wall clock",
898 | "wallet, billfold, notecase, pocketbook",
899 | "wardrobe, closet, press",
900 | "warplane, military plane",
901 | "washbasin, handbasin, washbowl, lavabo, wash-hand basin",
902 | "washer, automatic washer, washing machine",
903 | "water bottle",
904 | "water jug",
905 | "water tower",
906 | "whiskey jug",
907 | "whistle",
908 | "wig",
909 | "window screen",
910 | "window shade",
911 | "Windsor tie",
912 | "wine bottle",
913 | "wing",
914 | "wok",
915 | "wooden spoon",
916 | "wool, woolen, woollen",
917 | "worm fence, snake fence, snake-rail fence, Virginia fence",
918 | "wreck",
919 | "yawl",
920 | "yurt",
921 | "web site, website, internet site, site",
922 | "comic book",
923 | "crossword puzzle, crossword",
924 | "street sign",
925 | "traffic light, traffic signal, stoplight",
926 | "book jacket, dust cover, dust jacket, dust wrapper",
927 | "menu",
928 | "plate",
929 | "guacamole",
930 | "consomme",
931 | "hot pot, hotpot",
932 | "trifle",
933 | "ice cream, icecream",
934 | "ice lolly, lolly, lollipop, popsicle",
935 | "French loaf",
936 | "bagel, beigel",
937 | "pretzel",
938 | "cheeseburger",
939 | "hotdog, hot dog, red hot",
940 | "mashed potato",
941 | "head cabbage",
942 | "broccoli",
943 | "cauliflower",
944 | "zucchini, courgette",
945 | "spaghetti squash",
946 | "acorn squash",
947 | "butternut squash",
948 | "cucumber, cuke",
949 | "artichoke, globe artichoke",
950 | "bell pepper",
951 | "cardoon",
952 | "mushroom",
953 | "Granny Smith",
954 | "strawberry",
955 | "orange",
956 | "lemon",
957 | "fig",
958 | "pineapple, ananas",
959 | "banana",
960 | "jackfruit, jak, jack",
961 | "custard apple",
962 | "pomegranate",
963 | "hay",
964 | "carbonara",
965 | "chocolate sauce, chocolate syrup",
966 | "dough",
967 | "meat loaf, meatloaf",
968 | "pizza, pizza pie",
969 | "potpie",
970 | "burrito",
971 | "red wine",
972 | "espresso",
973 | "cup",
974 | "eggnog",
975 | "alp",
976 | "bubble",
977 | "cliff, drop, drop-off",
978 | "coral reef",
979 | "geyser",
980 | "lakeside, lakeshore",
981 | "promontory, headland, head, foreland",
982 | "sandbar, sand bar",
983 | "seashore, coast, seacoast, sea-coast",
984 | "valley, vale",
985 | "volcano",
986 | "ballplayer, baseball player",
987 | "groom, bridegroom",
988 | "scuba diver",
989 | "rapeseed",
990 | "daisy",
991 | "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum",
992 | "corn",
993 | "acorn",
994 | "hip, rose hip, rosehip",
995 | "buckeye, horse chestnut, conker",
996 | "coral fungus",
997 | "agaric",
998 | "gyromitra",
999 | "stinkhorn, carrion fungus",
1000 | "earthstar",
1001 | "hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa",
1002 | "bolete",
1003 | "ear, spike, capitulum",
1004 | "toilet tissue, toilet paper, bathroom tissue"
1005 | )
1006 | }
1007 |
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/ImageClassificationOperation.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import android.graphics.Bitmap
4 | import android.os.SystemClock
5 | import android.util.Log
6 | import androidx.lifecycle.LiveData
7 | import androidx.lifecycle.MutableLiveData
8 | import kotlinx.coroutines.CoroutineDispatcher
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.withContext
11 | import org.pytorch.IValue
12 | import org.pytorch.Module
13 | import org.pytorch.Tensor
14 | import org.pytorch.torchvision.TensorImageUtils
15 |
16 | const val TOP_K = 3
17 |
18 | class ImageClassificationOperation(private val ioDispatcher: CoroutineDispatcher) : ImageAnalysis {
19 | private var analyzeImageErrorState: Boolean = false
20 | private var module: Module? = null
21 | private var inputTensor: Tensor? = null
22 |
23 | private val _result = MutableLiveData(AnalysisResult(arrayOf("Result"), floatArrayOf(0F), 0, 0))
24 | override val result: LiveData = _result
25 |
26 | override suspend fun analyzeImage(
27 | bitmap: Bitmap,
28 | moduleFileAbsoluteFilePath: String
29 | ) {
30 | // Force Main thread
31 | withContext(Dispatchers.Main) {
32 | _result.value = AnalysisResult(arrayOf("Analyse Image..."), floatArrayOf(0F), 0, 0)
33 | _result.value = analyseImageImpl(bitmap, moduleFileAbsoluteFilePath)
34 | }
35 | }
36 |
37 | private suspend fun analyseImageImpl(
38 | bitmap: Bitmap,
39 | moduleFileAbsoluteFilePath: String
40 | ): AnalysisResult? = withContext(ioDispatcher) {
41 | if (analyzeImageErrorState) {
42 | null
43 | }
44 |
45 | try {
46 |
47 | module = Module.load(moduleFileAbsoluteFilePath)
48 |
49 | val startTime = SystemClock.elapsedRealtime()
50 |
51 | inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
52 | bitmap,
53 | TensorImageUtils.TORCHVISION_NORM_MEAN_RGB,
54 | TensorImageUtils.TORCHVISION_NORM_STD_RGB
55 | )
56 |
57 | val moduleForwardStartTime = SystemClock.elapsedRealtime()
58 | val outputTensor = module?.forward(IValue.from(inputTensor))?.toTensor()
59 | val moduleForwardDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime
60 |
61 | val scores = outputTensor?.dataAsFloatArray
62 | scores?.let {
63 | val ixs = Utils.topK(scores, TOP_K)
64 | val topKClassNames = Array(TOP_K) { i -> (i * i).toString() }
65 | val topKScores = FloatArray(TOP_K)
66 | for (i in 0 until TOP_K) {
67 | val ix = ixs[i]
68 | if (ix <= Constants.IMAGE_NET_CLASSNAME.size) {
69 | topKClassNames[i] = Constants.IMAGE_NET_CLASSNAME[ix]
70 | }
71 | topKScores[i] = scores[ix]
72 | }
73 | val analysisDuration = SystemClock.elapsedRealtime() - startTime
74 | AnalysisResult(
75 | topKClassNames,
76 | topKScores,
77 | moduleForwardDuration,
78 | analysisDuration
79 | )
80 | }
81 | } catch (e: Exception) {
82 | Log.e("TAG", "Error during image analysis", e)
83 | analyzeImageErrorState = true
84 | AnalysisResult(
85 | arrayOf("Error during image analysis " + e.message),
86 | floatArrayOf(0F),
87 | 0,
88 | 0
89 | )
90 | null
91 | }
92 | }
93 | }
94 |
95 | interface ImageAnalysis {
96 | val result: LiveData
97 | suspend fun analyzeImage(
98 | bitmap: Bitmap,
99 | moduleFileAbsoluteFilePath: String
100 | )
101 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/Listeners.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import android.content.Intent
4 | import android.provider.MediaStore
5 | import androidx.appcompat.app.AlertDialog
6 | import androidx.appcompat.app.AppCompatActivity
7 |
8 | class Listeners(private val activity: AppCompatActivity) {
9 |
10 | fun showPictureDialog() {
11 | val pictureDialog = AlertDialog.Builder(activity)
12 | pictureDialog.setTitle("Select Action")
13 | val pictureDialogItems = arrayOf("Select photo from gallery", "Capture photo from camera")
14 | pictureDialog.setItems(
15 | pictureDialogItems
16 | ) { _, which ->
17 | when (which) {
18 | 0 -> choosePhotoFromGallary()
19 | 1 -> takePhotoFromCamera()
20 | }
21 | }
22 | pictureDialog.show()
23 | }
24 |
25 | private fun takePhotoFromCamera() {
26 | val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
27 | activity.startActivityForResult(intent, CAMERA)
28 | }
29 |
30 | private fun choosePhotoFromGallary() {
31 | val galleryIntent = Intent(
32 | Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI
33 | )
34 |
35 | activity.startActivityForResult(galleryIntent, GALLERY)
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/LiveDataViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import android.app.Application
4 | import android.graphics.drawable.BitmapDrawable
5 | import android.widget.ImageView
6 | import androidx.lifecycle.AndroidViewModel
7 | import androidx.lifecycle.ViewModel
8 | import androidx.lifecycle.ViewModelProvider
9 | import androidx.lifecycle.viewModelScope
10 | import com.say.pytorchkotlindemo.Utils.assetFilePath
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.launch
13 | import java.io.File
14 |
15 | class LiveDataViewModel(
16 | private val app: Application,
17 | private val imageAnalysis: ImageAnalysis
18 | ) : AndroidViewModel(app) {
19 |
20 | private var moduleAssetName: String = "model_1.pt"
21 |
22 | fun analyseTheImage(imageView: ImageView) {
23 | viewModelScope.launch {
24 | val drawable = imageView.drawable as BitmapDrawable
25 | val bitmap = drawable.bitmap
26 | val moduleFileAbsoluteFilePath = File(
27 | assetFilePath(app, moduleAssetName)
28 | ).absolutePath
29 | imageAnalysis.analyzeImage(bitmap, moduleFileAbsoluteFilePath)
30 | }
31 | }
32 |
33 | val result = imageAnalysis.result
34 | }
35 |
36 | /**
37 | * Factory for [LiveDataViewModel].
38 | */
39 | class LiveDataVMFactory(private val application: Application) :
40 | ViewModelProvider.AndroidViewModelFactory(application) {
41 |
42 | private val imageClassificationOperation = ImageClassificationOperation(Dispatchers.IO)
43 |
44 | override fun create(modelClass: Class): T {
45 | @Suppress("UNCHECKED_CAST")
46 | return LiveDataViewModel(
47 | application, imageClassificationOperation
48 | ) as T
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import android.Manifest
4 | import android.content.Intent
5 | import android.graphics.Bitmap
6 | import android.graphics.ImageDecoder
7 | import android.os.Build
8 | import android.os.Bundle
9 | import android.provider.MediaStore
10 | import android.widget.Toast
11 | import androidx.activity.viewModels
12 | import androidx.appcompat.app.AppCompatActivity
13 | import androidx.databinding.DataBindingUtil
14 | import com.karumi.dexter.Dexter
15 | import com.karumi.dexter.MultiplePermissionsReport
16 | import com.karumi.dexter.PermissionToken
17 | import com.karumi.dexter.listener.PermissionRequest
18 | import com.karumi.dexter.listener.multi.MultiplePermissionsListener
19 | import com.say.pytorchkotlindemo.databinding.ActivityMainBinding
20 | import kotlinx.android.synthetic.main.activity_main.*
21 | import java.io.IOException
22 |
23 | const val GALLERY = 1
24 | const val CAMERA = 2
25 |
26 | class MainActivity : AppCompatActivity() {
27 |
28 | private val viewModel: LiveDataViewModel by viewModels { LiveDataVMFactory(application) }
29 |
30 | override fun onCreate(savedInstanceState: Bundle?) {
31 | super.onCreate(savedInstanceState)
32 |
33 | requestMultiplePermissions()
34 |
35 | // Obtain binding object using the Data Binding library
36 | val binding = DataBindingUtil.setContentView(
37 | this, R.layout.activity_main
38 | )
39 |
40 | // Set the LifecycleOwner to be able to observe LiveData objects
41 | binding.lifecycleOwner = this
42 |
43 | // Bind ViewModel
44 | binding.viewModel = viewModel
45 | binding.listeners = Listeners(this)
46 | }
47 |
48 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
49 | super.onActivityResult(requestCode, resultCode, data)
50 | if (resultCode == RESULT_CANCELED) {
51 | return
52 | }
53 | if (requestCode == GALLERY) {
54 | if (data != null) {
55 | val contentURI = data.data
56 | try {
57 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
58 | val bitmap =
59 | MediaStore.Images.Media.getBitmap(this.contentResolver, contentURI)
60 | Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT).show()
61 | iv.setImageBitmap(bitmap)
62 | } else {
63 | contentURI?.let {
64 | val source = ImageDecoder.createSource(this.contentResolver, it)
65 | val bitmap = ImageDecoder.decodeBitmap(source)
66 | Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT)
67 | .show()
68 | iv.setImageBitmap(bitmap)
69 | }
70 | }
71 | } catch (e: IOException) {
72 | e.printStackTrace()
73 | Toast.makeText(this@MainActivity, "Failed!", Toast.LENGTH_SHORT).show()
74 | }
75 |
76 | }
77 |
78 | } else if (requestCode == CAMERA) {
79 | val thumbnail = data?.extras?.get("data") as Bitmap
80 | iv.setImageBitmap(thumbnail)
81 | Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT).show()
82 | }
83 | }
84 |
85 | private fun requestMultiplePermissions() {
86 | Dexter.withActivity(this)
87 | .withPermissions(
88 | Manifest.permission.CAMERA,
89 | Manifest.permission.READ_EXTERNAL_STORAGE
90 | )
91 | .withListener(object : MultiplePermissionsListener {
92 | override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
93 | // check if all permissions are granted
94 | if (report?.areAllPermissionsGranted()!!) {
95 | Toast.makeText(
96 | applicationContext,
97 | "All permissions are granted by user!",
98 | Toast.LENGTH_SHORT
99 | ).show()
100 | }
101 |
102 | // check for permanent denial of any permission
103 | if (report.isAnyPermissionPermanentlyDenied) {
104 | // show alert dialog navigating to Settings
105 | //openSettingsDialog()
106 | Toast.makeText(
107 | applicationContext,
108 | "openSettingsDialog! ",
109 | Toast.LENGTH_SHORT
110 | )
111 | .show()
112 | }
113 | }
114 |
115 | override fun onPermissionRationaleShouldBeShown(
116 | permissions: MutableList?,
117 | token: PermissionToken?
118 | ) {
119 | token?.continuePermissionRequest()
120 | }
121 | })
122 | .withErrorListener {
123 | Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT)
124 | .show()
125 | }
126 | .onSameThread()
127 | .check()
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/app/src/main/java/com/say/pytorchkotlindemo/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import java.io.File
6 | import java.io.FileOutputStream
7 | import java.io.IOException
8 | import java.util.*
9 |
10 | object Utils {
11 | fun assetFilePath(context: Context, assetName: String): String? {
12 | val file = File(context.filesDir, assetName)
13 |
14 | try {
15 | context.assets.open(assetName).use { `is` ->
16 | FileOutputStream(file).use { os ->
17 | val buffer = ByteArray(4 * 1024)
18 | while (true) {
19 | val length = `is`.read(buffer)
20 | if (length <= 0)
21 | break
22 | os.write(buffer, 0, length)
23 | }
24 | os.flush()
25 | os.close()
26 | }
27 | return file.absolutePath
28 | }
29 | } catch (e: IOException) {
30 | Log.e("pytorchandroid", "Error process asset $assetName to file path")
31 | }
32 |
33 | return null
34 | }
35 |
36 | fun topK(a: FloatArray, topk: Int): IntArray {
37 | val values = FloatArray(topk)
38 | Arrays.fill(values, -java.lang.Float.MAX_VALUE)
39 | val ixs = IntArray(topk)
40 | Arrays.fill(ixs, -1)
41 |
42 | for (i in a.indices) {
43 | for (j in 0 until topk) {
44 | if (a[i] > values[j]) {
45 | for (k in topk - 1 downTo j + 1) {
46 | values[k] = values[k - 1]
47 | ixs[k] = ixs[k - 1]
48 | }
49 | values[j] = a[i]
50 | ixs[j] = i
51 | break
52 | }
53 | }
54 | }
55 | return ixs
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
20 |
21 |
32 |
33 |
44 |
45 |
57 |
58 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PytorchKotlinDemo
3 | Select or Capture Image
4 | Tell me
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/say/pytorchkotlindemo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.say.pytorchkotlindemo
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.3.72'
5 | repositories {
6 | google()
7 | jcenter()
8 |
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:4.0.0'
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 |
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Feb 01 03:55:51 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name='PytorchKotlinDemo'
3 |
--------------------------------------------------------------------------------