Tối ưu hóa Python GDAL ReadAsArray


9

Tôi đang sử dụng phương pháp GDAL ReadAsArray để làm việc với dữ liệu raster bằng cách sử dụng numpy (cụ thể là phân loại lại). Vì các trình quét của tôi lớn, tôi xử lý các mảng trong các khối, lặp lại qua từng khối và xử lý bằng một phương thức tương tự như ví dụ GeoExamples .

Bây giờ tôi đang xem cách tốt nhất để đặt kích thước của các khối này để tối ưu hóa thời gian cần thiết để xử lý toàn bộ raster. Nhận thức được các hạn chế với kích thước mảng numpy và việc sử dụng GDAL GetBlockSize để sử dụng kích thước khối "tự nhiên" của raster, tôi đã thử nghiệm bằng cách sử dụng một vài kích thước khối khác nhau, tạo thành bội số của kích thước "tự nhiên", với mã ví dụ dưới đây:

import timeit
try:
    import gdal
except:
    from osgeo import gdal

# Function to read the raster as arrays for the chosen block size.
def read_raster(x_block_size, y_block_size):
    raster = "path to large raster"
    ds = gdal.Open(raster)
    band = ds.GetRasterBand(1)
    xsize = band.XSize
    ysize = band.YSize
    blocks = 0
    for y in xrange(0, ysize, y_block_size):
        if y + y_block_size < ysize:
            rows = y_block_size
        else:
            rows = ysize - y
        for x in xrange(0, xsize, x_block_size):
            if x + x_block_size < xsize:
                cols = x_block_size
            else:
                cols = xsize - x
            array = band.ReadAsArray(x, y, cols, rows)
            del array
            blocks += 1
    band = None
    ds = None
    print "{0} blocks size {1} x {2}:".format(blocks, x_block_size, y_block_size)

# Function to run the test and print the time taken to complete.
def timer(x_block_size, y_block_size):
    t = timeit.Timer("read_raster({0}, {1})".format(x_block_size, y_block_size),
                     setup="from __main__ import read_raster")
    print "\t{:.2f}s\n".format(t.timeit(1))

raster = "path to large raster"
ds = gdal.Open(raster)
band = ds.GetRasterBand(1)

# Get "natural" block size, and total raster XY size. 
block_sizes = band.GetBlockSize()
x_block_size = block_sizes[0]
y_block_size = block_sizes[1]
xsize = band.XSize
ysize = band.YSize
band = None
ds = None

# Tests with different block sizes.
timer(x_block_size, y_block_size)
timer(x_block_size*10, y_block_size*10)
timer(x_block_size*100, y_block_size*100)
timer(x_block_size*10, y_block_size)
timer(x_block_size*100, y_block_size)
timer(x_block_size, y_block_size*10)
timer(x_block_size, y_block_size*100)
timer(xsize, y_block_size)
timer(x_block_size, ysize)
timer(xsize, 1)
timer(1, ysize)

Mà tạo ra các loại đầu ra sau đây:

474452 blocks size 256 x 16:
        9.12s

4930 blocks size 2560 x 160:
        5.32s

58 blocks size 25600 x 1600:
        5.72s

49181 blocks size 2560 x 16:
        4.22s

5786 blocks size 25600 x 16:
        5.67s

47560 blocks size 256 x 160:
        4.21s

4756 blocks size 256 x 1600:
        5.62s

2893 blocks size 41740 x 16:
        5.85s

164 blocks size 256 x 46280:
        5.97s

46280 blocks size 41740 x 1:
        5.00s

41740 blocks size 1 x 46280:
        800.24s

Tôi đã thử chạy nó cho một vài trình quét khác nhau, với các kích thước và loại pixel khác nhau và dường như có xu hướng tương tự, trong đó tăng gấp 10 lần kích thước x hoặc y (trong một số trường hợp, cả hai) giảm một nửa thời gian xử lý, điều này mặc dù không đáng kể trong ví dụ trên, có thể có nghĩa là một số phút cho các raster lớn nhất của tôi.

Vì vậy, câu hỏi của tôi là, tại sao hành vi này xảy ra?

