pytorch 常见函数

概率分布

torch.randn_like() 函数:返回一个与 input 形状相同的服从 N(0,1) 的张量

GPU 相关

查看 torch 的版本

torch.__version__

查看 cuda 是否 available:

torch.cuda.is_available()

查看 GPU 数量

torch.cuda.device_count()

  

数据读入

从文件中读取数据是必要的操作.  

从文件中读取

input = open("D:/hw/chapter1/w4/input.txt", "r")   

遍历数据每一行

import numpy as np 
import torch  
import torch.nn.functional as F  

input = open("D:/hw/chapter1/w4/input.txt", "r")    

# 遍历 input 数据中的每一行
for line in input:    
    # 将 line 中的每一行都以 float 的形式读入.   
    item = [float(i) for i in line.split()]
    b = torch.tensor(item)       
    print(b)  

判断字符串是否能转换成是数字

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

  

 

 

构建矩阵

import torch


# 构建全 0 的 (5, 3) 矩阵
x = torch.empty(5, 3)

# 构建随机数填充的 (5, 3) 矩阵
x = torch.rand(5, 3)

# 定义矩阵类型为 long 
x = torch.zeros(5, 3, dtype=torch.long)

# 直接定义 torch 矩阵  
x = torch.tensor([5.5, 3])


# 覆盖 x, 且全部元素为 0 
x = x.new_zeros(5, 3, dtype=torch.double)      

# 覆盖 x, 且全部元素为 1 
x = x.new_ones(5, 3, dtype = torch.long)       

# 用随机数覆盖 x, 矩阵大小不发生变化.  
x = torch.randn_like(x, dtype=torch.float)    

print(x)  

  

基本操作

这里是一些常见的对于 $\mathrm{tensor}$ 的操作,如果手写的话速度会很慢而且不方便.   

防止类型转换错误

torch.set_default_tensor_type(torch.DoubleTensor) 

赋值

# 将 y 赋值为 x
 
y.copy_(x)  

输出第 i 列 / 行

# 输出 x 的第 i 列/行 
x = torch.rand(5, 3)
print(x[:, 2])    # 输出 x 的第 3 列.  
print(x[2, :])    # 输出 x 的第 3 行.  
 

改变尺寸

# 改变尺寸. 
x = torch.randn(4, 4)
y = x.view(16)     # y 为 x 平展的结果.  
z = x.view(2, -1)  # 将 x 展为 (2, k) 
z = x.view(-1, 8)  # 将 x 展为 (k, 8)  

拼接

dim = 0: 上下拼接 x 和 z  
dim = 1: 左右拼接 x 和 z
x = torch.ones(2, 3)   
z = torch.zeros(2, 3)
y = torch.cat([x, z], dim = 0)   
y = torch.cat([x, z], dim = 1)  
print(y) 

矩阵乘法  

# 矩阵乘法:y1, y2, y3 获取的都是 x 与 x.T 的矩阵乘法.  
x = torch.ones(2, 3)   
y1 = x @ x.T
y2 = x.matmul(x.T) 
y3 = torch.empty(1, 1) 
torch.matmul(x, x.T, out=y3)

矩阵对应元素相乘

# 两个矩阵对应位置元素的乘积.   
z = torch.ones(2, 3)     
z1 = z * z
z2 = z.mul(z)     
z3 = torch.rand_like(z)       
torch.mul(z, z, out=z3)

y = torch.ones(2, 3)    
# 具有广播功能.   
y.mul_(torch.tensor([[2], [233]]))     # 带有 _ 结尾的运算会直接改变矩阵.   

将 tensor 变量转为数值变量

# item(): 将 torch 变量转换为普通数值变量 
h = torch.tensor([[1, 2], [3, 4]])       
agg = h.sum()
agg_item = agg.item()

矩阵每个位置乘/加数字

# 给矩阵的每个位置加一个数 / 乘一个数 
z = torch.ones(2, 3)  
z.mul_(233)
z.add_(-233) 

numpy 和 torch 共享地址

# numpy 和 torch 可以共享存储地址(即同时进行改变)  
t = torch.ones(2, 3)
n = t.numpy()

t.mul_(233)     # 这里 t 和 n 会被同时乘以 233

numpy 转为 tensor

# numpy 转为 tensor  

n = np.ones((1, 5))   
t = torch.from_numpy(n)     # t 就变成一个 tensor 了.   

普通矩阵转为 tensor  

# 将普通数据(矩阵)转为 tensor  
data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)
print(x_data)  

压缩数组与解压数组

dim = 0: 变为 (1, n)  

dim = 1: 变为 (n, 1)  

# 将 (1, n) 或 (n, 1)  压缩成 (n)   
x = torch.ones(1, 3)     
x = torch.squeeze(x)  
print(x.shape)  

y = torch.ones(3, 1)  
y = torch.squeeze(y)  
print(y.shape)  



