首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用神经网络求解FizzBuzz

用神经网络求解FizzBuzz
EN

Code Review用户
提问于 2022-11-08 20:59:35
回答 1查看 69关注 0票数 2

我用C编写了一个非常简单的人工智能,并通过Rails将其连接到web。它学习了fizzbuzz问题。我写这篇文章是因为20年后我又回到了就业市场。当然,那个时候github根本不存在。所以,现在找工作的环境完全不同了,我没有招聘人员正在寻找的资产。所以我在求你帮忙。我要求对此进行代码审查,以及你们给我的任何建议。https://github.com/rickcockerham/fizzbuzz-ai谢谢,瑞克

代码语言:javascript
复制
// Fbai class.                                                                                                                                                                                                                                                                                                                                                             
// A C program that learns the Fizz Buzz problem.                                                                                                                                                                                                                                                                                                                          
// I used my neural network code that I downloaded years ago and modified.                                                                                                                                                                                                                                                                                                 
// I have simplified the neural network code to make it only has complicated as                                                                                                                                                                                                                                                                                            
// it needs to be to solve this simple problem.  One hidden layer and four separate                                                                                                                                                                                                                                                                                        
// networks is all it takes to solve the FB problem in 5-10 learning runs.                                                                                                                                                                                                                                                                                                 
//################################################################################                                                                                                                                                                                                                                                                                         

#include 
#include 
#include 

//nn constants                                                                                                                                                                                                                                                                                                                                                             
double Error, eta = 0.1; // a very slow learning rate                                                                                                                                                                                                                                                                                                                      
double alpha = 0.90, smallwt = 0.2;
#define PASSES 1 //passes per training run.                                                                                                                                                                                                                                                                                                                                
#define NUMPATTERNS 100 // 1-100                                                                                                                                                                                                                                                                                                                                           
#define NUMHIDDEN 1 // hidden layers                                                                                                                                                                                                                                                                                                                                       
#define NUMINPUTS 1 //number of inputs. In this case it's just a single integer.                                                                                                                                                                                                                                                                                           
#define NNS 4 // one neural network output per norm,fizz,buzz,fizzbuzz                                                                                                                                                                                                                                                                                                     
double expected[NNS][NUMPATTERNS+1]; //holds the test data.                                                                                                                                                                                                                                                                                                                

// The weights and outputs of the neural network.                                                                                                                                                                                                                                                                                                                          
double WeightIH[NNS][NUMINPUTS+1][NUMHIDDEN+1];//2. bias and input                                                                                                                                                                                                                                                                                                         
double WeightHO[NNS][NUMHIDDEN+1];
double SumH[NNS][NUMPATTERNS+1][NUMHIDDEN+1], Hidden[NNS][NUMPATTERNS+1][NUMHIDDEN+1];
double SumO[NNS][NUMPATTERNS+1], Output[NNS][NUMPATTERNS+1];
double DeltaO[NNS], SumDOW[NNS][NUMHIDDEN+1], DeltaH[NNS][NUMHIDDEN+1];
double DeltaWeightIH[NNS][NUMINPUTS+1][NUMHIDDEN+1], DeltaWeightHO[NNS][NUMHIDDEN+1];

// The names of each network.                                                                                                                                                                                                                                                                                                                                              
#define NORM 0
#define FIZZ 1
#define BUZZ 2
#define FIZZBUZZ 3

void train();
int gotest(int);
void init_ai();

//########################################                                                                                                                                                                                                                                                                                                                                 
//random double.  I would normally use lib sodium for better random.                                                                                                                                                                                                                                                                                                       
double randd() {
  return rand() / (double)RAND_MAX;
}

//################################################################################                                                                                                                                                                                                                                                                                         
// Ruby - C interface code.                                                                                                                                                                                                                                                                                                                                                
// These functions are exposed to Ruby.                                                                                                                                                                                                                                                                                                                                    

VALUE rb_fbai;

VALUE gotrain(VALUE self) {
  train();//run a single training epoch.                                                                                                                                                                                                                                                                                                                                   
  return self;
}

VALUE reinit(VALUE self) {
  init_ai();// clear the weights and start over.                                                                                                                                                                                                                                                                                                                           
  return self;
}

VALUE valueat(VALUE self, VALUE testnum) {
  int testx = NUM2INT(testnum); //convert VALUE to int                                                                                                                                                                                                                                                                                                                     

  int returnval = gotest(testx);// get the AI output for this int.                                                                                                                                                                                                                                                                                                         

  return INT2NUM(returnval);//convert it back to a VALUE                                                                                                                                                                                                                                                                                                                   
}

