德尔福 - 超出界限的列表索引(4)

时间:2015-08-19 21:59:46

标签: delphi runtime-error

我知道这个问题已被提出了一百万次,但是,我无法理解为什么这个代码会抛出错误,我已经找到了导致错误的罪魁祸首FOR循环,但是,我没有看到任何错误它

我收到错误 - “列出索引超出界限(4)”

function TNetwork.FeedForward(InputVals : array of Real) : Real;
var
  I : Integer;
begin

  for I := 0 to Length(InputVals)-1 do
  begin
    Input[I].Input(InputVals[I]);
  end;

  for I := 0 to Length(Hidden)-1 do
  begin
    Hidden[I].CalcOutput;
  end;

  Output.CalcOutput;

  Result := Output.GetOutput;
  end;

第二个For循环发生错误,这里是我设置隐藏数组大小的地方。

constructor TNetwork.Create(Inputs, HiddenTotal : Integer);
var
  C : TConnection;
  I, J : Integer;
begin
  LEARNING_CONSTANT := 0.5;

  SetLength(Input,Inputs+1);
  SetLength(Hidden,HiddenTotal+1);

所以,正如我所看到的,循环只执行了三次,那么它为什么要尝试索引第四个空格呢?没关系为什么,更重要的是,怎么样?

如果有人可以对事业有所了解,并且有可能解决问题,我将永远感激不尽

为了完成,这是完整的单位..

unit NeuralNetwork_u;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, Math;

type
  TConnection = Class;
  TNeuron = class(TObject)
  protected
    Output : Real;
    Connections : TList;
    isBias : Boolean;
  public
    Constructor Create; overload;
    Constructor Create(BiasValue : Integer); overload;
    procedure CalcOutput;
    procedure AddConnection( Con : TConnection );
    function GetOutput : Real;
    Function F( X : Real ) : Real;
  end;

  TConnection = class
  private
    nFrom, nTo : TNeuron;
    Weight : Real;
  public
    constructor Create(a , b : TNeuron) ; overload;
    constructor Create(a, b : TNeuron ; W : Real) ; overload;
    function GetFrom : TNeuron;
    function GetTo : TNeuron;
    function GetWeight : Real;
    procedure AdjustWeight(DeltaWeight : Real);
  end;


type TInputNeuron = class(TNeuron)
public
  procedure Input (D : Real);
end;

type THiddenNeuron = class(TNeuron)
private
public
end;

type TOutputNeuron = Class(TNeuron)
private
public
end;

type TNetwork = class(TObject)
private
  LEARNING_CONSTANT : Real;
public
  Input : array of TInputNeuron;
  Hidden : array of THiddenNeuron;
  Output : TOutputNeuron;

  constructor Create(Inputs,HiddenTotal : Integer);
  function FeedForward(InputVals : array of Real) : Real;
  function Train(Inputs : array of Real ; Answer : Real) : Real;
  function TrainOnFile(Epochs : Integer ; TrainingFile : String) : Real;
end;

implementation

constructor TNeuron.Create;
begin
  Output := 0;
  Connections := TList.Create;
  isBias := False;
end;

Constructor TNeuron.Create(BiasValue : Integer);
begin
  Output := BiasValue;
  Connections := TList.Create;
  isBias := True;
end;

procedure TNeuron.CalcOutput;
var
  Sum : Real;
  Bias : Real;
  C : TConnection ;
  NeuronFrom, NeuronTo : TNeuron;
  I : Integer;
begin
  if isBias then

  else
  begin
    Sum := 0;
    Bias := 0;
    for I := 0 to Connections.Count do
    begin
      C := Connections[I];
      NeuronFrom := C.GetFrom;
      NeuronTo := C.GetTo;
      if NeuronTo = self then
      begin
        if NeuronFrom.isBias then
        begin
          Bias := NeuronFrom.GetOutput * C.GetWeight;
        end
        else
        begin
          Sum := Sum + NeuronFrom.GetOutput * C.GetWeight;
        end;
      end;
    end;
    Output := F(Bias + Sum);
  end;  
end;

procedure TNeuron.AddConnection(Con : TConnection);
begin
  Connections.Add(Con) ;
end;

function TNeuron.GetOutput : Real;
begin
  Result := Output;
end;

function TNeuron.F( X : Real ) : Real;
begin
  Result := 1.0 /(1.0 + Exp(-X));
end;

procedure TInputNeuron.Input ( D : Real);
begin
  Output := D;
end;

constructor TConnection.Create(a, b : TNeuron);
begin
  nFrom := a;
  nTo := b;
  Weight := Random * 2 - 1;
end;

constructor TConnection.Create(a, b : TNeuron ; w : Real);
begin
  nFrom := a;
  nTo := b;
  Weight := w;
end;

function TConnection.GetFrom : TNeuron;
begin
  Result := nFrom;
end;

function TConnection.GetTo : TNeuron;
begin
  Result := nTo;
end;

function TConnection.GetWeight;
begin
  Result := Weight;
end;

procedure Tconnection.AdjustWeight(DeltaWeight : Real);
begin
  Weight := Weight + DeltaWeight;
end;

constructor TNetwork.Create(Inputs, HiddenTotal : Integer);
var
  C : TConnection;
  I, J : Integer;
begin
  LEARNING_CONSTANT := 0.5;

  SetLength(Input,Inputs+1);
  SetLength(Hidden,HiddenTotal+1);

  for I := 0 to Length(Input)-1 do
  begin
    Input[I] := TInputNeuron.Create;
  end;

  for I := 0 to Length(Hidden)-1 do
  begin
    Hidden[I] := THiddenNeuron.Create;
  end;

  Input[Length(Input)-1] := TInputNeuron.Create(1);
  Hidden[Length(Hidden)-1] := THiddenNeuron.Create(1);

  Output := TOutputNeuron.Create;

  for I := 0 to Length(Input)-1 do
  begin
    for J := 0 to Length(Hidden)-1 do
    begin
      C := TConnection.Create(Input[I],Hidden[J]);
      Input[I].AddConnection(C);
      Hidden[J].AddConnection(C);
    end;  
  end;

  for I := 0 to Length(Hidden)-1 do
  begin
    C := TConnection.Create(Hidden[I],Output);
    Hidden[I].AddConnection(C);
    Output.AddConnection(C);
  end;  
end;

function TNetwork.FeedForward(InputVals : array of Real) : Real;
var
  I : Integer;
begin
  for I := 0 to Length(InputVals)-1 do
  begin
    Input[I].Input(InputVals[I]);
  end;

  for I := 0 to Length(Hidden)-1 do
  begin
    Hidden[I].CalcOutput;
  end;

  Output.CalcOutput;

  Result := Output.GetOutput;
end;

function TNetwork.Train(Inputs : array of Real ; Answer : Real) : Real;
var
  rResult : Real;
  deltaOutput, rOutput, deltaWeight, Sum, deltaHidden : Real;
  Connections : TList;
  C : TConnection;
  Neuron : TNeuron;
  I, J : Integer;
begin
  rResult := FeedForward(Inputs);
  deltaOutput := rResult * (1 - rResult) * (Answer - rResult);
  Connections := Output.Connections;
  for I := 0 to Connections.Count do
  begin
    C := Connections[I];
    Neuron := C.GetFrom;
    rOutput := Neuron.Output;
    deltaWeight := rOutput * deltaOutput;
    C.AdjustWeight(LEARNING_CONSTANT * deltaWeight);
  end;

  for I := 0 to Length(Hidden) do
  begin
    Connections := Hidden[I].Connections;
    Sum := 0;
    for J := 0 to Connections.Count do
    begin
      C := Connections[J];
      if c.GetFrom = Hidden[I] then
      begin
        Sum := Sum + (C.GetWeight * deltaOutput);
      end;
    end;

    for J := 0 to Connections.Count do
    begin
      C := Connections[I];
      if C.GetTo = Hidden[I] then
      begin
        rOutput := Hidden[I].GetOutput;
        deltaHidden := rOutput * ( 1 - rOutput);
        deltaHidden := deltaHidden * Sum;
        Neuron := C.GetFrom;
        deltaWeight := Neuron.GetOutput * deltaHidden;
        C.AdjustWeight(LEARNING_CONSTANT * deltaWeight);
      end;
    end;
  end;
  Result := rResult;
end;

function TNetwork.TrainOnFile(Epochs : Integer ; TrainingFile : string) : Real;
var
  FileT : TStringList;
  Inputss : array of Real;
  Outputss : Real;
  I, C : Integer;
  sTemp : String;
  NumInputs, NumOutputs : Integer;
begin
  // Load File
  FileT := TStringList.Create;
  try
    FileT.LoadFromFile(TrainingFile);
  except
    raise Exception.Create('Training File Does Not Exist');
  end;

  for I := 0 to FileT.Count-1 do
  begin
    sTemp := FileT[I];
    if I = 0 then
    begin
      // get Configurators
      Delete(sTemp,1,Pos(' ',stemp));   // no Longer need training Set count
      NumInputs := StrToInt(Copy(sTemp,1,Pos(' ',sTemp)-1));
      Delete(sTemp,1,Pos(' ',sTemp));
      NumOutputs := StrToInt(Copy(sTemp,1,Length(sTemp)));
      SetLength(Inputss,NumInputs+1);
    end
    else
    begin
      for C := 0 to NumInputs-1 do
      begin
        Inputss[C] := StrToFloat(Copy(sTemp,1,Pos(' ',sTemp)-1));
        Delete(sTemp,1,Pos(' ',sTemp));
      end;
      Outputss := StrToFloat(Copy(sTemp,1,Length(sTemp)));

      Train(Inputss,Outputss);
    end;
  end;
end;

end.

2 个答案:

答案 0 :(得分:3)

for I := 0 to Connections.Count do

你在这里运行列表的末尾。有效索引为0Connections.Count-1,包括TList。你太过分了。

你反复犯这个错误。当然,你需要在任何地方修复它。

当您执行TStringListsuccess等集合类的越界访问时,通常会看到列表索引超出范围错误。

另一方面,除非启用了范围检查,否则数组边界错误是不可预测的。如果您这样做,并且您应该这样做,那么您会收到此类事件的运行时错误。您需要启用范围检查。

答案 1 :(得分:2)

对于@ David的回答,这是一个小补充,而不是替代。

特别是当涉及动态数组时,执行类似

的操作
  for I := 0 to Length(Hidden)-1 do
  begin
    Hidden[I].CalcOutput;
  end;

是一种过早优化,因为如果

发生异常
    Hidden[I].CalcOutput;

行,对于没有完全使用Delphi调试器的人来说,如何使用它以及异常消息实际指的是什么(这并不总是显而易见的)来判断是否可能并不容易在Hidden []数组的索引或在其Ith项上调用CalcOutput时会出现异常。因此,至少出于调试目的,做这样的事情会很有用:

var
  H :  THiddenNeuron; 
[...]
  for I := 0 to Length(Hidden) -1 do
  begin
    H := Hidden[I];
    H.CalcOutput;
  end;

然后很容易区分原始代码可能出错的两个可能位置。