实时手势识别(1)- 基于手部检测+手部分类

news2024/11/17 1:38:19

目录

前言

1.实现效果

2.非端到端实现的原因

3.分类网络与数据准备

4.训练结果

5.测试结果

6.训练代码

7.训练日志

7.1ResNet18训练日志

7.2ShuffleNet_v2训练日志


前言

        利用YOLOv8获取手部区域,然后对手部区域进行分类,实现手势识别。

        本文使用检测+分类,对于一类手势只需200张训练图片,即可达到99%的准确率。

        在下一篇基于关键点+关键点分类,无需训练图片,即可实现对任意手势的识别,且达到99%的准确率。

手部检测数据集准备:基于YOLOv8的手部检测(1)- 手部数据集获取(数据集下载、数据清洗、处理与增强)

手部检测模型训练与调优:

基于YOLOv8的手部检测(2)- 模型训练、结果分析和超参数优化


1.实现效果

        hand使用yolov8-m检测得到,resnt表示ResNet18的分类结果,shfnt表示用shufflenet_v2的分类结果,conf是置信度。        


2.非端到端实现的原因

        手可以灵活地做出各种动作,导致手势含有模棱两可的语义。使用端到端的检测,会依赖大量的训练数据(标定大量的标准的动作)。

        用于手部检测分类的动作参考:

基于YOLOv8的手部检测(1)- 手部数据集获取(数据集下载、数据清洗、处理与增强)       

        总共分为以下18个类(外加1个无效类no_gesture):

        考虑以下动作:

        该动作在HaGRID中的标签为:no_gesture。而在观察上,该动作“类似”于将“paml”或者“stop inv”旋转了一定角度

        一方面,如果存在模棱两可的动作,使用端到端检测时,假设“paml”获得0.35的置信度,“stop inv”获得0.25的置信度,“no_gesture”获得0.3的置信度。这样会导致max(conf)=0.35,经过nms或者置信度阈值筛选后,导致手部都被无法检测

        另一方面,就是数据问题,每遇到一个新的手势,端到端网络就还需要重新训练(还需要考虑数据不平衡、各种参数微调等一系列问题)。

        因此,为我们可以训练一个高精度的手部检测模型,再将手势识别作为下游任务,训练一个简单模型去解决。

        本质上,这里还是使用RCNN的思想,用大量的手部数据(容易获得的)训练yolov8,获取高精度手部检测模型。再针对下游任务(手势识别、动作识别等)设计轻量化网络,仅需少量数据(难以获得的),即可进行调优。


3.分类网络与数据准备

        选用ResNet18()shuffle_net_v2。数据集从HaGRID中随机选取,然后读取标签获取标签内的patch

test每类选200张作为训练集,共200×18=3,600张;

val每类选200张作为验证集,共200×18=3,600张;

train每类选200张作为测试集,共500×18=9,000张。如下图所示,

        还有一类no_gesture类作废(缺乏背景语义下,部分手势和其他类别太像):


4.训练结果

        两个网络均使用pytorch官方的预训练模型进行微调,初始学习率设置为0.001,每轮衰减5%,总共训练10轮。

        因为只训练了10轮,ResNet18在测试集上还没有ShuffleNet_v2高,但实测ResNet18效果更好。

        ResNet18训练结果如下:

                    accuracy  macro avg  weighted avg  call  dislike  fist  four  like  mute   ok  one  palm  peace  peace_inverted  rock  stop  stop_inverted  three  three2  two_up  two_up_inverted
support                9000       9000         9000   500      500    500   500   500   500   500   500   500    500              500   500   500           500    500     500     500             500
precision              0.98       0.98         0.98   0.97     1.00   0.99  0.99  0.99  0.99  0.99  0.98  0.99   0.96             0.98  0.99  0.96          1.00   0.98    0.98    0.99            1.00
recall                 0.98       0.98         0.98   1.00     0.99   1.00  0.99  0.97  0.99  0.99  0.97  0.96   0.96             0.99  0.99  0.99          1.00   0.97    0.98    0.99            0.99
f1-score               0.98       0.98         0.98   0.99     1.00   0.99  0.99  0.98  0.99  0.99  0.98  0.97   0.96             0.99  0.99  0.97          1.00   0.98    0.98    0.99            0.99

        ShuffleNet_v2训练结果如下:

                 accuracy  macro avg  weighted avg  call  dislike  fist  four  like  mute   ok  one  palm  peace  peace_inverted  rock  stop  stop_inverted  three  three2  two_up  two_up_inverted
