背景意义

随着人工智能技术的迅猛发展,计算机视觉在各个领域的应用日益广泛,尤其是在物体识别和定位方面。麻将作为一种深受欢迎的传统棋牌游戏,其复杂的牌面结构和多样的牌型使得麻将识别成为计算机视觉领域的一项挑战。传统的麻将识别方法往往依赖于手工特征提取和规则设定,难以适应不同的环境和牌局变化。因此,基于深度学习的自动化麻将识别与定位系统的研究显得尤为重要。

本研究旨在基于改进的YOLOv11模型,构建一个高效的麻将识别与定位系统。YOLO(You Only Look Once)系列模型以其快速的检测速度和较高的准确率在实时物体检测中表现出色。通过对YOLOv11进行改进,我们期望能够提升其在麻将牌识别中的性能,尤其是在复杂背景和不同光照条件下的适应能力。

本项目使用的数据集包含36个类别的麻将牌,包括各种花色和特殊牌型,共计414张经过标注的图像。这些图像经过了多种预处理和数据增强技术,确保了模型训练的多样性和鲁棒性。通过引入数据增强方法,如随机高斯模糊,进一步提升了模型的泛化能力,使其能够更好地适应现实场景中的变化。

本研究不仅具有重要的学术价值,也为麻将游戏的智能化发展提供了技术支持。通过实现高效的麻将识别与定位系统,可以为在线麻将游戏、智能麻将桌等应用提供基础,推动传统文化与现代科技的融合,具有广泛的社会和经济意义。

图片效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据集信息

本项目的数据集专注于麻将识别与定位系统的训练,旨在改进YOLOv11模型的性能,以实现对麻将牌的高效识别与定位。数据集的主题围绕“4”展开,涵盖了麻将游戏中常见的多种牌型,具有丰富的多样性和复杂性。数据集共包含36个类别,具体类别包括:b1至b9的基本牌,baopai(宝牌)、baoting(报听)、chi(吃牌)、gang(杠牌)、guo(过牌)、peng(碰牌),以及多种特定的牌型标识(t1至t9和w1至w9),最后还有x2、x3和z等类别。这些类别不仅涵盖了麻将的基本构成,还涉及了游戏中的策略和玩法,为模型的训练提供了全面的基础。

数据集分为训练集、验证集和测试集,分别存放在指定的路径下,确保模型在不同阶段的学习和评估。训练集包含丰富的样本,旨在帮助模型学习麻将牌的特征和识别规律;验证集则用于调整模型参数,以提高其在未见数据上的表现;测试集则是对模型最终性能的检验,确保其在实际应用中的有效性和准确性。

通过使用这一数据集,研究人员可以深入探索麻将牌的视觉特征,并利用YOLOv11的先进技术进行实时识别与定位。这一系统的成功实现不仅能够提升麻将游戏的智能化水平,还能为相关领域的研究提供重要的数据支持和实践基础。整体而言,本项目的数据集为麻将识别与定位系统的研究提供了坚实的基础,具有广泛的应用前景和研究价值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心代码

以下是代码中最核心的部分,并附上详细的中文注释:

import torch
import torch.nn as nn
import torch.nn.functional as F

定义相对位置的函数

def rel_pos(kernel_size):
# 创建一个从-1到1的线性空间,步数为kernel_size
tensors = [torch.linspace(-1, 1, steps=kernel_size) for _ in range(2)]
# 生成网格坐标
kernel_coord = torch.stack(torch.meshgrid(*tensors), dim=-0)
kernel_coord = kernel_coord.unsqueeze(0) # 增加一个维度
return kernel_coord

定义SMP卷积层

class SMPConv(nn.Module):
def init(self, planes, kernel_size, n_points, stride, padding, groups):
super().init()

    self.planes = planes  # 输出通道数
    self.kernel_size = kernel_size  # 卷积核大小
    self.n_points = n_points  # 点的数量
    self.init_radius = 2 * (2/kernel_size)  # 初始化半径

    # 计算卷积核的相对位置
    kernel_coord = rel_pos(kernel_size)
    self.register_buffer('kernel_coord', kernel_coord)  # 注册为buffer,不会被优化

    # 初始化权重坐标
    weight_coord = torch.empty(1, n_points, 2)
    nn.init.trunc_normal_(weight_coord, std=0.2, a=-1., b=1.)  # 使用截断正态分布初始化
    self.weight_coord = nn.Parameter(weight_coord)  # 权重坐标作为可学习参数

    # 初始化半径
    self.radius = nn.Parameter(torch.empty(1, n_points).unsqueeze(-1).unsqueeze(-1))
    self.radius.data.fill_(value=self.init_radius)

    # 初始化权重
    weights = torch.empty(1, planes, n_points)
    nn.init.trunc_normal_(weights, std=.02)  # 使用截断正态分布初始化
    self.weights = nn.Parameter(weights)  # 权重作为可学习参数

