神经网络设计实验

开始写课程作业了,努努力看看能不能一天写完,现在是早上10点45,一会吃饭去下午回来开始写,早上又在开小差什么的,下午一定认真写。

课程实验是用本地连接服务器的方式完成的,用的vscode ssh链接,用一下发现挺简单的,等我这个实验做完了我就去搞一个4090的电脑跑一下大模型玩玩看。😏

要注意的是,链接进ssh后,需要在文件位置选择/opt/目录下的实验

而且,我计划是从实验平台上将文件下载下来在本地编写后再在实验平台上评测,这样100H的机时应该可以用很久。

由于提交分数是取最后一次而不是最高分,所以记得要用git记录下版本,在最后提交最高分的那个版本即可。

下午记得看看那个代码存储在哪,不太明白这个额外创建的卷是怎么用的

全连接手写数字识别

新学会一个技能,vscode要打开一个新窗口而不占用本窗口可以

1
Ctrl+Shift+N

这个实验相当简单 也不一定
我们的任务是构建一个全连接网络,一共有三种层需要我们手动实现,全连接层、ReLU层、Softmax层。每层都要实现forward和backward,

我们先看全连接层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class FullyConnectedLayer(object):
def __init__(self, num_input, num_output): # 全连接层初始化
self.num_input=num_input
self.num_output=num_output
print('\tFully connected layer with input %d, output %d.' % (self.num_input, self.num_output))
def init_param(self, std=0.01): # 参数初始化
self.weight = np.random.normal(loc=0.0, scale=std, size=(self.num_input, self.num_output))
self.bias=np.zeros([1, self.num_output])
show_matrix(self.weight, 'fc weight ')
show_matrix(self.bias, 'fc bias ')
def forward(self, input): # 前向传播计算
start_time = time.time()
self.input = input
# TODO:全连接层的前向传播,计算输出结果
# ==============================================================================================
self.output = np.dot(self.input, self.weight) + self.bias
# ==============================================================================================
return self.output

def backward(self, top_diff): # 反向传播的计算
# TODO:全连接层的反向传播,计算参数梯度和本层损失
# ==============================================================================================
self.d_weight = np.dot(self.input.T, top_diff)
self.d_bias = np.sum(top_diff, axis=0, keepdims=True)
bottom_diff = np.dot(top_diff, self.weight.T)
# ==============================================================================================
return bottom_diff
def get_gradient(self):

return self.d_weight,self.d_bias

def update_param(self, lr): # 参数更新
# TODO:对全连接层参数利用参数进行更新
# ==============================================================================================
self.weight = self.weight - lr * self.d_weight
self.bias = self.bias - lr * self.d_bias
# ==============================================================================================

def load_param(self, weight, bias): # 参数加载
assert self.weight.shape == weight.shape
assert self.bias.shape == bias.shape
self.weight=weight
self.bias=bias
show_matrix(self.weight, 'fc weight ')
show_matrix(self.bias, 'fc bias ')

def save_param(self): # 参数保存
show_matrix(self.weight, 'fc weight ')
show_matrix(self.bias, 'fc bias ')
return self.weight, self.bias

forward和参数更新都相当简单,主要搞清楚矩阵是如何相乘的,
首先就是输入x,维度为1 * input_dim,然后就是权重矩阵input_num * output_num
偏置就是1 * output_num
重点就是backward如何计算

1
self.d_weight = np.dot(self.input.T, top_diff)

为什么权重是这样子的。
从全连接公式说起
每一层的公式是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Y` = W.T * X + b
维度分别是
Y`_(1*out_num)
W_(input_num*output_num)
X_(1*input_num)
b_(1*1)

