NumPy 텐서의 결합 시간을 비교해 본다

13837 단어 파이썬numpy

의문



NumPy 의 텐서 ndarray 는 concatenate 또는 stack를 사용하여 결합할 수 있습니다. 여기서, 텐서를 수시로 생성해 그들을 결합한 새로운 텐서를 요구하고 싶었을 때,
  • 한 번 목록에 넣고 나서 마지막으로 정리해 결합하는지,
  • 생성된 텐서를 순차적으로 결합해 나가는지,

  • 어느 것이 빠릅니까? 보통으로 생각하면 단번에 결합하는 편이 빠를 것 같은 생각은 합니다만, 리스트는 어쩐지 늦다고 하는 이미지도 있습니다. 어느 쪽에서 태어난 이미지야 이거.

    자, 실험해 봅시다.

    대량 생성 코드



    아래의 코드를 num 를  5000 씩 증가시켜 그 실행 시간을 비교해 보겠습니다.
    from typing import List
    import datetime
    import random
    import time
    
    import numpy as np
    
    num = 5000
    
    def listing(num: int) -> np.ndarray:
        random.seed(0)
        arr_list: List[np.ndarray] = []
        for i in range(num):
            rand1: List[List[float]] = []
            for i in range(3):
                rand1.append([random.random(), random.random(), random.random(),])
            now_arr = np.asarray(rand1)
            arr_list.append(now_arr[np.newaxis, ...])
        return np.vstack(arr_list)
    
    def stacking(num: int) -> np.ndarray:
        random.seed(0)
        rand2: List[List[float]] = []
        for i in range(3):
            rand2.append([random.random(), random.random(), random.random(),])
        ret_arr = np.asarray(rand2)[np.newaxis, ...]
        for i in range(num - 1):
            rand3: List[List[float]] = []
            for i in range(3):
                rand3.append([random.random(), random.random(), random.random(),])
            now_arr = np.asarray(rand3)
            ret_arr = np.vstack((ret_arr,now_arr[np.newaxis, ...],))
        return ret_arr
    
    list_start_time = time.time()
    list_arr = listing(num)
    list_end_time = time.time()
    list_elapsed_time = list_end_time - list_start_time
    
    stack_start_time = time.time()
    stack_arr = stacking(num)
    stack_end_time = time.time()
    stack_elapsed_time = stack_end_time - stack_start_time
    
    print('list time: ' + str(datetime.timedelta(seconds=list_elapsed_time)))
    print('stack time: ' + str(datetime.timedelta(seconds=stack_elapsed_time)))
    
    

    결과는 다음과 같습니다. 역시 한 번에 결합하는 편이 빠른 것 같네요. 보고 싶어.



    list
    stack


    5000
    00:00.021
    00:00.068

    10000
    00:00.041
    00:00.186

    15000
    00:00.059
    00:00.618

    20000
    00:00.080
    00:02.843

    25000
    00:00.105
    00:06.640

    30000
    00:00.118
    00:09.918

    35000
    00:00.136
    00:13.639

    40000
    00:00.157
    00:18.389

    45000
    00:00.176
    00:24.626

    50000
    00:00.196
    00:30.691

    55000
    00:00.216
    00:37.342

    60000
    00:00.234
    00:44.673

    65000
    00:00.259
    00:52.917

    70000
    00:00.273
    01:02.477

    75000
    00:00.295
    01:11.633

    80000
    00:00.317
    01:21.016

    85000
    00:00.334
    01:31.909

    90000
    00:00.350
    01:43.772

    95000
    00:00.372
    01:58.346

    100000
    00:00.409
    02:09.706


    한 번에 결합하는 쪽은 처리 시간이 선형으로 증가하는 반면, 매번 결합에서는  2 승에 비례하고 있는 것처럼 보입니다. 오더의 관점에서는 생성수가 많을수록 매번 결합이 불리해집니다.




    소량 생성 코드



    그럼, 생성수가 적은 경우는 어떨까요. num 는  3 회로 억제하고, 그것을 100000 회 반복하여 시간을 계측해 봅니다.
    # 前略
    
    times = 100000
    
    list_start_time = time.time()
    for i in range(times):
        list_arr = listing(num)
    list_end_time = time.time()
    list_elapsed_time = list_end_time - list_start_time
    
    stack_start_time = time.time()
    for i in range(times):
        stack_arr = stacking(num)
    stack_end_time = time.time()
    stack_elapsed_time = stack_end_time - stack_start_time
    
    print('list time: ' + str(datetime.timedelta(seconds=list_elapsed_time)))
    print('stack time: ' + str(datetime.timedelta(seconds=stack_elapsed_time)))
    
    # list time: 0:00:02.036575
    # stack time: 0:00:02.294834
    
    

    이 경우에는 방금전 차이는 노골적이지는 않지만 역시 한 번에 결합하는 것이 약간 빠릅니다.

    요약



    어떠셨습니까? 역시 빠릅니다.

    생각해 보면, 리스트가 늦을 것 같은 것은 도중에 삽입되거나 빗질했을 때에 인덱스 가는 것이 운운 같은 이야기가 대본인 생각이 들기 때문에 속공으로 소비한다면 별로 문제없는 생각도 하네요.

    그럼에도 불구하고 나는 Python이나 NumPy에 관해서는 초보자도 좋은 곳이므로 이런 경우에 더 나은 실천이있을 것 같다.

    좋은 웹페이지 즐겨찾기