不确定性感知的运动表征学习:以足球轨迹数据为例
2026/8/29 11:21:10 网站建设 项目流程

在足球数据分析项目中,球员运动轨迹的表征学习一直是个既关键又棘手的问题。早期我在处理跟踪数据时,最头疼的不是模型结构,而是数据里无处不在的噪声:遮挡、ID 切换、传感器误差,都会让同一个球员的轨迹特征在训练和推理阶段出现明显偏移。如果模型不感知这种不确定性,学出来的表征会不稳定,下游的球员检索、战术分类任务都会受影响。这篇博客会围绕“在人类运动表征学习中显式捕获不确定性”展开,以足球场景为例,从数据增强、模型设计、损失函数到工程落地,给出一个可运行的闭环方案。

文章适合三类读者:一是做体育数据挖掘的算法工程师,二是正在研究人类运动表征或序列对比学习的同学,三是想了解如何把足球比赛跟踪数据转化为可训练特征的研究型开发者。读完你可以掌握不确定性建模的基本思路、数据增强的常见做法,以及一个基于 PyTorch 的不确定性感知对比学习主线示例。

1. 背景与核心概念

1.1 为什么足球运动需要表征学习

足球比赛数据通常来自两个层面:跟踪数据(Tracking Data)事件数据(Event Data)。跟踪数据记录了每位球员在每个时刻的场上位置,精度高、频率高;事件数据则记录了传球、射门、抢断等离散动作。跟踪数据能刻画球员的连续运动,但它本身的维度高、噪声大,直接用原始坐标做分析并不方便。

表征学习的本质,是把高维原始输入转换成低维、稠密、有语义的向量。在足球场景中,我们希望把一段轨迹变成一个向量,使得“运动风格相似”的球员在向量空间里距离更近。例如,善于内切边锋和习惯下底传中的边锋,其轨迹向量应该有明显区分。这种向量可以作为球员检索、战术分类、体能评估等下游任务的输入。

1.2 人类运动不确定性为什么容易被忽略

很多运动分析模型默认把跟踪数据当作精确值来处理。但真实的足球跟踪数据远没有那么干净:

  • 观测噪声:基于视觉的跟踪系统受光照、分辨率影响,坐标本身有误差。
  • 遮挡问题:球员拥挤时,身体检测框互相遮挡,轨迹会出现短暂断裂。
  • 身份切换:多人交叉跑位后,跟踪算法可能将两个球员的 ID 互换,导致轨迹跳变。
  • 语义歧义:同一段跑位在不同战术体系下意义不同,单纯看位置无法判断意图。

这些不确定性如果不处理,模型会把噪声当成真实运动特征学习进去,导致表征不稳定。比如同一名球员在不同场次的嵌入向量可能差异很大,因为遮挡或 ID 切换带来的异常片段干扰了特征提取。

1.3 从领域类比理解不确定性

“不确定性”不是一个新概念。在自动驾驶领域,行人轨迹预测模型通常会输出一个概率分布,而不是单个坐标;在语音识别里,模型会对不清晰的发音给出置信度。足球运动表征也应该借鉴这一点:模型不仅要输出运动表征向量,还要输出这个向量本身的置信度

另一个有价值的信息源是 fivethirtyeight 的 SPI(Soccer Power Index)评分,它提供了球队层面的进攻、防守能力评估。我们可以把 SPI 作为弱监督信号之一,帮助模型学习球员行为与球队整体表现之间的关联。虽然 SPI 是球队级指标,颗粒度比球员轨迹粗,但用于指导预训练收敛方向是有帮助的。

2. 数据基础与不确定性来源分析

2.1 跟踪数据的基本结构

典型的足球跟踪数据长这样:

时间戳球员ID队伍x坐标y坐标速度方向角度
12.0423home52.333.14.2120
12.0823home53.033.64.5118

这里的 x、y 通常是场上归一化坐标,速度单位常见为 m/s,方向角度是相对球场坐标系的朝向。我们要建模的是每个球员在一段连续时间窗口内的轨迹切片,例如 5 秒或 10 秒一个窗口,频率 10Hz 对应 50 到 100 帧。

2.2 不确定性来源的完整分类

我习惯把足球轨迹中的不确定性分成以下四类:

第一类是观测不确定性(Measurement Uncertainty)。源于传感器或视频检测算法的误差,坐标可能会偏离真实位置几十厘米甚至更多。这类不确定性通常可以用高斯分布近似。

