【发布时间】:2020-06-25 05:49:07
【问题描述】:
我正在开发一个 React 应用程序,使用 Tensorflow.js 根据图像对 Pokemon 进行分类。
-
我想要什么 - 上传口袋妖怪的图片,为同一个口袋妖怪生成预测。
-
实际发生的情况 - 当我上传一张图片进行预测时,输出始终是前一张图片。所以,第一个预测总是垃圾(随机口袋妖怪)。我上传第二个口袋妖怪时得到的预测总是针对第一个口袋妖怪。上传后的第 3 个 Pokemon 会预测第 2 个 Pokemon,依此类推。
请参阅问题的底部,了解它在哪些地方有效和在哪些地方无效。
这里是相关的代码-
-
我首先检查模型是否存在于
indexeddb,如果存在,我将其加载到状态model。如果没有,我从服务器获取它并将其存储在状态中。这就是第一个useEffect在第一次渲染页面时所做的事情。 -
我使用另一个
useEffect,只要findState.uploadedImage更改,它就会运行。这种状态存在于 Redux-toolkit 中。
这是问题的简短演示 => https://youtu.be/MX70zbupNWQ
这是应用网址 => https://poke-zoo.herokuapp.com/
这是 Github 存储库 => https://github.com/theairbend3r/poke-zoo/tree/master/frontend/src/features/find
这是文件SearchOutput.js。这会获取模型并进行预测。
const SearchOutput = () => {
const findState = useSelector(selectorFind)
const dispatch = useDispatch()
const imageRef = useRef(null)
const [model, setModel] = useState(null)
const [predictions, setPredictions] = useState([])
const MODEL_HTTP_URL = "api/pokeml/classify"
const MODEL_INDEXEDDB_URL = "indexeddb://poke-model"
useEffect(() => {
async function fetchModel() {
try {
const localClassifierModel = await tf.loadLayersModel(
MODEL_INDEXEDDB_URL
)
setModel(localClassifierModel)
console.log("Model loaded from IndexedDB")
} catch (e) {
const classifierModel = await tf.loadLayersModel(MODEL_HTTP_URL)
setModel(classifierModel)
await classifierModel.save(MODEL_INDEXEDDB_URL)
console.error(e)
}
}
fetchModel()
}, [])
const getTopKPred = (pred, k) => {
const predIdx = []
const predNames = []
const topkPred = [...pred].sort((a, b) => b - a).slice(0, k)
topkPred.map(i => predIdx.push(pred.indexOf(i)))
predIdx.map(i => predNames.push(idx2class[i]))
return predNames
}
useEffect(() => {
async function makePredictions() {
if (imageRef && model) {
try {
const imgTensor = tf.browser
.fromPixels(imageRef.current)
.resizeNearestNeighbor([160, 160])
.toFloat()
.sub(127.5)
.div(127.5)
.expandDims()
const y_pred = await model.predict(imgTensor).dataSync()
const topkPredNames = getTopKPred(y_pred, 5)
console.log(topkPredNames)
return topkPredNames
} catch (e) {
console.log("Unable to run predictions.")
}
}
}
makePredictions()
}, [findState.uploadedImage])
return (
<div>
{findState.uploadedImage && (
<img
ref={imageRef}
tw="border border-purple-700 p-1 rounded shadow-lg"
src={findState.uploadedImage}
width={600}
height={600}
/>
)}
<div>
{findState.matchesFound.length === 6 &&
findState.matchesFound.map(poke => (
<PokemonCardML
key={`key-${poke.id}`}
pokemonId={poke.id}
pokemonName={poke.name}
pokemonType={poke.type}
pokemonHeight={poke.height}
pokemonWeight={poke.weight}
pokemonBaseExperience={poke.baseExperience}
pokemonSprite={poke.sprites}
/>
))}
</div>
</div>
)
}
这是文件findSlice.js,它将输入图像存储到redux状态。
import { createSlice } from "@reduxjs/toolkit"
import axios from "axios"
const initialState = {
uploadedImage: "",
model: null,
matchesFound: [],
}
export const findSlice = createSlice({
name: "find",
initialState: initialState,
reducers: {
storeInputImage: (state, action) => {
state.uploadedImage = action.payload.uploadedImage
},
setModel: (state, action) => {
state.model = action.payload.model
},
},
})
export const selectorFind = state => state.find
export const { storeInputImage, setModel } = findSlice.actions
export default findSlice.reducer
有关问题的详细信息。
### Desktop
#### Table
| | Ubuntu | Windows | MacOS |
| ------- | :---------: | :--------------: | :--------------: |
| Firefox | not working | not working | not working |
| Chrome | not working | somewhat working | somewhat working |
| Safari | NA | NA | somewhat working |
#### Comments
| | Ubuntu | Windows | MacOS |
| :-----: | :--------------------------------------------------------------------------: | :--------------------------------------------------------------------------: | :--------------------------------------------------------------------------: |
| Firefox | Predictions are always one step behin for both Captured and Uploaded images. | Predictions are always one step behin for both Captured and Uploaded images. | Predictions are always one step behin for both Captured and Uploaded images. |
| Chrome | Works only on Captured Images. Uploaded images give same predictions always. | Works only on Captured Images. Uploaded images give same predictions always. | Works only on Captured Images. Uploaded images give same predictions always. |
| Safari | NA | NA | Works only on Captured Images. Uploaded images give same predictions always. |
### Mobile
#### Table
| | Android | iOS |
| ------- | :--------------: | :--------------: |
| Firefox | somewhat working | not working |
| Chrome | somewhat working | not working |
| Safari | NA | somewhat working |
#### Comments
| | Android | iOS |
| :-----: | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Firefox | No predictions load for a captured image. Works on uploaded images only. | Camera does not load. Uploaded images give same predictions always. |
| Chrome | Works on capture images only. Uploaded images give same predictions always. | Camera does not load. Uploaded images give same predictions always. |
| Safari | NA | Works only on Captured Images. Uploaded images give same predictions always. |
编辑:基于以下建议。这并没有解决问题。放在这里供参考。
const SearchOutput = () => {
const findState = useSelector(selectorFind)
const [imageRef, setImageRef] = useState(null)
const onChangeRef = useCallback(node => {
setImageRef(node)
}, [])
const [model, setModel] = useState(null)
const [predictions, setPredictions] = useState([])
const MODEL_HTTP_URL = "api/pokeml/classify"
const MODEL_INDEXEDDB_URL = "indexeddb://poke-model"
useEffect(() => {
async function fetchModel() {
try {
const localClassifierModel = await tf.loadLayersModel(
MODEL_INDEXEDDB_URL
)
setModel(localClassifierModel)
console.log("Model loaded from IndexedDB")
} catch (e) {
try {
const classifierModel = await tf.loadLayersModel(MODEL_HTTP_URL)
setModel(classifierModel)
await classifierModel.save(MODEL_INDEXEDDB_URL)
console.log("Model saved to IndexedDB")
} catch (e) {
console.log("Unable to load model at all: ", e)
}
}
}
fetchModel()
}, [])
useEffect(() => {
async function makePredictions() {
if (imageRef && model) {
console.log(
"Uploaded Image from inside the useEffect",
findState.uploadedImage
)
console.log("ImageRef from inside the useEffect", imageRef.current)
try {
const imgTensor = tf.browser
.fromPixels(imageRef.current)
.resizeNearestNeighbor([160, 160])
.toFloat()
.sub(127)
.div(127)
.expandDims()
const y_pred = await model.predict(imgTensor).data()
console.log(y_pred)
console.log(pokemonState)
const topkPredNames = getTopKPredPokeObj(y_pred, 6, pokemonState)
dispatch(storePredictions({ predictions: topkPredNames }))
console.log(topkPredNames)
return topkPredNames
} catch (e) {
console.log("Unable to run predictions.", e)
}
}
}
makePredictions()
}, [findState.uploadedImage])
return (
<div>
{findState.uploadedImage && (
<img
ref={onChangeRef}
src={findState.uploadedImage}
width="600"
height="600"
/>
)}
</div>
)
}
export default SearchOutput
【问题讨论】:
标签: reactjs tensorflow react-redux react-hooks tensorflow.js