# dim = 0 -> (1, n)  
# dim = 1 -> (n, 1)  
z = torch.ones(1, 5)   
z = torch.squeeze(z)    
z = torch.unsqueeze(z, dim = 1)  

print(z.shape)  

交换/重排矩阵的维度

# 可以将 3 * (2, 3) 的矩阵转为 (2, 3) * 3 的矩阵.   
x = torch.tensor( [[[2, 2, 2], [2, 2, 2]], [[1, 1, 1], [1, 1, 1]], [[3, 3, 3], [3, 3, 3]]])  

x = x.permute(1, 2, 0) 

for i in range(2) :
    for j in range(3):  
        print(x[i][j][0], x[i][j][1], x[i][j][2])  

 

将 numpy 数据保存到文件中   

np.savez('e.npz', ep = iep, train_loss = itrain_loss, test_acc = itest_acc)     


e = np.load('e.npz')
h = np.load('h.npz')  



ep = e['ep']  
train_loss = e['train_loss']  
test_acc = e['test_acc']  
        

  

保存网络框架

torch.save(net, './net')  
net = torch.load('./net')

  

梯度计算

手写反向传播过程是深度学习中最困难的过程之一,极易出错而且不好写。

pytorch 威力最大之处就是提供自动计算梯度的功能,可以极大方便反向传播的构建。

追踪梯度

# requires_grad = True: 要求追踪 w 的梯度  
# s.backward(): 由最后的变量向后传播.   

x = torch.ones(5)        # input tensor
y = torch.zeros(3)       # expected output
w = torch.randn(5, 3, requires_grad = True)
b = torch.randn(3, requires_grad = True)
z = torch.matmul(x, w) + b
p = z.sum()  
p.backward()  
# print(w.grad)            # 得到 w 中每一个元素相对于 p 的梯度.   

将变量从计算图中移除

# 将 z 从计算图中移除掉.   
# 法一
z = torch.matmul(x, w)+b
print(z.requires_grad)

with torch.no_grad():
    z = torch.matmul(x, w)+b
print(z.requires_grad)         # 发现 z 并不在计算图中了.  


# 法二  
z = torch.matmul(x, w)+b
z_det = z.detach()
print(z_det.requires_grad)     # z 从计算图中脱落了.  

  

深度学习框架

$\mathrm{Pytorch}$ 提供了可以直接调用的深度学习框架,速度和准确率都很高.    

损失函数

CrossEntropyLoss 

交叉熵函数,这里注意训练样本不能用 one - hot 表示,要直接存入结果

 

参数初始化

高斯初始化

这里 $\mathrm{mean}$ 是正态分布均值,$\mathrm{std}$ 是正态分布标准差

torch.nn.init.normal_(self.hidden.weight, mean = 0, std = 1)  

均匀分布

$\mathrm{a,b}$ 分别为均匀分布的下界和上界

torch.nn.init.uniform_(x, a = -100, b = 100) 

Xavier均匀分布初始化  

torch.nn.init.xavier_normal_(tensor, gain=1.0)

Xavier正态分布初始化

torch.nn.init.xavier_normal_(tensor, gain=1.0)

kaiming正态分布初始化

原则上只能配合 $\mathrm{relu}$ 函数使用

torch.nn.init.kaiming_normal_(tensor, a=0, mode='fan_in', nonlinearity='leaky_relu')

 

正则化

为了防止过拟合,可以加入 $\mathrm{L2}$ 正则化:

optimizer = torch.optim.Adam([{"params":net.hidden.weight, 'weight_decay': wd}], lr = 0.01) 

框架默认是不进行正则化的,这里要正则化的矩阵是 $\mathrm{hidden}$ 矩阵,$\mathrm{lambda=wd}$. 

 

 

 

回归问题

基本框架:

$\mathrm{super(Net, self)}$ 意味着继承 $\mathrm{torch.nn.Module}$ 中的属性并在起之上进行修改. 

class Net(torch.nn.Module):   
    def __init__(self, n_feature, n_hidden, n_out):  
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(n_feature, n_hidden)       
        self.predict = torch.nn.Linear(n_hidden, n_out)         

    def forward(self, X):   
        X = F.relu(self.hidden(X))  
        X = self.predict(X)      
        return X       
   

调用函数:

step = 2002 
net = Net(n_feature = 1, n_hidden = 10, n_out = 1)        # 构建神经网络
optimizer = torch.optim.SGD(net.parameters(), lr = 0.2)   # 选择梯度下降算法和学习率
loss_func = torch.nn.MSELoss()                            # 选择损失函数种类 
for st in range(1000):   
    out = net(x)       
    loss = loss_func(out, y)  
    optimizer.zero_grad()                                 # 梯度清空
    loss.backward()                                       # 开始反向传播
    optimizer.step()                                      # 按照梯度更新参数   

  

