# PyDyNet
**Repository Path**: WeltXing/PyDyNet
## Basic Information
- **Project Name**: PyDyNet
- **Description**: NumPy实现类PyTorch的动态计算图和神经网络(DNN, CNN, RNN)
- **Primary Language**: Python
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-08-07
- **Last Updated**: 2022-08-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Neural-network, PyTorch, numpy, CNN, RNN
## README
# PyDyNet:Neuron Network(DNN, CNN, RNN, etc) implementation using Numpy based on Autodiff
前作:[PyNet: Use NumPy to build neuron network](https://github.com/Kaslanarian/PyNet)。在那里我们基于求导规则实现了全连接网络。在这里,我们向当今的深度学习框架看齐,实现属于自己的DL框架。
**PyDyNet已被多个技术公众号和社区分享**:[居然用Numpy实现了一个深度学习框架](https://segmentfault.com/a/1190000042108301).
[](https://pepy.tech/project/pydynet)     
## Update
- 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](/pydynet/data.py)中的`train_loader`函数;
- 5.30: ver 0.0.3 将一维卷积算法退化成基于循环的im2col,新版本NumPy似乎不是很支持strided上数组的魔改;
- 7.22: ver 0.0.4 增加了Module类和Parameter类,将模块重组、增加多种Pytorch支持的初始化方式;正在撰写新的Manual;
- 7.28: ver 0.0.5 加入no_grad方法,可以像pytorch一样禁止自动微分,比如`@no_grad()`和`with no_grad()`,详见[autograd.py](/pydynet/autograd.py);
- ...
## Overview
PyDyNet也是纯NumPy实现的神经网络,语法受PyTorch的启发,大致结构如下:
```mermaid
graph BT
N ----> Dataset ----> Data(DataLoader)
N(numpy.ndarray) --> A(Tensor)
A --Eager execution--> B(Basic operators: add, exp, etc)
B --> E(Mechanism: Dropout, BN, etc)
E --> D
B --> C(Complex operators: softmax, etc)
C --> E
B --> D(Base Module:Linear, Conv2d, etc)
C --> D
B --Autograd--> A
N ----> GD(Optimizer:SGD, Adam, etc)
D --> M(Module:DNN, CNN, RNN, etc)
M --> Mission(PyDyNet)
Data --> Mission
GD --> Mission
```
文件结构
```bash
pydynet
├── __init__.py
├── autograd.py # 微分控制模块
├── data.py # 数据集模块
├── nn # 神经网络模块
│ ├── __init__.py
│ ├── functional.py # 函数类
│ ├── init.py # 初始化模块
│ ├── modules
│ │ ├── __init__.py
│ │ ├── activation.py # 激活函数
│ │ ├── batchnorm.py # BN
│ │ ├── conv.py # 卷积和池化
│ │ ├── dropout.py # dropout
│ │ ├── linear.py # 线性层
│ │ ├── loss.py # 损失函数类
│ │ ├── module.py # Module基类,包括Sequential
│ │ └── rnn.py # RNN
│ └── parameter.py # 参数化类
├── optim.py # 优化器类
└── tensor.py # 张量类
```
我们实现了:
1. 将NumPy数组包装成具有梯度等信息的张量(Tensor):
```python
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),并对部分运算加以重载:
```python
from pydynet import Tensor
import pydynet.functional as F
x = Tensor([1, 2, 3])
y = F.exp(x) + x
z = F.sum(x)
print(z.data) # 36.192...
```
3. 手动编写基础算子的梯度,实现和PyTorch相同的动态图自动微分机制(Autograd),从而实现反向传播
```python
from pydynet import Tensor
import pydynet.functional as F
x = Tensor([1, 2, 3], requires_grad=True)
y = F.log(x) + x
z = F.sum(y)
z.backward()
print(x.grad) # [2., 1.5, 1.33333333]
```
4. 基于基础算子实现更高级的算子(Complex operators),它们不再需要手动编写导数:
```python
def simple_sigmoid(x: Tensor):
return 1 / (1 + exp(-x))
```
5. 实现了Mudule,包括激活函数,损失函数等,从而我们可以像下面这样定义神经网络,损失函数项:
```python
import pydynet.nn as nn
import pydynet.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. 实现了多种优化器(`optimizer.py`),以及数据分批的接口(`dataloader.py`),从而实现神经网络的训练;其中优化器和PyTorch一样支持权值衰减,即正则化;
7. Dropout机制,Batch Normalization机制,以及将网络划分成训练阶段和评估阶段;
8. 基于im2col高效实现Conv1d, Conv2d, max_pool1d和max_pool2d,从而实现CNN;
9. 支持多层的**双向**RNN,LSTM和GRU;
10. 实现了PyTorch中的Dataset类、DataLoader类,从而将批数据集封装成迭代器;
11. 多种初始化方式,包括Kaiming和Xavier。
## Install
```bash
pip install pydynet
```
或本地安装
```bash
git clone https://github.com/Kaslanarian/PyDyNet
cd PyDyNet
python setup.py install
```
安装成功后就可以运行下面的例子
## Example
[tests](./tests)中是一些例子。
### AutoDiff
[autodiff.py](tests/autodiff.py)利用自动微分,对一个凸函数进行梯度下降:

### DNN
[DNN.py](tests/DNN.py)使用全连接网络对`sklearn`提供的数字数据集进行分类,训练参数
- 网络结构:Linear(64->64) + Sigmoid + Linear(64->10);
- 损失函数:Cross Entropy Loss;
- 优化器:Adam(lr=0.01);
- 训练轮次:50;
- 批大小(Batch size):32.
训练损失,训练准确率和测试准确率:
### CNN
[CNN.py](tests/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.
学习效果对比:
## Droput & BN
[dropout_BN.py](tests/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.
学习效果对比:
## RNN
[RNN.py](tests/RNN.py)中是一个用双向单层GRU对`sklearn`的数字图片数据集进行分类:
