GitHub deploy action builds and pushes to Sanger's S3 compatible storage

Update deploy action so main branch deploys to /latest/ path and dev (and for that matter all other branches) deploy to /branch-name/.
Added two env vars to the build step: PUBLIC_URL and REACT_APP_VERSION. First one makes the URLs point to the right place for each build and the second one is used in a meta tag added to index.html for version tracking (package version + branch name + commit hash) when deploying the app.
Finally, the build directory is uploaded to Sanger's S3 compatible storage.
The tag/release build and deploy to /stable/ part is still missing. I belive that should be a different action.yml alltogether and that can be a different PR. I think that to continue with the current development this one is good enough.

Very nice. I've just updated links in the README.md to point to the new demo locations for latest and dev deployments at Sanger. I've also updated the directory name in the S3 bucket to reflect the recent change in repo name. Please merge if you're happy.


expression: support function-based expressions

e.g.
select replace(x) from table;

hello, I want to have a try.


Huge loss when applying QAT on YOLOv8n

Hi @peterjc123,
I am adapting your quantized-aware training method to my YOLOv8 compression flow,
I follow this pipeline to train my model:
def calibrate(model, context: DLContext, eval=True):
    model.to(device=context.device)
    if eval:
        model.eval()
    else:
        model.train()
    avg_batch_time = AverageMeter()
    with torch.no_grad():
        end = time.time()
        for i, batch in enumerate(context.train_loader):
            if context.max_iteration is not None and i >= context.max_iteration:
                break
            img = batch['img'].to(context.device, non_blocking=True).float() / 255.0
            model(img)
            # measure elapsed time
            avg_batch_time.update(time.time() - end)
            end = time.time()
            if i % 10 == 0:
                print(f'Calibrate: [{i}/{len(context.train_loader)}]\tTime {avg_batch_time.avg:.5f}\t')
            context.iteration += 1

raw_model = torch.load(args.model_pretrained_dir)
model = cross_layer_equalize(raw_model, dummy_input, device, work_dir='TinyNeuralNet/out', cle_iters=2, hba_flag=False)

context.max_iteration = 100
calibrate(model, context=context, eval=True)

with model_tracer():
    quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
        config={'ignore_layerwise_config': True, 'asymmetric': True, 'per_tensor': True})
    qat_model = quantizer.quantize()

qat_model.to(device=device)
qat_model.train()
qat_model.apply(torch_q.enable_fake_quant)
qat_model.apply(torch_q.enable_observer)

And I met this error, the loss metrics of QAT flow are huge.
I think the wrong fake quantization of input cause this error.
WARNING (tinynn.graph.tracer) Constant generation is experimental and may yield error
  0%|          | 0/2004 [00:00<?, ?it/s]
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
        0/0     1.43GB     0.4511  4.359e+11  6.902e+08        112        320: 100%|██████████| 2004/2004 [04:49<00:00,  6.92it/s]
Ultralytics YOLOv8.0.124 🚀 Python-3.8.18 torch-2.0.0+cu117 CUDA:0 (Tesla V100-PCIE-32GB, 32501MiB)
Ultralytics YOLOv8.0.124 🚀 Python-3.8.18 torch-2.0.0+cu117 CUDA:0 (Tesla V100-PCIE-32GB, 32501MiB)
val: Scanning /data/hoangth34/tvm/tvm_yolov8/datasets/data_coco/labels/val.cache... 2692 images, 0 backgrounds, 0 corrupt: 100%|██████████| 2692/2692 [00:0
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95):   1%|          | 1/85 [00:00<00:49,  1.70it/s][0, 0, 320, 320]

Do you know how to fix it?
Thank you.

It seems that you are using QATQuantizer for PTQ. The correct way to do that is listed below.
from tinynn.graph.quantization.fake_quantize import set_ptq_fake_quantize
quantizer = QATQuantizer(
        model, dummy_input, work_dir='out', config={'override_qconfig_func': set_ptq_fake_quantize}
)

Hi @peterjc123,
Thanks for your reply, I had some experiments and I realized that I have to run model_rewrite() to train my model. Models that do not use this method will lack layers and does not expose correct output. So I ran:
   raw_model = torch.load(args.model_pretrained_dir)
    model = model_rewrite(raw_model, dummy_input, work_dir='TinyNeuralNet/out')

    with model_tracer():
        quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
                config={'asymmetric': True, 'per_tensor': True, 'override_qconfig_func': set_ptq_fake_quantize})
        qat_model = quantizer.quantize()

Now the model can be trained but training loss and validation metrics are terrible. I expect the losses go lower than 1 like the original model. But the optimizer seems got stuck at 3.0.
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
       1/49     2.27GB       3.01      2.835      2.919        114        320: 100%|██████████| 2004/2004 [06:03<00:00,  5.52it/s]

Do you know any methods that can be tried to resolve this problem?

It is advisable to first attempt Post-Training Quantization (PTQ) to quickly observe the loss introduced by quantization.
If the results of PTQ are devastating, such as a drop of more than 30 points, it may indicate that the model is not quantization-friendly and I will assist in conducting a more in-depth quantization analysis to try to recover the model's quantization accuracy..
I think QAT is recommended when the accuracy loss from PTQ is minimal and you want to further enhance the model's quantization precision.

Alternatively, could you share the YOLOv8 model file (or the open-source repository you used) and your QAT training script?

Thanks @zk1998,
Here is my script
import sys, os, argparse, random
sys.path.append(os.getcwd())
RANK = int(os.getenv("RANK", -1))

import torch
import torch.nn as nn
import torch.optim as optim
import torch.quantization as torch_q

from ultralytics import YOLO
from ultralytics.yolo.utils.loss import v8DetectionLoss

from tinynn.util.train_util import AverageMeter, DLContext, train, get_device
from tinynn.graph.quantization.quantizer import QATQuantizer
from tinynn.graph.tracer import model_tracer
from tinynn.converter import TFLiteConverter
from tinynn.graph.quantization.algorithm.cross_layer_equalization import cross_layer_equalize, model_rewrite, model_fuse_bn, clear_model_fused_bn
from tinynn.util.bn_restore import model_restore_bn
from tinynn.util.quantization_analysis_util import graph_error_analysis, layer_error_analysis
from tinynn.graph.quantization.fake_quantize import set_ptq_fake_quantize

from datetime import datetime
from pathlib import Path

from ultralytics.yolo.cfg import get_cfg
from ultralytics.utils import *
from ultralytics.yolo.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, NUM_THREADS, RANK, ROOT,
                                    callbacks, is_git_dir, yaml_load)
from torchsummary import summary
from copy import copy, deepcopy
from ultralytics.yolo import v8
from ultralytics.yolo.utils.checks import check_imgsz
from ultralytics.yolo.data.utils import check_det_dataset
from ultralytics.yolo.data import build_dataloader
from ultralytics.yolo.utils.torch_utils import de_parallel, torch_distributed_zero_first
from ultralytics.yolo.data.dataset import YOLODataset
from ultralytics.yolo.utils.files import increment_path
from ultralytics.utils.torch_utils import (
    EarlyStopping,
    de_parallel,
    init_seeds,
    one_cycle,
    select_device,
    strip_optimizer,
)

def get_default_config(DEFAULT_CFG_PATH="ultralytics/cfg/default.yaml"):
    # Default configuration
    DEFAULT_CFG_DICT = yaml_load(DEFAULT_CFG_PATH)
    for k, v in DEFAULT_CFG_DICT.items():
        if isinstance(v, str) and v.lower() == "none":
            DEFAULT_CFG_DICT[k] = None
    DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys()
    DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT)
    return DEFAULT_CFG

"""Build Dataset
"""
def get_dataloader(model, dataset_path, cfg, data, batch_size=16, rank=0, mode='train'):
    def build_dataset(model, img_path, mode='train', batch=None):
        gs = max(int(de_parallel(model).stride.max() if model else 0), 32)
        return YOLODataset(
            img_path=img_path,
            imgsz=320,
            batch_size=batch,
            augment=False,  # augmentation
            hyp=cfg,  # TODO: probably add a get_hyps_from_cfg function
            rect=False,  # rectangular batches
            cache=None,
            single_cls=False,
            stride=gs,
            pad=0.0 if mode == 'train' else 0.5,
            prefix=colorstr(f'{mode}: '),
            use_segments=False,
            use_keypoints=False,
            classes=None,
            data=data,
            fraction=1.0)

    assert mode in ['train', 'val']
    with torch_distributed_zero_first(rank):  # init dataset *.cache only once if DDP
        dataset = build_dataset(model, dataset_path, mode, batch_size)
    shuffle = mode == 'train'
    if getattr(dataset, 'rect', False) and shuffle:
        LOGGER.warning("WARNING ⚠ 'rect=True' is incompatible with DataLoader shuffle, setting shuffle=False")
        shuffle = False
    workers = 2 if mode == 'train' else 2
    return build_dataloader(dataset, batch_size, workers, shuffle, rank)

def get_validator(batch_size, saved_experiment_dir):
    cb = callbacks.get_default_callbacks()
    overrides = {'imgsz': 320, 'batch': batch_size, 'conf': 0.25, 'iou': 0.6, 'device': 'cuda:0'}
    overrides['rect'] = True
    overrides['mode'] = 'val'
    overrides.update(overrides)
    args = get_cfg(cfg=DEFAULT_CFG, overrides=overrides)
    args.data = 'sparseml_quantization/data.yaml'
    args.task = 'detect'
    args.rect = False
    args.imgsz = check_imgsz(320, max_dim=1)
    return v8.detect.DetectionValidator(save_dir=saved_experiment_dir, args=args, _callbacks=cb)

def calibrate(model, context: DLContext, eval=True):
    model.to(device=context.device)
    if eval:
        model.eval()
    else:
        model.train()
    avg_batch_time = AverageMeter()
    with torch.no_grad():
        end = time.time()
        for i, batch in enumerate(context.train_loader):
            if context.max_iteration is not None and i >= context.max_iteration:
                break
            img = batch['img'].to(context.device, non_blocking=True).float() / 255.0
            model(img)
            # measure elapsed time
            avg_batch_time.update(time.time() - end)
            end = time.time()
            if i % 10 == 0:
                print(f'Calibrate: [{i}/{len(context.train_loader)}]\tTime {avg_batch_time.avg:.5f}\t')
            context.iteration += 1

def setup_seed(seed, cuda_deterministic=True):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)
    os.environ["PYTHONHASHSEED"] = str(seed)
    if cuda_deterministic:  # slower, more reproducible
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False
    else:  # faster, less reproducible
        torch.backends.cudnn.deterministic = False
        torch.backends.cudnn.benchmark = True

