Overview
Il prossimo incontro tra Trans II e Nõmme United II promette di essere un’emozionante sfida calcistica. Basandoci sui dati statistici disponibili, possiamo fare alcune predizioni interessanti per gli appassionati scommettitori. Entro la fine del primo tempo ci si aspetta una partita dinamica e potenzialmente ricca di gol, mentre le cifre suggeriscono diverse opzioni di gioco per il secondo tempo.
Trans II
Nõmme United II
Predictions:
Market | Prediction | Odd | Result |
---|---|---|---|
Both Teams Not To Score In 1st Half | 83.40% | ||
Over 1.5 Goals | 84.20% | ||
Over 0.5 Goals HT | 72.20% | ||
Both Teams Not To Score In 2nd Half | 70.30% | ||
Both Teams Not to Score | 62.20% | 2.30 Make Bet | |
Home Team To Win | 64.30% | 1.73 Make Bet | |
Over 2.5 Goals | 63.90% | 1.48 Make Bet | |
Away Team To Score In 1st Half | 59.60% | ||
Away Team To Score In 2nd Half | 62.80% | ||
Home Team To Score In 1st Half | 56.90% | ||
Home Team To Score In 2nd Half | 53.90% | ||
Avg. Total Goals | 4.70% | ||
Avg. Goals Scored | 3.51% | ||
Avg. Conceded Goals | 1.58% |
Predictions – Primo Tempo
- Entrambe le Squadre non Segnano al Primo Tempo: 87.00 – Nonostante la probabilità elevata, le squadre potrebbero mostrare un inizio di partita cauto.
- Oltre 1.5 Gol: 84.80 – Questa probabilità indica una possibilità significativa di assistere a un match ricco di azioni e gol.
- Oltre 0.5 Gol al Primo Tempo: 71.00 – Suggestisce che almeno una delle squadre punterà a segnare entro il primo tempo.
- La Squadra Ospite Segna al Primo Tempo: 62.20 – La squadra ospite potrebbe sfruttare l’inizio del match per rendersi pericolosa.
- La Squadra in Casa Segna al Primo Tempo: 57.80 – La squadra di casa potrebbe rispondere con efficacia agli attacchi avversari.
Predictions – Secondo Tempo
- Entrambe le Squadre non Segnano al Secondo Tempo: 66.80 – Le difese potrebbero rafforzarsi nel secondo tempo, rischiando meno.
- Oltre 2.5 Gol: 61.10 – Una previsione che considera una possibile esplosione di gol nel corso della partita.
- Entrambe le Squadre non Segnano: 62.80 – Nonostante una certa quota, questo potrebbe essere un elemento improbabile data l’alta media di gol prevista.
- Vittoria della Squadra in Casa: 66.30 – La squadra in casa potrebbe avere i numeri dalla propria parte per centrare la vittoria.
- La Squadra Ospite Segna al Secondo Tempo: 61.90 – La squadra ospite potrebbe cercare di capovolgere eventuali svantaggi accumulati nel primo tempo.
- La Squadra in Casa Segna al Secondo Tempo: 57.30 – Potrebbero esserci continuità offensive anche nel secondo tempo da parte della squadra locale.
Gol Attesi
Gol Medi Totali: 4.60 – Si prevede un incontro ricco di azioni e portieri sollecitati, con un’appetibilità alta per i scommettitori.
Gol Segnati Medi: 3.31 – Entrambe le squadre sembrano disposte a mantenere un atteggiamento propositivo in campo.
Gol Conceduti Medi: 2.68 – Le difese dovranno essere all’altezza, dato il numero atteso di gol totali.
finbarrmoore/Efficient-Image-Correspondence-Classifier/README.md
# Efficient-Image-Correspondence-Classifier
By Finbarr Moore, Aditya Krishnamurthy, & Hongdong Li
[email protected] (404) 385-8425
This repository contains the code and data for the Efficient Image Correspondence Classifier presented at ICCV 2017.
All code has been written in python and uses the PyTorch framework for deep learning.
## Run the main pipeline
To reproduce the results as presented in the paper,
the main pipeline can be run using the single bash script.
`./run.sh`
To modify the input options, edit the corresponding arguments in `DefaultConfig.txt`.
After the python script is finished, it will output the mean average precision (mAP) at threshold `N` (e.g. n=100 from `DefaultConfig.txt`), the R@N, and
the AUC score of the evaluated dataset.
`./run.sh –help` will output a list of available options.
Notes:
* The image classification accuracy numbers may slightly vary from row to row due to PyTorch’s nondeterministic nature.
* The hdf5 file containing fppr and tpr_num of test set should be replace with the generated hdf5 file by separate python script `get_fppr_tpr.py` [please goto next section]
* The input image sizes are scaled to have short side=256 by default.
## Run get_fppr_tpr.py
To implement this function, one need to make a few edits in input arguments of `get_fppr_tpr.py`. Specifically, need to change the input score_file and the feature_file from this repository to whatever you’re running detector and descriptor with.
After running main pipeline, you will see two files in current directory: `fppr_tpr.h5` which contains the fppr and tpr of all data pairs that we consider to be true positive/negative, and `fppr_tpr.pkl` which contains true positive that is used to calculate mAP.
For a fair comparison with other researh works, we do not use all true positive data pairs to calculate mAP. Instead, we only use hard positives.
In other words, for each positive keypoint pair `(x,y)` we calculated a negative score as follow:
Score(x,y) = sigmoid( P(x)*P(y)*Correlationscores(x,y))
where `sigmoid` is just a regular transformation function.
Similarily for each negative keypoint pair `(x,y)` we calculate a positive score as follow:
Score(x,y) = sigmoid(P(x)+P(y)+Correlationscores(x,y))
So, we only select the positive keypoint pairs with larger negative scores, which is more difficult to distinguish with negatives than other positive pairs.
The structure of generated hdf5 file may look like:
`fppr = […]
tpr = […]
fpprNum = […]
tprNum = […]`
where fppr stands for false to true positive rate, i.e. FPR/TPR trade off;
tpr stands for true positive rate;
fpprNum stands for number of negatives while calculating false to true positive rate;
tprNum stands for number of positives while calculating true positive rate;
Please note that mAP computation uses a specific numbers of correspondences instead of computing it over all generated correspondences.
To see which correspondences are used for mAP computation, please inspect: `fppr_tpr.pkl`.
## Data
The model is trained on the following datasets and the code should be able to pull those datasets automatically:
1. Oxford5k
2. Paris6k
3. Holidays
4. ROC
All other data should be downloaded and organized before running the data.
Oxford and Paris data can be downloaded by the tool called `download_plusplus5k.py` which downloads
the original SIFT-descriptor matches and correspondence labels (positive and negative)
python ./download_plusplus5k.py –help
All datasets with the following folder structure must be organized into their own folder and
followed by the dictionary in `DefaultConfig.txt`. For example, if you have Oxford and Paris datasets,
you should create an `input_data` folder that in turn contains the following subdirectories: `Oxford` and `Paris`.
Then change the paths in `DefaultConfig.txt` to point to those files.
So for example your end directory structure should look like:
+ input_data
|– Oxford
| + features
| + h5 files
| + images
| + lists
| + scores
| + …
|
|– Paris
| + features
| + h5 files
| + images
| + lists
| + scores
| + …
|
## Citations
If you use this code for your work, please cite:
@inproceedings{moore2017efficient,
title={An Efficient Image Correspondence Classifier},
author={Moore, Finbarr and Krishnamurthy, Aditya and Li, Hongdong},
booktitle={Conference on Computer Vision and Pattern Recognition},
year={2017}
}
finbarrmoore/Efficient-Image-Correspondence-Classifier/train.py
from __future__ import print_function
from torch.autograd import Variable
import torch.nn as nn
import torch.optim as optim
import numpy as np
import torch.nn.functional as F
import torch.nn.init as init
import os
import argparse
import torch
from tqdm import tqdm
import loader
from network import Net
from util import Logger
from config import Config as Config
def main():
parser = argparse.ArgumentParser(description=’Efficient Image Correspondence Classifier’)
parser.add_argument(‘–config’, type=str,
default=’./Configs/DefaultConfig.txt’, help=’path to config file’)
parser.add_argument(‘–runId’, type=int, default=0, help=”run Id (used for logging purposes)”)
parser.add_argument(‘–batchSize’, type=int, default=1, help=’training batch size’)
args = parser.parse_args()
args.runId = “run_”+str(args.runId)
if not os.path.exists(‘./models’):
os.mkdir(‘./models’)
if os.path.exists(args.config):
print(“Loading configuration from: {}”.format(os.path.abspath(args.config)))
Config().parse(args.config)
else:
print(“nWarning: Config file {} not found! Using Default Config!”.format(args.config))
config = Config().config
logger = Logger(‘./logs/%s_%s’%(config[‘network’][‘name’], args.runId))
logging = logger.Log
logging(“network config {}”.format(config[‘network’]))
logging(“data config {}”.format(config[‘data’]))
# Dataset loading
data = loader.DataLoader(config[‘data’])
train_loader = data.loader(‘train’, config)
nTrainImgPerBatch = config[‘data’][‘batchSize’] * config[‘data’][‘imgPerTrainBatch’]
train_batch_size = config[‘data’][‘batchSize’]
# Create network
net = Net(config[‘network’])
GPU_ID = config[“train”][“GPU_ID”]
if GPU_ID==-1:
print(“Using CPU.”)
device = torch.device(“cpu”)
elif isinstance(GPU_ID, list):
n_gpu = len(GPU_ID)
factor = int(np.log10(n_gpu))
if n_gpu==1:
os.environ[“CUDA_VISIBLE_DEVICES”]=str(GPU_ID[0])
os.environ[“CUDA_VISIBLE_DEVICES”]=str(GPU_ID[0])#’0′
device = torch.device(“cuda:0”)
net.to(device)
net = torch.nn.DataParallel(net)
print(“Using GPU: “+str(GPU_ID[0]))
else:
os.environ[“CUDA_VISIBLE_DEVICES”]=str(GPU_ID)
device = torch.device(“cuda:”+str(GPU_ID))
net.to(device)
criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(net.parameters(), lr=config[‘train’][‘learningRate’], weight_decay=config[‘train’][‘weightDecay’])
logging(‘Total Iterations {}’.format(config[‘train’][‘numEpochs’] * len(train_loader)))
print_freq = int(len(train_loader) / 20)
lr_decay_step = int(nTrainImgPerBatch * config[‘train’][‘lrDecayEpochs’])
for epoch in range(config[‘train’][‘numEpochs’]):
print(‘n Epoch {}/{}’.format(epoch + 1, config[‘train’][‘numEpochs’]))
avg_loss = 0.0
net.train()
loss_log = []
if epoch >= lr_decay_step and (epoch-lr_decay_step) % lr_decay_step == 0:
logging(‘Decay learning rate by a factor of {} at Epoch {}, learning rate becomes {}’
.format(config[‘train’][‘lrDecay’], epoch+1, optimizer.param_groups[0][‘lr’] * config[‘train’][‘lrDecay’]))
optimizer.param_groups[0][‘lr’] *= config[‘train’][‘lrDecay’]
progress_bar = tqdm(enumerate(train_loader), total=len(train_loader))
for i, (img1, img2, descriptors1, descriptors2, matches) in progress_bar:
batchSize = img1.size(0)
img1 = img1.to(device)
img2 = img2.to(device)
matchesBool = matches.to(device)
descriptor1 = descriptors1.to(device)
descriptor2 = descriptors2.to(device)
prediction,_ = net(img1,img2)
loss = criterion(prediction.view(-1), matchesBool.view(-1))
optimizer.zero_grad()
loss.backward()
optimizer.step()
avg_loss += loss.item() / nTrainImgPerBatch * train_batch_size
#loss_log.append(np.array(loss.item()))
progress_bar.set_description(‘Epoch {}/{}. Iteration {}/{}. Loss: {:.4f}’
.format(epoch + 1, config[‘train’][‘numEpochs’], i+1 ,len(train_loader), loss.item()))
#progress_bar.set_postfix(loss=np.mean(loss_log[-config[‘print_freq’]:]))
print(‘n Epoch {}/{} Done: Avg Loss: {:.4f}n’.format(epoch+1,config[‘train’][‘numEpochs’],avg_loss))
logging(‘Epoch {} loss {}’.format(epoch+1,avg_loss))
model_dir = ‘./models/’+args.runId+’_’+str(epoch+1)+’_’+str(avg_loss)[:5]
if not os.path.exists(model_dir):
os.mkdir(model_dir)
if GPU_ID!=-1:
net.module.save(model_dir+’/’+’net_{:.4f}.pth’.format(avg_loss))
with open(model_dir+’/’+’net_%s.pt’%str(avg_loss)[:5], ‘wb’) as f:
torch.save({‘epoch’:epoch, ‘state_dict’: net.module.state_dict(), ‘optimizer’:optimizer.state_dict()}, f)
else:
with open(model_dir+’/’+’net_%s.pt’%str(avg_loss)[:5], ‘wb’) as f:
torch.save({‘epoch’:epoch,’state_dict’: net.state_dict(), ‘optimizer’:optimizer.state_dict()}, f)
if __name__ == ‘__main__’:
main()import numpy as np
from torch.utils.data import Dataset, DataLoader
from collections import OrderedDict
import torchvision.transforms as transforms
import torch.nn.functional as F
import h5py
import pickle
import os
from Image_folder import ImageFolderLoader
class Loader(Dataset):
def __init__(self,data_path):
dataset_list=[‘Oxford’,’Paris’,’Holidays’, ‘ROC’]
if not os.path.exists(data_path):
print(‘ERROR! ‘+ data_path +’ does not exist!’)
else:
self.imageFolderbyDataset={}
self.h5FolderbyDataset={}
self.h5LabelFolderbyDataset={}
for dataset_name in dataset_list:
dataset_relative_path=data_path+’/’+dataset_name.replace(‘_’,’/’)
if os.path.exists(dataset_relative_path):
self.imageFolderbyDataset[dataset_name] = ImageFolderLoader(dataset_relative_path+’/images’)
if os.path.exists(dataset_relative_path + ‘/h5/’):
self.h5FolderbyDataset[dataset_name] = dataset_relative_path+’/h5/’
else:
print(dataset_name+’ dataset does not have h5 folder!’)
if os.path.exists(dataset_relative_path + ‘/scores/’):
self.h5LabelFolderbyDataset[dataset_name] = dataset_relative_path+’/scores/’
else:
print(dataset_name+’ dataset does not have h5 label folder!’)
def getBatch(self,batchGroupSize,imgPerBatch,NegativePositiveRatio=100,pos_proposal_num=50,img_h=256,img_w=256,negativeNumber=128):
batchList=[]
for i in range(batchGroupSize):
isNeg=False
while not isNeg:
data_group=self._get_a_group()
img1,img2,label_x,h,W=data_group[0]
if data_group[1]:
isNeg=True
img1=np.zeros((img_h,img_w,3))
img2=np.zeros((img_h,img_w,3))
#print(img1.shape)
#print(img2.shape)
img1=transforms.functional.resize(img1,(img_h,img_w))
img2=transforms.functional.resize(img2,(img_h,img_w))
img1[np.where(img1==0)]=255
img2[np.where(img2==0)]=255
batchList.append([img1,img2,label_x,h,W,data_group[2]])
if len(batchList)==imgPerBatch:
return np.array(batchList[0][0]),np.array(batchList[0][1]),np.array(batchList[0][6]),np.array(batchList[0][2]),np.array(batchList[0][3]),np.array(batchList[0][4]), np.array([b[5] for b in batchList],dtype=bool)
def _get_a_group(self):
dataset=self._select_dataset()
random_number=np.random.randint(0,len(self.imageFolderbyDataset[dataset].query_image_list))
query_relative_path=self.imageFolderbyDataset[dataset].query_image_list[random_number]
features_label_filename=”