// define interface methods between Ruby and C                                                                                                                                                                                                                                                                                                                             
void Init_fbai() {
  rb_fbai = rb_define_class("Fbai", rb_cObject);
  rb_define_method(rb_fbai, "gotrain", gotrain, 0);
  rb_define_method(rb_fbai, "valueat", valueat, 1);
  rb_define_method(rb_fbai, "reinit", reinit, 0);

  init_ai();
}

//################################################################################                                                                                                                                                                                                                                                                                         
// the patterns are the training data.  It's an array of 3 values 0 if it's just x, 1 if it's %3, 2 if it's %5, and 3 if it's %3&%5                                                                                                                                                                                                                                        
// these are stored in three values for three sets of training patterns.                                                                                                                                                                                                                                                                                                   

void patterns() {

  memset(expected, 0.0, NNS * NUMPATTERNS+1); // all zeros first                                                                                                                                                                                                                                                                                                           

  for(int x = 1; x <= 100; x++) {

    if(x % 3 == 0 && x % 5 == 0) {
      expected[FIZZBUZZ][x] = 1.0; // set expexted[3][x] = 1.0 the rest are zeros.                                                                                                                                                                                                                                                                                         
    } else if(x % 5 == 0) {
      expected[BUZZ][x] = 1.0;
    } else if(x % 3 == 0) {
      expected[FIZZ][x] = 1.0;
    } else {
      expected[NORM][x] = 1.0;
    }
  }
}

//################################################################################                                                                                                                                                                                                                                                                                         
// clear all the weights and randomize them to learn the problem or learn it again.                                                                                                                                                                                                                                                                                        
void init_ai() {
  int nn,hid,i;

  ////////////////////////////////////////////////////////////////////////////////                                                                                                                                                                                                                                                                                         
  // init nn                                                                                                                                                                                                                                                                                                                                                               

  memset(Output, 0.0, NNS * (NUMPATTERNS+1)); // all zeros for outputs.                                                                                                                                                                                                                                                                                                    
  memset(Hidden, 0.0, NNS * (NUMPATTERNS+1) * (NUMHIDDEN+1));

  for(nn = 0; nn < NNS; nn++) { // loop through all neural nets                                                                                                                                                                                                                                                                                                            

    for( hid = 0 ; hid < NUMHIDDEN ; hid++ ) {    /* initialize WeightIH and DeltaWeightIH */
      for( i = 0; i <= 1; i++) {
        DeltaWeightIH[nn][i][hid] = 0.0 ;
        WeightIH[nn][i][hid] = 2.0 * ( randd() - 0.5 ) * smallwt ;
      }
    }
    /* initialize WeightHO and DeltaWeightHO */
    for( hid = 0 ; hid < NUMHIDDEN ; hid++ ) {
      DeltaWeightHO[nn][hid] = 0.0 ;
      WeightHO[nn][hid] = 2.0 * ( randd() - 0.5 ) * smallwt ;
    }

  }
  patterns();
}

//#############################################                                                                                                                                                                                                                                                                                                                            
// Returns -1 if the output is wrong otherwise it will return 0-3 as the output.                                                                                                                                                                                                                                                                                           
int gotest(int x) {
  double max = 0.0;
  int nn, maxx = 0;
  int correct = 0;
  for(nn = 0; nn < NNS; nn++) {
    if(Output[nn][x] > max) {
      max = Output[nn][x];
      maxx = nn;
      if(1.0 == expected[nn][x]) correct = 1;
    }
  }
  return (1 == correct ? maxx : -1);
}


