# 动手用CUDA实现CNN

## 设计

### 全连接层

```全连接

Y = X * W

dL/dX = dL/dY * W^T
dL/dW = X^T * dL/dY

Y = X + b

dL/db = sum(dL/dY, 0) 逐样本梯度求和

### 卷积层

```卷积

col = im2col(im) 根据im2col展开输入图
Y = F * col

dL/dF = dL/dY * col^T
dL/d_col = F^T * dL/dY
dL/d_im = col2im(dL/d_col)

Y = X + b 逐通道相加

dL/db = sum(sum(X, 2), 1) 对整个通道进行规约

### Maxpool

Maxpool的反向传播需要记录池化前元素的位置，然后把反向梯度直接传回

### 激活函数

```ReLU

Y = relu(X)

dL/dX = relu'(X) element_mul dL/dY 逐元素相乘

Sigmoid

Y = sigmoid(X)

dL/dX = sigmoid'(X) element_mul dL/dY 逐元素相乘

### Softmax

```Logsoftmax

Y = log_softmax(X) = x - log(exp(X) * 1_n) * 1_n^T

dL/dX = dL/dY - (dL/dY * 1_n * exp(x)) / (exp(x) * 1_n)

### NLLLoss

NLLLoss是平均负的对数似然损失，为了配合LogSoftmax使用而实现。设Y为样本标签矩阵，每一行为一个样本。N为样本数量

```前向传播
L = mean(sum(-log_P element_mul Y, 1), 0)

dL/d(log_P) = -Y / N

NLLLoss+LogSoftmax为我们常见的Softmax损失

## 实现

### 源码结构

```src
cuda        CUDA源码
minist      MNIST DEMO
test
cuda        CUDA源码单元测试
CMakeLists.txt  CMake编译脚本

## 测试

```网络结构
conv 1 32 5 relu
maxpool 2
conv 32 64 5 relu
maxpool 2
conv 64 128 3 relu
fc 4 * 128 128 relu
fc 128 10 relu
softmax
nllloss

shuffle = true
batch_size = 128
learning_rate = 0.003
L2 = 0.0001
beta = 0.99

1 epoch 93%
10 epochs 99.12%
30 epochs 99.23%
10s / epoch(GTX1070)