"sgl-kernel/vscode:/vscode.git/clone" did not exist on "3b80232d06694e848e54890eb6c4a0e0bf54ecea"
Commit 0063a668 authored by chenzk's avatar chenzk
Browse files

v1.0

parents
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
import os
import torch
import argparse
import imageio.v3 as iio
import numpy as np
from cotracker.utils.visualizer import Visualizer
from cotracker.predictor import CoTrackerOnlinePredictor
DEFAULT_DEVICE = (
"cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--video_path",
default="./assets/apple.mp4",
help="path to a video",
)
parser.add_argument(
"--checkpoint",
default=None,
help="CoTracker model parameters",
)
parser.add_argument("--grid_size", type=int, default=10, help="Regular grid size")
parser.add_argument(
"--grid_query_frame",
type=int,
default=0,
help="Compute dense and grid tracks starting from this frame",
)
args = parser.parse_args()
if not os.path.isfile(args.video_path):
raise ValueError("Video file does not exist")
if args.checkpoint is not None:
model = CoTrackerOnlinePredictor(checkpoint=args.checkpoint)
else:
model = torch.hub.load("facebookresearch/co-tracker", "cotracker3_online")
model = model.to(DEFAULT_DEVICE)
window_frames = []
def _process_step(window_frames, is_first_step, grid_size, grid_query_frame):
video_chunk = (
torch.tensor(
np.stack(window_frames[-model.step * 2 :]), device=DEFAULT_DEVICE
)
.float()
.permute(0, 3, 1, 2)[None]
) # (1, T, 3, H, W)
return model(
video_chunk,
is_first_step=is_first_step,
grid_size=grid_size,
grid_query_frame=grid_query_frame,
)
# Iterating over video frames, processing one window at a time:
is_first_step = True
for i, frame in enumerate(
iio.imiter(
args.video_path,
plugin="FFMPEG",
)
):
if i % model.step == 0 and i != 0:
pred_tracks, pred_visibility = _process_step(
window_frames,
is_first_step,
grid_size=args.grid_size,
grid_query_frame=args.grid_query_frame,
)
is_first_step = False
window_frames.append(frame)
# Processing the final video frames in case video length is not a multiple of model.step
pred_tracks, pred_visibility = _process_step(
window_frames[-(i % model.step) - model.step - 1 :],
is_first_step,
grid_size=args.grid_size,
grid_query_frame=args.grid_query_frame,
)
print("Tracks are computed")
# save a video with predicted tracks
seq_name = args.video_path.split("/")[-1]
video = torch.tensor(np.stack(window_frames), device=DEFAULT_DEVICE).permute(
0, 3, 1, 2
)[None]
vis = Visualizer(save_dir="./saved_videos", pad_value=120, linewidth=3)
vis.visualize(
video, pred_tracks, pred_visibility, query_frame=args.grid_query_frame
)
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
from setuptools import find_packages, setup
setup(
name="cotracker",
version="3.0",
install_requires=[],
packages=find_packages(exclude="notebooks"),
extras_require={
"all": ["matplotlib"],
"dev": ["flake8", "black"],
},
)
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
import torch
import unittest
from cotracker.models.core.model_utils import bilinear_sampler
class TestBilinearSampler(unittest.TestCase):
# Sample from an image (4d)
def _test4d(self, align_corners):
H, W = 4, 5
# Construct a grid to obtain indentity sampling
input = torch.randn(H * W).view(1, 1, H, W).float()
coords = torch.meshgrid(torch.arange(H), torch.arange(W))
coords = torch.stack(coords[::-1], dim=-1).float()[None]
if not align_corners:
coords = coords + 0.5
sampled_input = bilinear_sampler(input, coords, align_corners=align_corners)
torch.testing.assert_close(input, sampled_input)
# Sample from a video (5d)
def _test5d(self, align_corners):
T, H, W = 3, 4, 5
# Construct a grid to obtain indentity sampling
input = torch.randn(H * W).view(1, 1, H, W).float()
input = torch.stack([input, input + 1, input + 2], dim=2)
coords = torch.meshgrid(torch.arange(T), torch.arange(W), torch.arange(H))
coords = torch.stack(coords, dim=-1).float().permute(0, 2, 1, 3)[None]
if not align_corners:
coords = coords + 0.5
sampled_input = bilinear_sampler(input, coords, align_corners=align_corners)
torch.testing.assert_close(input, sampled_input)
def test4d(self):
self._test4d(align_corners=True)
self._test4d(align_corners=False)
def test5d(self):
self._test5d(align_corners=True)
self._test5d(align_corners=False)
# run the test
unittest.main()
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
import os
import random
import torch
import signal
import socket
import sys
import json
import torch.nn.functional as F
import numpy as np
import argparse
import logging
from pathlib import Path
from tqdm import tqdm
import torch.optim as optim
from torch.cuda.amp import GradScaler
from pytorch_lightning.lite import LightningLite
from cotracker.models.core.cotracker.cotracker3_offline import CoTrackerThreeOffline
from cotracker.models.core.cotracker.cotracker3_online import CoTrackerThreeOnline
from cotracker.utils.visualizer import Visualizer
from cotracker.models.core.model_utils import get_uniformly_sampled_pts
from cotracker.evaluation.core.evaluator import Evaluator
from cotracker.datasets.utils import collate_fn, collate_fn_train, dataclass_to_cuda_
from cotracker.models.core.cotracker.losses import (
sequence_loss,
sequence_BCE_loss,
sequence_prob_loss,
)
from cotracker.utils.train_utils import (
Logger,
get_eval_dataloader,
get_train_dataset,
sig_handler,
term_handler,
run_test_eval,
)
def fetch_optimizer(args, model):
"""Create the optimizer and learning rate scheduler"""
mlp_params = sum(
p.numel()
for name, p in model.named_parameters()
if p.requires_grad and "corr_mlp" in name
)
print(f"Total number of MlP parameters: {mlp_params}")
mlp_params = sum(
p.numel()
for name, p in model.named_parameters()
if p.requires_grad and "cmdtop" in name
)
print(f"Total number of cmdtop parameters: {mlp_params}")
total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Total number of parameters: {total_params}")
optimizer = optim.AdamW(
model.parameters(), lr=args.lr, weight_decay=args.wdecay, eps=1e-8
)
scheduler = optim.lr_scheduler.OneCycleLR(
optimizer,
args.lr,
args.num_steps + 100,
pct_start=0.05,
cycle_momentum=False,
anneal_strategy="cos",
)
return optimizer, scheduler
def forward_batch(batch, model, args):
video = batch.video
trajs_g = batch.trajectory
vis_g = batch.visibility
valids = batch.valid
B, T, C, H, W = video.shape
assert C == 3
B, T, N, D = trajs_g.shape
device = video.device
__, first_positive_inds = torch.max(vis_g, dim=1)
if args.query_sampling_method == "random":
assert B == 1
true_indices = torch.nonzero(vis_g[0])
# Group the indices by the first column (N)
grouped_indices = true_indices[:, 1].unique()
# Initialize an empty tensor to hold the sampled points
sampled_points = torch.empty((B, N, D))
indices = torch.empty((B, N, 1))
# For each unique N
for n in grouped_indices:
# Get the T indices where visibilities[0, :, n] is True
t_indices = true_indices[true_indices[:, 1] == n, 0]
# Select a random index from t_indices
random_index = t_indices[torch.randint(0, len(t_indices), (1,))]
# Use this random index to sample a point from the trajectories tensor
sampled_points[0, n] = trajs_g[0, random_index, n]
indices[0, n] = random_index.float()
# model.window_len = vis_g.shape[1]
queries = torch.cat([indices, sampled_points], dim=2)
else:
# We want to make sure that during training the model sees visible points
# that it does not need to track just yet: they are visible but queried from a later frame
N_rand = N // 4
# inds of visible points in the 1st frame
nonzero_inds = [
[torch.nonzero(vis_g[b, :, i]) for i in range(N)] for b in range(B)
]
for b in range(B):
rand_vis_inds = torch.cat(
[
nonzero_row[torch.randint(len(nonzero_row), size=(1,))]
for nonzero_row in nonzero_inds[b]
],
dim=1,
)
first_positive_inds[b] = torch.cat(
[rand_vis_inds[:, :N_rand], first_positive_inds[b : b + 1, N_rand:]],
dim=1,
)
ind_array_ = torch.arange(T, device=device)
ind_array_ = ind_array_[None, :, None].repeat(B, 1, N)
assert torch.allclose(
vis_g[ind_array_ == first_positive_inds[:, None, :]],
torch.ones(1, device=device),
)
gather = torch.gather(
trajs_g, 1, first_positive_inds[:, :, None, None].repeat(1, 1, N, D)
)
xys = torch.diagonal(gather, dim1=1, dim2=2).permute(0, 2, 1)
queries = torch.cat([first_positive_inds[:, :, None], xys[:, :, :2]], dim=2)
assert B == 1
if (
torch.isnan(queries).any()
or torch.isnan(trajs_g).any()
or queries.abs().max() > 1500
):
print("failed_sample")
print("queries time", queries[..., 0])
print("queries ", queries[..., 1:])
queries = torch.ones_like(queries).to(queries.device).float()
print("new queries", queries)
valids = torch.zeros_like(valids).to(valids.device).float()
print("new valids", valids)
model_output = model(
video=video, queries=queries[..., :3], iters=args.train_iters, is_train=True
)
tracks, visibility, confidence, train_data = model_output
coord_predictions, vis_predictions, confidence_predicitons, valid_mask = train_data
vis_gts = []
invis_gts = []
traj_gts = []
valids_gts = []
if args.offline_model:
S = T
seq_len = (S // 2) + 1
else:
S = args.sliding_window_len
seq_len = T
for ind in range(0, seq_len - S // 2, S // 2):
vis_gts.append(vis_g[:, ind : ind + S])
invis_gts.append(1 - vis_g[:, ind : ind + S])
traj_gts.append(trajs_g[:, ind : ind + S, :, :2])
val = valids[:, ind : ind + S]
if not args.offline_model:
val = val * valid_mask[:, ind : ind + S]
valids_gts.append(val)
seq_loss_visible = sequence_loss(
coord_predictions,
traj_gts,
valids_gts,
vis=vis_gts,
gamma=0.8,
add_huber_loss=args.add_huber_loss,
loss_only_for_visible=True,
)
confidence_loss = sequence_prob_loss(
coord_predictions, confidence_predicitons, traj_gts, vis_gts
)
vis_loss = sequence_BCE_loss(vis_predictions, vis_gts)
output = {"flow": {"predictions": tracks[0].detach()}}
output["flow"]["loss"] = seq_loss_visible.mean() * 0.05
output["flow"]["queries"] = queries.clone()
if not args.train_only_on_visible:
seq_loss_invisible = sequence_loss(
coord_predictions,
traj_gts,
valids_gts,
vis=invis_gts,
gamma=0.8,
add_huber_loss=False,
loss_only_for_visible=True,
)
output["flow_invisible"] = {"loss": seq_loss_invisible.mean() * 0.01}
output["visibility"] = {
"loss": vis_loss.mean(),
"predictions": visibility[0].detach(),
}
output["confidence"] = {
"loss": confidence_loss.mean(),
}
return output
class Lite(LightningLite):
def run(self, args):
def seed_everything(seed: int):
random.seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
seed_everything(42)
def seed_worker(worker_id):
worker_seed = torch.initial_seed() % 2**32
np.random.seed(worker_seed + worker_id)
random.seed(worker_seed + worker_id)
g = torch.Generator()
g.manual_seed(42)
if self.global_rank == 0:
eval_dataloaders = []
for ds_name in args.eval_datasets:
eval_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
if not args.debug:
final_dataloaders = [dl for dl in eval_dataloaders]
ds_name = "dynamic_replica"
final_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
ds_name = "tapvid_robotap"
final_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
ds_name = "tapvid_kinetics_first"
final_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
evaluator = Evaluator(args.ckpt_path)
visualizer = Visualizer(
save_dir=args.ckpt_path,
pad_value=180,
fps=1,
show_first_frame=0,
tracks_leave_trace=0,
)
if args.model_name == "cotracker_three":
if args.offline_model:
model = CoTrackerThreeOffline(
stride=args.model_stride,
corr_radius=args.corr_radius,
corr_levels=args.corr_levels,
window_len=args.sliding_window_len,
num_virtual_tracks=args.num_virtual_tracks,
model_resolution=args.crop_size,
linear_layer_for_vis_conf=args.linear_layer_for_vis_conf,
)
else:
model = CoTrackerThreeOnline(
stride=args.model_stride,
corr_radius=args.corr_radius,
corr_levels=args.corr_levels,
window_len=args.sliding_window_len,
num_virtual_tracks=args.num_virtual_tracks,
model_resolution=args.crop_size,
linear_layer_for_vis_conf=args.linear_layer_for_vis_conf,
)
else:
raise ValueError(f"Model {args.model_name} doesn't exist")
with open(args.ckpt_path + "/meta.json", "w") as file:
json.dump(vars(args), file, sort_keys=True, indent=4)
model.cuda()
train_dataset = get_train_dataset(args)
train_loader = torch.utils.data.DataLoader(
train_dataset,
batch_size=args.batch_size,
shuffle=True,
num_workers=args.num_workers,
worker_init_fn=seed_worker,
generator=g,
pin_memory=True,
collate_fn=collate_fn_train,
drop_last=True,
)
train_loader = self.setup_dataloaders(train_loader, move_to_device=False)
print("LEN TRAIN LOADER", len(train_loader))
optimizer, scheduler = fetch_optimizer(args, model)
total_steps = 0
if self.global_rank == 0:
logger = Logger(model, scheduler, ckpt_path=args.ckpt_path)
folder_ckpts = [
f
for f in os.listdir(args.ckpt_path)
if not os.path.isdir(f) and f.endswith(".pth") and not "final" in f
]
if len(folder_ckpts) > 0:
ckpt_path = sorted(folder_ckpts)[-1]
ckpt = self.load(os.path.join(args.ckpt_path, ckpt_path))
logging.info(f"Loading checkpoint {ckpt_path}")
if "model" in ckpt:
model.load_state_dict(ckpt["model"])
else:
model.load_state_dict(ckpt)
if "optimizer" in ckpt:
logging.info("Load optimizer")
optimizer.load_state_dict(ckpt["optimizer"])
if "scheduler" in ckpt:
logging.info("Load scheduler")
scheduler.load_state_dict(ckpt["scheduler"])
if "total_steps" in ckpt:
total_steps = ckpt["total_steps"]
logging.info(f"Load total_steps {total_steps}")
elif args.restore_ckpt is not None:
assert args.restore_ckpt.endswith(".pth") or args.restore_ckpt.endswith(
".pt"
)
logging.info("Loading checkpoint...")
strict = False
state_dict = self.load(args.restore_ckpt)
if "model" in state_dict:
state_dict = state_dict["model"]
state_dict = {
k: v
for k, v in state_dict.items()
if "time_emb" not in k and "pos_emb" not in k
}
if list(state_dict.keys())[0].startswith("module."):
state_dict = {
k.replace("module.", ""): v for k, v in state_dict.items()
}
model.load_state_dict(state_dict, strict=strict)
logging.info(f"Done loading checkpoint")
model, optimizer = self.setup(model, optimizer, move_to_device=False)
model.train()
save_freq = args.save_freq
scaler = GradScaler(enabled=False)
should_keep_training = True
global_batch_num = 0
epoch = -1
while should_keep_training:
epoch += 1
for i_batch, batch in enumerate(tqdm(train_loader)):
batch, gotit = batch
if not all(gotit):
print("batch is None")
continue
dataclass_to_cuda_(batch)
optimizer.zero_grad(set_to_none=True)
assert model.training
output = forward_batch(batch, model, args)
loss = 0
for k, v in output.items():
if "loss" in v:
loss += v["loss"]
if self.global_rank == 0:
for k, v in output.items():
if "loss" in v:
logger.writer.add_scalar(
f"live_{k}_loss", v["loss"].item(), total_steps
)
if "metrics" in v:
logger.push(v["metrics"], k)
if total_steps % save_freq == save_freq - 1:
visualizer.visualize(
video=batch.video.clone(),
tracks=batch.trajectory.clone()[..., :2],
visibility=batch.visibility.clone(),
filename="train_gt_traj_0",
writer=logger.writer,
step=total_steps,
)
visualizer.visualize(
video=batch.video.clone(),
tracks=output["flow"]["predictions"][None],
visibility=output["visibility"]["predictions"][None] > 0.8,
filename="train_pred_traj_0",
writer=logger.writer,
step=total_steps,
)
if len(output) > 1:
logger.writer.add_scalar(
f"live_total_loss", loss.item(), total_steps
)
logger.writer.add_scalar(
f"learning_rate", optimizer.param_groups[0]["lr"], total_steps
)
global_batch_num += 1
self.barrier()
self.backward(scaler.scale(loss))
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
scaler.step(optimizer)
scheduler.step()
scaler.update()
total_steps += 1
if self.global_rank == 0:
if (i_batch >= len(train_loader) - 1) or (
total_steps == 1 and args.validate_at_start
):
if (epoch + 1) % args.save_every_n_epoch == 0:
ckpt_iter = "0" * (6 - len(str(total_steps))) + str(
total_steps
)
save_path = Path(
f"{args.ckpt_path}/model_{args.model_name}_{ckpt_iter}.pth"
)
save_dict = {
"model": model.module.module.state_dict(),
"optimizer": optimizer.state_dict(),
"scheduler": scheduler.state_dict(),
"total_steps": total_steps,
}
logging.info(f"Saving file {save_path}")
self.save(save_dict, save_path)
if (epoch + 1) % args.evaluate_every_n_epoch == 0 or (
args.validate_at_start and epoch == 0
):
run_test_eval(
evaluator,
model,
eval_dataloaders,
logger.writer,
total_steps,
query_random=(
args.query_sampling_method is not None
and "random" in args.query_sampling_method
),
)
model.train()
torch.cuda.empty_cache()
self.barrier()
if total_steps > args.num_steps:
should_keep_training = False
break
if self.global_rank == 0:
print("FINISHED TRAINING")
PATH = f"{args.ckpt_path}/{args.model_name}_final.pth"
torch.save(model.module.module.state_dict(), PATH)
run_test_eval(
evaluator,
model,
final_dataloaders,
logger.writer,
total_steps,
query_random=(
args.query_sampling_method is not None
and "random" in args.query_sampling_method
),
)
logger.close()
if __name__ == "__main__":
signal.signal(signal.SIGUSR1, sig_handler)
signal.signal(signal.SIGTERM, term_handler)
parser = argparse.ArgumentParser()
parser.add_argument("--model_name", default="cotracker_three", help="model name")
parser.add_argument("--restore_ckpt", help="path to restore a checkpoint")
parser.add_argument("--ckpt_path", help="path to save checkpoints")
parser.add_argument(
"--batch_size", type=int, default=4, help="batch size used during training."
)
parser.add_argument("--num_nodes", type=int, default=1)
parser.add_argument(
"--num_workers", type=int, default=10, help="number of dataloader workers"
)
parser.add_argument(
"--mixed_precision", action="store_true", help="use mixed precision"
)
parser.add_argument("--lr", type=float, default=0.0005, help="max learning rate.")
parser.add_argument(
"--wdecay", type=float, default=0.00001, help="Weight decay in optimizer."
)
parser.add_argument(
"--num_steps", type=int, default=200000, help="length of training schedule."
)
parser.add_argument(
"--evaluate_every_n_epoch",
type=int,
default=1,
help="evaluate during training after every n epochs, after every epoch by default",
)
parser.add_argument(
"--save_every_n_epoch",
type=int,
default=1,
help="save checkpoints during training after every n epochs, after every epoch by default",
)
parser.add_argument(
"--validate_at_start",
action="store_true",
help="whether to run evaluation before training starts",
)
parser.add_argument(
"--save_freq",
type=int,
default=100,
help="frequency of trajectory visualization during training",
)
parser.add_argument(
"--traj_per_sample",
type=int,
default=768,
help="the number of trajectories to sample for training",
)
parser.add_argument(
"--dataset_root", type=str, help="path lo all the datasets (train and eval)"
)
parser.add_argument(
"--train_iters",
type=int,
default=4,
help="number of updates to the disparity field in each forward pass.",
)
parser.add_argument(
"--sequence_len", type=int, default=8, help="train sequence length"
)
parser.add_argument(
"--eval_datasets",
nargs="+",
default=["tapvid_davis_first"],
help="what datasets to use for evaluation",
)
parser.add_argument(
"--train_datasets",
nargs="+",
default=["kubric"],
help="what datasets to use for evaluation",
)
parser.add_argument(
"--random_frame_rate",
action="store_true",
help="remove space attention from CoTracker",
)
parser.add_argument(
"--num_virtual_tracks",
type=int,
default=None,
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--dont_use_augs",
action="store_true",
help="don't apply augmentations during training",
)
parser.add_argument(
"--offline_model",
action="store_true",
help="only sample trajectories with points visible on the first frame",
)
parser.add_argument(
"--sliding_window_len",
type=int,
default=16,
help="length of the CoTracker sliding window",
)
parser.add_argument(
"--model_stride",
type=int,
default=4,
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--corr_radius",
type=int,
default=3,
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--corr_levels",
type=int,
default=4,
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--crop_size",
type=int,
nargs="+",
default=[384, 512],
help="crop videos to this resolution during training",
)
parser.add_argument(
"--eval_max_seq_len",
type=int,
default=1000,
help="maximum length of evaluation videos",
)
parser.add_argument(
"--query_sampling_method",
type=str,
help="path lo all the datasets (train and eval)",
)
parser.add_argument(
"--random_number_traj",
action="store_true",
help="only sample trajectories with points visible on the first frame",
)
parser.add_argument(
"--add_huber_loss",
action="store_true",
help="only sample trajectories with points visible on the first frame",
)
parser.add_argument(
"--debug",
action="store_true",
help="only sample trajectories with points visible on the first frame",
)
parser.add_argument(
"--random_seq_len",
action="store_true",
help="only sample trajectories with points visible on the first frame",
)
parser.add_argument(
"--linear_layer_for_vis_conf",
action="store_true",
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--train_only_on_visible",
action="store_true",
help="stride of the CoTracker feature network",
)
args = parser.parse_args()
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s",
)
Path(args.ckpt_path).mkdir(exist_ok=True, parents=True)
from pytorch_lightning.strategies import DDPStrategy
Lite(
strategy=DDPStrategy(find_unused_parameters=False),
devices="auto",
accelerator="gpu",
precision="bf16" if args.mixed_precision else 32,
num_nodes=args.num_nodes,
).run(args)
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
import os
import random
import torch
import signal
import socket
import sys
import json
import numpy as np
import argparse
import logging
from pathlib import Path
from tqdm import tqdm
import torch.optim as optim
import torchvision
from torch.utils.data import DataLoader
from torch.cuda.amp import GradScaler
from pytorch_lightning.lite import LightningLite
from cotracker.models.bootstap_predictor import TAPIRPredictor
from cotracker.models.core.cotracker.cotracker import CoTracker2
from cotracker.models.core.cotracker.cotracker3_offline import CoTrackerThreeOffline
from cotracker.models.core.cotracker.cotracker3_online import CoTrackerThreeOnline
from cotracker.utils.visualizer import Visualizer
from cotracker.evaluation.core.evaluator import Evaluator
from cotracker.datasets.utils import collate_fn, collate_fn_train, dataclass_to_cuda_
from cotracker.models.core.model_utils import (
get_uniformly_sampled_pts,
get_points_on_a_grid,
get_sift_sampled_pts,
get_superpoint_sampled_pts,
)
from cotracker.models.core.cotracker.losses import sequence_loss
from cotracker.models.build_cotracker import build_cotracker
from cotracker.utils.train_utils import (
Logger,
get_eval_dataloader,
sig_handler,
term_handler,
run_test_eval,
)
def fetch_optimizer(args, model):
"""Create the optimizer and learning rate scheduler"""
total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Total number of parameters: {total_params}")
for name, param in model.named_parameters():
if "vis_conf_head" in name:
param.requires_grad = False
optimizer = optim.AdamW(
model.parameters(), lr=args.lr, weight_decay=args.wdecay, eps=1e-8
)
scheduler = optim.lr_scheduler.OneCycleLR(
optimizer,
args.lr,
args.num_steps + 100,
pct_start=0.0,
cycle_momentum=False,
anneal_strategy="cos",
)
return optimizer, scheduler
def forward_batch(batch, model, args, teacher_models):
video = batch.video
trajs_g = batch.trajectory
vis_g = batch.visibility
valids = batch.valid
B, T, C, H, W = video.shape
assert C == 3
B, T, N, D = trajs_g.shape
device = video.device
failed_sample = False
if args.real_data_filter_sift:
queries = get_sift_sampled_pts(video, N, T, [H, W], device=device)
if queries.shape[1] < N:
logging.warning(
f"SIFT wasn't able to extract enough features: {queries.shape[1]}"
)
failed_sample = True
queries = get_uniformly_sampled_pts(N, T, [H, W], device=device)
elif args.real_data_filter_superpoint:
queries = get_superpoint_sampled_pts(video, N, T, [H, W], device=device)
if queries.shape[1] < N:
logging.warning("SuperPoint wasn't able to extract enough features")
failed_sample = True
queries = get_uniformly_sampled_pts(N, T, [H, W], device=device)
else:
queries = get_uniformly_sampled_pts(N, T, [H, W], device=device)
# Inference with additional points sampled on a regular grid usually makes predictions better.
# So we sample these points and discard them thereafter
teacher_model_ind = random.choice(range(len(teacher_models)))
teacher_model_type, teacher_model = teacher_models[teacher_model_ind]
uniform_size = grid_size = sift_size = 0
queries_cat = queries.clone()
if "online" in teacher_model_type:
grid_size = args.train_grid_size
sift_size = args.train_sift_size
if grid_size > 0:
xy = get_points_on_a_grid(grid_size, [H, W], device=device)
xy = torch.cat([torch.zeros_like(xy[:, :, :1]), xy], dim=2) #
queries_cat = torch.cat([queries_cat, xy], dim=1) #
if sift_size > 0:
xy = get_sift_sampled_pts(video, sift_size, T, [H, W], device=device)
if xy.shape[1] == sift_size:
queries_cat = torch.cat([queries_cat, xy], dim=1) #
else:
sift_size = 0
elif "offline" in teacher_model_type:
uniform_size = 100
if uniform_size > 0:
xy = get_uniformly_sampled_pts(uniform_size, T, [H, W], device=device)
queries_cat = torch.cat([queries_cat, xy], dim=1) #
elif teacher_model_type == "tapir":
pass
else:
raise ValueError(f"Model type {teacher_model_type} doesn't exist")
if "cotracker_three" in teacher_model_type:
with torch.no_grad():
(
trajs_g,
vis_g,
confidence,
__,
) = teacher_model(video, queries_cat)
else:
with torch.no_grad():
trajs_g, vis_g, *_ = teacher_model(video, queries_cat)
confidence = torch.ones_like(vis_g)
# discarding additional points
if sift_size > 0 or grid_size > 0 or uniform_size > 0:
trajs_g = trajs_g[:, :, : -(grid_size**2) - sift_size - uniform_size]
vis_g = vis_g[:, :, : -(grid_size**2) - sift_size - uniform_size]
confidence = confidence[:, :, : -(grid_size**2) - sift_size - uniform_size]
vis_g = vis_g > 0.9
batch.trajectory = trajs_g
batch.visibility = vis_g
if args.model_name == "cotracker_three":
if (
torch.isnan(queries).any()
or torch.isnan(trajs_g).any()
or queries.abs().max() > 1500
):
logging.warning("failed_sample")
queries = torch.ones_like(queries).to(queries.device).float()
valids = torch.zeros_like(valids).to(valids.device).float()
tracks, visibility, confidence, train_data = model(
video=video, queries=queries, iters=args.train_iters, is_train=True
)
coord_predictions, vis_predictions, confidence_predicitons, valid_mask = (
train_data
)
if failed_sample:
valid_mask = torch.zeros_like(vis_g)
logging.warning("Making mask zero for failed sample")
vis_gts = []
invis_gts = []
traj_gts = []
valids_gts = []
if args.offline_model:
S = T
seq_len = (S // 2) + 1
else:
S = args.sliding_window_len
seq_len = T
for ind in range(0, seq_len - S // 2, S // 2):
vis_gts.append(vis_g[:, ind : ind + S].float())
invis_gts.append(1 - vis_g[:, ind : ind + S].float())
traj_gts.append(trajs_g[:, ind : ind + S, :, :2])
valids_gts.append(valids[:, ind : ind + S] * valid_mask[:, ind : ind + S])
seq_loss = sequence_loss(
coord_predictions,
traj_gts,
valids_gts,
vis=vis_gts,
gamma=0.8,
add_huber_loss=True,
loss_only_for_visible=True,
)
output = {
"flow": {"predictions": (tracks[0].detach() * valid_mask[..., None])[0]}
}
output["flow"]["loss"] = seq_loss.mean() * 0.05
output["flow"]["queries"] = queries.clone()
output["flow"]["query_frame"] = queries[0, :, 0].cpu().int()
output["visibility"] = {
"predictions": visibility[0].detach(),
}
if not (teacher_model_type == "tapir" or args.train_only_visible_points):
seq_loss_invisible = sequence_loss(
coord_predictions,
traj_gts,
valids_gts,
vis=invis_gts,
gamma=0.8,
add_huber_loss=False,
loss_only_for_visible=True,
)
output["flow_invisible"] = {"loss": seq_loss_invisible.mean() * 0.01}
return output
else:
predictions, visibility, train_data = model(
video=video, queries=queries, iters=args.train_iters, is_train=True
)
coord_predictions, vis_predictions, valid_mask = train_data
if failed_sample:
valid_mask = torch.zeros_like(valid_mask)
logging.warning("Making mask zero for failed sample")
vis_gts = []
traj_gts = []
valids_gts = []
delta = 6
S = args.sliding_window_len
pred_ind = 0
for ind in range(0, args.sequence_len - S // 2, S // 2):
vis_gts.append(vis_g[:, ind : ind + S])
traj_gts.append(trajs_g[:, ind : ind + S])
if (
teacher_model_type == "tapir"
or teacher_model_type == "online_cotracker_three"
or args.train_only_visible_points
):
valids_gts.append(
valids[:, ind : ind + S]
* valid_mask[:, ind : ind + S]
* vis_g[:, ind : ind + S]
> 0.9
)
else:
valids_gts.append(
valids[:, ind : ind + S] * valid_mask[:, ind : ind + S]
)
pred_ind += 1
seq_loss = sequence_loss(
coord_predictions,
traj_gts,
vis_gts,
valids_gts,
gamma=0.8,
loss_only_for_visible_pts=False,
)
batch.trajectory = batch.trajectory * valid_mask[..., None]
output = {"flow": {}}
output["flow"]["predictions"] = (predictions.detach() * valid_mask[..., None])[
0
]
output["flow"]["loss"] = seq_loss.mean()
output["flow"]["query_frame"] = queries[0, :, 0].cpu().int()
output["visibility"] = {
"predictions": visibility[0].detach(),
}
return output
class Lite(LightningLite):
def run(self, args):
def seed_everything(seed: int):
random.seed(seed)
os.environ["PYTHONHASHSEED"] = str(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
seed_everything(0)
def seed_worker(worker_id):
worker_seed = torch.initial_seed() % 2**32
np.random.seed(worker_seed)
random.seed(worker_seed)
g = torch.Generator()
g.manual_seed(0)
if self.global_rank == 0:
eval_dataloaders = []
for ds_name in args.eval_datasets:
eval_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
if not args.debug:
final_dataloaders = [dl for dl in eval_dataloaders]
ds_name = "tapvid_kinetics_first"
final_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
ds_name = "tapvid_robotap"
final_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
ds_name = "dynamic_replica"
final_dataloaders.append(
(ds_name, get_eval_dataloader(args.dataset_root, ds_name))
)
evaluator = Evaluator(args.ckpt_path)
visualizer = Visualizer(
save_dir=args.ckpt_path,
pad_value=180,
fps=1,
show_first_frame=0,
tracks_leave_trace=0,
)
if args.model_name == "cotracker":
model = CoTracker2(
stride=args.model_stride,
window_len=args.sliding_window_len,
num_virtual_tracks=args.num_virtual_tracks,
model_resolution=args.crop_size,
)
elif args.model_name == "cotracker_three":
if args.offline_model:
model = CoTrackerThreeOffline(
stride=4,
corr_radius=3,
window_len=60,
model_resolution=(384, 512),
linear_layer_for_vis_conf=True,
)
else:
model = CoTrackerThreeOnline(
stride=4,
corr_radius=3,
window_len=16,
model_resolution=(384, 512),
linear_layer_for_vis_conf=True,
)
else:
raise ValueError(f"Model {args.model_name} doesn't exist")
with open(args.ckpt_path + "/meta.json", "w") as file:
json.dump(vars(args), file, sort_keys=True, indent=4)
model.cuda()
teacher_models = []
from cotracker.datasets import real_dataset
train_dataset = real_dataset.RealDataset(
crop_size=args.crop_size,
seq_len=args.sequence_len,
traj_per_sample=args.traj_per_sample,
random_frame_rate=args.random_frame_rate,
random_seq_len=args.offline_model,
data_splits=args.real_data_splits,
random_resize=False,
limit_samples=args.limit_samples,
)
if args.model_name == "cotracker":
teacher_model_online = (
build_cotracker(
window_len=args.sliding_window_len, checkpoint=args.restore_ckpt
)
.cuda()
.eval()
)
teacher_models.append(("online", teacher_model_online))
elif args.model_name == "cotracker_three":
teacher_model_online = (
build_cotracker(
window_len=16,
offline=False,
checkpoint="./checkpoints/cotracker2v1.pth",
v2=True,
)
.cuda()
.eval()
)
teacher_models.append(("online", teacher_model_online))
else:
raise ValueError(f"Model {args.model_name} doesn't exist")
online_checkpoint = "./checkpoints/baseline_online.pth"
if args.model_name == "cotracker_three" and not args.offline_model:
online_checkpoint = args.restore_ckpt
print("online_checkpoint", online_checkpoint)
teacher_model_online_cot_three = (
build_cotracker(checkpoint=online_checkpoint, offline=False, window_len=16)
.cuda()
.eval()
)
teacher_models.append(
("online_cotracker_three", teacher_model_online_cot_three)
)
offline_checkpoint = "./checkpoints/baseline_offline.pth"
if args.model_name == "cotracker_three" and args.offline_model:
offline_checkpoint = args.restore_ckpt
teacher_model_offline_cot_three = (
build_cotracker(checkpoint=offline_checkpoint, offline=True, window_len=60)
.cuda()
.eval()
)
teacher_models.append(
("offline_cotracker_three", teacher_model_offline_cot_three)
)
teacher_model_tapir = TAPIRPredictor()
teacher_models.append(("tapir", teacher_model_tapir))
train_loader = DataLoader(
train_dataset,
batch_size=args.batch_size,
shuffle=True,
num_workers=args.num_workers,
worker_init_fn=seed_worker,
generator=g,
pin_memory=True,
collate_fn=collate_fn_train,
drop_last=True,
)
train_loader = self.setup_dataloaders(train_loader, move_to_device=False)
print("LEN TRAIN LOADER", len(train_loader))
optimizer, scheduler = fetch_optimizer(args, model)
total_steps = 0
if self.global_rank == 0:
logger = Logger(model, scheduler, args.ckpt_path)
folder_ckpts = [
f
for f in os.listdir(args.ckpt_path)
if not os.path.isdir(f) and f.endswith(".pth") and not "final" in f
]
if len(folder_ckpts) > 0:
ckpt_path = sorted(folder_ckpts)[-1]
ckpt = self.load(os.path.join(args.ckpt_path, ckpt_path))
logging.info(f"Loading checkpoint {ckpt_path}")
if "model" in ckpt:
model.load_state_dict(ckpt["model"])
else:
model.load_state_dict(ckpt)
if "optimizer" in ckpt:
logging.info("Load optimizer")
optimizer.load_state_dict(ckpt["optimizer"])
if "scheduler" in ckpt:
logging.info("Load scheduler")
scheduler.load_state_dict(ckpt["scheduler"])
if "total_steps" in ckpt:
total_steps = ckpt["total_steps"]
logging.info(f"Load total_steps {total_steps}")
elif args.restore_ckpt is not None:
assert args.restore_ckpt.endswith(".pth") or args.restore_ckpt.endswith(
".pt"
)
logging.info("Loading checkpoint...")
state_dict = self.load(args.restore_ckpt)
if "model" in state_dict:
state_dict = state_dict["model"]
if list(state_dict.keys())[0].startswith("module."):
state_dict = {
k.replace("module.", ""): v for k, v in state_dict.items()
}
model.load_state_dict(state_dict, strict=True)
logging.info(f"Done loading checkpoint")
model, optimizer = self.setup(model, optimizer, move_to_device=False)
# model.cuda()
model.train()
save_freq = args.save_freq
scaler = GradScaler(enabled=False)
should_keep_training = True
global_batch_num = 0
epoch = -1
if self.global_rank == 0 and args.validate_at_start:
run_test_eval(
evaluator,
model,
eval_dataloaders,
logger.writer,
total_steps,
)
model.train()
torch.cuda.empty_cache()
while should_keep_training:
epoch += 1
for i_batch, batch in enumerate(tqdm(train_loader)):
batch, gotit = batch
if not all(gotit):
print("batch is None")
continue
dataclass_to_cuda_(batch)
optimizer.zero_grad()
assert model.training
output = forward_batch(
batch, model, args, teacher_models=teacher_models
)
loss = 0
for k, v in output.items():
if "loss" in v:
loss += v["loss"]
if self.global_rank == 0:
for k, v in output.items():
if "loss" in v:
logger.writer.add_scalar(
f"live_{k}_loss", v["loss"].item(), total_steps
)
if "metrics" in v:
logger.push(v["metrics"], k)
if total_steps % save_freq == save_freq - 1:
visualizer.visualize(
video=batch.video.clone(),
tracks=batch.trajectory.clone(),
visibility=batch.visibility.clone(),
filename="train_gt_traj",
query_frame=output["flow"]["query_frame"],
writer=logger.writer,
step=total_steps,
)
visualizer.visualize(
video=batch.video.clone(),
tracks=output["flow"]["predictions"][None],
visibility=output["visibility"]["predictions"][None] > 0.6,
filename="train_pred_traj",
query_frame=output["flow"]["query_frame"],
writer=logger.writer,
step=total_steps,
)
if len(output) > 1:
logger.writer.add_scalar(
f"live_total_loss", loss.item(), total_steps
)
logger.writer.add_scalar(
f"learning_rate", optimizer.param_groups[0]["lr"], total_steps
)
global_batch_num += 1
self.barrier()
self.backward(scaler.scale(loss))
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), 10.0)
scaler.step(optimizer)
scheduler.step()
scaler.update()
total_steps += 1
if self.global_rank == 0:
if i_batch >= len(train_loader) - 1:
if (epoch + 1) % args.save_every_n_epoch == 0:
ckpt_iter = "0" * (6 - len(str(total_steps))) + str(
total_steps
)
save_path = Path(
f"{args.ckpt_path}/model_{args.model_name}_{ckpt_iter}.pth"
)
save_dict = {
"model": model.module.module.state_dict(),
"optimizer": optimizer.state_dict(),
"scheduler": scheduler.state_dict(),
"total_steps": total_steps,
}
logging.info(f"Saving file {save_path}")
self.save(save_dict, save_path)
if (epoch + 1) % args.evaluate_every_n_epoch == 0:
run_test_eval(
evaluator,
model,
eval_dataloaders,
logger.writer,
total_steps,
)
model.train()
torch.cuda.empty_cache()
self.barrier()
if total_steps > args.num_steps:
should_keep_training = False
break
if self.global_rank == 0:
print("FINISHED TRAINING")
PATH = f"{args.ckpt_path}/{args.model_name}_final.pth"
torch.save(model.module.module.state_dict(), PATH)
run_test_eval(
evaluator, model, final_dataloaders, logger.writer, total_steps
)
logger.close()
if __name__ == "__main__":
signal.signal(signal.SIGUSR1, sig_handler)
signal.signal(signal.SIGTERM, term_handler)
parser = argparse.ArgumentParser()
parser.add_argument("--model_name", default="cotracker_three", help="model name")
parser.add_argument("--restore_ckpt", help="path to restore a checkpoint")
parser.add_argument("--ckpt_path", help="path to save checkpoints")
parser.add_argument(
"--batch_size", type=int, default=4, help="batch size used during training."
)
parser.add_argument("--num_nodes", type=int, default=1)
parser.add_argument(
"--num_workers", type=int, default=10, help="number of dataloader workers"
)
parser.add_argument(
"--mixed_precision", action="store_true", help="use mixed precision"
)
parser.add_argument("--lr", type=float, default=0.0005, help="max learning rate.")
parser.add_argument(
"--wdecay", type=float, default=0.00001, help="Weight decay in optimizer."
)
parser.add_argument(
"--num_steps", type=int, default=200000, help="length of training schedule."
)
parser.add_argument(
"--evaluate_every_n_epoch",
type=int,
default=1,
help="evaluate during training after every n epochs, after every epoch by default",
)
parser.add_argument(
"--save_every_n_epoch",
type=int,
default=1,
help="save checkpoints during training after every n epochs, after every epoch by default",
)
parser.add_argument(
"--validate_at_start",
action="store_true",
help="whether to run evaluation before training starts",
)
parser.add_argument(
"--save_freq",
type=int,
default=100,
help="frequency of trajectory visualization during training",
)
parser.add_argument(
"--traj_per_sample",
type=int,
default=768,
help="the number of trajectories to sample for training",
)
parser.add_argument(
"--dataset_root", type=str, help="path lo all the datasets (train and eval)"
)
parser.add_argument(
"--train_iters",
type=int,
default=4,
help="number of updates to the disparity field in each forward pass.",
)
parser.add_argument(
"--sequence_len", type=int, default=8, help="train sequence length"
)
parser.add_argument(
"--eval_datasets",
nargs="+",
default=["tapvid_davis_first"],
help="what datasets to use for evaluation",
)
parser.add_argument(
"--num_virtual_tracks",
type=int,
default=None,
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--dont_use_augs",
action="store_true",
help="don't apply augmentations during training",
)
parser.add_argument(
"--sample_vis_1st_frame",
action="store_true",
help="only sample trajectories with points visible on the first frame",
)
parser.add_argument(
"--sliding_window_len",
type=int,
default=8,
help="length of the CoTracker sliding window",
)
parser.add_argument(
"--model_stride",
type=int,
default=8,
help="stride of the CoTracker feature network",
)
parser.add_argument(
"--crop_size",
type=int,
nargs="+",
default=[384, 512],
help="crop videos to this resolution during training",
)
parser.add_argument(
"--eval_max_seq_len",
type=int,
default=1000,
help="maximum length of evaluation videos",
)
parser.add_argument(
"--debug",
action="store_true",
help="saves launch time for faster debug",
)
parser.add_argument(
"--random_frame_rate",
action="store_true",
help="random_frame_rate",
)
parser.add_argument(
"--real_data_splits",
type=int,
nargs="+",
default=[0],
help="real data folders",
)
parser.add_argument(
"--loss_only_for_visible_pts",
action="store_true",
help="compute sequence loss only for visible points",
)
parser.add_argument(
"--real_data_filter_sift",
action="store_true",
help="select point to track based on SIFT features",
)
parser.add_argument(
"--train_grid_size",
type=int,
default=5,
help="number of extra regular grid points that we sample at training. This number will be squared",
)
parser.add_argument(
"--train_sift_size",
type=int,
default=0,
help="number of extra SIFT points that we sample at training.",
)
parser.add_argument(
"--real_data_filter_superpoint",
action="store_true",
help="select point to track based on SuperPoint features",
)
parser.add_argument(
"--train_only_visible_points",
action="store_true",
help="Loss only for visible points",
)
parser.add_argument(
"--offline_model",
action="store_true",
help="training the offline model",
)
parser.add_argument(
"--clean_kubric",
action="store_true",
help="filtering out bad tracks in Kubric",
)
parser.add_argument(
"--random_number_traj",
action="store_true",
help="when training on Kubric, sampling a random number \
of tracks between 1 and args.traj_per_sample",
)
parser.add_argument(
"--random_seq_len",
action="store_true",
help="when training on Kubric, cropping the sequence \
to have a length between 10 and args.sequence_len frames",
)
parser.add_argument(
"--uniform_query_sampling_method",
action="store_true",
help="Whether to sample points uniformly across time. Kubric training only",
)
parser.add_argument(
"--limit_samples", type=int, default=10000, help="limit samples on real data"
)
args = parser.parse_args()
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s",
)
Path(args.ckpt_path).mkdir(exist_ok=True, parents=True)
from pytorch_lightning.strategies import DDPStrategy
Lite(
strategy=DDPStrategy(find_unused_parameters=False),
devices="auto",
accelerator="gpu",
precision="bf16" if args.mixed_precision else 32,
num_nodes=args.num_nodes,
# precision=32,
).run(args)
---
license: cc-by-nc-4.0
tags:
- CoTracker
- vision
- cotracker
---
# Point tracking with CoTracker3
**CoTracker3** is a fast transformer-based model that was introduced in [CoTracker3: Simpler and Better Point Tracking by Pseudo-Labelling Real Videos](https://arxiv.org/abs/2410.11831).
It can track any point in a video and brings to tracking some of the benefits of Optical Flow.
You could read more about the paper on our [webpage](https://cotracker3.github.io/). Code is available [here](https://github.com/facebookresearch/co-tracker).
CoTracker can track:
- **Any pixel** in a video
- A **quasi-dense** set of pixels together
- Points can be manually selected or sampled on a grid in any video frame
## How to use
Here is how to use this model in the **offline mode**:
```pip install imageio[ffmpeg]```, then:
```python
import torch
# Download the video
url = 'https://github.com/facebookresearch/co-tracker/raw/refs/heads/main/assets/apple.mp4'
import imageio.v3 as iio
frames = iio.imread(url, plugin="FFMPEG") # plugin="pyav"
device = 'cuda'
grid_size = 10
video = torch.tensor(frames).permute(0, 3, 1, 2)[None].float().to(device) # B T C H W
# Run Offline CoTracker:
cotracker = torch.hub.load("facebookresearch/co-tracker", "cotracker3_offline").to(device)
pred_tracks, pred_visibility = cotracker(video, grid_size=grid_size) # B T N 2, B T N 1
```
and in the **online mode**:
```python
cotracker = torch.hub.load("facebookresearch/co-tracker", "cotracker3_online").to(device)
# Run Online CoTracker, the same model with a different API:
# Initialize online processing
cotracker(video_chunk=video, is_first_step=True, grid_size=grid_size)
# Process the video
for ind in range(0, video.shape[1] - cotracker.step, cotracker.step):
pred_tracks, pred_visibility = cotracker(
video_chunk=video[:, ind : ind + cotracker.step * 2]
) # B T N 2, B T N 1
```
Online processing is more memory-efficient and allows for the processing of longer videos or videos in real-time.
## BibTeX entry and citation info
```bibtex
@inproceedings{karaev24cotracker3,
title = {CoTracker3: Simpler and Better Point Tracking by Pseudo-Labelling Real Videos},
author = {Nikita Karaev and Iurii Makarov and Jianyuan Wang and Natalia Neverova and Andrea Vedaldi and Christian Rupprecht},
booktitle = {Proc. {arXiv:2410.11831}},
year = {2024}
}
```
\ No newline at end of file
icon.png

57.3 KB

from PIL import Image
import torch
from transformers import AutoModelForCausalLM
from transformers import AutoProcessor
dtype = torch.bfloat16
model = AutoModelForCausalLM.from_pretrained("microsoft/Magma-8B", trust_remote_code=True, torch_dtype=dtype)
processor = AutoProcessor.from_pretrained("microsoft/Magma-8B", trust_remote_code=True)
model.to("cuda")
# Inference
image = Image.open("./assets/images/magma_logo.jpg").convert("RGB")
convs = [
{"role": "system", "content": "You are agent that can see, talk and act."},
{"role": "user", "content": "<image_start><image><image_end>\nWhat is the letter on the robot?"},
]
prompt = processor.tokenizer.apply_chat_template(convs, tokenize=False, add_generation_prompt=True)
inputs = processor(images=[image], texts=prompt, return_tensors="pt")
inputs['pixel_values'] = inputs['pixel_values'].unsqueeze(0)
inputs['image_sizes'] = inputs['image_sizes'].unsqueeze(0)
inputs = inputs.to("cuda").to(dtype)
generation_args = {
"max_new_tokens": 500,
"temperature": 0.0,
"do_sample": False,
"use_cache": True,
"num_beams": 1,
}
with torch.inference_mode():
generate_ids = model.generate(**inputs, **generation_args)
generate_ids = generate_ids[:, inputs["input_ids"].shape[-1] :]
response = processor.decode(generate_ids[0], skip_special_tokens=True).strip()
print("response: ", response)
*.pyc
venv/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
*.eggs
.mypy_cache/
.vscode
/.idea/
/.ipynb_checkpoints
/kmeans_pytorch/.ipynb_checkpoints
MIT License
Copyright (c) 2020 subhadarshi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Things to include in the built package (besides the packages defined in setup.py)
include README.md
include LICENSE
\ No newline at end of file
# K Means using PyTorch
PyTorch implementation of kmeans for utilizing GPU
![Alt Text](https://media.giphy.com/media/WsYIwIHHXUcuiR8BeS/giphy.gif)
# Getting Started
```
import torch
import numpy as np
from kmeans_pytorch import kmeans
# data
data_size, dims, num_clusters = 1000, 2, 3
x = np.random.randn(data_size, dims) / 6
x = torch.from_numpy(x)
# kmeans
cluster_ids_x, cluster_centers = kmeans(
X=x, num_clusters=num_clusters, distance='euclidean', device=torch.device('cuda:0')
)
```
see [`example.ipynb`](https://github.com/subhadarship/kmeans_pytorch/blob/master/example.ipynb) for a more elaborate example
# Requirements
* [PyTorch](http://pytorch.org/) version >= 1.0.0
* Python version >= 3.6
# Installation
install with `pip`:
```
pip install kmeans-pytorch
```
**Installing from source**
To install from source and develop locally:
```
git clone https://github.com/subhadarship/kmeans_pytorch
cd kmeans_pytorch
pip install --editable .
```
# CPU vs GPU
see [`cpu_vs_gpu.ipynb`](https://github.com/subhadarship/kmeans_pytorch/blob/master/cpu_vs_gpu.ipynb) for a comparison between CPU and GPU
# Notes
- useful when clustering large number of samples
- utilizes GPU for faster matrix computations
- support euclidean and cosine distances (for now)
# Credits
- This implementation closely follows the style of [this](https://github.com/overshiki/kmeans_pytorch)
- Documentation is done using the awesome theme [jekyllbook](https://github.com/ebetica/jekyllbook)
# License
[MIT](https://github.com/subhadarship/kmeans_pytorch/blob/master/LICENSE)
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from kmeans_pytorch import kmeans, kmeans_predict\n",
"from sklearn.decomposition import PCA\n",
"from sklearn import datasets\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The clustering can be batched now, by handing over cluster_centers to kmeans. That it works can be seen quite nicely when going from batch 1 to batch 2, there's a blob that get's assigned the right cluster this time.\n",
"\n",
"\n",
"Note: The algorigthm runs into problems when it assigns the same points to two clusters. This happens often when resuming the clustering, but can occasionally also happen during a normal run. \n",
"It's not likely to occur with high dimensional data, and more data itself seems to work, too. See https://github.com/subhadarship/kmeans_pytorch/issues/3"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"seed = 18\n",
"num_clusters = 10\n",
"\n",
"# set random seed\n",
"np.random.seed(seed)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"n_samples = 1000\n",
"\n",
"blobs = datasets.make_blobs(n_samples=n_samples, random_state=seed, centers = num_clusters,n_features = 10)\n",
"\n",
"batch_1 = torch.from_numpy(blobs[0][:100])\n",
"\n",
"batch_2 = torch.from_numpy(blobs[0][100:200])\n",
"\n",
"batch_3 = torch.from_numpy(blobs[0][200:500])\n",
"\n",
"y = torch.from_numpy(blobs[0][500:])"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# plot\n",
"def plot_blobs(x,cluster_ids_x):\n",
" pca = PCA(2)\n",
" y_2d = pca.fit_transform(y)\n",
" x_2d = pca.transform(x)\n",
" \n",
" plt.figure(figsize=(4, 3), dpi=160)\n",
" plt.scatter(x_2d[:, 0], x_2d[:, 1], c=cluster_ids_x, cmap='cool')\n",
" plt.scatter(y_2d[:, 0], y_2d[:, 1], c=cluster_ids_y, cmap='cool', marker='X')\n",
" plt.scatter(\n",
" cluster_centers[:, 0], cluster_centers[:, 1],\n",
" c='white',\n",
" alpha=0.6,\n",
" edgecolors='black',\n",
" linewidths=2\n",
" )\n",
" #plt.axis([-1, 1, -1, 1])\n",
" plt.tight_layout()\n",
" plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ -3.57607944, -5.49279973, -11.24033377, -5.58584688,\n",
" -6.49597733, -3.66076857, 7.8863303 , 5.73574873,\n",
" 5.30682772, -6.52582304],\n",
" [ 3.65151091, -4.1693436 , 6.51452454, 6.11181855,\n",
" -6.03164542, 9.718691 , -0.27650898, 3.74241734,\n",
" -7.18632993, 3.88353736],\n",
" [ 1.60333625, 9.26137504, 4.9727277 , 2.59262293,\n",
" -7.83707719, 5.98862385, -1.25714363, 1.3738497 ,\n",
" -9.61690325, -6.60493591]])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"blobs[0][2:5]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# set device\n",
"if torch.cuda.is_available():\n",
" device = torch.device('cuda:0')\n",
"else:\n",
" device = torch.device('cpu')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"running k-means on cuda:0..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 4it [00:00, 300.74it/s, center_shift=0.000000, iteration=4, tol=0.000100] \n"
]
}
],
"source": [
"# k-means\n",
"cluster_ids_x, cluster_centers = kmeans(\n",
" X=batch_1, num_clusters=num_clusters, distance='euclidean', device=device\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"predicting on cuda:0..\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# predict cluster ids for y\n",
"cluster_ids_y = kmeans_predict(\n",
" y, cluster_centers, 'euclidean', device=device\n",
")\n",
"plot_blobs(y,cluster_ids_y)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 1it [00:00, 218.75it/s, center_shift=245.281052, iteration=2, tol=0.000100]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"running k-means on cuda:0..\n",
"resuming\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 3it [00:00, 128.70it/s, center_shift=0.000000, iteration=3, tol=0.000100] "
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"predicting on cuda:0..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# second batch\n",
"\n",
"# k-means with previous cluster centers\n",
"cluster_ids_x, cluster_centers = kmeans(\n",
" X=batch_2, num_clusters=num_clusters,\n",
" cluster_centers = cluster_centers,\n",
" distance='euclidean', device=device\n",
")\n",
"\n",
"# predict cluster ids for y\n",
"cluster_ids_y = kmeans_predict(\n",
" y, cluster_centers, 'euclidean', device=device\n",
")\n",
"\n",
"plot_blobs(y,cluster_ids_y)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 2it [00:00, 262.92it/s, center_shift=0.000000, iteration=2, tol=0.000100]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"running k-means on cuda:0..\n",
"resuming\n",
"predicting on cuda:0..\n"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# third batch\n",
"\n",
"# k-means with previous cluster centers\n",
"cluster_ids_x, cluster_centers = kmeans(\n",
" X=batch_3, num_clusters=num_clusters,\n",
" cluster_centers = cluster_centers,\n",
" distance='euclidean', device=device\n",
")\n",
"\n",
"\n",
"# predict cluster ids for y\n",
"cluster_ids_y = kmeans_predict(\n",
" y, cluster_centers, 'euclidean', device=device\n",
")\n",
"plot_blobs(y,cluster_ids_y)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
{
"cells": [
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"colab_type": "code",
"id": "1ddgCM_qEHZa",
"outputId": "9df5f286-0b1c-40a7-bc07-17a765c861b7"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: kmeans-pytorch in /usr/local/lib/python3.6/dist-packages (0.1)\n"
]
}
],
"source": [
"!pip install kmeans-pytorch"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "R8_IiKZZEU9i"
},
"outputs": [],
"source": [
"import torch\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from time import time\n",
"from kmeans_pytorch import kmeans, kmeans_predict"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "iyoljrh1FCxJ"
},
"outputs": [],
"source": [
"# set random seed\n",
"np.random.seed(123)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "tcnoTA16FHbJ"
},
"outputs": [],
"source": [
"# dimensions, num clusters\n",
"dims, num_clusters = 2, 3\n",
"\n",
"# data sizes\n",
"data_sizes = [100000, 1000000, 5000000, 10000000]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"colab_type": "code",
"id": "Ar-lcW3OFTXI",
"outputId": "056052bc-899e-45d9-f0f4-243eaac69764"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"data size: 100000\n",
"running k-means on cuda:0..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 6it [00:00, 19.37it/s, center_shift=0.000058, iteration=6, tol=0.000100]\n",
"[running kmeans]: 3it [00:00, 25.17it/s, center_shift=0.001187, iteration=4, tol=0.000100]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"gpu time: 9.147990465164185\n",
"running k-means on cpu..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 7it [00:00, 24.08it/s, center_shift=0.000048, iteration=7, tol=0.000100]\n",
"[running kmeans]: 0it [00:00, ?it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"cpu time: 0.2962355613708496\n",
"\n",
"data size: 1000000\n",
"running k-means on cuda:0..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 7it [00:02, 2.70it/s, center_shift=0.000070, iteration=7, tol=0.000100]\n",
"[running kmeans]: 0it [00:00, ?it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"gpu time: 2.6448638439178467\n",
"running k-means on cpu..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 6it [00:02, 2.66it/s, center_shift=0.000054, iteration=6, tol=0.000100]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"cpu time: 2.287574052810669\n",
"\n",
"data size: 5000000\n",
"running k-means on cuda:0..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 5it [00:09, 1.82s/it, center_shift=0.000037, iteration=5, tol=0.000100]\n",
"[running kmeans]: 0it [00:00, ?it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"gpu time: 9.346906185150146\n",
"running k-means on cpu..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"[running kmeans]: 6it [00:10, 1.79s/it, center_shift=0.000051, iteration=6, tol=0.000100]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"cpu time: 10.929628849029541\n",
"\n",
"data size: 10000000\n",
"running k-means on cuda:0..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n",
"[running kmeans]: 0it [00:00, ?it/s]\u001b[A\n",
"[running kmeans]: 0it [00:03, ?it/s, center_shift=0.108101, iteration=1, tol=0.000100]\u001b[A\n",
"[running kmeans]: 1it [00:03, 3.58s/it, center_shift=0.108101, iteration=1, tol=0.000100]\u001b[A\n",
"[running kmeans]: 1it [00:07, 3.58s/it, center_shift=0.007211, iteration=2, tol=0.000100]\u001b[A\n",
"[running kmeans]: 2it [00:07, 3.58s/it, center_shift=0.007211, iteration=2, tol=0.000100]\u001b[A\n",
"[running kmeans]: 2it [00:10, 3.58s/it, center_shift=0.001613, iteration=3, tol=0.000100]\u001b[A\n",
"[running kmeans]: 3it [00:10, 3.58s/it, center_shift=0.001613, iteration=3, tol=0.000100]\u001b[A\n",
"[running kmeans]: 3it [00:14, 3.58s/it, center_shift=0.000406, iteration=4, tol=0.000100]\u001b[A\n",
"[running kmeans]: 4it [00:14, 3.58s/it, center_shift=0.000406, iteration=4, tol=0.000100]\u001b[A\n",
"[running kmeans]: 4it [00:17, 3.58s/it, center_shift=0.000130, iteration=5, tol=0.000100]\u001b[A\n",
"[running kmeans]: 5it [00:17, 3.57s/it, center_shift=0.000130, iteration=5, tol=0.000100]\u001b[A\n",
"[running kmeans]: 5it [00:21, 3.57s/it, center_shift=0.000044, iteration=6, tol=0.000100]\u001b[A\n",
"[running kmeans]: 6it [00:21, 3.56s/it, center_shift=0.000044, iteration=6, tol=0.000100]\u001b[A"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"gpu time: 21.879725694656372\n",
"running k-means on cpu..\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n",
"\n",
"[running kmeans]: 0it [00:00, ?it/s]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 0it [00:03, ?it/s, center_shift=0.170225, iteration=1, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 1it [00:03, 3.54s/it, center_shift=0.170225, iteration=1, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 1it [00:07, 3.54s/it, center_shift=0.013261, iteration=2, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 2it [00:07, 3.57s/it, center_shift=0.013261, iteration=2, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 2it [00:10, 3.57s/it, center_shift=0.003844, iteration=3, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 3it [00:10, 3.59s/it, center_shift=0.003844, iteration=3, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 3it [00:14, 3.59s/it, center_shift=0.001250, iteration=4, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 4it [00:14, 3.59s/it, center_shift=0.001250, iteration=4, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 4it [00:18, 3.59s/it, center_shift=0.000416, iteration=5, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 5it [00:18, 3.60s/it, center_shift=0.000416, iteration=5, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 5it [00:21, 3.60s/it, center_shift=0.000139, iteration=6, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 6it [00:21, 3.61s/it, center_shift=0.000139, iteration=6, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 6it [00:25, 3.61s/it, center_shift=0.000047, iteration=7, tol=0.000100]\u001b[A\u001b[A\n",
"\n",
"[running kmeans]: 7it [00:25, 3.63s/it, center_shift=0.000047, iteration=7, tol=0.000100]\u001b[A\u001b[A"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"cpu time: 25.7757887840271\n"
]
}
],
"source": [
"gpu_times = []\n",
"cpu_times = []\n",
"\n",
"for data_size in data_sizes:\n",
" print(f'\\ndata size: {data_size}')\n",
"\n",
" # data\n",
" x = np.random.randn(data_size, dims) / 6\n",
" x = torch.from_numpy(x)\n",
"\n",
" # gpu\n",
" start_gpu = time()\n",
" kmeans_gpu = kmeans(X=x, num_clusters=num_clusters, device=torch.device('cuda:0'))\n",
" gpu_time = time() - start_gpu\n",
" gpu_times.append(gpu_time)\n",
" print(f'gpu time: {gpu_time}')\n",
" \n",
" # cpu\n",
" start_cpu = time()\n",
" kmeans_cpu = kmeans(X=x, num_clusters=num_clusters, device=torch.device('cpu'))\n",
" cpu_time = time() - start_cpu\n",
" cpu_times.append(cpu_time)\n",
" print(f'cpu time: {cpu_time}')"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 484
},
"colab_type": "code",
"id": "5V0vxpaUEnFd",
"outputId": "27b8d6ed-07b3-4c8f-af8b-19d24f542378"
},
"outputs": [
{
"data": {
"image/png": "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\nVUkBWqNRr+dJwc43gGPzuXpB1kDSflP11oJ1CJAkjSAFjPVSjy8GzgIeJaU/X6aOVknaAlimz3XM\nAUZExL016plI/SDrg2tdMCMi+tZoZ3VgDCmtfCtp6+cCA/LaPTOzjwxPFzQzs1JExCWkDXx/Qxqd\nWQS8ThoNOgvYKSKeaaGexcAhpE0m7891LCbtU/VX4NvADhHxWIv9ejr362JSlr55dEyI0bn8taTN\nLa8mBUDvkTa5fIY0NXLniLiwlbZb6NsMYEtgJGmEbSrp/S4BFpKyN44nTRfcqlaAtSJFxMKIOAX4\nFHA+6ecxm/QZLSSNaE0CLgQGA5s6wDKzjyKPZJmZmZmZmZXII1lmZmZmZmYlcpBlZmZmZmZWIgdZ\nZmZmZmZmJXKQZWZmZmZmViIHWWZmZmZmZiVykGVmZmZmZlYiB1lmZmZmZmYlcpBlZmZmZmZWIgdZ\nZmZmZmZmJXKQZWZmZmZmViIHWWZmZmZmZiVykGVmZmZmZlYiB1lmZmZmZmYlcpBlZmZmZmZWIgdZ\nZmZmZmZmJXKQZWZmZmZmViIHWWZmZmZmZiVykGVmZmZmZlYiB1lmZmZmZmYlcpBlZmZmZmZWov8B\nBjDvLG2pwEUAAAAASUVORK5CYII=\n",
"text/plain": [
"<Figure size 960x480 with 1 Axes>"
]
},
"metadata": {
"tags": []
},
"output_type": "display_data"
}
],
"source": [
"# plot\n",
"plt.figure(figsize=(6, 3), dpi=160)\n",
"plt.plot(data_sizes, gpu_times, marker='o', label='gpu', color='xkcd:vermillion')\n",
"plt.plot(data_sizes, cpu_times, marker='o', label='cpu', color='xkcd:neon blue')\n",
"plt.xticks(data_sizes)\n",
"plt.legend(fontsize=12)\n",
"plt.grid(alpha=0.2)\n",
"plt.xlabel('data size', fontsize=14)\n",
"plt.ylabel('time (s)', fontsize=14)\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {},
"colab_type": "code",
"id": "BHkQ-zw9EnsN"
},
"outputs": [],
"source": []
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"collapsed_sections": [],
"name": "cpu_vs_gpu.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
---
layout: default
title: "404: Page not found"
permalink: 404.html
---
<div class="page">
<p class="lead">Sorry, we've misplaced that URL or it's pointing to something that doesn't exist. <a href="/">Head back home</a> to try finding it again.</p>
</div>
permalink: pretty
# Setup
title: 'kmeans PyTorch'
#tagline: 'A Jekyll theme'
url: https://subhadarship.github.io/kmeans_pytorch/
baseurl: '/kmeans_pytorch'
# About/contact
author:
name: Subhadarshi Panda
url: https://subhadarship.github.io
github:
repo: https://github.com/subhadarship/kmeans_pytorch/
# Custom vars
version: 0.3
multilingual: false
src: "."
default_theme: "Rust"
# For Maths
markdown: kramdown
# To use hljs, disable the default highlighter
kramdown:
syntax_highlighter_opts:
disable: true
# Chapter Configuration (up to a 2 level nested list)
chapters:
- path: chapters/example/example.md
- path: chapters/cpu_vs_gpu/cpu_vs_gpu.md
<!DOCTYPE html>
<html lang="en" class="sidebar-visible no-js">
<head>
<meta charset="UTF-8">
<title>
{% if page.title == "Home" %}
{{ site.title }} &middot; {{ site.tagline }}
{% else %}
{{ page.title }} &middot; {{ site.title }}
{% endif %}
</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<!--<meta name="description" content="{{ site.description }}">-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="{{ site.baseurl }}/static/favicon.ico">
<link rel="apple-touch-icon" sizes="180x180" href="{{ site.baseurl }}/static/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="{{ site.baseurl }}/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/{{ site.baseurl }}/static/avicon-16x16.png">
<link rel="manifest" href="{{ site.baseurl }}/static/site.webmanifest">
<link rel="stylesheet" href="{{ site.baseurl }}/static/css/variables.css">
<link rel="stylesheet" href="{{ site.baseurl }}/static/css/general.css">
<link rel="stylesheet" href="{{ site.baseurl }}/static/css/chrome.css">
<link rel="stylesheet" href="{{ site.baseurl }}/static/css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="{{ site.baseurl }}/static/FontAwesome/css/font-awesome.min.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="{{ site.baseurl }}/static/highlight.css">
<link rel="stylesheet" href="{{ site.baseurl }}/static/tomorrow-night.css">
<link rel="stylesheet" href="{{ site.baseurl }}/static/ayu-highlight.css">
<!-- Katex -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous" onload="render_katex()"></script>
<!-- To automatically render math in text elements, include the auto-render extension: -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous"
onload="renderMathInElement(document.body, {delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
]});"></script>
</head>
<body class="ayu">
<!-- Provide site root to javascript -->
<script type="text/javascript">
var default_theme = "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
document.body.className = theme;
document.querySelector('html').className = theme + ' js';
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents" aria-hidden="false">
<div id="sidebar-scrollbox" class="sidebar-scrollbox">
{% comment %}
The code below generates the sidebar according to some
manually created table of contents in the _config.yml.
We assume the pages are unique.
{% endcomment %}
<ol class="chapter">
{% assign base_url = site.baseurl | append: "/" %}
{% if page.url == base_url %}
<li><a class="active" href="{{ site.baseurl }}/">Home</a></li>
{% else %}
<li><a href="{{ site.baseurl }}/">Home</a></li>
{% endif %}
{% comment %}
Hack to get a single element array...
{% endcomment %}
{% assign pagelist = base_url | split: 'DONOTSPLIT!#@$' %}
{% assign arraypath = base_url | split: 'DONOTSPLIT!#@$' %}
{% assign pagelist = pagelist | concat: arraypath %}
{% assign current_pagelist_index = pagelist | size %}
{% for chapter in site.chapters %}
{% assign node = site.pages | where: "path", chapter.path | first %}
{% assign arraypath = chapter.path | split: 'DONOTSPLIT!#@$' %}
{% assign pagelist = pagelist | concat: arraypath %}
{% assign chapteridx = forloop.index %}
{% if page.url == node.url %}
{% assign current_pagelist_index = pagelist | size %}
{% assign active = "active" %}
{% else %}
{% assign active = "" %}
{% endif %}
<li class="expanded "><a class="{{ active }}" href="{{ site.baseurl }}{{ node.url }}">
<strong aria-hidden="true">{{ chapteridx }}.</strong> {{ node.title }}
</a></li>
{% if chapter.sections %}
<ol class="section">
{% for section in chapter.sections %}
{% assign snode = site.pages | where: "path", section.path | first %}
{% assign arraypath = section.path | split: 'DONOTSPLIT!#@$' %}
{% assign pagelist = pagelist | concat: arraypath %}
{% if page.url == snode.url %}
{% assign current_pagelist_index = pagelist | size %}
{% assign active = "active" %}
{% else %}
{% assign active = "" %}
{% endif %}
<li class="expanded "><a class="{{ active }}" href="{{ site.baseurl }}{{ snode.url }}">
<strong aria-hidden="true">{{ chapteridx }}.{{ forloop.index }}.</strong> {{ snode.title }}
</a></li>
{% endfor %}
</ol>
{% endif %}
{% endfor %}
{% assign arraypath = pagelist | last | split: 'DONOTSPLIT!#@$' %}
{% assign pagelist = pagelist | concat: arraypath %}
{% comment %}
Now we can compute the next and previous page!
{% endcomment %}
{% assign prev_pagelist_index = current_pagelist_index | minus: 2 %}
{% assign page_next_path = pagelist[current_pagelist_index] %}
{% assign page_prev_path = pagelist[prev_pagelist_index] %}
{% assign page_next = site.pages | where: "path", page_next_path | first %}
{% assign page_prev = site.pages | where: "path", page_prev_path | first %}
<li><a href="{{ site.github.repo }}">GitHub project</a></li>
<!-- Here's some debug info: -->
<!--current_index: {{ current_pagelist_index }}-->
<!--next_page: {{ page_next_path }} -->
<!--previous_page: {{ page_prev_path }} -->
<!--the page list: {{ pagelist | jsonify }} -->
</ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
</div>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<h1 class="menu-title">{{ site.title }}</h1>
<div class="right-buttons">
<a href="{{ site.git_repository_url}}" title="Git repository" aria-label="Git repository">
<!-- <i id="git-repository-button" class="fa {{ site.git_repository_icon }}"></i> -->
<i id="git-repository-button"></i>
</a>
</div>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<div class="page">
<h1 class="page-title">{{ page.title }}</h1>
{{ content }}
</div>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="{{ site.baseurl }}{{ page_prev.url }}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="{{ site.baseurl }}{{ page_next.url }}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="{{ site.baseurl }}{{ page_prev.url }}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="{{ site.baseurl }}{{ page_next.url }}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script src="{{ site.baseurl }}/static/clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ site.baseurl }}/static/highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ site.baseurl }}/static/book.js" type="text/javascript" charset="utf-8"></script>
<script>
function render_katex() {
$("script[type='math/tex']").replaceWith(function() {
var tex = $(this).text();
return katex.renderToString(tex, {displayMode: false});
});
$("script[type='math/tex; mode=display']").replaceWith(function() {
var tex = $(this).html();
return katex.renderToString(tex.replace(/%.*/g, ''), {displayMode: true});
});
};
</script>
</body>
</html>
---
layout: default
title: CPU vs GPU
---
**How useful is using kmeans_pytorch if you have GPU?**
Let's find out !!
```python
# installation
!pip install kmeans-pytorch
```
Collecting kmeans-pytorch
Downloading https://files.pythonhosted.org/packages/b5/c9/eb5b82e7e9741e61acf1aff70530a08810aa0c7e2272c534ff7a150fc5bd/kmeans_pytorch-0.3-py3-none-any.whl
Installing collected packages: kmeans-pytorch
Successfully installed kmeans-pytorch-0.3
## Import Packages
```python
import torch
import numpy as np
import matplotlib.pyplot as plt
from time import time
from kmeans_pytorch import kmeans, kmeans_predict
```
## Set Random Seed (For Reproducibilty)
```python
# set random seed
np.random.seed(123)
```
## Set Number of Dimensions, Number of Clusters
```python
# dimensions, num clusters
dims, num_clusters = 2, 3
```
## Set Data Sizes
```python
# data sizes
data_sizes = [100000, 1000000, 5000000, 10000000]
```
## Compute CPU and GPU Times
```python
gpu_times = []
cpu_times = []
for data_size in data_sizes:
print(f'\ndata size: {data_size}')
# data
x = np.random.randn(data_size, dims) / 6
x = torch.from_numpy(x)
# gpu
start_gpu = time()
kmeans_gpu = kmeans(X=x, num_clusters=num_clusters, device=torch.device('cuda:0'))
gpu_time = time() - start_gpu
gpu_times.append(gpu_time)
print(f'gpu time: {gpu_time}')
# cpu
start_cpu = time()
kmeans_cpu = kmeans(X=x, num_clusters=num_clusters, device=torch.device('cpu'))
cpu_time = time() - start_cpu
cpu_times.append(cpu_time)
print(f'cpu time: {cpu_time}')
```
data size: 100000
running k-means on cuda:0..
[running kmeans]: 6it [00:00, 13.96it/s, center_shift=0.000058, iteration=6, tol=0.000100]
[running kmeans]: 2it [00:00, 16.60it/s, center_shift=0.003620, iteration=3, tol=0.000100]
gpu time: 10.371965885162354
running k-means on cpu..
[running kmeans]: 7it [00:00, 19.78it/s, center_shift=0.000048, iteration=7, tol=0.000100]
[running kmeans]: 0it [00:00, ?it/s]
cpu time: 0.36179161071777344
data size: 1000000
running k-means on cuda:0..
[running kmeans]: 7it [00:03, 2.31it/s, center_shift=0.000070, iteration=7, tol=0.000100]
[running kmeans]: 0it [00:00, ?it/s]
gpu time: 3.0890297889709473
running k-means on cpu..
[running kmeans]: 6it [00:02, 2.31it/s, center_shift=0.000054, iteration=6, tol=0.000100]
cpu time: 2.6320385932922363
data size: 5000000
[running kmeans]: 0it [00:00, ?it/s]
running k-means on cuda:0..
[running kmeans]: 5it [00:10, 2.02s/it, center_shift=0.000037, iteration=5, tol=0.000100]
[running kmeans]: 0it [00:00, ?it/s]
gpu time: 10.312965869903564
running k-means on cpu..
[running kmeans]: 0it [00:01, ?it/s, center_shift=0.069426, iteration=1, tol=0.000100]
[running kmeans]: 1it [00:01, 1.98s/it, center_shift=0.069426, iteration=1, tol=0.000100]
[running kmeans]: 1it [00:03, 1.98s/it, center_shift=0.004168, iteration=2, tol=0.000100]
[running kmeans]: 2it [00:03, 1.99s/it, center_shift=0.004168, iteration=2, tol=0.000100]
[running kmeans]: 2it [00:06, 1.99s/it, center_shift=0.001386, iteration=3, tol=0.000100]
[running kmeans]: 3it [00:06, 2.00s/it, center_shift=0.001386, iteration=3, tol=0.000100]
[running kmeans]: 3it [00:07, 2.00s/it, center_shift=0.000462, iteration=4, tol=0.000100]
[running kmeans]: 4it [00:07, 2.00s/it, center_shift=0.000462, iteration=4, tol=0.000100]
[running kmeans]: 4it [00:10, 2.00s/it, center_shift=0.000153, iteration=5, tol=0.000100]
[running kmeans]: 5it [00:10, 2.02s/it, center_shift=0.000153, iteration=5, tol=0.000100]
[running kmeans]: 5it [00:12, 2.02s/it, center_shift=0.000051, iteration=6, tol=0.000100]
[running kmeans]: 6it [00:12, 2.01s/it, center_shift=0.000051, iteration=6, tol=0.000100]
cpu time: 12.246060371398926
data size: 10000000
running k-means on cuda:0..
[running kmeans]: 0it [00:00, ?it/s]
[running kmeans]: 0it [00:03, ?it/s, center_shift=0.108101, iteration=1, tol=0.000100]
[running kmeans]: 1it [00:03, 3.98s/it, center_shift=0.108101, iteration=1, tol=0.000100]
[running kmeans]: 1it [00:08, 3.98s/it, center_shift=0.007211, iteration=2, tol=0.000100]
[running kmeans]: 2it [00:08, 4.03s/it, center_shift=0.007211, iteration=2, tol=0.000100]
[running kmeans]: 2it [00:12, 4.03s/it, center_shift=0.001613, iteration=3, tol=0.000100]
[running kmeans]: 3it [00:12, 4.04s/it, center_shift=0.001613, iteration=3, tol=0.000100]
[running kmeans]: 3it [00:16, 4.04s/it, center_shift=0.000406, iteration=4, tol=0.000100]
[running kmeans]: 4it [00:16, 4.01s/it, center_shift=0.000406, iteration=4, tol=0.000100]
[running kmeans]: 4it [00:20, 4.01s/it, center_shift=0.000130, iteration=5, tol=0.000100]
[running kmeans]: 5it [00:20, 3.99s/it, center_shift=0.000130, iteration=5, tol=0.000100]
[running kmeans]: 5it [00:24, 3.99s/it, center_shift=0.000044, iteration=6, tol=0.000100]
[running kmeans]: 6it [00:24, 4.00s/it, center_shift=0.000044, iteration=6, tol=0.000100]
gpu time: 24.558437824249268
running k-means on cpu..
[running kmeans]: 0it [00:00, ?it/s]
[running kmeans]: 0it [00:03, ?it/s, center_shift=0.170225, iteration=1, tol=0.000100]
[running kmeans]: 1it [00:03, 3.97s/it, center_shift=0.170225, iteration=1, tol=0.000100]
[running kmeans]: 1it [00:08, 3.97s/it, center_shift=0.013261, iteration=2, tol=0.000100]
[running kmeans]: 2it [00:08, 4.03s/it, center_shift=0.013261, iteration=2, tol=0.000100]
[running kmeans]: 2it [00:12, 4.03s/it, center_shift=0.003844, iteration=3, tol=0.000100]
[running kmeans]: 3it [00:12, 4.04s/it, center_shift=0.003844, iteration=3, tol=0.000100]
[running kmeans]: 3it [00:16, 4.04s/it, center_shift=0.001250, iteration=4, tol=0.000100]
[running kmeans]: 4it [00:16, 4.03s/it, center_shift=0.001250, iteration=4, tol=0.000100]
[running kmeans]: 4it [00:20, 4.03s/it, center_shift=0.000416, iteration=5, tol=0.000100]
[running kmeans]: 5it [00:20, 4.01s/it, center_shift=0.000416, iteration=5, tol=0.000100]
[running kmeans]: 5it [00:24, 4.01s/it, center_shift=0.000139, iteration=6, tol=0.000100]
[running kmeans]: 6it [00:24, 4.00s/it, center_shift=0.000139, iteration=6, tol=0.000100]
[running kmeans]: 6it [00:28, 4.00s/it, center_shift=0.000047, iteration=7, tol=0.000100]
[running kmeans]: 7it [00:28, 4.00s/it, center_shift=0.000047, iteration=7, tol=0.000100]
cpu time: 28.59460973739624
## Plot
Plot the CPU and GPU times
```python
# plot
plt.figure(figsize=(6, 3), dpi=160)
plt.plot(data_sizes, gpu_times, marker='o', label='gpu', color='xkcd:vermillion')
plt.plot(data_sizes, cpu_times, marker='o', label='cpu', color='xkcd:navy')
plt.xticks(data_sizes)
plt.legend(fontsize=12)
plt.grid(alpha=0.2)
plt.xlabel('data size', fontsize=14)
plt.ylabel('time (s)', fontsize=14)
plt.show()
```
![png](output_13_0.png)
## Key Takeaways
1. Using GPU is not always faster than using CPU for kmeans in PyTorch
2. Use GPU if the data size is large
```python
```
---
layout: default
title: Example
---
## Installation
Install easily using ```pip```
```python
!pip install kmeans-pytorch
```
Collecting kmeans-pytorch
Downloading https://files.pythonhosted.org/packages/b5/c9/eb5b82e7e9741e61acf1aff70530a08810aa0c7e2272c534ff7a150fc5bd/kmeans_pytorch-0.3-py3-none-any.whl
Installing collected packages: kmeans-pytorch
Successfully installed kmeans-pytorch-0.3
## Import packages
```kmeans_pytorch``` and other packages
```python
import torch
import numpy as np
import matplotlib.pyplot as plt
from kmeans_pytorch import kmeans, kmeans_predict
```
## Set random seed
For reproducibility
```python
# set random seed
np.random.seed(123)
```
## Generate data
1. Generate data from a random distribution
2. Convert to torch.tensor
```python
# data
data_size, dims, num_clusters = 1000, 2, 3
x = np.random.randn(data_size, dims) / 6
x = torch.from_numpy(x)
```
## Set Device
If available, set device to GPU
```python
# set device
if torch.cuda.is_available():
device = torch.device('cuda:0')
else:
device = torch.device('cpu')
```
## Perform K-Means
```python
# k-means
cluster_ids_x, cluster_centers = kmeans(
X=x, num_clusters=num_clusters, distance='euclidean', device=device
)
```
running k-means on cuda:0..
[running kmeans]: 7it [00:00, 29.79it/s, center_shift=0.000068, iteration=7, tol=0.000100]
### Cluster IDs and Cluster Centers
```python
# cluster IDs and cluster centers
print(cluster_ids_x)
print(cluster_centers)
```
tensor([2, 0, 2, 0, 1, 0, 1, 0, 1, 1, 2, 2, 0, 1, 0, 0, 0, 1, 2, 2, 0, 2, 1, 1,
2, 0, 1, 2, 2, 1, 2, 0, 1, 1, 2, 1, 1, 2, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2,
0, 1, 0, 2, 1, 0, 0, 2, 2, 1, 0, 1, 0, 2, 1, 1, 1, 0, 2, 1, 2, 1, 2, 1,
1, 2, 2, 1, 0, 2, 1, 1, 1, 2, 1, 1, 1, 0, 2, 2, 1, 2, 2, 1, 0, 0, 2, 1,
1, 0, 0, 0, 1, 1, 1, 0, 2, 1, 0, 2, 1, 2, 0, 0, 1, 0, 2, 2, 2, 1, 1, 1,
1, 0, 1, 0, 2, 1, 0, 1, 1, 2, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 2,
2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 1, 0, 2, 0, 0, 1, 0, 2, 2, 0, 0,
2, 1, 0, 1, 0, 2, 2, 0, 0, 0, 2, 0, 2, 2, 2, 1, 1, 0, 1, 2, 2, 0, 1, 0,
2, 2, 1, 1, 0, 0, 2, 2, 1, 0, 2, 0, 2, 1, 2, 1, 1, 0, 2, 0, 0, 2, 2, 2,
0, 1, 0, 1, 1, 2, 1, 2, 1, 0, 0, 2, 2, 2, 2, 0, 1, 1, 1, 2, 1, 0, 2, 0,
0, 2, 2, 1, 1, 0, 0, 2, 1, 1, 1, 2, 1, 0, 0, 1, 1, 2, 2, 1, 0, 0, 2, 1,
1, 0, 1, 2, 1, 2, 0, 2, 2, 0, 2, 1, 0, 1, 1, 1, 2, 0, 1, 2, 2, 1, 1, 1,
0, 1, 0, 1, 2, 0, 2, 1, 2, 1, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 0, 2, 1,
0, 0, 2, 0, 2, 0, 1, 2, 1, 2, 0, 0, 2, 1, 1, 1, 1, 0, 2, 0, 2, 2, 1, 0,
1, 2, 2, 1, 1, 1, 2, 2, 0, 0, 1, 2, 1, 1, 0, 1, 2, 1, 2, 0, 0, 2, 0, 1,
1, 1, 2, 2, 1, 2, 0, 2, 0, 0, 2, 0, 2, 1, 2, 1, 1, 2, 2, 0, 1, 0, 0, 0,
0, 1, 0, 2, 2, 1, 0, 2, 0, 0, 2, 2, 2, 0, 1, 2, 0, 2, 2, 1, 2, 1, 2, 1,
0, 0, 0, 2, 0, 2, 2, 2, 0, 1, 1, 0, 2, 2, 0, 2, 2, 1, 0, 0, 2, 2, 0, 0,
1, 0, 1, 2, 0, 2, 0, 1, 0, 0, 0, 1, 2, 2, 1, 1, 2, 1, 1, 1, 0, 0, 2, 0,
0, 0, 2, 1, 1, 1, 2, 2, 2, 2, 0, 0, 1, 2, 0, 0, 1, 2, 1, 0, 1, 0, 2, 2,
0, 0, 0, 0, 2, 1, 0, 2, 1, 1, 2, 1, 0, 2, 0, 2, 0, 2, 1, 1, 2, 1, 0, 0,
0, 1, 2, 1, 1, 0, 2, 0, 2, 1, 2, 1, 1, 2, 0, 1, 0, 0, 2, 0, 2, 2, 2, 1,
1, 2, 1, 1, 2, 1, 1, 1, 1, 0, 0, 2, 1, 1, 2, 1, 1, 2, 0, 0, 2, 1, 2, 1,
1, 1, 1, 1, 0, 0, 2, 2, 1, 0, 1, 2, 2, 0, 1, 0, 2, 0, 2, 2, 2, 0, 1, 2,
2, 0, 1, 2, 1, 1, 2, 1, 2, 1, 0, 2, 0, 2, 1, 0, 2, 0, 1, 2, 1, 2, 1, 0,
1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 2, 0, 0, 2, 1, 0, 1, 1, 1, 0, 0,
2, 1, 0, 2, 1, 1, 0, 2, 1, 2, 0, 2, 2, 1, 1, 0, 0, 2, 0, 2, 1, 1, 0, 1,
1, 0, 2, 2, 2, 1, 0, 0, 2, 1, 1, 1, 2, 1, 0, 1, 1, 1, 2, 2, 1, 1, 2, 1,
0, 1, 0, 0, 0, 2, 0, 1, 0, 0, 1, 1, 0, 1, 2, 1, 1, 1, 1, 0, 1, 0, 0, 2,
1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 0,
2, 2, 0, 2, 2, 1, 1, 1, 1, 0, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 0, 2,
2, 0, 2, 2, 0, 2, 1, 0, 0, 2, 0, 0, 1, 0, 2, 2, 0, 1, 2, 0, 0, 1, 1, 2,
2, 2, 0, 1, 2, 0, 0, 1, 2, 2, 0, 1, 0, 0, 2, 2, 0, 2, 1, 0, 1, 1, 2, 1,
0, 2, 1, 1, 0, 1, 1, 0, 2, 2, 2, 2, 1, 0, 0, 0, 2, 1, 2, 2, 0, 0, 0, 2,
1, 2, 1, 0, 2, 0, 0, 1, 1, 2, 2, 1, 2, 1, 2, 0, 0, 2, 1, 0, 1, 0, 0, 2,
2, 2, 2, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 1, 1, 0, 2, 0, 2, 0, 2, 0, 0, 1,
0, 0, 0, 2, 0, 2, 1, 2, 0, 1, 0, 2, 0, 0, 0, 1, 0, 1, 1, 1, 0, 2, 2, 0,
1, 2, 0, 1, 1, 2, 2, 1, 2, 1, 0, 1, 0, 2, 1, 1, 2, 1, 1, 2, 2, 0, 1, 0,
2, 2, 0, 2, 2, 2, 1, 1, 0, 1, 2, 0, 2, 1, 0, 2, 1, 0, 1, 0, 2, 2, 2, 2,
2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 1, 1, 2, 1, 0, 1, 1, 1, 0, 2, 2,
2, 2, 1, 2, 0, 1, 2, 0, 1, 1, 1, 1, 2, 2, 0, 0, 2, 1, 1, 1, 0, 2, 0, 2,
2, 2, 0, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0])
tensor([[-0.1075, -0.1522],
[ 0.1544, -0.0137],
[-0.0833, 0.1454]])
### Create More Data Just for Prediction
```python
# more data
y = np.random.randn(5, dims) / 6
y = torch.from_numpy(y)
```
## Predict
```python
# predict cluster ids for y
cluster_ids_y = kmeans_predict(
y, cluster_centers, 'euclidean', device=device
)
```
predicting on cuda:0..
### Show Predicted Cluster IDs
```python
print(cluster_ids_y)
```
tensor([1, 2, 0, 1, 2])
## Plot
plot the samples
```python
# plot
plt.figure(figsize=(4, 3), dpi=160)
plt.scatter(x[:, 0], x[:, 1], c=cluster_ids_x, cmap='cool')
plt.scatter(y[:, 0], y[:, 1], c=cluster_ids_y, cmap='cool', marker='X')
plt.scatter(
cluster_centers[:, 0], cluster_centers[:, 1],
c='white',
alpha=0.6,
edgecolors='black',
linewidths=2
)
plt.axis([-1, 1, -1, 1])
plt.tight_layout()
plt.show()
```
![png](output_21_0.png)
### Hope the example was useful !!
```python
```
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment