Are you getting different results per jump on the same item, or are you trying to replicate the same height on different objects?
ForceMode.Impulse is dependent on the mass of the object you're using it on (https://docs.unity3d.com/ScriptReference/ForceMode.Impulse.html).
If you want it to ignore the mass, ForceMode.VelocityChange (https://docs.unity3d.com/ScriptReference/ForceMode.VelocityChange.html) should do the trick.
rb.AddForce(transform.up * jumpForce, ForceMode.VelocityChange);
Something I didn't consider before this, how collisions are detected does appear to make a difference. If your Rigidbody is still falling when you trigger the "AddForce()" function, you'll be adding upward velocity with opposing downward force.
I used this example for detecting when my GameObject collided with the ground.
Slightly shortened, and changed "collision.contacts" to "collision.GetContact(0)", the editor warns that the first one causes memory garbage. Using this, I got the same height every jump.
void OnCollisionEnter(Collision col)
if(Vector3.Dot(col.GetContact(0).normal,Vector3.up) > 0.5)
isJumping = false;
Per Evolor's comment, (which they should definitely turn into an answer so I can upvote it), you can set velocity directly instead of adding force.
Adding this to my answer since you asked about changing the local velocity of the rigidbody as well. The discussion there seems to explain doing that pretty well.