示例#1
0
class PatchQuantizier():
    def __init__(self,
                 rec,
                 init_acc,
                 max_acc_loss,
                 patch_size,
                 out_rec=None,
                 default_in_pattern=None):
        self.patch_size = patch_size
        self.input_patterns = rec.all_patterns
        self.actual_patch_sizes = rec.patch_sizes
        self.input = rec.gen_pattern_lists(init_acc - max_acc_loss)

        if default_in_pattern is None:
            self.default_in_pattern = np.ones(
                (self.input_patterns.shape[0], self.input_patterns.shape[0]),
                dtype=self.input_patterns.dtype)
        else:
            self.default_in_pattern = default_in_pattern

        if out_rec is None:
            self._generate_patterns(rec.mode, rec.layers_layout,
                                    rec.gran_thresh, rec.filename,
                                    max_acc_loss, init_acc)
        else:
            self.output_rec = out_rec

    def number_of_iters(self):
        return self.output_rec.size

    def simulate(self, nn, test_gen):
        st_point = self.output_rec.find_resume_point()
        print('==> Starting PatchQuantizier simulation.')

        save_counter = 0
        for l in tqdm(range(st_point[0], len(self.input))):
            for c in range(st_point[1], len(self.output_rec.all_patterns[l])):
                st_point[1] = 0
                for p_idx in range(st_point[3],
                                   len(self.output_rec.all_patterns[l][c])):
                    st_point[3] = 0

                    if self.output_rec.mode == Mode.UNIFORM_FILTERS:
                        mask = mf.tile_opt(
                            self.output_rec.layers_layout[l],
                            self.output_rec.all_patterns[l][c][p_idx], True)
                    else:
                        mask = np.ones(mf.expend_dims(
                            self.output_rec.layers_layout[l], self.patch_size),
                                       dtype=self.default_in_pattern.dtype)
                        mask[c, :, :] = self.output_rec.all_patterns[l][c][
                            p_idx]

                    nn.net.strict_mask_update(update_ids=[l],
                                              masks=[torch.from_numpy(mask)])

                    if PQ_DEBUG:
                        test_acc = 100
                        ops_saved = 100
                        ops_total = 100
                    else:
                        _, test_acc, _ = nn.test(test_gen)
                        ops_saved, ops_total = nn.net.num_ops()
                        nn.net.reset_ops()
                    self.output_rec.addRecord(ops_saved, ops_total, test_acc,
                                              l, c, 0, p_idx)

                    save_counter += 1
                    if save_counter > cfg.SAVE_INTERVAL:
                        self.save_state()
                        save_counter = 0

        self.output_rec.fill_empty()
        self.save_state()

        print('==> finised PatchQuantizier simulation.')

    def is_finised(self):
        return self.output_rec.find_resume_point() is None

    def save_state(self):
        save_to_file(self.output_rec, True, cfg.RESULTS_DIR)

    def _generate_patterns(self, mode, layers_layout, gran_thresh,
                           rec_in_filename, max_acc_loss, init_acc):
        self.output_rec = Record(layers_layout, gran_thresh, False, mode,
                                 init_acc)
        self.output_rec.set_results_dimensions(no_of_layers=len(self.input),
                                               no_of_patches=[1] *
                                               len(self.input))

        if cfg.PATCHQ_UPDATE_RATIO == 1:
            no_of_patterns_gen, all_patterns = self._gen_patterns_zip_longest(
                layers_layout)
        else:
            no_of_patterns_gen, all_patterns = self._gen_patterns_zip_ratio(
                layers_layout)

        self.output_rec.set_all_patterns(all_patterns, RecordType.pQ_REC)
        self.output_rec.set_results_dimensions(
            no_of_patterns=no_of_patterns_gen,
            no_of_channels=[len(c) for c in all_patterns])

        fn = f'PatchQ{cfg.PQ_OPTION.value}r{cfg.PATCHQ_UPDATE_RATIO}_ma{max_acc_loss}_' + rec_in_filename
        if PQ_DEBUG:
            fn = 'DEBUG_' + fn
        self.output_rec.set_filename(fn)

    def _build_channel(self, channel_opt, l, c, layer_dims):
        new_patch_n = math.ceil(layer_dims[1] / self.actual_patch_sizes[l])
        new_patch_m = math.ceil(layer_dims[2] / self.actual_patch_sizes[l])
        channel = np.ones((new_patch_n * self.actual_patch_sizes[l],
                           new_patch_m * self.actual_patch_sizes[l]),
                          dtype=self.input_patterns.dtype)
        for patch_idx, opt in enumerate(channel_opt):
            if type(opt) is int:
                opt = self.input[l][c][patch_idx][opt]
            ii, jj = mf.get_patch_indexes(patch_idx, layer_dims[1],
                                          self.actual_patch_sizes[l])
            p = self.input_patterns[:, :, opt[0]]
            if (self.actual_patch_sizes[l] != self.patch_size):
                p = mf.tile_opt(
                    (self.actual_patch_sizes[l], self.actual_patch_sizes[l]),
                    p, False)
            channel = mf.change_one_patch2d(channel, ii, jj,
                                            self.actual_patch_sizes[l], p)
        return mf.crop(layer_dims, channel, self.patch_size)

    def _zip_ratio(self, curr_channel_opt, patches_to_update, channel_input):
        possible_patches = []
        last_stage_patches = []
        for patch, opt_idx in enumerate(curr_channel_opt):
            if cfg.TWO_STAGE and opt_idx + 1 < (len(channel_input[patch]) - 1):
                possible_patches.append(patch)
            elif cfg.TWO_STAGE and opt_idx + 1 == (len(channel_input[patch]) -
                                                   1):
                last_stage_patches.append(patch)
            elif not cfg.TWO_STAGE and opt_idx + 1 < (len(
                    channel_input[patch])):
                possible_patches.append(patch)

        if patches_to_update < len(possible_patches):
            if cfg.PQ_OPTION == cfg.PQ_modes.DEFAULT:
                sorted_patches = [
                    x for x, _ in sorted(zip(
                        possible_patches,
                        itemgetter(*possible_patches)(curr_channel_opt)),
                                         key=lambda pair: pair[1])
                ]
                if patches_to_update == 1:
                    patches_to_inc = [sorted_patches[0]]
                else:
                    patches_to_inc = list(
                        itemgetter(*range(patches_to_update))(sorted_patches))
        elif len(possible_patches) > 0:
            patches_to_inc = possible_patches
        else:
            patches_to_inc = []

        additional_patches = patches_to_update - len(patches_to_inc)
        if additional_patches > 0:
            if additional_patches < len(last_stage_patches):
                if cfg.PQ_OPTION == cfg.PQ_modes.DEFAULT:
                    if additional_patches == 1:
                        patches_to_inc.append(last_stage_patches[0])
                    else:
                        patches_to_inc += list(
                            itemgetter(*range(additional_patches))(
                                last_stage_patches))
            elif len(last_stage_patches) > 0:
                patches_to_inc += last_stage_patches

        if len(patches_to_inc) == 0:
            return None
        else:
            for patch in patches_to_inc:
                curr_channel_opt[patch] += 1
            return curr_channel_opt

    def _gen_patterns_zip_ratio(self, layers_layout):
        all_patterns = []
        no_of_patterns = [None] * len(self.input)
        for l in range(len(self.input)):
            layers = []
            no_of_patterns[l] = [0] * len(self.input[l])
            for c in range(len(self.input[l])):
                channels = []
                patches_to_update = math.ceil(cfg.PATCHQ_UPDATE_RATIO *
                                              len(self.input[l][c]))
                curr_channel_opt = [0] * len(self.input[l][c])
                while curr_channel_opt is not None:
                    no_of_patterns[l][c] += 1
                    channels.append(
                        self._build_channel(curr_channel_opt, l, c,
                                            layers_layout[l]))
                    curr_channel_opt = self._zip_ratio(curr_channel_opt,
                                                       patches_to_update,
                                                       self.input[l][c])
                layers.append(channels)
            all_patterns.append(layers)
        patterns_max_count = [
            max(no_of_patterns[l]) for l in range(len(self.input))
        ]
        return patterns_max_count, all_patterns

    def _gen_patterns_zip_longest(self, layers_layout):
        all_patterns = []
        no_of_patterns = [None] * len(self.input)
        for l in range(len(self.input)):
            layers = []
            no_of_patterns[l] = [0] * len(self.input[l])
            for c in range(len(self.input[l])):
                channels = []
                for channel_opt in zip_longest(*self.input[l][c],
                                               fillvalue=(-1, -1, -1)):
                    no_of_patterns[l][c] += 1
                    channels.append(
                        self._build_channel(channel_opt, l, c,
                                            layers_layout[l]))
                layers.append(channels)
            all_patterns.append(layers)
        patterns_max_count = [
            max(no_of_patterns[l]) for l in range(len(self.input))
        ]
        return patterns_max_count, all_patterns
