Pytorch框架下的语义分割实战(三,网络训练),超详细讲解!!

    科技2024-12-12  16

    接上一篇

    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()是二元交叉熵损失函数,只能解决二分类问题。 某博主说使用此函数时,前面需要加上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 '''

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

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

     

     

     

    Processed: 0.043, SQL: 8