def forward(self, x):
    # 生成卷积核
    kernels = self.make_kernels().unsqueeze(1)
    x = x.contiguous()  # 确保输入张量是连续的
    kernels = kernels.contiguous()

    # 根据输入数据类型选择合适的深度可分离卷积实现
    if x.dtype == torch.float32:
        x = _DepthWiseConv2dImplicitGEMMFP32.apply(x, kernels)
    elif x.dtype == torch.float16:
        x = _DepthWiseConv2dImplicitGEMMFP16.apply(x, kernels)
    else:
        raise TypeError("Only support fp32 and fp16, get {}".format(x.dtype))
    return x        

def make_kernels(self):
    # 计算卷积核的差异
    diff = self.weight_coord.unsqueeze(-2) - self.kernel_coord.reshape(1, 2, -1).transpose(1, 2)  # [1, n_points, kernel_size^2, 2]
    diff = diff.transpose(2, 3).reshape(1, self.n_points, 2, self.kernel_size, self.kernel_size)
    diff = F.relu(1 - torch.sum(torch.abs(diff), dim=2) / self.radius)  # 计算卷积核的权重

    # 计算最终的卷积核
    kernels = torch.matmul(self.weights, diff.reshape(1, self.n_points, -1))  # [1, planes, kernel_size*kernel_size]
    kernels = kernels.reshape(1, self.planes, *self.kernel_coord.shape[2:])  # [1, planes, kernel_size, kernel_size]
    kernels = kernels.squeeze(0)
    kernels = torch.flip(kernels.permute(0, 2, 1), dims=(1,))  # 反转卷积核
    return kernels

定义SMPCNN模块

