Pytorch框架下的语义分割实战(三,网络训练)

接上一篇

Pytorch框架下的语义分割实战(网络搭建)

今天我们看一看Z博是怎么训练网络的。。。

附上代码

'''
train.py
'''
from datetime import datetime
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from dataset import test_dataloader, train_dataloader
from model import FCNs,VGGNet
#我将FCN文件名改成了model,所以是from model import...
#同样将BagData文件名改成了dataset,所以是from dataset import...

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#device=torch.device("cpu")      #使用cpu
#device=torch.device("cuda")     #使用GPU

def train(epo_num=50, show_vgg_params=False):
    #vis = visdom.Visdom()   #pytorch中的可视化工具
    
    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)
    criterion = nn.BCELoss().to(device)
    optimizer = optim.SGD(fcn_model.parameters(), lr=1e-2, momentum=0.7)

    all_train_iter_loss = []
    all_test_iter_loss = []

    #计算时间
    prev_time = datetime.now()
    for epo in range(epo_num):
        train_loss = 0
        fcn_model.train()
        for index, (bag, bag_msk) in enumerate(train_dataloader):
            # bag.shape is torch.Size([4, 3, 160, 160])
            # bag_msk.shape is torch.Size([4, 2, 160, 160])
            bag = bag.to(device)
            bag_msk = bag_msk.to(device)

            optimizer.zero_grad()
            output = fcn_model(bag)
            output = torch.sigmoid(output) # output.shape is torch.Size([4, 2, 160, 160])
            # print(output)
            # print(bag_msk)
            loss = criterion(output, bag_msk)
            loss.backward()
            iter_loss = loss.item()
            all_train_iter_loss.append(iter_loss)
            train_loss += iter_loss
            optimizer.step()

            output_np = output.cpu().detach().numpy().copy() # output_np.shape = (4, 2, 160, 160)  
            output_np = np.argmin(output_np, axis=1)
            bag_msk_np = bag_msk.cpu().detach().numpy().copy() # bag_msk_np.shape = (4, 2, 160, 160) 
            bag_msk_np = np.argmin(bag_msk_np, axis=1)

        test_loss = 0
        fcn_model.eval()
        with torch.no_grad():
            for index, (bag, bag_msk) in enumerate(test_dataloader):
                bag = bag.to(device)
                bag_msk = bag_msk.to(device)
                optimizer.zero_grad()
                output = fcn_model(bag)
                output = torch.sigmoid(output) # output.shape is torch.Size([4, 2, 160, 160])
                loss = criterion(output, bag_msk)  #预测和原标签图的差
                iter_loss = loss.item()   #item得到一个元素张量里面的元素值,一般用于返回loss,acc
                all_test_iter_loss.append(iter_loss)
                test_loss += iter_loss

                output_np = output.cpu().detach().numpy().copy() # output_np.shape = (4, 2, 160, 160)  
                output_np = np.argmin(output_np, axis=1)
                bag_msk_np = bag_msk.cpu().detach().numpy().copy() # bag_msk_np.shape = (4, 2, 160, 160) 
                bag_msk_np = np.argmin(bag_msk_np, axis=1)

        cur_time = datetime.now()
        h, remainder = divmod((cur_time - prev_time).seconds, 3600)
        m, s = divmod(remainder, 60)
        time_str = "Time %02d:%02d:%02d" % (h, m, s)
        prev_time = cur_time
 

        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, '/Bags/results/fcn_model_{}.pt'.format(epo))
            print('fcn_model_{}.pt'.format(epo))


if __name__ == "__main__":
    train(epo_num=100, show_vgg_params=False)

①nn.BCELoss()

pytorch中nn.CrossEntropyLoss为交叉熵损失函数,用于解决多分类、二分类问题。
BCELoss是Binary CrossEntropyLoss缩写,nn.BCELoss()是二元交叉熵损失函数,只能解决二分类问题。
某CSDN博主说使用此函数时,前面需要加上Sigmoid函数,加上nn.Sigmoid()语句即可。

数学公式为Loss = -w*[p*log(q) + (1-p)*log(1-q)],其中p、q分别为理论标签、实际预测值,w为权重。这里的log对应数学上的ln。

参数说明:torch.nn.BCELoss(weight=None,size_average=True,reduce=True,reduction='mean')
①weight必须和target的shape一致,默认为None。
②默认情况下reduce=True,size_average=True
③若reduce=False,size_average无效,返回值为向量形式的loss
④若reduce=True,size_average=True,返回loss的均值,即loss.mean()
⑤若reduce=True,size_average=False,返回loss的和,即loss.sum()
⑥若reduction=‘none’,返回向量形式的loss
⑦若reduction=‘sum’,返回loss的和
⑧若reduction=‘elementwise_mean’,返回loss的平均值
⑨若reduction=‘mean’,返回loss的平均值

