我在我的React应用程序中使用ml5.js设置,我单击一个按钮来训练模型,然后单击另一个按钮进行预测。Test按钮在第一次工作,但在第二次抛出错误:
TypeError: Cannot read property 'classify' of undefined我相信这是因为一旦我运行预测部分,模型就会被删除?因为分类器现在未定义。我如何修改它,以便我可以反复单击Test按钮,并每次都获得新的预测。
我尝试了save()函数,但显然它只下载模型,而不是为应用程序保存模型。
export const Video: React.FC<ComponentProps> = (props: ComponentProps) => {
const [prediction, setPrediction] = useState<string>();
let capture: p5Types.Element;
let classifier: any;
const setup = (p5: p5Types, canvasParentRef: Element) => {
capture = p5.createCapture(p5.VIDEO).parent(canvasParentRef);
const featureExtractor = ml5.featureExtractor('MobileNet', modelReady);
classifier = featureExtractor.classification(capture, videoReady);
}
const draw = (p5: p5Types) => {
}
function gotResult() {
classifier.classify(capture, (err: any, result: any) => {
setPrediction(result[0].label);
});
}
function train() {
classifier.train((lossValue: any) => {
console.log('Loss is', lossValue);
});
//classifier.save();
}
return (<div><Sketch setup={setup} draw={draw} className="sketch" />
<div className="button">
<Button variant="contained" color="primary" onClick={() => classifier.addImage('first')}>First</Button>
<Button variant="contained" color="primary" onClick={() => classifier.addImage('second')}>Second</Button>
</div>
<div className="secondbutton">
<Button variant="contained" color="primary" onClick={() => train()}>Train!</Button>
<Button variant="contained" color="primary" onClick={() => gotResult()}>Test!</Button>
<br />
<span>Prediction: {prediction}</span>
</div>
</div>)
;
};Codesandbox:
https://codesandbox.io/s/hardcore-solomon-zb34l?file=/src/Component.tsx
更新代码:
export const VideoComponent: React.FC<ComponentProps> = (props: ComponentProps) => {
const [prediction, setPrediction] = useState<string>();
const [confidence, setConfidence] = useState<string>();
const [trainingComplete, setTrainingComplete] = useState<boolean>();
const captureRef = useRef<p5Types.Element>();
const classifierRef = useRef<any>();
const setup = (p5: p5Types, canvasParentRef: Element) => {
const capture = p5.createCapture(p5.VIDEO).parent(canvasParentRef);
const featureExtractor = ml5.featureExtractor("MobileNet", modelReady);
captureRef.current = capture;
classifierRef.current = featureExtractor.classification(capture, videoReady);
}
const draw = (p5: p5Types) => {
}
function gotResult() {
console.log('classifier in results', classifierRef.current);
classifierRef.current.classify(captureRef.current, (err: any, result: any) => {
setPrediction(result[0].label);
setConfidence(result[0].confidence);
});
}
function train() {
console.log('classifier in train', classifierRef.current);
classifierRef.current?.classify.train((lossValue: any) => {
console.log('Loss is', lossValue);
if (lossValue == null) {
//setTrainingComplete(true);
console.log('training complete')
}
});
}
return (
<div>
<Sketch setup={setup} draw={draw} className="sketch" />
<div className="button">
<Button variant="contained" color="primary" onClick={() => { classifierRef.current?.classifier.addImage('first'); console.log('image added') }}>First</Button>
<Button variant="contained" color="primary" onClick={() => { classifierRef.current?.classifier.addImage('second'); console.log('image added') }}>Second</Button>
</div>
<div className="secondbutton">
<Button variant="contained" color="primary" onClick={() => train()}>Train!</Button>
<Button variant="contained" color="primary" onClick={() => gotResult()}>Test!</Button>
<br />
{trainingComplete && (<span>Training Complete!</span>)}<br />
<span>Prediction: {prediction}</span><br />
</div>
</div>)
;
};发布于 2021-04-19 09:17:10
问题出在您用来存储有状态数据的两个let变量capture和classifier上。
let capture: p5Types.Element;
let classifier: any;
const setup = (p5: p5Types, canvasParentRef: Element) => {
capture = p5.createCapture(p5.VIDEO).parent(canvasParentRef);
const featureExtractor = ml5.featureExtractor('MobileNet', modelReady);
classifier = featureExtractor.classification(capture, videoReady);
}每次重新渲染时都会重新创建这些变量。如果你想让实例变量在重新渲染时保持不变,那么你需要使用useState或useRef。由于这两个变量来自p5包,并且可能会被其他函数修改,因此我认为useRef可能就是您在这里需要的。你可以使用read more about useRef in the React docs。
您需要在代码中添加一些额外的条件检查,因为captureRef.current可以是一个Element或undefined,因此在使用它之前,您需要确保您有一个Element。对于classifier,您可以像这样使用optional chaining operator:classifierRef.current?.classify()。
const captureRef = useRef<p5Types.Element>();
const classifierRef = useRef<any>();
const setup = (p5: p5Types, canvasParentRef: Element) => {
// I'm assigning to a variable before assigning to the ref
// so that we know that it is always defined inside this function
const capture = p5.createCapture(p5.VIDEO).parent(canvasParentRef);
const featureExtractor = ml5.featureExtractor("MobileNet", modelReady);
captureRef.current = capture;
classifierRef.current = featureExtractor.classification(capture, videoReady);
console.log("start", classifierRef.current);
};您应该尝试为classifier而不是any查找或创建一个实际的类型。它看起来像there is no types package for ml5,但是someone created a draft。
https://stackoverflow.com/questions/67116772
复制相似问题