<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Dropout
Dropout是一种用于深度神经网络的方法,用于避免过拟合.
在训练时,每次迭代中每层以提前设定的概率,称为keep_prob,来随机选择保留的节点,其他的节点在该次前向传播被忽略(设为0),同时在后向传播中也忽略.如下图中打叉的节点就是某次迭代中忽略的节点.  
作用,应用
Dropout主要有两个作用
Step2:  用pytorch来实现,尽量做到每层保留的节点为keep_prob * 节点数
Step4:  用numpy来实现,比较简单,当节点数量大时,随机的结果基本能够保证实际保留情况符合保留概率
<ASSISTANT_TASK:>
Python Code:
keep_prob = 0.5
do_dropout = True
Explanation: Dropout
Dropout是一种用于深度神经网络的方法,用于避免过拟合.
在训练时,每次迭代中每层以提前设定的概率,称为keep_prob,来随机选择保留的节点,其他的节点在该次前向传播被忽略(设为0),同时在后向传播中也忽略.如下图中打叉的节点就是某次迭代中忽略的节点.  
作用,应用
Dropout主要有两个作用:  
dropout在训练时每个迭代中相当于减小了网络规模,有正则化的作用.  
dropout可以避免把过多的权重放在某个节点上,而是把权重分散给全部的节点.   
在实践中,dropout在CV领域比较有效,因为数据输入一般是图片像素,维度很高,而网络层的形状,一般和输入形状相关,往往也很大.
Inverted Dropout
传统的dropout方法在训练时随机扔掉的节点,利用反向传播来更新保留的节点.但是在验证和测试的时候,会为每个节点乘以所在层的保留概率(keep_prob),这个操作叫做scale. 试想,每次使用模型预测的时候我们都要scale,比较麻烦.
Hinton等人提出inverted dropout,也就是在训练过程中,把保留的节点除以keep_prob,叫做inverted scale,来弥补随机扔掉的节点.这样,在验证和测试的时候,就不需要scale了.
参考
吴恩达老师解释dropout动机的视频
End of explanation
import torch
import copy
w1 = torch.randn(4, 4)  # 某层的weights
w = copy.deepcopy(w1)
w
def dropout_strict(w, keep_prob):
    implement inverted dropout ensuring that the share of kept neurons is strictly keep_prob.
    
    Args:
        w (torch.tensor) : weights before dropout
        keep_prob(float) : keep probability
    
    k = round(w.shape[1] * keep_prob)
    _, indices = torch.topk(torch.randn(w.shape[0], w.shape[1]), k)  
    keep = torch.zeros(4, 4).scatter_(dim=1, index=indices, src=torch.ones_like(w))  
    w *= keep
    w /= keep_prob
if do_dropout:
    dropout_strict(w, keep_prob)
    print(w)
Explanation: 用pytorch来实现,尽量做到每层保留的节点为keep_prob * 节点数
End of explanation
import numpy as np
import copy 
w1 = np.random.randn(4, 4)  # 某层的weights
w = copy.deepcopy(w1)
w
def dropout_loose(w, keep_prob):
    A simple Implementation of inverted dropout.
    
    Args:
        w(np.array) :- neurons subject to dropout
        keep_prob(float) :- keep probability
    
    keep =  np.random.rand(w.shape[0], w.shape[1]) < keep_prob
    w *= keep
    w /= keep_prob
    
if do_dropout:
    dropout_loose(w, keep_prob)
    print(w)
    
Explanation: 用numpy来实现,比较简单,当节点数量大时,随机的结果基本能够保证实际保留情况符合保留概率
End of explanation
<END_TASK>