neural network there'll be just like a densely connected layer and so you need to flatten it


Deep Learning with Python, TensorFlow, and Keras tutorial

before that layer so it's it's it's used for more than than the input layer we're just gonna use it


for the input layer just make our lives easier so once we've got that that's our input layer now we


want to do our hidden layers again we're gonna go with I think just two hidden layers this isn't a


complex problem to solve so again we're gonna use the model set up model dot add syntax and we're


gonna add and in fact I think what I'm gonna do is just copy paste and then rather than a flatten


layer it's a dense layer in the dense layer we're gonna pass a couple parameters here so the first


one is gonna be how many units in the layer so we're gonna use 128 units or 128 neurons in the


layer then we're gonna pass the activation function this is like the function like I said like a


stepper function or a sigmoid function what is gonna make that neuron fire or sort of fire whatever


so we're gonna use TF to nn dot relu for rectified linear this is kind of the default go-to activation


function just use it as your default and then later you can tweak it to see if you can get better


results but it's a pretty good one to always fall back on so we're gonna add the second one just by


copying and pasting again I'm gonna add a final one and this is our output layer which is still


gonna be a dense layer it's not 128 your output layer will always if it's in the case of


classification anyways it'll have your number of classifications in our case that's 10 and the


activation function we don't want it to be relu because we actually this is like a probability


distribution so we want to use softmax for a probability distribution so that is our entire


model we're done with defining you know the the architecture I guess of our model now what we need


to define is some parameters for the training of the model so here we're going to say model dot


compile and in here we're gonna pass some we're gonna pass the optimizer that we want to use


we're gonna pass the loss metric which loss you don't know we haven't really talked about it loss


is the degree of error basically it's it's it's it's what you got wrong so a neural network doesn't


actually attempt to optimize for accuracy it doesn't try to maximize the accuracy it's always


trying to minimize loss so the way that you calculate loss can make a huge impact because


it's it's what's losses relationship to your to your accuracy opt timer opta optimizer okay so the


optimizer that we're going to use is going to be the atom optimizer you could use something this


is basically it's just your it's your it's the this is like the most complex part of the entire


neural network so if you're familiar with gradient descent you could pass something like stochastic


gradient descent but the atom optimizer kind of like the rectified linear is the you know just


kind of the default go-to optimizer you can use others there's lots of them not lots but I don't


know ten or so in Keras anyways so anyways there's other ones to go with Adam seems to be the one


that you should start with for loss again there's many ways to calculate loss probably the most


popular one is a categorical cross entropy or some version of that and that in this case we're


going to use sparse you could also use binary like in the case of cats vs. dogs you probably


use binary in that case but you could you could just kind of blanket categorical cross entropy


everything anyways then finally what are the metrics we want to track like as we go and we're


going to just do accuracy accuracy okay so once we have all this we're actually ready to to train


the model so to train it's just model that fit and then you're gonna pass your what do you want


to fit so X train X test I'm sorry why okay X train Y train and then epochs three total brain


for it okay let's go ahead and run that and we should start to get some training hopefully it


doesn't crash me as I'm recording but okay looks good let's zoom out just slightly so it looks a


little better and we can see actually our accuracy is away already quite well our loss is also still


dropping so our accuracy should still be improving and sure enough it is awesome okay so we did


pretty good we got a 97% accuracy after only three epochs which is pretty darn good so once


we have this we can this was in sample so this might this is always going to really excite you


but what's really important to remember is neural networks are great at bidding the question is did


they overfit so the idea or the hope is that your model actually generalized right it learned


patterns and actual attributes to the toe to what makes an eight and what makes a four rather than


memorizing every single sample you passed and you'd be surprised how easily a model can just


memorize all the samples that you passed to do very well so the next thing we want to always do


is calculate the validation loss in the validation accuracy and that is just model dot evaluate


evaluate X test Y test and then we'll go ahead and just print val loss and val accuracy and we can


see here the loss is almost point eleven and the accuracy is 96.5 so a little less than the one that


we ended on and the loss is quite a bit higher relatively but you should expect that you should


expect your out-of-sample accuracy to be slightly lower and your loss to be slightly higher what you


definitely don't want to see is either too close or it too much of a Delta if there's a huge Delta


chances are you probably already have over fit and you'd want to like kind of dial it back a little


bit so that's basically everything as far as the basics of Keros and all that the only other things


that I wouldn't mind covering here is like if you want to save a model and load a model it's just


model dot save and we can save this as epic num reader dot model and then if you want to reload


that model we'll save it as it will call the new underscore model that's going to be equal to TF dot


Keros dot models dot load model and it's this exact model name whoops there we go so that's our


new model and then finally if we wanted to make a prediction we could say predictions equals new


model dot predict and keep in mind predict always takes a list this will get you a few times for


sure but anyways they'll take a list and we'll do X underscore test and then if we just print


predictions it's probably not going to look too friendly it's a little messy so what's going on


here these are all one hot arrays and it's it these are our probability distributions so what


do we do with these so I'm going to use numpy you can also use TF dot arg max but it's an abstract


it's a tensor and we have to pull it down we need a session and all that it's just easier to import


numpy for at least for this tutorial here import numpy as NP and then print for example NP dot


arg max arg max let's do predictions and let's just do the zero with prediction okay it says


it's a seven so the prediction for X test zero like the zero with index is it's a seven so gee


if only we had a way to draw it okay we could definitely do this so we can do PLT dot M show


and we're gonna do X test zero with and then PLT dot show oh look at that it's a seven okay so I


think that's basically all the things I would want to show you guys as far as like just a quick and


you know quick start with deep learning and Python and Keras and TensorFlow this just barely scratches


the surface there's so many things for us to do I definitely plan to have at least one more follow-up


video covering things like loading and outside datasets and definitely some tensor board reading


the model understanding what's going on and also what's going wrong because that's eventually you


know it's really fun when we're doing tutorials and problems are like already solved and we know


the answer it's very exciting but in reality a lot of times you have to dig to find the model that


works with your data so anyways that's definitely something we have to cover or at least that you're


gonna have to learn somehow or other anyway that is all for now if you've got questions comments


concerns whatever feel free to leave them below definitely check out reddit.com slash r slash


machine learning the learn machine learning subreddit you can come join our discord if


you've got questions that's just discord dot GG slash syntax we'll get you there also a special


thanks to my most recent channel members Daniel Jeffrey KB Abhijit H nur Newcastle geek fuba 44


Jason and eight counts thank you guys so much for your support without you guys I couldn't do stuff


Efficient and Modular Implicit Differentiation (Machine Learning Research Paper Explained)

Hello, there. Today, we're going to look at efficient and modular implicit differentiation


by researchers of Google research. This paper on a high level extends what you know from


frameworks like TensorFlow or PyTorch or JAX in terms of automatic differentiation, it


extends it to multi level optimization procedures. So this paper makes it possible that you differentiate


through an inner optimization loop without having to unroll that inner optimization loop


and without having to implement the optimization procedure in a differentiable way. This has been


done before for single instances of problems, always with sort of specific derivations for


that particular problem. But this paper provides a unified framework of doing this. And so it's


a bit of a technical paper. And we won't go in this to technical mode, because I'm also not the


most or the biggest expert on the methods used here, I just wanted to raise a bit of awareness


that this exists, because the ability to back propagate through sort of inner optimization


procedures, and even like other things in a unified way, without having to unroll, I think it unlocks


a bunch of research that has been quite cumbersome so far, and could be interesting to a lot of


people, they do provide code and everything. And they prove or they show that many special instances


that have been derived in the past, and also a bunch of new ones, are just instances of their


framework and can be solved sometimes much more easily with their framework. They even provide


some approximation guarantees, and so on. I think interesting to us is just going to be


a little bit of the insight of why and how this works and the fact that it exists. So let's jump


in. The they say that automatic differentiation has revolutionized machine learning. It allows


expressing complex computations by composing elementary ones in creative ways, and removes


the burden of computing their derivatives by hand. This is absolutely true. If you look at old papers


in deep learning, half the paper would be spent on, you know, deriving the gradients of the


architecture that was just proposed, so you could actually implement it. And now we have autodiff,


which means that the frameworks, they simply do this by themselves, you just compose a bunch of


functions, and you call gradient on them. This is a big part of what has spurred the deep learning


revolution in the past few years, at least from a implementation point of view, right, I don't think


a lot of architectures would have happened if people always had to derive the gradients by hand.


And it's kind of obvious to do this, if you know the back prop algorithm, but still,


it is a big helper. Now, as I said, this paper, this paper exposes our sorry, this paper extends


the concept, the spirit of autodiff to a much larger class of applications. They say more


recently, differentiation of optimization problem solutions has attracted widespread attention


with applications such as optimization as a layer and in bi level problems such as hyperparameter


optimization and meta learning. So the key here is differentiation of optimization problem solutions.


So I have an inner optimization problem, and I obtain a solution. And I want to back propagate


through not only through the solution itself, but actually through the path that led me to finding


that solution. And meta learning is a good example, hyperparameter optimization, of course, as well.


So in meta learning, what you do, and this is a this is a simple thing, there are many


various tasks in meta learning. But I've done a video on one of those, which is called I MAML.


It's an extension of MAML. And I think the M stands for meta learning.


