Performs element-wise binary division (with Numpy-style broadcasting support).
| 3295 | |
| 3296 | |
| 3297 | class Div(Operator): |
| 3298 | """ |
| 3299 | Performs element-wise binary division (with Numpy-style broadcasting support). |
| 3300 | """ |
| 3301 | |
| 3302 | def __init__(self): |
| 3303 | super(Div, self).__init__() |
| 3304 | |
| 3305 | def forward(self, a, b): |
| 3306 | """ |
| 3307 | Return `np.div(a,b)`, where a and b are CTensor. |
| 3308 | """ |
| 3309 | ori_type = None |
| 3310 | if a.data_type() != singa.kFloat32: |
| 3311 | ori_type = a.data_type() |
| 3312 | a = a.AsType(singa.kFloat32) |
| 3313 | b = b.AsType(singa.kFloat32) |
| 3314 | res = singa.__mul__(a, singa.PowFloat(b, -1.0)) |
| 3315 | # res = singa.__div__(a, b) |
| 3316 | if ori_type is not None: |
| 3317 | res = res.AsType(ori_type) |
| 3318 | if training: |
| 3319 | self.input = (singa.MultFloat(a, -1.0), singa.PowFloat(b, -1.0) |
| 3320 | ) # -a, 1/b |
| 3321 | self.shape0 = list(a.shape()) |
| 3322 | self.shape1 = list(b.shape()) |
| 3323 | self.shape3 = list(res.shape()) |
| 3324 | return res |
| 3325 | |
| 3326 | def backward(self, dy): |
| 3327 | """ |
| 3328 | Args: |
| 3329 | dy (CTensor): the gradient tensor from upper operations |
| 3330 | Returns: |
| 3331 | a CTensor tuple for (da, db), da is data for dL / da, db is data |
| 3332 | for dL / db. |
| 3333 | """ |
| 3334 | #dy/dx_0 = b^(-1) |
| 3335 | #dy/dx_1 = (-a)*b^(-2) |
| 3336 | dx0 = singa.__mul__(dy, self.input[1]) |
| 3337 | dx1 = singa.__mul__(self.input[0], singa.PowFloat(self.input[1], 2.0)) |
| 3338 | dx1 = singa.__mul__(dy, dx1) |
| 3339 | if (type(dy) == float) or self.shape0 == self.shape1: |
| 3340 | assert self.shape0 == self.shape1, ('should have same shape') |
| 3341 | return dx0, dx1 |
| 3342 | # handle broadcast |
| 3343 | dx0 = back_broadcast(self.shape3, self.shape0, dx0) |
| 3344 | dx1 = back_broadcast(self.shape3, self.shape1, dx1) |
| 3345 | return dx0, dx1 |
| 3346 | |
| 3347 | |
| 3348 | def div(a, b): |