grad在python什么模块_深度学习(Deep Learning)基础概念1:神经网络基础介绍及一层神经网络的python实现...

此专栏文章随时更新编辑,如果你看到的文章还没写完,那么多半是作者正在更新或者上一次没有更新完,请耐心等待,正常的频率是每天更新一篇文章。

该文章是“深度学习(Deep Learning)”系列文章的第一部分,首发于知乎的专栏“深度学习+自然语言处理(NLP)”。

该系列文章的目的在于理清利用深度学习进行自然语言处理的一些基本概念。

以下是相关文章的链接地址:

====================================================================

按照惯例先放出文章目录:推导 sigmoid函数的梯度

推导交叉熵函数关于softmax向量的梯度

推导包含一个隐藏层神经网络的梯度

神经网络参数的讨论

sigmoid函数及其梯度的python实现

梯度检查器的python实现

神经网络的正向和反向传递及其python实现

====================================================================

下面开始正文:

1. 推导sigmoid函数的梯度

我们想要推导sigmoid函数的梯度,并证明它的梯度的表达式可以用sigmoid函数表示(比较拗口,往下看)。

首先,sigmoid函数如下:

equation?tex=%5Csigma%28x%29+%3D+%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x%7D%7D

在我么开始求梯度之前,先弄清楚一个更重要的终极问题:sigmoid函数能干神马???

如果你把该函数在坐标轴上画出来,sigmoid函数长这个样子:

观察上面这张图,我们的问题迎刃而解:sigmoid函数能够把一个实数,转换成为[0-1]之间的数,也就是可以转换成概率!!!

了解了这个函数的意义比求梯度的意义重要一万倍!!!

下面求其梯度:

我们假设输入x是一个实数,那么对其求导得到

equation?tex=%5Csigma%27%28x%29+%3D+%5Cfrac%7Be%5Ex%7D%7B%7B%281%2Be%5E%7Bx%7D%29%7D%5E2%7D (这里我们只关注结果,忽略求导过程,如果读者读者感兴趣,可以自行计算),进而通过一些列计算,可以表示为

equation?tex=%5Csigma%27%28x%29+%3D+%5Csigma%28x%29%281-%5Csigma%28x%29%29

2. 推导交叉熵函数关于softmax向量的梯度

在自然语言处理(NLP)基础概念(一):词向量及其生成方法介绍的4.2节中,我们提到过连续袋模型,其中,为了评估预测值与真实值的差距,我们引入了测量函数:交叉熵(cross entropy)。

交叉熵就是计算真实值

equation?tex=y ,和预测值

equation?tex=%5Cbar+y 之间的‘距离’。

其中y是one-hot向量。

那么如果我们能够得到交叉熵对于输入矩阵

equation?tex=%5Ctheta 的梯度,并使其最小,那么本质上我们就是求得“什么样的

equation?tex=%5Ctheta 能够使交叉熵最小”。

很显然,这对训练神经网络模型意义重大。

这里,我们表示交叉熵函数如下:

equation?tex=H%28%5Cbar%7By%7D%2Cy%29+%3D+-+%5Csum_%7Bj%3D1%7D%5E%7B%7CV%7C%7D%7By_jlog%7B%5Cbar%7By_j%7D%7D%7D

那么对其求导能够得到(这里省略了求导过程):

equation?tex=H%28%5Cbar%7By%7D%2Cy%29+%3D+%5Cbar+y-y

这个结果说明,当预测值等于真实值时,梯度最小。

3. 推导包含一个隐藏层神经网络的梯度

推导包含一个隐藏层神经网络的梯度,也就是说得到

equation?tex=%5Cfrac%7B%5Cpartial+J%7D%7B%5Cpartial+x%7D ,其中

equation?tex=J%3DCE%28y%2C%5Cbar+y%29 ,是这个神经网络的测量函数。这里的x是输入层的输入。

而上面第二部分,我们是对

equation?tex=%5Ctheta 求导,是输出层的输入。

为了说清楚,用下图举例说明:

首先,让我们弄清楚一件事,x是输入层的输入,那么从输入层到输出层,x经历了什么呢?

见以下分割线包含的部分。

====================================================================

首先经历从输入层到隐藏层:先给x加权重和偏差:

equation?tex=z_1%3DxW_1%2Bb_1

equation?tex=z_1 代入激活函数(这里sigmoid是隐藏层的激活函数(activation function)得到

equation?tex=h%3Dsigmoid%28xW_1%2Bb_1%29

然后,从隐藏层的输出h到输出层的输出

equation?tex=%5Cbar+y经历了如下过程:同样增加权重和偏差:

equation?tex=z_2%3DhW_2%2Bb_2

equation?tex=z_2 代入激活函数(这里是softmax函数,见自然语言处理(NLP)基础概念(二):Softmax介绍及其python实现)就得到了我们的预测值,也就是输出层的输出值

equation?tex=%5Cbar+y

====================================================================

现在,我们要做的是,求测量函数对于x的梯度。而第二节中,我们求的是测量函数对于输出层的输入的梯度,也就是对于

equation?tex=z_2 的梯度。

现在我们开始推导:求

equation?tex=%5Cfrac%7B%5Cpartial%7BCE%7D%7D%7B%5Cpartial+x%7D 比较困难,而求

equation?tex=%5Cfrac%7B%5Cpartial+z_1%7D%7B%5Cpartial+x%7D 比较简单,所以我们利用链式法则(chain rule)得到:

equation?tex=%5Cfrac%7B%5Cpartial%7BCE%7D%7D%7B%5Cpartial+x%7D%3D%5Cfrac%7B%5Cpartial%7BCE%7D%7D%7B%5Cpartial+z_1%7D%5Cfrac%7B%5Cpartial%7Bz_1%7D%7D%7B%5Cpartial+x%7D

但是这里又遇到了同样的问题,求

equation?tex=%5Cfrac%7B%5Cpartial%7BCE%7D%7D%7B%5Cpartial+z_1%7D 比较困难。我们可以继续应用链式法则,这样一直应用,最后得到:

equation?tex=%5Cfrac+%7B%5Cpartial+CE%7D%7Bx%7D+%3D+%5Cfrac+%7B%5Cpartial+CE%7D%7Bz_2%7D+%5Cfrac+%7B%5Cpartial+z_2%7D%7Bh%7D+%5Cfrac+%7B%5Cpartial+h%7D%7Bz_1%7D+%5Cfrac+%7B%5Cpartial+z_1%7D%7Bx%7D+ 下面分别求这4个偏导数:

其中

equation?tex=+%5Cfrac+%7B%5Cpartial+CE%7D%7Bz_2%7D+我们已经在第二部分求过了,是

equation?tex=%5Cbar+y-y

根据矩阵求导法则

equation?tex=%5Cfrac+%7B%5Cpartial+z_2%7D%7Bh%7D+

equation?tex=W_2%5ET

求 h相对于

equation?tex=z_1的导数,这部分我们也已经得到了答案(见本文的第一部分),所以

equation?tex=%5Cfrac+%7B%5Cpartial+h%7D%7Bz_1%7D%3D%5Csigma%27%28z%29+%3D+%5Csigma%28z%29%281-%5Csigma%28z%29%29

同样根据矩阵求导法则,

equation?tex=+%5Cfrac+%7B%5Cpartial+z_1%7D%7Bx%7D+

equation?tex=W_1%5ET

问题迎刃而解!

这里,最重要的问题来了!!!求

equation?tex=%5Cfrac%7B%5Cpartial%7BCE%7D%7D%7B%5Cpartial+x%7D 的意义是什么???

问题的答案也显而易见,我们想知道,输入值是什么时,CE最小。

这也是测试函数CE的存在意义(回想一下测试函数的定义),输入等于什么的情况下,预测值

equation?tex=%5Cbar+y 和真实值

equation?tex=y 之间的‘距离’最小。

神经网络也是利用这一点优化模型参数,从而得到最好的结果。

4. 神经网络参数的讨论

Dx代表输入的维度, H代表隐藏层的神经元数量, Dy代表输出的维度,那么下图的神经网络中参数数量是多少呢?

先给出答案:(Dx+1)*H+(H+1)*Dy

首先,这是一个只有一层隐藏层的神经网络。

输入的维度是Dx的话,那么输入层的数量就是Dx+1,这里为什么+1,因为1乘以一个数就是一个实数,代表

equation?tex=z%3DWx%2Bb 中的b。

我们想知道的是参数的数量,也就是有多少W,有多少b。

很显然,Dx是多少就有多少W,b只有一个,所以对于一个神经元来说参数数量是Dx+1。

现在有H个神经元,那么参数数量就是(Dx+1)*H。

同样的道理,我们可以得出,从隐藏层到输出层有(H+1)*Dy个参数。

所以参数的总数量就是(Dx+1)*H+(H+1)*Dy。

这里还可以再进一步推导,如果我们有N个隐藏层,每一层有(1~m)个神经元呢?读者可以安装上面的思路自行推导。

5. sigmoid函数及其梯度的python实现

下面是sigmoid函数以及求其梯度的python代码,代码包括三个函数。

其中sigmoid(x)用来对x进行sigmoid。

sigmoid_grad(x)用来计算sigmoid函数的梯度。这里有个技巧,就是利用了文章第一部分的结论。

test_sigmoid_basic()函数提供了几个例子用于测试前两个函数。

脚本可以被直接执行:

if __name__ == "__main__":

上面这行代码的作用是“让你写的脚本模块既可以导入到别的模块中用,另外该模块自己也可执行。”(“Make a script both importable and executable”)如果还是不太明白可以看这篇文章。

import numpy as np

def sigmoid(x):

"""Compute the sigmoid function for the input here.Arguments:x -- A scalar or numpy array.Return:s -- sigmoid(x)"""

s = 1./(1.+np.exp(-x))

return s

def sigmoid_grad(s):

"""Compute the gradient for the sigmoid function here. Note thatfor this implementation, the input s should be the sigmoidfunction value of your original input x.Arguments:s -- A scalar or numpy array.Return:ds -- Your computed gradient."""

ds = s*(1-s)

return ds

def test_sigmoid_basic():

"""Some simple tests to get you started.Warning: these are not exhaustive."""

print "Running basic tests..."

x = np.array([[1, 2], [-1, -2]])

f = sigmoid(x)

g = sigmoid_grad(f)

print f

f_ans = np.array([

[0.73105858, 0.88079708],

[0.26894142, 0.11920292]])

assert np.allclose(f, f_ans, rtol=1e-05, atol=1e-06)

print g

g_ans = np.array([

[0.19661193, 0.10499359],

[0.19661193, 0.10499359]])

assert np.allclose(g, g_ans, rtol=1e-05, atol=1e-06)

print "You should verify these results by hand!\n"

if __name__ == "__main__":

test_sigmoid_basic();

6. 梯度检查器的python实现

为了方便以后检查梯度是否正确,利用导数的定义对梯度进行验证,以下是python实现:

import numpy as np

import random

# First implement a gradient checker by filling in the following functions

def gradcheck_naive(f, x):

""" Gradient check for a function f.Arguments:f -- a function that takes a single argument and outputs thecost and its gradientsx -- the point (numpy array) to check the gradient at"""

rndstate = random.getstate()

random.setstate(rndstate)

fx, grad = f(x) # Evaluate function value at original point

h = 1e-4 # Do not change this!

# Iterate over all indexes in x

# flags=['multi_index'] can get all dimension index

# Set op_flags to make array readable and writable.

it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])

