海量数据集的AI自动化预测打标 -- 矿业音频分类

两个月前公司有个AI标注的训练数据需求调研,正巧清华某个团队有此需求,于是进行合作。一共开源了三个模型的初版。记录下自己的实现

声音样本多标签预测 - 矿山矿业场景: github.com/STARTORUS/t...


概述:让AI听懂机器的"健康密码"

想象一下,在一个庞大的矿山作业现场,几十台大型设备日夜运转------挖掘机、传送带、液压系统、电机......每台设备都在"说话",发出各种声音。经验丰富的老师傅能通过听声音判断设备是否正常:"这个轴承声音不对劲,可能要坏了""这个电机转速不稳"。

矿业音频ML Backend 就是将这种"听音辨机"的专家经验数字化、智能化 ,通过AI自动识别设备音频特征,预测设备状态、故障类型和维护优先级,实现预测性维护


一、业务价值:Why - 为什么矿业需要音频智能诊断?

1.1 行业痛点

在矿业生产场景中,设备故障会带来巨大损失:

场景1:突发故障停产 ⚠️

某铁矿主传送带轴承突然损坏:

  • 生产线停工12小时
  • 直接经济损失超过500万元
  • 抢修成本是计划维护的3-5倍
  • 如果能提前3天预警,可避免90%损失

场景2:过度维护浪费 💸

采用定期维护策略:

  • 按固定周期更换零件(如每3个月)
  • 很多零件还能继续使用就被更换
  • 维护成本高昂,资源浪费严重
  • 真正需要维护的设备却可能被忽略

场景3:人工巡检效率低 🚶

传统巡检方式:

  • 工人每天巡检上百台设备
  • 只能检查外观和简单读数
  • 无法24小时监控
  • 依赖个人经验,缺乏标准化

1.2 ML Backend的价值

矿业音频ML Backend通过声音指纹识别,实现:

预测性维护 :提前3-7天预警故障,避免突发停产
降低成本30% :从定期维护转向按需维护
24小时监控 :AI不知疲倦,实时监测所有设备
标准化诊断:将专家经验固化为算法,减少人为误判

ROI计算示例

  • 投入:部署ML Backend系统 50万元
  • 收益:年避免故障损失 200万 + 降低维护成本 80万 = 280万
  • 投资回报周期:2-3个月

二、系统架构:What - 矿业音频ML Backend是什么?

2.1 整体架构

graph TB subgraph "数据采集层" A1[音频采集设备] --> A2[MinIO对象存储] A3[传感器数据] --> A2 end subgraph "Label Studio前端" B1[标注界面] --> B2[任务管理] end subgraph "ML Backend核心层" C1[_wsgi.py服务入口] --> C2[MiningAudioMLBackend
业务编排] C2 --> C3[AudioFeatureExtractor
特征提取] C2 --> C4[MiningAudioClassifier
神经网络模型] C2 --> C5[MinIODownloader
数据下载] end subgraph "AI引擎层" D1[Librosa音频处理] D2[PyTorch深度学习] D3[标准化器StandardScaler] end subgraph "模型存储" E1[(预训练模型.pth)] E2[(特征标准化器.pkl)] end A2 -->|S3 API| C5 B2 -->|HTTP API| C1 C3 --> D1 C4 --> D2 C4 --> D3 C4 -.加载.-> E1 C3 -.加载.-> E2 style C2 fill:#4CAF50,color:#fff style C4 fill:#FF5722,color:#fff style D2 fill:#2196F3,color:#fff

2.2 核心组件剖析

🎯 MiningAudioMLBackend - 业务编排中心

这是整个系统的**"大脑"**,协调各个模块完成音频诊断:

python 复制代码
class MiningAudioMLBackend(LabelStudioMLBase):
    """矿业音频多标签分类ML后端"""
    
    def setup(self):
        # 初始化特征提取器
        self.feature_extractor = AudioFeatureExtractor()
        
        # 加载深度学习模型
        self.model = MiningAudioClassifier(input_dim=72)
        
        # 初始化MinIO下载器(对接对象存储)
        self.minio_downloader = MinIODownloader(...)

设计亮点

  • 懒加载机制:只在第一次预测时初始化,加快启动速度
  • 状态管理:记录训练次数、模型版本等元信息
  • 异常隔离:预测失败不影响其他任务

🔬 AudioFeatureExtractor - 音频特征工程专家

