Performs stochastic rounding from source tensor to target tensor. Args: target: Destination tensor (determines the target format) source: Source tensor (typically float32) eps: Optional minimum value for stochastic rounding (for numerical stability)
(
target: torch.Tensor,
source: torch.Tensor,
eps: Optional[float] = None
)
| 140 | |
| 141 | |
| 142 | def copy_stochastic( |
| 143 | target: torch.Tensor, |
| 144 | source: torch.Tensor, |
| 145 | eps: Optional[float] = None |
| 146 | ) -> None: |
| 147 | """ |
| 148 | Performs stochastic rounding from source tensor to target tensor. |
| 149 | |
| 150 | Args: |
| 151 | target: Destination tensor (determines the target format) |
| 152 | source: Source tensor (typically float32) |
| 153 | eps: Optional minimum value for stochastic rounding (for numerical stability) |
| 154 | """ |
| 155 | with torch.no_grad(): |
| 156 | # If target is float32, just copy directly |
| 157 | if target.dtype == torch.float32: |
| 158 | target.copy_(source) |
| 159 | return |
| 160 | |
| 161 | # Special handling for int8 |
| 162 | if target.dtype == torch.int8: |
| 163 | # Scale the source values to utilize the full int8 range |
| 164 | scaled = source * 127.0 # Scale to [-127, 127] |
| 165 | |
| 166 | # Add random noise for stochastic rounding |
| 167 | noise = torch.rand_like(scaled) - 0.5 |
| 168 | rounded = torch.round(scaled + noise) |
| 169 | |
| 170 | # Clamp to int8 range |
| 171 | clamped = torch.clamp(rounded, -127, 127) |
| 172 | target.copy_(clamped.to(torch.int8)) |
| 173 | return |
| 174 | |
| 175 | mantissa_bits, _ = get_format_params(target.dtype) |
| 176 | |
| 177 | # Convert source to int32 view |
| 178 | source_int = source.view(dtype=torch.int32) |
| 179 | |
| 180 | # Calculate number of bits to round |
| 181 | bits_to_round = 23 - mantissa_bits # 23 is float32 mantissa bits |
| 182 | |
| 183 | # Create random integers for stochastic rounding |
| 184 | rand = torch.randint_like( |
| 185 | source, |
| 186 | dtype=torch.int32, |
| 187 | low=0, |
| 188 | high=(1 << bits_to_round), |
| 189 | ) |
| 190 | |
| 191 | # Add random values to the bits that will be rounded off |
| 192 | result = source_int.clone() |
| 193 | result.add_(rand) |
| 194 | |
| 195 | # Mask to keep only the bits we want |
| 196 | # Create mask with 1s in positions we want to keep |
| 197 | mask = (-1) << bits_to_round |
| 198 | result.bitwise_and_(mask) |
| 199 |
no test coverage detected