NN输出倾向于最新的培训示例

时间:2017-08-17 09:57:17

标签: python neural-network

我正在努力让我的NN认出“快乐”和“悲伤”的面孔,用20x20画布手绘。我使用400个输入图层单元,100个隐藏图层单元和2个输出单元(快乐/悲伤)。隐藏和激活的激活功能输出层是sigmoid。

我正在逐步训练神经网络,手动绘制一张脸,选择它是快乐还是悲伤,并将训练样本喂给神经网络。此外,在我绘制时,程序会动态显示NN输出。

问题在于,只要我连续添加一堆快乐面孔,“快乐”的输出就会提升到接近1.然而,如果我开始添加悲伤的面孔,输出会变为happy = 0.0241 ......伤心= 0.9988 ......

有时候,两个输出都会上升到几乎一个(快乐= 0.99 /悲伤= 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()

1 个答案:

答案 0 :(得分:0)

如果其他人有类似的问题,我通过降低画布分辨率(从20x20到7x7)来解决它。我想这么高的分辨率需要更多的训练样本。 此外,我制作了一套训练集,并经过几次迭代(大约8个时期为我做了诀窍)。

解决方案很简单:如果您的输入更复杂,则需要更多培训。