这是系统的**"耳朵"**,将音频信号转换为机器可理解的特征向量:

特征提取流程

graph LR A[原始音频
采样率25kHz] --> B[时域特征
ZCR/RMS] A --> C[频域特征
MFCC/频谱] B --> D[统计量
均值/标准差/最值] C --> D D --> E[72维特征向量] style A fill:#FFC107 style E fill:#4CAF50,color:#fff

详细特征说明

特征类别 特征名称 物理意义 故障诊断价值
时域 过零率(ZCR) 信号正负交替频率 检测旋转设备转速异常
时域 能量(RMS) 信号幅值强度 识别振动强度变化
频域 MFCC(13维) 频谱包络特征 模拟人耳听觉,识别声纹
频域 频谱质心 频率分布中心 检测频率偏移(如轴承磨损)
频域 频谱滚降 高频能量占比 识别冲击性故障
频域 频谱带宽 频率分布范围 判断频谱复杂度

特征维度计算

scss 复制代码
基础特征 = 13(MFCC) + 1(ZCR) + 1(RMS) + 1(质心) + 1(滚降) + 1(带宽) = 18
统计量 = 4种 (均值、标准差、最大值、最小值)
总维度 = 18 × 4 = 72维

代码实现核心

python 复制代码
def extract_features(self, audio_path):
    # 1. 加载音频(使用librosa统一接口)
    y, sr = librosa.load(audio_path, sr=self.sample_rate)
    
    # 2. 时域特征
    zcr = librosa.feature.zero_crossing_rate(y, hop_length=512)
    energy = librosa.feature.rms(y=y, hop_length=512)
    
    # 3. 频域特征
    mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
    spectral_centroid = librosa.feature.spectral_centroid(y=y, sr=sr)
    
    # 4. 合并特征矩阵
    features = np.vstack([mfccs, zcr, energy, ...])
    
    # 5. 计算统计量
    feature_stats = np.hstack([
        np.mean(features, axis=1),  # 均值
        np.std(features, axis=1),   # 标准差
        np.max(features, axis=1),   # 最大值
        np.min(features, axis=1)    # 最小值
    ])
    
    return feature_stats  # 返回72维向量

🧠 MiningAudioClassifier - 深度神经网络

这是系统的**"诊断医生"**,基于特征向量预测设备状态:

网络架构

graph TB A[输入层
72维特征] --> B[全连接层256] B --> C[批归一化BN] C --> D[ReLU激活] D --> E[Dropout 0.3] E --> F[全连接层128] F --> G[批归一化BN] G --> H[ReLU激活] H --> I[Dropout 0.3] I --> J[全连接层64] J --> K[批归一化BN] K --> L[ReLU激活] L --> M[Dropout 0.3] M --> N1[设备状态头
3类] M --> N2[故障类型头
4类] M --> N3[优先级头
3类] N1 --> O1[Sigmoid激活] N2 --> O2[Sigmoid激活] N3 --> O3[Sigmoid激活] style A fill:#FFC107 style M fill:#4CAF50,color:#fff style O1 fill:#FF5722,color:#fff style O2 fill:#FF5722,color:#fff style O3 fill:#FF5722,color:#fff

设计要点

  1. 多标签分类

    不同于传统单标签分类,这里使用3个分类头

    python 复制代码
    # 设备状态: normal/abnormal/maintenance_needed
    self.equipment_status_head = nn.Linear(64, 3)
    
    # 故障类型: bearing/motor/hydraulic/belt
    self.fault_type_head = nn.Linear(64, 4)
    
    # 优先级: low/medium/high
    self.priority_head = nn.Linear(64, 3)
  2. 批归一化(Batch Normalization)

    • 加速训练收敛
    • 提高模型泛化能力
    • 注意:推理时必须设置为eval模式!
  3. Dropout正则化

    • 防止过拟合
    • dropout率0.3(保留70%神经元)
  4. Sigmoid激活

    • 多标签场景下,每个标签独立判断
    • 输出概率值0-1

📦 MinIODownloader - 数据桥接层

对接MinIO对象存储,支持从S3 URL下载音频文件:

