MiniFlow -- 5.Sigmoid Funcition

前几节写了线性方程,但是如果我们想预测概率,可能梯度爆炸,于是我们使用激活函数对输出进行约束
如我们使用sigmoid
在这里插入图片描述
sigmoid可以将输出约束到0到1
线性变换对于简单的线性计算是非常有效的,但是神经网络需要更为复杂的计算。对于一个原始的神经网络设计:感知器,表现为二进制,这里会设计一些阈值和权重,当输入太大的话,就输出1,输入太小的话就输出0,但是二进制感知器是不连续的。
sigmoid函数是完美的连续s函数
在这里插入图片描述

根据求导数的规则,sigmoid的导数为
在这里插入图片描述
我们使用numpy来实现sigmod函数

    def _sigmoid(self, x):
        return 1./(1+np.exp(-x))

在代码里实现了sigmod类,于是网络结构成了
Input >Linear>sigmod
对于Input来说只有outbound_nodes(Linear)
Linear包含inbound_nodes(Input)和outbound_nodes (Sigmod)
Sigmod只有inbound_nodes(Linear),

在这里插入图片描述

于是我们来重新分析一下topological_sort
这时候G的内容如下
G是一个字典,key是每一个节点,value是其输入和输出的列表,可以看到, set()是无需不重复列表
Input节点没有输入,输出是Linear
Linear的输入是Input列表,输出是一个Sigmoid节点
Sigmoid没有输出,输入是Linear

{
	<miniflow.Input object at 0x000002291D228588>: 
		{'in': set(), 'out': {<miniflow.Linear object at 0x000002291EF64208>}}, 
	<miniflow.Linear object at 0x000002291EF64208>: 
		{'in': {<miniflow.Input object at 0x000002291D228588>, <miniflow.Input object at 0x000002291D330888>, <miniflow.Input object at 0x000002291D26BD88>}, 'out': {<miniflow.Sigmoid object at 0x000002291EFD6BC8>}}, 
	<miniflow.Input object at 0x000002291D26BD88>:
		{'in': set(), 'out': {<miniflow.Linear object at 0x000002291EF64208>}},
	<miniflow.Input object at 0x000002291D330888>: 
		{'in': set(), 'out': {<miniflow.Linear object at 0x000002291EF64208>}}, 
	<miniflow.Sigmoid object at 0x000002291EFD6BC8>: 
		{'in': {<miniflow.Linear object at 0x000002291EF64208>}, 'out': set()}
}

L是节点列表,表示节点计算顺序

[
	<miniflow.Input object at 0x0000021FB7628A88>, 
	<miniflow.Input object at 0x0000021FB76E7208>,
	<miniflow.Input object at 0x0000021FB57B6948>, 
	<miniflow.Linear object at 0x0000021FB9338B08>, 
	<miniflow.Sigmoid object at 0x0000021FB753B7C8>
]

nn.py


from miniflow import *
import numpy as np


if __name__ == "__main__":
    X, W, b = Input(), Input(), Input()
    f = Linear(X, W, b)
    g = Sigmoid(f)
    # 2*2 行批次,列特征
    X_ = np.array([[-1., -2.], [-1, -2]])
    # 行特征,列输出特征数量
    W_ = np.array([[2., -3], [2., -3]])
    b_ = np.array([-3., -5])


    feed_dict = {X: X_, W: W_, b: b_}
    graph = topological_sort(feed_dict)
    output = forward_pass(g, graph)

    print(output)

miniflow.py

import numpy as np

class Node(object):
    def __init__(self, inbound_nodes=[]):
        # 输入节点列表 用户前向计算
        self.inbound_nodes = inbound_nodes
        # 输出节点列表 用户反向传播
        self.outbound_nodes = []
        # A calculated value 本节点的计算值
        self.value = 0
        # Add this node as an outbound node on its inputs.
        # 将本节点作为输入节点的输出节点
        for n in self.inbound_nodes:
            n.outbound_nodes.append(self)

    def forward(self):
        """
        Forward propagation 虚函数
        前向运算 基于 inbound_nodes 输入节点列表的 value 计算输入节点列表的输出值
        存储在 self.value
        :return:
        """
        raise NotImplemented


