Skip to content

Commit a5d54aa

Browse files
committed
Add fp16 support
1 parent 3c5e828 commit a5d54aa

10 files changed

Lines changed: 204 additions & 78 deletions

File tree

dist_ir/backend/torch.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from ..executor.rank_projector import project
1515
from ..ir import Function, cpprint
1616
from ..ir.device import Device
17-
from ..ir.type import Int32, Int64, Float32, Type
17+
from ..ir.type import Int32, Int64, Float16, Float32, Type
1818

1919
# NOTE: The code currently suffers from this issue, more investigation needed:
2020
# https://github.com/pytorch/pytorch/issues/11201
@@ -166,6 +166,8 @@ def _recv(shape=None, from_d=None, group=None, dtype=None, ctx=None):
166166
x = torch.zeros(shape).int()
167167
elif isinstance(dtype, Int64):
168168
x = torch.zeros(shape).long()
169+
elif isinstance(dtype, Float16):
170+
x = torch.zeros(shape).half()
169171
elif isinstance(dtype, Float32):
170172
x = torch.zeros(shape).float()
171173
else:

examples/gpt2.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,8 @@ def _resolve_dtype(dtype):
561561
return torch.int32
562562
elif dtype == np.int64:
563563
return torch.int64
564+
elif dtype == np.float16:
565+
return torch.float16
564566
elif dtype == np.float32:
565567
return torch.float32
566568
else:

examples/gpt2_grid_search.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class GPTGridSearch(GridSearch):
1010
def __init__(
1111
self,
1212
backend,
13+
dtype,
1314
use_gpu,
1415
output_file,
1516
device_throughput,
@@ -38,6 +39,7 @@ def __init__(
3839
super().__init__(
3940
model_params,
4041
backend,
42+
dtype,
4143
use_gpu,
4244
output_file,
4345
device_throughput,

examples/grid_search.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def __init__(
4343
self,
4444
model_params,
4545
backend,
46+
dtype,
4647
use_gpu,
4748
output_file,
4849
device_throughput,
@@ -55,6 +56,7 @@ def __init__(
5556
):
5657
self.model_params = model_params
5758
self.backend = backend
59+
self.dtype = dtype
5860
self.use_gpu = use_gpu
5961
self.output_file = output_file
6062
self.device_throughput = device_throughput
@@ -272,6 +274,7 @@ def run_grid_search(args, grid_search_cls):
272274
}
273275
grid_search = grid_search_cls(
274276
args.backend,
277+
args.dtype,
275278
args.use_gpu,
276279
args.output_file,
277280
args.device_throughput,

examples/mlp.py

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
import torch
66

77
from dist_ir.ir import FunctionMaker, Topology, get_uniform_topology, Value
8-
from dist_ir.ir.type import Int32, Float32, Tensor, abstract_values
9-
from dist_ir.executor import CostModel, Simulator, infer_types
8+
from dist_ir.ir.type import Int32, Float16, Float32, Tensor, abstract_values
9+
from dist_ir.executor import (
10+
CostModel,
11+
Simulator,
12+
ConcreteValue,
13+
infer_types,
14+
sequentially_execute,
15+
)
1016
from dist_ir.transforms import mlp_dhp_transform
1117
from .parser import Parser
1218
import dist_ir.backend.torch as torch_backend
@@ -39,42 +45,40 @@ def get_typed_input_values(inputs, batch_size, input_dim, output_dim):
3945
return tuple(typed_inputs)
4046

4147

42-
def get_input_data(batch_size, dim, num_layers):
43-
x = np.random.normal(size=(batch_size, dim))
44-
z = np.random.normal(size=(batch_size, dim))
45-
n = batch_size
46-
weights = [np.random.normal(size=(dim, dim))]
47-
for i in range(1, num_layers - 1):
48-
weights.append(np.random.normal(size=(dim, dim)))
49-
weights.append(np.random.normal(size=(dim, dim)))
48+
def get_input_data(inputs, batch_size, input_dim, output_dim, device, dtype):
49+
input_data = []
50+
x = np.random.normal(0, 0.02, size=(batch_size, input_dim))
51+
z = np.random.normal(0, 0.02, size=(batch_size, output_dim))
52+
n = np.int64(batch_size)
53+
weights = [np.random.normal(0, 0.02, size=inp.type.shape) for inp in inputs[3:]]
5054
input_data = [x, z, n] + weights
51-
input_data = [
52-
v.astype(np.float32) if i != 2 else v for i, v in enumerate(input_data)
53-
]
55+
input_data = [v.astype(dtype) if i != 2 else v for i, v in enumerate(input_data)]
56+
input_data = [ConcreteValue(v, device) for v in input_data]
57+
assert len(input_data) == len(inputs)
5458
return input_data
5559

5660

57-
def mlp(input_dim, hidden_dim, output_dim, num_hidden_layers, device):
61+
def mlp(input_dim, hidden_dim, output_dim, num_hidden_layers, device, dtype):
5862
function = FunctionMaker(name="mlp")
5963
x = function.add_input_value(
6064
"x",
61-
Tensor(dtype=Float32(), shape=None, device=device),
65+
Tensor(dtype=dtype(), shape=None, device=device),
6266
)
6367
z = function.add_input_value(
6468
"z",
65-
Tensor(dtype=Float32(), shape=None, device=device),
69+
Tensor(dtype=dtype(), shape=None, device=device),
6670
)
6771
n = function.add_input_value("n", Int32(device=device))
6872
weights = []
6973
for i in range(num_hidden_layers - 1):
7074
w = function.add_input_value(
7175
f"w{chr(ord('A')+i)}",
72-
Tensor(dtype=Float32(), shape=(input_dim, hidden_dim), device=device),
76+
Tensor(dtype=dtype(), shape=(input_dim, hidden_dim), device=device),
7377
)
7478
weights.append(w)
7579
w = function.add_input_value(
7680
f"w{chr(ord('A')+i+1)}",
77-
Tensor(dtype=Float32(), shape=(hidden_dim, output_dim), device=device),
81+
Tensor(dtype=dtype(), shape=(hidden_dim, output_dim), device=device),
7882
)
7983
weights.append(w)
8084

@@ -107,24 +111,24 @@ def mlp(input_dim, hidden_dim, output_dim, num_hidden_layers, device):
107111

108112

109113
def mlp_inference(
110-
batch_size, input_dim, hidden_dim, output_dim, num_hidden_layers, device
114+
batch_size, input_dim, hidden_dim, output_dim, num_hidden_layers, device, dtype
111115
):
112116
function = FunctionMaker(name="mlp")
113117
weights = []
114118
for i in range(num_hidden_layers - 1):
115119
w = function.add_input_value(
116120
f"w{chr(ord('A')+i)}",
117-
Tensor(dtype=Float32(), shape=(input_dim, hidden_dim), device=device),
121+
Tensor(dtype=dtype(), shape=(input_dim, hidden_dim), device=device),
118122
)
119123
weights.append(w)
120124
w = function.add_input_value(
121125
f"w{chr(ord('A')+i+1)}",
122-
Tensor(dtype=Float32(), shape=(hidden_dim, output_dim), device=device),
126+
Tensor(dtype=dtype(), shape=(hidden_dim, output_dim), device=device),
123127
)
124128
weights.append(w)
125129
x = function.add_input_value(
126130
"x",
127-
Tensor(dtype=Float32(), shape=(batch_size, input_dim), device=device),
131+
Tensor(dtype=dtype(), shape=(batch_size, input_dim), device=device),
128132
)
129133

130134
a = x
@@ -136,7 +140,7 @@ def mlp_inference(
136140

137141

138142
def mlp_inference_dp(
139-
batch_size, input_dim, hidden_dim, output_dim, num_hidden_layers, devices
143+
batch_size, input_dim, hidden_dim, output_dim, num_hidden_layers, devices, dtype
140144
):
141145
num_devices = len(devices)
142146
assert batch_size % num_devices == 0
@@ -147,16 +151,16 @@ def mlp_inference_dp(
147151
for i in range(num_hidden_layers - 1):
148152
weights[i, d] = function.add_input_value(
149153
f"w{chr(ord('A')+i)}_{d.device_id}",
150-
Tensor(dtype=Float32(), shape=(input_dim, hidden_dim), device=d),
154+
Tensor(dtype=dtype(), shape=(input_dim, hidden_dim), device=d),
151155
)
152156
weights[num_hidden_layers - 1, d] = function.add_input_value(
153157
f"w{chr(ord('A')+i+1)}_{d.device_id}",
154-
Tensor(dtype=Float32(), shape=(hidden_dim, output_dim), device=d),
158+
Tensor(dtype=dtype(), shape=(hidden_dim, output_dim), device=d),
155159
)
156160
x[d] = function.add_input_value(
157161
f"x_{d.device_id}",
158162
Tensor(
159-
dtype=Float32(), shape=(batch_size // num_devices, input_dim), device=d
163+
dtype=dtype(), shape=(batch_size // num_devices, input_dim), device=d
160164
),
161165
)
162166

@@ -274,20 +278,38 @@ def simulate(function, input_types, topology, allreduce_parameters=None):
274278
return simulation
275279

276280

277-
def run_pytorch(function, input_data, world_size, use_gpu=True):
281+
def run_pytorch(function, input_data, world_size, use_gpu=torch.cuda.is_available()):
282+
# TODO: Move this to a utils file
283+
def _resolve_dtype(dtype):
284+
if dtype == np.int32:
285+
return torch.int32
286+
elif dtype == np.int64:
287+
return torch.int64
288+
elif dtype == np.float16:
289+
return torch.float16
290+
elif dtype == np.float32:
291+
return torch.float32
292+
else:
293+
raise NotImplementedError(dtype)
294+
278295
if use_gpu and world_size > torch.cuda.device_count():
279296
raise ValueError(
280297
f"Specified world size is {world_size}, but only "
281298
f"{torch.cuda.device_count()} GPUs available"
282299
)
300+
pytorch_input_data = [
301+
torch.tensor(x.val, dtype=_resolve_dtype(x.val.dtype))
302+
if isinstance(x.val, np.ndarray)
303+
else torch.tensor(x.val, dtype=torch.int32)
304+
for x in input_data
305+
]
283306
input_types = abstract_values(
284307
input_data,
285308
tuple(
286309
Tensor if isinstance(input_data[i].val, np.ndarray) else Int32
287310
for i in range(len(input_data))
288311
),
289312
)
290-
pytorch_input_data = [torch.tensor(x.val, dtype=torch.float32) for x in input_data]
291313
per_rank_outputs, runtimes = torch_backend.run_pytorch(
292314
function,
293315
pytorch_input_data,
@@ -302,6 +324,7 @@ def run_pytorch(function, input_data, world_size, use_gpu=True):
302324
def run_mlp(
303325
phase,
304326
backend,
327+
dtype,
305328
use_gpu,
306329
batch_size,
307330
input_dim,
@@ -319,6 +342,8 @@ def run_mlp(
319342
trace_file,
320343
verbose=False,
321344
):
345+
dist_ir_dtype = Float32 if dtype == "fp32" else Float16
346+
numpy_dtype = np.float32 if dtype == "fp32" else np.float16
322347
world_size = dp_degree * hp_degree * pp_degree
323348
topology = get_uniform_topology(
324349
world_size,
@@ -335,6 +360,7 @@ def run_mlp(
335360
output_dim,
336361
num_hidden_layers,
337362
topology.devices[0],
363+
dist_ir_dtype,
338364
)
339365
elif phase == "inference":
340366
fn = mlp_inference(
@@ -343,13 +369,24 @@ def run_mlp(
343369
output_dim,
344370
num_hidden_layers,
345371
topology.devices[0],
372+
dist_ir_dtype,
346373
)
347374

348375
if verbose:
349376
parameter_count, model_size, parameter_count_str, model_size_str = get_stats(fn)
350377
print("Parameter count:", parameter_count_str)
351378
print("Model size:", model_size_str)
352379

380+
if backend == "pytorch":
381+
input_data = get_input_data(
382+
fn.inputs,
383+
batch_size,
384+
input_dim,
385+
output_dim,
386+
topology.devices[0],
387+
numpy_dtype,
388+
)
389+
353390
if world_size > 1:
354391
init_fn, transformed_fn = mlp_dhp_transform(
355392
fn,
@@ -365,13 +402,17 @@ def run_mlp(
365402
init_fn = infer_types(init_fn, typed_inputs)
366403
transformed_fn = infer_types(transformed_fn, init_fn.outputs)
367404
input_types = tuple(output.type for output in init_fn.outputs)
405+
if backend == "pytorch":
406+
transformed_input_data = sequentially_execute(init_fn, input_data)
368407
else:
369408
typed_inputs = get_typed_input_values(
370409
fn.inputs, batch_size, input_dim, output_dim
371410
)
372411
fn = infer_types(fn, typed_inputs)
373412
transformed_fn = fn
374413
input_types = tuple(inp.type for inp in fn.inputs)
414+
if backend == "pytorch":
415+
transformed_input_data = input_data
375416
transformed_fn = add_optimizer_ops(transformed_fn)
376417
if backend == "simulate":
377418
simulation = simulate(transformed_fn, input_types, topology)
@@ -381,19 +422,14 @@ def run_mlp(
381422
simulation.dump_chrome_trace(trace_file)
382423
return simulation
383424
elif backend == "pytorch":
384-
input_data = [
385-
ConcreteValue(
386-
np.random.normal(size=typ.size).astype(np.float32), device=typ.device
387-
)
388-
for typ in input_types
389-
]
390-
return run_pytorch(fn, input_data, world_size, use_gpu)
425+
return run_pytorch(transformed_fn, transformed_input_data, world_size, use_gpu)
391426

392427

393428
def main(args):
394429
run_mlp(
395430
args.phase,
396431
args.backend,
432+
args.dtype,
397433
args.use_gpu,
398434
args.batch_size,
399435
args.input_dim,

examples/mlp_grid_search.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import numpy as np
2+
13
from dist_ir.ir import Value
2-
from dist_ir.ir.type import Tensor
4+
from dist_ir.ir.type import Tensor, Float32, Float16
35
from dist_ir.executor import infer_types, sequentially_execute, ConcreteValue
46
from dist_ir.transforms import mlp_dhp_transform
57
from . import mlp
@@ -11,6 +13,7 @@ class MLPGridSearch(GridSearch):
1113
def __init__(
1214
self,
1315
backend,
16+
dtype,
1417
use_gpu,
1518
output_file,
1619
device_throughput,
@@ -30,6 +33,7 @@ def __init__(
3033
super().__init__(
3134
model_params,
3235
backend,
36+
dtype,
3337
use_gpu,
3438
output_file,
3539
device_throughput,
@@ -46,16 +50,25 @@ def get_model_and_input_data(self, batch_size, model_size):
4650
if model_size not in self.models:
4751
num_layers, dim = self.model_params[model_size]
4852
self.models[model_size] = mlp.mlp(
49-
dim, dim, dim, num_layers, self.topology.devices[0]
53+
dim,
54+
dim,
55+
dim,
56+
num_layers,
57+
self.topology.devices[0],
58+
Float32 if self.dtype == "fp32" else Float16,
5059
)
5160

5261
fn = self.models[model_size]
5362
num_layers, dim = self.model_params[model_size]
5463
if self.backend == "pytorch":
55-
input_data = mlp.get_input_data(batch_size, dim, num_layers)
56-
input_data = tuple(
57-
ConcreteValue(t, inp.type.device)
58-
for t, inp in zip(input_data, fn.inputs)
64+
dtype = np.float32 if self.dtype == "fp32" else np.float16
65+
input_data = mlp.get_input_data(
66+
fn.inputs,
67+
batch_size,
68+
dim,
69+
dim,
70+
self.topology.devices[0],
71+
dtype,
5972
)
6073
else:
6174
input_data = mlp.get_typed_input_values(fn.inputs, batch_size, dim, dim)

0 commit comments

Comments
 (0)