深度学习组件手动实现

卷积

import numpy as np input_data=https://www.it610.com/article/[ [[1,0,1,2,1], [0,2,1,0,1], [1,1,0,2,0], [2,2,1,1,0], [2,0,1,2,0]],[[2,0,2,1,1], [0,1,0,0,2], [1,0,0,2,1], [1,1,2,1,0], [1,0,1,1,1]] ] weights_data=[ [[ 1, 0, 1], [-1, 1, 0], [ 0,-1, 0]], [[-1, 0, 1], [ 0, 0, 1], [ 1, 1, 1]] ]#fm:[h,w] #kernel:[k,k] #return rs:[h,w] def compute_conv(fm,kernel): [h,w]=fm.shape [k,_]=kernel.shape r=int(k/2) #定义边界填充0后的map padding_fm=np.zeros([h+2,w+2],np.float32) #保存计算结果 rs=np.zeros([h,w],np.float32) #将输入在指定该区域赋值,即除了4个边界后,剩下的区域 padding_fm[1:h+1,1:w+1]=fm #对每个点为中心的区域遍历 for i in range(1,h+1): for j in range(1,w+1): #取出当前点为中心的k*k区域 roi=padding_fm[i-r:i+r+1,j-r:j+r+1] #计算当前点的卷积,对k*k个点点乘后求和 rs[i-1][j-1]=np.sum(roi*kernel) return rs def my_conv2d(input,weights): [c,h,w]=input.shape [_,k,_]=weights.shape outputs=np.zeros([h,w],np.float32)#对每个feature map遍历,从而对每个feature map进行卷积 for i in range(c): #feature map==>[h,w] f_map=input[i] #kernel ==>[k,k] w=weights[i] rs =compute_conv(f_map,w) outputs=outputs+rsreturn outputsdef main():#shape=[c,h,w] input = np.asarray(input_data,np.float32) #shape=[in_c,k,k] weights =np.asarray(weights_data,np.float32) rs=my_conv2d(input,weights) print(rs) if __name__=='__main__': main()

反卷积(反卷积=卷积+填充+裁剪)
input_data=https://www.it610.com/article/[ [[1,0,1], [0,2,1], [1,1,0]],[[2,0,2], [0,1,0], [1,0,0]],[[1,1,1], [2,2,0], [1,1,1]],[[1,1,2], [1,0,1], [0,2,2]]] weights_data=[ [[[ 1, 0, 1], [-1, 1, 0], [ 0,-1, 0]], [[-1, 0, 1], [ 0, 0, 1], [ 1, 1, 1]], [[ 0, 1, 1], [ 2, 0, 1], [ 1, 2, 1]], [[ 1, 1, 1], [ 0, 2, 1], [ 1, 0, 1]]],[[[ 1, 0, 2], [-2, 1, 1], [ 1,-1, 0]], [[-1, 0, 1], [-1, 2, 1], [ 1, 1, 1]], [[ 0, 0, 0], [ 2, 2, 1], [ 1,-1, 1]], [[ 2, 1, 1], [ 0,-1, 1], [ 1, 1, 1]]] ]#根据输入map([h,w])和卷积核([k,k]),计算卷积后的feature map import numpy as np def compute_conv(fm,kernel): [h,w]=fm.shape [k,_]=kernel.shape r=int(k/2) #定义边界填充0后的map padding_fm=np.zeros([h+2,w+2],np.float32) #保存计算结果 rs=np.zeros([h,w],np.float32) #将输入在指定该区域赋值,即除了4个边界后,剩下的区域 padding_fm[1:h+1,1:w+1]=fm #对每个点为中心的区域遍历 for i in range(1,h+1): for j in range(1,w+1): #取出当前点为中心的k*k区域 roi=padding_fm[i-r:i+r+1,j-r:j+r+1] #计算当前点的卷积,对k*k个点点乘后求和 rs[i-1][j-1]=np.sum(roi*kernel) return rs #填充0 def fill_zeros(input): [c,h,w]=input.shape rs=np.zeros([c,h*2+1,w*2+1],np.float32)for i in range(c): for j in range(h): for k in range(w): rs[i,2*j+1,2*k+1]=input[i,j,k] return rsdef my_deconv(input,weights): #weights shape=[out_c,in_c,h,w] [out_c,in_c,h,w]=weights.shape out_h=h*2 out_w=w*2 rs=[] for i in range(out_c): w=weights[i] tmp=np.zeros([out_h,out_w],np.float32) for j in range(in_c): conv=compute_conv(input[j],w[j]) #注意裁剪,最后一行和最后一列去掉 tmp=tmp+conv[0:out_h,0:out_w] rs.append(tmp)return rs def main(): input=np.asarray(input_data,np.float32) input= fill_zeros(input) weights=np.asarray(weights_data,np.float32) deconv=my_deconv(input,weights)print(np.asarray(deconv))if __name__=='__main__': main()

Dropout
import numpy as npdef dropout(x, p, mode='train'): keep_prob = 1 - p if mode == 'train': x *= np.random.binomial(1, keep_prob, size=x.shape) else: x *= keep_prob return x --------------------- test = np.random.binomial(5, 0.5, 10)#伯努利二项式分布 print(test) 输出:[1 5 5 2 4 2 3 3 2 3] (一次抛5枚硬币,每枚硬币正面朝上概率为0.5,做10次试验,求每次试验发生正面朝上的硬币个数:)