The I here for implicit, which is of course going to be related to the implicit differentiation,


we do right here, or implicit. The implicit here stands for the fact that we can implicitly


derive the gradient, we don't have to go through the whole unrolling. So in I MAML, there is a


setting where you have multiple tasks, you have a data set, and there is task one, task two,


task three. So maybe this is classifying food by taste, this is classifying food by calories,


this is classifying food by some other nutrient or color or something like this. Now, and this all


should happen with the same architecture of neural network simply, you know, solving different tasks.


So obviously, the different tasks are going to have different optima different local


optima. And from deep learning, of course, we know that these are never in the same place.


There are many local optima. But let's just pretend for a moment, we knew that these were the


three optima. The task of meta learning is can we find an initialization that is really good such


that if we fine tune on any of these tasks, if we if we get data from any of these tasks, we can


learn it really quickly. So if you know, you know, if you see here, if we choose this as an


initialization, it's going to take us a while to get to any of these solutions. However, if we


choose this as our initialization, we're here pretty quickly. And in fact, if a new tasks comes


that is similar to the other ones, let's say one here, right, that's kind of similar, it's on the


same hyperplane, whatnot, you can see that we're also there fairly quickly. So if we're going to


find the initialization, we're going to find it really quickly. So the question is, how do we


find the blue point? Obviously, we don't know where the green points are. And they're non


deterministic anyway. And the answer is, we start with anyone like this one, we start with a guess,


and we move point, you know, step by step into a better direction, just as we do with gradient


direction is, in order to know what a good direction is, we need to know how good is this


initialization. So consider this one, how good is this initialization? Well, in order to do that,


we actually need to do the optimization procedure. So we do that, and we see well,


that leads us in that direction, we optimize for a different task that leads us in that direction.


And now we get an idea that hey, maybe if all the tasks go into the same direction,


maybe, you know, it would be good if we also went into that direction. Specifically, what we want


is we want the gradient, the gradient with respect to our initialization of the solution


of a particular task, given that initialization, right? Now, these solution itself, of course,


is an optimization procedure. So you have an inner optimization procedure that you want to


back propagate through, what you usually have to do is you have to unroll that optimization


procedure. So if you think of gradient descent, so here is your weights. And what you do is you


subtract learning rate times the gradient. So here is it at step t, right? learning rate with respect


to the weights of f of x and w t. Okay, that's your standard gradient descent. So what does


that give you? All of that gives you w t plus one. And now you do another step of gradient descent,


okay, so minus again, gradient with respect to this, this, this, maybe it's a different data


point, maybe it's the same plus one. Okay, so it's, it already gets complicated, because now


this quantity here, which is all the quantity of above appears twice. Okay. And if you do another


step, of course, that quantity is going to replicate and be anywhere. And Autoday framework


can keep track of that. So if you do this, and you actually write down from your first thing,


you write down, you can unroll all of this into one big expression that gives you the end of the


optimization procedure, the end of gradient descent, given the beginning, you can do that.


And the TensorFlow or pytorch, they can keep track of this, it's just it's going to be a big


expression, it's going to be really, really slow. And further, what it needs, what you need to do is


you need to actually implement the gradient descent procedure as a differentiable procedure,


which is usually not done, usually in especially in TensorFlow and pytorch, the gradient descent,


the optimization procedures, they're sort of outside of the Autoday framework in JAX,


it's a bit different. But in in TensorFlow and pytorch, the optimization procedures for good


reason, they themselves aren't differentiable. So you'd have to reimplement them in a differentiable


way. All of that is fairly cumbersome. And people have asked themselves, can we do better,


especially in this technique called iMammal? People have found that instead of unrolling,


what we can do is if we regularize this objective in sort of a good way, so we add some sort of a


regularizer here, then we can calculate the gradient, this outer gradient without having to


go through the whole unrolling step. A similar situation you can imagine with hyper parameter


optimization, if you actually want to do gradient descent on your hyper parameter,


so you have some sort of a validation set, right? I want to minimize your loss, your validation


loss on your validation set, right of your, with respect to your hyper parameter lambda.


And the solution you find is you minimize with respect to the weights of your loss function on


the training set. This is all green and looks horrible. But okay, I think that's it. Okay,


so you want to, for, oh, we need a lambda, we need a lambda right here. Okay. So for a given,


for a given lambda, for a given hyper parameter, we want to find the best, the best weights, okay.


But then we want to find the best lambda such that the weights give us the best validation loss,


right? Such that the weights that came from the training data set give us the best validation loss.


We do this right now with grid search, but we could definitely imagine doing this with gradient


descent if we could get a gradient for that hyper parameter. But that requires us to back propagate


through this inner optimization procedure, through the actual learning of the neural network. Now,


given that neural networks usually train in thousands or millions of steps, unrolling that


is not going to be an option. Like TensorFlow is good, but it's not that good. Okay. So it can


technically keep track of it, but it's just not going to be possible. So for all of these problems


or for many of these problems, people have devised individual solutions like given very, very strict


requirements, given the exact problem formulations, we do have solutions where we don't have to unroll.


However, these are case by case and much like the old papers on neural networks where every time


you have to derive your gradient here, every one of these papers has to sort of derive how they


apply their conditions, how they do, how they apply the Karush-Kuhn-Tucker conditions in order to get


the implicit gradient and so on. And this here, this paper is what what auto diff is for these


old papers. So they go on. Yeah, they say involves case by case tedious mathematical derivations.


In this paper, we propose a unified, efficient and modular approach for implicit differentiation of


optimization problems. In our approach, the user defines in Python in the case of our implementation,


a function f capturing the optimality conditions of the problem to be differentiated. Once this is


done, we leverage auto def on f and implicit differentiation to automatically differentiate


the optimization problem. Okay, so what you do is you don't, you don't specify the gradient of the


optimization procedure. You specify a function that captures the optimality conditions of the


problem to be differentiated. And if that function here is differentiable, then this framework can


do its its magic to give you the gradient through the optimization procedure. So we shift away from


the optimization procedure itself having to be differentiable to only the specification of the


optimality conditions having to be differentiable, which is a huge gain, right? Yeah, so they say it


can, it can be this can be actually done in many ways, you can choose your solver and so on,


but we'll go through the through the very, very basics right here. Okay. This is ultimately what


is going to end up and this is a problem of, I think, hyper parameter optimization, as we saw.


So this is ridge regression. And ridge regression is a you have a data set, okay, you have labels.


So x is a is a is a matrix where each kind of row, I think is a column, I think row is a data


point and y is a vector of labels, numeric labels. And what you want to do is you want to find weights


w, such that w times x equals to y. That is linear regression, of course. Now in ridge regression,


you have a regularization on y, sorry, on w. So it's easier, you often to specify the loss. So


what you want is that this is small, but also that w has some small norm. And


they want this being small, and you want the norm of w also to be small. And this is a common


regularization technique to want the norm of w to be small, it sort of means that your line kind of


stays rather flat. So if you have a bunch of outliers, they won't affect your your


approximation too much. It's a very, it's a very common technique. The important part is there is


a hyper parameter right here. And this hyper parameter is a matter of choice. This is the


regularization constant. Now with this framework, we can run gradient descent on that hyper


parameter. And the way we have to do it is the following. So we start actually with down here.


So this called ridge solver, this is the inner optimization, this is the solver of the ridge


regression. Now ridge regression has a closed form solution, we can just solve, we can put this as a


linear problem. So here, you get x times x, and here we get x times y, and then you get yourself


a diagonal matrix that you can multiply with the regularization constant. And then you can simply


put up this linear system. So that's the linear system corresponds to x times x plus theta, well,


in this case, in our case, it was lambda, this should equal to x times y. So if you solve this,


then you'll get if you solve this, you get the what am I saying? Sorry, the linear system is going


to be this times w, if you solve this for w, you'll get the direct solution to rich regression.


There's no gradient descent here, but it will be totally cool if this contained gradient descent.


Okay, the next thing you'd have to do is you have to specify the optimality conditions. Now,


in this case, we're sort of going to repeat the loss function of ridge regression. So as you can


see here, the optimality conditions, of course, are dependent on x here and x is going to be x is


going to be the w actually, what we call w. And theta is your hyper parameter. So you can see,


this is just the loss here, you multiply w by x and subtract y. That's what's called the residual.


And this here is the the square norm of that. So in our loss function up here, we'd have sort of


square l two norms everywhere. And you can see here, this is the regularization. And the half


here is for easier differentiation. We don't have it. But doesn't matter. Okay, so this here is


simply the loss function of ridge regression, you can imagine more complicated things. Now, if I give


you the loss function, how do you what you need to give me is a function that is zero when


optimality is met. And now that's pretty easy. If I have a loss function, the gradient of that loss


function is exactly such a function, okay, the gradient of the loss function is zero whenever the


inner problem is optimal. So whenever the ridge regression is solved to optimality, the gradient


of this loss function is zero. Now we have all the ingredients. So what we can do now is we can use


their custom decorator right here to say that here is the optimality condition f is the optimality


condition on this inner optimization problem. And if you do this, then you can just back propagate


back propagate through that. So here you can see that you can take the Jacobian of the ridge


solver at here, this is lambda equals 10, for example. So you can simply take derivatives


through the inner optimization procedure, because you have supplied this without having to back


propagate through the inner procedure itself. Hope this was a little bit clear. So again,


you need to specify of course, the inner procedure, which is this thing here. In our meta learning


case, this would be the gradient descent, the inner gradient descent, you need to specify the


optimality conditions, which in the easy case is simply a loss function. And then the optimality


condition is the derivative of the gradient of the loss function. It's optimal whenever that is zero,


and you supply the optimality condition in the custom annotation to the function. And then you


can simply treat that inner function as if it were any other thing that you could back propagate


through. So cool, so cool. Okay, they go into the they go into the whole math behind this. And I


don't want to go too much into the math. But all of this essentially comes from the the implicit


function theorem. So if you have this optimality condition, you may have noticed it needs to be


zero at optimum. And this is what's called a root. And the root is specified like this. So


you have this inner function that depends on theta, and you have the optimality condition


that depends on the solution to the inner function. And it depends on the or can depend


on the parameter itself. If you have a construct like this, under some regularity conditions on f,


you can, the implicit function theorem tells you that, in essence, you can express the gradient


of these things with respect to each other. So from this, you can get the derivative of this inner


thing. You can get that locally, okay, without having to back propagate through the procedure


of how you found it. So right, it's so it's an implicit gradient, because it's it's defined


as a as implicitly as a function of the other argument right here.


If you look at this thing, and you take the total derivative of this right here, you can


use the chain rule to arrive at the expression down here. So if you derive the first argument


right here, you get the chain rule in in in theta, right? So you differentiate with respect to the


first argument. And then you also have to differentiate that first argument right here.


And then you differentiate with with respect to the second argument. And that is already theta,


of course. So now you can see we've ended up with only partial derivatives right here of simple


arguments. So we need three things. Ultimately, I see this is the thing we want the gradient


of the solution of the inner optimization procedure. Now, if we reorder a bit, you can


see the other things that we need for that is the number zero, that's easy. We need two derivatives


of F, both are just simple partial derivatives with respect to the arguments of F. And if F,


therefore, is differentiable, then we can get those things, right. And that's the exact shift


I talked about before. So instead of the optimization procedure having to be differentiable,


only the optimality condition now needs to be differentiable. And that's a much easier thing.


And again, we can use auto diff, we can use these frameworks for that. So as long as we can specify


F, in terms of somehow functions of the framework, we're good. The only so obviously, the this


function here is fully differentiable, because it's the loss of logistic regression. The only


tricky thing right here is that F, big F, capital F is actually the gradient of that function.


So what we need is the framework to be able to differentiate the gradient again, so to, to,


obviously, the gradient of the derivative of capital F would be the derivative of the derivative


of lowercase F. But usually frameworks can do this, right, and this loss function is certainly


differentiable twice. Alright, and then it's just a linear system, as you can see down here. So this,


this is what they call a, this is b, this is j. So what you have to do is you solve the linear


system, a x plus s or equals b, and then whatever comes out here, that's your gradient. And you can


use any classic sort of linear solver for that. So to repeat, you obtain a and b by using auto


def on the optimality conditions. And then you simply have to solve a linear system to get the


gradient of your solution of the inner optimization problem without ever having to unroll that inner


optimization procedure without having to back propagate through the steps of how you've,


how you arrived at that inner optimum. And that's the cool trick right here. So they can only do


this with a root, they can own, they can also do this with optimalities that are specified as fixed


points. So whenever the optimal solution to the inner problem has the property of being a fixed


point of some function, T can also use this method. So they I think they provide two different


decorators, one is custom root, and one is a custom fixed point. And from there you go.


So they discuss what they need, they discuss the technicalities, they actually don't ever need to,


they don't ever need to calculate these things fully, because they could become pretty big,


they actually only need to calculate Jacobian vector products and vector Jacobian products,


and they go into the technicalities here of how they obtain those. And the cool thing is that


this fully integrates with the auto def framework. So here they talk about pre processing and post


processing mappings. So you know, what if we don't need the solution of the inner problem itself?


What if we need a function of that and so on, this can all be taken care of by the audit


framework themselves, sorry, itself. They see our implementation is based on jacks.


And they say it's it enters the picture in at least two ways, we can lean heavily on jacks


within our implementation, and we integrate the differentiation routines introduced by our framework


into jacks is existing audit system. In doing the latter, we override jacks is default auto


def behavior, eg of differentiating transparently through an iterative solvers unrolled iterations.


So if you stick this in, you can just differentiate through these things as if they were


any other differentiable function in jacks. Very, very cool. So the last thing. So here are here are


all the different things that reduce to their method. If you actually, if you go and look,


they give a lot of different examples of what other techniques reduce to their methods,


especially specifically, you know, we've seen these simple optimization procedures, but you can


also do sort of proximal methods. In the inner optimization problem, you can do things like


projected gradient fixed point, which is maybe important for something like adversarial examples,


where you have to minimize a function, but at the same time, you have to stay within some convex set.


So you always back project onto that set. So now we can back propagate through the procedure of


finding an adversarial example. Very cool. And they even give bounds because you cannot ever


exactly calculate these things. So they give bounds on how far you're off. And lastly,


they do experiments. And these are just more examples. So their first experiment,


pretty straightforward hyper parameter optimization of multi class SVMs. So in a support vector machine,


you generally have a hyper parameter. And that hyper parameter here is sort of the strength of the


regularization, or like how much you trade off margin versus slack, I believe I've done SVMs in


a long time, especially multi class, yet you need to stay within, sorry, you need to maximize the


margin while staying within the probability simplex because it's multi class. So that's kind


of a constrained inner problem. But you would like to find the best hyper parameter for the tradeoff


parameter for the SVM with respect to an outer validation set. Okay, so, you know, that's, that's


a problem with two levels, and they can do it right here. They can do dictionary learning. So


in usually in dictionary learning, it's, it's not, you need to somehow obtain the dictionary,


and then you optimize using the dictionary. So in dictionary learning, you have a some sort of a data


point, maybe an image, and you map that into entries in a dictionary. And then you use those


entries to do something with it. And then you have some kind of a loss right here. However,


you can't optimize these functions that map and the dictionary itself at the same time,


it becomes unstable. So what people do is they do alternating or they have also they back propagate


through some inner thing, you know, in this thing, you can actually back propagate through


the inner thing through the inner problem, and find those dictionary elements as a function of


which dictionary elements would actually most optimally solve the outer problems. Lastly,


this is data set distillation. They want to find the optimal data set of size 10. Right, this is


the data set that so if give me one image per class, and if I train a neural network or whatever


on that class on that data set of 10 images, I want the best possible validation loss, okay. And


that is an optimization. So what you need to do is you need to start with 10 random images, you


train your classifier, you measure it on the on the validation set or whatever the test set. And


then you back propagate through the whole thing to update your data set itself. And in the end,


you end up with the optimal data set, you can see that this is also a two level optimization problem


with maybe some constraints right here. I think this is a very cool idea. Honestly, it's probably


it's probably I mean, it existed before, but you can now do this. And in last, they have these


molecular dynamics where they want to, to see if we change kind of the size of these molecules,


how do all of these things change. So on again, this reduces to quite complex. This is the inner


problem right here. But I think the point of all of this is that if you have a problem where it has


sort of an outer and inner optimization structure, and you want to use back propagation for the outer


problem through the inner problem, give this method a try. It's pretty cool. If you're interested in


the more technical aspect, give it a read. And that was it for me. I wish you a pleasant rest


Direct Feedback Alignment Scales to Modern Deep Learning Tasks and Architectures (Paper Explained)

Hi there. Today we'll look at Direct Feedback Alignment Scales to Modern Deep Learning Tasks


and Architectures by Giulia Loney, Jacopo Poli, Francois Boniface and Florian Crisakala.


So this paper on a high level, it replaces the backpropagation algorithm in deep learning


architectures with this algorithm called direct feedback alignment, which is more biologically


plausible. The algorithm has been around for a while, but it hasn't yet been shown to be


applicable to really modern big deep learning architectures and then perform on par with


backprop on modern deep learning tasks. This paper, as I understand it, is the first one


to demonstrate that it can do that. So this is very much an engineering paper, an applied


paper, and we're going to mostly go into direct feedback alignment as such. And I don't think


we're going to go too much into what the actual empirical findings are, because they even


though they're impressive, and it's a good piece of engineering, I think they can be


summarized pretty much by it, it works not yet on par with backpropagation, but into


a promising direction. Alright, as always, if you like content like this, consider sharing


it out and leaving a like and tell me in the comments what you like, of course, subscribe


if you aren't yet that that is, you know, essential. Otherwise, how are we going to


hear from me in the future? Okay, let's dive in. They say despite being the workhorse of


deep learning, the backpropagation algorithm is no panacea. It enforces sequential layer


updates thus preventing efficient parallelization of the training process. Furthermore, its


biological plausibility is being challenged. Alternative schemes have been devised yet


under the constraints of synaptic asymmetry. None have scaled to modern deep learning tasks


and architectures. Here we challenge this perspective and study the applicability of


direct feedback alignment to neural view synthesis, recommender systems, geometric learning and


natural language processing. In contrast with previous studies, limited to computer vision


tasks, our findings show that it successfully trains a large range of state of the art deep


learning architectures with performance close to fine tuned backpropagation. At variance


