2016-09-26 23 views
7

Tôi đang làm việc với Torch7 trên máy Linux CentOS 7. Tôi đang cố gắng áp dụng mạng nơron nhân tạo nhân tạo (ANN) vào tập dữ liệu của mình, để giải quyết vấn đề phân loại nhị phân nhị phân. Tôi đang sử dụng một perceptron đa lớp đơn giản .Ngọn đuốc, tại sao mạng lưới thần kinh nhân tạo của tôi dự đoán luôn là số không?

Tôi đang sử dụng các gói Torch sau: tối ưu, đèn pin.

Vấn đề là Perceptron tôi luôn dự đoán không giá trị (yếu tố phân loại là số không), và tôi không thể hiểu tại sao ...

Dưới đây là bộ dữ liệu của tôi ("dataset_file.csv"). Có 34 tính năng và 1 mục tiêu nhãn (cột cuối cùng, đó có thể là 0 hoặc 1):

0.55,1,0,1,0,0.29,1,0,1,0.46,1,1,0,0.67,1,0.37,0.41,1,0.08,0.47,0.23,0.13,0.82,0.46,0.25,0.04,0,0,0.52,1,0,0,0,0.33,0 
0.65,1,0,1,0,0.64,1,0,0,0.02,1,1,1,1,0,0.52,0.32,0,0.18,0.67,0.47,0.2,0.64,0.38,0.23,1,0.24,0.18,0.04,1,1,1,1,0.41,0 
0.34,1,0.13,1,0,0.33,0,0.5,0,0.02,0,0,0,0.67,1,0.25,0.55,1,0.06,0.23,0.18,0.15,0.82,0.51,0.22,0.06,0,0,0.6,1,0,0,0,0.42,1 
0.46,1,0,1,0,0.14,1,0,0,0.06,0,1,1,0,1,0.37,0.64,1,0.14,0.22,0.17,0.1,0.94,0.65,0.22,0.06,0.75,0.64,0.3,1,1,0,0,0.2,0 
0.55,1,0,1,0,0.14,1,0.5,1,0.03,1,1,0,1,1,0.42,0.18,0,0.16,0.55,0.16,0.12,0.73,0.55,0.2,0.03,0.54,0.44,0.35,1,1,0,0,0.11,0 
0.67,1,0,1,0,0.71,0,0.5,0,0.46,1,0,1,1,1,0.74,0.41,0,0.1,0.6,0.15,0.15,0.69,0.42,0.27,0.04,0.61,0.48,0.54,1,1,0,0,0.22,1 
0.52,1,0,1,0,0.21,1,0.5,0,0.01,1,1,1,0.67,0,0.27,0.64,0,0.08,0.34,0.14,0.21,0.85,0.51,0.2,0.05,0.51,0.36,0.36,1,1,0,0,0.23,0 
0.58,1,0.38,1,0,0.36,1,0.5,1,0.02,0,1,0,1,1,0.38,0.55,1,0.13,0.57,0.21,0.23,0.73,0.52,0.19,0.03,0,0,0.6,1,0,0,0,0.42,0 
0.66,1,0,1,0,0.07,1,0,0,0.06,1,0,0,1,1,0.24,0.32,1,0.06,0.45,0.16,0.13,0.92,0.57,0.27,0.06,0,0,0.55,1,0,0,0,0.33,0 
0.39,1,0.5,1,0,0.29,1,0,1,0.06,0,0,0,1,1,0.34,0.45,1,0.1,0.31,0.12,0.16,0.81,0.54,0.21,0.02,0.51,0.27,0.5,1,1,0,0,0.32,0 
0.26,0,0,1,0,0.21,1,0,0,0.02,1,1,1,0,1,0.17,0.36,0,0.19,0.41,0.24,0.26,0.73,0.55,0.22,0.41,0.46,0.43,0.42,1,1,0,0,0.52,0 
0.96,0,0.63,1,0,0.86,1,0,1,0.06,1,1,1,0,0,0.41,0.5,1,0.08,0.64,0.23,0.19,0.69,0.45,0.23,0.06,0.72,0.43,0.45,1,1,0,0,0.53,0 
0.58,0,0.25,1,0,0.29,1,0,1,0.04,1,0,0,0,1,0.4,0.27,1,0.09,0.65,0.21,0.16,0.8,0.57,0.24,0.02,0.51,0.28,0.5,1,1,1,0,0.63,0 
0.6,1,0.5,1,0,0.73,1,0.5,1,0.04,1,0,1,0,1,0.85,0.64,1,0.16,0.71,0.24,0.21,0.72,0.45,0.23,0.1,0.63,0.57,0.13,1,1,1,1,0.65,0 
0.72,1,0.25,1,0,0.29,1,0,0,0.06,1,0,0,1,1,0.31,0.41,1,0.17,0.78,0.24,0.16,0.75,0.54,0.27,0.09,0.78,0.68,0.19,1,1,1,1,0.75,0 
0.56,0,0.13,1,0,0.4,1,0,0,0.23,1,0,0,1,1,0.42,1,0,0.03,0.14,0.15,0.13,0.85,0.52,0.24,0.06,0,0,0.56,1,0,0,0,0.33,0 
0.67,0,0,1,0,0.57,1,0,1,0.02,0,0,0,1,1,0.38,0.36,0,0.08,0.12,0.11,0.14,0.8,0.49,0.22,0.05,0,0,0.6,1,0,0,0,0.22,0 
0.67,0,0,1,0,0.36,1,0,0,0.23,0,1,0,0,0,0.32,0.73,0,0.25,0.86,0.26,0.16,0.62,0.35,0.25,0.02,0.46,0.43,0.45,1,1,1,0,0.76,0 
0.55,1,0.5,1,0,0.57,0,0.5,1,0.12,1,1,1,0.67,1,1,0.45,0,0.19,0.94,0.19,0.22,0.88,0.41,0.35,0.15,0.47,0.4,0.05,1,1,1,0,0.56,1 
0.61,0,0,1,0,0.43,1,0.5,1,0.04,1,0,1,0,0,0.68,0.23,1,0.12,0.68,0.25,0.29,0.68,0.45,0.29,0.13,0.58,0.41,0.11,1,1,1,1,0.74,0 
0.59,1,0.25,1,0,0.23,1,0.5,0,0.02,1,1,1,0,1,0.57,0.41,1,0.08,0.05,0.16,0.15,0.87,0.61,0.25,0.04,0.67,0.61,0.45,1,1,0,0,0.65,0 
0.74,1,0.5,1,0,0.26,1,0,1,0.01,1,1,1,1,0,0.76,0.36,0,0.14,0.72,0.12,0.13,0.68,0.54,0.54,0.17,0.93,0.82,0.12,1,1,0,0,0.18,0 
0.64,0,0,1,0,0.29,0,0,1,0.15,0,0,1,0,1,0.33,0.45,0,0.11,0.55,0.25,0.15,0.75,0.54,0.27,0.05,0.61,0.64,0.43,1,1,0,0,0.23,1 
0.36,0,0.38,1,0,0.14,0,0.5,0,0.02,1,1,1,0.33,1,0.18,0.36,0,0.17,0.79,0.21,0.12,0.75,0.54,0.24,0.05,0,0,0.52,1,0,0,0,0.44,1 
0.52,0,0.75,1,0,0.14,1,0.5,0,0.04,1,1,1,0,1,0.36,0.68,1,0.08,0.34,0.12,0.13,0.79,0.59,0.22,0.02,0,0,0.5,1,0,0,0,0.23,0 
0.59,0,0.75,1,0,0.29,1,0,0,0.06,1,1,0,0,1,0.24,0.27,0,0.12,0.7,0.2,0.16,0.74,0.45,0.26,0.02,0.46,0.32,0.52,1,0,0,0,0.33,0 
0.72,1,0.38,1,0,0.43,0,0.5,0,0.06,1,0,1,0.67,1,0.53,0.32,0,0.2,0.68,0.16,0.13,0.79,0.45,0.25,0.09,0.61,0.57,0.15,1,1,0,0,0.22,1 

