遲到的故障公告:錯誤的緩存數據引發新版博客後台發布后的故障

10月18日晚上 22:00 ,我們對處於灰度發布階段的新版博客後台(Angular 8.2.7 + .NET Core 3.0)進行了一次發布操作,在發布後由於清除緩存 web api 的一個 bug 造成在發布后通過新版博客後台修改的博文無法訪問(404錯誤);在發現問題后,我們回退至發布之前的版本,但是由於 appsettings.Production.json 配置文件的不一致造成回退後的版本出現 500 錯誤;在修復配置文件問題后,在 docker swarm 集群上部署時又遭遇奇怪的容器健康檢查失敗的問題,多次部署后才成功,直至 23:00 左右才恢復正常。

非常抱歉,這次故障給使用新版博客後台的園友帶來了很大的麻煩,請您諒解。

在這次發布中包含一個比較大但卻沒有引起我們足夠重視的變更,原先在博客後台代碼中進行的清除 memcached 緩存(修改博文時清除對應的緩存)的操作改為調用 web api ,在實現清除緩存 web api 時由於沒有足夠重視在沒有寫集成測試覆蓋的情況下就發布了,從而沒有及時發現其中埋藏的一個 bug ,這個 bug 是由下面的 C# 代碼引起的:

await _cacheService.RemoveAsync(CacheKeyManager.GetBlogPost(blogId.Value, postId.Value));
var post = await blogPostService.GetCachedPostById(blogId.Value, postId.Value);            
//...
if (post.DisplayOnHomePage)
{
    await ClearHomePostsList(blogId.Value);
}
//..

上面的代碼中在清除所修改博文的緩存后,又獲取該博文進一步清除與該博文相關聯的緩存,調用 GetCachedPostById 方法時又創建了緩存,但由於實現時漏寫了 DTO 映射配置代碼,造成緩存的 BlogPostDto 字段值不完整從而 PostId 的值為 0 。在我們的緩存機制中,對於不存在的博文,會 new 一個空的 PostId 為 0 的 BlogPostDto 放入緩存,所以 PostId 為 0 的緩存數據都當作不存在的博文直接響應 404 ,故障因此而引發。

針對這次故障,在修掉 bug 代碼的同時我們將採取以下改進措施:

1)對從緩存中獲取的數據進行校驗並自動修復,這樣即使出現錯誤的緩存數據,也可以減少對業務的影響。

else if (blogPost.PostId != postId)
{
    blogPost = await GetBlogPostById(blogId, postId);
    await _cacheService.UpdateAsync(cacheKey, 3600, blogPost);
}

2)加強 Code Review

3)提高集成測試的覆蓋率

4)解決生產環境配置管理的問題

5)改用 k8s 部署生產環境

最近的新版博客後台發布故障暴露了我們在團隊開發能力上的落後,我們正在努力改進與提升,希望大家能夠諒解我們暫時的 low 。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

佛羅倫斯颶風橫掃美國,可再生能源設備受創如何?

摘錄自2018年10月2日科技新報報導

美國2018年9月遭佛羅倫斯颶風侵襲,災情慘重,許多人擔心可再生能源基礎建設是否能夠抵擋這樣的天災侵襲?美國各大電力公司正在全面盤點受損情況,目前看來,可再生能源在許多防備天災的安全技術下,大體上通過考驗。

事實上,過去幾次美國重要風災已經證明太陽能設備抵擋風災的能力,不論是德州的哈維風災或是夏威夷風災,若房屋本身結構沒有問題,太陽能板也都能挺過颶風的肆虐。

因此,極端氣候的颶風接連來襲,並未讓美國住宅太陽能安裝打退堂鼓,反倒是颶風後集中式大電網因為輸配電設備與線路損壞,使得美國人更重視分散式能源,颶風連續來襲使得加裝能源儲存系統的用戶比例大增。在加州,住宅太陽能安裝商彼得生狄恩(PetersenDean)近 6 個月的客戶選擇安裝能源儲存的比例高達一半。佛羅倫斯颶風過後,南北卡羅萊納州安裝商也接到許多用戶希望安裝能源儲存系統的要求。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

PowerMock學習(三)之Mock局部變量

編寫powermock用例步驟:

  • 類上面先寫這兩個註解@RunWith(PowerMockRunner.class)、@PrepareForTest(StudentService.class)
  • 先模擬一個假對象即studentdao方法中的局部變量
  • 用無參的方式new對象
  • 再模擬這個對象被調用時,是否有返回,有返回值給出默認值,沒有用doNothing()
  • 驗證有返回值使用assertEquals即可,無返回值使用Mockito.verify驗證

實際案例

