Aracılığıyla paylaş


Uygulamalı Laboratuvar görüntü tanıma

Bu öğretici için en son ana sürümün veya yakında yayınlanacak olan 1.7 CNTK gerektiğini unutmayın. Bu öğreticinin başlangıçta tasarlandığı KDD CNTK Hands-On Öğreticisi yönergelerinde ara ikili indirme bulunabilir.

Hands-On Lab: Convolutional Networks, Batch Normalization ve Residual Nets ile görüntü tanıma

Bu uygulamalı laboratuvarda, CNTK ile kıvrım tabanlı görüntü tanımanın nasıl uygulandığı gösterilmektedir. Ortak bir kıvrımlı görüntü tanıma mimarisiyle başlayacağız, Batch Normalleştirme'yi ekleyecek ve sonra bunu bir Artık Ağa (ResNet-20) genişleteceğiz.

Uygulayacağınız teknikler şunlardır:

  • önceden tanımlanmış bir işlem eklemek için CNTK ağ tanımını değiştirme (bırakma)
  • Ağdaki yinelenen parçaları yeniden kullanılabilir bir modüle ayıklamak için kullanıcı tanımlı işlevler oluşturma
  • özel ağ yapıları uygulama (ResNet bağlantı atlama)
  • özyinelemeli döngüleri kullanarak aynı anda çok sayıda katman oluşturma
  • paralel eğitim
  • kıvrımlı ağlar
  • toplu normalleştirme

Önkoşullar

CNTK zaten yüklediğinizi ve CNTK komutunu çalıştırabileceğinizi varsayıyoruz. Bu öğretici KDD 2016'da gerçekleştirildi ve yeni bir derleme gerektiriyor, kurulum yönergeleri için lütfen buraya bakın . Bu sayfadan ikili yükleme paketi indirme yönergelerini izleyebilirsiniz. Görüntüyle ilgili görevler için bunu CUDA uyumlu GPU'ya sahip bir makinede yapmanız gerekir.

Ardından, lütfen bir ZIP arşivi indirin (yaklaşık 12 MB): Bu bağlantıya tıklayın ve ardından İndir düğmesine tıklayın. Arşiv, bu öğreticinin dosyalarını içerir. Lütfen arşive gidin ve çalışma dizininizi olarak ImageHandsOnayarlayın. Aşağıdaki dosyalarla çalışacaksınız:

Son olarak CIFAR-10 veri kümesini indirip dönüştürmemiz gerekir. Dönüştürme adımı yaklaşık 10 dakika sürer. Lütfen çalışma dizininde de bulabileceğiniz aşağıdaki iki Python betikini yürütün:

wget -rc http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
tar xvf www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
python CifarConverter.py cifar-10-batches-py

Bu, görüntüleri PNG dosyalarına, eğitim için 50000'e ve test için 10000'e dönüştürür ve sırasıyla aşağıdaki iki dizine yerleştirilir: cifar-10-batches-py/data/train ve cifar-10-batches-py/data/test.

Model Yapısı

Bu öğreticiye basit bir kıvrımlı modelle başlayacağız. 3 kat 5x5 konvolution + doğrusal olmayanlık + 3x3 maksimum havuzlama ile 2 kat boyut azaltma katmanlarından oluşur, daha sonra yoğun bir gizli katman ve 10 yönlü softmax sınıflandırıcıya girişi oluşturmak için yoğun bir dönüşüm izler.

Veya CNTK ağ açıklaması olarak. Lütfen hızlı bir bakış atın ve yukarıdaki açıklamayla eşleştirin:

featNorm = features - Constant (128)
l1 = ConvolutionalLayer {32, (5:5), pad = true, activation = ReLU,
                         init = "gaussian", initValueScale = 0.0043} (featNorm)
p1 = MaxPoolingLayer {(3:3), stride = (2:2)} (l1)
l2 = ConvolutionalLayer {32, (5:5), pad = true, activation = ReLU,
                         init = "gaussian", initValueScale = 1.414} (p1)
p2 = MaxPoolingLayer {(3:3), stride = (2:2)} (l2)
l3 = ConvolutionalLayer {64, (5:5), pad = true, activation = ReLU,
                         init = "gaussian", initValueScale = 1.414} (p2)
p3 = MaxPoolingLayer {(3:3), stride = (2:2)} (l3)
d1 = DenseLayer {64, activation = ReLU, init = "gaussian", initValueScale = 12} (p3)
z  = LinearLayer {10, init = "gaussian", initValueScale = 1.5} (d1)