while not it.finished:

ix = it.multi_index

# Try modifying x[ix] with h defined above to compute

# numerical gradients. Make sure you call random.setstate(rndstate)

# before calling f(x) each time. This will make it possible

# to test cost functions with built in randomness later.

random.setstate(rndstate)

tmp1 = np.copy(x)

tmp1[ix] = tmp1[ix] + h

f1, _ = f(tmp1)

random.setstate(rndstate)

tmp2 = np.copy(x)

tmp2[ix] = tmp2[ix] - h

f2, _ = f(tmp2)

numgrad = (f1 - f2) / (2 * h)

print(numgrad,grad[ix])

print(max(1,abs(numgrad), abs(grad[ix])))

# Compare gradients

reldiff = abs(numgrad - grad[ix]) / max(1, abs(numgrad), abs(grad[ix]))

if reldiff > 1e-5:

print "Gradient check failed."

print "First gradient error found at index%s" % str(ix)

print "Your gradient:%f\tNumerical gradient:%f" % (

grad[ix], numgrad)

return

it.iternext() # Step to next dimension

print "Gradient check passed!"

def sanity_check():

"""Some basic sanity checks."""

quad = lambda x: (np.sum(x ** 2), x * 2)

print "Running sanity checks..."

gradcheck_naive(quad, np.array(123.456)) # scalar test

