精华内容
下载资源
问答
  • 损失函数

    2021-02-13 22:32:13
    1、损失函数目的 损失函数loss function)是用来估量模型的预测值f(x)与真实值Y的不一致程度,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就...回归常见的损失函数有:均方差(Mean S

    1、损失函数目的

    损失函数loss function)是用来估量模型的预测值f(x)与真实值Y的不一致程度,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就越好。损失函数是经验风险函数的核心部分,也是结构风险函数重要组成部分。模型的结构风险函数包括了经验风险项和正则项,通常可以表示成如下式子:

    2、损失函数、代价函数、目标函数之间的关系

    损失函数是代价函数的一部分,代价函数是目标函数的一种

    3、常见的损失函数

    回归常见的损失函数有:均方差(Mean Squared Error,MSE)平均绝对误差(Mean Absolute Error Loss,MAE)Huber Loss是一种将MSE与MAE结合起来,取两者优点的损失函数,也被称作Smooth Mean Absolute Error Loss 、分位数损失(Quantile Loss)损失函数。

    分类常见的损失函数有:交叉熵损失(Cross Entropy Loss)合页损失(Hinge Loss)0/1损失函数指数损失对数损失/对数似然损失(Log-likelihood Loss)

    4、回归常见的损失函数

    4.1、 均方差损失(Mean Squared Error Loss)

     

    均方差(Mean Squared Error,MSE)损失是机器学习、深度学习回归任务中最常用的一种损失函数,也称为 L2 Loss。其基本形式如下:

    可以看到这个实际上就是均方差损失的形式。也就是说在模型输出与真实值的误差服从高斯分布的假设下,最小化均方差损失函数与极大似然估计本质上是一致的,因此在这个假设能被满足的场景中(比如回归),均方差损失是一个很好的损失函数选择;当这个假设没能被满足的场景中(比如分类),均方差损失不是一个好的选择

    4.2、平均绝对误差损失(Mean Absolute Error Loss)

    平均绝对误差(Mean Absolute Error Loss,MAE)是另一类常用的损失函数,也称为L1 Loss。其基本形式如下:

    MAE与MSE的区别:

    • MSE比MAE能够更快收敛:当使用梯度下降算法时,MSE损失的梯度为,而MAE损失的梯度为正负1。所以。MSE的梯度会随着误差大小发生变化,而MAE的梯度一直保持为1,这不利于模型的训练
    • MAE对异常点更加鲁棒:从损失函数上看,MSE对误差平方化,使得异常点的误差过大;从两个损失函数的假设上看,MSE假设了误差服从高斯分布,MAE假设了误差服从拉普拉斯分布,拉普拉斯分布本身对于异常点更加鲁棒

    4.3、Huber Loss

    Huber Loss是一种将MSE与MAE结合起来,取两者优点的损失函数,也被称作Smooth Mean Absolute Error Loss 。其原理很简单,就是在误差接近0时使用MSE,误差较大时使用MAE,公式为:

    在 内实际上就是MSE的损失,使损失函数可导并且梯度更加稳定;在区间内为MAE损失,降低了异常点的影响,使训练更加鲁棒

    4.4、 分位数损失(Quantile Loss)

    分位数回归Quantile Regression是一类在实际应用中非常有用的回归算法,通常的回归算法是拟合目标值的期望(MSE)或者中位数(MAE),而分位数回归可以通过给定不同的分位点,拟合目标值的不同分位数。

    式中的r为分位数,这个损失函数是一个分段的函数,当r>0.5时,低估()的损失要比高估的损失更大;反之,当r<0.5 时,高估的损失要比低估的损失更大,分位数损失实现了分别用不同的系数控制高估和低估的损失,进而实现分位数回归。特别地,当r=0.5时,分位数损失退化为MAE损失,从这里可以看出 MAE 损失实际上是分位数损失的一个特例—中位数回归

    5、分类常见损失函数

    5.1、0-1损失函数(zero-one loss)

    5.2、 log对数损失函数

     

    5.3、 指数损失函数(exponential loss)

    5.4、hinge损失函数

    支持向量机Support Vector Machine (SVM)模型的损失函数本质上就是Hinge Loss + L2正则化。

    5.5、交叉熵损失函数 (Cross-entropy loss function)

    5.5.1、二分问题的交叉熵损失

    5.5.2、多分类问题的交叉熵损失函数

     

    5.5.3、交叉熵损失的优缺点

     

    6、交叉熵函数最大似然函数的联系和区别

    区别:交叉熵函数使用来描述模型预测值和真实值的差距大小,越大代表越不相近;似然函数的本质就是衡量在某个参数下,整体的估计和真实的情况一样的概率,越大代表越相近。

    联系:交叉熵函数可以由最大似然函数在伯努利分布的条件下推导出来,或者说最小化交叉熵函数的本质就是对数似然函数的最大化

     

    参考文章

    https://zhuanlan.zhihu.com/p/58883095(损失函数简单介绍,简单说明了常见的损失函数和相关优缺点)

    https://zhuanlan.zhihu.com/p/97698386(挺详细的损失函数介绍,并阐明了损失函数背后所依赖的数学原理)

    https://www.jianshu.com/p/43318a3dc715(KL散度详细原理介绍)

    https://www.cnblogs.com/guoyaohua/p/9217206.html(书中损失函数计算)

     

    展开全文
  • 在进入今天的select模型的主题之前,我们先来简单了解一下五I/O模型:(1)阻塞I/O(默认采用这种方式)在服务端socket编程中,我们常见的accpet函数、recv函数都是采取的阻塞形式。以recv为例: 当上层应用App...

    在进入今天的select模型的主题之前,我们先来简单了解一下五种I/O模型:

    (1)阻塞I/O(默认采用这种方式)


    在服务端socket编程中,我们常见的accpet函数、recv函数都是采取的阻塞形式。以recv为例: 当上层应用App调用recv系统调用时,如果对等方没有发送数据(Linux内核缓冲区中没有数据),上层应用Application1将阻塞;当对等方发送了数据,Linux内核recv端缓冲区数据到达,内核会把数据copy给用户空间。然后上层应用App解除阻塞,执行下一步操作。

    (2)非阻塞I/O(不推荐)


    上层应用如果应用非阻塞模式, 会循环调用recv函数,接受数据。若缓冲区没有数据,上层应用不会阻塞,recv返回值为-1,错误码是EWOULDBLOCK(图中的标记有误)。上层应用程序不断轮询有没有数据到来。造成上层应用忙等待。大量消耗CPU。因此非阻塞模式很少直接用。应用范围小,一般和IO复用配合使用

    (3)信号驱动I/O模型(不经常使用)



    上层应用建立SIGIO信号处理程序。当缓冲区有数据到来,内核会发送信号告诉上层应用App; 当上层应用App接收到信号后,调用recv函数,因缓冲区有数据,recv函数一般不会阻塞。但是这种用于模型用的比较少,属于典型的“拉模式(上层应用被动的去Linux内核空间中拉数据)”。即:上层应用App,需要调用recv函数把数据拉进来,会有时间延迟,我们无法避免在延迟时,又有新的信号的产生,这也是他的缺陷。

    (4)异步I/O(不常用)


    上层应用调用aio_read函数,同时提交一个应用层的缓冲区buf;调用完毕后,不会阻塞。上层应用程序App可以继续其他任务; 当TCP/IP协议缓冲区有数据时,Linux主动的把内核数据copy到用户空间。然后再给上层应用App发送信号;告诉App数据到来,需要处理!

       异步IO属于典型的“推模式”, 是效率最高的一种模式,上层应用程序App有异步处理的能力(在Linux内核的支持下,处理其他任务的同时,也可支持IO通讯, 与Windows平台下的完成端口作用类似IOCP)。

    (5)I/O复用的select模型(本篇的重点)


    试想如果你遇到下面的问题会怎么处理?

    1)server除了要对外响应client的服务外,还要能够接受标准输入的命令来进行管理。

    假如使用上述阻塞方式,在单线程中,accept调用和read调用必定有先后顺序,而它们都是阻塞的。比如先调用accept,后调用    read,那么如果没有客户请求时,服务器会一直阻塞在accept,没有机会调用read,也就不能响应标准输入的命令。 

    2) server要对外提供大量的client请求服务。

     假如使用阻塞方式,在单线程中,由于accept和recev都是阻塞式的,那么当一个client被服务器accept后,它可能在send发送消息时阻塞,因此服务器就会阻塞在recev调用。即时此时有其他的client进行connect,也无法进行响应。


    这时就需要select来解决啦!select实现的是一个管理者的功能: 用select来管理多个IO, 一旦其中的一个IO或者多个IO检测到我们所感兴趣的事件, select就返回, 返回值就是检测到的事件个数, 并且由第2~4个参数返回那些IO发送了事件, 这样我们就可以遍历这些事件, 进而处理这些事件。

    有人说,我用多线程不就可以了吗?但是在UNIX平台下多进程模型擅长处理并发长连接,但却不适用于连接频繁产生和关闭的情形。当然select并不是最高效的,有着O(N)的时间复杂度,关于更高效的epoll我将在后面的博客中继续讲解,欢迎大家关注,╰( ̄▽ ̄)╮

    1. #include <sys/select.h>    
    2. #include <sys/time.h>    
    3. #include <sys/types.h>    
    4. #include <unistd.h>    
    5. int select(int nfds, fd_set *readfds, fd_set *writefds,    
    6.            fd_set *exceptfds, struct timeval *timeout);  

    nfds: is the highest-numbered file descriptor in any of the three sets,plus 1[读,写,异常集合中的最大文件描述符+1].

    fd_set[四个宏用来对fd_set进行操作]

           FD_CLR(int fd, fd_set *set);

           FD_ISSET(int fd, fd_set *set);

           FD_SET(int fd, fd_set *set);

           FD_ZERO(fd_set *set);

    timeout[从调用开始到select返回前,会经历的最大等待时间, 注意此处是指的是相对时间]

    1. /timeval结构:    
    2. struct timeval    
    3. {    
    4.     long    tv_sec;     /* seconds */    
    5.     long    tv_usec;    /* microseconds */    
    6. };    
    7. //一些调用使用3个空的set, n为0, 一个非空的timeout来达到较为精确的sleep.  

    Linux中, select函数改变了timeout值,用来指示还剩下的时间,但很多实现并不改timeout。

    为了较好的可移植性,timeout在循环中一般常被重新赋初值。

    Timeout取值:

        timeout== NULL

            无限等待,被信号打断时返回-1, errno 设置成 EINTR

        timeout->tv_sec == 0 && tvptr->tv_usec == 0

            不等待立即返回

        timeout->tv_sec != 0 || tvptr->tv_usec != 0

            等待特定时间长度, 超时返回0

    :关于select用来设置超时时间的用法可以参考我的另外一篇博客 http://blog.csdn.net/nk_test/article/details/49050379

    返回值:

       如果成功,返回所有sets中描述符的个数;如果超时,返回0;如果出错,返回-1.



    下面是使用select改进服务器端和客户端的程序,解决了上述提出的两个问题:

    服务器端:

    1. /*示例1: 用select来改进echo回声服务器的client端的echoClient函数  
    2. 使得可以在单进程的情况下同时监听多个文件描述符;  
    3. */    
    4. void echoClient(int sockfd)    
    5. {    
    6.     char buf[512];    
    7.     fd_set rset;    
    8.     //确保标准输入不会被重定向    
    9.     int fd_stdin = fileno(stdin);    
    10.     int maxfd = fd_stdin > sockfd ? fd_stdin : sockfd;    
    11.     while (true)    
    12.     {    
    13.         FD_ZERO(&rset);  
    14.         //监视两个I/O    
    15.         FD_SET(fd_stdin, &rset);    
    16.         FD_SET(sockfd, &rset);    
    17.         int nReady = select(maxfd+1, &rset, NULL, NULL, NULL);  //不需要的置NULL   
    18.         if (nReady == -1)    
    19.             err_exit("select error");    
    20.         else if (nReady == 0)    
    21.             continue;    
    22.     
    23.         /** nReady > 0: 检测到了可读事件 **/    
    24.     
    25.         if (FD_ISSET(fd_stdin, &rset))    
    26.         {    
    27.             memset(buf, 0, sizeof(buf));    
    28.             if (fgets(buf, sizeof(buf), stdin) == NULL)    
    29.                 break;    
    30.             if (writen(sockfd, buf, strlen(buf)) == -1)    
    31.                 err_exit("write socket error");    
    32.         }    
    33.         if (FD_ISSET(sockfd, &rset))    
    34.         {    
    35.             memset(buf, 0, sizeof(buf));    
    36.             int readBytes = readline(sockfd, buf, sizeof(buf));    
    37.             if (readBytes == 0)    
    38.             {    
    39.                 cerr << "server connect closed..." << endl;    
    40.                 exit(EXIT_FAILURE);    
    41.             }    
    42.             else if (readBytes == -1)    
    43.                 err_exit("read-line socket error");    
    44.     
    45.             cout << buf;    
    46.         }    
    47.     }    
    48. }   

    客户端:


    1. /*示例2: 用select来改进echo回射服务器的server端的接受连接与处理连接部分的代码:  
    2. 使得可以在单进程的情况下处理多客户连接, 对于单核的CPU来说, 单进程使用select处理连接与监听套接字其效率不一定就会比多进程/多线程性能差;  
    3. */    
    4.     struct sockaddr_in clientAddr;    
    5.     socklen_t addrLen;    
    6.     int maxfd = listenfd;    
    7.     fd_set rset;    
    8.     fd_set allset;    
    9.     FD_ZERO(&rset);    
    10.     FD_ZERO(&allset);    
    11.     FD_SET(listenfd, &allset);    
    12.      
    13.     int client[FD_SETSIZE];  //用于保存已连接的客户端套接字   
    14.     for (int i = 0; i < FD_SETSIZE; ++i)    
    15.         client[i] = -1;    
    16.     int maxi = 0;   //用于保存最大的不空闲的位置, 用于select返回之后遍历数组    
    17.     
    18.     while (true)    
    19.     {    
    20.         rset = allset;    
    21.         int nReady = select(maxfd+1, &rset, NULL, NULL, NULL);    
    22.         if (nReady == -1)    
    23.         {    
    24.             if (errno == EINTR)    
    25.                 continue;    
    26.             err_exit("select error");    
    27.         }    
    28.         //nReady == 0表示超时, 但是此处是一定不会发生的    
    29.         else if (nReady == 0)    
    30.             continue;    
    31.     
    32.         if (FD_ISSET(listenfd, &rset))    
    33.         {    
    34.             addrLen = sizeof(clientAddr);    
    35.             int connfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);    
    36.             if (connfd == -1)    
    37.                 err_exit("accept error");    
    38.     
    39.             int i;    
    40.             for (i = 0; i < FD_SETSIZE; ++i)    
    41.             {    
    42.                 if (client[i] < 0)    
    43.                 {    
    44.                     client[i] = connfd;    
    45.                     if (i > maxi)    
    46.                         maxi = i;    
    47.                     break;    
    48.                 }    
    49.             }    
    50.             if (i == FD_SETSIZE)    
    51.             {    
    52.                 cerr << "too many clients" << endl;    
    53.                 exit(EXIT_FAILURE);    
    54.             }    
    55.             //打印客户IP地址与端口号    
    56.             cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)    
    57.                  << ", " << ntohs(clientAddr.sin_port) << endl;    
    58.             //将连接套接口放入allset, 并更新maxfd    
    59.             FD_SET(connfd, &allset);    
    60.             if (connfd > maxfd)    
    61.                 maxfd = connfd;    
    62.     
    63.             if (--nReady <= 0)    
    64.                 continue;    
    65.         }    
    66.     
    67.         /**如果是已连接套接口发生了可读事件**/    
    68.         for (int i = 0; i <= maxi; ++i)    
    69.             if ((client[i] != -1) && FD_ISSET(client[i], &rset))    
    70.             {    
    71.                 char buf[512] = {0};    
    72.                 int readBytes = readline(client[i], buf, sizeof(buf));    
    73.                 if (readBytes == -1)    
    74.                     err_exit("readline error");    
    75.                 else if (readBytes == 0)    
    76.                 {    
    77.                     cerr << "client connect closed..." << endl;    
    78.                     FD_CLR(client[i], &allset);    
    79.                     close(client[i]);    
    80.                     client[i] = -1;    
    81.                 }    
    82.                 //注意此处: Server从Client获取数据之后并没有立即回射回去,    
    83.                 //        而是等待四秒钟之后再进行回射    
    84.                 sleep(4);    
    85.                 cout << buf;    
    86.                 if (writen(client[i], buf, readBytes) == -1)    
    87.                     err_exit("writen error");    
    88.     
    89.                 if (--nReady <= 0)    
    90.                     break;    
    91.             }    
    92.     }   
    展开全文
  • 78.常见的异常类有哪些? 、网络 79.http 响应码 301 和 302 代表的是什么?有什么区别? 80.forward 和 redirect 的区别? 81.简述 tcp 和 udp的区别? 82.tcp 为什么要三次握手,两次不行吗?为什么? 83.说一下...
  • 目录 一、创建字典 二、访问字典里值 三、修改字典 四、删除字典元素 五、字典键特性 ...Python字典是另一可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。...

    目录

    一、创建字典

    二、访问字典里的值

    三、修改字典

    四、删除字典元素

    五、字典键的特性

    六、字典内置函数&方法

    七、判断python字典中key是否存在的

    八、python字典按照value进行排序

    九、OrderedDict 有序字典以及读取json串时如何保持原有顺序


    Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。

     

    一、创建字典

    字典由键和对应值成对组成。字典也被称作关联数组或哈希表。基本语法如下:

    dict = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
    
    # 也可如此创建字典
    
    dict1 = { 'abc': 456 }
    dict2 = { 'abc': 123, 98.6: 37 }

    注意:

    每个键与值用冒号隔开(:),每对用逗号,每对用逗号分割,整体放在花括号中({})。

    键必须独一无二,但值则不必。

    值可以取任何数据类型,但必须是不可变的,如字符串,数或元组。

     

    二、访问字典里的值

    把相应的键放入熟悉的方括弧,如下实例:

    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    
    print ("dict['Name']: ", dict['Name'])
    print ("dict['Age']: ", dict['Age'] )
    
    #以上实例输出结果:
    
    #dict['Name']:  Zara
    #dict['Age']:  7

    如果用字典里没有的键访问数据,会输出错误如下:

    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    print ("dict['Alice']: ", dict['Alice'] )
    
    # 以上实例输出结果:
    
    #KeyError: 'Alice'

     

    三、修改字典

    向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:

    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    
    dict['Age'] = 8; # update existing entry
    dict['School'] = "DPS School"; # Add new entry
    
    print ("dict['Age']: ", dict['Age'])
    print ("dict['School']: ", dict['School'])
    
    #以上实例输出结果:
    
    #dict['Age']:  8
    #dict['School']:  DPS School

     

    四、删除字典元素

    能删单一的元素也能清空字典,清空只需一项操作。

    显示删除一个字典用del命令,如下实例:

    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
    
    del dict['Name'] # 删除键是'Name'的条目
    dict.clear()     # 清空词典所有条目 KeyError: 'Age'
    del dict         # 删除词典 TypeError: 'type' object is not subscriptable
    
    print ("dict['Age']: ", dict['Age'])
    
    # 但这会引发一个异常,因为用del后字典不再存在

     

    五、字典键的特性

    字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的,但键不行。

    两个重要的点需要记住:

    1)不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住,如下实例:

    dict = {'Name': 'Zara', 'Age': 7, 'Name': 'Manni'}
    
    print("dict['Name']: ", dict['Name'])
    
    #以上实例输出结果:
    
    #dict['Name']:  Manni

    2)键必须不可变,所以可以用数,字符串或元组充当,所以用列表就不行,如下实例:

    dict = {['Name']: 'Zara', 'Age': 7}
    
    print("dict['Name']: ", dict['Name'])
     
    # 以上实例输出结果:
    # TypeError: unhashable type: 'list'

     

    六、字典内置函数&方法

    Python字典包含了以下内置函数:     

    cmp(dict1, dict2)  #比较两个字典元素。

    len(dict)              #计算字典元素个数,即键的总数。

    str(dict)              #输出字典可打印的字符串表示。

    type(variable)     #返回输入的变量类型,如果变量是字典就返回字典类型。  

     

    七、判断python字典中key是否存在的

    一般有两种通用做法:

    第一种方法:使用自带函数实现:

    在python的字典的属性方法里面有一个has_key()方法:

    #生成一个字典
    d = {'name':Tom, 'age':10, 'Tel':110}
    
    #打印返回值
    print d.has_key('name')
    
    #结果返回True

    第二种方法:使用in方法:

    #生成一个字典
    d = {'name':Tom, 'age':10, 'Tel':110}
    
    #打印返回值,其中d.keys()是列出字典所有的key
    print 'name' in d.keys()
    print 'name' in d
    
    #两个的结果都是返回True

    除了使用in还可以使用not in,判定这个key不存在,使用in要比has_key要快。

    如果要判断多个 可以使用集合:

    if {"test", "file", "name"}.issubset(data.keys()):
        print("find")

     

    八、python字典按照value进行排序

    先说几个解决的方法,具体的有时间再细说

    d = {'a':1,'b':4,'c':2}

    字典是这个,然后要对字典按照value进行排序

    方法一:

    sorted(d.items(),key = lambda x:x[1],reverse = True)

    方法二:

    import operator
    
    sorted(d.items(),key = operator.itemgetter(1))

    方法三:

    f = zip(d.values(),d.keys())
    
    sorted(f)

    //结果是 [(1, 'a'), (2, 'c'), (4, 'b')]

    zip 之后,zip函数默认会对第一个元素进行排序的,如何取消排序?

     

    九、OrderedDict 有序字典以及读取json串时如何保持原有顺序

    1. OrderedDict 有序字典

    OrderedDict是dict的子类,它记住了内容添加的顺序。

    dict本身是无序的,OrderedDict之所以能记住顺序,是将对应关系转化为元组进行存储,顺序通过列表来记录,以此实现保持原有顺序的功能

    OrderedDict([(3, 'A'), (2, 'B'), (1, 'C')])

    而原字典的存储形式是这样的

    {1: 'C', 2: 'B', 3: 'A'}

    比较时,OrderedDict要内容和顺序完全相同才会视为相等。
    示例:

    import collections
    
    d = collections.OrderedDict()
    d[3] = 'A'
    d[2] = 'B'
    d[1] = 'C'
    for k, v in d.items():
       print(k, v)

    结果是顺序(按程序读取顺序输出)

    而如果d是一般的dict,则结果是逆序(输出顺序与key值有关)

    2.读取json串时如何保持原有顺序

    import json
    
    from collections import OrderedDict
    metadata = json.loads(text, object_pairs_hook=OrderedDict);

    metadata中properties的顺序是跟text中定义的顺序是一样的。

     

     

    展开全文

空空如也

空空如也

1 2 3 4 5
收藏数 95
精华内容 38
关键字:

常见的八种函数模型