Tôi đã mong đợi sử dụng ít khối hơn để cải thiện thời gian xử lý, nhưng các thử nghiệm sử dụng ít nhất không phải là nhanh nhất. Ngoài ra, tại sao bài kiểm tra cuối cùng lại mất nhiều thời gian hơn bài kiểm tra trước đó? Có một số loại ưu tiên với các trình quét để đọc theo hàng hoặc cột, hoặc trong hình dạng của khối được đọc, tổng kích thước? Điều tôi hy vọng nhận được từ điều này là thông tin để có được một thuật toán cơ bản cùng nhau để có thể đặt kích thước khối của raster thành một giá trị tối ưu, tùy thuộc vào kích thước của đầu vào.

Lưu ý rằng đầu vào của tôi là một raster lưới ESRI ArcINFO, có kích thước khối "tự nhiên" là 256 x 16 và tổng kích thước của raster của tôi trong ví dụ này là 41740 x 46280.


Thử nghiệm tuyệt vời! giúp đỡ nhiều chúc mừng
Ê-sai Daniel

Câu trả lời:


4

Bạn đã thử sử dụng một blockize bằng nhau. Tôi xử lý dữ liệu raster có thứ tự 200k x 200k pixel và khá thưa thớt. Rất nhiều điểm chuẩn đã mang lại khối 256x256 pixel là hiệu quả nhất cho các quy trình của chúng tôi. Đây là tất cả để làm với bao nhiêu tìm kiếm đĩa được yêu cầu để lấy một khối. Nếu khối quá lớn thì việc ghi nó vào đĩa liền kề sẽ khó hơn, nghĩa là tìm kiếm nhiều hơn. Tương tự như vậy, nếu nó quá nhỏ, bạn sẽ cần thực hiện nhiều lần đọc để xử lý toàn bộ raster. Nó cũng giúp đảm bảo tổng kích thước là một sức mạnh của hai. 256x256 tình cờ là kích thước khối địa lý mặc định trong gdal, vì vậy có lẽ họ đã rút ra kết luận tương tự


Các khối 256 x 256 nhanh hơn một chút so với hầu hết các thử nghiệm khác (và bằng 2560 x 16 và 41740 x 1), nhưng chỉ khoảng 5%. Tuy nhiên, bằng cách chuyển đổi raster của tôi sang định dạng địa lý, đó là tùy chọn nhanh nhất ít nhất 20%, do đó, đối với các tiff ít nhất có vẻ là một lựa chọn tốt về kích thước khối. Gdal của tôi đã có khối địa lý mặc định chặn ở 128 x 128, mặc dù.
ssast

1
Có, nếu bạn có lựa chọn định dạng, geotiff là lựa chọn tốt nhất - cho đến nay thời gian phát triển nhất đã được đưa vào trình điều khiển này. Đồng thời thử nghiệm nén và nếu dữ liệu của bạn thưa thớt (nhiều giá trị null), bạn nên xem xét bằng cách sử dụng tùy chọn tạo SPARSE_OK và bỏ qua việc đọc / ghi các khối null
James

Rất tốt để biết để tham khảo trong tương lai, mặc dù tôi bị mắc kẹt với việc đọc lưới ESRI ArcINFO cho ví dụ đã cho.
ssast

Ngoài ra, để biết sự khác biệt giữa hai ví dụ cuối cùng, bạn sẽ muốn đọc về thứ tự chính hàng so với thứ tự chính của cột. Một lần nữa, có bao nhiêu yêu cầu tìm kiếm đĩa để xây dựng khối được yêu cầu.
James

1

Sự nghi ngờ của tôi là bạn đang thực sự va chạm với bộ đệm khối của GDAL và đó là một nút sẽ có tác động đáng kể đến đường cong tốc độ xử lý của bạn.

Xem cụ thể về SetConfigOptions , GDAL_CACHEMAXđể biết thêm chi tiết về điều này và điều tra cách thay đổi giá trị đó thành thứ gì đó lớn hơn đáng kể tương tác với mô phỏng của bạn.


Sau khi đặt bộ đệm thành 1 GB với gdal.SetCacheMax (1000000000), đã có một vài giây giảm qua hầu hết các thử nghiệm, ngoại trừ 1 x ysize cuối cùng, tăng tốc lên đến 40 giây. Giảm bộ nhớ cache xuống 1 mb thực sự tăng tốc tất cả các bài kiểm tra nhưng hai bài kiểm tra cuối cùng. Tôi nghĩ điều này là do tôi đang sử dụng kích thước khối tự nhiên cho hầu hết các thử nghiệm và không có khối chồng lấp, do đó, bộ đệm không cần thiết ngoại trừ hai thử nghiệm cuối cùng.
ssast
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.