天天看點

可視化(一):在模型訓練過程中,繪制特征的可視化圖一,用途二,步驟

原文

一,用途

主要用于證明方法的有效性、增加工作量、增加論文字數。,用于比較驗證。

可視化兩個圖,使用了新方法的和使用之前的,互相比較,根據圖示内容寫論文,說明新方法展現的作用。

二,步驟

1,加載資料并預處理

加載資料:通過classdataset,生成資料加載疊代器。(這裡僅加載一張圖檔,跳過此操作)

資料(圖檔)預處理:調整大小 —— 轉化為Tensor格式 —— 歸一化 —— 資料增強 —— 圖檔資料處理等(這裡取前三個)

def image_proprecess(img_path):
    img = Image.open(img_path)
    data_transforms = transforms.Compose([
        transforms.Resize((384, 384), interpolation=3),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ])
    data = data_transforms(img)
    data = torch.unsqueeze(data,0)
    return data
           

加載一張圖時,使用 torch.unsqueeze 将三維張量變成四維。

2,修改網絡

當需要可視化某一層的特征圖時,需要将該層的特征圖傳回出來,是以修改網絡中的 forward 函數:

def forward(self, x):
    x = self.model.conv1(x)
    x = self.model.bn1(x)
    x = self.model.relu(x)
    x = self.model.maxpool(x)
    feature = self.model.layer1(x)
    x = self.model.layer2(feature)
    x = self.model.layer3(x)
    x = self.model.layer4(x)
    return feature,x
           

3, 定義網絡并加載預訓練模型

def Init_Setting(epoch):
    dirname = '/mnt/share/VideoReID/share/models/Methods5_trial1'
    model = siamese_resnet50(701, stride=1, pool='avg')
    trained_path = os.path.join(dirname, 'net_%03d.pth' % epoch)
    print("load %03d.pth" % epoch)
    model.load_state_dict(torch.load(trained_path))
    model = model.cuda().eval()
    return model
           

注:最後一行,為将網絡設定為推理模式

4,可視化特征圖

将特征圖的某一通道轉化為一張圖來進行可視化:

def visualize_feature_map(img_batch,out_path,type,BI):
    feature_map = torch.squeeze(img_batch)
    feature_map = feature_map.detach().cpu().numpy()

    feature_map_sum = feature_map[0, :, :]
    feature_map_sum = np.expand_dims(feature_map_sum, axis=2)
    for i in range(0, 2048):
        feature_map_split = feature_map[i,:, :]
        feature_map_split = np.expand_dims(feature_map_split,axis=2)
        if i > 0:
            feature_map_sum +=feature_map_split
        feature_map_split = BI.transform(feature_map_split)

        plt.imshow(feature_map_split)
        plt.savefig(out_path + str(i) + "_{}.jpg".format(type) )
        plt.xticks()
        plt.yticks()
        plt.axis('off')

    feature_map_sum = BI.transform(feature_map_sum)
    plt.imshow(feature_map_sum)
    plt.savefig(out_path + "sum_{}.jpg".format(type))
    print("save sum_{}.jpg".format(type))
           
  1. 參數img_batch是從網絡中的某一層傳回來的特征圖,BI是雙線性插值的函數,自定義的,下面會講。
  2. 由于隻可視化了一張圖檔,是以img_batch是四維的,且batchsize維為1。第三行将它從GPU上弄到CPU上,并變成numpy格式。
  3. 剩下部分主要完成将每個通道變成一張圖,以及将所有通道每個元素對應位置相加,并儲存。

雙線性插值

在經過多次網絡下采樣後,後面層的特征圖一般變得隻有7×7,16×16大小。可視化後特别小,是以需要對其進行上采樣。雙線性插值就是上采樣方法之一,

class BilinearInterpolation(object):
    def __init__(self, w_rate: float, h_rate: float, *, align='center'):
        if align not in ['center', 'left']:
            logging.exception(f'{align} is not a valid align parameter')
            align = 'center'
        self.align = align
        self.w_rate = w_rate
        self.h_rate = h_rate

    def set_rate(self,w_rate: float, h_rate: float):
        self.w_rate = w_rate    # w 的縮放率
        self.h_rate = h_rate    # h 的縮放率

    # 由變換後的像素坐标得到原圖像的坐标    針對高
    def get_src_h(self, dst_i,source_h,goal_h) -> float:
        if self.align == 'left':
            # 左上角對齊
            src_i = float(dst_i * (source_h/goal_h))
        elif self.align == 'center':
            # 将兩個圖像的幾何中心重合。
            src_i = float((dst_i + 0.5) * (source_h/goal_h) - 0.5)
        src_i += 0.001
        src_i = max(0.0, src_i)
        src_i = min(float(source_h - 1), src_i)
        return src_i
    # 由變換後的像素坐标得到原圖像的坐标    針對寬
    def get_src_w(self, dst_j,source_w,goal_w) -> float:
        if self.align == 'left':
            # 左上角對齊
            src_j = float(dst_j * (source_w/goal_w))
        elif self.align == 'center':
            # 将兩個圖像的幾何中心重合。
            src_j = float((dst_j + 0.5) * (source_w/goal_w) - 0.5)
        src_j += 0.001
        src_j = max(0.0, src_j)
        src_j = min((source_w - 1), src_j)
        return src_j

    def transform(self, img):
        source_h, source_w, source_c = img.shape  # (235, 234, 3)
        goal_h, goal_w = round(
            source_h * self.h_rate), round(source_w * self.w_rate)
        new_img = np.zeros((goal_h, goal_w, source_c), dtype=np.uint8)

        for i in range(new_img.shape[0]):       # h
            src_i = self.get_src_h(i,source_h,goal_h)
            for j in range(new_img.shape[1]):
                src_j = self.get_src_w(j,source_w,goal_w)
                i2 = ceil(src_i)
                i1 = int(src_i)
                j2 = ceil(src_j)
                j1 = int(src_j)
                x2_x = j2 - src_j
                x_x1 = src_j - j1
                y2_y = i2 - src_i
                y_y1 = src_i - i1
                new_img[i, j] = img[i1, j1]*x2_x*y2_y + img[i1, j2] * \
                    x_x1*y2_y + img[i2, j1]*x2_x*y_y1 + img[i2, j2]*x_x1*y_y1
        return new_img
#使用方法
BI = BilinearInterpolation(8, 8)
feature_map = BI.transform(feature_map)
           

5,主函數流程

imgs_path = "/path/to/imgs/"
save_path = "/save/path/to/output/"
model = Init_Setting(120)
BI = BilinearInterpolation(8, 8)

data = image_proprecess(out_path + "0836.jpg")
data = data.cuda()
output, _ = model(data)
visualize_feature_map(output, save_path, "drone", BI)
           

僅作學習記錄分享,侵聯删。

繼續閱讀