Andrew Ng还解释说,当你阅读论文时(即使是最有影响力的论文),你可能也会发现有些部分没什么用,或者没什么意义。因此,如果你读了一篇论文,其中一些内容没有意义(这并不罕见),那么你可以先略读。除非你想要掌握它,那就花更多的时间。确实,当我在阅读ILSVRC、COCO等顶级比赛许多获奖模型的论文时,其中都有对比赛情况的详细结果介绍,我觉得这些部分一定程度上是可以扫读和跳读的。
感悟
目前我阅读过大多数论文的组成一般为Abstract、Introduction、Related Work、Method、Experiment、Conclusion。 可能阅历丰富的研究者能够从Abstract中提炼出比较关键的信息,但我个人认为,一篇文章最关键的是Introduction部分,该部分一般会包括前因后果和文章有哪几个contribution的总结,涵盖了本文解决的问题和一些主要概念和思路。 Related Work主要是对之前论文的分析,相当于是Introduction部分中前因的具体分析,相当于精简版的综述,如果对该领域比较了解的话完全可以跳读,但如果不熟悉该领域的话还是能从中学到很多重要的信息的。 Method部分是对Introduction部分中contribution的具体化,从这里开始会涉及到较多理论的内容,细品还是略读要靠自己拿捏。 Experiment是比较容易忽略的部分,不过有时候会提及一些trick,如果有ablation experiments的话可以重点关注一下。注意,在一些预印论文网站上的占坑论文有可能实验部分不是很完全,这是我们用于判断该篇论文结论是否可靠的依据。 Conclusion其实是Introduction的缩写,如果有未来研究方向的展望的话可以看一下。
Andrew Ng还解释说,当你阅读论文时(即使是最有影响力的论文),你可能也会发现有些部分没什么用,或者没什么意义。因此,如果你读了一篇论文,其中一些内容没有意义(这并不罕见),那么你可以先略读。除非你想要掌握它,那就花更多的时间。确实,当我在阅读ILSVRC、COCO等顶级比赛许多获奖模型的论文时,其中都有对比赛情况的详细结果介绍,我觉得这些部分一定程度上是可以扫读和跳读的。
感悟
目前我阅读过大多数论文的组成一般为Abstract、Introduction、Related Work、Method、Experiment、Conclusion。 可能阅历丰富的研究者能够从Abstract中提炼出比较关键的信息,但我个人认为,一篇文章最关键的是Introduction部分,该部分一般会包括前因后果和文章有哪几个contribution的总结,涵盖了本文解决的问题和一些主要概念和思路。 Related Work主要是对之前论文的分析,相当于是Introduction部分中前因的具体分析,相当于精简版的综述,如果对该领域比较了解的话完全可以跳读,但如果不熟悉该领域的话还是能从中学到很多重要的信息的。 Method部分是对Introduction部分中contribution的具体化,从这里开始会涉及到较多理论的内容,细品还是略读要靠自己拿捏。 Experiment是比较容易忽略的部分,不过有时候会提及一些trick,如果有ablation experiments的话可以重点关注一下。注意,在一些预印论文网站上的占坑论文有可能实验部分不是很完全,这是我们用于判断该篇论文结论是否可靠的依据。 Conclusion其实是Introduction的缩写,如果有未来研究方向的展望的话可以看一下。
Condensation(Conditional density propagation)条件密度传播使用了原始的外观作为主要特征来描述目标,采用了粒子滤波,这是一种非参数化滤波方法,属于生成式模型。它定义了一个粒子样本集,该样本集描述了每个粒子的坐标、运动速度、高和宽、尺度变化等状态;此外,通过一个状态转移矩阵和噪声定义系统状态方程。基于蒙特卡洛方法,粒子滤波将贝叶斯滤波方法中的积分运算转化为粒子采样求样本均值问题,通过对状态空间的粒子的随机采样来近似求解后验概率。
2002
Mean Shift
Mean Shift采用均值漂移作为搜索策略,这是一种无参概率估计方法,该方法利用图像特征直方图构造空间平滑的概率密度函数,通过沿着概率密度函数的梯度方向迭代,搜索函数局部最大值。在当时成为了常用的视觉跟踪系统的目标搜索方法,简单易实现,但鲁棒性较低。
MOSSE(Minimum Output Sum of Squared Error)使用相关滤波来做目标跟踪(不是第一个,但可以看作前期的一个代表),其速度能够达到600多帧每秒,但是效果一般,这主要是因为它只使用了简单的raw pixel特征。 相比之前的算法,MOSSE能够形成更加明确的峰值,减少了漂移;此外,MOSSE可以在线更新,同时还采用了PSR来检测遮挡或者跟丢的情况,从而决定是否需要停止更新。 值得一提的是,MOSSE在做相关操作之前,对每张图都进行了减去平均值的处理,这有利于淡化背景对相关操作的影响。另外假如发生光照变化的话,减去均值也有利于减小这种变化的影响。此外要注意,输出的特征应乘以汉宁窗(一种余弦窗),用于确定搜索区域(也就是不为0的区域),且有利于突出中心的特征。
Condensation(Conditional density propagation)条件密度传播使用了原始的外观作为主要特征来描述目标,采用了粒子滤波,这是一种非参数化滤波方法,属于生成式模型。它定义了一个粒子样本集,该样本集描述了每个粒子的坐标、运动速度、高和宽、尺度变化等状态;此外,通过一个状态转移矩阵和噪声定义系统状态方程。基于蒙特卡洛方法,粒子滤波将贝叶斯滤波方法中的积分运算转化为粒子采样求样本均值问题,通过对状态空间的粒子的随机采样来近似求解后验概率。
2002
Mean Shift
Mean Shift采用均值漂移作为搜索策略,这是一种无参概率估计方法,该方法利用图像特征直方图构造空间平滑的概率密度函数,通过沿着概率密度函数的梯度方向迭代,搜索函数局部最大值。在当时成为了常用的视觉跟踪系统的目标搜索方法,简单易实现,但鲁棒性较低。
MOSSE(Minimum Output Sum of Squared Error)使用相关滤波来做目标跟踪(不是第一个,但可以看作前期的一个代表),其速度能够达到600多帧每秒,但是效果一般,这主要是因为它只使用了简单的raw pixel特征。 相比之前的算法,MOSSE能够形成更加明确的峰值,减少了漂移;此外,MOSSE可以在线更新,同时还采用了PSR来检测遮挡或者跟丢的情况,从而决定是否需要停止更新。 值得一提的是,MOSSE在做相关操作之前,对每张图都进行了减去平均值的处理,这有利于淡化背景对相关操作的影响。另外假如发生光照变化的话,减去均值也有利于减小这种变化的影响。此外要注意,输出的特征应乘以汉宁窗(一种余弦窗),用于确定搜索区域(也就是不为0的区域),且有利于突出中心的特征。
Initializing workspace ... Verifying native components ... Testing TraX protocol support for tracker NCC. Tracker execution interrupted: Unable to establish connection. TraX support not detected. 错误使用 tracker_load (line 127) Tracker has not passed the TraX support test.
如果完成上面之后,执行还有问题,可能是路径没有设置对。打开vot-toolkit/workspace/tracker_XXX.m(XXX是你创建工作区时设置的跟踪算法的名称)。找到最后一行:% tracker_linkpath = {}; % A cell array of custom library directories used by the tracker executable (optional)。 去掉前面的注释符,添加路径tracker_linkpath = {'absolute_path/trax/build'};(记得修改这里的absolute_path)。 据TraX的作者所说,TraX出错一般不是vot toolkit本身的问题,如果你使用的是其他的算法,请确保该算法的.m或者.py文件和vot.m或者vot.py文件处在同一个目录下。如果没有,可到vot-toolkit/tracker/examples中的matlab或者python目录下复制。
TraX
折腾了半天,总得知道这个TraX是个什么东西,根据TraX文档中所说:TraX stands for visual Tracking eXchange, the protocol was designed to make development and testing of visual tracking algorithms simpler and faster. 其实我当初折腾的时候想法是:我不要simpler and faster,我现在只想跑通哈哈哈哈哈。
Initializing workspace ... Verifying native components ... Testing TraX protocol support for tracker NCC. Tracker execution interrupted: Unable to establish connection. TraX support not detected. 错误使用 tracker_load (line 127) Tracker has not passed the TraX support test.
如果完成上面之后,执行还有问题,可能是路径没有设置对。打开vot-toolkit/workspace/tracker_XXX.m(XXX是你创建工作区时设置的跟踪算法的名称)。找到最后一行:% tracker_linkpath = {}; % A cell array of custom library directories used by the tracker executable (optional)。 去掉前面的注释符,添加路径tracker_linkpath = {'absolute_path/trax/build'};(记得修改这里的absolute_path)。 据TraX的作者所说,TraX出错一般不是vot toolkit本身的问题,如果你使用的是其他的算法,请确保该算法的.m或者.py文件和vot.m或者vot.py文件处在同一个目录下。如果没有,可到vot-toolkit/tracker/examples中的matlab或者python目录下复制。
TraX
折腾了半天,总得知道这个TraX是个什么东西,根据TraX文档中所说:TraX stands for visual Tracking eXchange, the protocol was designed to make development and testing of visual tracking algorithms simpler and faster. 其实我当初折腾的时候想法是:我不要simpler and faster,我现在只想跑通哈哈哈哈哈。
Srivastava等人(2014)提出Dropout,以防止神经网络过拟合。Dropout是一种神经网络模型平均正则化方法,通过增加噪声到其隐藏单元。在训练过程中,它会从神经网络中随机抽取出单元和连接。Dropout可以用于像RBM(Srivastava et al.,2014)这样的图形模型中,也可以用于任何类型的神经网络。最近提出的一个关于Dropout的改进是Fraternal Dropout,用于循环神经网络(RNN)。
Srivastava等人(2014)提出Dropout,以防止神经网络过拟合。Dropout是一种神经网络模型平均正则化方法,通过增加噪声到其隐藏单元。在训练过程中,它会从神经网络中随机抽取出单元和连接。Dropout可以用于像RBM(Srivastava et al.,2014)这样的图形模型中,也可以用于任何类型的神经网络。最近提出的一个关于Dropout的改进是Fraternal Dropout,用于循环神经网络(RNN)。
#初始化字典矩阵 def_initialize(self, y): u, s, v = np.linalg.svd(y) self.dictionary = u[:, :self.n_components]
#使用KSVD更新字典的过程 def_update_dict(self, y, d, x): for i in range(self.n_components): #选择X中第i行(从0开始)中非零项 index = np.nonzero(x[i, :])[0] #如果没有非零项,则直接进入下一次for循环 if len(index) == 0: continue #更新D中第i列 d[:, i] = 0 #计算误差矩阵 r = (y - np.dot(d, x))[:, index] #利用SVD的方法,来求解更新字典和稀疏系数矩阵 u, s, v = np.linalg.svd(r, full_matrices = False) #使用左奇异矩阵的第0列更新字典 d[:, i] = u[:, 0].T #使用第0个奇异值和右奇异矩阵的第0行的乘积更新稀疏系数矩阵 x[i, index] = s[0] * v[0, :] return d, x
#KSVD迭代过程 deffit(self, y): self._initialize(y) for i in range(self.max_iter): #在最大迭代范围内 #稀疏编码 x = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs) #计算容差 e = np.linalg.norm(y - np.dot(self.dictionary, x)) #满足容差就结束 if e < self.tol: break #更新字典 self._update_dict(y, self.dictionary, x)
#稀疏编码 self.sparsecode = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs)
#初始化字典矩阵 def_initialize(self, y): u, s, v = np.linalg.svd(y) self.dictionary = u[:, :self.n_components]
#使用KSVD更新字典的过程 def_update_dict(self, y, d, x): for i in range(self.n_components): #选择X中第i行(从0开始)中非零项 index = np.nonzero(x[i, :])[0] #如果没有非零项,则直接进入下一次for循环 if len(index) == 0: continue #更新D中第i列 d[:, i] = 0 #计算误差矩阵 r = (y - np.dot(d, x))[:, index] #利用SVD的方法,来求解更新字典和稀疏系数矩阵 u, s, v = np.linalg.svd(r, full_matrices = False) #使用左奇异矩阵的第0列更新字典 d[:, i] = u[:, 0].T #使用第0个奇异值和右奇异矩阵的第0行的乘积更新稀疏系数矩阵 x[i, index] = s[0] * v[0, :] return d, x
#KSVD迭代过程 deffit(self, y): self._initialize(y) for i in range(self.max_iter): #在最大迭代范围内 #稀疏编码 x = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs) #计算容差 e = np.linalg.norm(y - np.dot(self.dictionary, x)) #满足容差就结束 if e < self.tol: break #更新字典 self._update_dict(y, self.dictionary, x)
#稀疏编码 self.sparsecode = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs)
# Home page setting # path: Root path for your blogs index page. (default = '') # per_page: Posts displayed per page. (0 = disable pagination) # order_by: Posts order. (Order by date descending by default) index_generator: path:'' per_page:10 order_by:-date
<divid="new"></div> <scriptsrc="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script> <script>AV.initialize("YOUR_APPID", "YOUR_APPKEY");</script> <scripttype="text/javascript"> var updatedAt="" var title="" var url="" var query = new AV.Query('Counter'); query.notEqualTo('id',0); query.descending('updatedAt'); query.limit(10); query.find().then(function (todo) { for (var i=0;i<10;i++){ var result=todo[i].attributes; title=result.title; updatedAt=result.updatedAt; url=result.url; var content="<p>"+"<a href='"+"YOUR_URL"+url+"' target='_blank'>"+title+"</a>"+"</p>"; document.getElementById("new").innerHTML+=content } }, function (error) { console.log("error"); }); </script>
# Home page setting # path: Root path for your blogs index page. (default = '') # per_page: Posts displayed per page. (0 = disable pagination) # order_by: Posts order. (Order by date descending by default) index_generator: path:'' per_page:10 order_by:-date
<divid="new"></div> <scriptsrc="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script> <script>AV.initialize("YOUR_APPID", "YOUR_APPKEY");</script> <scripttype="text/javascript"> var updatedAt="" var title="" var url="" var query = new AV.Query('Counter'); query.notEqualTo('id',0); query.descending('updatedAt'); query.limit(10); query.find().then(function (todo) { for (var i=0;i<10;i++){ var result=todo[i].attributes; title=result.title; updatedAt=result.updatedAt; url=result.url; var content="<p>"+"<a href='"+"YOUR_URL"+url+"' target='_blank'>"+title+"</a>"+"</p>"; document.getElementById("new").innerHTML+=content } }, function (error) { console.log("error"); }); </script>
善于承认不足是一种良好的品质,作者在文中也来了这样一个转折:“However, it often diverges on longer sequences or the sequences that have very small frame-to-frame variations.”意思是说这种方法在长序列或者目标在帧与帧之间变化不大时表现不佳(会偏离目标)。 回顾一下,当初设计这种方法的目的是模型在接收第一帧之后能够很快地收敛到精度和鲁棒性很好的一组参数位置,这就是说,我们训练得到的$\alpha $相对来说是比较大的,这就导致了它在上述情况下的不稳定。 为此,作者的解决办法是“find a learning rate for subsequent frames and then use existing optimization algorithms to update the models as was done in the original versions of the trackers”,也就是仅用学习到的$\theta _{0}$和$\alpha $来做初始化,然后在随后的在线更新过程中,仍用原来版本的方式进行更新。这里原来的版本指的是CREST和MDNet,作者在这两个tracker的基础上改进出了MetaCREST和MetaSDNet,下面接着讲。
自己接触元学习的相关算法之后,总想着直接套用到别的任务上去。这篇论文和我的想法有点类似,但作者在实际实现时肯定用了更多的方法来解决各种各样的难题。而这篇文章也只能说是用元学习的思想做了一些探索,引用作者的一部分总结: “Other than target appearance modeling, which is the focus of this paper, there are many other important factors in object tracking algorithms. For example, when or how often to update the model, how to manage the database, and how to define the search space. These considerations are sometimes more important than target appearance modeling. In future work we propose including handling of these as part of learning and meta-learning.” 总而言之,还有很长的路要走~
善于承认不足是一种良好的品质,作者在文中也来了这样一个转折:“However, it often diverges on longer sequences or the sequences that have very small frame-to-frame variations.”意思是说这种方法在长序列或者目标在帧与帧之间变化不大时表现不佳(会偏离目标)。 回顾一下,当初设计这种方法的目的是模型在接收第一帧之后能够很快地收敛到精度和鲁棒性很好的一组参数位置,这就是说,我们训练得到的$\alpha $相对来说是比较大的,这就导致了它在上述情况下的不稳定。 为此,作者的解决办法是“find a learning rate for subsequent frames and then use existing optimization algorithms to update the models as was done in the original versions of the trackers”,也就是仅用学习到的$\theta _{0}$和$\alpha $来做初始化,然后在随后的在线更新过程中,仍用原来版本的方式进行更新。这里原来的版本指的是CREST和MDNet,作者在这两个tracker的基础上改进出了MetaCREST和MetaSDNet,下面接着讲。
自己接触元学习的相关算法之后,总想着直接套用到别的任务上去。这篇论文和我的想法有点类似,但作者在实际实现时肯定用了更多的方法来解决各种各样的难题。而这篇文章也只能说是用元学习的思想做了一些探索,引用作者的一部分总结: “Other than target appearance modeling, which is the focus of this paper, there are many other important factors in object tracking algorithms. For example, when or how often to update the model, how to manage the database, and how to define the search space. These considerations are sometimes more important than target appearance modeling. In future work we propose including handling of these as part of learning and meta-learning.” 总而言之,还有很长的路要走~
既然Meta Learning的目的是实现快速学习,而快速学习的关键就是神经网络的梯度下降要准且快,那么是否可以让神经网络利用以往的任务学习如何预测梯度,这样面对新的任务,只要梯度预测得准,那么学习得就会更快。 在Learning to Learn by Gradient Descent by Gradient Descent一文中(好好品味这个题目),作者提出了这样一种方法,即训练一个通用的神经网络来预测梯度,用一次二次方程的回归问题来训练,这种方法得到的神经网络优化算法比Adam、RMSProp还要好。
学习记忆的学习
元学习其实也可以利用以往的经验来学习,于是这又诞生了一系列模型。
记忆增强神经网络
一般的神经网络不具有记忆功能,输出的结果只基于当前的输入。而LSTM网络的出现则让网络有了记忆,它能够根据之前的输入给出当前的输出。但是,LSTM的记忆程度并不是那么理想,对于比较长的输入序列,LSTM的最终输出只与最后的几步输入有关,也就是long dependency问题,当然这个问题可以由注意力机制解决,然而还是不能从根本上解决长期记忆的问题,原因是由于LSTM是假设在时间序列上的输入输出:由t-1时刻得到t时刻的输出,然后再循环输入t时刻的结果得到t+1时刻的输出,这样势必会使处于前面序列的输入被淹没,导致这部分记忆被“丢掉”。 基于以上问题,研究者们提出了神经图灵机等记忆增强神经网络模型。我们知道,人除了用脑子记,还会使用做笔记等方式做辅助,当我们忘记时,我们可以去看笔记来获得相关的记忆。记忆增强神经网络的思想就是如此,它让所有的笔记的“读”“写”操作都可微分化,因此可以用神经网络误差后向传播的方式去训练模型。 在记忆增强神经网络中,我们引入外部存储器来存储样本表示和类标签信息。以Meta-Learning with Memory-augmented Neural Networks这篇文章为例,我们看一下它的网络结构。
那么,我们之前让机器learn,现在想办法让机器learn to learn,那之后是不是还要learn to learn to learn再learn to learn to learn to learn呢?哈哈套娃警告。 难以想象未来的机器会是怎么样的,如此智能真的有点细思极恐呢。话说回来,Meta Learning方兴未艾,各种神奇的idea层出不穷,但是真正的杀手级算法尚未出现,让我们拭目以待!
]]>
+
元学习(Meta Learning)即让机器学习如何去学习(learn to learn)。我前几天看到这个概念,觉得非常有意思,这几天也一直在看相关的概念和implement,发现其实很多方法或者思想已经在最新的一些工作中得到有意或者无意运用。因此我决定对我目前的了解做一个总结,或许能给之后的思考带来启发。 强烈推荐台湾教授李宏毅关于Meta Learning的课程录像,油管上有资源,总共4个part,讲得真的非常清楚! 此外,斯坦福在2019年秋季也推出了多任务学习和元学习的CS330,感兴趣可以看一看,语速稍快,可以锻炼一下英语。 由于目前对这个领域的了解还不够深入,分类可能不是很恰当,以后待理解加深之后再做调整,如有错误还请见谅。
既然Meta Learning的目的是实现快速学习,而快速学习的关键就是神经网络的梯度下降要准且快,那么是否可以让神经网络利用以往的任务学习如何预测梯度,这样面对新的任务,只要梯度预测得准,那么学习得就会更快。 在Learning to Learn by Gradient Descent by Gradient Descent一文中(好好品味这个题目),作者提出了这样一种方法,即训练一个通用的神经网络来预测梯度,用一次二次方程的回归问题来训练,这种方法得到的神经网络优化算法比Adam、RMSProp还要好。
学习记忆的学习
元学习其实也可以利用以往的经验来学习,于是这又诞生了一系列模型。
记忆增强神经网络
一般的神经网络不具有记忆功能,输出的结果只基于当前的输入。而LSTM网络的出现则让网络有了记忆,它能够根据之前的输入给出当前的输出。但是,LSTM的记忆程度并不是那么理想,对于比较长的输入序列,LSTM的最终输出只与最后的几步输入有关,也就是long dependency问题,当然这个问题可以由注意力机制解决,然而还是不能从根本上解决长期记忆的问题,原因是由于LSTM是假设在时间序列上的输入输出:由t-1时刻得到t时刻的输出,然后再循环输入t时刻的结果得到t+1时刻的输出,这样势必会使处于前面序列的输入被淹没,导致这部分记忆被“丢掉”。 基于以上问题,研究者们提出了神经图灵机等记忆增强神经网络模型。我们知道,人除了用脑子记,还会使用做笔记等方式做辅助,当我们忘记时,我们可以去看笔记来获得相关的记忆。记忆增强神经网络的思想就是如此,它让所有的笔记的“读”“写”操作都可微分化,因此可以用神经网络误差后向传播的方式去训练模型。 在记忆增强神经网络中,我们引入外部存储器来存储样本表示和类标签信息。以Meta-Learning with Memory-augmented Neural Networks这篇文章为例,我们看一下它的网络结构。
那么,我们之前让机器learn,现在想办法让机器learn to learn,那之后是不是还要learn to learn to learn再learn to learn to learn to learn呢?哈哈套娃警告。 难以想象未来的机器会是怎么样的,如此智能真的有点细思极恐呢。话说回来,Meta Learning方兴未艾,各种神奇的idea层出不穷,但是真正的杀手级算法尚未出现,让我们拭目以待!
]]>
- <!-- build time:Sat May 02 2020 23:29:05 GMT+0800 (GMT+08:00) --><p>元学习(Meta Learning)即让机器学习如何去学习(learn to learn)。我前几天看到这个概念,觉得非常有意思,这几天也一直在
+ <!-- build time:Sun May 03 2020 09:40:01 GMT+0800 (GMT+08:00) --><p>元学习(Meta Learning)即让机器学习如何去学习(learn to learn)。我前几天看到这个概念,觉得非常有意思,这几天也一直在
@@ -493,13 +493,13 @@
2020-02-02T05:32:16.000Z2020-02-07T04:27:33.180Z
-
因此我们需要学习的是$d_{x}\left ( A \right )$,$d_{y}\left ( A \right )$,$d_{w}\left ( A \right )$,$d_{h}\left ( A \right )$这四个变换。当输入的A与GT相差较小时,可以认为这种变换是一种线性变换,那么就可以用线性回归来进行微调。
因此我们需要学习的是$d_{x}\left ( A \right )$,$d_{y}\left ( A \right )$,$d_{w}\left ( A \right )$,$d_{h}\left ( A \right )$这四个变换。当输入的A与GT相差较小时,可以认为这种变换是一种线性变换,那么就可以用线性回归来进行微调。
这里摘录上面参考资料中的一段话,我觉得说得很明白了。 Using a network trained on one dataset on a different problem is possible because neural networks exhibit “transfer learning”. The first few layers of the network learn to detect general features such as edges and color blobs that are good discriminating features across many different problems. The features learnt by the later layers are higher level, more problem specific features. These layers can either be removed or the weights for these layers can be fine-tuned during back-propagation.
这里摘录上面参考资料中的一段话,我觉得说得很明白了。 Using a network trained on one dataset on a different problem is possible because neural networks exhibit “transfer learning”. The first few layers of the network learn to detect general features such as edges and color blobs that are good discriminating features across many different problems. The features learnt by the later layers are higher level, more problem specific features. These layers can either be removed or the weights for these layers can be fine-tuned during back-propagation.
snap是ubuntu母公司Canonical于2016年4月发布ubuntu16.04时候引入的一种安全的、易于管理的、沙盒化的软件包格式,与传统的dpkg和apt有着很大的区别。在ubuntu软件中心下载安装的似乎都是snap管理的。这让一些商业闭源软件也能在linux上发布,说白了是ubuntu为了获得linux发行版霸权的一个重要举措,因此没少招黑。知乎上看到这么一句话,笑半天:“Fuck the political correct, make linux great again.(says 川·乌班图·普)”。
snap是ubuntu母公司Canonical于2016年4月发布ubuntu16.04时候引入的一种安全的、易于管理的、沙盒化的软件包格式,与传统的dpkg和apt有着很大的区别。在ubuntu软件中心下载安装的似乎都是snap管理的。这让一些商业闭源软件也能在linux上发布,说白了是ubuntu为了获得linux发行版霸权的一个重要举措,因此没少招黑。知乎上看到这么一句话,笑半天:“Fuck the political correct, make linux great again.(says 川·乌班图·普)”。
]]>
- <!-- build time:Sat May 02 2020 23:29:05 GMT+0800 (GMT+08:00) --><p>在我安装ubuntu18.04LTS的时候,由于下载语言包是真的久,我就翻了一下ubuntu安装界面的介绍,其中一开始就是对snap store
+ <!-- build time:Sun May 03 2020 09:40:01 GMT+0800 (GMT+08:00) --><p>在我安装ubuntu18.04LTS的时候,由于下载语言包是真的久,我就翻了一下ubuntu安装界面的介绍,其中一开始就是对snap store
@@ -829,13 +829,13 @@
2020-01-26T00:34:48.000Z2020-01-26T02:12:38.151Z
-
似乎是为了支持由武汉深之度科技开发的国产linux系统Deepin,近年来许多常用软件都提供了linux客户端,比如QQ for linux,baidunetdisk for linux。然而我安装百度网盘后发现打不开,一打开就报错,后来才知道百度网盘仅支持ubuntu18之后的版本。于是就又涉及到deb包的卸载问题了。
似乎是为了支持由武汉深之度科技开发的国产linux系统Deepin,近年来许多常用软件都提供了linux客户端,比如QQ for linux,baidunetdisk for linux。然而我安装百度网盘后发现打不开,一打开就报错,后来才知道百度网盘仅支持ubuntu18之后的版本。于是就又涉及到deb包的卸载问题了。
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE #optional, but recommended
这条命令应该就是添加新的密匙并信任,一般在配置apt-get源之前运行。 对apt-key的描述如下:“apt-key is used to manage the list of keys used by apt to authenticate packages. Packages which have been authenticated using these keys will be considered trusted.”由于每个发布的Debian软件包都是通过密钥认证的,而apt-key命令正是用来管理Debian软件包密钥的。
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE #optional, but recommended
这条命令应该就是添加新的密匙并信任,一般在配置apt-get源之前运行。 对apt-key的描述如下:“apt-key is used to manage the list of keys used by apt to authenticate packages. Packages which have been authenticated using these keys will be considered trusted.”由于每个发布的Debian软件包都是通过密钥认证的,而apt-key命令正是用来管理Debian软件包密钥的。
以前觉得深度学习就是有很多层的神经网络,或者周志华提出的深度随机森林,总之只要是有很“深”的结构就是深度学习。直到不久前一位计科大佬告诉我深度学习是end-to-end(也表示成“e2e”)的,当时听的也是一知半解,回去查了一下后终于恍然大悟。本文主要基于Andrew Ng的课程中“What is end-to-end deep learning?”和“Whether to use end-to-end learning?”两节。推荐可以去看一看,讲得可以说是很浅显易懂了。
什么是end-to-end learning
传统机器学习的流程往往由多个独立的模块组成,比如在一个典型的自然语言处理(Natural Language Processing)问题中,包括分词、词性标注、句法分析、语义分析等多个独立步骤,每个步骤是一个独立的任务,其结果的好坏会影响到下一步骤,从而影响整个训练的结果,这就是非端到端的。 而深度学习模型在训练过程中,从输入端(输入数据)到输出端得到一个预测结果,该结果与真实结果相比较会得到一个误差,这个误差将用于模型每一层的调整(比如反向传播),这种训练直到模型收敛或达到预期的效果才结束,这就是端到端(end-to-end)的。
Andrew Ng在视频课程中举了一个例子:百度的门禁系统可以识别靠近的人脸并放行。 如果直接使用端到端学习,那么需要训练的数据集就是一系列照片或者视频,其中人会随机出现在任何位置、任何距离等等,而这样标注好的数据集是很匮乏的。 但是,如果我们把这个任务拆解成两个子任务。首先,在照片或者视频中定位人脸,然后放大(使人脸居中等);其次,对放大好的人脸再进行检验。这两种任务都有非常丰富的数据集或者方法可供使用。实际上,我觉得可以应用两个端到端的模型来解决这两个问题,但合起来就不是端到端的了。但在目前现有数据量的情况下,这依然能比直接端到端的方法表现得好。
实际上,实现可视化的方法有多种,可以利用反卷积,也可以对一系列图像求响应值,上面的两个例子就是用了不同的方法(前者是针对一张图,而Andrew Ng用了一个数据集)。在Visualizing and Understanding Convolutional Networks一文中,作者也提出了一些更复杂的方式来可视化卷积神经网络的计算。我在computer-vision笔记:上采样和下采样中,也对反卷积进行了介绍。 在NLP领域,也有类似的发现,比如一些训练过后的神经元对特定标点的响应特别强烈,而有一些训练过后的神经元对一些特定语气词的响应特别强烈。
]]>
+
以前觉得深度学习就是有很多层的神经网络,或者周志华提出的深度随机森林,总之只要是有很“深”的结构就是深度学习。直到不久前一位计科大佬告诉我深度学习是end-to-end(也表示成“e2e”)的,当时听的也是一知半解,回去查了一下后终于恍然大悟。本文主要基于Andrew Ng的课程中“What is end-to-end deep learning?”和“Whether to use end-to-end learning?”两节。推荐可以去看一看,讲得可以说是很浅显易懂了。
什么是end-to-end learning
传统机器学习的流程往往由多个独立的模块组成,比如在一个典型的自然语言处理(Natural Language Processing)问题中,包括分词、词性标注、句法分析、语义分析等多个独立步骤,每个步骤是一个独立的任务,其结果的好坏会影响到下一步骤,从而影响整个训练的结果,这就是非端到端的。 而深度学习模型在训练过程中,从输入端(输入数据)到输出端得到一个预测结果,该结果与真实结果相比较会得到一个误差,这个误差将用于模型每一层的调整(比如反向传播),这种训练直到模型收敛或达到预期的效果才结束,这就是端到端(end-to-end)的。
Andrew Ng在视频课程中举了一个例子:百度的门禁系统可以识别靠近的人脸并放行。 如果直接使用端到端学习,那么需要训练的数据集就是一系列照片或者视频,其中人会随机出现在任何位置、任何距离等等,而这样标注好的数据集是很匮乏的。 但是,如果我们把这个任务拆解成两个子任务。首先,在照片或者视频中定位人脸,然后放大(使人脸居中等);其次,对放大好的人脸再进行检验。这两种任务都有非常丰富的数据集或者方法可供使用。实际上,我觉得可以应用两个端到端的模型来解决这两个问题,但合起来就不是端到端的了。但在目前现有数据量的情况下,这依然能比直接端到端的方法表现得好。
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters [2]Visual Object Tracking using Adaptive Correlation Filters [3]Exploiting the Circulant Structure of Tracking-by-detection with Kernels
在论文High-Speed Tracking with Kernelized Correlation Filters的introduction部分,有这样一句话:“we argue that undersampling negatives is the main factor inhibiting performance in tracking.”也就是说,负样本的欠采样是阻碍跟踪效果的主要因素。这在之前的文章中介绍过,这里就不在细述了。 这句话主要针对的问题是我们可以从一张图像中获得几乎无限的负样本。但由于跟踪的时间敏感性,我们的跟踪算法只能在尽可能多地采集样本和维持较低的计算需求之间取得一个平衡。之前通常的做法是从每一帧中随机选择几个样本。 KCF的一大贡献就是采用了一种更方便的方法迅速获取更多的负样本,以便于能够训练出一个更好的分类器。作者发现,在傅里叶域中,如果我们使用特定的模型进行转换,一些学习算法实际上变得更容易(in the Fourier domain, some learning algorithms actually become easier as we add more samples, if we use a specific model for translations)。 具体的做法如下,首先利用一个n维列向量来表示目标,记为$x$,然后利用$x$和一个循环移位矩阵$P$生成一个循环矩阵,其目的是使用一个base sample(正样本)和生成多个虚拟样本(负样本)来训练一个分类器。
获得了这样一个循环矩阵之后,作者接下来说:“all circulant matrices are made diagonal by the Discrete Fourier Transform(DFT), regardless of the generating vector x.”就是说循环矩阵的生成向量是完全指定的,且循环矩阵有一个非常好的性质:对任意生成向量$\widehat{x}$,我们都可以通过离散傅立叶变换(具有线性性)对循环矩阵进行对角化表示。
这个y是高斯加权后的值。初始目标的位置在padding后的search window的中心,循环移位得到的多个样本反应的是背景信息,而且离中心越远,就越不是目标,所以我们对标签进行高斯加权就刚好可以体现这种可能性准则。KCF里的输出是一个二维response矩阵,里面元素的大小代表该位置下的目标为预测目标的可能性,因此,在训练的时候就是输入是特征,而输出是一个gaussian_shaped_label,一般分类的标签是二值的,或者多值离散的,但是这个高斯标签反应的是由初始目标移位采样形成的若干样本距离初识样本越近可能性越大的准则,在代码中,高斯的峰值被移动到了左上角(于是四个角的值偏大),原因在论文的附录中进行了解释:“after computing a cross-correlation between two images in the Fourier domain and converting back to the spatial domain, it is the top-left element of the result that corresponds to a shift of zero”,也就是说目标零位移对应的是左上角的值。这样一来,我们在预测目标位置的时候,只需要pos=pos+find(response==max(response(:)))就好。如果把峰值放在中心点的话,就会“unnecessarily cause the detection output to be shifted by half a window”。
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters [2]Visual Object Tracking using Adaptive Correlation Filters [3]Exploiting the Circulant Structure of Tracking-by-detection with Kernels
在论文High-Speed Tracking with Kernelized Correlation Filters的introduction部分,有这样一句话:“we argue that undersampling negatives is the main factor inhibiting performance in tracking.”也就是说,负样本的欠采样是阻碍跟踪效果的主要因素。这在之前的文章中介绍过,这里就不在细述了。 这句话主要针对的问题是我们可以从一张图像中获得几乎无限的负样本。但由于跟踪的时间敏感性,我们的跟踪算法只能在尽可能多地采集样本和维持较低的计算需求之间取得一个平衡。之前通常的做法是从每一帧中随机选择几个样本。 KCF的一大贡献就是采用了一种更方便的方法迅速获取更多的负样本,以便于能够训练出一个更好的分类器。作者发现,在傅里叶域中,如果我们使用特定的模型进行转换,一些学习算法实际上变得更容易(in the Fourier domain, some learning algorithms actually become easier as we add more samples, if we use a specific model for translations)。 具体的做法如下,首先利用一个n维列向量来表示目标,记为$x$,然后利用$x$和一个循环移位矩阵$P$生成一个循环矩阵,其目的是使用一个base sample(正样本)和生成多个虚拟样本(负样本)来训练一个分类器。
获得了这样一个循环矩阵之后,作者接下来说:“all circulant matrices are made diagonal by the Discrete Fourier Transform(DFT), regardless of the generating vector x.”就是说循环矩阵的生成向量是完全指定的,且循环矩阵有一个非常好的性质:对任意生成向量$\widehat{x}$,我们都可以通过离散傅立叶变换(具有线性性)对循环矩阵进行对角化表示。
这个y是高斯加权后的值。初始目标的位置在padding后的search window的中心,循环移位得到的多个样本反应的是背景信息,而且离中心越远,就越不是目标,所以我们对标签进行高斯加权就刚好可以体现这种可能性准则。KCF里的输出是一个二维response矩阵,里面元素的大小代表该位置下的目标为预测目标的可能性,因此,在训练的时候就是输入是特征,而输出是一个gaussian_shaped_label,一般分类的标签是二值的,或者多值离散的,但是这个高斯标签反应的是由初始目标移位采样形成的若干样本距离初识样本越近可能性越大的准则,在代码中,高斯的峰值被移动到了左上角(于是四个角的值偏大),原因在论文的附录中进行了解释:“after computing a cross-correlation between two images in the Fourier domain and converting back to the spatial domain, it is the top-left element of the result that corresponds to a shift of zero”,也就是说目标零位移对应的是左上角的值。这样一来,我们在预测目标位置的时候,只需要pos=pos+find(response==max(response(:)))就好。如果把峰值放在中心点的话,就会“unnecessarily cause the detection output to be shifted by half a window”。
HOG(Histogram of Oriented Gradient),中文译为方向梯度直方图。它是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子,通过计算像局部区域中不同方向上梯度的值,然后进行累积,得到代表这块区域特征的直方图,可将其输入到分类器里面进行目标检测。 下面是论文中所呈现的进行人物检测时所采用的特征提取与目标检测的流程,本文将主要分析特征提取的部分(论文中对运用SVM分类器做检测的部分分析甚少,因此不做重点)。
或许会发现本文中好多的图例都用了同一位女士的脸,这里就扯点题外话。 照片中的女子名为Lena Soderberg,对计算机视觉领域有一定的接触的朋友应该对这张照片不会陌生。这张照片是标准的数字图像处理用例,各种算法研究经常会使用这张图作为模板。那为什么要用这幅图呢? David C. Munson在“A Note on Lena”中给出了两条理由:
HOG(Histogram of Oriented Gradient),中文译为方向梯度直方图。它是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子,通过计算像局部区域中不同方向上梯度的值,然后进行累积,得到代表这块区域特征的直方图,可将其输入到分类器里面进行目标检测。 下面是论文中所呈现的进行人物检测时所采用的特征提取与目标检测的流程,本文将主要分析特征提取的部分(论文中对运用SVM分类器做检测的部分分析甚少,因此不做重点)。
或许会发现本文中好多的图例都用了同一位女士的脸,这里就扯点题外话。 照片中的女子名为Lena Soderberg,对计算机视觉领域有一定的接触的朋友应该对这张照片不会陌生。这张照片是标准的数字图像处理用例,各种算法研究经常会使用这张图作为模板。那为什么要用这幅图呢? David C. Munson在“A Note on Lena”中给出了两条理由:
在Visual Object Tracking using Adaptive Correlation Filters一文中,我看到这样一句话:“The Peak-to-Sidelobe Ratio(PSR), which measures the strength of a correlation peak, can be used to detect occlusions or tracking failure, to stop the online update, and to reacquire the track if the object reappears with a similar appearance.”其大意为:用来衡量相关峰值强度的Peak-to-Sidelobe Ratio可以用于检测遮挡或者跟踪失误、停止实时更新和在相似外观再次出现时重新获取跟踪路径。我读完在想:这个PSR是什么?这么有用。结果百度了半天翻了几页没发现有任何有关它介绍或者解释的文章。于是看了一些英文文献,将自己的一些浅见写下来。
参考文献: [1]Understanding and Diagnosing Visual Tracking Systems [2]Visual Object Tracking using Adaptive Correlation Filters [3]Adaptive Model Update via Fusing Peak-to-sidelobe Ratio and Mean Frame Difference for Visual Tracking [4]Multi-Cue Correlation Filters for Robust Visual Tracking
What
由于没有找到任何中文翻译,我只能取一个相近的(感觉指的差不多)。在百度百科中,我找到了如下解释:PSLR,峰值旁瓣比,peak side lobe ratio,定义为主瓣峰值强度对于最强旁瓣的峰值强度之比,多用于雷达信号脉冲压缩后对信号的评估。
注意:百度百科内的名词与我遇到的相差了一个“to”,且缩写也不同。
上面是百度百科内的一个配图,根据百科解释,最高的主瓣与第二高的主瓣之差,即是PLSR(峰值旁瓣比),在这里大小为-13.4dB。 此外,我还找到了一个称为峰均比(PAPR,peak-to-average power ratio)的概念,它等于波形的振幅和其有效值(RMS)之比,主要是针对功率的,这里就不细说了。 后来,我在一篇光学期刊的文章上找到了一个比较可靠的翻译,该文献中有一个名为“峰旁比”的名词,且文献内容与目标追踪相关。因此我暂且称其为峰旁比吧。个人觉得比峰值旁瓣比简洁且好听。
Why
其实中文翻译并不重要,重要的是它的作用。 在查阅文献的过程中,我看到了这样一个公式:
其中$P_{sr}^{t}$是此时第t帧的峰旁比,$f_{t}$是对于第t帧分类器预测的响应,$\mu _{t}$和$\sigma _{t}$分别是响应图$f$的均值和方差。 根据这种计算方法,我们可以大概分析一下峰旁比的作用。当初看到时,我觉得它与我在物理实验中做过的音叉共振实验中的品质因数有相似之处(品质因数$Q=\frac{f_{0}}{f_{2}-f_{1}}$)。 由公式可知,当响应中的峰值较高,且响应分布相对而言集中在峰值及周围时,峰旁比就会较高;反之,峰旁比就会较低。 那么什么时候会造成峰旁比较低呢?根据论文描述可以获得提示,当遇到遮挡,或者目标跟丢即响应区内不含目标主体时,就不会出现一个那么明显的峰值响应,同时响应也会较为分散了,此时分母较大、分子较小,峰旁比就会变低。 下面也是Visual Object Tracking using Adaptive Correlation Filters中的一张figure(这篇文章提出了MOSSE),我们需要的是a much stronger peak which translates into less drift and fewer dropped tracks。看了这个想必应该知道峰旁比发挥的作用和大致原因了。
和上面的峰值旁瓣比、峰均比相比较,显然峰旁比的定义能更好地表征响应的集中程度。
How
由峰旁比定义所得出的性质可知,峰旁比可以作为模型预测定位准确性和可信度的判据。我们可以利用峰旁比来调整Model Updater(The model updater controls the strategy and frequency of updating the observation model. It has to strike a balance between model adaptation and drift.) 我的想法是,我们可以设置一个threshold,当峰旁比小于这个threshold时,表示模型未能准确定位到目标(可信度较低),这时我们可以停止模型的更新,或者通过减小学习率等方法减慢模型的更新速度以防止模型受背景或者遮挡物较大影响,而当目标再次出现时难以复原导致最终完全跟丢的问题;而当峰旁比大于这个threshold时,我们可以实时更新模型,或者运用较大的学习率(也可以根据峰旁比将学习率划分成几个等级)。
]]>
+
在Visual Object Tracking using Adaptive Correlation Filters一文中,我看到这样一句话:“The Peak-to-Sidelobe Ratio(PSR), which measures the strength of a correlation peak, can be used to detect occlusions or tracking failure, to stop the online update, and to reacquire the track if the object reappears with a similar appearance.”其大意为:用来衡量相关峰值强度的Peak-to-Sidelobe Ratio可以用于检测遮挡或者跟踪失误、停止实时更新和在相似外观再次出现时重新获取跟踪路径。我读完在想:这个PSR是什么?这么有用。结果百度了半天翻了几页没发现有任何有关它介绍或者解释的文章。于是看了一些英文文献,将自己的一些浅见写下来。
参考文献: [1]Understanding and Diagnosing Visual Tracking Systems [2]Visual Object Tracking using Adaptive Correlation Filters [3]Adaptive Model Update via Fusing Peak-to-sidelobe Ratio and Mean Frame Difference for Visual Tracking [4]Multi-Cue Correlation Filters for Robust Visual Tracking
What
由于没有找到任何中文翻译,我只能取一个相近的(感觉指的差不多)。在百度百科中,我找到了如下解释:PSLR,峰值旁瓣比,peak side lobe ratio,定义为主瓣峰值强度对于最强旁瓣的峰值强度之比,多用于雷达信号脉冲压缩后对信号的评估。
注意:百度百科内的名词与我遇到的相差了一个“to”,且缩写也不同。
上面是百度百科内的一个配图,根据百科解释,最高的主瓣与第二高的主瓣之差,即是PLSR(峰值旁瓣比),在这里大小为-13.4dB。 此外,我还找到了一个称为峰均比(PAPR,peak-to-average power ratio)的概念,它等于波形的振幅和其有效值(RMS)之比,主要是针对功率的,这里就不细说了。 后来,我在一篇光学期刊的文章上找到了一个比较可靠的翻译,该文献中有一个名为“峰旁比”的名词,且文献内容与目标追踪相关。因此我暂且称其为峰旁比吧。个人觉得比峰值旁瓣比简洁且好听。
Why
其实中文翻译并不重要,重要的是它的作用。 在查阅文献的过程中,我看到了这样一个公式:
其中$P_{sr}^{t}$是此时第t帧的峰旁比,$f_{t}$是对于第t帧分类器预测的响应,$\mu _{t}$和$\sigma _{t}$分别是响应图$f$的均值和方差。 根据这种计算方法,我们可以大概分析一下峰旁比的作用。当初看到时,我觉得它与我在物理实验中做过的音叉共振实验中的品质因数有相似之处(品质因数$Q=\frac{f_{0}}{f_{2}-f_{1}}$)。 由公式可知,当响应中的峰值较高,且响应分布相对而言集中在峰值及周围时,峰旁比就会较高;反之,峰旁比就会较低。 那么什么时候会造成峰旁比较低呢?根据论文描述可以获得提示,当遇到遮挡,或者目标跟丢即响应区内不含目标主体时,就不会出现一个那么明显的峰值响应,同时响应也会较为分散了,此时分母较大、分子较小,峰旁比就会变低。 下面也是Visual Object Tracking using Adaptive Correlation Filters中的一张figure(这篇文章提出了MOSSE),我们需要的是a much stronger peak which translates into less drift and fewer dropped tracks。看了这个想必应该知道峰旁比发挥的作用和大致原因了。
和上面的峰值旁瓣比、峰均比相比较,显然峰旁比的定义能更好地表征响应的集中程度。
How
由峰旁比定义所得出的性质可知,峰旁比可以作为模型预测定位准确性和可信度的判据。我们可以利用峰旁比来调整Model Updater(The model updater controls the strategy and frequency of updating the observation model. It has to strike a balance between model adaptation and drift.) 我的想法是,我们可以设置一个threshold,当峰旁比小于这个threshold时,表示模型未能准确定位到目标(可信度较低),这时我们可以停止模型的更新,或者通过减小学习率等方法减慢模型的更新速度以防止模型受背景或者遮挡物较大影响,而当目标再次出现时难以复原导致最终完全跟丢的问题;而当峰旁比大于这个threshold时,我们可以实时更新模型,或者运用较大的学习率(也可以根据峰旁比将学习率划分成几个等级)。
这里先介绍一下ntpd(Network Time Protocol (NTP) daemon),如官方文档所说,它的作用是sets and maintains the system time of day in synchronism with Internet standard time servers。因此,我们可以通过ntpdate命令进行设置,其基本格式如下:
这里先介绍一下ntpd(Network Time Protocol (NTP) daemon),如官方文档所说,它的作用是sets and maintains the system time of day in synchronism with Internet standard time servers。因此,我们可以通过ntpdate命令进行设置,其基本格式如下:
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters
循环矩阵(Circulant Matrices)
任意循环矩阵可以被傅里叶变换矩阵对角化。(All circulant matrices are made diagonal by the Discrete Fourier Transform (DFT), regardless of the generating vector x.)我们在文献中往往会看到这样一个变换:
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters
循环矩阵(Circulant Matrices)
任意循环矩阵可以被傅里叶变换矩阵对角化。(All circulant matrices are made diagonal by the Discrete Fourier Transform (DFT), regardless of the generating vector x.)我们在文献中往往会看到这样一个变换:
MinGW,是Minimalist GNU for Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。 当初报错的时候,我也是很诧异,因为之前使用CodeBlocks和Visual Studio的时候明明是有的。而这次在matlab中编译C/C++时怎么就找不到了。 因为之前使用CodeBlocks也有找不到的情况,我当时是重装了一遍CodeBlocks解决问题的,因此我上网开了一下有没有类似的方法。按道理来说已经装了VS是可以找到的,但好像也存在即使安装了VS、matlab还是找不到编译器的情况。可以使用mex看一下具体是哪些路径没有匹配上,似乎可以通过修改注册表的方法解决,但我没有尝试。
毕竟是花了一个晚上,看了mathworks上网友们的各种solution,试错了许多方法,这里记录两个貌似要成功的方法(其实最后还是失败了),或许会有参考价值。 这里有一个被许多网友强调、要注意的是:下载后的mingw文件(没错它只有15kb看上去好假)要在打开的matlab中,找到相应的下载目录,右键点击然后选择下载并安装(download and install),否则似乎会出错。
MinGW,是Minimalist GNU for Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。 当初报错的时候,我也是很诧异,因为之前使用CodeBlocks和Visual Studio的时候明明是有的。而这次在matlab中编译C/C++时怎么就找不到了。 因为之前使用CodeBlocks也有找不到的情况,我当时是重装了一遍CodeBlocks解决问题的,因此我上网开了一下有没有类似的方法。按道理来说已经装了VS是可以找到的,但好像也存在即使安装了VS、matlab还是找不到编译器的情况。可以使用mex看一下具体是哪些路径没有匹配上,似乎可以通过修改注册表的方法解决,但我没有尝试。
毕竟是花了一个晚上,看了mathworks上网友们的各种solution,试错了许多方法,这里记录两个貌似要成功的方法(其实最后还是失败了),或许会有参考价值。 这里有一个被许多网友强调、要注意的是:下载后的mingw文件(没错它只有15kb看上去好假)要在打开的matlab中,找到相应的下载目录,右键点击然后选择下载并安装(download and install),否则似乎会出错。
df1 = pd.DataFrame(np.random.randn(6, 4), index = dates, columns = list('ABCD'))
df1 >>> A B C D 2013-01-010.469112-0.282863-1.509059-1.135632 2013-01-021.212112-0.1732150.119209-1.044236 2013-01-03-0.861849-2.104569-0.4949291.071804 2013-01-040.721555-0.706771-1.0395750.271860 2013-01-05-0.4249720.5670200.276232-1.087401 2013-01-06-0.6736900.113648-1.4784270.524988
df1 = pd.DataFrame(np.random.randn(6, 4), index = dates, columns = list('ABCD'))
df1 >>> A B C D 2013-01-010.469112-0.282863-1.509059-1.135632 2013-01-021.212112-0.1732150.119209-1.044236 2013-01-03-0.861849-2.104569-0.4949291.071804 2013-01-040.721555-0.706771-1.0395750.271860 2013-01-05-0.4249720.5670200.276232-1.087401 2013-01-06-0.6736900.113648-1.4784270.524988
import time #这里是为了用来延时,代替训练的时间 numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in range(numOfTimes): print("\r", "progress percentage:{0}%".format((round(i + 1) * 100 / numOfTimes)), end = "", flush = True) time.sleep(0.02) #若前面from time import sleep,这里直接sleep(0.02)即可
import tqdm import time numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in tqdm.tqdm(range(numOfTimes)): time.sleep(0.02) #代替训练等耗时过程 pass
也可以直接from tqdm import tqdm,这样后面就不需要tqdm.tqdm了。
利用progressbar
库如其名,这个库就是用来做进度条的。如果没有的话,它和tqdm都可以使用pip来安装。
1 2 3 4 5 6
import progressbar from time import sleep numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 progress = progressbar.ProgressBar() for i in progress(range(numOfTimes)): sleep(0.02)
import time #这里是为了用来延时,代替训练的时间 numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in range(numOfTimes): print("\r", "progress percentage:{0}%".format((round(i + 1) * 100 / numOfTimes)), end = "", flush = True) time.sleep(0.02) #若前面from time import sleep,这里直接sleep(0.02)即可
import tqdm import time numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in tqdm.tqdm(range(numOfTimes)): time.sleep(0.02) #代替训练等耗时过程 pass
也可以直接from tqdm import tqdm,这样后面就不需要tqdm.tqdm了。
利用progressbar
库如其名,这个库就是用来做进度条的。如果没有的话,它和tqdm都可以使用pip来安装。
1 2 3 4 5 6
import progressbar from time import sleep numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 progress = progressbar.ProgressBar() for i in progress(range(numOfTimes)): sleep(0.02)
`timescale 1ns / 1ps //unit 1ns, precision 1ps module control( outputreg Cnt_EN, //enable the counter count, so that the counting period can be controled outputwire Cnt_CR, //clear the counter every time when the measure begins outputwire Latch_Sig, //at its posedge, the value of the counter will be stored/latched input nRST, //system reset signal input CP //1Hz standard clock signal ); always @ (posedge CP ornegedge nRST) begin if(~nRST) //generate enable counting signal Cnt_EN = 1'b0; //don't count else Cnt_EN = ~Cnt_EN; //two frequency divider for the clock signal end assign Latch_Sig = ~Cnt_EN; //generate latch signal assign Cnt_CR = nRST & (~CP & Latch_Sig); //generate the clear signal for the counter endmodule
计数模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
`timescale 1ns / 1ps //unit 1ns, precision 1ps module counter( outputreg [3:0] Q, input CR, EN, CP ); always @ (posedge CP orposedge CR) begin if(CR) Q <= 4'b0000; //reset to zero elseif(~EN) Q <= Q; //stop counting elseif(Q == 4'b1001) Q <= 4'b0000; else Q <= Q + 1'b1; //counting, plus one end endmodule
`timescale 1ns / 1ps //unit 1ns, precision 1ps module control( outputreg Cnt_EN, //enable the counter count, so that the counting period can be controled outputwire Cnt_CR, //clear the counter every time when the measure begins outputwire Latch_Sig, //at its posedge, the value of the counter will be stored/latched input nRST, //system reset signal input CP //1Hz standard clock signal ); always @ (posedge CP ornegedge nRST) begin if(~nRST) //generate enable counting signal Cnt_EN = 1'b0; //don't count else Cnt_EN = ~Cnt_EN; //two frequency divider for the clock signal end assign Latch_Sig = ~Cnt_EN; //generate latch signal assign Cnt_CR = nRST & (~CP & Latch_Sig); //generate the clear signal for the counter endmodule
计数模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
`timescale 1ns / 1ps //unit 1ns, precision 1ps module counter( outputreg [3:0] Q, input CR, EN, CP ); always @ (posedge CP orposedge CR) begin if(CR) Q <= 4'b0000; //reset to zero elseif(~EN) Q <= Q; //stop counting elseif(Q == 4'b1001) Q <= 4'b0000; else Q <= Q + 1'b1; //counting, plus one end endmodule
`timescale 1ns / 1ps //top module module runningwatch( input start, input stop, input store, input reset, input CLK, outputreg TM_EN, //enable the timer outputreg SD_EN, //enable register outputreg DP_SEL, //the screen show which data outputreg [15:0] regRecord, //data the register storing outputreg [15:0] TMRecord, //timer data output [6:0] tenmsLight, hunmsLight, onesLight, tensLight ); reg [3:0] tenMS, hunMS, oneS, tenS; //four 4bit digits from small to high and each from 0 to 9 reg tenmsup, hunmsup, onesup; //the signals if the bigger digit than itself should add //allocate state parameter S0 = 3'B000; //initial state parameter S1 = 3'B001; //TIMING:timer set as 00.00,record does not change,show timer,timer counts,TM_EN = 1, SD_EN = 0, DP_SEL = 0 parameter S2 = 3'B010; //PAUSE:timer does not change,record does not change,show timer,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 0 parameter S3 = 3'B011; //UPDATE:timer does not change,record set as timer,show register,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 1 parameter S4 = 3'B100; //KEEP:timer does not change,record does not change,show register,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 1 parameter S5 = 3'B101; //RESET:timer set as 00.00,record set as 99.99,show timer,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 0 reg [2:0] state; reg [2:0] next_state; //reg CLK; initial//only run once begin regRecord = 16'B0010011100001111; TMRecord = 16'B0000000000000000; state = S0; tenMS = 0; hunMS = 0; oneS = 0; tenS = 0; end //to judge if store the timer's data wirenew; reg newRecord; _16bit_Comp comparator(TMRecord, regRecord, new); //compare always @ (new) newRecord = new; reg [15:0] MAX = 16'B0010011100001111; //sequential logic part always @ (posedge CLK) //update the state at each posedge begin state <= next_state; end //combinatory logic part //state transform always @ (state or start or stop or store or reset or newRecord) begin next_state = S0; //if not press the key, back to the initial state case(state) S0: //initial state begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S1: //TIMING begin TM_EN = 1; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end
S2: //PAUSE begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S3: //UPDATE begin TM_EN = 0; SD_EN = 1; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S4: //KEEP begin TM_EN = 0; SD_EN = 0; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S5: //RESET begin TM_EN = 0; SD_EN = 1; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end default: begin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end//default initial state endcase end //reset to zero always @ (posedge reset orposedge start) begin tenMS <= 0; hunMS <= 0; oneS <= 0; tenS <= 0; TMRecord <= 0; end //the followings are which have stated before: //reg [3:0] tenMS, hunMS, oneS, tenS are four 4bit digits from small to high and each from 0 to 9 //reg tenmsup, hunmsup, onesup are the signals if the bigger digit than itself should add //timer, divide into four digits //10ms always @ (posedge CLK) begin if(TM_EN) begin TMRecord = TMRecord + 1; if(tenMS < 9) begin tenMS <= tenMS + 1; tenmsup <= 0; end else begin tenMS <= 0; tenmsup <= 1; end end end //100ms always @ (posedge tenmsup) begin if(TM_EN) begin if(hunMS < 9) begin hunMS <= hunMS + 1; hunmsup <= 0; end else begin hunMS <= 0; hunmsup <= 1; end end end //1s always @ (posedge hunmsup) begin if(TM_EN) begin if(oneS < 9) begin oneS <= oneS + 1; onesup <= 0; end else begin oneS <= 0; onesup <= 1; end end end //10s always @ (posedge onesup) begin if(TM_EN) begin if(tenS < 9) tenS <= oneS + 1; else oneS <= 0; end end //save to the register wire [15:0] newReg; _16bit_Reg register(SD_EN, TMRecord, regRecord, MAX, reset, CLK, newReg); always @ (newReg) regRecord = newReg; //change BCD to tube lights watchDrive TENms(tenMS, tenmsLight); watchDrive HUNms(hunMS, hunmsLight); watchDrive ONEs(oneS, onesLight); watchDrive TENs(tenS, tensLight); endmodule
`timescale 1ns / 1ps //top module module runningwatch( input start, input stop, input store, input reset, input CLK, outputreg TM_EN, //enable the timer outputreg SD_EN, //enable register outputreg DP_SEL, //the screen show which data outputreg [15:0] regRecord, //data the register storing outputreg [15:0] TMRecord, //timer data output [6:0] tenmsLight, hunmsLight, onesLight, tensLight ); reg [3:0] tenMS, hunMS, oneS, tenS; //four 4bit digits from small to high and each from 0 to 9 reg tenmsup, hunmsup, onesup; //the signals if the bigger digit than itself should add //allocate state parameter S0 = 3'B000; //initial state parameter S1 = 3'B001; //TIMING:timer set as 00.00,record does not change,show timer,timer counts,TM_EN = 1, SD_EN = 0, DP_SEL = 0 parameter S2 = 3'B010; //PAUSE:timer does not change,record does not change,show timer,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 0 parameter S3 = 3'B011; //UPDATE:timer does not change,record set as timer,show register,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 1 parameter S4 = 3'B100; //KEEP:timer does not change,record does not change,show register,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 1 parameter S5 = 3'B101; //RESET:timer set as 00.00,record set as 99.99,show timer,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 0 reg [2:0] state; reg [2:0] next_state; //reg CLK; initial//only run once begin regRecord = 16'B0010011100001111; TMRecord = 16'B0000000000000000; state = S0; tenMS = 0; hunMS = 0; oneS = 0; tenS = 0; end //to judge if store the timer's data wirenew; reg newRecord; _16bit_Comp comparator(TMRecord, regRecord, new); //compare always @ (new) newRecord = new; reg [15:0] MAX = 16'B0010011100001111; //sequential logic part always @ (posedge CLK) //update the state at each posedge begin state <= next_state; end //combinatory logic part //state transform always @ (state or start or stop or store or reset or newRecord) begin next_state = S0; //if not press the key, back to the initial state case(state) S0: //initial state begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S1: //TIMING begin TM_EN = 1; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end
S2: //PAUSE begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S3: //UPDATE begin TM_EN = 0; SD_EN = 1; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S4: //KEEP begin TM_EN = 0; SD_EN = 0; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S5: //RESET begin TM_EN = 0; SD_EN = 1; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end default: begin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end//default initial state endcase end //reset to zero always @ (posedge reset orposedge start) begin tenMS <= 0; hunMS <= 0; oneS <= 0; tenS <= 0; TMRecord <= 0; end //the followings are which have stated before: //reg [3:0] tenMS, hunMS, oneS, tenS are four 4bit digits from small to high and each from 0 to 9 //reg tenmsup, hunmsup, onesup are the signals if the bigger digit than itself should add //timer, divide into four digits //10ms always @ (posedge CLK) begin if(TM_EN) begin TMRecord = TMRecord + 1; if(tenMS < 9) begin tenMS <= tenMS + 1; tenmsup <= 0; end else begin tenMS <= 0; tenmsup <= 1; end end end //100ms always @ (posedge tenmsup) begin if(TM_EN) begin if(hunMS < 9) begin hunMS <= hunMS + 1; hunmsup <= 0; end else begin hunMS <= 0; hunmsup <= 1; end end end //1s always @ (posedge hunmsup) begin if(TM_EN) begin if(oneS < 9) begin oneS <= oneS + 1; onesup <= 0; end else begin oneS <= 0; onesup <= 1; end end end //10s always @ (posedge onesup) begin if(TM_EN) begin if(tenS < 9) tenS <= oneS + 1; else oneS <= 0; end end //save to the register wire [15:0] newReg; _16bit_Reg register(SD_EN, TMRecord, regRecord, MAX, reset, CLK, newReg); always @ (newReg) regRecord = newReg; //change BCD to tube lights watchDrive TENms(tenMS, tenmsLight); watchDrive HUNms(hunMS, hunmsLight); watchDrive ONEs(oneS, onesLight); watchDrive TENs(tenS, tensLight); endmodule
function[errors, ans, time] = bisection(low, high, max, stopError) %二分法 %func是待求零点的函数 %low,high分别是解区间的上下限 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fl = func(low); fh = func(high); error = high - low; fori = 1 : max mid = (low + high ) / 2; fm = func(mid); if fm * fl > 0 low = mid; else high = mid; end error = high - low; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(mid); %转换成角度 end
输入命令[errorsB, ans, time] = bisection(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = linecut(a, b, max, stopError) %弦截法 %func是待求零点的函数 %a,b是在解的领域取的两点,这里取解区间的两个端点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fa = func(a); fb = func(b); error = abs(a - b); fori = 1 : max x = b - (b - a) * fb / (fb - fa); a = b; b = x; fa = func(a); fb = func(b); error = abs(a - b); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(b); %转换成角度 end
输入命令[errorsL, ans, time] = linecut(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = steffensen(x, max, stopError) %Steffensen方法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 f = func(x); fori = 1 : max o = x - f ^ 2 / (f - func(x - f)); error = abs(x - o); x = o; f = func(o); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
选取初始点为$0$,输入命令[errorsS1, ans, time] = steffensen(0, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = picard(x, max, stopError) %Picard迭代法 %interation是迭代函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = interation(x); error = abs(x - o); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
输入命令[errorsP, ans, time] = picard(0, 50, 1.7e-5)求解:
function[errors, ans, time] = newton(x, max, stopError) %Newton迭代法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = x - func(x) / df(x); error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
输入命令[errorsN, ans, time] = newton(0, 50, 1.7e-5)进行计算,得解:
function[errors, ans, time] = hill(x, max, stopError) %Newton下山法 % 此处显示详细说明 format long %为提高精度,保留更多位数 l = 1; fori = 1 : max o = x - l * func(x) / df(x); whileabs(func(o)) > abs(func(x)) %不满足下山条件 l = l / 2; o = x - l * func(x) / df(x); end error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
function[errors, ans, time] = bisection(low, high, max, stopError) %二分法 %func是待求零点的函数 %low,high分别是解区间的上下限 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fl = func(low); fh = func(high); error = high - low; fori = 1 : max mid = (low + high ) / 2; fm = func(mid); if fm * fl > 0 low = mid; else high = mid; end error = high - low; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(mid); %转换成角度 end
输入命令[errorsB, ans, time] = bisection(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = linecut(a, b, max, stopError) %弦截法 %func是待求零点的函数 %a,b是在解的领域取的两点,这里取解区间的两个端点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fa = func(a); fb = func(b); error = abs(a - b); fori = 1 : max x = b - (b - a) * fb / (fb - fa); a = b; b = x; fa = func(a); fb = func(b); error = abs(a - b); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(b); %转换成角度 end
输入命令[errorsL, ans, time] = linecut(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = steffensen(x, max, stopError) %Steffensen方法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 f = func(x); fori = 1 : max o = x - f ^ 2 / (f - func(x - f)); error = abs(x - o); x = o; f = func(o); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
选取初始点为$0$,输入命令[errorsS1, ans, time] = steffensen(0, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = picard(x, max, stopError) %Picard迭代法 %interation是迭代函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = interation(x); error = abs(x - o); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
输入命令[errorsP, ans, time] = picard(0, 50, 1.7e-5)求解:
function[errors, ans, time] = newton(x, max, stopError) %Newton迭代法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = x - func(x) / df(x); error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
输入命令[errorsN, ans, time] = newton(0, 50, 1.7e-5)进行计算,得解:
function[errors, ans, time] = hill(x, max, stopError) %Newton下山法 % 此处显示详细说明 format long %为提高精度,保留更多位数 l = 1; fori = 1 : max o = x - l * func(x) / df(x); whileabs(func(o)) > abs(func(x)) %不满足下山条件 l = l / 2; o = x - l * func(x) / df(x); end error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
kaggle是一个著名的数据科学竞赛平台,暑假里我也抽空自己独立完成了三四个getting started级别的比赛。对于MNIST数据集,想必入门计算机视觉的人应该也不会陌生。kaggle上getting started的第一个比赛就是Digit Recognizer:Learn computer vision fundamentals with the famous MNIST data。当时作为入门小白的我,使用了入门级的方法KNN完成了我的第一次机器学习(自认为KNN是最最基础的算法,对它的介绍可见我的另一篇博文machine-learning笔记:机器学习的几个常见算法及其优缺点,真的非常简单,但也极其笨拙)。而最近我又使用CNN再一次尝试了这个数据集,踩了不少坑,因此想把两次经历统统记录在这,可能会有一些不足之处,留作以后整理优化。
import matplotlib from matplotlib import pyplot as plt %matplotlib inline
导入训练数据:
1 2 3 4 5 6 7 8 9 10
trainSet = [] with open('train.csv','r') as trainFile: lines=csv.reader(trainFile) for line in lines: trainSet.append(line) trainSet.remove(trainSet[0])
rawTrainData = np.mat(rawTrainData) #转化成矩阵,或许不需要 m, n = np.shape(rawTrainData) trainData = np.zeros((m, n)) #创建初值为0的ndarray for i in range(m): for j in range(n): trainData[i, j] = int(rawTrainData[i, j]) #转化并赋值
rawTrainLabel = np.mat(rawTrainLabel) #或许不需要 m, n = np.shape(rawTrainLabel) trainLabel = np.zeros((m, n)) for i in range(m): for j in range(n): trainLabel[i, j] = int(rawTrainLabel[i, j])
这里我们可以查看以下数据的维度,确保没有出错。
为了方便起见,我们把所有pixel不为0的点都设置为1。
1 2 3 4 5
m, n = np.shape(trainData) for i in range(m): for j in range(n): if trainData[i, j] != 0: trainData[i, j] = 1
testSet = [] with open('test.csv','r') as testFile: lines=csv.reader(testFile) for line in lines: testSet.append(line) testSet.remove(testSet[0])
testSet = np.array(testSet) rawTestData = testSet
rawTestData = np.mat(rawTestData) m, n = np.shape(rawTestData) testData = np.zeros((m, n)) for i in range(m): for j in range(n): testData[i, j] = int(rawTestData[i, j])
m, n = np.shape(testData) for i in range(m): for j in range(n): if testData[i, j] != 0: testData[i, j] = 1
#分割出验证集 m, n = np.shape(trainLabel) trainingTrainLabel = np.zeros((m, n - trainingTestSize)) for i in range(m): for j in range(n - trainingTestSize): trainingTrainLabel[i, j] = trainLabel[i, j] trainingTestLabel = np.zeros((m, trainingTestSize)) for i in range(m): for j in range(trainingTestSize): trainingTestLabel[i, j] = trainLabel[i, n - trainingTestSize + j] m, n = np.shape(trainData) trainingTrainData = np.zeros((m - trainingTestSize, n)) for i in range(m - trainingTestSize): for j in range(n): trainingTrainData[i, j] = trainData[i, j] trainingTestData = np.zeros((trainingTestSize, n)) for i in range(trainingTestSize): for j in range(n): trainingTestData[i, j] = trainData[m - trainingTestSize + i, j]
#使k值为3到9依次尝试 training = [] for x in range(3, 10): error = 0 for y in range(trainingTestSize): answer = (classify(trainingTestData[y], trainingTrainData, trainingTrainLabel, x)) print'the classifier came back with: %d, %.2f%% has done, the k now is %d' % (answer, (y + (x - 3) * trainingTestSize) / float(trainingTestSize * 7) * 100, x) #方便知道进度 if answer != trainingTestLabel[0, y]: error += 1 training.append(error)
m, n = np.shape(testData) result = [] for i in range(m): answer = (classify(testData[i], trainData, trainLabel, theK)) result.append(answer) print'the classifier came back with: %d, %.2f%% has done' % (answer, i / float(m) * 100)
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import pandas as pd import numpy as np from math import *
%matplotlib inline import matplotlib.pyplot as plt import matplotlib.cm as cm
for epoch in range(EPOCH): for step, (x, y) in enumerate(train_loader): b_x = Variable(x) b_y = Variable(y) output = cnn(b_x) loss = loss_func(output, b_y) #cross entropy loss #update W optimzer.zero_grad() loss.backward() optimzer.step() print('epoch%d' % (epoch + 1), '-', 'batch%d' % step, '-', 'loss%f' % loss) #查看训练过程 print('No.%depoch is over' % (epoch + 1))
代入测试集求解:
1 2 3 4 5
output = cnn(test_data[:]) #print(output)
result = torch.max(output, 1)[1].squeeze() #print(result)
仿照KNN中的结果转存函数,定义saveResult函数。
1 2 3 4 5 6 7
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
defforward(self, x): x = self.conv1(x) x = self.conv2(x) x = x.view(x.size(0), -1) x = self.fc(x) x = self.dropout(x) output = F.softmax(self.out(x)) return output
kaggle是一个著名的数据科学竞赛平台,暑假里我也抽空自己独立完成了三四个getting started级别的比赛。对于MNIST数据集,想必入门计算机视觉的人应该也不会陌生。kaggle上getting started的第一个比赛就是Digit Recognizer:Learn computer vision fundamentals with the famous MNIST data。当时作为入门小白的我,使用了入门级的方法KNN完成了我的第一次机器学习(自认为KNN是最最基础的算法,对它的介绍可见我的另一篇博文machine-learning笔记:机器学习的几个常见算法及其优缺点,真的非常简单,但也极其笨拙)。而最近我又使用CNN再一次尝试了这个数据集,踩了不少坑,因此想把两次经历统统记录在这,可能会有一些不足之处,留作以后整理优化。
import matplotlib from matplotlib import pyplot as plt %matplotlib inline
导入训练数据:
1 2 3 4 5 6 7 8 9 10
trainSet = [] with open('train.csv','r') as trainFile: lines=csv.reader(trainFile) for line in lines: trainSet.append(line) trainSet.remove(trainSet[0])
rawTrainData = np.mat(rawTrainData) #转化成矩阵,或许不需要 m, n = np.shape(rawTrainData) trainData = np.zeros((m, n)) #创建初值为0的ndarray for i in range(m): for j in range(n): trainData[i, j] = int(rawTrainData[i, j]) #转化并赋值
rawTrainLabel = np.mat(rawTrainLabel) #或许不需要 m, n = np.shape(rawTrainLabel) trainLabel = np.zeros((m, n)) for i in range(m): for j in range(n): trainLabel[i, j] = int(rawTrainLabel[i, j])
这里我们可以查看以下数据的维度,确保没有出错。
为了方便起见,我们把所有pixel不为0的点都设置为1。
1 2 3 4 5
m, n = np.shape(trainData) for i in range(m): for j in range(n): if trainData[i, j] != 0: trainData[i, j] = 1
testSet = [] with open('test.csv','r') as testFile: lines=csv.reader(testFile) for line in lines: testSet.append(line) testSet.remove(testSet[0])
testSet = np.array(testSet) rawTestData = testSet
rawTestData = np.mat(rawTestData) m, n = np.shape(rawTestData) testData = np.zeros((m, n)) for i in range(m): for j in range(n): testData[i, j] = int(rawTestData[i, j])
m, n = np.shape(testData) for i in range(m): for j in range(n): if testData[i, j] != 0: testData[i, j] = 1
#分割出验证集 m, n = np.shape(trainLabel) trainingTrainLabel = np.zeros((m, n - trainingTestSize)) for i in range(m): for j in range(n - trainingTestSize): trainingTrainLabel[i, j] = trainLabel[i, j] trainingTestLabel = np.zeros((m, trainingTestSize)) for i in range(m): for j in range(trainingTestSize): trainingTestLabel[i, j] = trainLabel[i, n - trainingTestSize + j] m, n = np.shape(trainData) trainingTrainData = np.zeros((m - trainingTestSize, n)) for i in range(m - trainingTestSize): for j in range(n): trainingTrainData[i, j] = trainData[i, j] trainingTestData = np.zeros((trainingTestSize, n)) for i in range(trainingTestSize): for j in range(n): trainingTestData[i, j] = trainData[m - trainingTestSize + i, j]
#使k值为3到9依次尝试 training = [] for x in range(3, 10): error = 0 for y in range(trainingTestSize): answer = (classify(trainingTestData[y], trainingTrainData, trainingTrainLabel, x)) print'the classifier came back with: %d, %.2f%% has done, the k now is %d' % (answer, (y + (x - 3) * trainingTestSize) / float(trainingTestSize * 7) * 100, x) #方便知道进度 if answer != trainingTestLabel[0, y]: error += 1 training.append(error)
m, n = np.shape(testData) result = [] for i in range(m): answer = (classify(testData[i], trainData, trainLabel, theK)) result.append(answer) print'the classifier came back with: %d, %.2f%% has done' % (answer, i / float(m) * 100)
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import pandas as pd import numpy as np from math import *
%matplotlib inline import matplotlib.pyplot as plt import matplotlib.cm as cm
for epoch in range(EPOCH): for step, (x, y) in enumerate(train_loader): b_x = Variable(x) b_y = Variable(y) output = cnn(b_x) loss = loss_func(output, b_y) #cross entropy loss #update W optimzer.zero_grad() loss.backward() optimzer.step() print('epoch%d' % (epoch + 1), '-', 'batch%d' % step, '-', 'loss%f' % loss) #查看训练过程 print('No.%depoch is over' % (epoch + 1))
代入测试集求解:
1 2 3 4 5
output = cnn(test_data[:]) #print(output)
result = torch.max(output, 1)[1].squeeze() #print(result)
仿照KNN中的结果转存函数,定义saveResult函数。
1 2 3 4 5 6 7
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
defforward(self, x): x = self.conv1(x) x = self.conv2(x) x = x.view(x.size(0), -1) x = self.fc(x) x = self.dropout(x) output = F.softmax(self.out(x)) return output
过了一会有一个男老师进来说一些有关考试的注意事项,说完没多久大家就到隔壁的考试教室刷脸入场了。 考场的教室和等候的教室一样,也是黄色的日光灯,看着也挺舒适。入场顺序是按照姓氏的首字母顺序的,我进去的比较早。尽管A考场大概也就二三十个人,但整个入场过程还是挺久的。 考官把我领到座位上,虽然是随机抽的但好像我的考位还是我的序号。为我把身份证插在旁边的卡槽里之后,考官又为我输了激活码进入考试界面,然后没说什么就走了。 考试的隔间挺好,靠桌子往里坐一点就完全看不到旁边了。首先是确认姓名的界面,然而考官走了我也没处问,担心确认了就直接开始考试了因此久久没敢点。由于别人还在入场,因此我不敢太早开始考试。我回头看了一眼,发现是我进候考室以来就注意到的那个男生。虽然没问过他,但看上去他这次绝对不是一战了。 过了一会,我听到有人点鼠标的声音,于是我也鼓足勇气开始点。前面大概有七八的页面都是只需continue的direction界面,而且这个界面是不会自动跳转的,我在这里停留了很久。 终于,大概第十个人入场的时候,我听到有人开始试音了。意外的是,第一个开始试音的人居然真的在介绍他生活的城市。哈哈哈看来也是首考的,不知道待会整个考场一齐开始诠释人类的本质的时候,他有什么感想。这里我暗暗庆幸自己报了班。 当大家都在诠释人类的本质时,我心里觉得还是挺可乐的。不过就在这时,我听到前面提到的那位久经沙场的老哥也开始复读了,于是我又点了一个continue。 每个continue我的拖好久才点,不过入场真的是挺久的。大概有十个人完成试音之后,我才看到了describe the city you live in,心想这个时间还是可以的。
接下来就是听力了,我的听力是加试,有3个section。第一个section的对话我考虑太久,导致最后答lecture三道题要在一分钟之内答完。当时也只能以这个section只有50%的概率计入成绩来安慰自己。 第二个section做得还行,一些笔记还是没记到要点上,还是得多练。遗憾的是,我听力有好几篇都没听懂听力开头“you will hear part of a lecture in a ……gy class”中学科具体是什么,如果能听懂的话肯定是有一定帮助的,词汇量还不够啊!
过了一会有一个男老师进来说一些有关考试的注意事项,说完没多久大家就到隔壁的考试教室刷脸入场了。 考场的教室和等候的教室一样,也是黄色的日光灯,看着也挺舒适。入场顺序是按照姓氏的首字母顺序的,我进去的比较早。尽管A考场大概也就二三十个人,但整个入场过程还是挺久的。 考官把我领到座位上,虽然是随机抽的但好像我的考位还是我的序号。为我把身份证插在旁边的卡槽里之后,考官又为我输了激活码进入考试界面,然后没说什么就走了。 考试的隔间挺好,靠桌子往里坐一点就完全看不到旁边了。首先是确认姓名的界面,然而考官走了我也没处问,担心确认了就直接开始考试了因此久久没敢点。由于别人还在入场,因此我不敢太早开始考试。我回头看了一眼,发现是我进候考室以来就注意到的那个男生。虽然没问过他,但看上去他这次绝对不是一战了。 过了一会,我听到有人点鼠标的声音,于是我也鼓足勇气开始点。前面大概有七八的页面都是只需continue的direction界面,而且这个界面是不会自动跳转的,我在这里停留了很久。 终于,大概第十个人入场的时候,我听到有人开始试音了。意外的是,第一个开始试音的人居然真的在介绍他生活的城市。哈哈哈看来也是首考的,不知道待会整个考场一齐开始诠释人类的本质的时候,他有什么感想。这里我暗暗庆幸自己报了班。 当大家都在诠释人类的本质时,我心里觉得还是挺可乐的。不过就在这时,我听到前面提到的那位久经沙场的老哥也开始复读了,于是我又点了一个continue。 每个continue我的拖好久才点,不过入场真的是挺久的。大概有十个人完成试音之后,我才看到了describe the city you live in,心想这个时间还是可以的。
接下来就是听力了,我的听力是加试,有3个section。第一个section的对话我考虑太久,导致最后答lecture三道题要在一分钟之内答完。当时也只能以这个section只有50%的概率计入成绩来安慰自己。 第二个section做得还行,一些笔记还是没记到要点上,还是得多练。遗憾的是,我听力有好几篇都没听懂听力开头“you will hear part of a lecture in a ……gy class”中学科具体是什么,如果能听懂的话肯定是有一定帮助的,词汇量还不够啊!
Andrew Ng还解释说,当你阅读论文时(即使是最有影响力的论文),你可能也会发现有些部分没什么用,或者没什么意义。因此,如果你读了一篇论文,其中一些内容没有意义(这并不罕见),那么你可以先略读。除非你想要掌握它,那就花更多的时间。确实,当我在阅读ILSVRC、COCO等顶级比赛许多获奖模型的论文时,其中都有对比赛情况的详细结果介绍,我觉得这些部分一定程度上是可以扫读和跳读的。
感悟
目前我阅读过大多数论文的组成一般为Abstract、Introduction、Related Work、Method、Experiment、Conclusion。 可能阅历丰富的研究者能够从Abstract中提炼出比较关键的信息,但我个人认为,一篇文章最关键的是Introduction部分,该部分一般会包括前因后果和文章有哪几个contribution的总结,涵盖了本文解决的问题和一些主要概念和思路。 Related Work主要是对之前论文的分析,相当于是Introduction部分中前因的具体分析,相当于精简版的综述,如果对该领域比较了解的话完全可以跳读,但如果不熟悉该领域的话还是能从中学到很多重要的信息的。 Method部分是对Introduction部分中contribution的具体化,从这里开始会涉及到较多理论的内容,细品还是略读要靠自己拿捏。 Experiment是比较容易忽略的部分,不过有时候会提及一些trick,如果有ablation experiments的话可以重点关注一下。注意,在一些预印论文网站上的占坑论文有可能实验部分不是很完全,这是我们用于判断该篇论文结论是否可靠的依据。 Conclusion其实是Introduction的缩写,如果有未来研究方向的展望的话可以看一下。
Andrew Ng还解释说,当你阅读论文时(即使是最有影响力的论文),你可能也会发现有些部分没什么用,或者没什么意义。因此,如果你读了一篇论文,其中一些内容没有意义(这并不罕见),那么你可以先略读。除非你想要掌握它,那就花更多的时间。确实,当我在阅读ILSVRC、COCO等顶级比赛许多获奖模型的论文时,其中都有对比赛情况的详细结果介绍,我觉得这些部分一定程度上是可以扫读和跳读的。
感悟
目前我阅读过大多数论文的组成一般为Abstract、Introduction、Related Work、Method、Experiment、Conclusion。 可能阅历丰富的研究者能够从Abstract中提炼出比较关键的信息,但我个人认为,一篇文章最关键的是Introduction部分,该部分一般会包括前因后果和文章有哪几个contribution的总结,涵盖了本文解决的问题和一些主要概念和思路。 Related Work主要是对之前论文的分析,相当于是Introduction部分中前因的具体分析,相当于精简版的综述,如果对该领域比较了解的话完全可以跳读,但如果不熟悉该领域的话还是能从中学到很多重要的信息的。 Method部分是对Introduction部分中contribution的具体化,从这里开始会涉及到较多理论的内容,细品还是略读要靠自己拿捏。 Experiment是比较容易忽略的部分,不过有时候会提及一些trick,如果有ablation experiments的话可以重点关注一下。注意,在一些预印论文网站上的占坑论文有可能实验部分不是很完全,这是我们用于判断该篇论文结论是否可靠的依据。 Conclusion其实是Introduction的缩写,如果有未来研究方向的展望的话可以看一下。
self.inplanes = 64 self.dilation = 1 if replace_stride_with_dilation isNone: # each element in the tuple indicates if we should replace # the 2x2 stride with a dilated convolution instead replace_stride_with_dilation = [False, False, False] if len(replace_stride_with_dilation) != 3: raise ValueError("replace_stride_with_dilation should be None " "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) self.groups = groups self.base_width = width_per_group self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = norm_layer(self.inplanes) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2, dilate=replace_stride_with_dilation[0]) self.layer3 = self._make_layer(block, 256, layers[2], stride=2, dilate=replace_stride_with_dilation[1]) self.layer4 = self._make_layer(block, 512, layers[3], stride=2, dilate=replace_stride_with_dilation[2]) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0)
# Zero-initialize the last BN in each residual branch, # so that the residual branch starts with zeros, and each residual block behaves like an identity. # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 if zero_init_residual: for m in self.modules(): if isinstance(m, Bottleneck): nn.init.constant_(m.bn3.weight, 0) elif isinstance(m, BasicBlock): nn.init.constant_(m.bn2.weight, 0)
defforward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x)
x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x)
x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x)
return x
def_resnet(arch, block, layers, pretrained, progress, **kwargs): model = ResNet(block, layers, **kwargs) if pretrained: state_dict = load_state_dict_from_url(model_urls[arch], progress=progress) model.load_state_dict(state_dict) return model
defresnet18(pretrained=False, progress=True, **kwargs): r"""ResNet-18 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
defresnet34(pretrained=False, progress=True, **kwargs): r"""ResNet-34 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet50(pretrained=False, progress=True, **kwargs): r"""ResNet-50 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet101(pretrained=False, progress=True, **kwargs): r"""ResNet-101 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defresnet152(pretrained=False, progress=True, **kwargs): r"""ResNet-152 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
defresnext50_32x4d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-50 32x4d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 4 return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnext101_32x8d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-101 32x8d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 8 return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defwide_resnet50_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-50-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defwide_resnet101_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-101-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
self.inplanes = 64 self.dilation = 1 if replace_stride_with_dilation isNone: # each element in the tuple indicates if we should replace # the 2x2 stride with a dilated convolution instead replace_stride_with_dilation = [False, False, False] if len(replace_stride_with_dilation) != 3: raise ValueError("replace_stride_with_dilation should be None " "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) self.groups = groups self.base_width = width_per_group self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = norm_layer(self.inplanes) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2, dilate=replace_stride_with_dilation[0]) self.layer3 = self._make_layer(block, 256, layers[2], stride=2, dilate=replace_stride_with_dilation[1]) self.layer4 = self._make_layer(block, 512, layers[3], stride=2, dilate=replace_stride_with_dilation[2]) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0)
# Zero-initialize the last BN in each residual branch, # so that the residual branch starts with zeros, and each residual block behaves like an identity. # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 if zero_init_residual: for m in self.modules(): if isinstance(m, Bottleneck): nn.init.constant_(m.bn3.weight, 0) elif isinstance(m, BasicBlock): nn.init.constant_(m.bn2.weight, 0)
defforward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x)
x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x)
x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x)
return x
def_resnet(arch, block, layers, pretrained, progress, **kwargs): model = ResNet(block, layers, **kwargs) if pretrained: state_dict = load_state_dict_from_url(model_urls[arch], progress=progress) model.load_state_dict(state_dict) return model
defresnet18(pretrained=False, progress=True, **kwargs): r"""ResNet-18 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
defresnet34(pretrained=False, progress=True, **kwargs): r"""ResNet-34 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet50(pretrained=False, progress=True, **kwargs): r"""ResNet-50 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet101(pretrained=False, progress=True, **kwargs): r"""ResNet-101 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defresnet152(pretrained=False, progress=True, **kwargs): r"""ResNet-152 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
defresnext50_32x4d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-50 32x4d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 4 return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnext101_32x8d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-101 32x8d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 8 return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defwide_resnet50_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-50-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defwide_resnet101_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-101-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) for epoch in range(100): if epoch % 5 == 0: for p in optimizer.param_groups: p['lr'] *= 0.9#学习率超参的位置:optimizer.state_dict()['param_groups'][0]['lr']
这里是每过5个epoch就进行一次衰减。
lambda自定义衰减
1 2 3 4 5 6 7 8
import numpy as np model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) lambda1 = lambda epoch: np.sin(epoch) / epoch scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda = lambda1) for epoch in range(100): scheduler.step()
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ExponentialLR(optimizer, gamma = 0.9) for epoch in range(100): scheduler.step()
这种方法就是在每个epoch中lr都乘以gamma,从而达到连续衰减的效果。
余弦式调整
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max = 20) for epoch in range(100): scheduler.step()
这里的T_max对应1/2个cos周期所对应的epoch数值。
基于loss和accuracy
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode = 'min', factor = 0.1, patience = 10, verbose = False, threshold = 0.0001, threshold_mode = 'rel', cooldown = 0, min_lr = 0, eps = 1e-08) for epoch in range(100): scheduler.step()
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) for epoch in range(100): if epoch % 5 == 0: for p in optimizer.param_groups: p['lr'] *= 0.9#学习率超参的位置:optimizer.state_dict()['param_groups'][0]['lr']
这里是每过5个epoch就进行一次衰减。
lambda自定义衰减
1 2 3 4 5 6 7 8
import numpy as np model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) lambda1 = lambda epoch: np.sin(epoch) / epoch scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda = lambda1) for epoch in range(100): scheduler.step()
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ExponentialLR(optimizer, gamma = 0.9) for epoch in range(100): scheduler.step()
这种方法就是在每个epoch中lr都乘以gamma,从而达到连续衰减的效果。
余弦式调整
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max = 20) for epoch in range(100): scheduler.step()
这里的T_max对应1/2个cos周期所对应的epoch数值。
基于loss和accuracy
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode = 'min', factor = 0.1, patience = 10, verbose = False, threshold = 0.0001, threshold_mode = 'rel', cooldown = 0, min_lr = 0, eps = 1e-08) for epoch in range(100): scheduler.step()
赤池信息准则(Akaike Information Criterion,AIC)公式定义如下:其中k表示模型参数个数(复杂度),L表示经验误差(似然函数)。 当需要从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型。
BIC准则
贝叶斯信息准则(Bayesian Information Criterion,BIC)是对AIC准则的改进,定义如下:与AIC不同,这里k的系数不再是常数。其中n代表的是样本量(数据量),这样,BIC准则就与样本量相关了。当样本量足够时,过拟合的风险变小,我们就可以允许模型复杂一些。 这里再次附上这张直观的图片,方便理解与体会。简析可参考machine-learning笔记:机器学习中正则化的理解。
赤池信息准则(Akaike Information Criterion,AIC)公式定义如下:其中k表示模型参数个数(复杂度),L表示经验误差(似然函数)。 当需要从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型。
BIC准则
贝叶斯信息准则(Bayesian Information Criterion,BIC)是对AIC准则的改进,定义如下:与AIC不同,这里k的系数不再是常数。其中n代表的是样本量(数据量),这样,BIC准则就与样本量相关了。当样本量足够时,过拟合的风险变小,我们就可以允许模型复杂一些。 这里再次附上这张直观的图片,方便理解与体会。简析可参考machine-learning笔记:机器学习中正则化的理解。
我们直接到维基百科搜索regularization: 里面第一段是这样解释的:In mathematics, statistics, and computer science, particularly in machine learning and inverse problems, regularization is the process of adding information in order to solve an ill-posed problem or to prevent overfitting. 这就和我们在机器学习应用中的目的比较相近了。
我们直接到维基百科搜索regularization: 里面第一段是这样解释的:In mathematics, statistics, and computer science, particularly in machine learning and inverse problems, regularization is the process of adding information in order to solve an ill-posed problem or to prevent overfitting. 这就和我们在机器学习应用中的目的比较相近了。
下面奉上宝贵的论文: 论文原版 论文中文版 从introduction第一句开始,作者就开始了一段长长的吐槽: Current approaches to object recognition make essential use of machine learning methods… 吐槽Yann LeCun大佬的论文被顶会拒收了仅仅因为Yann LeCun使用了神经网络。其实,那段时间之前,由于SVM等机器学习方法的兴起,神经网络是一种被许多ML大佬们看不起的算法模型。 在introduction的最后,作者留下了这样一句经典的话: All of our experiments suggest that our results can be improved simply by waiting for faster GPUs and bigger datasets to become available. 有没有感觉到一种新世界大门被打开的感觉呢? 有关论文别的内容,我暂不多说了,大家可以自己看论文学习与体会。 附上推荐重点阅读的章节:3.1 ReLU Nonlinearity;3.5 Overall Architecture;4 Reducing Overfitting。
下面奉上宝贵的论文: 论文原版 论文中文版 从introduction第一句开始,作者就开始了一段长长的吐槽: Current approaches to object recognition make essential use of machine learning methods… 吐槽Yann LeCun大佬的论文被顶会拒收了仅仅因为Yann LeCun使用了神经网络。其实,那段时间之前,由于SVM等机器学习方法的兴起,神经网络是一种被许多ML大佬们看不起的算法模型。 在introduction的最后,作者留下了这样一句经典的话: All of our experiments suggest that our results can be improved simply by waiting for faster GPUs and bigger datasets to become available. 有没有感觉到一种新世界大门被打开的感觉呢? 有关论文别的内容,我暂不多说了,大家可以自己看论文学习与体会。 附上推荐重点阅读的章节:3.1 ReLU Nonlinearity;3.5 Overall Architecture;4 Reducing Overfitting。
defforward(self, x): x = F.relu(self.conv1_1(x)) x = F.relu(self.conv1_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) #输入x经过卷积之后,经过激活函数ReLU,循环两次,最后使用2x2的窗口进行最大池化Max pooling,然后更新到x x = F.relu(self.conv2_1(x)) x = F.relu(self.conv2_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv3_1(x)) x = F.relu(self.conv3_2(x)) x = F.relu(self.conv3_3(x)) x = F.relu(self.conv3_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv4_1(x)) x = F.relu(self.conv4_2(x)) x = F.relu(self.conv4_3(x)) x = F.relu(self.conv4_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv5_1(x)) x = F.relu(self.conv5_2(x)) x = F.relu(self.conv5_3(x)) x = F.relu(self.conv5_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = x.view(-1, self.num_flat_features(x)) #view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备 x = self.fc1(x) #输入x经过全连接1,然后更新x x = self.fc2(x) x = self.fc3(x) return x
defnum_flat_features(self, x): size = x.size()[1:] #all dimensions except the batch dimension num_features = 1 for s in size: num_features *= s return num_features
defforward(self, x): x = F.relu(self.conv1_1(x)) x = F.relu(self.conv1_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) #输入x经过卷积之后,经过激活函数ReLU,循环两次,最后使用2x2的窗口进行最大池化Max pooling,然后更新到x x = F.relu(self.conv2_1(x)) x = F.relu(self.conv2_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv3_1(x)) x = F.relu(self.conv3_2(x)) x = F.relu(self.conv3_3(x)) x = F.relu(self.conv3_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv4_1(x)) x = F.relu(self.conv4_2(x)) x = F.relu(self.conv4_3(x)) x = F.relu(self.conv4_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv5_1(x)) x = F.relu(self.conv5_2(x)) x = F.relu(self.conv5_3(x)) x = F.relu(self.conv5_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = x.view(-1, self.num_flat_features(x)) #view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备 x = self.fc1(x) #输入x经过全连接1,然后更新x x = self.fc2(x) x = self.fc3(x) return x
defnum_flat_features(self, x): size = x.size()[1:] #all dimensions except the batch dimension num_features = 1 for s in size: num_features *= s return num_features
至此,我们已经完成了本地环境的搭建,在这里,我想先介绍hexo中常用的命令。 hexo n "文章标题":用于创建新的博文(欲删除文章,直接删除md文件并用下面的命令更新即可)。 hexo s也就是hexo start:hexo会监视文件变动并自动更新,通过所给的地址localhost:4000/就可以直接在本地预览更新后的网站了。这里不需要generate,保存修改后的本地文件后可以直接看到效果。 部署到远端服务器三步曲:
1 2 3
hexo clean #清除缓存,网页正常情况下可以忽略此条命令,执行该指令后,会删掉站点根目录下的public文件夹。 hexo g #generate静态网页(静态网页这里指没有前端后端的网页而不是静止),该命令把md编译为html并存到public文件目录下。 hexo d #将本地的更改部署到远端服务器(需要一点时间,请过一会再刷新网页)。
此外,上面最后两步也可以使用hexo g -d直接代替。 如果出现ERROR Deployer not found: git报错,可以使用npm install --save hexo-deployer-git命令解决。
至此,我们已经完成了本地环境的搭建,在这里,我想先介绍hexo中常用的命令。 hexo n "文章标题":用于创建新的博文(欲删除文章,直接删除md文件并用下面的命令更新即可)。 hexo s也就是hexo start:hexo会监视文件变动并自动更新,通过所给的地址localhost:4000/就可以直接在本地预览更新后的网站了。这里不需要generate,保存修改后的本地文件后可以直接看到效果。 部署到远端服务器三步曲:
1 2 3
hexo clean #清除缓存,网页正常情况下可以忽略此条命令,执行该指令后,会删掉站点根目录下的public文件夹。 hexo g #generate静态网页(静态网页这里指没有前端后端的网页而不是静止),该命令把md编译为html并存到public文件目录下。 hexo d #将本地的更改部署到远端服务器(需要一点时间,请过一会再刷新网页)。
此外,上面最后两步也可以使用hexo g -d直接代替。 如果出现ERROR Deployer not found: git报错,可以使用npm install --save hexo-deployer-git命令解决。
在Visual Object Tracking using Adaptive Correlation Filters一文中,我看到这样一句话:“The Peak-to-Sidelobe Ratio(PSR), which measures the strength of a correlation peak, can be used to detect occlusions or tracking failure, to stop the online update, and to reacquire the track if the object reappears with a similar appearance.”其大意为:用来衡量相关峰值强度的Peak-to-Sidelobe Ratio可以用于检测遮挡或者跟踪失误、停止实时更新和在相似外观再次出现时重新获取跟踪路径。我读完在想:这个PSR是什么?这么有用。结果百度了半天翻了几页没发现有任何有关它介绍或者解释的文章。于是看了一些英文文献,将自己的一些浅见写下来。
参考文献: [1]Understanding and Diagnosing Visual Tracking Systems [2]Visual Object Tracking using Adaptive Correlation Filters [3]Adaptive Model Update via Fusing Peak-to-sidelobe Ratio and Mean Frame Difference for Visual Tracking [4]Multi-Cue Correlation Filters for Robust Visual Tracking
What
由于没有找到任何中文翻译,我只能取一个相近的(感觉指的差不多)。在百度百科中,我找到了如下解释:PSLR,峰值旁瓣比,peak side lobe ratio,定义为主瓣峰值强度对于最强旁瓣的峰值强度之比,多用于雷达信号脉冲压缩后对信号的评估。
注意:百度百科内的名词与我遇到的相差了一个“to”,且缩写也不同。
上面是百度百科内的一个配图,根据百科解释,最高的主瓣与第二高的主瓣之差,即是PLSR(峰值旁瓣比),在这里大小为-13.4dB。 此外,我还找到了一个称为峰均比(PAPR,peak-to-average power ratio)的概念,它等于波形的振幅和其有效值(RMS)之比,主要是针对功率的,这里就不细说了。 后来,我在一篇光学期刊的文章上找到了一个比较可靠的翻译,该文献中有一个名为“峰旁比”的名词,且文献内容与目标追踪相关。因此我暂且称其为峰旁比吧。个人觉得比峰值旁瓣比简洁且好听。
Why
其实中文翻译并不重要,重要的是它的作用。 在查阅文献的过程中,我看到了这样一个公式:
其中$P_{sr}^{t}$是此时第t帧的峰旁比,$f_{t}$是对于第t帧分类器预测的响应,$\mu _{t}$和$\sigma _{t}$分别是响应图$f$的均值和方差。 根据这种计算方法,我们可以大概分析一下峰旁比的作用。当初看到时,我觉得它与我在物理实验中做过的音叉共振实验中的品质因数有相似之处(品质因数$Q=\frac{f_{0}}{f_{2}-f_{1}}$)。 由公式可知,当响应中的峰值较高,且响应分布相对而言集中在峰值及周围时,峰旁比就会较高;反之,峰旁比就会较低。 那么什么时候会造成峰旁比较低呢?根据论文描述可以获得提示,当遇到遮挡,或者目标跟丢即响应区内不含目标主体时,就不会出现一个那么明显的峰值响应,同时响应也会较为分散了,此时分母较大、分子较小,峰旁比就会变低。 下面也是Visual Object Tracking using Adaptive Correlation Filters中的一张figure(这篇文章提出了MOSSE),我们需要的是a much stronger peak which translates into less drift and fewer dropped tracks。看了这个想必应该知道峰旁比发挥的作用和大致原因了。
和上面的峰值旁瓣比、峰均比相比较,显然峰旁比的定义能更好地表征响应的集中程度。
How
由峰旁比定义所得出的性质可知,峰旁比可以作为模型预测定位准确性和可信度的判据。我们可以利用峰旁比来调整Model Updater(The model updater controls the strategy and frequency of updating the observation model. It has to strike a balance between model adaptation and drift.) 我的想法是,我们可以设置一个threshold,当峰旁比小于这个threshold时,表示模型未能准确定位到目标(可信度较低),这时我们可以停止模型的更新,或者通过减小学习率等方法减慢模型的更新速度以防止模型受背景或者遮挡物较大影响,而当目标再次出现时难以复原导致最终完全跟丢的问题;而当峰旁比大于这个threshold时,我们可以实时更新模型,或者运用较大的学习率(也可以根据峰旁比将学习率划分成几个等级)。
在Visual Object Tracking using Adaptive Correlation Filters一文中,我看到这样一句话:“The Peak-to-Sidelobe Ratio(PSR), which measures the strength of a correlation peak, can be used to detect occlusions or tracking failure, to stop the online update, and to reacquire the track if the object reappears with a similar appearance.”其大意为:用来衡量相关峰值强度的Peak-to-Sidelobe Ratio可以用于检测遮挡或者跟踪失误、停止实时更新和在相似外观再次出现时重新获取跟踪路径。我读完在想:这个PSR是什么?这么有用。结果百度了半天翻了几页没发现有任何有关它介绍或者解释的文章。于是看了一些英文文献,将自己的一些浅见写下来。
参考文献: [1]Understanding and Diagnosing Visual Tracking Systems [2]Visual Object Tracking using Adaptive Correlation Filters [3]Adaptive Model Update via Fusing Peak-to-sidelobe Ratio and Mean Frame Difference for Visual Tracking [4]Multi-Cue Correlation Filters for Robust Visual Tracking
What
由于没有找到任何中文翻译,我只能取一个相近的(感觉指的差不多)。在百度百科中,我找到了如下解释:PSLR,峰值旁瓣比,peak side lobe ratio,定义为主瓣峰值强度对于最强旁瓣的峰值强度之比,多用于雷达信号脉冲压缩后对信号的评估。
注意:百度百科内的名词与我遇到的相差了一个“to”,且缩写也不同。
上面是百度百科内的一个配图,根据百科解释,最高的主瓣与第二高的主瓣之差,即是PLSR(峰值旁瓣比),在这里大小为-13.4dB。 此外,我还找到了一个称为峰均比(PAPR,peak-to-average power ratio)的概念,它等于波形的振幅和其有效值(RMS)之比,主要是针对功率的,这里就不细说了。 后来,我在一篇光学期刊的文章上找到了一个比较可靠的翻译,该文献中有一个名为“峰旁比”的名词,且文献内容与目标追踪相关。因此我暂且称其为峰旁比吧。个人觉得比峰值旁瓣比简洁且好听。
Why
其实中文翻译并不重要,重要的是它的作用。 在查阅文献的过程中,我看到了这样一个公式:
其中$P_{sr}^{t}$是此时第t帧的峰旁比,$f_{t}$是对于第t帧分类器预测的响应,$\mu _{t}$和$\sigma _{t}$分别是响应图$f$的均值和方差。 根据这种计算方法,我们可以大概分析一下峰旁比的作用。当初看到时,我觉得它与我在物理实验中做过的音叉共振实验中的品质因数有相似之处(品质因数$Q=\frac{f_{0}}{f_{2}-f_{1}}$)。 由公式可知,当响应中的峰值较高,且响应分布相对而言集中在峰值及周围时,峰旁比就会较高;反之,峰旁比就会较低。 那么什么时候会造成峰旁比较低呢?根据论文描述可以获得提示,当遇到遮挡,或者目标跟丢即响应区内不含目标主体时,就不会出现一个那么明显的峰值响应,同时响应也会较为分散了,此时分母较大、分子较小,峰旁比就会变低。 下面也是Visual Object Tracking using Adaptive Correlation Filters中的一张figure(这篇文章提出了MOSSE),我们需要的是a much stronger peak which translates into less drift and fewer dropped tracks。看了这个想必应该知道峰旁比发挥的作用和大致原因了。
和上面的峰值旁瓣比、峰均比相比较,显然峰旁比的定义能更好地表征响应的集中程度。
How
由峰旁比定义所得出的性质可知,峰旁比可以作为模型预测定位准确性和可信度的判据。我们可以利用峰旁比来调整Model Updater(The model updater controls the strategy and frequency of updating the observation model. It has to strike a balance between model adaptation and drift.) 我的想法是,我们可以设置一个threshold,当峰旁比小于这个threshold时,表示模型未能准确定位到目标(可信度较低),这时我们可以停止模型的更新,或者通过减小学习率等方法减慢模型的更新速度以防止模型受背景或者遮挡物较大影响,而当目标再次出现时难以复原导致最终完全跟丢的问题;而当峰旁比大于这个threshold时,我们可以实时更新模型,或者运用较大的学习率(也可以根据峰旁比将学习率划分成几个等级)。
HOG(Histogram of Oriented Gradient),中文译为方向梯度直方图。它是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子,通过计算像局部区域中不同方向上梯度的值,然后进行累积,得到代表这块区域特征的直方图,可将其输入到分类器里面进行目标检测。 下面是论文中所呈现的进行人物检测时所采用的特征提取与目标检测的流程,本文将主要分析特征提取的部分(论文中对运用SVM分类器做检测的部分分析甚少,因此不做重点)。
或许会发现本文中好多的图例都用了同一位女士的脸,这里就扯点题外话。 照片中的女子名为Lena Soderberg,对计算机视觉领域有一定的接触的朋友应该对这张照片不会陌生。这张照片是标准的数字图像处理用例,各种算法研究经常会使用这张图作为模板。那为什么要用这幅图呢? David C. Munson在“A Note on Lena”中给出了两条理由:
HOG(Histogram of Oriented Gradient),中文译为方向梯度直方图。它是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子,通过计算像局部区域中不同方向上梯度的值,然后进行累积,得到代表这块区域特征的直方图,可将其输入到分类器里面进行目标检测。 下面是论文中所呈现的进行人物检测时所采用的特征提取与目标检测的流程,本文将主要分析特征提取的部分(论文中对运用SVM分类器做检测的部分分析甚少,因此不做重点)。
或许会发现本文中好多的图例都用了同一位女士的脸,这里就扯点题外话。 照片中的女子名为Lena Soderberg,对计算机视觉领域有一定的接触的朋友应该对这张照片不会陌生。这张照片是标准的数字图像处理用例,各种算法研究经常会使用这张图作为模板。那为什么要用这幅图呢? David C. Munson在“A Note on Lena”中给出了两条理由:
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters [2]Visual Object Tracking using Adaptive Correlation Filters [3]Exploiting the Circulant Structure of Tracking-by-detection with Kernels
在论文High-Speed Tracking with Kernelized Correlation Filters的introduction部分,有这样一句话:“we argue that undersampling negatives is the main factor inhibiting performance in tracking.”也就是说,负样本的欠采样是阻碍跟踪效果的主要因素。这在之前的文章中介绍过,这里就不在细述了。 这句话主要针对的问题是我们可以从一张图像中获得几乎无限的负样本。但由于跟踪的时间敏感性,我们的跟踪算法只能在尽可能多地采集样本和维持较低的计算需求之间取得一个平衡。之前通常的做法是从每一帧中随机选择几个样本。 KCF的一大贡献就是采用了一种更方便的方法迅速获取更多的负样本,以便于能够训练出一个更好的分类器。作者发现,在傅里叶域中,如果我们使用特定的模型进行转换,一些学习算法实际上变得更容易(in the Fourier domain, some learning algorithms actually become easier as we add more samples, if we use a specific model for translations)。 具体的做法如下,首先利用一个n维列向量来表示目标,记为$x$,然后利用$x$和一个循环移位矩阵$P$生成一个循环矩阵,其目的是使用一个base sample(正样本)和生成多个虚拟样本(负样本)来训练一个分类器。
获得了这样一个循环矩阵之后,作者接下来说:“all circulant matrices are made diagonal by the Discrete Fourier Transform(DFT), regardless of the generating vector x.”就是说循环矩阵的生成向量是完全指定的,且循环矩阵有一个非常好的性质:对任意生成向量$\widehat{x}$,我们都可以通过离散傅立叶变换(具有线性性)对循环矩阵进行对角化表示。
这个y是高斯加权后的值。初始目标的位置在padding后的search window的中心,循环移位得到的多个样本反应的是背景信息,而且离中心越远,就越不是目标,所以我们对标签进行高斯加权就刚好可以体现这种可能性准则。KCF里的输出是一个二维response矩阵,里面元素的大小代表该位置下的目标为预测目标的可能性,因此,在训练的时候就是输入是特征,而输出是一个gaussian_shaped_label,一般分类的标签是二值的,或者多值离散的,但是这个高斯标签反应的是由初始目标移位采样形成的若干样本距离初识样本越近可能性越大的准则,在代码中,高斯的峰值被移动到了左上角(于是四个角的值偏大),原因在论文的附录中进行了解释:“after computing a cross-correlation between two images in the Fourier domain and converting back to the spatial domain, it is the top-left element of the result that corresponds to a shift of zero”,也就是说目标零位移对应的是左上角的值。这样一来,我们在预测目标位置的时候,只需要pos=pos+find(response==max(response(:)))就好。如果把峰值放在中心点的话,就会“unnecessarily cause the detection output to be shifted by half a window”。
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters [2]Visual Object Tracking using Adaptive Correlation Filters [3]Exploiting the Circulant Structure of Tracking-by-detection with Kernels
在论文High-Speed Tracking with Kernelized Correlation Filters的introduction部分,有这样一句话:“we argue that undersampling negatives is the main factor inhibiting performance in tracking.”也就是说,负样本的欠采样是阻碍跟踪效果的主要因素。这在之前的文章中介绍过,这里就不在细述了。 这句话主要针对的问题是我们可以从一张图像中获得几乎无限的负样本。但由于跟踪的时间敏感性,我们的跟踪算法只能在尽可能多地采集样本和维持较低的计算需求之间取得一个平衡。之前通常的做法是从每一帧中随机选择几个样本。 KCF的一大贡献就是采用了一种更方便的方法迅速获取更多的负样本,以便于能够训练出一个更好的分类器。作者发现,在傅里叶域中,如果我们使用特定的模型进行转换,一些学习算法实际上变得更容易(in the Fourier domain, some learning algorithms actually become easier as we add more samples, if we use a specific model for translations)。 具体的做法如下,首先利用一个n维列向量来表示目标,记为$x$,然后利用$x$和一个循环移位矩阵$P$生成一个循环矩阵,其目的是使用一个base sample(正样本)和生成多个虚拟样本(负样本)来训练一个分类器。
获得了这样一个循环矩阵之后,作者接下来说:“all circulant matrices are made diagonal by the Discrete Fourier Transform(DFT), regardless of the generating vector x.”就是说循环矩阵的生成向量是完全指定的,且循环矩阵有一个非常好的性质:对任意生成向量$\widehat{x}$,我们都可以通过离散傅立叶变换(具有线性性)对循环矩阵进行对角化表示。
这个y是高斯加权后的值。初始目标的位置在padding后的search window的中心,循环移位得到的多个样本反应的是背景信息,而且离中心越远,就越不是目标,所以我们对标签进行高斯加权就刚好可以体现这种可能性准则。KCF里的输出是一个二维response矩阵,里面元素的大小代表该位置下的目标为预测目标的可能性,因此,在训练的时候就是输入是特征,而输出是一个gaussian_shaped_label,一般分类的标签是二值的,或者多值离散的,但是这个高斯标签反应的是由初始目标移位采样形成的若干样本距离初识样本越近可能性越大的准则,在代码中,高斯的峰值被移动到了左上角(于是四个角的值偏大),原因在论文的附录中进行了解释:“after computing a cross-correlation between two images in the Fourier domain and converting back to the spatial domain, it is the top-left element of the result that corresponds to a shift of zero”,也就是说目标零位移对应的是左上角的值。这样一来,我们在预测目标位置的时候,只需要pos=pos+find(response==max(response(:)))就好。如果把峰值放在中心点的话,就会“unnecessarily cause the detection output to be shifted by half a window”。
因此我们需要学习的是$d_{x}\left ( A \right )$,$d_{y}\left ( A \right )$,$d_{w}\left ( A \right )$,$d_{h}\left ( A \right )$这四个变换。当输入的A与GT相差较小时,可以认为这种变换是一种线性变换,那么就可以用线性回归来进行微调。
因此我们需要学习的是$d_{x}\left ( A \right )$,$d_{y}\left ( A \right )$,$d_{w}\left ( A \right )$,$d_{h}\left ( A \right )$这四个变换。当输入的A与GT相差较小时,可以认为这种变换是一种线性变换,那么就可以用线性回归来进行微调。
善于承认不足是一种良好的品质,作者在文中也来了这样一个转折:“However, it often diverges on longer sequences or the sequences that have very small frame-to-frame variations.”意思是说这种方法在长序列或者目标在帧与帧之间变化不大时表现不佳(会偏离目标)。 回顾一下,当初设计这种方法的目的是模型在接收第一帧之后能够很快地收敛到精度和鲁棒性很好的一组参数位置,这就是说,我们训练得到的$\alpha $相对来说是比较大的,这就导致了它在上述情况下的不稳定。 为此,作者的解决办法是“find a learning rate for subsequent frames and then use existing optimization algorithms to update the models as was done in the original versions of the trackers”,也就是仅用学习到的$\theta _{0}$和$\alpha $来做初始化,然后在随后的在线更新过程中,仍用原来版本的方式进行更新。这里原来的版本指的是CREST和MDNet,作者在这两个tracker的基础上改进出了MetaCREST和MetaSDNet,下面接着讲。
自己接触元学习的相关算法之后,总想着直接套用到别的任务上去。这篇论文和我的想法有点类似,但作者在实际实现时肯定用了更多的方法来解决各种各样的难题。而这篇文章也只能说是用元学习的思想做了一些探索,引用作者的一部分总结: “Other than target appearance modeling, which is the focus of this paper, there are many other important factors in object tracking algorithms. For example, when or how often to update the model, how to manage the database, and how to define the search space. These considerations are sometimes more important than target appearance modeling. In future work we propose including handling of these as part of learning and meta-learning.” 总而言之,还有很长的路要走~
善于承认不足是一种良好的品质,作者在文中也来了这样一个转折:“However, it often diverges on longer sequences or the sequences that have very small frame-to-frame variations.”意思是说这种方法在长序列或者目标在帧与帧之间变化不大时表现不佳(会偏离目标)。 回顾一下,当初设计这种方法的目的是模型在接收第一帧之后能够很快地收敛到精度和鲁棒性很好的一组参数位置,这就是说,我们训练得到的$\alpha $相对来说是比较大的,这就导致了它在上述情况下的不稳定。 为此,作者的解决办法是“find a learning rate for subsequent frames and then use existing optimization algorithms to update the models as was done in the original versions of the trackers”,也就是仅用学习到的$\theta _{0}$和$\alpha $来做初始化,然后在随后的在线更新过程中,仍用原来版本的方式进行更新。这里原来的版本指的是CREST和MDNet,作者在这两个tracker的基础上改进出了MetaCREST和MetaSDNet,下面接着讲。
自己接触元学习的相关算法之后,总想着直接套用到别的任务上去。这篇论文和我的想法有点类似,但作者在实际实现时肯定用了更多的方法来解决各种各样的难题。而这篇文章也只能说是用元学习的思想做了一些探索,引用作者的一部分总结: “Other than target appearance modeling, which is the focus of this paper, there are many other important factors in object tracking algorithms. For example, when or how often to update the model, how to manage the database, and how to define the search space. These considerations are sometimes more important than target appearance modeling. In future work we propose including handling of these as part of learning and meta-learning.” 总而言之,还有很长的路要走~
Condensation(Conditional density propagation)条件密度传播使用了原始的外观作为主要特征来描述目标,采用了粒子滤波,这是一种非参数化滤波方法,属于生成式模型。它定义了一个粒子样本集,该样本集描述了每个粒子的坐标、运动速度、高和宽、尺度变化等状态;此外,通过一个状态转移矩阵和噪声定义系统状态方程。基于蒙特卡洛方法,粒子滤波将贝叶斯滤波方法中的积分运算转化为粒子采样求样本均值问题,通过对状态空间的粒子的随机采样来近似求解后验概率。
2002
Mean Shift
Mean Shift采用均值漂移作为搜索策略,这是一种无参概率估计方法,该方法利用图像特征直方图构造空间平滑的概率密度函数,通过沿着概率密度函数的梯度方向迭代,搜索函数局部最大值。在当时成为了常用的视觉跟踪系统的目标搜索方法,简单易实现,但鲁棒性较低。
MOSSE(Minimum Output Sum of Squared Error)使用相关滤波来做目标跟踪(不是第一个,但可以看作前期的一个代表),其速度能够达到600多帧每秒,但是效果一般,这主要是因为它只使用了简单的raw pixel特征。 相比之前的算法,MOSSE能够形成更加明确的峰值,减少了漂移;此外,MOSSE可以在线更新,同时还采用了PSR来检测遮挡或者跟丢的情况,从而决定是否需要停止更新。 值得一提的是,MOSSE在做相关操作之前,对每张图都进行了减去平均值的处理,这有利于淡化背景对相关操作的影响。另外假如发生光照变化的话,减去均值也有利于减小这种变化的影响。此外要注意,输出的特征应乘以汉宁窗(一种余弦窗),用于确定搜索区域(也就是不为0的区域),且有利于突出中心的特征。
Condensation(Conditional density propagation)条件密度传播使用了原始的外观作为主要特征来描述目标,采用了粒子滤波,这是一种非参数化滤波方法,属于生成式模型。它定义了一个粒子样本集,该样本集描述了每个粒子的坐标、运动速度、高和宽、尺度变化等状态;此外,通过一个状态转移矩阵和噪声定义系统状态方程。基于蒙特卡洛方法,粒子滤波将贝叶斯滤波方法中的积分运算转化为粒子采样求样本均值问题,通过对状态空间的粒子的随机采样来近似求解后验概率。
2002
Mean Shift
Mean Shift采用均值漂移作为搜索策略,这是一种无参概率估计方法,该方法利用图像特征直方图构造空间平滑的概率密度函数,通过沿着概率密度函数的梯度方向迭代,搜索函数局部最大值。在当时成为了常用的视觉跟踪系统的目标搜索方法,简单易实现,但鲁棒性较低。
MOSSE(Minimum Output Sum of Squared Error)使用相关滤波来做目标跟踪(不是第一个,但可以看作前期的一个代表),其速度能够达到600多帧每秒,但是效果一般,这主要是因为它只使用了简单的raw pixel特征。 相比之前的算法,MOSSE能够形成更加明确的峰值,减少了漂移;此外,MOSSE可以在线更新,同时还采用了PSR来检测遮挡或者跟丢的情况,从而决定是否需要停止更新。 值得一提的是,MOSSE在做相关操作之前,对每张图都进行了减去平均值的处理,这有利于淡化背景对相关操作的影响。另外假如发生光照变化的话,减去均值也有利于减小这种变化的影响。此外要注意,输出的特征应乘以汉宁窗(一种余弦窗),用于确定搜索区域(也就是不为0的区域),且有利于突出中心的特征。
defforward(self, x): x = F.relu(self.conv1_1(x)) x = F.relu(self.conv1_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) #输入x经过卷积之后,经过激活函数ReLU,循环两次,最后使用2x2的窗口进行最大池化Max pooling,然后更新到x x = F.relu(self.conv2_1(x)) x = F.relu(self.conv2_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv3_1(x)) x = F.relu(self.conv3_2(x)) x = F.relu(self.conv3_3(x)) x = F.relu(self.conv3_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv4_1(x)) x = F.relu(self.conv4_2(x)) x = F.relu(self.conv4_3(x)) x = F.relu(self.conv4_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv5_1(x)) x = F.relu(self.conv5_2(x)) x = F.relu(self.conv5_3(x)) x = F.relu(self.conv5_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = x.view(-1, self.num_flat_features(x)) #view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备 x = self.fc1(x) #输入x经过全连接1,然后更新x x = self.fc2(x) x = self.fc3(x) return x
defnum_flat_features(self, x): size = x.size()[1:] #all dimensions except the batch dimension num_features = 1 for s in size: num_features *= s return num_features
defforward(self, x): x = F.relu(self.conv1_1(x)) x = F.relu(self.conv1_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) #输入x经过卷积之后,经过激活函数ReLU,循环两次,最后使用2x2的窗口进行最大池化Max pooling,然后更新到x x = F.relu(self.conv2_1(x)) x = F.relu(self.conv2_2(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv3_1(x)) x = F.relu(self.conv3_2(x)) x = F.relu(self.conv3_3(x)) x = F.relu(self.conv3_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv4_1(x)) x = F.relu(self.conv4_2(x)) x = F.relu(self.conv4_3(x)) x = F.relu(self.conv4_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = F.relu(self.conv5_1(x)) x = F.relu(self.conv5_2(x)) x = F.relu(self.conv5_3(x)) x = F.relu(self.conv5_4(x)) x = F.max_pool2d(x, kernel_size = 2, stride = 2) x = x.view(-1, self.num_flat_features(x)) #view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备 x = self.fc1(x) #输入x经过全连接1,然后更新x x = self.fc2(x) x = self.fc3(x) return x
defnum_flat_features(self, x): size = x.size()[1:] #all dimensions except the batch dimension num_features = 1 for s in size: num_features *= s return num_features
下面奉上宝贵的论文: 论文原版 论文中文版 从introduction第一句开始,作者就开始了一段长长的吐槽: Current approaches to object recognition make essential use of machine learning methods… 吐槽Yann LeCun大佬的论文被顶会拒收了仅仅因为Yann LeCun使用了神经网络。其实,那段时间之前,由于SVM等机器学习方法的兴起,神经网络是一种被许多ML大佬们看不起的算法模型。 在introduction的最后,作者留下了这样一句经典的话: All of our experiments suggest that our results can be improved simply by waiting for faster GPUs and bigger datasets to become available. 有没有感觉到一种新世界大门被打开的感觉呢? 有关论文别的内容,我暂不多说了,大家可以自己看论文学习与体会。 附上推荐重点阅读的章节:3.1 ReLU Nonlinearity;3.5 Overall Architecture;4 Reducing Overfitting。
下面奉上宝贵的论文: 论文原版 论文中文版 从introduction第一句开始,作者就开始了一段长长的吐槽: Current approaches to object recognition make essential use of machine learning methods… 吐槽Yann LeCun大佬的论文被顶会拒收了仅仅因为Yann LeCun使用了神经网络。其实,那段时间之前,由于SVM等机器学习方法的兴起,神经网络是一种被许多ML大佬们看不起的算法模型。 在introduction的最后,作者留下了这样一句经典的话: All of our experiments suggest that our results can be improved simply by waiting for faster GPUs and bigger datasets to become available. 有没有感觉到一种新世界大门被打开的感觉呢? 有关论文别的内容,我暂不多说了,大家可以自己看论文学习与体会。 附上推荐重点阅读的章节:3.1 ReLU Nonlinearity;3.5 Overall Architecture;4 Reducing Overfitting。
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) for epoch in range(100): if epoch % 5 == 0: for p in optimizer.param_groups: p['lr'] *= 0.9#学习率超参的位置:optimizer.state_dict()['param_groups'][0]['lr']
这里是每过5个epoch就进行一次衰减。
lambda自定义衰减
1 2 3 4 5 6 7 8
import numpy as np model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) lambda1 = lambda epoch: np.sin(epoch) / epoch scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda = lambda1) for epoch in range(100): scheduler.step()
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ExponentialLR(optimizer, gamma = 0.9) for epoch in range(100): scheduler.step()
这种方法就是在每个epoch中lr都乘以gamma,从而达到连续衰减的效果。
余弦式调整
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max = 20) for epoch in range(100): scheduler.step()
这里的T_max对应1/2个cos周期所对应的epoch数值。
基于loss和accuracy
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode = 'min', factor = 0.1, patience = 10, verbose = False, threshold = 0.0001, threshold_mode = 'rel', cooldown = 0, min_lr = 0, eps = 1e-08) for epoch in range(100): scheduler.step()
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) for epoch in range(100): if epoch % 5 == 0: for p in optimizer.param_groups: p['lr'] *= 0.9#学习率超参的位置:optimizer.state_dict()['param_groups'][0]['lr']
这里是每过5个epoch就进行一次衰减。
lambda自定义衰减
1 2 3 4 5 6 7 8
import numpy as np model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) lambda1 = lambda epoch: np.sin(epoch) / epoch scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda = lambda1) for epoch in range(100): scheduler.step()
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ExponentialLR(optimizer, gamma = 0.9) for epoch in range(100): scheduler.step()
这种方法就是在每个epoch中lr都乘以gamma,从而达到连续衰减的效果。
余弦式调整
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max = 20) for epoch in range(100): scheduler.step()
这里的T_max对应1/2个cos周期所对应的epoch数值。
基于loss和accuracy
1 2 3 4 5 6
model = net() LR = 0.01 optimizer = Adam(model.parameters(), lr = LR) scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode = 'min', factor = 0.1, patience = 10, verbose = False, threshold = 0.0001, threshold_mode = 'rel', cooldown = 0, min_lr = 0, eps = 1e-08) for epoch in range(100): scheduler.step()
self.inplanes = 64 self.dilation = 1 if replace_stride_with_dilation isNone: # each element in the tuple indicates if we should replace # the 2x2 stride with a dilated convolution instead replace_stride_with_dilation = [False, False, False] if len(replace_stride_with_dilation) != 3: raise ValueError("replace_stride_with_dilation should be None " "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) self.groups = groups self.base_width = width_per_group self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = norm_layer(self.inplanes) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2, dilate=replace_stride_with_dilation[0]) self.layer3 = self._make_layer(block, 256, layers[2], stride=2, dilate=replace_stride_with_dilation[1]) self.layer4 = self._make_layer(block, 512, layers[3], stride=2, dilate=replace_stride_with_dilation[2]) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0)
# Zero-initialize the last BN in each residual branch, # so that the residual branch starts with zeros, and each residual block behaves like an identity. # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 if zero_init_residual: for m in self.modules(): if isinstance(m, Bottleneck): nn.init.constant_(m.bn3.weight, 0) elif isinstance(m, BasicBlock): nn.init.constant_(m.bn2.weight, 0)
defforward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x)
x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x)
x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x)
return x
def_resnet(arch, block, layers, pretrained, progress, **kwargs): model = ResNet(block, layers, **kwargs) if pretrained: state_dict = load_state_dict_from_url(model_urls[arch], progress=progress) model.load_state_dict(state_dict) return model
defresnet18(pretrained=False, progress=True, **kwargs): r"""ResNet-18 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
defresnet34(pretrained=False, progress=True, **kwargs): r"""ResNet-34 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet50(pretrained=False, progress=True, **kwargs): r"""ResNet-50 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet101(pretrained=False, progress=True, **kwargs): r"""ResNet-101 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defresnet152(pretrained=False, progress=True, **kwargs): r"""ResNet-152 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
defresnext50_32x4d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-50 32x4d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 4 return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnext101_32x8d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-101 32x8d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 8 return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defwide_resnet50_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-50-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defwide_resnet101_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-101-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
self.inplanes = 64 self.dilation = 1 if replace_stride_with_dilation isNone: # each element in the tuple indicates if we should replace # the 2x2 stride with a dilated convolution instead replace_stride_with_dilation = [False, False, False] if len(replace_stride_with_dilation) != 3: raise ValueError("replace_stride_with_dilation should be None " "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) self.groups = groups self.base_width = width_per_group self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = norm_layer(self.inplanes) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2, dilate=replace_stride_with_dilation[0]) self.layer3 = self._make_layer(block, 256, layers[2], stride=2, dilate=replace_stride_with_dilation[1]) self.layer4 = self._make_layer(block, 512, layers[3], stride=2, dilate=replace_stride_with_dilation[2]) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0)
# Zero-initialize the last BN in each residual branch, # so that the residual branch starts with zeros, and each residual block behaves like an identity. # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 if zero_init_residual: for m in self.modules(): if isinstance(m, Bottleneck): nn.init.constant_(m.bn3.weight, 0) elif isinstance(m, BasicBlock): nn.init.constant_(m.bn2.weight, 0)
defforward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x)
x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x)
x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x)
return x
def_resnet(arch, block, layers, pretrained, progress, **kwargs): model = ResNet(block, layers, **kwargs) if pretrained: state_dict = load_state_dict_from_url(model_urls[arch], progress=progress) model.load_state_dict(state_dict) return model
defresnet18(pretrained=False, progress=True, **kwargs): r"""ResNet-18 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, **kwargs)
defresnet34(pretrained=False, progress=True, **kwargs): r"""ResNet-34 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet50(pretrained=False, progress=True, **kwargs): r"""ResNet-50 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnet101(pretrained=False, progress=True, **kwargs): r"""ResNet-101 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defresnet152(pretrained=False, progress=True, **kwargs): r"""ResNet-152 model from `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, **kwargs)
defresnext50_32x4d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-50 32x4d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 4 return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defresnext101_32x8d(pretrained=False, progress=True, **kwargs): r"""ResNeXt-101 32x8d model from `"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_ Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['groups'] = 32 kwargs['width_per_group'] = 8 return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
defwide_resnet50_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-50-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], pretrained, progress, **kwargs)
defwide_resnet101_2(pretrained=False, progress=True, **kwargs): r"""Wide ResNet-101-2 model from `"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_ The model is the same as ResNet except for the bottleneck number of channels which is twice larger in every block. The number of channels in outer 1x1 convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 channels, and in Wide ResNet-50-2 has 2048-1024-2048. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet progress (bool): If True, displays a progress bar of the download to stderr """ kwargs['width_per_group'] = 64 * 2 return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], pretrained, progress, **kwargs)
以前觉得深度学习就是有很多层的神经网络,或者周志华提出的深度随机森林,总之只要是有很“深”的结构就是深度学习。直到不久前一位计科大佬告诉我深度学习是end-to-end(也表示成“e2e”)的,当时听的也是一知半解,回去查了一下后终于恍然大悟。本文主要基于Andrew Ng的课程中“What is end-to-end deep learning?”和“Whether to use end-to-end learning?”两节。推荐可以去看一看,讲得可以说是很浅显易懂了。
什么是end-to-end learning
传统机器学习的流程往往由多个独立的模块组成,比如在一个典型的自然语言处理(Natural Language Processing)问题中,包括分词、词性标注、句法分析、语义分析等多个独立步骤,每个步骤是一个独立的任务,其结果的好坏会影响到下一步骤,从而影响整个训练的结果,这就是非端到端的。 而深度学习模型在训练过程中,从输入端(输入数据)到输出端得到一个预测结果,该结果与真实结果相比较会得到一个误差,这个误差将用于模型每一层的调整(比如反向传播),这种训练直到模型收敛或达到预期的效果才结束,这就是端到端(end-to-end)的。
Andrew Ng在视频课程中举了一个例子:百度的门禁系统可以识别靠近的人脸并放行。 如果直接使用端到端学习,那么需要训练的数据集就是一系列照片或者视频,其中人会随机出现在任何位置、任何距离等等,而这样标注好的数据集是很匮乏的。 但是,如果我们把这个任务拆解成两个子任务。首先,在照片或者视频中定位人脸,然后放大(使人脸居中等);其次,对放大好的人脸再进行检验。这两种任务都有非常丰富的数据集或者方法可供使用。实际上,我觉得可以应用两个端到端的模型来解决这两个问题,但合起来就不是端到端的了。但在目前现有数据量的情况下,这依然能比直接端到端的方法表现得好。
以前觉得深度学习就是有很多层的神经网络,或者周志华提出的深度随机森林,总之只要是有很“深”的结构就是深度学习。直到不久前一位计科大佬告诉我深度学习是end-to-end(也表示成“e2e”)的,当时听的也是一知半解,回去查了一下后终于恍然大悟。本文主要基于Andrew Ng的课程中“What is end-to-end deep learning?”和“Whether to use end-to-end learning?”两节。推荐可以去看一看,讲得可以说是很浅显易懂了。
什么是end-to-end learning
传统机器学习的流程往往由多个独立的模块组成,比如在一个典型的自然语言处理(Natural Language Processing)问题中,包括分词、词性标注、句法分析、语义分析等多个独立步骤,每个步骤是一个独立的任务,其结果的好坏会影响到下一步骤,从而影响整个训练的结果,这就是非端到端的。 而深度学习模型在训练过程中,从输入端(输入数据)到输出端得到一个预测结果,该结果与真实结果相比较会得到一个误差,这个误差将用于模型每一层的调整(比如反向传播),这种训练直到模型收敛或达到预期的效果才结束,这就是端到端(end-to-end)的。
Andrew Ng在视频课程中举了一个例子:百度的门禁系统可以识别靠近的人脸并放行。 如果直接使用端到端学习,那么需要训练的数据集就是一系列照片或者视频,其中人会随机出现在任何位置、任何距离等等,而这样标注好的数据集是很匮乏的。 但是,如果我们把这个任务拆解成两个子任务。首先,在照片或者视频中定位人脸,然后放大(使人脸居中等);其次,对放大好的人脸再进行检验。这两种任务都有非常丰富的数据集或者方法可供使用。实际上,我觉得可以应用两个端到端的模型来解决这两个问题,但合起来就不是端到端的了。但在目前现有数据量的情况下,这依然能比直接端到端的方法表现得好。
这里摘录上面参考资料中的一段话,我觉得说得很明白了。 Using a network trained on one dataset on a different problem is possible because neural networks exhibit “transfer learning”. The first few layers of the network learn to detect general features such as edges and color blobs that are good discriminating features across many different problems. The features learnt by the later layers are higher level, more problem specific features. These layers can either be removed or the weights for these layers can be fine-tuned during back-propagation.
这里摘录上面参考资料中的一段话,我觉得说得很明白了。 Using a network trained on one dataset on a different problem is possible because neural networks exhibit “transfer learning”. The first few layers of the network learn to detect general features such as edges and color blobs that are good discriminating features across many different problems. The features learnt by the later layers are higher level, more problem specific features. These layers can either be removed or the weights for these layers can be fine-tuned during back-propagation.
既然Meta Learning的目的是实现快速学习,而快速学习的关键就是神经网络的梯度下降要准且快,那么是否可以让神经网络利用以往的任务学习如何预测梯度,这样面对新的任务,只要梯度预测得准,那么学习得就会更快。 在Learning to Learn by Gradient Descent by Gradient Descent一文中(好好品味这个题目),作者提出了这样一种方法,即训练一个通用的神经网络来预测梯度,用一次二次方程的回归问题来训练,这种方法得到的神经网络优化算法比Adam、RMSProp还要好。
学习记忆的学习
元学习其实也可以利用以往的经验来学习,于是这又诞生了一系列模型。
记忆增强神经网络
一般的神经网络不具有记忆功能,输出的结果只基于当前的输入。而LSTM网络的出现则让网络有了记忆,它能够根据之前的输入给出当前的输出。但是,LSTM的记忆程度并不是那么理想,对于比较长的输入序列,LSTM的最终输出只与最后的几步输入有关,也就是long dependency问题,当然这个问题可以由注意力机制解决,然而还是不能从根本上解决长期记忆的问题,原因是由于LSTM是假设在时间序列上的输入输出:由t-1时刻得到t时刻的输出,然后再循环输入t时刻的结果得到t+1时刻的输出,这样势必会使处于前面序列的输入被淹没,导致这部分记忆被“丢掉”。 基于以上问题,研究者们提出了神经图灵机等记忆增强神经网络模型。我们知道,人除了用脑子记,还会使用做笔记等方式做辅助,当我们忘记时,我们可以去看笔记来获得相关的记忆。记忆增强神经网络的思想就是如此,它让所有的笔记的“读”“写”操作都可微分化,因此可以用神经网络误差后向传播的方式去训练模型。 在记忆增强神经网络中,我们引入外部存储器来存储样本表示和类标签信息。以Meta-Learning with Memory-augmented Neural Networks这篇文章为例,我们看一下它的网络结构。
那么,我们之前让机器learn,现在想办法让机器learn to learn,那之后是不是还要learn to learn to learn再learn to learn to learn to learn呢?哈哈套娃警告。 难以想象未来的机器会是怎么样的,如此智能真的有点细思极恐呢。话说回来,Meta Learning方兴未艾,各种神奇的idea层出不穷,但是真正的杀手级算法尚未出现,让我们拭目以待!
既然Meta Learning的目的是实现快速学习,而快速学习的关键就是神经网络的梯度下降要准且快,那么是否可以让神经网络利用以往的任务学习如何预测梯度,这样面对新的任务,只要梯度预测得准,那么学习得就会更快。 在Learning to Learn by Gradient Descent by Gradient Descent一文中(好好品味这个题目),作者提出了这样一种方法,即训练一个通用的神经网络来预测梯度,用一次二次方程的回归问题来训练,这种方法得到的神经网络优化算法比Adam、RMSProp还要好。
学习记忆的学习
元学习其实也可以利用以往的经验来学习,于是这又诞生了一系列模型。
记忆增强神经网络
一般的神经网络不具有记忆功能,输出的结果只基于当前的输入。而LSTM网络的出现则让网络有了记忆,它能够根据之前的输入给出当前的输出。但是,LSTM的记忆程度并不是那么理想,对于比较长的输入序列,LSTM的最终输出只与最后的几步输入有关,也就是long dependency问题,当然这个问题可以由注意力机制解决,然而还是不能从根本上解决长期记忆的问题,原因是由于LSTM是假设在时间序列上的输入输出:由t-1时刻得到t时刻的输出,然后再循环输入t时刻的结果得到t+1时刻的输出,这样势必会使处于前面序列的输入被淹没,导致这部分记忆被“丢掉”。 基于以上问题,研究者们提出了神经图灵机等记忆增强神经网络模型。我们知道,人除了用脑子记,还会使用做笔记等方式做辅助,当我们忘记时,我们可以去看笔记来获得相关的记忆。记忆增强神经网络的思想就是如此,它让所有的笔记的“读”“写”操作都可微分化,因此可以用神经网络误差后向传播的方式去训练模型。 在记忆增强神经网络中,我们引入外部存储器来存储样本表示和类标签信息。以Meta-Learning with Memory-augmented Neural Networks这篇文章为例,我们看一下它的网络结构。
那么,我们之前让机器learn,现在想办法让机器learn to learn,那之后是不是还要learn to learn to learn再learn to learn to learn to learn呢?哈哈套娃警告。 难以想象未来的机器会是怎么样的,如此智能真的有点细思极恐呢。话说回来,Meta Learning方兴未艾,各种神奇的idea层出不穷,但是真正的杀手级算法尚未出现,让我们拭目以待!
Srivastava等人(2014)提出Dropout,以防止神经网络过拟合。Dropout是一种神经网络模型平均正则化方法,通过增加噪声到其隐藏单元。在训练过程中,它会从神经网络中随机抽取出单元和连接。Dropout可以用于像RBM(Srivastava et al.,2014)这样的图形模型中,也可以用于任何类型的神经网络。最近提出的一个关于Dropout的改进是Fraternal Dropout,用于循环神经网络(RNN)。
Srivastava等人(2014)提出Dropout,以防止神经网络过拟合。Dropout是一种神经网络模型平均正则化方法,通过增加噪声到其隐藏单元。在训练过程中,它会从神经网络中随机抽取出单元和连接。Dropout可以用于像RBM(Srivastava et al.,2014)这样的图形模型中,也可以用于任何类型的神经网络。最近提出的一个关于Dropout的改进是Fraternal Dropout,用于循环神经网络(RNN)。
至此,我们已经完成了本地环境的搭建,在这里,我想先介绍hexo中常用的命令。 hexo n "文章标题":用于创建新的博文(欲删除文章,直接删除md文件并用下面的命令更新即可)。 hexo s也就是hexo start:hexo会监视文件变动并自动更新,通过所给的地址localhost:4000/就可以直接在本地预览更新后的网站了。这里不需要generate,保存修改后的本地文件后可以直接看到效果。 部署到远端服务器三步曲:
1 2 3
hexo clean #清除缓存,网页正常情况下可以忽略此条命令,执行该指令后,会删掉站点根目录下的public文件夹。 hexo g #generate静态网页(静态网页这里指没有前端后端的网页而不是静止),该命令把md编译为html并存到public文件目录下。 hexo d #将本地的更改部署到远端服务器(需要一点时间,请过一会再刷新网页)。
此外,上面最后两步也可以使用hexo g -d直接代替。 如果出现ERROR Deployer not found: git报错,可以使用npm install --save hexo-deployer-git命令解决。
至此,我们已经完成了本地环境的搭建,在这里,我想先介绍hexo中常用的命令。 hexo n "文章标题":用于创建新的博文(欲删除文章,直接删除md文件并用下面的命令更新即可)。 hexo s也就是hexo start:hexo会监视文件变动并自动更新,通过所给的地址localhost:4000/就可以直接在本地预览更新后的网站了。这里不需要generate,保存修改后的本地文件后可以直接看到效果。 部署到远端服务器三步曲:
1 2 3
hexo clean #清除缓存,网页正常情况下可以忽略此条命令,执行该指令后,会删掉站点根目录下的public文件夹。 hexo g #generate静态网页(静态网页这里指没有前端后端的网页而不是静止),该命令把md编译为html并存到public文件目录下。 hexo d #将本地的更改部署到远端服务器(需要一点时间,请过一会再刷新网页)。
此外,上面最后两步也可以使用hexo g -d直接代替。 如果出现ERROR Deployer not found: git报错,可以使用npm install --save hexo-deployer-git命令解决。
# Home page setting # path: Root path for your blogs index page. (default = '') # per_page: Posts displayed per page. (0 = disable pagination) # order_by: Posts order. (Order by date descending by default) index_generator: path:'' per_page:10 order_by:-date
<divid="new"></div> <scriptsrc="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script> <script>AV.initialize("YOUR_APPID", "YOUR_APPKEY");</script> <scripttype="text/javascript"> var updatedAt="" var title="" var url="" var query = new AV.Query('Counter'); query.notEqualTo('id',0); query.descending('updatedAt'); query.limit(10); query.find().then(function (todo) { for (var i=0;i<10;i++){ var result=todo[i].attributes; title=result.title; updatedAt=result.updatedAt; url=result.url; var content="<p>"+"<a href='"+"YOUR_URL"+url+"' target='_blank'>"+title+"</a>"+"</p>"; document.getElementById("new").innerHTML+=content } }, function (error) { console.log("error"); }); </script>
# Home page setting # path: Root path for your blogs index page. (default = '') # per_page: Posts displayed per page. (0 = disable pagination) # order_by: Posts order. (Order by date descending by default) index_generator: path:'' per_page:10 order_by:-date
<divid="new"></div> <scriptsrc="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script> <script>AV.initialize("YOUR_APPID", "YOUR_APPKEY");</script> <scripttype="text/javascript"> var updatedAt="" var title="" var url="" var query = new AV.Query('Counter'); query.notEqualTo('id',0); query.descending('updatedAt'); query.limit(10); query.find().then(function (todo) { for (var i=0;i<10;i++){ var result=todo[i].attributes; title=result.title; updatedAt=result.updatedAt; url=result.url; var content="<p>"+"<a href='"+"YOUR_URL"+url+"' target='_blank'>"+title+"</a>"+"</p>"; document.getElementById("new").innerHTML+=content } }, function (error) { console.log("error"); }); </script>
元学习(Meta Learning)即让机器学习如何去学习(learn to learn)。我前几天看到这个概念,觉得非常有意思,这几天也一直在看相关的概念和implement,发现其实很多方法或者思想已经在最新的一些工作中得到有意或者无意运用。因此我决定对我目前的了解做一个总结,或许能给之后的思考 ...
元学习(Meta Learning)即让机器学习如何去学习(learn to learn)。我前几天看到这个概念,觉得非常有意思,这几天也一直在看相关的概念和implement,发现其实很多方法或者思想已经在最新的一些工作中得到有意或者无意运用。因此我决定对我目前的了解做一个总结,或许能给之后的思考 ...
kaggle是一个著名的数据科学竞赛平台,暑假里我也抽空自己独立完成了三四个getting started级别的比赛。对于MNIST数据集,想必入门计算机视觉的人应该也不会陌生。kaggle上getting started的第一个比赛就是Digit Recognizer:Learn computer vision fundamentals with the famous MNIST data。当时作为入门小白的我,使用了入门级的方法KNN完成了我的第一次机器学习(自认为KNN是最最基础的算法,对它的介绍可见我的另一篇博文machine-learning笔记:机器学习的几个常见算法及其优缺点,真的非常简单,但也极其笨拙)。而最近我又使用CNN再一次尝试了这个数据集,踩了不少坑,因此想把两次经历统统记录在这,可能会有一些不足之处,留作以后整理优化。
import matplotlib from matplotlib import pyplot as plt %matplotlib inline
导入训练数据:
1 2 3 4 5 6 7 8 9 10
trainSet = [] with open('train.csv','r') as trainFile: lines=csv.reader(trainFile) for line in lines: trainSet.append(line) trainSet.remove(trainSet[0])
rawTrainData = np.mat(rawTrainData) #转化成矩阵,或许不需要 m, n = np.shape(rawTrainData) trainData = np.zeros((m, n)) #创建初值为0的ndarray for i in range(m): for j in range(n): trainData[i, j] = int(rawTrainData[i, j]) #转化并赋值
rawTrainLabel = np.mat(rawTrainLabel) #或许不需要 m, n = np.shape(rawTrainLabel) trainLabel = np.zeros((m, n)) for i in range(m): for j in range(n): trainLabel[i, j] = int(rawTrainLabel[i, j])
这里我们可以查看以下数据的维度,确保没有出错。
为了方便起见,我们把所有pixel不为0的点都设置为1。
1 2 3 4 5
m, n = np.shape(trainData) for i in range(m): for j in range(n): if trainData[i, j] != 0: trainData[i, j] = 1
testSet = [] with open('test.csv','r') as testFile: lines=csv.reader(testFile) for line in lines: testSet.append(line) testSet.remove(testSet[0])
testSet = np.array(testSet) rawTestData = testSet
rawTestData = np.mat(rawTestData) m, n = np.shape(rawTestData) testData = np.zeros((m, n)) for i in range(m): for j in range(n): testData[i, j] = int(rawTestData[i, j])
m, n = np.shape(testData) for i in range(m): for j in range(n): if testData[i, j] != 0: testData[i, j] = 1
#分割出验证集 m, n = np.shape(trainLabel) trainingTrainLabel = np.zeros((m, n - trainingTestSize)) for i in range(m): for j in range(n - trainingTestSize): trainingTrainLabel[i, j] = trainLabel[i, j] trainingTestLabel = np.zeros((m, trainingTestSize)) for i in range(m): for j in range(trainingTestSize): trainingTestLabel[i, j] = trainLabel[i, n - trainingTestSize + j] m, n = np.shape(trainData) trainingTrainData = np.zeros((m - trainingTestSize, n)) for i in range(m - trainingTestSize): for j in range(n): trainingTrainData[i, j] = trainData[i, j] trainingTestData = np.zeros((trainingTestSize, n)) for i in range(trainingTestSize): for j in range(n): trainingTestData[i, j] = trainData[m - trainingTestSize + i, j]
#使k值为3到9依次尝试 training = [] for x in range(3, 10): error = 0 for y in range(trainingTestSize): answer = (classify(trainingTestData[y], trainingTrainData, trainingTrainLabel, x)) print'the classifier came back with: %d, %.2f%% has done, the k now is %d' % (answer, (y + (x - 3) * trainingTestSize) / float(trainingTestSize * 7) * 100, x) #方便知道进度 if answer != trainingTestLabel[0, y]: error += 1 training.append(error)
m, n = np.shape(testData) result = [] for i in range(m): answer = (classify(testData[i], trainData, trainLabel, theK)) result.append(answer) print'the classifier came back with: %d, %.2f%% has done' % (answer, i / float(m) * 100)
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import pandas as pd import numpy as np from math import *
%matplotlib inline import matplotlib.pyplot as plt import matplotlib.cm as cm
for epoch in range(EPOCH): for step, (x, y) in enumerate(train_loader): b_x = Variable(x) b_y = Variable(y) output = cnn(b_x) loss = loss_func(output, b_y) #cross entropy loss #update W optimzer.zero_grad() loss.backward() optimzer.step() print('epoch%d' % (epoch + 1), '-', 'batch%d' % step, '-', 'loss%f' % loss) #查看训练过程 print('No.%depoch is over' % (epoch + 1))
代入测试集求解:
1 2 3 4 5
output = cnn(test_data[:]) #print(output)
result = torch.max(output, 1)[1].squeeze() #print(result)
仿照KNN中的结果转存函数,定义saveResult函数。
1 2 3 4 5 6 7
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
defforward(self, x): x = self.conv1(x) x = self.conv2(x) x = x.view(x.size(0), -1) x = self.fc(x) x = self.dropout(x) output = F.softmax(self.out(x)) return output
kaggle是一个著名的数据科学竞赛平台,暑假里我也抽空自己独立完成了三四个getting started级别的比赛。对于MNIST数据集,想必入门计算机视觉的人应该也不会陌生。kaggle上getting started的第一个比赛就是Digit Recognizer:Learn computer vision fundamentals with the famous MNIST data。当时作为入门小白的我,使用了入门级的方法KNN完成了我的第一次机器学习(自认为KNN是最最基础的算法,对它的介绍可见我的另一篇博文machine-learning笔记:机器学习的几个常见算法及其优缺点,真的非常简单,但也极其笨拙)。而最近我又使用CNN再一次尝试了这个数据集,踩了不少坑,因此想把两次经历统统记录在这,可能会有一些不足之处,留作以后整理优化。
import matplotlib from matplotlib import pyplot as plt %matplotlib inline
导入训练数据:
1 2 3 4 5 6 7 8 9 10
trainSet = [] with open('train.csv','r') as trainFile: lines=csv.reader(trainFile) for line in lines: trainSet.append(line) trainSet.remove(trainSet[0])
rawTrainData = np.mat(rawTrainData) #转化成矩阵,或许不需要 m, n = np.shape(rawTrainData) trainData = np.zeros((m, n)) #创建初值为0的ndarray for i in range(m): for j in range(n): trainData[i, j] = int(rawTrainData[i, j]) #转化并赋值
rawTrainLabel = np.mat(rawTrainLabel) #或许不需要 m, n = np.shape(rawTrainLabel) trainLabel = np.zeros((m, n)) for i in range(m): for j in range(n): trainLabel[i, j] = int(rawTrainLabel[i, j])
这里我们可以查看以下数据的维度,确保没有出错。
为了方便起见,我们把所有pixel不为0的点都设置为1。
1 2 3 4 5
m, n = np.shape(trainData) for i in range(m): for j in range(n): if trainData[i, j] != 0: trainData[i, j] = 1
testSet = [] with open('test.csv','r') as testFile: lines=csv.reader(testFile) for line in lines: testSet.append(line) testSet.remove(testSet[0])
testSet = np.array(testSet) rawTestData = testSet
rawTestData = np.mat(rawTestData) m, n = np.shape(rawTestData) testData = np.zeros((m, n)) for i in range(m): for j in range(n): testData[i, j] = int(rawTestData[i, j])
m, n = np.shape(testData) for i in range(m): for j in range(n): if testData[i, j] != 0: testData[i, j] = 1
#分割出验证集 m, n = np.shape(trainLabel) trainingTrainLabel = np.zeros((m, n - trainingTestSize)) for i in range(m): for j in range(n - trainingTestSize): trainingTrainLabel[i, j] = trainLabel[i, j] trainingTestLabel = np.zeros((m, trainingTestSize)) for i in range(m): for j in range(trainingTestSize): trainingTestLabel[i, j] = trainLabel[i, n - trainingTestSize + j] m, n = np.shape(trainData) trainingTrainData = np.zeros((m - trainingTestSize, n)) for i in range(m - trainingTestSize): for j in range(n): trainingTrainData[i, j] = trainData[i, j] trainingTestData = np.zeros((trainingTestSize, n)) for i in range(trainingTestSize): for j in range(n): trainingTestData[i, j] = trainData[m - trainingTestSize + i, j]
#使k值为3到9依次尝试 training = [] for x in range(3, 10): error = 0 for y in range(trainingTestSize): answer = (classify(trainingTestData[y], trainingTrainData, trainingTrainLabel, x)) print'the classifier came back with: %d, %.2f%% has done, the k now is %d' % (answer, (y + (x - 3) * trainingTestSize) / float(trainingTestSize * 7) * 100, x) #方便知道进度 if answer != trainingTestLabel[0, y]: error += 1 training.append(error)
m, n = np.shape(testData) result = [] for i in range(m): answer = (classify(testData[i], trainData, trainLabel, theK)) result.append(answer) print'the classifier came back with: %d, %.2f%% has done' % (answer, i / float(m) * 100)
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import pandas as pd import numpy as np from math import *
%matplotlib inline import matplotlib.pyplot as plt import matplotlib.cm as cm
for epoch in range(EPOCH): for step, (x, y) in enumerate(train_loader): b_x = Variable(x) b_y = Variable(y) output = cnn(b_x) loss = loss_func(output, b_y) #cross entropy loss #update W optimzer.zero_grad() loss.backward() optimzer.step() print('epoch%d' % (epoch + 1), '-', 'batch%d' % step, '-', 'loss%f' % loss) #查看训练过程 print('No.%depoch is over' % (epoch + 1))
代入测试集求解:
1 2 3 4 5
output = cnn(test_data[:]) #print(output)
result = torch.max(output, 1)[1].squeeze() #print(result)
仿照KNN中的结果转存函数,定义saveResult函数。
1 2 3 4 5 6 7
defsaveResult(result): with open('result.csv', 'w') as myFile: myWriter = csv.writer(myFile) for i in result: tmp = [] tmp.append(i) myWriter.writerow(tmp)
defforward(self, x): x = self.conv1(x) x = self.conv2(x) x = x.view(x.size(0), -1) x = self.fc(x) x = self.dropout(x) output = F.softmax(self.out(x)) return output
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters
循环矩阵(Circulant Matrices)
任意循环矩阵可以被傅里叶变换矩阵对角化。(All circulant matrices are made diagonal by the Discrete Fourier Transform (DFT), regardless of the generating vector x.)我们在文献中往往会看到这样一个变换:
参考文献: [1]High-Speed Tracking with Kernelized Correlation Filters
循环矩阵(Circulant Matrices)
任意循环矩阵可以被傅里叶变换矩阵对角化。(All circulant matrices are made diagonal by the Discrete Fourier Transform (DFT), regardless of the generating vector x.)我们在文献中往往会看到这样一个变换:
我们直接到维基百科搜索regularization: 里面第一段是这样解释的:In mathematics, statistics, and computer science, particularly in machine learning and inverse problems, regularization is the process of adding information in order to solve an ill-posed problem or to prevent overfitting. 这就和我们在机器学习应用中的目的比较相近了。
我们直接到维基百科搜索regularization: 里面第一段是这样解释的:In mathematics, statistics, and computer science, particularly in machine learning and inverse problems, regularization is the process of adding information in order to solve an ill-posed problem or to prevent overfitting. 这就和我们在机器学习应用中的目的比较相近了。
赤池信息准则(Akaike Information Criterion,AIC)公式定义如下:其中k表示模型参数个数(复杂度),L表示经验误差(似然函数)。 当需要从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型。
BIC准则
贝叶斯信息准则(Bayesian Information Criterion,BIC)是对AIC准则的改进,定义如下:与AIC不同,这里k的系数不再是常数。其中n代表的是样本量(数据量),这样,BIC准则就与样本量相关了。当样本量足够时,过拟合的风险变小,我们就可以允许模型复杂一些。 这里再次附上这张直观的图片,方便理解与体会。简析可参考machine-learning笔记:机器学习中正则化的理解。
赤池信息准则(Akaike Information Criterion,AIC)公式定义如下:其中k表示模型参数个数(复杂度),L表示经验误差(似然函数)。 当需要从一组可供选择的模型中选择最佳模型时,通常选择AIC最小的模型。
BIC准则
贝叶斯信息准则(Bayesian Information Criterion,BIC)是对AIC准则的改进,定义如下:与AIC不同,这里k的系数不再是常数。其中n代表的是样本量(数据量),这样,BIC准则就与样本量相关了。当样本量足够时,过拟合的风险变小,我们就可以允许模型复杂一些。 这里再次附上这张直观的图片,方便理解与体会。简析可参考machine-learning笔记:机器学习中正则化的理解。
#初始化字典矩阵 def_initialize(self, y): u, s, v = np.linalg.svd(y) self.dictionary = u[:, :self.n_components]
#使用KSVD更新字典的过程 def_update_dict(self, y, d, x): for i in range(self.n_components): #选择X中第i行(从0开始)中非零项 index = np.nonzero(x[i, :])[0] #如果没有非零项,则直接进入下一次for循环 if len(index) == 0: continue #更新D中第i列 d[:, i] = 0 #计算误差矩阵 r = (y - np.dot(d, x))[:, index] #利用SVD的方法,来求解更新字典和稀疏系数矩阵 u, s, v = np.linalg.svd(r, full_matrices = False) #使用左奇异矩阵的第0列更新字典 d[:, i] = u[:, 0].T #使用第0个奇异值和右奇异矩阵的第0行的乘积更新稀疏系数矩阵 x[i, index] = s[0] * v[0, :] return d, x
#KSVD迭代过程 deffit(self, y): self._initialize(y) for i in range(self.max_iter): #在最大迭代范围内 #稀疏编码 x = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs) #计算容差 e = np.linalg.norm(y - np.dot(self.dictionary, x)) #满足容差就结束 if e < self.tol: break #更新字典 self._update_dict(y, self.dictionary, x)
#稀疏编码 self.sparsecode = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs)
#初始化字典矩阵 def_initialize(self, y): u, s, v = np.linalg.svd(y) self.dictionary = u[:, :self.n_components]
#使用KSVD更新字典的过程 def_update_dict(self, y, d, x): for i in range(self.n_components): #选择X中第i行(从0开始)中非零项 index = np.nonzero(x[i, :])[0] #如果没有非零项,则直接进入下一次for循环 if len(index) == 0: continue #更新D中第i列 d[:, i] = 0 #计算误差矩阵 r = (y - np.dot(d, x))[:, index] #利用SVD的方法,来求解更新字典和稀疏系数矩阵 u, s, v = np.linalg.svd(r, full_matrices = False) #使用左奇异矩阵的第0列更新字典 d[:, i] = u[:, 0].T #使用第0个奇异值和右奇异矩阵的第0行的乘积更新稀疏系数矩阵 x[i, index] = s[0] * v[0, :] return d, x
#KSVD迭代过程 deffit(self, y): self._initialize(y) for i in range(self.max_iter): #在最大迭代范围内 #稀疏编码 x = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs) #计算容差 e = np.linalg.norm(y - np.dot(self.dictionary, x)) #满足容差就结束 if e < self.tol: break #更新字典 self._update_dict(y, self.dictionary, x)
#稀疏编码 self.sparsecode = linear_model.orthogonal_mp(self.dictionary, y, n_nonzero_coefs = self.n_nonzero_coefs)
function[errors, ans, time] = bisection(low, high, max, stopError) %二分法 %func是待求零点的函数 %low,high分别是解区间的上下限 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fl = func(low); fh = func(high); error = high - low; fori = 1 : max mid = (low + high ) / 2; fm = func(mid); if fm * fl > 0 low = mid; else high = mid; end error = high - low; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(mid); %转换成角度 end
输入命令[errorsB, ans, time] = bisection(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = linecut(a, b, max, stopError) %弦截法 %func是待求零点的函数 %a,b是在解的领域取的两点,这里取解区间的两个端点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fa = func(a); fb = func(b); error = abs(a - b); fori = 1 : max x = b - (b - a) * fb / (fb - fa); a = b; b = x; fa = func(a); fb = func(b); error = abs(a - b); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(b); %转换成角度 end
输入命令[errorsL, ans, time] = linecut(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = steffensen(x, max, stopError) %Steffensen方法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 f = func(x); fori = 1 : max o = x - f ^ 2 / (f - func(x - f)); error = abs(x - o); x = o; f = func(o); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
选取初始点为$0$,输入命令[errorsS1, ans, time] = steffensen(0, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = picard(x, max, stopError) %Picard迭代法 %interation是迭代函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = interation(x); error = abs(x - o); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
输入命令[errorsP, ans, time] = picard(0, 50, 1.7e-5)求解:
function[errors, ans, time] = newton(x, max, stopError) %Newton迭代法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = x - func(x) / df(x); error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
输入命令[errorsN, ans, time] = newton(0, 50, 1.7e-5)进行计算,得解:
function[errors, ans, time] = hill(x, max, stopError) %Newton下山法 % 此处显示详细说明 format long %为提高精度,保留更多位数 l = 1; fori = 1 : max o = x - l * func(x) / df(x); whileabs(func(o)) > abs(func(x)) %不满足下山条件 l = l / 2; o = x - l * func(x) / df(x); end error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
function[errors, ans, time] = bisection(low, high, max, stopError) %二分法 %func是待求零点的函数 %low,high分别是解区间的上下限 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fl = func(low); fh = func(high); error = high - low; fori = 1 : max mid = (low + high ) / 2; fm = func(mid); if fm * fl > 0 low = mid; else high = mid; end error = high - low; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(mid); %转换成角度 end
输入命令[errorsB, ans, time] = bisection(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = linecut(a, b, max, stopError) %弦截法 %func是待求零点的函数 %a,b是在解的领域取的两点,这里取解区间的两个端点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fa = func(a); fb = func(b); error = abs(a - b); fori = 1 : max x = b - (b - a) * fb / (fb - fa); a = b; b = x; fa = func(a); fb = func(b); error = abs(a - b); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(b); %转换成角度 end
输入命令[errorsL, ans, time] = linecut(0, pi / 6, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = steffensen(x, max, stopError) %Steffensen方法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 f = func(x); fori = 1 : max o = x - f ^ 2 / (f - func(x - f)); error = abs(x - o); x = o; f = func(o); errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
选取初始点为$0$,输入命令[errorsS1, ans, time] = steffensen(0, 50, 1.7e-5),求得结果如下:
function[errors, ans, time] = picard(x, max, stopError) %Picard迭代法 %interation是迭代函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = interation(x); error = abs(x - o); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(o); %转换成角度 end
输入命令[errorsP, ans, time] = picard(0, 50, 1.7e-5)求解:
function[errors, ans, time] = newton(x, max, stopError) %Newton迭代法 %func是待求零点的函数 %x是初始点 %max是最多循环步数,防止死循环 %stopError是预定精度,作为终止条件 %errors记录每次循环的误差 %ans记录最终求解结果,表示为角度 %time是总的循环次数 format long %为提高精度,保留更多位数 fori = 1 : max o = x - func(x) / df(x); error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
输入命令[errorsN, ans, time] = newton(0, 50, 1.7e-5)进行计算,得解:
function[errors, ans, time] = hill(x, max, stopError) %Newton下山法 % 此处显示详细说明 format long %为提高精度,保留更多位数 l = 1; fori = 1 : max o = x - l * func(x) / df(x); whileabs(func(o)) > abs(func(x)) %不满足下山条件 l = l / 2; o = x - l * func(x) / df(x); end error = abs(o - x); x = o; errors(i) = error; if error < stopError, break, end end time = i; ans = rad2deg(x); %转换成角度 end
MinGW,是Minimalist GNU for Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。 当初报错的时候,我也是很诧异,因为之前使用CodeBlocks和Visual Studio的时候明明是有的。而这次在matlab中编译C/C++时怎么就找不到了。 因为之前使用CodeBlocks也有找不到的情况,我当时是重装了一遍CodeBlocks解决问题的,因此我上网开了一下有没有类似的方法。按道理来说已经装了VS是可以找到的,但好像也存在即使安装了VS、matlab还是找不到编译器的情况。可以使用mex看一下具体是哪些路径没有匹配上,似乎可以通过修改注册表的方法解决,但我没有尝试。
毕竟是花了一个晚上,看了mathworks上网友们的各种solution,试错了许多方法,这里记录两个貌似要成功的方法(其实最后还是失败了),或许会有参考价值。 这里有一个被许多网友强调、要注意的是:下载后的mingw文件(没错它只有15kb看上去好假)要在打开的matlab中,找到相应的下载目录,右键点击然后选择下载并安装(download and install),否则似乎会出错。
MinGW,是Minimalist GNU for Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。 当初报错的时候,我也是很诧异,因为之前使用CodeBlocks和Visual Studio的时候明明是有的。而这次在matlab中编译C/C++时怎么就找不到了。 因为之前使用CodeBlocks也有找不到的情况,我当时是重装了一遍CodeBlocks解决问题的,因此我上网开了一下有没有类似的方法。按道理来说已经装了VS是可以找到的,但好像也存在即使安装了VS、matlab还是找不到编译器的情况。可以使用mex看一下具体是哪些路径没有匹配上,似乎可以通过修改注册表的方法解决,但我没有尝试。
毕竟是花了一个晚上,看了mathworks上网友们的各种solution,试错了许多方法,这里记录两个貌似要成功的方法(其实最后还是失败了),或许会有参考价值。 这里有一个被许多网友强调、要注意的是:下载后的mingw文件(没错它只有15kb看上去好假)要在打开的matlab中,找到相应的下载目录,右键点击然后选择下载并安装(download and install),否则似乎会出错。
在Visual Object Tracking using Adaptive Correlation Filters一文中,我看到这样一句话:“The Peak-to-Sidelobe Ratio(PSR), which measures the strength of a correlation ...
实践出真知。在之前的博文deep-learning笔记:使网络能够更深——ResNet简介与pytorch实现中,我对何恺明大神的CVPR最佳论文中提出的残差网络做了简单介绍。而就在第二年(2016年),何恺明的团队就发表了“Identity Mappings in Deep Residual Ne ...
在Visual Object Tracking using Adaptive Correlation Filters一文中,我看到这样一句话:“The Peak-to-Sidelobe Ratio(PSR), which measures the strength of a correlation ...
实践出真知。在之前的博文deep-learning笔记:使网络能够更深——ResNet简介与pytorch实现中,我对何恺明大神的CVPR最佳论文中提出的残差网络做了简单介绍。而就在第二年(2016年),何恺明的团队就发表了“Identity Mappings in Deep Residual Ne ...
以前觉得深度学习就是有很多层的神经网络,或者周志华提出的深度随机森林,总之只要是有很“深”的结构就是深度学习。直到不久前一位计科大佬告诉我深度学习是end-to-end(也表示成“e2e”)的,当时听的也是一知半解,回去查了一下后终于恍然大悟。本文主要基于Andrew Ng的课程中“What is ...
本文紧接前一篇文章machine-learning笔记:准确率和召回率,具体到目标检测中来谈一谈两个指标:AP和mAP。AP即average precision平均准确率,而mAP即mean average precision,翻译成平均平均准确率…不太好听,我且称它为均匀平均准确率吧。目标检测中的 ...
以前觉得深度学习就是有很多层的神经网络,或者周志华提出的深度随机森林,总之只要是有很“深”的结构就是深度学习。直到不久前一位计科大佬告诉我深度学习是end-to-end(也表示成“e2e”)的,当时听的也是一知半解,回去查了一下后终于恍然大悟。本文主要基于Andrew Ng的课程中“What is ...
本文紧接前一篇文章machine-learning笔记:准确率和召回率,具体到目标检测中来谈一谈两个指标:AP和mAP。AP即average precision平均准确率,而mAP即mean average precision,翻译成平均平均准确率…不太好听,我且称它为均匀平均准确率吧。目标检测中的 ...
似乎是为了支持由武汉深之度科技开发的国产linux系统Deepin,近年来许多常用软件都提供了linux客户端,比如QQ for linux,baidunetdisk for linux。然而我安装百度网盘后发现打不开,一打开就报错,后来才知道百度网盘仅支持ubuntu18之后的版本。于是就又涉及到 ...
似乎是为了支持由武汉深之度科技开发的国产linux系统Deepin,近年来许多常用软件都提供了linux客户端,比如QQ for linux,baidunetdisk for linux。然而我安装百度网盘后发现打不开,一打开就报错,后来才知道百度网盘仅支持ubuntu18之后的版本。于是就又涉及到 ...
import time #这里是为了用来延时,代替训练的时间 numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in range(numOfTimes): print("\r", "progress percentage:{0}%".format((round(i + 1) * 100 / numOfTimes)), end = "", flush = True) time.sleep(0.02) #若前面from time import sleep,这里直接sleep(0.02)即可
import tqdm import time numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in tqdm.tqdm(range(numOfTimes)): time.sleep(0.02) #代替训练等耗时过程 pass
也可以直接from tqdm import tqdm,这样后面就不需要tqdm.tqdm了。
利用progressbar
库如其名,这个库就是用来做进度条的。如果没有的话,它和tqdm都可以使用pip来安装。
1 2 3 4 5 6
import progressbar from time import sleep numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 progress = progressbar.ProgressBar() for i in progress(range(numOfTimes)): sleep(0.02)
import time #这里是为了用来延时,代替训练的时间 numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in range(numOfTimes): print("\r", "progress percentage:{0}%".format((round(i + 1) * 100 / numOfTimes)), end = "", flush = True) time.sleep(0.02) #若前面from time import sleep,这里直接sleep(0.02)即可
import tqdm import time numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 for i in tqdm.tqdm(range(numOfTimes)): time.sleep(0.02) #代替训练等耗时过程 pass
也可以直接from tqdm import tqdm,这样后面就不需要tqdm.tqdm了。
利用progressbar
库如其名,这个库就是用来做进度条的。如果没有的话,它和tqdm都可以使用pip来安装。
1 2 3 4 5 6
import progressbar from time import sleep numOfTimes = 200#总循环次数,可以是总训练数据量等,这里设为200 progress = progressbar.ProgressBar() for i in progress(range(numOfTimes)): sleep(0.02)
df1 = pd.DataFrame(np.random.randn(6, 4), index = dates, columns = list('ABCD'))
df1 >>> A B C D 2013-01-010.469112-0.282863-1.509059-1.135632 2013-01-021.212112-0.1732150.119209-1.044236 2013-01-03-0.861849-2.104569-0.4949291.071804 2013-01-040.721555-0.706771-1.0395750.271860 2013-01-05-0.4249720.5670200.276232-1.087401 2013-01-06-0.6736900.113648-1.4784270.524988
df1 = pd.DataFrame(np.random.randn(6, 4), index = dates, columns = list('ABCD'))
df1 >>> A B C D 2013-01-010.469112-0.282863-1.509059-1.135632 2013-01-021.212112-0.1732150.119209-1.044236 2013-01-03-0.861849-2.104569-0.4949291.071804 2013-01-040.721555-0.706771-1.0395750.271860 2013-01-05-0.4249720.5670200.276232-1.087401 2013-01-06-0.6736900.113648-1.4784270.524988
过了一会有一个男老师进来说一些有关考试的注意事项,说完没多久大家就到隔壁的考试教室刷脸入场了。 考场的教室和等候的教室一样,也是黄色的日光灯,看着也挺舒适。入场顺序是按照姓氏的首字母顺序的,我进去的比较早。尽管A考场大概也就二三十个人,但整个入场过程还是挺久的。 考官把我领到座位上,虽然是随机抽的但好像我的考位还是我的序号。为我把身份证插在旁边的卡槽里之后,考官又为我输了激活码进入考试界面,然后没说什么就走了。 考试的隔间挺好,靠桌子往里坐一点就完全看不到旁边了。首先是确认姓名的界面,然而考官走了我也没处问,担心确认了就直接开始考试了因此久久没敢点。由于别人还在入场,因此我不敢太早开始考试。我回头看了一眼,发现是我进候考室以来就注意到的那个男生。虽然没问过他,但看上去他这次绝对不是一战了。 过了一会,我听到有人点鼠标的声音,于是我也鼓足勇气开始点。前面大概有七八的页面都是只需continue的direction界面,而且这个界面是不会自动跳转的,我在这里停留了很久。 终于,大概第十个人入场的时候,我听到有人开始试音了。意外的是,第一个开始试音的人居然真的在介绍他生活的城市。哈哈哈看来也是首考的,不知道待会整个考场一齐开始诠释人类的本质的时候,他有什么感想。这里我暗暗庆幸自己报了班。 当大家都在诠释人类的本质时,我心里觉得还是挺可乐的。不过就在这时,我听到前面提到的那位久经沙场的老哥也开始复读了,于是我又点了一个continue。 每个continue我的拖好久才点,不过入场真的是挺久的。大概有十个人完成试音之后,我才看到了describe the city you live in,心想这个时间还是可以的。
接下来就是听力了,我的听力是加试,有3个section。第一个section的对话我考虑太久,导致最后答lecture三道题要在一分钟之内答完。当时也只能以这个section只有50%的概率计入成绩来安慰自己。 第二个section做得还行,一些笔记还是没记到要点上,还是得多练。遗憾的是,我听力有好几篇都没听懂听力开头“you will hear part of a lecture in a ……gy class”中学科具体是什么,如果能听懂的话肯定是有一定帮助的,词汇量还不够啊!
过了一会有一个男老师进来说一些有关考试的注意事项,说完没多久大家就到隔壁的考试教室刷脸入场了。 考场的教室和等候的教室一样,也是黄色的日光灯,看着也挺舒适。入场顺序是按照姓氏的首字母顺序的,我进去的比较早。尽管A考场大概也就二三十个人,但整个入场过程还是挺久的。 考官把我领到座位上,虽然是随机抽的但好像我的考位还是我的序号。为我把身份证插在旁边的卡槽里之后,考官又为我输了激活码进入考试界面,然后没说什么就走了。 考试的隔间挺好,靠桌子往里坐一点就完全看不到旁边了。首先是确认姓名的界面,然而考官走了我也没处问,担心确认了就直接开始考试了因此久久没敢点。由于别人还在入场,因此我不敢太早开始考试。我回头看了一眼,发现是我进候考室以来就注意到的那个男生。虽然没问过他,但看上去他这次绝对不是一战了。 过了一会,我听到有人点鼠标的声音,于是我也鼓足勇气开始点。前面大概有七八的页面都是只需continue的direction界面,而且这个界面是不会自动跳转的,我在这里停留了很久。 终于,大概第十个人入场的时候,我听到有人开始试音了。意外的是,第一个开始试音的人居然真的在介绍他生活的城市。哈哈哈看来也是首考的,不知道待会整个考场一齐开始诠释人类的本质的时候,他有什么感想。这里我暗暗庆幸自己报了班。 当大家都在诠释人类的本质时,我心里觉得还是挺可乐的。不过就在这时,我听到前面提到的那位久经沙场的老哥也开始复读了,于是我又点了一个continue。 每个continue我的拖好久才点,不过入场真的是挺久的。大概有十个人完成试音之后,我才看到了describe the city you live in,心想这个时间还是可以的。
接下来就是听力了,我的听力是加试,有3个section。第一个section的对话我考虑太久,导致最后答lecture三道题要在一分钟之内答完。当时也只能以这个section只有50%的概率计入成绩来安慰自己。 第二个section做得还行,一些笔记还是没记到要点上,还是得多练。遗憾的是,我听力有好几篇都没听懂听力开头“you will hear part of a lecture in a ……gy class”中学科具体是什么,如果能听懂的话肯定是有一定帮助的,词汇量还不够啊!
这里先介绍一下ntpd(Network Time Protocol (NTP) daemon),如官方文档所说,它的作用是sets and maintains the system time of day in synchronism with Internet standard time servers。因此,我们可以通过ntpdate命令进行设置,其基本格式如下:
这里先介绍一下ntpd(Network Time Protocol (NTP) daemon),如官方文档所说,它的作用是sets and maintains the system time of day in synchronism with Internet standard time servers。因此,我们可以通过ntpdate命令进行设置,其基本格式如下:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE #optional, but recommended
这条命令应该就是添加新的密匙并信任,一般在配置apt-get源之前运行。 对apt-key的描述如下:“apt-key is used to manage the list of keys used by apt to authenticate packages. Packages which have been authenticated using these keys will be considered trusted.”由于每个发布的Debian软件包都是通过密钥认证的,而apt-key命令正是用来管理Debian软件包密钥的。
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE #optional, but recommended
这条命令应该就是添加新的密匙并信任,一般在配置apt-get源之前运行。 对apt-key的描述如下:“apt-key is used to manage the list of keys used by apt to authenticate packages. Packages which have been authenticated using these keys will be considered trusted.”由于每个发布的Debian软件包都是通过密钥认证的,而apt-key命令正是用来管理Debian软件包密钥的。
似乎是为了支持由武汉深之度科技开发的国产linux系统Deepin,近年来许多常用软件都提供了linux客户端,比如QQ for linux,baidunetdisk for linux。然而我安装百度网盘后发现打不开,一打开就报错,后来才知道百度网盘仅支持ubuntu18之后的版本。于是就又涉及到deb包的卸载问题了。
似乎是为了支持由武汉深之度科技开发的国产linux系统Deepin,近年来许多常用软件都提供了linux客户端,比如QQ for linux,baidunetdisk for linux。然而我安装百度网盘后发现打不开,一打开就报错,后来才知道百度网盘仅支持ubuntu18之后的版本。于是就又涉及到deb包的卸载问题了。
snap是ubuntu母公司Canonical于2016年4月发布ubuntu16.04时候引入的一种安全的、易于管理的、沙盒化的软件包格式,与传统的dpkg和apt有着很大的区别。在ubuntu软件中心下载安装的似乎都是snap管理的。这让一些商业闭源软件也能在linux上发布,说白了是ubuntu为了获得linux发行版霸权的一个重要举措,因此没少招黑。知乎上看到这么一句话,笑半天:“Fuck the political correct, make linux great again.(says 川·乌班图·普)”。
snap是ubuntu母公司Canonical于2016年4月发布ubuntu16.04时候引入的一种安全的、易于管理的、沙盒化的软件包格式,与传统的dpkg和apt有着很大的区别。在ubuntu软件中心下载安装的似乎都是snap管理的。这让一些商业闭源软件也能在linux上发布,说白了是ubuntu为了获得linux发行版霸权的一个重要举措,因此没少招黑。知乎上看到这么一句话,笑半天:“Fuck the political correct, make linux great again.(says 川·乌班图·普)”。
`timescale 1ns / 1ps //top module module runningwatch( input start, input stop, input store, input reset, input CLK, outputreg TM_EN, //enable the timer outputreg SD_EN, //enable register outputreg DP_SEL, //the screen show which data outputreg [15:0] regRecord, //data the register storing outputreg [15:0] TMRecord, //timer data output [6:0] tenmsLight, hunmsLight, onesLight, tensLight ); reg [3:0] tenMS, hunMS, oneS, tenS; //four 4bit digits from small to high and each from 0 to 9 reg tenmsup, hunmsup, onesup; //the signals if the bigger digit than itself should add //allocate state parameter S0 = 3'B000; //initial state parameter S1 = 3'B001; //TIMING:timer set as 00.00,record does not change,show timer,timer counts,TM_EN = 1, SD_EN = 0, DP_SEL = 0 parameter S2 = 3'B010; //PAUSE:timer does not change,record does not change,show timer,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 0 parameter S3 = 3'B011; //UPDATE:timer does not change,record set as timer,show register,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 1 parameter S4 = 3'B100; //KEEP:timer does not change,record does not change,show register,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 1 parameter S5 = 3'B101; //RESET:timer set as 00.00,record set as 99.99,show timer,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 0 reg [2:0] state; reg [2:0] next_state; //reg CLK; initial//only run once begin regRecord = 16'B0010011100001111; TMRecord = 16'B0000000000000000; state = S0; tenMS = 0; hunMS = 0; oneS = 0; tenS = 0; end //to judge if store the timer's data wirenew; reg newRecord; _16bit_Comp comparator(TMRecord, regRecord, new); //compare always @ (new) newRecord = new; reg [15:0] MAX = 16'B0010011100001111; //sequential logic part always @ (posedge CLK) //update the state at each posedge begin state <= next_state; end //combinatory logic part //state transform always @ (state or start or stop or store or reset or newRecord) begin next_state = S0; //if not press the key, back to the initial state case(state) S0: //initial state begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S1: //TIMING begin TM_EN = 1; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end
S2: //PAUSE begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S3: //UPDATE begin TM_EN = 0; SD_EN = 1; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S4: //KEEP begin TM_EN = 0; SD_EN = 0; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S5: //RESET begin TM_EN = 0; SD_EN = 1; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end default: begin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end//default initial state endcase end //reset to zero always @ (posedge reset orposedge start) begin tenMS <= 0; hunMS <= 0; oneS <= 0; tenS <= 0; TMRecord <= 0; end //the followings are which have stated before: //reg [3:0] tenMS, hunMS, oneS, tenS are four 4bit digits from small to high and each from 0 to 9 //reg tenmsup, hunmsup, onesup are the signals if the bigger digit than itself should add //timer, divide into four digits //10ms always @ (posedge CLK) begin if(TM_EN) begin TMRecord = TMRecord + 1; if(tenMS < 9) begin tenMS <= tenMS + 1; tenmsup <= 0; end else begin tenMS <= 0; tenmsup <= 1; end end end //100ms always @ (posedge tenmsup) begin if(TM_EN) begin if(hunMS < 9) begin hunMS <= hunMS + 1; hunmsup <= 0; end else begin hunMS <= 0; hunmsup <= 1; end end end //1s always @ (posedge hunmsup) begin if(TM_EN) begin if(oneS < 9) begin oneS <= oneS + 1; onesup <= 0; end else begin oneS <= 0; onesup <= 1; end end end //10s always @ (posedge onesup) begin if(TM_EN) begin if(tenS < 9) tenS <= oneS + 1; else oneS <= 0; end end //save to the register wire [15:0] newReg; _16bit_Reg register(SD_EN, TMRecord, regRecord, MAX, reset, CLK, newReg); always @ (newReg) regRecord = newReg; //change BCD to tube lights watchDrive TENms(tenMS, tenmsLight); watchDrive HUNms(hunMS, hunmsLight); watchDrive ONEs(oneS, onesLight); watchDrive TENs(tenS, tensLight); endmodule
`timescale 1ns / 1ps //top module module runningwatch( input start, input stop, input store, input reset, input CLK, outputreg TM_EN, //enable the timer outputreg SD_EN, //enable register outputreg DP_SEL, //the screen show which data outputreg [15:0] regRecord, //data the register storing outputreg [15:0] TMRecord, //timer data output [6:0] tenmsLight, hunmsLight, onesLight, tensLight ); reg [3:0] tenMS, hunMS, oneS, tenS; //four 4bit digits from small to high and each from 0 to 9 reg tenmsup, hunmsup, onesup; //the signals if the bigger digit than itself should add //allocate state parameter S0 = 3'B000; //initial state parameter S1 = 3'B001; //TIMING:timer set as 00.00,record does not change,show timer,timer counts,TM_EN = 1, SD_EN = 0, DP_SEL = 0 parameter S2 = 3'B010; //PAUSE:timer does not change,record does not change,show timer,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 0 parameter S3 = 3'B011; //UPDATE:timer does not change,record set as timer,show register,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 1 parameter S4 = 3'B100; //KEEP:timer does not change,record does not change,show register,timer does not count,TM_EN = 0, SD_EN = 0, DP_SEL = 1 parameter S5 = 3'B101; //RESET:timer set as 00.00,record set as 99.99,show timer,timer does not count,TM_EN = 0, SD_EN = 1, DP_SEL = 0 reg [2:0] state; reg [2:0] next_state; //reg CLK; initial//only run once begin regRecord = 16'B0010011100001111; TMRecord = 16'B0000000000000000; state = S0; tenMS = 0; hunMS = 0; oneS = 0; tenS = 0; end //to judge if store the timer's data wirenew; reg newRecord; _16bit_Comp comparator(TMRecord, regRecord, new); //compare always @ (new) newRecord = new; reg [15:0] MAX = 16'B0010011100001111; //sequential logic part always @ (posedge CLK) //update the state at each posedge begin state <= next_state; end //combinatory logic part //state transform always @ (state or start or stop or store or reset or newRecord) begin next_state = S0; //if not press the key, back to the initial state case(state) S0: //initial state begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S1: //TIMING begin TM_EN = 1; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end
S2: //PAUSE begin TM_EN = 0; SD_EN = 0; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S3: //UPDATE begin TM_EN = 0; SD_EN = 1; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S4: //KEEP begin TM_EN = 0; SD_EN = 0; DP_SEL = 1; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end S5: //RESET begin TM_EN = 0; SD_EN = 1; DP_SEL = 0; if(start) begin next_state = S1; TM_EN = 1; SD_EN = 0; DP_SEL = 0; end elseif(stop) begin next_state = S2; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end elseif(store & newRecord) begin next_state = S3; TM_EN = 0; SD_EN = 1; DP_SEL = 1; end elseif(store & ~newRecord) begin next_state = S4; TM_EN = 0; SD_EN = 0; DP_SEL = 1; end elseif(reset) begin next_state = S5; TM_EN = 0; SD_EN = 1; DP_SEL = 0; end elsebegin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end end default: begin next_state = S0; TM_EN = 0; SD_EN = 0; DP_SEL = 0; end//default initial state endcase end //reset to zero always @ (posedge reset orposedge start) begin tenMS <= 0; hunMS <= 0; oneS <= 0; tenS <= 0; TMRecord <= 0; end //the followings are which have stated before: //reg [3:0] tenMS, hunMS, oneS, tenS are four 4bit digits from small to high and each from 0 to 9 //reg tenmsup, hunmsup, onesup are the signals if the bigger digit than itself should add //timer, divide into four digits //10ms always @ (posedge CLK) begin if(TM_EN) begin TMRecord = TMRecord + 1; if(tenMS < 9) begin tenMS <= tenMS + 1; tenmsup <= 0; end else begin tenMS <= 0; tenmsup <= 1; end end end //100ms always @ (posedge tenmsup) begin if(TM_EN) begin if(hunMS < 9) begin hunMS <= hunMS + 1; hunmsup <= 0; end else begin hunMS <= 0; hunmsup <= 1; end end end //1s always @ (posedge hunmsup) begin if(TM_EN) begin if(oneS < 9) begin oneS <= oneS + 1; onesup <= 0; end else begin oneS <= 0; onesup <= 1; end end end //10s always @ (posedge onesup) begin if(TM_EN) begin if(tenS < 9) tenS <= oneS + 1; else oneS <= 0; end end //save to the register wire [15:0] newReg; _16bit_Reg register(SD_EN, TMRecord, regRecord, MAX, reset, CLK, newReg); always @ (newReg) regRecord = newReg; //change BCD to tube lights watchDrive TENms(tenMS, tenmsLight); watchDrive HUNms(hunMS, hunmsLight); watchDrive ONEs(oneS, onesLight); watchDrive TENs(tenS, tensLight); endmodule
`timescale 1ns / 1ps //unit 1ns, precision 1ps module control( outputreg Cnt_EN, //enable the counter count, so that the counting period can be controled outputwire Cnt_CR, //clear the counter every time when the measure begins outputwire Latch_Sig, //at its posedge, the value of the counter will be stored/latched input nRST, //system reset signal input CP //1Hz standard clock signal ); always @ (posedge CP ornegedge nRST) begin if(~nRST) //generate enable counting signal Cnt_EN = 1'b0; //don't count else Cnt_EN = ~Cnt_EN; //two frequency divider for the clock signal end assign Latch_Sig = ~Cnt_EN; //generate latch signal assign Cnt_CR = nRST & (~CP & Latch_Sig); //generate the clear signal for the counter endmodule
计数模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
`timescale 1ns / 1ps //unit 1ns, precision 1ps module counter( outputreg [3:0] Q, input CR, EN, CP ); always @ (posedge CP orposedge CR) begin if(CR) Q <= 4'b0000; //reset to zero elseif(~EN) Q <= Q; //stop counting elseif(Q == 4'b1001) Q <= 4'b0000; else Q <= Q + 1'b1; //counting, plus one end endmodule
`timescale 1ns / 1ps //unit 1ns, precision 1ps module control( outputreg Cnt_EN, //enable the counter count, so that the counting period can be controled outputwire Cnt_CR, //clear the counter every time when the measure begins outputwire Latch_Sig, //at its posedge, the value of the counter will be stored/latched input nRST, //system reset signal input CP //1Hz standard clock signal ); always @ (posedge CP ornegedge nRST) begin if(~nRST) //generate enable counting signal Cnt_EN = 1'b0; //don't count else Cnt_EN = ~Cnt_EN; //two frequency divider for the clock signal end assign Latch_Sig = ~Cnt_EN; //generate latch signal assign Cnt_CR = nRST & (~CP & Latch_Sig); //generate the clear signal for the counter endmodule
计数模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
`timescale 1ns / 1ps //unit 1ns, precision 1ps module counter( outputreg [3:0] Q, input CR, EN, CP ); always @ (posedge CP orposedge CR) begin if(CR) Q <= 4'b0000; //reset to zero elseif(~EN) Q <= Q; //stop counting elseif(Q == 4'b1001) Q <= 4'b0000; else Q <= Q + 1'b1; //counting, plus one end endmodule
Initializing workspace ... Verifying native components ... Testing TraX protocol support for tracker NCC. Tracker execution interrupted: Unable to establish connection. TraX support not detected. 错误使用 tracker_load (line 127) Tracker has not passed the TraX support test.
如果完成上面之后,执行还有问题,可能是路径没有设置对。打开vot-toolkit/workspace/tracker_XXX.m(XXX是你创建工作区时设置的跟踪算法的名称)。找到最后一行:% tracker_linkpath = {}; % A cell array of custom library directories used by the tracker executable (optional)。 去掉前面的注释符,添加路径tracker_linkpath = {'absolute_path/trax/build'};(记得修改这里的absolute_path)。 据TraX的作者所说,TraX出错一般不是vot toolkit本身的问题,如果你使用的是其他的算法,请确保该算法的.m或者.py文件和vot.m或者vot.py文件处在同一个目录下。如果没有,可到vot-toolkit/tracker/examples中的matlab或者python目录下复制。
TraX
折腾了半天,总得知道这个TraX是个什么东西,根据TraX文档中所说:TraX stands for visual Tracking eXchange, the protocol was designed to make development and testing of visual tracking algorithms simpler and faster. 其实我当初折腾的时候想法是:我不要simpler and faster,我现在只想跑通哈哈哈哈哈。
Initializing workspace ... Verifying native components ... Testing TraX protocol support for tracker NCC. Tracker execution interrupted: Unable to establish connection. TraX support not detected. 错误使用 tracker_load (line 127) Tracker has not passed the TraX support test.
如果完成上面之后,执行还有问题,可能是路径没有设置对。打开vot-toolkit/workspace/tracker_XXX.m(XXX是你创建工作区时设置的跟踪算法的名称)。找到最后一行:% tracker_linkpath = {}; % A cell array of custom library directories used by the tracker executable (optional)。 去掉前面的注释符,添加路径tracker_linkpath = {'absolute_path/trax/build'};(记得修改这里的absolute_path)。 据TraX的作者所说,TraX出错一般不是vot toolkit本身的问题,如果你使用的是其他的算法,请确保该算法的.m或者.py文件和vot.m或者vot.py文件处在同一个目录下。如果没有,可到vot-toolkit/tracker/examples中的matlab或者python目录下复制。
TraX
折腾了半天,总得知道这个TraX是个什么东西,根据TraX文档中所说:TraX stands for visual Tracking eXchange, the protocol was designed to make development and testing of visual tracking algorithms simpler and faster. 其实我当初折腾的时候想法是:我不要simpler and faster,我现在只想跑通哈哈哈哈哈。