support             9000      9000          9000     500      500   500   500   500   500   500   500   500    500              500   500   500           500    500     500     500             500
precision           0.99      0.99          0.99    0.98     1.00  0.99  0.99  1.00  0.99  0.99  0.99  0.98   0.98             0.97  0.98  0.98          1.00   0.99    0.98    1.00            0.99
recall              0.99      0.99          0.99    1.00     1.00  1.00  0.99  0.99  0.99  0.98  0.97  0.98   0.96             1.00  1.00  0.98          1.00   0.99    0.97    0.99            1.00
f1-score            0.99      0.99          0.99    0.99     1.00  1.00  0.99  0.99  0.99  0.99  0.98  0.98   0.97             0.98  0.99  0.98          1.00   0.99    0.98    0.99            1.00

5.测试结果

        如果动作比较“标注”还是很准的,但是存在视角、遮挡问题时候,准确率就低很多了。尤其视角问题,不加入深度估计,仅用2D识别,限制了准确率的上限。


6.训练代码

        训练用的代码如下,只需指定数据集地址和选用的模型

import os
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms, models
from torchvision.models import ResNet18_Weights
from torchvision.models import shufflenet_v2_x1_0, ShuffleNet_V2_X1_0_Weights
from torch.utils.data import DataLoader
from tqdm import tqdm
from sklearn.metrics import classification_report, accuracy_score, recall_score
import logging
import time
import datetime


# 训练和验证函数
def train_model(model, criterion, optimizer, scheduler, num_epochs=10):
    best_model_wts = model.state_dict()
    best_acc = 0.0

    for epoch in range(num_epochs):
        print(f'Epoch {epoch + 1}/{num_epochs}')
        logger.info(f'Epoch {epoch + 1}/{num_epochs}')
        print('-' * 50)
        logger.info('-' * 50)

        # 每个epoch都有训练和验证阶段
        for phase in ["train", "val"]:
            if phase == "train":
                model.train()  # 设置模型为训练模式
            else:
                model.eval()  # 设置模型为评估模式

            running_loss = 0.0
            running_corrects = 0
            all_labels = []
            all_preds = []

            # 遍历数据
            for inputs, labels in tqdm(dataloaders[phase]):
                inputs = inputs.to(device)
                labels = labels.to(device)

                # 清零梯度
                optimizer.zero_grad()

                # 前向传播
                with torch.set_grad_enabled(phase == "train"):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    # 仅在训练阶段进行反向传播和优化
                    if phase == "train":
                        loss.backward()
                        optimizer.step()

                # 统计
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
                all_labels.extend(labels.cpu().numpy())
                all_preds.extend(preds.cpu().numpy())

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]
            epoch_recall = recall_score(all_labels, all_preds, average='macro')

            print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f} Recall: {epoch_recall:.4f}')
            logger.info(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f} Recall: {epoch_recall:.4f}')

            # 深度复制模型
            if phase == "val" and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = model.state_dict()
                # 保存当前最好的模型
                torch.save(best_model_wts, f"best_model_{model_choose}.pth")
                print(f"模型在第 {epoch + 1} 轮取得最好表现,已保存。")
                logger.info(f"模型在第 {epoch + 1} 轮取得最好表现,已保存。")

        # 学习率衰减
        scheduler.step()

        time.sleep(0.2)

    print(f'Best val Acc: {best_acc:.4f}')
    logger.info(f'Best val Acc: {best_acc:.4f}')
    logger.info(f"最佳模型已保存为: best_model_{model_choose}.pth")
    return model


