網頁

2023年6月21日 星期三

如何在 python 中使用 tao 產生的 yolov4 模型

參考 Nvidia TAO Computer Vision Sample Workflows 產生 yolov4-tiny 模型
此 模型 與 一般產生 的 模型 不一樣
一般產生的模型 參考 tensorrt_demos 即可在 python 中使用

只能將 
tao yolo_v4_tiny export 出的模型(.etlt)用於 DeepStream
而由 
tao  converter 產生的 trt.engine 不能使用於 DeepStream 也不能在 python 中使用

有說明如何使用 tao 產生的模型在 Triton 伺服器上
在 yolov3_postprocessor.py 中發現 tao 產生的 yolo
已經將輸出的 NMS 處理過, 並將內容置於 
BatchNMS(-1,1): 偵測出的數量
BatchNMS_1(-1,200,4): 座標
BatchNMS_2(-1,200): 信心
BatchNMS_3(-1,200): 類別
輸入的方式也有改變
cv2 讀出的圖 不需 cvtColor, 也不用除以 255.0
只需將 BHWC 轉成 BCHW
img = img.transpose((2, 0, 1)).astype(np.float32)

tao 的執行是在 docker 中,所以很難除錯
發現下列命令,可以直接進入 docker 中,執行 python, 查詢版本環境等
docker run -it --rm --gpus all \
  -v "/mnt/Data/tao/yolo_v4_tiny_1.4.1":"/workspace/tao-experiments" \
  -v "/mnt/Data/TensorRT/tensorrt_demos":"/workspace/tensorrt_demos" \
  -v "/mnt/CT1000SSD/ImageData/Light":"/workspace/Light" \
  nvcr.io/nvidia/tao/tao-toolkit:4.0.0-tf1.15.5 \
  bash

將模型轉換成 TensorRT 除了使用
!tao converter -k $KEY \
                   -p Input,1x3x416x416,8x3x416x416,16x3x416x416 \
                   -e $USER_EXPERIMENT_DIR/export/trt.engine \
                   -t fp32 \
                   $USER_EXPERIMENT_DIR/export/yolov4_cspdarknet_tiny_epoch_$EPOCH.etlt
外, 也可使用
!tao-deploy yolo_v4_tiny gen_trt_engine \
  -m $USER_EXPERIMENT_DIR/export/yolov4_cspdarknet_tiny_epoch_$EPOCH.etlt \
  -e $SPECS_DIR/yolo_v4_tiny_retrain_kitti.txt \
  -k $KEY \
  --data_type fp32 \
  --batch_size 1 \
  --engine_file $USER_EXPERIMENT_DIR/export/yolov4_tao_deplay.trt
但若是要在不同平台上轉換
參考 TAO Converter 下載安裝,並執行轉換
./tao-converter_v4.0.0_trt8.5.1.7 \
  -k nvidia_tlt \
  -p Input,1x3x416x416,2x3x416x416,4x3x416x416 \
  -e yolo_v4_tiny_1.4.1/yolo_v4_tiny/export/yolov4_tao_converter_fp32.engine \
  -t fp32 \
  yolo_v4_tiny_1.4.1/yolo_v4_tiny/export/yolov4_cspdarknet_tiny_epoch_080.etlt

參考 tensorrt_demos 修改 utils/yolo_with_plugins.py, 改名成 triton_yolo_with_plugins.py 如下
"""yolo_with_plugins.py
Implementation of TrtYOLO class with the yolo_layer plugins.
"""
from __future__ import print_function
import ctypes
import numpy as np
import cv2
import tensorrt as trt
import pycuda.driver as cuda

try:
    ctypes.cdll.LoadLibrary('./plugins/libyolo_layer.so')
except OSError as e:
    raise SystemExit('ERROR: failed to load ./plugins/libyolo_layer.so.  '
                     'Did you forget to do a "make" in the "./plugins/" '
                     'subdirectory?') from e

