Skip to content

NumPy实现类PyTorch的动态计算图和神经网络(DNN, CNN, RNN)

License

Notifications You must be signed in to change notification settings

Kaslanarian/PyDyNet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PyDyNet:Neuron Network(DNN, CNN, RNN, etc) implementation using Numpy based on Autodiff

前作:PyNet: Use NumPy to build neuron network。在那里我们基于求导规则实现了全连接网络。在这里,我们向当今的深度学习框架看齐,实现属于自己的DL框架。

PyDyNet已被多个技术公众号和社区分享居然用Numpy实现了一个深度学习框架.

Downloads Downloads

更新日志

  • 5.10: ver 0.0.1 修改损失函数的定义方式:加入reduction机制,加入Embedding;
  • 5.15: ver 0.0.2 重构了RNN, LSTM和GRU,支持双向;
  • 5.16: ver 0.0.2 允许PyDyNet作为第三方库安装;开始手册的撰写(基于Sphinx).
  • 5.29: ver 0.0.3 加入了Dataset和Dataloader,现在可以像PyTorch一样定义数据集和分割数据集,具体参考data.py中的train_loader函数;
  • 5.30: ver 0.0.3 将一维卷积算法退化成基于循环的im2col,新版本NumPy似乎不是很支持strided上数组的魔改;
  • 7.22: ver 0.0.4/0.05 增加了Module类和Parameter类,将模块重组、增加多种Pytorch支持的初始化方式;正在撰写新的Manual;
  • 7.28: ver 0.0.6 加入no_grad方法,可以像pytorch一样禁止自动微分,比如@no_grad()with no_grad(),详见autograd.py;
  • 8.09: ver 0.0.7 基于cupy,PyDyNet现在可以使用显卡加速训练,用法与PyTorch一致,详见testscu*.py
  • 8.18: ver 0.0.8 加入学习率调整策略,实现了训练过程中自动调节学习率;
  • 10.21: ver 0.0.9 加入tensor的split方法,基于此改进了RNN;
  • 10.23: ver 0.0.10 重写RNN, LSTM和GRU,支持多层双向;
  • ...

Overview

PyDyNet也是纯NumPy(0.0.7版本后加入CuPy,其用法和NumPy一致)实现的神经网络,语法受PyTorch的启发,大致结构如下:

graph BT
   N(numpy.ndarray/cupy.ndarray) ----> ds(Dataset) ----> Data(DataLoader)--> Mission
   N --> A(Tensor) --Eager execution--> B(Basic operators: add, exp, etc)
   B -.Autograd-.-> A
   B --> CO(Complex operators:softmax,etc)
   --> f(Function:linear, conv2d, etc) 
   --> M(Basic Module:Linear,Conv2d,etc)
   --> CM(Advanced Module:CNN,RNN,etc)
   --> Mission(PyDyNet)
   N --> GD(Optimizer:SGD, Adam, etc) ----> LS(lr_scheduler:StepLR, etc)--> Mission

虚线表示用户可以通过no_grad来关闭自动微分功能。更全面的架构图(Thanks to duma-repo):

img