接着上一篇文章中的代碼,修改下service中的代碼,這次我不通過構造器注入Dao,在方法中new一個StudentDao,創建一個名為StudentNewService的類。

具體示例代碼如下:

package com.rongrong.powermock.service;

import com.rongrong.powermock.dao.StudentDao;

/**
 * @author rongrong
 * @version 1.0
 * @date 2019/11/17 21:13
 */
public class StudentNewService {


    /**
     * 獲取學生個數
     * @return返回學生總數
     */
    public int getTotal() {
        StudentDao studentDao = new StudentDao();
        return studentDao.getTotal();
    }

    /**
     * 創建學生
     * @param student
     */
    public void createStudent(Student student) {
        StudentDao studentDao = new StudentDao();
        studentDao.createStudent(student);
    }
}

針對上面修改部分代碼,進行單元測試,以下代碼有採用傳統方式測試和採用powermock方式進行測試,具體代碼如下:

package com.rongrong.powermock.service;

import com.rongrong.powermock.dao.StudentDao;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
 * @author rongrong
 * @version 1.0
 * @date 2019/11/20 21:42
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest(StudentNewService.class)
public class TestNewStudentService {

    /**
     * 傳統方式測試
     */
    @Test
    public void testGetStudentTotal() {
        StudentNewService studentNewService = new StudentNewService();
        int total = studentNewService.getTotal();
        assertEquals(total, 10);
    }

    /**
     * @desc測試有返回值類型 採用powermock進行測試獲取學生個數
     */
    @Test
    public void testGetStudentTotalWithPowerMock() {
        //先模擬一個假對象即studentdao方法中的局部變量
        StudentDao studentDao = PowerMockito.mock(StudentDao.class);
        try {
            //這句話我按照英文理解就是,我用無參的方式new了一個StudentDao對象
            PowerMockito.whenNew(StudentDao.class).withNoArguments().thenReturn(studentDao);
            //再模擬這個對象被調用時,我們默認假定返回10個證明調用成功
            PowerMockito.when(studentDao.getTotal()).thenReturn(10);
            //這裏就是service就不用再說了
            StudentNewService studentNewService = new StudentNewService();
            int total = studentNewService.getTotal();
            assertEquals(total, 10);
        } catch (Exception e) {
            fail("測試失敗了!!!");
            e.printStackTrace();
        }

    }

    /**
     * @desc測試的無返回值類型 採用powermock進行測試創建學生
     */
    @Test
    public void testCreateStudentWithPowerMock() {
        //先模擬一個假對象即studentdao方法中的局部變量
        StudentDao studentDao = PowerMockito.mock(StudentDao.class);
        try {
            //這句話我按照英文理解就是,我用無參的方式new了一個StudentDao對象
            PowerMockito.whenNew(StudentDao.class).withNoArguments().thenReturn(studentDao);
            Student student = new Student();
            //這句話註釋與否都能運行通過,也就是我只能判斷他是否被調用
            //PowerMockito.doNothing().when(studentDao).createStudent(student);
            //這裏就是service就不用再說了
            StudentNewService studentNewService = new StudentNewService();
            studentNewService.createStudent(student);
            Mockito.verify(studentDao).createStudent(student);
        } catch (Exception e) {
            fail("測試失敗了!!!");
            e.printStackTrace();
        }

    }

}

運行上面的測試用例,會發現第一個失敗,後面兩個都運行成功,即有返回值和無返回值類型的測試(void類型)。

 

 

注意:對於無返回值類型的測試,只能驗證其是否被調用,這裏還請注意。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

併發編程-硬件加持的CAS操作夠快么?

Talk is cheap

CAS(Compare And Swap),即比較並交換。是解決多線程并行情況下使用鎖造成性能損耗的一種機制,CAS操作包含三個操作數——內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論位置V的值是否等於A, 都將返回V原有的值。

CAS的含義是”我認為V的值應該是A,如果是,那我將V的值更新為B,否則不修改並告訴V的值實際是多少“

Show you my code

在單線程環境中分別使用無鎖,加鎖以及cas進行十組5億次累加運算,然後打印出平均耗時。

 /**
 * cas對比加鎖測試
 *
 * @author Jann Lee
 * @date 2019-11-21 0:12
 **/
public class CasTest {

