엔터프라이즈급 보안: ISO 27001 및 SOC 2 Type I 규정을 준수합니다.

Link to this sectionYOLOv7: Trainable Bag-of-Freebies#

2022년 7월에 출시된 YOLOv7은 출시 당시 실시간 객체 탐지 분야에서 중요한 진전을 이루었습니다. 이 모델은 GPU V100에서 56.8%의 AP를 달성하며 출시 시점에 새로운 벤치마크를 세웠습니다. YOLOv7은 속도와 정확도 측면에서 YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5와 같은 기존 객체 탐지기들을 능가했습니다. 이 모델은 다른 데이터셋이나 사전 학습된 가중치를 사용하지 않고 MS COCO 데이터셋으로 밑바닥부터 학습되었습니다. YOLOv7의 소스 코드는 GitHub에서 확인할 수 있습니다. YOLO11YOLO26과 같은 최신 모델들은 이후 효율성이 개선되어 더 높은 정확도를 달성했음을 참고하시기 바랍니다.

SOTA 객체 탐지기와 YOLOv7 비교

Link to this sectionSOTA 객체 탐지기 비교#

YOLO 비교 표의 결과로부터 제안된 방법이 속도와 정확도 사이에서 종합적으로 가장 우수한 균형을 갖추고 있음을 알 수 있습니다. YOLOv7-tiny-SiLU를 YOLOv5-N (r6.1)과 비교하면, 저희 방법이 127 fps 더 빠르며 AP는 10.7% 더 정확합니다. 또한, YOLOv7은 161 fps의 프레임 속도에서 51.4%의 AP를 보이는 반면, 동일한 AP를 가진 PPYOLOE-L은 78 fps의 프레임 속도만을 제공합니다. 파라미터 사용량 면에서 YOLOv7은 PPYOLOE-L보다 41% 더 적습니다.

114 fps의 추론 속도를 가진 YOLOv7-X와 99 fps의 추론 속도를 가진 YOLOv5-L (r6.1)을 비교하면, YOLOv7-X는 AP를 3.9% 향상시킬 수 있습니다. YOLOv7-X를 비슷한 규모의 YOLOv5-X (r6.1)와 비교할 경우, YOLOv7-X의 추론 속도는 31 fps 더 빠릅니다. 또한 파라미터와 연산량 측면에서 YOLOv7-X는 YOLOv5-X (r6.1) 대비 파라미터는 22%, 연산량은 8% 감소시켰지만 AP는 2.2% 향상시켰습니다 (출처).

성능
모델파라미터
(M)
FLOPs
(G)
크기
(픽셀)
FPSAPtest / val
50-95
APtest
50
APtest
75
APtest
S
APtest
M
APtest
L
YOLOX-S9.026.864010240.5% / 40.5%-----
YOLOX-M25.373.86408147.2% / 46.9%-----
YOLOX-L54.2155.66406950.1% / 49.7%-----
YOLOX-X99.1281.96405851.5% / 51.1%-----
PPYOLOE-S7.917.464020843.1% / 42.7%60.5%46.6%23.2%46.4%56.9%
PPYOLOE-M23.449.964012348.9% / 48.6%66.5%53.0%28.6%52.9%63.8%
PPYOLOE-L52.2110.16407851.4% / 50.9%68.9%55.6%31.4%55.3%66.1%
PPYOLOE-X98.4206.66404552.2% / 51.9%69.9%56.5%33.3%56.3%66.4%
YOLOv5-N (r6.1)1.94.5640159- / 28.0%-----
YOLOv5-S (r6.1)7.216.5640156- / 37.4%-----
YOLOv5-M (r6.1)21.249.0640122- / 45.4%-----
YOLOv5-L (r6.1)46.5109.164099- / 49.0%-----
YOLOv5-X (r6.1)86.7205.764083- / 50.7%-----
YOLOR-CSP52.9120.464010651.1% / 50.8%69.6%55.7%31.7%55.3%64.7%
YOLOR-CSP-X96.9226.86408753.0% / 52.7%71.4%57.9%33.7%57.1%66.8%
YOLOv7-tiny-SiLU6.213.864028638.7% / 38.7%56.7%41.7%18.8%42.4%51.9%
YOLOv736.9104.764016151.4% / 51.2%69.7%55.9%31.8%55.5%65.0%
YOLOv7-X71.3189.964011453.1% / 52.9%71.2%57.8%33.8%57.1%67.4%
YOLOv5-N6 (r6.1)3.218.41280123- / 36.0%-----
YOLOv5-S6 (r6.1)12.667.21280122- / 44.8%-----
YOLOv5-M6 (r6.1)35.7200.0128090- / 51.3%-----
YOLOv5-L6 (r6.1)76.8445.6128063- / 53.7%-----
YOLOv5-X6 (r6.1)140.7839.2128038- / 55.0%-----
YOLOR-P637.2325.612807653.9% / 53.5%71.4%58.9%36.1%57.7%65.6%
YOLOR-W679.8453.212806655.2% / 54.8%72.7%60.5%37.7%59.1%67.1%
YOLOR-E6115.8683.212804555.8% / 55.7%73.4%61.1%38.4%59.7%67.7%
YOLOR-D6151.7935.612803456.5% / 56.1%74.1%61.9%38.9%60.4%68.7%
YOLOv7-W670.4360.012808454.9% / 54.6%72.6%60.1%37.3%58.7%67.1%
YOLOv7-E697.2515.212805656.0% / 55.9%73.5%61.2%38.0%59.9%68.4%
YOLOv7-D6154.7806.812804456.6% / 56.3%74.0%61.8%38.8%60.1%69.5%
YOLOv7-E6E151.7843.212803656.8% / 56.8%74.4%62.1%39.3%60.5%69.0%

