淘先锋技术网

首页 1 2 3 4 5 6 7

最近开始写了自己项目的第一个pytoch神经网络,其实官方的文档和案例已经写的很不错了,但是还是有很多的坑,尤其是在数据集以及损失函数方面有问题,记录一下(顺序乱,请酌情使用Ctrl+F):
1、Loss在使用之前要实例化。
这个其实很容易理解,无论是我们自己定义loss类还是直接使用torch的内置损失函数,都是类的方法调用,因此在使用之前要进行实例化
这里贴出我使用的损失函数类,用于颜色恒常性研究的(Color constancy),也希望大佬们指点一下看看有没有写错,使用的是常用的角度误差函数(训练的时候loss有的时候出现nan,现在还不确定是不是损失函数写错了,过后更新)

#定义损失函数
class angleloss(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self,w1,w2):
        z = torch.mul(w1,w2)
        z = torch.sum(z,dim = 2)

        m1 = torch.pow(w1,2)
        m1 = torch.sum(m1, dim = 2)
        m1 = torch.pow(m1,0.5)

        m2 = torch.pow(w2,2)
        m2 = torch.sum(m2, dim = 2)
        m2 = torch.pow(m2,0.5)

        m = torch.mul(m1,m2)

        out = torch.div(z,m)
        out = torch.acos(out)
        out = torch.sum(out)

        return out
myloss = angleloss()

2、网络的input是以batch形式进入的,所以在我们组织图片数据集的时候,要定义好每个batch的大小,这个还是小事情。重要的是在写网络的时候,要注意输入的tensor的第一维度是batch,第二维度是颜色通道,之后是长宽,不要弄混了。

3、若做图像的时候想取其中一个颜色通道,要用切片的方式而不是引用的方式,引用方式会改变tensor的维度,时期第二维度消失。这个应该很容易理解,例如我们取list中的某个数字,使用的是引用的方式,list变成了零维数字;而用切片,则还是list。
例如,网络输入tensor.shape = [64,3,32,32] 我要取RGB通道中的R通道,则应该用[:,0:1,:,:](用了中文冒号别介意,英文看不清),这样取出来的tensor是[64,1,32,32]

4、定义损失函数类的时候,也要注意传入的tensor第一维度是batch,在写损失函数的时候要避免对第一维度进行操作,而在最后需要在第一维度上把所有loss进行相加。也就是说一组batch(多个图片训练结果)只输出一个loss。

5、在建立数据集时,

> transforms.ToTensor()

需要在

transforms.Normalize()

之前,在图像的操作之后,例如:

    color_dataset = ColorConstancyDataset(csv_file="E:\\e_data\\groundtruth.csv",
                                      root_dir="E:\\e_data\\",
                                      transform = transforms.Compose([
                                          transforms.Resize(64),
                                          transforms.ToTensor(),
                                          transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                            ]))

6、图像载入
pytorch的图像载入可以用opencv,也可以用Image包,但是对图像进行颜色通道转换的时候,Image会报错,需要用opencv将图片读取(这个时候图片是矩阵格式),并使用cv2.cvtColor()函数进行颜色空间转换,再使用Image.fromarray()将矩阵(图片)转换为Image格式,只有这个格式可以应用后面的transforms.ToTensor(),否则需要自己写totensor的方法。

7、GPU加速问题
我们都知道,在驱动CUDA等环境配好支持GPU加速的时候,可以使用.cuda()将模型放在GPU上跑,但是这个.cuda()加在哪里,这里进行一下总结说明:
首先,对于训练时初始化模型的时候,需要加
其次,导入的数据在放入模型训练的时候,需要加
最后,计算损失函数时,groundtruth调用的时候,需要加。

    net = self_subtraction_net(self_subtraction_block).cuda()

	outputs = net(inputs.cuda())

	loss = myloss(outputs.cuda(), labels)