草庐IT

python - 修改神经网络对单个示例进行分类

coder 2023-08-24 原文

这是我对深度学习类(class)中 Andrew NG 的神经网络之一的自定义扩展,我正在尝试为二进制分类生成 0 或 1,而不是生成 0 或 1
对多个示例进行分类。

输入和输出都是一种热编码。

在没有太多训练的情况下,我的准确度为 'train accuracy: 67.51658067499625 %'
如何对单个训练示例进行分类而不是对所有训练示例进行分类?

我认为我的实现中存在一个错误,因为该网络的一个问题是训练示例 (train_set_x) 和输出值 (train_set_y) 都需要具有相同的维度,否则会收到与矩阵维度相关的错误。
例如使用:

train_set_x = np.array([
    [1,1,1,1],[0,1,1,1],[0,0,1,1]
])

train_set_y = np.array([
    [1,1,1],[1,1,0],[1,1,1]
])

返回错误:
ValueError                                Traceback (most recent call last)
<ipython-input-11-0d356e8d66f3> in <module>()
     27 print(A)
     28 
---> 29 np.multiply(train_set_y,A)
     30 
     31 def initialize_with_zeros(numberOfTrainingExamples):

ValueError:操作数无法与形状一起广播 (3,3) (1,4)

网络代码:
import numpy as np
import matplotlib.pyplot as plt
import h5py
import scipy
from scipy import ndimage
import pandas as pd
%matplotlib inline

train_set_x = np.array([
    [1,1,1,1],[0,1,1,1],[0,0,1,1]
])

train_set_y = np.array([
    [1,1,1,0],[1,1,0,0],[1,1,1,1]
])

numberOfFeatures = 4
numberOfTrainingExamples = 3

def sigmoid(z):
    s = 1 / (1 + np.exp(-z))  
    return s

w = np.zeros((numberOfTrainingExamples , 1))
b = 0
A = sigmoid(np.dot(w.T , train_set_x))    
print(A)

np.multiply(train_set_y,A)

def initialize_with_zeros(numberOfTrainingExamples):
    w = np.zeros((numberOfTrainingExamples , 1))
    b = 0
    return w, b

def propagate(w, b, X, Y):

    m = X.shape[1]

    A = sigmoid(np.dot(w.T , X) + b)    

    cost = -(1/m)*np.sum(np.multiply(Y,np.log(A)) + np.multiply((1-Y),np.log(1-A)), axis=1)

    dw =  ( 1 / m ) *   np.dot( X, ( A - Y ).T )    # consumes ( A - Y )
    db =  ( 1 / m ) *   np.sum( A - Y )    # consumes ( A - Y ) again

#     cost = np.squeeze(cost)

    grads = {"dw": dw,
             "db": db}

    return grads, cost

def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = True):

    costs = []

    for i in range(num_iterations):

        grads, cost = propagate(w, b, X, Y)

        dw = grads["dw"]
        db = grads["db"]

        w = w - (learning_rate * dw)
        b = b - (learning_rate * db)

        if i % 100 == 0:
            costs.append(cost)

        if print_cost and i % 10000 == 0:
            print(cost)

    params = {"w": w,
              "b": b}

    grads = {"dw": dw,
             "db": db}

    return params, grads, costs

