Group datapoints of the same shape together to batches. It doesn't require input DataFlow to be homogeneous anymore: it can have datapoints of different shape, and batches will be formed from those who have the same shape. Note: It is implemented by a dict{shape -> data
| 191 | |
| 192 | |
| 193 | class BatchDataByShape(BatchData): |
| 194 | """ |
| 195 | Group datapoints of the same shape together to batches. |
| 196 | It doesn't require input DataFlow to be homogeneous anymore: it can have |
| 197 | datapoints of different shape, and batches will be formed from those who |
| 198 | have the same shape. |
| 199 | |
| 200 | Note: |
| 201 | It is implemented by a dict{shape -> datapoints}. |
| 202 | Therefore, datapoints of uncommon shapes may never be enough to form a batch and |
| 203 | never get generated. |
| 204 | """ |
| 205 | def __init__(self, ds, batch_size, idx): |
| 206 | """ |
| 207 | Args: |
| 208 | ds (DataFlow): input DataFlow. ``dp[idx]`` has to be an :class:`np.ndarray`. |
| 209 | batch_size (int): batch size |
| 210 | idx (int): ``dp[idx].shape`` will be used to group datapoints. |
| 211 | Other components are assumed to be batch-able. |
| 212 | """ |
| 213 | super(BatchDataByShape, self).__init__(ds, batch_size, remainder=False) |
| 214 | self.idx = idx |
| 215 | |
| 216 | def reset_state(self): |
| 217 | super(BatchDataByShape, self).reset_state() |
| 218 | self.holder = defaultdict(list) |
| 219 | self._guard = DataFlowReentrantGuard() |
| 220 | |
| 221 | def __iter__(self): |
| 222 | with self._guard: |
| 223 | for dp in self.ds: |
| 224 | shp = dp[self.idx].shape |
| 225 | holder = self.holder[shp] |
| 226 | holder.append(dp) |
| 227 | if len(holder) == self.batch_size: |
| 228 | yield BatchData.aggregate_batch(holder) |
| 229 | del holder[:] |
| 230 | |
| 231 | |
| 232 | class FixedSizeData(ProxyDataFlow): |