

import argparse
import os
import re

import numpy as np
import PIL
import torch
from timm import create_model
from torch.optim.lr_scheduler import OneCycleLR
from torch.utils.data import DataLoader, Dataset
from torchvision.transforms import Compose, RandomResizedCrop, Resize, ToTensor

from accelerate import Accelerator




def  lowerCAmelCase(			SCREAMING_SNAKE_CASE_ )->	Tuple:



    """simple docstring"""






    UpperCamelCase_      =	fname.split(os.path.sep )[-1]
    return re.search(r"^(.*)_\d+\.jpg$" ,	SCREAMING_SNAKE_CASE_ ).groups()[0]






class 	__magic_name__				(       snake_case							):






     def __init__(							self		,	_lowercase		,	_lowercase=None		,	_lowercase=None  )->    List[str]:
         UpperCamelCase_      =	file_names
         UpperCamelCase_      =	image_transform
         UpperCamelCase_      =	label_to_id






     def __len__(							self  )->    Dict:
         return len(self.file_names  )






     def __getitem__(							self		,	_lowercase  )->    List[str]:
         UpperCamelCase_      =	self.file_names[idx]
         UpperCamelCase_      =	PIL.Image.open(_lowercase  )
         UpperCamelCase_      =	raw_image.convert("RGB"  )
         if self.image_transform is not None:
             UpperCamelCase_      =	self.image_transform(_lowercase  )
         UpperCamelCase_      =	extract_label(_lowercase  )
         if self.label_to_id is not None:
             UpperCamelCase_      =	self.label_to_id[label]
         return {"image": image, "label": label}