Link to this section개요#

Real-time object detection is an important component in many computer vision systems, including multi-object tracking, autonomous driving, robotics, and medical image analysis. In recent years, real-time object detection development has focused on designing efficient architectures and improving the inference speed of various CPUs, GPUs, and neural processing units (NPUs). YOLOv7 supports both mobile GPU and GPU devices, from the edge to the cloud.

아키텍처 최적화에 중점을 두는 기존 실시간 객체 탐지기와 달리, YOLOv7은 학습 과정의 최적화에 집중합니다. 여기에는 추론 비용을 늘리지 않으면서 객체 탐지의 정확도를 높이기 위해 설계된 모듈 및 최적화 방법이 포함되며, 이를 "훈련 가능한 Bag-of-Freebies"라고 합니다.

Link to this section주요 특징#

YOLOv7은 다음과 같은 몇 가지 주요 기능을 도입합니다:

  1. 모델 재매개변수화(Model Re-parameterization): YOLOv7은 경사 전파 경로 개념을 통해 서로 다른 네트워크의 레이어에 적용할 수 있는 전략인 계획된 재매개변수화 모델을 제안합니다.

  2. 동적 라벨 할당(Dynamic Label Assignment): 다중 출력 레이어를 가진 모델의 학습은 "서로 다른 브랜치의 출력에 대해 어떻게 동적 타겟을 할당할 것인가?"라는 새로운 문제를 제시합니다. 이 문제를 해결하기 위해 YOLOv7은 coarse-to-fine lead guided label assignment라는 새로운 라벨 할당 방법을 도입합니다.

  3. 확장 및 복합 스케일링(Extended and Compound Scaling): YOLOv7은 매개변수와 계산을 효과적으로 활용할 수 있는 실시간 객체 탐지기를 위한 "확장" 및 "복합 스케일링" 방법을 제안합니다.

  4. 효율성(Efficiency): YOLOv7이 제안하는 방법은 최신 실시간 객체 탐지기 대비 매개변수를 약 40%, 계산량을 50% 효과적으로 줄일 수 있으며, 더 빠른 추론 속도와 더 높은 탐지 정확도를 제공합니다.

Link to this section사용 예제#

Ultralytics는 yolov7.pt 사전 학습된 가중치나 ultralytics/cfg/models/v7/ YAML 파일을 게시하지 않으며, YOLOv7에 대한 네이티브 PyTorch 학습 및 추론은 Ultralytics Python 패키지에서 지원되지 않습니다. 그러나 아래와 같이 ONNX 또는 TensorRT로 내보내어 업스트림 YOLOv7 저장소에서 학습된 YOLOv7 체크포인트를 Ultralytics로 가져올 수 있습니다.

Link to this sectionONNX 내보내기(Export)#

