精华内容
下载资源
问答
  • Unix下可用5I/O模型: 1)阻塞I/O,进程处于阻塞模式时,让出CPU,进入休眠状态; 2)非阻塞I/O,非阻塞模式使用并普遍,因为非阻塞模式会浪费大量CPU资源; 3)I/O复用(select和poll),针对批量IP...

    Unix下可用的5种I/O模型:

    1)阻塞I/O,进程处于阻塞模式时,让出CPU,进入休眠状态;
    2)非阻塞I/O,非阻塞模式的使用并不普遍,因为非阻塞模式会浪费大量的CPU资源;
    3)I/O复用(select和poll),针对批量IP操作时,使用I/O多路复用,非常有好;
    4)信号驱动I/O(SIGIO)
    5)异步I/O(POSIX的aio_系列函数)

    一个输入操作通常包括两个不同的阶段:

    1)等待数据准备好;
    2)从内核向进程复制数据;

    对于一个套接字的输入操作,第一步通常涉及等待数据从网络中到达。当所等待分组到达时,它被复制到内核中某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区。

    5.1阻塞I/O

    阻塞 I/O 模式是最普遍使用的 I/O 模式。一个套接字建立后所处于的模式就是阻塞 I/O 模式。(因为Linux系统默认的IO模式是阻塞模式)
    对于一个 UDP 套接字来说,数据就绪的标志比较简单:
    (1)已经收到了一整个数据报
    (2)没有收到。

    而 TCP 这个概念就比较复杂,需要附加一些其他的变量。
    最流行的I/O模型是阻塞式I/O(blocking I/O) 模型,默认情况下,所有的套接字都是阻塞的。阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。以数据包套接字为例,如图

    这里写图片描述

    图1

    进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区或者发生错误才返回。最常见的错误是系统调用被信号中断。我们说进程从调用recvfrom开始到它返回的整段时间内是被阻塞的,recvfrom成功返回后,进程开始处理数据报。

    5.2非阻塞I/O

    进程把一个套接口设置成非阻塞是在通知内核:当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠,而是返回一个错误。

    这里写图片描述

    图2

    前三次调用recvfrom 时没有数据可返回,因此内核转而立即返回一个EWOULDBLOCK 错误。第四次调用 recvfrom 时已有一个数据报准备好,它被复制到应用程序缓冲区,于是recvfrom 成功返回。我们接着处理数据。

    当一个应用程序使用了非阻塞模式的套接字,它需要使用一个循环来不听的测试是否一个文件描述符有数据可读(称做 polling(轮询))。应用程序不停的 polling 内核来检查是否 I/O操作已经就绪。这将是一个极浪费 CPU资源的操作。这种模式使用中不是很普遍。
    非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

    5.3 I/O复用

    在使用 I/O 多路技术的时候,我们调用 select()函数和 poll()函数或epoll函数(2.6内核开始支持),在调用它们的时候阻塞,而不是我们来调用 recvfrom(或recv)的时候阻塞。主要可以调用select和epoll;对一个IO端口,两次调用,两次返回,比阻塞IO并没有什么优越性;关键是能实现同时对多个IO端口进行监听,可以等待多个描述符就绪;

    I/O复用模型会用到select、poll、epoll函数,这几个函数也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。

    当我们调用 select函数阻塞的时候,select 函数等待数据报套接字进入读就绪状态。当select函数返回的时候, 也就是套接字可以读取数据的时候。 这时候我们就可以调用 recvfrom函数来将数据拷贝到我们的程序缓冲区中。

    对于单个I/O操作,和阻塞模式相比较,select()和poll()或epoll并没有什么高级的地方。而且,在阻塞模式下只需要调用一个函数:读取或发送函数。在使用了多路复用技术后,我们需要调用两个函数了:

    先调用 select()函数或poll()函数,然后才能进行真正的读写。

    多路复用的高级之处在于:它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。

    这里写图片描述

    图3

    IO 多路技术一般在下面这些情况中被使用:

     当一个客户端需要同时处理多个文件描述符的输入输出操作的时候(一般来说是标准的输入输出和网络套接字),I/O 多路复用技术将会有机会得到使用。
     当程序需要同时进行多个套接字的操作的时候。
     如果一个 TCP 服务器程序同时处理正在侦听网络连接的套接字和已经连接好的套接字。
     如果一个服务器程序同时使用 TCP 和 UDP 协议。
     如果一个服务器同时使用多种服务并且每种服务可能使用不同的协议(比如 inetd就是这样的)。

    5.4信号驱动I/O模型

    我们也可以用信号,让内核在描述字就绪时发送SIGIO信号通知我们。我们称这种模型为信号驱动I/O(signal-driven I/O)。

    我们首先开启套接口的信号驱动I/O功能,并通过sigaction系统调用安装一个信号处理函数。该系统调用立即发回,我们的进程继续工作,也就是说它没有被阻塞。当数据报准备好时,内核就为该进程产生一个SIGIO信号。我们随后既可以在信号处理函数中调用recvfrom读取数据报,并通知主循环数据已经准备好待处理,也可以立即通知主循环,让它读取数据报。

    无论如何处理SIGIO信号,这种模型的优势在于等待数据报到达期间,进程不被阻塞。主循环可以继续执行,只要不时等待来自信号处理函数的通知:既可以是数据已经准备好被处理,也可以是数据报已准备好被读取。

    这里写图片描述

    图4

    5.5异步I/O模型

    异步I/O(asynchronous I/O)有POSIX规范定义。后来演变成当前POSIX规范的各种早期标准定义的实时函数中存在的差异已经取得一致。一般地说,这些函数的工作机制是:告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到我们自己的缓冲区)完成后通知我们。这种模型与前与前面介绍的信号驱动模型的主要区别在于:信号驱动I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知我们I/O操作何时完成。

    这里写图片描述

    图5

    各种模型的比较

    这里写图片描述

    图6

    可以看出,前4种模型的主要区别在于第一阶段,因为它们的第二阶段是一样的:在数据从内核复制到调用者的缓冲区起见,进程阻塞与recvfrom 调用,相反。异步I/O模型在这两个阶段都需要处理,从而不同于其他四种模型。

    同步I/O与异步I/O对比
    POSIX把这两个术语定义如下:
    ·同步I/O操作(synchronous I/O operation)导致请求进程阻塞,直到I/O操作完成。
    ·异步I/O(asynchronous I/O operation)不导致请求进程阻塞。

    根据上述定义,我们前4种模型----阻塞I/O模型、非阻塞I/O模型、I/O复用模型和信号去驱动I/O模型都是同步I/O模型,因为其中真正的I/O操作(recvfrom)将阻塞进程。只有异步I/O模型与POSIX定义的异步I/O相匹配。

    5.6 select 函数

    该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
    作为一个例子,我们可以调用select,告知内核仅在下列情况发生时才返回:
    1)集合{ 1, 4, 5 } 中任何描述符准备好读;
    2)集合{ 2, 7 } 中任何描述符准备好写;
    3)集合{ 1, 4 } 中任何描述符有异常条件待处理;

    也就是说,我们调用 select 告知内核对哪些描述符(就读、写或异常条件)感兴趣以及等待多长时间。我们感兴趣的描述符不局限于套接字,任何描述符都可以用select 来测试。函数描述如下:

     #include <sys/select.h>  
     #include <sys/time.h>  
      
    int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,   
                 const struct timeval *timeout);  
    

    从最后一个参数timeout 开始介绍,它告知内核等待所指定描述符中任何一个就绪可花多长时间。其timeval结构用于指定这段时间的秒数和微妙数。

    struct timeval  
    {  
        long tv_sec; //seconds  
        long tv_usec; //mircoseconds  
    }  
    

    这个参数有以下三种可能:
    1)永远的等待下去:仅在有一个描述符准备好I/O时才返回。为此,我们把这个参数设置为空指针;
    2)等待一段固定时间:在有一个描述符准备好I/O时返回,但是不超过由该参数所指向的timeval 结构中指定的秒数和微秒数;
    3)根本不等待:检查描述符后立即反悔,这称为轮询(polling)。为此,该参数必须指向一个timeval结构,而且其中的定时器值(由该结构指定的秒数和微秒数)必须为0;
    中间的三个参数 readset 、writeset 和 exceptset 指定我们要让内核测试读、写和异常条件的描述符。

    select 使用描述符集,通常是同一个整数数组,其中每个整数中的每一位对于一个描述符。举例来说,假设使用32位整数,那么该数组的每一个元素对应于描述符031,第二位元素对应于描述符3263,依次类推, 它们隐藏 为 fd_set 的数据类型和以下四个宏中:
    void FD_ZERO(fd_set *fdset); //从fdset中清除所有的文件描述符
    void FD_SET(int fd, fd_set *fdset); //将fd加入到fdset
    void FD_CLR(int fd, fd_set *fdset); //将fd从fdset里面清除
    int FD_ISSET(int fd, fd_set *fdset); //判断fd是否在fdset集合中
    举个例子,以下代码用于定义一个fd_set 类型的变量,然后打开描述符 1、4 和 5 的对应位;
    fd_set rset;

    FD_ZERO(&rset);
    FD_SET(1, &rset);
    FD_SET(4 &rset);
    FD_SET(5, &rset);
    描述符集的初始化非常重要,因为作为自动变量分配的一个描述符集如果没有初始化,那么可能发生不可预期的后果。

    select 函数修改由指针 readset 、writeset 和 exceptset 所指向的描述符集,因而这三个参数都是值-结果参数。调用该函数时,我们指定所关心的描述符的值,该函数返回时,结果将指示哪些描述符就绪。该函数返回后,我们使用FD_ISSET宏测试 fd_set 数据类型中的描述符。描述符集内任何与未就绪描述符对应的位返回时均清0。为此,每次重新调用select函数时,我们都得再次把所以描述符集内所关心的为均置一。

    数的返回值表示跨所有描述符集的已就绪的总位数。如果任何描述符就绪之前定时器到时,那么返回0.返回-1表示出错。

    描述符就绪条件:
    对于可读文件描述符集以下四种情况会导致置位:
    1、socket接收缓冲区中的数据量大于或等于当前缓冲区的低水位线.此时对于read操作不会被阻塞并且返回一个正值(读取的字节数).低水位线可以通过SO_RCVLOWAT选项设定,对于Tcp和Udp来说其默认值为1.
    2、socket连接的读端被关闭,如shutdown(socket, SHUT_RD)或者close(socket).对应底层此时会接到一个FIN包,read不会被阻塞但会返回0.代表读到socket末端.
    3、socket是一个监听socket并且有新连接等待.此时accept操作不会被阻塞.
    4、发生socket错误.此时read操作会返回SOCKET_ERROR(-1).可以通过errno来获取具体错误信息.

    对于可写文件描述符集以下四种情况会导致置位:
    【1】socket发送缓冲区中的可用缓冲大小大于或等于发送缓冲区中的低水位线并且满足以下条件之一
    (1)、socket已连接
    (2)、socket本身不要求连接,典型如Udp
    低水位线可以通过SO_SNDLOWAT选项设置.对于Tcp和Udp来说一般为2048.
    【2】socket连接的写端被关闭,如shutdown(socket, SHUT_WR)或者close(socket).在一个已经被关闭写端的句柄上写数据会得到SIGPIPE的信号(errno).
    【3】一个非阻塞的connect操作连接成功 或者 connect操作失败.
    【4】发生socket错误.此时write操作会返回SOCKET_ERROR(-1).可以通过errno来获取具体错误信息.

    对于异常文件描述符集只有一种情况(针对带外数据):
    当收到带外数据(out-of-band)时或者socket的带外数据标志未被清除.
    下面看个具体例子:
    【参见附件/server.c】

    #include <stdio.h>  
    #include <string.h>  
    #include <stdlib.h>  
    #include <unistd.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <sys/select.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #define PORT 8888  
    #define MAXSIZE 128  
      
    int main()  
    {  
        int i,nbyte;  
        int listenfd, confd, maxfd;  
        char buffer[MAXSIZE];  
        fd_set global_rdfs, current_rdfs;  
        struct sockaddr_in addr,clientaddr;  
        int addrlen = sizeof(struct sockaddr_in);  
        int caddrlen = sizeof(struct sockaddr_in);  
        if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)  
        {  
            perror("socket error");  
            exit(-1);  
        }  
        else  
        {  
            printf("socket successfully!\n");  
            printf("listenfd : %d\n",listenfd);  
        }  
        memset(&addr, 0 ,addrlen);  
        addr.sin_family = AF_INET;  
        addr.sin_port = htons(PORT);  
        addr.sin_addr.s_addr = htonl(INADDR_ANY);  
        if(bind(listenfd,(struct sockaddr *)&addr,addrlen) == -1)  
        {  
            perror("bind error");  
            exit(-1);  
        }  
        else  
        {  
            printf("bind successfully!\n");  
            printf("listen port:%d\n",PORT);  
        }  
        if(listen(listenfd,5) == -1)  
        {  
            perror("listen error");  
            exit(-1);  
        }  
        else  
        {  
            printf("listening...\n");  
        }  
        maxfd = listenfd;  
        FD_ZERO(&global_rdfs);  
        FD_SET(listenfd,&global_rdfs);  
        while(1)  
        {  
            current_rdfs = global_rdfs;  
            if(select(maxfd + 1,current_rdfs, NULL, NULL,0) < 0)  
            {  
                perror("select error");  
                exit(-1);  
            }  
            for(i = 0; i <= listenfd + 1; i++)  
            {  
                if(FD_ISSET(i,current_rdfs))  
                {  
                    if(i == listenfd)  
                    {  
                        if((confd = accept(listenfd,(struct sockaddr *)&clientaddr,&caddrlen)) == -1)  
                        {  
                            perror("accept error");  
                            exit(-1);  
                        }  
                        else  
                        {  
                            printf("Connect from [IP:%s PORT:%d]\n",  
                                    inet_ntoa(clientaddr.sin_addr),clientaddr.sin_port);  
                            FD_SET(confd,&global_rdfs);  
                            maxfd = (maxfd > confd ? maxfd : confd);  
                        }  
                    }  
                    else  
                    {  
                        if((nbyte = recv(i, buffer, sizeof(buffer),0)) < 0)  
                        {  
                            perror("recv error");  
                            exit(-1);  
                        }  
                        else if(nbyte == 0)  
                        {  
                            close(i);  
                            FD_CLR(i,&global_rdfs);  
                        }  
                        else  
                        {  
                            printf("recv:%s\n",buffer);  
                            send(i, buffer, sizeof(buffer),0);  
                        }  
                    }  
                }  
            }  
        }  
        return 0;  
    }  
    

    执行结果如下:
    $ ./select2
    socket successfully!
    listenfd : 3
    bind successfully!
    listen port:8888
    listening…
    Connect from [IP:192.168.3.51 PORT:1992]
    recv:hello

    Connect from [IP:192.168.3.53 PORT:2248]

    本章参考代码

    点击进入

    展开全文
  • Java网络编程---UDP

    2020-10-27 09:00:55
    UDP是一无连接传输协议(网络中传输数据格式在网络编程中就被称作协议)。该协议称为用户数据报协议。 UDP特点 1.无连接。只要知道对端IP和端口号就可以直接进行传输而需要建立连接(例如生活中发短信,...

    UDP简述

    UDP是一种无连接传输协议(网络中传输的数据格式在网络编程中就被称作协议)。该协议称为用户数据报协议。

    UDP特点

    1.无连接。只要知道对端的IP和端口号就可以直接进行传输而不需要建立连接(例如生活中的发短信,只管发,不在意对方是否能收到)
    2.不可靠。没有确认机制,没有重传机制。(例如打微信电话时候网络不稳定或是信号不好,听不清楚对方说什么,这就是因为丢失数据包导致的)
    3.速度快。UDP是IOS模型传输层其中之一,除此之外还有TCP,TCP控制相对来说比较复杂,其中使用到的机制包括三次握手、流量控制、滑动窗口、序列号、确认号等,链路比较多。而UDP是无连接的,链路的开销比较小所以速度快

    代码实现

    客户端

    import java.io.IOException;
    import java.net.*;
    import java.util.Scanner;
    
    public class Client {
        public static void main(String[] args) {
            Scanner sca = new Scanner(System.in);
            try {
                //创建发送端套接字
                DatagramSocket socket = new DatagramSocket();
                //指定ip
                InetAddress ip = InetAddress.getByName("localhost");
                //指定一个端口
                int port = 9999;
                //创建一个容器
                byte data[];
                while(true){
                    System.out.println("你发送的东西");
                    String str = sca.next();
                    //把数据放进容器
                    data = str.getBytes();
                    //打包数据
                    DatagramPacket packet = new DatagramPacket(data, data.length,ip,port);
                    //发送数据报包
                    socket.send(packet);
                    if (str.equals("exit")){
                        break;
                    }
                }
                //释放资源
                socket.close();
            } catch (SocketException | UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    服务器

    import java.io.IOException;
    import java.net.*;
    
    public class Server{
        public static void main(String[] args) {
            try {
                //创建套接字并将其绑定到本地主机上的指定端口。
                DatagramSocket socket = new DatagramSocket(9999);
                //创建接受数据的容器
                byte []data = new byte[1024];
                //创建一个接受数据的数据包
                DatagramPacket datagramPacket = new DatagramPacket(data, data.length);
                while(true){
                    //开始接收数据
                    socket.receive(datagramPacket);
                    //解析数据
                    String str = new String(datagramPacket.getData(),0, datagramPacket.getLength());
                    //接收到的数据
                    System.out.println(datagramPacket.getAddress()+"发送的消息:"+str);
                    if (str.equals("exit")){
                        break;
                    }
                }
                socket.close();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    PS:先启动服务器再启动客户端

    展开全文
  • 借助于此框架,读者可理解WinSock的具体细节,包括WindowsSockets概述、OSI网络参考模型、TCP/IP协议簇中的协议和可用的服务、WinSock网络应用程序的框架及其工作机制、WinSock的三种操作模式、socket通信机制等;...
  • 借助于此框架,读者可理解WinSock的具体细节,包括WindowsSockets概述、OSI网络参考模型、TCP/IP协议簇中的协议和可用的服务、WinSock网络应用程序的框架及其工作机制、WinSock的三种操作模式、socket通信机制等;...
  • 吴恩达深度学习专项课程...实验1要求实现三种不同权重参数初始化方式,通过对其效果比较,说明参数初始化重要性,选择一个最好初始化方式;实验2要求实现正则化方法,包括L2正则化和dropout,比较使用/...

    吴恩达深度学习专项课程的所有实验均采用iPython Notebooks实现,不熟悉的朋友可以提前使用一下Notebooks。本周包含三个实验,这三个实验都基于一个3层神经网络模型(模型已经帮助你实现好了)进行演示。实验1要求实现三种不同的权重参数初始化方式,通过对其效果的比较,说明参数初始化的重要性,选择一个最好的初始化方式;实验2要求实现正则化方法,包括L2正则化和dropout,比较使用/不使用正则化模型的效果,说明正则化在解决模型过拟合方面的重要性;实验3要求实现梯度检验,来检查反向传播计算的梯度,确保反向传播实现的正确性。

     

    目录

    一、实验1:初始化

    1.实验综述

    2.导入必要的包

    3.神经网络模型

    3.Zero 初始化

    4.随机初始化

    5.He 初始化

    6.结论

    二、实验2:正则化

    1.实验综述

    2.导入必要的包

    3.不带正则化的模型

    4.L2正则化

    5.Dropout

    6.结论

    三、实验3:梯度检查

    1.实验综述

    2.导入必要的包

    3.梯度检验时怎么工作的?

    四、实验完整代码


    一、实验1:初始化

    1.实验综述

    2.导入必要的包

    import numpy as np
    import matplotlib.pyplot as plt
    import sklearn
    import sklearn.datasets
    #init_utils.py 中定义了3层神经网络结构相关的函数实现 以及数据集的加载函数 绘制决策边界的函数
    from init_utils import sigmoid, relu, compute_cost, forward_propagation, backward_propagation
    from init_utils import update_parameters, predict, load_dataset, plot_decision_boundary, predict_dec
    
    %matplotlib inline
    #设置绘图的默认风格
    plt.rcParams['figure.figsize'] = (7.0, 4.0) # 默认大小
    plt.rcParams['image.interpolation'] = 'nearest'
    plt.rcParams['image.cmap'] = 'gray' #默认色调
    
    #加载平面数据集
    train_X, train_Y, test_X, test_Y = load_dataset()
    • 待分类平面数据集可视化效果

    • 实验任务

    3.神经网络模型

    • 定义神经网络模型
    #神经网络模型
    def model(X, Y, learning_rate = 0.01, num_iterations = 15000, print_cost=False,initialization="he"):
        '''
        训练网络
        
        参数:
        X:训练集样本特征矩阵(n_x,m_train)
        Y:训练集样本标签 0/1 (1,m_train)
        learning_rate:学习率
        num_iterations:梯度下降法迭代次数
        print_cost:为True时,每1000次迭代打印一次cost
        initialization:选择权重参数初始化方式 "zeros","random","he"
        
        返回:
        parameters:训练好的参数 字典形式
            parameters["W" + str(l)] = ... 
            parameters["b" + str(l)] = ...
        '''
        
        np.random.seed(1)
        costs = [] #存储每1000次前向传播计算的代价
        layers_dims = [X.shape[0],10,5,1] #非定义3层神经网络各层的单元数
        
        #初始化方式
        if initialization == "zeros":
            parameters = initialize_parameters_zeros(layers_dims)
        elif initialization == "random":
            parameters = initialize_parameters_random(layers_dims)
        elif initialization == "he":
            parameters = initialize_parameters_he(layers_dims)
        
        #梯度下降迭代
        for i in range(num_iterations):
            
            #前向传播
            a3,caches = forward_propagation(X,parameters)
            
            #计算代价
            cost = compute_cost(a3,Y)
            
            #反向传播计算梯度
            grads = backward_propagation(X,Y,caches)
            
            #更新参数
            parameters = update_parameters(parameters,grads,learning_rate)
            
            #每100次迭代打印一次代价 并存储
            if print_cost and i%1000==0:
                print("Cost after iteration {}: {}".format(i, np.squeeze(cost)))
                costs.append(cost)
                
        #绘制代价对迭代次数的变化曲线
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per hundreds)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
        
        return parameters
            

    3.Zero 初始化

    • 代码实现 
    
    def initialize_parameters_zeros(layers_dims):
        """
        参数:
        layer_dims:网络每一层的单元数
        
        返回:
        parameters:初始化后的参数 字典形式
           "W1", "b1", ..., "WL", "bL":
                        Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
                        bl -- bias vector of shape (layer_dims[l], 1)
        """
        parameters = {}
        L = len(layers_dims) #神经网络层数+1
        
        for l in range(1,L): #1~L-1
            parameters["W"+str(l)] = np.zeros((layers_dims[l],layers_dims[l-1]))
            parameters["b"+str(l)] = np.zeros((layers_dims[l],1))
        
        return parameters
    • 测试代码
    parameters = initialize_parameters_zeros([3,2,1])
    print("W1 = " + str(parameters["W1"]))
    print("b1 = " + str(parameters["b1"]))
    print("W2 = " + str(parameters["W2"]))
    print("b2 = " + str(parameters["b2"]))

    • 训练模型

    使用0初始化方式,训练神经网络模型,15000次梯度下降迭代

    parameters = model(train_X, train_Y,print_cost=True,initialization = "zeros")
    print ("On the train set:")
    predictions_train = predict(train_X, train_Y, parameters)
    print ("On the test set:")
    predictions_test = predict(test_X, test_Y, parameters)

    此时模型的表现非常差,代价并没有减小。算法表现可能还不如瞎猜。

    • 查看模型在训练/测试集上的具体预测值
    print ("predictions_train = " + str(predictions_train))
    print ("predictions_test = " + str(predictions_test))

    模型的预测结果全为0.

    • 绘制决策边界
    plt.title("Model with Zeros initialization")
    axes = plt.gca()
    axes.set_xlim([-1.5,1.5])
    axes.set_ylim([-1.5,1.5])
    plot_decision_boundary(lambda x: predict_dec(parameters,x.T), train_X, np.squeeze(train_Y))

    • 总结

    4.随机初始化

    • 代码实现
    
    def initialize_parameters_random(layers_dims):
        
        """
        参数:
        layer_dims:网络每一层的单元数
        
        返回:
        parameters:初始化后的参数 字典形式
           "W1", "b1", ..., "WL", "bL":
                        Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
                        bl -- bias vector of shape (layer_dims[l], 1)
        """
        np.random.seed(3)
        parameters = {}
        L = len(layers_dims) #神经网络层数+1
        
        for l in range(1,L): #1~L-1
            parameters["W"+str(l)] = np.random.randn(layers_dims[l],layers_dims[l-1])*10
            parameters["b"+str(l)] = np.zeros((layers_dims[l],1))
        return parameters
    
    • 测试代码
    parameters = initialize_parameters_random([3, 2, 1])
    print("W1 = " + str(parameters["W1"]))
    print("b1 = " + str(parameters["b1"]))
    
    print("W2 = " + str(parameters["W2"]))
    print("b2 = " + str(parameters["b2"]))

    • 训练模型

    使用随机初始化方式,训练神经网络模型,15000次梯度下降迭代

    parameters = model(train_X, train_Y,print_cost=True,initialization = "random")
    print ("On the train set:")
    predictions_train = predict(train_X, train_Y, parameters)
    print ("On the test set:")
    predictions_test = predict(test_X, test_Y, parameters)

    • 查看模型具体的预测值
    print (predictions_train)
    print (predictions_test)

    • 绘制决策边界
    plt.title("Model with large random initialization")
    axes = plt.gca()
    axes.set_xlim([-1.5,1.5])
    axes.set_ylim([-1.5,1.5])
    plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, np.squeeze(train_Y))

    • 总结

    5.He 初始化

    • 代码实现
    
    def initialize_parameters_he(layers_dims):
        
        """
        参数:
        layer_dims:网络每一层的单元数
        
        返回:
        parameters:初始化后的参数 字典形式
           "W1", "b1", ..., "WL", "bL":
                        Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
                        bl -- bias vector of shape (layer_dims[l], 1)
        """
        np.random.seed(3)
        parameters = {}
        L = len(layers_dims) #神经网络层数+1
        
        for l in range(1,L): #1~L-1
            parameters["W"+str(l)] = np.random.randn(layers_dims[l],layers_dims[l-1])*np.sqrt(2./layers_dims[l-1])
            parameters["b"+str(l)] = np.zeros((layers_dims[l],1))
        return parameters
    
    • 测试代码
    parameters = initialize_parameters_he([2, 4, 1])
    print("W1 = " + str(parameters["W1"]))
    print("b1 = " + str(parameters["b1"]))
    print("W2 = " + str(parameters["W2"]))
    print("b2 = " + str(parameters["b2"]))

    • 训练模型

    使用He初始化方式,训练神经网络模型,15000次梯度下降迭代。

    parameters = model(train_X, train_Y,print_cost=True, initialization = "he")
    print ("On the train set:")
    predictions_train = predict(train_X, train_Y, parameters)
    print ("On the test set:")
    predictions_test = predict(test_X, test_Y, parameters)

    • 绘制决策边界
    plt.title("Model with He initialization")
    axes = plt.gca()
    axes.set_xlim([-1.5,1.5])
    axes.set_ylim([-1.5,1.5])
    plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, np.squeeze(train_Y))

    6.结论

     

    二、实验2:正则化

    1.实验综述

    2.导入必要的包

    import numpy as np
    import matplotlib.pyplot as plt
    #reg_utils.py 定义好了一个3层的神经网络结构所包含的必要函数以及本实验中能用到的重要函数
    from reg_utils import sigmoid, relu, plot_decision_boundary, initialize_parameters, load_2D_dataset, predict_dec
    from reg_utils import compute_cost, predict, forward_propagation, backward_propagation, update_parameters
    import sklearn
    import sklearn.datasets
    import scipy.io
    from testCases import * #提供测试用例
    
    %matplotlib inline
    #设置绘图的默认风格
    plt.rcParams['figure.figsize'] = (7.0, 4.0) 
    plt.rcParams['image.interpolation'] = 'nearest'
    plt.rcParams['image.cmap'] = 'gray'
    • 可视化待分类数据集
    train_X, train_Y, test_X, test_Y = load_2D_dataset()

    3.不带正则化的模型

    • 神经网络模型
    def model(X, Y, learning_rate = 0.3, num_iterations = 30000, print_cost = True, lambd = 0, keep_prob = 1):
        
        '''
        神经网络模型
        
        参数:
        X:训练集样本特征矩阵(n_x,m_train)
        Y:训练集样本标签 0/1 (1,m_train)
        learning_rate:学习率
        num_iterations:梯度下降法迭代次数
        print_cost:为True时,每10000次迭代打印一次cost
        lambd:正则化系数
        keep_prob:每一层单元的保留概率
        
        返回:
        parameters:训练好的参数 字典形式
            parameters["W" + str(l)] = ... 
            parameters["b" + str(l)] = ...
        '''
            
        grads = {}
        costs = []                            # 保存每10000次迭代的cost
        m = X.shape[1]                        # 样本数
        layers_dims = [X.shape[0], 20, 3, 1]  #3层网络 各层的单元数
        
        # 初始化模型参数 返回字典
        parameters = initialize_parameters(layers_dims)
    
        # 梯度下降法迭代过程
    
        for i in range(0, num_iterations):
    
            # 前向传播: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID.
            if keep_prob == 1: #不使用dropout
                a3, cache = forward_propagation(X, parameters)
            elif keep_prob < 1: #使用dropout
                a3, cache = forward_propagation_with_dropout(X, parameters, keep_prob)
            
            # 代价函数
            if lambd == 0: #不使用L2正则化
                cost = compute_cost(a3, Y)
            else:           #使用L2正则化
                cost = compute_cost_with_regularization(a3, Y, parameters, lambd)
                
            # 反向传播
            assert(lambd==0 or keep_prob==1)    # 可能同时使用L2正则化和dropout
                                                # 本次实验一次只使用一个
            if lambd == 0 and keep_prob == 1: #不使用L2也不使用dropout
                grads = backward_propagation(X, Y, cache)
            elif lambd != 0:  #使用L2正则化
                grads = backward_propagation_with_regularization(X, Y, cache, lambd)
            elif keep_prob < 1:  #使用dropout
                grads = backward_propagation_with_dropout(X, Y, cache, keep_prob)
            
            # 更新参数
            parameters = update_parameters(parameters, grads, learning_rate)
            
            # 每10000次迭代打印/保存一次cost
            if print_cost and i % 10000 == 0:
                print("Cost after iteration {}: {}".format(i, cost))
            if print_cost and i % 1000 == 0:
                costs.append(cost)
        
        # 绘制cost随迭代次数的变化曲线
        plt.plot(costs)
        plt.ylabel('cost')
        plt.xlabel('iterations (x1,000)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()
        
        return parameters
    • 训练不带正则化的模型

    训练一个不带任何正则化的模型,观察它在训练/测试集上的准确率。

    parameters = model(train_X, train_Y)
    print ("On the training set:")
    predictions_train = predict(train_X, train_Y, parameters)
    print ("On the test set:")
    predictions_test = predict(test_X, test_Y, parameters)

    • 绘制决策边界
    plt.title("Model without regularization")
    axes = plt.gca()
    axes.set_xlim([-0.75,0.40])
    axes.set_ylim([-0.75,0.65])
    plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, np.squeeze(train_Y))

    • 总结

    4.L2正则化

    • 实现带L2正则化的代价函数
    #实现带L2正则化的代价函数
    def compute_cost_with_regularization(A3, Y, parameters, lambd):
        '''
        实现带L2正则化的代价函数
        
        参数:
        A3:前向传播计算的模型输出(1,m)
        Y:样本真实标签 (1,m)
        parameters:模型参数 字典形式
        lambd:正则化系数
        
        返回:
        cost:计算的带正则化的代价
        '''
        W1 = parameters['W1']
        W2 = parameters['W2']
        W3 = parameters['W3']
        m = A3.shape[1]
        
        cross_entropy_cost = compute_cost(A3,Y)
        
        L2_regularization_cost = 1./m*lambd/2*(np.sum(np.square(W1))+np.sum(np.square(W2))+np.sum(np.square(W3)))
        cost = L2_regularization_cost + cross_entropy_cost
        return cost
    • 测试代码
    A3, Y_assess, parameters = compute_cost_with_regularization_test_case()
    
    print("cost = " + str(compute_cost_with_regularization(A3, Y_assess, parameters, lambd = 0.1)))

    • 实现带L2正则化的反向传播函数

    
    def backward_propagation_with_regularization(X, Y, cache, lambd):
        """
        实现带L2正则化的反向传播
        
        参数:
        X:样本特征矩阵 (nx,m)
        Y: 样本真实标签(1,m)
        cache:前向传播中缓存的中间结果
        lambd:正则化系数
        
        返回:
        grads:每次迭代后模型中参数的梯度 dZ,dW,db
        """
        
        m = X.shape[1]
        (Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3) = cache
        
        dZ3 = A3 - Y
        dW3 = 1./m*np.dot(dZ3,A2.T)+lambd/m*W3
        db3 = 1./m*np.sum(dZ3,axis=1,keepdims=True)
        dA2 = np.dot(W3.T,dZ3)
        
        dZ2 = dA2*np.int64(A2>0)
        dW2 = 1./m*np.dot(dZ2,A1.T)+lambd/m*W2
        db2 = 1./m*np.sum(dZ2,axis=1,keepdims=True)
        dA1 = np.dot(W2.T,dZ2)
        
        dZ1 = dA1*np.int64(A1>0)
        dW1 = 1./m*np.dot(dZ1,X.T)+lambd/m*W1
        db1 = 1./m*np.sum(dZ1,axis=1,keepdims=True)
    
        
        gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2,
                     "dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1, 
                     "dZ1": dZ1, "dW1": dW1, "db1": db1}
        
        return gradients
    • 测试代码
    X_assess, Y_assess, cache = backward_propagation_with_regularization_test_case()
    
    grads = backward_propagation_with_regularization(X_assess, Y_assess, cache, lambd = 0.7)
    print ("dW1 = "+ str(grads["dW1"]))
    print ("dW2 = "+ str(grads["dW2"]))
    print ("dW3 = "+ str(grads["dW3"]))

    • 训练带L2正则化的模型

    parameters = model(train_X, train_Y, lambd = 0.7)
    print ("On the train set:")
    predictions_train = predict(train_X, train_Y, parameters)
    print ("On the test set:")
    predictions_test = predict(test_X, test_Y, parameters)

    模型在测试集上的准确率提升到了93%。而且没有在训练集上出现明显的过拟合。

    • 绘制决策边界
    plt.title("Model with L2-regularization")
    axes = plt.gca()
    axes.set_xlim([-0.75,0.40])
    axes.set_ylim([-0.75,0.65])
    plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, np.squeeze(train_Y))

    • 总结

    5.Dropout

    dropout是在深度学习中广泛使用的正则化技术。 它在每次迭代中使一些神经单元随机失活.

    当你使一些关闭一些神经元, 实际上就简化了模型. dropout的思想就是对于每次迭代,训练的是一个不同的模型(只使用神经元的一个子集). 使用dropout,神经元对之前其他神经元的激活输出不再那么敏感(不会赋予很大的权重),因为这些神经元随时都可能关闭

    • 带Dropout的前向传播

    • 代码实现
    
    
    def forward_propagation_with_dropout(X, parameters, keep_prob = 0.5):
        """
        实现带dropout的前向传播: LINEAR -> RELU + DROPOUT -> LINEAR -> RELU + DROPOUT -> LINEAR -> SIGMOID.
        
        参数:
        X:输入特征矩阵(nx=2,m)
        参数 -- 字典形式 包含 "W1", "b1", "W2", "b2", "W3", "b3":
                        W1 -- weight matrix of shape (20, 2)
                        b1 -- bias vector of shape (20, 1)
                        W2 -- weight matrix of shape (3, 20)
                        b2 -- bias vector of shape (3, 1)
                        W3 -- weight matrix of shape (1, 3)
                        b3 -- bias vector of shape (1, 1)
        keep_prob - 使用dropout的层的单元保留概率
        
        返回:
        A3 :模型前向传播输出 (1,m)
        cache :前向传播的缓存结果 便于与反向传播共享参数 元组形式
        """
        
        np.random.seed(1)
        
        W1 = parameters["W1"]
        b1 = parameters["b1"]
        W2 = parameters["W2"]
        b2 = parameters["b2"]
        W3 = parameters["W3"]
        b3 = parameters["b3"]
        
        Z1 = np.dot(W1,X)+b1
        A1 = relu(Z1)
        
        D1 = np.random.rand(A1.shape[0],A1.shape[1])
        D1 = (D1<keep_prob)
        A1 = A1*D1
        A1 /= keep_prob
        
        Z2 = np.dot(W2,A1)+b2
        A2 = relu(Z2)
        
        D2 = np.random.rand(A2.shape[0],A2.shape[1])
        D2 = (D2<keep_prob)
        A2 = A2*D2
        A2 /= keep_prob
        
        Z3 = np.dot(W3,A2)+b3
        A3 = sigmoid(Z3)
        
        
        cache = (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3)
        
        return A3, cache
    • 测试代码
    X_assess, parameters = forward_propagation_with_dropout_test_case()
    
    A3, cache = forward_propagation_with_dropout(X_assess, parameters, keep_prob = 0.7)
    print ("A3 = " + str(A3))

     

    • 带Dropout的反向传播

    • 代码实现
    
    def backward_propagation_with_dropout(X, Y, cache, keep_prob):
        """
        实现带dropout的反向传播
        
        参数:
        X:输入特征矩阵(nx=2,m)
        Y: 样本真实标签(1,m)
        cache:forward_propagation_with_dropout()缓存的结果,并与共享参数
        keep_prob:使用dropout的层的单元保留概率
        
        返回:
        gradients grads:每次迭代后模型中参数的梯度 dZ,dW,db
        """
        
        m = X.shape[1]
        (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) = cache
        
        dZ3 = A3 - Y
        dW3 = 1./m*np.dot(dZ3,A2.T)
        db3 = 1./m*np.sum(dZ3,axis=1,keepdims=True)
        dA2 = np.dot(W3.T,dZ3)
        
        dA2 = dA2*D2
        dA2 /= keep_prob
        
        dZ2 = dA2*np.int64(A2>0)
        dW2 = 1./m*np.dot(dZ2,A1.T)
        db2 = 1./m*np.sum(dZ2,axis=1,keepdims=True)
        dA1 = np.dot(W2.T,dZ2)
        
        dA1 = dA1*D1
        dA1 /= keep_prob
        
        dZ1 = dA1*np.int64(A1>0)
        dW1 = 1./m*np.dot(dZ1,X.T)
        db1 = 1./m*np.sum(dZ1,axis=1,keepdims=True)
        
        gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2,
                     "dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1, 
                     "dZ1": dZ1, "dW1": dW1, "db1": db1}
        
        return gradients
    • 测试代码
    X_assess, Y_assess, cache = backward_propagation_with_dropout_test_case()
    
    gradients = backward_propagation_with_dropout(X_assess, Y_assess, cache, keep_prob = 0.8)
    
    print ("dA1 = " + str(gradients["dA1"]))
    print ("dA2 = " + str(gradients["dA2"]))

    • 训练带有Dropout的mox

    parameters = model(train_X, train_Y, keep_prob = 0.86, learning_rate = 0.3)
    
    print ("On the train set:")
    predictions_train = predict(train_X, train_Y, parameters)
    print ("On the test set:")
    predictions_test = predict(test_X, test_Y, parameters)

    Dropout效果非常好,模型在测试集上的准确率达到了95%,模型不仅在训练集上不再过拟合,而且在测试集上效果也非常好。

    • 绘制决策边界
    plt.title("Model with dropout")
    axes = plt.gca()
    axes.set_xlim([-0.75,0.40])
    axes.set_ylim([-0.75,0.65])
    plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, np.squeeze(train_Y))

     

    • 总结

    6.结论

    三、实验3:梯度检查

    1.实验综述

    2.导入必要的包

    import numpy as np
    from testCases import * #提供测试用例
    #gc_utils.py 提供梯度检验实验需要的函数
    from gc_utils import sigmoid, relu, dictionary_to_vector, vector_to_dictionary, gradients_to_vector

    3.梯度检验时怎么工作的?

    • 一维梯度检验

    • 代码实现
    
    def forward_propagation(x, theta):
        """
        实现线性前向传播就算 (J(theta) = theta * x)
        
        参数:
        x -- 实数输入
        theta -- 模型参数,也是实数
        
        返回:
        J --  J(theta) = theta * x
        """
        
        J = theta*x
        
        
        return J
    def backward_propagation(x, theta):
        """
        计算J对theta的梯度 (see Figure 1).
        
        参数:
        x -- 实数输入
        theta -- 模型参数,也是实数
        
        返回:
        dtheta -- J对theta的梯度
        """
        
        dtheta = x
        
        return dtheta
    • 实现梯度检查

    • 代码实现
    
    def gradient_check(x, theta, epsilon = 1e-7):
        """
        实现梯度检验
        
        参数:
        x -- 实数输入
        theta -- 模型参数,也是实数
        epsilon -- 非常小的数
        
        返回:
        difference -- 近似梯度和反向传播计算的梯度的距离
        """
        
        thetaplus = theta + epsilon
        thetaminus = theta - epsilon
        J_plus = forward_propagation(x,thetaplus)
        J_minus = forward_propagation(x,thetaminus)
        gradapprox = (J_plus-J_minus)/(2*epsilon)
        
        grad = backward_propagation(x,theta)
        
        numerator = np.linalg.norm(grad - gradapprox)
        denominator = np.linalg.norm(grad)+np.linalg.norm(gradapprox)
        difference = numerator/denominator
        
        if difference < 1e-7:
            print ("The gradient is correct!")
        else:
            print ("The gradient is wrong!")
        
        return difference

     

    x, theta = 2, 4
    difference = gradient_check(x, theta)
    print("difference = " + str(difference))

    • N维梯度检验

     

    • 代码实现
    def forward_propagation_n(X, Y, parameters):
        """
        实现上图中3层神经网络的前向传播
        
        参数:
        X -- 样本特征矩阵 (nx,m)
        Y -- 样本真实标签 (1,m)
        模型参数 -- 字典形式 包含 "W1", "b1", "W2", "b2", "W3", "b3":
                        W1 -- weight matrix of shape (5, 4)
                        b1 -- bias vector of shape (5, 1)
                        W2 -- weight matrix of shape (3, 5)
                        b2 -- bias vector of shape (3, 1)
                        W3 -- weight matrix of shape (1, 3)
                        b3 -- bias vector of shape (1, 1)
        
        返回:
        cost -- m个样本的cost值
        """
        
        m = X.shape[1]
        W1 = parameters["W1"]
        b1 = parameters["b1"]
        W2 = parameters["W2"]
        b2 = parameters["b2"]
        W3 = parameters["W3"]
        b3 = parameters["b3"]
    
        # LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID
        Z1 = np.dot(W1,X)+b1
        A1 = relu(Z1)
        Z2 = np.dot(W2,A1)+b2
        A2 = relu(Z2)
        Z3 = np.dot(W3,A2)+b3
        A3 = sigmoid(Z3)
    
        # Cost
        logprobs = -Y*np.log(A3)-(1-Y)*np.log(1-A3)
        cost = 1./m*np.sum(logprobs)
        
        cache = (Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3)
        
        return cost, cache
    def backward_propagation_n(X, Y, cache):
     
        """
        实现上图中3层神经网络的反向传播
        
        参数:
        X -- 样本特征矩阵 (nx,m)
        Y -- 样本真实标签 (1,m)
        cache -- 前向传播中缓存的值 参数共享
        
        返回:
        gradients -- 字典形式 模型参数的梯度 dZ,dW,db
        """
        
        m = X.shape[1]
        (Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3) = cache
        
        dZ3 = A3 - Y
        dW3 = 1./m*np.dot(dZ3,A2.T)
        db3 = 1./m*np.sum(dZ3,axis=1,keepdims=True)
        dA2 = np.dot(W3.T,dZ3)
        
        dZ2 = dA2*np.int64(A2>0)
        dW2 = 1./m*np.dot(dZ2,A1.T)
        db2 = 1./m*np.sum(dZ2,axis=1,keepdims=True)
        dA1 = np.dot(W2.T,dZ2)
        
        dZ1 = dA1*np.int64(A1>0)
        dW1 = 1./m*np.dot(dZ1,X.T)
        db1 = 1./m*np.sum(dZ1,axis=1,keepdims=True)
        
        gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,
                     "dA2": dA2, "dZ2": dZ2, "dW2": dW2, "db2": db2,
                     "dA1": dA1, "dZ1": dZ1, "dW1": dW1, "db1": db1}
        
        return gradients
    • 梯度检查工作原理

    • 实现梯度检查

    • 代码实现
    # GRADED FUNCTION: gradient_check_n
    
    def gradient_check_n(parameters, gradients, X, Y, epsilon = 1e-7):
        """
        实现n维梯度检查
        
        参数:
        parameters -- Python字典 包含模型所有参数 "W1", "b1", "W2", "b2", "W3", "b3":
        grad -- 反向传播计算的参数梯度,字典形式,和参数对应
        X -- 样本特征矩阵 (nx,m)
        Y -- 样本真实标签 (1,m)
        epsilon -- 一个很小的偏移值
        
        返回:
        difference -- 近似梯度向量和反向传播计算的梯度向量的距离
        """
        parameters_values,_ = dictionary_to_vector(parameters) #把模型参数拉伸为向量
        grad = gradients_to_vector(gradients) #把反向传播计算的梯度拉伸为向量
        num_parameters = len(parameters_values)#参数数量
        J_plus = np.zeros((num_parameters,1))
        J_minus = np.zeros((num_parameters,1))
        gradapprox = np.zeros((num_parameters,1))
        
        #计算每个参数的近似梯度
        for i in range(num_parameters):
            theta_plus = np.copy(parameters_values)
            theta_plus[i][0] = theta_plus[i][0]+epsilon
            J_plus[i],_ = forward_propagation_n(X,Y,vector_to_dictionary(theta_plus))
            
            theta_minus = np.copy(parameters_values)
            theta_minus[i][0] = theta_minus[i][0]-epsilon
            J_minus[i],_ = forward_propagation_n(X,Y,vector_to_dictionary(theta_minus))
            
            gradapprox[i] = (J_plus[i]-J_minus[i])/(2*epsilon)
            
        difference = np.linalg.norm(grad-gradapprox)/(np.linalg.norm(grad)+np.linalg.norm(gradapprox))
        
    
        if difference > 1e-7:
            print ("\033[93m" + "There is a mistake in the backward propagation! difference = " + str(difference) + "\033[0m")
        else:
            print ("\033[92m" + "Your backward propagation works perfectly fine! difference = " + str(difference) + "\033[0m")
        
        return difference
    X, Y, parameters = gradient_check_n_test_case()
    
    cost, cache = forward_propagation_n(X, Y, parameters)
    gradients = backward_propagation_n(X, Y, cache)
    difference = gradient_check_n(parameters, gradients, X, Y)

    • 总结

     

    四、实验完整代码

    实验完整代码       下载密码:pfdo

     

     

     

     

    展开全文
  •  本书适合于大学高年级学生或研究生的网络编程入门课程,也可作为程序员参考书。   作译者 作者:Douglas E.Comer  Douglas Comer博博士是Purdue Univ教授,讲授操作系统和计算机网络课程,早在20世纪70午...
  • XML高级编程

    2012-05-30 12:02:59
    本书是由从一个核心辐射出去的三个主线组成的。读者当然可以从第1章开始,然后按顺序逐章阅读到最后一章,但读者也可以根据自己的需要找到一个更为直接的途径。每个人应该阅读本书的核心章节以理解XML包含的基本内容...
  • 4.6 网络通信基本方法 29 4.7 LINIX中提供基本I/O功能 29 4.8 将Linux I/O用于TCP/IP 30 4.9 小结 31 深入研究 31 习题 31 第5章 套接字API 32 5.1 引言 32 5.2 Berkeley套接字 32 5.3 指明一个...
  • Tcl_TK编程权威指南pdf

    热门讨论 2011-03-25 09:30:55
    本书的大部分内容是有关Tcl脚本编程的,而有关使用C语言来创建Tcl扩展模块的内容没有着重讲述。我有幸一直参与Tcl核心技术的开发活动,希望通过本书能够将自己使用Tcl时获得的切身体会表达出来。 为什么要使用Tcl ...
  • 本书是由从一个核心辐射出去的三个主线组成的。读者当然可以从第1章开始,然后按顺序逐章阅读到最后一章,但读者也可以根据自己的需要找到一个更为直接的途径。每个人应该阅读本书的核心章节以理解XML包含的基本内容...
  • 精通qt4编程(源代码)

    热门讨论 2010-03-17 19:10:40
    \ 第5章 布局管理 卢传富布局管理是GUI应用程序编程的一个重要方面。Qt提供了多种布局管理部件,包括Qt布局管理器、分裂器、栈部件、工作空间部件和多文档区部件等。本章一一介绍了这些部件,并举例说明了它们在图形...
  • 精通Qt4编程(第二版)源代码

    热门讨论 2014-01-19 13:07:18
    \ 第5章 布局管理 卢传富布局管理是GUI应用程序编程的一个重要方面。Qt提供了多种布局管理部件,包括Qt布局管理器、分裂器、栈部件、工作空间部件和多文档区部件等。本章一一介绍了这些部件,并举例说明了它们在图形...
  • 理解C#仅仅是编写Internet或网络识别应用程序语言也很重要。它还提供了一编写Windows平台上几乎任何类型软件或组件方式。另外,C#和.NET都对开发人员编写程序方式进行了革新,更易于实现在Windows上...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...
  • 7.8.1 取得文件路径的三种情况 206 7.8.2 打开成功后获取路径 207 7.8.3 在其他时刻获得文件路径 209 7.8.4 在打开请求完成之前获得路径 209 7.8.5 把短名转换为长名 211 7.9 把sfilter编译成静态库 212 7.9.1 如何...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 283
精华内容 113
关键字:

网络编程的三种模型不包括