如何在 sagas 中使用异步加载的资产和 react native?

How to use async loaded assets in sagas with react native?

我正在使用 redux-saga 和 tensorflow js 构建一个 Expo 应用程序。初始化应用程序时必须异步加载模型。在所有示例中,模型都加载到组件中并存储在组件的状态中。

但是我想在 saga 中而不是直接在组件中执行推理。

我不知道如何编写初始化过程以便能够从 saga 中访问加载的模型。

App.js 我有以下内容:

export default class App extends React.Component {
  state = {
    isLoadingComplete: false,
  };

  render() {
    if (!this.state.isLoadingComplete) {
      return (
        <AppLoading
          startAsync={this._loadResourcesAsync}
          onError={this._handleLoadingError}
          onFinish={this._handleFinishLoading}
        />
      )
    } else {
      return (
        <Provider store={store}>
           .....
        </Provider>
      )
    }

并且我已将 tfjs doc 模型的初始化和预热代码放入 this._loadResourcesAsync:

  _loadResourcesAsync = async () => {
    await Promise.all([
      Asset.loadAsync([
        require('./assets/images/splash.png'),
        require('./assets/images/icon.png'),
      ]),
      Font.loadAsync({
        ...Icon.MaterialIcons.font,
        ...Icon.MaterialCommunityIcons.font,
        ...Icon.FontAwesome.font,
        ...Icon.Feather.font,
      }),
      tf.ready(),
    ])
    const modelUrl = 'https://storage.googleapis.com/tfjs-models/savedmodel/mobilenet_v2_1.0_224/model.json';
    const model = await tf.loadGraphModel(modelUrl);
    const zeros = tf.zeros([1, 224, 224, 3]);
    model.predict(zeros).print();
  };

我不知道以后如何在 saga 中访问这个模型。

编辑

@senthil 建议使用单例模式后,我尝试将此代码放在单独的文件中或直接放在 _loadResourcesAsync 中,但这会使应用程序崩溃

const modelUrl = 'https://storage.googleapis.com/tfjs-models/savedmodel/mobilenet_v2_1.0_224/model.json';

let instance;

async function createInstance() {
  console.log("createInstance")
  const model = await tf.loadGraphModel(modelUrl);
  console.log("model", model)
  // Warm-up
  const zeros = tf.zeros([1, 224, 224, 3]);
  console.log("zeros", zeros)
  model.predict(zeros).print();
  return {model}
}

async function getInstance() {
  console.log("getInstance")
  console.log("instance", instance)
  if (!instance) {
    instance = await createInstance();
  }
  return instance;
}

const {model} = await getInstance()
console.log("encoder", model)

在日志中我看到代码卡在 const model = await tf.loadGraphModel(modelUrl);

在这种情况下,您必须保持状态,例如

// let's assume, this is your App.js
import MLModel from "./MLModel";

export default class App extends React.Component {
  state = {
    isLoadingComplete: false,
  };

  render() {
    if (!this.state.isLoadingComplete) {
      return (
        <AppLoading
          startAsync={async () => { 
             await this._loadOtherResources();
             MLModel.loadModel(() => {
                this.setState({isLoadingComplete:true});
             })
           }}
          onError={this._handleLoadingError}
          onFinish={this._handleFinishLoading}
        />
      )
    } else {
      return (
        <Provider store={store}>
           .....
        </Provider>
      )
    }

在你的 MLModel.js

// MlModel.js file should have a class

class MLModel {
   let model = null;

   getModel(){
     return this.model;
   }

   async loadModel(onModelLoadCompleteCallback) {
    const modelUrl = '<URL>';
    const model = await tf.loadGraphModel(modelUrl);
    // I'm not sure what'll below line do exactly like mutate or return
    // I'm assuming this is async and will mutate the model object.
    await model.predict(zeros).print();
    this.model = model;
    onModelLoadCompleteCallback();
   }
}

export default new MLMoldel();

以同样的方式,您也应该能够从其他任何地方加载模型。

注意:我没有执行和检查,可能有一些编译错误忽略它们,但最终这是我想传达的东西。