CNN 

基础知识

设原图为 $(n,n)$, 过滤器为 $(f,f)$, 填充为 $p$, 步长为 $s$

则有新图 $o = \left \lfloor \frac{n+2p-f}{s} \right \rfloor + 1$, 且一般过滤器长度为奇数.    

流程:卷积 -> 激活函数激活 -> 池化 -> 下一轮卷积......    -> 平展为向量并连向全连接神经网络

基本框架

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(  
            # input shape (209, 3, 64, 64)
            nn.Conv2d(    
                in_channels = 3,   
                out_channels = 5,    
                kernel_size = 4,      # filter size  
                stride = 2,           # filter step
                padding = 1,          # 填充大小.    
            ),                        # output shape (209, 5, 32, 32)
            nn.ReLU(),    # activation
            nn.MaxPool2d(kernel_size = 2),    # 在 2x2 空间里向下采样, output shape (5, 16, 16)
        )           
        self.conv2 = nn.Sequential(     # input shape (209, 5, 16, 16)
            nn.Conv2d(5, 32, 5, 1, 0),  # out   shape (209, 32, 12, 12)
            nn.ReLU(),  
            nn.MaxPool2d(2),            # output shape (209, 32, 6, 6)
        )
        self.out = nn.Linear(32 * 6 * 6, 2)   # fully connected layer, output 2 classes

    def forward(self, x):   
        x = self.conv1(x) 
        x = self.conv2(x)
        x = x.view(x.size(0), -1)          # 展平多维的卷积图成 (209, 32 * 6 * 6) 
        output = self.out(x)                
        return output

  

例:吴恩达第 3 次课程作业.  

训练数据正确率达到 $99$% 的时候测试准确率达到了 $84$%,对于二维图片的识别率非常好.  

import torch 
import numpy as np 
import torch.nn.functional as F  
import torch.nn as nn  
import torchvision
from lr_utils import load_dataset 

torch.set_default_tensor_type(torch.DoubleTensor)

def debug(a, b):  
    print("训练次数 " + str(a) + ": " + str(b))   

def trans_torch(a, b, c, d):  
    return torch.from_numpy(a), torch.from_numpy(b), torch.from_numpy(c), torch.from_numpy(d) 

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(  
            # input shape (209, 3, 64, 64)
            nn.Conv2d(    
                in_channels = 3,   
                out_channels = 5,    
                kernel_size = 4,      # filter size  
                stride = 2,           # filter step
                padding = 1,          # 填充大小.    
            ),                        # output shape (209, 5, 32, 32)
            nn.ReLU(),    # activation
            nn.MaxPool2d(kernel_size = 2),    # 在 2x2 空间里向下采样, output shape (5, 16, 16)
        )           
        self.conv2 = nn.Sequential(     # input shape (209, 5, 16, 16)
            nn.Conv2d(5, 32, 5, 1, 0),  # out   shape (209, 32, 12, 12)
            nn.ReLU(),  
            nn.MaxPool2d(2),            # output shape (209, 32, 6, 6)
        )
        self.out = nn.Linear(32 * 6 * 6, 2)   # fully connected layer, output 2 classes

    def forward(self, x):   
        x = self.conv1(x) 
        x = self.conv2(x)
        x = x.view(x.size(0), -1)          # 展平多维的卷积图成 (209, 32 * 6 * 6) 
        output = self.out(x)                
        return output

X, Y, tx, ty , classes = load_dataset()   
X, Y, tx, ty = trans_torch(X, Y, tx, ty)  
X , tx = X.permute(0, 3, 1, 2) / 255, tx.permute(0, 3, 1, 2) / 255  
Y = torch.squeeze(Y)         
ty = torch.squeeze(ty)  

# CNN 卷积神经网络: 达到了非常高的检测效果.   
cnn = CNN()  
optimizer = torch.optim.SGD(cnn.parameters(), lr = 0.03)   
loss_func = nn.CrossEntropyLoss()  
step = 4000   
    
for i in range(step):     
    output = cnn(X)      
    loss = loss_func(output, Y)
    optimizer.zero_grad()   
    loss.backward()  
    optimizer.step()   
    if i % 100 == 0:  
        cc = 0    
        for j in range(209):  
            cur = 0  
            if output[j][1] > output[j][0]:  
                cur = 1  
            if cur == Y[j]:   
                cc += 1    
        debug(i + 1, cc / 209 * 100)      
        cc = 0  
        outt = cnn(tx)  
        for j in range(50):      
            cur = 0  
            if outt[j][1] > outt[j][0]:  
                cur = 1  
            if cur == ty[j]:  
                cc += 1  
        print("测试数据 " + str(i + 1) + ": " + str(cc * 2))           

 

 

posted @ 2022-03-11 14:35  guangheli  阅读(88)  评论(0)    收藏  举报