python 复制代码
def _get_local_path_for_s3(self, s3_url):
    # s3://bucket-name/path/to/audio.wav
    
    # 1. 生成本地缓存路径
    cache_dir = user_cache_dir('label-studio')
    url_hash = hashlib.md5(s3_url.encode()).hexdigest()[:6]
    local_path = f"{cache_dir}/{url_hash}__{filename}"
    
    # 2. 下载文件
    self._download_s3_file(s3_url, local_path)
    
    return local_path

设计亮点

  • 缓存机制:避免重复下载
  • 哈希命名:防止文件名冲突
  • 资源管理:正确关闭S3连接,避免内存泄漏

三、技术实现:How - 诊断流程详解

3.1 端到端预测流程

sequenceDiagram participant LS as Label Studio participant Backend as MiningAudioMLBackend participant Downloader as MinIODownloader participant Extractor as AudioFeatureExtractor participant Model as MiningAudioClassifier participant MinIO as MinIO存储 LS->>Backend: 预测请求
s3://audio-annotations/device1.wav Backend->>Downloader: 解析S3 URL Downloader->>MinIO: 下载音频文件 MinIO-->>Downloader: 返回音频数据 Downloader-->>Backend: 本地文件路径 Backend->>Extractor: 提取特征 Extractor->>Extractor: Librosa加载音频
采样率25kHz Extractor->>Extractor: 计算时域特征
ZCR/RMS Extractor->>Extractor: 计算频域特征
MFCC/频谱 Extractor->>Extractor: 统计量聚合
72维向量 Extractor-->>Backend: 特征向量 Backend->>Backend: 特征标准化
StandardScaler Backend->>Model: 神经网络推理 Model->>Model: 前向传播 Model-->>Backend: 多标签预测结果 Backend->>Backend: 格式化为Label Studio格式 Backend-->>LS: 返回预测
设备状态/故障类型/优先级

3.2 关键技术点

技术点1:特征标准化

为什么需要标准化?

不同特征的数值范围差异巨大:

  • MFCC均值:-50 ~ +50
  • 能量RMS:0.001 ~ 1.0
  • 频谱质心:500 ~ 5000

如果不标准化,大数值特征会主导模型学习,小数值特征被忽略。

StandardScaler原理

ini 复制代码
标准化公式: x_scaled = (x - mean) / std

示例:
原始特征: [1000, 0.01, 50]
均值:     [500, 0.005, 25]
标准差:   [200, 0.003, 10]
标准化后: [2.5, 1.67, 2.5]  # 数值范围统一

代码实现

python 复制代码
# 训练时拟合标准化器
self.scaler.fit(training_features)

# 推理时使用
features_scaled = self.scaler.transform(features)

技术点2:批归一化的陷阱

问题 :推理时模型必须设置为eval()模式,否则报错

原因

python 复制代码
# 训练模式(training=True)
# BatchNorm使用当前batch的统计量
mean_batch = current_batch.mean()
std_batch = current_batch.std()

# 评估模式(training=False)  
# BatchNorm使用训练时的全局统计量
mean_global = running_mean  # 训练时累积
std_global = running_std

单样本推理问题

  • 训练模式下,单样本batch的std=0
  • 导致除零错误

解决方案

python 复制代码
# 模型加载后立即设置为评估模式
self.model.load_state_dict(torch.load(model_path))
self.model.eval()  # 关键!

# 推理时禁用梯度计算
with torch.no_grad():
    outputs = self.model(features)

技术点3:多标签预测

预测结果示例

python 复制代码
{
    'equipment_status': [
        {'label': 'abnormal', 'confidence': 0.85}
    ],
    'fault_type': [
        {'label': 'bearing_fault', 'confidence': 0.72},
        {'label': 'motor_fault', 'confidence': 0.58}
    ],
    'priority': [
        {'label': 'high_priority', 'confidence': 0.91}
    ]
}

阈值策略

python 复制代码
threshold = 0.5  # 置信度阈值

for category, logits in outputs.items():
    probs = logits.cpu().numpy()[0]  # Sigmoid输出
    
    predicted_labels = []
    for i, prob in enumerate(probs):
        if prob > threshold:  # 超过阈值才认为是阳性
            label_name = MINING_LABELS[category][i]
            predicted_labels.append({
                'label': label_name,
                'confidence': float(prob)
            })

多标签 vs 多分类的区别

  • 多分类:一个样本只属于一个类别(如猫/狗/鸟)
  • 多标签:一个样本可以同时属于多个标签(如"轴承故障+高优先级")

3.3 Label Studio格式转换

转换逻辑

