Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
fairscale
Commits
08c10993
Unverified
Commit
08c10993
authored
Feb 08, 2021
by
msbaines
Committed by
GitHub
Feb 08, 2021
Browse files
[refactor] AsyncPipe: do not sub-class MultiProcessPipe (#370)
parent
77d94861
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
307 additions
and
52 deletions
+307
-52
fairscale/nn/pipe/async_pipe.py
fairscale/nn/pipe/async_pipe.py
+248
-6
fairscale/nn/pipe/async_pipeline.py
fairscale/nn/pipe/async_pipeline.py
+40
-4
fairscale/nn/pipe/multiprocess_pipe.py
fairscale/nn/pipe/multiprocess_pipe.py
+14
-36
fairscale/nn/pipe/rpc.py
fairscale/nn/pipe/rpc.py
+5
-6
No files found.
fairscale/nn/pipe/async_pipe.py
View file @
08c10993
...
@@ -6,14 +6,20 @@
...
@@ -6,14 +6,20 @@
from
collections
import
OrderedDict
from
collections
import
OrderedDict
from
dataclasses
import
dataclass
,
field
from
dataclasses
import
dataclass
,
field
import
itertools
import
itertools
from
typing
import
TYPE_CHECKING
,
Any
,
Iterable
,
List
,
Optional
,
Tuple
,
Union
import
threading
from
typing
import
TYPE_CHECKING
,
Any
,
Dict
,
Iterable
,
List
,
Optional
,
Tuple
,
Union
import
warnings
import
torch
import
torch
from
torch
import
Tensor
,
nn
from
torch
import
Tensor
,
nn
from
fairscale.nn.model_parallel
import
get_pipeline_parallel_group
from
.
import
microbatch
from
.async_pipeline
import
AsyncPipeline
from
.async_pipeline
import
AsyncPipeline
from
.async_schedule
import
Invocation
,
Location
,
ModuleWrapper
from
.async_schedule
import
Invocation
,
Location
,
ModuleWrapper
from
.multiprocess_pipe
import
MultiProcessPipe
from
.batchnorm
import
DeferredBatchNorm
from
.skip.layout
import
SkipLayout
from
.skip.skippable
import
Skippable
from
.skip.skippable
import
Skippable
from
.types
import
LazyModule
from
.types
import
LazyModule
...
@@ -38,10 +44,164 @@ class PartitionInfo:
...
@@ -38,10 +44,164 @@ class PartitionInfo:
return
len
(
self
.
modules
)
return
len
(
self
.
modules
)
class
AsyncPipe
(
MultiProcessPipe
):
def
verify_module
(
module
:
Union
[
nn
.
Sequential
,
List
[
LazyModule
]])
->
None
:
def
__init__
(
self
,
*
args
:
Any
,
**
kwargs
:
Any
):
if
len
(
set
(
map
(
id
,
module
)))
!=
len
(
module
):
super
().
__init__
(
*
args
,
**
kwargs
)
raise
ValueError
(
"module with duplicate children is not supported"
)
self
.
pipelined_backward
=
False
def
check_balance
(
module
:
Union
[
nn
.
Sequential
,
List
[
LazyModule
]],
balance
:
List
[
int
])
->
None
:
if
len
(
module
)
!=
sum
(
balance
):
raise
ValueError
(
f
"module and sum of balance have different length (module:
{
len
(
module
)
}
, sum of balance:
{
sum
(
balance
)
}
)"
)
if
any
(
x
<=
0
for
x
in
balance
):
raise
ValueError
(
f
"all balance numbers must be positive integer (balance:
{
balance
}
)"
)
MOVING_DENIED
=
TypeError
(
"denied to move parameters and buffers, because Pipe should manage device placement"
)
class
AsyncPipe
(
Module
):
"""Wraps an arbitrary :class:`nn.Sequential <torch.nn.Sequential>` module
to train on Pipe_. If the module requires lots of memory, Pipe will be
very efficient.
Pipe combines pipeline parallelism with checkpointing to reduce peak
memory required to train while minimizing device under-utilization.
You should determine the balance when defining a :class:`AsyncPipe` module, as
balancing will not be done automatically. The module will be partitioned
into multiple devices according to the given balance. You may rely on
heuristics to find your own optimal configuration.
Args:
module (torch.nn.Sequential):
sequential module to be parallelized
balance (ints):
list of number of layers in each partition
Keyword Args:
group (ProcessGroup):
the process group that all
pipeline stages are a member of. Defaults to
`get_pipeline_parallel_group()`
worker_map (Dict[int, str]):
a map from worker name (the first argument to
`torch.distributed.rpc.init_rpc`) to global rank (i.e.
`torch.distributed.get_rank()`) needed in order for pipeline stages
to communicate with each other
input_device (device):
the device on which tensors should be located before being passed to
the first module in a given pipeline stage
chunks (int):
number of micro-batches (default: ``1``)
checkpoint (str):
when to enable checkpointing, one of ``'always'``,
``'except_last'``, or ``'never'`` (default: ``'except_last'``)
deferred_batch_norm (bool):
whether to use deferred BatchNorm moving statistics (default:
:data:`False`, see :class:`DeferredBatchNorm` for more
details)
Raises:
TypeError:
the module is not a :class:`nn.Sequential <torch.nn.Sequential>`.
ValueError:
invalid arguments, or wrong balance
IndexError:
the number of devices is fewer than the number of partitions.
"""
#: The number of layers in each partition.
balance
:
List
[
int
]
=
[]
# ^^
# The default value [] required for Sphinx's autoattribute.
#: The devices mapped to each partition.
#:
#: ``devices[-1]`` refers to the device of the last partition, which means
#: it is the output device. Probably, you need to use it to transfer the
#: target to calculate the loss without a device mismatch
#: :exc:`RuntimeError`. For example::
#:
#: out_device = pipe.devices[-1]
#:
#: for input, target in loader:
#: target = target.to(out_device, non_blocking=True)
#: output = pipe(input)
#: loss = F.cross_entropy(output, target)
#:
#: The number of micro-batches.
chunks
:
int
=
1
#: The checkpoint mode to determine when to enable checkpointing. It is one
#: of ``'always'``, ``'except_last'``, or ``'never'``.
checkpoint
:
str
=
"except_last"
def
__init__
(
self
,
module
:
Union
[
nn
.
Sequential
,
List
[
LazyModule
]],
balance
:
Iterable
[
int
],
*
,
group
:
Optional
[
torch
.
distributed
.
ProcessGroup
]
=
None
,
worker_map
:
Optional
[
Dict
[
int
,
str
]]
=
None
,
input_device
:
Union
[
None
,
int
,
str
,
torch
.
device
]
=
None
,
chunks
:
int
=
chunks
,
checkpoint
:
str
=
checkpoint
,
deferred_batch_norm
:
bool
=
False
,
)
->
None
:
super
().
__init__
()
if
chunks
<=
0
:
raise
ValueError
(
"number of chunks must be positive integer"
)
if
checkpoint
not
in
[
"always"
,
"except_last"
,
"never"
]:
raise
ValueError
(
"checkpoint is not one of 'always', 'except_last', or 'never'"
)
self
.
balance
=
list
(
balance
)
verify_module
(
module
)
check_balance
(
module
,
self
.
balance
)
self
.
chunks
=
chunks
self
.
checkpoint
=
checkpoint
self
.
pipeline
:
Optional
[
AsyncPipeline
]
self
.
lock
=
threading
.
Lock
()
self
.
worker_map
=
worker_map
self
.
input_device
=
input_device
self
.
group
:
torch
.
distributed
.
ProcessGroup
if
group
is
None
:
self
.
group
=
get_pipeline_parallel_group
()
else
:
self
.
group
=
group
if
self
.
group
.
size
()
<
len
(
self
.
balance
):
raise
IndexError
(
f
"too few ranks to hold given partitions (ranks:
{
self
.
group
.
size
()
}
, partitions:"
f
"
{
len
(
self
.
balance
)
}
)"
)
self
.
_skip_layout
=
SkipLayout
(
len
(
module
),
{})
# FIXME(tom)
rank
=
self
.
group
.
rank
()
self
.
final_stage
=
rank
==
len
(
self
.
balance
)
-
1
if
rank
>=
len
(
self
.
balance
):
warnings
.
warn
(
"More ranks than partitions, some ranks unused"
)
self
.
partitions
:
List
[
ModuleWrapper
]
=
[]
self
.
pipeline
=
None
else
:
self
.
partitions
=
self
.
instantiate_partition
(
module
,
self
.
balance
,
self
.
group
)
if
deferred_batch_norm
:
for
part
in
self
.
partitions
:
part
.
module
=
DeferredBatchNorm
.
convert_deferred_batch_norm
(
part
.
module
,
chunks
)
for
name
,
part
in
enumerate
(
self
.
partitions
):
self
.
add_module
(
str
(
name
),
part
.
module
)
self
.
create_pipeline
()
del
module
def
create_pipeline
(
self
)
->
None
:
def
create_pipeline
(
self
)
->
None
:
# The micro-batch index where the checkpointing stops.
# The micro-batch index where the checkpointing stops.
...
@@ -150,3 +310,85 @@ class AsyncPipe(MultiProcessPipe):
...
@@ -150,3 +310,85 @@ class AsyncPipe(MultiProcessPipe):
result
.
append
(
wrapper
)
result
.
append
(
wrapper
)
return
result
return
result
def
__len__
(
self
)
->
int
:
"""Counts the length of the underlying sequential module."""
return
sum
(
len
(
p
)
for
p
in
self
.
partitions
)
def
__getitem__
(
self
,
index
:
int
)
->
nn
.
Module
:
"""Gets a layer in the underlying sequential module."""
partitions
:
List
[
Any
]
partitions
=
self
.
partitions
if
index
<
0
:
partitions
=
partitions
[::
-
1
]
for
partition
in
partitions
:
try
:
if
isinstance
(
partition
,
ModuleWrapper
):
return
partition
.
module
[
index
]
else
:
return
partition
[
index
]
except
IndexError
:
pass
shift
=
len
(
partition
)
if
index
<
0
:
index
+=
shift
else
:
index
-=
shift
raise
IndexError
def
__iter__
(
self
)
->
Iterable
[
nn
.
Module
]:
"""Iterates over children of the underlying sequential module."""
for
partition
in
self
.
partitions
:
yield
from
partition
.
module
def
forward
(
self
,
input
:
TensorOrTensors
,
*
,
event
=
None
)
->
TensorOrTensors
:
# type: ignore
""":class:`AsyncPipe` is a fairly transparent module wrapper. It doesn't
modify the input and output signature of the underlying module. But
there's type restriction. Input and output have to be a
:class:`~torch.Tensor` or a tuple of tensors. This restriction is
applied at partition boundaries too.
Args:
input (torch.Tensor or tensors): input mini-batch
Returns:
tensor or tensors: output mini-batch
Raises:
TypeError: input is not a tensor or tensors.
"""
microbatch
.
check
(
input
)
if
not
self
.
pipeline
:
# No pipeline is not illegal, more ranks than partitions
return
input
# Divide a mini-batch into micro-batches.
batches
=
microbatch
.
scatter
(
input
,
self
.
chunks
)
# Run pipeline parallelism.
with
self
.
lock
:
self
.
pipeline
.
run
(
self
.
training
,
batches
,
event
)
if
self
.
final_stage
:
output
=
microbatch
.
gather
(
batches
)
else
:
# Don't merge micro-batches to avoid unnecessary edges in autograd
# graph
# FIXME(tom) should figure out a proper type here
output
=
batches
# type: ignore
return
output
def
back_helper
(
self
,
output
:
List
[
microbatch
.
Batch
])
->
None
:
if
self
.
final_stage
:
raise
ValueError
(
"back_helper should only be called on non-final stages"
)
if
self
.
pipeline
:
self
.
pipeline
.
back_helper
(
output
)
fairscale/nn/pipe/async_pipeline.py
View file @
08c10993
...
@@ -4,18 +4,54 @@
...
@@ -4,18 +4,54 @@
# LICENSE file in the root directory of this source tree.
# LICENSE file in the root directory of this source tree.
import
logging
import
logging
import
os
from
threading
import
Event
from
threading
import
Event
from
typing
import
List
,
Optional
from
typing
import
Dict
,
List
,
Optional
,
Union
import
torch
import
torch
from
.async_schedule
import
AsyncEventLoop
from
.async_schedule
import
AsyncEventLoop
,
ModuleWrapper
from
.messages
import
MakeTransport
from
.microbatch
import
Batch
from
.microbatch
import
Batch
from
.
multiprocess_pipeline
import
MultiProcessPipeline
from
.
skip.layout
import
SkipLayout
from
.skip.tracker
import
SkipTrackerThroughPotals
from
.skip.tracker
import
SkipTrackerThroughPotals
class
AsyncPipeline
(
MultiProcessPipeline
):
class
AsyncPipeline
:
"""The async pipeline parallelism for Pipe."""
def
__init__
(
self
,
partitions
:
List
[
ModuleWrapper
],
skip_layout
:
SkipLayout
,
checkpoint_stop
:
int
,
group
:
torch
.
distributed
.
ProcessGroup
,
*
,
worker_map
:
Optional
[
Dict
[
int
,
str
]]
=
None
,
input_device
:
Union
[
None
,
int
,
str
,
torch
.
device
]
=
None
,
final_stage
:
bool
=
False
,
)
->
None
:
self
.
partitions
=
partitions
self
.
skip_layout
=
skip_layout
self
.
__checkpoint_stop
=
checkpoint_stop
self
.
group
=
group
self
.
training
:
bool
self
.
transport
=
MakeTransport
(
use_rpc
=
(
"OMPI_COMM_WORLD_RANK"
not
in
os
.
environ
)
or
(
"FORCE_RPC"
in
os
.
environ
),
worker_map
=
worker_map
,
input_device
=
input_device
,
)
self
.
input_device
=
input_device
self
.
final_stage
=
final_stage
@
property
def
checkpoint_stop
(
self
)
->
int
:
# Disable checkpointing if in eval mode.
training
=
self
.
partitions
[
0
].
module
.
training
if
not
training
:
return
0
return
self
.
__checkpoint_stop
def
run
(
self
,
training
:
bool
,
batches
:
List
[
Batch
],
event
:
Optional
[
Event
])
->
None
:
def
run
(
self
,
training
:
bool
,
batches
:
List
[
Batch
],
event
:
Optional
[
Event
])
->
None
:
"""Runs pipeline parallelism.
"""Runs pipeline parallelism.
...
...
fairscale/nn/pipe/multiprocess_pipe.py
View file @
08c10993
...
@@ -20,7 +20,7 @@
...
@@ -20,7 +20,7 @@
"""The MultiProcessPipe interface."""
"""The MultiProcessPipe interface."""
from
collections
import
OrderedDict
from
collections
import
OrderedDict
import
threading
import
threading
from
typing
import
TYPE_CHECKING
,
Any
,
Dict
,
Iterable
,
List
,
Optional
,
Tuple
,
Union
from
typing
import
TYPE_CHECKING
,
Dict
,
Iterable
,
List
,
Optional
,
Tuple
,
Union
import
warnings
import
warnings
import
torch
import
torch
...
@@ -210,17 +210,18 @@ class MultiProcessPipe(Module):
...
@@ -210,17 +210,18 @@ class MultiProcessPipe(Module):
self
.
final_stage
=
rank
==
len
(
self
.
balance
)
-
1
self
.
final_stage
=
rank
==
len
(
self
.
balance
)
-
1
if
rank
>=
len
(
self
.
balance
):
if
rank
>=
len
(
self
.
balance
):
warnings
.
warn
(
"More ranks than partitions, some ranks unused"
)
warnings
.
warn
(
"More ranks than partitions, some ranks unused"
)
self
.
partition
s
:
List
[
ModuleWrapper
]
=
[]
self
.
partition
=
nn
.
Sequential
()
self
.
pipeline
=
None
self
.
pipeline
=
None
else
:
else
:
self
.
partition
s
=
self
.
instantiate_partition
(
module
,
self
.
balance
,
self
.
group
)
self
.
partition
=
self
.
instantiate_partition
(
module
,
self
.
balance
,
self
.
group
)
if
deferred_batch_norm
:
if
deferred_batch_norm
:
for
part
in
self
.
partitions
:
self
.
partitition
=
DeferredBatchNorm
.
convert_deferred_batch_norm
(
self
.
partition
,
chunks
)
part
.
module
=
DeferredBatchNorm
.
convert_deferred_batch_norm
(
part
.
module
,
chunks
)
self
.
add_module
(
str
(
0
),
self
.
partition
)
for
name
,
part
in
enumerate
(
self
.
partitions
):
self
.
add_module
(
str
(
name
),
part
.
module
)
self
.
create_pipeline
()
self
.
create_pipeline
()
# TODO(msb) Remove this hack at some point.
self
.
partitions
=
[
ModuleWrapper
(
self
.
partition
,
Location
(
self
.
group
.
rank
(),
0
))]
del
module
del
module
def
create_pipeline
(
self
)
->
None
:
def
create_pipeline
(
self
)
->
None
:
...
@@ -228,7 +229,7 @@ class MultiProcessPipe(Module):
...
@@ -228,7 +229,7 @@ class MultiProcessPipe(Module):
checkpoint_stop
=
{
"always"
:
self
.
chunks
,
"except_last"
:
self
.
chunks
-
1
,
"never"
:
0
}[
self
.
checkpoint
]
checkpoint_stop
=
{
"always"
:
self
.
chunks
,
"except_last"
:
self
.
chunks
-
1
,
"never"
:
0
}[
self
.
checkpoint
]
self
.
pipeline
=
MultiProcessPipeline
(
self
.
pipeline
=
MultiProcessPipeline
(
self
.
partitions
,
[
ModuleWrapper
(
self
.
partition
,
Location
(
self
.
group
.
rank
(),
0
))]
,
self
.
_skip_layout
,
self
.
_skip_layout
,
checkpoint_stop
,
checkpoint_stop
,
group
=
self
.
group
,
group
=
self
.
group
,
...
@@ -239,48 +240,25 @@ class MultiProcessPipe(Module):
...
@@ -239,48 +240,25 @@ class MultiProcessPipe(Module):
def
instantiate_partition
(
def
instantiate_partition
(
self
,
module
:
Union
[
nn
.
Sequential
,
List
[
LazyModule
]],
balance
:
List
[
int
],
group
:
torch
.
distributed
.
ProcessGroup
,
self
,
module
:
Union
[
nn
.
Sequential
,
List
[
LazyModule
]],
balance
:
List
[
int
],
group
:
torch
.
distributed
.
ProcessGroup
,
)
->
List
[
ModuleWrapper
]
:
)
->
nn
.
Sequential
:
rank
=
group
.
rank
()
rank
=
group
.
rank
()
first_layer
=
sum
(
balance
[:
rank
])
first_layer
=
sum
(
balance
[:
rank
])
num_layers
=
balance
[
rank
]
num_layers
=
balance
[
rank
]
layers
=
module
[
first_layer
:
first_layer
+
num_layers
]
layers
=
module
[
first_layer
:
first_layer
+
num_layers
]
instantiated_layers
=
[
l
if
isinstance
(
l
,
nn
.
Module
)
else
l
()
for
l
in
layers
]
instantiated_layers
=
[
l
if
isinstance
(
l
,
nn
.
Module
)
else
l
()
for
l
in
layers
]
return
[
ModuleWrapper
(
nn
.
Sequential
(
*
instantiated_layers
)
,
Location
(
rank
,
0
))]
return
nn
.
Sequential
(
*
instantiated_layers
)
def
__len__
(
self
)
->
int
:
def
__len__
(
self
)
->
int
:
"""Counts the length of the underlying sequential module."""
"""Counts the length of the underlying sequential module."""
return
sum
(
len
(
p
)
for
p
in
self
.
partition
s
)
return
self
.
partition
.
__len__
(
)
def
__getitem__
(
self
,
index
:
int
)
->
nn
.
Module
:
def
__getitem__
(
self
,
index
:
int
)
->
nn
.
Module
:
"""Gets a layer in the underlying sequential module."""
"""Gets a layer in the underlying sequential module."""
partitions
:
List
[
Any
]
return
self
.
partition
.
__getitem__
(
index
)
partitions
=
self
.
partitions
if
index
<
0
:
partitions
=
partitions
[::
-
1
]
for
partition
in
partitions
:
try
:
if
isinstance
(
partition
,
ModuleWrapper
):
return
partition
.
module
[
index
]
else
:
return
partition
[
index
]
except
IndexError
:
pass
shift
=
len
(
partition
)
if
index
<
0
:
index
+=
shift
else
:
index
-=
shift
raise
IndexError
def
__iter__
(
self
)
->
Iterable
[
nn
.
Module
]:
def
__iter__
(
self
)
->
Iterable
[
nn
.
Module
]:
"""Iterates over children of the underlying sequential module."""
"""Iterates over children of the underlying sequential module."""
for
partition
in
self
.
partitions
:
return
self
.
partition
.
__iter__
()
yield
from
partition
.
module
def
forward
(
self
,
input
:
TensorOrTensors
,
*
,
event
=
None
)
->
TensorOrTensors
:
# type: ignore
def
forward
(
self
,
input
:
TensorOrTensors
,
*
,
event
=
None
)
->
TensorOrTensors
:
# type: ignore
""":class:`MultiProcessPipe` is a fairly transparent module wrapper. It doesn't
""":class:`MultiProcessPipe` is a fairly transparent module wrapper. It doesn't
...
...
fairscale/nn/pipe/rpc.py
View file @
08c10993
...
@@ -14,13 +14,12 @@ from torch.distributed.distributed_c10d import _get_global_rank
...
@@ -14,13 +14,12 @@ from torch.distributed.distributed_c10d import _get_global_rank
from
fairscale.nn.model_parallel.initialize
import
get_pipeline_parallel_group
from
fairscale.nn.model_parallel.initialize
import
get_pipeline_parallel_group
from
.async_pipe
import
AsyncPipe
from
.async_pipe
import
AsyncPipe
from
.multiprocess_pipe
import
MultiProcessPipe
from
.types
import
EVENT_LOOP_QUEUE
,
PipeMessage
,
TensorOrTensors
from
.types
import
EVENT_LOOP_QUEUE
,
PipeMessage
,
TensorOrTensors
DEFAULT_MAX_SOURCE_POSITIONS
=
1024
DEFAULT_MAX_SOURCE_POSITIONS
=
1024
DEFAULT_MAX_TARGET_POSITIONS
=
1024
DEFAULT_MAX_TARGET_POSITIONS
=
1024
PipeModel
:
MultiProcess
Pipe
PipeModel
:
Async
Pipe
PipeResult
:
TensorOrTensors
PipeResult
:
TensorOrTensors
...
@@ -72,7 +71,7 @@ class PipeBackRedirect(torch.autograd.Function):
...
@@ -72,7 +71,7 @@ class PipeBackRedirect(torch.autograd.Function):
return
(
None
,
None
,
None
,
None
,
None
,
None
)
return
(
None
,
None
,
None
,
None
,
None
,
None
)
def
callback_with_model
(
callback
:
Callable
[[
Any
,
MultiProcess
Pipe
],
None
],
ctx
:
Any
)
->
None
:
def
callback_with_model
(
callback
:
Callable
[[
Any
,
Async
Pipe
],
None
],
ctx
:
Any
)
->
None
:
try
:
try
:
group
=
get_pipeline_parallel_group
()
# FIXME(tom) handle dynamic group
group
=
get_pipeline_parallel_group
()
# FIXME(tom) handle dynamic group
set_device_based_on_group
(
group
)
set_device_based_on_group
(
group
)
...
@@ -121,7 +120,7 @@ class PipeRPCWrapper(nn.Module):
...
@@ -121,7 +120,7 @@ class PipeRPCWrapper(nn.Module):
futures
=
[
f
.
wait
()
for
f
in
futures
]
futures
=
[
f
.
wait
()
for
f
in
futures
]
def
foreach_worker
(
def
foreach_worker
(
self
,
callback
:
Callable
[[
Any
,
MultiProcess
Pipe
],
None
],
ctx
:
Any
=
None
,
*
,
include_self
:
bool
=
False
self
,
callback
:
Callable
[[
Any
,
Async
Pipe
],
None
],
ctx
:
Any
=
None
,
*
,
include_self
:
bool
=
False
)
->
None
:
)
->
None
:
"""Call `callback` on each worker with the `ctx` and model local to that
"""Call `callback` on each worker with the `ctx` and model local to that
worker. e.g.
worker. e.g.
...
@@ -197,7 +196,7 @@ class PipeRPCWrapper(nn.Module):
...
@@ -197,7 +196,7 @@ class PipeRPCWrapper(nn.Module):
@
staticmethod
@
staticmethod
def
_recv_result
(
def
_recv_result
(
model
:
MultiProcess
Pipe
,
shapes
:
SizeOrSizes
,
dtypes
:
DtypeOrDtypes
,
message
:
PipeMessage
model
:
Async
Pipe
,
shapes
:
SizeOrSizes
,
dtypes
:
DtypeOrDtypes
,
message
:
PipeMessage
)
->
TensorOrTensors
:
)
->
TensorOrTensors
:
group
=
get_pipeline_parallel_group
()
group
=
get_pipeline_parallel_group
()
set_device_based_on_group
(
group
)
set_device_based_on_group
(
group
)
...
@@ -245,7 +244,7 @@ class PipeRPCWrapper(nn.Module):
...
@@ -245,7 +244,7 @@ class PipeRPCWrapper(nn.Module):
set_device_based_on_group
(
group
)
set_device_based_on_group
(
group
)
kwargs
[
"group"
]
=
group
kwargs
[
"group"
]
=
group
kwargs
[
"input_device"
]
=
torch
.
device
(
"cuda"
,
torch
.
cuda
.
current_device
())
kwargs
[
"input_device"
]
=
torch
.
device
(
"cuda"
,
torch
.
cuda
.
current_device
())
model
=
MultiProcess
Pipe
(
*
args
,
**
kwargs
)
model
=
Async
Pipe
(
*
args
,
**
kwargs
)
model
.
cuda
()
model
.
cuda
()
global
PipeModel
global
PipeModel
PipeModel
=
model
PipeModel
=
model
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment