我最初使用CSDN估计是在2014年左右,当时还在读研,除了在当时比较有名的BBS例如小木虫上进行学术交流外,我发现很多问题百度后,都会转到CSDN,而且文章内容颇为专业,很多问题也都有专业的回答,于是我知道了CSDN(从事多年)网。
2016年毕业后从事汽车研发工作,之后对CSDN的访问频率不降反升,因为工作中遇到的很多实际技术问题,在CSDN上仍能找到很有意义的指导,直到2020年由于CSDN对我来说已经从一个“一次性”的搜索引擎,逐渐变为了需要持续关注的充电站,我注册了CSDN账号。
在2021年左右(或许更早),汽车行业中自动驾驶领域一下出圈走红。神经元网络、机器学习对我来说并不是陌生的概念,早在2010年左右读本科的时候就听说过了,我对此领域也很好奇(用计算机写神经元?这也太酷辣!),但是受限于当时资料太少(以及受到当时硬件性能的限制,深度学习领域也没什么实质性的发展),我仅能了解到一些初级概念,例如BP网络。真是没想到深度学习、人工智能以如此快的速度进入到我的专业领域。以及后来的AIGC,已经改变了我的工作模式!
出于对知识的好奇、对技术的追求(实际上是为了保持职业上的竞争力)我决定潜心研究自动驾驶技术,就从底层的深度学习算法开始。由于我本硕都是机械专业,想进入到深度学习领域还是有许多技术门槛需要征服,于是进行了大量的学习。而我在选择如何记录学习过程时,想到了CSDN的博客功能,机缘巧合在两年前发了第一篇博客(学习笔记)。
最初CSDN博客对我来说仅是一个学习笔记,记录我的学习理解和学习感悟。后来我发现:嘿!CSDN上爱学习的人可真多,我这学习笔记都有人看,这极大地鼓舞了我的学习信心,也坚定了我持续创作的决心。
随着学习的深入,我开始从借鉴别人的代码,逐渐可以自己进行coding。而bug!是真的多次使我血压飙升!我感觉debug就像在大海中游泳,我不知道离岸边还要游多远,最糟糕的是我甚至根本不知道游的方向对不对。而从CSDN上获得的大量灵感,帮助我解决了很多很多bug,这是孤军奋战不可能达到的效果。
教是最好的学。我在解决这些bug,把我的学习过程写成博客帮助别人学习后,我又发现了一些理解不到位,或者有更好方法的地方,这又促进了我的技术能力提升。
我觉得现在已经迈过了门槛期,学习和写博客已经成为了日常生活的一部分,基于PyTorch一些常见的bug已经基本淌过一遍,现在来到了比较稳定的创作期,后续不会像以前创作东一榔头西一棒槌,对于学习路线的规划现在已逐渐清晰。
虽然我希望能尽早完成百篇博客的目标,但我更注重发文的质而不是量,我的要求是每篇文章不讲废话、不讲套话;技术问题直击灵魂,直奔主题;基于实操,不纸上谈兵;要有自己的理解,文章有亮点,不人云亦云,知其然也要知其所以然!
我觉得写的最好的代码是基于NumPy构建LSTM网络模型的代码:
- import numpy as np
- from tqdm import tqdm
- import matplotlib.pyplot as plt
-
- train_x = np.linspace(0.01,1,600).reshape(100,6,1)
- train_y = train_x * train_x + np.random.randn(100,6,1)/200
-
-
- def sigmoid(x):
- return 1/(1+np.exp(-x))
-
-
- class HiddenLayer():
- def __init__(self,input_size, hidden_size):
- self.w_f = np.random.randn(hidden_size, input_size) #定义各个门的权重, 忘记门
- self.w_i = np.random.randn(hidden_size, input_size) #输入门
- self.w_g = np.random.randn(hidden_size, input_size) #新记忆门
- self.w_o = np.random.randn(hidden_size, input_size) #输出门
-
- self.v_f = np.random.randn(hidden_size,hidden_size)
- self.v_i = np.random.randn(hidden_size,hidden_size)
- self.v_g = np.random.randn(hidden_size,hidden_size)
- self.v_o = np.random.randn(hidden_size,hidden_size)
-
- self.b_f = np.zeros([hidden_size, 1]) #输入限定为一维向量
- self.b_i = np.zeros([hidden_size, 1])
- self.b_g = np.zeros([hidden_size, 1])
- self.b_o = np.zeros([hidden_size, 1])
-
- def forward(self, x, h_pre, c_pre): #h_pre为h_t-1, c_pre为c_t-1
-
- self.Fgate = sigmoid(np.dot(self.w_f, x) + np.dot(self.v_f, h_pre) + self.b_f)
- self.Igate = sigmoid(np.dot(self.w_i, x) + np.dot(self.v_i, h_pre) + self.b_i)
- self.Ggate = np.tanh(np.dot(self.w_g, x) + np.dot(self.v_g, h_pre) + self.b_g)
- self.Ogate = sigmoid(np.dot(self.w_o, x) + np.dot(self.v_o, h_pre) + self.b_o)
-
- c_cur = self.Fgate * c_pre + self.Igate * self.Ggate #c_cur为c_t
- h_cur = self.Ogate * np.tanh(c_cur)
-
- return h_cur, c_cur
-
- def backward(self, Fgate, Igate, Ggate, Ogate, x, grad_cnext, Fgate_next, grad_hcur, c_cur,c_pre, h_pre):
-
-
- self.grad_ccur = grad_cnext * Fgate_next + grad_hcur * Ogate * (1 - np.tanh(c_cur) * np.tanh(c_cur))
- self.grad_hpre = self.grad_ccur*(np.dot(self.v_f.T, c_pre*Fgate*(1-Fgate)) + np.dot(self.v_g.T,Igate*(1-Ggate*Ggate)) + np.dot(self.v_i.T,Ggate*Igate*(1-Igate)))
-
- self.grad_wf = np.dot(self.grad_ccur * c_pre * Fgate * (1 - Fgate), x.T) #这里要注意矩阵的转置!!!
- self.grad_wi = np.dot(self.grad_ccur * Ggate * Igate * (1 - Igate), x.T)
- self.grad_wg = np.dot(self.grad_ccur * Igate * (1 - Ggate * Ggate), x.T)
- self.grad_wo = np.dot(grad_hcur*np.tanh(c_cur)*Ogate*(1-Ogate),x.T)
-
-
- self.grad_vf = np.dot(self.grad_ccur * c_pre * Fgate * (1 - Fgate), h_pre.T)
- self.grad_vi = np.dot(self.grad_ccur * Ggate * Igate * (1 - Igate), h_pre.T)
- self.grad_vg = np.dot(self.grad_ccur * Igate * (1 - Ggate * Ggate), h_pre.T)
- self.grad_vo = np.dot(grad_hcur * np.tanh(c_cur) * Ogate * (1 - Ogate), h_pre.T)
-
- self.grad_bf = self.grad_ccur * c_pre * Fgate * (1 - Fgate)
- self.grad_bi = self.grad_ccur * Ggate * Igate * (1 - Igate)
- self.grad_bg = self.grad_ccur * Igate * (1 - Ggate * Ggate)
- self.grad_bo = grad_hcur * np.tanh(c_cur) * Ogate * (1 - Ogate)
-
- def step(self, lr=0.01):
- self.w_f = self.w_f - lr * self.grad_wf
- self.w_i = self.w_i - lr * self.grad_wi
- self.w_g = self.w_g - lr * self.grad_wg
- self.w_o = self.w_o - lr * self.grad_wo
-
- self.v_f = self.v_f - lr*self.grad_vf
- self.v_i = self.v_i - lr * self.grad_vi
- self.v_g = self.v_g - lr * self.grad_vg
- self.v_o = self.v_o - lr * self.grad_vo
-
- self.b_f = self.b_f - lr*self.grad_bf
- self.b_i = self.b_i - lr * self.grad_bi
- self.b_g = self.b_g - lr * self.grad_bg
- self.b_o = self.b_o - lr * self.grad_bo
-
-
- class OutputLayer():
- def __init__(self, hidden_size, output_size):
-
- self.w_h = np.ones([output_size, hidden_size])
- self.b_h = np.zeros([output_size, 1])
-
- def forward(self, h_cur):
- return np.dot(self.w_h, h_cur) + self.b_h
-
- def backward(self,y,h_cur, train_data):
- delta = y - train_data
- self.grad_wh = np.dot(delta, h_cur.T)
- self.grad_hcur = np.dot(self.w_h.T, delta)
- self.grad_bh = delta
-
- def step(self, lr=0.001):
- self.w_h = self.w_h - lr * self.grad_wh
- self.b_h = self.b_h - lr * self.grad_bh
- ————————————————
- 版权声明:本文为CSDN博主「使者大牙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
- 原文链接:https://blog.csdn.net/m0_49963403/article/details/130428280
这段代码从Python语法上来说十分简单,没有任何高级的技巧,可能仅学习Python不到一周的新手都能看得懂。但是其让我引以为傲的地方是对LSTM网络反向传播的数学推导,这即使在CSDN上应该也算得上是首创。
这也提醒着我:不是为了会coding而学习coding,是为了要实现算法而学习coding。代码的灵魂在于其背后的算法!
目标就是百篇博客吧,成为优质作者,博客专家(多么现实的目标)