    @Test
    public void test() {
        long times = 500_000_000;
        // 記錄耗時
        List<Long> elapsedTime4NoLock = new ArrayList<>(10);
        List<Long> elapsedTime4Synchronized = new ArrayList<>(10);
        List<Long> elapsedTime4ReentrantLock = new ArrayList<>(10);
        List<Long> elapsedTime4Cas = new ArrayList<>(10);

        // 進行10組試驗
        for (int j = 0; j < 10; j++) {
            // 無鎖
            long startTime = System.currentTimeMillis();
            for (long i = 0; i < times; i++) {
            }
            long endTime = System.currentTimeMillis();
            elapsedTime4NoLock.add(endTime - startTime);

            // synchronized 關鍵字(隱式鎖)
            startTime = endTime;
            for (long i = 0; i < times; ) {
                i = addWithSynchronized(i);
            }
            endTime = System.currentTimeMillis();
            elapsedTime4Synchronized.add(endTime - startTime);

            // ReentrantLock 顯式鎖
            startTime = endTime;
            ReentrantLock lock = new ReentrantLock();
            for (long i = 0; i < times; ) {
                i = addWithReentrantLock(i, lock);
            }
            endTime = System.currentTimeMillis();
            elapsedTime4ReentrantLock.add(endTime - startTime);

            // cas(AtomicLong底層是用cas實現)
            startTime = endTime;
            AtomicLong atomicLong = new AtomicLong();
            while (atomicLong.getAndIncrement() < times) {
            }
            endTime = System.currentTimeMillis();
            elapsedTime4Cas.add(endTime - startTime);
        }

        System.out.println("無鎖計算耗時: " + average(elapsedTime4NoLock) + "ms");
        System.out.println("synchronized計算耗時: " + average(elapsedTime4Synchronized) + "ms");
        System.out.println("ReentrantLock計算耗時: " + average(elapsedTime4ReentrantLock) + "ms");
        System.out.println("cas計算耗時: " + average(elapsedTime4Cas) + "ms");

    }

    /**
     * synchronized加鎖
     */
    private synchronized long addWithSynchronized(long i) {
        i = i + 1;
        return i;
    }

    /**
     * ReentrantLock加鎖
     */
    private long addWithReentrantLock(long i, Lock lock) {
        lock.lock();
        i = i + 1;
        lock.unlock();
        return i;
    }

    /**
     * 計算平均耗時
     */
    private double average(Collection<Long> collection) {
        return collection.stream().mapToLong(i -> i).average().orElse(0);
    }
}

從案例中我們可能看出在單線程環境場景下cas的性能要高於鎖相關的操作。當然,在競爭比較激烈的情況下性能可能會有所下降,因為要不斷的重試和回退或者放棄操作,這也是CAS的一個缺點所在,因為這些重試,回退等操作通常用開發者來實現。

CAS的實現並非是簡單的代碼層面控制的,而是需要硬件的支持,因此在不同的體系架構之間執行的性能差異很大。但是一個很管用的經驗法則是:在大多數處理器上,在無競爭的鎖獲取和釋放的”快速代碼路徑“上的開銷,大約是CAS開銷的兩倍。

為何CAS如此優秀

硬件加持,現代大多數處理器都從硬件層面通過一些列指令實現CompareAndSwap(比較並交換)同步原語,進而使操作系統和JVM可以直接使用這些指令實現鎖和併發的數據結構。我們可以簡單認為,CAS是將比較和交換合成是一個原子操作

JVM對CAS的支持, 由於Java程序運行在JVM上,所以應對不同的硬件體系架構的處理則需要JVM來實現。在不支持CAS操作的硬件上,jvm將使用自旋鎖來實現。

CAS的ABA問題

cas操作讓我們減少了鎖帶來的性能損耗,同時也給我們帶來了新的麻煩-ABA問題。

在線程A讀取到x的值與執行CAS操作期間,線程B對x執行了兩次修改,x的值從100變成200,然後再從200變回100;而後在線程A執行CAS操作過程中並未發現x發生過變化,成功修改了x的值。由於x的值100 ->200->100,所以稱之為ABA的原因。

魔高一尺道高一丈,解決ABA的問題目前最常用的辦法就是給數據加上“版本號”,每次修改數據時同時改變版本號即可。

Q&A

在競爭比較激烈的情況下,CAS要進行回退,重試等操作才能得到正確的結果,那麼CAS一定比加鎖性能要高嗎?

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

哈雷五年內推出電動機車

經典重型機車品牌哈雷終於將正式邁向電動車行列?媒體報導,哈雷高級副總裁Sean Cumming在受訪時透漏,哈雷將在五年內推出一款貨真價實的哈雷電動機車。

《癮科技》報導哈雷曾在2014年以Project LiveWire為名推出一款電動機車原型車,行駛續航力只有96公里左右;續航力差強人意的原因是,為了兼顧車體的美觀而無法安裝體積過於龐大的電池。

Sean Cumming在受訪時表示,公司會在五年內推出電動機車,但並未透漏更多細節。由於哈雷機車車體較大,或許就能安裝電容量更大的電池;未來電池的能量密度也會更高,續航力問題也許能獲得解決。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

2016 國際IoT 車用光電技術趨勢論壇-5車聯網時代

