Kita harus menambahkan variabel global untuk memaksa PyTorch menggunakan algoritma deterministik bitwise. Soumith menyarankan untuk menambahkan flag ke sub-paket torch.experimental
karena kami tidak yakin tentang beberapa detailnya.
Determinisme bitwise antar run terkadang berguna untuk debugging. Namun, sulit untuk menulis algoritma deterministik yang efisien untuk beberapa operasi.
Ketika torch.experimental.deterministic
adalah False
(default), PyTorch harus menggunakan algoritme tercepat yang tersedia untuk operasi tertentu. Ketika torch.experimental.deterministic
adalah True
, PyTorch hanya boleh menggunakan algoritme deterministik. PyTorch harus mengeluarkan peringatan jika kita tidak memiliki algoritme deterministik yang tersedia untuk operasi tertentu dan torch.experimental.deterministic
adalah True
.
Kita sudah memiliki flag torch.backends.cudnn.deterministic
untuk mengontrol pilihan algoritma cuDNN. Kita harus menyimpan flag ini untuk saat ini dan membatasi cuDNN ke algo deterministik jika torch.backends.cudnn.deterministic
atau torch.experimental.deterministic
adalah True.
Kami hanya bertujuan untuk determinisme bitwise antara berjalan pada mesin dengan arsitektur dan konfigurasi yang sama. Misalnya, bahkan ketika torch.experimental.deterministic
Benar, kami tidak bertujuan untuk determinisme bitwise ketika salah satu dari berikut ini bervariasi:
Saya sarankan menambahkan fitur ini dalam dua langkah. Langkah pertama adalah menambahkan flag torch.backends.cudnn.deterministic
dan menambahkan peringatan ke operasi non-deterministik. Langkah kedua adalah menambahkan implementasi deterministik untuk operasi non-deterministik.
Ada sebagian daftar operasi non-deterministik di dokumen PyTorch .
Bagaimana seharusnya torch.experimental.deterministic
berinteraksi dengan benih RNG? Haruskah itu menetapkan seed default jika tidak ada seed manual yang disetel? Haruskah itu mengeluarkan peringatan jika tidak ada seed manual yang disetel?
cc @ezyang @gchanan @zou3519
Ini acungan jempol dari saya. Masalah utamanya adalah bagaimana benar-benar meluncurkan ini di mana-mana di basis kode; tidak ada yang lebih buruk untuk mengklaim bahwa kita deterministik, tetapi kemudian diam-diam tidak :)
Saya setuju dan pendekatan saya adalah menandai operasi dan kesalahan ketika deterministik aktif dan kami tahu mereka tidak.
Saya pikir kesalahan pada operasi non-deterministik terlalu keras. Peringatan sepertinya pengalaman yang lebih lancar
Saya pikir defaultnya adalah melempar, tetapi saya kira kita dapat mendukung properti multi-nilai di sana (non-deterministik tidak apa-apa, peringatkan, lempar).
Saya harus mengakui bahwa saya tidak benar-benar melihat kasus penggunaan peringatan. Ketika orang cukup peduli dengan deterministik untuk mengaktifkannya, mereka mungkin mengharapkan kesalahan. Anda selalu dapat mematikannya untuk panggilan tertentu untuk mengatakan bahwa Anda setuju dengan nondeterminisme apa pun yang ada di sana.
Kesalahan, peringatan, dokumentasi yang tepat...
Yang terakhir adalah suatu keharusan.
Peringatan atau kesalahan? Aku akan pergi dengan kesalahan.
melempar tampak hebat. Saya setuju dengan Adam bahwa memberikan opsi untuk memperingatkan daripada melempar tampaknya masuk akal.
Terima kasih telah menimbang. Pada akhirnya, upaya utama untuk bendera ternary adalah bendera itu sendiri, dan itu tidak sulit.
Saya akan menambahkan bendera ke Context.h dan memercikkan (melalui fungsi utilitas) AT_ERROR dan AT_CHECK.
Halo,
Ada berita tentang bendera ini?
Determinisme sangat penting.
Dari pengalaman saya, versi saat ini memungkinkan determinisme lebih dari satu gpu, hingga presisi 1e-16
, menggunakan benih tetap. Perhatikan bahwa perbedaan yang sangat kecil dapat diperbesar dan hasilnya divergen.
Tolong, pertimbangkan kasus multigpu juga (setidaknya untuk K
gpus tetap, perilakunya harus deterministik. Saya dapat mencapai semacam determinisim yang rusak dari waktu ke waktu karena suatu alasan saya tidak mengerti untuk saat ini (menggunakan nightly build 1.2.0.dev20190616
).). Saya berjuang dengan itu sekarang ( 1 , 2 ).
Terima kasih!
@t-vi apakah Anda aktif mengerjakan ini?
Saya tidak ingin mencegah Anda melakukannya.
@t-vi Maaf jika saya tidak jelas, saya tidak berencana untuk mengerjakan ini :) . Hanya mencoba memahami apakah ada orang yang secara aktif melakukannya.
Setelah hampir satu tahun, masalah interpolasi non-deterministik masih belum terpecahkan.
Semoga komunitas dapat menambahkan fitur ini :)
Mungkin interpolasi deterministik akan sangat membantu pengguna.
~ Saya belum benar-benar mengiklankannya, tetapi mengingat bahwa tampaknya ada lebih banyak minat pengguna daripada sumber daya pengembang yang dialokasikan, saya mencantumkan ini sebagai proyek yang dapat Anda pilih di halaman sponsor github saya ketika saya mengatur ini.
Saya cukup yakin kami dapat membuat kemajuan yang baik pada akhir tahun dan interpolasi tentu saja adalah salah satu hal yang saya punya rencana untuk memperbaikinya (mirip dengan pseudocode untuk fold bahwa saya ada di suatu tempat dalam masalah) tetapi tidak tidak termasuk dalam daftar prioritas saya sendiri.~
Ternyata tidak menarik.
interpolasi deterministik akan sangat membantu. tautan
Prioritas menabrak, terutama untuk CUDA, berdasarkan umpan balik pengguna
Saya senang sudah diperbaiki, terima kasih!
@t-vi untuk bersikap adil, saya tidak berpikir "prioritas menabrak" sama dengan "itu sedang diperbaiki" :).
Menantikan solusi
colesbury menyebutkan bahwa satu alasan pembunuh untuk algoritme deterministik bukanlah karena determinisme sebenarnya masalahnya, tetapi Anda dapat mengesampingkannya saat Anda mengaktifkannya;)
Bagaimana seharusnya
torch.experimental.deterministic
berinteraksi dengan benih RNG? Haruskah itu menetapkan seed default jika tidak ada seed manual yang disetel? Haruskah itu mengeluarkan peringatan jika tidak ada seed manual yang disetel?
Saya sarankan untuk tidak menyetel benih jika tidak ada yang disetel oleh pengguna. Untuk satu karena itu memasangkan dua antarmuka yang tidak diperlukan (pengguna yang peduli dengan determinisme akan memahami RNG dengan sangat baik, menurut saya). Lebih penting lagi, ini sangat sulit dilakukan dengan andal; seseorang dapat menggunakan RNG dalam aplikasi multi-proses/utas, memiliki subkelas torch.Generator
, menggunakan numpy.random
juga, dll.
Tidak yakin tentang peringatan, hanya jika ada tempat yang waras untuk mengaturnya (misalnya apakah Anda kemudian memaksa untuk menyemai sebelum determinism=True
daripada di modul/fungsi yang sama di mana RNG digunakan?).
Saya hanya ingin tahu bahwa ketika saya menetapkan torch.backends.cudnn.deterministic=True
, operator interpolasi masih tidak dapat deterministik. Apakah interpolasi pytorch tidak menggunakan cudnn ?
Mungkin tidak. Anda dapat nvprof menjalankan interpolasi Anda untuk memeriksa dengan pasti.
Saya bertanya-tanya apakah kita harus terus memberikan argumen deterministic
dalam panggilan fungsi setelah torch.experimental.deterministic
diimplementasikan. Mungkin kita harus melakukannya, karena pengguna mungkin lebih suka determinisme untuk beberapa operasi dan kecepatan untuk operasi lain.
Jika kita melakukan menjaga argumen, maka apa yang terjadi jika torch.experimental.deterministic
dan fungsi ini deterministic
bendera menentang satu sama lain. Haruskah torch.experimental.deterministic = True
berarti "gunakan determinisme dalam semua kasus, apa pun yang terjadi", atau haruskah itu berarti "gunakan determinisme sebagai nilai default, tetapi jika argumen deterministic
ditentukan dalam pemanggilan fungsi, maka gunakan pengaturan itu untuk panggilan fungsi tertentu itu." Dengan kata lain, bagaimana seharusnya kode di bawah ini ditangani? Adakah yang tahu bagaimana flag torch.backends.cudnn.deterministic
bekerja dalam situasi yang sama?
torch.experimental.deterministic = True
torch.some_operation(deterministic=False)
@kurtamohler Pertanyaan bagus. Saya pikir perbaikan termudah adalah membuatnya bool? deterministic=None
, dan kemudian menafsirkan None
berarti "menghormati torch.experimental.deterministic
", dan jika tidak, gunakan persis apa yang diminta pengguna.
Kami memiliki situasi yang mirip dengan konvolusi, tetapi cara yang dilakukan adalah bahwa ada convolution
tanpa argumen benchmark
, dan kemudian _convolution
dengan argumen eksplisit patokan.
Saya pikir salah satu dari solusi ini dapat diterima; namun, pendekatan konvolusi memiliki manfaat tambahan karena tidak membocorkan flag deterministic
internal ke API yang terlihat oleh pengguna (kecuali jika mereka menggunakan API internal).
Apa alasan untuk "Saya ingin menjadi deterministik di mana-mana, tetapi _tidak di operator khusus ini_"? Apakah ini benar-benar seharusnya menjadi kasus penggunaan yang cukup umum untuk menjamin penambahan input tambahan ke banyak operator kami (dan sebagian besar yang kompleks)? IMO akan lebih baik untuk menyediakan manajer konteks untuk mengaktifkan determinisme.
@apaszke , ya saya pikir Anda benar bahwa akan lebih baik menggunakan pengelola konteks untuk mengaktifkan determinisme. Saya tidak akan mengatakan bahwa kita harus menambahkan argumen deterministic
ke operator mana pun, tetapi beberapa operator sudah memilikinya. Apakah lebih baik untuk menghapus semua itu dan menghancurkan BC, atau akan lebih baik untuk menyimpannya dan membiarkannya menimpa torch.experimental.deterministic
?
Saya akan mengatakan bahwa kita harus menghapusnya atau menjadikannya pribadi setidaknya (yaitu awalan garis bawah atau sth).
Saya ingin tahu apakah fitur deterministik untuk fungsi interpolasi ditutup dan tidak akan diimplementasikan?
Tidak, kami menerima versi deterministik dari SEMUA fungsi di PyTorch
@ezyang versi pytorch mana yang memiliki fungsi F.interpolate deterministik? apakah ini mulai dari pytorch 1.6? atau tersedia dalam versi stabil terbaru (1.5)? atau apakah saya harus mengunduh dan menginstal Pytorch dari sumber?
Saya akan senang untuk mulai mengerjakan ini
Komit di atas hanya menambahkan bendera, itu belum memengaruhi operasi apa pun. Saya akan menghargai jika seseorang dapat meluangkan waktu beberapa menit untuk melihatnya dan memberi tahu saya jika saya melakukan sesuatu yang salah atau jika ada yang dapat diperbaiki sejauh ini. Saya mendasarkan ini dari bagaimana torch.backends.cudnn.deterministic
diimplementasikan.
Ini terlihat OK, tetapi saya merasa penamaan internal tidak boleh menyertakan eksperimental (karena, seolah-olah, suatu hari Anda ingin membuatnya tidak eksperimental, dan itu tidak harus melibatkan harus mengganti nama semua bit implementaiton!)
@ezyang , ya itu masuk akal, saya akan mengganti nama.
Saya menambahkan torch.experimental.deterministic_error_level
, mirip dengan apa yang dilakukan @t-vi dalam karya sebelumnya tentang masalah ini. deterministic_error_level
mengontrol perilaku kesalahan/peringatan jika deterministic == True
dan fungsi yang diberikan tidak memiliki implementasi deterministik. Itu dapat diatur ke 2 (kesalahan), 1 (peringatan), atau 0 (diam).
Jika pengguna menyetelnya ke nilai lain, saya ingin melempar pengecualian runtime python yang dapat ditangkap. Biasanya, saya akan menggunakan TORCH_CHECK()
untuk perilaku seperti itu, tetapi dalam kasus ini, pengecualian tidak dapat ditangkap dan saya tidak yakin mengapa. Inilah panggilan TORCH_CHECK()
: tautan
Inilah yang terjadi ketika pemeriksaan itu gagal:
>>> import torch
>>> try:
... torch.experimental.deterministic_error_level=50
... except:
... print('exception caught')
...
terminate called after throwing an instance of 'c10::Error'
what(): error level 50 is invalid, must be one of 0: None, 1: Warn, or 2: Error
Exception raised from longToErrorLevel at ../aten/src/ATen/Context.cpp:85 (most recent call first):
frame #0: c10::Error::Error(c10::SourceLocation, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) + 0x58 (0x7f53e2cc0878 in /work/kurtamohler/development/pytorch-deterministic-flag/torch/lib/libc10.so)
frame #1: at::Context::longToErrorLevel(long) + 0x122 (0x7f53f6d61a82 in /work/kurtamohler/development/pytorch-deterministic-flag/torch/lib/libtorch_cpu.so)
frame #2: THPModule_setDeterministicErrorLevel(_object*, _object*) + 0x31 (0x7f53fb5625d1 in /work/kurtamohler/development/pytorch-deterministic-flag/torch/lib/libtorch_python.so)
<omitting python frames>
frame #23: __libc_start_main + 0xe7 (0x7f5432d62b97 in /lib/x86_64-linux-gnu/libc.so.6)
Aborted (core dumped)
Jika ada yang tahu bagaimana saya bisa memperbaikinya, beri tahu saya.
@kurtamohler adalah THPModule_setDeterministicErrorLevel
hilang HANDLE_TH_ERRORS / END_ HANDLE_TH_ERRORS makro? Mereka diperlukan untuk menangkap pengecualian C++ dan menerjemahkannya ke dalam pengembalian kesalahan Python.
Ah itu dia, terima kasih @colesbury!
Saya mulai menambahkan peringatan non-deterministik ke semua penelepon atomicAdd
. Saya perhatikan bahwa beberapa penelepon hanya menggunakan atomicAdd
dalam kasus tertentu. Misalnya, adaptive_avg_pool3d_backward
hanya digunakan jika (isizeW%osizeW != 0) || (isizeH%osizeH != 0) || (isizeT%osizeT != 0)
benar. Haruskah saya hanya memperingatkan dalam kasus-kasus ini dan mencoba menyampaikannya dalam pesan kesalahan, atau apakah tidak apa-apa untuk hanya memperingatkan setiap kali fungsi-fungsi ini dipanggil apakah atomicAdd
akhirnya digunakan atau tidak?
Mungkin lebih mudah diterapkan dan lebih mudah dipahami jika Anda waspada tanpa syarat.
@ngimel , saya sudah memikirkan cara menggunakan CUBLAS_WORKSPACE_CONFIG
untuk memastikan penggunaan aliran deterministik, dan saya pikir ada dua pendekatan utama yang harus dipertimbangkan.
Jika seseorang menggunakan salah satu versi CUDA yang terpengaruh (10.2 atau lebih tinggi saat ini), dan torch.set_deterministic(True)
dipanggil, gunakan std::getenv
untuk memastikan bahwa CUBLAS_WORKSPACE_CONFIG
adalah :16:8
atau :4096:8
. Jika tidak, lakukan salah satu (1) atau (2):
Lempar kesalahan yang memberi tahu pengguna untuk mengatur variabel dengan tepat.
Secara otomatis mengatur variabel dengan putenv
( _putenv
pada Windows). Namun, ada beberapa keputusan desain lebih lanjut yang terkait dengan ini. Haruskah kita memilih :16:8
(kinerja lebih rendah, tetapi penggunaan memori lebih sedikit) atau :4096:8
(kinerja lebih tinggi, tetapi penggunaan memori lebih banyak)? Juga, jika pengguna menyetel variabel ke beberapa nilai non-deterministik lainnya, kita harus melacak nilai asli dan mengembalikannya jika torch.set_deterministic(False)
dipanggil, atau kita dapat membuat kesalahan yang memberi tahu pengguna bahwa mereka perlu menghapus variabel, atau skema lainnya.
Juga, saya tidak tahu apakah menyetel variabel saat aplikasi sedang berjalan akan benar-benar memengaruhi, jadi saya tidak tahu pasti apakah opsi (2) memungkinkan. Variabel mungkin hanya diperiksa sekali, saat runtime CUDA dimulai atau saat handle cuBLAS dibuat. Saya tidak dapat menemukan informasi tentang ini, jadi saya mungkin harus mencari tahu secara eksperimental (saya harus menggunakan pereproduksi penggunaan aliran non-deterministik untuk menulis tes, jadi saya akan melihat ini) . Saya juga mencari panggilan API, daripada menggunakan variabel lingkungan, tetapi CUDA sepertinya tidak menawarkannya.
Apakah Anda memiliki pendapat yang kuat tentang opsi mana yang lebih baik? Opsi (2) mungkin akan lebih ramah pengguna, tetapi mungkin kurang transparan daripada opsi (1).
Saya tidak tahu apakah menyetel variabel saat aplikasi sedang berjalan akan benar-benar berpengaruh
Untuk menindaklanjuti pertanyaan ini, menyetel variabel lingkungan di dalam skrip pytorch tampaknya tidak memengaruhi determinisme aliran CUDA. Saya memodifikasi skrip dari https://github.com/pytorch/pytorch/issues/39849 untuk dijalankan beberapa kali dan membandingkan statistik pelatihan untuk memeriksa perilaku non-deterministik. Ia mencoba mengatur CUBLAS_WORKSPACE_CONFIG=:4096:8
untuk memastikan penggunaan aliran deterministik: https://github.com/kurtamohler/pytorch-perf-test-scripts/blob/master/nondeterministic_alert/cuda_stream_nondeterminism.py
Menjalankannya menunjukkan bahwa kita tidak mendapatkan perilaku deterministik dari menyetel variabel di dalam skrip:
$ python cuda_stream_nondeterminism.py
Before setting var: not deterministic
After setting var: not deterministic
After restoring old var: not deterministic
Tetapi menjalankannya dengan variabel lingkungan yang disetel di luar skrip membuatnya deterministik:
$ CUBLAS_WORKSPACE_CONFIG=:4096:8 python cuda_stream_nondeterminism.py
Before setting var: possibly deterministic
After setting var: possibly deterministic
After restoring old var: possibly deterministic
Catatan, ini mencetak "mungkin deterministik" karena saya hanya menjalankan fungsi pelatihan 5 kali, dan mungkin untuk beruntung bahkan jika perilaku tidak benar-benar deterministik.
Mungkin jika saya dapat menginisialisasi ulang aliran cuda, itu akan memaksanya untuk menghormati variabel CUBLAS_WORKSPACE_CONFIG
diubah. Saya ingin mencobanya, tetapi saya tidak tahu bagaimana atau apakah mungkin melakukannya saat runtime. Jika seseorang tahu, tolong beri tahu saya.
Saya menemukan bahwa saya dapat membuat dan menggunakan aliran baru dengan:
with torch.cuda.stream(torch.cuda.Stream()):
Tetapi aliran baru tidak menghormati pengaturan variabel lingkungan yang diubah. Saya juga menemukan torch.cuda.init()
, tetapi sayangnya, itu tidak boleh dilakukan jika cuda telah diinisialisasi.
Jadi, kecuali kami dapat memikirkan sesuatu yang lain untuk dicoba, sepertinya kami mungkin tidak dapat mengubah konfigurasi ruang kerja secara otomatis, jadi kami mungkin hanya perlu membuat kesalahan yang memberi tahu pengguna untuk mengaturnya.
Yap, pengaturan variabel lingkungan setelah konteks cuda telah diinisialisasi tidak berpengaruh, jadi sayangnya itu semua atau tidak sama sekali solusi. Melempar kesalahan yang memberi tahu pengguna untuk mengaturnya terdengar masuk akal.
Saat ini, sepertinya tidak mungkin untuk memeriksa versi CUDA dari file yang dikompilasi non-nvcc, jadi saya yakin saya harus menambahkannya ke aten/src/ATen/cuda/detail/CUDAHooks.h
(memeriksa versi cuDNN adalah bagian dari antarmuka itu) . Jika ada yang tahu lebih baik, tolong beri tahu saya.
Komit di atas menambahkan kesalahan. Tapi saya perlu mencari tahu apa yang harus dilakukan dengan unit test sekarang. Ada dua masalah:
CUBLAS_WORKSPACE_CONFIG
tidak disetel dengan benar), infrastruktur pengujian harus dapat secara otomatis mengubah variabel lingkungan sebelum menjalankan pengujiantorch.set_deterministic
yang ada tidak rusak, kita perlu menyetel CUBLAS_WORKSPACE_CONFIG
dengan benar. Kami berpotensi hanya mengatur variabel ini secara default di semua pekerjaan CI yang menggunakan cuda >= 10.2.Saya menemukan bahwa saya dapat mengatur variabel lingkungan dari skrip python, lalu memuat ulang modul obor untuk membuatnya menghormati nilai baru:
>>> import torch
>>> torch.set_deterministic(True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/work/kurtamohler/development/pytorch-deterministic-flag-cuda-env-var/torch/__init__.py", line 306, in set_deterministic
_C._set_deterministic(d)
RuntimeError: To enable deterministic behavior with CUDA >= 10.2, you must set environment variable CUBLAS_WORKSPACE_CONFIG=:4096:8 or CUBLAS_WORKSPACE_CONFIG=:16:8. For more information, go to https://docs.nvidia.com/cuda/cublas/index.html#cublasApi_reproducibility
>>> import os
>>> os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'
>>> from importlib import reload
>>> torch = reload(torch)
>>> torch.set_deterministic(True)
Saya tidak tahu apakah memuat ulang obor juga akan menyebabkan CUDA menghormati perubahan ini, tetapi setidaknya ini memberi kami cara untuk menguji unit untuk pesan kesalahan. Meskipun saya harus bertanya, mungkinkah ada masalah dengan memuat ulang modul obor di dalam unit test?
EDIT: Ternyata saya tidak perlu memuat ulang obor untuk membuatnya melihat variabel lingkungan yang berubah. Juga, memuat ulang setelah mengubah variabel tidak memengaruhi runtime CUDA.
Komit di atas membahas semua masalah yang saya sebutkan dalam komentar saya sebelumnya. Saya menambahkan dekorator untuk membungkus tes API apa pun yang memanggil torch.set_deterministic()
, untuk sementara menyetel CUBLAS_WORKSPACE_CONFIG=:4096:8
hanya jika diperlukan. Ini juga mengembalikan flag deterministik dan pengaturan CUBLAS_WORKSPACE_CONFIG ke keadaan sebelum pengujian dijalankan.
Saya menyadari bahwa dokumen reproduktifitas menyebutkan bahwa perilaku CuDNN deterministik memerlukan:
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
Apakah seseorang di utas ini tahu persis apa benchmark
itu, dan mengapa torch.backends.cudnn.deterministic = True
tidak cukup?
Kami mungkin ingin memaksa benchmark
dimatikan jika torch.is_deterministic() == True
. Dengan kata lain, alih-alih meneruskan ctx.benchmarkCuDNN()
langsung ke at::_convolution()
, mungkin seharusnya ctx.benchmarkCuDNN() && !ctx.deterministic()
pada baris ini: https://github.com/pytorch/pytorch/blob/ master/aten/src/ATen/native/Convolution.cpp#L602
Jika kami tidak melakukan perubahan ini, sepertinya orang yang menggunakan set_deterministic
dan CuDNN harus melakukan ini:
torch.set_deterministic(True)
torch.backends.cudnn.benchmark = False
Artinya set_deterministic()
saja tidak akan mencakup semuanya, yang menurut saya membingungkan.
cc @ezyang @colesbury @t-vi @ngimel
Saat menghadapi konfigurasi konvolusi baru, benchmark=True
menjalankan semua implementasi cudnn yang tersedia dan memilih yang tercepat, menyimpan implementasi yang dipilih, sehingga semua panggilan berikutnya ke konvolusi dengan parameter yang sama akan menggunakannya. Jadi, jika deterministic
juga disetel ke True
hasilnya akan deterministik selama cache ini tetap ada, yaitu selama Anda berada dalam proses yang sama. Jika ada implementasi dengan runtime yang dekat, saat berikutnya Anda memulai proses dan menjalankan benchmarking lagi, implementasi lain mungkin menang, dan hasilnya (sementara masih deterministik dalam pengertian yang dijelaskan di atas) akan berbeda dari run sebelumnya. Jadi, untuk menjamin determinisme antar run, Anda harus mematikan benchmarking.
Jadi begitu. Jadi mungkin hanya determinisme dalam proses, bukan determinisme lintas-proses, yang penting untuk beberapa aplikasi, sehingga orang dapat merasa berguna untuk tetap dapat menggunakan pembandingan jika mereka menetapkan torch.set_deterministic(True)
. Dalam hal ini, saya seharusnya tidak mengubah perilaku saat ini. Selama saya memperbarui dokumen untuk memperjelasnya, saya tidak melihat masalah dengan itu.
Saya membuat halaman wiki untuk membantu kontributor PyTorch menambahkan dukungan untuk torch.set_deterministic()
: https://github.com/pytorch/pytorch/wiki/How-to-support-%60torch.set_deterministic ()%60-in- PyTorch-operator
Setiap perbaikan dipersilakan.
Juga, saya tidak yakin apakah bagian "Fungsi yang saat ini tidak didukung" harus ada di wiki ini atau apakah akan lebih baik sebagai masalah github baru (halaman wiki dapat ditautkan ke sana). Apakah ada yang punya preferensi?
Hai, saya ingin berbicara tentang rencana ke depan untuk torch.deterministic
. Ada beberapa pertanyaan tingkat tinggi yang perlu kita jawab:
torch.deterministic
? Apa yang diharapkan pengguna? Apakah upaya terbaik benar-benar bermanfaat bagi pengguna? Jika tidak berguna, apakah lebih baik mendefinisikan torch.deterministic
dalam hal operasi apa yang dikendalikannya?torch.deterministic
, apakah masuk akal untuk menghilangkan argumen kata kunci deterministic=
sepenuhnya dari API yang dihadapi publik ( bmm
, saya melihat Anda).Dimulai dengan (1), dokumentasi saat ini untuk torch.deterministic mengatakan:
r"""Sets a global flag to force all operations to use a deterministic
implementation if available. If an operation that does not have a
deterministic implementation is called while this setting is True, the
operation will throw a RuntimeError.
Note that deterministic operations tend to have worse performance than
non-deterministic operations.
Meskipun ini mungkin benar untuk keadaan akhir akhirnya, ini secara tidak akurat mewakili situasi saat ini, di mana banyak operasi belum diaudit dan untuk model tertentu, kami tidak tahu apakah torch.deterministic
benar-benar akan melakukan apa yang seharusnya dilakukan. tertulis di kaleng dan buat model Anda deterministik / naikkan kesalahan saat Anda menekan nondet. Jadi pada dasarnya, implementasi kami bermasalah sehubungan dengan semantik ini, dan akan terus bermasalah di masa mendatang. Ini bukan keadaan yang bagus untuk berada.
Kita bisa mengubah dokumentasi torch.deterministic untuk memperbaiki ini. Beberapa kemungkinan perubahan:
Poin-poin kedua mengarah ke (2): jika torch.deterministic sekarang ada sebagai cara untuk mengaktifkan determinisme, jauh lebih penting untuk mendukung determinisme secara langsung di API pengguna. Jadi kita mungkin seharusnya tidak menambahkan argumen deterministic
ke bmm. Kami mungkin mempertimbangkan untuk mengekspos fungsi internal jika Anda ingin mengaktifkan sesuatu secara langsung, tetapi deterministic
seharusnya tidak tersedia langsung pada fungsi itu sendiri.
Bagaimana menurut anda? Saya pikir mengubah dokumen mungkin adalah cara termudah untuk mendapatkan jalur yang berkelanjutan. Ada beberapa detail lain, seperti cara mengisi daftar lengkap, tetapi semantik ini mungkin lebih masuk akal daripada semantik "ideal" yang sebenarnya tidak benar.
cc @gchanan @mruberry
@zou3519 berpotongan dengan Q juga di https://github.com/pytorch/pytorch/pull/38683#issuecomment -662590937
Saya senang Anda mengajukan pertanyaan ini @ezyang , @zou3519 , dan @mruberry. Saya setuju bahwa dokumentasi yang saya tulis adalah representasi palsu dari keadaan saat ini.
Saya menyukai gagasan untuk membuat daftar lengkap semua fungsi yang dipengaruhi oleh torch.set_deterministic()
, sehingga kami tidak membohongi pengguna. Terima kasih telah menambahkannya ke 1.6.0, @zou3519.
Saya setuju bahwa kita tidak boleh menawarkan pengaturan deterministic
sebagai argumen fungsi langsung.
Untuk permainan akhir, saya senang untuk terus mengerjakan ini selama diperlukan, tetapi ini harus diatur sehingga siapa pun dapat dengan cepat mempelajari cara membantu.
Dalam jangka panjang, saya pikir memberikan daftar lengkap fungsi yang terpengaruh adalah keputusan yang valid, tetapi saya tidak berpikir bahwa strategi saja akan memaksimalkan kegunaan flag deterministik. Kami dapat mengkategorikan fungsi (dalam satu lingkungan tertentu) seperti ini:
Tentu saja kasus yang ideal adalah menghilangkan kategori 3 sepenuhnya, dan kemudian daftar fungsi kategori 2 sudah cukup. Namun, fungsi kategori 3 akan tetap ada untuk jangka waktu yang signifikan (atau mungkin selamanya, jika tidak semua kontributor mengetahui pertanyaan determinisme, atau komit secara tidak sengaja menghilangkan determinisme untuk suatu fungsi, dll.). Jadi meskipun kita memiliki daftar lengkap dari semua fungsi kategori 2, pengguna tidak memiliki cara sederhana untuk mengetahui apakah fungsi yang tidak muncul dalam daftar adalah deterministik atau tidak (bisa kategori 1 atau 3). Misalnya, torch.add
tidak muncul di daftar, jadi bagaimana pengguna tahu bahwa itu deterministik?
Mungkin kita bisa memikirkan untuk mempertahankan daftar fungsi kategori 3 juga. Tetapi mempertahankan daftar ini secara manual akan sangat sulit karena berbagai alasan, jadi saya ingin tahu apakah kami dapat mengotomatiskannya. Kami berpotensi menyiapkan tugas CI yang menjalankan tes determinisme pada semua fungsi. Tidak mungkin untuk 100% membuktikan secara induktif bahwa suatu fungsi adalah deterministik, dan fungsi nondeterministik terkadang dapat memberikan hasil yang sama beberapa kali jika kita tidak beruntung. Tetapi semakin sering kita menjalankan tes ini, semakin yakin kita tentang kategori mana setiap fungsi menjadi bagiannya.
Ada juga pertanyaan tentang cara paling efisien menyampaikan kepada pengguna segala sesuatu yang kita ketahui dan tidak ketahui tentang setiap fungsi dan setiap platform. Mungkin kita bisa membuat tabel dari semua fungsi kategori 2 dan 3 pada setiap platform. Alangkah baiknya jika tes determinisme dapat secara otomatis memverifikasi bahwa tabel ini benar.
Hanya brainstorming, mungkin ide-ide ini lebih sulit daripada nilainya. Rencana yang lebih pragmatis dapat secara signifikan lebih berkelanjutan, bahkan jika kurang ideal.
Apakah torch.add
deterministik?
import torch
n = 512
device = 'cuda'
a = torch.arange(n**3, device=device, dtype=torch.float32)
a = a.reshape((n, n, n))
b = torch.arange(n**3, device=device, dtype=torch.float32)
b = b.reshape((n, n, n))
out_zero = torch.zeros((n, n, n), device=device)
out_zero = out_zero.set_(out_zero.storage(), storage_offset=0, size=a.size(), stride=(1,1,1))
out_one = torch.zeros((n, n, n), device=device)
out_one = out_one.set_(out_one.storage(), storage_offset=0, size=a.size(), stride=(1,1,1))
torch.add(a, b, out=out_zero)
torch.add(a, b, out=out_one)
(out_zero == out_one).all()
: tensor(False, device='cuda:0')
Kita mungkin harus mendokumentasikan bahwa tensor yang tumpang tindih melanggar kontrak determinisme apa pun yang kita tuju.
Mencantumkan operasi yang dipengaruhi oleh bendera "determinisme" terdengar bagus. Namun, melangkah mundur sedikit, sepertinya kita benar-benar berbicara tentang dua hal:
use_deterministic
?)Bendera untuk hal pertama tampaknya mudah. Yang kedua, bagaimanapun, sedikit lebih rumit. Saya khawatir sulit untuk mengetahui apakah operasi perpustakaan matematika seperti oneDNN, cuDNN, dan MAGMA bersifat deterministik, terutama di seluruh versi dan perangkat keras. Apakah Anda punya ide tentang cara terbaik untuk mengatasi ini, @kurtamohler? Mungkin kita bisa memperingatkan semua operasi non-deterministik asli dan juga memperingatkan ketika panggilan perpustakaan matematika dibuat juga? Peringatan sekali per proses seharusnya tidak terlalu mengganggu.
Pendekatan peringatan ini memerlukan peninjauan banyak algoritme dan memanggil situs sebelum ditayangkan, tetapi tidak perlu memblokir tanda untuk memilih algoritme deterministik jika tersedia.
(Hal ketiga yang sedang dibahas adalah cara terbaik untuk menyajikan pemilihan algo deterministik (melalui flag global atau sebagai kwargs pada fungsi), tetapi saya pikir kita dapat menunda diskusi itu sampai kita menentukan rencana untuk flag?)
Saya pikir kita seharusnya tidak membiarkan yang sempurna menjadi musuh yang baik di sini. Saya tidak tahu kapan 100% aman untuk menggunakan tensor yang tumpang tindih dengan PyTorch, dan kesan saya adalah bahwa bukan orang biasa yang menggunakannya.
Kesan saya dari forum adalah bahwa kebanyakan orang terkejut bahwa mereka menjalankan sesuatu dua kali dan mendapatkan gradien yang berbeda darinya, paling sering karena salah satu fungsi asli PyTorch menggunakan atomAdd.
Jika kami mendapat peringatan untuk itu, kami telah membahas sebagian besar kasus yang membuat orang bertanya-tanya. Sesuatu yang terasa seperti setengahnya sebenarnya dari upscaling ke belakang.
Saya pikir kita harus dengan jelas menyatakan bahwa ini adalah upaya terbaik sejauh menyangkut lib eksternal dan bahwa kita menambahkan peringatan saat kita mengetahui masalah, tetapi kesan saya adalah bahwa kernel asli kita sebenarnya adalah yang paling penting.
Saya tidak tahu kapan 100% aman untuk menggunakan tensor yang tumpang tindih dengan PyTorch, dan kesan saya adalah bahwa bukan orang biasa yang menggunakannya.
Ya, dan program apa pun yang mungkin diklasifikasikan sebagai kesalahan. Maksud saya, kita harus berhati-hati untuk mendokumentasikan kontrak apa pun yang kita buat untuk bendera-bendera ini.
Saya pikir kita harus dengan jelas menyatakan bahwa ini adalah upaya terbaik sejauh menyangkut lib eksternal dan bahwa kita menambahkan peringatan saat kita mengetahui masalah ...
Doc mungkin mengatakan sesuatu seperti, "panggilan perpustakaan matematika yang diketahui tidak deterministik..."?
Saya setuju dengan @t-vi (dan saya sangat menyukai pengamatan bahwa setengah dari nondeterminisme yang dilaporkan meningkat ke belakang). Secara khusus, saya pikir keadaan di mana kami memiliki sebagian fungsi yang didokumentasikan yang diketahui nondeterministik (atau bahkan sebagian mendokumentasikan beberapa fungsi menjadi deterministik) benar-benar lebih baik daripada yang kami tidak memberikan indikasi sama sekali--hal utama adalah untuk tidak mengklaim mendukung hal-hal yang tidak kami lakukan! Saya setuju bahwa ini adalah aktivitas yang berguna untuk memikirkan tentang bagaimana seseorang dapat melakukan pengujian determinisme, tetapi saya pikir ini sebagai aktivitas ortogonal untuk menandai API yang jelas-jelas non-deterministik.
Karena banyak ide telah beredar, izinkan saya mengikuti pemikiran spesifik saya tentang beberapa di antaranya:
Saya tidak berpikir kita harus khawatir tentang determinisme lintas versi/perangkat keras -- semoga berhasil.
Ketika kita memperingatkan tentang nondeterminisme, itu seharusnya karena nondeterminisme sedang terjadi, bukan karena MUNGKIN terjadi. Jika Anda memperingatkan, orang akan mulai mengabaikan peringatan.
memang terlihat rumit. Misalnya bagaimana jika saya menjalankan beberapa operasi dan implementasi PyTorch bersifat deterministik, tetapi beberapa ekstensi telah menimpa sesuatu (melalui kunci pengiriman, fungsi obor, atau lainnya) dan sekarang saya tidak tahu. Jika itu benar-benar sumber non-determinisme saya, sepertinya menyedihkan untuk tidak diperingatkan.
Jika itu benar-benar sumber non-determinisme saya, sepertinya menyedihkan untuk tidak diperingatkan.
Tentu, tetapi pengguna juga bisa saja tidak melibatkan kami dalam kejahatan nondeterministik mereka, dan tentu saja Anda tidak akan berharap untuk diperingatkan saat itu;)
Saya yakin kami dapat menutup masalah ini sekarang karena API bendera ada dan didokumentasikan dengan baik.
@kurtamohler Kerja yang luar biasa. Terima kasih.
Apakah ini berarti, kita dapat menggunakan torch.manual_seed(111)
untuk mengatur semua deterministik, termasuk operasi interpolation
?
Tidak. Lihatlah catatan Reproduksibilitas / Keacakan .
Sejauh ini, kami memiliki infrastruktur, menandai sumber yang diketahui tentang non-determinisme dan dokumentasi yang sangat ditingkatkan sehingga Anda dapat mengetahui apa yang terjadi.
Jika Anda mencapai operasi non-deterministik, Anda masih kurang beruntung, tetapi sekarang lebih masuk akal untuk mengerjakannya.
Interpolasi khususnya tampaknya sesuatu yang dapat dibuat deterministik dengan menulis kernel yang tidak terlalu rumit untuk mundur.
@t-vi Hai, Sekarang pytorch 1.7 dirilis, apakah kernel interpolasi mundur telah diperbarui?
Jadi kernel upsampling CUDA dan mundur terletak di aten/src/ATen/native/cuda/UpSample*
. Sebuah grep menunjukkan bahwa linear, bilinear, kubik memiliki mundur nondeterministik (mereka memiliki penanda peringatan), tetapi terdekat tidak.
@kurtamohler akan menjadi orang yang jauh lebih baik untuk bertanya.
Komentar yang paling membantu
Hai, saya ingin berbicara tentang rencana ke depan untuk
torch.deterministic
. Ada beberapa pertanyaan tingkat tinggi yang perlu kita jawab:torch.deterministic
? Apa yang diharapkan pengguna? Apakah upaya terbaik benar-benar bermanfaat bagi pengguna? Jika tidak berguna, apakah lebih baik mendefinisikantorch.deterministic
dalam hal operasi apa yang dikendalikannya?torch.deterministic
, apakah masuk akal untuk menghilangkan argumen kata kuncideterministic=
sepenuhnya dari API yang dihadapi publik (bmm
, saya melihat Anda).Dimulai dengan (1), dokumentasi saat ini untuk torch.deterministic mengatakan:
Meskipun ini mungkin benar untuk keadaan akhir akhirnya, ini secara tidak akurat mewakili situasi saat ini, di mana banyak operasi belum diaudit dan untuk model tertentu, kami tidak tahu apakah
torch.deterministic
benar-benar akan melakukan apa yang seharusnya dilakukan. tertulis di kaleng dan buat model Anda deterministik / naikkan kesalahan saat Anda menekan nondet. Jadi pada dasarnya, implementasi kami bermasalah sehubungan dengan semantik ini, dan akan terus bermasalah di masa mendatang. Ini bukan keadaan yang bagus untuk berada.Kita bisa mengubah dokumentasi torch.deterministic untuk memperbaiki ini. Beberapa kemungkinan perubahan:
Poin-poin kedua mengarah ke (2): jika torch.deterministic sekarang ada sebagai cara untuk mengaktifkan determinisme, jauh lebih penting untuk mendukung determinisme secara langsung di API pengguna. Jadi kita mungkin seharusnya tidak menambahkan argumen
deterministic
ke bmm. Kami mungkin mempertimbangkan untuk mengekspos fungsi internal jika Anda ingin mengaktifkan sesuatu secara langsung, tetapideterministic
seharusnya tidak tersedia langsung pada fungsi itu sendiri.Bagaimana menurut anda? Saya pikir mengubah dokumen mungkin adalah cara termudah untuk mendapatkan jalur yang berkelanjutan. Ada beberapa detail lain, seperti cara mengisi daftar lengkap, tetapi semantik ini mungkin lebih masuk akal daripada semantik "ideal" yang sebenarnya tidak benar.
cc @gchanan @mruberry