python 复制代码
def _convert_to_labelstudio_format(self, predictions, task_id):
    results = []
    
    for category, labels in predictions.items():
        for label_info in labels:
            results.append({
                "from_name": f"mining_{category}",  # 对应标注配置
                "to_name": "audio",
                "type": "choices",
                "value": {
                    "choices": [label_info['label']]
                },
                "score": label_info['confidence']  # 置信度
            })
    
    return {"result": results, "model_version": "mining_audio_v1.0"}

Label Studio配置示例

xml 复制代码
<View>
  <Audio name="audio" value="$audio"/>
  
  <Choices name="mining_equipment_status" toName="audio">
    <Choice value="normal"/>
    <Choice value="abnormal"/>
    <Choice value="maintenance_needed"/>
  </Choices>
  
  <Choices name="mining_fault_type" toName="audio">
    <Choice value="bearing_fault"/>
    <Choice value="motor_fault"/>
    <Choice value="hydraulic_leak"/>
    <Choice value="belt_fault"/>
  </Choices>
</View>

四、实战应用:真实场景深度剖析

场景1:传送带轴承故障预警

背景:某露天矿主传送带,日运送矿石5000吨,轴承故障历史记录:

  • 每次故障停产8-12小时
  • 年均发生3次
  • 单次损失约300万元

传统做法

  • 每月人工巡检,听声音判断
  • 依赖老师傅经验(退休后经验流失)
  • 无法24小时监控

ML Backend方案

  1. 数据采集

    • 在传送带关键位置安装麦克风
    • 每小时采集10秒音频样本
    • 自动上传到MinIO存储
  2. 模型预测

    python 复制代码
    # 音频特征分析
    特征向量 → [MFCC高频能量异常, 频谱质心偏移, RMS振幅增大]
    
    # 模型输出
    设备状态: abnormal (置信度: 0.87)
    故障类型: bearing_fault (置信度: 0.75)
    优先级: high_priority (置信度: 0.82)
  3. 预警流程

    graph LR A[音频采集] --> B[特征提取] B --> C[模型预测] C --> D{置信度>0.7?} D -->|是| E[发送预警] D -->|否| F[正常监控] E --> G[维护工单] G --> H[计划性停机检修]

实施效果

  • 提前5天预警轴承磨损
  • 安排计划性停机(晚上低峰期检修)
  • 避免突发停产,年节省900万元
  • 轴承使用寿命延长20%(及时维护减少连锁损伤)

场景2:液压系统泄漏检测

背景:挖掘机液压系统泄漏特征:

  • 异常"嘶嘶"高频声
  • 传统检测:人工检查油压表+目视漏油
  • 问题:微小泄漏早期难以发现

音频诊断优势

python 复制代码
# 液压泄漏的音频特征
特征模式:
- 频谱带宽显著增大(高频噪声)
- 频谱滚降点升高(高频能量占比增加)
- MFCC特定频段异常

# 模型识别
故障类型: hydraulic_leak (置信度: 0.81)

对比实验

检测方法 识别准确率 漏检率 误报率
人工巡检 65% 35% 10%
压力传感器 75% 25% 15%
音频ML 88% 12% 8%

场景3:多设备健康度监控大屏

需求:矿山调度中心希望实时查看所有设备健康状态

实现方案

python 复制代码
# 定时任务:每小时批量预测
def scheduled_prediction():
    devices = get_all_mining_devices()  # 获取所有设备列表
    
    for device in devices:
        # 获取最新音频
        audio_url = f"s3://audio-data/{device.id}/latest.wav"
        
        # 执行预测
        prediction = model.predict([{"data": {"audio": audio_url}}])
        
        # 更新设备状态
        device.health_score = calculate_health_score(prediction)
        device.save()

健康度计算

python 复制代码
def calculate_health_score(prediction):
    score = 100  # 基础分
    
    # 根据预测结果扣分
    if 'abnormal' in prediction['equipment_status']:
        score -= 30
    
    if 'bearing_fault' in prediction['fault_type']:
        score -= 40
    elif 'motor_fault' in prediction['fault_type']:
        score -= 35
    
    if 'high_priority' in prediction['priority']:
        score -= 20
    
    return max(0, score)

可视化大屏

