「弱小和无知不是生存的障碍,傲慢才是」|

shumei52

园龄:1年7个月粉丝:9关注:1

神经网络入门之三 C环境部署

此篇文章在2022年12月5日被记录

入门神经网络三

C环境部署

  • 为什么要部署到C环境

上面两篇文章中,我们详细讲解了采集样本与样本训练,生成了一个模型文件,经过测试我们的模型成功率在90%以上,但是我们想将这个模型利用起来,实时检测我们的运动姿态,在ESP32上运行torch显然是不现实的。因此我们将参数保存下来,用C语言复现一遍,在esp32上运算这样才有实际使用价值。

  • 网络结构中的数据变化

我们的第一层网络结构为5个卷积核的卷积层(包含relu),第二层为pooling的下采样,第三层为全连接层,传入的数据为3*50的数据,数据变化结构如下:

  1. 经过第一层五个卷积核的卷积后成为5X1X48的数据
  2. 经过relu后变为全大于5X1X48全大于零的数据
  3. 经过pool下采样后变为5X1X24的数据
  4. 将5个卷积完成的数据拉直,成为1X120的数据
  5. 三个全连接层参数分别乘积+偏执参数,得到1X3的数据,最终最大值为结果
  • 从模型中中读取参数,做成C语言可以调用的数组:

上文提到在这个网址https://netron.app/,可以查看我们训练生成的模型,当然也可以查看模型的详细参数,如图是五个卷积核的参数,我们将它保存下来做成C数组存起来供后面调用。我们需要保存的参数总共有5个卷积核,三个全连接参数,三个全连接偏执参数,其中的五个卷积核偏执参数我没有引入,因为我认为它的作用太小了(其实是因为不知道咋算),我保存在/C_CNN_TEST/parameters.h。

img

  • C语言建立网络:

定义静态数组:

float convout[5][48] = {0}; //卷积完成的结果

float poolout[5][24] = {0}; //下采样完成的结果

float NormalizationOut[120] = {0}; //拍扁完成的结果

float linearOut[3] = {0}; //全连接层完成的结果

卷积激活操作:

void convetAndRelu(float in[3][50], float w[3][3], float out[48]) //用一种很笨的方法完成了卷积,仅仅适用于这个网络
{
    float sum = 0;
    for (int i = 0; i < 48; i++)
    {
        sum += in[0][i] * w[0][0];
        sum += in[0][i + 1] * w[0][3];
        sum += in[0][i + 2] * w[0][2];
        sum += in[1][i] * w[1][0];
        sum += in[1][i + 1] * w[1][4];
        sum += in[1][i + 2] * w[1][2];
        sum += in[2][i] * w[2][0];
        sum += in[2][i + 1] * w[2][5];
        sum += in[2][i + 2] * w[2][2];
        (sum > 0) ? (out[i] = sum) : (out[i] = 0);
        sum = 0;
    }
}

下采样

void pool(float in[48], float out[24]) //下采样
{
    for (int i = 0; i < 24; i++)
    {
        (in[2 * i] > in[2 * i + 1]) ? (out[i] = in[2 * i]) : (out[i] = in[2 * i + 1]);
    }
}

归一操作

void Normalization(float in1[24], float in2[24], float in3[24], float in4[24], float in5[24], float out[120]) //归一化
{
    for (int i = 0; i < 24; i++)
    {
        out[i] = in1[i];
        out[24 + i] = in2[i];
        out[48 + i] = in3[i];
        out[72 + i] = in4[i];
        out[96 + i] = in5[i];
    }
}

全连接操作

void Linear(float in[120], float lin1[120], float lin2[120], float lin3[120], float out[3]) //全连接
{
    for (int i = 0; i < 120; i++)
    {
        out[0] += in[i] * lin1[i];

        out[1] += in[i] * lin2[i];

        out[2] += in[i] * lin3[i];
    }
    out[0] += lin_bias[0]; //全连接层加bias
    out[1] += lin_bias[1];
    out[2] += lin_bias[2];
}

对外开放调用接口

void NetWork(float input[3][50])
{
    //printf("convetAndReluAndpool\n");
    for (int i = 0; i < 5; i++)
    {
        convetAndRelu(input, w[i], convout[i]);
        pool(convout[i], poolout[i]);
    }
    //printf("Normalization\n");
    Normalization(poolout[0], poolout[1], poolout[2], poolout[3], poolout[4], NormalizationOut);
    //printf("Linear\n");
    Linear(NormalizationOut, liner1, liner2, liner3, linearOut);
//    printf("rest=%f", linearOut[0]);
//    printf("walk=%f", linearOut[1]);
//    printf("run=%f\n", linearOut[2]);
    if (linearOut[0] > linearOut[1])
    {
        if (linearOut[0] > linearOut[2])
        {
            printf("state is rest\n");
        }
        else
        {
            printf("state is run\n");
        }
    }
    else
    {
        printf("state is walk\n");
    }
    // SoftmaxFunc(linearOut,softmaxOut,3);
}

调用接口

NetWork(run_sample[3][50]);

C语言测试

我把python中的测试数据转换为C文件可调用的数组,在C环境下测试,休息与走路状态的正确率为100%,跑步状态下的准确率在70%往上。

esp32测试

我将网络移植到ESP32,间隔一段时间读取三轴的加速度数据,预测运动状态,当前运动状态用板载蜂鸣器表示,最终可以获得不错的预测结果:
uint16_t value_index = 0;
void loop() {
  delay(153); //为什么是152ms,是因为采集数据的时候写道flash里面也需要时间,这部分不能省略
  if(value_index<50)
  {
      mpu6050.update();
      acc_buffer[0][value_index] = (float)mpu6050.getAccX()*1000;
      acc_buffer[1][value_index] = (float)mpu6050.getAccY()*1000;
      acc_buffer[2][value_index] = (float)mpu6050.getAccZ()*1000;
      value_index++;   
  }
  else
  {
      value_index = 0;
      beepbeep(NetWork(acc_buffer));
  }
}

后记,我的C语言功底比较差,用最简单的方式实现了网络预测,现在有较好的C语言深度学习框架,可以直接拿来使用:
https://github.com/tsk15535904190/TinyMaix
https://github.com/tsk15535904190/libonnx

本文作者:shumei52

本文链接:https://www.cnblogs.com/shumei52/p/18599779

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   shumei52  阅读(53)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起