# 测试模型
def test_model(model):
    model.eval()
    running_corrects = 0
    all_labels = []
    all_preds = []

    with torch.no_grad():
        for inputs, labels in tqdm(dataloaders["test"]):
            inputs = inputs.to(device)
            labels = labels.to(device)

            outputs = model(inputs)
            _, preds = torch.max(outputs, 1)

            running_corrects += torch.sum(preds == labels.data)
            all_labels.extend(labels.cpu().numpy())
            all_preds.extend(preds.cpu().numpy())

    test_acc = accuracy_score(all_labels, all_preds)
    test_recall = recall_score(all_labels, all_preds, average='macro')

    print(f'Test Acc: {test_acc:.4f} Recall: {test_recall:.4f}')
    logger.info(f'Test Acc: {test_acc:.4f} Recall: {test_recall:.4f}')
    print("Per-class accuracy:")
    logger.info("Per-class accuracy:")
    report = classification_report(all_labels, all_preds, target_names=class_names)
    print(report)
    logger.info(report)


if __name__ == "__main__":
    # 设置自定义参数
    model_choose = "resnet18"   # "shuffle_net_v2"
    assert model_choose in ["resnet18", "shuffle_net_v2"], "输入模型名称为:resnet18 或者 shuffle_net_v2"

    # 设置日志文件路径和配置
    timestamp = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    log_filename = f"train_{timestamp}_{model_choose}.log"
    logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s - %(message)s')
    logger = logging.getLogger()

    # 指定数据路径和类别标签
    data_dir = {
        "train": "F:/datasets/hagrid/yolo_cls/test",    # 测试集和验证集每个类都是200张
        "val": "F:/datasets/hagrid/yolo_cls/val",
        "test": "F:/datasets/hagrid/yolo_cls/train"     # 训练集数量多作为测试集
    }

    # 指定类别标签
    hagrid_cate_file = ["call", "dislike", "fist", "four", "like", "mute", "ok", "one", "palm", "peace",
                        "peace_inverted",
                        "rock", "stop", "stop_inverted", "three", "three2", "two_up", "two_up_inverted"]

    hagrid_cate_dict = {hagrid_cate_file[i]: i for i in range(len(hagrid_cate_file))}
    print(hagrid_cate_dict)
    logger.info(f"类别字典: {hagrid_cate_dict}")

    # 超参数设置
    batch_size = 32
    num_epochs = 10
    learning_rate = 0.001

    # 数据预处理和增强
    data_transforms = {
        "train": transforms.Compose([
            transforms.Resize((224, 224)),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
        "val": transforms.Compose([
            transforms.Resize((224, 224)),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
        "test": transforms.Compose([
            transforms.Resize((224, 224)),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
    }

    # 数据集加载
    image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir[x]), data_transforms[x]) for x in
                      ["train", "val", "test"]}
    dataloaders = {x: DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True, num_workers=0) for x in
                   ["train", "val", "test"]}
    dataset_sizes = {x: len(image_datasets[x]) for x in ["train", "val", "test"]}
    class_names = image_datasets["train"].classes

    # 检查类别数是否正确
    assert len(class_names) == len(
        hagrid_cate_file), f"类别数[{len(class_names)}]不匹配文件夹数[{len(hagrid_cate_file)}],请检查数据集文件夹是否正确。"

    # 检查是否有GPU
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    # 使用选择的模型
    if model_choose == "resnet18":
        model = models.resnet18(weights=ResNet18_Weights.IMAGENET1K_V1)
    else:
        model = shufflenet_v2_x1_0(weights=ShuffleNet_V2_X1_0_Weights.IMAGENET1K_V1)

    # 修改全连接层以适应新任务的类别数
    num_ftrs = model.fc.in_features
    model.fc = nn.Linear(num_ftrs, len(hagrid_cate_file))

    # 将模型移动到GPU(如果有的话)
    model = model.to(device)

    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)

    # 定义学习率调度器,每个 epoch 衰减 5%
    scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.95)

    # 训练模型
    model = train_model(model, criterion, optimizer, scheduler, num_epochs=num_epochs)

    # 测试模型
    test_model(model)

