語義分割遠程使用GPU+語義分割編寫流程(pytorch)

作爲一個只學習了一點點語義分割模型的小白,真正實戰起來還是一個鴻溝,最近遇到了很多小白初期肯定都會遇到的問題,在這裏一一說一下,希望能夠幫助到小白們。

1、實驗室服務器有GPU,我們如何使用服務器的GPU進行模型的訓練呢?

答:我這裏採用的方法是使用pycharm連接遠程服務器,網上有很多此類的教程,我其實只在pycharm裏面配置了遠程服務器,然後就可以可視化服務器的文件了,本地的文件可以和服務器的文件同步,也就是你把文件放進pycharm裏面,然後upload,就跑到服務器裏面了,這和你用xshell使用rz命令上傳文件是一樣的。

這裏需要注意一點:我們可視化遠程服務器文件後,可以在自己電腦的pycharm上編輯服務器文件,然後上傳,服務器的代碼就成功更改了,不過編輯是在本地,實際運行可不是讓你運行pycharm,而是用命令行連接服務器後,使用python 文件名.py運行代碼,在代碼裏面使用GPU就可以了

  1. 將本地pycharm遠程連接帶有GPU的服務器
  2. 將本地編寫的文件upload到服務器
  3. 打開命令行,ssh連接到服務器
  4. cd進入代碼所在地址,輸入python 文件名.py運行代碼

GPU使用是在代碼裏面寫的,pytorch使用GPU代碼如下:

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

2、知道了如何使用GPU,那麼我們如何進行語義分割代碼的編寫和運行呢?

答:我看到網上此類的教程不多,於是自己將詳細的教程寫一下。(基於pytorch)

流程主要分類四個方面吧:

  1. 圖像處理
  2. 模型建立
  3. 訓練模型並保存最優模型
  4. 讀取模型進行測試

因爲我是小白,所以接下來我將詳細說明在pytorch中進行上面四個方面的具體過程。

一、圖像處理部分

我們進入pytorch官網,可以看到如下庫:

如果需要進行圖像處理,那麼我們使用Pytorch——計算機視覺工具包:torchvision

Pytorch——計算機視覺工具包:torchvision

torchvision獨立於Pytorch,需通過pip install torchvision 安裝。 
torchvision 主要包含以下三部分:

models : 提供深度學習中各種經典的網絡結構以及訓練好的模型,包括Alex Net, VGG系列、ResNet系列、Inception系列等;
datasets:提供常用的數據集加載,設計上都是繼承torch.utils.data.Dataset,主要包括MMIST、CIFAR10/100、ImageNet、COCO等;
transforms: 提供常用的數據預處理操作,主要包括對Tensor及PIL Image對象的操作。

具體操作過程如下:

1、首先寫transform,transform的輸入是圖片,輸出是對圖片的操作結果。(參見pytorchvison.transforms文檔)

例如這樣:

transform=transforms.Compose([
    transforms.Resize(224),  #縮放圖片(Image),保持長寬比不變,最短邊爲224像素
    transforms.CenterCrop(224), #從圖片中間裁剪出224*224的圖片
    transforms.ToTensor(), #將圖片Image轉換成Tensor,歸一化至【0,1】
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
    #標準化,規定均值和方差                   
])

2、採用cv2庫的imread、resize等函數對圖像進行一些早期處理。(參見cv2實現數據增強的博客)

例如這樣:

        imgB = cv2.imread('bag_data_msk/' + img_name, 0)
        imgB = cv2.resize(imgB, (160, 160))
        imgB = imgB / 255
        imgB = imgB.astype('uint8')
        imgB = onehot(imgB, 2)  # 因爲此代碼是二分類問題,即分割出手提包和背景兩樣就行,因此這裏參數是2
        imgB = imgB.transpose(2, 0, 1)  # imgB不經過transform處理,所以要手動把(H,W,C)轉成(C,H,W)
        imgB = torch.FloatTensor(imgB)

3、對圖像進行transform處理。

例如這樣:

    img_name = r'bag3.jpg'  # 預測的圖片
    imgA = cv2.imread(img_name)
    imgA = cv2.resize(imgA, (160, 160))
    imgA = transform(imgA)

4、將本地數據集轉化爲pytorch的Dataset類。(參見Pytorch中正確設計並加載數據集方法)

也就是說要將我們自己的數據集轉化爲pytorch的數據集類,這樣才能將數據集加載進DataLoader中。

Dataset類是Pytorch中圖像數據集中最爲重要的一個類,也是Pytorch中所有數據集加載類中應該繼承的父類。其中父類中的兩個私有成員函數必須被重載,否則將會觸發錯誤提示:

  • def getitem(self, index):
  • def len(self):

其中__len__應該返回數據集的大小,而__getitem__應該編寫支持數據集索引的函數,例如通過dataset[i]可以得到數據集中的第i+1個數據。

例如這樣:

class BagDataset(Dataset):
    def __init__(self, transform=None):
        self.transform = transform

    def __len__(self):
        return len(os.listdir('bag_data'))

    def __getitem__(self, idx):
        img_name = os.listdir('bag_data')[idx]
        imgA = cv2.imread('bag_data/' + img_name)
        imgA = cv2.resize(imgA, (160, 160))
        # print(imgA.shape)
        imgB = cv2.imread('bag_data_msk/' + img_name, 0)
        imgB = cv2.resize(imgB, (160, 160))
        imgB = imgB / 255
        imgB = imgB.astype('uint8')
        imgB = onehot(imgB, 2)  # 因爲此代碼是二分類問題,即分割出手提包和背景兩樣就行,因此這裏參數是2
        imgB = imgB.transpose(2, 0, 1)  # imgB不經過transform處理,所以要手動把(H,W,C)轉成(C,H,W)
        imgB = torch.FloatTensor(imgB)
        if self.transform:
            imgA = self.transform(imgA)  # 一轉成向量後,imgA通道就變成(C,H,W)
        return imgA, imgB

5、定義訓練集個數和測試集個數,並進行劃分。(參見Pytorch劃分數據集的方法

例如這樣:

train_size = int(0.9 * len(bag))  # 整個訓練集中,百分之90爲訓練集
test_size = len(bag) - train_size
train_dataset, test_dataset = random_split(bag, [train_size, test_size])  # 按照給定的長度將數據集劃分成沒有重疊的新數據集組合

6、定義DataLoader。

Dataset是一個包裝類,用來將數據包裝爲Dataset類,然後傳入DataLoader中,我們再使用DataLoader這個類來更加快捷的對數據進行操作。

DataLoader是一個比較重要的類,它爲我們提供的常用操作有:batch_size(每個batch的大小), shuffle(是否進行shuffle操作), num_workers(加載數據的時候使用幾個子進程)
例如這樣:

train_dataloader = DataLoader(train_dataset, batch_size=4, shuffle=True, num_workers=4)
test_dataloader = DataLoader(test_dataset, batch_size=4, shuffle=True, num_workers=4)

到這裏,我們主要做了如下任務:

  1. 讀取圖像
  2. 圖像增強
  3. 圖像處理
  4. 數據集轉換
  5. 定義訓練集和測試集個數,並通過random_split切分得到
  6. 定義DataLoader,將圖像集傳入

到這裏,第一模塊:圖像處理部分大致就這樣了。

二、模型建立

網絡這部分就不多說了,因爲網上有各種語義分割的網絡結構,而且你從github上一搜索好多是。

三、訓練模型

  1. 設置GPU訓練
  2. 獲得模型,並將模型分配給GPU
  3. 設置損失函數評判標準
  4. 設置優化方法
  5. 第一個for循環epoch
  6. 第二個for循環從DataLoader中獲得圖像數據
  7. 將圖像傳入模型中,獲得結果,並將結果二值化
  8. 優化器梯度設置爲0,將輸出和真實結果計算損失,損失反向傳播,優化器.step()
  9. 設置輸出顯示,保存模型等

1、設置GPU訓練

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

2、獲得模型,並將模型分配給GPU

    vgg_model = VGGNet(requires_grad=True, show_params=show_vgg_params)
    fcn_model = FCNs(pretrained_net=vgg_model, n_class=2)
    fcn_model = fcn_model.to(device)

3、設置損失函數評判標準

4、設置優化方法

    criterion = nn.BCELoss().to(device)
    optimizer = optim.SGD(fcn_model.parameters(), lr=1e-2, momentum=0.7)

5、第一個for循環epoch

for epo in range(epo_num):

6、第二個for循環從DataLoader中獲得圖像數據

for index, (bag, bag_msk) in enumerate(train_dataloader):

7、將圖像傳入模型中,獲得結果,並將結果二值化

output = fcn_model(bag)
output = torch.sigmoid(output)

8、優化器梯度設置爲0,將輸出和真實結果計算損失,損失反向傳播,優化器.step()

optimizer.zero_grad()
loss = criterion(output, bag_msk)
loss.backward()
optimizer.step()

9、設置輸出顯示,保存模型等

print('epoch train loss = %f, epoch test loss = %f, %s'
              % (train_loss / len(train_dataloader), test_loss / len(test_dataloader), time_str))

if np.mod(epo, 5) == 0:
    torch.save(fcn_model, 'checkpoints/fcn_model_{}.pt'.format(epo))
    print('saveing checkpoints/fcn_model_{}.pt'.format(epo))

四、測試

  1. 加載模型
  2. 設置transform或者cv2將圖像轉化成想輸入的大小
  3. 傳入模型輸出顯示或保存

大致過程就是這樣的,如果你想要實現一下的話,可以參考網上的:

pytorch用FCN語義分割手提包數據集(訓練+預測單張輸入圖片代碼)

我已經試過了,能夠成功運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章