您的位置:首页 > 理论基础 > 计算机网络

[ 深度学习初识- 实操笔记 ] 全连接神经网络-手写数字识别项目

2020-05-09 04:16 3351 查看

深度学习初识

  • 2. 全连接神经网络
  • 1. 神经网络

    (1)感知机

    一个神经元。
    感知机接收多个输入信号,输出一个信号,与广义线性回归类似 ,即有Y = WX+B 。
    广义线性回归中有核函数,在感知机中称为激活函数(提供非线性能力),在感知机中,激活函数常用 sigmoid函数。
    广义线性回归和感知机算法的训练都是由梯度下降法,加上正则化降低损失的。

    (2)多层神经网络 MLP

    多个感知机,分布在多层神经网络上,即神经网络按一层一层构建,构成深度神经网络。深度神经网络的学习过程被称为深度学习。
    模型可简单表示为:f…f(X,θ):即上一层的输出作为下一层的输入,第一层的结果称为一阶特征,第二层的结果称为二阶特征……层次越深,得到的特征就越抽象,网络就越聪明,但是层次越深,深度网络就存在梯度弥散和梯度暴涨的问题,即当层次越深,后面得到的梯度太大或太小,使得超出界限或特征消失。

    第一层模型简单表示:f(WX) - W 为n行m列矩阵,代表这一层上有n个感知机,每个感知机有m个输入; X 为m行k列,即m个输入,k个输出。因此这一层有k个输出结果; f为激活函数。

    第二层模型简单表示:f(f(WX)X) - f(WX)作为第二层的权重W,即第一层的输出,n行k列……

    (3)激活函数

    功能:激活每一个神经元,提供非线性能力。
    Sigmoid/tanh 函数,这两个函数有饱和值,即在做深层神经网络的时候容易梯度弥散。
    ReLU/Leaky ReLU,具有抗弥散能力,提供非线性能力的部分在拐点处(即原点),ReLU负轴为0,容易让神经元死掉,LeakyReLU为ReLU改进版。

    (4)输出函数

    神经网络的最后一层,输出范围具有限制,因此输出层的激活函数不同。
    在多分类输出函数常用:softMax(x),损失loss为one-hot即每一个类别上的概率;当输出层要输出一个概率时候,常用sigmoid(x);当输出层不做改变时候,常用linear(x)……

    2. 全连接神经网络

    项目实例:手写数字识别项目

    每一层的输出都与下一层的每个感知机相连。
    Python+Pytorch代码实现:主要有三部分实现,数据部分data,网络模型构建net,网络训练train。

    (1)数据部分data:

    pytorch提供的数据处理库:

    from torch.utils.data import Dataset

    创建一个数据类继承Dataset:
    def init(self,root,is_train = True):
    主要用于初始化数据,载入/保存数据。可保存所有数据或者数据路径,这里保存数据路径,root 即为数据路径根地址。is_train 用来判断读取的为训练集还是测试集。
    def len(self):
    主要用来返回数据长度。
    def getitem(self,index):
    用来索引到每条数据,并处理每条数据。
    数据展平:这里是因为每个像素作为一个输入。
    数据归一化,标签/类别转换为one-hot编码。

    class MNISTDataset(Dataset):
    
    def __init__(self, root, is_train=True):
    self.dataset = []  # 记录所有数据
    sub_dir = "TRAIN" if is_train else "TEST"
    for tag in os.listdir(f"{root}/{sub_dir}"):
    img_dir = f"{root}/{sub_dir}/{tag}"
    for img_filename in os.listdir(img_dir):
    img_path = f"{img_dir}/{img_filename}"
    self.dataset.append((img_path, tag))
    
    # 数据集有多少数据
    def __len__(self):
    return len(self.dataset)
    
    # 每条数据的处理方式
    def __getitem__(self, index):
    data = self.dataset[index]
    
    img_data = cv2.imread(data[0], cv2.IMREAD_GRAYSCALE)
    img_data = img_data.reshape(-1) #数据展平
    img_data = img_data / 255 #归一化
    
    #one_hot
    tag_one_hot = np.zeros(10)
    tag_one_hot[int(data[1])] = 1
    
    return np.float32(img_data), np.float32(tag_one_hot)

    (2)网络模型部分 net

    pytorch提供的网络模型库:

    from torch import nn

    创建一个网络模型类继承nn.Module。
    def init (self): 用来初始化网络组件
    nn.Sequential(…)里面可放网络每层的运算。

    下面的例子:输入层为784个像素点,第一层采用用ReLU为激活函数的线性模型,784个输入,100个输出。第二层即输出层,one-hot编码输出采用SoftMax为激活函数,上一层100个输入,10个输出(手写数字10个分类:1-10用one-hot编码输出10个概率结果,哪一位的概率最大,即为那一个分类)

    def forward(self,x): x为输入矩阵NV (N张图片,每张图片V-784个像素)。输入的结果在sequential(x)组合组件中运算得到返回输出。

    import torch
    from torch import nn
    class NetV(nn.Module):
    
    def __init__(self):
    super().__init__()
    
    self.sequential = nn.Sequential(
    nn.Linear(784, 100),
    nn.ReLU(),
    nn.Linear(100, 10),
    nn.Softmax()
    )
    
    def forward(self, x):
    return self.sequential(x)
    
    

    (3)训练部分train:

    加载前面建好的数据库和网络库。
    DataLoader库的功能是为训练数据/测试数据,分包训练。
    optim库为优化模型。
    tensorboard库提供将每轮训练的数据图表化显示的工具。(便于观察数据的变化,如损失,权重…)

    import torch
    from day01.data import *
    from day01.net import *
    from torch.utils.data import DataLoader
    from torch import optim
    from torch.utils.tensorboard import SummaryWriter

    def init(self,root):
    加载训练数据,加载测试数据,创建模型,创建优化器。

    self.test_dataloader = DataLoader(self.test_dataset, batch_size=100, shuffle=True)
    用DataLoader分包训练,每包100个数据。

    (还可以加载上次训练的权重:

    self.net.load_state_dict(torch.load("./checkpoint/2.t"))

    def call(self):
    以下面为例,最大轮次尽量设置毕竟大,可手动停止训练。

    self.net.train()#模型初始化
    y = self.net(imgs)#输入图片 作为模型训练 得到输出结果y
    loss = torch.mean((tags - y) ** 2) # 输出结果和正确结果做平方差取平均-损失
    
    #优化器固定三步
    self.opt.zero_grad()#梯度归零
    loss.backward()
    self.opt.step()
    import torch
    from day01.data import *
    from day01.net import *
    from torch.utils.data import DataLoader
    from torch import optim
    from torch.utils.tensorboard import SummaryWriter
    DEVICE = "cuda:0"
    
    class Train:
    
    def __init__(self, root):
    
    self.summaryWriter = SummaryWriter("./logs")
    
    # 加载训练数据
    self.train_dataset = MNISTDataset(root, True)
    self.train_dataloader = DataLoader(self.train_dataset, batch_size=100, shuffle=True)
    
    # 加载测试数据
    self.test_dataset = MNISTDataset(root, False)
    self.test_dataloader = DataLoader(self.test_dataset, batch_size=100, shuffle=True)
    
    # 创建模型
    self.net = NetV()
    # self.net.load_state_dict(torch.load("./checkpoint/2.t"))
    self.net.to(DEVICE)
    # 创建优化器
    self.opt = optim.Adam(self.net.parameters())
    
    # 训练代码
    def __call__(self):
    for epoch in range(100000):
    sum_loss = 0.
    for i, (imgs, tags) in enumerate(self.train_dataloader):
    imgs, tags = imgs.to(DEVICE), tags.to(DEVICE)
    
    self.net.train()
    
    y = self.net(imgs)
    loss = torch.mean((tags - y) ** 2)
    
    self.opt.zero_grad()
    loss.backward()
    self.opt.step()
    
    sum_loss += loss.cpu().detach().item()
    
    avg_loss = sum_loss / len(self.train_dataloader)
    
    sum_score = 0.
    test_sum_loss = 0.
    for i, (imgs, tags) in enumerate(self.test_dataloader):
    imgs, tags = imgs.to(DEVICE), tags.to(DEVICE)
    
    self.net.eval()
    
    test_y = self.net(imgs)
    test_loss = torch.mean((tags - test_y) ** 2)
    test_sum_loss += test_loss.cpu().detach().item()
    
    predict_tags = torch.argmax(test_y, dim=1)
    label_tags = torch.argmax(tags, dim=1)
    sum_score += torch.sum(torch.eq(predict_tags, label_tags).float()).cpu().detach().item()
    
    test_avg_loss = test_sum_loss / len(self.test_dataloader)
    score = sum_score / len(self.test_dataset)
    
    self.summaryWriter.add_scalars("loss", {"train_loss": avg_loss, "test_loss": test_avg_loss}, epoch)
    self.summaryWriter.add_scalar("score", score, epoch)
    
    print(epoch, avg_loss, test_avg_loss, score)
    
    torch.save(self.net.state_dict(), f"./checkpoint/{epoch}.t")
    
    if __name__ == '__main__':
    train = Train("../data/MNIST_IMG")
    train()
    

    每轮训练后可保存权重

    torch.save(self.net.state_dict(), f"./checkpoint/{epoch}.t")
    ,便于下次运行或封装成pt包。
    先设置gpu
    DEVICE = "cuda:0"
    将数据和网络放入设置好的gpu,
    to(DEVICE)
    进行运算

    xianyu_blog 原创文章 4获赞 0访问量 118 关注 私信
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