7.训练日志

7.1ResNet18训练日志

2024-08-17 11:21:23,641 - 类别字典: {'call': 0, 'dislike': 1, 'fist': 2, 'four': 3, 'like': 4, 'mute': 5, 'ok': 6, 'one': 7, 'palm': 8, 'peace': 9, 'peace_inverted': 10, 'rock': 11, 'stop': 12, 'stop_inverted': 13, 'three': 14, 'three2': 15, 'two_up': 16, 'two_up_inverted': 17}
2024-08-17 11:21:23,889 - Epoch 1/10
2024-08-17 11:21:23,890 - --------------------------------------------------
2024-08-17 11:21:40,028 - train Loss: 0.5494 Acc: 0.8342 Recall: 0.8342
2024-08-17 11:21:47,005 - val Loss: 0.2359 Acc: 0.9264 Recall: 0.9264
2024-08-17 11:21:48,996 - 模型在第 1 轮取得最好表现,已保存。
2024-08-17 11:21:49,204 - Epoch 2/10
2024-08-17 11:21:49,204 - --------------------------------------------------
2024-08-17 11:22:02,927 - train Loss: 0.1531 Acc: 0.9553 Recall: 0.9553
2024-08-17 11:22:10,354 - val Loss: 0.1603 Acc: 0.9503 Recall: 0.9503
2024-08-17 11:22:12,926 - 模型在第 2 轮取得最好表现,已保存。
2024-08-17 11:22:13,131 - Epoch 3/10
2024-08-17 11:22:13,131 - --------------------------------------------------
2024-08-17 11:22:27,164 - train Loss: 0.0930 Acc: 0.9733 Recall: 0.9733
2024-08-17 11:22:34,581 - val Loss: 0.1362 Acc: 0.9564 Recall: 0.9564
2024-08-17 11:22:36,373 - 模型在第 3 轮取得最好表现,已保存。
2024-08-17 11:22:36,577 - Epoch 4/10
2024-08-17 11:22:36,577 - --------------------------------------------------
2024-08-17 11:22:50,791 - train Loss: 0.0715 Acc: 0.9814 Recall: 0.9814
2024-08-17 11:22:57,828 - val Loss: 0.2039 Acc: 0.9286 Recall: 0.9286
2024-08-17 11:22:58,034 - Epoch 5/10
2024-08-17 11:22:58,034 - --------------------------------------------------
2024-08-17 11:23:12,574 - train Loss: 0.0669 Acc: 0.9808 Recall: 0.9808
2024-08-17 11:23:19,866 - val Loss: 0.0915 Acc: 0.9717 Recall: 0.9717
2024-08-17 11:23:21,782 - 模型在第 5 轮取得最好表现,已保存。
2024-08-17 11:23:21,991 - Epoch 6/10
2024-08-17 11:23:21,991 - --------------------------------------------------
2024-08-17 11:23:36,421 - train Loss: 0.0390 Acc: 0.9883 Recall: 0.9883
2024-08-17 11:23:43,620 - val Loss: 0.0788 Acc: 0.9731 Recall: 0.9731
2024-08-17 11:23:45,665 - 模型在第 6 轮取得最好表现,已保存。
2024-08-17 11:23:45,880 - Epoch 7/10
2024-08-17 11:23:45,880 - --------------------------------------------------
2024-08-17 11:24:00,492 - train Loss: 0.0200 Acc: 0.9936 Recall: 0.9936
2024-08-17 11:24:07,786 - val Loss: 0.0890 Acc: 0.9731 Recall: 0.9731
2024-08-17 11:24:07,995 - Epoch 8/10
2024-08-17 11:24:07,995 - --------------------------------------------------
2024-08-17 11:24:22,876 - train Loss: 0.0191 Acc: 0.9944 Recall: 0.9944
2024-08-17 11:24:30,326 - val Loss: 0.0578 Acc: 0.9808 Recall: 0.9808
2024-08-17 11:24:32,870 - 模型在第 8 轮取得最好表现,已保存。
2024-08-17 11:24:33,082 - Epoch 9/10
2024-08-17 11:24:33,082 - --------------------------------------------------
2024-08-17 11:24:47,532 - train Loss: 0.0102 Acc: 0.9983 Recall: 0.9983
2024-08-17 11:24:54,677 - val Loss: 0.0308 Acc: 0.9894 Recall: 0.9894
2024-08-17 11:24:56,289 - 模型在第 9 轮取得最好表现,已保存。
2024-08-17 11:24:56,505 - Epoch 10/10
2024-08-17 11:24:56,505 - --------------------------------------------------
2024-08-17 11:25:11,238 - train Loss: 0.0059 Acc: 0.9983 Recall: 0.9983
2024-08-17 11:25:18,503 - val Loss: 0.0405 Acc: 0.9878 Recall: 0.9878
2024-08-17 11:25:18,712 - Best val Acc: 0.9894
2024-08-17 11:25:18,712 - 最佳模型已保存为: best_model_resnet18.pth
2024-08-17 11:25:37,443 - Test Acc: 0.9849 Recall: 0.9849
2024-08-17 11:25:37,443 - Per-class accuracy:
2024-08-17 11:25:37,461 -                  precision    recall  f1-score   support

           call       0.97      1.00      0.99       500
        dislike       1.00      0.99      1.00       500
           fist       0.99      1.00      0.99       500
           four       0.99      0.99      0.99       500
           like       0.99      0.97      0.98       500
           mute       0.99      0.99      0.99       500
             ok       0.99      0.99      0.99       500
            one       0.98      0.97      0.98       500
           palm       0.99      0.96      0.97       500
          peace       0.96      0.96      0.96       500
 peace_inverted       0.98      0.99      0.99       500
           rock       0.99      0.99      0.99       500
           stop       0.96      0.99      0.97       500
  stop_inverted       1.00      1.00      1.00       500
          three       0.98      0.97      0.98       500
         three2       0.98      0.98      0.98       500
         two_up       0.99      0.99      0.99       500