第二类是缺失不确定性(Missing Data Uncertainty)。球员被遮挡或出场替换时,轨迹数据缺失。处理缺失时如果用简单的线性插值,相当于强行“编造”了一段运动,会带来虚假特征。

第三类是关联不确定性(Association Uncertainty)。多目标跟踪中 ID 切换导致同一 ID 对应了不同球员。这是最隐蔽的问题,因为它不表现为明显异常,但会让表征学习学到错误的身份特征。

第四类是语义不确定性(Semantic Uncertainty)。同样的轨迹在不同战术语境下意义不同,例如“后退跑”可能是在防守回追,也可能是在为队友拉开空间。模型如果不结合上下文,很难判断运动意图。

2.3 运动员运动不确定性的实际影响

为了说明不确定性对表征学习的影响,我们做一个直观实验。取同一球员的两段无噪声轨迹,和一个加入不同程度噪声的轨迹,分别送入一个简单的 LSTM 编码器,观察嵌入向量之间的距离。结果通常会是这样:即使加噪幅度不大(例如坐标高斯噪声标准差 0.5 米),嵌入向量的欧式距离也会显著增大。这说明原始编码器对输入扰动非常敏感。

这也是为什么模型需要具备不确定性感知能力:它应该知道哪些输入片段是可信的,哪些是模糊的,并在特征聚合时降低模糊片段的影响。

3. 不确定性建模方法概览

3.1 概率嵌入思想

传统表征学习把输入样本映射成确定性向量,例如z = encoder(x)。概率嵌入改为把样本映射成一个分布,常见做法是让模型输出均值向量和方差向量:

z_mean, z_log_var = encoder(x)

训练时,我们不仅希望同类样本的均值接近,还希望模型能根据输入质量调整方差:输入清晰时方差小,输入模糊时方差大。这样下游任务可以综合均值和方差做决策。

3.2 贝叶斯方法与近似推断

严格的贝叶斯方法需要对模型权重求后验分布,在深度学习里通常不可直接计算。工程上常用的近似方法有三种:

MC Dropout:在推理时开启 Dropout,多次前向得到多个预测,用其均值和方差近似后验不确定性。优点是改动小,缺点是会增加推理耗时,且并非真正的贝叶斯推断。

深度集成(Deep Ensemble):训练多个不同初始化或不同数据子集的模型,推理时综合多个模型的预测差异。这是当前最稳健的不确定性估计方法之一,但训练成本翻倍。

证据回归(Evidential Regression):把网络输出建模为 Normal-Inverse-Gamma 分布的参数,用单次前向即可得到认识不确定性和偶然不确定性。训练稍微复杂,推理很高效。

在足球运动表征场景中,我建议先从**不确定头(Uncertainty Head)**入手,也就是在编码器最后一层同时输出表征和 log-方差。实现简单,效果直观。

3.3 对比学习中的不确定性加权

对比学习(Contrastive Learning)的目标是拉近正样本对、推开负样本对。经典 InfoNCE 损失对每个样本的贡献是等权的:

loss = -log( exp(sim(z_i, z_j)/tau) / sum_k(exp(sim(z_i, z_k)/tau)) )

当某个样本被严重遮挡或轨迹不完整时,它生成的表征并不可靠,却依然以相同权重参与损失计算,这会拖累整个模型。不确定性加权的思路是:将样本的预测方差映射为损失权重,方差越大,权重越小。这样模型不会为了拟合模糊样本而扭曲特征空间。

4. 数据增强:低成本引入不确定性

4.1 为什么把数据增强放在核心位置

在真实训练环境中,我们不一定能获得大量标注好的“不确定性程度”。数据增强的价值在于:它能模拟出运动数据中的常见扰动模式,让模型在不增加标注成本的情况下,学会对这些扰动鲁棒

在足球轨迹任务中,一个较强的增强策略组合应包含空间抖动、时间掩码、速度扰动和坐标旋转。

4.2 基础增强实现

下面是一个基于 NumPy 的增强模块示例,文件路径:soccer_rep/augment.py

