So it would seem that a safe way to implement a function that does my own custom initialization would be to use torch.no_grad as you suggested:
torch.manual_seed(1)
def do_init2(layer):
    with torch.no_grad():
        layer.weight.normal_(0, 10)  #  10 so we can check expected behavior
        layer.bias.fill_(0)

lin = nn.Linear(4, 5)
print("before")
print(lin.weight)
print(lin.bias)

do_init2(lin)

print("after")
print(lin.weight)
print(lin.bias)

output:
before
Parameter containing:
tensor([[ 0.2576, -0.2207, -0.0969,  0.2347],
        [-0.4707,  0.2999, -0.1029,  0.2544],
        [ 0.0695, -0.0612,  0.1387,  0.0247],
        [ 0.1826, -0.1949, -0.0365, -0.0450],
        [ 0.0725, -0.0020,  0.4371,  0.1556]], requires_grad=True)
Parameter containing:
tensor([-0.1862, -0.3020, -0.0838, -0.2157, -0.1602], requires_grad=True)
after
Parameter containing:
tensor([[ 11.7120,  17.6743,  -0.9536,   1.3937],
        [-12.1501,   7.3117,  11.7180,  -9.2739],
        [  5.4514,   0.6628,  -4.3704,   7.6260],
        [ 11.6327,  -0.0907,  -8.4246,   1.3741],
        [  9.3864,  -1.8600,  -6.4464,  15.3925]], requires_grad=True)
Parameter containing:
tensor([0., 0., 0., 0., 0.], requires_grad=True)

Thank you for helping me understand these mechanics a bit better!