我们实现了:

  1. 将NumPy数组包装成具有梯度等信息的张量(Tensor):

    Example

    from pydynet import Tensor
    
    x = Tensor(1., requires_grad=True)
    print(x.data) # 1.
    print(x.ndim, x.shape, x.is_leaf) # 0, (), True

  2. 将NumPy数组的计算(包括数学运算、切片、形状变换等)抽象成基础算子(Basic operators),并对部分运算加以重载:

    Example

    import pydynet as pdn
    from pydynet import Tensor
    
    x = Tensor([1, 2, 3])
    y = pdn.exp(x) + x
    z = pdn.sum(x)
    print(z.data) # 36.192...

  3. 手动编写基础算子的梯度,实现和PyTorch相同的动态图自动微分机制(Autograd),从而实现反向传播

    Example

    import pydynet as pdn
    from pydynet import Tensor
    
    x = Tensor([1., 2., 3.], requires_grad=True)
    y = pdn.log(x) + x
    z = pdn.sum(y)
    
    z.backward()
    print(x.grad) # [2., 1.5, 1.33333333]

  4. 基于基础算子实现更高级的算子(Complex operators),它们不再需要手动编写导数:

    Example

    import pydynet as pdn
    
    def simple_sigmoid(x: pdn.Tensor):
        return 1 / (1 + pdn.exp(-x))

  5. 实现了Mudule,包括激活函数,损失函数等,从而我们可以像下面这样定义神经网络,损失函数项:

    Example

    import pydynet.nn as nn
    import pydynet.nn.functional as F
    
    n_input = 64
    n_hidden = 128
    n_output = 10
    
    class Net(nn.Module):
        def __init__(self) -> None:
            super().__init__()
            self.fc1 = nn.Linear(n_input, n_hidden)
            self.fc2 = nn.Linear(n_hidden, n_output)
    
        def forward(self, x):
            x = self.fc1(x)
            x = F.sigmoid(x)
            return self.fc2(x)
    
    net = Net()
    loss = nn.CrossEntropyLoss()
    l = loss(net(X), y)
    l.backward()

  6. 实现了多种优化器和学习率衰减策略,从而实现神经网络的训练;其中优化器和PyTorch一样支持权值衰减,即正则化:

    Example

    from pydynet.optim import Adam, StepLR
    
    ...
    net = Net()
    optimizer = Adam(net.parameters(), lr=0.01)
    lr_scheduler = StepLR(optimizer, step_size=10)
    
    for epoch in range(EPOCHES):
        for data in data_loader:
            train(...)
            optimizer.step()
        lr_scheduler.step()

  7. 实现了Dataset和DataLoader对数据集进行加载与划分:

    Example

    from pydynet.data import Dataset, DataLoader
    
    class TrainSet(Dataset):
        def __init__(self, X, y) -> None:
            self.data = X
            self.target = y
    
        def __getitem__(self, index):
            return self.data[index], self.target[index]
    
        def __len__(self):
            return len(self.data)
    
     data_loader = DataLoader(TrainSet(X, y), batch_size, shuffle)

  8. Dropout机制,Batch Normalization机制,以及将网络划分成训练阶段和评估阶段;

  9. 基于im2col高效实现Conv1d, Conv2d, max_pool1d和max_pool2d,从而实现CNN;

  10. 支持多层的多层双向RNN,LSTM和GRU;

  11. 多种初始化方式,包括Kaiming和Xavier;

  12. 基于cupy实现了显卡计算和训练:

    Example

    from pydynet import Tensor
       
    x = Tensor([1., 2., 3.], device='cuda')
    y = Tensor([1., 2., 3.], device='cuda')
    z = (x * y).sum()
    
    w = Tensor([1., 2., 3.]) # CPU上的Tensor
    x * w # 报错

Install

pip install pydynet

或本地安装

git clone https://github.com/Kaslanarian/PyDyNet
cd PyDyNet
python setup.py install

安装成功后就可以运行下面的例子

Example

tests中是一些例子。

AutoDiff

autodiff.py利用自动微分,对一个凸函数进行梯度下降:

ad

DNN

DNN.py使用全连接网络对sklearn提供的数字数据集进行分类,训练参数

  • 网络结构:Linear(64->64) + Sigmoid + Linear(64->10);
  • 损失函数:Cross Entropy Loss;
  • 优化器:Adam(lr=0.01);
  • 训练轮次:50;
  • 批大小(Batch size):32.

训练损失,训练准确率和测试准确率:

dnn

CNN

CNN.py使用三种网络对fetch_olivetti_faces人脸(64×64)数据集进行分类并进行性能对比:

  1. Linear + Sigmoid + Linear;
  2. Conv1d + MaxPool1d + Linear + ReLU + Linear;
  3. Conv2d + MaxPool2d + Linear + ReLU + Linear.

其余参数相同:

  • 损失函数:Cross Entropy Loss;
  • 优化器:Adam(lr=0.01);
  • 训练轮次:50;
  • 批大小(Batch size):32.

学习效果对比:

cnn

Droput & BN

dropout_BN.py使用三种网络对fetch_olivetti_faces人脸(64×64)数据集进行分类并进行性能对比:

  1. Linear + Sigmoid + Linear;
  2. Linear + Dropout(0.05) + Sigmoid + Linear;
  3. Linear + BN + Sigmoid + Linear.

其余参数相同:

  • 损失函数:Cross Entropy Loss;
  • 优化器:Adam(lr=0.01);
  • 训练轮次:50;
  • 批大小(Batch size):32.

学习效果对比:

BN

RNN

RNN.py中是一个用双向单层GRU对sklearn的数字图片数据集进行分类:

RNN

cuda相关

cuDNN.py, cuCNN.py, cuDropoutBN.py, cuRNN.py分别是上面四种网络的cuda版本,并对网络进行了相应的修改,主要是介绍如何使用PyDyNet的显卡功能,且已经在无显卡和有显卡的环境下都通过了测试。

Net Dataset Parameters CPU time GPU time
FC Digits (1970×64) batch_size=128, epoch=50 30.8s±392ms 22.4s±298ms
CNN1d OlivettiFaces (400×4096) batch_size=64, epoch=50 8.76s±68.7ms 4.49s±16.3ms
CNN2d OlivettiFaces (400×4096) batch_size=64, epoch=50 14.1s±285ms 4.54s±49ms

事实上,对于越庞大的网络(更宽,更深,卷积),GPU加速效果更好。

Releases

No releases published

Packages

No packages published

Languages