解析深度学习入门代码f = lambda w: net.loss(x, t)

    在学习 深度学习入门:基于python的理论与实现 第四章时,求损失函数对应神经网络权重的梯度遇到该代码,惑之,故研之。

一、先来看一个lambda简单例子
def my_test(x):
   # 代码3
   print("my_test")
   return x

if __name__ == "__main__":
   f = lambda x : my_test(x) # 代码1
   print(f(2))  # 代码2

解析:

f = lambda x:my_test(x)   # 代码1
等价于
def f(x):
	return my_test(x)

这里利用lambda匿名函数定义了一个函数f,匿名函数转正,有名字了,函数形参为x,函数体是冒号后面的部分。注意这里只是定义了函数f,没有进行调用。

print(f(2))  # 代码2

这里调用函数f,跳转到定义f的地方执行(代码1处),并将实参2传给形参x。之后代码1处执行函数体,调用my_test函数(代码3)。
代码3执行结束返回到代码1处,代码1处再将返回值给代码2。
总结执行流程:

调用过程:1-->2-->1-->3
返回过程:3-->1-->2
二、损失函数对权重的梯度解析
f = lambda w: net.loss(x, t)  # 定义函数f
等价于
def f(w):
	return net.loss(x, t)
dW = numerical_gradient(f, net.W)

解析:当调用 numerical_gradient(f,x)函数时,形参f接收实参f,形参x接收网络权重net.W;在该函数里使用numpy的迭代器遍历x(源net.W)数组,并修改索引idx对应的权重值。当执行到fxh1=f(x)时,首先会调用f,将实参x(被修改过的net.W)传给形参w,之后执行函数体net.loss(x, t)计算损失,将损失返回给numerical_gradient函数里的fxh1。fxh2=f(x)同理。之后利用损失fxh1和损失fxh2计算与之相对应权重的偏导数。使用迭代器继续循环,直到将x(net.W)遍历结束,损失关于net.W的所有偏导数计算完成,最后将梯度返回给dW。打印输出。
    影响过程:修改权重net.W,直接影响原始输出值z,z再影响y,之后用y来计算损失函数的值来改变loss的值,最后用loss来计算偏导数。就可以得到损失函数loss对权重net.W的梯度。

源文件:gradient_simpleNet.py
# -*- coding: utf-8 -*-
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录中的文件而进行的设定
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient


class simpleNet:
    def __init__(self):
        self.W = np.random.randn(2,3)  # 初始化权重,2*3的权重

    def predict(self, x):
        return np.dot(x, self.W)  # 关键步骤,这里会使用修改过的权重进行计算

    def loss(self, x, t):
        z = self.predict(x)  # 原始输出
        y = softmax(z)  # 输出层激活函数处理
        loss = cross_entropy_errorvv(y, t)  # 计算损失函数的值
        return loss
        
if __name__ == "__main__":
	x = np.array([0.6, 0.9])  # 输入
	t = np.array([0, 0, 1])  # 监督数据
	
	net = simpleNet() 
	
	f = lambda w: net.loss(x, t)  # 定义函数f
	dW = numerical_gradient(f, net.W)  # 计算损失函数对权重的梯度
	
	print("dw:", dW)
源文件:gradient.py
# -*- coding:utf-8 -*-
import numpy as np


def numerical_gradient(f, x):
    """
    求解f关于x的梯度,通过numpy提供的迭代器,不管x是一维还是二维都可以计算;
    因为通过迭代器可以一个一个元素的读取计算。
    """

    h = 1e-4
    grad = np.zeros_like(x)  # 初始化梯度为0
    
    it = np.nditer(x, flags=["multi_index"], op_flags=['readwrite'])  # 创建迭代器
    while not it.finished:
        idx = it.multi_index  # 获取元素对应的索引(行索引,列索引)
        tmp_val = x[idx]  
        x[idx] = float(tmp_val) + h  # 修改x
        fxh1 = f(x)  # f(x+h)  # 计算修改x后对应的函数值
        x[idx] = float(tmp_val) - h
        fxh2 = f(x)  # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)  # 计算偏导数
        x[idx] = tmp_val   # 还原该x[idx]值
        it.iternext()  # 遍历下一个值
    return grad

if __name__ == "__main__":
    pass
  • 19
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 21
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值