gradcheck_naive(quad, np.random.randn(3,)) # 1-D test

gradcheck_naive(quad, np.random.randn(4,5)) # 2-D test

print ""

if __name__ == "__main__":

sanity_check()

这里包括两个函数,gradcheck_naive(f, x)用于检查梯度,def sanity_check()用于生成几个例子进行测试。

gradcheck_naive(f, x)的主要思想是‘用定义求出来的导数’和‘用我们自己写的函数求出来的导数’进行对比,如果结果不相等(代码中是比对结果> 1e-5)就报错。

这里我们利用一个简单的函数

equation?tex=f%28x%29%3Dx%5E2 进行测试,我们知道它的导数是

equation?tex=f%27%28x%29%3D2x

这个测试函数的python实现为:quad = lambda x: (np.sum(x ** 2), x * 2)

如果不明白lambda的作用,看这里。

在gradcheck_naive(f, x)函数中,我们首先定义一个极小的变量h = 1e-4

那么根据导数的定义,f(x)=(f(x+h)-f(x-h))/2h

上述定义的python实现是下面这段代码:

random.setstate(rndstate)

tmp1 = np.copy(x)

tmp1[ix] = tmp1[ix] + h

f1, _ = f(tmp1)

random.setstate(rndstate)

tmp2 = np.copy(x)

tmp2[ix] = tmp2[ix] - h

f2, _ = f(tmp2)

numgrad = (f1 - f2) / (2 * h)

print(numgrad,grad[ix])

print(max(1,abs(numgrad), abs(grad[ix])))

最后我们比较定义和函数求出来的值是否一致,代码如下:

reldiff = abs(numgrad - grad[ix]) / max(1, abs(numgrad), abs(grad[ix]))

注意,这里为什么有个max(1, abs(numgrad), abs(grad[ix]))?

因为如果 abs(numgrad), abs(grad[ix])是小于1的数的话,除以一个小于一的数使结果变得更大,即便这两个值真的很接近。

7. 神经网络的正向和反向传递及其python实现

#!/usr/bin/env python

import numpy as np

import random

from q1_softmax import softmax

from q2_sigmoid import sigmoid, sigmoid_grad

from q2_gradcheck import gradcheck_naive

def forward_backward_prop(data, labels, params, dimensions):

"""Forward and backward propagation for a two-layer sigmoidal networkCompute the forward propagation and for the cross entropy cost,and backward propagation for the gradients for all parameters.Arguments:data -- M x Dx matrix, where each row is a training example.labels -- M x Dy matrix, where each row is a one-hot vector.params -- Model parameters, these are unpacked for you.dimensions -- A tuple of input dimension, number of hidden unitsand output dimension"""

### Unpack network parameters (do not modify)

ofs = 0

Dx, H, Dy = (dimensions[0], dimensions[1], dimensions[2])

W1 = np.reshape(params[ofs:ofs+ Dx * H], (Dx, H))

ofs += Dx * H

b1 = np.reshape(params[ofs:ofs + H], (1, H))

ofs += H

W2 = np.reshape(params[ofs:ofs + H * Dy], (H, Dy))

ofs += H * Dy