with common beliefs, our work supports that challenging tasks can be tackled in the absence


of weight transport. So there's a lot to unpack in this particular abstract right here. So


first of all, what's the problem with backpropagation? Backpropagation, they have they have two


quarrels right here. First of all, it's preventing efficient parallelization of the training


process. So what does that mean? So in backpropagation, I'm pretty sure you all know, it's basic backpropagation,


but you have an input to a neural network. And the neural network has a bunch of layers.


So the input will travel layer by layer. And at the end, you'll get some output and your


output y hat, let's call it here what the neural network thinks the let's say it's a


classifier thinks that the class of this particular x should be now in the data set, you have


your true label, and then you compare that to your output label, and you can compute


a loss function. Now, the whole question of the backpropagation algorithm is how do I


need to change my layers of the neural network in order to make the loss as small as possible.


And for that, you can use backpropagation, that means you can take that loss and you


can backpropagate it down the layers in order to update each layer individually. So the


first problem they have here with the backpropagation algorithm, and it's not, I mean, it's kind


of a secondary problem, but it is that is sequential. So in order to update this layer


right here, you need to have already back propagated to this layer, and then you need


to back propagate further to this and to this layer. So it's a sequential task, you need


to back propagate down the layers again, whereas what is more plausible, but what would be


more efficient if if we could somehow update all the layers in parallel, but this is a


minor quarrel. The bigger one is that backpropagation isn't biologically plausible. We know that


in real neurons, you have your your dendrites, your inputs, and you have your axon, and the


signal only travels in one direction, we don't know of a feedback mechanism in true neurons


in the brain that would allow for information sort of to flow in the opposite direction,


there is there is information flowing the opposite direction, but it's it's, I guess,


I think it's too slow. And it's so it's not really, it can't be, there's no analogous


way of backpropagation, there's no nothing in the brain that would take the role of the


backpropagation algorithm. Specifically, if each layer is characterized by a weight matrix,


right here, what backpropagation does is it uses the transpose of that weight matrix to


back propagate. So these, these arrows to the front, right here, they use the weight


matrices, and these arrows to the back, they use the transposes of the weight matrices.


So the transposes of the weight matrices, sort of relay the information of what needs


to change, that would be the loss, what needs to change to make the loss as small as possible,


they relay this information down to the other layers. And we don't know of any biological


analog, analogy to this mechanism right here, this transpose, it acts as sort of a layer


inverse. And that is called weight transport. So weight transport means that you can you


can do something like the transpose of the weights basically, to carry to bring information


from the next layer back to this layer. And in biology, we don't have this. And in direct


feedback alignment, we don't have this either. So direct feedback alignment, the next thing


here in this abstract is the algorithm that they are going to apply here, direct feedback


alignment, and we'll go into what it is, but it is more biologically plausible, in that


what it does is it takes the loss somehow, and it distributes it globally to all of these


layers like this. And it does so without requiring these transposes and also without requiring


these sequential steps. So both of their proposed problems here would be solved by this. They


say they say that in contrast with previous studies limited to computer vision tasks.


So what people have tried to do is they have tried to apply this DFA algorithm to computer


vision tasks. But in computer vision, most architectures are CNNs. And as I understand


it, as far as I understand it, DFA can only right now be applied to linear layers. So


something that is w x plus b, and then a non linearity. It cannot even though you can write


to CNN as like a linear layer with constraints. As I read this paper, I think to interpret


that you can only apply DFA to fully connected layers or things that look kind of like fully


connected layers. So what they're going to do in their experiments is they're going to


take these big architectures like transformers and replace parts of them with the parts that


act as fully connected layers with with DFA updates. So well, they're not going to replace


the layers, but they're going to replace the back propagation part of it with DFA updates.


It remains to say that they still use back propagation at some places where they can't


replace the updates with DFA. And that means where the layer isn't, you know, a fully connected


layer or I guess it's too big, they somehow have to make it work. So often they will not


update, for example, the embedding layers, and things like this. Okay, so what they're


saying is they go away from computer vision tasks. Because if you go to computer vision,


and CNNs rule that world, right, you can only do four feet forward layers, fully connected


layers, you're going to lose already. And so, yeah, it's kind of an unfair fight in


that in that sense. But even in absence of that, they say we apply this to neural view


synthesis recommender systems, geometric learning and natural language processing. So these


are quite diverse tasks. And they're going to be quite diverse architectures that they're


applying it to, for example, in geometric learning, I believe they do graph neural networks.


And there, there, they replace the, the usually in graph neural networks, there are fully


connected layers that connect the two the vertices and the edges together and compute


properties of them. So that's a pretty good point for using DFA, right? Because what you're


looking for is state of the art tasks and architectures that still employ fully connected


layers because there your algorithm can shine. Okay, so that's it. And they're basically


going to show that this is performance is close to fine tuned back propagation. Right.


So what is DFA? What is this direct feedback alignment? And for that, I actually want to


jump papers right here and go to this other paper that describes DFA in a bit in a bit,


not more detail, but in a graphic fashion. So this paper right here, direct feedback


alignment provides learning in deep neural networks by RL Nocklund, sorry, Nocklund shows


some theoretical properties about DFA. Now, I don't want to go into the theory right here


or in the math, but I mainly like this paper for this particular graphic right here. So


in the back propagation algorithm, as you can see, you forward propagate using these


weight matrices, and then you back propagate using the transposes of the weight matrices.


Now one step after that is this thing right here. It's called feedback alignment. It's


not the same thing as direct feedback alignment. In feedback alignment, you simply say, Well,


I won't back prop using these transposes because I can't because that's not biologically possible.


What I'll do is I'll use other matrices. And these other matrices are going to be random


matrices. And by random matrices, we really mean a matrix that is of you know, the correct


shape, the same shape as this W transpose. But each entry is going to be sampled from


a like a random Gaussian, right? Now, I don't mean like the distribution of Gaussians, but


you fix this matrix once at the beginning of training by sampling from Gaussian, and


then you leave it there. And that's going to be the matrix that you use for relaying


the signal back through the layers. Now, you might protest and say, wait, that's not going


to work. Because specifically, this thing right here, it you know that you need to know


the weights here to know what you need to change in the lower layers, you need to somehow


have that information in there, how are you going to know what to change? And that's a


valid question. And I will give my opinion of why this works. Okay. In a second in two


seconds. First, this is feedback alignment. So simply use random matrices to back propagate,


so to say, and then you have direct feedback alignment and direct feedback alignment goes


a step further. Because in feedback alignment, you still do this in a sequential manner.


Direct feedback alignment simply takes whatever the top change should be the change to the


top layer. So how do I need to change the top layer, and it back propagates that in


a this global fashion to all the layers directly using random matrices, okay. And then this


is IFA we're not going to look at today, because that's not relevant for this other paper.


But I hope you can sort of see the overview here. So let's go back. Scroll, scroll, scroll,


scroll, scroll, scroll, scroll. Okay, so here is the mathematical formulation of all of


this. And it pays to look at it to understand what's going on. So they characterize a neural


network right here as having n layers. Each neural network is the following each neural


each layer takes whatever is the output of the last layer, multiplies it by a weight


matrix. And that's going to be your a quantity, you put a through a non linearity to obtain


the next layers input. Okay, so the H is the output of this layer, and the input of the


next layer. At the very end, your last output is going to be your estimation of the labels.


So your last non linearity is probably going to be something like a, a softmax or something


like this. Okay. So how can we how can we have this as a concept in our heads? If you


have the neural network right here, what you want to do is you want to forward prop always


using your weight matrix w, and then your non linearity of that particular layer. And


then the last in the last layer, you get your y hat, as we saw before. Now the question


is, how can we adjust? How can we adjust this w right here to make y hat more into the direction


of y. And here it's in here, it's useful to think of the last layer as a vector output.


Like usually we think of the loss function. But in all of these algorithms, they always


start with the derivative of the loss function with respect to the last layer output, so


a y, and a y is here right before the non linearity. If you remember, this was f of


a y. And this here, I guess, is the softmax. So if this is a classifier, the a y here,


those are the lockets. And that's the output of your last layer. So it, instead of having


y and y hat, right, sorry, y hat right here, it pays to maybe think of the output as a


vector, and the desired output as another vector. And the desired output is of course


going to be one hot vector in the case of in the case of a classification. But it, you


know, if you think of it like this, then you will recognize, okay, I need to change if


this is my estimated output, and I want to achieve this output, I need to change it into


this direction, right to get more into the same direction as the output I want. The entire


question now becomes how do I tell the lower layers about this change right here? This


is the change that I want to make in the lower layers? How do I get the lower layers such


that they provide me with that signal with with the green signal instead of the red signal?


So I need to propagate this blue difference. In the back propagation algorithm, you can


simply ask the system, right? So we've built entire frameworks on being able to back propagate


TensorFlow, pytorch, jacks, whatever. Because with back propagation, we can simply ask the


system this question. So here is how should I change the weights of my layer to make the


loss smaller? You can just ask that you can say, what's the gradient of the loss with


respect to the to my weights, and the negative sign here is because you want to make the


loss smaller. Okay, and that is going to be a straightforward calculation. How does that


calculation go? It's going to involve this right here is the last layer's output. This


right here, as you can see, over here is going to be this is going to be whatever comes back