def train(args, model, optimizer, scheduler, criterion, train_loader, validator, context, max_epochs, cfg, saved_experiment_dir):
    loss_names = ['box_loss', 'cls_loss', 'dfl_loss']
    model = model.to(context.device)
    tloss = None
    best_fitness = -1e5
    early_stopper = 0

    for epoch in range(max_epochs):
        # For each epoch
        pbar = TQDM(enumerate(train_loader), total=len(train_loader))
        if epoch == 5:
            train_loader.dataset.close_mosaic(hyp=cfg)
            train_loader.reset()
        # TRAIN!!!
        model.train()
        print(('\n' + '%11s' * (4 + len(loss_names))) % ('Epoch', 'GPU_mem', *loss_names, 'Instances', 'Size'))

        for i, batch in pbar:
            # Warm Up!
            # ni = i +  len(train_loader) * epoch
            # nw = max(round(3 * len(train_loader)), 100)
            # if ni <= nw:
            #     xi = [0, nw]
            #     for j, x in enumerate(optimizer.param_groups):
            #         x["lr"] = np.interp(
            #             ni, xi, [0.1 if j == 0 else 0.0, x["initial_lr"] * one_cycle(1, 0.01, max_epochs)(epoch)])
            #         if "momentum" in x:
            #             x["momentum"] = np.interp(ni, xi, [0.8, 0.937])

            optimizer.zero_grad()
            # Preprocess batch!
            batch['img'] = batch['img'].to(context.device, non_blocking=True).float() / 255.0
            output = model(batch['img'])
            loss, loss_items = criterion(output, batch)
            loss.backward()

            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0)
            optimizer.step()

            # Loss infos
            tloss = ((tloss * i + loss_items) / (i + 1) if tloss is not None else loss_items)
            mem = f"{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}GB"  #(GB)
            loss_len = tloss.shape[0] if len(tloss.shape) else 1
            losses = tloss if loss_len > 1 else torch.unsqueeze(tloss, 0)
            # Progress bar
            pbar.set_description(
                        ("%11s" * 2 + "%11.4g" * (2 + loss_len))
                        % (f"{epoch}/{max_epochs-1}",  mem, *losses, batch["cls"].shape[0], batch["img"].shape[-1])
                    )

            if (epoch == max_epochs // 3):
                print("[INFO] Freeze quantizer parameters!")
                model.apply(torch.quantization.disable_observer)
             elif (epoch == max_epochs // 3 * 2):
                print("[INFO] Freeze batch-norm mean and variance estimates!")
                model.apply(torch.nn.intrinsic.qat.freeze_bn_stats)

        validate_model = deepcopy(model)
        metrics = validator(model=validate_model)
        fitness = metrics["fitness"]

        if not best_fitness or best_fitness < fitness:
            best_fitness = fitness
        else:
            early_stopper += 1

        save_model(epoch, best_fitness, fitness, model, optimizer,
            save_path=saved_experiment_dir / "weights")

        scheduler.step()
        del validate_model
        torch.cuda.empty_cache()

        if early_stopper == 5:
            break

    return model

def save_model(epoch, best_fitness, fitness, model, optimizer, save_path):
    """Save model checkpoints based on various conditions."""
    ckpt = {
        'epoch': epoch,
        'best_fitness': best_fitness,
        'model': deepcopy(de_parallel(model)),
        'optimizer': optimizer.state_dict(),
        'date': datetime.now().isoformat()}

    try:
        import dill as pickle
    except ImportError:
        import pickle

    if not os.path.exists(save_path):
        os.makedirs(save_path)
    last = save_path / "last.pt"
    best = save_path / "best.pt"
    torch.save(ckpt, last, pickle_module=pickle)
    if best_fitness == fitness:
        torch.save(ckpt, best, pickle_module=pickle)
    del ckpt

def qat(args):
    dataset_yaml_path = '/data/hoangtv23/workspace_AIOT/model_compression_flow/sparseml_quantization/data.yaml'
    # uncompressed_model_dir = "yolov8n.pt"

    saved_experiment_dir = "TinyNeuralNet/tinynn_runs/exp_yolov8n"
    saved_experiment_dir = increment_path(Path(saved_experiment_dir))

    context = DLContext()

    # Config consists of Augmentation Informations
    cfg = get_default_config()
    cfg.data = dataset_yaml_path

    # Declare Model
    raw_model = torch.load(args.model_pretrained_dir)

    raw_model.args = cfg
    dummy_input = torch.rand(1, 3, 320, 320)

    data = check_det_dataset(dataset_yaml_path)
    trainset, testset = data['train'], data.get('val') or data.get('test')

    device = get_device()
    context.device = device

    train_loader = get_dataloader(raw_model, trainset, cfg, data, args.batch_size, RANK, "train")
    context.train_loader = train_loader

    test_loader = get_dataloader(raw_model, testset, cfg, data, args.batch_size*2, RANK, "val")
    validator = v8.detect.DetectionValidator(test_loader, save_dir=saved_experiment_dir, args=copy(cfg))

    # validator = get_validator(batch_size=args.batch_size, saved_experiment_dir=saved_experiment_dir)
    model = model_rewrite(raw_model, dummy_input, work_dir='TinyNeuralNet/out')

    context.max_iteration = 100
    calibrate(model, context=context, eval=True)

    with model_tracer():
        quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
                config={'asymmetric': True, 'per_tensor': True, 'override_qconfig_func': set_ptq_fake_quantize})
        qat_model = quantizer.quantize()

    qat_model.to(device=device)

    """ Build Optimizer!
    """
    optimizer = torch.optim.Adam(qat_model.parameters(), lr= args.base_lr, weight_decay=args.weight_decay)
    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=args.num_epochs + 1, eta_min=0)

    """ Build Criterion!
    """
    criterion = v8DetectionLoss(raw_model)

    """ Train!
    """
    qat_model.train()
    qat_model.apply(torch_q.enable_fake_quant)
    qat_model.apply(torch_q.enable_observer)

    """ Train Model!
    """
    qat_model = train(args, qat_model, optimizer, scheduler, criterion, train_loader,
         validator, context, args.num_epochs, cfg, saved_experiment_dir)

    """ Error Analysis!
    """
    dummy_input_real = next(iter(train_loader))['img'].cuda().type(torch.FloatTensor)
    graph_error_analysis(qat_model, dummy_input_real, metric='cosine')
    layer_error_analysis(qat_model, dummy_input_real, metric='cosine')

    qat_model.apply(torch_q.disable_observer)
    metrics = validator(model=deepcopy(qat_model))
    print(metrics)

    with torch.no_grad():
        qat_model.eval()
        qat_model.cpu()
        qat_model = quantizer.convert(qat_model)
        torch.backends.quantized.engine = quantizer.backend
        converter = TFLiteConverter(qat_model, dummy_input.cpu(), tflite_path='TinyNeuralNet/out/quantized_model.tflite')
        converter.convert()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--workers', type=int, default=4)
    parser.add_argument('--num-epochs', type=int, default=50)
    parser.add_argument('--batch-size', type=int, default=32)
    parser.add_argument('--base-lr', type=float, default=1e-1)
    parser.add_argument('--weight-decay', type=float, default=1e-6)
    parser.add_argument('--model-pretrained-dir', type=str, default='oto_pruning/cache/version_split_bbox_conf/DetectionModel_compressed.pt')
    setup_seed(seed=2048, cuda_deterministic=False)
    args = parser.parse_args()
    qat(args)

I saved the rewritten model and load it with QATQuantizer() with the setting 'rewrite_graph': False, 'force_overwrite': False. But It takes me 20 epochs to achieve 0.04 mAPs 😃. Although the difference output between the rewritten and the original one is zero. I really don't know what happened here.

If the rewritten model's mAPs has no difference with the original model, I strongly recommend you first use the rewritten model(the py file and pth file in out dir) to try post-quantization  and then evaluate the mAPs of the ptq_model（after pytorch quantization converter.

Thank you very much for your support @zk1998,
I have my own version for YOLOv8 PTQ.
I am trying the QAT version with your method to produce the Integer-arithmetic-only Inference model.

@hoangtv2000 Hi, for reproducing your issue, if we utilize QAT, then it will very time-consuming. So we use PTQ instead. And we believe if PTQ works, then QAT certainly work better.

But It takes me 20 epochs to achieve 0.04 mAPs

Nope, it doesn't sound right. For a correct setup, it should not be dropping that much.

@ >     # validator = get_validator(batch_size=args.batch_size, saved_experiment_dir=saved_experiment_dir)     model = model_rewrite(raw_model, dummy_input, work_dir='TinyNeuralNet/out')
Could you please tell me how you performed model_rewrite?

I use rewrite function in TinyNeuralNet/tinynn/graph/quantization/algorithm/cross_layer_equalization.py
def model_rewrite(model, dummy_input, work_dir='out') -> nn.Module:
    """rewrite model to non-block style"""
    with model_tracer():
        graph = trace(model, dummy_input)
        model_name = type(model).__name__
        model_rewrite = f'{model_name}_cle_Rewrite'
        model_name_rewrite_lower = model_rewrite.lower()
        model_ns = f'out.{model_name_rewrite_lower}'
        model_code_path = os.path.join(work_dir, f'{model_name_rewrite_lower}.py')
        model_weights_path = os.path.join(work_dir, f'{model_name_rewrite_lower}.pth')
        graph.eliminate_dead_graph_pass()
        if not os.path.exists(work_dir):
            os.makedirs(work_dir)
        graph.generate_code(model_code_path, model_weights_path, model_rewrite)

        # Import the new model
        rewritten_model = import_from_path(model_ns, model_code_path, model_rewrite)()
        rewritten_model.load_state_dict(torch.load(model_weights_path))
        # os.unlink(model_weights_path)
        return rewritten_model

# args.model_pretrained_dir is the trained and pruned model path.
raw_model = torch.load(args.model_pretrained_dir)
dummy_input = torch.rand(1, 3, 320, 320).to(device)
model = model_rewrite(raw_model, dummy_input, work_dir='TinyNeuralNet/out')

model = model_rewrite(raw_model, dummy_input, work_dir='TinyNeuralNet/out')

Would you please skip this step for now?

In my cases, models that are not rewritten will missing layers and cannot expose correct output. Specifically, it lacks some layers for bbox and confidence score prediction, so the model can be used later. The model losses are also not reduced, so I think rewriting the model is not a problem.
Set up:
raw_model = torch.load(args.model_pretrained_dir)
    with model_tracer():
        raw_model.to(device)
        quantizer = QATQuantizer(raw_model, dummy_input, work_dir='TinyNeuralNet/out',
                config={'asymmetric': True, 'per_tensor': True, 'override_qconfig_func': set_ptq_fake_quantize})
        qat_model = quantizer.quantize()

Error report:
Ultralytics YOLOv8.0.124 🚀 Python-3.8.18 torch-2.0.0+cu117 CUDA:0 (Tesla V100-PCIE-32GB, 32501MiB)

      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
Ultralytics YOLOv8.0.124 🚀 Python-3.8.18 torch-2.0.0+cu117 CUDA:0 (Tesla V100-PCIE-32GB, 32501MiB)
[INFO] By passing warm up!!!

                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95):   0%|          | 0/22 [00:00<?, ?it/s]WARNING ⚠ NMS time limit 6.900s exceeded
OUTPUT TENSOR SHAPE: [torch.Size([128, 65, 40, 40]), torch.Size([128, 65, 20, 20]), torch.Size([128, 65, 10, 10])]
WARNING ⚠ NMS time limit 6.900s exceeded

                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95):   0%|          | 0/22 [00:08<?, ?it/s]