b2 = np.reshape(params[ofs:ofs + Dy], (1, Dy))

### YOUR CODE HERE: forward propagation

h = sigmoid(np.dot(data,W1) +b1)

pred = sigmoid(np.dot(h, W2) + b2)

cost = (-1) * np.sum(labels * np.log(pred) + (1 - labels) * np.log(1 - pred))

### END YOUR CODE

### YOUR CODE HERE: backward propagation

dout = pred - labels

dh = np.dot(dout, W2.T) * sigmoid_grad(h)

gradW2 = np.dot(h.T, dout)

gradb2 = np.sum(dout, 0)

gradW1 = np.dot(data.T, dh)

gradb1 = np.sum(dh, 0)

### END YOUR CODE

### Stack gradients (do not modify)

grad = np.concatenate((gradW1.flatten(), gradb1.flatten(),

gradW2.flatten(), gradb2.flatten()))

return cost, grad

def sanity_check():

"""Set up fake data and parameters for the neural network, and test usinggradcheck."""

print "Running sanity check..."

N = 20

dimensions = [10, 5, 10]

data = np.random.randn(N, dimensions[0]) # each row will be a datum

# creat one-hot vector

labels = np.zeros((N, dimensions[2]))

for i in xrange(N):

labels[i, random.randint(0,dimensions[2]-1)] = 1

params = np.random.randn((dimensions[0] + 1) * dimensions[1] + (

dimensions[1] + 1) * dimensions[2], )

gradcheck_naive(lambda params:

forward_backward_prop(data, labels, params, dimensions), params)

if __name__ == "__main__":

sanity_check()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338914.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu终端命令停止_从命令行关闭Linux计算机的5种方法

没有操作系统是完美的。 即使相对稳定,驱动程序和应用程序也可能存在问题。 Linux也不例外。 尽管比Windows更稳定(在许多情况下,并非全部!),但可能还需要重新启动Linux计算机。 这可能是因为某些东西不起作用。 或者,您可能通过SSH连接到远程计算机或服务器,并希望它重新…

C语言编写简单朗读发音小工具!!

各位,今天给大家带来C语言结合VBS脚本写的一个简单的朗读小工具,做一个能够发音的C语言程序(保证简单,人人都能学会)。具备的知识体系:C语言基本框架C语言输入输出C语言文件操作C语言system函数VBS指令&…

jgit_JGit身份验证说明

jgitJGit中的身份验证与本地Git大致相同。 支持SSH和HTTP(S)等常用协议及其身份验证方法。 本文总结了如何使用JGit身份验证API安全地访问远程Git存储库。 尽管本文中的示例使用CloneCommand,但是可以将所描述的技术应用于连接到远程存储库的…

未发现oracle(tm)客户端和网络组件_SpringColud Eureka的服务注册与发现

一、Eureka简介本文中所有代码都会上传到git上,请放心浏览 项目git地址:https://github.com/839022478/Spring-Cloud在传统应用中,组件之间的调用,通过有规范的约束的接口来实现,从而实现不同模块间良好的协作。但是被…

mysql global index_Oracle中addsplit partition对globallocal index的影响

生产库中某些大表的分区异常,需要对现有表进行在线操作,以添加丢失分区,因为是生产库,还是谨慎点好,今天有空,针对addspli生产库中某些大表的分区异常,需要对现有表进行在线操作,以添…

sap寄售退货单_多个退货单

sap寄售退货单我曾经听说过,过去人们一直在努力使方法具有单个出口点。 我知道这是一种过时的方法,从未认为它特别值得注意。 但是最近我与一些仍坚持该想法的开发人员联系(最后一次是在这里 ),这让我开始思考。 因此…

课堂经验值管理小程序_微信小程序怎么管理门店?

微信门店小程序是一种不用注册下载就能使用的购物平台,近年来很是流行,而且它操作简单,能让用户快速找到自己需要的产品,然后进行购买,深得用户喜爱,有用户的地方就会有商家,商家想拥有自己的微…

C语言 | 直接插入排序