Ultralytics와 함께 YOLOv7 ONNX 모델을 사용하려면:

  1. (선택 사항) Ultralytics를 설치하고 ONNX 모델을 내보내 필요한 종속성을 자동으로 설치하십시오:

    pip install ultralytics
    yolo export model=yolo26n.pt format=onnx
  2. YOLOv7 저장소의 내보내기 도구를 사용하여 원하는 YOLOv7 모델을 내보내십시오:

    git clone https://github.com/WongKinYiu/yolov7
    cd yolov7
    python export.py --weights yolov7-tiny.pt --grid --end2end --simplify --topk-all 100 --iou-thres 0.65 --conf-thres 0.35 --img-size 640 640 --max-wh 640
  3. 다음 스크립트를 사용하여 Ultralytics와 호환되도록 ONNX 모델 그래프를 수정하십시오:

    import numpy as np
    import onnx
    from onnx import helper, numpy_helper
    
    # Load the ONNX model
    model_path = "yolov7/yolov7-tiny.onnx"  # Replace with your model path
    model = onnx.load(model_path)
    graph = model.graph
    
    # Fix input shape to batch size 1
    input_shape = graph.input[0].type.tensor_type.shape
    input_shape.dim[0].dim_value = 1
    
    # Define the output of the original model
    original_output_name = graph.output[0].name
    
    # Create slicing nodes
    sliced_output_name = f"{original_output_name}_sliced"
    
    # Define initializers for slicing (remove the first value)
    start = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_start")
    end = numpy_helper.from_array(np.array([7], dtype=np.int64), name="slice_end")
    axes = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_axes")
    steps = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_steps")
    
    graph.initializer.extend([start, end, axes, steps])
    
    slice_node = helper.make_node(
        "Slice",
        inputs=[original_output_name, "slice_start", "slice_end", "slice_axes", "slice_steps"],
        outputs=[sliced_output_name],
        name="SliceNode",
    )
    graph.node.append(slice_node)
    
    # Define segment slicing
    seg1_start = numpy_helper.from_array(np.array([0], dtype=np.int64), name="seg1_start")
    seg1_end = numpy_helper.from_array(np.array([4], dtype=np.int64), name="seg1_end")
    seg2_start = numpy_helper.from_array(np.array([4], dtype=np.int64), name="seg2_start")
    seg2_end = numpy_helper.from_array(np.array([5], dtype=np.int64), name="seg2_end")
    seg3_start = numpy_helper.from_array(np.array([5], dtype=np.int64), name="seg3_start")
    seg3_end = numpy_helper.from_array(np.array([6], dtype=np.int64), name="seg3_end")
    
    graph.initializer.extend([seg1_start, seg1_end, seg2_start, seg2_end, seg3_start, seg3_end])
    
    # Create intermediate tensors for segments
    segment_1_name = f"{sliced_output_name}_segment1"
    segment_2_name = f"{sliced_output_name}_segment2"
    segment_3_name = f"{sliced_output_name}_segment3"
    
    # Add segment slicing nodes
    graph.node.extend(
        [
            helper.make_node(
                "Slice",
                inputs=[sliced_output_name, "seg1_start", "seg1_end", "slice_axes", "slice_steps"],
                outputs=[segment_1_name],
                name="SliceSegment1",
            ),
            helper.make_node(
                "Slice",
                inputs=[sliced_output_name, "seg2_start", "seg2_end", "slice_axes", "slice_steps"],
                outputs=[segment_2_name],
                name="SliceSegment2",
            ),
            helper.make_node(
                "Slice",
                inputs=[sliced_output_name, "seg3_start", "seg3_end", "slice_axes", "slice_steps"],
                outputs=[segment_3_name],
                name="SliceSegment3",
            ),
        ]
    )
    
    # Concatenate the segments
    concat_output_name = f"{sliced_output_name}_concat"
    concat_node = helper.make_node(
        "Concat",
        inputs=[segment_1_name, segment_3_name, segment_2_name],
        outputs=[concat_output_name],
        axis=1,
        name="ConcatSwapped",
    )
    graph.node.append(concat_node)
    
    # Reshape to [1, -1, 6]
    reshape_shape = numpy_helper.from_array(np.array([1, -1, 6], dtype=np.int64), name="reshape_shape")
    graph.initializer.append(reshape_shape)
    
    final_output_name = f"{concat_output_name}_batched"
    reshape_node = helper.make_node(
        "Reshape",
        inputs=[concat_output_name, "reshape_shape"],
        outputs=[final_output_name],
        name="AddBatchDimension",
    )
    graph.node.append(reshape_node)
    
    # Get the shape of the reshaped tensor
    shape_node_name = f"{final_output_name}_shape"
    shape_node = helper.make_node(
        "Shape",
        inputs=[final_output_name],
        outputs=[shape_node_name],
        name="GetShapeDim",
    )
    graph.node.append(shape_node)
    
    # Extract the second dimension
    dim_1_index = numpy_helper.from_array(np.array([1], dtype=np.int64), name="dim_1_index")
    graph.initializer.append(dim_1_index)
    
    second_dim_name = f"{final_output_name}_dim1"
    gather_node = helper.make_node(
        "Gather",
        inputs=[shape_node_name, "dim_1_index"],
        outputs=[second_dim_name],
        name="GatherSecondDim",
    )
    graph.node.append(gather_node)
    
    # Subtract from 100 to determine how many values to pad
    target_size = numpy_helper.from_array(np.array([100], dtype=np.int64), name="target_size")
    graph.initializer.append(target_size)
    
    pad_size_name = f"{second_dim_name}_padsize"
    sub_node = helper.make_node(
        "Sub",
        inputs=["target_size", second_dim_name],
        outputs=[pad_size_name],
        name="CalculatePadSize",
    )
    graph.node.append(sub_node)
    
    # Build the [2, 3] pad array:
    # 1st row -> [0, 0, 0] (no padding at the start of any dim)
    # 2nd row -> [0, pad_size, 0] (pad only at the end of the second dim)
    pad_starts = numpy_helper.from_array(np.array([0, 0, 0], dtype=np.int64), name="pad_starts")
    graph.initializer.append(pad_starts)
    
    zero_scalar = numpy_helper.from_array(np.array([0], dtype=np.int64), name="zero_scalar")
    graph.initializer.append(zero_scalar)
    
    pad_ends_name = "pad_ends"
    concat_pad_ends_node = helper.make_node(
        "Concat",
        inputs=["zero_scalar", pad_size_name, "zero_scalar"],
        outputs=[pad_ends_name],
        axis=0,
        name="ConcatPadEnds",
    )
    graph.node.append(concat_pad_ends_node)
    
    pad_values_name = "pad_values"
    concat_pad_node = helper.make_node(
        "Concat",
        inputs=["pad_starts", pad_ends_name],
        outputs=[pad_values_name],
        axis=0,
        name="ConcatPadStartsEnds",
    )
    graph.node.append(concat_pad_node)
    
    # Create Pad operator to pad with zeros
    pad_output_name = f"{final_output_name}_padded"
    pad_constant_value = numpy_helper.from_array(
        np.array([0.0], dtype=np.float32),
        name="pad_constant_value",
    )
    graph.initializer.append(pad_constant_value)
    
    pad_node = helper.make_node(
        "Pad",
        inputs=[final_output_name, pad_values_name, "pad_constant_value"],
        outputs=[pad_output_name],
        mode="constant",
        name="PadToFixedSize",
    )
    graph.node.append(pad_node)
    
    # Update the graph's final output to [1, 100, 6]
    new_output_type = onnx.helper.make_tensor_type_proto(
        elem_type=graph.output[0].type.tensor_type.elem_type, shape=[1, 100, 6]
    )
    new_output = onnx.helper.make_value_info(name=pad_output_name, type_proto=new_output_type)
    
    # Replace the old output with the new one
    graph.output.pop()
    graph.output.extend([new_output])
    
    # Save the modified model
    onnx.save(model, "yolov7-ultralytics.onnx")
  4. 그런 다음 수정된 ONNX 모델을 로드하고 Ultralytics에서 평소와 같이 추론을 실행할 수 있습니다:

    from ultralytics import ASSETS, YOLO
    
    model = YOLO("yolov7-ultralytics.onnx", task="detect")
    
    results = model(ASSETS / "bus.jpg")