def  lowerCAmelCase(			SCREAMING_SNAKE_CASE_ ,	SCREAMING_SNAKE_CASE_ )->	str:



    """simple docstring"""






    UpperCamelCase_      =	Accelerator(cpu=args.cpu ,	mixed_precision=args.mixed_precision )

    # Sample hyper-parameters for learning rate, batch size, seed and a few other HPs
    UpperCamelCase_      =	config["lr"]
    UpperCamelCase_      =	int(config["num_epochs"] )
    UpperCamelCase_      =	int(config["seed"] )
    UpperCamelCase_      =	int(config["batch_size"] )
    UpperCamelCase_      =	config["image_size"]
    if not isinstance(SCREAMING_SNAKE_CASE_ ,	(list, tuple) ):
        UpperCamelCase_      =	(image_size, image_size)

    # Grab all the image filenames
    UpperCamelCase_      =	[os.path.join(args.data_dir ,	SCREAMING_SNAKE_CASE_ ) for fname in os.listdir(args.data_dir ) if fname.endswith(".jpg" )]

    # Build the label correspondences
    UpperCamelCase_      =	[extract_label(SCREAMING_SNAKE_CASE_ ) for fname in file_names]
    UpperCamelCase_      =	list(set(SCREAMING_SNAKE_CASE_ ) )
    id_to_label.sort()
    UpperCamelCase_      =	{lbl: i for i, lbl in enumerate(SCREAMING_SNAKE_CASE_ )}

    # Set the seed before splitting the data.
    np.random.seed(SCREAMING_SNAKE_CASE_ )
    torch.manual_seed(SCREAMING_SNAKE_CASE_ )
    torch.cuda.manual_seed_all(SCREAMING_SNAKE_CASE_ )

    # Split our filenames between train and validation
    UpperCamelCase_      =	np.random.permutation(len(SCREAMING_SNAKE_CASE_ ) )
    UpperCamelCase_      =	int(0.8 * len(SCREAMING_SNAKE_CASE_ ) )
    UpperCamelCase_      =	random_perm[:cut]
    UpperCamelCase_      =	random_perm[cut:]

    # For training we use a simple RandomResizedCrop
    UpperCamelCase_      =	Compose([RandomResizedCrop(SCREAMING_SNAKE_CASE_ ,	scale=(0.5, 1.0) ), ToTensor()] )
    UpperCamelCase_      =	PetsDataset(
        [file_names[i] for i in train_split] ,	image_transform=SCREAMING_SNAKE_CASE_ ,	label_to_id=SCREAMING_SNAKE_CASE_ )

    # For evaluation, we use a deterministic Resize
    UpperCamelCase_      =	Compose([Resize(SCREAMING_SNAKE_CASE_ ), ToTensor()] )
    UpperCamelCase_      =	PetsDataset([file_names[i] for i in eval_split] ,	image_transform=SCREAMING_SNAKE_CASE_ ,	label_to_id=SCREAMING_SNAKE_CASE_ )

    # Instantiate dataloaders.
    UpperCamelCase_      =	DataLoader(SCREAMING_SNAKE_CASE_ ,	shuffle=SCREAMING_SNAKE_CASE_ ,	batch_size=SCREAMING_SNAKE_CASE_ ,	num_workers=4 )
    UpperCamelCase_      =	DataLoader(SCREAMING_SNAKE_CASE_ ,	shuffle=SCREAMING_SNAKE_CASE_ ,	batch_size=SCREAMING_SNAKE_CASE_ ,	num_workers=4 )

    # Instantiate the model (we build the model here so that the seed also control new weights initialization)
    UpperCamelCase_      =	create_model("resnet50d" ,	pretrained=SCREAMING_SNAKE_CASE_ ,	num_classes=len(SCREAMING_SNAKE_CASE_ ) )

    # We could avoid this line since the accelerator is set with `device_placement=True` (default value).
    # Note that if you are placing tensors on devices manually, this line absolutely needs to be before the optimizer
    # creation otherwise training will not work on TPU (`accelerate` will kindly throw an error to make us aware of that).
    UpperCamelCase_      =	model.to(accelerator.device )

    # Freezing the base model
    for param in model.parameters():
        UpperCamelCase_      =	False
    for param in model.get_classifier().parameters():
        UpperCamelCase_      =	True

    # We normalize the batches of images to be a bit faster.
    UpperCamelCase_      =	torch.tensor(model.default_cfg["mean"] )[None, :, None, None].to(accelerator.device )
    UpperCamelCase_      =	torch.tensor(model.default_cfg["std"] )[None, :, None, None].to(accelerator.device )

    # Instantiate optimizer
    UpperCamelCase_      =	torch.optim.Adam(params=model.parameters() ,	lr=lr / 2_5 )

    # Instantiate learning rate scheduler
    UpperCamelCase_      =	OneCycleLR(optimizer=SCREAMING_SNAKE_CASE_ ,	max_lr=SCREAMING_SNAKE_CASE_ ,	epochs=SCREAMING_SNAKE_CASE_ ,	steps_per_epoch=len(SCREAMING_SNAKE_CASE_ ) )

    # Prepare everything
    # There is no specific order to remember, we just need to unpack the objects in the same order we gave them to the
    # prepare method.
    UpperCamelCase_     ,					UpperCamelCase_     ,					UpperCamelCase_     ,					UpperCamelCase_     ,					UpperCamelCase_      =	accelerator.prepare(
        SCREAMING_SNAKE_CASE_ ,	SCREAMING_SNAKE_CASE_ ,	SCREAMING_SNAKE_CASE_ ,	SCREAMING_SNAKE_CASE_ ,	SCREAMING_SNAKE_CASE_ )

    # Now we train the model
    for epoch in range(SCREAMING_SNAKE_CASE_ ):
        model.train()
        for step, batch in enumerate(SCREAMING_SNAKE_CASE_ ):
            # We could avoid this line since we set the accelerator with `device_placement=True`.
            UpperCamelCase_      =	{k: v.to(accelerator.device ) for k, v in batch.items()}
            UpperCamelCase_      =	(batch["image"] - mean) / std
            UpperCamelCase_      =	model(SCREAMING_SNAKE_CASE_ )
            UpperCamelCase_      =	torch.nn.functional.cross_entropy(SCREAMING_SNAKE_CASE_ ,	batch["label"] )
            accelerator.backward(SCREAMING_SNAKE_CASE_ )
            optimizer.step()
            lr_scheduler.step()
            optimizer.zero_grad()

        model.eval()
        UpperCamelCase_      =	0
        UpperCamelCase_      =	0
        for _, batch in enumerate(SCREAMING_SNAKE_CASE_ ):
            # We could avoid this line since we set the accelerator with `device_placement=True`.
            UpperCamelCase_      =	{k: v.to(accelerator.device ) for k, v in batch.items()}
            UpperCamelCase_      =	(batch["image"] - mean) / std
            with torch.no_grad():
                UpperCamelCase_      =	model(SCREAMING_SNAKE_CASE_ )
            UpperCamelCase_      =	outputs.argmax(dim=-1 )
            UpperCamelCase_     ,					UpperCamelCase_      =	accelerator.gather_for_metrics((predictions, batch["label"]) )
            UpperCamelCase_      =	predictions == references
            num_elems += accurate_preds.shape[0]
            accurate += accurate_preds.long().sum()

        UpperCamelCase_      =	accurate.item() / num_elems
        # Use accelerator.print to print only on the main process.
        accelerator.print(f"epoch {epoch}: {1_0_0 * eval_metric:.2f}" )




