Skip to main content

SoccerNet challenge development kit

Project description

dude-k

This repository contains code for training and evaluating slightly refined TDEED model for 2025 Ball Action Spotting Challenge. The details of the challenge can be found here: https://www.soccer-net.org/tasks/ball-action-spotting

Contribution:

Installation

uv sync
uv pip install -e .  

Datasets

To get started you need to download SoccerNet datasets


SN-BAS-2025

https://huggingface.co/datasets/SoccerNet/SN-BAS-2025

First download the dataset from huggingface data hub:

from huggingface_hub import snapshot_download
snapshot_download(repo_id="SoccerNet/SN-BAS-2025",
                  repo_type="dataset", revision="main",
                  local_dir="SoccerNet/SN-BAS-2025")

After signing NDA and receiving password you go to SoccerNet/SN-BAS-2025 and unzip train.zip test.zip and valid.zip files into the same directory (you basically ignore the existing splits)

#  7-zip example
7z x train.zip -o/path/to/data/soccernet/sn_bas_2025
7z x test.zip -o/path/to/data/soccernet/sn_bas_2025
7z x valid.zip -o/path/to/data/soccernet/sn_bas_2025

(7z will ask you for the password you receive via email after signing NDA)


Broadcast videos (Optional)

It is recommended to download dataset from challenge from previous years. They have some overlapping/similar labels and will be useful for pretraining. Be aware that this dataset is pretty beefy - it contains around 1.2TB of videos.

https://www.soccer-net.org/data#h.ov9k48lcih5g

from SoccerNet.Downloader import SoccerNetDownloader
downloader=SoccerNetDownloader(LocalDirectory="/path/to/data/soccernet/videos")
downloader.password = "Password for videos (received after filling the NDA)"
downloader.downloadGames(
    files=["1_720p.mkv", "2_720p.mkv"],
    split=["train","valid","test",]
)
downloader.downloadGames(
    files=["1_224p.mkv", "2_224p.mkv"], 
    split=["train","valid","test"]
)

