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 ImageHandsOn
ayarlayın.
Aşağıdaki dosyalarla çalışacaksınız:
ImageHandsOn.cntk
: Aşağıda tanıtacağımız ve birlikte çalışacağımız CNTK yapılandırma dosyası.cifar10.pretrained.cmf
: Başlayacağımız yapılandırmanın sonuç modeli.cifar10.ResNet.cmf
: Aşağıda oluşturacağımız ResNet sürümünün sonuç modeli.
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 (command
değ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 test
PNG dosyalarıyla dolu bir dizin cifar-10-batches-py/data
bulursunuz.
CNTK ImageDeserializer
standart görüntü biçimlerini tüketir.
ayrıca ve test_map.txt
dosyaları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ı ce
yapı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 Eval
belirttiğ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
dropoutRate
SGD
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 rn2
rn3
de 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 z
toplu 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