mirror of
https://github.com/wassname/keras-js.git
synced 2026-09-11 12:20:53 +08:00
update ResNet50 demo
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
export const IMAGE_URLS = [
|
||||
{ name: 'cat', value: 'http://i.imgur.com/CzXTtJV.jpg' },
|
||||
{ name: 'dog', value: 'http://i.imgur.com/OB0y6MR.jpg' },
|
||||
{ name: 'bridge', value: 'http://i.imgur.com/Bvke53p.jpg' }
|
||||
]
|
||||
@@ -10,13 +10,11 @@ const MODEL_FILEPATHS_DEV = {
|
||||
weights: '/demos/data/mnist_cnn/mnist_cnn_weights.buf',
|
||||
metadata: '/demos/data/mnist_cnn/mnist_cnn_metadata.json'
|
||||
}
|
||||
|
||||
const MODEL_FILEPATHS_PROD = {
|
||||
model: 'demos/data/mnist_cnn/mnist_cnn.json',
|
||||
weights: 'https://transcranial.github.io/keras-js-demos-data/mnist_cnn/mnist_cnn_weights.buf',
|
||||
metadata: 'demos/data/mnist_cnn/mnist_cnn_metadata.json'
|
||||
}
|
||||
|
||||
const MODEL_CONFIG = {
|
||||
filepaths: (process.env.NODE_ENV === 'production') ? MODEL_FILEPATHS_PROD : MODEL_FILEPATHS_DEV
|
||||
}
|
||||
|
||||
@@ -8,13 +8,11 @@ const MODEL_FILEPATHS_DEV = {
|
||||
weights: '/demos/data/mnist_vae/mnist_vae_weights.buf',
|
||||
metadata: '/demos/data/mnist_vae/mnist_vae_metadata.json'
|
||||
}
|
||||
|
||||
const MODEL_FILEPATHS_PROD = {
|
||||
model: 'demos/data/mnist_vae/mnist_vae.json',
|
||||
weights: 'https://transcranial.github.io/keras-js-demos-data/mnist_vae/mnist_vae_weights.buf',
|
||||
metadata: 'demos/data/mnist_vae/mnist_vae_metadata.json'
|
||||
}
|
||||
|
||||
const MODEL_CONFIG = {
|
||||
filepaths: (process.env.NODE_ENV === 'production') ? MODEL_FILEPATHS_PROD : MODEL_FILEPATHS_DEV
|
||||
}
|
||||
|
||||
+12
-11
@@ -79,7 +79,7 @@
|
||||
height: 160px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
@@ -92,8 +92,13 @@
|
||||
padding: 6px 0;
|
||||
|
||||
.output-label {
|
||||
text-align: right;
|
||||
width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-family: $font-2;
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
color: $color-2;
|
||||
padding: 0 6px;
|
||||
border-right: 2px solid $color-1-lighter;
|
||||
@@ -101,18 +106,14 @@
|
||||
|
||||
.output-bar {
|
||||
height: 8px;
|
||||
transition: height 0.2s ease-out;
|
||||
}
|
||||
|
||||
.output-bar-rest {
|
||||
height: 8px;
|
||||
background: none;
|
||||
transition: width 0.2s ease-out;
|
||||
}
|
||||
|
||||
.output-value {
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
margin-left: 5px;
|
||||
font-family: $font-2;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
color: $color-2;
|
||||
}
|
||||
}
|
||||
@@ -120,7 +121,7 @@
|
||||
.output-class.predicted {
|
||||
.output-label {
|
||||
color: $color-1;
|
||||
border-right-color: $color-1;
|
||||
border-left-color: $color-1;
|
||||
}
|
||||
|
||||
.output-value {
|
||||
|
||||
+29
-11
@@ -5,6 +5,7 @@ import ndarray from 'ndarray'
|
||||
import ops from 'ndarray-ops'
|
||||
import find from 'lodash/find'
|
||||
import * as utils from './utils'
|
||||
import { IMAGE_URLS } from './image-urls'
|
||||
import { ARCHITECTURE_DIAGRAM, ARCHITECTURE_CONNECTIONS } from './resnet50-arch'
|
||||
|
||||
const MODEL_FILEPATHS_DEV = {
|
||||
@@ -12,23 +13,15 @@ const MODEL_FILEPATHS_DEV = {
|
||||
weights: '/demos/data/resnet50/resnet50_weights.buf',
|
||||
metadata: '/demos/data/resnet50/resnet50_metadata.json'
|
||||
}
|
||||
|
||||
const MODEL_FILEPATHS_PROD = {
|
||||
model: 'demos/data/resnet50/resnet50.json',
|
||||
weights: 'https://transcranial.github.io/keras-js-demos-data/resnet50/resnet50_weights.buf',
|
||||
metadata: 'demos/data/resnet50/resnet50_metadata.json'
|
||||
}
|
||||
|
||||
const MODEL_CONFIG = {
|
||||
filepaths: (process.env.NODE_ENV === 'production') ? MODEL_FILEPATHS_PROD : MODEL_FILEPATHS_DEV
|
||||
}
|
||||
|
||||
const IMAGE_URL_LIST = [
|
||||
{ name: 'cat', value: 'http://i.imgur.com/CzXTtJV.jpg' },
|
||||
{ name: 'dog', value: 'http://i.imgur.com/OB0y6MR.jpg' },
|
||||
{ name: 'bridge', value: 'http://i.imgur.com/Bvke53p.jpg' }
|
||||
]
|
||||
|
||||
/**
|
||||
*
|
||||
* VUE COMPONENT
|
||||
@@ -46,7 +39,7 @@ export const ResNet50 = Vue.extend({
|
||||
modelRunning: false,
|
||||
imageURLInput: null,
|
||||
imageURLSelect: null,
|
||||
imageURLSelectList: IMAGE_URL_LIST,
|
||||
imageURLSelectList: IMAGE_URLS,
|
||||
imageLoading: false,
|
||||
imageLoadingError: false,
|
||||
output: null,
|
||||
@@ -77,7 +70,13 @@ export const ResNet50 = Vue.extend({
|
||||
return this.model.layersWithResults
|
||||
},
|
||||
outputClasses: function () {
|
||||
if (!this.output) return []
|
||||
if (!this.output) {
|
||||
let empty = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
empty.push({ name: '.', probability: 0 })
|
||||
}
|
||||
return empty
|
||||
}
|
||||
return utils.imagenetClassesTopK(this.output, 5)
|
||||
}
|
||||
},
|
||||
@@ -134,6 +133,11 @@ export const ResNet50 = Vue.extend({
|
||||
},
|
||||
|
||||
loadImageToCanvas: function (url) {
|
||||
if (!url) {
|
||||
this.clearAll()
|
||||
return
|
||||
}
|
||||
|
||||
this.imageLoading = true
|
||||
loadImage(
|
||||
url,
|
||||
@@ -174,7 +178,7 @@ export const ResNet50 = Vue.extend({
|
||||
|
||||
// data processing
|
||||
// see https://github.com/fchollet/keras/blob/master/keras/applications/imagenet_utils.py
|
||||
let dataTensor = ndarray(data, [width, height, 4])
|
||||
let dataTensor = ndarray(new Float32Array(data), [width, height, 4])
|
||||
let dataProcessedTensor = ndarray(new Float32Array(width * height * 3), [width, height, 3])
|
||||
ops.subseq(dataTensor.pick(null, null, 0), 103.939)
|
||||
ops.subseq(dataTensor.pick(null, null, 1), 116.779)
|
||||
@@ -190,6 +194,20 @@ export const ResNet50 = Vue.extend({
|
||||
this.output = outputData['fc1000']
|
||||
this.modelRunning = false
|
||||
})
|
||||
},
|
||||
|
||||
clearAll: function () {
|
||||
this.modelRunning = false
|
||||
this.imageURLInput = null
|
||||
this.imageURLSelect = null
|
||||
this.imageLoading = false
|
||||
this.imageLoadingError = false
|
||||
this.output = null
|
||||
|
||||
this.model.layersWithResults = []
|
||||
|
||||
const ctx = document.getElementById('input-canvas').getContext('2d')
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -46,17 +46,14 @@
|
||||
<div class="column output-column">
|
||||
<div class="output">
|
||||
<div class="output-class"
|
||||
:class="{ 'predicted': $index === 0 }"
|
||||
v-for="entry in outputClasses"
|
||||
:class="{ 'predicted': i === 0 && outputClasses[i].probability.toFixed(2) > 0 }"
|
||||
v-for="i in [0, 1, 2, 3, 4]"
|
||||
>
|
||||
<div class="output-label">{{ entry.name }}</div>
|
||||
<div class="output-label">{{ outputClasses[i].name }}</div>
|
||||
<div class="output-bar"
|
||||
style="width: {{ Math.round(100 * entry.probability) }}px; background: rgba(27, 188, 155, {{ entry.probability.toFixed(2) }});"
|
||||
style="width: {{ Math.round(100 * outputClasses[i].probability) }}px; background: rgba(27, 188, 155, {{ outputClasses[i].probability.toFixed(2) }});"
|
||||
></div>
|
||||
<div class="output-bar-rest"
|
||||
style="width: {{ 100 - Math.round(100 * entry.probability) }}px;"
|
||||
></div>
|
||||
<div class="output-value">{{ Math.round(100 * entry.probability) }}%</div>
|
||||
<div class="output-value">{{ Math.round(100 * outputClasses[i].probability) }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user