//################################################################################                                                                                                                                                                                                                                                                                         
//################################################################################                                                                                                                                                                                                                                                                                         
//################################################################################                                                                                                                                                                                                                                                                                         
// training run for the AI.                                                                                                                                                                                                                                                                                                                                                
// This code was downloaded from the internet many years ago and modifed for my other AI project ai-stocktrading.com                                                                                                                                                                                                                                                       
// I've simplifed it for this small demo.                                                                                                                                                                                                                                                                                                                                  
void train() {

  int hid, nn, p, epoch;

  for(nn = 0; nn < NNS; nn++) { // loop through both neural nets                                                                                                                                                                                                                                                                                                           

    for( epoch = 0 ; epoch < PASSES ; epoch++) {
      Error = 0.0;

      for( p = 1 ; p < NUMPATTERNS+1 ; p++ ) {    /* repeat for all the training patterns */

        for( hid = 1 ; hid <= NUMHIDDEN ; hid++ ) {    /* compute hidden unit activations */
          SumH[nn][p][hid] = WeightIH[nn][0][hid] ;// bias against input 0                                                                                                                                                                                                                                                                                                 

          SumH[nn][p][hid] += expected[nn][p] * WeightIH[nn][1][hid]; //double np is the input 1-100                                                                                                                                                                                                                                                                       
          Hidden[nn][p][hid] = 1.0/(1.0 + exp(-SumH[nn][p][hid])) ;
        }


        /* compute output unit activations and errors */
        SumO[nn][p] = WeightHO[nn][0]; // bias                                                                                                                                                                                                                                                                                                                             
        for( hid = 1 ; hid <= NUMHIDDEN ; hid++ ) {
          SumO[nn][p] += Hidden[nn][p][hid] * WeightHO[nn][hid] ;
        }

        // Sigmoidal Outputs                                                                                                                                                                                                                                                                                                                                               
        Output[nn][p] = 1.0/(1.0 + exp(-SumO[nn][p]));

       //Sigmoidal Outputs, SSE                                                                                                                                                                                                                                                                                                                                           
        DeltaO[nn] = (expected[nn][p] - Output[nn][p]) * Output[nn][p] * (1.0 - Output[nn][p]) ;

        for( hid = 1 ; hid <= NUMHIDDEN ; hid++ ) {    /* 'back-propagate' errors to hidden layer */
          SumDOW[nn][hid] = WeightHO[nn][hid] * DeltaO[nn];
          DeltaH[nn][hid] = SumDOW[nn][hid] * Hidden[nn][p][hid] * (1.0 - Hidden[nn][p][hid]) ;
        }

        for( hid = 1; hid <= NUMHIDDEN ; hid++ ) {     /* update weights WeightIH */
          DeltaWeightIH[nn][0][hid] = eta * DeltaH[nn][hid] + alpha * DeltaWeightIH[nn][0][hid] ;
          WeightIH[nn][0][hid] += DeltaWeightIH[nn][0][hid] ;

          DeltaWeightIH[nn][1][hid] = eta * expected[nn][p] * DeltaH[nn][hid] + alpha * DeltaWeightIH[nn][1][hid];
          WeightIH[nn][1][hid] += DeltaWeightIH[nn][1][hid] ;
        }

        /* update weights WeightHO */
        DeltaWeightHO[nn][0] = eta * DeltaO[nn] + alpha * DeltaWeightHO[nn][0] ;
        WeightHO[nn][0] += DeltaWeightHO[nn][0] ;
        for( hid = 1 ; hid <= NUMHIDDEN ; hid++ ) {
          DeltaWeightHO[nn][hid] = eta * Hidden[nn][p][hid] * DeltaO[nn] + alpha * DeltaWeightHO[nn][hid] ;
          WeightHO[nn][hid] += DeltaWeightHO[nn][hid] ;
        }

      }//for num patterns                                                                                                                                                                                                                                                                                                                                                  

    } // for epochs                                                                                                                                                                                                                                                                                                                                                        

  }//for nns                                                                                                                                                                                                                                                                                                                                                               

}// train                                                                                                                                                                                                                                                                                                                                                                  

index_controller.rb

代码语言:javascript
复制
require 'fbai'

class IndexController < ApplicationController
  layout false

  # I need the AI to survive between calls to the testit function.                                                                                                                                                                                                                                                                                                         
  $ai = Fbai.new

  def index
    #reset the AI                                                                                                                                                                                                                                                                                                                                                          
    $ai.reinit();
  end

  # this will return a string of numbers and their value (x,fizz,buzz,fizzbuzz)                                                                                                                                                                                                                                                                                            
  def testit
    ret = '';

    for x in 1..100
      data = $ai.valueat(x).to_i
      ret << "#{x}="
      if(-1 == data)
        ret << '-err-'
      elsif(0 == data)
        ret << "#{x}"
      elsif(2 != data)
    ret << 'FIZZ'
      end
      if(1 < data)
    ret << 'BUZZ'
      end
      ret << " "
    end
    render html: ret, layout: false
  end

  # this tells the AI to do one training pass.  Then the testit function is called again to read the results.                                                                                                                                                                                                                                                              
  def trainmore
    $ai.gotrain()
    render plain: 'success'
  end

end

index.html.erb

代码语言:javascript
复制
    div {
        width:80px;
        height:30px;
        float:left;
        border:1px solid black;
        margin:1px;
    }
    .clearleft {
        width:0px;
        clear: left;
        border: none;
    }



    
    Neural Network leaning the FizzBuzz problem...
    Training run #0

    <% for x in 0..99
if x % 5 == 0 %>
    
    <% end %>
    <%=x%>
    <% end %>


<%= javascript_tag do %>

const donere = /err/;
var run = 0;

callnext_number();

const timeit = setInterval(callnext_number, 2000);