import numpy as np def spatial_jitter(track, sigma=0.3): """对轨迹坐标加入高斯噪声,模拟跟踪系统观测误差。 track: ndarray, shape (T, 2) """ noise = np.random.normal(0, sigma, size=track.shape) return track + noise def time_mask(track, mask_len=10, fill_value=0.0): """随机遮挡一段时间窗口,模拟遮挡或检测缺失。 返回: masked_track, mask mask[i] = 1 表示该帧有效,0 表示被遮挡。 """ track = track.copy() T = track.shape[0] mask = np.ones(T, dtype=np.float32) if T <= mask_len: return track, mask start = np.random.randint(0, T - mask_len) track[start:start + mask_len] = fill_value mask[start:start + mask_len] = 0.0 return track, mask def speed_jitter(track, scale=1.1): """轻微扰动位移幅度,改变运动速度,模拟速度测量误差。""" diff = np.diff(track, axis=0, prepend=track[:1]) jitter = np.random.uniform(1 / scale, scale, size=diff.shape) return track[:1] + np.cumsum(diff * jitter, axis=0)

time_mask的返回值里有一个 mask,它会被拼接到模型输入中,帮助编码器区分有效帧和填充帧。这个设计很关键:模型需要知道哪些帧是被遮挡的,而不是把填充值当作真实运动信息

4.3 增强策略的工程注意点

增强要控制强度。如果空间抖动标准差过大,会把“加速变向”这类真实特征也破坏掉;如果时间掩码太长,模型会直接失去对该样本的判断能力。实际操作中,我会先用小强度验证模型能正常收敛,再逐步加大增强强度。

另一个注意点是增强后处理。对于速度、方向这类派生特征,最好在增强后的坐标上重新计算,不要沿用原始速度。否则坐标增强与速度特征会产生不一致,模型会学到错误关联。

5. 模型设计:不确定性感知的运动表征网络

5.1 网络结构总览

整个链路可以拆成四部分:

  1. 输入构造:将轨迹坐标与 mask 拼接,得到(T, input_dim)输入。
  2. 序列编码器:使用 GRU 或 LSTM 学习轨迹的时间依赖。
  3. 双头输出:一个头输出表征向量z,另一个头输出不确定性log_var
  4. 损失函数:对比损失 + 不确定性正则。

下面给出核心模型代码,文件路径:soccer_rep/model.py

import torch import torch.nn as nn import torch.nn.functional as F class TrajectoryEncoder(nn.Module): """将一段轨迹映射为表征向量和不确定性。""" def __init__(self, input_dim=3, hidden_dim=64, latent_dim=32): super().__init__() self.rnn = nn.GRU(input_dim, hidden_dim, batch_first=True) self.projection = nn.Sequential( nn.Linear(hidden_dim, hidden_dim), nn.ReLU(inplace=True), nn.Linear(hidden_dim, latent_dim), ) self.uncertainty_head = nn.Sequential( nn.Linear(hidden_dim, hidden_dim), nn.ReLU(inplace=True), nn.Linear(hidden_dim, 1), ) def forward(self, x): # x: (B, T, input_dim) out, _ = self.rnn(x) # (B, T, hidden_dim) last = out[:, -1, :] # 取最后一个时刻状态 z = self.projection(last) # (B, latent_dim) log_var = self.uncertainty_head(last).squeeze(-1) # (B,) return z, log_var

这个结构有两个要点。

第一,为什么用 GRU 而不是 Transformer?足球轨迹长度通常在 50 到 100 帧,GRU/LSTM 对这类中等长度序列已经足够,且训练成本低。如果你有长上下文需求(例如整场比赛),可以换成 Transformer Encoder,但要注意位置编码问题。

第二,log_var预测的是对数方差,而不是直接预测方差。因为方差必须是正数,让网络直接输出正值需要额外约束,而对数形式可以让训练更稳定。使用时可通过torch.exp(log_var)还原方差。

5.2 不确定性感知的对比损失

对比学习有多种实现,这里采用 InfoNCE 的简化版本。为了引入不确定性,将样本的预测方差转换为损失权重;同时加入方差正则项,防止模型把所有样本都预测为高方差来逃避学习。

文件路径:soccer_rep/loss.py

