Thuật toán tích chập nhanh & chính xác (như FFT) cho dải động cao?


8

Dường như tích chập dựa trên FFT chịu độ phân giải dấu phẩy động hạn chế do đánh giá mọi thứ xung quanh gốc rễ của sự thống nhất, như bạn có thể thấy trong lỗi trong mã Python này:1014

from scipy.signal import convolve, fftconvolve
a = [1.0, 1E-15]
b = [1.0, 1E-15]
convolve(a, b)     # [  1.00000000e+00,   2.00000000e-15,   1.00000000e-30]
fftconvolve(a, b)  # [  1.00000000e+00,   2.11022302e-15,   1.10223025e-16]

Có bất kỳ thuật toán tích chập nhanh nào không gặp phải vấn đề này không?
Hoặc là tích chập trực tiếp (bậc hai) là cách duy nhất để có được một giải pháp chính xác?

(Cho dù số lượng nhỏ như vậy có đủ ý nghĩa để không bị cắt giảm bên cạnh quan điểm của tôi.)


Lưu ý rằng convolve()chỉ cần gọi fftconvolve()ngay bây giờ, nếu kích thước đầu vào lớn. Chỉ định method='direct'nếu bạn muốn trực tiếp.
endolith

@endolith: Điểm tốt! Tôi mới học được điều đó gần đây nhưng quên nó ở đây.
dùng541686

Câu trả lời:


5

Tuyên bố miễn trừ trách nhiệm: Tôi biết chủ đề này cũ hơn, nhưng nếu một người đang tìm kiếm "dải động cao tích chập chính xác nhanh" hoặc tương tự thì đây là một trong những kết quả đầu tiên chỉ có một vài kết quả tốt. Tôi muốn chia sẻ những hiểu biết của tôi về chủ đề này để nó có thể giúp đỡ ai đó trong tương lai. Tôi xin lỗi nếu tôi có thể sử dụng các thuật ngữ sai trong câu trả lời của mình, nhưng mọi thứ tôi tìm thấy trong chủ đề này khá mơ hồ và dẫn đến nhầm lẫn ngay cả trong chủ đề này. Tôi hy vọng người đọc sẽ hiểu.

Tích chập trực tiếp hầu hết chính xác với độ chính xác của máy cho từng điểm, nghĩa là sai số tương đối thường xấp xỉ hoặc gần bằng 1.e-16 cho độ chính xác kép cho mỗi điểm của kết quả. Mỗi điểm có 16 chữ số đúng. Tuy nhiên, các lỗi làm tròn có thể có ý nghĩa đối với các kết quả lớn bất thường, và nói đúng ra, người ta nên cẩn thận với việc hủy bỏ và sử dụng một cái gì đó như tổng hợp Kahan và các loại dữ liệu chính xác đủ cao, nhưng trong thực tế, lỗi này hầu như luôn luôn tối ưu.

Lỗi của tích chập FFT ngoài lỗi làm tròn là lỗi "tương đối toàn cục", nghĩa là lỗi ở mỗi điểm phụ thuộc vào độ chính xác của máy và giá trị cực đại của kết quả. Ví dụ: nếu giá trị đỉnh của kết quả là 2.e9, thì sai số tuyệt đối ở mỗi điểm là . Vì vậy, nếu một giá trị trong kết quả được cho là rất nhỏ, hãy giả sử21091016=2107109, lỗi tương đối ở điểm đó có thể rất lớn. Tích chập FFT về cơ bản là vô dụng nếu bạn cần các lỗi tương đối nhỏ ở phần đuôi của kết quả, ví dụ: bạn có sự phân rã theo cấp số nhân của dữ liệu và cần các giá trị chính xác ở phần đuôi. Thật thú vị nếu tích chập FFT không bị giới hạn bởi lỗi đó, nó có các lỗi làm tròn nhỏ hơn nhiều so với tích chập trực tiếp, vì rõ ràng bạn thực hiện ít phép cộng / nhân. Đây thực sự là lý do tại sao mọi người thường tuyên bố tích chập FFT là chính xác hơn, và họ gần như đúng theo một nghĩa nào đó, vì vậy họ có thể khá kiên quyết.

Unforunately có không sửa chữa phổ biến dễ dàng để có được nhanh và chính xác nhiều nếp cuộn, nhưng tùy thuộc vào vấn đề của bạn có thể có một ... Tôi đã tìm thấy hai:

Nếu bạn có các hạt mịn có thể xấp xỉ tốt bằng một đa thức ở đuôi, thì Phương pháp Đa cực nhanh hộp đen với phép nội suy Ch Quashev có thể thú vị đối với bạn. Nếu hạt nhân của bạn "đẹp" thì điều này thực sự hoạt động hoàn hảo: bạn có được độ phức tạp tính toán tuyến tính (!) Và độ chính xác của máy. Nếu điều này phù hợp với vấn đề của bạn, bạn nên sử dụng nó. Tuy nhiên, nó không dễ thực hiện.

Đối với một số hạt nhân cụ thể (các hàm lồi tôi nghĩ, thường là từ mật độ xác suất), bạn có thể sử dụng "sự thay đổi theo cấp số nhân" để nhận được lỗi tối ưu trong một phần đuôi của kết quả. Có một luận án PHD và một github với việc thực hiện python bằng cách sử dụng nó một cách có hệ thống, và tác giả đã đưa ra kết luận FFT chính xác . Tuy nhiên, trong hầu hết các trường hợp, điều này không hữu ích lắm, vì nó hồi quy trở lại tích chập trực tiếp hoặc dù sao bạn cũng có thể sử dụng tích chập FFT. Mặc dù mã tự động làm điều đó, tất nhiên là tốt.

--------------------BIÊN TẬP:--------------------

Tôi đã xem xét một chút về thuật toán Karatsuba (tôi thực sự đã thực hiện một triển khai nhỏ) và với tôi có vẻ như nó thường có hành vi lỗi tương tự như tích chập FFT, tức là bạn gặp lỗi liên quan đến giá trị cực đại của kết quả. Do tính chất phân chia và chinh phục của thuật toán, một số giá trị ở phần cuối của kết quả thực sự có lỗi tốt hơn, nhưng tôi không thấy một cách có hệ thống dễ dàng để biết cái nào hoặc trong bất kỳ trường hợp nào sử dụng quan sát này. Quá tệ, lúc đầu tôi nghĩ Karatsuba có thể là thứ gì đó hữu ích ở giữa sự kết hợp trực tiếp và FFT. Nhưng tôi không thấy các trường hợp sử dụng phổ biến trong đó Karatsuba nên được ưu tiên hơn hai thuật toán tích chập chung.

Và để thêm vào sự thay đổi theo cấp số nhân tôi đã đề cập ở trên: Có nhiều trường hợp bạn có thể sử dụng nó để cải thiện kết quả của một phép chập, nhưng một lần nữa, nó không phải là một sửa chữa phổ quát. Tôi thực sự sử dụng điều này cùng với tích chập FFT để có kết quả khá tốt (trong trường hợp chung cho tất cả các đầu vào: ở cùng một lỗi tồi tệ nhất với tích chập FFT bình thường, ở mức tương đối tốt nhất ở từng điểm đối với độ chính xác của máy). Nhưng một lần nữa, điều này chỉ thực sự hoạt động độc đáo đối với các nhân và dữ liệu cụ thể, nhưng đối với tôi cả nhân và dữ liệu hoặc phần nào theo cấp số nhân trong phân rã.


+1 chào mừng & cảm ơn bạn rất nhiều vì đã đăng bài này! :)
dùng541686

1
Ồ tôi cũng đã học được điều gì đó và đó là một thuật ngữ mới cho điều gì đó tôi đã làm từ năm 1993. Thuật toán tổng hợp Kahan này có vẻ giống hệt như những gì tôi đã gọi là tạo hình nhiễu bằng 0 trong hàm truyền nhiễu sang đầu ra đặt ngay tại DC hoặc số 0 được đặt tạiz=1 trên zmáy bay. Randy Yates gọi đó là " tiết kiệm phân số ", là một tên chung ngắn gọn cho nó. Tôi tự hỏi ai là mr / ms Kahan là ai và khi nào nó được ghi có.
robert bristow-johnson

2
Ấn bản gốc của Kahan dường như là từ năm 1964.
oli

hôm nay thật bất ngờ. Trên thực tế, một lúc nọ, @DanBoschen đã hỏi một câu đố dsp, xem xét phạm vi động của các số dấu phẩy động, thực ra là về khái niệm tương tự về việc thêm các số rất nhỏ vào các số rất lớn ...
Fat32

3

Một ứng cử viên là thuật toán Karatsuba , chạy trongO(Nlog23)O(N1.5849625)thời gian. Nó không dựa trên biến đổi. Ngoài ra còn có một số mã với lời giải thích trong Lưu trữ mã nguồn Music-DSP, trông giống như một khám phá độc lập về một thuật toán tương tự.

Kiểm tra việc triển khai Python của thuật toán Karatsuba (được cài đặt bởi sudo pip install karatsuba) bằng các số trong câu hỏi của bạn cho thấy rằng ngay cả với các số dấu phẩy động 64 bit, lỗi tương đối là lớn đối với một trong các giá trị đầu ra:

import numpy as np
from karatsuba import *
k = make_plan(range(2), range(2))
l = [np.float64(1), np.float64(1E-15)]
np.set_printoptions(formatter={'float': lambda x: format(x, '.17E')})
print "Karatsuba:"
print(k(l, l)[0:3])
print "Direct:"
print(np.convolve(l, l)[0:3])