2016台北國際光電週將於6月15日至17日假台北世貿南港展覽館展出,本屆在光電產業大力支持下,結合了國內知名學會、公會,和產業聯盟,齊心推動國際光電大展、平面顯示器展、LED照明展、精密光學展、太陽光電展,以及奈米科技等6展,並開闢車用光電、生醫、3D列印、前瞻學術、雷射與真空技術等6個展區,加上同期舉行之植物工廠展,光電科技不僅跨足農業、醫療、傳統產業等,而且還搭上物聯網與車用光電的跨領域列車,可看出台北國際光電週與產業正進行之蛻變。   2016 國際IoT 車用光電技術趨勢論壇於2016年6月15日-17日舉辦,結合物聯網與車用光電市場,探討未來車用市場發展。工研院資通所車在資通訊與控制系統組組長 蔣村杰表示強化行車安全為車聯網當務之急。V2X 通訊技術大約包含六個層面: 汽車對汽車 V2V、汽車對路側設備 V2R、汽車對基礎設施 V2I、汽車對行人V2P、汽車對機車 V2M、汽車對公車 V2T。其中,V2V 車間通訊技術已發展日趨成熟。工研院為全球少數公司具有完整V2X 解決方案。  

  同時提到全球車聯網發展趨勢上,在政策面上,歐美相繼立法推動車聯網應用與服務,也宣布2022年9月1日起AEB 自動緊急剎車輔助系統將列為新車標準配備之中。   並且,未來智慧車輛系統三大趨勢包含: 車聯網;智慧感測,能結合影像辨識、環境偵測、等應用並發展客製化車用積體電路 (ASIC);先進駕駛輔助系統。  

凱銳光電 蔡家祥處長提出,物聯網應用於家庭之中,提升舒適程度;而應用於車輛之中,則是提升安全程度。智慧車載功能之中則包含安全駕駛、行車資訊彙整、車主運營效益、車上乘客資訊提供與娛樂。以車載資訊暨娛樂系統的挑戰來看,寬頻化、資安、自動駕駛等問題需要克服。當然未來,無人駕駛車時代隨之來臨!   國際富豪汽車股份有限公司 (VOLVO) 地區經理 吳廷颺提出 VOLVO 最重視駕駛安全性。在物聯網時代之下,車輛感測前方路況,提供警示或是緊急自動剎車;行人進入危險區域,提供警示或是緊急自動剎車;無人駕駛等等。時至今日,VOLVO 已正式售出200萬輛配備City Safety 自動煞車功能。   若以自動駕駛來說,VOLVO 從2009年起開始研發執行Drive Me。未來真正的自動駕駛除可判別周遭環境,甚至是駕駛者未能注意到的狀況,採用雷達、相機提供警告或是真正在危險時,可以直接執行指令,2017年將有可能提供100萬輛自動駕駛車於市。   (本文內容由授權使用)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

福斯汽車:電動車續航力目標300公里

在爆出排氣檢測造假、並付出高額罰金與賠償金後,福斯(VW)被強制投資20億美金於研發零碳排汽車。這個危機促使福斯在轉型的路上更為積極,並喊出「所有電動車續航力都須達300公里」的目標。

福斯的全球行銷主管Jurgen Stackman在Goodwood FOS會後受訪時表示,集團認為中等價位的家庭用車是電動車打入主流車款的關鍵,而非高階車款。各國駕駛所能接受的中等價位依經濟狀況有別,如美國消費者最能接受美金3.5萬元的車款,歐洲則是美金2.8萬元,但巴西可能只有美金1.2萬元的車款稱得上中階車。

由於各國對「中階車款」的定義和接受度相距甚遠,福斯表示,考慮研發一款專門提供給電動車的模組化平台MEB,可供旗下各廠牌發展電動車系列使用,包括:VW、Audi、Skoda、Porsche、Lamborghini、Bugatti等。

目前,福斯已上市的電動車僅有e-Golf 一款,售價自2.89萬美元起跳。藉由MEB平台,福斯目標在2025~2030年生產30款、300萬輛電動車,相當於提前了公司原先計畫的電動車商業化時程。Stackman透露,福斯未來的電動車都將搭載至少60kWh的蓄電池,續航力須達290~450km,以減輕消費者對於長途行駛的不安感。

(照片來源:福斯汽車)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

三星投資比亞迪,傳砸美金5億取得4%股權

中國電動車市場蓬勃,海外投資也躍躍欲試。市場傳出南韓三星電子的中國分公司將參與中國最大的電動車廠商比亞迪(BYD)增資,投資人民幣30億元(約美金5億元)取得比亞迪的4%股權。