import torch import torch.nn.functional as F def uncertainty_contrastive_loss(z1, z2, log_var1, log_var2, tau=0.1, reg=0.1): """不确定性感知的对比损失。 z1, z2: 来自同一个轨迹不同增强视图的表征向量 log_var1, log_var2: 两个视图的不确定性对数方差 """ # 归一化表征向量,便于计算余弦相似度 z1 = F.normalize(z1, dim=-1) z2 = F.normalize(z2, dim=-1) # InfoNCE 损失,对角线是正样本对 sim_matrix = z1 @ z2.T / tau labels = torch.arange(z1.size(0), device=z1.device) loss_cl = F.cross_entropy(sim_matrix, labels) # 样本权重:方差越大,权重越小;这里用 detach 阻止梯度流回 log_var weight1 = torch.exp(-torch.clamp(log_var1, min=0, max=5)) weight2 = torch.exp(-torch.clamp(log_var2, min=0, max=5)) sample_weight = (weight1 + weight2) / 2 loss_cl_weighted = (loss_cl * sample_weight.detach()).mean() # 正则项:避免预测无限大的方差 loss_uncertainty = (log_var1.pow(2).mean() + log_var2.pow(2).mean()) / 2 return loss_cl_weighted + reg * loss_uncertainty

这段代码里有一个细节需要解释:sample_weight.detach()的作用是让权重只影响损失大小,不让梯度通过权重传播到log_var。如果我们不 detach,模型可能采取“调大方差来降低损失”的投机策略,而不是学习更好的表征。正则项用log_var.pow(2),作用是让方差保持在一个合理范围,不要极端化。

5.3 与下游任务结合

训练好的编码器输出的z可以作为通用运动特征,输入到下游模型中。下游任务的类型取决于业务场景:

  • 球员检索:给一段未知球员轨迹,从球员库中找出最可能是同一人的片段。
  • 战术分类:把轨迹编码后输入分类器,判断这是一次边路进攻还是中路渗透。
  • 异常检测:如果某个片段的不确定性特别高,说明该片段可能被遮挡或存在 ID 切换,系统可以标记出来人工复核。

如果要用 SPI 评分做弱监督,可以把比赛对应球队的进攻/防守评分作为辅助标签,对z接一个小分类头,与对比损失联合训练。这样既保留了轨迹自身的结构信息,又融合了球队层面的语义信息。

6. 完整实战案例

6.1 项目结构

为了便于演示,我建立了一个最小的工程目录:

soccer_rep/ ├── data.py # 模拟轨迹数据生成 ├── augment.py # 数据增强 ├── model.py # 编码器 + 不确定性头 ├── loss.py # 对比学习损失 ├── train.py # 训练主流程 └── visualize.py # 表征可视化

下面我把 train.py 和 data.py 的完整内容写出来。

6.2 模拟数据生成

由于真实的足球跟踪数据通常受版权和保护限制,不适合在公开教程中直接提供完整数据集。这里我用正弦波叠加随机成分,模拟一个“进攻推进过程中球员跑位”的轨迹。虽然运动模式简单,但足以验证整个建模流程。

文件路径:soccer_rep/data.py

import numpy as np def simulate_player_trajectory(length=120, n_players=6, seed=0): """生成模拟足球进攻场景下的球员轨迹。 返回: ndarray, shape (n_players, length, 2) """ rng = np.random.RandomState(seed) t = np.arange(length) # 模拟球的移动:从后场向前场推进,带左右摆动 ball_x = 30 + 20 * t / length + 3 * np.sin(2 * np.pi * t / 35) ball_y = 34 + 6 * np.cos(2 * np.pi * t / 25) trajectories = [] for i in range(n_players): # 每个球员围绕球的位置做不同相位、不同幅度的跑位 phase_x = rng.uniform(0, 2 * np.pi) phase_y = rng.uniform(0, 2 * np.pi) amp_x = rng.uniform(5, 15) amp_y = rng.uniform(3, 10) px = ball_x + amp_x * np.cos(2 * np.pi * t / 40 + phase_x) py = ball_y + amp_y * np.sin(2 * np.pi * t / 30 + phase_y) trajectories.append(np.stack([px, py], axis=-1)) return np.stack(trajectories, axis=0) def build_train_pair(track, input_dim=3): """对一个轨迹做两次不同增强,返回模型输入对。""" from augment import spatial_jitter, time_mask, speed_jitter # 视图1:空间抖动 view1 = spatial_jitter(track, sigma=0.3) # 视图2:空间抖动 + 时间掩码 view2 = spatial_jitter(track, sigma=0.3) view2, mask2 = time_mask(view2, mask_len=12) # 拼接 mask 通道 mask1 = np.ones(track.shape[0], dtype=np.float32) x1 = np.concatenate([view1, mask1[:, None]], axis=-1) x2 = np.concatenate([view2, mask2[:, None]], axis=-1) return x1.astype(np.float32), x2.astype(np.float32)