class SMPCNN(nn.Module):
def init(self, in_channels, out_channels, kernel_size, stride, groups, n_points=None, n_points_divide=4):
super().init()
self.kernel_size = kernel_size
if n_points is None:
n_points = int((kernel_size**2) // n_points_divide) # 计算点的数量

    padding = kernel_size // 2
    # 使用SMP卷积和标准卷积组合
    self.smp = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,
                       stride=stride, padding=padding, groups=groups, n_points=n_points)
    self.small_kernel = 5
    self.small_conv = Conv(in_channels, out_channels, self.small_kernel, stride, self.small_kernel // 2, groups, act=False)

def forward(self, inputs):
    out = self.smp(inputs)  # 通过SMP卷积层
    out += self.small_conv(inputs)  # 加上小卷积的输出
    return out

定义SMPBlock模块

class SMPBlock(nn.Module):
def init(self, in_channels, dw_channels, lk_size, drop_path, n_points=None, n_points_divide=4):
super().init()
self.pw1 = conv_bn_relu(in_channels, dw_channels, 1, 1, 0, groups=1) # 逐点卷积
self.pw2 = conv_bn(dw_channels, in_channels, 1, 1, 0, groups=1) # 逐点卷积
self.large_kernel = SMPCNN(in_channels=dw_channels, out_channels=dw_channels, kernel_size=lk_size,
stride=1, groups=dw_channels, n_points=n_points, n_points_divide=n_points_divide)
self.lk_nonlinear = nn.ReLU() # 激活函数
self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() # 路径丢弃

def forward(self, x):
    out = self.pw1(x)  # 逐点卷积
    out = self.large_kernel(out)  # 大卷积核处理
    out = self.lk_nonlinear(out)  # 激活
    out = self.pw2(out)  # 逐点卷积
    return x + self.drop_path(out)  # 残差连接

代码核心部分说明:
SMPConv: 这是一个自定义的卷积层,使用了相对位置编码和可学习的权重坐标来生成卷积核。
SMPCNN: 这个模块结合了SMP卷积和小卷积,增强了特征提取能力。
SMPBlock: 这是一个块结构,包含逐点卷积和SMP卷积,支持残差连接和路径丢弃。
这些部分是整个模型的核心,负责特征提取和信息传递。

这个程序文件 SMPConv.py 定义了一些用于深度学习的卷积模块,主要是针对卷积神经网络(CNN)进行优化和扩展。代码中包含了多个类和函数,主要包括 SMPConv、SMPCNN、SMPCNN_ConvFFN 和 SMPBlock,它们的设计目的是为了提高卷积操作的灵活性和效率。

首先,文件中导入了一些必要的库,包括 PyTorch 的核心模块和一些自定义的卷积模块。接着,定义了一个辅助函数 rel_pos,用于生成相对位置的张量,这在后续的卷积操作中会用到。

SMPConv 类是文件的核心部分,它继承自 nn.Module。在初始化方法中,定义了一些参数,包括输出通道数、卷积核大小、点数、步幅和填充等。通过调用 rel_pos 函数,生成卷积核的坐标,并注册为缓冲区。接着,初始化权重坐标和半径,并定义权重参数。forward 方法实现了前向传播,调用 make_kernels 方法生成卷积核,并根据输入数据的类型选择合适的深度可分离卷积实现。

make_kernels 方法计算卷积核的具体形状和权重,使用了重塑和矩阵乘法等操作来生成最终的卷积核。该方法还实现了对半径的限制,以确保在训练过程中保持稳定。

get_conv2d 函数根据输入参数决定使用自定义的 SMPConv 还是标准的 nn.Conv2d,以便在特定条件下使用优化的卷积实现。enable_sync_bn 和 get_bn 函数用于选择同步批归一化或普通批归一化。

conv_bn 和 conv_bn_relu 函数分别用于构建带有批归一化和激活函数的卷积层,方便在模型中使用。

SMPCNN 类结合了 SMPConv 和一个小卷积层,通过前向传播将两者的输出相加,以增强特征提取能力。

SMPCNN_ConvFFN 类实现了一个前馈网络模块,包含了两个逐点卷积层和一个非线性激活函数,结合了 DropPath 技术以提高模型的鲁棒性。

最后,SMPBlock 类将多个模块组合在一起,形成一个完整的块结构,包括逐点卷积、SMP 卷积和激活函数,并实现了残差连接。

整体来看,这个文件实现了一种灵活的卷积结构,旨在通过自定义的卷积操作和组合策略来提高卷积神经网络的性能,适用于各种深度学习任务。

10.4 CTrans.py
以下是经过简化并注释的核心代码部分:

import torch
import torch.nn as nn
import numpy as np
from torch.nn import Dropout, Softmax, LayerNorm

class Channel_Embeddings(nn.Module):
“”“从图像的补丁和位置生成嵌入”“”
def init(self, patchsize, img_size, in_channels):
super().init()
img_size = (img_size, img_size) # 将图像大小转换为元组
patch_size = (patchsize, patchsize) # 将补丁大小转换为元组
n_patches = (img_size[0] // patch_size[0]) * (img_size[1] // patch_size[1]) # 计算补丁数量

    # 定义补丁嵌入层
    self.patch_embeddings = nn.Sequential(
        nn.MaxPool2d(kernel_size=5, stride=5),  # 最大池化层
        nn.Conv2d(in_channels=in_channels,
                  out_channels=in_channels,
                  kernel_size=patchsize // 5,
                  stride=patchsize // 5)  # 卷积层
    )

    # 定义位置嵌入参数
    self.position_embeddings = nn.Parameter(torch.zeros(1, n_patches, in_channels))
    self.dropout = Dropout(0.1)  # Dropout层

def forward(self, x):
    """前向传播,生成嵌入"""
    if x is None:
        return None
    x = self.patch_embeddings(x)  # 通过补丁嵌入层
    x = x.flatten(2)  # 展平
    x = x.transpose(-1, -2)  # 转置
    embeddings = x + self.position_embeddings  # 添加位置嵌入
    embeddings = self.dropout(embeddings)  # 应用Dropout
    return embeddings

class Attention_org(nn.Module):
“”“自定义的多头注意力机制”“”
def init(self, vis, channel_num):
super(Attention_org, self).init()
self.vis = vis
self.KV_size = sum(channel_num) # 键值对的大小
self.channel_num = channel_num
self.num_attention_heads = 4 # 注意力头的数量

    # 定义查询、键、值的线性变换
    self.query = nn.ModuleList([nn.Linear(c, c, bias=False) for c in channel_num])
    self.key = nn.Linear(self.KV_size, self.KV_size, bias=False)
    self.value = nn.Linear(self.KV_size, self.KV_size, bias=False)
    self.softmax = Softmax(dim=3)  # Softmax层
    self.attn_dropout = Dropout(0.1)  # Dropout层

def forward(self, *embeddings):
    """前向传播,计算注意力"""
    multi_head_Q = [query(emb) for query, emb in zip(self.query, embeddings) if emb is not None]
    multi_head_K = self.key(torch.cat(embeddings, dim=2))  # 合并所有嵌入
    multi_head_V = self.value(torch.cat(embeddings, dim=2))

    # 计算注意力分数
    attention_scores = [torch.matmul(Q, multi_head_K) / np.sqrt(self.KV_size) for Q in multi_head_Q]
    attention_probs = [self.softmax(score) for score in attention_scores]  # 计算注意力概率

    # 应用Dropout
    attention_probs = [self.attn_dropout(prob) for prob in attention_probs]
    context_layers = [torch.matmul(prob, multi_head_V) for prob in attention_probs]  # 计算上下文层

    return context_layers  # 返回上下文层

class ChannelTransformer(nn.Module):
“”“通道变换器模型”“”
def init(self, channel_num=[64, 128, 256, 512], img_size=640, patchSize=[40, 20, 10, 5]):
super().init()
self.embeddings = nn.ModuleList([Channel_Embeddings(patchSize[i], img_size // (2 ** (i + 2)), channel_num[i]) for i in range(len(channel_num))])
self.encoder = Encoder(channel_num) # 编码器
self.reconstruct = nn.ModuleList([Reconstruct(channel_num[i], channel_num[i], kernel_size=1, scale_factor=(patchSize[i], patchSize[i])) for i in range(len(channel_num))]) # 重构层

def forward(self, en):
    """前向传播,处理输入数据"""
    embeddings = [embed(en[i]) for i, embed in enumerate(self.embeddings) if en[i] is not None]
    encoded = self.encoder(*embeddings)  # 编码
    reconstructed = [recon(enc) + en[i] for i, (recon, enc) in enumerate(zip(self.reconstruct, encoded)) if en[i] is not None]  # 重构并加上残差
    return reconstructed  # 返回重构后的输出

代码说明:
Channel_Embeddings:这个类负责将输入图像转换为补丁嵌入,并添加位置嵌入。
Attention_org:实现了一个多头注意力机制,计算输入嵌入之间的注意力分数并生成上下文层。
ChannelTransformer:这是整个模型的核心部分,负责处理输入数据,通过嵌入、编码和重构步骤生成最终输出。
这个程序文件 CTrans.py 实现了一个名为 ChannelTransformer 的深度学习模型,主要用于图像处理任务。该模型基于变换器(Transformer)架构,特别关注于通道信息的处理。以下是对代码的详细讲解。

首先,文件引入了一些必要的库,包括 torch 和 torch.nn,这些库提供了构建神经网络所需的基本模块和函数。接着,定义了几个类,每个类都有其特定的功能。

Channel_Embeddings 类用于构建图像的嵌入表示。它接收图像的尺寸和通道数,并通过卷积和池化操作将图像划分为多个补丁。补丁的嵌入通过位置嵌入进行增强,并添加了 dropout 层以防止过拟合。

Reconstruct 类负责将经过处理的嵌入重新构建为图像。它使用卷积层和上采样操作来实现这一点,并通过批归一化和激活函数(ReLU)进行处理。

Attention_org 类实现了多头注意力机制。它接受多个嵌入作为输入,计算查询(Query)、键(Key)和值(Value),并通过注意力得分计算出上下文层。该类还包含 dropout 层以增强模型的鲁棒性。

Mlp 类实现了一个简单的多层感知机(MLP),包含两个全连接层和一个激活函数(GELU)。它用于在模型中进行特征变换。

Block_ViT 类将注意力机制和前馈网络结合在一起,形成一个完整的变换器块。它首先对输入的嵌入进行层归一化,然后通过注意力机制进行处理,最后通过 MLP 进行特征转换。

Encoder 类包含多个 Block_ViT 层,负责对输入的嵌入进行编码。它通过层归一化对每个通道的嵌入进行处理,并在每个变换器块中传递注意力权重。

ChannelTransformer 类是整个模型的核心。它初始化了多个嵌入层、编码器和重构层。模型的前向传播方法接收输入图像,计算嵌入,经过编码器处理后,再通过重构层输出结果。

最后,GetIndexOutput 类用于从模型的输出中提取特定索引的结果。

整体来看,这个模型通过结合多头注意力机制和前馈网络,能够有效地处理图像的通道信息,并在图像重建任务中表现出色。每个模块的设计都考虑到了深度学习中的常见技术,如层归一化、dropout 和激活函数等,以提高模型的性能和稳定性。

源码文件

在这里插入图片描述

源码获取

欢迎大家点赞、收藏、关注、评论啦 、查看👇🏻获取联系方式👇🏻

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