2017-08-17 112 views
0

我試圖讓我的NN在20x20的畫布中手工繪製出「快樂」和「悲傷」的表情。我使用了400個輸入圖層單元,100個隱藏圖層單元和2個輸出單元(開心/傷心)。隱藏的&輸出圖層的激活功能是sigmoid。NN輸出傾向於最新的訓練示例

我正在通過手動繪製人臉,選擇是否快樂或難過,並將訓練樣本送入神經網絡來逐步訓練神經網絡。另外,當我繪製時,程序會動態顯示NN輸出。

問題是,只要我連續添加一堆快樂的面孔,「happy」的輸出就會提高到接近1.但是,如果我開始添加悲傷面孔,輸出會變爲happy = 0.0241 ... sad = 0.9988 ...

有時,兩個輸出都會上升到接近1(happy = 0.99/sad = 0.99)。

看來它應該以這種方式工作,但爲了測試神經網絡,我開始在畫布的上半部分繪製HAPPY面部,並在下半部分繪製SAD面部。同樣的事情發生了(輸出傾向於最新的樣本),但是我增加了50個訓練樣例,輸出似乎不會對上/下半部分的繪畫做出反應。

我不明白,如果我正確地構建NN或正確提供數據(它只是一個400(或0.01(白色)或0.99(黑色)大小的數組)。

如何防止此行爲?

神經網絡類:

import scipy.special 
import numpy 
class NeuralNetwork: 
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): 
    # set number of nodes in each input, hidden, output layer 
    self.inodes = inputnodes 
    self.hnodes = hiddennodes 
    self.onodes = outputnodes 

    # learning rate 
    self.lr = learningrate 

    # activation function 
    self.activation_function = lambda x: scipy.special.expit(x) 

    # link weight matrices, wih and who 
    self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes)) 
    self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes)) 

    pass 

# train the neural network 
def train(self, inputs_list, targets_list): 
    # convert inputs list to 2d array 
    inputs = numpy.array(inputs_list, ndmin=2).T 
    targets = numpy.array(targets_list, ndmin=2).T 

    # calculate signals into hidden layer 
    hidden_inputs = numpy.dot(self.wih, inputs) 
    # calculate the signals emerging from hidden layer 
    hidden_outputs = self.activation_function(hidden_inputs) 

    # calculate signals into final output layer 
    final_inputs = numpy.dot(self.who, hidden_outputs) 
    # calculate signals emerging from final output layer 
    final_outputs = self.activation_function(final_inputs) 

    # error is the (target - actual) 
    output_errors = targets - final_outputs 

    # hidden layer error is the output_errors, split by weights, recombined at hidden nodes 
    hidden_errors = numpy.dot(self.who.T, output_errors) 

    # update the weights for the links between the hidden and output layers 
    self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), 
            numpy.transpose(hidden_outputs)) 

    # update the weights for the links between the input and hidden layers 
    self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), 
            numpy.transpose(inputs)) 

    pass 

def query(self, inputs_list): 
    # convert inputs list to 2d array 
    inputs = numpy.array(inputs_list, ndmin=2).T 

    # calculate signals into hidden layer 
    hidden_inputs = numpy.dot(self.wih, inputs) 

    # calculate the signals emerging from the hidden layer 
    hidden_outputs = self.activation_function(hidden_inputs) 

    # calculate signals into final output layer 
    final_inputs = numpy.dot(self.who, hidden_outputs) 
    # calculate the signals emerging from final output layer 
    final_outputs = self.activation_function(final_inputs) 
    return final_outputs 

主要代碼:

from tkinter import * 
import numpy 
# scipy.special for the sigmoid function expit() 
import scipy.special 
# library for plotting arrays 
import matplotlib.pyplot 
from nn import * 

root = Tk() 
frame = Frame(root) 

w = Canvas(frame, width=400, height=400, background="green") 
w.pack() 

canvasRectangles = [] 

for i in range(20): 
    ls = [] 
    for k in range(20): 
     x = 20*i 
     y = 20*k 
     ls.append(w.create_rectangle(x,y,x+20,y+20,fill="white")) 
    canvasRectangles.append(ls) 

label = Label(frame,text='Number pressed: N/A') 
label.pack() 

