-
Notifications
You must be signed in to change notification settings - Fork 1
Create a new README and patch bugs from rewrite #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
I still need to test the example and maybe polish documentation a bit before merging. |
Weird, I'm encountering a lot of bugs while testing with an example that don't appear in the actual unit tests. I'm not sure why this is. |
it seems to always hang after the first 2-3 generations. it happens in both crossover and division reproduction. |
printing from the |
So I've just stumbled into this crate, and I'm not even sure how you're getting past the first generation, I just get errors coming from here. I'll try to get it to work.
use std::ops::Deref;
use neat::*;
const TESTS: [(usize, usize, usize); 4] = [(0, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)];
const INPUTS: usize = 2;
const OUTPUTS: usize = 2;
#[derive(Clone, PartialEq, RandomlyMutable, DivisionReproduction)]
struct Agent {
net: NeuralNetwork<INPUTS, OUTPUTS>,
}
impl Prunable for Agent {}
impl GenerateRandom for Agent {
fn gen_random(rng: &mut impl rand::Rng) -> Self {
Self {
net: NeuralNetwork::new(MutationSettings::default(), rng),
}
}
}
impl Deref for Agent {
type Target = NeuralNetwork<INPUTS, OUTPUTS>;
fn deref(&self) -> &Self::Target {
&self.net
}
}
fn fitness(agent: &Agent) -> f32 {
let mut fit = 0.0;
for (a, b, c) in TESTS {
let prediction = agent.predict([a as f32, b as f32]);
let correct = max_index(prediction) == c;
fit += match correct {
true => 1.0,
false => -0.1,
}
}
fit
}
fn max_index<T>(v: T) -> usize
where
T: IntoIterator,
<T as IntoIterator>::Item: PartialOrd,
{
v.into_iter()
.enumerate()
.reduce(|(ai, av), (bi, bv)| match bv > av {
true => (bi, bv),
false => (ai, av),
})
.unwrap()
.0
}
fn main() {
let mut sim = GeneticSim::new(Vec::gen_random(1000), fitness, division_pruning_nextgen);
sim.next_generation();
} |
I have it patched already on a codespace, I just discovered more bugs so I didn't end up pushing. |
Alright, I'll just figure out the easiest way and stare at it more KEKW. Good job on (as far as I know) somehow the best documented ML crate by the way. |
I did end up discovering a bunch of cases within stuff like After patching like 3 of them and printing whenever a mutation occurs in a generation, it passes a lot more generations but eventually still hangs, even if there were no mutations occurring in the generation directly prior to the one where it hangs. I’ll probably push these patches either tonight or tomorrow morning (my weekdays are super busy and I mainly just work on this in study hall and downtime between classes) so you can take a look. |
oh wait I'm stupid this is literally the lock and I spent god knows how long doing nothing |
yeah spamming println everywhere typically works better than gdb in deadlock/livelock situations. i had to implement a rather complex task management system (and if i really want to make it more efficient i would have to fork rayon, which sounds awful to do) in order to handle joins properly without wasting a ton of cpu usage or spamming locks (which fully deadlock on all threads bc they stop the entire rayon thread while locking) and i have no idea if it actually works because my unit tests apparently just completely lied to me. i still have no clue how the unit tests manage to pass but not an example that does something pretty similar. |
For now, this seems to fix the lock without any immediately apparent downsides, I'm not sure if I'm missing something important here, but I'll roll with it. diff --git a/src/neuralnet.rs b/src/neuralnet.rs
index cce0d61..9e9ee3a 100644
--- a/src/neuralnet.rs
+++ b/src/neuralnet.rs
@@ -137,19 +139,17 @@ impl<const I: usize, const O: usize> NeuralNetwork<I, O> {
fn eval(&self, loc: impl AsRef<NeuronLocation>, cache: Arc<NeuralNetCache<I, O>>) {
let loc = loc.as_ref();
- if !cache.claim(loc) {
+ if !cache.is_ready(loc) && !cache.claim(loc) {
+ // two things can happen here:
+ // we're trying to get a neuron that's not ready, which
+ // seems to cause deadlocks every time
+ // or
// some other thread is already
// waiting to do this task, currently doing it, or done.
// no need to do it again.
return;
}
- while !cache.is_ready(loc) {
- // essentially spinlocks until the dependency tasks are complete,
- // while letting this thread do some work on random tasks.
- rayon::yield_now();
- }
-
let val = cache.get(loc);
let n = self.get_neuron(loc);
|
The cache by default is not ready, meaning that this code essentially just returns when it reaches the first hidden layer neuron. The Btw the reason this whole system is in place is because I can |
I pushed some of my patches if you want to take a look. I drastically reduced the size of the simulation in |
Oh wait maybe you are right. There's no point in a complex claiming and waiting system if I can just make it so the last task to reach the neuron runs on it and then cancel any other ones. Not sure how I didn't think of that. |
might want to add the tracing crate to this as a feature or something to help with debugging. i'll create a separate issue for it |
Without the Perhaps I have two |
Also probably going to branch out and implement #94 just so it's easier to debug this PR. |
oops for whatever reason my git is on a different branch but still pushed to here smh |
update tracing branch
Tracing Feature
Considering #83 to help even further with debugging. Tracing adds a lot of context but it's still pretty hard to visualize what's happening. Also it spams a ton of output. Would be better if I could dump all that info somewhere and then render/visualize it. |
The problem with doing any rendering stuff is that I do most of the work for this crate on a codespace, which can't render windows. Maybe I could output it to an image file, but then it's hard to really browse the spans and such. |
Working on a pretty major update for |
Actually since the changes are relatively small, I could probably just make another PR once this is merged. I'm kind of tired of doing everything in this one branch. It's been open for way too long. |
No description provided.