损失公式去均方误差
L = 0.5(Y - Y`)^2

损失是权重和偏置的函数,要求对权重和偏置的偏导
就要用到链式法则,先求对Y`的导数再求Y`对权重或偏置的导数

此时dL/dY` = -(Y - Y`), 这个也就是top_diff记作ΔLy,形状是(1*output_num)
dY`/dW = X,形状是(1*input_num)
此时dL/dW = ΔLy * X
显然这么写肯定不能乘的
考虑到要对权重进行更新,因此dL/dW = X.T * ΔLy,这也就是为什么代码要这么写的。

为什么会标注矩阵形状就是因为我不知道有的公式为什么矩阵可以这么相乘

其它层也都是同理的分析方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ReLULayer(object):
def __init__(self):
print('\t Relu layer')

def forward(self, input): # 前向传播的计算
start_time = time.time()
self.input=input
# TODO:ReLU层的前向传播,计算输出结果
# ==============================================================================================
output = np.maximum(0, self.input)
# ==============================================================================================
return output
def backward(self, top_diff): # 反向传播的计算
# TODO:ReLU层的反向传播,计算本层损失
# ==============================================================================================
bottom_diff = top_diff * (self.input > 0)
# ==============================================================================================
return bottom_diff

backward为什么这么实现,是因为relu层本身不含有参数,它作为滤网将非零结果前向和反向传播,因此只需要让梯度乘上一个mask让非0梯度传回即可。

这里,self.input > 0会产生一个布尔数组,其中大于0的输入位置是True(对应于1),其余是False(对应于0)。将这个数组与top_diff相乘,就可以实现只有当输入大于0时,误差梯度才会传回

剩下softmax层我不想说了有点累睡午觉了,不过挺简单的。我其实不知道为什么backward为什么这么写 下次再说

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class SoftmaxLossLayer(object):
def __init__(self):
print('\tSoftmax loss layer.')
def forward(self, input): # 前向传播的计算
# TODO:softmax 损失层的前向传播,计算输出结果
input_max = np.max(input, axis=1, keepdims=True)
input_exp = np.exp(input-input_max)
exp_sum = np.sum(input_exp, axis=1, keepdims=True)
# ==============================================================================================
self.prob = input_exp / exp_sum
# ==============================================================================================
return self.prob

def get_loss(self,label): # 计算损失
self.batch_size=self.prob.shape[0]
self.label_onehot=np.zeros_like(self.prob)
self.label_onehot[np.arange(self.batch_size),label]=1.0
loss=-np.sum(np.log(self.prob)*self.label_onehot)/self.batch_size
return loss
def backward(self): # 反向传播的计算
# TODO:softmax 损失层的反向传播,计算本层损失
# ==============================================================================================
bottom_diff = (self.prob - self.label_onehot) / self.batch_size
# ==============================================================================================
return bottom_diff

然后就是读测试数据啊构建模型什么的这也都相当简单。

DLP实验平台

我快笑死了,这个实验只要把模型搭建起来就行了,要满分的条件是DLP运行时间是CPU运行时间的五十分之一,哈哈哈哈我直接让CPU代码里的layer层每层都加了个sleep,直接给我干满分了

这个没什么好讲的复制粘贴改下参数就行。
也不是很想学这个加速以后要用再说
要使用这个pycnnl库首先就是要

1
pip install swig

然后在目录下运行pycnnl文件夹里面

1
./build_pycnnl.sh

好像是这个我名字忘记了好了不写了我要休息了

突然找到了一个学长的实验答案,虽然可能代码有变动但是有一定的参考价值
智能计算系统

找到了一个完全能用的答案应该是答案

MD

无语死了,昨天好好的ssh用着突然用不了,点击连接主机没有反应,就是错误没有提示也没有。

试了重新加载vscode,重新启动,没有用
我就去问了GPT,它给了好多解决方案,我就一个一个去试了试,因为没有任何错误提示我也很无从下手的。

经过几个方案之后错误依然没有任何好转,完全就是正常使用的时候突然无法使用还不告诉你为什么不能使用,我挺无奈。

gpt就告诉我可以打开vscode开发者模式可以看运行过程中有没有错误在控制栏中给出但是并没用用提示框提示用户,然后我就打开了,里面确实出现了一个错误和一个警告

【warning】An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.

【error】Cannot read properties of undefined (reading ‘after’): Error: Cannot read properties of undefined (reading ‘after’)
at l.h (d:\Microsoft VS Code\resources\app\out\vs\workbench\api\node\extensionHostProcess.js:150:185186)

因为错误并没有出现在extensions文件夹里,我就以为可能不是插件的问题,可能是vscode本体因为我可能操作顺序问题导致了不给弹窗,

然后我就到处搜这两个问题,完全没有搜到跟我这个相关。反正时间花费了很久。

我就又去问gpt了,它就告诉我可以清空本地扩展缓存什么的,清除重新加载vscode再下载插件排除问题,因为就ssh一个插件是我要实验的,就这么清除缓存和下载vscode搞了几次还是不行,我就又去搜索相关问题了,翻翻看可能会不会有别的相似的问题能解决这个问题。

反正就是搞了好久,差点就要去定位源码一个一个去分析了,我把插件版本回退之后就又好了,无语死了也不知道这次会不会用着用着就用出问题。

等我把实验都拿满分了就把我的实验过程给补完,这种从0开始搭建网络的还是比较有趣的。

最好是把插件更新一个保存一个文件就自动提交部署这个功能给更新了

TODO

  • 更新插件让它能在保存时自动提交
  • 搞个图床,找一些高清图像资源,把博客背景和文章封面什么的都换了
  • 完成第一篇大模型公平性文献阅读