from the back propagation. So in back propagation, you always have to think of, if you want to


update these weights, you need two quantities, you need whatever comes from the bottom or


came from the bottom during the forward pass, and whatever comes from the top during the


backward pass. And this quantity here is going to be the one that came from the top. And


it's basically how you need to change the next layer in order to make the loss happier.


And by using this right here, you pull it back to this layer. So how do I need to change


this layer? And here you see that dreaded transpose of that weight matrix. This is what


we can't do in biology. But this is what back propagation does. So it pulls back how you


need to change the next layer, it pulls it back to this layer. So this quantity right


here is basically how do I need to change the output of this particular layer in order


to make the loss happier. And then you multiply it by the signal that comes from the bottom.


And that will give you how you need to change your weights. Okay. So the green part is how


does the output of the layer need to change and the multiplied by the blue part, it's


how do the weights need to change. And of course, the non linearity is in there as well.


But let's, let's just leave the non linearity away because it's really not important for


this particular thing. So this is what backprop does. What does DFA do? DFA here, again asks,


how should I change the weights of layer i and DFA says, Well, first, you need to compute


this thing right here. This is you see the derivative of the loss with respect to a y


now a y is the output of the last layer. These are in in our case, for example, your log


it's okay, note that this is still a gradient. So it's not like we can't differentiate anymore,


we simply can't do back propagation from layer to layer. Okay, so this is the quantity. How


do we need to change the last layer's output? And we're going to take that and simply feed


it through this random matrix, and then multiply again, let's leave this away, multiply it


by the by this thing right here. So if I get my colors correct, like this, again, you have


your neural network, you want to update these weights, the green is what comes from the


top. Now it doesn't come from the next layer, but the green actually comes from all the


way at the end. Sorry, you can't see that I still have to get used to that new frame


of view. So the green comes all the way from the end, and the blue comes from down here.


Okay, so this is weird, right? Because especially because this is just modulated by a random


matrix. So how can this possibly work? That's the question. And I, you know, I had some


thoughts, but I haven't read too much about it. So I might be completely wrong. Or this


might be completely known in the community. I have no idea. I'll just give my opinion


right here. So first of all, you have to see if to compare this to backprop. So what's


actually changing is this green part right here, right? We agree that this is the thing


that's changing. And what do we say, does the green part mean, the green part basically


tells you how do you how should the output of this layer change? Okay, by adjusting the


weights in the direction of the thing on the right side of the equality sign, you're going


to change the output of the layer into the direction of that green part. Now, in backpropagation,


the green part basically tells you how should the output of this layer change in order to


make the losses happy as possible. Now, we don't have that anymore. Here, we simply change


the output of the layer into the into the direction of a random transformation of the


of the change we would like to have in the output. Now, okay, that's the, the first thing


is we understand what's different. And we understand what the green quantity means.


Green quantity means how should the output of our layer change? Okay, second thing. If


you look at the last layer of a neural network that that logits layer, right, what does it


actually do? Let's say we have that's a three dimensional last layer, which means you have


three classes, right? If your last layer is three dimensional, you have three classes,


each axis represents one class because you encode the classes as one hot vectors. So


this might be C, the class label equals zero, this might be C equals one, this might be


C equals two. If you have something that you forward propagate through your neural network,


and let's say it comes out to be like this, what would you classify that as? Now you classify


that as the whatever class has the the biggest inner product with that vector, which would


be the C equals zero class right here. And what is this quantity going to be? How should


you update this output in order to make the loss happier? Now that depends on your true


label. But let's say your true label is actually the zero label. Now, what you want to do is


you want to update that thing into the direction here, right, such that it is more aligned


with the axis. So what happens if you pull that back through a random matrix? Now, the


thing you have to know about random matrices like this is that they do approximately preserve


distances and angles. So technically, if you pull this back, what you're going to induce


is another coordinate system in that other space. Now, this can be a higher or lower


dimensional space, I frankly, I don't care. But what you're going to induce is a coordinate


system. And what do you pull through that B matrix? So this is the bi matrix, you fix


it, right? This is really important, you fix it at the beginning of training, it's always


the same, it preserves distances and angles approximately, you pull back that quantity,


which is the okay, my colors are all screwed, which is the green arrow over here, you pull


back this green arrow here. So what does it mean? What so the output right here, the output


vector that came from the lower layers, right? That's the forward propagated that through


your network. So maybe in this layer, it actually pointed here, we don't know. But let's say


it pointed here. If we pull back the green thing, it might point here. Okay, now, this


is, since it's a random matrix, we don't know, we know that the angle is approximately preserved,


okay, but you know, the end the lengths are approximately preserved with relative to each


other. But it doesn't really tell you too much. So why is this useful? And to see why


it's useful, you need to consider other inputs, we don't just input this one vector, we input


a whole bunch of data. Now let's consider two other vectors. So first, I want to consider


this this blue vector right here. Now, the blue vector is also going to have a label


of zero. So what does the blue vectors update look like the blue vector is going to be pulled


into this direction. And I also want to consider this red vector right here, the red vector


is of class one. So what does the red vectors update going to look like, like this, right?


And if I consider now the red and the blue vector in this space, right, let's just draw


them at random, like so, okay, what I do know, actually, that's that's for consistent. Let's


draw the blue somewhere here, and the red somewhere here. What I do know is that the


angles and distances are preserved. So what is the green thing going to look like the


update for the blue vector is going to be something like this. And the update for the


red vector is going to maybe be something like this, you know, away from from those.


So what is happening in that lower space, you'll notice that the two vectors that are


supposed to be in the same class, this and this, they are going to be pulled together.


Now the direction they're pulled in, that's determined by this random matrix. But we know


they're going to be pulled together because they are pulled together in this space in


the final space. Okay, and they're going to be pulled apart from the red vector, okay,


because that red vector is going to be pulled towards a different class in the in the last


space. And since the distances and angles are approximately preserved, it's going to


be pulled away from these in this space. So what this induces, in my opinion, is some


sort of it induces this coordinate system where if you make the last layer axis aligned


because you want to classify it, it kind of clusters things that belong in the same class


in these previous weight spaces, right? And because and if you do this layer by layer,


so if you do this in layer k, and then you make the job easier for any layer k plus one


that's in between here, right? Because they now the things in the same class are already


together pretty okay. Now you map it through a weight and the non linearity they might,


you know, intertwine a bit again, but there's there more together than they would be otherwise.


So you make the job for the next layer easier, which means that the next layer can also can


even better cluster things. And what you'll end up with in this last layer is the is a


basically a class or next to last layer is basically a clustering, where everything that's


supposed to be in the same class is together and far apart from each other. And since the


last layer is the classification layer, it's going to have a really easy job separating


those classes and performing good classification. So that's what I think is happening in this


algorithm. So even though the layers don't know how to change to help the last layer,


by the fact that these random matrices induce a clustering together, you know, by back propagating


these updates here, it helps the last layer, make it makes its job really easy. And, you


know, that's all the classifier needs. And I want to I want to show again, this is my


opinion, this is not anything of value. It's just my hypothesis of why something like this


could work. I want to show you in this paper that I've shown you before right here, they


do actually do these experiments with DFA. And they show that you can see top row shows


feature obtained with back propagation, bottom row shows features obtained with DFA. I think


these are input and features. I'm not sure where exactly they are in the network. But


you can see that this clustering clearly emerges. So oh, yeah, here, from left to right input


images first hidden layer, second hidden layer, third hidden layer. So you can see that the


clustering from layer to layer in backprop, and also in DFA is better and better. So the


reason why backprop is good, maybe it's just that because it also really induces clusterings


like this, I don't know, maybe backprop does even does something on top of that. Because


I mean, backprop has all the properties of this and more, right. But still, this this


is congruent with my hypothesis of what's happening. So what do they do with it, they


take this algorithm, and they apply it to these architectures. Now, let's, for example,


look at one of them, this neural view synthesis with neural radiance fields. So neural radiance


fields is a type of model to do this task of where you get a bunch of views of an object


in 3d, or, you know, a bunch of views around an object, and you're supposed to render a


new view. And you can see that the DFA parameter or the DFA updated nerve neural radiance field


model is pretty close to the backpropagation updated one, you can see it's a bit more blurry,


but it it works, right. And I think the this paper is really trying to show that look,


this works, it doesn't work, you know, extremely well, but it works. And it works on a level


that hasn't been seen before. So here, if you consider these results higher is better


on the synthetic data set here, even you see that if you have the same model with backprop,


it performs better than with DFA. But the DFA for that model performs better than these


other baseline models that have themselves been trained with backpropagation. So it's


definitely in the direction of being competitive. And that's the same thing they show with all


of these experiments. So they apply this to graph networks, they apply this to transformers.


And as I said, it's not there yet you see that. So in the transformers, they have these


settings where in macro, they just use it DFA for the individual blocks and micro, they


use it for each layer, and already told you that you still in the attention mechanism,


you still have to use backprop within the attention mechanism. But it is much more of


a plausible algorithm than the backpropagation through the entire network. And they show


that if they appropriately tweak the hyper parameters, they do get into the direction


of something that's performant, at least with this macro strategy. Now, this is nowhere


close to this is nowhere close to what the to what the backpropagation algorithm achieves.


But it's sort of it's sort of an indication that if the community could work as much on


this as it has worked on backpropagation, then probably will make a lot of like we could


we could push this to a place where it does perform on par with backprop or very close


to it. So I do invite you to go and look at the experiments, they have a lot of lot of


details on how they did it. And exactly how you have to change the architectures to make


DFA work and the hyper parameters and so on. So that's really cool. And they have some


more outputs right here of the view synthesis and so on. Yeah, if you are interested in


that thing, I again, I don't want to disrespect it. It's just I don't think there is much


point in me going over it. It's the results are always sort of the same that DFA it. It's


not there yet, but it's a good direction. Yeah, I hope this was informative. Let me know if


you disagree about my assessment of DFA I could be completely wrong or you know, I Yeah,


Line Finding with Hough Lines - Python plays Grand Theft Auto 5 p.5

What's going on everybody welcome to part 5 of our Python plays Grand Theft Auto tutorial video series thing.


In this video what we're going to be doing is building on the last video where we at least got the region of interest.


Took a little longer than I was hoping but got it.


And now what we're going to do is use the hue lines algorithm to find the lines, at least the major lines in our image data.


So we're going to keep the ROI because we're going to find lines after ROI because it's just wasted processing to find lines outside of the region that we're actually interested in.


So the next thing we're going to do here is I guess we'll do it in process image.


So after we've done the region of interest we're going to have, we're basically going to do the hue line.


So we're going to say lines equals cv2.huelines and I'm sorry if that's not hue lines by the way if it's like Hoff lines or something I don't know.


Someone feel free to correct me below I always mispronounce all these names.


Anyway p and don't forget the p there. Now we feed through the processed image which needs to be edges.


You would never, I mean you probably could I don't know what the result would be it probably wouldn't be good though.


You want to feed through to do the hue lines, again sorry if I'm mispronouncing.


If you want to do those you want to make sure you're feeding through some sort of edge detection which in our case is the canny edge to the hue lines or Hoff lines or whatever.


So processed image, oh I am still on screen I'm surprised this is such a mess.


Let me at least pull up to here so I don't make the mistake and not show anything.


So we feed through an image imagery that has edges, just edges basically.


And then what we're going to pass is a bunch of variables.


The rh0 is one, we're going to pass numpy.py divided by 180, this is your theta.


The threshold will be 180, the I think is it min length?


Let me pull up the documents, I'll link to the documents in the text based version of the tutorial.


It will also be in the GitHub and all that.


Oh perfect here we go.


Let me pull this up, so you can learn more about these things if you want.


Yeah you've got minimum line length and then maximum line gap.


So minimum line length is like how long should this line at minimum be right?


Like do we want to detect two pixel long lines? I don't think so.


So what's the minimum length and then sometimes through aliasing or whatever there's a line gap.


So for example let me just pull up this image because it's really clear.


So like obviously we probably wouldn't but if you look at this like there's a gap between these detected lines.


Well from the actual image that's actually really a line.


The problem is the edge detection algorithm detected that there was an edge and then there's not an edge or something.


But in reality, and that's just going to happen with the edge detection algorithm.


I'm trying to see if there's any others.


I don't really see one but that's kind of an example of what can happen.


So you want to allow some sort of gap.


The other thing that's happening, let me print out the image again, is you can see look at all the aliasing happening here.


It's very jaggedy.


So like for example these aren't touching.


I can't get any closer but these aren't really touching.


So that is likely to be a problem very shortly from now.


Okay so 180 for the threshold.


What was it? Min line length?


Let's go with 20.


I'm pretty sure that's in pixels.


And then max line gap, 15.


I don't know.


This will all probably be tweaked later on.


But I just want to get somewhere.


So what this does is returns an array of arrays that contain the lines.


Which is kind of weird.


And I'll show you what I mean.


But it's going to mess with us just like this wanted the brackets around it.


It's going to return to us something similar.


I don't know why it thinks that way but it does.


So it's going to return lines based on the edge image that you pass through it.


So all we have are just coordinates.


X, Y, X, Y.


So X1, Y1, X2, Y2 and if you drew a straight line between those, those are the lines it found.


Okay we've got to draw these lines.


So rather than muddy up this one, I'm going to create a draw underscore lines function.


It doesn't exist.


We're going to create it.


But for now we're just going to say what we'd like to be able to do is draw lines where?


On the processed image and then with what?


The lines that we just found.


Okay.


So now let's do the draw lines function.


So it does just somewhere around here.


Let's define and actually draw lines will wind up being a really important function.


So I'm just going to put it at the top so it's easier for us to find.


For now it's going to be super simple.


Draw lines.


It takes an image and it takes some lines that we're going to draw.


Then for line in lines, this is going to return, like you might think lines would contain like this.


X1, Y1, Y2, something like that.


You might think that's the case.


That's not the case.


It's like this and it's a bunch of those and I'm not sure why.


But anyway, so for line in lines, we're going to say now chords for coordinates equals line zero width because it's stupid.


Now we can reference the lines themselves inside.


So then what we can do is CV2.line.


This is a way to just literally draw lines on a image.


And then you pass the coordinates for the lines.


So X1, Y1, X2, Y2.


What is the color of that line?


Let's just do 2B, 2B, 2B, 2B, 2B, 5.


And then the thickness of the line, we'll say three.


One would be one pixel, three will be three pixels.


So it will be easier for us to see the actual line.


Now for coordinates, that's going to be chords zero, one, two, three.


Cool.


So that's actually just going to draw it right on the image.


And the way that OpenCV works is it lets you modify the thing.


So we don't need to return it or anything.


We're just kind of modifying it.


It's kind of strange, but this will actually draw the lines on the thing.


We actually don't need to return an image.


So that's actually totally cool.


We're done.


Now draw lines.


Okay.


So I think we're about ready.


Let's see what typos I've done today.


So let's go ahead and run this.


I've already kind of made a pretty big mistake, but I'll get to it.


So we can see there's at least a line there.


This already broke.


No, it's still going.


Interesting.


But it's probably going to break any moment now.


Please work.


Did it break this time?


Let me see here.


Yeah, it broke.


So one error with our logic here is here, four line in lines.


Well, if it doesn't find any lines, that's not going to work out.


So what we need to do is just throw this into a try.


Accept.


Fight me.


Pass.


Okay.


Oh, I've committed a horrible sin.


All right.


So it felt good, though.


It felt so good.


All right, so hopefully you can see that in the video.


So wow, that guy totally just went around me.


What a prick.


Anyway, so you can see there's like lots of little lines here, but not quite what...


Dude, the people of Grand Theft Auto are pretty freaking weird.


But it's not quite detecting everything we expected.


And again, that's most likely because of the aliasing that's going on there.


It's very jaggedy.


So now what we want to do is let me close this and let me bring this back up.


So we can fix that with just blurring it a little bit.


So blurring is just what it sounds like.


You can take like a square of pixels and just kind of blur it.


Like that's basically what it's doing.


Just an algorithm that does that for you.


So what we'll do is add a Gaussian blur.


So you can't see that.


Okay, so before...


Okay, let me think about this.


Yeah, we want to definitely blur it after the edges, not before the edges,


because then the edge detection would just do a line again.


So after the edges, we'd like to blur it.


So process Oong equals CV2.GaussianBlur.


We are going to blur the processed underscore image.


We blur it with a...


I don't remember if it's want square brackets or braces.


Okay, CV2.GaussianBlur.


I'm Googling it at the moment if it's not clear.


Let me just pull it over as I'm looking so you guys aren't just bored, I suppose.


Let's do this Gaussian...


Okay, yeah.


So it wants...


Okay.


All right.


Let's do it.


Where am I?


Here we go.


So we'll do the 5x5.


That sounds like a grand plan.


And then what was the last parameter there?


A zero.


What is a zero?


I'm not quite sure what that zero is.


It would be nice if... I don't care.


Let's throw in the zero.


We'll see what happens.


I just want some blurring.


I don't need to get too fancy about it.


Done.


Let's move this over now.


Let's run this.


It's looking good already.


It's finding lines everywhere.


Look, oh, so many lines.


Okay.


All right.


So now we'll freeze frame here.


Beautiful.


So now if we were...


Can you see?


No, you can't.


Oh, yes, you can see my mouse.


Very difficult, though.


It's not very easy.


Anyway, now we have lines.


And my thinking is using a little bit of logic, we could...


Well, first of all, we could change the blur a little bit,


or we could change the parameters on the actual lines function.


So we had the minimum distance, and then we had the max gap.


So what we could do is change...


Change...


It's hard because it's updating, so it keeps pushing me.


We could change this, like min distance, to 50.


And then let's just rerun it.


Wow, really?


That didn't make as big of a change as I was kind of expecting.


Well, some of these lines are like 100 pixels or something.


So let's do 100 then.


And then we could probably lower the gap.


Wow, are you kidding me?


Are you...


What the hell?


This is not even listening to me.


Those aren't 100 pixels long.


You're full of it.


You're just full of it.


Maybe it's accounting for the gap and not drawing on the...


No, because it's returning the line.


Let's change the gap to 5 pixels.


I think it's in pixels.


I swear nothing's changing.


Oh, my gosh.


I wonder if I'm doing something wrong.


Somebody can...


Somebody feel free to correct my code.


This just feels wrong.


Maybe it's...


What if we did...


So I'm just going to take a few things before I just quit life.


It's a little better, I guess, but not that much better.


It's very frustrating.


Anyway, I'm going to return back to...


Let's do 15.


What was the initial setting?


Let's do like 30, 15.


That should be probably good enough.


Despite this being relatively...


My idea is to... We can tweak this a little bit if we need to,


but my idea is to...


If we just take some of the longest lines or even better,


we could take...


There's a lot of little things we can do to probably improve this.


What are the longest lines?


What are the best-ish looking lines?


Where are most of the lines taking place?


Something like that where...


You could take slope and bias.


What lines have very similar slope and biases?


For example, there's a bunch of lines right here that are pretty close to each other.


Then here, these are quite a few lines here.


Unfortunately, there's a lot out here that I'm not really too happy about.


There's definitely some tweaking that's going to need to go on.


I'm going to change to 15.


Try that again.


Anyway, there's definitely some tweaking that'll need to go on,


but there's definitely also some logic that we could throw into here


to make this be a little more accurate.


Anyway, I'm going to go ahead and cut this one off here.


I think maybe in the next video,


I'll try to get us to come up with some way of determining the lanes.


Then that'll probably...


I'll probably try to figure out from there


whether or not we should move to coming up with more rules


or if we could try to make an AI at that point.


I don't know.


Anyways, questions, comments, suggestions, whatever, leave them below.


Again, all the code will be on GitHub.


If you have ideas for improvement, share them with us.


Before we go, let me just...


Let me stop this and then just show you the ending.


Like I said, everything will be up on GitHub,


but basically the ending hue lines was for the threshold 180, 20, 15.


We can modify a few other things,


but first let's just try to come up with some sort of logic


that will pick a lane,


and then if we're having a problem at that point,


we can come back to this.


I also...


I can't remember how fast those loops were.


Let's see what our frames are.


So we're paying a decent penalty on frame rate already.


About...


What are we getting, like five frames a second now?


So we'll have to see on that one how we can hopefully somehow improve that.


I'm trying to think...


We'll have to look through this


and see if I can come up with a better way to make this more efficient.


First let's do the lanes, and then from there,


we'll see what we can do about dumbing this down.


But that might be another reason why we might want to go the AI route,


where, as strange as it might be,


we can run that on the GPU.


It might be actually faster that way.


But anyway, a lot of stuff to think about.


I'm going to cut it here.


In the next tutorial, we will do our best to try to find some lanes.


Probably what I come up with won't be the best,


and hopefully somebody can come up with something that is a little more robust


than what I'm going to push out.


But we'll see what happens,


My GitHub (Trash code I wrote during PhD)

Hey, what's going on? So I've recently graduated the PhD and during that time, I've written


a lot of code, which is mostly garbage, but I thought we go through my GitHub, and I'll


show you the most exciting and useless things I've ever written. So if you're on my GitHub,


you're going to find a bunch of things including video related materials such as like the clip


music video, you can make your own music video right here. You should watch if you haven't.


There's the Minecraft neural network I provide you with the Minecraft world. If you haven't


watched that video, please do it GPU stat, which is a tracker for GPU machines and sending


it to a server and then displaying it. This is what our lab uses for seeing who uses which


GPUs, which is you know, fairly useful. I think this is the single most popular thing


I've written during my PhD because that's people actually use it. So there is the flatland


repository. So flatland is something we did some time ago, and then I was a total slug


and completely failed in supervising the project. Let's not talk about this. You also find code


for our conference submissions, of course, but then we get into the real stuff. srun


is a little tool that you can use. What it does is it simply copies directory to a server


via SSH, it then runs a script on that server, and then it copies back a directory called


logs. That's pretty easy. And I use that all the time is very good if you have a bunch


of code in a folder and the output is a directory called logs, you're good to go. Otherwise,


you'll have to change this a bit. Okay, at that point, I had no clue that you could use


temp dir to make temporary directories. Oh, God, look at this. So it happened too many


times that I didn't do this from the directory where I actually had my code but from the


from the home directory. So it's synced my entire home directory to the server. So I


just know. See, this counts as UX. No, I'm pretty sure it does. And this right here,


this is the crown jewel, right? It is a system that manages my experiments. So in rat, there


is a bunch of things in here, there is a worker. And what the worker would do is it would sit


on a server, and it would listen to a database for new experiments that it should run. And


if so, it will pull the code from a MongoDB. So so that the queue isn't is a is a Redis


queue, and we pull code from a MongoDB. And then it would run that code, but it would


only do so if the GPU is free. So to change this RQ thing in order to check whether or


not the GPU is free, you can see right here, there's a check of whether or not the GPU


is already occupied. And if it is occupied, it would just not do the task and put it back


into the queue. However, if it is not occupied, it would run. So the neat thing you can do


with this thing is if a lab mate of yours is running on a GPU, you just put this worker


on the same GPU. And then as soon as their job is done, it's like, boom, you got it.


I'm sorry, I'm sorry. But for the most part, it actually prevents you from interfering


with other people. You know, that's pretty neat. And your jobs won't fail just because


there's already something on the GPU. So the core of this thing is you can run an experiment


config, which means you can upload different hyper parameters, and then jobs would be generated


according to those hyper parameters. And I even built in a hyper parameter optimizer.


So you can give ranges and it would search through them either in grid search or in random


sampling. So here we have a search strategy. And I built in so much stuff you can merge


experiments. I mean, look at this, this is a this is quite a bit of engineering going


into here. It even has a TensorBoard thing. Whenever a job is finished running, the worker


would actually put it back into the database. And this command right here will get me all


the event files from TensorBoard. And then it would actually label the directories with


the names of the hyper parameters. So you actually see directly in the run name, which


run has which hyper parameters. This is so freakin useful because usually TensorBoard


runs are just like run one run two or the date or some stupid thing. Confirm really?


No, I built this in to prevent myself from doing stupid stuff. But I also built like


an override flag. You know, like there's delete all. So as I said, this is it probably doesn't


work anymore because I know the redis queue dependencies have shifted and so on. Yeah,


if you want if you want some inspiration, feel free, feel absolutely free to clone this.


I don't want it anymore. When I started systems like weights and biases and so on, they just


didn't exist. So I had to run my own. Similarly, y plot is my attempt at writing a plotting


library that works with TensorBoard events. And so extracting data from TensorBoard events,


this is all so useless right now except this smoothing thing that I got from scipy, which


was pretty useful. Then y pack is you can tell my name. I'm very innovative with my


names. I think that's just a set of routines that I implemented for working with torch


and TensorFlow. Again, this is probably all useless. So there's deepfool. Look at that.


Most of this is completely useless now because these things are mostly in the libraries themselves.


confprod is what I use. Oh, look at that. This is a part of rat actually, this is what


generates the products of configurations. That's why. Yeah, I even wrote a readme. I


wrote a readme, a small utility library to generate cross products of experiment configurations.


Just look at the unit test. And hopefully it should become clear how it works. Let's


I don't think so. I mean, look at that. This is beautiful. Look, you can like spec out


something like this. You can see like so there is you want SGD optimization. And these are


the different step sizes and you can sample and this seems like a good a good thing. I


mean, there are probably 50 libraries today that do that much better than than I ever


could. Fountain Oh, fountain was my own data set library, like c410. It would it would


download it from a server and it would extract it if it's not there. Yes, this all exists


now in torch vision. And for the ML for NLP in hugging face. What a useless thing. This


thing right here, I think so in TensorFlow one, if you youngsters remember that it was


quite a bit harder to save and restore and do anything like this. So this will be a library


that if your checkpoint doesn't quite fit, it would restore whatever is there. And I


think it would also if the shapes don't fit, it would do like a random projection to make


the shapes fit. And if they don't fit, this you had to implement like a graph operation


just to get the restore to work. This is a plug in I wrote for Chrome, because I was


annoyed that I couldn't cite an archive article from the article itself. So I wrote a plugin


that goes to Google Scholar and scrapes the the Google Scholar bit tech entry in directly


to lot to archive it doesn't work anymore. But I think there are other plugins now. These


are actually good. This is a continuous compiler. As you can see, it's not very sophisticated.


And of course, I did write my own archive scraper, there was still a time when I read


all of archive, this is not possible anymore. But I did read all of archive for at least


certain lists. So I had had many more than these lists, new papers every morning. And


I would just read through the abstracts in the train. And those are repositories from


my masters. And so this is the first public repository ever from the pattern recognition


class in my bachelor studies. What is here? linear kernel, poly kernel, RBF, this looks


like support vector machines, right? Did I implement this? Here's an SVM classifier implemented.


Yikes. And this who does that? Who does private methods with a dunder? No, that's reserved.


Whoever did this passed me no nonlinear SVM without any sort of automatic back propagation.


No, no, stop. Yeah, but this is a this is a support vector machine without without SGD.


I think we used to calculate support vector machines with sort of a quadratic programming,


I think that we got that from somewhere. In any case, this was my very, very first public


commit to GitHub. And it was already a machine learning lecture. So I guess I had this coming


for a while. If you are interested in useless repositories, check out my GitHub, I'd be


happy to see what your GitHub says look like. So this was more of a nostalgia thing. But


Methods - Value Receivers - Go Lang Practical Programming Tutorial p.7