bản in nào:

Karatsuba:
[1.0, 1.9984014443252818e-15, 1.0000000000000001e-30]
Direct:
[1.00000000000000000E+00 2.00000000000000016E-15 1.00000000000000008E-30]

2
Có thêm] ở cuối liên kết đến thuật toán Karatsuba

+1 bởi vì nó tuyệt vời và tôi chưa bao giờ nghĩ rằng Karatsuba là một thuật toán tích chập, nhưng thật tuyệt nếu bạn có thể giải thích tại sao nó nên giải quyết vấn đề này. Tôi có thể dễ dàng nhìn thấy nó cho trường hợp 2x2, nhưng trong cài đặt đệ quy chung, tôi không thấy lý do tại sao nó nên khắc phục vấn đề này. Nó có vẻ hợp lý với tôi rằng nó thậm chí có thể không thể sửa chữa nói chung, nhưng tôi không biết.
dùng541686

1
@OlliNiemitalo: Cách dễ dàng để giải thích là tôi muốn sai số tương đối thấp so với trực tiếp O(n2)tích chập. (Mọi định nghĩa hợp lý về "thấp" sẽ hoạt động ở đây ... lỗi tương đối tôi gặp phải với FFT là như1014không phải là thấp theo bất kỳ định nghĩa nào.)
user541686

1
Các nhân đôi của IEEE chỉ có độ chính xác từ 15 đến 16 chữ số thập phân trong trường hợp chung. Vì vậy, 1e-14 là một lỗi kích thước hợp lý cho một chuỗi một số phép toán số học (trừ khi bạn chọn một vài giá trị ma thuật).
hotpaw2

1
Nếu bạn đã từng thiết kế một bộ cộng điểm nổi, bạn sẽ biết rằng số mũ được xác định bởi kết quả mantissa trong quá trình chuẩn hóa. Bạn đã chọn những con số tạo ra một lớp phủ hẹp không chắc chắn.
hotpaw2

3

Thay vì loại bỏ thuật toán tích chập nhanh, tại sao không sử dụng FFT với dải động cao hơn?

Một câu trả lời cho câu hỏi này cho thấy cách sử dụng thư viện Eigen FFT với tính năng đa bội hóa.


2

Tôi tin rằng độ chính xác của thuật toán Cordic có thể được mở rộng theo như bạn muốn, nếu vậy hãy sử dụng một DFT số nguyên và độ dài từ phù hợp với vấn đề của bạn.

Điều tương tự cũng sẽ đúng với tích chập trực tiếp, sử dụng số nguyên rất dài.


1

Phép tích phân thời gian bậc hai để có kết quả DFT thường kém chính xác hơn (có thể phát sinh nhiễu số lượng tử hữu hạn hơn, do phân lớp sâu hơn các bước số học) so với thuật toán FFT thông thường khi sử dụng cùng loại số học và đơn vị vận hành.

Bạn có thể muốn thử các loại dữ liệu có độ chính xác cao hơn (số học chính xác hoặc số học bignum).


Er, đây sử dụng cùng loại số học và đơn vị hoạt động phải không? Rõ ràng nó chính xác hơn. Tôi nghĩ loại tiếng ồn mà bạn đang nói không giống với loại tiếng tôi đang nói. Nguồn gốc của sự thống nhất có độ lớn bằng 1, có nghĩa là chúng đơn giản không thể đại diện cho các giá trị rất nhỏ. Điều này dường như không hoàn toàn liên quan đến câu hỏi làm thế nào tiếng ồn lan truyền qua hệ thống.
dùng541686

Nó chỉ có vẻ chính xác hơn trong ví dụ của bạn bởi vì bạn đã chọn độ dài và giá trị trong đó việc làm tròn xảy ra có lợi cho bạn. Hãy thử một loạt các kết cấu dài hơn nhiều với nhiều hệ số khác không với phân bố chứa một độ lớn.
hotpaw2

Vấn đề tôi đang cố gắng giải quyết không liên quan gì đến làm tròn. Đó là một vấn đề khác tôi không cố gắng giải quyết. Các ví dụ ban đầu tôi có giống hệt như những gì bạn vừa nói, và chúng hoạt động tốt với tích chập trực tiếp nhưng đã bị FFT phá hủy.
dùng541686

Làm tròn (hoặc các phương pháp lượng tử hóa khác) có liên quan đến tất cả các số học chính xác hữu hạn. Một số kết quả tính toán thay đổi khi làm tròn, số khác không hoặc thay đổi ít hơn.
hotpaw2

Tôi không bao giờ tuyên bố khác. Điều tôi vừa nói với bạn là vấn đề tôi đang cố gắng giải quyết không liên quan gì đến làm tròn số. Đó là một vấn đề khác. Tôi không quan tâm để tránh làm tròn, nhưng tôi quan tâm để tránh vấn đề này.
dùng541686
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.