Traceback (most recent call last):
  File "TinyNeuralNet/yolov8n_quantization.py", line 391, in <module>
    qat(args)
  File "TinyNeuralNet/yolov8n_quantization.py", line 358, in qat
    qat_model = train(args, qat_model, optimizer, scheduler, criterion, train_loader,
  File "TinyNeuralNet/yolov8n_quantization.py", line 240, in train
    metrics = validator(model=validate_model)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/utils/_contextlib.py", line 115, in decorate_context
    return func(*args, **kwargs)
  File "/data/hoangtv23/workspace_AIOT/model_compression_flow/ultralytics/yolo/engine/validator.py", line 171, in __call__
    self.update_metrics(preds, batch)
  File "/data/hoangtv23/workspace_AIOT/model_compression_flow/ultralytics/yolo/v8/detect/val.py", line 109, in update_metrics
    self.confusion_matrix.process_batch(predn, labelsn)
  File "/data/hoangtv23/workspace_AIOT/model_compression_flow/ultralytics/yolo/utils/metrics.py", line 246, in process_batch
    self.matrix[detection_classes[m1[j]], gc] += 1  # correct
IndexError: index 9 is out of bounds for axis 0 with size 2

with model_tracer():
    model = YOLO("yolov8n-cls.pt").model
    dummy_input = torch.rand((1, 3, 224, 224))
    quantizer = PostQuantizer(model, dummy_input, work_dir='out')
    ptq_model = quantizer.quantize()

    with model_tracer():
        model = YOLO("yolov8n-cls.pt").model
        dummy_input = torch.rand((1, 3, 224, 224))
        quantizer = PostQuantizer(model, dummy_input, work_dir='out')
        ptq_model = quantizer.quantize()

this use case can be traced correctly.

@hoangtv2000  Actually, we will also perform rewrite if you call quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out'). If this fails, then it means TinyNN Graph Tracer is unable to capture the computation flow of the model. Please ensure that you pass in instances of nn.Module for PostQuantizer or QATQuantizer.

Yes, the original model is nn.Module of course.
And the rewritten model is nn.Module and is equal to the original model.
So, I think the rewritten model is traced right and the problem comes from the optimizer.

Yes, the original model is nn.Module of course. And the rewritten model is nn.Module and is equal to the original model. So, I think the rewritten model is traced right and the problem comes from the optimizer.

I think I know the reason. it is because the computation logic is slightly different between training mode and evaluation mode. Given the fact that we actually rewrite the model and trace only once in a single mode, it is inevitable that the traced graph won't work for the other mode. You may have to patch the generated model code a little bit so that it works for both training and evaluation.

see https://github.com/ultralytics/ultralytics/blob/0f2bee4cc6d337d94c828e38cc5579eede2bcc69/ultralytics/nn/modules/head.py#L21 for more details.

Thank you @peterjc123,
Your suggestion seems not working, I split the model to 2 phases training and evaluation in forward() and the training result does not change. So, I think the problem comes from the optimization.

Hi @hoangtv2000  , you can try to quantize Yolov8 detection model as below:

You need to use PostQuantizer to properly trace the complete model in eval mode.

Modify the source code of the ultralytics package so that tinynn can properly trace the model in eval mode.

Use the following code to ensure tracing in eval mode (clear the out directory before tracing):

with model_tracer():
    model = YOLO("yolov8n.pt").model
    dummy_input = torch.rand((1, 3, 224, 224))

    quantizer = PostQuantizer(model, dummy_input, work_dir='out', config={'force_overwrite': False})
    ptq_model = quantizer.quantize()

Now, you can see the generated xx_q.py and xx_q.pth files in the ./out directory. These are model files that can be loaded and used. To align the differences between train/eval mode in yolov8 , you need to modify the return.

Then,you can use the QAT script normally, you need to check if the QAT fake-quantized model's mAPS is still usable before training. This means you should run a validation before qat script line 96:

with model_tracer():
    model = YOLO("yolov8n.pt").model
    dummy_input = torch.rand((1, 3, 224, 224))

    context = DLContext()
    ...

    # set force_overwrite to False to reuse your modified traced model
    quantizer = QATQuantizer(model, dummy_input, work_dir='out1', config={'force_overwrite': False})
    ptq_model = quantizer.quantize()

# Do calibration/inference to get quantization param
ptq_model.eval()
ptq_model.apply(torch.quantization.disable_fake_quant)
ptq_model.apply(torch.quantization.enable_observer)
calibrate(ptq_model, context)
# ptq_model(img_tensor)

# Disable observer and enable fake quantization to validate model with quantization error
ptq_model.apply(torch.quantization.disable_observer)
ptq_model.apply(torch.quantization.enable_fake_quant)
validata(ptq_model, context)

# do qat as normal
ptq_model.apply(torch.quantization.enable_fake_quant)
ptq_model.apply(torch.quantization.enable_observer)
...

Thanks for your response @zk1998,
I think I find the cause, I loaded the PTQ rewritten model of your step 1 and validate, it preserves the same mAP of the original model. But when I run
quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
                config={'asymmetric': True, 'per_tensor': True, 'force_rewrite': False, 'rewrite_graph': False})
qat_model = quantizer.quantize()

The mAP of QAT is dropped to zero. So, I think the problem comes from here.

Thanks for your response @zk1998, I think I find the cause, I loaded the PTQ rewritten model of your step 1 and validate, it preserves the same mAP of the original model. But when I run
quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
                config={'asymmetric': True, 'per_tensor': True, 'force_rewrite': False, 'rewrite_graph': False})
qat_model = quantizer.quantize()

The mAP of QAT is dropped to zero. So, I think the problem comes from here.

There is no 'force_rewrite': False but 'force_overwrite': False and you should also set 'rewrite_graph': True.

I know but it will delete my edits
        if self.training:
            return [fake_dequant_1_0, fake_dequant_1_1, fake_dequant_1_2]
        else:
            return [fake_dequant_0_0, fake_dequant_0_1], [fake_dequant_1_0, fake_dequant_1_1, fake_dequant_1_2]

if I set 'rewrite_graph': True

@hoangtv2000  It will not delete your edits.if you pass 'force_overwrite': False.

Wow that was strange, here is my script and it breaks my model. I will try your solution, thank you for helping me so much.
    from TinyNeuralNet.out.detectionmodel_q import QDetectionModel
    model = QDetectionModel()
    dummy_input = torch.rand(1, 3, 320, 320)
    model.load_state_dict(torch.load('TinyNeuralNet/out/detectionmodel_q.pth'))
    model.to(device=device)

    quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
            config={'asymmetric': True, 'per_tensor': True, 'force_rewrite': False, 'rewrite_graph': True})
    qat_model = quantizer.quantize()

    qat_model.to(device=device)

No, you didn't follow our usage. Come on.

    from TinyNeuralNet.out.detectionmodel_q import QDetectionModel
    model = QDetectionModel()
    dummy_input = torch.rand(1, 3, 320, 320)
    model.load_state_dict(torch.load('TinyNeuralNet/out/detectionmodel_q.pth'))
    model.to(device=device)

    quantizer = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
            config={'asymmetric': True, 'per_tensor': True, 'force_rewrite': False, 'rewrite_graph': True})
    qat_model = quantizer.quantize()

    qat_model.to(device=device)

If you pass in the rewritten model as shown in this piece of code, then you should pass "rewrite_graph": False.  Does it work btw?

I saved the rewritten model and load it with QATQuantizer() with the setting 'rewrite_graph': False, 'force_overwrite': False. But It takes me 20 epochs to achieve 0.04 mAPs 😃. Although the difference output between the rewritten and the original one is zero. I really don't know what happened here. Maybe the optimization method is used in QAT example is not correct for my case.

I was so silly due to not pay attention to answer, sorry for that.
At the first time I rewrite the model with PostQuantizer and save, then run the rewritten model with QATQuantizer with the setting 'asymmetric': True, 'per_tensor': True, 'force_overwrite': False, 'rewrite_graph': False and it causes huge losses. Even I set no_catch() in the ultralytics source code and seperate the rewritten code for training/evaluation.
Btw, if I calibrate the model before training, I got AssertionError: min nan should be less than max nan error at the input fake quantization node.
      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size