解题思路:直接插入排序是一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表。C语言源代码演示:#include//头文件 int main()//主函数 {void insort(int post[],int n)…

mysql+after+commit_Spring事务aftercommit原理及实践

来道题CREATE TABLE goods (id bigint(20) NOT NULL AUTO_INCREMENT,good_id varchar(20) DEFAULT NULL,num int(11) DEFAULT NULL,PRIMARY KEY (id),KEY goods_good_id_index (good_id)) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ciClass.forName("c…

序列化和反序列化的概念_序列化的概念

序列化和反序列化的概念讨论了为什么Optional不可序列化以及如何处理(即将推出)之后,让我们仔细看看序列化。 总览 这篇文章介绍了序列化的一些关键概念。 它尝试精简地执行此操作,而不会涉及太多细节,包括将建议降至…

python自动解析json_Python语言解析JSON详解

本文主要向大家介绍了Python语言解析JSON详解,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。 JSON 函数使用 JSON 函数需要导入 json 库:import json。函数 描述json.dumps 将 Python 对象编码成 JSON 字符串json.loads 将已…

C语言必学的12个排序算法:基数排序

# 基本思想基数排序(radix sort),同样时一种非比较的内部排序算法,主要基于多关键字排序的思想进行排序,它将单个关键字按照基数分成“多个关键字”进行排序。例如整数789是一个关键字,可以按照十进制位划分多关键字(十…

有没有code能改xml内容_Spring源码解析-applicationContext.xml加载和bean的注册

applicationContext文件加载和bean注册流程​ Spring对于从事Java开发的boy来说,再熟悉不过了,对于我们这个牛逼的框架的介绍就不在这里复述了,Spring这个大杂烩,怎么去使用怎么去配置,各种百度谷歌都能查到很多大牛教…

C语言数据类型转换

首先变量的数据类型是可以转换的。转换的方法有两种,一种是自动转换,另一种是强制转换。自动转换即当不同类型的数据进行混合运算时,编译系统将按照一定的规则自动完成。而强制类型转换是由程序员通过编程强制转换数据的类型。自动转换的规则…

jdk 9和jdk8_JDK 9 –给圣诞老人的信?

jdk 9和jdk8众所周知,冬天(尤其是圣诞节前的时间)是做梦的合适时机,希望有一个梦想似乎可以触及的时刻。 当孩子们和大人在纸上或在他们对圣诞老人的虚构或真实信件中写下自己的梦想时,希望他们的梦想将成为现实。 这很…

java 类持久化_Java 持久化之 -- IO 全面整理(看了绝不后悔)

目录:一、java io 概述什么是IO?IO包括输入流和输出流,输入流指的是将数据以字符或者字节形式读取到内存 分为字符输入流和字符输入流输入流指的是从内存读取到外界 ,分为字符输入流和字节输出流Java IO即Java 输入输出系统。不管…

idea 找不到或无法加载主类_解决IDEA中Groovy项目no Groovy library is defined的问题

实验环境IDEA2019.1.2Groovy-2.5.8错误重现新建了一个Groovy工程,指定了groovy版本,如图新建了一个简单的Groovy Class,运行,出现如下错误错误的尝试(以下是试错过程,并不能解决问题,读者可以不要跟着操作&…

C语言标识符、关键字和注释

这一节主要讲解C语言中的几个基本概念。标识符定义变量时,我们使用了诸如“a”“abc”“mn123”这样的名字,它们都是程序员自己起的,一般能够表达出变量的作用,这叫做标识符(Identifier)。标识符就是程序员…

java与java ee_Java EE 8怎么了?

java与java eeJava EE 8的工作进展顺利。 是时候赶上了! 无需费力就可以潜入… 不要忘记Java EE 7….. 围绕三个重要主题 HTML 5对齐–用于WebSocket的Java API(JSR 356),JSON处理(JSR 353),JA…

java 类.class_面试官:Java反射是什么?我回答不上来!

一.概念反射就是把Java的各种成分映射成相应的Java类。Class类的构造方法是private,由JVM创建。反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和…