(it may happen that transfer drops unexpectedly - the workaround for it is to use this code: https://gist.github.com/int8/6b5db0e6e16dfaa8bea9154d3774dec3)

At this point /path/to/data/soccernet/videos contains all the historical broadcasts.

Broadcast videos themselves do not contain any annotations. They are included in SoccerNet/SN-BAS-2025/ExtraLabelsActionSpotting500games you downloaded from huggingface data hub earlier.

unzip them into /path/to/data/soccernet/videos

7z x train_labels.zip -o/path/to/data/soccernet/videos 
7z x test_labels.zip -o/path/to/data/soccernet/videos 
7z x valid_labels.zip -o/path/to/data/soccernet/videos 

Using and extending the code

If you want to extend the code to train your own model you can use following interface for accessing the data:

from dudek.data.team_bas import SoccerVideo

# load bas video 
bas_video = SoccerVideo.bas_video_from_path(
    "/path/to/data/soccernet/sn_bas_2025/england_efl/2019-2020/2019-10-01 - Brentford - Bristol City/",
    resolution=224
)

# video metadata 
print(bas_video.league) # "england_efl"
print(bas_video.season) # "2019-2020"
print(bas_video.match) # "2019-10-01 - Brentford - Bristol City"
print(bas_video.absolute_path) # "/path/to/data/soccernet/sn_bas_2025/england_efl/2019-2020/2019-10-01 - Brentford - Bristol City/224p.mp4"

# video annotations 
print(bas_video.annotations) # list of annotations

# check out single annotation
annotation  = bas_video.annotations[0]
# get frame number of that annotation  
annotation.get_frame_nr(fps=bas_video.metadata_fps)
team = annotation.team # Team.LEFT or Team.RIGHT

label = annotation.label # enum value of ActionLabel or BASLabel 


# load action spotting video (from < 2025 dataset) - this will load 2 videos as they are divided into halfs 
action_spotting_video = SoccerVideo.action_spotting_video_from_path(
    "/path/to/data/soccernet/videos/england_epl/2014-2015/2015-02-21 - 18-00 Chelsea 1 - 1 Burnley",
    resolution=224
)

# you can do pretty much the same thing with action spotting video as with bas video
# the only difference is enum class of annotation label being ActionLabel (not BASLabel)

You can also load all the videos from bas dataset (and optionally save frames to FS for further processing)

from dudek.utils.video import load_bas_videos, load_action_spotting_videos

bas_videos = load_bas_videos(
    "/path/to/data/soccernet/sn_bas_2025/",
    resolution=224
)

# save frames to FS for further processing (this may take a while) 
for video in bas_videos:
    # by default frames are saved to FS (same dir as original video under .frames* folder) 
    video.save_frames(
        target_width=224,
        target_height=224,
        stride=2,
        grayscale=False,
    )

# use frames to generate short clips 
single_video = bas_videos[0]

# split video to continuous clips (where gap of max 2 frames is accepted) 
clips = single_video.get_clips(
    accepted_gap=2
)

# then split each clip to smaller clips of fixed size: 
fixed_length_clips = []
for clip in clips:
    fixed_length_clips += clip.split(
        clip_frames_count=200,
        overlap=190
    )

fixed_length_clip = fixed_length_clips[0]

# you can save this short video clip as video for visual inspection 
fixed_length_clip.save_as_labelled_video(
    output_path="clip.mp4", fps=12
)

# access clip frames and their attributes 
for frame in fixed_length_clip.frames:    
    print(frame.frame_path)
    print(frame.annotation)
    print(frame.original_video_frame_nr)
    # ...

To train any model via pytorch you may want to get inspired by baseline TDEED model:

from dudek.ml.data.tdeed import TdeedVideoClip, TeamTDeedDataset
from dudek.data.team_bas import BASLabel

# get single TDEED input clip 
tdeed_clip = TdeedVideoClip.from_video_clip(
    fixed_length_clip,
    labels_displacement=4,
    flip_proba=0.25,  # horizontal flip probability 
    camera_movement_proba=0.25,  # random camera movement probability    
    crop_proba=0.25,    
    labels_enum=BASLabel
)

# or corresponding pytorch dataset
dataset = TeamTDeedDataset(
    clips=fixed_length_clips,
    displacement=4,
    flip_proba=0.25,  # horizontal flip probability
    camera_move_proba=0.25,  # random camera movement probability    
    crop_proba=0.25,
    labels_enum=BASLabel
)

How to reproduce Dudek result on SN-BAS-2025

In case u don't want to mess with the code too much you can use CLI shipped with this package to reproduce dudek results. First thing to do is to extract frames from the videos. In case you want to pretrain on all broadcasts videos and then fine-tune on SN-BAS-2025 you need to extract frames from both datasets:

Extracting frames

bas-frame-extract extract-bas-frames \
    --dataset_path="/path/to/data/soccernet/sn_bas_2025/" \
    --resolution=224 \
    --stride=2 \
    --frame_target_width=224 \
    --frame_target_height=224
bas-frame-extract extract-action-spotting-frames  \
    --dataset_path="/path/to/data/soccernet/videos/" \
    --resolution=224 \
    --stride=2 \
    --frame_target_width=224 \
    --frame_target_height=224

This may take a while - up to 24h depending on your hardware, please also be aware it may take a bit of your disk space (around extra 1.2TB).

Once you are done with that, you can train a baseline model:

Pretraining

Start by pretraining on broadcast videos:

bas-tdeed-train pretrain --help 
Usage: bas-tdeed-train pretrain [OPTIONS]

Options:
  --dataset_path TEXT             [required]
  --resolution INTEGER
  --clip_frames_count INTEGER
  --overlap INTEGER
  --displacement INTEGER
  --flip_proba FLOAT
  --camera_move_proba FLOAT
  --crop_proba FLOAT
  --even_choice_proba FLOAT
  --nr_epochs INTEGER
  --warm_up_epochs INTEGER
  --learning_rate FLOAT
  --train_batch_size INTEGER
  --val_batch_size INTEGER
  --eval_metric TEXT
  --start_eval_epoch_nr INTEGER
  --loss_foreground_weight INTEGER
  --features_model_name TEXT
  --temporal_shift_mode TEXT
  --acc_grad_iter INTEGER
  --enforce_train_epoch_size INTEGER
  --enforce_val_epoch_size INTEGER
  --gaussian_blur_kernel_size INTEGER
  --tdeed_arch_n_layers INTEGER
  --tdeed_arch_sgp_ks INTEGER
  --tdeed_arch_sgp_k INTEGER
  --save_every_epoch BOOLEAN
  --save_as TEXT
  --wandb_experiment_name TEXT
  --random_seed INTEGER

Simplest example:

bas-tdeed-train pretrain \ 
  --dataset_path=/path/to/data/soccernet/videos/ \ 
  --resolution=224 \ 
  --save_as=pretrained.pt \ 
  --clip_frames_count=80 \ 
  --overlap=40 \ 
  --enforce_train_epoch_size=6000

To monitor pretraining run tensorboard --logdir=runs and go to http://localhost:6006/

Once you are done with that your best model will be stored as "pretrained.pt" in the current directory

Fine-tuning

you can now fine-tune it on SN-BAS-2025:

bas-tdeed-train train --help                                                                                                 

Usage: bas-tdeed-train train [OPTIONS]

Options:
  --dataset_path TEXT             [required]
  --resolution INTEGER
  --clip_frames_count INTEGER
  --overlap INTEGER
  --displacement INTEGER
  --flip_proba FLOAT
  --camera_move_proba FLOAT
  --crop_proba FLOAT
  --even_choice_proba FLOAT
  --nr_epochs INTEGER
  --warm_up_epochs INTEGER
  --learning_rate FLOAT
  --train_batch_size INTEGER
  --val_batch_size INTEGER
  --eval_metric TEXT
  --start_eval_epoch_nr INTEGER
  --loss_foreground_weight INTEGER
  --features_model_name TEXT
  --temporal_shift_mode TEXT
  --acc_grad_iter INTEGER
  --enforce_train_epoch_size INTEGER
  --enforce_val_epoch_size INTEGER
  --gaussian_blur_kernel_size INTEGER
  --tdeed_arch_n_layers INTEGER
  --tdeed_arch_sgp_ks INTEGER
  --tdeed_arch_sgp_k INTEGER
  --model_checkpoint_path TEXT
  --save_as TEXT
  --experiment_name TEXT
  --random_seed INTEGER
  --help                          Show this message and exit.


The simplest approach is:

 bas-tdeed-train train \ 
  --dataset_path=/path/to/data/soccernet/sn_bas_2025/ \ 
  --resolution=224 --model_checkpoint_path=pretrained.pt \ 
  --clip_frames_count=80 \
  --overlap=68 \
  --enforce_train_epoch_size=6000

Again, go to wandb or tensorboard web interface to monitor fine-tuning progress. Here you should see mAP for eval set instead of loss. By defaults splits are the same as those provided by challenge organizers (random_seed default param does that trick for you)

Fine-tuning with no evaluation

The simplest scenario to provide submission to the challenge, is to train the model on the whole dataset. In this scenario you will fine-tune the model for N epochs.

 bas-tdeed-train train-challenge \ 
  --dataset_path=/mnt/data4t/soccernet/sn_bas_2025/ \ 
  --resolution=224 \ 
  --model_checkpoint_path=pretrained.pt \ 
  --clip_frames_count=80 \ 
  --overlap=68 \ 
  --enforce_train_epoch_size=6000 \ 
  --nr_epochs=30 
  --save_as=tdeed_challenge.pt

Preparing submission archive

First, unzip challenge dataset to separate directory:

7z x challenge.zip -o/path/to/data/soccernet/challenge_bas_data # same as before you need to provide NDA password 

Next, extract frames from challenge videos:

bas-frame-extract extract-bas-frames \                                                                                                                                                                                                                                                                             kamil@matka
    --dataset_path="path/to/data/soccernet/challenge_bas_data" \
    --resolution=224 \
    --save_all=true \ 
    --stride=2 \
    --frame_target_width=224 \
    --frame_target_height=224

And finally we can produce submission.zip to be uploaded to codebench platform:

bas-tdeed-train create-solution \ 
  --dataset_path=/mnt/data4t/soccernet/challenge_data \ 
  --resolution=224 \ 
  --model_checkpoint_path=tdeed_challenge.pt

This should produce submission.zip in your local directory. Cross your fingers and upload it to codebench.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dude_k-0.1.0.tar.gz (37.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dude_k-0.1.0-py3-none-any.whl (43.6 kB view details)

Uploaded Python 3

File details

Details for the file dude_k-0.1.0.tar.gz.

File metadata

  • Download URL: dude_k-0.1.0.tar.gz
  • Upload date:
  • Size: 37.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.5

File hashes

Hashes for dude_k-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a4de7513d04a70c88474741ff5d333f9396e3e83d1b39dc691e4da67418eb848
MD5 f14df85d17a3e662b77fe8f69bcf5eb6
BLAKE2b-256 1b56cc10cc62d5d02ff5bc138a100b8df1c329672d55c6696c8a72ed39a9cf81

See more details on using hashes here.

File details

Details for the file dude_k-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dude_k-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 43.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.5

File hashes

Hashes for dude_k-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b3cf93cc08e0eed84a4bf80d272ceb85cf42e33f9dcde603a5b327262e55e4b9
MD5 8dd5ebd709069ea5cce16a46f0104ccd
BLAKE2b-256 8225c523fb9731519f56f3a927219b91cdc60eeae479526e743b27f1e539dbea

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page