less 复制代码
┌────────────────────────────────────────────┐
│        矿山设备健康监控大屏                  │
├────────────────────────────────────────────┤
│ 传送带A  [████████░░] 85分 状态:良好        │
│ 传送带B  [████░░░░░░] 45分 ⚠️ 需维护        │
│ 挖掘机1  [██████████] 95分 状态:优秀        │
│ 挖掘机2  [███░░░░░░░] 35分 🚨 紧急维修      │
│ 液压泵1  [███████░░░] 70分 状态:一般        │
└────────────────────────────────────────────┘

五、技术优化与最佳实践

5.1 性能优化策略

优化1:批量推理

问题:逐个音频预测效率低,GPU利用率不足

解决方案

python 复制代码
def predict_batch(self, audio_paths):
    # 批量提取特征
    features_list = []
    for path in audio_paths:
        features = self.feature_extractor.extract_features(path)
        features_list.append(features)
    
    # 批量推理(GPU并行计算)
    features_batch = torch.stack(features_list)
    with torch.no_grad():
        outputs = self.model(features_batch)
    
    return outputs

效果

  • 单样本推理:100ms/样本
  • 批量推理(batch=32):20ms/样本
  • 加速5倍

优化2:模型量化

目的:减少模型大小,加速推理

python 复制代码
# FP32 → INT8量化
import torch.quantization as quant

# 动态量化(推理时量化)
model_quantized = quant.quantize_dynamic(
    model, 
    {nn.Linear},  # 量化全连接层
    dtype=torch.qint8
)

# 模型大小: 50MB → 13MB (减少74%)
# 推理速度: 提升1.5-2倍

优化3:特征缓存

场景:同一音频文件可能被多次预测

python 复制代码
import hashlib
from functools import lru_cache

@lru_cache(maxsize=100)
def extract_features_cached(audio_path_hash):
    return self.feature_extractor.extract_features(audio_path)

# 使用
audio_hash = hashlib.md5(open(audio_path, 'rb').read()).hexdigest()
features = extract_features_cached(audio_hash)

5.2 模型训练最佳实践

实践1:数据增强

目的:增加训练样本多样性,提升泛化能力

python 复制代码
import audiomentations as AA

augmenter = AA.Compose([
    AA.AddGaussianNoise(min_amplitude=0.001, max_amplitude=0.015, p=0.5),
    AA.TimeStretch(min_rate=0.8, max_rate=1.25, p=0.5),
    AA.PitchShift(min_semitones=-4, max_semitones=4, p=0.5),
    AA.Shift(min_fraction=-0.5, max_fraction=0.5, p=0.5),
])

# 应用数据增强
augmented_audio = augmenter(samples=audio_data, sample_rate=25000)

增强策略说明

  • 高斯噪声:模拟环境噪音
  • 时间拉伸:模拟转速变化
  • 音调偏移:模拟设备老化
  • 时间偏移:增加时间多样性

实践2:类别平衡

问题:正常样本远多于故障样本(不平衡数据)

解决方案

python 复制代码
from torch.utils.data import WeightedRandomSampler

# 计算类别权重
class_counts = [normal_count, abnormal_count, maintenance_count]
class_weights = 1.0 / torch.tensor(class_counts, dtype=torch.float)

# 样本权重
sample_weights = [class_weights[label] for label in labels]

# 加权采样器
sampler = WeightedRandomSampler(
    weights=sample_weights,
    num_samples=len(sample_weights),
    replacement=True
)

# 使用
train_loader = DataLoader(dataset, sampler=sampler, batch_size=32)

实践3:多任务学习策略

损失函数设计

python 复制代码
def multi_label_loss(outputs, targets):
    # 三个任务的BCE损失
    loss_status = F.binary_cross_entropy(
        outputs['equipment_status'], 
        targets['equipment_status']
    )
    
    loss_fault = F.binary_cross_entropy(
        outputs['fault_type'], 
        targets['fault_type']
    )
    
    loss_priority = F.binary_cross_entropy(
        outputs['priority'], 
        targets['priority']
    )
    
    # 加权组合
    total_loss = 0.4 * loss_status + 0.4 * loss_fault + 0.2 * loss_priority
    return total_loss

权重设置依据

  • 设备状态:最重要(0.4)
  • 故障类型:重要(0.4)
  • 优先级:次要(0.2)

六、总结与展望

6.1 技术创新点