IOU
def IOU(x1,y1,X1,Y1,x2,y2,X2,Y2): xx=max(x1,x2) XX=min(X1,X2) yy=max(y1,y2) YY=min(Y1,Y2) m=max(0,XX-xx) n=max(0,YY-yy) jiao=m*n bing=(X1-x1+1)*(Y1-y1+1)+(X2-x2+1)*(Y2-y2+1)-jiao#+1防止为0 return jiao/bing

NMS
def py_cpu_nms(dets, thresh): #首先数据赋值和计算对应矩形框的面积 #dets的数据格式是dets[[xmin,ymin,xmax,ymax,scores]....] x1 = dets[:,0] y1 = dets[:,1] x2 = dets[:,2] y2 = dets[:,3] areas = (y2-y1+1) * (x2-x1+1) scores = dets[:,4] print('areas',areas) print('scores ',scores) #这边的keep用于存放,NMS后剩余的方框 keep = []#取出分数从大到小排列的索引。.argsort()是从小到大排列,[::-1]是列表头和尾颠倒一下。 index = scores.argsort()[::-1] print(index) #上面这两句比如分数[0.72 0.80.92 0.72 0.81 0.9 ] #对应的索引index[254130]记住是取出索引,scores列表没变。#index会剔除遍历过的方框,和合并过的方框。 while index.size >0: print(index.size) #取出第一个方框进行和其他方框比对,看有没有可以合并的 i = index[0]# every time the first is the biggst, and add it directly#因为我们这边分数已经按从大到小排列了。 #所以如果有合并存在,也是保留分数最高的这个,也就是我们现在那个这个 #keep保留的是索引值,不是具体的分数。 keep.append(i) print(keep) print('x1',x1[i]) print(x1[index[1:]]) #计算交集的左上角和右下角 #这里要注意,比如x1[i]这个方框的左上角x和所有其他的方框的左上角x的 x11 = np.maximum(x1[i], x1[index[1:]])# calculate the points of overlap y11 = np.maximum(y1[i], y1[index[1:]]) x22 = np.minimum(x2[i], x2[index[1:]]) y22 = np.minimum(y2[i], y2[index[1:]])print(x11,y11,x22,y22) #这边要注意,如果两个方框相交,X22-X11和Y22-Y11是正的。 #如果两个方框不相交,X22-X11和Y22-Y11是负的,我们把不相交的W和H设为0. w = np.maximum(0, x22-x11+1) h = np.maximum(0, y22-y11+1)#计算重叠面积就是上面说的交集面积。不相交因为W和H都是0,所以不相交面积为0 overlaps = w*h print('overlaps is',overlaps)#这个就是IOU公式(交并比)。 #得出来的ious是一个列表,里面拥有当前方框和其他所有方框的IOU结果。 ious = overlaps / (areas[i]+areas[index[1:]] - overlaps) print('ious is',ious)#接下来是合并重叠度最大的方框,也就是合并ious中值大于thresh的方框 #我们合并的操作就是把他们剔除,因为我们合并这些方框只保留下分数最高的。 #我们经过排序当前我们操作的方框就是分数最高的,所以我们剔除其他和当前重叠度最高的方框 #这里np.where(ious<=thresh)[0]是一个固定写法。 idx = np.where(ious<=thresh)[0] print(idx) #把留下来框在进行NMS操作 #这边留下的框是去除当前操作的框,和当前操作的框重叠度大于thresh的框 #每一次都会先去除当前操作框,所以索引的列表就会向前移动移位,要还原就+1,向后移动一位 index = index[idx+1]# because index start from 1 print(index) return keep

BatchNormalization
def Batchnorm_simple_for_train(x, gamma, beta, bn_param): """ param:x: 输入数据,设shape(B,L) param:gama : 缩放因子γ param:beta : 平移因子β param:bn_param: batchnorm所需要的一些参数 eps: 接近0的数,防止分母出现0 momentum : 动量参数,一般为0.9, 0.99, 0.999 running_mean :滑动平均的方式计算新的均值,训练时计算,为测试数据做准备 running_var: 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备 """ running_mean = bn_param['running_mean']#shape = [B] running_var = bn_param['running_var']#shape = [B] momentun = bn_param['momentun']#shape = [B] results = 0. # 建立一个新的变量x_mean=x.mean(axis=0)# 计算x的均值 x_var=x.var(axis=0)# 计算方差running_mean = momentum * running_mean + (1 - momentum) * x_mean running_var = momentum * running_var + (1 - momentum) * x_varx_normalized=(x - running_mean)/np.sqrt(running_var + eps)# 归一化 results = gamma * x_normalized + beta# 缩放平移#记录新的值 bn_param['running_mean'] = running_mean bn_param['running_var'] = running_var return results , bn_paramdef Batchnorm_simple_for_test(x, gamma, beta, bn_param): """ param:x: 输入数据,设shape(B,L) param:gama : 缩放因子γ param:beta : 平移因子β param:bn_param: batchnorm所需要的一些参数 eps: 接近0的数,防止分母出现0 momentum : 动量参数,一般为0.9, 0.99, 0.999 running_mean :滑动平均的方式计算新的均值,训练时计算,为测试数据做准备 running_var: 滑动平均的方式计算新的方差,训练时计算,为测试数据做准备 """ running_mean = bn_param['running_mean']#shape = [B] running_var = bn_param['running_var']#shape = [B] results = 0. # 建立一个新的变量x_normalized=(x-running_mean )/np.sqrt(running_var +eps)# 归一化 results = gamma * x_normalized + beta# 缩放平移return results , bn_param

    推荐阅读