What's going on everybody? Welcome to part 7 of our Go Language tutorial series.


In this part what we're going to be talking about is methods in Go.


So, in Go there's two types of methods. You've got value receivers and you've got pointer receivers.


Value receivers are methods that are just going to do calculations on values.


They just receive values and that's all they can do.


If you want to be able to actually modify something that's actually, you know, some part of that struct,


like if you want to change a value in that struct, you then need a pointer receiver because you're actually trying to change something.


So, anyways, let's go ahead and get into it to kind of exemplify both of these and so you can kind of see what I mean.


So, first of all, we're going to add a couple new constants.


So, we're going to say const and this will be U16BitMax and we're going to say that's of float 64


and we're going to say that's equal to 65535, so that's the max.


And then we're going to say const kmh underscore multiple and that's also going to be a float 64


and we're going to say that's equal to 1.60934.


That is the multiple between, like, kilometers per hour and miles per hour.


So, one mile per hour equals 1.6 kilometers per hour.


So, now, with that, let's go ahead and calculate the kilometers per hour of this car.


So, to do that, we don't actually need to change any value, we're just going to reference some of these values and do the calculation.


So, this is like a simple game and we're just going to say wherever that gas pedal is, it's a direct relationship with how fast it's going.


And, of course, you can use brake pedal and have that impacted as well.


But, basically, you know, in a real car, you could go full throttle and you wouldn't be going your max speed of your car.


But this is like a super simple game. It's so simple it doesn't even exist.


So, anyway, let's go ahead and make a method that's going to calculate kilometers per hour.


So, this is going to be a value receiver because it doesn't actually, it just needs to receive values.


It doesn't need to modify anything or change anything.


So, we don't need to actually access the type that we're passing.


So, we're just going to say funk and then in here, this is how you can associate this function to a type which is going to make it a method.


So, funk c car. So, this is going to be associated with the car struct and then we can reference it with just c, the c variable basically.


So, funk c car kilometers per hour, empty parameters, we're not going to be passing any parameters.


And then we can begin the function. So, in fact, it's going to return a value.


It's going to return kilometers per hour. So, we actually do need to have float 64 there.


And now we're ready to build the function. So, this is just immediately going to return something.


And also, I'll probably call this function a million times, but because we're associating it with the struct, it's officially a method.


So, it's kind of like in Python, if you write methods in classes, they look just like functions.


So, anyway, but it's definitely not a function and you couldn't do the same thing with a function.


So, you couldn't take a function past the car type and then do operations on it.


You wouldn't be able to, it doesn't work that way. So, anyways, back on track.


So, to do this, we're going to return the float 64 conversion of c. gas pedal because we could not, we can't.


Because what we're going to need to do is multiply what's the gas pedal position times what is the c. top speed of the car in kilometers per hour divided by the u 16 bit max.


And that will return to us the top speed of the car. If the gas pedal is at full, this would be 225 in our example down here.


So, anyway, we need to convert c. gas pedal to a float 64 because top speed is that float 64, u 16 bit max, float 64. So, that's why we're converting it to a float 64.


Normally, u 16 bit max doesn't make any sense for it to be a float 64, but I knew that my only use of that was going to be in this kind of calculation.


So, why not save us the time of a conversion and just go ahead and do it this way.


Okay, so that's kilometers per hour. So, now what we could do is we can, okay, there's the gas pedal position, but we could also, let's just do another line and print out a car dot kilometers per hour.


And we just do it just like we would any other method. So, let's go ahead and save that and run that and make sure we didn't make any mistakes.


Go run, go tut tut dot go. So, as we can see, that's the current position and it's going 76.70 kilometers per hour.


If we were to change the gas pedal, let's change it to 65,000. So, not quite max, but pretty much max.


This car should be going almost 225 miles an hour or kilometers per hour. And there you go, it is.


So, cool. Now, let's go ahead and we could write a miles per hour method. So, I'm just going to go ahead and copy this, paste.


We can change this to miles per hour. And really the only change we would need to make is now we need to also divide this by the multiple.


So, the KMH multiple. So, I'm just going to copy that and then divide by KMH multiple.


And then now we can print out miles per hour. Run it and there you go. So, it's 138 miles per hour, 223 kilometers per hour.


So, that is how we could go about doing a value receiver method for Go. But, as I was saying, there's another type of method called the pointer receiver.


And that's where we can actually modify certain values. So, that's what I'm going to be talking about in the next tutorial.


If you have any questions, comments, concerns, or whatever up to this point, feel free to leave them below.


Decorators - Intermediate Python Programming p.18

Everybody what's going on welcome to part 18 of our intermediate python tutorial series in this video what we're talking about is


decorators and what they do so decorators as they sound add


Decoration to your function you can kind of think of them almost like they wrap your function around


So just as a quick example. You don't have to write this out


This is just an example of say a contact page on a flask application


In web development with both flask and Django decorators are pretty common at least for me. That was where I first


Really had to use decorators


And basically what this does is you know you write your function that does something it returns this template this contact template


And then the beauty of using a web framework is you can just use this decorator and using this decorator


It wraps this function and basically add some code to it


That says okay when the user goes and visits this URL we do the thing that the this function we return this template


That's the contact template, okay?


So just a really quick example of where where decorators are used in the wild now. Let's actually talk about decorators in and


See how they work truly with example


So let's say let's say you've got a function and this function is for a new GPU and this GPU is


We return a new Tesla


Nice, it's a nice GPU Christmas is coming anybody want to send me one of these


Just let me know I'll give you my address


Next we've got we could do print new GPU


We can save and run that


Oh, we didn't run it. Okay there. We go. Don't forget your parentheses


So we run it sure enough


It's a new GPU now since you guys are sending it to me for Christmas


Maybe you want to wrap the GPU so you might have a new function and we'll say define add


wrapping


When you wrap something you're you're wrapping right you're wrapping something


So you're gonna pass whatever the item is that you want to wrap into this wrapping


function this will be our decorator function and


Now we're gonna say we're gonna define wrapped underscore item and what this is gonna. Do is return a


a wrapped up box of


Something and then we'll do dot format


string version of whatever the item is


So


So we return that and then now at the for the actual add wrapping function


We're going to return


wrapped


item


So now what we can do is at


New GPU we can wrap it so we can say boom add


wrapping and


That will decorate


and our wrapping paper to our


New Tesla p100 GPU so we can now run literally new GPU nothing changes


We've just added that wrapping with the decorator, so this is basically our decoration


We can run that and now what we get is actually a wrapped up box of a new Tesla p100 GPU


Thank you guys. I love your wrapping so


What's nice is with this wrapping functionality when you have?


Separate functions and also you can all you can use this on like class methods and stuff like that


You can use it to all kinds of things so right you could say define


a new bicycle


I don't need one of these you don't need to send me one return, but seriously on that GPU. Let me know a new bicycle


And we can wrap that as well so we can add


Add wrapping to that and then return print rather new


bicycle


And you get a wrapped up box of a new bicycle, okay, so you can use wrapping to do that kind of stuff now


What happens if?


You added wrapping to the wrapping so you're one of these people who like


Does boxes inside of boxes to fool people what it is so for example with this GPU the box will be you know?


Maybe about like this big or something


But you're one of these people that puts it in a huge box and then puts another box over it and stuff like that so


So maybe you would do you can do this you can add


Add-wrapping, so we'll just add another wrapping or you could even have


You can put like another you could create a new decorator function


That's a bow or something like that something different than just adding wrapping twice, but anyway


We can do the same thing now. It's wrapped up box over wrapped up box of a new Tesla p100 GPU


But you could have created rather a decorator function that was you know add wrapping add


Add bow and then have the box or add bow add wrapping the box whatever


Okay, so you can do that kind of double


The double wrapping now one thing that probably won't matter to most of you


But especially when you're using this possibly with object-oriented programming and so on what if we said print new GPU dot?


name so we're just going to grab the name of


What should be just like the function name basically let's see what it says though


Instead what we're returned is wrapped item because it's actually a wrapped item function now because what it returns is this


and in many cases


You're not going to want that you're going to want that to actually return new GPU like so if we did this


Right it's going to say the name is actually it's a new GPU function right and so depending on what you want


Maybe you actually want it to say this because it is wrapped item function as well. It's a wrapped item


So that's true, but maybe you actually would rather this be


The the original function name what you can do is you could come to the top here and from funk tools


tools import wraps and that gives us that wraps as a decorator so we can say is at wraps


item and


And then basically we change nothing else. We'll save and run that and it's the original function now


So it doesn't that name object or the the name method rather will look it


Overwritten if you don't want it to again. They're going to be times where well it is a wrapped item right so


You are going to want to override it, but then there's going to be other times where?


But it's really actually a new GPU. I don't want to overwrite that you could do that and


There's probably plenty of times where you don't even care so do whatever you want it now


We're going to do is is basically in case this function and another function is going to be defined add


wrapping with


Style and we'll pass the style


and then we'll tab this over and


Now we're going to say a


And then we'll do some formatting


And then over here. We'll say style comma string item


So you might say it nicely or badly or whatever there return wrapped item


And then we come down here and actually we're going to return add


wrapping


And now what we can say is we can add wrapping


Let's say beautiful


Awesome so print new GPU save that run that


add