def model(X_train, Y_train, num_iterations, learning_rate = 0.5, print_cost = False):

    w, b = initialize_with_zeros(numberOfTrainingExamples)

    parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost = True)
    w = parameters["w"]
    b = parameters["b"]
    Y_prediction_train = sigmoid(np.dot(w.T , X_train) + b) 

    print("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))

model(train_set_x, train_set_y, num_iterations = 20000, learning_rate = 0.0001, print_cost = True)

更新:此实现中存在一个错误,即训练示例对 (train_set_x , train_set_y)必须包含相同的维度。可以指出应该如何修改线性代数的方向吗?

更新2:

我修改了@Paul Panzer 的答案,使学习率为 0.001 并且 train_set_x 、 train_set_y 对是唯一的:
train_set_x = np.array([
    [1,1,1,1,1],[0,1,1,1,1],[0,0,1,1,0],[0,0,1,0,1]
])

train_set_y = np.array([
    [1,0,0],[0,0,1],[0,1,0],[1,0,1]
])

grads = model(train_set_x, train_set_y, num_iterations = 20000, learning_rate = 0.001, print_cost = True)

# To classify single training example : 

print(sigmoid(dw @ [0,0,1,1,0] + db))

此更新产生以下输出:
-2.09657359028
-3.94918577439
[[ 0.74043089  0.32851512  0.14776077  0.77970162]
 [ 0.04810012  0.08033521  0.72846174  0.1063849 ]
 [ 0.25956911  0.67148488  0.22029838  0.85223923]]
[[1 0 0 1]
 [0 0 1 0]
 [0 1 0 1]]
train accuracy: 79.84462279013312 %
[[ 0.51309252  0.48853845  0.50945862]
 [ 0.5110232   0.48646923  0.50738869]
 [ 0.51354109  0.48898712  0.50990734]]

print(sigmoid(dw @ [0,0,1,1,0] + db))产生一个曾经舍入匹配的向量 train_set_y对应值:[0,1,0] ?

修改以生成一个向量(将 [0,0,1,1,0] 添加到 numpy 数组并进行转置):
print(sigmoid(dw @ np.array([[0,0,1,1,0]]).T + db))

返回:
array([[ 0.51309252],
       [ 0.48646923],
       [ 0.50990734]])

同样,将这些值四舍五入到最接近的整数会产生向量 [1,0,1][0,1,0]是期待。

这些是为单个训练示例生成预测的错误操作?

最佳答案

您的困难来自不匹配的维度,所以让我们解决问题并尝试解决问题。

您的网络有许多输入和功能,让我们称其为 N_in ( numberOfFeatures 在您的代码中)。它有许多对应于不同类别的输出,我们称其为 N_out .输入和输出通过权重连接 w .

现在问题来了。连接是多对多的,所以我们需要为 N_out x N_in 中的每一个添加一个权重。成对的输出和输入。因此在您的代码中 w 的形状必须改为 (N_out, N_in) .您可能还需要一个偏移量 b对于每个输出,所以 b 应该是大小为 (N_out,) 的向量或者更确切地说 (N_out, 1)所以它适用于 2d 术语。

我已经在下面的修改后的代码中修复了这个问题,并试图让它变得非常明确。我还提出了一个模拟数据创建者的讨价还价。

关于 one-hot 编码的分类输出,我不是神经网络方面的专家,但我认为,大多数人都理解它,因此类是互斥的,因此模拟输出中的每个样本都应该有一个 1,其余的都是 0。

边注:

有一次,一个竞争性的答案建议您摆脱 1-...成本函数中的术语。虽然这对我来说似乎是一个有趣的想法,但我的直觉( 编辑 现在使用无梯度最小化器确认;在下面的代码中使用 activation="hybrid"。求解器将简单地最大化所有至少在一个训练示例。)它不会像那样工作,因为成本将无法惩罚误报(详细说明见下文)。为了使它工作,你必须添加某种正则化。一种似乎有效的方法是使用 softmax而不是 sigmoid . softmax是为了一热么sigmoid是二进制。它确保输出是“模糊一热”。

因此我的建议是:

  • 如果您想坚持使用 sigmoid并且没有明确强制执行 one-hot 预测。保留 1-...学期。
  • 如果要使用较短的成本函数。强制执行 One-hot 预测。例如使用 softmax而不是 sigmoid .

  • 我添加了一个 activation="sigmoid"|"softmax"|"hybrid"在模型之间切换的代码的参数。我还提供了 scipy 通用最小化器,当成本梯度不可用时,它可能很有用。

    回顾成本函数的工作原理:

    成本是该术语的所有类和所有训练样本的总和
    -y log (y') - (1-y) log (1-y')
    

    其中 y 是预期响应,即输入的“y”训练样本(“x”训练样本)给出的响应。 y' 是预测值,即具有当前权重和偏差的网络生成的响应。现在,因为预期响应是 0 或 1,所以可以写出单个类别和单个训练样本的成本
    -log (y')   if   y = 1
    -log(1-y')  if   y = 0
    

    因为在第一种情况下 (1-y) 为零,所以第二项消失,在第二种情况下 y 为零,所以第一项消失。
    现在人们可以说服自己成本很高,如果
  • 预期响应 y 为 1,网络预测 y' 接近于零
  • 预期响应 y 为 0,网络预测 y' 接近 1

  • 换句话说,成本在惩罚错误预测方面发挥了作用。现在,如果我们去掉第二项 (1-y) log (1-y')这个机制的一半消失了。如果预期响应为 1,低预测仍然会产生成本,但如果预期响应为 0,成本将为零,无论预测如何,特别是高预测(或误报)将不受惩罚。

    现在,因为总成本是所有训练样本的总和,所以存在三种可能性。
  • 所有训练样本都规定类别为零:
    那么成本将完全独立于该类的预测,并且无法进行学习
  • 一些训练样本将类归零,一些归一:
    然后因为“假阴性”或“未命中”仍然受到惩罚但假阳性不是网络将找到最小化成本的最简单方法,即不加选择地增加所有样本的类别预测
  • 所有训练样本都规定该类为一:
    与第二种情况基本相同,只是这里没有问题,因为这是正确的行为

  • 最后,如果我们使用 softmax 为什么它会起作用?而不是 sigmoid ?误报仍然是不可见的。现在很容易看出 softmax 的所有类的总和是 1。因此,如果至少减少另一类以进行补偿,我只能增加对一类的预测。特别是,没有假阴性就不可能有假阳性,而成本将检测到假阴性。

    关于如何获得二元预测:

    对于二元预期响应,四舍五入确实是适当的程序。对于 one-hot,我宁愿找到最大值,将其设置为 1,将所有其他值设置为零。我添加了一个方便的功能,predict ,实现。
    import numpy as np
    from scipy import optimize as opt
    from collections import namedtuple
    
    # First, a few structures to keep ourselves organized
    
    Problem_Size = namedtuple('Problem_Size', 'Out In Samples')
    Data = namedtuple('Data', 'Out In')
    Network = namedtuple('Network', 'w b activation cost gradient most_likely')
    
    def get_dims(Out, In, transpose=False):
        """extract dimensions and ensure everything is 2d
        return Data, Dims"""
        # gracefully acccept lists etc.
        Out, In = np.asanyarray(Out), np.asanyarray(In)
        if transpose:
            Out, In = Out.T, In.T
        # if it's a single sample make sure it's n x 1
        Out = Out[:, None] if len(Out.shape) == 1 else Out
        In = In[:, None] if len(In.shape) == 1 else In
        Dims = Problem_Size(Out.shape[0], *In.shape)
        if Dims.Samples != Out.shape[1]:
            raise ValueError("number of samples must be the same for Out and In")
        return Data(Out, In), Dims
    
    
    def sigmoid(z):
        s = 1 / (1 + np.exp(-z))  
        return s
    
    def sig_cost(Net, data):
        A = process(data.In, Net)
        logA = np.log(A)
        return -(data.Out * logA + (1-data.Out) * (1-logA)).sum(axis=0).mean()
    
    def sig_grad (Net, Dims, data):
        A = process(data.In, Net)
        return dict(dw =  (A - data.Out) @ data.In.T / Dims.Samples,
                    db =  (A - data.Out).mean(axis=1, keepdims=True))
    
    def sig_ml(z):
        return np.round(z).astype(int)
    
    def sof_ml(z):
        hot = np.argmax(z, axis=0)
        z = np.zeros(z.shape, dtype=int)
        z[hot, np.arange(len(hot))] = 1
        return z
    
    def softmax(z):
        z = z - z.max(axis=0, keepdims=True)
        z = np.exp(z)
        return z / z.sum(axis=0, keepdims=True)
    
    def sof_cost(Net, data):
        A = process(data.In, Net)
        logA = np.log(A)
        return -(data.Out * logA).sum(axis=0).mean()
    
    sof_grad = sig_grad
    
    def get_net(Dims, activation='softmax'):
        activation, cost, gradient, ml = {
            'sigmoid': (sigmoid, sig_cost, sig_grad, sig_ml),
            'softmax': (softmax, sof_cost, sof_grad, sof_ml),
            'hybrid': (sigmoid, sof_cost, None, sig_ml)}[activation]
        return Network(w=np.zeros((Dims.Out, Dims.In)),
                       b=np.zeros((Dims.Out, 1)),
                       activation=activation, cost=cost, gradient=gradient,
                       most_likely=ml)
    
    def process(In, Net):
        return Net.activation(Net.w @ In + Net.b)
    
    def propagate(data, Dims, Net):
        return Net.gradient(Net, Dims, data), Net.cost(Net, data)
    
    def optimize_no_grad(Net, Dims, data):
        def f(x):
            Net.w[...] = x[:Net.w.size].reshape(Net.w.shape)
            Net.b[...] = x[Net.w.size:].reshape(Net.b.shape)
            return Net.cost(Net, data)
        x = np.r_[Net.w.ravel(), Net.b.ravel()]
        res = opt.minimize(f, x, options=dict(maxiter=10000)).x
        Net.w[...] = res[:Net.w.size].reshape(Net.w.shape)
        Net.b[...] = res[Net.w.size:].reshape(Net.b.shape)
    
    def optimize(Net, Dims, data, num_iterations, learning_rate, print_cost = True):
    
        w, b = Net.w, Net.b
        costs = []
    
        for i in range(num_iterations):
    
            grads, cost = propagate(data, Dims, Net)
    
            dw = grads["dw"]
            db = grads["db"]
    
            w -= learning_rate * dw
            b -= learning_rate * db
    
            if i % 100 == 0:
                costs.append(cost)
    
            if print_cost and i % 10000 == 0:
                print(cost)
    
        return grads, costs
    
    def model(X_train, Y_train, num_iterations, learning_rate = 0.5, print_cost = False, activation='sigmoid'):
    
        data, Dims = get_dims(Y_train, X_train, transpose=True)
        Net = get_net(Dims, activation)
    
        if Net.gradient is None:
            optimize_no_grad(Net, Dims, data)
        else:
            grads, costs = optimize(Net, Dims, data, num_iterations, learning_rate, print_cost = True)
    
        Y_prediction_train = process(data.In, Net)
    
        print(Y_prediction_train)
        print(data.Out)
        print(Y_prediction_train.sum(axis=0))
        print("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - data.Out)) * 100))
        return Net
    
    def predict(In, Net, probability=False):
        In = np.asanyarray(In)
        is1d = In.ndim == 1
        if is1d:
            In = In.reshape(-1, 1)
        Out = process(In, Net)
        if not probability:
            Out = Net.most_likely(Out)
        if is1d:
            Out = Out.reshape(-1)
        return Out
    
    def create_data(Dims):
        Out = np.zeros((Dims.Out, Dims.Samples), dtype=int)
        Out[np.random.randint(0, Dims.Out, (Dims.Samples,)), np.arange(Dims.Samples)] = 1
        In = np.random.randint(0, 2, (Dims.In, Dims.Samples))
        return Data(Out, In)
    
    train_set_x = np.array([
        [1,1,1,1,1],[0,1,1,1,1],[0,0,1,1,0],[0,0,1,0,1]
    ])
    
    train_set_y = np.array([
        [1,0,0],[1,0,0],[0,0,1],[0,0,1]
    ])
    
    Net1 = model(train_set_x, train_set_y, num_iterations = 20000, learning_rate = 0.001, print_cost = True, activation='sigmoid')
    
    Net2 = model(train_set_x, train_set_y, num_iterations = 20000, learning_rate = 0.001, print_cost = True, activation='softmax')
    
    Net3 = model(train_set_x, train_set_y, num_iterations = 20000, learning_rate = 0.001, print_cost = True, activation='hybrid')
    
    Dims = Problem_Size(8, 100, 50)
    data = create_data(Dims)
    model(data.In.T, data.Out.T, num_iterations = 40000, learning_rate = 0.001, print_cost = True, activation='softmax') 
    model(data.In.T, data.Out.T, num_iterations = 40000, learning_rate = 0.001, print_cost = True, activation='sigmoid') 
    

    关于python - 修改神经网络对单个示例进行分类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47308181/

    有关python - 修改神经网络对单个示例进行分类的更多相关文章

    1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

      在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

    4. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

      我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

    5. ruby - 如何进行排列以有效地定制输出 - 2

      这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

    6. ruby - 即使失败也继续进行多主机测试 - 2

      我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

    7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

      我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

    8. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

      这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

    9. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

      我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

    10. Python 相当于 Perl/Ruby ||= - 2

      这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

    随机推荐