2017-08-10 18 views
1

我們剛剛開始使用CNTK創建二元分類器的項目。CNTK二元分類器

我們的數據集是這樣的:

|attribs 1436000 24246.3124164245 |isMatch 1 
|attribs 535000 21685.9351529239 |isMatch 1 
|attribs 729000 8988.24232231086 |isMatch 1 
|attribs 436000 4787.7521169184 |isMatch 1 
|attribs 110000 38236394.456649 |isMatch 0 
|attribs 808000 39512500.9870238 |isMatch 0 
|attribs 108000 28432968.9161523 |isMatch 0 
|attribs 816000 39512231.5629576 |isMatch 0 

我們正試圖確定一個校車站是否計劃路線一致。第一個值是計劃停止和實際停止之間的增量時間(毫秒),第二個值是計劃位置和實際位置(毫米)之間的增量距離。

我遇到的問題是(可能是對如何使用CNTK的一個基本誤解),無論我如何調整數據,隱藏節點,批量大小或任何其他旋鈕,我都會繼續得到幾乎相同的結果。我可以評估最荒謬的投入,我一直得到1.00。

我該如何修改數據或模型以獲得更準確的結果?

完整的代碼是在這裏:

import numpy as np 
import cntk as C 
from cntk import Trainer # to train the NN 
from cntk.learners import sgd, learning_rate_schedule, \ 
    UnitType 
from cntk.ops import * # input_variable() def 
from cntk.logging import ProgressPrinter 
from cntk.initializer import glorot_uniform 
from cntk.layers import default_options, Dense 
from cntk.io import CTFDeserializer, MinibatchSource, \ 
    StreamDef, StreamDefs, INFINITELY_REPEAT 


def my_print(arr, dec): 
    # print an array of float/double with dec decimals 
    fmt = "%." + str(dec) + "f" # like %.4f 
    for i in range(0, len(arr)): 
     print(fmt % arr[i] + ' ', end='') 
    print("\n") 


def create_reader(path, is_training, input_dim, output_dim): 
    return MinibatchSource(CTFDeserializer(path, StreamDefs(
     features=StreamDef(field='attribs', shape=input_dim, 
          is_sparse=False), 
     labels=StreamDef(field='isMatch', shape=output_dim, 
         is_sparse=False) 
    )), randomize=is_training, 
          max_sweeps=INFINITELY_REPEAT if is_training else 1) 


def save_weights(fn, ihWeights, hBiases, 
       hoWeights, oBiases): 
    f = open(fn, 'w') 
    for vals in ihWeights: 
     for v in vals: 
      f.write("%s\n" % v) 
    for v in hBiases: 
     f.write("%s\n" % v) 
    for vals in hoWeights: 
     for v in vals: 
      f.write("%s\n" % v) 
    for v in oBiases: 
     f.write("%s\n" % v) 
    f.close() 


