I was following this example https://www.youtube.com/watch?v=cdUNkwXx-I4 & then when i went to test i keep getting this error, but in the code he used he didn’t add shape;
Right now I’m just trying to get 1 bird to think.
Uncaught Error: tensor2d() requires shape to be provided when `values` are a flat/TypedArray
at Object.Gte [as tensor2d] (tensor2d.js:61:11)
at nn.js:49:21
at engine.js:469:20
at e.value (engine.js:480:19)
at e.value (engine.js:467:17)
at Object.X5 [as tidy] (globals.js:192:17)
at NeuralNetwork.predict (nn.js:48:8)
at Bird.think (Bird.js:26:29)
at draw (FlappyBird.js:24:8)
at e.default.redraw (p5.min.js:2:529954)
here a link to code the video uses website-archive/Courses/natureofcode/11.3_neuroevolution_tfjs.js/nn.js at main · CodingTrain/website-archive · GitHub
Oh Yea, I’m trying to get 1 bird to think before adding mutate
flappybird.js
var bird;
var savedBird = [];
var pipe = [];
var sp = 200;
var mx = 50;
var pipeCount = 0;
function setup() {
createCanvas(600,500);
tf.setBackend('cpu');
bird = new Bird();
pipe.push(new Pipe(sp,mx));
}
function draw() {
background(0);
fill(255);
textSize(20);
text("PC: " + pipeCount, 20, 60);
text("PL: " + pipe.length, 20, 80);
bird.show();
bird.move();
bird.think();
for (var i = 0; i < pipe.length; i++){
pipe[i].show();
pipe[i].move();
if (pipe[i].destroy == true){
pipe.splice(i,1);
bird.score += 1;
}
}
if (pipeCount == 5){
pipeCount = 0;
mx += 10;
}
}
function keyPressed(){
if (keyCode == 38){bird.yspd = -1;}
if (keyCode == 40){bird.yspd = 1;}
}
bird.js
class Bird{
constructor(){
this.x = 32;
this.y = height/2;
this.yspd = 1;
this.w = 32;
this.score = 0;
this.brain = new NeuralNetwork(5,8,2);
}
dispose(){
this.brain.dispose();
}
mutate() {
this.brain.mutate(0.1);
}
think(){
let inputs = [];
inputs[0] = this.x;
inputs[1] = this.y;
inputs[2] = this.yspd;
inputs[3] = pipe[0].x;
inputs[4] = pipe[0].top - (pipe[0].w/2);
let output = this.brain.predict(this.inputs);
if (output[0] > output[1]){this.yspd = 1;}
if (output[0] < output[1]){this.yspd = -1;}
}
show(){
fill(255,255,0);
ellipse(this.x,this.y,this.w,this.w);
fill(255);
textSize(20);
text("S: " + this.score, 5, 20);
}
move(){
this.y += this.yspd;
if (this.y + (this.w/2) > height || this.y - (this.w/2) < 0){this.yspd = 0;}
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- PLEASE NO CHANGES BELOW THIS LINE (UNTIL I SAY SO) -->
<script language="javascript" type="text/javascript" src="libraries/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
<script language="javascript" type="text/javascript" src="Bird.js"></script>
<script language="javascript" type="text/javascript" src="GA.js"></script>
<script language="javascript" type="text/javascript" src="nn.js"></script>
<script language="javascript" type="text/javascript" src="pipe.js"></script>
<script language="javascript" type="text/javascript" src="FlappyBird.js"></script>
<!-- OK, YOU CAN MAKE CHANGES BELOW THIS LINE AGAIN -->
<style>
body {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
</body>
</html>
nn.js
class NeuralNetwork{
constructor(a,b,c){
if (a instanceof tf.Sequential){
this.model = a;
} else {
this.input_nodes = a;
this.hidden_nodes = b;
this.output_nodes = c;
this.model = this.createModel();
}
}
mutate(rate){
tf.tidy(() => {
const weights = this.model.getWeights();
const mutatedWeights = [];
for (let i = 0; i < weightslength; i++){
let tensor = weights[i];
let shape = weights[i].shape;
let values = tensor.dataSync().slice();
for (let j = 0; j < values.length; j++){
if (random(1) < rate){
let w = values[j];
values[j] = w + randomGaussian();
}
}
let newTensor = tf.tensor(values, shape);
mutatedWeights[i] = newTensor();
}
this.model.setWeights(mutatedWeights);
});
}// mutate
copy(){
return tf.tidy (() => {
const modelCopy = this.createModel();
const weights = this.model.getWeights();
const weightCopies = [];
for (var i = 0; i < weights.length; i++){
weightCopies[i] = weights[i].clone();
}
modelCopy.setWeights(weightCopies);
return new NeuralNetwork(modelCopy);
});
}
predict(inputs){
tf.tidy(() => {
const xs = tf.tensor2d([inputs]);
const ys = this.model.predict(xs);
});
}
dispose(){
this.model.dispose();
}
createModel(){
const model = tf.sequential();
const hidden = tf.layers.dense({
units: this.hidden_nodes,
inputShape: [this.input_nodes],
activation: 'sigmoid'
});
model.add(hidden);
const output = tf.layers.dense({
units: this.output_nodes,
activation: 'softmax'
});
model.add(output);
return model;
}// create
}
pipe.js
class Pipe{
constructor(s,m){
this.x = 550;
this.space = s;
this.top = round(random(20,height-(this.space+20)));
this.bottom = height - this.top - this.space;
this.w = 50;
this.destroy = false;
this.minx = m;
this.create = false;
pipeCount += 1;
this.xspd = 1;
}
show(){
fill(255);
rect(this.x,0,this.w,this.top);
rect(this.x,height - this.bottom,this.w,this.bottom);
}
move(){
this.x -= this.xspd;
if (this.x < -100){
this.destroy = true;
this.xspd = 0;
}
if (this.x < this.minx && this.create == false){
pipe.push(new Pipe(sp,mx));
this.create = true;
}
}// move
}