首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TypeError:无法读取未定义的属性'classify‘(保存ml5.js模型)

TypeError:无法读取未定义的属性'classify‘(保存ml5.js模型)
EN

Stack Overflow用户
提问于 2021-04-16 06:32:01
回答 1查看 152关注 0票数 0

我在我的React应用程序中使用ml5.js设置,我单击一个按钮来训练模型,然后单击另一个按钮进行预测。Test按钮在第一次工作,但在第二次抛出错误:

代码语言:javascript
复制
TypeError: Cannot read property 'classify' of undefined

我相信这是因为一旦我运行预测部分,模型就会被删除?因为分类器现在未定义。我如何修改它,以便我可以反复单击Test按钮,并每次都获得新的预测。

我尝试了save()函数,但显然它只下载模型,而不是为应用程序保存模型。

代码语言:javascript
复制
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

更新代码:

代码语言:javascript
复制
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>)
        ;
};
EN

回答 1

Stack Overflow用户

发布于 2021-04-19 09:17:10

问题出在您用来存储有状态数据的两个let变量captureclassifier上。

代码语言:javascript
复制
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);
}

每次重新渲染时都会重新创建这些变量。如果你想让实例变量在重新渲染时保持不变,那么你需要使用useStateuseRef。由于这两个变量来自p5包,并且可能会被其他函数修改,因此我认为useRef可能就是您在这里需要的。你可以使用read more about useRef in the React docs

您需要在代码中添加一些额外的条件检查,因为captureRef.current可以是一个Elementundefined,因此在使用它之前,您需要确保您有一个Element。对于classifier,您可以像这样使用optional chaining operatorclassifierRef.current?.classify()

代码语言:javascript
复制
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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67116772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档