深度学习组件手动实现

Posted anie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习组件手动实现相关的知识,希望对你有一定的参考价值。

卷积

import numpy as np
input_data=[
              [[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+rs   

    return outputs

def 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=[
               [[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 rs

def 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 np

def 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.8  0.92 0.72 0.81 0.9 ]    
    #  对应的索引index[  2   5    4     1    3   0  ]记住是取出索引,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_var

    x_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_param

def 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

以上是关于深度学习组件手动实现的主要内容,如果未能解决你的问题,请参考以下文章

阿里PAI深度学习组件:Tensorflow实现图片智能分类实验

深度学习100例 | 第4例:水果识别 - PyTorch实现

深度学习100例 | 第4例:水果识别 - PyTorch实现

深度学习100例 | 第2例:人脸表情识别 - PyTorch实现

深度学习100例 | 第2例:人脸表情识别 - PyTorch实现

深度学习100例 | 第3天:交通标志识别 - PyTorch实现