First, avoid “for” loops in your forward. You want to use tensor operations that are calling C code.
If I understand embedding correctly, with N dimensions and dictionary of size S, you want to create S maps associating each integer from the input with a unique float.
Then, torch.gather() is your best friend 
# create an example input with 30 possible characters, 
# 3 batchs, sentence_len = 7, word_len = 5
x = torch.floor(torch.rand(3,7,5)*30).long()

# create embedding weights with 4 dictionnaries for 30 characters
# maping to [-1,1] segment
w = 1-2*torch.rand(30,4,1,1,1)

# get indices ready to pick values in w:
idx = torch.cat([x.unsqueeze(0)]*4,0).unsqueeze(0) # (1,4,3,7,5)
# align w with indices and pick values from w
# and squeeze the fake dimention used for aligment:
x_emb = w.expand_as(30,4,3,7,5).gather(0,idx).squeeze() # (4,3,7,5)

I think x_emb is what you are looking for