这里有一个值得注意的设计:mask1全为 1,表示视图 1 没有遮挡;mask2则标记了视图中被时间掩码遮挡的位置。两者拼接进输入通道,编码器能够区分“真实位置”和“填充位置”。

6.3 训练主流程

文件路径:soccer_rep/train.py

import torch import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset from data import simulate_player_trajectory, build_train_pair from model import TrajectoryEncoder from loss import uncertainty_contrastive_loss def main(): # 1. 准备数据 tracks = simulate_player_trajectory(length=120, n_players=20, seed=1) pairs = [build_train_pair(t) for t in tracks] x1 = torch.tensor([p[0] for p in pairs]) x2 = torch.tensor([p[1] for p in pairs]) dataset = TensorDataset(x1, x2) loader = DataLoader(dataset, batch_size=8, shuffle=True) # 2. 初始化模型 model = TrajectoryEncoder(input_dim=3, hidden_dim=64, latent_dim=32) optimizer = optim.Adam(model.parameters(), lr=1e-3) # 3. 训练循环 model.train() for epoch in range(30): total_loss = 0.0 for batch_x1, batch_x2 in loader: optimizer.zero_grad() z1, log_var1 = model(batch_x1) z2, log_var2 = model(batch_x2) loss = uncertainty_contrastive_loss(z1, z2, log_var1, log_var2) loss.backward() optimizer.step() total_loss += loss.item() print(f"epoch {epoch + 1:02d}, loss {total_loss / len(loader):.4f}") torch.save(model.state_dict(), "encoder.pth") if __name__ == "__main__": main()

在这个示例中,我故意把n_players=20,并从每个球员的轨迹生成一对增强视图。训练过程中,模型需要学会把同一个球员的不同增强视图映射到相近位置,同时把不同球员的映射分开。由于视图 2 被时间掩码遮挡了一部分,模型必须学会在信息不完整的情况下仍然保持辨识能力。

6.4 运行与验证

运行训练脚本:

cd soccer_rep python train.py

预期输出类似:

epoch 01, loss 2.9143 epoch 02, loss 2.5861 epoch 03, loss 2.3137 ... epoch 30, loss 0.6842

损失下降说明模型在逐渐学会区分不同球员的轨迹。

之后可以用下面的代码快速验证表征质量:计算同一球员两张增强视图的表征余弦相似度,以及不同球员之间的相似度。正常情况下,同一球员的相似度应当明显高于不同球员。

import torch from model import TrajectoryEncoder from data import simulate_player_trajectory from augment import spatial_jitter device = torch.device("cpu") model = TrajectoryEncoder(input_dim=3) model.load_state_dict(torch.load("encoder.pth")) model.eval() with torch.no_grad(): # 取第一个球员作为示例 tracks = simulate_player_trajectory(length=120, n_players=6, seed=2) t0 = tracks[0] view_a = torch.tensor(spatial_jitter(t0, 0.2), dtype=torch.float32) view_b = torch.tensor(spatial_jitter(t0, 0.2), dtype=torch.float32) za, _ = model(view_a.unsqueeze(0)) zb, _ = model(view_b.unsqueeze(0)) sim_same = torch.cosine_similarity(za, zb).item() t1 = tracks[1] view_c = torch.tensor(spatial_jitter(t1, 0.2), dtype=torch.float32) zc, _ = model(view_c.unsqueeze(0)) sim_diff = torch.cosine_similarity(za, zc).item() print(f"same player similarity: {sim_same:.4f}") print(f"different player similarity: {sim_diff:.4f}")

这里要强调,模拟数据比较简单,训练出的表征质量只是为了验证流程。真实项目中如果把数据换成标准化的足球跟踪数据,并且把窗口滑动、多尺度采样等工程技术加上,效果会明显更好。

7. 常见问题与排查思路

7.1 问题排查表