示例#2
0
class ChannelQuantizier():
    def __init__(self, rec, init_acc, max_acc_loss, patch_size, out_rec=None, default_in_pattern=None):
        self.patch_size = patch_size
        self.input_patterns = rec.all_patterns
        self.input = rec.gen_pattern_lists(init_acc - max_acc_loss)
        
        input_new = []
        self.no_of_patterns = 0
        for l in range(len(self.input)):
            input_new.append([self.input[l][c][0] for c in range(rec.layers_layout[l][0])])
            self.no_of_patterns += max([len(self.input[l][c][0]) for c in range(rec.layers_layout[l][0])])
        self.input = input_new

        if default_in_pattern is not None:
            self.default_in_pattern = default_in_pattern
        elif rec.mode == Mode.MAX_GRANULARITY:
            self.default_in_pattern = np.ones((self.patch_size, self.patch_size), dtype=self.input_patterns[0][0][0].dtype)
        else:
            self.default_in_pattern = np.ones((self.input_patterns.shape[0], self.input_patterns.shape[0]),
                                              dtype=self.input_patterns.dtype)

        if out_rec is None:
            self._generate_patterns(rec.mode, rec.layers_layout, rec.gran_thresh, rec.filename, max_acc_loss, init_acc)
        else:
            self.output_rec = out_rec
            
    def number_of_iters(self):
        return self.no_of_patterns

    def simulate(self, nn, test_gen):
        st_point = self.output_rec.find_resume_point()
        print('==> starting ChannelQuantizier simulation.')

        save_counter = 0
        for layer in tqdm(range(st_point[0], len(self.input))):
            for p_idx in range(st_point[3], len(self.output_rec.all_patterns[layer])):
                st_point[3] = 0
                nn.net.strict_mask_update(update_ids=[layer],
                                              masks=[torch.from_numpy(self.output_rec.all_patterns[layer][p_idx])])
                if CQ_DEBUG:
                    test_acc = 100
                    ops_saved = 100
                    ops_total = 100
                else:
                    _, test_acc, _ = nn.test(test_gen)
                    ops_saved, ops_total = nn.net.num_ops()
                    nn.net.reset_ops()
                self.output_rec.addRecord(ops_saved, ops_total, test_acc, layer, 0, 0, p_idx)

                save_counter += 1
                if save_counter > cfg.SAVE_INTERVAL:
                    self.save_state()
                    save_counter = 0

        self.save_state()
        print('==> finised ChannelQuantizier simulation.')

    def is_finised(self):
        return self.output_rec.find_resume_point() is None

    def save_state(self):
        save_to_file(self.output_rec, True, cfg.RESULTS_DIR)

    def _generate_patterns(self, mode, layers_layout, gran_thresh, rec_in_filename, max_acc_loss, init_acc):
        self.output_rec = Record(layers_layout, gran_thresh, False, mode, init_acc)
        self.output_rec.set_results_dimensions(no_of_layers=len(self.input),
                                               no_of_channels=[1] * len(self.input),
                                               no_of_patches=[1] * len(self.input))
        if cfg.CHANNELQ_UPDATE_RATIO == 1:
            no_of_patterns_gen, all_patterns = self._gen_patterns_zip_longest(mode, layers_layout)
        else:
            no_of_patterns_gen, all_patterns = self._gen_patterns_zip_ratio(mode, layers_layout)
        
        self.output_rec.set_all_patterns(all_patterns, RecordType.cQ_REC)
        self.output_rec.set_results_dimensions(no_of_patterns=no_of_patterns_gen)

        fn = f'ChannelQ{cfg.CQ_OPTION.value}r{cfg.CHANNELQ_UPDATE_RATIO}_ma{max_acc_loss}_' + rec_in_filename
        if CQ_DEBUG:
            fn = 'DEBUG_' + fn
        self.output_rec.set_filename(fn)
        
    def _build_layer(self, layer_dims, layer_opt, l, mode):
        layer = np.ones(mf.expend_dims(layer_dims, self.patch_size), dtype=self.default_in_pattern.dtype)
        for idx, opt in enumerate(layer_opt):
            if type(opt) is int:
                opt = self.input[l][idx][opt]
            if opt[0] == -1:
                tmp = mf.tile_opt((layer_dims[1], layer_dims[2]),
                                               self.default_in_pattern, False)
            elif mode == Mode.MAX_GRANULARITY:
                tmp = mf.tile_opt((layer_dims[1], layer_dims[2]),
                                               self.input_patterns[l][idx][opt[0]], False)
            else:
                tmp = mf.tile_opt((layer_dims[1], layer_dims[2]),
                                               self.input_patterns[:, :, opt[0]], False)
            layer[idx, :, :] = mf.crop(layer_dims,tmp, self.patch_size)
        return layer
    
    def _gen_patterns_zip_ratio(self, mode, layers_layout):
        all_patterns = []
        no_of_patterns = [None] * len(self.input)
        for l in range(len(self.input)):
            channels_to_update = math.ceil(cfg.CHANNELQ_UPDATE_RATIO*layers_layout[l][0])
            layers = []
            curr_layer_opt = [0]*layers_layout[l][0]
            while curr_layer_opt is not None:
                layers.append(self._build_layer(layers_layout[l], curr_layer_opt, l, mode))
                curr_layer_opt = self._zip_ratio(curr_layer_opt, channels_to_update, self.input[l])
            no_of_patterns[l] = len(layers)
            all_patterns.append(layers)
        return no_of_patterns, all_patterns
    
    def _zip_ratio(self, curr_layer_opt, channels_to_update, layer_input):
        possible_channels = []
        last_stage_channels = []
        for channel, opt_idx in enumerate(curr_layer_opt):
            if cfg.TWO_STAGE and opt_idx+1 < (len(layer_input[channel])-1):
                possible_channels.append(channel)
            elif cfg.TWO_STAGE and opt_idx+1 == (len(layer_input[channel])-1):
                last_stage_channels.append(channel)
            elif not cfg.TWO_STAGE and opt_idx+1 < (len(layer_input[channel])):
                possible_channels.append(channel)
        
        if channels_to_update < len(possible_channels):
            if cfg.CQ_OPTION == cfg.CQ_modes.DEFAULT:
                sorted_channels = [x for x,_ in sorted(zip(possible_channels, itemgetter(*possible_channels)(curr_layer_opt)), key=lambda pair: pair[1])]
                if channels_to_update == 1:
                    channels_to_inc = [sorted_channels[0]]
                else:
                    channels_to_inc = sorted_channels[:channels_to_update]
        elif len(possible_channels) > 0:
            channels_to_inc = possible_channels
        else:
            channels_to_inc = []
            
        additional_channels = channels_to_update - len(channels_to_inc)
        if additional_channels > 0:
            if additional_channels < len(last_stage_channels):
                if cfg.CQ_OPTION == cfg.CQ_modes.DEFAULT:
                    if additional_channels == 1:
                        channels_to_inc.append(last_stage_channels[0])
                    else:
                        channels_to_inc += last_stage_channels[:additional_channels]
            elif len(last_stage_channels) > 0:
                channels_to_inc += last_stage_channels
        
        if len(channels_to_inc) == 0:
            return None
        else:
            for channel in channels_to_inc:
                curr_layer_opt[channel] += 1
            return curr_layer_opt 

    def _gen_patterns_zip_longest(self, mode, layers_layout):
        all_patterns = []
        no_of_patterns = [None] * len(self.input)
        for l in range(len(self.input)):
            layers = []
            for layer_opt in zip_longest(*self.input[l], fillvalue=(-1, -1, -1)):
                layers.append(self._build_layer(layers_layout[l], layer_opt, l, mode))
            no_of_patterns[l] = len(layers)
            all_patterns.append(layers)
        return no_of_patterns, all_patterns
    
    def _clean_input(self):
        for l in range(len(self.input)):
            for c in range(len(self.input[l])):
                self.input[l][c][:] = [tup for tup in self.input[l][c] if self._determine(tup)]


    def _determine(self, tup):
        p_idx, ops_saved, acc, tot_ops = tup
        if ops_saved == 0 and p_idx != -1:
            return False
        return True