Bu işleçler hakkında daha fazla bilgiyi burada bulabilirsiniz: ConvolutionalLayer{}, MaxPoolingLayer{}, DenseLayer{}, LinearLayer{}.

CNTK Yapılandırması

Yapılandırma Dosyası

CNTK'de bir modeli eğitmek ve test etmek için, CNTK çalıştırmak istediğiniz işlemleri (commanddeğişken) belirten bir yapılandırma dosyası ve her komut için bir parametre bölümü sağlamamız gerekir.

Eğitim komutu için CNTK anlatılması gerekir:

  • verileri okuma (reader bölüm)
  • model işlevi ve hesaplama grafında (BrainScriptNetworkBuilder bölüm) giriş ve çıkışları
  • öğrenci için hiper parametreler (SGD bölüm)

Değerlendirme komutu için CNTK şunları bilmesi gerekir:

  • test verilerini okuma (reader bölüm)
  • değerlendirilecek ölçümler (evalNodeNames parametre)

Aşağıda, başlayacağımız yapılandırma dosyası yer alır. Gördüğünüz gibi, CNTK yapılandırma dosyası, bir kayıt hiyerarşisinde düzenlenmiş parametre tanımlarından oluşan bir metin dosyasıdır. CNTK'in söz dizimini kullanarak temel parametre değiştirme işlemini nasıl desteklediğini $parameterName$ de görebilirsiniz. Gerçek dosya yukarıda belirtilenden yalnızca birkaç tane daha fazla parametre içeriyor, ancak lütfen dosyayı tarayın ve az önce bahsedilen yapılandırma öğelerini bulun:

# CNTK Configuration File for training a simple CIFAR-10 convnet.
# During the hands-on tutorial, this will be fleshed out into a ResNet-20 model.

command = TrainConvNet:Eval

makeMode = false ; traceLevel = 0 ; deviceId = "auto"

rootDir = "." ; dataDir  = "$rootDir$" ; modelDir = "$rootDir$/Models"

modelPath = "$modelDir$/cifar10.cmf"

# Training action for a convolutional network
TrainConvNet = {
    action = "train"

    BrainScriptNetworkBuilder = {
        imageShape = 32:32:3
        labelDim = 10

        model (features) = {
            featNorm = features - Constant (128)
            l1 = ConvolutionalLayer {32, (5:5), pad=true, activation=ReLU,
                                     init="gaussian", initValueScale=0.0043} (featNorm)
            p1 = MaxPoolingLayer {(3:3), stride=(2:2)} (l1)
            l2 = ConvolutionalLayer {32, (5:5), pad=true, activation=ReLU,
                                     init="gaussian", initValueScale=1.414} (p1)
            p2 = MaxPoolingLayer {(3:3), stride=(2:2)} (l2)
            l3 = ConvolutionalLayer {64, (5:5), pad=true, activation=ReLU,
                                     init="gaussian", initValueScale=1.414} (p2)
            p3 = MaxPoolingLayer {(3:3), stride=(2:2)} (l3)
            d1 = DenseLayer {64, activation=ReLU, init="gaussian", initValueScale=12} (p3)
            z  = LinearLayer {10, init="gaussian", initValueScale=1.5} (d1)
        }.z

        # inputs
        features = Input {imageShape}
        labels   = Input {labelDim}

        # apply model to features
        z = model (features)

        # connect to system
        ce       = CrossEntropyWithSoftmax (labels, z)
        errs     = ErrorPrediction         (labels, z)

        featureNodes    = (features)
        labelNodes      = (labels)
        criterionNodes  = (ce)
        evaluationNodes = (errs)
        outputNodes     = (z)
    }

    SGD = {
        epochSize = 50000

        maxEpochs = 30 ; minibatchSize = 64
        learningRatesPerSample = 0.00015625*10:0.000046875*10:0.000015625
        momentumAsTimeConstant = 600*20:6400
        L2RegWeight = 0.03

        firstMBsToShowResult = 10 ; numMBsToShowResult = 100
    }

    reader = {
        verbosity = 0 ; randomize = true
        deserializers = ({
            type = "ImageDeserializer" ; module = "ImageReader"
            file = "$dataDir$/cifar-10-batches-py/train_map.txt"
            input = {
                features = { transforms = (
                    { type = "Crop" ; cropType = "RandomSide" ; sideRatio = 0.8 ; jitterType = "UniRatio" } :
                    { type = "Scale" ; width = 32 ; height = 32 ; channels = 3 ; interpolations = "linear" } :
                    { type = "Transpose" }
                )}
                labels = { labelDim = 10 }
            }
        })
    }
}

