【问题标题】:How to deploy a trigger word detection with tensorflow如何使用 tensorflow 部署触发词检测
【发布时间】:2020-04-01 14:26:19
【问题描述】:

我正在研究“触发词检测”模型,我决定将模型部署到我的手机上。

模型的输入形状是(None, 5511, 101)。 输出形状为(None, 1375, 1)

但在实际部署的 App 中,模型无法一次性获取 5511 个时间步,而是手机传感器产生的音频帧是一帧一帧的。

如何将这些数据一一提供给模型并在每个时间步得到输出?

该模型是一个循环模型。但是“model.predict()”的第一个参数是(None,5511,101),我打算做的是

output = []
for i in range(5511): 
    a = model.func(i, (None,1,101))
    output.append(a)

模型结构:

【问题讨论】:

    标签: tensorflow keras lstm recurrent-neural-network


    【解决方案1】:

    这个问题可以通过使时间步长轴动态化来解决。换句话说,当你定义模型时,时间步数应该设置为None。下面是一个示例,说明它如何适用于您的模型的简化版本:

    from keras.layers import GRU, Input, Conv1D
    from keras.models import Model
    import numpy as np
    
    x = Input(shape=(None, 101))
    h = Conv1D(196, 15, strides=4)(x)
    h = GRU(1, return_sequences=True)(h)
    model = Model(x, h)
    
    
    # The model works for the original number of timesteps (5511)
    batch_size = 2
    out = model.predict(np.random.rand(batch_size, 5511, 101))
    print(out.shape)
    
    
    # ... but also for fewer timesteps (say 32)
    out = model.predict(np.random.rand(batch_size, 32, 101))
    print(out.shape)
    
    
    # However, it will not work if timesteps < Conv1D filter_size (15)!
    out = model.predict(np.random.rand(batch_size, 14, 101))
    print(out.shape)
    

    但是请注意,除非您将输入序列填充到 15,否则您将无法输入少于 15 个时间步(Conv1D 过滤器的维度)。

    【讨论】:

      【解决方案2】:

      您应该在循环模型中更改您的模型,您可以一次提供一个数据片段,或者您应该考虑更改模型并及时使用适用于(重叠)窗口的东西,您可以在其中应用模型每隔几条数据,得到一个部分输出。

      仍然取决于模型,您可能只在最后得到您想要的输出。你应该相应地设计它。

      这里是一个例子:https://hacks.mozilla.org/2018/09/speech-recognition-deepspeech/

      【讨论】:

      • 该模型是一个循环模型。但是“model.predict()”采用第一个参数(None,5511,101),而我倾向于做的是“for i in range(5511): model.predict(i, (None,1,101))”
      • 不,你的模型不是一个完全循环的网络。你有一个很大的 Conv1D,你不能一次计算一个。您应该放弃香草 Keras,并按照他们在我发送给您的链接中的建议执行一些操作。
      • 可能一次不要使用 1 个样本。获取样本窗口并使用在窗口上具有 conv1D 的循环模型并继续。
      【解决方案3】:

      为了逐步传递输入,您需要带有stateful=True 的循环层。

      卷积层肯定会阻止你实现你想要的。要么删除它,要么以 15 个步骤为一组传递输入(其中 15 是卷积的内核大小)。

      您需要将这 15 个步骤与步幅 4 进行协调,并且可能需要填充。如果我可以建议,为了避免数学困难,你可以使用kernel_size=16stride=4input_steps = 5512,这是4 的倍数,这是你的步幅值。 (这将避免填充并允许更轻松的计算),并且您的输出步骤将是 1375 完美圆。

      那么你的模型会是这样的:

      inputs = Input(batch_shape=(batch_size,None, 101)) #where you will always use input shapes of (batch_size, 16, 101)
      out = Conv1D(196, 16, strides=4)(inputs)
      ...
      ...
      out = GRU(..., stateful=True)(out)
      ...
      out = GRU(..., stateful=True)(out)
      ...
      ...
      
      model = Model(inputs, out)
      

      stateful=True 模型必须具有固定的批量大小。它可以是 1,但为了优化您的处理速度,如果您有多个序列要并行处理(并且彼此独立),请使用更大的批量大小。

      为了一步一步地工作,首先,您需要重置状态(无论何时使用stateful=True 模型,每次要输入新序列或新批次时,您都需要保持重置状态并行序列)。

      所以:

      #will start a new batch containing a number of sequences equal to batch_size:
      model.reset_states()
      
      #received 16 steps from batch_size sequences:
      steps = an_array_shaped((batch_size, 16, 101))
      
      #for training 
      model.train_on_batch(steps, something_for_y_shaped((batch_size, 1, 1)), ...)
          #I don't recommend to train like this because of the batch normalizations    
          #If you can train the entire length at once, do it.    
          #never forget: for full length training, you would need model.reset_states() every batch. 
      
      #for predicting:
      predictions = model.predict_on_batch(steps, ...)
      
      #received 4 new steps from X sequences:
      steps = np.concatenate([steps[:,4:], new_steps], axis=1)
      
      #these new steps belong to the "same" batch_size sequences! Don't call reset states!
      #repeat one of the above for training or predicting
      new_predictions = model.predict_on_batch(steps, ...)
      predictions = np.concatenate([predictions, new_predictions], axis=1)
      
      #keep repeating this loop until you reach the last step
      
      Finally, when you reached the last step, for safety, call `model.reset_states()` again, everything that you input will be "new" sequences, not new "steps" or the previous sequences. 
      
      ------------
      
      # Training hint
      
      If you are able to train with the full sequences (not step by step), use a `stateful=False` model, train normally with `model.fit(...)`, later you recreate the model exactly, but using `stateful=True`, copy the weights with `new_model.set_weights(old_model.get_weights())`, and use the new model for predicting like above. 
      

      【讨论】:

      • 感谢您的指导性回答!这正是我打算弄清楚的。我还有一个问题:这个训练有素的模型可以在 android 的“tensorflow lite”中工作吗?
      • 因为我没有在 android 的 tf lite 中找到一个类似“reset_states”的 api,而且对 tf 的动态 rnn 的支持也不发达,我想这个解决方案不能在 android 中工作.
      • 我已经在我的 android 中测试了一个只有一层 lstm 且“stateful=True”的简单模型。虽然整个过程没有引发异常,但 tf lite 中的输出与 python 中的原始模型不同。
      • 在python中,模型的输出是十个随机数,而在tf lite中输出的是十个相同的数。
      猜你喜欢
      • 2016-05-04
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-04
      • 2014-12-17
      相关资源
      最近更新 更多