《深度学习入门》-神经网络的梯度

 以下是书中给的这部分代码,我在学习中遇到的问题是net.W传递问题,即net.W是如何参与函数运算的,大家有其它的问题可以留言交流。

import sys, os
sys.path.append(os.pardir)
from common.functions import softmax, cross_entropy_error
import numpy as np
import matplotlib.pylab as plt

def numerical_gradient(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)
    
    # np.nditer是迭代器
    # flags=['multi_index']表示对a进行多重索引
    # op_flags=['readwrite']表示不仅可以对a进行read(读取),还可以write(写入),即相当于在创建这个迭代器的时候,我们就规定好了有哪些权限。
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:

        # 计算x+h处的函数值
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x) # f(x+h)
        
        # 计算x-h处的函数值
        x[idx] = tmp_val - h 
        fxh2 = f(x) # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)
        
        x[idx] = tmp_val # 还原值
        it.iternext()   
        
    return grad
# 建立类
class simpleNet:
    def __init__(self):
        self.W = np.random.randn(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_error(y, t) #输出一个值
        return loss

x = np.array([0.6, 0.9])#输入的图像数据
t = np.array([0, 0, 1])#正确标签

net = simpleNet()
# 求损失函数关于权重参数的梯度
f = lambda w: net.loss(x, t)
# print(f)
# def f(W):
#     return net.loss(x, t)
dW = numerical_gradient(f, net.W)

print(dW)

 下面从这一段代码给出解释:

f = lambda w: net.loss(x, t)
# 也可写为
def f(W):
    return net.loss(x, t)

 上面为lambda匿名函数,下面为有名字的函数,区别仅此而已。重点在于,这一函数的调用源于w的改变,这一点很重要。

接着是这一段代码: 

dW = numerical_gradient(f, net.W)

这一段代码是调用上一块定义的函数f,和随机生成的W数组。看到这里的时候,我很迷惑net.W是如何参与运算的,在这里废了不少时间,希望能给遇到同类问题的同学一点启发。

接着是调用:

 

idx = it.multi_index
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
这一段最后一句很容易让我们初学者摸不着头脑,因为上述定义的f在我们看来应该有两个参数x,t。而这两个参数已经定义好了,那么net.W怎么参与运算呢。
注意此时的net.W中的值已经发生改变

这就是答案:

class simpleNet:
    def __init__(self):
        self.W = np.random.randn(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_error(y, t) #输出一个值
        return loss

当调用f时,首先进行z的运算,此时调用predict函数进行矩阵乘法运算,注意,由于在上一步中net.W发生改变,这里self.W发生相应改变,所以每次输出的z值是不一样的!即每次返回的fxh1,fxh2值是不一样的!

至此问题解决,总结一下:

f作为形式上的损失函数,在w改变时被调用,然后真实的损失函数loss进行运算,由于self.W值改变,所以每次返回的值都不一样,最终获得损失函数关于权重的梯度值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值