下面用代码展示一下此函数的作用吧...

import torch 
import torch.nn as nn

m = nn.Sigmoid()
loss = nn.BCELoss(size_average=False, reduce=False)

input = torch.randn(3, requires_grad=True)

#empty()是构造一个张量函数,构造了一个1*3的张量,取值范围为[0,2-1],用来初始化target
#如果函数有下标'_',表示此函数是Tensor中的内建函数
target = torch.empty(3).random_(2)  
lossinput = m(input)
output = loss(lossinput, target)
#print(input)
print(' The value of input is', lossinput)
print('\n The value of output target is', target)
print('\n The value of loss is', output)

'''
Out:

The value of input is tensor([0.4625, 0.6193, 0.3062], grad_fn=<SigmoidBackward>)

 The value of output target is tensor([1., 0., 0.])

 The value of loss is tensor([0.7712, 0.9658, 0.3656], grad_fn=<BinaryCrossEntropyBackward>)
'''

②optim.SGD(fcn_model.parameters(), lr, momentum)

SGD的全称是Stochastic Gradient Descent(随机梯度下降)。
梯度下降法主要有三种:批量、随机、小批量
①批量梯度下降法:整个训练数据集计算梯度
②随机梯度下降法:随机取一个样本计算梯度
③小批量梯度下降法:选取少数(即batch_size的大小)样本组成一个小批量样本,用这个小批量样本计算梯度。

fcn_model.parameters():获取fcn_model网络中的参数。搭建好神经网络后,网络的参数都保存在parameters()函数中。

learning rate(lr):学习率较小时,收敛到极值的速度较慢。学习率较大时,容易在收敛过程中发生震荡。

momentum:物理学中指力对时间的累积。每次x的更新量v=-dx*lr,其中dx是目标函数func(x)对x的一阶导。
当本次梯度下降-dx*lr的方向与上次更新量v的方向相同时,上次的更新量能够对本次的搜索起到一个正向加速的作用。 
当本次梯度下降-dx*lr的方向与上次更新量v的方向相反时,上次的更新量能够对本次的搜索起到一个减速的作用。

③enumerate()

此函数用于一个可遍历的数据对象,如list,tuple等。返回值是数据和对应的下标,一般用在for循环中。
下面看代码吧...

seasons = ['Spring', 'Summer', 'Fall', 'Winter']
list(enumerate(seasons))

'''
Out:
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
'''
list(enumerate(seasons, start=1))

'''
Out:
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
'''


for s in enumerate(seasons):
    print(s)

print('\n')

for i,s in enumerate(seasons):
    print(s,i)

print('\n')

for i,s in enumerate(seasons):
    print(i,s)


'''
Out:

(0, 'Spring')
(1, 'Summer')
(2, 'Fall')
(3, 'Winter')


Spring 0
Summer 1
Fall 2
Winter 3


0 Spring
1 Summer
2 Fall
3 Winter
'''

④output.cpu().detach().numpy().copy()

.cpu():将数据移至cpu中

.detach():返回一个新的Variable,从当前计算图中分离下来,但是仍指向原变量的存放位置,只是没有梯度,即使后期令requi_grad=True,也不具有梯度。后面进行反向传播时,需要调用detach()的Variable就会停止,不会再继续向前传播。
参考网址:https://blog.csdn.net/weixin_33913332/article/details/93300411

.numpy():将tensor转为numpy数据

.copy():复制

⑤np.argmin()

该函数时给出一组数据中最小值的下标。

import numpy as np
data = [1,4,2,6,0,0]
print(np.argmin(data))

data1 = [[0,2,3],[1,2,3],[4,3,2]]  #默认将列表展平,显示最小值的下标
print(np.argmin(data1))
print(np.argmin(data1, axis=1))

data2 = [[[1,2]],[[3,0]],[[4,9]]]
print(np.argmin(data2))

'''
Out:

4
0
[0 0 2]
3
'''

⑥divmod()

此函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组。

print('a:', divmod(7,2))
print('b:', divmod(8,2))

'''
Out:

a: (3, 1)
b: (4, 0)
'''

⑦.second()

'''
以秒为单位计算时间差
'''
import datetime

t1 = datetime.datetime.strptime("2016-08-24 10:30:00", "%Y-%m-%d %H:%M:%S")
t2 = datetime.datetime.strptime("2016-08-24 12:30:00", "%Y-%m-%d %H:%M:%S")

interval_time = (t2 - t1).seconds
print(interval_time)

'''
Out:
7200
'''

好了,到这里就先告一段落了,有不对的地方,欢迎留言指正哦....

下个项目见(*๓´╰╯`๓)

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值