two_up_inverted       1.00      0.99      0.99       500

       accuracy                           0.98      9000
      macro avg       0.98      0.98      0.98      9000
   weighted avg       0.98      0.98      0.98      9000

7.2ShuffleNet_v2训练日志

2024-08-17 11:17:30,440 - 类别字典: {'call': 0, 'dislike': 1, 'fist': 2, 'four': 3, 'like': 4, 'mute': 5, 'ok': 6, 'one': 7, 'palm': 8, 'peace': 9, 'peace_inverted': 10, 'rock': 11, 'stop': 12, 'stop_inverted': 13, 'three': 14, 'three2': 15, 'two_up': 16, 'two_up_inverted': 17}
2024-08-17 11:17:30,621 - Epoch 1/10
2024-08-17 11:17:30,621 - --------------------------------------------------
2024-08-17 11:17:43,236 - train Loss: 1.5118 Acc: 0.6367 Recall: 0.6367
2024-08-17 11:17:49,254 - val Loss: 0.3228 Acc: 0.9358 Recall: 0.9358
2024-08-17 11:17:49,451 - 模型在第 1 轮取得最好表现,已保存。
2024-08-17 11:17:49,656 - Epoch 2/10
2024-08-17 11:17:49,656 - --------------------------------------------------
2024-08-17 11:17:59,048 - train Loss: 0.2338 Acc: 0.9414 Recall: 0.9414
2024-08-17 11:18:05,083 - val Loss: 0.1439 Acc: 0.9594 Recall: 0.9594
2024-08-17 11:18:05,439 - 模型在第 2 轮取得最好表现,已保存。
2024-08-17 11:18:05,642 - Epoch 3/10
2024-08-17 11:18:05,642 - --------------------------------------------------
2024-08-17 11:18:15,266 - train Loss: 0.1144 Acc: 0.9706 Recall: 0.9706
2024-08-17 11:18:21,317 - val Loss: 0.1059 Acc: 0.9675 Recall: 0.9675
2024-08-17 11:18:21,512 - 模型在第 3 轮取得最好表现,已保存。
2024-08-17 11:18:21,717 - Epoch 4/10
2024-08-17 11:18:21,717 - --------------------------------------------------
2024-08-17 11:18:31,382 - train Loss: 0.0764 Acc: 0.9803 Recall: 0.9803
2024-08-17 11:18:37,578 - val Loss: 0.0775 Acc: 0.9761 Recall: 0.9761
2024-08-17 11:18:37,789 - 模型在第 4 轮取得最好表现,已保存。
2024-08-17 11:18:37,990 - Epoch 5/10
2024-08-17 11:18:37,990 - --------------------------------------------------
2024-08-17 11:18:47,682 - train Loss: 0.0589 Acc: 0.9833 Recall: 0.9833
2024-08-17 11:18:53,721 - val Loss: 0.0632 Acc: 0.9817 Recall: 0.9817
2024-08-17 11:18:53,918 - 模型在第 5 轮取得最好表现,已保存。
2024-08-17 11:18:54,125 - Epoch 6/10
2024-08-17 11:18:54,125 - --------------------------------------------------
2024-08-17 11:19:03,877 - train Loss: 0.0449 Acc: 0.9869 Recall: 0.9869
2024-08-17 11:19:10,379 - val Loss: 0.0748 Acc: 0.9775 Recall: 0.9775
2024-08-17 11:19:10,592 - Epoch 7/10
2024-08-17 11:19:10,592 - --------------------------------------------------
2024-08-17 11:19:20,337 - train Loss: 0.0188 Acc: 0.9964 Recall: 0.9964
2024-08-17 11:19:26,734 - val Loss: 0.0469 Acc: 0.9833 Recall: 0.9833
2024-08-17 11:19:27,107 - 模型在第 7 轮取得最好表现,已保存。
2024-08-17 11:19:27,320 - Epoch 8/10
2024-08-17 11:19:27,320 - --------------------------------------------------
2024-08-17 11:19:37,212 - train Loss: 0.0240 Acc: 0.9942 Recall: 0.9942
2024-08-17 11:19:43,468 - val Loss: 0.0517 Acc: 0.9853 Recall: 0.9853
2024-08-17 11:19:43,664 - 模型在第 8 轮取得最好表现,已保存。
2024-08-17 11:19:43,872 - Epoch 9/10
2024-08-17 11:19:43,872 - --------------------------------------------------
2024-08-17 11:19:53,617 - train Loss: 0.0144 Acc: 0.9953 Recall: 0.9953
2024-08-17 11:19:59,916 - val Loss: 0.0415 Acc: 0.9867 Recall: 0.9867
2024-08-17 11:20:00,167 - 模型在第 9 轮取得最好表现,已保存。
2024-08-17 11:20:00,369 - Epoch 10/10
2024-08-17 11:20:00,369 - --------------------------------------------------
2024-08-17 11:20:10,223 - train Loss: 0.0082 Acc: 0.9992 Recall: 0.9992
2024-08-17 11:20:16,711 - val Loss: 0.0369 Acc: 0.9892 Recall: 0.9892
2024-08-17 11:20:16,910 - 模型在第 10 轮取得最好表现,已保存。
2024-08-17 11:20:17,121 - Best val Acc: 0.9892
2024-08-17 11:20:17,121 - 最佳模型已保存为: best_model_shuffle_net_v2.pth
2024-08-17 11:20:36,232 - Test Acc: 0.9877 Recall: 0.9877
2024-08-17 11:20:36,232 - Per-class accuracy:
2024-08-17 11:20:36,251 -                  precision    recall  f1-score   support

           call       0.98      1.00      0.99       500
        dislike       1.00      1.00      1.00       500
           fist       0.99      1.00      1.00       500
           four       0.99      0.99      0.99       500
           like       1.00      0.99      0.99       500
           mute       0.99      0.99      0.99       500
             ok       0.99      0.98      0.99       500
            one       0.99      0.97      0.98       500
           palm       0.98      0.98      0.98       500
          peace       0.98      0.96      0.97       500
 peace_inverted       0.97      1.00      0.98       500
           rock       0.98      1.00      0.99       500
           stop       0.98      0.98      0.98       500
  stop_inverted       1.00      1.00      1.00       500
          three       0.99      0.99      0.99       500
         three2       0.98      0.97      0.98       500
         two_up       1.00      0.99      0.99       500
