首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python ANN实现

Python ANN实现
EN

Code Review用户
提问于 2019-09-08 19:24:06
回答 1查看 125关注 0票数 -1

最近,我在网上了解了反向传播,并试图实现它。我还不确定我是否正确。我很困惑,很想再看一双关于这个代码的眼睛。请帮助我理解如何改进这一点,如果这是正确的。

Implementation

代码语言:javascript
复制
"""
Artificial Neural Network
"""

import numpy as np


def sigmoid(x, derivative=False):
    output = 1 / (1 + np.exp(-x))
    if derivative:
        return output * (1 - output)
    return output


def tanh(x, derivative=False):
    output = 2 * sigmoid(2 * x) - 1
    if derivative:
        return 1 - output ** 2
    return output


class Layer:
    def __init__(self, num_input, num_output, activation_fn=tanh):
        # num_rows = num_input, num_cols = num_output
        self.weights = activation_fn(np.random.rand(num_input, num_output))
        self.bias = activation_fn(np.random.rand(1, num_output))
        self.activation_fn = activation_fn
        self.raw = None
        self.activated = None
        self.input_data = None

    def __str__(self):
        return "Weights:\n" + str(self.weights) + "\nBias:\n" + str(self.bias)

    def output(self, x):
        self.input_data = x
        self.raw = np.dot(x, self.weights) + self.bias
        self.activated = self.activation_fn(self.raw)
        return self.activated

    def output_der(self):
        return self.activation_fn(self.activated, derivative=True)


class NeuralNetwork:
    def __init__(self, layers, eta=0.1):
        if len(layers) < 2:
            raise Exception("Layers needs to have input and output")
        self.layers = self.init_layers(layers)
        self.eta = eta

    def __str__(self):
        s = ""
        for i, l in enumerate(self.layers):
            s += "Layer {}.\n{}\n\n".format(i, str(l))
        s += "--------------"
        return s

    def init_layers(self, layers):
        ann = []
        i = 0
        while i < len(layers) - 1:
            ann.append(Layer(layers[i], layers[i + 1]))
            i += 1
        return ann

    def train(self, dataset, times=45):
        # item[0] = input
        # item[1] = label
        # backpropagation is an online algorithm (one example at a time)
        for i in range(times):
            error = 0
            output = 0
            for item in dataset:
                output = self.forward(np.array(item[0]))
                # loss_at_output_layer = -(label - output)
                self.backward(output - item[1])
                error += (item[1] - output) ** 2
            print(error)

    def hot_encode(self, output):
        top = max(output)
        for i in range(len(output)):
            output[i] = 0 if output[i] != top else 1
        return output

    def test(self, dataset):
        accuracy = 0
        for item in dataset:
            output = self.forward(np.array(item[0]))
            if np.array_equal(self.hot_encode(output[0]), item[1]):
                accuracy += 1
        print("Accuracy: {}\n".format(accuracy / len(dataset)))

    def forward(self, item):
        x = item
        for l in self.layers:
            x = l.output(x)
        return x

    def backward(self, loss):
        # delta_i = error * Δoutput_i
        deltas = []
        for l in reversed(self.layers):
            deltas.append(np.multiply(loss, l.output_der()))
            loss = np.dot(deltas[-1], l.weights.T)
            l.weights -= self.eta * np.multiply(deltas[-1], l.weights)
            l.bias -= self.eta * deltas[-1]

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

"""
Driver Code
"""

def normalize(data):
    return (2 * (data - min(data)) / (max(data) - min(data))) - 1


def get_dataset(filename):
    with open(filename, "r") as f:
        raw = {}
        for line in f:
            line_data = line.split(",")
            feature = normalize(np.array(list(map(float, line_data[:-1]))))
            if line_data[-1] in raw:
                raw[line_data[-1]].append(feature)
            else:
                raw[line_data[-1]] = [feature]
        hot_encoding = {}
        for i, label in enumerate(raw):
            hot_encoding[label] = np.zeros(len(raw))
            hot_encoding[label][i] = 1
        dataset = []
        for label in raw:
            for feature in raw[label]:
                dataset.append([feature, hot_encoding[label]])
        return dataset


if __name__ == "__main__":
    classifier = NeuralNetwork([4, 3], eta=0.01)
    print("{}\n".format(classifier))
    dataset = get_dataset("./iris.data")
    np.random.shuffle(dataset)
    print(dataset)
    split_ratio = int(2 * len(dataset) / 3)
    classifier.train(dataset[:split_ratio], times=50)
    classifier.test(dataset[split_ratio:])
    print("{}\n".format(classifier))

我正试图在虹膜数据集上测试它,但它并不收敛。我尝试了以下架构:

  • 4输入,3*3隐藏,3输出(热编码)
  • 4‘,3’,3 '‘
  • 4‘,5’,3 '‘

请帮助我识别如何改进算法、表示和代码质量。请让我知道如何改进这个问题,以帮助您更好地回答这个问题。非常感谢!

EN

回答 1

Code Review用户

发布于 2019-09-08 19:45:12

编码风格

首先,我不是代码审查员。不过,您的代码似乎没有问题。在编写Python脚本时,有一些基本的编码约定,比如变量命名、注释、docstring等等,我没有对它们进行讨论,因为我正在学习它,您可以找到它这里

Implementation

有几个基本的ANN不能正确地收敛,例如:

  • 首先,IRIS dataset是一个相当小的数据集;它通常使用大约70%的数据集进行培训(如果有监督的话)(这里就是这种情况),其余的数据集用于验证。
  • 我很难通过你的数学调试,但它可能是一个原因,数学可能有一些问题,网络不收敛。为了确保,您可以用一个非常简单的训练和测试数据集(比IRIS简单得多)一步一步地测试它(Neuron由Neuron可能,如果愿意的话),以查看是否可能存在一些bug。
  • 如果没有错误,则ANN的体系结构将影响其收敛性。我想你可能不需要三层隐层,一个有10到30个神经元的隐藏层可能对IRIS来说还行。有时,加入太多的神经元会使网络陷入数学局部极小的困境。您可能需要确保输入和输出层根据数据集具有正确的神经元数目。
  • 可能会有一些相关的教程来从头开始实现ANNs,查找它们不会是个坏主意。也许是一些有Neuron类的东西。

集成

您还可以应用一些已经内置的模块来执行此操作,例如在本例中使用KNN,我非常肯定您知道:

代码语言:javascript
复制
from sklearn import neighbors, datasets, preprocessing
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix

iris = datasets.load_iris() 
X, y = iris.data[:, :], iris.target

Xtrain, Xtest, y_train, y_test = train_test_split(X, y)
scaler = preprocessing.StandardScaler().fit(Xtrain)
Xtrain = scaler.transform(Xtrain)
Xtest = scaler.transform(Xtest)

knn = neighbors.KNeighborsClassifier(n_neighbors=4)
knn.fit(Xtrain, y_train)
y_pred = knn.predict(Xtest)

print(accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred))
print(confusion_matrix(y_test, y_pred))

输出

代码语言:javascript
复制
0.8947368421052632
              precision    recall  f1-score   support

           0       1.00      1.00      1.00        13
           1       0.79      0.92      0.85        12
           2       0.91      0.77      0.83        13

    accuracy                           0.89        38
   macro avg       0.90      0.90      0.89        38
weighted avg       0.90      0.89      0.89        38

[[13  0  0]
 [ 0 11  1]
 [ 0  3 10]]

总体

我认为你正试图从零开始实施ANN,这是很好的。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/227684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档