Traceback (most recent call last):
  File "TinyNeuralNet/yolov8n_quantization.py", line 399, in <module>
    qat(args)
  File "TinyNeuralNet/yolov8n_quantization.py", line 365, in qat
    qat_model = train(args, qat_model, optimizer, scheduler, criterion, train_loader,
  File "TinyNeuralNet/yolov8n_quantization.py", line 212, in train
    output = model(batch['img'])
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1501, in _call_impl
    return forward_call(*args, **kwargs)
  File "/data/hoangtv23/workspace_AIOT/model_compression_flow/TinyNeuralNet/out/detectionmodel_q.py", line 190, in forward
    model_0_conv = self.model_0_conv(fake_quant_0)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1538, in _call_impl
    result = forward_call(*args, **kwargs)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/nn/intrinsic/qat/modules/conv_fused.py", line 224, in forward
    return self._forward(input)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/nn/intrinsic/qat/modules/conv_fused.py", line 101, in _forward
    return self._forward_approximate(input)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/nn/intrinsic/qat/modules/conv_fused.py", line 114, in _forward_approximate
    scaled_weight = self.weight_fake_quant(self.weight * scale_factor.reshape(weight_shape))
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/nn/modules/module.py", line 1501, in _call_impl
    return forward_call(*args, **kwargs)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/quantization/fake_quantize.py", line 194, in forward
    _scale, _zero_point = self.calculate_qparams()
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/quantization/fake_quantize.py", line 189, in calculate_qparams
    return self.activation_post_process.calculate_qparams()
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/quantization/observer.py", line 508, in calculate_qparams
    return self._calculate_qparams(self.min_val, self.max_val)
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/quantization/observer.py", line 315, in _calculate_qparams
    if not check_min_max_valid(min_val, max_val):
  File "/home/vht/anaconda3/envs/perception/lib/python3.8/site-packages/torch/ao/quantization/utils.py", line 317, in check_min_max_valid
    assert min_val <= max_val, "min {} should be less than max {}".format(
AssertionError: min nan should be less than max nan

So, how about the fake-quantized qat-prepared model's mAPs before training which I mentioned at https://github.com/alibaba/TinyNeuralNetwork/issues/337#issuecomment-2205330949 step3

Hi @zk1998,
Here are some of my experiments,
(0) Validate original model
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 22/22 [00:24<00:00,  1.13s/it]
                   all       2692      10774       0.77      0.564      0.652       0.42
                   all       2692      10774       0.77      0.564      0.652

(1) PostQuantize to get rewritten model => Load rewritten model and Validate model performace
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 22/22 [00:24<00:00,  1.10s/it]
                   all       2692      10774       0.77      0.564      0.652       0.42
                   all       2692      10774       0.77      0.564      0.652       0.42

(2) PostQuantize to get rewritten model => Load rewritten model and perform QATQuantizer => Validate model performace
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 22/22 [01:44<00:00,  4.76s/it]
                   all       2692      10774          0          0          0          0
                   all       2692      10774          0          0          0          0

(3) PostQuantize to get rewritten model => Load rewritten model and perform QATQuantizer => Calibrate by training set => Validate model performace
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 22/22 [02:04<00:00,  5.67s/it]
                   all       2692      10774     0.0227       0.05    0.00356    0.00121
                   all       2692      10774     0.0227       0.05    0.00356    0.00121

Hi @hoangtv2000 . It seems that the quantization error is unacceptable, and QAT will degrade to training from scratch. I am trying to reproduce the YOLOv8 detection quantization experiment, which will take some time.

Yeah, I tried the quantization with PostQuantizer() and it got the same behavior with QAT quantization method. The mAPs after quantized are reduced to zero. I checked whether the QAT or PTQ ready model lost pretrained weights, but it did not.
with model_tracer():
    model = torch.load(args.model_pretrained_dir).cpu()
    quantizer = PostQuantizer(model, torch.rand(1, 3, 320, 320), work_dir='TinyNeuralNet/out')
    ptq_model = quantizer.quantize()

# Do calibration/inference to get quantization param
ptq_model.eval()
ptq_model.apply(torch_q.disable_fake_quant)
ptq_model.apply(torch_q.enable_observer)
context.max_iteration = 100
calibrate(ptq_model, context)

# Disable observer and enable fake quantization to validate model with quantization error
ptq_model.apply(torch_q.disable_observer)
ptq_model.apply(torch_q.enable_fake_quant)
metrics = validator(model=deepcopy(ptq_model))

And the mAPs come to nearly zero.
             Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100%|██████████| 22/22 [01:38<00:00,  4.49s/it]
               all       2692      10774    0.00177      0.127      0.001   0.000334

@hoangtv2000 Would you please organize the data and the code you used to perform training? I think an end-to-end example helps here because we are new to the YOLO framework. There's just too much info in this thread and we may get distracted by something unrelated.

I tested the dummy input/output and evaluation mAPs with the rewritten model and the original one. The output tensors of them when tested on dummy input are the same. But the mAPs are so difference, so I think the problem comes from the conflict of training/evaluation code and the rewritten model. I will further investigate the cause and solution then notify you later.

Update, the rewritten model is still perserve accuracy, but the qat ready model is changed. So the problem comes from the  QATQuantizer.quantize() function.
from TinyNeuralNet.out.detectionmodel_q import QDetectionModel
model = QDetectionModel()
model.load_state_dict(torch.load('TinyNeuralNet/out/detectionmodel_q.pth'))
model.to(device=device)

metrics = validator(model=deepcopy(model)) # mAP = 0.65, not changed.

quantizer  = QATQuantizer(model, dummy_input, work_dir='TinyNeuralNet/out',
            config={'asymmetric': True, 'per_tensor': True, 'force_overwrite': False, 'rewrite_graph': False})
qat_model = quantizer.quantize()
qat_model.to(device=device)

metrics = validator(model=deepcopy(qat_model )) # mAP = 0.0286, dropped from scratch

I had a new experiment on yolov5 and its mAP50 is also dropped from 0.7 to 0.0.

@hoangtv2000 Would you please organize the data and the code you used to perform training? I think an end-to-end example helps here because we are new to the YOLO framework. There's just too much info in this thread and we may get distracted by something unrelated.

All of the code is used to train and evaluate YOLOv8 is come from offical repo of ultralytics and the code for YOLOv5 can be founded here.
I just took their pretrained model, loaded it and tested on your QAT engine.

It will take some time for us to replicate the issue since we are not familiar with yolo pipeline. Let's just not talk about something unrelated here and focus on one problem because there are already plenty of them here. Thanks for your patience and understanding.

Hi @hoangtv2000 , I replicate the quantization pipeline in COCO8 on yolov8n.pt using :

Ultralytics YOLOv8.2.48
Python-3.8.16
torch-1.13.1

And the script is modified from your code https://github.com/alibaba/TinyNeuralNetwork/issues/337#issuecomment-2199675183. Here is my example script, and the quantization error is acceptable.
import sys, os, argparse, random

sys.path.append(os.getcwd())
RANK = int(os.getenv("RANK", -1))

import torch
import torch.nn as nn
import torch.optim as optim
import torch.quantization as torch_q

from ultralytics import YOLO
from ultralytics.utils.loss import v8DetectionLoss

from tinynn.util.train_util import AverageMeter, DLContext, train, get_device
from tinynn.graph.quantization.quantizer import QATQuantizer, PostQuantizer
from tinynn.graph.tracer import model_tracer

from ultralytics.cfg import get_cfg
from ultralytics.utils import *
from ultralytics.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_KEYS, LOGGER, NUM_THREADS, RANK, ROOT,
                                    callbacks, is_git_dir, yaml_load)
# from torchsummary import summary
from copy import copy, deepcopy
# from ultralytics import v8
import ultralytics.models.yolo as v8
from ultralytics.utils.checks import check_imgsz
from ultralytics.data.utils import check_det_dataset
from ultralytics.data import build_dataloader
from ultralytics.utils.torch_utils import de_parallel, torch_distributed_zero_first
from ultralytics.data.dataset import YOLODataset
from ultralytics.utils.files import increment_path
from ultralytics.utils.torch_utils import (
    EarlyStopping,
    de_parallel,
    init_seeds,
    one_cycle,
    select_device,
    strip_optimizer,
)

def get_default_config(DEFAULT_CFG_PATH="ultralytics/cfg/default.yaml"):
    # Default configuration
    DEFAULT_CFG_DICT = yaml_load(DEFAULT_CFG_PATH)
    for k, v in DEFAULT_CFG_DICT.items():
        if isinstance(v, str) and v.lower() == "none":
            DEFAULT_CFG_DICT[k] = None
    DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys()
    DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT)
    return DEFAULT_CFG

"""Build Dataset
"""
def get_dataloader(model, dataset_path, cfg, data, batch_size=16, rank=0, mode='train'):
    def build_dataset(model, img_path, mode='train', batch=None):
        gs = max(int(de_parallel(model).stride.max() if model else 0), 32)
        return YOLODataset(
            img_path=img_path,
            imgsz=640,
            batch_size=batch,
            augment=False,  # augmentation
            hyp=cfg,  # TODO: probably add a get_hyps_from_cfg function
            rect=False,  # rectangular batches
            cache=None,
            single_cls=False,
            stride=gs,
            pad=0.0 if mode == 'train' else 0.5,
            prefix=colorstr(f'{mode}: '),
            # use_segments=False,
            # use_keypoints=False,
            classes=None,
            data=data,
            fraction=1.0)

    assert mode in ['train', 'val']
    with torch_distributed_zero_first(rank):  # init dataset *.cache only once if DDP
        dataset = build_dataset(model, dataset_path, mode, batch_size)
    shuffle = mode == 'train'
    if getattr(dataset, 'rect', False) and shuffle:
        LOGGER.warning("WARNING ⚠ 'rect=True' is incompatible with DataLoader shuffle, setting shuffle=False")
        shuffle = False
    workers = 2 if mode == 'train' else 2
    return build_dataloader(dataset, batch_size, workers, shuffle, rank)

def get_validator(batch_size, saved_experiment_dir):
    cb = callbacks.get_default_callbacks()
    overrides = {'imgsz': 640, 'batch': batch_size, 'conf': 0.25, 'iou': 0.6, 'device': 'cuda:0'}
    overrides['rect'] = True
    overrides['mode'] = 'val'
    overrides.update(overrides)
    args = get_cfg(cfg=DEFAULT_CFG, overrides=overrides)
    args.data = 'sparseml_quantization/data.yaml'
    args.task = 'detect'
    args.rect = False
    args.imgsz = check_imgsz(640, max_dim=1)
    return v8.detect.DetectionValidator(save_dir=saved_experiment_dir, args=args, _callbacks=cb)

def setup_seed(seed, cuda_deterministic=True):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)
    os.environ["PYTHONHASHSEED"] = str(seed)
    if cuda_deterministic:  # slower, more reproducible
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False
    else:  # faster, less reproducible
        torch.backends.cudnn.deterministic = False
        torch.backends.cudnn.benchmark = True

def post_tnn(args):
    raw_model = torch.load('yolov8n.pt')

    dataset_yaml_path = '/data/zhouye/0603/TinyNeuralNetwork/examples/quantization/yolo/coco8.yml'
    cfg = get_default_config(DEFAULT_CFG_PATH='/data/miniconda3/envs/torch113/lib/python3.8/site-packages/ultralytics/cfg/default.yaml')
    cfg.data = dataset_yaml_path
    data = check_det_dataset(dataset_yaml_path)
    trainset, testset = data['train'], data.get('val') or data.get('test')
    calib_loader = get_dataloader(raw_model['model'], trainset, cfg, data, args.batch_size, RANK, "val")
    device = get_device()
    context = DLContext()
    context.device = device
    context.train_loader = calib_loader
    test_loader = get_dataloader(raw_model['model'], testset, cfg, data, args.batch_size, RANK, "val")
    saved_experiment_dir = "out/exp_yolov8_og_"
    saved_experiment_dir = increment_path(Path(saved_experiment_dir))
    validator = v8.detect.DetectionValidator(test_loader, save_dir=saved_experiment_dir, args=copy(cfg))
    calib_dir_tmp = "out/exp_yolov8_calib_tmp_"
    calib_dir_tmp = increment_path(Path(calib_dir_tmp))
    calibrator = v8.detect.DetectionValidator(calib_loader, save_dir=calib_dir_tmp, args=copy(cfg))
    calibrator.training = False

    model = raw_model['model'].float()
    print('origin model validating...')
    validator(model=deepcopy(model))

    dummy_input = torch.rand((1, 3, 640, 640))

    with model_tracer():
        # Firstly, you should trace model in eval mode,
        # then manually modify the traced model to accommodate the differences between evaluation and training modes.
        # quantizer = PostQuantizer(
        #     model, dummy_input, work_dir='out'
        # )
        # exit()

        # Once you generate traced model and modified the output and input, use the code below to set qat quantizer.
        from out.detectionmodel_q import QDetectionModel
        rewrite_model = QDetectionModel()
        rewrite_model.load_state_dict(torch.load('out/detectionmodel_q.pth'))
        quantizer = QATQuantizer(rewrite_model, dummy_input, work_dir='out', config={'force_rewrite': False, "rewrite_graph": False,})

        ptq_model = quantizer.quantize()

    # add attr to fit AutoBackend when validating using ultralytics.
    def ptq_fuse(self, verbose=None):
        return self
    import types
    ptq_model.fuse = types.MethodType(ptq_fuse, ptq_model)
    ptq_model.stride = model.stride
    ptq_model.names = model.names
    ptq_model.nc = model.nc

    # Use ultralytics's validator to do calibrating(or training if use qat),
    # !!!!you must keep the img-preprocessing is the same as validating (keep in mind when trianing).
    ptq_model.apply(torch.quantization.disable_fake_quant)
    ptq_model.apply(torch.quantization.enable_observer)
    ptq_model.eval()
    calibrator.args.imgsz = 640
    bar = TQDM(calib_loader, desc="calibrating", total=len(calib_loader))
    # we do one inference to simulate qat init state
    for batch_i, batch in enumerate(bar):
        batch = calibrator.preprocess(batch)
        ptq_model(batch["img"])
        break

    # Disable observer and enable fake quantization to validate model with quantization error
    ptq_model = deepcopy(ptq_model)
    ptq_model = ptq_model.to(device)
    dummy_input = dummy_input.to(device)
    ptq_model.apply(torch.quantization.disable_observer)
    ptq_model.apply(torch.quantization.enable_fake_quant)
    ptq_model(dummy_input)
    validator.args.imgsz = 640

    # Remove the postprocess(DFL block) to improve acc which hurts quantized model's mAPs a lot.
    unq_flag = False
    print('here are unquantized module')
    for name, module in ptq_model.named_modules():
        if 'fake_dequant_inner_0_0_0' in name:
            unq_flag = True

        if (
            # the decoding of boxes and class from multiple-level feature maps is hard to quantize
            # btw, yolov8 trainer will not train this block, so it should use float for inference.
            (unq_flag and  name.split('_')[-1].isdigit() and int(name.split('_')[-1]) >= 22)
        ):
            module.apply(torch.quantization.disable_fake_quant)
            print(name)

    print('validating fake-quantized model...')
    quant_result_dir = "out/exp_yolov8_quant"
    quant_result_dir = increment_path(Path(quant_result_dir))
    validator = v8.detect.DetectionValidator(test_loader, save_dir=quant_result_dir, args=copy(cfg))
    validator(model=deepcopy(ptq_model))

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--workers', type=int, default=4)
    parser.add_argument('--num-epochs', type=int, default=50)
    parser.add_argument('--batch-size', type=int, default=1)
    parser.add_argument('--base-lr', type=float, default=1e-1)
    parser.add_argument('--weight-decay', type=float, default=1e-6)
    parser.add_argument('--model-pretrained-dir', type=str,
                        default='oto_pruning/cache/version_split_bbox_conf/DetectionModel_compressed.pt')
    setup_seed(seed=2048, cuda_deterministic=False)
    args = parser.parse_args()
    post_tnn(args)