two_up_inverted       0.99      1.00      1.00       500

       accuracy                           0.99      9000
      macro avg       0.99      0.99      0.99      9000
   weighted avg       0.99      0.99      0.99      9000

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2049671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

powershell 终端 执行 pnpm -v报错

1.问题描述: 明明全局已安装 pnpm ,但在vscode默认终端 powershell 执行 pnpm -v 却报错: 2.问题根因: 原因是 PowerShell 执行策略问题。 3.解决方案: 以管理员身份运行 PowerShell 查看 PowerShell 的执行策略…

初探systemⅡ·慢思考

本篇笔记记录于 May 30th, 2023 oai联合创始人Andrej曾在微软大会上的报告中有提到LLMs对于人类快、慢思考两种认知推理模式的当下探索与未来展望,这里曾经得到的启示是:未来在模型的训练与推理侧是否会出现一种新的长链认知范式?如在RLHF过程…

秋招突击——8/13——并查集——复习{有塔一面}——新作{亲戚关系}

文章目录 引言复习并查集模板复习——有塔一面 新作亲戚关系 总结 引言 这两天准备腾讯的第二面,看了很多人的面经,发现考并查集的题目蛮多的,这里整理学习一下! 复习 并查集模板 这里学习了B站的麦克老师的课程,对…

