Skip to content

Commit 7e194bc

Browse files
authored
Merge pull request #1229 from MouseLand/bfloat16_quantization
Bfloat16 quantization
2 parents 79b0fcb + 083434f commit 7e194bc

5 files changed

Lines changed: 1037 additions & 9 deletions

File tree

cellpose/core.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def assign_device(use_torch=True, gpu=False, device=0):
109109
return device, gpu
110110

111111

112-
def _to_device(x, device):
112+
def _to_device(x, device, dtype=torch.float32):
113113
"""
114114
Converts the input tensor or numpy array to the specified device.
115115
@@ -121,7 +121,7 @@ def _to_device(x, device):
121121
torch.Tensor: The converted tensor on the specified device.
122122
"""
123123
if not isinstance(x, torch.Tensor):
124-
X = torch.from_numpy(x).to(device, dtype=torch.float32)
124+
X = torch.from_numpy(x).to(device, dtype=dtype)
125125
return X
126126
else:
127127
return x
@@ -137,7 +137,8 @@ def _from_device(X):
137137
Returns:
138138
numpy.ndarray: The converted NumPy array.
139139
"""
140-
x = X.detach().cpu().numpy()
140+
# The cast is so numpy conversion always works
141+
x = X.detach().cpu().to(torch.float32).numpy()
141142
return x
142143

143144

@@ -151,7 +152,7 @@ def _forward(net, x):
151152
Returns:
152153
Tuple[numpy.ndarray, numpy.ndarray]: The output predictions (flows and cellprob) and style features.
153154
"""
154-
X = _to_device(x, device=net.device)
155+
X = _to_device(x, device=net.device, dtype=net.dtype)
155156
net.eval()
156157
with torch.no_grad():
157158
y, style = net(X)[:2]

cellpose/models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class CellposeModel():
8989
"""
9090

9191
def __init__(self, gpu=False, pretrained_model="cpsam", model_type=None,
92-
diam_mean=None, device=None, nchan=None):
92+
diam_mean=None, device=None, nchan=None, use_bfloat16=True):
9393
"""
9494
Initialize the CellposeModel.
9595
@@ -99,6 +99,7 @@ def __init__(self, gpu=False, pretrained_model="cpsam", model_type=None,
9999
model_type (str, optional): Any model that is available in the GUI, use name in GUI e.g. "livecell" (can be user-trained or model zoo).
100100
diam_mean (float, optional): Mean "diameter", 30. is built-in value for "cyto" model; 17. is built-in value for "nuclei" model; if saved in custom model file (cellpose>=2.0) then it will be loaded automatically and overwrite this value.
101101
device (torch device, optional): Device used for model running / training (torch.device("cuda") or torch.device("cpu")), overrides gpu input, recommended if you want to use a specific GPU (e.g. torch.device("cuda:1")).
102+
use_bfloat16 (bool, optional): Use 16bit float precision instead of 32bit for model weights. Default to 16bit (True).
102103
"""
103104
if diam_mean is not None:
104105
models_logger.warning(
@@ -139,7 +140,8 @@ def __init__(self, gpu=False, pretrained_model="cpsam", model_type=None,
139140
)
140141

141142
self.pretrained_model = pretrained_model
142-
self.net = Transformer().to(self.device)
143+
dtype = torch.bfloat16 if use_bfloat16 else torch.float32
144+
self.net = Transformer(dtype=dtype).to(self.device)
143145

144146
if os.path.exists(self.pretrained_model):
145147
models_logger.info(f">>>> loading model {self.pretrained_model}")

cellpose/train.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def _loss_fn_seg(lbl, y, device):
4848
veci = 5. * lbl[:, -2:]
4949
loss = criterion(y[:, -3:-1], veci)
5050
loss /= 2.
51-
loss2 = criterion2(y[:, -1], (lbl[:, -3] > 0.5).float())
51+
loss2 = criterion2(y[:, -1], (lbl[:, -3] > 0.5).to(y.dtype))
5252
loss = loss + loss2
5353
return loss
5454

@@ -454,6 +454,11 @@ def train_seg(net, train_data=None, train_labels=None, train_files=None,
454454
# network and loss optimization
455455
X = torch.from_numpy(imgi).to(device)
456456
lbl = torch.from_numpy(lbl).to(device)
457+
458+
if X.dtype != net.dtype:
459+
X = X.to(net.dtype)
460+
lbl = lbl.to(net.dtype)
461+
457462
y = net(X)[0]
458463
loss = _loss_fn_seg(lbl, y, device)
459464
if y.shape[1] > 3:

cellpose/vit_sam.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class Transformer(nn.Module):
1212
def __init__(self, backbone="vit_l", ps=8, nout=3, bsize=256, rdrop=0.4,
13-
checkpoint=None):
13+
checkpoint=None, dtype=torch.float32):
1414
super(Transformer, self).__init__()
1515

1616
# instantiate the vit model, default to not loading SAM
@@ -49,6 +49,8 @@ def __init__(self, backbone="vit_l", ps=8, nout=3, bsize=256, rdrop=0.4,
4949
for blk in self.encoder.blocks:
5050
blk.window_size = 0
5151

52+
self.dtype = dtype
53+
5254
def forward(self, x):
5355
# same progression as SAM until readout
5456
x = self.encoder.patch_embed(x)
@@ -59,7 +61,7 @@ def forward(self, x):
5961
if self.training and self.rdrop > 0:
6062
nlay = len(self.encoder.blocks)
6163
rdrop = (torch.rand((len(x), nlay), device=x.device) <
62-
torch.linspace(0, self.rdrop, nlay, device=x.device)).float()
64+
torch.linspace(0, self.rdrop, nlay, device=x.device)).to(x.dtype)
6365
for i, blk in enumerate(self.encoder.blocks):
6466
mask = rdrop[:,i].unsqueeze(-1).unsqueeze(-1).unsqueeze(-1)
6567
x = x * mask + blk(x) * (1-mask)
@@ -90,6 +92,9 @@ def load_model(self, PATH, device, strict = False):
9092
else:
9193
self.load_state_dict(state_dict, strict = strict)
9294

95+
if self.dtype != torch.float32:
96+
self = self.to(self.dtype)
97+
9398

9499
@property
95100
def device(self):

0 commit comments

Comments
 (0)