BC и GAIL падали на любой машине с GPU - #45
Merged
Merged
Conversation
agent = BC(env) # device="auto" -> cuda
data = collect_expert_dataset(...) # device="cpu", always
agent.train(data) # RuntimeError on the first batch
RuntimeError: Expected all tensors to be on the same device, but got mat1
is on cpu, different from other tensors on cuda:0
That is the way the README uses BC, and it has never worked on a machine with a
GPU -- which, for a reinforcement learning library, is most of them.
Nothing here needed designing. `ReplayBatch.to()` exists, and its docstring is
this bug: "Lets an agent train from a dataset stored on a different device (for
example a CPU-collected offline dataset feeding a CUDA agent) without a device
mismatch." CQL, IQL, TD3BC and DiffusionPolicy all call it on the line they
sample. `decisionrl.imitation` had two sample sites and neither did. Both now
do, exactly as the four siblings do.
GAIL's is the subtler of the two: it builds its policy dataset on `self.device`
already, so only the expert side arrives from elsewhere -- and it always does,
because it is the caller's, built by `collect_expert_dataset`, which is a "cpu"
default with no way to say otherwise.
Why nobody saw it: `test_bc_predicts_and_round_trips`, `test_bc_imitates_expert`
and `test_gail_imitates_expert` fail on any GPU machine and pass on every CI
runner, because the runners have none. The library was green for as long as it
was only ever tested where the bug cannot happen.
So the regression tests do not need a GPU either. Two of them check the step
rather than the crash -- that each batch is routed through `.to(self.device)` --
by spying on the batch's own `to`. On a runner the move is a no-op, but its
absence still fails, which is the property that matters: on the unfixed source
with `CUDA_VISIBLE_DEVICES=-1`, both fail with `moved == []`. The third asserts
the crash end to end and skips without CUDA, and says in its docstring that CI
cannot run it, because that difference going unstated is the whole story here.
Measured on a CUDA machine: `tests/test_imitation.py` was 3 failed, 2 passed
before and is 5 passed after. On CPU it is 7 passed, 1 skipped. `test_offline.py`
and `test_diffusion.py` are unchanged either way -- they were already correct.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Это ровно то, как BC используется в README. И это никогда не работало на машине с GPU — а для библиотеки обучения с подкреплением это большинство машин.
Ничего придумывать не пришлось
ReplayBatch.to()уже существует, и его докстринг — это описание данного бага:CQL,IQL,TD3BCиDiffusionPolicy— все зовут его на той же строке, где сэмплят:У
decisionrl.imitationбыло два места, где сэмплят, и ни одно этого не делало. Теперь делают оба, ровно как четыре соседа.У GAIL случай тоньше: свой policy-датасет он строит уже на
self.device, так что «извне» приходит только экспертная сторона — и приходит всегда, потому что она каллерская, собраннаяcollect_expert_dataset, у которого"cpu"захардкожен дефолтом и сказать иначе нечем.Почему этого никто не видел
test_bc_predicts_and_round_trips,test_bc_imitates_expertиtest_gail_imitates_expertпадают на любой машине с GPU и проходят на каждом раннере CI, потому что у раннеров GPU нет.Библиотека была зелёной ровно столько, сколько её проверяли только там, где баг невозможен.
Поэтому регрессионным тестам GPU тоже не нужен
Два из трёх проверяют шаг, а не падение — что каждый батч проходит через
.to(self.device), — подглядывая за собственнымtoу батча. На раннере перенос — no-op, но его отсутствие всё равно роняет тест. Это и есть нужное свойство:То есть этот баг был бы пойман в CI, без всякого GPU.
Третий тест утверждает падение целиком и пропускается без CUDA — и говорит в докстринге, что CI его запустить не может, потому что именно необъявленность этой разницы и есть вся история.
Измерено
test_imitation.pyна CUDA-машинеtest_imitation.pyна CPUtest_offline.py,test_diffusion.pyruff checkчист.