精华内容
下载资源
问答
  • 为了弥补这一差距,本研究提出了一种新颖的可解释性深度学习方法,即基于分段对抗和注意深度学习的基于生成对抗网络(GAN-PiWAD),以预测社交媒体中的健康错误信息传播。 GAN-PiWAD改进了最新的可解释方法,捕获了...
  • 这种分层架构的软件必然使软件的耦合性降低,内聚性加强,但分层带来的缺点是增加了软件开发的重复性工作[3],同时分层也会使应用变得相对复杂[4],进而可能会使编程产生一些不必要的错误。由于JavaWeb应用业务逻辑...

    0.引言      

           大多数的JavaWeb应用一般都采用多层架构[, 即软件结构采用分层的思想。这种分层架构的软件必然使软件的耦合性降低,内聚性加强,但分层带来的缺点是增加了软件开发的重复性工作,同时分层也会使应用变得相对复杂,进而可能会使编程产生一些不必要的错误。由于JavaWeb应用业务逻辑的复杂性,容易发生一些意想不到的错误和异常,给系统的调试带来不必要的麻烦,不友好的提示信息使编程者对错误和异常无从下手。特别是当发生异常时,Java异常栈输出的信息只能给程序员来看,是绝对不能展示给用户的。而且一旦项目发布成最终版本运行时,也十分有必要跟踪和记录所发生的错误和异常的详细信息,并返回一个特定的友好界面给用户。 在传统的JavaWeb应用中,应用程序通常是采用硬编码的方式来避免将要发生的错误和异常,对应用程序中的异常经常使用try…catch语句进行处理,哪 里可能会抛出异常,就在哪里进行捕获,这些语句似乎成了应对编译器而不得已的手段。为了简化,往往在catch代码块中什么也不写,try…catch语句成了一种摆设。甚至干脆就用关键字throws声明抛出异常,不对异常进行处理。这样不但会使写出来的程序杂乱无序,到处都是一些无用的try…catch语句,程序的可读性、可修改性大大降低,而且还会增加程序员的工作量。

          针对以上问题,考虑到JavaWeb应用开发、日后运行、升级和维护,在Java异常机制的基础上构建了一个在JavaWeb环境中的错误处理和异常处理的框架模型。该模型对异常和错误进行统一管理,并在一个集中的位置统一处理,程序的可读性、可维护性、可修改性、鲁棒性等都得到了提高。本文使用Struts、Spring、Hibernate架构三层JavaWeb应用。Struts作为表示层,Spring作为业务逻辑层,Hibernate作为持久层。


    1.Struts+Spring+Hibernate三层架构

           一个好的JavaWeb项目的软件体系结构应该分多层的,分的层越多,程序中模块之间的耦合度就越低,模块的内聚性就越强,但应用程序也会变得相对复杂。一般情况下,分成三层比较适中。本文讨论的不是软件体系结构,而是在Java异常机制的基础上构建一个在JavaWeb环境中的错误处理和异常处理的通用框架模型。所以在此仅简单地给出了软件的三层体系结构模型,即JavaWeb三层结构模型,如图1所示。



    2.错误与异常处理模型


           本文所说的错误是特定的一类错误,例如保存记录时该记录已经存在;删除时该记录不存在,连接数据库出错,事务没有及时打开或关闭等都将其视为错误。而异常在Java中都是Throwable类的子类,在它之下包含两个子类Error与Exception,当在Java虚拟机中发生动态连接失败或其他的定位失败时,Java虚拟机抛出一个Error对象。当程序不捕获或抛出Errors对象时,永远不会遇到需要实例化Error的应用,那么需要关心的就是Exception类。


    2.1错误和异常处理原则

          本文对错误的处理方式是采用抛出自定义类型的异常,这样便于对异常和错误进行统一管理,提高JavaWeb应用程序的健壮性。JavaWeb应用开发中产生的异常都应该继承Exception(属于checkedexcpetion类型)。而且JavaWeb应用一般采用三层或多层架构,程序员没有必要在各个层中对错误和异常进行处理,应用中的每一层在包装并传递异常时要过滤掉Runtime-Exception,从责任这个角度看uncheckedexception是程序应该负担的责任;checkedexception是具体应用负担的责任。无论如何我们都不应该将uncheckedexception这样的异常暴露给客户的,因为他们没有解决这个问题的责任,应该将这种异常封装成checkedexception类型的异常,由具体的应用程序来负担这个责任。


    2.2错误处理策略

           程序中可能会发生很多的错误,例如当执行删除记录、插入记录、修改记录和复杂的业务逻辑等错误,当出现了错误应该如何处理呢?
          传统的处理方法是采用编程的方式来提高应用程序的健壮性。当发生错误时,由程序来控制给用户提示友好信息或者显示一个错误提示界面。很显然这种处理方式的实质就是增加程序的代码量来弥补程序中的不足,治标没有治本,不能从根本上解决问题。
    本文采用的错误处理策略是当发生错误时,将错误和发生错误时转向的页面封装成一个异常对象将其抛出,然后将异常集中到一个统一的位置进行处理。显而易见,采用这种错误处理的方式的优点在于:当运行中的程序发生错误时就抛出一个详细的异常对象,根据发生的异常信息来决定转向到不同的页。避免因采用编程而被忽略的一些错误(由于代码量的增加而导致的错误)。

    2.3异常处理策略

           程序中可能会发生很多的异常,例如业务逻辑、未找到指定的文件、类型转换失败等异常时,Web应用程序应该将异常和发生异常时转向的页面封装成一个新的异常对象将其抛出,然后将异常集中到一个统一的位置进行处理。显然,采用这种异常处理的方式的优点在于Java中的异常栈信息没有展现给用户,而是将异常信息和友好的页面展现给用户。
           使用异常对应用程序错误和异常进行统一管理的好处在于:由于Java的异常机制允许调用者可以不对异常进行处理,而用关键字throws抛出异常,这将会使异常向上一级传递,即当前环境没有足够的信息和能力来解决这个异常时,就可以把这个异常交到一个更高级的有能力处理的环境中,在这里将做出对异常的处理,形成一个异常的传递链。这样可以将所有的异常通过这样的传递链集中到一个统一的位置进行统一处理。
          它能使错误代码变得更有条理,与采用硬编码的方式来处理错误方式相比,代码量会明显减少,并且通过这种错误报告机制,只需在一个地方处理错误,即在所谓的“异常处理程序”中处理,这种方式节省了代码,而且把“描述做什么事”的代码和“出了问题怎么办”的代码相分离。总之,与采用硬编码的方式来处理错误的方法相比,异常机制使代码的阅读、编写和调试工作更加井井有条。

    2.4异常抛出策略和捕获位置

           在图1所示的JavaWeb三层架构模型中,我们可以利用Java的多态机制,只捕获自定义的基类异常(例如BasicException),它包含了所有应用程序异常的默认行为,但是具体业务逻辑抛出的异常可以是BasicEx-ception类的任何子类异常,使用多态来隐藏异常的具体的实现类。这意味着BasicException异常(仅仅是这个异常)可以放到抛出checked异常的每个方法的throws子句中,不能包含其他任何应用程序异常。当应用程序发生了某个具体的异常(BasicException的派生类)时,应用程序应该做出在哪一界面上显示哪条错误消息的决策,即在什么位置捕获异常。本文选择的位置是控制器(Struts的Action),它恰恰有根据不同的异常来设置不同的错误信息和跳转到不同的错误页面的能力,而且Action的位置是最接近客户端表示层的,所以这个位置是最恰当的。

           这样所有的异常会在一个集中的公共位置得到处理,使用模板方法(TemplateMethod)设计模式并结合Struts的DispatchAction编写一个模板方法,并在该模板方法中捕获BasicException异常,这将会捕获到所有的子类异常。因此我们采用的策略是:持久层中的所有方法都抛出BasicException异常,不对其处理;业务逻辑层中的所有方法采用像持久层中的策略,同样不对异常进行处理,即抛出BasicEx-ception异常。利用这种传播异常的通用机制,将异常以一种普适的方式集中到距离客户端最近的控制器中处理。这样处理有很多优点:不需要在throws子句中放入大量的checked异常;throws子句中只需要有一个异常,不需要再对应用程序异常使用混乱的catch块;如果需要处理它们,一个catch块(用于BasicException)就足够了,程序员也不需要亲自进行异常处理(日志记录以及获取错误代码),使编程者更加专注于业务逻辑的处理,而错误和异常的处理与记录可以使用后文提到的Facade接口完成。

    3.错误与异常处理模型实现

    3.1错误与异常层次结构

           本文仅以两类错误和两类异常为例展开讨论,但本文构建的错误和异常处理框架模型是适合任意多的错误和异常种类,只要它们间接继承BasicException类,例如数据没有找到类型的错误,例如DataNot-FoundExceptionextendsBasicException。逻辑异常:LogicaExceptionextendsBasicException数据查找错误:DataExceptionextendsBasicExcep-tion权限异常:RightExceptionextendsBasicException登录错误:LoginExceptionextendsBasicException在具体工程项目实现时,可以根据需要增加错误和异常的种类。

    3.2应用与模型交互

           本框架模型是在StrutsAction层负责决定对错误与异常采取什么操作。这种决策涉及到识别抛出异常的代码。此外还需要知道在处理错误与异常之后应该把错误消息重定向到哪一界面。我们需要对基于异常类型获得错误代码这个过程进行抽象,同时还应该执行日志记录。我们把这些工作抽象成一个接口,该接口基于外观设计模式也叫总管模式(Facade模式)[10~11],该模式为子系统中的一组接口提供一个统一外部访问入口。
           外观定义了一个更高级别的接口,使子系统变得更加易于访问,是用于处理所有派生自BasicException的异常的整个异常处理系统的外观。也就是说该接口是连接应用程序与框架模型的一个桥梁,为复杂的异常处理框架模型提供一个统一的操作门面。采用这种设计模式的优点在于:
           它为应用逻辑屏蔽了异常框架模型子系统的复杂性,使得异常框架模型系统更加容易使用。实现了子系统与应用逻辑之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。方便在子系统中添加新功能,只需要在Facade里添加新的方法,然后调用拥有新功能的类或方法就可以了,原来实际执行任务的类不需改变。如图2所示,给出了异常处理模型的时序图。

           从图2可以看出采用这种Facade模式使得业务逻辑控制器只与异常处理门面打交道,简化了业务逻辑关于异常处理的编程,使程序员更加专注于业务逻辑的编程。如图3所示,给出了异常处理模型的时序图。

                                          


                                                            



           从图3可以看出异常处理系统通过异常处理门面,调用异常工具类将发生的所有可能的错误和异常统一封装成ExDTO对象返回给控制器,同时也将异常的详细信息记录到日志文件中有助于日后的调试以及查找错误。
          下面给出一个在StrutsAction方法中进行异常处理的例子。

    try{
    /*
    处理应用程序的业务逻辑
    调用业务逻辑层的业务逻辑方法,该业务方法声明抛出Ba-
    sicException
    */}
    catch(BasicExceptione){
    //定义错误和异常处理者
    ExceptionHandlereh=newExceptionHandler();ExDTOexDto=eh.handleException(“context”,user,ex);ActionMessagesmessages=newActionMessages();messages.add(ActionMessages.GLOBALMESSAGE,newActionMessage(exDTO.getMessageCode()));
    saveMessages(request,messages);//转到用户有好界面
    returnmapping.findForward("errorAndExceptionOccur");}

    3.3精简Struts的Action的代码

          从上面编写Action的方法可以看出,每个方法都必须书写捕获异常的模板代码,应该避免这样的编码方式,解决方式是利用Struts的DispatchAction的工作机制(这里不对该类的工作方式进行介绍,可以查看帮助文档),并结合模板方法模式(TemplateMethod)[10,11]重写模板方法execute,并将不变的处理错误和异常模板的代码写在execute方法中,把具体的可变的业务逻辑控制方法留给子类来实现。下面给出一个自定义的
    StrutsDispatchAction中的execute方法的具体实现例子。
    try{
    ActionForwardfoward=
    dispatchMethod(mapping,form,request,response,name);returnfoward;}
    //处理用户定义错误和异常catch(BaseAppExceptione){
    //定义错误和异常处理者
    ExceptionHandlereh=newExceptionHandler();ExDTOexDto=eh.handleException(expDTO.getContext(),userId,e);
    ActionMessagesmessages=newActionMessages();messages.add(ActionMessages.GLOBAL_MESSAGE,newActionMessage(exDTO.getMessageCode()));saveMessages(request,messages);//转到用户有好界面
    returnmapping.findForward("errorAndExceptionOccur");}
    //处理非用户定义错误和异常catch(Exceptionex){
    //对错误和异常进行记录
    ExceptionUtil.logException(this.getClass(),ex,userId);throwex;
    }finally
    {exDisplay.set(null);}

    经过这样的处理,每个Structs的Action只要继承DispatchAction类就可以自动继承错误和异常处理代码,节省大量代码的编写。

    4.结语

           本文提出了一种关于错误处理和异常处理的框架模型,并利用三层架构思想实现了该模型,解决了JavaWeb应用中错误处理和异常处理普遍存在的问题。当应用发生错误和异常时,该模型能将错误和异常详细信息记录到日志文件中,同时控制器能够根据该信息将页面跳转到指定的网页上。
           由于本文重点介绍错误与异常处理模型,故可以选用不同的工具加以实现。例如表示层可以选用JSF、Struts2;业务逻辑层可以选用Jdon;持久层可以选用其他的ORM框架,例如KylinORM、MyBatis等。
    展开全文
  • 应用很可能以错误的方式使用 SSL,从而导致恶意实体能够拦截网络上的应用数据。为了帮助您确保您的应用不会出现这种情况,本文重点介绍了使用安全网络协议的常见陷阱,并解决对使用公钥基础结构 (PKI) 关注较多的...

    通过 HTTPS 和 SSL 确保安全


    安全套接字层 (SSL)(现在技术上称为传输层安全协议 (TLS))是一个通用构建块,用于在客户端与服务器之间进行加密通信。应用很可能以错误的方式使用 SSL,从而导致恶意实体能够拦截网络上的应用数据。为了帮助您确保您的应用不会出现这种情况,本文重点介绍了使用安全网络协议的常见陷阱,并解决对使用公钥基础结构 (PKI) 关注较多的问题。

    概念


    在典型的 SSL 使用场景中,会使用一个包含公钥及与其匹配的私钥的证书配置服务器。作为 SSL 客户端与服务器握手的一部分,服务器将通过使用公钥加密签署其证书来证明自己具有私钥。

    不过,任何人都可以生成他们自己的证书和私钥,因此,一个简单的握手只能说明服务器知道与证书公钥匹配的私钥,除此之外什么都证明不了。解决此问题的一个方法是让客户端拥有其信任的一个或多个证书集。如果证书不在此集合中,则不会信任服务器。

    但这个简单的方法有几个缺点。服务器应能够随时间的推移升级到更强的密钥(“密钥旋转”),使用新的公钥替换证书中的公钥。遗憾的是,客户端应用现在必须根据服务器配置发生的变化进行更新。如果服务器不在应用开发者的控制下(例如,如果服务器是一个第三方网络服务),则很容易出现问题。如果应用必须与网络浏览器或电子邮件应用等任意服务器通信,那么,此方法也会带来问题。

    为弥补这些缺点,通常使用来自知名颁发者(称为证书颁发机构 (CA))发放的证书配置服务器。主机平台一般包含其信任的知名 CA 的列表。从 Android 4.2 (Jelly Bean) 开始,Android 目前包含在每个版本中更新的 100 多个 CA。CA 具有一个证书和一个私钥,这点与服务器相似。为服务器发放证书时,CA 使用其私钥签署服务器证书。然后,客户端可以验证该服务器是否具有平台已知的 CA 发放的证书。

    不过,在解决一些问题的同时,使用 CA 也会引发其他问题。因为 CA 为许多服务器发放证书,因此,您仍需要某种方式来确保您与您需要的服务器通信。为解决这个问题,CA 发放的证书通过 gmail.com 等具体名称或 *.google.com 等通配型主机集识别服务器。

    以下示例会让这些概念更具体。下面的代码段来自命令行,openssl 工具的 s_client 命令将查看 Wikipedia 的服务器证书信息。它指定端口 443,因为此端口是 HTTPS的默认端口。此命令将 openssl s_client 的输出发送到 openssl x509,后者将根据 X.509 标准格式化与证书有关的信息。具体而言,此命令会要求相关主题,主题包含服务器名称信息和可识别 CA 的颁发者。

    $ openssl s_client -connect wikipedia.org:443 | openssl x509 -noout -subject -issuer
    subject= /serialNumber=sOrr2rKpMVP70Z6E9BT5reY008SJEdYv/C=US/O=*.wikipedia.org/OU=GT03314600/OU=See www.rapidssl.com/resources/cps (c)11/OU=Domain Control Validated - RapidSSL(R)/CN=*.wikipedia.org
    issuer= /C=US/O=GeoTrust, Inc./CN=RapidSSL CA
    

    您会看到证书是由 RapidSSL CA 为与 *.wikipedia.org 匹配的服务器发放的。

    一个 HTTPS 示例


    假设您有一个由知名 CA 发放证书的网络服务器,那么,您可以使用如下简单代码发起安全的请求:

    URL url = new URL("https://wikipedia.org");
    URLConnection urlConnection = url.openConnection();
    InputStream in = urlConnection.getInputStream();
    copyInputStreamToOutputStream(in, System.out);

    没错,就这么简单。如果您要调整 HTTP 请求,您可以切换到 HttpURLConnection。有关 HttpURLConnection 的 Android 文档就如何处理请求和响应标头,以及如何发布内容、管理 Cookie、使用代理、缓存响应等提供了更多示例。但对于验证证书和主机名的细节,Android 框架在 API 中为您考虑了这些细节。这些是您尽可能想要实现的目标。不过,下面还有一些其他注意事项。

    验证服务器证书的常见问题


    假设没有从 getInputStream() 接收内容,将引发异常:

    javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
            at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
    

    出现此情况的原因有很多,其中包括:

    1. 颁发服务器证书的 CA 未知
    2. 服务器证书不是由 CA 签署的,而是自签署
    3. 服务器配置缺少中间 CA

    下面几部分将讨论如何解决这些问题,同时保持与服务器的连接处于安全状态。

    未知的证书颁发机构

    在这种情况下,由于您具有系统不信任的 CA,将发生 SSLHandshakeException。原因可能是您有一个来自 Android 还未信任的新 CA 的证书,或您的应用在没有 CA 的较旧版本上运行。CA 未知的原因通常是因为它不是公共 CA,而是政府、公司或教育机构等组织发放的仅供自己使用的私有 CA。

    幸运的是,您可以指示 HttpsURLConnection 信任特定的 CA 集。此过程可能有点复杂,下面的示例展示了这个过程,从 InputStream 获取一个特定的 CA,用该 CA 创建 KeyStore,然后用后者创建和初始化 TrustManagerTrustManager 是系统用于从服务器验证证书的工具,可以使用一个或多个 CA 从KeyStore 创建,而创建的 TrustManager 将仅信任这些 CA。

    如果是新的 TrustManager,此示例将初始化一个新的 SSLContext,后者可以提供一个 SSLSocketFactory,您可以通过 HttpsURLConnection 用它来替换默认的 SSLSocketFactory。这样一来,连接将使用您的 CA 验证证书。

    下面是使用华盛顿大学的机构 CA 的完整示例:

    // Load CAs from an InputStream
    // (could be from a resource or ByteArrayInputStream or ...)
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    // From https://www.washington.edu/itconnect/security/ca/load-der.crt
    InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
    Certificate ca;
    try {
        ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
    } finally {
        caInput.close();
    }
    
    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    
    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);
    
    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);
    
    // Tell the URLConnection to use a SocketFactory from our SSLContext
    URL url = new URL("https://certs.cac.washington.edu/CAtest/");
    HttpsURLConnection urlConnection =
        (HttpsURLConnection)url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());
    InputStream in = urlConnection.getInputStream();
    copyInputStreamToOutputStream(in, System.out);

    借助一个知道您的 CA 的自定义 TrustManager,系统能够验证您的服务器证书是否来自值得信任的颁发者。

    注意:许多网站都会介绍一个糟糕的替代解决方案,让您安装一个没用的 TrustManager。如果您这样做还不如不加密通信,因为任何人都可以在公共 WLAN 热点下,使用伪装成您的服务器的代理发送您的用户流量,通过 DNS 欺骗攻击您的用户。然后,攻击者可以记录密码和其他个人数据。此方法之所以有效是因为攻击者可以生成一个证书,且没有可以切实验证证书是否来自值得信任的来源的 TrustManager,从而使您的应用可与任何人通信。因此,不要这样做,暂时性的也不行。如果您可以始终让您的应用信任服务器证书的颁发者,那就这样做吧。

    自签署的服务器证书

    导致出现 SSLHandshakeException 的第二种情况是自签署证书,表示服务器将按照自己的 CA 进行操作。这与证书颁发机构未知的情况相似,因此,您可以使用前面部分介绍的方法。

    您可以创建自己的 TrustManager,这次直接信任服务器证书。这种方法具有前面所述的将应用与证书直接关联的所有弊端,但可以安全地操作。不过,您应谨慎为之,以确保您的自签署证书具有合理的强密钥。从 2012 年开始,可以接受一个指数为 65537 的 2048 位 RSA 签名,此签名的有效期为一年。旋转密钥时,您应查看颁发机构(例如 NIST)针对可接受的密钥提供的建议

    缺少中间证书颁发机构

    导致出现 SSLHandshakeException 的第三种情况是缺少中间 CA。大多数公共 CA 不直接签署服务器证书。相反,它们使用自己的主要 CA 证书(称为根 CA)签署中间 CA。这样一来,根 CA 可以离线存储,从而降低泄露风险。不过,Android 等操作系统通常仅直接信任根 CA,这会在服务器证书(由中间 CA 签署)与证书验证程序(了解根 CA)之间留下一个小的信任缺口。为了解决这个问题,服务器在 SSL 握手期间不会仅向客户端发送它的证书,而是发送一个证书链,包括服务器 CA 以及到达可信的根 CA 所需要的任意中间证书。

    要了解其实际应用,请看一下通过 openssl s_client 命令查看的 mail.google.com 证书链:

    $ openssl s_client -connect mail.google.com:443
    ---
    Certificate chain
     0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=mail.google.com
       i:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
     1 s:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
       i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
    ---
    

    这表明服务器会为 mail.google.com 发送一个由 Thawte SGC CA(中间 CA)发放的证书,同时为 Thawte SGC CA 发送一个由 Verisign CA(Android 信任的主要 CA)发放的证书。

    不过,对服务器进行配置以便不添加必要的中间 CA 也是屡见不鲜。例如,下面的服务器会引发 Android 浏览器错误和 Android 应用异常:

    $ openssl s_client -connect egov.uscis.gov:443
    ---
    Certificate chain
     0 s:/C=US/ST=District Of Columbia/L=Washington/O=U.S. Department of Homeland Security/OU=United States Citizenship and Immigration Services/OU=Terms of use at www.verisign.com/rpa (c)05/CN=egov.uscis.gov
       i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 International Server CA - G3
    ---
    

    有趣的是,在大多数桌面浏览器中访问此服务器不会引发完全未知的 CA 或自签署服务器证书所引发的类似错误。这是因为大多数桌面浏览器都会将可信的中间 CA 缓存一段时间。当浏览器从某个网站访问和了解中间 CA 后,下次它就不需要将中间 CA 添加在证书链中。

    有些网站会专门为提供资源的辅助网络服务器这样做。例如,他们可能让具有完整证书链的服务器提供主 HTML 页面,让不包含 CA 的服务器提供图像、CSS 或 JavaScript 等资源,以节省带宽。遗憾的是,这些服务器有时候可能会提供您正在尝试从 Android 应用调用的网络服务,这一点让人难以接受。

    可以通过两种方法解决此问题:

    • 配置服务器以便在服务器链中添加中间 CA。大多数 CA 都可以提供有关如何为所有常用网络服务器执行此操作的文档。如果您需要网站至少通过 Android 4.2 使用默认 Android 浏览器,那么这是唯一的方法。
    • 或者,像对待其他任何未知 CA 一样对待中间 CA,并创建一个 TrustManager 以直接信任它,如前面的两部分中所述。

    主机名验证的常见问题


    正如本文开头所述,验证 SSL 连接有两个关键环节。首先是验证证书是否来自值得信任的来源,这是前面部分重点讲述的内容。而此部分侧重于第二个环节:确保您正在通信的服务器提供正确的证书。如果没有提供,您通常会看到类似于下面的错误:

    java.io.IOException: Hostname 'example.com' was not verified
            at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
            at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
    

    出现此错误的一个原因是服务器配置错误。配置服务器所使用的证书不具有与您尝试连接的服务器匹配的主题或主题备用名称字段。许多不同的服务器可能使用一个证书。例如,使用 openssl s_client -connect google.com:443 | openssl x509 -text 查看 google.com 证书,您不仅可以看到一个支持*.google.com 的主题,而且还能看到适用于 *.youtube.com*.android.com 等的主题备用名称。仅当您要连接的服务器名称没有被证书列为可接受时才会发生这种错误。

    不幸的是,还有另外一个原因也会引发此错误,即虚拟托管。当多个使用 HTTP 的主机名共享服务器时,网络服务器可以通过 HTTP/1.1 请求识别客户端正在寻找哪个目标主机名。遗憾的是,使用 HTTPS 会使情况变得复杂,因为服务器必须在看到 HTTP 请求前知道返回哪个证书。为了解决此问题,较新的 SSL 版本(特别是 TLSv.1.0 及更高版本)支持服务器名称指示 (SNI),后者允许 SSL 客户端向服务器指定预期的主机名,以便可以返回正确的证书。

    幸运的是,自 Android 2.3 开始,HttpsURLConnection 就支持 SNI。如果您需要支持 Android 2.2(及更旧的版本),一种解决办法是在一个唯一端口上设置备用虚拟主机,以便了解要返回哪个服务器证书。

    比较极端的替代方法是不使用服务器默认情况下返回的验证程序,而是将 HostnameVerifier 替换为不使用您的虚拟机主机名的验证程序。

    注意:如果其他虚拟主机不在您的控制之下,则更换 HostnameVerifier 非常危险,因为中间人攻击会在您不知情的情况下将流量引向其他服务器。

    如果您仍确定要替换主机名验证,请看下面的示例,它将针对单个 URLConnection 的验证程序替换为确认主机名至少符合应用预期的验证程序:

    // Create an HostnameVerifier that hardwires the expected hostname.
    // Note that is different than the URL's hostname:
    // example.com versus example.org
    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            HostnameVerifier hv =
                HttpsURLConnection.getDefaultHostnameVerifier();
            return hv.verify("example.com", session);
        }
    };
    
    // Tell the URLConnection to use our HostnameVerifier
    URL url = new URL("https://example.org/");
    HttpsURLConnection urlConnection =
        (HttpsURLConnection)url.openConnection();
    urlConnection.setHostnameVerifier(hostnameVerifier);
    InputStream in = urlConnection.getInputStream();
    copyInputStreamToOutputStream(in, System.out);

    但请记住,如果您发现自己更换了主机名验证,特别是因虚拟托管引起的更换,那么,当其他虚拟主机不在您的控制之下时,这样做仍非常危险,您应找到一个可以避免此问题的备用托管安排。

    有关直接使用 SSLSocket 的警告


    到目前为止,所举示例都是侧重于使用 HttpsURLConnection 的 HTTPS。有时候应用需要单独使用 SSL与 HTTP。例如,某个电子邮件应用可能使用 SSL 的变体 SMTP、POP3 或 IMAP。在这些情况下,应用将需要直接使用 SSLSocket,与 HttpsURLConnection 在内部执行的操作非常相似。

    目前为止所介绍的用于处理证书验证问题的技术也适用于 SSLSocket。事实上,使用自定义 TrustManager 时,传递到 HttpsURLConnection 的是SSLSocketFactory。因此,如果您需要使用一个带有 SSLSocket 的自定义 TrustManager,请遵循相同的步骤,并使用 SSLSocketFactory 创建您的SSLSocket

    注意SSLSocket 不会执行主机名验证。由您的应用执行自己的主机名验证,最好通过使用预期的主机名调用 getDefaultHostnameVerifier() 进行验证。另外,请注意,出现错误时,HostnameVerifier.verify() 不会引发异常,而是返回一个布尔结果,您必须明确地检查该结果。

    以下示例向您展示了如何执行此操作。该示例显示在没有 SNI 支持的情况下连接到 gmail.com 端口 443 时,您将收到 mail.google.com 的证书。在此情况下,这正是期待的结果,因此,请执行检查以确保证书确实是 mail.google.com 的证书:

    // Open SSLSocket directly to gmail.com
    SocketFactory sf = SSLSocketFactory.getDefault();
    SSLSocket socket = (SSLSocket) sf.createSocket("gmail.com", 443);
    HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
    SSLSession s = socket.getSession();
    
    // Verify that the certicate hostname is for mail.google.com
    // This is due to lack of SNI support in the current SSLSocket.
    if (!hv.verify("mail.google.com", s)) {
        throw new SSLHandshakeException("Expected mail.google.com, "
                                        "found " + s.getPeerPrincipal());
    }
    
    // At this point SSLSocket performed certificate verificaiton and
    // we have performed hostname verification, so it is safe to proceed.
    
    // ... use socket ...
    socket.close();

    列入黑名单


    为了仅向正确验证的服务器和域的所有者发放证书,SSL 非常依赖 CA。少数情况下,CA 也会受骗,如 Comodo 和 DigiNotar 出现了信息泄露,从而导致某个主机名的证书被发放给服务器或域的所有者以外的其他人。

    为了降低此风险,Android 提供了将某些证书甚至整个 CA 列入黑名单的功能。尽管此名单过去已内置到操作系统中,但从 Android 4.2 开始,可以远程更新此名单,便于处理将来的泄露问题。

    证书固定


    通过名称为证书固定的技术,应用可以更好地保护自己免受以欺诈方式发放的证书的攻击。这里基本上使用上面未知 CA 案例中提供的示例,将应用的可信 CA 限制在一个很小的 CA 集范围内,应用的服务器将使用这个集合。这样可以防止因泄露系统中其他 100 多个 CA 中的某个 CA 而破坏应用安全通道。

    客户端证书


    本文重点讲述 SSL 用户与服务器进行安全通信。SSL 也支持客户端证书的概念,客户端证书允许服务器验证客户端的身份。尽管这超出了本文的讨论范围,但使用的技术与指定自定义 TrustManager 相似。请在 HttpsURLConnection 的相关文档中查看有关创建自定义 KeyManager 的讨论。

    Nogotofail:网络流量安全测试工具


    对于已知的 TLS/SSL 漏洞和错配置,可以通过 Nogotofail 轻松确认您的应用程序是否安全。它是一款自动执行的工具,功能强大并且可扩展,用于测试通过它传送网络流量的任意设备的网络安全问题。

    Nogotofail 可用于三个主要用例:

    • 查找错误和漏洞。
    • 验证修复并监测回归。
    • 了解哪些应用和设备正在生成哪些流量。

    Nogotofail 适用于 Android、iOS、Linux、Windows、Chrome 操作系统、OSX。事实上,任何用于连接互联网的设备都可以使用 Nogotofail。在 Android 和 Linux 上提供了一个易于使用的客户端来配置设置和获取通知,同时还提供了一个本身可作为路由器、VPN 服务器或代理部署的攻击引擎。

    您可以在 Nogotofail 开源项目网站上访问此工具。


    原文链接:https://developer.android.com/training/articles/security-ssl.html#CommonHostnameProbs


    展开全文
  • 最优化方法:L1和L2正则化regularization

    万次阅读 多人点赞 2016-08-18 17:06:31
    http://blog.csdn.net/pipisorry/article/details/52108040机器学习和深度学习常用的规则化方法之一:L范数正则化(规格化)。一般来说,监督学习可以看做最小化下面的目标函数):θ∗=arg⁡min&...

    http://blog.csdn.net/pipisorry/article/details/52108040

    机器学习和深度学习常用的规则化方法之一:L范数正则化(规格化)。

    一般来说,监督学习可以看做最小化下面的目标函数):

    θ=argminθ1Ni=1NL(yi,f(xi;θ))+λ Φ(θ)

    规则项Ω(w)

        loss项可参考[机器学习算法及其损失函数 ]。Note:似然函数(likelihood function)的负对数被叫做误差函数(error function)。

    这里我们先把目光转向“规则项Ω(w)”。规则化函数Ω(w)也有很多种选择,一般是模型复杂度的单调递增函数,模型越复杂,规则化值就越大。比如,规则化项可以是模型参数向量的范数。然而,不同的选择对参数w的约束不同,取得的效果也不同,但我们在论文中常见的都聚集在:零范数、一范数、二范数、迹范数、Frobenius范数和核范数等等[矩阵论:向量范数和矩阵范数]。

    这么多范数,到底它们表达啥意思?具有啥能力?什么时候才能用?什么时候需要用呢?

    某小皮



    L0范数、L1范数与稀疏

           L0范数是指向量中非0的元素的个数。如果我们用L0范数来规则化一个参数矩阵W的话,就是希望W的大部分元素都是0。换句话说,让参数W是稀疏的。看到了“稀疏”二字,大家都应该从“压缩感知”和“稀疏编码”中醒悟过来,原来用的“稀疏”就是通过它来实现的。可是看到的papers世界中,稀疏不是都通过L1范数||W||1来实现吗?这里把L0和L1放在一起的原因,因为他们有着某种不寻常的关系。

    L1范数是什么?它为什么可以实现稀疏?

           L1范数是指向量中各个元素绝对值之和,也有个美称叫“稀疏规则算子”(Lasso regularization)

    为什么L1范数会使权值稀疏?

    1 有人可能会这样回答“它是L0范数的最优凸近似”。

    2 实际上,还存在一个更美的回答:任何的规则化算子,如果他在Wi=0的地方不可微,并且可以分解为一个“求和”的形式,那么这个规则化算子就可以实现稀疏。这说是这么说,W的L1范数是绝对值,|w|在w=0处是不可微,但这还是不够直观,这里因为我们需要和L2范数进行对比分析,所以关于L1范数的直观理解,请待会看看第二节。

    3 权值稀疏的推导

    正则化的目标函数如下所示

    相比 L2正则化, L1正则化会产生更 稀疏(sparse)的解。此处稀疏性指的是 最优值中的一些参数为 0。和 L2正则化相比, L1正则化的稀疏性具有本质的不同。由L1正则化导出的稀疏性质已经被广泛地用于特征选择机制。特征选择从可用的特征子集选择出有意义的特征,化简机器学习问题。

    [深度学习]

    既然L0可以实现稀疏,为什么不用L0,而要用L1呢?

    个人理解,一是因为L0范数很难优化求解(NP难问题),二是L1范数是L0范数的最优凸近似,而且它比L0范数要容易优化求解。

    为什么要稀疏?参数稀疏有什么好处呢?

    1)特征选择(Feature Selection):

           稀疏规则化关键原因在于它能实现特征的自动选择。一般来说,xi的大部分元素(特征)都是和最终的输出yi没有关系或者不提供任何信息的,在最小化目标函数的时候考虑xi这些额外的特征,虽然可以获得更小的训练误差,但在预测新的样本时,这些没用的信息反而会被考虑,从而干扰了对正确yi的预测。稀疏规则化算子的引入就是为了完成特征自动选择的使命,它会学习去掉这些没有信息的特征,把这些特征对应的权重置为0。

    2)可解释性(Interpretability):

           另一个好处是参数变少可以使整个模型获得更好的可解释性。

    例如患某种病的概率是y,然后我们收集到的数据x是1000维的,也就是我们需要寻找这1000种因素到底是怎么影响患上这种病的概率的。假设我们这个是个回归模型:y=w1*x1+w2*x2+…+w1000*x1000+b(当然了,为了让y限定在[0,1]的范围,一般还得加个Logistic函数)。通过学习,如果最后学习到的w*就只有很少的非零元素,例如只有5个非零的wi,那么我们就有理由相信,这些对应的特征在患病分析上面提供的信息是巨大的,决策性的。也就是说,患不患这种病只和这5个因素有关,那医生就好分析多了。但如果1000个wi都非0,医生面对这1000种因素,累觉不爱。


    L2范数与过拟合

           L2范数在回归里面,它的回归叫“岭回归”(Ridge Regression),也叫它“权值衰减weight decay”。

    向目标函数添加一个正则项使权重更加接近原点。更一般地,我们可以将参数正则化为接近空间中的任意特定点,令人惊讶的是这样也仍有正则化效果,但是特定点越接近真实值结果越好。当我们不知道正确的值应该是正还是负时,零是有意义的默认值。

    模型具有以下总的目标函数


    与之对应的梯度为

    使用单步梯度下降更新权重,即执行以下更新:


    换种写法就是:

    \

    L2范数正则:权值衰减带来的影响

    只有在显著减小目标函数方向上的参数会保留得相对完好。在无助于目标函数减小的方向(对应~Hessian~矩阵较小的特征值)上改变参数不会显著增加梯度。这种不重要方向对应的分量会在训练过程中因正则化而衰减掉。

    权重衰减的效果是沿着由 H 的特征向量所定义的轴缩放w∗。

    单个步骤发生的变化:在每步执行通常的梯度更新之前先收缩权重向量(将权重向量乘以一个常数因子)。

    训练的整个过程发生的变化

     

    研究线性回归。线性回归的代价函数是平方误差之和。


    [深度学习]

    L2范数的优点

    1)学习理论的角度:

           从学习理论的角度来说,L2范数可以防止过拟合,提升模型的泛化能力。[Machine Learning - VII. Regularization规格化 (Week 3) ]

    2)优化计算的角度:

           从优化或者数值计算的角度来说,L2范数有助于处理条件数 condition number不好的情况下矩阵求逆很困难的问题(解释看下面)。[数值分析:矩阵求逆]

    为什么L2范数可以防止过拟合?模型越简单?

           L2范数是指向量各元素的平方和然后求平方根。我们让L2范数的规则项||W||2最小,可以使得W的每个元素都很小,都接近于0,但 与L1范数不同,它不会让它等于0,而是接近于0。而越小的参数说明模型越简单,越简单的模型则越不容易产生过拟合现象

    为什么越小的参数说明模型越简单?奥卡姆剃刀(Occam's razor)原理?

    限制了参数很小,实际上就限制了多项式某些分量的影响很小。

    所以为什么参数越小,说明模型越简单呢?这是因为越复杂的模型,越是会尝试对所有的样本进行拟合,甚至包括一些异常样本点,这就容易造成在较小的区间里预测值产生较大的波动,这种较大的波动也反映了在这个区间里的导数很大,而只有较大的参数值才能产生较大的导数。因此复杂的模型,其参数值会比较大

    拟合函数求导后,不同feature的求导后参数就对应着这个feature的波动大小,而在此feature上只有取值变化剧烈才会有很大的波动,所以就会产生过拟合。

    这也是为什么过拟合的时候系数会很大?如下图所示,过拟合,就是拟合函数需要顾忌每一个点,最终形成的拟合函数波动很大。在某些很小的区间里,函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值(绝对值)非常大,由于自变量值可大可小,所以只有系数足够大,才能保证导数值很大。


    [ 机器学习之:正则化] [ 知乎:机器学习中使用「正则化来防止过拟合」到底是一个什么原理?为什么正则化项就可以防止过拟合?]*

    一句话总结下:通过L2范数,我们可以实现了对模型空间的限制,从而在一定程度上避免了过拟合。

    迭代优化的算法的规则化收敛速度优化

    线性回归最优解:最小二乘法

    因为目标函数如果是二次的,对于线性回归来说,那实际上是有解析解的,求导并令导数等于零即可得到最优解为:

           然而,如果当我们的样本X的数目比每个样本的维度还要小的时候(欠定方程),矩阵X'X将会不是满秩的( rank(X'X) = rank(X)  ≤ min(m,n) = m,X'X是n*n矩阵,秩<=m<n),也就是X'X会变得不可逆,所以w*就没办法直接计算出来了,或者更确切地说,将会有无穷多个解(因为我们方程组的个数小于未知数的个数)。也就是说,我们的数据不足以确定一个解,如果我们从所有可行解里随机选一个的话,很可能并不是真正好的解,总而言之,我们过拟合了。

           但如果加上L2规则项,就变成了下面这种情况,就可以直接求逆了:

           这里面,专业点的描述是:要得到这个解,我们通常并不直接求矩阵的逆,而是通过解线性方程组的方式(例如高斯消元法)来计算。考虑没有规则项的时候,也就是λ=0的情况,如果矩阵X'X的 condition number 很大的话,解线性方程组就会在数值上相当不稳定,而这个规则项的引入则可以改善condition number

    [Machine Learning - IV. Linear Regression with Multiple Variables多变量线性规划 (Week 2) ]

           另外,如果使用迭代优化的算法,condition number 太大仍然会导致问题:它会拖慢迭代的收敛速度,而规则项从优化的角度来看,实际上是将目标函数变成λ-strongly convex(λ强凸)的了

    什么是λ强凸?

           当f满足:

           时,我们称f为λ-stronglyconvex函数,其中参数λ>0。当λ=0时退回到普通convex 函数的定义。

           在直观的说明强凸之前,我们先看看普通的凸是怎样的。假设我们让f在x的地方做一阶泰勒近似(一阶泰勒展开忘了吗?f(x)=f(a)+f'(a)(x-a)+o(||x-a||).):

           直观来讲,convex 性质是指函数曲线位于该点处的切线,也就是线性近似之上,而 strongly convex 则进一步要求位于该处的一个二次函数上方,也就是说要求函数不要太“平坦”而是可以保证有一定的“向上弯曲”的趋势。专业点说,就是convex 可以保证函数在任意一点都处于它的一阶泰勒函数之上,而strongly convex可以保证函数在任意一点都存在一个非常漂亮的二次下界quadratic lower bound。当然这是一个很强的假设,但是同时也是非常重要的假设。可能还不好理解,那我们画个图来形象的理解下。

           如果我们的函数f(w)如左图红色那个函数,我们取我们的最优解w*的地方都会位于蓝色虚线的那根二次函数之上,这样就算wt和w*离的比较近的时候,f(wt)和f(w*)的值差别还是挺大的,也就是会保证在我们的最优解w*附近的时候,还存在较大的梯度值,这样我们才可以在比较少的迭代次数内达到w*。但对于右图,红色的函数f(w)只约束在一个线性的蓝色虚线之上,假设是如右图的很不幸的情况(非常平坦),那在wt还离我们的最优点w*很远的时候,我们的近似梯度(f(wt)-f(w*))/(wt-w*)就已经非常小了,在wt处的近似梯度∂f/∂w就更小了,这样通过梯度下降wt+1=wt-α*(∂f/∂w),我们得到的结果就是w的变化非常缓慢,像蜗牛一样,非常缓慢的向我们的最优点w*爬动,那在有限的迭代时间内,它离我们的最优点还是很远。

           所以仅仅靠convex 性质并不能保证在梯度下降和有限的迭代次数的情况下得到的点w会是一个比较好的全局最小点w*的近似点(插个话,有地方说,实际上让迭代在接近最优的地方停止,也是一种规则化或者提高泛化性能的方法)。正如上面分析的那样,如果f(w)在全局最小点w*周围是非常平坦的情况的话,我们有可能会找到一个很远的点。但如果我们有“强凸”的话,就能对情况做一些控制,我们就可以得到一个更好的近似解。至于有多好,这里面有一个bound,这个 bound 的好坏也要取决于strongly convex性质中的常数α的大小。

    如果要获得strongly convex怎么做?

    最简单的就是往里面加入一项(α/2)*||w||2。这里的alpha就是上式中的lambda???

    实际上,在梯度下降中,目标函数收敛速率的上界实际上是和矩阵XTX的 condition number有关,XTX的 condition number 越小,上界就越小,也就是收敛速度会越快。

    一句话总结:L2范数不但可以防止过拟合,还可以让我们的优化求解变得稳定和快速。

    L1和L2的差别

    为什么一个让绝对值最小,一个让平方最小,会有那么大的差别呢?有两种几何上直观的解析:

    下降速度

           我们知道,L1和L2都是规则化的方式,我们将权值参数以L1或者L2的方式放到代价函数里面去。然后模型就会尝试去最小化这些权值参数。个人理解:这个最小化就像一个下坡的过程,L1和L2的差别就在于这个“坡”不同,如下图:L1就是按绝对值函数的“坡”下降的,而L2是按二次函数的“坡”下降。所以实际上在0附近,L1的下降速度比L2的下降速度要快。所以会非常快得降到0。

    模型空间的限制

           实际上,对于L1和L2规则化的代价函数来说,我们可以写成以下形式:

           也就是说,我们将模型空间限制在w的一个L1-ball 中。为了便于可视化,我们考虑两维的情况,在(w1, w2)平面上可以画出目标函数的等高线,而约束条件则成为平面上半径为C的一个 norm ball 。等高线与 norm ball 首次相交的地方就是最优解:

    彩色线就是优化过程中遇到的等高线,一圈代表一个目标函数值,圆心就是样本观测值(假设一个样本),半径就是误差值,受限条件就是黑色边界(就是正则化那部分),二者相交处,才是最优参数。

           可以看到,L1-ball 与L2-ball 的不同就在于L1在和每个坐标轴相交的地方都有“角”出现,而目标函数的测地线除非位置摆得非常好,大部分时候都会在角的地方相交。注意到在角的位置就会产生稀疏性,例如图中的相交点就有w1=0,而更高维的时候(想象一下三维的L1-ball 是什么样的?)除了角点以外,还有很多边的轮廓也是既有很大的概率成为第一次相交的地方,又会产生稀疏性。

           相比之下,L2-ball 就没有这样的性质,因为没有角,所以第一次相交的地方出现在具有稀疏性的位置的概率就变得非常小了。这就从直观上来解释了为什么L1-regularization 能产生稀疏性,而L2-regularization 不行的原因了。

    Note: 不少人会用“模型复杂度”替代上面的“模型空间”。但“模型复杂度”往往容易给人一个误解,认为是一个模型本身长得复杂。例如5次多项式就要比2次多项式复杂,这是错的。因此我更愿意用“模型空间”,强调“复杂度”是候选模型的“数量”,而不是模型本事的“长相”。

    2范最优值不在坐标轴上,不稀疏

    1范可能多个值,没有解,两线之间的所有梯度集合,图像都在线上面。使用次梯度subgradient解决?

    [PRML前三章]

    [大数据分析中的优化算法选讲 刘歆 (AMSS, CAS)]

    一句话总结就是:L1会趋向于产生少量的特征,而其他的特征都是0,而L2会选择更多的特征,这些特征都会接近于0。Lasso在特征选择时候非常有用,而Ridge就只是一种规则化而已。



    不同角度看待规则化项和过拟合

    regularize这个词更多的意思是“使系统化”,“使体系化”,也就是说不要走极端。

           1 监督机器学习

    监督机器学习问题无非就是“minimize your error while regularizing your parameters”,也就是在规则化参数的同时最小化误差。最小化误差是为了让我们的模型拟合我们的训练数据,而规则化参数是防止我们的模型过分拟合我们的训练数据。

        因为参数太多,会导致我们的模型复杂度上升,容易过拟合,也就是我们的训练误差会很小。但训练误差小并不是我们的最终目标,我们的目标是希望模型的测试误差小,也就是能准确的预测新的样本。所以,我们需要保证模型“简单”的基础上最小化训练误差,这样得到的参数才具有好的泛化性能(也就是测试误差也小),而模型“简单”就是通过规则函数来实现的。另外,规则项的使用还可以约束我们的模型的特性,这样就可以将人对这个模型的先验知识融入到模型的学习当中,强行地让学习到的模型具有人想要的特性,例如稀疏、低秩、平滑等等。有时候人的先验是非常重要的。前人的经验会让你少走很多弯路,这就是为什么我们平时学习最好找个大牛带带的原因。对机器学习也是一样,如果被我们人稍微点拨一下,它肯定能更快的学习相应的任务。目前这个媒介只能由规则项来担当了。

        2奥卡姆剃刀(Occam's razor)原理

    规则化符合奥卡姆剃刀(Occam's razor)原理。它的思想很平易近人:在所有可能选择的模型中,我们应该选择能够很好地解释已知数据并且十分简单的模型。

        3 Bayes先验解释

    贝叶斯估计的角度来看,规则化项对应于模型参数w的先验概率

    从贝叶斯学派角度来看,是加上了一个(参数w的)先验,然后计算后验,形式与1中的完全相同。因为数据中所包含信息的不充足是无法通过各类优化算法弥补的,所以需要引入一些先验信息或者说假设。这些先验信息就体现在正则化项的范数上,L0 L1/2 L1 是稀疏的, L2是光滑的。

    最小二乘回归问题:加2范数正则等价于加了高斯分布的先验,加1范数正则相当于加拉普拉斯分布先验。L1假设的是模型的参数取值满足拉普拉斯分布,L2假设的模型参数是满足高斯分布。简而言之就是:L1是假设参数服从双指数分布,利于保证权值向量的稀疏性;L2是假设参数服从高斯分布,利于防止过拟合。

    Orangeprince 的回答非常学院派,也非常系统。 过拟合表现在训练数据上的误差非常小,而在测试数据上误差反而增大。其原因一般是模型过于复杂,过分得去拟合数据的噪声和outliers. 正则化则是对模型参数添加先验,使得模型复杂度较小,对于噪声以及outliers的输入扰动相对较小。 以正则化项和损失函数都是l_2 norm 为例,下面贴一张上课用的slide.

    我们相当于是给模型参数w 添加了一个协方差为1/alpha 的零均值高斯分布先验。 对于alpha =0,也就是不添加正则化约束,则相当于参数的高斯先验分布有着无穷大的协方差,那么这个先验约束则会非常弱,模型为了拟合所有的训练数据,w可以变得任意大不稳定。alpha越大,表明先验的高斯协方差越小,模型约稳定, 相对的variance也越小。
    也正如其他答题者所说, 加入正则化是 在bias和variance之间做一个tradeoff。
    [ 知乎:机器学习中使用「正则化来防止过拟合」到底是一个什么原理?为什么正则化项就可以防止过拟合?]

    [机器学习中的范数规则化之(一)L0、L1与L2范数 ]

    2范数正则示例

    error func = -lg(p(D|w))

    加先验p(w) = e^(-x^2)*常数

     error func = -lg(p(D|w)p(w)) = -lg(p(D|w))  -lg(p(w)) = -lg(p(D|w))  + λ(x^2) 等价于-lg(p(D|w))  + λ||x||_2

    Lasso(1范数正则)举例
    w^\star = argmin_w \| y - X w \|_2^2 + \lambda \|w \|_1.
    其实就是如下概率模型的最大后验。
    y = X w + \epsilon,
    \epsilon \sim N(0, \sigma^2),
    w_i \sim DoubleExponential(\lambda)
    如果不对w加拉普拉斯分布的先验,最大后验得到的是
    w^\star = argmin_w \| y - X w \|_2^2

        4 结构风险最小化

    民间还有个说法就是,规则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项(regularizer)或惩罚项(penalty term)。统计学习理论的核心为泛化方程,也就是 \mathcal{R}_{ept} \le \mathcal{R}_{emp} + \mathcal{G}_m[\mathcal{F}],其中左边表示期望风险,就是你在测试集上的错误率,右边第一项表示经验风险,就是你在训练集上的错误率,右边第二项称之为泛化复杂度,它取决于训练样本数m和模型\mathcal{F}。我们知道一般情况下,\mathcal{R}_{emp} \le \mathcal{R}_{ept} 训练集上的损失一定小于测试集上的损失。所以,结合起来有: \mathcal{R}_{emp}  \le \mathcal{R}_{ept}  \le \mathcal{R}_{emp} + \mathcal{G}_m[\mathcal{F}],如果此时泛化复杂度为0,那么测试集上的效果就和训练集上的效果一致,这时,学习机就具有了绝对的泛化能力。然而实际上,我们很难找到一个模型,其在训练集上损失小并且同时泛化复杂度也小。

    言归正传,我们对于线性模型或者说更为广泛意义下的线性模型(比如前馈神经网络可以看做一种层叠的线性模型),有如下泛化方程:

    \mathcal{R}_{ept} \le \mathcal{R}_{emp} + (RL)^{K-1}ln^{\frac{3}{2}(K-1)}(m)\sqrt{\frac{R^2N^2}{m}} + \sqrt{\frac{ln(\delta^{-1})}{m}}
    其中: R=||\vec w||_l, L为神经网络激活函数的李普希兹系数, N为样本的最大范数, m 为训练集样本数, K为神经网络层数,其中,一般的感知器可看做 1 层神经网络 (K=1)。依据我们上述对统计泛化的描述,我们知道右边的第二项应该越小越好,越小的话,学习机泛化能力越强,测试集上的效果就越有保证!所以我们必须最小化 R,也就是最小化 ||\vec w||_l,这就是从统计泛化角度解释了权系数范数的作用。
    最小化权系数范数 \min ||\vec w||_l 的统计学习本质是提高泛化能力。

        5 数学角度

    从数学角度来看,原来的不适定问题,加入这一项约束可以得到一个较好的解。正则化理论是表明智能推理方法存在的一个信号。
    [ 机器学习中引入L2范数的意义是什么? - 知乎]

        6 偏置方差分解

    经典的是bias-variance decomposition,这种解释更加倾向于直观理解;

    传统的机器学习中的bias-variance trade-off的解释

    考虑二值分类问题。

    X\in R^k是特征集合,Y\in \left\{ 0 ,1 \right\} PX\times Y上的概率分布,记H是所有的X\rightarrow Y的可测函数的集合。

    R^\ast =arginf R(h)h\in H是所有分类器中分类性能最好的一个。

    R(h)=\int_{X\times Y}1_{ h(x\ne y) } dxdy称分类器h的泛化误差

    这里做一点解释,P是真实的数据生成机制,可测函数只是一个技术性条件,非数学系的可以无视,泛化误差代表分类器的预测能力,泛化误差越小越好。

    我们希望找到一个分类函数使得泛化误差最小。

    L=\left\{ f:X\rightarrow Y\right\} 中所有的线性函数。记l^\ast 是所有线性分类函数里泛化误差最小的。

    对于任意线性分类函数f它的泛化误差有如下分解

    R(f)-R(R^\ast )=R(f)-R(l^\ast )+R(l^\ast )-R(R^\ast )

    第一部分称模型的variance,反映的是算法性能的优劣,在线性模型里就是反应最小二乘估计量或者极大似然估计量的好坏。

    第二部分称模型的bias,反映的是模型本身的优劣,即线性模型本身作为分类函数的好坏。

    这样就很清楚了,若扩大我们搜索的分类函数的范围,bias这一部分会减小,但一般说来我们搜索到l^\ast 可能性会下降,这样就增大了variance。所以在搜索范围上我们需要做一种权衡,这种权衡就是bias-variance trade-off。正则化使我们减少搜索范围,这样variance的部分会减小,bias的部分又不会增大太快。这就是为什么正则化有可能会改善我们泛化误差。这是一个非常一般的框架。

    [ 偏置方差分解Bias-variance Decomposition]
    [ 知乎:机器学习中使用「正则化来防止过拟合」到底是一个什么原理?为什么正则化项就可以防止过拟合?]

        7 Stein‘s Phenomenon

    这是高维统计学里最重要的发现之一。当维数大于等于3时

    x_{i} \sim N(\theta ,\sigma ^2I_{d} ) d\geq 3则用均值估计\theta 居然不是最好的估计量。

    E(\bar{x} -\theta )^2\geq E(\theta _{ JS} -\theta )^2 对于\theta 取任何值都成立。

    换句话说用Stein估计量去估计均值会比极大似然估计量要好。这个估计量看起来很复杂,大家先不用管他。Stein估计量有一种Shrinkage(数据收缩)的现象。这种Shrinkage导致的结果就是估计量的方差减小。虽然这个估计量是有偏的,但是由于方差减小可以补偿估计量的偏差。所以导致这个估计量比极大似然估计量要好。

    正则化导致估计量的Shrinkage(如估计的参数更新时乘以了一个小于1的数),Shrinkage导致variance减小,如果variance的减小可以补偿bias,则正则化可以改善泛化误差。
    皮皮blog



    作为约束的范数惩罚

    我们可以构造一个广义 Lagrange 函数来最小化受约束的函数,即在原始目标函数加上一系列惩罚项。每个惩罚是一个系数之间的乘积,称为Karush– Kuhn– Tucker (Karush– Kuhn– Tucker) 乘子,以及一个表示约束是否满足的函数。 如果我们想约束 Ω(θ) 小于某个常数 k,我们可以构建广义 Lagrange 函数

    解决这个问题需要同时改变 θ 和 α。

    为了洞察约束的影响,我们可以固定 α∗,把这个问题看成只跟 θ 有关的函数:

    使用惩罚强加约束

    可以把参数范数惩罚看作对权重强加的约束。如果 Ω 是 L2 范数,那么权重就是被约束在一个 L2 球中。如果 Ω 是 L1 范数, 那么权重就是被约束在一个 L1 范数限制的区域中。通常我们不知道权重衰减系数 α∗ 约束的区域大小,因为 α∗ 的值不直接告诉我们 k 的值。

    不使用惩罚强加约束的原因是惩罚可能导致非凸优化过程而陷入局部极小 (对应于小的 θ)。

    显式约束和重投影

    修改下降算法(如随机梯度下降算法),使其先计算 J(θ) 的下降步,然后将 θ 投影到满足 Ω(θ) < k 的最近点。如果我们知道什么样的 k 是合适的,而不想花时间寻找对应于此 k 处的 α 值。

    重投影的显式约束还对优化过程增加了一定的稳定性。

    Hinton et al. (2012b) 尤其推荐由Srebro and Shraibman (2005) 引入的策略:约束神经网络层的权重矩阵每列的范数,而不是限制整个权重矩阵的Frobenius范数。

    [深度学习]

    机器学习规则化的拓展

    由于大部分场景下,我们都是对于单目标值进行训练,即求权值向量的L2值(权值向量的模的大小),然而在多目标值训练时,我们要求解权值矩阵的L2值,怎么求?意义是什么?

    [关于线性模型你可能还不知道的二三事(三、特征值与奇异值的魔力)]

    其它相关资料

    [关于线性模型你可能还不知道的二三事(一、样本)

    关于线性模型你可能还不知道的二三事(二、也谈民主)

    关于线性模型你可能还不知道的二三事(三、特征值与奇异值的魔力)]

    from: http://blog.csdn.net/pipisorry/article/details/52108040

    ref: [wikipedia Regularization (mathematics)]


    展开全文
  • Java 使用静态工厂方法替代构造方法

    千次阅读 2020-04-13 09:35:06
    1. 考虑使用静态工厂方法替代构造方法 一个类允许客户端获取其实例的传统方式是提供一个公共构造方法。 其实还有另一种技术应该成为每个程序员工具箱的一部分。 一个类可以提供一个公共静态工厂方法,它只是一个返回...

    1. 考虑使用静态工厂方法替代构造方法

    一个类允许客户端获取其实例的传统方式是提供一个公共构造方法。 其实还有另一种技术应该成为每个程序员工具箱的一部分。 一个类可以提供一个公共静态工厂方法,它只是一个返回类实例的静态方法。 下面是一个 Boolean 简单的例子(boolean 基本类型的包装类)。 此方法将 boolean 基本类型转换为 Boolean 对象引用:

    public static Boolean valueOf(boolean b) {
        return b ? Boolean.TRUE : Boolean.FALSE;
    }
    

    注意,静态工厂方法与设计模式中的工厂方法模式不同[Gamma95]。本条目中描述的静态工厂方法在设计模式中没有直接的等价。

    类可以为其客户端提供静态工厂方法,而不是公共构造方法。提供静态工厂方法而不是公共构造方法有优点也有缺点。

    静态工厂方法的一个优点是,与构造方法不同,它们是有名字的。 如果构造方法的参数本身并不描述被返回的对象,则具有精心选择名称的静态工厂更易于使用,并且生成的客户端代码更易于阅读。 例如,返回一个可能为素数的 BigInteger 的构造方法 BigInteger(int,int,Random) 可以更好地表示为名为 BigInteger.probablePrime 的静态工厂方法。 (这个方法是在 Java 1.4 中添加的。)

    一个类只能有一个给定签名的构造方法。 程序员知道通过提供两个构造方法来解决这个限制,这两个构造方法的参数列表只有它们的参数类型的顺序不同。 这是一个非常糟糕的主意。 这样的 API 用户将永远不会记得哪个构造方法是哪个,最终会错误地调用。 阅读使用这些构造方法的代码的人只有在参考类文档的情况下才知道代码的作用。

    因为他们有名字,所以静态工厂方法不会受到上面讨论中的限制。在类中似乎需要具有相同签名的多个构造方法的情况下,用静态工厂方法替换构造方法,并仔细选择名称来突出它们的差异。

    静态工厂方法的第二个优点是,与构造方法不同,它们不需要每次调用时都创建一个新对象。 这允许不可变类 (详见第 17 条)使用预先构建的实例,或者在构造时缓存实例,并反复分配它们以避免创建不必要的重复对象。Boolean.valueof(boolean) 方法说明了这种方法:它从不创建对象。这种技术类似于 Flyweight 模式[Gamma95]。如果经常请求等价对象,那么它可以极大地提高性能,特别是在创建它们的代价非常昂贵的情况下。

    静态工厂方法重复调用返回相同实例这个特点可以让类在任何时候都能对实例保持严格的控制。这样做的类被称为实例控制类( instance-controlled)。有很多理由足以让我们去我们编写实例控制类。实例控制可以保证一个类是单例 的(详见第 3 条) 或不可实例化的 (详见第 4 条)。同时,它允许一个不可变的值类 (详见第 17 条) 保证不存在两个相等但不相同的实例,也就是说当且仅当 a == b 时才有 a.equals(b)。这是Flyweight模式的基础[Gamma95]。Enum 类型 (详见第 34 条)可以做到这点。

    静态工厂方法的第三个优点是,与构造方法不同,它们可以返回其返回类型的任何子类型的对象。 这为你在选择返回对象的类时提供了很大的灵活性。

    这种灵活性的一个应用是 API 可以返回对象而不需要公开它的类。 以这种方式隐藏实现类会使 API 非常紧凑。 这种技术适用于基于接口的框架(详见第 20 条),其中接口为静态工厂方法提供自然返回类型。

    在 Java 8 之前,接口不能有静态方法。根据约定,一个名为 Type 的接口的静态工厂方法被放入一个不可实例化的伙伴类(companion class)(详见第 4 条)Types 类中。例如,Java 集合框架有 45 个接口的实用工具实现,提供不可修改的集合、同步集合等等。几乎所有这些实现都是通过静态工厂方法在一个不可实例化的类 (java .util. collections) 中返回的。返回对象的类都隐藏的。

    Collections 框架 API 的规模要比它之前返回的 45 个单独的公共类要小得多,每个类在集合框架中都有一个便利的实现。不仅是 API 的大部分减少了,还包括概念上的权重:程序员要想使用 API必须掌握的概念的数量和难度。程序员知道返回的对象恰好有其接口指定的 API,因此不需要为实现类读阅读额外的类文档。此外,使用这种静态工厂方法需要客户端通过接口而不是实现类来引用返回的对象,这通常是良好的实践(详见第 64 条)。

    从 Java 8 开始,接口不能包含静态方法的限制被取消了,所以通常没有理由为接口提供一个不可实例化的伴随类。 很多公开的静态成员应该放在这个接口本身。 但是,请注意,将这些静态方法的大部分实现代码放在单独的包私有类中仍然是必要的。 这是因为 Java 8 要求所有接口的静态成员都是公共的。 Java 9 允许私有静态方法,但静态字段和静态成员类仍然需要公开。

    静态工厂的第四个优点是返回对象的类可以根据输入参数的不同而不同。 声明的返回类型的任何子类都是允许的。 返回对象的类也可以随每次发布而不同。

    EnumSet 类(详见第 36 条)没有公共构造方法,只有静态工厂。 在 OpenJDK 实现中,它们根据底层枚举类型的大小返回两个子类中的一个的实例:大多数枚举类型具有 64 个或更少的元素,静态工厂将返回一个 RegularEnumSet 实例, 底层是long 类型;如果枚举类型具有六十五个或更多元素,则工厂将返回一个 JumboEnumSet 实例,底层是long 类型的数组。

    这两个实现类的存在对于客户端而言是不可见的。 如果 RegularEnumSet 对于小的枚举类型不再具有性能优势,则可以在未来版本中将其淘汰,且不会产生任何不良影响。 同样,如果可以证明添加 EnumSet 的更多的实现可以提高性能,那么在未来的版本可能就会这样做。 客户既不知道也不关心他们从工厂返回的对象的类别; 他们只需要知道它是 EnumSet 的子类。

    静态工厂的第五个优点是,在编写包含该方法的类时,返回的对象的类不需要存在。 这种灵活的静态工厂方法构成了服务提供者框架的基础,比如 Java 数据库连接 AP(JDBC)。服务提供者框架是提供者实现服务的系统,并且系统使得实现对客户端可用,从而将客户端从实现中分离出来。

    服务提供者框架中有三个基本组:服务接口,它表示实现;提供者注册 API,提供者用来注册实现;以及服务访问 API,客户端使用该 API 获取服务的实例。服务访问 API 允许客户指定选择实现的标准。在缺少这样的标准的情况下,API 返回一个默认实现的实例,或者允许客户通过所有可用的实现进行遍历。服务访问 API 是灵活的静态工厂,它构成了服务提供者框架的基础。

    服务提供者框架的一个可选的第四个组件是一个服务提供者接口,它描述了一个生成服务接口实例的工厂对象。在没有服务提供者接口的情况下,必须对实现进行反射实例化(详见第 65 条)。在 JDBC 的情况下,Connection 扮演服务接口的一部分,DriverManager.registerDriver 提供程序注册 API、DriverManager.getConnection 是服务访问 API,Driver 是服务提供者接口。

    服务提供者框架模式有许多变种。 例如,服务访问 API 可以向客户端返回比提供者提供的更丰富的服务接口。 这是桥接模式[Gamma95]。 依赖注入框架(详见第 5 条)可以被看作是强大的服务提供者。 从 Java 6 开始,平台包含一个通用的服务提供者框架 java.util.ServiceLoader,所以你不需要,一般也不应该自己编写(详见第 59 条)。 JDBC 不使用 ServiceLoader,因为前者早于后者。

    只提供静态工厂方法的主要限制是,没有公共或受保护构造方法的类不能被子类化。 例如,要想将 Collections 框架中任何遍历的实现类进行子类化,是不可能的。但是这样也会因祸得福,因为它鼓励程序员使用组合(composition)而不是继承(详见第 18 条),并且是不可变类型锁需要的(详见第 17 条)。

    静态工厂方法的第二个缺点是,程序员很难找到它们。 它们不像构造方法那样在 API 文档中明确的标注出来。因此,对于提供了静态方法而不是构造器的类来说,想要查明如何实例化一个类是十分困难的。Javadoc 工具可能有一天会注意到静态工厂方法。与此同时,通过关注类或者接口的文档中静态方法,并且遵守标准的命名习惯,也可以弥补这一劣势。下面是一些静态工厂方法的常用名称。以下清单这是列出了其中的一小部分:

    • from —— 类型转换方法,它接受单个参数并返回此类型的相应实例,例如:Date d = Date.from(instant);
    • of —— 聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起,例如:Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
    • valueOf —— from 和 to 更为详细的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
    • instance 或 getinstance —— 返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options);
    • create 或 newInstance —— 与 instance 或 getInstance 类似,除此之外该方法保证每次调用返回一个新的实例,例如:Object newArray = Array.newInstance(classObject, arrayLen);
    • getType —— 与 getInstance 类似,但是在工厂方法处于不同的类中的时候使用。getType 中的 Type 是工厂方法返回的对象类型,例如:FileStore fs = Files.getFileStore(path);
    • newType —— 与 newInstance 类似,但是在工厂方法处于不同的类中的时候使用。newType中的 Type 是工厂方法返回的对象类型,例如:BufferedReader br = Files.newBufferedReader(path);
    • type —— getType 和 newType 简洁的替代方式,例如:List<Complaint> litany = Collections.list(legacyLitany);

    总之,静态工厂方法和公共构造方法都有它们的用途,并且了解它们的相对优点是值得的。通常,静态工厂更可取,因此避免在没有考虑静态工厂的情况下直接选择使用公共构造方法。

    展开全文
  • 常用数据科学方法总结梳理笔记

    千次阅读 2019-05-10 16:27:06
    常用数据科学方法 【未经允许,不得转载】 ...
  • 提出利用基于公共近邻的裁剪方法对相似矩阵进行裁剪,通过计算数据结点的往返距离得出各个结点的离群值评分,弥补了传统基于稳态分布随机游走的离群点检测方法的缺陷。实验结果表明:该方法在事务图数据离群点检测...
  • 结构化方法、面向对象方法的区别

    千次阅读 2016-06-22 09:32:16
    结构化方法、面向对象方法的区别 1.结构化方法遵循的基本原则 结构化方法的基本思想就是将待解决的问题看作一个系统从而用系统科学的思想方法来分析和解决问题结构化方法遵循以下基本原则 (1)抽象...
  • 数学表达式识别一般分为字符识别和结构分析两部分,而且大多数现有的方法是先进行字符识别然后将字符识别的结果作为结构分析的输入再进行结构分析,在这种分步识别的过程中,字符识别的错误会被继承到结构分析阶段,...
  • 白盒测试的六种方法比较分析 一、摘要 白盒测试是测试人员常用的一种测试方法,越来越受到测试工程师的重视。白盒测试并不是简单的按照代码测试用例而走,需要根据不同的测试需求,结合不同的测试对象,使用适合的...
  • Python打包exe文件方法汇总【4种】

    万次阅读 多人点赞 2018-10-21 22:15:11
    title: Python打包exe文件方法 copyright: true top: 0 date: 2018-08-11 21:08:21 tags: 打包 categories: Python进阶笔记 permalink: password: keywords: description: 使用py2exe,pyinstaller,cx_Freeze,...
  • 团队激励方法

    千次阅读 2010-12-06 15:34:02
    政策激励能影响其他激励方法的运用,而其他激励方法却无法弥补政策激励的失误。 1、考核激励 哀兵必胜 背水一战 大棒政策 压力产生动力 这是我们考核月不搞竞赛的理由 2、淘汰机制(清退冗员) 3、...
  • TensorFlow中EMA的概念和正确使用方法

    千次阅读 2019-03-06 17:05:53
    弥补不足:初始数据积累不足的情况 深度学习训练中的作用 实现 典型步骤 一个EMA影子变量的例子 进一步接近真实情景,让w1变动 例2:global_step的trainable设置 最后,怎么用影子变量来测试? 模拟训练与...
  • 软件界面设计思想方法

    万次阅读 2015-03-04 10:16:28
    上述教育缺陷绝非短期内能够解决得了,我写这个问题不是发发牢骚,而是提醒软件企业关注这个问题:中国现阶段软件界面设计的人才数量和行业水平远远落后于技术开发,企业要抓住一切机会弥补这个缺陷,否则做不出优秀...
  • 数据分析中缺失值的处理方法

    万次阅读 2016-03-27 22:16:27
    对于主观数据,人将影响数据的真实性,存在缺失值的样本的其他属性的真实值不能保证,那么依赖于这些属性值的插补也是不可靠的,所以对于主观数据一般不推荐插补的方法。插补主要是针对客观数据,它的可靠性有保证。
  • 集成学习方法及思想总结

    万次阅读 多人点赞 2018-02-20 23:46:18
    集成学习(Ensemble Learning)有时也被笼统地称作提升(Boosting)方法,广泛用于分类和回归任务。它最初的思想很简单:使用一些(不同的)方法改变原始训练样本的分布,从而构建多个不同的分类器,并将这些分类器...
  • 协作频谱感知技术利用空间的宏集合弥补了单用户在认知无线电宽带频谱感知过程中可能出现检测错误的问题,但在复杂的信号重构过程中增加了计算量。针对这种情况,论文提出了一种改进的基于DCS的分布式多用户协作频谱...
  • 文本特征提取方法研究

    万次阅读 2017-09-27 10:25:22
    文本挖掘就是从大量的文档中发现隐含知识和模式的一种方法和工具,它从数据挖掘发展而来,但与传统的数据挖掘又有许多不同。文本挖掘的对象是海量、异构、分布的文档(web);文档内容是人类所使用的自然语言,缺乏计算机...
  • 所谓清理是指对数据集进行丢弃,填充,替换和重复数据删除等操作,以达到消除异常,纠正错误弥补丢失的目的。 缺失值 是数据记录中行记录丢失,也称为数据记录丢失。数据列的缺失值,即由于各种原因导致数据缺失的...
  • 多因素分析模型解决方法Finally, all data were cleansed and ready to analyze. Andy started overenthusiastically to visualize the data to get a first impression of the data. He had many dimensions and ...
  • C++中输入字符串的几种方法

    万次阅读 多人点赞 2018-08-26 17:19:39
    C++中常见的几种输入字符串的方法如下: cin、cin.get()、cin.getline()、getline()、gets()、getchar() 1. cin&gt;&gt; 用法一:最常用、最基本的用法,输入一个数字: #include &lt;iostream&...
  • 快速清除钮可取代触控进行全选并删除的一连串复杂动作,而密码显示钮可协助用户确认输入内容,弥补触控打字慢、错误率高的困扰。但是基于Web系统安全的考虑,需要禁用该功能
  • JavaScript常用数组操作方法

    千次阅读 多人点赞 2018-11-13 09:57:18
    concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,仅会返回被连接数组的一个副本。 2、join() join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的,默认使用’,'...
  • 引言贝叶斯方法是天生用来做推断的方法,然而它常隐藏在课本的...《Probabilistic Programming and Bayesian Methods for Hackers》一书试图弥补以上的遗憾。 有关概率编程和贝叶斯方法的实验,我将以该在线书籍作为学
  • 工厂方法模式+策略模式。

    千次阅读 2018-10-09 15:29:35
    该逻辑没有考虑账户余额不足的情况,也没有考虑异常情况,比如并发情况,一张卡有两笔消费同时发生时,是不是就发生错误了?一张卡同时有两笔消费会出现这种情况吗?会的,网络阻塞的情况,MQ多通道发送,在网络繁忙...
  • 医学图像分割方法

    千次阅读 2015-12-08 19:32:50
    源于:医学图像分割方法综述 定义:图像中具有特殊含义的不同区域分开,这些区域互相不交叉,每个区域满足特定区域的一致性(连通),这些区域的总和构成整幅图像。 分类: 基于区域的分割方法 ...
  • 车辆轨迹预测方法的优缺点总结: 马尔科夫模型: 优点: 1、能够计算出具有维修能力和多重降级状态的系统的概率。 缺点: 预测准确率比较低。 一阶马尔科夫模型只考虑当前轨迹点对未来轨迹点的影响,不能充分...
  • RNA 二级结构预测方法

    千次阅读 2019-12-13 16:30:42
    1 比较序列分析方法 比较序列分析方法,其工作原理其实比较简单,它以 RNA 序列中互补碱基间的共变联配(英文名称为 covariant-alignment)活动为基础;以已知的 RNA 序列的数据为依据标准,以查找被测算 RNA 序列中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 49,749
精华内容 19,899
关键字:

弥补错误的方法