def  lowerCAmelCase(			)->	Dict:



    """simple docstring"""






    UpperCamelCase_      =	argparse.ArgumentParser(description="Simple example of training script." )
    parser.add_argument("--data_dir" ,	required=SCREAMING_SNAKE_CASE_ ,	help="The data folder on disk." )
    parser.add_argument(
        "--mixed_precision" ,	type=SCREAMING_SNAKE_CASE_ ,	default=SCREAMING_SNAKE_CASE_ ,	choices=["no", "fp16", "bf16", "fp8"] ,	help="Whether to use mixed precision. Choose"
        "between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >= 1.10."
        "and an Nvidia Ampere GPU." ,	)
    parser.add_argument(
        "--checkpointing_steps" ,	type=SCREAMING_SNAKE_CASE_ ,	default=SCREAMING_SNAKE_CASE_ ,	help="Whether the various states should be saved at the end of every n steps, or 'epoch' for each epoch." ,	)
    parser.add_argument("--cpu" ,	action="store_true" ,	help="If passed, will train on the CPU." )
    UpperCamelCase_      =	parser.parse_args()
    UpperCamelCase_      =	{"lr": 3E-2, "num_epochs": 3, "seed": 4_2, "batch_size": 6_4, "image_size": 2_2_4}
    training_function(SCREAMING_SNAKE_CASE_ ,	SCREAMING_SNAKE_CASE_ )


if __name__ == "__main__":
 main()



from __future__ import annotations




def  lowerCAmelCase(			SCREAMING_SNAKE_CASE_ )->	str:



    """simple docstring"""






    global graph, reversed_graph, scc, component, visit, stack
    if visit[u]:
        return
    UpperCamelCase_      =	True
    for v in graph[u]:
        dfs(SCREAMING_SNAKE_CASE_ )
    stack.append(SCREAMING_SNAKE_CASE_ )




def  lowerCAmelCase(			SCREAMING_SNAKE_CASE_ )->	Dict:



    """simple docstring"""






    global graph, reversed_graph, scc, component, visit, stack
    if visit[u]:
        return
    UpperCamelCase_      =	True
    component.append(SCREAMING_SNAKE_CASE_ )
    for v in reversed_graph[u]:
        dfsa(SCREAMING_SNAKE_CASE_ )




def  lowerCAmelCase(			)->	Dict:



    """simple docstring"""






    global graph, reversed_graph, scc, component, visit, stack
    for i in range(SCREAMING_SNAKE_CASE_ ):
        dfs(SCREAMING_SNAKE_CASE_ )
    UpperCamelCase_      =	[False] * n
    for i in stack[::-1]:
        if visit[i]:
            continue
        UpperCamelCase_      =	[]
        dfsa(SCREAMING_SNAKE_CASE_ )
        scc.append(SCREAMING_SNAKE_CASE_ )
    return scc


if __name__ == "__main__":
 # n - no of nodes, m - no of edges
 SCREAMING_SNAKE_CASE  ,       SCREAMING_SNAKE_CASE		:str				  =    list(map(int, input().strip().split()))

 SCREAMING_SNAKE_CASE		:list[list[int]]				  =    [[] for _ in range(n)]  # graph
 SCREAMING_SNAKE_CASE		:list[list[int]]				  =    [[] for i in range(n)]  # reversed graph
 # input graph data (edges)
 for _ in range(m):
  SCREAMING_SNAKE_CASE  ,       SCREAMING_SNAKE_CASE		:str				  =    list(map(int, input().strip().split()))
  graph[u].append(v)
  reversed_graph[v].append(u)

 SCREAMING_SNAKE_CASE		:list[int]				  =    []
 SCREAMING_SNAKE_CASE		:list[bool]				  =    [False] * n
 SCREAMING_SNAKE_CASE		:list[int]				  =    []
 SCREAMING_SNAKE_CASE		:list[int]				  =    []
 print(kosaraju())
