V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ALLROBOT
V2EX  ›  程序员

请教一下,肌电的手势分类的应该用啥 CNN 模型?

  •  
  •   ALLROBOT · 2022-04-10 19:31:10 +08:00 · 1706 次点击
    这是一个创建于 939 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我不知道用什么 CNN 分类器能很好预测值

    16 个电极模拟的值,每列代表某个电极在人体表面读取的生物信号强度数值,等数据缩放完了,数据格式大概如下:

    [[-0.00001221  0.00001285  0.00000142 -0.00000145  0.00000089  0.00000128
      -0.00000432 -0.0000021  -0.00001083 -0.00000186 -0.000001   -0.00000192
       0.00000232  0.00000245 -0.00000036  0.00000399]
     [-0.00001103  0.00001196 -0.00000081 -0.00000296  0.00000162  0.00000013
      -0.00000231 -0.0000021  -0.00000726 -0.00000127  0.00000254 -0.00000042
       0.00000163  0.00000758 -0.00000008  0.00000972]
       ...
       ]
    

    若使用 PIL 的 Image.fromarray(200 条 16 列的数值矩阵),输出为: image9a8ecb040d8e6004.png

    假若手打出 6 的手势,那么 16 个电极的一些电极贴近弯曲 3 个手指向后的手臂肌肉层能读取比较大的数值

    可是,我用以下的代码训练几百轮,结果预测效果不太好,好几次预测,总是把实际值为 1 的手势预测输出 6

        def CNN(input_shape=(100,16,1), classes=9):
            X_input = Input(input_shape)
    
            X = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='tanh', name='conv1')(
                X_input)
            X = MaxPooling2D(pool_size=(10, 1), strides=(10, 1), name='pool1')(X)
    
            X = Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='tanh', name='conv2')(X)
            X = MaxPooling2D(pool_size=(2, 1), strides=(2, 1), name='pool2')(X)
    
            X = Conv2D(filters=128, kernel_size=(3, 1), strides=(1, 1), padding='same', activation='tanh', name='conv3')(X)
            X = MaxPooling2D(pool_size=(2, 1), strides=(2, 1), name='pool3')(X)
    
            X = Flatten(name='flatten')(X)
            X = Dropout(0.5)(X)
            X = Dense(64, activation='tanh', name='fc1')(X)
            X = Dropout(0.4)(X)
            X = Dense(64, activation='tanh', name='fc2')(X)
            X = Dropout(0.3)(X)
            X = Dense(classes, activation='softmax')(X)
    
            model = Model(inputs=X_input, outputs=X, name='MultipleCNN')
            return model
            
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
    model.fit(X_train, Y_train, epochs=500, batch_size=64, verbose=1,validation_data=(X_test, Y_test), callbacks=callbacks_list)
    
    

    输出

    ......
    Epoch 00999: val_accuracy did not improve from 0.82502
    Epoch 1000/1000
    138/138 [==============================] - 1s 8ms/step - loss: 0.0639 - accuracy: 0.9790 - val_loss: 1.0930 - val_accuracy: 0.8060
    
    Epoch 01000: val_accuracy did not improve from 0.82502
    276/276 [==============================] - 1s 3ms/step - loss: 0.0034 - accuracy: 0.9990
    Train Loss = 0.003447444410994649
    Train Accuracy = 0.9989800453186035
    69/69 [==============================] - 0s 3ms/step - loss: 1.0930 - accuracy: 0.8060
    Test Loss = 1.0929756164550781
    Test Accuracy = 0.8059836626052856
    time: 1228.2580664157867
    

    我迷糊了,测试集有 80%准确率,我实际测了十几下,怎么都是预测错的😂

    兄弟萌,这种数据应该用啥模型的比较好?

    第 1 条附言  ·  2022-04-10 21:11:08 +08:00
    顺便求指教,更改模型结构需要什么诀窍,才能使识别精度上来呢
    第 2 条附言  ·  2022-04-10 22:43:48 +08:00
    CNN 预测不准的问题解决了,是我的提取数据的一个步骤出错了
    23 条回复    2022-04-10 23:27:58 +08:00
    airqj
        1
    airqj  
       2022-04-10 19:48:38 +08:00
    从 vgg 枚举到最新模型不就知道了 :)
    ALLROBOT
        2
    ALLROBOT  
    OP
       2022-04-10 20:23:37 +08:00
    @airqj #1 VGG 枚举到最新模型?原谅我,我是深度学习野路子的,你说的 VGG 怎么枚举到最新模型我真不知道😂

    (网上有 VGG 模型,我姑且试试看吧)
    ALLROBOT
        3
    ALLROBOT  
    OP
       2022-04-10 20:59:25 +08:00
    问了导师结果被喷了😢,说我 CNN 模型和别人的太重复了,写不出来新什么东西

    我问能用 VGG 模型,导师一顿狂喷为啥非要用别人的模型,你就不能改一改网络结构吗,至少把精度提高到 90%

    😢😢😢 @airqj #1 能指教一下怎么改模型吗

    虽然自学了吴恩达、周志华的课程,对于这些模型结构我比较陌生,有什么改模型的诀窍吗,求指路😥
    jdhao
        4
    jdhao  
       2022-04-10 21:07:06 +08:00 via Android
    vgg 肯定不行,都是处理二维图像的,你的数据是一维的,别听不懂的人在那瞎扯淡。

    大概率你需要自己试试不同的模型,或者特征上下点功夫,对特征做一些特征工程变换?
    ALLROBOT
        5
    ALLROBOT  
    OP
       2022-04-10 21:08:42 +08:00
    @jdhao #4 VGG 应该可以的,因为我把肌电数据处理成二维图像,再输入到模型中
    ALLROBOT
        6
    ALLROBOT  
    OP
       2022-04-10 21:10:08 +08:00
    导师带过几个涉及深度学习的项目😂
    @jdhao #4
    jdhao
        7
    jdhao  
       2022-04-10 21:14:59 +08:00 via Android
    @ALLROBOT 你这数据就 16 维,你怎么转图像? vgg 输入都是 224*224*3 的图像
    ALLROBOT
        8
    ALLROBOT  
    OP
       2022-04-10 21:18:51 +08:00 via Android
    @jdhao 以时间窗滑动,每个时间窗内的 16 列数据处理成( 100 ,16 ,1 )
    Cortez
        9
    Cortez  
       2022-04-10 21:33:38 +08:00
    @ALLROBOT 不是 1 行 16 列的信号对应一个动作嘛?
    Calibans
        10
    Calibans  
       2022-04-10 21:38:40 +08:00 via iPhone
    试试 lstm 或者 transformer
    nightwitch
        11
    nightwitch  
       2022-04-10 21:44:38 +08:00
    刚好做过类似的,只是我是在骨架的数据上做的。 在测试集上准确度和现实场景中的准确度会差很多,因为在现实场景下做手势动作的情况太多变了,数据集覆盖不了真实情况。真实的数据流是没有明确的起始和结束的,数据会和你数据集里切好段的差很多。

    你把在测试集上的准确度提上来以后,在真实场景下用还要调很久,不是简单套个模型就 ok 的
    airqj
        12
    airqj  
       2022-04-10 21:55:53 +08:00
    @jdhao 大把模型把一维数据转成二维数据然后用 cnn 来识别,比如有的语音识别就先把语音信号来个 fft 处理再输入 cnn
    @ALLROBOT 怪我没审好题。你这数据才 16 维,感觉都用不到 cnn,xgboost 大法试试
    ALLROBOT
        13
    ALLROBOT  
    OP
       2022-04-10 21:56:34 +08:00 via Android
    @Cortez 各个电极的值加起来除以电极的个数得到均值,如果高于休息状态的均值视为活动段,此时时间窗开始滑动

    @Calibans 好的,我正想用几个模型看看呢


    @nightwitch 真实场景一般怎么调的正好提高精度哈?

    我不是手动打标签的,给肌电设了阈值,某个电极的高于阈值可以视为活动段开始,低于的视为结束

    关于数据集,我尽可能覆盖面广一点,不同动作或力度的同一手势都收集看看
    ALLROBOT
        14
    ALLROBOT  
    OP
       2022-04-10 21:57:55 +08:00 via Android
    @airqj 网上的数据集是 16 列的,现实的传感器仅有 6 个(#-.-)
    ttgo
        15
    ttgo  
       2022-04-10 21:58:54 +08:00
    在一个展会上学生区里见过个类似的,512 还是 128 来着长度的信号识别手势,人家就用了两个 fc 。。
    ALLROBOT
        16
    ALLROBOT  
    OP
       2022-04-10 21:59:45 +08:00 via Android
    @Cortez 再补充一下,每行 16 列是传感器几百次采样频率中的一次
    airqj
        17
    airqj  
       2022-04-10 22:05:34 +08:00
    @ALLROBOT 说不定回归模型还靠谱一些 🐶
    Gezqh
        18
    Gezqh  
       2022-04-10 22:11:27 +08:00
    是时间序列的数据么?可以找一些专门用来对多维时间序列进行分类的模型吧?
    Gezqh
        19
    Gezqh  
       2022-04-10 22:12:07 +08:00
    或者是将时间序列数据转换成梅尔频谱试试(时域到频域)?
    ALLROBOT
        20
    ALLROBOT  
    OP
       2022-04-10 22:39:16 +08:00
    @ttgo #15 很惭愧,我比不上人家调的优秀

    @Gezqh #18 大概不是?时间序列是随着时间流动收集数据的,模型按不同时间预测数据可能对应的状态,而肌电活动段按时间窗口分割的,单单提取一个时间窗口不分时间前后,模型只对一个时间窗内的不同电极的生物信号强度,负责对比各列的数值大小从而预测对应的状态,预测状态和上一个或下一个时间窗口关系不大(如果时间窗口包括休息状态的肌电,预测容易出错)
    Cortez
        21
    Cortez  
       2022-04-10 22:41:20 +08:00
    @ALLROBOT 我怎么理解的是这个跟时间没关系啊,为什么用时间窗呢?如果每行 16 列是一个数据,各列的顺序又是固定的,哪怕是传感器几百次采样频率中的一次,那也就是一个姿势你可以采集很多组几乎相同的样本,这时候只要后期处理数据时注意 balance 就可以了。等训练好后,每次读出一组 16 列数据就可以进行一次分类。
    ALLROBOT
        22
    ALLROBOT  
    OP
       2022-04-10 23:05:51 +08:00
    @Cortez #21 不用时间窗的话,错误率比较高,我无法确保一帧能传达准确的信息(技术有限,我做不到一帧能预测准确)

    和语音识别有点类似,分析语音信号的连续几十帧分别对应什么值,语音识别只分析一帧的话....
    Cortez
        23
    Cortez  
       2022-04-10 23:27:58 +08:00
    @ALLROBOT 那如果用时间窗口的话也应该是在每行之内进行卷积,跨行咋解释?
    语音识别和这个不一样,语音是和时间相关的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1225 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 18:01 · PVG 02:01 · LAX 10:01 · JFK 13:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.