MySQL与SQLserver

与MySQL的差别 SQL Server和MySQL都是广泛使用的关系数据库管理系统(RDBMS),它们的SQL语法有很多相似之处,但也存在一些差异。以下是一些主要的语法区别: 1. 数据库和表的创建 SQL Server CREATE DATABASE databas…

Ma Spaghet!

目录 一、题目 二、思路 三、payload 3.1 方案一 3.2 方案二(官方) 四、思考与总结 一、题目 <!-- Challenge --> <h2 id"spaghet"></h2> <script>spaghet.innerHTML (new URL(location).searchParams.get(somebody) || "Somebody…

产品经理-​你做产品经理有什么优势?(39)

你做产品经理有什么优势&#xff1f; 这是一个关于自我认知、个人优势的问题 人贵有自知之明&#xff0c;求职者应该对自己的优缺点有一个客观、深入的认识 大公司往往更加看重你的基本素质&#xff08;逻辑分析、学习能力、潜力等&#xff09; 因为大公司有相对成熟的培养体系…

OpenDDS的Rtps_Udp传输协议可靠性QoS收发基本流程

OpenDDS中,实现了Rtps_Udp传输协议(非纯udp)的可靠性传输。传输的线程包括: 1)发送方线程主要线程和定时器 《1》应用线程 《2》网络异步发送线程 《3》Heartbeat定时器 《4》Nak_response定时器 2)接收方主要线程和定时器 《1》网络异步接收线程 《2》heartbeat_respons…

Java | Leetcode Java题解之第344题反转字符串

题目&#xff1a; 题解&#xff1a; class Solution {public void reverseString(char[] s) {int n s.length;for (int left 0, right n - 1; left < right; left, --right) {char tmp s[left];s[left] s[right];s[right] tmp;}} }

【C++】智能指针详解

一、从new和delete谈起 在C中&#xff0c;可以使用new和delete关键字进行对象的创建和销毁&#xff0c;new一个对象实际上是在堆上分配内存&#xff0c;而new出来的对象也要自己用delete释放&#xff0c;从而回收内存&#xff0c;否则会造成内存的泄露。由程序员自己new来分配…

[手机Linux PostmarketOS]五, docker安装和使用

