| 1210 | |
| 1211 | |
| 1212 | class CrossEntropy(Operator): |
| 1213 | |
| 1214 | def __init__(self, t): |
| 1215 | super(CrossEntropy, self).__init__() |
| 1216 | self.t = t.data |
| 1217 | |
| 1218 | """ |
| 1219 | Calculte negative log likelihood loss for a batch of training data. |
| 1220 | """ |
| 1221 | |
| 1222 | def forward(self, x): |
| 1223 | """ |
| 1224 | Args: |
| 1225 | x (CTensor): 1d or 2d tensor, the prediction data(output) |
| 1226 | of current network. |
| 1227 | t (CTensor): 1d or 2d tensor, the target data for training. |
| 1228 | Returns: |
| 1229 | loss (CTensor): scalar. |
| 1230 | """ |
| 1231 | loss = singa.SumAll(singa.__mul__(self.t, singa.Log(x))) |
| 1232 | loss /= -x.shape()[0] |
| 1233 | self.x = x |
| 1234 | return loss |
| 1235 | |
| 1236 | def backward(self, dy=1.0): |
| 1237 | """ |
| 1238 | Args: |
| 1239 | dy (float or CTensor): scalar, accumulate gradient from outside |
| 1240 | of current network, usually equal to 1.0 |
| 1241 | Returns: |
| 1242 | dx (CTensor): data for the dL /dx, L is the loss, x is the output |
| 1243 | of current network. note that this is true for |
| 1244 | dy = 1.0 |
| 1245 | """ |
| 1246 | |
| 1247 | dx = singa.__div__(self.t, self.x) |
| 1248 | dx *= float(-1.0 / self.x.shape()[0]) |
| 1249 | if isinstance(dy, float): |
| 1250 | # dtype of dy: float |
| 1251 | dx *= dy |
| 1252 | return dx |
| 1253 | elif isinstance(dy, CTensor): |
| 1254 | pass # TODO, broadcast elementwise multiply seems not support |
| 1255 | |
| 1256 | |
| 1257 | def cross_entropy(x, t): |