《韓國經濟日報》、《日經》等媒體指出,三星電子於7月15日發布消息,指出將投資人民幣30億元取得比亞迪的4%股權。但比亞迪於同日下午否認三星的投資金額。

中國最大電動車廠,比亞迪大發利市

比亞迪以電動車、油電混和車等新能源車產品,於2015年搶下61,772輛的銷售佳績,銷售額達人民幣776億元。在中國,比亞迪亦有30%左右的市占率,且在中央政府持續推動電動車的動能下,比亞迪2016年提出銷量倍增的目標,對零組件的需求也跟著增加。

比亞迪成立於1995年,除電動車事業外,亦有一般汽車、IT產業、新能源產業等相關事業群。目前,比亞迪所使用的車用電池主要皆為自主生產,使比亞迪成為中國目前少數可整合新能源發電、儲能系統、電動車事業的公司之一。

三星積極佈局電動車市場

三星集團對電動車市場的布局行動頻頻。2015年12月,三星電子成立「電裝事業組」,致力於生產次世代汽車零組件,例如:車載半導體、電池、顯示器等。無人駕駛車與聯網汽車也是此事業組的發展方向。

三星表示,本次對比亞迪的投資主要是提高資本業務、零組件供應方面的合作,以搶攻中國正要起飛的電動車市場。但三星也強調不會涉入比亞迪的經營,純屬財務投資。

除了注資比亞迪外,三星旗下的三星SDI也與中國逆變器廠商陽光電源(Sungrow)於合肥投資儲能系統廠,年產能2,000MWh,第一期已於日前投產。此外,三星SDI也曾申請中國工信部的電動車車用電池補助名單,但鎩羽而歸。若要搶攻中國市場,與中國本地企業合作是必須採取的行動。

三星並非第一個入股比亞迪的外資,美國股神巴菲特所擁有的投資公司Berkshire Hathaway曾在2008年取得比亞迪近10%股權,成為一大股東。除此之外,美商蘋果公司在5月12日宣布砸下10億美元投資中國叫車服務公司「滴滴打車」,為三星帶來了中國市場的競爭壓力。