Something you must pay attention:

Ultralytics's validator, predictor and trainer are overly encapsulated for ease of use, but in our work, we need to modify the model definition, requiring us to get a flatten model definition(out/xx.py). At this point, some APIs and model attributes from ultralytics's may become invalid. Careful handling is needed to ensure alignment (or you may need to rewrite all the validation/training code).
The decoding of boxes and class from multiple-level feature maps is hard to quantize, so you may need to move it to cpu to do float-computation. The other parts can be produced an Integer-arithmetic-only Inference model.
I have tested the quantization on coco8 using yolov8n.pt, the origin mAPs is:

the qat init(with quantzation error) model's mAPs is:

So I believe YOLOv8 can achieve full INT8 quantization, whether using PTQ or QAT.
You can check the script to get more details.

Hi @zk1998,
I really did it, thank you so much!!!


Get headers from request

Some API services require header signing. The client provides no easy way to determine what the headers will ultimately look like as they are dynamically generated on execute().
Please provide a way to view what headers will be generated if execute() were called next.

HttpExecuteInterceptor does exactly that.
You could register an interceptor by HttpRequest#setInterceptor().

Thanks, I'll give this a try. Closing this for now.

Reopening, headers are unpopulated. Looks like the headers are generated after the intercept is called.

If you set Logging level to CONFIG for com.google.api.client.http.HttpTransport its going to log all headers along with curl request. This will help to see all the headers. I am closing this issue for now. Please reopen this issue if this doesnt help.


Add Threefish/Skein implementation

Developed by Bruce Schneier et al.
Threefish  is a fast, tweakable block cipher.
Skein  is a secure hash function which uses Threefish.
The design specification for the Threefish cipher can be found in the design specification for Skein.

I'm working on this and should have a pull request for Threefish out in a day or two.


ZeroCam

Do we know if the ZeroCam is compatible with the seedsigner? They're both "5MP 1080p" so I'm optimistic. Wondering what the difference is between that and the OV5647 version, and whether someone's build an enclosure for this model.

This article in German lists the ZeroCam so I'm guessing it works.

@SeedSigner himself (herself?) has provided a prototype design for a case for the ZeroCam. I can try and print this once I finish building the hardware.

From a software perspective, yes. This is confirmed by Seedsigner within the community Telegram group as recently as this month (see screenshot) as well as by various contributors.

From a hardware perspective, it depends on which enclosure you're going for. Not all 3D printable enclosure designs fit with each camera model:
https://github.com/SeedSigner/seedsigner/tree/dev/enclosures

Thank you @bitcoinprecept for answering the question!


wineWow64Packages.unstableFull: 9.12 -> 9.13

Automatic update generated by nixpkgs-update tools. This update was made based on information from passthru.updateScript.
meta.description for wineWow64Packages.unstableFull is: Open Source implementation of the Windows API on top of X, OpenGL, and Unix
meta.homepage for wineWow64Packages.unstableFull is: https://www.winehq.org/
Updates performed

Ran passthru.UpdateScript

To inspect upstream changes
Impact
Checks done

built on NixOS
The tests defined in passthru.tests, if any, passed
found 9.13 with grep in /nix/store/1vjv117xygnakzmr2ss2q0qrl5csan4a-wine-wow64-9.13
found 9.13 in filename of file in /nix/store/1vjv117xygnakzmr2ss2q0qrl5csan4a-wine-wow64-9.13

Rebuild report (if merged into master) (click to expand)

23 total rebuild path(s)

23 package rebuild(s)

First fifty rebuilds by attrpath

grapejuice
pipelight
vinegar
wine-staging
wine64Packages.staging
wine64Packages.stagingFull
wine64Packages.unstable
wine64Packages.unstableFull
winePackages.staging
winePackages.stagingFull
winePackages.unstable
winePackages.unstableFull
wineWow64Packages.staging
wineWow64Packages.stagingFull
wineWow64Packages.unstable
wineWow64Packages.unstableFull
wineWowPackages.staging
wineWowPackages.stagingFull
wineWowPackages.unstable
wineWowPackages.unstableFull
yabridge
yabridgectl

Instructions to test this update (click to expand)

Either download from Cachix:
nix-store -r /nix/store/1vjv117xygnakzmr2ss2q0qrl5csan4a-wine-wow64-9.13 \
  --option binary-caches 'https://cache.nixos.org/ https://nix-community.cachix.org/' \
  --option trusted-public-keys '
  nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=
  cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
  '

(The Cachix cache is only trusted for this store-path realization.)
For the Cachix download to work, your user must be in the trusted-users list or you can use sudo since root is effectively trusted.
Or, build yourself:
nix-build -A wineWow64Packages.unstableFull https://github.com/r-ryantm/nixpkgs/archive/974a2e0577aaed1ab81d9c2d5459616256d032b0.tar.gz

Or:
nix build github:r-ryantm/nixpkgs/974a2e0577aaed1ab81d9c2d5459616256d032b0#wineWow64Packages.unstableFull

After you've downloaded or built it, look at the files and if there are any, run the binaries:
ls -la /nix/store/1vjv117xygnakzmr2ss2q0qrl5csan4a-wine-wow64-9.13
ls -la /nix/store/1vjv117xygnakzmr2ss2q0qrl5csan4a-wine-wow64-9.13/bin

Pre-merge build results
We have automatically built all packages that will get rebuilt due to
this change.
This gives evidence on whether the upgrade will break dependent packages.
Note sometimes packages show up as failed to build independent of the
change, simply because they are already broken on the target branch.
Result of nixpkgs-review run on x86_64-linux 1

11 packages failed to build:

pipelight
wine-staging (winePackages.stagingFull)
wine64Packages.staging
wine64Packages.stagingFull
winePackages.staging
wineWow64Packages.staging
wineWow64Packages.stagingFull
wineWowPackages.staging
wineWowPackages.stagingFull
yabridge
yabridgectl

11 packages built:

grapejuice
grapejuice.dist
vinegar
wine64Packages.unstable
wine64Packages.unstableFull
winePackages.unstable
winePackages.unstableFull
wineWow64Packages.unstable
wineWow64Packages.unstableFull
wineWowPackages.unstable
wineWowPackages.unstableFull

Maintainer pings
cc @avnik @7c6f434c @bendlas @jmc-figueira @reckenrode for testing.

This doesn’t include wine-staging, but wine-staging 9.13 fails to build for me.
1 out of 4 hunks FAILED -- saving rejects to file dlls/advapi32/tests/security.c.rej
[PATCH] ERR: Textual patch did not apply, aborting.
Failed to apply patch server-Stored_ACLs/0004-server-Temporarily-store-the-full-security-descripto.patch

Hmm weird it doesn't look like we have a downstream patch that should conflict over this file…

Wine 9.14 is out. wine-staging has the same problem. However, I did notice something strange. If I nix build .#legacyPackages.x86_64-{darwin,linux}.wine64Packages.staging on the updated branch, it fails in the same place. If I run the build manually, the patch applies successfully. It makes no sense.

@reckenrode it's because you have git in PATH, and the gitapply.sh script will use git apply if it's available:
 111   │ # Redirect to git apply if available
 112   │ if [ "$nogit" -eq 0 ] && command -v git >/dev/null 2>&1; then
 113   │     exec git apply --whitespace=nowarn "$@"
 114   │     exit 1
 115   │ fi

When running nix build there's no git command in patchPhase as it's not in nativeBuildInputs, so the script falls back to using the regular patch command, which apparently has some problems with these patches. Adding gitMinimal to nativeBuildInputs fixes this.


[disk] exclude rootfs by default

Note: Please remember to review the Datadog Contribution Guidelines
if you have not yet done so.
What does this PR do?
Excludes rootfs by default. Fix for https://github.com/DataDog/dd-agent/issues/3081
Motivation
Issue created in dd-agent repo, reported again to support.

Just a general comment: technically this a BC breaking change, as such even if it makes sense to exclude rootfs filesystems we should be careful about excluding them by default.
Before merging this, we should double-check that these metrics are not actively used by customers on monitors (and dashboards)

@olivielpeau Leaving as is to avoid BC, but adding a note about rootfs in the yaml.


Fix issue templates

Fixes issues from #24585

Thank you for your contribution! Follow this checklist to help us incorporate your contribution quickly and easily:

[ ] Mention the appropriate issue in your description (for example: addresses #123), if applicable. This will automatically add a link to the pull request in the issue. If you would like the issue to automatically close on merging the pull request, comment fixes #<ISSUE NUMBER> instead.
[ ] Update CHANGES.md with noteworthy changes.
[ ] If this contribution is large, please file an Apache Individual Contributor License Agreement.

See the Contributor Guide for more tips on how to make review process smoother.
To check the build health, please visit https://github.com/apache/beam/blob/master/.test-infra/BUILD_STATUS.md
GitHub Actions Tests Status (on master branch)

See CI.md for more information about GitHub Actions CI.

Example of this working - https://github.com/damccorm/beam/issues/158 and https://github.com/damccorm/beam/issues/new/choose


FEAT: add a pathTemplate option to cope with different uri path schemes

Ref: https://github.com/SpoonX/aurelia-api/issues/176#issuecomment-256657132
Proposal
Add a pathTemplate property to Rest with a default of '${resource}/${id}', that is used to build the actual url to fetch. The property must be added at the end of the ctor as optional.
Please note this isn't an ES6 template string, the ${resource} and ${id} will be simply substituted with the first two parameters of various Rest methods (either resource and id, or resource and criteria).
Also add a new setDefaultPathTemplate() method to the config, that must be called prior to registerEndpoint to set a custom default for all endpoints (in a field like defaultPathTemplate, passed as the last parameter to the Rest ctor).
Things to consider:

the join method in aurelia-path will not be used anymore, and it is simply a user's responsibility to pass sensible parameters with proper slashes. No assumptions could be made on the contents of the pathTemplate property.
the hasSlash hack must be removed for this to work properly (already logged as https://github.com/SpoonX/aurelia-api/issues/146)

Benefits
One could use that property to talk to an API that expects resource paths in other formats, like OData style:
'${resource}(${id})' -> path(id)

After more thinking about it, I'd add a restOptions parameter to registerEndpoint, that the user could use to change the pathTemplate of that specific Rest instance (and the useTraditionalUriTemplates flag of my other PR).
It's not so uncommon to have different APIs for different micro-services, that are baked my completely different technologies, so it makes sense having the ability to tweak the settings on an individual base..

yeah, needs to be allways on endpoint basis. eg the authentication provider could be completely different

Don't know if the removal of hard-coded join and the slash hack could be a potential BC for consumers..
What do u think?

i don't as such care to much about the slash hack. it should be solved on serverside. but making a 4.0 would be fine

add a Date object parsing option

add a Date object parsing option

What do you mean?

aurelia-path converts criteria as {date: new Date} to "" instead of eg date=1.1.1970

@doktordirk ah ok, but it's out of this issue's scope.. and it's not an easy one either
Maybe open another issue if you wish, but Date conversion is a pretty subtle task in JS as you surely know. IMHO it's better to stick with that conversion pre-api call, when one can use mature libraries like momentjs and it's companion moment-timezone (that's what I do in every project, never touch a date conversion without my good old friend moment ;)

PathTemplate via restOptions would be neat.

@zeko77 It would It's now resource based, but making that configurable is absolutely a cool idea. PRs are welcome!

Closing this for now. If this is still relevant, feel free to reopen the issue.
Note: this is a copy-paste comment to clean up the issues. It's not personal, and I didn't review the issue before posting this. They're all outdated and I need a way to figure out what's still relevant.
Thank you for understanding :)


Enclose each step of Repairnator in a timeout

We got a lot of stucked docker containers because of non responding mvn commands. I think we should actually put a timeout for each step of Repairnator process.

It seems a good idea. How would we choose the timeout for each step? I mean, each step differs (maybe a lot) regarding the time of execution, e.g. clone can be way faster than test, thus we should probably put a timeout for test greater than for clone. Maybe we could define, for each step, a timeout based on previous experiments, e.g. for step clone the average (or median) execution time is x, then we get this x to be the timeout for step clone? WDYT?

I was actually thinking about 3 different mechanism:

for all steps using maven goal, to use the same mechanism as Travis: 10 minutes without log = timeout,
for repair steps, to use continue using our current timeouts,
for other steps, to define an absolute timeout (and yeah, we can use your idea there)

This sounds a good plan.

For the record, step one might be done for free using changes proposed in: https://github.com/apache/maven-invoker/pull/1

Actually I think I won't do step 3: each time the build got stuck it was because of Maven goal, so I proposed to already close this issue. WDYT @fermadeiral ?

each time the build got stuck it was because of Maven goal

In this case, it's not necessary by now to put timeout in the other steps. I agree about closing this issue. If we have problems in the future because of the other steps, then we put timeout for them.


Auto-zoom effect

Is there a way to emblement an auto-zoom effect upon transition between scenes along with the current (fade-in) effect where the current scene is being zoomed into the next scene while the fade-in effect takes place?

Just figured a simple loop to solve it using lookTo. Thank you.

hey! can you share the solution?


Move appKeepers struct to a different package

Closes: #1319
What is the purpose of the change

Move appKeepers struct to a different package

Brief change log

Create new package called keepers at app/keepers,
Move logic from app/keepers.go to new module

Testing and Verifying

This change is a trivial rework / code cleanup without any test coverage.

Documentation and Release Note

Does this pull request introduce a new feature or user-facing behavior changes? no
Is a relevant changelog entry added to the Unreleased section in CHANGELOG.md? no
How is the feature or change documented? not applicable

Thanks for making this!

Codecov Report

Merging #1327 (67fb1be) into main (039f686) will not change coverage.
The diff coverage is n/a.

@@           Coverage Diff           @@
##             main    #1327   +/-   ##
=======================================
  Coverage   19.53%   19.53%
=======================================
  Files         200      200
  Lines       27532    27532
=======================================
  Hits         5377     5377
  Misses      21153    21153
  Partials     1002     1002

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 039f686...67fb1be. Read the comment docs.


Merge graphics and forms from bitbucket

There are unmerged commits in bitbucket that need to be merged with adjustments in how user_id are managed by keycloack.
Tasks:
1 - Analysis to explore differences between isa-robot and bitbucket repos ( new graphics and some basic forms to handle multi-company and others that may not be necessary to merge: for example, users forms that now are handled by kcloak).
2 - To code necessary adjustments in the back and front end.
Source repositories.
https://bitbucket.org/portalqualis/vigilancia-frontend/
https://bitbucket.org/portalqualis/vigilancia-backend/

Deve ser feito DOJO de 2 horas prévia.


How to force every version of IE (including IE11) to be updated to another browser

In the doc, I've seen the lowerThan property that allow me to detect if the IE version is below 11, but is there any solution that allow me to block the IE11 also ?

Oops, I have'nt seen #198 before sorry for duplicate !


not work

Heimdall is work for base64 not RSA?

Not sure what you mean by this question, Heimdall uses a symmetric key to actually encrypt the text (as RSA has a length limit on how much data it can encrypt), then encrypts the symmetric key with the RSA key. This is also documented in the README

Marking as closed, nothing I can really help with here.

thanks, ok now

thanks ,it is work now


anyone getting files OK?

I think I have latest build yet I get errors trying any id on YT, it was fine until sometime mid Dec 2020 then just stopped working.
error parsing signature tokensfail logged in ttyhist, status 1

Sorry that last bit "fail logged in ttyhist, status 1" is my command history system
the actual error output is just
error parsing signature tokens

Sorry that last bit "fail logged in ttyhist, status 1" is my command history system
the actual error output is just
error parsing signature tokens

hi @cw1nte
I have run the integration tests, all tests are green. Could you provide some information like video id and your  build version?

hi @cw1nte
I have run the integration tests, all tests are green. Could you provide some information like video id and your  build version?

Hi Julian, how do I get a build version for you?
If I run ./youtubedr -v
then I just get empty fields and the go version...
I tried /youtubedr MQxdk7QOM28

Hi Julian, how do I get a build version for you?
If I run ./youtubedr -v
then I just get empty fields and the go version...
I tried /youtubedr MQxdk7QOM28

Hi Julian, how do I get a build version for you?
If I run ./youtubedr -v
then I just get empty fields and the go version...
I tried ./youtubedr MQxdk7QOM28

Hi Julian, how do I get a build version for you?
If I run ./youtubedr -v
then I just get empty fields and the go version...
 You just find the issue for version command. I will open issue for it.
Do you try  " ./youtubedr download MQxdk7QOM28"?  After  a certain version, the commands are changed.
without download command

with download command

I suppose you are using old version, maybe download the newest version again can solve the issue.  If any problem, please let us know.

hell cw1nte,
great ! You just find the issue for version command. I will open issue for it.
Do you try  " ./youtubedr download MQxdk7QOM28"?  After  a certain version, the commands are changed.
without download command

with download command

I suppose you are using old version, maybe download the newest version again can solve the issue.  If any problem, please let us know.

Hi,
I have tried to update latest and build here with go, there may be an ssh certificate problem stopping me get updates... Not had time to dig into that one yet.
Last tried 13 Jan:
$ go get -u github.com/kkdai/cmd/youtube
cd .; git clone -- https://github.com/kkdai/cmd /Users/colinwin/go/src/github.com/kkdai/cmd
Cloning into '/Users/colinwin/go/src/github.com/kkdai/cmd'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
package github.com/kkdai/cmd/youtube: exit status 128
I have looked briefly into work arounds for the username issue without result.
But the old version WAS working OK in early December, last. Looking at the github files I could not really find any code changes since then that might explain - and that was what I was really interested in for my own project!
I for sure have the version without download command.
$ ./youtubedr download MQxdk7QOM28
extractVideoID failed: the video id must be at least 10 characters long
$ ./youtubedr version
extractVideoID failed: the video id must be at least 10 characters long
./youtubedr -version
Version:
Commit:
Date:
Go Version:  go1.14.2

Hi,
I have tried to update latest and build here with go, there may be an ssh certificate problem stopping me get updates... Not had time to dig into that one yet.
Last tried 13 Jan:
$ go get -u github.com/kkdai/cmd/youtube
cd .; git clone -- https://github.com/kkdai/cmd /Users/colinwin/go/src/github.com/kkdai/cmd
Cloning into '/Users/colinwin/go/src/github.com/kkdai/cmd'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
package github.com/kkdai/cmd/youtube: exit status 128
I have looked briefly into work arounds for the username issue without result.
But the old version WAS working OK in early December, last. Looking at the github files I could not really find any code changes since then that might explain - and that was what I was really interested in for my own project!
I for sure have the version without download command.
$ ./youtubedr download MQxdk7QOM28
extractVideoID failed: the video id must be at least 10 characters long
$ ./youtubedr version
extractVideoID failed: the video id must be at least 10 characters long
./youtubedr -version
Version:
Commit:
Date:
Go Version:  go1.14.2

Oops, can't edit that post but this was the pasted text..
`$ go get -u github.com/kkdai/cmd/youtube
cd .; git clone -- https://github.com/kkdai/cmd /Users/colinwin/go/src/github.com/kkdai/cmd
Cloning into '/Users/colinwin/go/src/github.com/kkdai/cmd'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
package github.com/kkdai/cmd/youtube: exit status 128
fail logged in history log DB, status 1
`

Oops, can't edit that post but this was the pasted text..
`$ go get -u github.com/kkdai/cmd/youtube
cd .; git clone -- https://github.com/kkdai/cmd /Users/colinwin/go/src/github.com/kkdai/cmd
Cloning into '/Users/colinwin/go/src/github.com/kkdai/cmd'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
package github.com/kkdai/cmd/youtube: exit status 128
fail logged in history log DB, status 1
`

@cw1nte  could you try "go get -u github.com/kkdai/youtube/v2/cmd/youtubedr" ?

@cw1nte  could you try "go get -u github.com/kkdai/youtube/v2/cmd/youtubedr" ?

Btw, I'm getting error for this id PbP0_yYXcHU, could someone check ?
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x12e78b9]

goroutine 1 [running]:
github.com/kkdai/youtube/v2.(*Client).GetStreamURLContext(0xc00027f280, 0x145a0c0, 0xc000016178, 0xc000452100, 0x0, 0xc0004aa000, 0x335, 0x0, 0x0)
	/Users/Hai/Golang/pkg/mod/github.com/kkdai/youtube/v2@v2.4.1/client.go:84 +0x29
github.com/kkdai/youtube/v2.(*Client).GetStreamURL(...)
	/Users/Hai/Golang/pkg/mod/github.com/kkdai/youtube/v2@v2.4.1/client.go:79

@greentornado
I tried with the latest version 2.4.1 and I am not getting this error. I tested with this command:
youtubedr download -q 135 PbP0_yYXcHU

and sometimes I am getting a unexpected status code: 204 error and sometimes it downloads a 5 seconds video. I think it is because this is a live stream URL. Can these be downloaded?

got same like @john-black-3k , it seems like  live stream issue, need to check again  when the live stream is finished

any update?

I got some signature error
2021/02/24 11:48:47 GET https://youtube.com/get_video_info?video_id=_EVCman5puE&eurl=https://youtube.googleapis.com/v/_EVCman5puE
{ItagNo:18 URL: MimeType:video/mp4; codecs="avc1.42001E, mp4a.40.2" Quality:medium Cipher:s=CcwZALH-6r1pWyCW7ADg_4RDRYYQK2RnP38rrGq7XcAICo2mr6FnLlSvL0SZde5AqqE26kvYVCCSDaOR2Un_8ZpXAIARw8JQ0qOAgOAg&sp=sig&url=https://r7---sn-42u-i5oee.googlevideo.com/videoplayback%3Fexpire%3D1614163728%26ei%3DsNo1YLyKCtGmlQTIj4SYBg%26ip%3D<IP_ADDRESS>%26id%3Do-ACLc5iQASegSz_a21N4VwyC8Gsihefh9RTCdkU2sG6QQ%26itag%3D18%26source%3Dyoutube%26requiressl%3Dyes%26mh%3D1h%26mm%3D31%252C26%26mn%3Dsn-42u-i5oee%252Csn-npoe7ns7%26ms%3Dau%252Conr%26mv%3Dm%26mvi%3D7%26pl%3D21%26initcwndbps%3D1682500%26vprv%3D1%26mime%3Dvideo%252Fmp4%26ns%3DIAe1EbnjcYnzwRoSu3APGjsF%26gir%3Dyes%26clen%3D24221634%26ratebypass%3Dyes%26dur%3D285.675%26lmt%3D1595074853156436%26mt%3D1614141875%26fvip%3D3%26fexp%3D23983797%26c%3DWEB%26txp%3D5432434%26n%3DWTU_HH8nVrX613TN%26sparams%3Dexpire%252Cei%252Cip%252Cid%252Citag%252Csource%252Crequiressl%252Cvprv%252Cmime%252Cns%252Cgir%252Cclen%252Cratebypass%252Cdur%252Clmt%26lsparams%3Dmh%252Cmm%252Cmn%252Cms%252Cmv%252Cmvi%252Cpl%252Cinitcwndbps%26lsig%3DAG3C_xAwRQIhAL0wXXMPraK_afsEmqzQfNJiIqujXPeFG4nxG_Jj8qokAiB-s81L85xPfzEos1x-8jYcySR6LgzYRRrSs7il8WBIjQ%253D%253D Bitrate:678477 FPS:30 Width:640 Height:360 LastModified:1595074853156436 ContentLength:24221634 QualityLabel:360p ProjectionType:RECTANGULAR AverageBitrate:678299 AudioQuality:AUDIO_QUALITY_LOW ApproxDurationMs:285675 AudioSampleRate:44100 AudioChannels:2 InitRange:<nil> IndexRange:<nil>}
2021/02/24 11:48:48 GET https://youtube.com/embed/_EVCman5puE?hl=en
2021/02/24 11:48:48 GET https://youtube.com/s/player/5a096a9f/player_ias.vflset/en_US/base.js
error parsing signature tokens (#obj=0, #func=0)

Please check :d

@greentornado  , thank for info.
I think it's the problem youtube changes its deciper signature again.  We try to fix it soon.

@Julian-Chu 25 Jan, OP here... @cw1nte could you try "go get -u github.com/kkdai/youtube/v2/cmd/youtubedr" ???
I get a fail: $ go get -u github.com/kkdai/youtube/v2/cmd/youtubedr
package github.com/kkdai/youtube/v2/cmd/youtubedr: cannot find package "github.com/kkdai/youtube/v2/cmd/youtubedr" in any of:
/usr/local/go/src/github.com/kkdai/youtube/v2/cmd/youtubedr (from $GOROOT)
/Users/colinwin/go/src/github.com/kkdai/youtube/v2/cmd/youtubedr (from $GOPATH)
fail logged in history log DB, status 1 [MY LOGGING NOTE]
I have run with various mixes of switches among -v(verbose) -i -x but did not get any more information ...
I do not do much in go and have been very busy elsewhere, so apologies for not getting back. I tried a number of similar commands to get some sort of new version built. In fact I have never had success with specific go package versions and have no time to find out how it is meant to be set up, it seems a complex area trying to suit multiple differing needs of sub- and main projects...
go version go1.14.2 darwin/amd64

@greentornado
I think yt fixed it,  current version youtube should works
@cw1nte  thanks for feedback, I think we should update document and guide to be more friendly. Hope it can help u when u have time to come back. I will put it into plan

@Julian-Chu i see it working again, thanks


Visual Automation using Screenshot not working

I used the click "image name".png command to click on items on the website for visual automation. The click command worked a few days also but now it is not working. My friend, Fionne is also having the same problem. We already tried to redo the ss and made sure that the resolution was 100% or the recommended one. May I know how to solve this issue? Attached are my file codes.
Uploading SGX.zip…

(user closed as there is a duplicated issue created here https://github.com/kelaberetiv/TagUI/issues/628)


Add scrolling over TOC

This PR modifies TOC CSS container to be scrollable.

Thanks for the PR and working example. I'm happy with this change so will merge it in now.


Supabase Auth Warning

Version
@nuxtjs/supabase: 1.3.5
nuxt: 3.12.3
Reproduction Link

Steps to reproduce
const user = useSupabaseUser()
watchEffect(() => {
    if (user.value) {
        navigateTo('/')
    }
})

What is Expected?

no warning (

What is actually happening?
 WARN  Using the user object as returned from supabase.auth.getSession() or from some
 supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage
 medium (usually cookies on the server) and many not be authentic. Use supabase.auth.getUser() instead
 which authenticates the data by contacting the Supabase Auth server.

This issue is related to the supabase/ssr lib. Can you please upvote this issue to encourage the Supabase maintainers to address it.

OK, I'll do it.

I upvoted it as well. In the meantime, do you have any recommendations?

It's not impacting your app. Let's wait for the fix from the Supabase team.

Just updated from 1.2.2 to 1.4.0 and getting this issue now, before it was fine with the same code

Just leaving my hack here for anyone who cannot deal with the log messages lol. It probably only works for package managers that can do patching and I'll use pnpm as an example:
pnpm patch @supabase/auth-js

Remember/store the output to run to commit your patch when done with the following

Now cd to the /tmp/xxx path and edit the following files:

dist/main/GoTrueClient.js
dist/module/GoTrueClient.js

What to edit?
I did a find for console.warn and on lines 822 and 817 respectively I just added a // in front of the line logging Using the user object ....
When done, cd back to the project and run
pnpm patch-commit `/tmp/xxxx`

Unfortunately this silences the log for real insecure usage too, so that's a trade-off you'll have to make for cleaner dev logs.


Modify diag-aug and ASE default

Diagonal augmentation leads to better estimation of latent positions, at least in unweighted case.

make the behavior for directed graphs be to average in and out degree
make ASE use diag-aug before running as a default kwarg

@j1c i forget do we want this for Omni too? Seems reasonable. Working on this now

for weighted graphs, i believe our default is 'cep-ptr' o 'diag-aug'.
so, even if weights are negative, assuming we ptr them, i think we still have the same procedure?


Scenario 2a - Model does not align with paper (even after parameter fix)

The number of infections peaks too early and is too great in magnitude for the population (ignore the y-axis-label it is actually # of people infected not percentage i.e. I multiplied the fractions by 14.57e6).

I'm not positive why this may be occuring, as far as I can tell the model parameters match those in voc2_driver. If I also use a different set of values for the betas, matching those from output.mat (resulting data after running voc2_driver.m), then the peak infections aligns more closely with the paper but is still too early and too large. See here:

This leads me to believe the error lies elsewhere other than the parameters.

Adding plot from Slack discussion:

Fixed with recent push.


Warning about PathToRegexp

Hi I am using webpack for build my application but it has warning, that crash my app
WARNING in ./node_modules/framework7/dist/framework7.esm.bundle.js 337:1749-1761 "export 'default' (imported as 'PathToRegexp') was not found in 'path-to-regexp' What cause of it?
I already changed config like this https://github.com/framework7io/framework7-template-vue-webpack/blob/master/build/webpack.base.conf.js#L46-L49
Versions:
"webpack": "^3.6.0",
"framework7": "^2.3.1",
"node": "9.10.1"
I use downgrade to version 2.0.7 like this:
http://forum.framework7.io/t/warning-about-path-to-regexp/2395
But when built app and opened it, I got:
Cannot read property 'f7Page' of undefined
But app is working - it's weird.

Oh, I made mistake when I declared v-if directive for f7Page inside f7View. It closes.


Error when creating deploy.caffemodel with two classes using load_caffe_weights.py, ValueError: cannot reshape array of size 157248 into shape (6,576,1,1)

dump_tensorflow_weights.py works well with the downloaded ssdlite_mobilenet_v2_coco_2018_05_09 model. But stuck at converting it to caffe model using the load_caffe_weights.py script
Traceback (most recent call last):
File "load_caffe_weights.py", line 82, in
load_data(net_deploy)
File "load_caffe_weights.py", line 74, in load_data
net.params[key][0].data[...] = load_weights(prefix + '_weights.dat', net.params[key][0].data.shape)
File "load_caffe_weights.py", line 17, in load_weights
weights = np.fromfile(path, dtype=np.float32).reshape(shape)
ValueError: cannot reshape array of size 157248 into shape (6,576,1,1)

did you fixed this error,i got the same error

I got same Error. Did you fix it?

@baiboat  @tringn please look at the #22
I continued my work with MobileNetV1. Stopped at this error. Ha vent tried yet with solutions in #22

File "dump_tensorflow_weights.py", line 77, in
tmp = caffe_weights.reshape(boxes, -1).copy()
ValueError: cannot reshape array of size 31104 into shape (0,newaxis)


etcdctlv3: ping command

Add a ping command that can ping each of the member and know about its health.
A ping should issue a linearized read.
If etcdctlv3 cannot reach to the member (network errors), then the member is unhealthy from the client's perspective. There might be an issue at client side or the member might be dead.
If linearized read succeeds, then the member is healthy and the cluster is healthy.
If linearized read fails, then the member is healthy but the cluster is not healthy from this member's perspective. Might be the member is partitioned or the cluster is not working.

/cc @mqliang maybe you are interested in this one.

I am a little confused about this feature. It seems that  etcdctl cluster-health could also know about the members' and cluster's health status.
Even if the member is partitioned, raft index of this member will not make progress and /helath endpoint will return {"health": "false"}. Cluster is healthy if majority (quorum) of etcd members are healthy, otherwise cluster is unhealthy.

@mqliang This is for v3. Cluster health is confusing actually: see https://github.com/coreos/etcd/issues/3852

closed via #4812


improve github actions - deprecated workflow

for details:
https://github.com/esciencecenter-digital-skills/training-infrastructure/actions/runs/3312624352

Actually, it failed because my tests failed. That's now updated. There is a lot of info about deprecated workflows though

I think we can close this; our GA workflows run! 🎉


curlCode: 6, Couldn't resolve host name

Describe the bug
After about 10 minutes of intensive list, get, put, delete request to a specific bucket we get curlCode: 6, Couldn't resolve host name. The client is a EC2 instance. Besides the SDK retries, the client code retries a few times as well but the error persists. After  some time, with no code changes, everything works again but still fails after 10 minutes of requests. The EC2 and the bucket are in the same us-east-1 region.
Expected Behavior
No errors
Current Behavior
We enabled AWS debug log. Here is a snippet:
[DEBUG] 2022-04-28 19:21:49.640 AWSAuthV4Signer [139760352270080] Canonical Request String: GET
/
list-type=2&prefix=...
amz-sdk-invocation-id:5B5B995D-12C7-4E88-A63E-C66E553A5F51
amz-sdk-request:attempt=6; max=11
content-type:application/xml
host:foo.s3.us-east-1.amazonaws.com
x-amz-api-version:2006-03-01
x-amz-content-sha256:UNSIGNED-PAYLOAD
x-amz-date:20220428T192149Z
amz-sdk-invocation-id;amz-sdk-request;content-type;host;x-amz-api-version;x-amz-content-sha256;x-amz-date
UNSIGNED-PAYLOAD
[DEBUG] 2022-04-28 19:21:49.640 AWSAuthV4Signer [139760352270080] Final String to sign: AWS4-HMAC-SHA256
20220428T192149Z
20220428/us-east-1/s3/aws4_request
b4d2f505824b36c129243ece09bb5d665aaf760c88dd90a6b4497f127e2481cc
[DEBUG] 2022-04-28 19:21:49.640 AWSAuthV4Signer [139760352270080] Final computed signing hash: f8f0dd9bf9aee42bc5f91f2a6917fadf2c06718adfc15a10bbb8cd2b8e0887d9
[DEBUG] 2022-04-28 19:21:49.640 AWSAuthV4Signer [139760352270080] Signing request with: AWS4-HMAC-SHA256 Credential=AKIAX3GSQRN3HSJPB5CG/20220428/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invoca
tion-id;amz-sdk-request;content-type;host;x-amz-api-version;x-amz-content-sha256;x-amz-date, Signature=f8f0dd9bf9aee42bc5f91f2a6917fadf2c06718adfc15a10bbb8cd2b8e0887d9
[DEBUG] 2022-04-28 19:21:49.640 AWSClient [139760352270080] Request Successfully signed
[DEBUG] 2022-04-28 19:21:49.640 CurlHandleContainer [139760352270080] Attempting to acquire curl connection.
[DEBUG] 2022-04-28 19:21:49.640 CurlHandleContainer [139760352270080] No current connections available in pool. Attempting to create new connections.
[DEBUG] 2022-04-28 19:21:49.640 CurlHandleContainer [139760352270080] attempting to grow pool size by 2
[INFO] 2022-04-28 19:21:49.640 CurlHandleContainer [139760352270080] Pool grown by 2
[INFO] 2022-04-28 19:21:49.640 CurlHandleContainer [139760352270080] Connection has been released. Continuing.
[DEBUG] 2022-04-28 19:21:49.640 CurlHandleContainer [139760352270080] Returning connection handle 0x7f1bf887ad90
[DEBUG] 2022-04-28 19:21:49.640 CurlHttpClient [139760352270080] Obtained connection handle 0x7f1bf887ad90
[DEBUG] 2022-04-28 19:21:49.641 CURL [139760352270080] (Text) Could not resolve host: foo.s3.us-east-1.amazonaws.com
[DEBUG] 2022-04-28 19:21:49.641 CURL [139760352270080] (Text) Closing connection 0
[ERROR] 2022-04-28 19:21:49.641 CurlHttpClient [139760352270080] Curl returned error code 6 - Couldn't resolve host name
[DEBUG] 2022-04-28 19:21:49.641 CurlHandleContainer [139760352270080] Destroy curl handle: 0x7f1bf887ad90 and decrease pool size by 1.
[DEBUG] 2022-04-28 19:21:49.641 AWSClient [139760352270080] Request returned error. Attempting to generate appropriate error codes from response
[ERROR] 2022-04-28 19:21:49.641 AWSClient [139760352270080] HTTP response code: -1
Resolved remote host IP address:
Request ID:
Exception name:
Error message: curlCode: 6, Couldn't resolve host name
0 response headers:

Reproduction Steps
A suite of get, put, list, and delete requests.
Possible Solution
No response
Additional Information/Context
No response
AWS CPP SDK version used
1.8.3
Compiler and Version used
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Operating System and version
CentOS Linux release 7.7.1908 (Core)

Hey @vudh1, just wanted to check in and see whether there is any ETA on this. Thanks!

I changed my client code to create a new S3client for every request. It looks like the error is no longer happening. So, I would conclude that something is going with the long running S3Clients and resetting them clears that up. Any guidance from the maintainers would be appreciated.

Hi, do you have sample of reproducible code that we can use to investigate?

Unfortunately, the code using the AWS SDK is embedded into a larger software and pulling it out for a repro would be prohibitive.
Just to point out that the application worked fine for about a year and we have not seen such errors before. We have not changed the AWS SDK version or the code before this started happening. We have seen the same behavior happening in about the same time-frame, in an unrelated application using a different language binding of the AWS SDK. So, based on this empirical evidence I would conclude that the issue is not the SDK nor our code, but a change that took place on the S3 servers about a week ago.
Now, our application is a long running process, making S3 requests from time to time in batches. The original implementation creates an S3Client instance for each batch of S3 requests. This implementation has the issue described in the top comment.
We tried two ways of changing our implementation and both made the error go away:

We create an S3Client for each S3 request (as mentioned in my previous comment)
We create only one S3Client instance for the life of the process

I wish more guidance would be provided by AWS on how the SDK should be used in such applications and how we should deal with this type of errors.

I am running some simple test with loop to see if I can reproduce the same behavior. In that mean time, can you check if this problem is still persisting with our current version of SDK (1.9.251)?

Got it. Just in case it helps, here is our module that interacts with AWS https://github.com/Paradigm4/bridge/blob/xremove/src/S3Driver.cpp The last two functions _retryLoop and _deleteAndUpdate are the ones that make the actual AWS requests.

Hi @rvernica I see that in the code you gave, few changes (like here) might have been made for workaround solution right?
We are trying to see where the cause of behavior so can you send the reproducible code without the changes?

The change you linked above is made to recover in case we encounter a curlCode: 6 error.
The workaround change was actually done in this commit by moving the client = std::make_unique<Aws::S3::S3Client>(); instance from the S3Driver class to the S3Init class.
In more details, before the change, the S3Client instance was inside our S3Driver class. This meant that an S3Client instance is created for each batch of S3 requests. The approach worked fine for a year, but recently resulted in the curlCode: 6 errors.
After the change, the S3Cleint instance was moved inside our S3Init class. This class is initialized once per process, so only one S3Client instance is created. This made the curlCode: 6 error go away.

Could this issue be related to this https://github.com/aws/aws-sdk-cpp/issues/1614 ? It looks like it was reported but never fixed.

Hi guys, I had the same problem. In my case, the problem appeared after accessing the API more than 1011 times.
I initialized the API (InitAPI) in my original code on each s3 operation.
I moved InitAPI to the main (instead of having them on each s3 operation), which solves the problem for me.
----- one single initialization ----
Aws::SDKOptions options;
options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
Aws::InitAPI(options);
{
.... your code ....
}
Aws::ShutdownAPI(options);

I am using  Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never fix this, you can have a try.
auto s3_client = Aws::MakeShared<Aws::S3::S3Client>(                 "allocationTag",                 Aws::Auth::AWSCredentials(Aws::String(ACCESS_KEY_ID), Aws::String(SECRET_KEY)),                 config,                 Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never,                 false );

@rvernica are you still running into this bug? If so does using Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never fix it for you?


How big is one "step"

I want it to walk around a park, and not leave said park. How many mi/km is one step?_

I always assume it's the circles that you can make visible on PokemonGo-Map which are about 150m in diameter.
Could be wrong though.


chore: check-code ci job uses danger-github-oss context

This PR resolves PHIRE-82
Description

This switches the CI check-code job to read danger github token from CircleCI contexts. By my understanding, that is the only job that requires this var.
PR Checklist
~- [ ] I have tested my changes on iOS and Android.~
~- [ ] I hid my changes behind a feature flag, or they don't need one.~
~- [ ] I have included screenshots or videos, or I have not changed the UI.~
~- [ ] I have added tests, or my changes don't require any.~
~- [ ] I added an app state migration, or my changes do not require one.~
~- [ ] I have added a changelog entry below, or my changes do not require one.~

[ ] I have documented any follow-up work that this PR will require, or it does not require any

To the reviewers 👀
~- [ ] I would like at least one of the reviewers to run this PR on the simulator or device.~
To the Assignee 👀
❗ Migration: ❗

[ ] unset DANGER_GITHUB_API_TOKEN CircleCI project environment variable before merging

#nochangelog
Need help with something? Have a look at our docs, or get in touch with us.

Warnings

:warning:

✅ No changelog changes

  Generated by :no_entry_sign: dangerJS against acd2a70d457f78b249e7958edec54ebe115641c9


feat: checkRequired schema validation

What issue does this pull request resolve?
#1403
What changes did you make?
The strict mode validation now validates if every single key of a required property exists in the sibling properties definition of a JSON schema definition of type object.
Is there anything that requires more attention while reviewing?
Feedback welcome at any time.
ToDo-List:

[x] basic check of object-type schema definitions
[x] configuration parameter
[ ] additional tests
[x] documentation

Maybe it wants the conflicts resolved first before it runs the tests? The tests at on PR - not on the branch.

Looks great - some minor comments/suggestions.
The additional tests would cover scenarios with, for example, this passing:
{
  properties: {foo: {}, bar: {}},
  allOf: [{
    allOf: [{
      if: {required: ["foo"]},
      then: {required: ["bar"]}
    }]
  }]
}

and this failing:
{
  properties: {foo: {}, bar: {}},
  allOf: [{
    allOf: [{
      if: {required: ["bar"]},
      then: {required: ["baz"]}
    }]
  }]
}

(the options could be just set to true to throw exception)

{
  properties: {foo: {}, bar: {}},
  allOf: [{
    allOf: [{
      if: {required: ["bar"]},
      then: {required: ["baz"]}
    }]
  }]
}

This test case fails currently because - as u said in the issue - the required keyword is evaluated first. In this case checking the immediate parent schema doesnt help because the properties referenced are 2 parents above the required keyword.
How can we fix that?

when you say fails - do you mean that strictRequired throws the exception? If so it should do it. Or you mean it doesn’t throw? Need to check the code - will try to do it tomorrow.

when you say fails - do you mean that strictRequired throws the exception? If so it should do it. Or you mean it doesn’t throw? Need to check the code - will try to do it tomorrow.

It should - and at that commit it did not. But I double checked the "required"-condition I implemented and it did not get the correct result. I corrected that with a slight modification of your condition-suggestion above.
I think the === undefined check is necessary or else the condition will be falsy if the prop does not exist due to the way the conditional chaining operator works, resulting in the and-condition to be evaluated and false.
The current implementation works for the new cases and the base cases but fails the test cases with "one-level"-if-then schemas.

yes - good catch - I see the problem. So it sees the properties defined in the siblings of "required", but it doesn't see the properties defined in the siblings of the parents of required...
And this is quite a common use case, so we can't just ignore it...
I two several solutions:

ad-hoc - ajv would add defined properties to SchemaCxt outside of processing of properties keyword - anywhere in the compilation framework. This means that it would happen even in case when "properties" keyword is not used - specifically, in JTD subclass. Not a huge problem, but hacky...
allow keywords define pre-processing hooks - meaning that ajv would have to iterate all keywords twice. Also not good.
change the order of applicator keywords (although I tried and it still fails - need to check why). Either way, I don't like it - it just acknowledges that it is brittle and can break some dependents...

Need to think a bit more about it...
This should not work by the way (that is required inside if should not see required inside then - this is not a normal situation when it might needed and it would be next level difficult to make work anyway):
{
  type: "object",
  properties: {foo: {}},
  if: {required: ["bar"]},
  then: {properties: {bar: {type: "boolean"}}},
}

Option 4 is to accept it as a limitation and document :)

Option 5: check “properties” that is a sibling of the parent as well
that actually might be an optimal trade-off

option 5 is to add hooks that keywords could pass to the framework - there's been a couple of scenarios where it would have been useful too. In this case required would pass callback (via say it.post(fn) or some other API) that would be called after all keywords in the schema object were processed.

I personally do not need feature-completeness. My personal requirements are mostly satisfied with the base cases I assume, so going for accepting it as a limitation until you have a reasonable solution in place is okay for me.

But I guess that throwing in strict mode for strictRequired is not an option then?

Throwing is ok if it is opt in, but logging is not ok if it is a relatively common case - if{required is a common approach to the poor man's missing discriminator pattern... Probably it is worth supporting discriminator to differentiate between oneOf/anyOf branches, as described in some issue, but it is non-standard and JTD includes discriminator already (and required is not needed there as well, as it's default)...
I am leaning towards hooks tbh to implement it - will think a bit longer about it.


Change default keybindings for subword navigation

Closes #53750

 Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.:x: cauebs sign nowYou have signed the CLA already but the status is still pending? Let us recheck it.

alt left is conflicting with "Back" command

This creates conflicts with existing keybindings, both on macOS and Windows.


'in: body' parameters doesn't work on the top level of Path Item Object

parameters with 'in: body' parameter only works under the Operation Object.
Check 'Fixed Fields' of 'Path Item Object' on (http://swagger.io/specification/)

Thanks for reporting @flyjwayur. Would you mind adding a unit test to show the desired behavior?

@flyjwayur do you have an example of a definition that does not work? I'd like to understand the problem.