1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| class Transformer: """ Transform input for feeding into a Net. Note: this is mostly for illustrative purposes and it is likely better to define your own input preprocessing routine for your needs. Parameters ---------- net : a Net for which the input should be prepared """ def __init__(self, inputs): self.inputs = inputs self.transpose = {} self.channel_swap = {} self.raw_scale = {} self.mean = {} self.input_scale = {} def __check_input(self, in_): if in_ not in self.inputs: raise Exception('{} is not one of the net inputs: {}'.format( in_, self.inputs)) def preprocess(self, in_, data): """ Format input for Caffe: - convert to single - resize to input dimensions (preserving number of channels) - transpose dimensions to K x H x W - reorder channels (for instance color to BGR) - scale raw input (e.g. from [0, 1] to [0, 255] for ImageNet models) - subtract mean - scale feature Parameters ---------- in_ : name of input blob to preprocess for data : (H' x W' x K) ndarray !!!!输入data必须是单个image,后面有限制 Returns ------- caffe_in : (K x H x W) ndarray for input to a Net """ self.__check_input(in_) caffe_in = data.astype(np.float32, copy=False) transpose = self.transpose.get(in_) channel_swap = self.channel_swap.get(in_) raw_scale = self.raw_scale.get(in_) mean = self.mean.get(in_) input_scale = self.input_scale.get(in_) in_dims = self.inputs[in_][2:] if caffe_in.shape[:2] != in_dims: caffe_in = resize_image(caffe_in, in_dims) if transpose is not None: caffe_in = caffe_in.transpose(transpose) if channel_swap is not None: caffe_in = caffe_in[channel_swap, :, :] if raw_scale is not None: caffe_in *= raw_scale if mean is not None: caffe_in -= mean if input_scale is not None: caffe_in *= input_scale return caffe_in def deprocess(self, in_, data): """ Invert Caffe formatting; see preprocess(). """ self.__check_input(in_) decaf_in = data.copy().squeeze() transpose = self.transpose.get(in_) channel_swap = self.channel_swap.get(in_) raw_scale = self.raw_scale.get(in_) mean = self.mean.get(in_) input_scale = self.input_scale.get(in_) if input_scale is not None: decaf_in /= input_scale if mean is not None: decaf_in += mean if raw_scale is not None: decaf_in /= raw_scale if channel_swap is not None: decaf_in = decaf_in[np.argsort(channel_swap), :, :] if transpose is not None: decaf_in = decaf_in.transpose(np.argsort(transpose)) return decaf_in def set_transpose(self, in_, order): """ Set the input channel order for e.g. RGB to BGR conversion as needed for the reference ImageNet model. Parameters ---------- in_ : which input to assign this channel order order : the order to transpose the dimensions """ self.__check_input(in_) if len(order) != len(self.inputs[in_]) - 1: raise Exception('Transpose order needs to have the same number of ' 'dimensions as the input.') self.transpose[in_] = order def set_channel_swap(self, in_, order): """ Set the input channel order for e.g. RGB to BGR conversion as needed for the reference ImageNet model. N.B. this assumes the channels are the first dimension AFTER transpose. Parameters ---------- in_ : which input to assign this channel order order : the order to take the channels. (2,1,0) maps RGB to BGR for example. """ self.__check_input(in_) if len(order) != self.inputs[in_][1]: raise Exception('Channel swap needs to have the same number of ' 'dimensions as the input channels.') self.channel_swap[in_] = order def set_raw_scale(self, in_, scale): """ Set the scale of raw features s.t. the input blob = input * scale. While Python represents images in [0, 1], certain Caffe models like CaffeNet and AlexNet represent images in [0, 255] so the raw_scale of these models must be 255. Parameters ---------- in_ : which input to assign this scale factor scale : scale coefficient """ self.__check_input(in_) self.raw_scale[in_] = scale def set_mean(self, in_, mean): """ Set the mean to subtract for centering the data. Parameters ---------- in_ : which input to assign this mean. mean : mean ndarray (input dimensional or broadcastable) """ self.__check_input(in_) ms = mean.shape if mean.ndim == 1: if ms[0] != self.inputs[in_][1]: raise ValueError('Mean channels incompatible with input.') mean = mean[:, np.newaxis, np.newaxis] else: if len(ms) == 2: ms = (1,) + ms if len(ms) != 3: raise ValueError('Mean shape invalid') if ms != self.inputs[in_][1:]: raise ValueError('Mean shape incompatible with input shape.') self.mean[in_] = mean def set_input_scale(self, in_, scale): """ Set the scale of preprocessed inputs s.t. the blob = blob * scale. N.B. input_scale is done AFTER mean subtraction and other preprocessing while raw_scale is done BEFORE. Parameters ---------- in_ : which input to assign this scale factor scale : scale coefficient """ self.__check_input(in_) self.input_scale[in_] = scale
|
Comments