def _preprocess_yolo(img, input_shape, letter_box=False):
    """Preprocess an image before TRT YOLO inferencing.
    # Args
        img: int8 numpy array of shape (img_h, img_w, 3)
        input_shape: a tuple of (H, W)
        letter_box: boolean, specifies whether to keep aspect ratio and
                    create a "letterboxed" image for inference
    # Returns
        preprocessed img: float32 numpy array of shape (3, H, W)
    """
    if letter_box:
        img_h, img_w, _ = img.shape
        new_h, new_w = input_shape[0], input_shape[1]
        offset_h, offset_w = 0, 0
        if (new_w / img_w) <= (new_h / img_h):
            new_h = int(img_h * new_w / img_w)
            offset_h = (input_shape[0] - new_h) // 2
        else:
            new_w = int(img_w * new_h / img_h)
            offset_w = (input_shape[1] - new_w) // 2
        resized = cv2.resize(img, (new_w, new_h))
        img = np.full((input_shape[0], input_shape[1], 3), 127, dtype=np.uint8)
        img[offset_h:(offset_h + new_h), offset_w:(offset_w + new_w), :] = resized
    else:
        img = cv2.resize(img, (input_shape[1], input_shape[0]))

    #img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img = img.transpose((2, 0, 1)).astype(np.float32)
    #img /= 255.0
    return img

class HostDeviceMem(object):
    """Simple helper data class that's a little nicer to use than a 2-tuple."""
    def __init__(self, host_mem, device_mem):
        self.host = host_mem
        self.device = device_mem

    def __str__(self):
        return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device)

    def __repr__(self):
        return self.__str__()

def get_input_shape(engine):
    """Get input shape of the TensorRT YOLO engine."""
    binding = engine[0]
    assert engine.binding_is_input(binding)
    binding_dims = engine.get_binding_shape(binding)
    if len(binding_dims) == 4:
        return tuple(binding_dims[2:])
    elif len(binding_dims) == 3:
        return tuple(binding_dims[1:])
    else:
        raise ValueError('bad dims of binding %s: %s' % (binding, str(binding_dims)))

def allocate_buffers(engine, context):
    """Allocates all host/device in/out buffers required for an engine."""
    inputs = []
    outputs = []
    bindings = []
    stream = cuda.Stream()
    for binding in engine:
        binding_dims = engine.get_binding_shape(binding)
        binding_dtype = engine.get_tensor_dtype(binding)
        binding_format = engine.get_tensor_format_desc(binding)
        binding_loc = engine.get_tensor_location(binding)
        binding_mode = engine.get_tensor_mode(binding)
        binding_shape = engine.get_tensor_shape(binding)
        binding_shape_inference = engine.is_shape_inference_io(binding)
        print('binding_dims:{} {} {}'.format(binding, binding_dims, binding_dtype))
        print('  {}'.format(binding_format))
        print('  {} {} {} {}'.format(binding_loc, binding_mode, binding_shape, binding_shape_inference))
        size = trt.volume(binding_dims)
        if size < 0: size *= -1;
        print('  size:{}'.format(size))
        dtype = trt.nptype(engine.get_binding_dtype(binding))
        # Allocate host and device buffers
        host_mem = cuda.pagelocked_empty(size, dtype)
        device_mem = cuda.mem_alloc(host_mem.nbytes)
        # Append the device buffer to device bindings.
        bindings.append(int(device_mem))
        # Append to the appropriate list.
        if engine.binding_is_input(binding):
            #binding_pro_shape = engine.get_profile_shape(0, binding)
            #print('  {}'.format(binding_pro_shape))
            if binding_dims[0] == -1:
                alloc_dims = np.copy(binding_dims)
                alloc_dims[0] = 1
                context.set_binding_shape(0, alloc_dims)
            inputs.append(HostDeviceMem(host_mem, device_mem))
        else:
            outputs.append(HostDeviceMem(host_mem, device_mem))
    return inputs, outputs, bindings, stream