docker容器 一&#xff0c;docker安装和配置 安装 docker 和 docker-compose&#xff1a; sudo apk add docker docker-cli-compose #安装docker sudo service docker start #启动docker服务 sudo rc-update add docker default #设置docker为自启动可选关…

【PostgreSQL003】PostgreSQL数据表空间膨胀,磁盘爆满,应用宕机(经验总结,已更新)

1.一直以来想写下基于PostgreSQL的系列文章&#xff0c;作为较火的数据ETL工具&#xff0c;也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下PostgreSQL数据库相关知识体系。空间膨胀&#xff08;主键、外键、…

汇编语言:call、call far ptr、call word ptr、call dword ptr、call 寄存器

引言 call指令是转移指令&#xff0c;CPU执行call指令&#xff0c;进行两步操作&#xff1a; &#xff08;1&#xff09;将当前IP或当前CS和IP压入栈中 &#xff08;2&#xff09;转移。call指令不能短转移&#xff0c;除此之外&#xff0c;call指令转移的方法跟jmp指令的原理…

柔性超级电容器咋储能?生物聚合物在其中起啥作用?有啥挑战?

*本文只作阅读笔记分享* 一、引言 随着对化石燃料影响的日益关注&#xff0c;开发用于先进电化学能量存储设备的绿色和可再生材料变得至关重要。超级电容器因其出色的寿命、安全性和宽温度操作范围等优势而成为有前途的储能候选者。柔性超级电容器特别适合为轻质可穿戴电子设…

xss GAME (xss漏洞攻击1-8)

目录 xss网页链接 第一关 第二关 第三关 ​编辑第四关 ​编辑第五关 ​编辑第六关 第七关 第一种 Function构建函数 第二种 tostring parseInt 第三种 silce() ​编辑第八关&#xff08;安全过滤框架 dom破坏&#xff09; xss网页链接 XSS Game - Learning XSS Ma…

linux之网络子系统-GSO/TSO 源码分析

一、GSO/TSO GSO 目前在内核5.10.* 版本时&#xff0c;已经是合入主线&#xff0c;就是对TCP/UDP都支持并且在网络协议栈GSO功能是默认打开的。虽然可以通过ethtool -K 网卡名 gso off 关闭&#xff0c;但是在L3/L4还是走GSO逻辑&#xff0c;关不掉。我目前是没有找到内核源码…

NextJs - 服务端/客户端组件之架构多样性设计

NextJs - 服务端/客户端组件之架构多样性设计 前言一. 架构设计1.1 SSR流式渲染常见错误设计之 - 根页面同步阻塞1.2 架构设计之 - 客户端组件依赖于服务端组件数据① 使用 Redux 完成数据共享 1.3 架构设计之 - 单页内的分步骤跳转① 如何做到服务端组件和客户端组件之间的切换…

libevent之android与鸿蒙编译过程

背景 最近基于libevent开发了一个端侧的缓存代理库&#xff0c;先是基于macOS编译开发的&#xff0c;基本0问题&#xff0c;后来移植到鸿蒙与android时遇到一些编译链接问题。 libevent版本如下&#xff1a; 软件版本号libevent-2.1.8 android编译 编译环境 android studio…

EmguCV学习笔记

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 笔者的博客网址&#xff1a;https://blog.csdn.net/uruseibest 本教程将分为VB.Net和C#两个版本分别进行发布。 教程VB.net版本请…

Go Roadmap-Basics中文笔记

Go Roadmap-Basics 地址&#xff1a;https://roadmap.sh/golang 简介&#xff1a;Github star No.6 学习路线 Go 中译版 Learn the Basics Go特点&#xff1a;静态类型&#xff0c;运行速度快&#xff0c;编译语言&#xff0c;编译速度快&#xff0c;自动垃圾回收&#xff…

【2】初识JVM

目录 一.什么是JVM 二.JVM的功能 2.1即时编译 三.常见的JVM​编辑 ​编辑 总结​编辑 一.什么是JVM 二.JVM的功能 2.1即时编译 三.常见的JVM 总结