问题现象常见原因解决思路
损失不下降学习率过大或过小将学习率调至 1e-4 到 1e-3 范围,并添加学习率衰减
表征相似度普遍偏高模型没有学到区分性特征增加负样本数量,或增大 batch size
log_var 全部变成正向大值正则项过强或对比损失过弱降低正则系数reg,或去掉clamp上限后重试
同一球员相似度反而低于不同球员数据增强强度过强,样本被破坏减小spatial_jitter的 sigma,缩短time_mask的窗口
推理结果不稳定训练时 mask 随机性在推理时未处理推理时保证输入通道完整,不包含随机 mask;或用多次推理取均值

7.2 几个常见疑问的详细说明

第一个问题是“为什么不直接把方差输出当置信度使用”。预测出的log_var只是一个相对置信度信号,它代表模型认为该样本的不确定性高低,并非准确校准过的概率值。如果业务上需要校准的置信度,建议使用 MC Dropout、深度集成等后验近似方法,并在验证集上做校准评估。

第二个问题是“数据增强的强度如何选择”。这需要结合数据本身来判断。跟踪数据的标准误差如果是 0.3 米,那么spatial_jitter的 sigma 取 0.3 就是合理的;如果你希望模型对恶劣天气或低帧率更鲁棒,可以适当增加到 0.6 到 0.8,但不能过大,否则会破坏运动语义。

第三个问题是“对比学习训练需要多少数据”。理论上,对比学习需要较大的数据量才能学到通用特征。但如果数据规模有限,可以先用预训练模型或公开的轨迹数据做预训练,再做微调。对足球场景,也可以先从单场比赛内划分多个时间窗口做自监督训练,积累特征后再迁移到跨比赛任务。

8. 最佳实践与工程建议

8.1 数据层的工程规范

数据质量直接决定表征质量。我建议按以下顺序梳理数据:

  1. 坐标归一化:将所有坐标映射到统一坐标系,消除不同采集设备带来的偏差。
  2. 缺失值标记:不要直接用插值覆盖缺失段,而是保留 mask 信息,让模型自己学会处理缺失。
  3. 窗口采样策略:训练时使用随机起始位置采样多个窗口,增强样本多样性;推理时使用固定滑动窗口,保证结果可复现。
  4. 身份切换检测:如果能拿到跟踪系统的置信度或 frame ID,可以标记可能发生 ID 切换的时间段,作为高不确定性样本处理。

8.2 模型训练与评估建议

训练流程上,建议先把不确定性头暂时关闭,用普通对比学习训练一个基线;打开不确定性头再训练,对比两组实验在下游任务上的表现。这样你能看出不确定性加权是否真的带来提升。

评估指标方面,除了分类准确率,还应关注表征的稳定性。具体做法是:对同一轨迹多次加入不同噪声,输入模型得到多个嵌入向量,统计它们之间的平均距离。距离越小,说明表征越稳定,不确定性建模越有效。

8.3 生产环境中的注意事项

上线到生产环境时,有几个额外问题需要处理。

计算性能方面,如果推理频率很高,建议把 GRU 编码器导出为 ONNX 格式,用 GPU 推理;或者把模型量化后部署到边缘设备。复杂度方面,如果一次推理要对整场比赛所有球员逐窗口计算,开销会很大,可以先做球员检测、再对目标球员片段编码,避免全局计算。

弱监督标签方面,SPI 评分这类球队级指标只能作为粗粒度辅助信号,不建议直接作为球员级轨迹的强标签,否则会引入大量噪声。更好的做法是用同一球员的多场比赛轨迹做自监督训练,再用少量人工标注做微调。

8.4 如何进一步扩展

这个流程可以扩展的方向很多:如果你关注多人交互,可以用图神经网络建模球员之间的相对位置关系;如果你关注意图预测,可以在编码器顶部加一个解码器,预测未来 N 帧的位置分布;如果你研究的是少样本场景,可以借助预训练表征 + 小样本分类器完成新战术类型的识别。核心思想是一致的:先让模型学会稳定、可信的运动表征,再根据业务需要接入具体任务。

对初学同学,我的建议是不要一开始就照搬复杂的贝叶斯网络,先用这个最简单的“编码器 + 不确定性头 + 对比损失”框架跑通,再逐步加入更多技术。把代码改到自己熟悉的数据上,观察不同增强策略、不同损失权重对表征的影响,你对不确定性建模的理解会扎实很多。

如果这篇文章对你有帮助,建议收藏备用,之后在实践中遇到相关问题时方便查阅。也欢迎在评论区交流你在足球运动分析或表征学习落地中遇到的问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询