def do_demo(): 
    # create NN, train, test, predict 
    input_dim = 2 
    hidden_dim = 30 
    output_dim = 1 
    train_file = "trainData_cntk.txt" 
    test_file = "testData_cntk.txt" 
    input_Var = C.ops.input_variable(input_dim, np.float32) 
    label_Var = C.ops.input_variable(output_dim, np.float32) 
    print("Creating a 2-21 tanh softmax NN for Stop data ") 
    with default_options(init=glorot_uniform()): 
     hLayer = Dense(hidden_dim, activation=C.ops.tanh, 
         name='hidLayer')(input_Var) 
     oLayer = Dense(output_dim, activation=C.ops.softmax, 
         name='outLayer')(hLayer) 
    nnet = oLayer 
    # ---------------------------------- 
    print("Creating a cross entropy mini-batch Trainer \n") 
    ce = C.cross_entropy_with_softmax(nnet, label_Var) 
    pe = C.classification_error(nnet, label_Var) 
    fixed_lr = 0.05 
    lr_per_batch = learning_rate_schedule(fixed_lr, 
              UnitType.minibatch) 
    learner = C.sgd(nnet.parameters, lr_per_batch) 

    trainer = C.Trainer(nnet, (ce, pe), [learner]) 
    max_iter = 5000 # 5000 maximum training iterations 
    batch_size = 100 # mini-batch size 5 
    progress_freq = 1000 # print error every n minibatches 
    reader_train = create_reader(train_file, True, input_dim, 
           output_dim) 
    my_input_map = { 
     input_Var: reader_train.streams.features, 
     label_Var: reader_train.streams.labels 
    } 
    pp = ProgressPrinter(progress_freq) 
    print("Starting training \n") 
    for i in range(0, max_iter): 
     currBatch = reader_train.next_minibatch(batch_size, 
               input_map=my_input_map) 
     trainer.train_minibatch(currBatch) 
     pp.update_with_trainer(trainer) 
    print("\nTraining complete") 
    # ---------------------------------- 
    print("\nEvaluating test data \n") 
    reader_test = create_reader(test_file, False, input_dim, 
           output_dim) 
    numTestItems = 200 
    allTest = reader_test.next_minibatch(numTestItems, 
             input_map=my_input_map) 
    test_error = trainer.test_minibatch(allTest) 
    print("Classification error on the test items = %f" 
      % test_error) 
    # ---------------------------------- 
    # make a prediction for an unknown flower 
    # first train versicolor = 7.0,3.2,4.7,1.4,0,1,0 
    unknown = np.array([[10000002000, 24275329.7232828]], dtype=np.float32) 
    print("\nPredicting Stop Match for input features: ") 
    my_print(unknown[0], 1) # 1 decimal 
    predicted = nnet.eval({input_Var: unknown}) 
    print("Prediction is: ") 
    my_print(predicted[0], 3) # 3 decimals 
    # --------------------------------- 
    print("\nTrained model input-to-hidden weights: \n") 
    print(hLayer.hidLayer.W.value) 
    print("\nTrained model hidden node biases: \n") 
    print(hLayer.hidLayer.b.value) 
    print("\nTrained model hidden-to-output weights: \n") 
    print(oLayer.outLayer.W.value) 
    print("\nTrained model output node biases: \n") 
    print(oLayer.outLayer.b.value) 
    save_weights("weights.txt", hLayer.hidLayer.W.value, 
       hLayer.hidLayer.b.value, oLayer.outLayer.W.value, 
       oLayer.outLayer.b.value) 
    return 0 # success 


def main(): 
    print("\nBegin Stop Match \n") 
    np.random.seed(0) 
    do_demo() # all the work is done in do_demo() 


if __name__ == "__main__": 
    main() 
# end script 

回答

1

我認爲這個問題是,你的輸出層是用一種softmax()激活功能,但當時使用的是cross_entropy_with_softmax()爲您的損失函數。因此,在培訓期間,您的結果將被評估爲softmax的softmax。

在輸出圖層中使用activation=None並查看您的訓練是如何進行的。

在您的預測代碼中,您顯然必須將softmax應用於您的評估,因此類似C.ops.softmax(nnet).eval({input_Var: unknown})。回顧一下我所做的一個例子,我使用C.softmax,但是這可能與我寫這個例子時的命名空間差異與您正在使用的CNTK版本不同。 PS:如果你正在做二進制分類,那麼你實際上不需要使用softmax,因爲它真的是用於多類分類問題。它應該仍然在二進制情況下工作。

PPS:在訓練期間,在每個小批次之後打印出損失是非常有用的,這樣您可以看到梯度下降是否收斂。我想你會發現在你現在的模型中並不是這樣。

PPS:我剛剛注意到您的變量output_dim設置爲1.我不知道在這種情況下您將使用softmax獲得什麼行爲。通常softmax會應用於一個熱編碼輸出,所以在二進制情況下,您將有兩個輸出,可以給出正確結果爲零或一個的概率。同樣,在訓練之前,你需要明顯地熱點編碼你的基本事實。無法確定您的方法是否有效,但看起來很腥。

+0

我真的希望我完全理解你在這裏說的。但作爲一個總的noob,我不這樣做。你有什麼機會讓我讀一些書來加快速度? – Wjdavis5

+1

我不知道比完成http://www.coursera.org/learn/machine-learning/home/welcome更快的路線 –

1

當你在一個只有一個元素的矢量上做softmax時,無論你做什麼,你都會在輸出中得到1。正確的方法是有兩個輸出(也使標籤爲「0 1」或「1 0」),並且不使用softmax激活,因爲cross_entropy_with_softmax具有softmax內置。

一旦你這樣做,你可能會遇到其他問題,最顯着的是投入是巨大的。神經網絡的輸入類似於它們的輸入很小並且以0爲中心。我會通過在訓練集上減去它的平均值併除以它的標準偏差來標準化每個特徵。