Link to this sectionTensorRT 내보내기(Export)#

  1. ONNX 내보내기 섹션의 1-2단계를 따르십시오.

  2. TensorRT Python 패키지를 설치하십시오:

    pip install tensorrt
  3. 다음 스크립트를 실행하여 수정된 ONNX 모델을 TensorRT 엔진으로 변환하십시오:

    from ultralytics.utils.export import export_engine
    
    export_engine("yolov7-ultralytics.onnx", half=True)
  4. Ultralytics에서 모델을 로드하고 실행하십시오:

    from ultralytics import ASSETS, YOLO
    
    model = YOLO("yolov7-ultralytics.engine", task="detect")
    
    results = model(ASSETS / "bus.jpg")

Link to this section인용 및 감사의 글#

실시간 객체 탐지 분야에 중요한 기여를 한 YOLOv7 저자들에게 감사를 표합니다:

인용
@inproceedings{wang2023yolov7,
  title={YOLOv7: Trainable Bag-of-Freebies Sets New State-of-the-Art for Real-Time Object Detectors},
  author={Wang, Chien-Yao and Bochkovskiy, Alexey and Liao, Hong-Yuan Mark},
  booktitle={Proceedings of the IEEE/CVF conference on Computer Vision and Pattern Recognition (CVPR)},
  pages={7464--7475},
  year={2023}
}

