2

我正在使用 p5 和 ml5.js 通过我的网络摄像头添加一些图像来训练 ML 模型。火车功能像这样工作得很好。但是,如果我取消注释 train 函数中的 if 语句:

if (lossValue == null)

classifier因为之后的值,undefined它将在下一步中引发错误。为什么会发生这种情况,我该如何解决?如果我只是在 if 语句中使用 console.log,它不会产生问题。但是,如果我在其中使用 setState,它会将分类器设置为未定义。

export const Component: React.FC<ComponentProps> = (props: ComponentProps) => {
    const [prediction, setPrediction] = useState<string>();
    const [confidence, setConfidence] = useState<string>();
    const [trainingComplete, setTrainingComplete] = useState<boolean>();
    //const [lossValue, setLoss] = useState<any>();

    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 modelReady() {
        console.log('Model Ready');
    }

    function videoReady() {
        console.log('Video Ready');
    }


    function gotResult() {
        console.log('classifier in results', classifier);
        classifier.classify(capture, (err: any, result: any) => {
            setPrediction(result[0].label);
            
        });
    }

    function train() {
        console.log('classifier in train', classifier);
        classifier.train((lossValue: any) => {
            console.log('Loss is', lossValue);
            // if (lossValue == null){
            //  setTrainingComplete(true);
            // }
        });
        console.log('classifier in train', classifier);
    }



    return (<div><Sketch setup={setup} draw={draw} className="sketch" />
        <div className="button">
            <Button variant="contained" color="primary" onClick={() => {classifier.addImage('first');console.log('image added')}}>First</Button>
            <Button variant="contained" color="primary" onClick={() => {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 />
        </div>
    </div>)
        ;
};

代码沙盒:

https://codesandbox.io/s/hardcore-solomon-zb34l?file=/src/Component.tsx

4

2 回答 2

4

您正在定义classifier为一个let变量。它不是一个状态,因此它不会在重新渲染中持续存在。每次你的组件被重新渲染时,代码let classifier: any;都会被执行并classifier变成undefined.

当您调用setState这样的函数时,setTrainingComplete(true)会更改组件的状态并使其重新渲染。因此,您失去了 的价值classifier

您想保留 的值,classifier因此您需要使用useStateuseRef钩子来存储它。我通常useRef在处理来自具有自己内部状态的外部库的复杂对象时使用。这就是我在这里的建议。

const classifierRef = useRef<any>();
function train() {
    const classifier = classifierRef.current;
    console.log('classifier in train', classifier);
    classifier?.train((lossValue: any) => {
        console.log('Loss is', lossValue);
        if (lossValue == null) {
            setTrainingComplete(true);
        }
    });
    console.log('classifier in train', classifier);
}
于 2021-04-19T01:32:17.273 回答
1

您还必须为捕获变量添加useRef 。https://dementorwriter.medium.com/picture-classification-with-react-ml5-c45672aeb961

于 2021-08-07T16:32:08.837 回答