async function callnext_number() {
    var ret = '';
    promi = new Promise(fillin => {jQuery.ajax({
    url: "index/testit",
        type: "GET",
    success: function(data){
            var vals = data.split(' ');
            console.log(vals);
            for(let x = 1; x <= 100; x++) {
        let ans = vals[x-1].split('=');
        $('#val'+x).html(ans[1]);
        if(donere.exec(ans[1])) {
                    $('#val'+x).css("background-color","#ff3333");
        } else {
                    $('#val'+x).css("background-color","white");
        }
            }
            if(donere.exec(data)) {
        jQuery.ajax({url: "index/trainmore",type: "GET"});
            } else {
        clearInterval(timeit);
        alert('done');
            }
            $('#runnumber').html(++run);
    },
        error: function(data) {
            alert(data);
    }//return
    });
                                  }
               );
    await promi;

    return;
}//call next

<% end %>
EN

回答 1

Code Review用户

回答已采纳

发布于 2022-11-09 14:20:36

一般观测

我不能评论代码中的ruby部分,因为我不知道ruby。

C中没有类,但您可以使用结构来实现相同的目的。

尝试将行长度保持在100个字符以下,现在所有IDE都支持超过80个字符,但默认情况下并非所有IDE和编辑器都提供行换。

尽量将函数长度保持在一个屏幕上,那些大于这些功能的函数很难理解和维护。

避免全局变量

很难读、写、调试和维护使用全局变量的程序。程序中的任何函数都可以修改全局变量,因此需要在对代码进行更改之前对每个函数进行检查。在C和C++中,全局变量会影响命名空间,如果它们在多个文件中定义,它们可能导致链接错误。这个堆叠溢出问题的答案提供了更全面的解释。

还不清楚是否使用了全局变量Error,尽管它最终被分配到了void train()函数中。

如果Erroreta是真正的常量,那么现代C现在支持常量声明:

代码语言:javascript
复制
const double Error = 1;
const double eta = 0.1;

根据需要声明变量

在上世纪70年代和80年代C的原始版本中,变量必须声明在函数的顶部。现在情况不再是这样了,这是一种建议的编程实践,可以根据需要声明变量。在C语言中,该语言不提供变量的默认初始化,因此变量应该作为声明的一部分进行初始化。为了提高可读性和可维护性,每个变量都应该在自己的行上声明和初始化。

现代版本的C允许在循环中初始化循环变量:

代码语言:javascript
复制
void train() {
    size_t hid;

    for (size_t nn = 0; nn < NNS; nn++) { // loop through both neural nets
        for (size_t epoch = 0; epoch < PASSES; epoch++) {

            for (size_t p = 1; p < NUMPATTERNS + 1; p++) {    /* repeat for all the training patterns */

                for (hid = 1; hid <= NUMHIDDEN; hid++) {    /* compute hidden unit activations */
                    SumH[nn][p][hid] = WeightIH[nn][0][hid];// bias against input 0                                                                                                                                                                                                                                                                                                 

                    SumH[nn][p][hid] += expected[nn][p] * WeightIH[nn][1][hid]; //double np is the input 1-100                                                                                                                                                                                                                                                                       
                    Hidden[nn][p][hid] = 1.0 / (1.0 + exp(-SumH[nn][p][hid]));
                }

对于数组索引,

更喜欢size_t而不是int

对于索引数组,size_t类型比int更可取,它是一个无符号类型,因此它不会变成负值,它还将根据编译器和操作系统对最大可能的数组进行适当的大小调整( int或long)。在上面的本地声明示例中,size_t类型替代了int。

函数复杂度

void train()函数太复杂,可以分解成较小的函数,一个明显的例子是以下代码:

代码语言:javascript
复制
                SumO[nn][p] = WeightHO[nn][0]; // bias
                for (hid = 1; hid <= NUMHIDDEN; hid++) {
                    SumO[nn][p] += Hidden[nn][p][hid] * WeightHO[nn][hid];
                }

这里也有一个叫做单一责任原则的编程原则。单一责任原则指出:

每个模块、类或函数都应该对软件提供的功能的单个部分负责,而该责任应该完全由该模块、类或函数封装。

注释

对于块注释,我个人更喜欢原始的C风格评论:

代码语言:javascript
复制
/* Fbai class.
 * A C program that learns the Fizz Buzz problem.
 * I used my neural network code that I downloaded years ago and modified.
 * I have simplified the neural network code to make it only has complicated as
 * it needs to be to solve this simple problem.  One hidden layer and four separate
 * networks is all it takes to solve the FB problem in 5-10 learning runs.
 */

对于其他评论,我更喜欢更新的//注释样式。您所使用的样式是一致的,不要像在void train()函数中那样混合代码块中的类型。

不清楚为什么有3行代码分隔符注释:

代码语言:javascript
复制
//################################################################################
//################################################################################
//################################################################################
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

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

复制
相关文章

相似问题

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