# Eval action
Eval = {
    action = "eval"
    minibatchSize = 16
    evalNodeNames = errs
    reader = {
        verbosity = 0 ; randomize = true
        deserializers = ({
            type = "ImageDeserializer" ; module = "ImageReader"
            file = "$dataDir$/cifar-10-batches-py/test_map.txt"
            input = {
                features = { transforms = (
                   { type = "Scale" ; width = 32 ; height = 32 ; channels = 3 ; interpolations = "linear" } :
                   { type = "Transpose" }
                )}
                labels = { labelDim = 10 }
            }
        })
    }
}

Veri ve Veri Okuma

CIFAR-10 verilerini indirdikten ve betiği bu öğreticinin başında istendiği gibi çalıştırdıktan CifarConverter.py sonra, adlı iki alt dizin train içeren ve testPNG dosyalarıyla dolu bir dizin cifar-10-batches-py/databulursunuz. CNTK ImageDeserializer standart görüntü biçimlerini tüketir.

ayrıca ve test_map.txtdosyalarını train_map.txt da bulabilirsiniz. İkincisine baktığımızda,

% more cifar-10-batches-py/test_map.txt
cifar-10-batches-py/data/test/00000.png 3
cifar-10-batches-py/data/test/00001.png 8
cifar-10-batches-py/data/test/00002.png 8
...

Her iki dosya da iki sütundan oluşur; burada ilki görüntü dosyasının yolunu, ikincisi de sınıf etiketini sayısal dizin olarak içerir. Bu sütunlar okuyucu girişlerine features karşılık gelir ve labels şu şekilde tanımlanmıştır:

 features = { transforms = (
     { type = "Crop" ; cropType = "RandomSide" ; sideRatio = 0.8 ; jitterType = "UniRatio" } :
     { type = "Scale" ; width = 32 ; height = 32 ; channels = 3 ; interpolations = "linear" } :
     { type = "Transpose" }
 )}
 labels = { labelDim = 10 }

Ek transforms bölüm, okunan görüntülere bir dizi (ortak) dönüşüm uygulamasını söyler ImageDeserializer . Daha fazla bilgi için buraya bakın.

Çalıştırma

Yukarıdaki yapılandırma dosyasını çalışma klasöründeki adın ImageHandsOn.cntk altında bulabilirsiniz. Çalıştırmak için lütfen yukarıdaki yapılandırmayı şu komutla yürütür:

cntk  configFile=ImageHandsOn.cntk

Ekranınız günlük iletilerinden oluşan bir flurry ile canlanır (CNTK bazen konuşulabilir), ancak her şey yolunda giderse, yakında şunu görürsünüz:

Training 116906 parameters in 10 out of 10 parameter tensors and 28 nodes with gradient

ve ardından şuna benzer bir çıkışla devam edin:

Finished Epoch[ 1 of 10]: [Training] ce = 1.66950797 * 50000; errs = 61.228% * 50000
Finished Epoch[ 2 of 10]: [Training] ce = 1.32699016 * 50000; errs = 47.394% * 50000
Finished Epoch[ 3 of 10]: [Training] ce = 1.17140398 * 50000; errs = 41.168% * 50000

Bu size öğrendiğini gösterir. Her Dönem, 50000 eğitim görüntüsünden bir geçişi temsil eder. Ayrıca, ikinci dönem sonrasında, adlı ceyapılandırmanın bu dönemdeki 50000 örnek üzerinde ölçülen 1,33'e ulaştığını ve aynı 50000 eğitim örneğinde hata oranının %47 olduğunu bildirir.

Not Yalnızca CPU kullanan makineler yaklaşık 20 kat daha yavaştır. İlk günlük çıkışını görmeniz bile çok dakika sürer. Sistemin ilerlediğinden emin olmak için izlemeyi etkinleştirerek kısmi sonuçları görebilirsiniz ve bu da oldukça hızlı görünmelidir:

cntk  configFile=ImageHandsOn.cntk  traceLevel=1