(照片:比亞迪新能源車「元」。來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

網絡權重初始化方法總結(下):Lecun、Xavier與He Kaiming

目錄

博客: | |

權重初始化最佳實踐

書接上回,全0、常數、過大、過小的權重初始化都是不好的,那我們需要什麼樣的初始化?

  • 因為對權重\(w\)的大小和正負缺乏先驗,所以應初始化在0附近,但不能為全0或常數,所以要有一定的隨機性,即數學期望\(E(w)=0\)
  • 因為梯度消失和梯度爆炸,權重不易過大或過小,所以要對權重的方差\(Var(w)\)有所控制

  • 深度神經網絡的多層結構中,每個激活層的輸出對後面的層而言都是輸入,所以我們希望不同激活層輸出的方差相同,即\(Var(a^{[l]})=Var(a^{[l-1]})\),這也就意味不同激活層輸入的方差相同,即\(Var(z^{[l]})=Var(z^{[l-1]})\)
  • 如果忽略激活函數,前向傳播和反向傳播可以看成是權重矩陣(轉置)的連續相乘。數值太大,前向時可能陷入飽和區,反向時可能梯度爆炸,數值太小,反向時可能梯度消失。所以初始化時,權重的數值範圍(方差)應考慮到前向和後向兩個過程

權重的隨機初始化過程可以看成是從某個概率分佈隨機採樣的過程,常用的分佈有高斯分佈、均勻分佈等,對權重期望和方差的控制可轉化為概率分佈的參數控制,權重初始化問題也就變成了概率分佈的參數設置問題

在上回中,我們知道反向傳播過程同時受到權重矩陣和激活函數的影響,那麼,在激活函數不同以及每層超參數配置不同(輸入輸出數量)的情況下,權重初始化該做怎樣的適配?這裏,將各家的研究成果匯總如下,

其中,扇入\(fan\_in\)和扇出\(fan\_out\)分別為當前全連接層的輸入和輸出數量,更準確地說,1個輸出神經元與\(fan\_in\)個輸入神經元有連接(the number of connections feeding into the node),1個輸入神經元與\(fan\_out\)個輸出神經元有連接(the number of connections flowing out of the node),如下圖所示(來自),

對於卷積層而言,其權重為\(n\)\(c\times h \times w\)大小的卷積核,則一個輸出神經元與\(c\times h \times w\)個輸入神經元有連接,即\(fan\_in = c\times h \times w\),一個輸入神經元與\(n\times h \times w\)個輸出神經元有連接,即\(fan\_out=n\times h \times w\)

期望與方差的相關性質

接下來,首先回顧一下期望與方差計算的相關性質。

對於隨機變量\(X\),其方差可通過下式計算,
\[ Var(X) = E(X^2) – (E(X))^2 \]
若兩個隨機變量\(X\)\(Y\),它們相互獨立,則其協方差為0,
\[ Cov(X, Y) = 0 \]
進一步可得\(E(XY)=E(X)E(Y)\),推導如下,
\[ \begin{align} Cov(X, Y) &= E((X-E(X))(Y-E(Y))) \\ &= E(XY)-E(X)E(Y) =0 \end{align} \]
兩個獨立隨機變量和的方差,
\[ \begin{aligned} \operatorname{Var}(X+Y) &=E\left((X+Y)^{2}\right)-(E(X+Y))^{2} \\ &=E\left(X^{2}+Y^{2}+2 X Y\right)-(E(X)+E(Y))^{2} \\ &=\left(E\left(X^{2}\right)+E\left(Y^{2}\right)+2 E(X Y)\right)-\left((E(X))^{2}+(E(Y))^{2}+2 E(X) E(Y)\right) \\ &=\left(E\left(X^{2}\right)+E\left(Y^{2}\right)+2 E(X) E(Y)\right)-\left((E(X))^{2}+(E(Y))^{2}+2 E(X) E(Y)\right) \\ &=E\left(X^{2}\right)-(E(X))^{2}+E\left(Y^{2}\right)-(E(Y))^{2} \\ &=\operatorname{Var}(X)+\operatorname{Var}(Y) \end{aligned} \]
兩個獨立隨機變量積的方差,
\[ \begin{aligned} \operatorname{Var}(X Y) &=E\left((X Y)^{2}\right)-(E(X Y))^{2} \\ &=E\left(X^{2}\right) E\left(Y^{2}\right)-(E(X) E(Y))^{2} \\ &=\left(\operatorname{Var}(X)+(E(X))^{2}\right)\left(\operatorname{Var}(Y)+(E(Y))^{2}\right)-(E(X))^{2}(E(Y))^{2} \\ &=\operatorname{Var}(X) \operatorname{Var}(Y)+(E(X))^{2} \operatorname{Var}(Y)+\operatorname{Var}(X)(E(Y))^{2} \end{aligned} \]

全連接層方差分析

對線性組合層+非線性激活層,計算如下所示,其中\(z_i^{[l-1]}\)\(l-1\)層第\(i\)個激活函數的輸入,\(a_i^{[l-1]}\)為其輸出,\(w_{ij}^{[l]}\)為第\(l\)層第\(i\)個輸出神經元與第\(j\)個輸入神經元連接的權重,\(b^{[l]}\)為偏置,計算方式如下
\[ \begin{align}a_i^{[l-1]} &= f(z_i^{[l-1]}) \\z_i^{[l]} &= \sum_{j=1}^{fan\_in} w_{ij}^{[l]} \ a_j^{[l-1]}+b^{[l]} \\a_i^{[l]} &= f(z_i^{[l]})\end{align} \]
在初始化階段,將每個權重以及每個輸入視為隨機變量,可做如下假設和推斷,

  • 網絡輸入的每個元素\(x_1,x_2,\dots\)獨立同分佈
  • 每層的權重隨機初始化,同層的權重\(w_{i1}, w_{i2}, \dots\)獨立同分佈,且期望\(E(w)=0\)
  • 每層的權重\(w\)和輸入\(a\)隨機初始化且相互獨立,所以兩者之積構成的隨機變量\(w_{i1}a_1, w_{i2}a_2, \dots\)亦相互獨立,且同分佈;
  • 根據上面的計算公式,同層的\(z_1, z_2, \dots\)獨立同分佈,同層的\(a_1, a_2, \dots\)也為獨立同分佈

需要注意的是,上面獨立同分佈的假設僅在初始化階段成立,當網絡開始訓練,根據反向傳播公式,權重更新后不再相互獨立。

在初始化階段,輸入\(a\)與輸出\(z\)方差間的關係如下,令\(b=0\)
\[ \begin{align} Var(z) &=Var(\sum_{j=1}^{fan\_in} w_{ij} \ a_j) \\ &= fan\_in \times (Var(wa)) \\ &= fan\_in \times (Var(w) \ Var(a) + E(w)^2 Var(a) + Var(w) E(a)^2) \\ &= fan\_in \times (Var(w) \ Var(a) + Var(w) E(a)^2) \end{align} \]

tanh下的初始化方法

若激活函數為線性恆等映射,即\(f(x)=x\),則\(a = z\),自然\(E(a)=E(z)\)\(Var(a) = Var(z)\)

因為網絡輸入的期望\(E(x)=0\),每層權重的期望\(E(w) = 0\),在前面相互獨立的假設下,根據公式\(E(XY)=E(X)E(Y)\),可知\(E(a)=E(z)=\sum E(wa)=\sum E(w)E(a)=0\)。由此可得,
\[ Var(a^{[l]}) = Var(z^{[l]}) = fan\_in \times Var(w) \times Var(a^{[l-1]}) \]
更進一步地,令\(n^{[l]}\)為第\(l\)層的輸出數量(\(fan\_out\)),則第\(l\)層的輸入數量($fan_in \()即前一層的輸出數量為\)n^{[l-1]}\(。第\)L$層輸出的方差為
\[ \begin{align} Var(a^{L}) = Var(z^{[L]}) &= n^{[L-1]} Var(w^{[L]}) Var(a^{[L-1]}) \\ &=\left[\prod_{l=1}^{L} n^{[l-1]} Var(w^{[l]})\right] {Var}(x) \end{align} \]
反向傳播時,需要將上式中的\(n^{[l-1]}\)替換為\(n^{[l]}\)(即\(fan\_in\)替換為\(fan\_out\)),同時將\(x\)替換為損失函數對網絡輸出的偏導。

所以,經過\(t\)層,前向傳播和反向傳播的方差,將分別放大或縮小
\[ \prod^{t} n^{[l-1]} Var(w^{[l]}) \\ \prod^{t} n^{[l]} Var(w^{[l]}) \]
為了避免梯度消失和梯度爆炸,最好保持這個係數為1。

需要注意的是,上面的結論是在激活函數為恆等映射的條件下得出的,而tanh激活函數在0附近可近似為恆等映射,即$tanh(x) \approx x $。

Lecun 1998

Lecun 1998年的paper ,在輸入Standardization以及採用tanh激活函數的情況下,令\(n^{[l-1]}Var(w^{[l]})=1\),即在初始化階段讓前向傳播過程每層方差保持不變,權重從如下高斯分佈採樣,其中第\(l\)層的\(fan\_in = n^{[l-1]}\)
\[ W \sim N(0, \frac{1}{fan\_in}) \]

Xavier 2010

在paper 中,Xavier和Bengio同時考慮了前向過程和反向過程,使用\(fan\_in\)\(fan\_out\)的平均數對方差進行歸一化,權重從如下高斯分佈中採樣,
\[ W \sim N(0, \frac{2}{fan\_in + fan\_out}) \]
同時文章中還提及了從均勻分佈中初始化的方法,因為均勻分佈的方差與分佈範圍的關係為
\[ Var(U(-n, n)) = \frac{n^2}{3} \]
若令\(Var(U(-n, n)) = \frac{2}{fan\_in + fan\_out}\),則有
\[ n = \frac{\sqrt{6}}{\sqrt{fan\_in + fan\_out}} \]
即權重也可從如下均勻分佈中採樣,
\[ W \sim U(-\frac{\sqrt{6}}{\sqrt{fan\_in + fan\_out}}, \frac{\sqrt{6}}{\sqrt{fan\_in + fan\_out}}) \]
在使用不同激活函數的情況下,是否使用Xavier初始化方法對test error的影響如下所示,圖例中帶\(N\)的表示使用Xavier初始化方法,Softsign一種為類tanh但是改善了飽和區的激活函數,圖中可以明顯看到tanh 和tanh N在test error上的差異。

論文還有更多訓練過程中的權重和梯度對比圖示,這裏不再貼出,具體可以參見論文。

ReLU/PReLU下的初始化方法

搬運一下上面的公式,
\[ Var(z)= fan\_in \times (Var(w) \ Var(a) + Var(w) E(a)^2) \]
因為激活函數tanh在0附近可近似為恆等映射,所以在初始化階段可以認為\(E(a) = 0\),但是對於ReLU激活函數,其輸出均大於等於0,不存在負數,所以\(E(a) = 0\)的假設不再成立。

但是,我們可以進一步推導得到,
\[ \begin{align} Var(z) &= fan\_in \times (Var(w) \ Var(a) + Var(w) E(a)^2) \\ &= fan\_in \times (Var(w) (E(a^2) – E(a)^2)+Var(w)E(a)^2) \\ &= fan\_in \times Var(w) \times E(a^2) \end{align} \]

He 2015 for ReLU

對於某個具體的層\(l\)則有,
\[ Var(z^{[l]}) = fan\_in \times Var(w^{[l]}) \times E((a^{[l-1]})^2) \]
如果假定\(w{[l-1]}\)來自某個關於原點對稱的分佈,因為\(E(w^{[l-1]}) = 0\),且\(b^{[l-1]} = 0\),則可以認為\(z^{[l-1]}\)分佈的期望為0,且關於原點0對稱。

對於一個關於原點0對稱的分佈,經過ReLU后,僅保留大於0的部分,則有
\[ \begin{align}Var(x) &= \int_{-\infty}^{+\infty}(x-0)^2 p(x) dx \\&= 2 \int_{0}^{+\infty}x^2 p(x) dx \\&= 2 E(\max(0, x)^2)\end{align} \]
所以,上式可進一步得出,
\[ \begin {align}Var(z^{[l]}) &= fan\_in \times Var(w^{[l]}) \times E((a^{[l-1]})^2) \\&= \frac{1}{2} \times fan\_in \times Var(w^{[l]}) \times Var(z^{[l-1]}) \end{align} \]
類似地,需要放縮係數為1,即
\[ \frac{1}{2} \times fan\_in \times Var(w^{[l]}) = 1 \\ Var(w) = \frac{2}{fan\_in} \]
即從前向傳播考慮,每層的權重初始化為
\[ W \sim N(0, \frac{2}{fan\_in}) \]
同理,從後向傳播考慮,每層的權重初始化為
\[ W \sim N(0, \frac{2}{fan\_out}) \]
文中提到,單獨使用上面兩个中的哪一個都可以,因為當網絡結構確定之後,兩者對方差的放縮係數之比為常數,即每層扇入扇出之比的連乘,解釋如下,

使用Xavier和He初始化,在激活函數為ReLU的情況下,test error下降對比如下,22層的網絡,He的初始化下降更快,30層的網絡,Xavier不下降,但是He正常下降。

He 2015 for PReLU

對於PReLU激活函數,負向部分為\(f(x) = ax\),如下右所示,

對於PReLU,求取\(E((a^{[l-1]})^2)\)可對正向和負向部分分別積分,不難得出,
\[ \frac{1}{2} (1 + a^2) \times fan\_in \times Var(w^{[l]}) = 1 \\Var(w) = \frac{2}{(1 + a^2) fan\_in} \\W \sim N(0, \frac{2}{(1 + a^2) fan\_in}) \\W \sim N(0, \frac{2}{(1 + a^2) fan\_out}) \]

caffe中的實現

儘管He在paper中說單獨使用\(fan\_in\)\(fan\_out\)哪個都可以,但是,在Caffe的實現中,還是提供了兩者平均值的方式,如下所示,當然默認是使用\(fan\_in\)

小結

至此,對深度神經網絡權重初始化方法的介紹已告一段落。雖然因為BN層的提出,權重初始化可能已不再那麼緊要。但是,對經典權重初始化方法經過一番剖析后,相信對神經網絡運行機制的理解也會更加深刻。

以上。

參考

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

比亞迪新能源車上海補貼將腰斬 銷量已現大滑坡

兩個月前,比亞迪在上海失去了兩萬元(人民幣,下同)地方補貼,兩個月後,又將失去5000元補貼,仍然在手的只剩5000元, 昨(25)天,比亞迪確認,已經接到上海有關部門的通知,比亞迪新能源汽車在滬補貼將減半,並將成為受補貼「按量退坡」影響的首家新能源汽車企業。  
 
銷量沖4萬,福兮禍兮   在上海收穫了4萬的銷量,對於比亞迪來說,是福,也是禍。   上海市新能源汽車推進辦透露,2014年以來,比亞迪品牌新能源乘用車在上海累計銷量距離4萬輛僅一步之遙。按照相關政策,如累計銷量達到4萬輛以上,上海市地方補貼將降至每輛5000元,較目前減半。部分消費者因擔心比亞迪新能源汽車實際購車價提高而轉向享受更高補貼的其他品牌新能源汽車。  
公司是否貼補看市場反應   從6月份開始,比亞迪為了挽救主力車型「秦」在上海市場的銷量,採取廠家和經銷商聯合補貼1.4萬元,以補齊無法拿到政府1.4萬元額外補貼的差價。不過,比亞迪6月初的補貼政策7月底即將到期,到期後,比亞迪是否會出臺力度更大的補貼,挽回價格上的不利?昨天,比亞迪公關部相關人士透露,目前還在商討,具體的市場政策要看市場反應。  
今年上海銷量已現大滑坡   上海補貼退坡已導致比亞迪在上海市場一蹶不振。今年以來,比亞迪銷量呈現直線下滑,市場份額也被上汽取代。去年上海的插電混動市場上,比亞迪幾乎是一家獨大,在上海的銷量超越大本營深圳。而今年4月以後,隨著上海插電式混動汽車准入技術門檻的提高,比亞迪的表現疲軟。   上海的疲態拖累比亞迪「秦」全國銷量大跌,今年上半年“秦”僅賣出9404輛,不足萬輛的成績相較其去年同期的1.6萬輛,同比大跌42.9%。另一款新能源車型「秦」EV也只賣出1725輛。 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整