hdnLayer1Label = Label(frame,text="Hidden Layer 1",justify=LEFT,wraplength=300) 
hdnLayer1Label.pack() 

outLayerLabel = Label(frame,text="Output Layer",justify=LEFT,wraplength=300) 
outLayerLabel.pack() 


def clearCanvas(): 
    for i in range(20): 
      for k in range(20): 
       w.itemconfig(canvasRectangles[i][k],fill="white") 


def key(event): 
    if event.char is 'r': 
     clearCanvas() 
    else: 
     if event.char is '1': 
      label.config(text="SMILE: Happy") 
     if event.char is '2': 
      label.config(text="SMILE: Sad") 
     global number 
     number = event.char 


def initNN(): 

    input_nodes = 400 
    hidden_nodes = 100 
    output_nodes = 2 
    learning_rate = 0.3 

    global n 
    n = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate) 


def queryNN(rectangles): 
    unscaledInputs = getRectangleValues(rectangles) 
    arr = numpy.array(unscaledInputs) 
    scaledInputs = scaleInputs(arr) 

    res = n.query(scaledInputs) 
    return res 


def trainNN(rectangles, desiredOuts): 
    inputs = getRectangleValues(rectangles) 
    arr = numpy.array(inputs) 
    # Scale the inputs 
    scaledInputs = scaleInputs(arr) 
    global n 
    n.train(scaledInputs, desiredOuts) 
    pass 


def getRectangleValues(rectangles): 
    rectvals = [] 
    for col in range(20): 
     for row in range(20): 
      if w.itemcget(rectangles[col][row], "fill") == "black": 
       rectvals.append(0) 
      else: 
       rectvals.append(1) 
    return rectvals 




def tab(event): 

    desiredOuts = [0, 0] 

    if number is '1': 
     desiredOuts[0] = 1 
     print("desiredSmile= HAPPY") 
    if number is '2': 
     desiredOuts[1] = 1 
     print("desiredSmile= SAD") 

    print(desiredOuts) 
    trainNN(canvasRectangles, desiredOuts) 
    clearCanvas() 


def draw(event): 
    x = event.x 
    y = event.y 
    if x <= 400 and y <= 400 and x >= 0 and y >= 0: 
     squarex = int(translate(x, 0, 400, 0, 20)) 
     squarey = int(translate(y, 0, 400, 0, 20)) 
     if not squarex is 20 or not squarey is 20: 
      w.itemconfig(canvasRectangles[squarex][squarey], fill="black") 
      outLayerLabel.config(text="Output: " + repr(queryNN(canvasRectangles))) 


def translate(value, leftMin, leftMax, rightMin, rightMax): 
    # Figure out how 'wide' each range is 
    leftSpan = leftMax - leftMin 
    rightSpan = rightMax - rightMin 

    # Convert the left range into a 0-1 range (float) 
    valueScaled = float(value - leftMin)/float(leftSpan) 

    # Convert the 0-1 range into a value in the right range. 
    return rightMin + (valueScaled * rightSpan) 


def scaleInputs(unscaledins): 
    return (numpy.asfarray(unscaledins)/1.0 * 0.99) + 0.01 


initNN() 

w.bind("<Button-1>", draw) 
w.bind("<B1-Motion>", draw) 
frame.bind("1",key) 
frame.bind("2",key) 
frame.bind("r", key) 
frame.bind("<Tab>", tab) 

frame.pack() 
frame.focus_set() 


'root.after(0,doWork)' 
root.mainloop() 
+0

這與您昨天或前一天所做的問題有何不同?此外,修復縮進並放置完整的代碼(導入缺失) –

+1

爲什麼您關心網絡在學習階段的表現?訓練結束後,是否將面部分類錯誤? –

+0

@IgnacioVergaraKausel我提出了問題並離開了,所以我無法添加源代碼。 –

回答

0

如果其他人有類似的問題,我解決它通過降低屏幕的分辨率(20×20,從7×7到)。我想這樣的高分辨率需要更多的訓練樣本。 另外,我做了一個訓練集並重復了幾次(大約8個時代爲我完成了這個技巧)。

解決方案很簡單:如果您的輸入更復雜,則需要更多的培訓。

相關問題