Và đây là mã Torch Lua tôi:

-- add comma to separate thousands 
function comma_value(amount) 
    local formatted = amount 
    while true do 
    formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') 
    if (k==0) then 
     break 
    end 
    end 
    return formatted 
end 

-- function that computes the confusion matrix 
function confusion_matrix(predictionTestVect, truthVect, threshold, printValues) 

    local tp = 0 
    local tn = 0 
    local fp = 0 
    local fn = 0 
    local MatthewsCC = -2 
    local accuracy = -2 
    local arrayFPindices = {} 
    local arrayFPvalues = {} 
    local arrayTPvalues = {} 
    local areaRoc = 0 

    local fpRateVett = {} 
    local tpRateVett = {} 
    local precisionVett = {} 
    local recallVett = {} 

    for i=1,#predictionTestVect do 

    if printValues == true then 
     io.write("predictionTestVect["..i.."] = ".. round(predictionTestVect[i],4).."\ttruthVect["..i.."] = "..truthVect[i].." "); 
     io.flush(); 
    end 

    if predictionTestVect[i] >= threshold and truthVect[i] >= threshold then 
     tp = tp + 1 
     arrayTPvalues[#arrayTPvalues+1] = predictionTestVect[i] 
     if printValues == true then print(" TP ") end 
    elseif predictionTestVect[i] < threshold and truthVect[i] >= threshold then 
     fn = fn + 1 
     if printValues == true then print(" FN ") end 
    elseif predictionTestVect[i] >= threshold and truthVect[i] < threshold then 
     fp = fp + 1 
     if printValues == true then print(" FP ") end 
     arrayFPindices[#arrayFPindices+1] = i; 
     arrayFPvalues[#arrayFPvalues+1] = predictionTestVect[i] 
    elseif predictionTestVect[i] < threshold and truthVect[i] < threshold then 
     tn = tn + 1 
     if printValues == true then print(" TN ") end 
    end 
    end 

    print("TOTAL:") 
    print(" FN = "..comma_value(fn).."/"..comma_value(tonumber(fn+tp)).."\t (truth == 1) & (prediction < threshold)"); 
    print(" TP = "..comma_value(tp).."/"..comma_value(tonumber(fn+tp)).."\t (truth == 1) & (prediction >= threshold)\n"); 

    print(" FP = "..comma_value(fp).."/"..comma_value(tonumber(fp+tn)).."\t (truth == 0) & (prediction >= threshold)"); 
    print(" TN = "..comma_value(tn).."/"..comma_value(tonumber(fp+tn)).."\t (truth == 0) & (prediction < threshold)\n"); 

    local continueLabel = true 

    if continueLabel then 
     upperMCC = (tp*tn) - (fp*fn) 
     innerSquare = (tp+fp)*(tp+fn)*(tn+fp)*(tn+fn) 
     lowerMCC = math.sqrt(innerSquare) 

     MatthewsCC = -2 
     if lowerMCC>0 then MatthewsCC = upperMCC/lowerMCC end 
     local signedMCC = MatthewsCC 
     print("signedMCC = "..signedMCC) 

     if MatthewsCC > -2 then print("\n::::\tMatthews correlation coefficient = "..signedMCC.."\t::::\n"); 
     else print("Matthews correlation coefficient = NOT computable"); end 

     accuracy = (tp + tn)/(tp + tn +fn + fp) 
     print("accuracy = "..round(accuracy,2).. " = (tp + tn)/(tp + tn +fn + fp) \t \t [worst = -1, best = +1]"); 

     local f1_score = -2 
     if (tp+fp+fn)>0 then 
    f1_score = (2*tp)/(2*tp+fp+fn) 
    print("f1_score = "..round(f1_score,2).." = (2*tp)/(2*tp+fp+fn) \t [worst = 0, best = 1]"); 
     else 
    print("f1_score CANNOT be computed because (tp+fp+fn)==0")  
     end 

     local totalRate = 0 
     if MatthewsCC > -2 and f1_score > -2 then 
    totalRate = MatthewsCC + accuracy + f1_score 
    print("total rate = "..round(totalRate,2).." in [-1, +3] that is "..round((totalRate+1)*100/4,2).."% of possible correctness"); 
     end 

     local numberOfPredictedOnes = tp + fp; 
     print("numberOfPredictedOnes = (TP + FP) = "..comma_value(numberOfPredictedOnes).." = "..round(numberOfPredictedOnes*100/(tp + tn + fn + fp),2).."%"); 

     io.write("\nDiagnosis: "); 
     if (fn >= tp and (fn+tp)>0) then print("too many FN false negatives"); end 
     if (fp >= tn and (fp+tn)>0) then print("too many FP false positives"); end 


     if (tn > (10*fp) and tp > (10*fn)) then print("Excellent ! ! !"); 
     elseif (tn > (5*fp) and tp > (5*fn)) then print("Very good ! !"); 
     elseif (tn > (2*fp) and tp > (2*fn)) then print("Good !"); 
     elseif (tn >= fp and tp >= fn) then print("Alright"); 
     else print("Baaaad"); end 
    end 

    return {accuracy, arrayFPindices, arrayFPvalues, MatthewsCC}; 
end 


-- Permutations 
-- tab = {1,2,3,4,5,6,7,8,9,10} 
-- permute(tab, 10, 10) 
function permute(tab, n, count) 
     n = n or #tab 
     for i = 1, count or n do 
     local j = math.random(i, n) 
     tab[i], tab[j] = tab[j], tab[i] 
     end 
     return tab 
end 

-- round a real value 
function round(num, idp) 
    local mult = 10^(idp or 0) 
    return math.floor(num * mult + 0.5)/mult 
end 



-- ##############################3 

local profile_vett = {} 
local csv = require("csv") 
local fileName = "dataset_file.csv" 

print("Readin' "..tostring(fileName)) 
local f = csv.open(fileName) 
local column_names = {} 

local j = 0 
for fields in f:lines() do 

    if j>0 then 
    profile_vett[j] = {} 
     for i, v in ipairs(fields) do 
    profile_vett[j][i] = tonumber(v); 
     end 
    j = j + 1 
    else 
    for i, v in ipairs(fields) do 
    column_names[i] = v 
    end 
    j = j + 1 
    end 
end 

OPTIM_PACKAGE = true 
local output_number = 1 
THRESHOLD = 0.5 -- ORIGINAL 
DROPOUT_FLAG = false 
MOMENTUM = false 
MOMENTUM_ALPHA = 0.5 
MAX_MSE = 4 
LEARN_RATE = 0.001 
ITERATIONS = 100 

local hidden_units = 2000 
local hidden_layers = 1 

local hiddenUnitVect = {2000, 4000, 6000, 8000, 10000} 
-- local hiddenLayerVect = {1,2,3,4,5} 
local hiddenLayerVect = {1} 

local profile_vett_data = {} 
local label_vett = {} 

for i=1,#profile_vett do 
    profile_vett_data[i] = {} 

    for j=1,#(profile_vett[1]) do 
    if j<#(profile_vett[1]) then 
     profile_vett_data[i][j] = profile_vett[i][j] 
    else 
     label_vett[i] = profile_vett[i][j] 
    end  
    end 
end 

print("Number of value profiles (rows) = "..#profile_vett_data); 
print("Number features (columns) = "..#(profile_vett_data[1])); 
print("Number of targets (rows) = "..#label_vett); 

local table_row_outcome = label_vett 
local table_rows_vett = profile_vett 

-- ######################################################## 

-- START 

local indexVect = {}; 
for i=1, #table_rows_vett do indexVect[i] = i; end 
permutedIndexVect = permute(indexVect, #indexVect, #indexVect); 

TEST_SET_PERC = 20 
local test_set_size = round((TEST_SET_PERC*#table_rows_vett)/100) 

print("training_set_size = "..(#table_rows_vett-test_set_size).." elements"); 
print("test_set_size = "..test_set_size.." elements\n"); 

local train_table_row_profile = {} 
local test_table_row_profile = {} 
local original_test_indexes = {} 

for i=1,#table_rows_vett do 
    if i<=(tonumber(#table_rows_vett)-test_set_size) then 
    train_table_row_profile[#train_table_row_profile+1] = {torch.Tensor(table_rows_vett[permutedIndexVect[i]]), torch.Tensor{table_row_outcome[permutedIndexVect[i]]}} 
    else 

    original_test_indexes[#original_test_indexes+1] = permutedIndexVect[i]; 

    test_table_row_profile[#test_table_row_profile+1] = {torch.Tensor(table_rows_vett[permutedIndexVect[i]]), torch.Tensor{table_row_outcome[permutedIndexVect[i]]}} 
    end 
end 

require 'nn' 
perceptron = nn.Sequential() 
input_number = #table_rows_vett[1] 

perceptron:add(nn.Linear(input_number, hidden_units)) 
perceptron:add(nn.Sigmoid()) 
if DROPOUT_FLAG==true then perceptron:add(nn.Dropout()) end 

for w=1,hidden_layers do 
    perceptron:add(nn.Linear(hidden_units, hidden_units)) 
    perceptron:add(nn.Sigmoid()) 
    if DROPOUT_FLAG==true then perceptron:add(nn.Dropout()) end 
end 
perceptron:add(nn.Linear(hidden_units, output_number)) 


function train_table_row_profile:size() return #train_table_row_profile end 
function test_table_row_profile:size() return #test_table_row_profile end 


-- OPTIMIZATION LOOPS 
local MCC_vect = {} 

for a=1,#hiddenUnitVect do 
    for b=1,#hiddenLayerVect do 

    local hidden_units = hiddenUnitVect[a] 
    local hidden_layers = hiddenLayerVect[b] 
    print("hidden_units = "..hidden_units.."\t output_number = "..output_number.." hidden_layers = "..hidden_layers) 


    local criterion = nn.MSECriterion() 
    local lossSum = 0 
    local error_progress = 0 

     require 'optim' 
     local params, gradParams = perceptron:getParameters()  
     local optimState = nil 

     if MOMENTUM==true then 
    optimState = {learningRate = LEARN_RATE} 
     else 
    optimState = {learningRate = LEARN_RATE, 
       momentum = MOMENTUM_ALPHA } 
     end 

     local total_runs = ITERATIONS*#train_table_row_profile 

     local loopIterations = 1 
     for epoch=1,ITERATIONS do 
    for k=1,#train_table_row_profile do 

     -- Function feval 
     local function feval(params) 
     gradParams:zero() 

     local thisProfile = train_table_row_profile[k][1] 
     local thisLabel = train_table_row_profile[k][2] 

     local thisPrediction = perceptron:forward(thisProfile) 
     local loss = criterion:forward(thisPrediction, thisLabel) 

     -- print("thisPrediction = "..round(thisPrediction[1],2).." thisLabel = "..thisLabel[1]) 

     lossSum = lossSum + loss 
     error_progress = lossSum*100/(loopIterations*MAX_MSE) 

     if ((loopIterations*100/total_runs)*10)%10==0 then 
      io.write("completion: ", round((loopIterations*100/total_runs),2).."%") 
      io.write(" (epoch="..epoch..")(element="..k..") loss = "..round(loss,2).." ")  
      io.write("\terror progress = "..round(error_progress,5).."%\n") 
     end 

     local dloss_doutput = criterion:backward(thisPrediction, thisLabel) 

     perceptron:backward(thisProfile, dloss_doutput) 

     return loss,gradParams 
     end 
     optim.sgd(feval, params, optimState) 
     loopIterations = loopIterations+1 
    end  
     end 


    local correctPredictions = 0 
    local atleastOneTrue = false 
    local atleastOneFalse = false 
    local predictionTestVect = {} 
    local truthVect = {} 

    for i=1,#test_table_row_profile do 
     local current_label = test_table_row_profile[i][2][1] 
     local prediction = perceptron:forward(test_table_row_profile[i][1])[1] 

     predictionTestVect[i] = prediction 
     truthVect[i] = current_label 

     local labelResult = false 

     if current_label >= THRESHOLD and prediction >= THRESHOLD then 
    labelResult = true 
     elseif current_label < THRESHOLD and prediction < THRESHOLD then 
    labelResult = true 
     end 

     if labelResult==true then correctPredictions = correctPredictions + 1; end 

    print("\nCorrect predictions = "..round(correctPredictions*100/#test_table_row_profile,2).."%") 

    local printValues = false 
    local output_confusion_matrix = confusion_matrix(predictionTestVect, truthVect, THRESHOLD, printValues) 
    end 
end 

Có ai có một ý tưởng về việc tại sao tôi kịch bản được dự đoán chỉ có các yếu tố không?

EDIT: Tôi thay thế các tập dữ liệu ban đầu với phiên bản bình thường của nó, mà tôi sử dụng trong kịch bản của tôi

+1

Tôi không quen thuộc với ngọn đuốc/lua nhưng tôi không thể tìm thấy bất kỳ bước dữ liệu bình thường trong mã của bạn. Có phải bạn đang làm thứ này? Điều này là rất quan trọng (đặc biệt là vì bạn có một cột với giá trị rất lớn so với những người khác)! Bạn cũng có thể muốn hiển thị một số convergence. Lỗi đào tạo có giảm không? – sascha

+0

@sascha Cảm ơn, tôi đang sử dụng tập dữ liệu đã chuẩn hóa, nhưng tôi đã vô tình chèn tập dữ liệu gốc. Bây giờ tôi đã thay thế tập dữ liệu gốc bằng tập dữ liệu đã chuẩn hóa. Cảm ơn vì đã chú ý đến nó. Và có, lỗi đào tạo thường giảm từ ~ 15 đến ~ 6. –

Trả lời

2

Khi tôi chạy mã ban đầu của mình, đôi khi tôi nhận được tất cả số không được dự đoán và đôi khi tôi nhận được hiệu suất hoàn hảo. Điều này cho thấy mô hình ban đầu của bạn rất nhạy cảm với việc khởi tạo các giá trị tham số.

Nếu tôi sử dụng giá trị hạt giống torch.manualSeed(0) (vì vậy chúng tôi luôn có cùng khởi tạo), tôi nhận được hiệu suất hoàn hảo mọi lúc. Nhưng đây không thực sự là một giải pháp chung.

Để có được một sự cải thiện chung chúng tôi đã thực hiện các thay đổi sau:

  1. Giảm số lượng đơn vị ẩn. Trong mã ban đầu, bạn có lớp ẩn duy nhất là 2000 đơn vị. Nhưng bạn chỉ có 34 đầu vào và 1 đầu ra Thường thì bạn chỉ cần số lượng đơn vị ẩn là giữa số lượng đầu vào và đầu ra. Tôi đã giảm số này thành 50.
  2. Các nhãn là không đối xứng, chỉ có 5/27 (19%) nhãn là nhãn, vì vậy bạn thực sự nên chia các tập kiểm tra đào tạo theo cách sao cho duy trì tỷ lệ của số không đến 0. Bây giờ tôi đã tăng kích thước thiết lập thử nghiệm lên '50'%.
  3. Tôi cũng đã tăng tỷ lệ học cách '0.01', quay MOMENTUM trên, và tăng ITERATIONS đến 200.

Khi tôi chạy mô hình này 20 lần (unseeded) Tôi đã nhận Excellent hiệu suất 19 lần. Để cải thiện hơn nữa, bạn có thể tinh chỉnh các tham số siêu hơn nữa. Và cũng nên xem xét nhiều lần khởi tạo với một bộ xác thực riêng biệt để chọn mô hình "tốt nhất" (mặc dù điều này sẽ chia nhỏ hơn nữa bộ dữ liệu đã rất nhỏ của bạn).

-- add comma to separate thousands 
function comma_value(amount) 
    local formatted = amount 
    while true do 
    formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') 
    if (k==0) then 
     break 
    end 
    end 
    return formatted 
end 

-- function that computes the confusion matrix 
function confusion_matrix(predictionTestVect, truthVect, threshold, printValues) 

    local tp = 0 
    local tn = 0 
    local fp = 0 
    local fn = 0 
    local MatthewsCC = -2 
    local accuracy = -2 
    local arrayFPindices = {} 
    local arrayFPvalues = {} 
    local arrayTPvalues = {} 
    local areaRoc = 0 

    local fpRateVett = {} 
    local tpRateVett = {} 
    local precisionVett = {} 
    local recallVett = {} 

    for i=1,#predictionTestVect do 

    if printValues == true then 
     io.write("predictionTestVect["..i.."] = ".. round(predictionTestVect[i],4).."\ttruthVect["..i.."] = "..truthVect[i].." "); 
     io.flush(); 
    end 

    if predictionTestVect[i] >= threshold and truthVect[i] >= threshold then 
     tp = tp + 1 
     arrayTPvalues[#arrayTPvalues+1] = predictionTestVect[i] 
     if printValues == true then print(" TP ") end 
    elseif predictionTestVect[i] < threshold and truthVect[i] >= threshold then 
     fn = fn + 1 
     if printValues == true then print(" FN ") end 
    elseif predictionTestVect[i] >= threshold and truthVect[i] < threshold then 
     fp = fp + 1 
     if printValues == true then print(" FP ") end 
     arrayFPindices[#arrayFPindices+1] = i; 
     arrayFPvalues[#arrayFPvalues+1] = predictionTestVect[i] 
    elseif predictionTestVect[i] < threshold and truthVect[i] < threshold then 
     tn = tn + 1 
     if printValues == true then print(" TN ") end 
    end 
    end 

    print("TOTAL:") 
    print(" FN = "..comma_value(fn).."/"..comma_value(tonumber(fn+tp)).."\t (truth == 1) & (prediction < threshold)"); 
    print(" TP = "..comma_value(tp).."/"..comma_value(tonumber(fn+tp)).."\t (truth == 1) & (prediction >= threshold)\n"); 

    print(" FP = "..comma_value(fp).."/"..comma_value(tonumber(fp+tn)).."\t (truth == 0) & (prediction >= threshold)"); 
    print(" TN = "..comma_value(tn).."/"..comma_value(tonumber(fp+tn)).."\t (truth == 0) & (prediction < threshold)\n"); 

    local continueLabel = true 

    if continueLabel then 
     upperMCC = (tp*tn) - (fp*fn) 
     innerSquare = (tp+fp)*(tp+fn)*(tn+fp)*(tn+fn) 
     lowerMCC = math.sqrt(innerSquare) 

     MatthewsCC = -2 
     if lowerMCC>0 then MatthewsCC = upperMCC/lowerMCC end 
     local signedMCC = MatthewsCC 
     print("signedMCC = "..signedMCC) 

     if MatthewsCC > -2 then print("\n::::\tMatthews correlation coefficient = "..signedMCC.."\t::::\n"); 
     else print("Matthews correlation coefficient = NOT computable"); end 

     accuracy = (tp + tn)/(tp + tn +fn + fp) 
     print("accuracy = "..round(accuracy,2).. " = (tp + tn)/(tp + tn +fn + fp) \t \t [worst = -1, best = +1]"); 

     local f1_score = -2 
     if (tp+fp+fn)>0 then 
    f1_score = (2*tp)/(2*tp+fp+fn) 
    print("f1_score = "..round(f1_score,2).." = (2*tp)/(2*tp+fp+fn) \t [worst = 0, best = 1]"); 
     else 
    print("f1_score CANNOT be computed because (tp+fp+fn)==0")  
     end 

     local totalRate = 0 
     if MatthewsCC > -2 and f1_score > -2 then 
    totalRate = MatthewsCC + accuracy + f1_score 
    print("total rate = "..round(totalRate,2).." in [-1, +3] that is "..round((totalRate+1)*100/4,2).."% of possible correctness"); 
     end 

     local numberOfPredictedOnes = tp + fp; 
     print("numberOfPredictedOnes = (TP + FP) = "..comma_value(numberOfPredictedOnes).." = "..round(numberOfPredictedOnes*100/(tp + tn + fn + fp),2).."%"); 

     io.write("\nDiagnosis: "); 
     if (fn >= tp and (fn+tp)>0) then print("too many FN false negatives"); end 
     if (fp >= tn and (fp+tn)>0) then print("too many FP false positives"); end 


     if (tn > (10*fp) and tp > (10*fn)) then print("Excellent ! ! !"); 
     elseif (tn > (5*fp) and tp > (5*fn)) then print("Very good ! !"); 
     elseif (tn > (2*fp) and tp > (2*fn)) then print("Good !"); 
     elseif (tn >= fp and tp >= fn) then print("Alright"); 
     else print("Baaaad"); end 
    end 

    return {accuracy, arrayFPindices, arrayFPvalues, MatthewsCC}; 
end 


-- Permutations 
-- tab = {1,2,3,4,5,6,7,8,9,10} 
-- permute(tab, 10, 10) 
function permute(tab, n, count) 
     n = n or #tab 
     for i = 1, count or n do 
     local j = math.random(i, n) 
     tab[i], tab[j] = tab[j], tab[i] 
     end 
     return tab 
end 

-- round a real value 
function round(num, idp) 
    local mult = 10^(idp or 0) 
    return math.floor(num * mult + 0.5)/mult 
end 



-- ##############################3 

local profile_vett = {} 
local csv = require("csv") 
local fileName = "dataset_file.csv" 

print("Readin' "..tostring(fileName)) 
local f = csv.open(fileName) 
local column_names = {} 

local j = 0 
for fields in f:lines() do 

    if j>0 then 
    profile_vett[j] = {} 
     for i, v in ipairs(fields) do 
    profile_vett[j][i] = tonumber(v); 
     end 
    j = j + 1 
    else 
    for i, v in ipairs(fields) do 
    column_names[i] = v 
    end 
    j = j + 1 
    end 
end 

OPTIM_PACKAGE = true 
local output_number = 1 
THRESHOLD = 0.5 -- ORIGINAL 
DROPOUT_FLAG = false 
MOMENTUM_ALPHA = 0.5 
MAX_MSE = 4 

-- CHANGE: increased learn_rate to 0.01, reduced hidden units to 50, turned momentum on, increased iterations to 200 
LEARN_RATE = 0.01 
local hidden_units = 50 
MOMENTUM = true 
ITERATIONS = 200 
------------------------------------- 

local hidden_layers = 1 

local hiddenUnitVect = {2000, 4000, 6000, 8000, 10000} 
-- local hiddenLayerVect = {1,2,3,4,5} 
local hiddenLayerVect = {1} 

local profile_vett_data = {} 
local label_vett = {} 

for i=1,#profile_vett do 
    profile_vett_data[i] = {} 

    for j=1,#(profile_vett[1]) do 
    if j<#(profile_vett[1]) then 
     profile_vett_data[i][j] = profile_vett[i][j] 
    else 
     label_vett[i] = profile_vett[i][j] 
    end  
    end 
end 

print("Number of value profiles (rows) = "..#profile_vett_data); 
print("Number features (columns) = "..#(profile_vett_data[1])); 
print("Number of targets (rows) = "..#label_vett); 

local table_row_outcome = label_vett 
local table_rows_vett = profile_vett 

-- ######################################################## 

-- START 

-- Seed random number generator 
-- torch.manualSeed(0) 

local indexVect = {}; 
for i=1, #table_rows_vett do indexVect[i] = i; end 
permutedIndexVect = permute(indexVect, #indexVect, #indexVect); 

-- CHANGE: increase test_set to 50% 
TEST_SET_PERC = 50 
--------------------------- 

local test_set_size = round((TEST_SET_PERC*#table_rows_vett)/100) 

print("training_set_size = "..(#table_rows_vett-test_set_size).." elements"); 
print("test_set_size = "..test_set_size.." elements\n"); 

local train_table_row_profile = {} 
local test_table_row_profile = {} 
local original_test_indexes = {} 

for i=1,#table_rows_vett do 
    if i<=(tonumber(#table_rows_vett)-test_set_size) then 
    train_table_row_profile[#train_table_row_profile+1] = {torch.Tensor(table_rows_vett[permutedIndexVect[i]]), torch.Tensor{table_row_outcome[permutedIndexVect[i]]}} 
    else 

    original_test_indexes[#original_test_indexes+1] = permutedIndexVect[i]; 

    test_table_row_profile[#test_table_row_profile+1] = {torch.Tensor(table_rows_vett[permutedIndexVect[i]]), torch.Tensor{table_row_outcome[permutedIndexVect[i]]}} 
    end 
end 

require 'nn' 
perceptron = nn.Sequential() 
input_number = #table_rows_vett[1] 

perceptron:add(nn.Linear(input_number, hidden_units)) 
perceptron:add(nn.Sigmoid()) 
if DROPOUT_FLAG==true then perceptron:add(nn.Dropout()) end 

for w=1,hidden_layers do 
    perceptron:add(nn.Linear(hidden_units, hidden_units)) 
    perceptron:add(nn.Sigmoid()) 
    if DROPOUT_FLAG==true then perceptron:add(nn.Dropout()) end 
end 
perceptron:add(nn.Linear(hidden_units, output_number)) 


function train_table_row_profile:size() return #train_table_row_profile end 
function test_table_row_profile:size() return #test_table_row_profile end 


-- OPTIMIZATION LOOPS 
local MCC_vect = {} 

for a=1,#hiddenUnitVect do 
    for b=1,#hiddenLayerVect do 

    local hidden_units = hiddenUnitVect[a] 
    local hidden_layers = hiddenLayerVect[b] 
    print("hidden_units = "..hidden_units.."\t output_number = "..output_number.." hidden_layers = "..hidden_layers) 


    local criterion = nn.MSECriterion() 
    local lossSum = 0 
    local error_progress = 0 

     require 'optim' 
     local params, gradParams = perceptron:getParameters()  
     local optimState = nil 

     if MOMENTUM==true then 
    optimState = {learningRate = LEARN_RATE} 
     else 
    optimState = {learningRate = LEARN_RATE, 
       momentum = MOMENTUM_ALPHA } 
     end 

     local total_runs = ITERATIONS*#train_table_row_profile 

     local loopIterations = 1 
     for epoch=1,ITERATIONS do 
    for k=1,#train_table_row_profile do 

     -- Function feval 
     local function feval(params) 
     gradParams:zero() 

     local thisProfile = train_table_row_profile[k][1] 
     local thisLabel = train_table_row_profile[k][2] 

     local thisPrediction = perceptron:forward(thisProfile) 
     local loss = criterion:forward(thisPrediction, thisLabel) 

     -- print("thisPrediction = "..round(thisPrediction[1],2).." thisLabel = "..thisLabel[1]) 

     lossSum = lossSum + loss 
     error_progress = lossSum*100/(loopIterations*MAX_MSE) 

     if ((loopIterations*100/total_runs)*10)%10==0 then 
      io.write("completion: ", round((loopIterations*100/total_runs),2).."%") 
      io.write(" (epoch="..epoch..")(element="..k..") loss = "..round(loss,2).." ")  
      io.write("\terror progress = "..round(error_progress,5).."%\n") 
     end 

     local dloss_doutput = criterion:backward(thisPrediction, thisLabel) 

     perceptron:backward(thisProfile, dloss_doutput) 

     return loss,gradParams 
     end 
     optim.sgd(feval, params, optimState) 
     loopIterations = loopIterations+1 
    end  
     end 


    local correctPredictions = 0 
    local atleastOneTrue = false 
    local atleastOneFalse = false 
    local predictionTestVect = {} 
    local truthVect = {} 

    for i=1,#test_table_row_profile do 
     local current_label = test_table_row_profile[i][2][1] 
     local prediction = perceptron:forward(test_table_row_profile[i][1])[1] 

     predictionTestVect[i] = prediction 
     truthVect[i] = current_label 

     local labelResult = false 

     if current_label >= THRESHOLD and prediction >= THRESHOLD then 
    labelResult = true 
     elseif current_label < THRESHOLD and prediction < THRESHOLD then 
    labelResult = true 
     end 

     if labelResult==true then correctPredictions = correctPredictions + 1; end 

    print("\nCorrect predictions = "..round(correctPredictions*100/#test_table_row_profile,2).."%") 

    local printValues = false 
    local output_confusion_matrix = confusion_matrix(predictionTestVect, truthVect, THRESHOLD, printValues) 
    end 
end 
end 

dán dưới đây là sản phẩm của 1 trong số 20 chạy:

Correct predictions = 100% 
TOTAL: 
FN = 0/4 (truth == 1) & (prediction < threshold)  
TP = 4/4 (truth == 1) & (prediction >= threshold) 

FP = 0/9 (truth == 0) & (prediction >= threshold) 
TN = 9/9 (truth == 0) & (prediction < threshold) 

signedMCC = 1 

:::: Matthews correlation coefficient = 1 :::: 

accuracy = 1 = (tp + tn)/(tp + tn +fn + fp)  [worst = -1, best = +1] 
f1_score = 1 = (2*tp)/(2*tp+fp+fn)  [worst = 0, best = 1] 
total rate = 3 in [-1, +3] that is 100% of possible correctness 
numberOfPredictedOnes = (TP + FP) = 4 = 30.77% 

Diagnosis: Excellent ! ! ! 
+0

Cảm ơn Khalid, nó thực sự hiệu quả! Câu hỏi: làm thế nào bạn biết rằng số đơn vị ẩn phải được giảm xuống còn '50'? Làm thế nào bạn biết rằng tỷ lệ học tập nên được tăng lên đến 0,01'? Làm thế nào bạn biết rằng số lặp nên được tăng lên đến '200'? –

+0

Có một bài báo hay [ở đây] (https://arxiv.org/pdf/1206.5533v2.pdf) với lời khuyên về điều chỉnh siêu tham số, mặc dù tôi phải thừa nhận rằng tôi chưa có cơ hội để đọc nhiều về nó. Quá trình suy nghĩ của tôi trước hết là làm cho mạng chỉ lớn đến mức cần thiết (như đã đề cập trong câu hỏi hiếm khi một mạng cần nhiều hơn gấp đôi kích thước (chiều rộng) của các lớp đầu vào/đầu ra lớn hơn) . Sau đó thử nghiệm với các thông số khác là nhanh hơn (như mô hình đào tạo nhanh hơn). – kabdulla

0

Rất có thể NN của bạn đang học quá chậm và do đó không hiểu bất cứ điều gì. Deeplearning4j có một bài viết tuyệt vời trên troubleshooting neural net training, điều này có thể làm sáng tỏ một số hiệu ứng của các hyperparameters khác nhau.

Sau khi đã có một cái nhìn tại mã của bạn, đầu tiên tôi sẽ cố gắng những điều sau đây:

  • Điều chỉnh tỷ lệ học:
    Bạn đã cố định tỷ lệ học cách: LEARN_RATE = 0.001. Thử các giá trị giữa 1e-11e-8.
  • Chỉnh sửa lớp ẩn của bạn:
    Bạn có thể phải tinh chỉnh lớp ẩn của mình: hiddenUnitVect = {2000, 4000, 6000, 8000, 10000}. Điều này có vẻ hơi lớn đối với nhiệm vụ trong tầm tay. Hãy thử một mạng lưới nhỏ hơn đầu tiên và tăng kích thước nếu nó không tổng quát tốt.
Các vấn đề liên quan