공식 YOLOv7 논문은 CVF 2023 Open Access에 게재되었으며, arXiv에 프리프린트가 있습니다. 저자들은 그들의 연구 결과를 공개적으로 제공했으며, 코드베이스는 GitHub에서 액세스할 수 있습니다. 우리는 이 분야의 발전과 연구 결과를 더 넓은 커뮤니티가 이용할 수 있도록 노력한 저자들의 공로를 높이 평가합니다.

Link to this sectionFAQ#

Link to this sectionYOLOv7이란 무엇이며 왜 실시간 객체 탐지 분야에서 혁신적인 것으로 간주됩니까?#

2022년 7월에 발표된 YOLOv7은 출시 당시 탁월한 속도와 정확도를 달성한 중요한 실시간 객체 탐지 모델이었습니다. 이 모델은 매개변수 사용량과 추론 속도 면에서 YOLOX, YOLOv5, PPYOLOE와 같은 동시대 모델들을 능가했습니다. YOLOv7의 두드러진 특징은 모델 재매개변수화와 동적 라벨 할당으로, 이는 추론 비용을 늘리지 않으면서 성능을 최적화합니다. 아키텍처에 대한 기술적 세부 정보 및 다른 최신 객체 탐지기와의 비교 지표는 YOLOv7 논문을 참조하십시오.

Link to this sectionYOLOv7은 YOLOv4 및 YOLOv5와 같은 이전 YOLO 모델을 어떻게 개선했습니까?#

YOLOv7은 모델 재매개변수화 및 동적 라벨 할당을 포함한 여러 혁신을 도입하여 학습 과정을 개선하고 추론 정확도를 높였습니다. YOLOv5와 비교할 때, YOLOv7은 속도와 정확도를 크게 향상시켰습니다. 예를 들어, YOLOv7-X는 YOLOv5-X에 비해 정확도를 2.2% 향상시키고 매개변수를 22% 줄였습니다. 자세한 비교는 SOTA 객체 탐지기 비교 성능 표에서 확인할 수 있습니다.

Link to this sectionYOLOv7을 Ultralytics 도구 및 플랫폼과 함께 사용할 수 있습니까?#

현재 Ultralytics는 YOLOv7 ONNX 및 TensorRT 추론만 지원합니다. Ultralytics에서 YOLOv7의 ONNX 및 TensorRT 내보내기 버전을 실행하려면 사용 예시 섹션을 확인하십시오.

Link to this section내 데이터셋을 사용하여 사용자 지정 YOLOv7 모델을 학습하려면 어떻게 해야 합니까?#

사용자 지정 YOLOv7 모델을 설치하고 학습하려면 다음 단계를 따르십시오:

  1. YOLOv7 저장소를 복제(Clone)하십시오:

    git clone https://github.com/WongKinYiu/yolov7
  2. 복제된 디렉토리로 이동하여 종속성을 설치하십시오:

    cd yolov7
    pip install -r requirements.txt
  3. 저장소에서 제공하는 사용 지침에 따라 데이터셋을 준비하고 모델 매개변수를 구성하십시오. 추가 안내가 필요하면 최신 정보 및 업데이트를 위해 YOLOv7 GitHub 저장소를 방문하십시오.

  4. 학습 후에는 사용 예시에 표시된 대로 모델을 ONNX 또는 TensorRT로 내보내 Ultralytics에서 사용할 수 있습니다.

Link to this sectionYOLOv7에서 도입된 주요 기능과 최적화는 무엇입니까?#

YOLOv7은 실시간 객체 탐지를 혁신하는 몇 가지 주요 기능을 제공합니다:

  • 모델 재매개변수화(Model Re-parameterization): 경사 전파 경로를 최적화하여 모델의 성능을 향상시킵니다.
  • 동적 라벨 할당(Dynamic Label Assignment): coarse-to-fine lead guided 방법을 사용하여 여러 브랜치의 출력에 동적 타겟을 할당함으로써 정확도를 향상시킵니다.
  • 확장 및 복합 스케일링(Extended and Compound Scaling): 매개변수와 계산을 효율적으로 활용하여 다양한 실시간 애플리케이션에 맞게 모델을 확장합니다.
  • 효율성(Efficiency): 다른 최신 모델 대비 매개변수 수를 40%, 계산량을 50% 줄이는 동시에 더 빠른 추론 속도를 달성합니다.

이러한 기능에 대한 자세한 내용은 YOLOv7 개요 섹션을 참조하십시오.

댓글