代码如下
1 | #!/usr/bin/env python |
1 | #!/usr/bin/env python |
1 | #!/usr/bin/env python |
小结:最终在kaggle上打分0.59940,这是用lr做的一个分类,后续准备用循环神经网络来做,进一步优化。
具体为:在每层像素矩阵上按步长扫描下去,扫描到的像素矩阵和卷积核中对应位置元素做哈达玛积,然后再将得到的对应位置元素相加,即为卷积核一个扫描的输出值,卷积核扫描完一个像素矩阵上所有像素,得到一个新的特征图矩阵,也是这个卷积层的输出,一个卷积核相当于一个特征提取器,一个卷积核得到一个特征图(feature map)。
卷积核大小:3X3, 5X5;常用3X3的卷积核。
卷积中特征图大小计算公式:
wout=(win+2xpadding-F+1)/stride
此时,输入特征图大小与输出特征图大小一样,’SAME’,padding为特征图填充圈数,可知:当卷积核F=3时,padding=1,依此类推。
卷积核元素:卷积核元素即是要训练的模型神经元参数,又叫权重(weight)。
具体为:首先随机初始化参数,训练模型时,即在反向传播时不断更新这些参数,直至寻找到最优参数。最优参数通过损失函数来评估。
像素矩阵:如何得到?彩色图像有RGB(red,green,blue)三个通道,即三个像素矩阵,各个像素矩阵用二维矩阵来表示,像素取值范围[0,255],其中255为白色,0为黑色
卷积可以对原图像进行二次转化,提取特征图;相当于信号处理的滤波器,如拉普拉斯滤波(高通滤波器,保留高频边缘,用于边缘检测,需要用二阶导数),高斯滤波,这些滤波器都可以写成卷积核形式,如拉普拉斯算子(中心位置数字-8,其余数字为1,目的系数之和为0),拉普拉斯算子对噪声很敏感。
prewitt算子:检测水平,垂直,对角线;sobel算子:中心系数使用权重2,较好抑制噪声,检测水平,垂直,对角线。
在进行卷积操作后,像素矩阵维度会变小,不方便计算,padding操作后卷积出来的特征图矩阵会核原矩阵尺寸一样。
具体为:给原始像素矩阵的四周添上一圈0。
在进行卷积操作后,提取得到特征图,特征图中相邻区域中有相似特征信息(可以互相替代),可以删去一部分冗余信息,减少参数数量并降低计算量,抑制了过拟合风险,同时保留了平移,旋转,尺度的不变性。
具体有:最大池化(max_pooling):(取局部领域中最大值。更好的保留纹理特征)和平均池化(mean_pooling):(求局部领域所有值和的平均值。更好保留整体数据特征)。
常用的是最大池化。常用2x2的滤波器(filter),2的步长(stride)进行扫描,特征图的高度(height)、宽度(width)减半,通道数不变。
池化也增加了图像的感受野,提升了模型的能力。
即特征图上一个像素对应回输入图像的区域大小。(需要通过卷积核尺寸和池化滤波器尺寸和步长计算)
思想:从最后一层特征图开始,从下往上的计算(倒着计算)。先计算最深层在前一层上的感受野,然后依此类推逐层推算到输入层(即第一层)。最后一层的特征图的感受野等于其卷积核的大小,第i层特征图的感受野大小和第i层的卷积核和步长相关,还和第i+1层的感受野大小相关。
感受野计算公式:RFi = (RFi+1 - 1) x Stridei + Kerneli+1
其中:i是当前特征层的层数;RFi是第i层感受野大小;RFi+1是第i+1层感受野大小;Stridei是第i层卷积核步长;Kerneli+1是第i层卷积核尺寸大小。
1个3x3卷积核感受野为3x3,2个3x3卷积核感受野为5x5,3个3x3卷积核感受野为7x7,n个3x3卷积核感受野为2n+1 x 2n+1,n为3x3卷积核个数;池化层卷积核一般为2x2,卷积层卷积核一般为3x3;
若无池化,4个3x3卷积核感受野为9x9,而加入3个2x2卷积核的池化层后,感受野变为30x30,很明显感受野迅速增大。
根据此特点,越深层的特征点描述的原图像信息越全面,可通过增加网络层数,增加池化层,和使用更大的卷积核来增加感受野。
实际的有效感受野是一个高斯分布,增大有效感受野:空洞卷积(不丢失分辨率(精确定位),扩大感受野(检测分割大目标))。
空洞卷积:在相同计算条件下,提供了更大感受野。空洞位置填0.
通过在原卷积核元素之间插入空格来使原卷积核扩张。扩张率(dilation rate)表示扩张程度。但是参数数量是一样的,不会增加卷积核的大小。
比较:一个5x5大小的区域经过2次3x3的卷积后,变成一个像素点;一个13x13大小的区域经过2次3x3的空洞卷积后,变成了一个像素点。
空洞卷积与普通卷积相比:卷积核大小一样,即参数数量一样,输出的特征图大小一样,区别在于空洞卷积在不做pooling损失信息的情况下有更大的感受野,
扩张率:卷积核个元素之间间隔数量。显然普通卷积核的扩张率为0,感受野3x3;
空洞卷积感受野计算公式:
F = (2log2rate+2 - 1) x (2log2rate+2 - 1)
普通卷积,扩张率为1,感受野3x3;扩张率为2,感受野为7x7;扩张率为4,感受野为15x15;
将池化后的像素拉开,变成一维向量,方便输入到全连接层。
将无序的序列调整为有序序列,
冒泡排序,选择排序,插入排序,希尔排序,
1.冒泡排序(bubble sort):比较相邻两个元素的大小,前一个比后一个大,则交换元素,
1 | '''冒泡排序''' |
1 | class Solution { |
2.选择排序(selection sort):每次假定一个数最小,然后,再找一个最小的,如果有,就交换。
1.先在未排序序列中找到最小元素,放到数组第一个位置,从剩余未序列序列中找最小元素,然后放到已排序序列的末尾。
1 | '''选择排序''' |
1 | class Solution { |
3.插入排序(insertion sort): 将数组分为两个部分,前面是有序部分,后面是无序部分,每次从无序部分从前往后拿一个数,在有序部分从后向前比较,找到位置插入。
在前面已排序数组找到插入位置。
1 | def insert_sort(nums): |
1.快速排序(quick_sort):使用分治的思想,把一个序列分成较小和较大两个序列。
挑选左边第一个元素为基准,进行分割,所有比基准小的放在基准前面,反之放基准后面,对基准的排序完成;递归的将小于基准的子序列和大于基准的子序列分别排序,同样的方法;递归结束的边界条件是序列的大小是1或0(显然已有序)。
1 | def quick_sort(nums): # 快排python |
1 | class Solution { //快排C++ |
冒泡,选择,插入,都有两个for循环,所以时间复杂度为O(n2),
快排因为有一个for循环,所以有n,再每次循环有一次减半,log,故为nlogn
学习计算机科学知识,有过很多想法,就我感受而言,如果一开始就拿书啃,我是根本看不下去的,看少了没用,看多了助眠。我曾啃过,计算机科学导论,Python编程,等书,过程是很痛苦的,事后也没记住。现在想来,大概是低效的学习。总结一句话,任何无法学以致用的知识都会迅速被忘记。
对我而言,最高效的学习方法就是做一个有难度的项目。遇到问题,先有一个尝试,一定要知道为什么行得通或为什么行不通,只有知道一个方法为什么有效或不有效,何时有效何时无效,才能增进对这个问题的理解,然后基于此提出有价值的策略。此刻去有针对性的查阅,这时我会找到答案,会很兴奋。
比如我当年学习python,就是通过一个爬虫,然后现在也是做项目的过程中,学习到各种操作。
比如numpy,pandas,sklearn,tensorflow,都是在做项目的过程中,学会的。
基本过程就是,先做,然后一点点优化。
我提升最大的时候是做LR的时候,作完LR,从效率上看,通过这样一个项目,完爆了我啃书,抄作业的花费精力学习。
书该看的时候还是要看的,但是要讲时机,讲方法,要带着目的去看。
编程类的大部分书应该当作字典来用,它有系统性的指南,当在任何一方面遇到问题,难查到百度不到的知识,这是它的价值。
开始的时候,先有一个粗略的了解,再去实践,再填补细节。
说到神经网络,先说神经网络解决的两个大的问题,分类和回归。
回归问题,预测出一个连续数值,神经网络是怎么做的?首先,确定几层hidden layer,每层隐藏层有多少个神经元,如2层隐藏层,第一层32各神经元,第二层64各神经元,在输入层确定输入的特征向量,特征有多少维,就有多少个输入节点,如特征总共15维,就有15个输入节点,这15个特征值乘以对应权重,组成一个线性回归模型,然后经过relu激活函数激活,成为神经元节点的值,对每一个神经元进行这个操作,确定输出层一个节点,是倒数第二层隐藏层所有神经元乘以对应权重的线性回归模型,得到输出值,一次前向传播完成,预测值和标签值是有误差的,用MSE均方差来衡量这个误差大小,同时这是一个2次函数,所以是凸函数,有全局最小值,开始优化模型参数,梯度下降法(数据量大就用随机梯度下降,数据量小可以用批量梯度下降),原理是,以3层隐藏层举例,第2层隐藏层函数由第一层含权重w1组成,第3层隐藏层函数由第2层和第1层权重w2和w1组成,于是,对w3求一阶偏导得到第3层权重w3的梯度,对该梯度再求w2的梯度得第2层w2的梯度,同理得w1梯度,根据链式法则,因此w3的值是根据w2得到,w2由w1得到,得到梯度后,开始沿着负梯度方向以特定步长(步长大小应该先大后小)开始迭代更新参数,直至MSE最小,当MSE逐渐稳定时,输出此时的模型参数,模型训练完毕。
设计一个回归神经网络模型:先初始化一批权重向量,拥有一篇特征向量(即训练数据),1.设计一个线性回归模型,2.设计一个relu激活函数用来激活,3.设计一个求输出层值的函数,4.设计一个MSE函数求预测值与真实值的MSE,作为损失函数,5.设计一个求关于权重参数的偏导函数,6.设计一个迭代权重参数函数,迭代更新每一个权重参数
神经网络层数一般1~2层隐藏层即可很好拟合,强如yolov1也只用了2层全连接神经网络。
分类问题,预测一个概率值,它会预测出Item是属于哪个分类的概率,如yolov1中,就是预测20个种类的item的概率,神经网络是怎么做的?首先,是确定几层hiddenlayer,每层隐藏层有多少个神经元,然后确定输入的特征向量有多少维度,就有多少输入节点,乘以对应权重参数,组成一个线性回归模型,然后经过sigmoid激活函数激活,(这里sigmoid函数输出值正好是(0,1)之间,正好是一个概率的取值,故用sigmoid函数),成为神经元节点的值,对每一个神经元进行这个操作,确定输出层的多个节点,如20分类就有20个输出节点,倒数第二层所有神经元乘以对应权重,得到对应20个输出值,然后对20个输出值输入softmax操作,转换成20个item的每个Item的概率,而标签是一种分类,分类和概率无法衡量误差,回到神经网络核心,我们是要找到一组最能正确表现(既不过拟合也不欠拟合)模型的模型参数,问题转化为,我们希望找到一组参数,最大概率的生成当前样本,于是求得似然函数,取对数,然后加上负号除以样本个数变为损失函数(又叫交叉熵损失函数),求最大似然转化为求损失函数最小值,然后对每个权重参数求一阶偏导数,还是根据链式法则,求出所有权重参数的梯度,然后沿负梯度方向以特定步长开始迭代更新参数。
设计一个分类神经网络模型:先初始化一批权重向量,拥有一篇特征向量(即训练数据)1.设计一个线性回归模型,2.设计一个sigmoid激活函数用来激活,3.设计一个softmax函数用来求各分类的概率,4.设计一个似然函数,后变成损失函数,5.设计一个求关于权重参数的偏导函数,6.设计一个迭代权重参数函数,迭代更新每一个权重参数
CNN用于处理图片,提取图像特征方法,没有时序概念,不考虑数据之间的关联性,没有记忆能力,输入和输出格式都是固定的,
RNN用于处理时序数据,某一时刻输出和当前时刻还和之前某几个时刻的输出相关,有记忆能力,做语音识别或机器翻译时,如:处理一句话,RNN提取特征时会考虑某个词和前后词的关系。
如:进行图像识别时,我们并不在意前一个决策结果是什么,用CNN,但是自然语言处理时,上一个词很大程度影响了下一个词,”词不离句”,这是有相关性的,用RNN。
这两者结合起来,就是CNN=眼睛,RNN=嘴巴耳朵。
最简单的RNN,有一个上个传递值,当前输入,然后经过一个线性组合。
1.过拟合原因:数据太少,模型太复杂。
解决办法:1.增加训练数据;2.降低模型复杂度:增加正则化参数,约束权重参数不会太大;在神经网络中,dropout随机忽略掉一部分神经元,如dropout=0.2;在神经网络中,减少隐藏层和神经元个数。
防止过拟合:加入正则化参数,
过拟合表现:低偏差,高方差。偏差(预测值与实际值的偏差程度,即拟合能力),方差(数据变化时的影响)。
欠拟合原因:模型太简单。
解决办法:增加新特征,减小正则化参数,使用更复杂的模型,如集成学习,深度学习模型。
欠拟合表现:高偏差,低方差
2.分类问题评价指标
对于二分类问题,可以用混淆矩阵,精确率和召回率,
P=TP/(TP+FP),R=TP/(TP+FN)
回归问题评价指标:MSE,MAE适用误差相对明显,RMSE适用误差不是很明显
两个思考题:
1.有25匹马,一个赛场,赛场有5个跑道,要比赛找出前3名,问充分必要条件最少需要多少场。
要求,不允许记时,可以推导,比如A>B, B>C => A>C。
答案:7种,1.先分成5组ABCDE,跑出5个第一名(A1,B1,C1,D1,E1),2.然后5个第一名跑一次,跑出全局第一名,3.去掉最后两个第一名的那两组,然后让全局第一名的第二名和5个第一名的2和3名的第2名,加起来5个一起跑,第1和1名就是全局第2和3名,共7次。
2.给一个方法,找出字符串中包含所有指定字母的最小子串?
如aaacbcaabdfafsfa中,包含字母ab的最小子串是ab,包含字母sbf的最小子串是bdfafs,不需要考虑顺序
编程题python版本:
#编程题:两个有序(从小到大)单链表,合并为一个有序的单链表,不要使用递归
class ListNode:
def init(self, x):
self.val = x
self.next = None
def mergeTwoLists(list1, list2):
return None
1 | class ListNode: |
#编程题:求二叉树中节点的最大距离,即二叉树中相距最远的两个节点之间的距离。
class TreeNode(object):
def init(self, x):
self.val = x
self.left = None
self.right = None
def GetMaxDistance(oNode):
return 0
1 | class TreeNode(object): |

节点的最大距离,附图这棵树,返回4

数组是一种顺序表,在内存中是一串连续的一套地址,用来存储数据,是1对1的数据结构。
在python中,数组list是天生的动态数组,在java里面叫做arraylist。
连续存储。
在java或者C++中,数组只能存放同一种类型的数据,但python中可以存放各种类型数据。
这是因为python数组中存放的是数据存放的地址,地址的数据类型是一样的,而数组中存放地址的地址自然也是连续的,这样就实现了用数组存放各种类型数据。
但同时也会造成一个问题,就是花费了更大的存储开销,而且当要用到2维数组即矩阵,或者更高维数组如n维张量时,这种结构显然低效,而且python也不支持多维数组,也没有各种运算函数,但用C语言写的numpy解决了这些问题,numpy支持n维数组,即支持ndarray,因为最低是二维数组,二维数组即是矩阵,故可看作numpy支持矩阵以及矩阵运算,也就是说,哪怕在numpy写一个1维数组,那它也是行矩阵或列矩阵,当然三维数组就是将矩阵(二维数组)放在了一个更大的数组里面,可依次类推。
同时numpy也支持各种针对n维数组的运算,提供大量n维数组运算的函数库。但是numpy是不支持gpu加速运算的,因此使用tensorflow通过gpu加速。一般当数组维度达到3维及以上时,可以叫做张量(tensor).
在tensorflow中,所有数组都可以叫做tensor,
如:1维数组=1维张量,二维数组=矩阵=2维张量,三维数组=3维张量,依此类推。
因此业界一般使用tensorflow-gpu来进行张量计算,但是numpy可用来进行数据预处理,并且numpy的ndarray也能被tensorflow转化为tensor使用。
一维数组存储地址计算:a[i]为,数组首地址+i*一个数组元素字节所占长度。
1.增加元素分3种:
增加方式 | 代码 | 时间复杂度 |
---|---|---|
尾部增加 | list.append(‘item’) | O(1) |
头部增加 | list.insert(0,’item’) | O(n) |
中间增加 | list.insert(2,’item’) | O(n) |
2.删除元素分3种:
增加方式 | 代码 | 时间复杂度 |
---|---|---|
尾部删除 | list.pop() | O(1) |
头部删除 | list.pop(0) | O(n) |
中间删除 | list.pop(2) | O(n) |
3.修改元素:时间复杂度O(1),按索引修改
如:list[0] = ‘item2’
4.查找元素:时间复杂度O(1),按索引查找,
如:list[0] = ‘item2’
为什么python数组增删时间复杂度是O(n)?
因为增删时数据的拷贝覆盖,如头部增加就要把所有数组元素向后移动一个位置,然后再把元素增加到头部,中间增加是相同的道理。
基于此,若增删操作很少,查改操作很多,又不会out of memory,可采用数组存储数据。
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true