I haven’t had much time to write lately. Between consulting work and my master’s studies, spare time is scarce — which I think is understandable.
That said, I really enjoy it, despite how tiring it can be. I’ve learned (and keep learning) a lot from each course, so I already have mixed feelings about finishing the program next year.
Still, there’s no denying it’s a heavy workload. So, I thought I’d share a few pointers for anyone planning to take CS-6601: Artificial Intelligence at Georgia Tech.
The Course
This is the artificial intelligence course in the program. It covers most of the major topics in classical AI and ML, with a few “modern” ones like deep learning sprinkled in.
The material follows the structure of the Russell & Norvig textbook — the classic AI book — and supplements it with papers in the recommended readings section. (Seriously, read the papers. They’re important.)
I’ve been using an old copy of the Global Edition I bought a few years ago, and it works perfectly fine. A few chapters are rearranged, but the titles match, so it’s easy to find your way around.
To be honest, I haven’t bothered watching the lectures. Instead, I’ve focused on the book and the papers, and so far that’s worked very well. I had read the book before, so this time it’s more of a refresher — I keep it on my desk and flip through it whenever I need to look something up or clarify a concept.

Evaluation
About 60% of your final grade comes from six assignments. They’re heavy and time-consuming, but they’re also where you’ll learn the most. The topics are:
- A1: Search
- A2: Game Playing & Adversarial Search
- A3: Bayesian Networks
- A4: Decision Trees & Ensemble Learning
- A5: Gaussian Mixture Models
- A6: Hidden Markov Models
There’s also a midterm (15%) and a final exam (20%). Both are open-book and open-note, and you get a full week to complete them — but don’t be fooled, they’re still tough. You don’t want to wait until exam week to start learning the material.
The remaining 5% comes from short quizzes, which are fairly easy to score well on.
Additionally, there are 10 extra-credit quizzes worth up to 3% bonus on your final grade. The extra points aren’t huge, but they’re excellent practice for the exams, so they’re worth doing if you have time.
Difficulty
The midterm was manageable — a lot of work, but totally doable. I haven’t taken the final yet, but I expect it to be similar.
The assignments, however, are hard and require a lot of time (20–60 hours each). The difficulty isn’t evenly distributed either. So far (I’m still missing the last two), here’s how I’d rank them:
- A1: The toughest by far — feels like an initiation ritual for the course.
- A2: Third hardest — a breath of fresh air after A1.
- A3: Easiest — very guided and intuitive.
- A4: Second hardest — implementation was straightforward, but optimization took hours and multiple reworks.
- A5: ???
- A6: ???
Practical Advice
I’ve been trying to finish assignments early so that I can share a few tips on the course forum. Some classmates found them useful, so I’ll just respost them here. (You can’t share implementation details, of course, so most of my advice is about strategy and tooling.)
Also, they change the assignments each semester, so these may not be as helpful as I wish they could be. But still, the most important piece of advice for all of them is the same: Start early and use the book whenever you get stuck.
For Assignment 1
-
Learn to use the PyCharm debugger: It’s much easier to figure out what’s wrong with your code if you use the built-in debugging features of the IDE. Just put a few breakpoints and learn to walk through your code while inspecting the values of the most important variables, it will save you a bunch of time. If you are using classes to model your problem you can implement the repr method for each of them, this makes inspection easier. Way more effective than using print statements.
-
Get the warm-up exercises right and clean: The first four exercises are kind of easy, but it’s a good idea to spend time understanding all the intricacies of your solution, cleaning it up, and contrasting their mechanisms, it will be super helpful for the rest of the assignment.
-
Overwrite inputs: You can assign values to any input (goal, target, and so on) at the beginning of the method, this is very useful for debugging your programs.I found that test scenarios that involve t and n are especially useful for figuring out what’s wrong with your code. Update: There is no need to do this, Raymond pointed out that search_case_visualizer.py is a better solution for this precise problem. PD: Turns out I was a dummy and the TA’s already gave you a tool for doing this, but in a better way.
-
Execute by hand: Every single time I got stuck in this assignment, a solution was always reached by grabbing a piece of paper and walking through a test scenario by hand, and finally comparing the steps with the ones my program took. I cannot overstate how useful this process is.
-
The Pareto principle: It’s important to make good use of your time, so notice that you do not need to solve 100% of each exercise to get a good score. Try to score full marks for all the warm-up exercises (those are an important foundation for the last four programs), but be more flexible with the big exercises. Solving the problem for the last few corner cases can take hours of refining, so instead of waiting to get full marks on an exercise (let’s say you are already scoring >90% for bidirectional A*, which awards 26/29 points), do some work on the next problems. It’s much better to come back later to refine an imperfect solution than it is to reach the last day without having touched the tridirectional search problems.
For Assignment 2
Follow the implementation order given in the notebook: It feels tempting to jump straight into alpha-beta pruning and then using that on your min-max section, but it’s far easier to just add the pruning on top of a nice/clean min-max implementation.
-
A recursive implementation may be easier/cleaner: I did not try the alternative, but it turned out that implementing both techniques using recursion was quite easy and clean, I would rather try that before attempting an alternative route.
-
Iterative deepening is quite good: The stuff we learned about iterative-deepening search on the previous section of the course can be handy for this one. Depending on how good your custom evaluation function is, a solid implementation of ID is enough to get a perfect score.
-
There is some randomness in GS evaluation: So if your performance is close to the goal, you can just re-run the evaluation, it may get you over the threshold for full marks, just be mindful about execution limits on a given time window (like no more than 6 runs every 6 hours for 2c)
-
Get creative with evaluation functions: There are a lot of things you can try, and the Board class gives you access to a bunch of useful data. You can, for example, create a weight that controls how aggressive your strategy is by giving more importance to how many options you still have open, versus how much your move constraints the opponents next moves. You can also change the function’s behavior as the game progresses; you may want to prioritize different strategies at different stages of the game. You can get very, very creative with this part, just remember that you will be calling this function a lot, so it should be quick to compute.
-
Pay attention to time_left: You can ignore it and get full marks for parts a and b, but this one is important to take into account if you want to beat all part C bots, use it wisely!
-
Clean and easy to understand is important: Spending time making your design clean and easy to understand is crucial, you may end up spending some time doing hyper-parameter tuning for section C, and being able to quickly locate where to make the right set of changes will save you a lot of time.
For Assignment 3
-
Understand cardinality: The James Bond part of the assignment was quite straightforward, but I got stuck for a while because I did not get right away what they meant by cardinality, and understanding it is important for setting the right values of variable_card and evidence_card. I think native English speakers will not have the same problem I had, but it’s always worth pointing it out.
-
It is easier to calculate the game network values programmatically: For the James bond section, it is very easy to do it all by hand because you are dealing with binary states, but for the game board, because each attribute (skill level and outcome) can take more than two values, the process for calculating a reciprocal is a bit harder. I recommend setting by hand the values for the skill level nodes, but it would be a good idea to calculate the probabilities for the game outcome nodes’ TabularCPD with just a few lines of code, it turned out to be easy and the solution is quite clean.
-
On the sampler implementations: Contrary to what I was expecting, implementing the MH_sampler turned out to be easier than implementing the Gibbs sampler. The challenging part of the Gibbs implementation is keeping in mind all the right indices when accessing the probability tables, so I recommend writing in a piece of paper an example of the data structure for the probabilities of , say, the AvB outcomes, and using it as a guide when deciding which indices to use. The MH sampler is way simpler in this regard, so it gave me much less trouble.
-
One extra test: I felt very uncomfortable working on the sampler implementations without any test to verify whether I was doing a good job, but creating a skeleton for the compare_sampling method, and then a little test for running a comparison was very helpful in making me feel more reassured while I was developing the solution, so it may be also helpful for you to try this approach.
-
The toughest thing in this assignment, at least for me, is the knowledge that you have just 7 submissions, so there is little room for experimenting with different implementations. I would recommend creating a local test that lets you run the comparison method a few times and collect some statistical data about performance differences between the two samplers, as well as how close they are to the reference posterior. This will let you iterate quickly and set the right values for N, delta, and the number of burn_in iterations.
For Assignment 4
-
Implementation is easy, optimization is hard: I found this assignment to be very “on rails”, the instructions and implementations are quite straightforward, but most of the effort went into making changes to make the code run fast enough to pass Gradescope. Like always, it’s better to start with a clean, easy-to-understand solution and work from there.
-
Vectorize everything: I do not think it’s possible to pass this assignment without using vectorized operations whenever you can. On that note, I gave up on using Counter and just opted for using np.bincount, that saved me some time.
-
Learn to use the profiler: Pycharm comes bundled with a profiler, as do most other tools. In PyCharm, just go to decision_trees_submission_tests, right-clicked the test you want to run and then selected More Run/Debug, and then Profile ‘
', I don't think I would have been able to effectively optimize the solution without the help of the profiler, it was probably the most important tool in this assignment. -
Watch out for division by 0 errors: Mostly for the stats part of the assignment, there are some scenarios where they can happen.
-
Helpful optimizations: I know this is going to be very different for everyone, because all implementations will be very distinct, but for me the most dramatic changes in performance came from :
-
Vectorizing as much as I could, and using numpy functions whenever possible
-
Caching the results of some operations and then just computing updates/differences
-
Figuring out the two/three functions that consumed the most runtime and focusing on improving those
For Assignment 5
I don’t know, haven’t done it yet.
For Assignment 6
I don’t know, haven’t done it yet.
Worth It?
I’m really enjoying this course — it’s a strong contender for my favorite in the program (out of the eight I’ve completed so far). It demands attention and effort, but I don’t think I’ve learned as much from any other class. The TA’s are all very helpful and knowledgeable (some of the best in the program thus far), so you can always ask for help if you get stuck.
So yeah, I totally recommend it!