Epoch[ 1 of 10]-Minibatch[-498-   1, 0.13%]: ce = 2.30260658 * 64; errs = 90.625% * 64
...
Epoch[ 1 of 10]-Minibatch[   1- 100, 12.80%]: ce = 2.10434176 * 5760; errs = 78.472% * 5760
Epoch[ 1 of 10]-Minibatch[ 101- 200, 25.60%]: ce = 1.82372971 * 6400; errs = 68.172% * 6400
Epoch[ 1 of 10]-Minibatch[ 201- 300, 38.40%]: ce = 1.69708496 * 6400; errs = 62.469% * 6400

Eğitim tamamlandığında (bir Surface Book ve Titan-X GPU'ya sahip bir masaüstü makinede yaklaşık 3 dakika sürer), son ileti şuna benzer olacaktır:

Finished Epoch[10 of 10]: [Training] ce = 0.74679766 * 50000; errs = 25.486% * 50000

ağın kaybı başarıyla azalttığını ve eğitim kümesinde ce %25,5 sınıflandırma hatasına ulaştığını gösterir. Değişkenimiz command ikinci bir komut Evalbelirttiği için CNTK bu eylemle devam eder. Test kümesinin 10000 görüntüsündeki sınıflandırma hata oranını ölçer.

Final Results: Minibatch[1-625]: errs = 24.180% * 10000

Test hatası oranı eğitime yakın. CIFAR-10 oldukça küçük bir veri kümesi olduğundan, bu modelimizin henüz tam olarak yakınsanmadığının bir göstergesidir (ve aslında, 30 dönem boyunca çalıştırmak sizi yaklaşık % 20'ye getirecektir).

Bu işlem bitene kadar beklemek istemiyorsanız, örneğin bir ara model çalıştırabilirsiniz.

cntk  configFile=ImageHandsOn.cntk  command=Eval  modelPath=Models/cifar10.cmf.5
Final Results: Minibatch[1-625]: errs = 31.710% * 10000

veya önceden eğitilmiş modelimizi çalıştırın:

cntk  configFile=ImageHandsOn.cntk  command=Eval  modelPath=cifar10.pretrained.cmf
Final Results: Minibatch[1-625]: errs = 24.180% * 10000

Modeli Değiştirme

Aşağıda, CNTK yapılandırmalarını değiştirme alıştırması yapmak için size görevler verilecektir. Çözümler bu belgenin sonunda verilmiştir... ama lütfen olmadan deneyin!

Görev 1: Açılan Öğe Ekleme

Modellerin genelleştirilebilirliğini artırmaya yönelik yaygın bir teknik, açılan menüdür. bir CNTK modeline açılan liste eklemek için

  • CNTK işlevine Dropout() açılan işlemi eklemek istediğiniz yere bir çağrı ekleyin
  • açılan olasılığını tanımlamak için adlı bölüme bir parametre dropoutRateSGD ekleyin

Bu özel görevde, lütfen ilk 1 dönem için hiçbir bırakma belirtmeyin ve ardından %50'lik bir bırakma oranı belirtin. Bunun nasıl yapılacağını görmek için lütfen belgelere göz atın Dropout() .

Her şey iyi gittiyse, ilk 1 dönem için hiçbir değişiklik gözlemleyeceksiniz, ancak ikinci dönemle birlikte bir kez açılan bir kez daha az bir iyileşme ce göreceksiniz. Bu beklenen bir durumdur. (Bu özel yapılandırma için, aslında tanıma doğruluğu iyileşmez.) Yalnızca 10 dönem eğitim yaklaşık %32 olduğunda nihai sonuç elde edilir. Bırakma için 10 dönem yeterli değildir.

Lütfen çözüme buradan bakın.

2. Görev: Yinelenen Parçaları İşleve Ayıklayarak Model Tanımını Basitleştirme

Örnekte, sıra (Convolution >> ReLU >> Pooling) üç kez yinelenir. Göreviniz, bu üç işlemi yeniden kullanılabilir bir modülde gruplandıran bir BrainScript işlevi yazmaktır. Bu dizinin üç kullanım alanının da farklı parametreler (çıkış boyutları, başlatma ağırlığı) kullandığını unutmayın. Bu nedenle, yazdığınız işlev giriş verilerine ek olarak bu ikisini parametre olarak almalıdır. Örneğin, şu şekilde tanımlanabilir:

MyLayer (x, depth, initValueScale)

Bunu çalıştırdığınızda, sonuç ce ve errs değerlerin aynı olmasını beklersiniz. Ancak GPU üzerinde çalıştırırsanız cuDNN'nin geri yayma uygulamasında belirlenemeyenler küçük farklılıklara neden olur.

Lütfen çözüme buradan bakın.

Görev 3: BatchNormalization Ekleme

(CNTK toplu normalleştirme uygulaması cuDNN'yi temel alır.

Toplu normalleştirme, yakınsamayı hızlandırmak ve geliştirmek için popüler bir tekniktir. CNTK toplu normalleştirme olarak BatchNormalizationLayer{}uygulanır.

Uzamsal form (tüm piksel konumlarının paylaşılan parametrelerle normalleştirildiği) isteğe bağlı bir parametre tarafından çağrılır: BatchNormalizationLayer{spatialRank=2}.

Lütfen üç kıvrım katmanına da ve iki yoğun katmanın arasına toplu normalleştirme ekleyin. Toplu normalleştirmenin doğrusal olmayandan hemen önce eklenmesi gerektiğini unutmayın. Bu nedenle parametresini activation kaldırmanız ve bunun yerine CNTK işlevine ReLU()açık çağrılar eklemeniz gerekir.

Ayrıca, toplu normalleştirme yakınsama hızını değiştirir. Şimdi ilk 7 dönem için öğrenme oranlarını 3 kat artıralım ve parametrelerini 0 olarak ayarlayarak momentum ve L2 normalleştirmesini devre dışı bırakalım.

Çalıştırırken, eğitim günlüğünde ek öğrenilebilir parametrelerin listelendiğini görürsünüz. Nihai sonuç %28 civarında olur ve bu da aynı sayıda yinelemeden sonra toplu normalleştirme olmadan 4 puan daha iyidir. Yakınsama gerçekten de hız kazanacaktır.

Lütfen çözüme buradan bakın.

Görev 4: Artık Ağa Dönüştür

Yukarıdaki yapılandırma, CNTK yapılandırmalarını çalıştırma ve değiştirme ile ellerinizi kirletmeye yönelik bir "oyuncak" örneğidir ve sizin için geri dönüş sürelerini düşük tutmak için kasıtlı olarak tam yakınsama çalıştırmadık. Şimdi daha gerçek bir yapılandırmaya geçelim: Artık Ağ. Artık Ağ (https://arxiv.org/pdf/1512.03385v1.pdf), katmanların girişten çıkışa eşleme öğrenmek yerine düzeltme terimini öğrendiği değiştirilmiş bir derin ağ yapısıdır.

(Bu Görev ayrıca toplu normalleştirme işlemi için bir GPU gerektirir, ancak çok fazla zaman varsa, bazı doğruluk kaybıyla toplu normalleştirme çağrılarını düzenleyerek bir CPU üzerinde çalıştırmayı deneyebilirsiniz.)

Başlamak için lütfen önceki yapılandırmayı değiştirin. İlk olarak lütfen model işlevini şu işlevle model(features) değiştirin:

        MySubSampleBN (x, depth, stride) =
        {
            s = Splice ((MaxPoolingLayer {(1:1), stride = (stride:stride)} (x) : ConstantTensor (0, (1:1:depth/stride))), axis = 3)  # sub-sample and pad: [W x H x depth/2] --> [W/2 x H/2 x depth]
            b = BatchNormalizationLayer {spatialRank = 2, normalizationTimeConstant = 4096} (s)
        }.b
        MyConvBN (x, depth, initValueScale, stride) =
        {
            c = ConvolutionalLayer {depth, (3:3), pad = true, stride = (stride:stride), bias = false,
                                    init = "gaussian", initValueScale = initValueScale} (x)
            b = BatchNormalizationLayer {spatialRank = 2, normalizationTimeConstant = 4096} (c)
        }.b
        ResNetNode (x, depth) =
        {
            c1 = MyConvBN (x,  depth, 7.07, 1)
            r1 = ReLU (c1)
            c2 = MyConvBN (r1, depth, 7.07, 1)
            r  = ReLU (c2)
        }.r
        ResNetIncNode (x, depth) =
        {
            c1 = MyConvBN (x,  depth, 7.07, 2)  # note the 2
            r1 = ReLU (c1)
            c2 = MyConvBN (r1, depth, 7.07, 1)
            r  = ReLU (c2)
        }.r
        model (features) =
        {
            conv1 = ReLU (MyConvBN (features, 16, 0.26, 1))
            rn1   = ResNetNode (ResNetNode (ResNetNode (conv1, 16), 16), 16)

            rn2_1 = ResNetIncNode (rn1, 32)
            rn2   = ResNetNode (ResNetNode (rn2_1, 32), 32)

            rn3_1 = ResNetIncNode (rn2, 64)
            rn3   = ResNetNode (ResNetNode (rn3_1, 64), 64)

            pool = AveragePoolingLayer {(8:8)} (rn3)

            z = LinearLayer {labelDim, init = "gaussian", initValueScale = 0.4} (pool)
        }.z

ve SGD yapılandırmasını şu şekilde değiştirin:

SGD = {
    epochSize = 50000

    maxEpochs = 160 ; minibatchSize = 128
    learningRatesPerSample = 0.0078125*80:0.00078125*40:0.000078125
    momentumAsTimeConstant = 1200
    L2RegWeight = 0.0001

    firstMBsToShowResult = 10 ; numMBsToShowResult = 500
}

Göreviniz, aşağıdaki değerli ASCII sanatında ortaya konan yapıyı uygulamak için ve bunları değiştirmektir ResNetNode()ResNetNodeInc() :

            ResNetNode                   ResNetNodeInc

                |                              |
         +------+------+             +---------+----------+
         |             |             |                    |
         V             |             V                    V
    +----------+       |      +--------------+   +----------------+
    | Conv, BN |       |      | Conv x 2, BN |   | SubSample, BN  |
    +----------+       |      +--------------+   +----------------+
         |             |             |                    |
         V             |             V                    |
     +-------+         |         +-------+                |
     | ReLU  |         |         | ReLU  |                |
     +-------+         |         +-------+                |
         |             |             |                    |
         V             |             V                    |
    +----------+       |        +----------+              |
    | Conv, BN |       |        | Conv, BN |              |
    +----------+       |        +----------+              |
         |             |             |                    |
         |    +---+    |             |       +---+        |
         +--->| + |<---+             +------>+ + +<-------+
              +---+                          +---+
                |                              |
                V                              V
            +-------+                      +-------+
            | ReLU  |                      | ReLU  |
            +-------+                      +-------+
                |                              |
                V                              V

Lütfen günlükteki doğrulama çıktısını doğru yaptığınıza onaylayın.

Bunun tamamlanması uzun sürer. Beklenen çıkış şuna benzer olacaktır:

Finished Epoch[ 1 of 160]: [Training] ce = 1.57037109 * 50000; errs = 58.940% * 50000
Finished Epoch[ 2 of 160]: [Training] ce = 1.06968234 * 50000; errs = 38.166% * 50000
Finished Epoch[ 3 of 160]: [Training] ce = 0.85858969 * 50000; errs = 30.316% * 50000

öte yandan, atlama bağlantıları olmayan yanlış model aşağıdakine daha çok benzer:

Finished Epoch[ 1 of 160]: [Training] ce = 1.72901219 * 50000; errs = 66.232% * 50000
Finished Epoch[ 2 of 160]: [Training] ce = 1.30180430 * 50000; errs = 47.424% * 50000
Finished Epoch[ 3 of 160]: [Training] ce = 1.04641961 * 50000; errs = 37.568% * 50000

Lütfen çözüme buradan bakın.

Görev 5: Birçok Katmanı Otomatik Olarak Oluşturma

Son olarak, en iyi performans gösteren ResNet'in 152 katmanı vardır. 152 ayrı ifadenin yazılması çok sıkıcı ve hataya açık olacağından, şimdi tanımı otomatik olarak bir yığını ResNetNode()oluşturacak şekilde değiştireceğiz.

Göreviniz şu imzaya sahip bir işlev yazmaktır:

ResNetNodeStack (x, depth, L)

buradaL, yukarıdaki ifadesini parametreli bir çağrıyla değiştirebilmemiz için rn1 kaç ResNetNodes tane yığılması gerektiğini belirtir:

rn1   = ResNetNodeStack (conv1, 16, 3)  # 3 means 3 such nodes

ve ve için rn2rn3de benzer şekilde. İhtiyacınız olacak araçlar koşullu ifadedir:

z = if cond then x else y

ve özyineleme.

Bu eğitim Titan-X'te yaklaşık yarım saat devam edecek. Doğru yaptıysanız, günlüğün başında şu ileti bulunur:

Training 200410 parameters in 51 out of 51 parameter tensors and 112 nodes with gradient:

Başvuru için bu modelin önceden eğitilmiş bir sürümünü ekleyeceğiz. Hata oranını şu komutla ölçebilirsiniz:

cntk  configFile=ImageHandsOn.ResNet.cntk  command=Eval

ve şunun gibi bir sonuç görmelidir:

Final Results: Minibatch[1-625]: errs = 8.400% * 10000; top5Errs = 0.290% * 10000

Bu hata oranı, özgün ResNet kağıdında (https://arxiv.org/pdf/1512.03385v1.pdfTablo 6) bildirilene çok yakındır.

Lütfen çözüme buradan bakın.

Görev 6: Paralel Eğitim

Son olarak, birden çok GPU'nuz varsa CNTK MPI (İleti Geçirme Arabirimi) kullanarak eğitimi paralelleştirmenize olanak tanır. Bu model, minibatch boyutları gibi daha fazla ayarlama yapmadan çok fazla hız elde etmek için çok küçük (mevcut minibatch boyutu ayarı, kullanılabilir GPU çekirdeklerinin tam kullanımını elde etmek için çok küçük). Bununla birlikte, gerçek dünya iş yüklerine geçtikten sonra bunu nasıl yapacağınızı bilmeniz için hareketleri gözden geçirelim.

Lütfen bloğuna aşağıdaki satırı SGD ekleyin:

SGD = {
    ...
    parallelTrain = {
        parallelizationMethod = "DataParallelSGD"
        parallelizationStartEpoch = 2
        distributedMBReading = true
        dataParallelSGD = { gradientBits = 1 }
    }
}

ve ardından şu komutu yürütür:

mpiexec -np 4 cntk  configFile=ImageHandsOn.cntk  stderr=Models/log  parallelTrain=true

Sırada Ne Var?

Bu öğretici, var olan bir yapılandırmayı almak ve belirli yollarla değiştirmek için alıştırmalar gerçekleştirmiştir:

  • önceden tanımlanmış işlem ekleme (bırakma)
  • yinelenen parçaları yeniden kullanılabilir modüllere ayıklama (işlevler)
  • yeniden düzenleme (toplu normalleştirme eklemek için)
  • özel ağ yapıları (ResNet atlama bağlantısı)
  • özyineleme kullanarak yinelenen yapıları parametreleştirme

ve paralelleştirme ile eğitimi nasıl hızlandıracağımızı gördük.

Peki buradan nereye gidiyoruz? Graf oluşturma stili olarak adlandırdığımız bu örneklerde kullanılan desenin hataya açık olabileceğini zaten keşfetmiş olabilirsiniz. Hata tespit mi?

model (features) =
{
    l1 = ConvolutionalLayer {32, (5:5), pad = true, activation = ReLU,
                             init = "gaussian", initValueScale = 0.0043} (featNorm)
    p1 = MaxPoolingLayer {(3:3), stride = (2:2)} (l1)
    l2 = ConvolutionalLayer {64, (5:5), pad = true, activation = ReLU,
                             init = "gaussian", initValueScale = 1.414} (p1)
    p2 = MaxPoolingLayer {(3:3), stride = (2:2)} (l1)
    d1 = DenseLayer {64, activation = ReLU, init = "gaussian", initValueScale = 12} (p2)
    z  = LinearLayer {10, init = "gaussian", initValueScale = 1.5} (d1)
}.z

Bu hatayı önlemenin bir yolu işlev bileşimini kullanmaktır. Aşağıdakiler, aynı yazıyı yazmanın alternatif ve daha kısa bir yoludur:

model = Sequential (
    ConvolutionalLayer {32, (5:5), pad = true, activation = ReLU,
                        init = "gaussian", initValueScale = 0.0043} :
    MaxPoolingLayer {(3:3), stride = (2:2)} :
    ConvolutionalLayer {64, (5:5), pad = true, activation = ReLU,
                        init = "gaussian", initValueScale = 1.414} :
    MaxPoolingLayer {(3:3), stride = (2:2)} :
    DenseLayer {64, activation = ReLU, init = "gaussian", initValueScale = 12} :
    LinearLayer {10, init = "gaussian", initValueScale = 1.5}
)

Bu stil bir sonraki uygulamalı öğretici olan Yinelenen Ağlarla Metin Anlama'da tanıtılacak ve kullanılacaktır.

Çözümler

Çözüm 1: Açılan Öğe Ekleme

Model tanımını aşağıdaki gibi değiştirin:

p3 = MaxPoolingLayer {(3:3), stride = (2:2)} (l3)
d1 = DenseLayer {64, activation = ReLU, init = "gaussian", initValueScale = 12} (p3)
d1_d = Dropout (d1)    ##### added
z  = LinearLayer {10, init = "gaussian", initValueScale = 1.5} (d1_d)  ##### d1 -> d1_d

ve SGD bölümü:

SGD = {
    ...
    dropoutRate = 0*5:0.5   ##### added
    ...
}

Çözüm 2: Yinelenen Parçaları İşleve Ayıklayarak Model Tanımını Basitleştirme

İşlev tanımını aşağıdaki gibi ekleyin:

MyLayer (x, depth, initValueScale) =
{
    c = ConvolutionalLayer {depth, (5:5), pad = true, activation = ReLU,
                            init = "gaussian", initValueScale = initValueScale} (x)
    p = MaxPoolingLayer {(3:3), stride = (2:2)} (c)
}.p

ve kullanmak için model tanımını güncelleştirin

featNorm = features - Constant (128)
p1 = MyLayer (featNorm, 32, 0.0043)  ##### replaced
p2 = MyLayer (p1,       32, 1.414)   ##### replaced
p3 = MyLayer (p2,       64, 1.414)   ##### replaced
d1 = DenseLayer {64, activation = ReLU, init = "gaussian", initValueScale = 12} (p3)

Çözüm 3: BatchNormalization Ekleme

Değiştir MyLayer():

MyLayer (x, depth, initValueScale) =
{
    c = ConvolutionalLayer {depth, (5:5), pad = true,  ##### no activation=ReLU
                            init = "gaussian", initValueScale = initValueScale} (x)
    b = BatchNormalizationLayer {spatialRank = 2} (c)
    r = ReLU (b)   ##### now called explicitly
    p = MaxPoolingLayer {(3:3), stride = (2:2)} (r)
}.p

ve kullanın. Ayrıca önüne ztoplu normalleştirme ekleyin:

d1 = DenseLayer {64, init = "gaussian", initValueScale = 12} (p3)
d1_bnr = ReLU (BatchNormalizationLayer {} (d1))  ##### added BN and explicit ReLU
d1_d = Dropout (d1_bnr)                          ##### d1 -> d1_bnr
z  = LinearLayer {10, init = "gaussian", initValueScale = 1.5} (d1_d)

SGD bölümünde bu parametreleri güncelleştirin:

SGD = {
    ....
    learningRatesPerSample = 0.00046875*7:0.00015625*10:0.000046875*10:0.000015625
    momentumAsTimeConstant = 0
    L2RegWeight = 0
    ...
}

Çözüm 4: Artık Ağa Dönüştür

ve ResNetNodeInc() için ResNetNode() doğru uygulamalar şunlardır:

    ResNetNode (x, depth) =
    {
        c1 = MyConvBN (x,  depth, 7.07, 1)
        r1 = ReLU (c1)
        c2 = MyConvBN (r1, depth, 7.07, 1)
        r  = ReLU (x + c2)   ##### added skip connection
    }.r
    ResNetIncNode (x, depth) =
    {
        c1 = MyConvBN (x,  depth, 7.07, 2)  # note the 2
        r1 = ReLU (c1)
        c2 = MyConvBN (r1, depth, 7.07, 1)

        xs = MySubSampleBN (x, depth, 2)

        r  = ReLU (xs + c2)   ##### added skip connection
    }.r

Çözüm 5: Birçok Katmanı Otomatik Olarak Oluşturma

Bu, uygulamadır:

    ResNetNodeStack (x, depth, L) =
    {
        r = if L == 0
            then x
            else ResNetNode (ResNetNodeStack (x, depth, L-1), depth)
    }.r

veya daha kısa:

    ResNetNodeStack (x, depth, L) =
        if L == 0
        then x
        else ResNetNode (ResNetNodeStack (x, depth, L-1), depth)

Model işlevinizi de değiştirmeniz gerekir:

        conv1 = ReLU (MyConvBN (features, 16, 0.26, 1))
        rn1   = ResNetNodeStack (conv1, 16, 3)  ##### replaced

        rn2_1 = ResNetIncNode (rn1, 32)
        rn2   = ResNetNodeStack (rn2_1, 32, 2)  ##### replaced

        rn3_1 = ResNetIncNode (rn2, 64)
        rn3   = ResNetNodeStack (rn3_1, 64, 2)  ##### replaced