class Input(Node):
    def __init__(self):
        """
        Input node 没有 inbound nodes ,他是整个神经网络的开始
        因此不需要进行任何操作
        """
        # 输入节点列表为空
        Node.__init__(self)

    def forward(self):
        pass

class Linear(Node):
    def __init__(self, X, W, b):
        # Notice the ordering of the inputs passed to the
        # Node constructor.
        Node.__init__(self, [X, W, b])

    def forward(self):
        X = self.inbound_nodes[0].value
        W = self.inbound_nodes[1].value
        b = self.inbound_nodes[2].value
        self.value = np.dot(X, W) + b


class Sigmoid(Node):
    def __init__(self, node):
        Node.__init__(self, [node])

    def _sigmoid(self, x):
        return 1./(1+np.exp(-x))

    def forward(self):
        x = self.inbound_nodes[0].value

        self.value = self._sigmoid(x)


"""
Can you augment the Add class so that it accepts
any number of nodes as input?

Hint: this may be useful:
https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists
"""


class Add(Node):
    def __init__(self, *inputs):
        """
        You could access x and y in forward with
        self.inbound_nodes[0] (x) and self.inbound_nodes[1](y)
        这里我们要计算x和y的和,那么输入节点就是x,y,那么x,y 就是本届点的输入节点,也就是self.inbound_nodes[0]
        :param x: Node input
        :param y: Node input
        """
        Node.__init__(self, inputs)

    def forward(self):
        for n in self.inbound_nodes:
            self.value += n.value


def topological_sort(feed_dict):
    """
    我们将所有节点构成一个graphs,一个计算图
    :param feed_dict: 这个一个输入节点的字典,key 是Input node value 是初始化的值
    :return: 返回一个序列化的节点列表
    """
    # 提取所有输入节点
    input_nodes = [n for n in feed_dict.keys()]
    G = {}
    # 所有输入节点列表
    nodes = [n for n in input_nodes]
    # 这里将所有输入节点和输出节点作为G的key node, value也是一个字典,in记录key node的所有输入节点列表,out记录key node 的所有输出节点列表
    # 其中一个G的一个元素如下,node 可以是Input 也可以是Add, 如果node是Input 那么in为空,如果node是末尾节点,out为空
    # 如果node是中间节点,name in是输入节点列表, out就是输出节点
    #       |-in list         |-in list
    # node1 |           node2 |
    #       |-out list        |-out list

    while len(nodes) > 0:
        # 从头部弹出一个节点 node
        n = nodes.pop(0)
        if n not in G:
            G[n] = {"in": set(), "out": set()}
        for m in n.outbound_nodes:
            if m not in G:
                G[m] = {"in": set(), "out": set()}
            G[n]["out"].add(m)
            G[m]["in"].add(n)
            nodes.append(m)

    L = []
    # 无序不重复
    S = set(input_nodes)
    # 这里序列化L,L为 input input out
    while len(S) > 0:
        n = S.pop()
        # 给输入节点赋值,如果n节点是输入节点,就将赋值
        if isinstance(n, Input):
            n.value = feed_dict[n]
        # 将节点n加到L中
        L.append(n)
        # 检查当前的节点的输出节点,n 可能是 Input Add,或者隐藏层 最后一层的节点没有outbound_nodes
        for m in n.outbound_nodes:
            # 删除当前节点中的输出
            G[n]["out"].remove(m)
            # 删除输出节点中的输入
            G[m]['in'].remove(n)
            # 如果 G[m]["in"] 为空的时候说明输入都添加完了,将输出添加到最后
            if len(G[m]["in"]) == 0:
                S.add(m)
    return L


def forward_pass(output_node, sorted_nodes):
    """
    Performs a forward pass through a list of sorted nodes.
    :param output_node: A node in the graph, should be the output node(have no outgoing edges)
    :param sorted_nodes: A topologically sorted list of nodes.
    :return: the out
    """
    for n in sorted_nodes:
        n.forward()

    return output_node.value
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值