def do_inference(context, bindings, inputs, outputs, stream, batch_size=1):
    """do_inference (for TensorRT 6.x or lower)
    This function is generalized for multiple inputs/outputs.
    Inputs and outputs are expected to be lists of HostDeviceMem objects.
    """
    # Transfer input data to the GPU.
    [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
    # Run inference.
    context.execute_async(batch_size=batch_size,
                          bindings=bindings,
                          stream_handle=stream.handle)
    # Transfer predictions back from the GPU.
    [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
    # Synchronize the stream
    stream.synchronize()
    # Return only the host outputs.
    return [out.host for out in outputs]

def do_inference_v2(context, bindings, inputs, outputs, stream):
    """do_inference_v2 (for TensorRT 7.0+)
    This function is generalized for multiple inputs/outputs for full
    dimension networks.
    Inputs and outputs are expected to be lists of HostDeviceMem objects.
    """
    # Transfer input data to the GPU.
    [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
    # Run inference.
    context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
    # Transfer predictions back from the GPU.
    [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
    # Synchronize the stream
    stream.synchronize()
    # Return only the host outputs.
    return [out.host for out in outputs]

class TrtYOLO(object):
    """TrtYOLO class encapsulates things needed to run TRT YOLO."""
    def _load_engine(self):
        TRTbin = 'yolo/%s.trt' % self.model
        TRTbin = self.model
        with open(TRTbin, 'rb') as f, trt.Runtime(self.trt_logger) as runtime:
            return runtime.deserialize_cuda_engine(f.read())

    def __init__(self, model, category_num=80, letter_box=False, cuda_ctx=None):
        """Initialize TensorRT plugins, engine and conetxt."""
        self.model = model
        self.category_num = category_num
        self.letter_box = letter_box
        self.cuda_ctx = cuda_ctx
        if self.cuda_ctx:
            self.cuda_ctx.push()

        self.inference_fn = do_inference if trt.__version__[0] < '7' \
                                         else do_inference_v2
        self.trt_logger = trt.Logger(trt.Logger.INFO)
        # add for errors
        # IPluginCreator not found in Plugin Registry
        # getPluginCreator could not find plugin: BatchedNMSDynamic_TRT version: 1
        # Serialization assertion plan->header.magicTag == rt::kPLAN_MAGIC_TAG failed
        trt.init_libnvinfer_plugins(self.trt_logger, namespace="")
        self.engine = self._load_engine()

        self.input_shape = get_input_shape(self.engine)

        try:
            self.context = self.engine.create_execution_context()
            self.inputs, self.outputs, self.bindings, self.stream = \
                allocate_buffers(self.engine, self.context)
        except Exception as e:
            raise RuntimeError('fail to allocate CUDA resources') from e
        finally:
            if self.cuda_ctx:
                self.cuda_ctx.pop()

    def __del__(self):
        """Free CUDA memories."""
        del self.outputs
        del self.inputs
        del self.stream

    def detect(self, img, letter_box=None):
        """Detect objects in the input image."""
        letter_box = self.letter_box if letter_box is None else letter_box
        img_h, img_w, _ = img.shape
        img_resized = _preprocess_yolo(img, self.input_shape, letter_box)
        #print(img_resized.shape, img_resized.dtype)

        # Set host input to the image. The do_inference() function
        # will copy the input to the GPU before executing.
        self.inputs[0].host = np.ascontiguousarray(img_resized)
        if self.cuda_ctx:
            self.cuda_ctx.push()
        trt_outputs = self.inference_fn(
            context=self.context,
            bindings=self.bindings,
            inputs=self.inputs,
            outputs=self.outputs,
            stream=self.stream)
        if self.cuda_ctx:
            self.cuda_ctx.pop()

        y_pred = [i.reshape(1, -1,)[:1] for i in trt_outputs]
        keep_k, boxes, scores, cls_id = y_pred
        #print(keep_k.shape)
        #print(boxes.shape)
        keep_k[0,0] = 1
        locs = np.empty((0,4), dtype=np.uint)
        cids = np.empty((0,1), dtype=np.uint)
        confs = np.empty((0,1), dtype=np.float32)
        for idx, k in enumerate(keep_k.reshape(-1)):
            mul = np.array([img_w,img_h,img_w,img_h])
            loc = boxes[idx].reshape(-1, 4)[:k] * mul
            loc = loc.astype(np.uint)
            cid = cls_id[idx].reshape(-1, 1)[:k]
            cid = cid.astype(np.uint)
            conf = scores[idx].reshape(-1, 1)[:k]
            locs = np.concatenate((locs, loc), axis=0)
            cids = np.concatenate((cids, cid), axis=0)
            confs = np.concatenate((confs, conf), axis=0)
        #print(locs.shape, cids.shape, confs.shape)
        #print(locs, cids, confs)
        return locs, confs, cids

下列程式使用上列的程式
import cv2
import numpy as np
import tensorrt as trt
import pycuda.autoinit # This is needed for initializing CUDA driver
import pycuda.driver as cuda
from utils.triton_yolo_with_plugins import TrtYOLO

#MODEL_PATH = '/workspace/tao-experiments/yolo_v4_tiny/export/yolov4_tao_convert.engine'
MODEL_PATH = '/workspace/tao-experiments/yolo_v4_tiny/export/yolov4_tao_deplay.trt'
#MODEL_PATH = '/workspace/tao-experiments/yolo_v4_tiny/export/trt.engine'
        
def main():
    trt_yolo = TrtYOLO(MODEL_PATH, 5, True)
    img_org = cv2.imread('bb.jpg')
    img = np.copy(img_org)
    print(img.shape, img.dtype)
    boxes, confs, clss = trt_yolo.detect(img, False)
    print(boxes.shape, confs.shape, clss.shape)
    print(boxes, confs, clss)
    for box, conf, clss in zip(boxes, confs, clss):
        x_min, y_min, x_max, y_max = box[0], box[1], box[2], box[3]
        cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (255, 255, 255), 2)
        print(box, conf, clss)
    cv2.imwrite('aa.jpg', img)
    print('aaa')

if __name__ == '__main__':
    main()

除錯說明
訊息: Serialization assertion plan->header.magicTag == rt::kPLAN_MAGIC_TAG failed
解決: TensorRt 的版本不一致,安裝不同版本,或利用 docker
訊息: IPluginCreator not found in Plugin Registry
訊息: getPluginCreator could not find plugin: BatchedNMSDynamic_TRT version: 1
解決: 需安裝 TensorRT OSS
在 load_engine() 之前加上
trt.init_libnvinfer_plugins(self.trt_logger, namespace="")

2023年6月6日 星期二

在 Jetson 上設定 VNC server

參考 https://developer.nvidia.com/embedded/learn/tutorials/vnc-setup
或 L4T-README/README-vnc.txt

$ cd /usr/lib/systemd/user/graphical-session.target.wants
$ sudo ln -s ../vino-server.service ./.

$ gsettings set org.gnome.Vino prompt-enabled false
$ gsettings set org.gnome.Vino require-encryption false

$ gsettings set org.gnome.Vino authentication-methods "['vnc']"
$ gsettings set org.gnome.Vino vnc-password $(echo -n 'YourPassword'|base64)

$ vi vino.sh
DISP=`ps -u $(id -u) -o pid= | \
    while read pid; do
        cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | grep '^DISPLAY=:'
    done | grep -o ':[0-9]*' | sort -u`
echo $DISP
/usr/lib/vino/vino-server --display=$DISP

重新開機

2023年6月2日 星期五

DeepStream 之 nvdspreprocess 使用注意事項

nvdspreprocess 使用在 PGIE(Primary Gst Inference Engine)

g_object_set(G_OBJECT(pgie), "input-tensor-meta", 1, NULL);
or PGIE 的設定檔
input-tensor-from-meta=1

nvdspreprocess 的設定檔
# 需搭配 pgie_config.txt 的 model
# 0=NCHW, 1=NHWC, 2=CUSTOM
network-input-order=0
network-input-shape=2;3;384;1248
processing-width=1248
processing-height=384
tensor-name=Input
# 需搭配 pgie_config.txt 的 net-scale-factor
pixel-normalization-factor=1.0

2023年5月4日 星期四

Nvidia TAO Computer Vision Sample Workflows

參考: Nvidia TAO(Train, Adapt, and Optimize)

user@host:~$ pip3 install --upgrade pip
Traceback (most recent call last):
  File "/home/user/.local/bin/pip3", line 7, in <module>
    from pip._internal.cli.main import main
ModuleNotFoundError: No module named 'pip._internal'

user@host:~$ python3 -m pip --version
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
user@host:~$ python3 -m pip install --upgrade pip
Collecting pip
  Cache entry deserialization failed, entry ignored
  Using cached https://files.pythonhosted.org/packages/a4/6d/6463d49a933f547439d6b5b98b46af8742cc03ae83543e4d7688c2420f8b/pip-21.3.1-py3-none-any.whl
Installing collected packages: pip
Successfully installed pip-21.3.1

user@host:~$ pip3 install virtualenv
user@host:~$ pip3 install virtualenvwrapper
user@host:~$ mkdir .virtualenvs
user@host:~$ vi .bashrc
export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source $HOME/.local/bin/virtualenvwrapper.sh
user@host:~$ source .bashrc
user@host:~$ mkvirtualenv tao -p /usr/bin/python3
(tao) user@host:~$ deactivate
user@host:~$ lsvirtualenv
user@host:~$ workon tao
(tao) user@host:~$ pip3 install nvidia-pyindex
(tao) user@host:~$ pip3 install nvidia-tao
(tao) user@host:~$ pip3 install jupyter
(tao) user@host:~$ tao info

到 https://catalog.ngc.nvidia.com/orgs/nvidia/teams/tao/resources/cv_samples 網站
右上角 Download 選 WGET 或 CLI, 會將命令拷貝至剪貼簿,如下命令,並執行
ngc registry resource download-version "nvidia/tao/cv_samples:v1.4.1"
wget --content-disposition https://api.ngc.nvidia.com/v2/resources/nvidia/tao/cv_samples/versions/v1.4.1/zip -O cv_samples_v1.4.1.zip

(tao) user@host:~/Data/tao$ unzip -u cv_samples_v1.4.1.zip -d ./cv_samples_v1.4.1 && rm -rf cv_samples_v1.4.1.zip 
user@host:~/Data/tao$ cp -ar cv_samples_v1.4.1/yolo_v4_tiny/ yolo_v4_tiny_1.4.1
(tao) user@host:~/Data/tao$ cd cv_samples_v1.4.1/
(tao) user@host:~/Data/tao/cv_samples_v1.4.1$ 
(tao) user@host:~/Data/tao/cv_samples_v1.4.1$ jupyter notebook --ip 0.0.0.0 --port 8888 --allow-root
依據命令返回說明,開啟網頁
進入 yolo_v4_tiny, 點選 yolo_v4_tiny.ipynb
修改下列環境變數到你真實的位置
%env LOCAL_PROJECT_DIR=YOUR_LOCAL_PROJECT_DIR_PATH
%env LOCAL_PROJECT_DIR=/home/user/Data/tao/yolo_v4_tiny_1.4.1
檢查工具版本
(tao) user@host:~/Data/tao/yolo_v4_tiny_1.4.1$ python3 --version
(tao) user@host:~/Data/tao/yolo_v4_tiny_1.4.1$ docker version
(tao) user@host:~/Data/tao/yolo_v4_tiny_1.4.1$ apt list -a nvidia-container-toolkit
(tao) user@host:~/Data/tao/yolo_v4_tiny_1.4.1$ apt list -a nvidia-docker2
(tao) user@host:~/Data/tao/yolo_v4_tiny_1.4.1$ nvidia-smi
(tao) user@host:~/Data/tao/yolo_v4_tiny_1.4.1$ docker login nvcr.io

到 https://catalog.ngc.nvidia.com/ 搜尋 object
可找到 TAO Pretrained Object Detection
進入,點選右上 Download, 選 CLI,將命令拷貝
可由命令查到真實位置
ngc registry model download-version "nvidia/tao/pretrained_object_detection:cspdarknet_tiny"

參考 https://catalog.ngc.nvidia.com/orgs/nvidia/containers/deepstream
user@host:~/Data/V2Pdetect$ docker run --gpus all -it --rm --net=host --privileged -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -w /opt/nvidia/deepstream/deepstream-6.2 nvcr.io/nvidia/deepstream:6.2-devel

查詢已安裝套件的版本
參考 https://docs.nvidia.com/metropolis/deepstream/dev-guide/text/DS_Quickstart.html?highlight=compatibility#platform-and-os-compatibility
其中 nvidia driver 的版本, docker 是使用 host 的 driver
root@host:/opt/nvidia/deepstream/deepstream-6.2# pip list
root@host:/opt/nvidia/deepstream/deepstream-6.2# dpkg -l|grep nvinfer
root@host:/opt/nvidia/deepstream/deepstream-6.2# dpkg -l|grep cudnn
root@host:/opt/nvidia/deepstream/deepstream-6.2# dpkg -l|grep cudnn
root@host:/opt/nvidia/deepstream/deepstream-6.2# cat /etc/os-release 
root@host:/opt/nvidia/deepstream/deepstream-6.2# update-alternatives --display cuda
root@host:/opt/nvidia/deepstream/deepstream-6.2# nvidia-smi

root@host:/opt/nvidia/deepstream/deepstream-6.2# ./install.sh 
root@host:/opt/nvidia/deepstream/deepstream-6.2# ./user_additional_install.sh 

user@host:~/Data/DeepStream/deepstream_tao_apps$ git clone https://github.com/NVIDIA-AI-IOT/deepstream_tao_apps.git
user@host:~/Data/DeepStream/deepstream_tao_apps$ cd deepstream_tao_apps
user@host:~/Data/DeepStream/deepstream_tao_apps/deepstream_tao_apps$ git show-ref
user@host:~/Data/DeepStream/deepstream_tao_apps/deepstream_tao_apps$ cd ..
user@host:~/Data/DeepStream/deepstream_tao_apps$ mv deepstream_tao_apps deepstream_tao_apps-tao4.0_ds6.2ga
user@host:~/Data/DeepStream/deepstream_tao_apps$ cd deepstream_tao_apps-tao4.0_ds6.2ga/

user@host:~/Data/V2Pdetect$ docker run --gpus all -it --rm --net=host --privileged \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -v /etc/localtime:/etc/localtime \
  -v /home/user/Data/DeepStream/deepstream_tap_apps/deepstream_tao_apps-tao4.0_ds6.2ga/:/home/deepstream_tao_apps \
  -v /home/user/Data/V2Pdetect/multi_rtsp:/home/multi_rtsp \
  -e DISPLAY=$DISPLAY \
  -w /opt/nvidia/deepstream/deepstream-6.2 \
  nvcr.io/nvidia/deepstream:6.2-devel

root@host:/opt/nvidia/deepstream/deepstream-6.2# cd /home/deepstream_tao_apps/
root@host:/home/deepstream_tao_apps# ./download_models.sh 
root@host:/home/deepstream_tao_apps# ls models/yolov4-tiny/
root@host:/home/deepstream_tao_apps# cd post_processor/
root@host:/home/deepstream_tao_apps/post_processor# make
Makefile:25: *** "CUDA_VER is not set".  Stop.
root@host:/home/deepstream_tao_apps/post_processor# dpkg -l | grep CUDA
root@host:/home/deepstream_tao_apps/post_processor# export CUDA_VER=11.8
root@host:/home/deepstream_tao_apps/post_processor# cd ../apps/tao_detection/
root@host:/home/deepstream_tao_apps/apps/tao_detection# make
自己準備個 sample_720p.h264,以便測試
root@host:/home/deepstream_tao_apps/apps/tao_detection# ./ds-tao-detection -c ../../configs/yolov4-tiny_tao/pgie_yolov4_tiny_tao_config.txt -i file:///home/deepstream_tao_apps/sample/streams/sample_720p.h264 -d
root@host:/home/deepstream_tao_apps/apps/tao_detection# ./ds-tao-detection -c ../../configs/yolov4-tiny_tao/pgie_yolov4_tiny_tao_config.txt -i rtsp://root:passwd@192.168.0.107:554/live1s1.sdp -d

將 tao 產生的 labels.txt, yolov4_cspdarknet_tiny_epoch_080.etlt 拷貝到 deepstream_tao_apps 下
並合併 nvinfer_config.txt 和 pgie_yolov4_tiny_tao_config.txt 
root@host:/home/deepstream_tao_apps/apps/tao_detection# ./ds-tao-detection -c ../../configs/yolov4-tiny_tao/pgie_light.txt -i file:///home/deepstream_tao_apps/sample/streams/sample_720p.h264 -d

root@host:/home/multi_rtsp# apt-get update
root@host:/home/multi_rtsp# apt-get install libopencv-dev
root@host:/home/multi_rtsp# apt-get install libclutter-gst-3.0-dev

2023年3月29日 星期三

檢查 memory leak

安裝 valgrind
$ sudo apt update
$ sudo apt install snapd
$ sudo snap install valgrind --classic

$ gcc -g -o debug_prog debug_prog.c
$ g++ -g -o debug_prog debug_prog.c

開啟兩個 terminal
$ valgrind --vgdb=yes --vgdb-error=0 --tool=memcheck --leak-check=full ./debug_prog

$ gdb ./debug_prog
(gdb) target remote | vgdb
(gdb) break linenum
(gdb) next
(gdb) step
(gdb) monitor leak_check full reachable any
(gdb) kill
(gdb) quit

若只是單純檢查 memory leak
$ valgrind --tool=memcheck --leak-check=full ./debug_prog

suppression 一些錯誤
$ valgrind --tool=memcheck --leak-check=full --gen-suppressions=all ./debug_prog
...
{
   <insert_a_suppression_name_here>
   Memcheck:Leak
   match-leak-kinds: definite
   fun:malloc
   fun:g_malloc
   obj:/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.4
   fun:call_init
   fun:_dl_init
   obj:/lib/x86_64-linux-gnu/ld-2.27.so
}
...

利用上個命令的輸出,產生 local.supp 檔
$ valgrind --tool=memcheck --leak-check=full --supressions=./local.supp ./debug_prog
$ valgrind --tool=memcheck --leak-check=full --gen-suppressions=all --log-file=supp.log --supressions=./local.supp ./debug_prog
$ cat ./supp.log | ./suppressions.sh > local.supp
$ valgrind --tool=memcheck --leak-check=full --supressions=./local.supp --supressions=./gtk.supp ./debug_prog

suppressions.sh 若產生下列錯誤
awk: 34: unexpected character '&'
需改變 awk 的版本為 gawk
$ awk -W version
$ sudo apt-get update
$ sudo apt-get install gawk

去除 definitely loss
== 16,384 bytes in 1 blocks are definitely lost in loss record 1,443 of 1,448
==    at 0x4C330C5: malloc (vg_replace_malloc.c:393)
==    by 0x6A0BBD8: g_malloc (gmem.c:99)
==    by 0x6A1674B: g_quark_init (gquark.c:62)
==    by 0x40108D2: call_init (dl-init.c:72)
==    by 0x40108D2: _dl_init (dl-init.c:119)
==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

下載 gst.supp 和 glib.supp gtk.supp
https://gitlab.freedesktop.org/gstreamer/common/-/blob/master/gst.supp
https://github.com/GNOME/glib/blob/main/tools/glib.supp
https://gist.github.com/pendingchaos/81feddb95c06aeb58e2f

Makefile 的
CFLAGS+= -g -O0

安裝 libglib 的 debug symbols 版本
$ echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse
deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | \
sudo tee -a /etc/apt/sources.list.d/ddebs.list
$ sudo apt install ubuntu-dbgsym-keyring
$ sudo apt update
$ sudo apt install libglib2.0-bin-dbgsym libglib2.0-0-dbgsym libglib2.0-dev-bin-dbgsym


export G_DEBUG=gc-friendly
export G_SLICE=always-malloc

valgrind -v --time-stamp=yes --tool=memcheck --leak-check=full \
  --gen-suppressions=all --log-file=supp.log \
  --suppressions=./glib.supp \
  --suppressions=./gst.supp \
  --suppressions=./gtk.supp \
  ./main

常用觀測記憶體使用狀態命令
$ while true; do echo -n `date +"%Y/%m/%d %H:%M:%S"`" " | tee -a aaa.log ; grep "VmRSS" /proc/26885/status | tee -a aaa.log ; sleep 60 ; done
$ watch "grep 'VmRSS\|VmPeak\|VmData\|VmStk\|VmExe\|VmLib\|Threads' /proc/26885/status" 


2023年3月21日 星期二

deepstream create_pipeline 分析

/opt/nvidia/deepstream/deepstream-6.0/sources/apps/sample_apps/deepstream-app/deepstream_app.c
create_pipeline (AppCtx * appCtx,
    bbox_generated_callback bbox_generated_post_analytics_cb,
    bbox_generated_callback all_bbox_generated_cb, perf_callback perf_cb,
    overlay_graphics_callback overlay_graphics_cb)
{
    multi_src_bin = create_multi_source_bin {
        sub_bins[] = create_camera_source_bin | 
            create_uridecode_src_bin | 
            create_rtsp_src_bin | 
            create_uridecode_src_bin_audio;
        sub_bins[] - nvstreammux;
    };
    create_common_elements {
        secondary_gie_bin = create_secondary_gie_bin {
            sub_bins[] = create_secondary_gie {
                secondary_gie = nvinfer | nvinferserver
                if (num_children == 0) {
                    queue - secondary_gie - fakesink
                } else {
                    queue - secondary_gie - tee
                }
            };
            tee - queue
            tee - sub_bins[]...
        };
        dsanalytics_bin = create_dsanalytics_bin {
            queue - nvdsanalytics
        };
        tracker_bin = create_tracking_bin { nvtracker };
        primary_gie_bin = create_primary_gie_bin {
            queue - nvvideoconvert - (nvinfer | nvinferserver) 
        };
        preprocess_bin = create_preprocess_bin {
            queue | nvdspreprocess
        };
        common_elements = nvmsgconv - tee
        {   preprocess_bin - primary_gie_bin - tracker_bin - 
            dsanalytics_bin - secondary_gie_bin - common_elements - 
            tee
        };
        secondary_gie_bin(src) -> bbox_generated_post_analytics_cb()
        sink_elem = preprocess_bin
        src_elem = tee
    };
    dsexample_bin = create_dsexample_bin { 
        queue - nvvideoconvert - capsfilter - dsexample 
    };
    demuxer = { nvstreamdemux };
    instance_bins[] = create_processing_instance {
        osd_bin = create_osd_bin { 
            queue - nvvideoconvert - queue - nvdsosd 
        };
        sink_bin = create_sink_bin {
            sub_bins[] = create_render_bin | 
                create_encode_file_bin | 
                create_udpsink_bin | 
                create_msg_conv_broker_bin
            queue - tee - sub_bins[]
        };
        osd_bin - sink_bin
        (sink)osd_bin -> all_bbox_generated_cb()
        (sink)osd_bin -> overlay_graphics_cb()
    };
    demux_instance_bins[] = create_demux_pipeline {
        osd_bin = create_osd_bin {
            queue - nvvideoconvert - queue - nvdsosd 
        };
        demux_sink_bin = create_demux_sink_bin {
            sub_bins[] = create_render_bin |
                create_encode_file_bin |
                create_udpsink_bin |
                create_msg_conv_broker_bin
            queue - tee - sub_bins[]
        };
        osd_bin - demux_sink_bin
    };
    tiled_display_bin = create_tiled_display_bin {
        queue - nvmultistreamtiler
    };
    if (tiled_display_config.enable) {
        multi_src_bin - (sink_elem-src_elem) - dsexample_bin - tiler_tee
            tiler_tee - nvstreamdemux - demux_instance_bins[]
            tiler_tee - tiled_display_bin - instance_bins[]
    } else {
        multi_src_bin - (sink_elem-src_elem) - dsexample_bin - demuxer - instance_bins[]
    };
};

2023年3月17日 星期五

ubuntu cpu 工作頻率設定

$ sudo apt-get install cpufrequtils
$ cpufreq-info
$ for i in {0..15}
> do
>   sudo cpufreq-set -d 800000 -u 3200000 -c $i
> done
$ watch -n1 "grep Hz /proc/cpuinfo | grep -v model"
$ watch sensors