本项目在矿业音频诊断领域的创新:

  1. 多标签联合预测

    • 传统方法:单独预测故障类型
    • 本方案:同时预测状态/故障/优先级,提供全面诊断
  2. 端到端深度学习

    • 传统方法:手工设计特征+简单分类器
    • 本方案:神经网络自动学习特征表示
  3. 工业级工程实现

    • 对接MinIO存储
    • 标准化部署流程
    • 完善的异常处理

6.2 适用场景总结

行业领域 应用场景 核心价值
矿业 设备故障预警 避免停产损失
制造业 生产线质检 提升产品质量
能源 风机/水泵监控 延长设备寿命
交通 轨道/桥梁巡检 保障安全

6.3 未来发展方向

方向1:多模态融合

思路:结合音频+振动+温度多种传感器

python 复制代码
class MultiModalClassifier(nn.Module):
    def __init__(self):
        self.audio_encoder = AudioFeatureExtractor()
        self.vibration_encoder = VibrationFeatureExtractor()
        self.temperature_encoder = TemperatureFeatureExtractor()
        
        # 多模态融合
        self.fusion_layer = nn.Linear(72+64+32, 128)

优势

  • 单一传感器可能漏检
  • 多模态互补,提升准确率

方向2:自监督预训练

思路:在大规模无标注音频上预训练

python 复制代码
# 对比学习
def contrastive_loss(audio1, audio2, temperature=0.5):
    # 同一设备不同时间的音频为正样本
    # 不同设备的音频为负样本
    ...

价值

  • 降低标注成本
  • 迁移学习到新设备

方向3:因果诊断

思路:不仅预测故障,还解释原因

python 复制代码
# 注意力机制可视化
attention_weights = model.get_attention()

# 分析关键频段
critical_freqs = find_critical_frequencies(attention_weights)
# "故障由2kHz-3kHz异常振动引起"

附录:部署运维指南

1. Docker部署

bash 复制代码
# 构建镜像
docker build -t mining-audio-backend .

# 启动容器
docker run -d \
  -p 9090:9090 \
  -v /data/models:/app/models \
  -v /data/cache:/app/cache \
  --name mining-audio \
  mining-audio-backend

# 健康检查
curl http://localhost:9090/health

2. 监控指标

python 复制代码
# 关键指标
metrics = {
    'prediction_latency': 150,  # 平均预测延迟(ms)
    'accuracy': 0.88,            # 准确率
    'throughput': 100,           # 吞吐量(样本/秒)
    'model_version': 'v1.0',
    'gpu_utilization': 0.75      # GPU利用率
}

3. 故障排查

问题1:预测延迟高

bash 复制代码
# 检查GPU是否正常
nvidia-smi

# 检查批量大小
# 增大batch_size可提升GPU利用率

问题2:准确率下降

bash 复制代码
# 检查数据分布漂移
# 定期使用新数据微调模型
python train_model.py --finetune

总结 :矿业音频ML Backend将声学诊断专家的经验 转化为自动化智能系统 ,实现从"事后维修"到"预测性维护"的范式转变,为矿业、制造业等重工业领域的智能化升级提供了可落地的AI解决方案。通过深度学习技术,让机器学会**"听音辨机"**,提前预警故障,避免停产损失,是工业4.0时代的重要应用方向。

相关推荐
吃着火锅x唱着歌44 分钟前
LeetCode 3185.构成整天的下标对数目II
算法·leetcode·职场和发展
鱼鱼块1 小时前
《最小栈的巧妙设计:用辅助栈实现 O(1) 获取最小值》
javascript·算法·面试
San301 小时前
反转字符串与两数之和:两道简单题背后的 JavaScript 思维深度
javascript·算法·面试
喜欢吃燃面1 小时前
算法竞赛中的堆
c++·学习·算法
资深web全栈开发1 小时前
LeetCode 1590:使数组和能被 p 整除(前缀和 + 哈希表优化)
算法·leetcode·前缀和·算法优化·哈希表·go 语言·取模运算
CoderYanger1 小时前
递归、搜索与回溯-综合练习:27.黄金矿工
java·算法·leetcode·深度优先·1024程序员节
zs宝来了1 小时前
HOT100系列-堆类型题
数据结构·算法·排序算法
Christo32 小时前
ICML-2019《Optimal Transport for structured data with application on graphs》
人工智能·算法·机器学习·数据挖掘
sin_hielo2 小时前
leetcode 1590
数据结构·算法·leetcode