notes_0915

  2018-9-15 


  1. 尽量少使用显式循环
    用向量化(并行运算) 即将元素作为向量进行计算
    numpy.dot(x,y)
    numpy.exp(v)
    等等 numpy有很多向量化函数
    即为点乘
    平时计算的时候也可以直接用向量化计算,速度快很多

  2. 神经网络——堆叠的线性分类器
    一个网元就是一个线性分类器

  3. 激活函数的选择 ReLU>sigmod
    ReLU最常用,sigmod基本不用

  4. tensor = 张量
    在pytorch中,matrix即为张量

  5. tensor,list,numpy array, tensor list的 转换方法

    list = [[1,2,3],[3,4,5]]
    tensor = torch.Tensor(list) #List->Tensor
    narray = numpy.array(list)  #List->narray
    tensor = torch.from_numpy(narray) #narray->tensor
    narray = tensor.numpy()   #Tensor->narray
    注意list narray tensor之间的转换方法
    将tensor list转变为tensor: 
    用torch.stack而不是torch.Tensor
    tensor_list = [tensor0,tensor1,tensor2..]=>tensor
    tensor = torch.stack(tensor_list)
    注意tensor中的格式必须相同,如果想要和list一样合并变长tensor必须用cat)
  6. Tensor数学运算

    tensor.sub(b)  #tensor-b
    fin = torch.add(tensor1,tensor2) #fin = tensor1+tensor2
    (mul div同add)
    
    torch.sum()
    
    #批矩阵相乘函数
    torch.bmm(A,B)

    对numpy array求math function,不要用math.function,直接用numpy.function如

    np.exp(nparray)

    如果对tensor求math函数的报错only one element tensors can be converted to Python scalars的话,就将tensor转化为numpy array再用numpy库的数学函数求

  7. torch.Varibale和torch.Tensor用法基本一致,可以替换使用
    Variable包装了一个Tensor,并且保存着梯度和创建这个Variablefunction的引用
    本质上Variable和Tensor没有什么区别,
    不过Variable会放在一个计算图里面,
    可以进行前向传播和反向传播以及求导

  8. 显卡信息
    nvidia-smi

  9. sum(condition)
    计算满足condition的总数
    eg:sum(predict == label)
    preidict 是一个list
    label是一个list
    他们形状相同
    则统计两个列表中对应元素相同的个数

  10. batch
    每一次从训练集/验证集/预测集 里面取数(从dataloader里取),都是以一个batch为一组来取
    按batch进行训练的模型,在使用的时候也是按batch进行预测,输出的也是按batch的输出值

  11. 释放CUDA显存
    torch.cuda.empty_cache()

  12. 保存和加载模型

    #直接保存模型和参数
    torch.save(model_object, 'resnet.pth')
    #直接加载模型和参数
    model = torch.load('resnet.pth')
    
    #但要注意! 加载的时候,得先运行网络的定义!(即要先有网络结构,它才会把加载的参数填入网络)
    #加载预训练模型
    https://blog.csdn.net/lscelory/article/details/81482586
  13. 测试的时候爆显存有可能是忘记设置no_grad, 示例代码如下:

    with torch.no_grad():
            for ii,(inputs,filelist) in tqdm(enumerate(test_loader), desc='predict'):
                if opt.use_gpu:
                    inputs = inputs.cuda()
                    if len(inputs.shape) < 4:
                        inputs = inputs.unsqueeze(1)
                else:
                    if len(inputs.shape) < 4:
                        inputs = torch.transpose(inputs, 1, 2)
                        inputs = inputs.unsqueeze(1)

    先设置不使用梯度,然后将测试时候的batchsize设置成训练时候的二分之一或者三分之一就不会爆了。
    可能原因是测试的时候真的需要更大的显存。

  14. 指定使用哪块GPU 0123

    os.environ["CUDA_VISIBLE_DEVICES"] = 3
  15. 保存和加载模型 ,获得模型权重参数

    # 保存和加载整个模型
    torch.save(model, 'model.pkl')
    model = torch.load('model.pkl')
    
    # 仅保存和加载模型参数(推荐使用)
    torch.save(model.state_dict(), 'params.pkl')
    # 注意是先在里面torch.load文件 在加载到model(网络实例)的权重字典里
    model.load_state_dict(torch.load('params.pkl'))

    得到模型权重: model.state_dict

  16. 查看trainset打的标签
    trainset.class_to_idx

  17. nn.Linear层就相当于一个y = w·x + b

  18. 对于带有梯度的tensor(由于variable和tensor合并了, 在cuda且求了grad),要对其操作则要
    tensor.cpu().detach() 再进行运算操作
    detach可以去掉去梯度部分

  19. Pytorch 训练和测试时记得加 model.train 和 model.eval 设置模型模式
    如果用到了BN和dropout,用PyTorch进行训练和测试时一定注意要把实例化的model指定train/eval,eval()时,框架会自动把BN和DropOut固定住,不会取平均,而是用训练好的值,不然的话,一旦test的batch_size过小,很容易就会被BN层导致生成图片颜色失真极大。
    这两个方法是针对在网络train和eval时采用不同方式的情况,比如Batch Normalization和Dropout

    Class Inpaint_Network()
    ......
    Model = Inpaint_Nerwoek()
    #train:
    Model.train(mode=True)
    .....
    #test:
    Model.eval()
  20. glob模块 (非常有用的文件读取操作模块)
    glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,类似于Windows下的文件搜索,支持通配符操作,_,?,[]这三个通配符,_代表0个或多个字符,?代表一个字符,[]匹配指定范围内的字符,如[0-9]匹配数字。两个主要方法如下。
    ①glob方法
    glob模块的主要方法就是glob,该方法返回所有匹配的文件路径列表(list);该方法需要一个参数用来指定匹配的路径字符串(字符串可以为绝对路径也可以为相对路径),其返回的文件名只包括当前目录里的文件名,不包括子文件夹里的文件。
    比如:

    glob.glob(r’c:*.txt’)
    #我这里就是获得C盘下的所有txt文件
    glob.glob(r’E:\pic**.jpg’)
    #获得指定目录下的所有jpg文件
    #使用相对路径:
    glob.glob(r’../*.py’)

    ②iglob方法

     获取一个**迭代器**( iterator )对象,使用它可以逐个获取匹配的文件路径名。与glob.glob()的区别是:glob.glob同时获取所有的匹配路径,而 glob.iglob一次只获取一个匹配路径。
    

    这样就可以不一次性读完所有文件,节约内存
    下面是一个简单的例子:

    f = glob.iglob(r'../*.py') 
    print f 
    >> <generator object iglob at 0x00B9FF80>
    
    for py in f:
        print py
  21. 常用help看用法..torch里的函数用法繁多

  22. 向量运算的一个注意点:要先去掉梯度!
    涉及梯度计算的Tensor(以前是被封装成Variable,但后来合并了),需要用.data来取得其tensor
    eg:loss.data outputs.data
    损失函数返回值,模型输出,都是含有梯度的向量,需要用.data再参与运算!

  23. 注意单元素tensor
    Use tensor.item() to convert a 0-dim tensor to a Python number
    比如每个batch的loss返回值、sum(tensor1==tensor2)等都是单元素tensor
    tensor和普通数字不能随意运算,不然会出错
    要注意,tensor运算得到的结果也是tensor,就算是sum(tensor1==tensor2)得到相等元素数量,得到的也是tensor(x) (x为相等元素数量,一个常数),依然需要sum(temsor1==temsor2).item()才能参与普通数字运算
    否则会出莫名其妙的错误!:比如

    t1 = torch.Tensor([2,3,4,5])
    t2 = torch.Tensor([2,3,7,6])
    sum(t1==t2)
    >> tensor(2,dtype=torch.uint8)
    sum(t1==t2)/10
    >> tensor(0,dtype=torch.uint8)
    torch.sum(t1==t2)
    >> tensor(2)
    torch.sum(t1==t2)/10
    >> tensor(0)
    
    #这样才正确
    sum(t1==t2).item()/10
    >> 0.2
    torch.sum(t1==t2).item()/10
    >> 0.2
    
    #tensor除(/)一个常数是整除! 
  24. 数据集
    最好使用三个数据集:训练集、验证集、测试集
    sklearn.model_selection.train_test_split 函数可用于方便的划分数据集

  25. dropout 和 dropout2d的区别
    torch.nn.Dropout对所有元素中每个元素按照概率0.5更改为零
    而torch.nn.Dropout2d是对每个通道按照概率0.5置为0(即一个通道全为0)

  26. 对于网络

    class model(nn.Module)
    ...
    
    net = model()
    
    model.features
    net
  27. 注意a = a.cuda() 要赋值回去

  28. torch的交叉熵的输入第一个位置的输入应该是在每个label下的概率, 而不是对应的label
    否则会报错dimension out of range (expected to be in range of [-1, 0], but got 1)

  29. 返回对象的属性值
    vars()
    用法vars(object)
    可用于很多封装对象如dataloader等等

  30. 交叉熵损失函数中的weight参数 (权重)

    weight = torch.FloatTensor([0.13859937, 0.5821059, 0.63871904, 2.30220396, 7.1588294, 0]).cuda()
  31. 迁移学习修改网络应该直接修改层,修改线性层的out_features会遇到问题

    #应该直接修改最后一层网络
    vgg.classifier[6] = nn.Linear(4096,2)
  32. 注意初始化网络结构和传入参数到网络里进行计算的区别
    初始化网络实体的时候是传入init()里的参数,相当于初始化网络部件
    传入参数是传入forward()里的传输,这个传入的就需要计算了
    先初始化网络再传入参数进行计算

  33. 输入损失函数的真实标签项,必须为long类型 不能是tensor float!tensor int!

    具体如此生成:

    list = [1,2,3]
    tensor = torch.LongTensor(list)
  34. cuda runtime error: device-side assert triggered at xxx
    这个问题一般来自模型输出的label数量和标签类别种类数量不同。要洗一遍数据集的标签

  35. 自定义层

    可以自己定义层,只需要继承自nn.Module并实现forward()函数

    问题:需要实现backwards函数吗?它会自动求导吗?

    pytorch可以自动求导,但如果实现的层不可导,就需要自己实现梯度的反向传递比如存在if条件,孤立点,拐点,就需要自定义求导式)也就是所谓的 “Extending torch.autograd”. 官网虽然给了例子

    以下举例,自己建立了一个计算Gram Matrix 格拉姆矩阵的层(由于是可导的,所以不需要自己实现)

  36. 继承的时候别忘了super().__init__()


且听风吟