Hướng dẫn dùng train def python

Python cung cấp nhiều các hàm dựng sẵn [built-in-function], ngoài ra ta có thể tự định nghĩa các hàm của riêng mình. Những hàm này còn được gọi là user-defined function.

  • Hàm sau khi được định nghĩa sẽ không tự thực thi.
  • Hàm chỉ thực thi khi được gọi đến.

Chú ý!

Khi định nghĩa hàm ta nên đặt tên hàm là một động từ, vì hàm thể hiện một hành động, một tác vụ của chương trình.

Một số quy tắc khi định nghĩa hàm trong Python


Trong Python, chúng ta định nghĩa hàm theo quy tắc sau:

  • Định nghĩa hàm sẽ bắt đầu với từ khóa def, sau đó là tên hàm và cặp dấu ngoặc [ ]
  • Cặp dấu [ ] sẽ chứa các tham số của hàm [nếu có]
  • Câu lệnh đầu tiên của hàm có thể là một lệnh tùy chọn, để mô tả về hàm [còn gọi là docstring]
  • Thân của hàm sẽ bắt đầu với một dấu : và được thụt lề.
  • Lệnh return dùng để thoát ra khỏi hàm, và trả lại giá trị từ hàm.

Cú pháp định nghĩa hàm trong Python


Ta sử dụng Cú pháp như sau để định nghĩa hàm trong Python:

Cú pháp [Syntax] định nghĩa hàm trong Python

 

Ví dụ định nghĩa hàm:

Ở đây ta đã định nghĩa ra một hàm có tên là my_function[].

Hàm này chỉ đơn giản in ra một chuỗi.

Sau đó ta gọi hàm vừa tạo:

      print["Hello from a Function"]


Hướng dẫn sử dụng tham số với hàm trong Python


Hàm có thể có các tham số.

Tham số cho phép thay đổi nội dung bên trong hàm, làm cho hàm trở nên linh hoạt hơn, động hơn.

Hàm có thể trả về kết quả khác nhau dựa trên giá trị truyền vào của tham số khác nhau.

Chú ý!

Khi định nghĩa hàm, ta khai báo bao nhiêu tham số, thì khi gọi hàm, ta cần truyền bấy nhiêu giá trị vào hàm.

Ví dụ: Ở đây ta định nghĩa một hàm add[] cho phép tính tổng của hai số được truyền từ bên ngoài vào hàm. Sau đó ta nhập hai số vào từ bàn phím, rồi gọi hàm vừa tạo.

# Nhập 2 số vào từ bàn phím

x = int[input["Nhập số thứ nhất:"]]

y = int[input["Nhập số thứ hai:"]]

# Gọi hàm add[] vừa được định nghĩa ở trên

# In ra tổng vừa tính được

print["Tổng là: " + str[tong]]

> Lưu ý: Trong python, bạn muốn nối giá trị thì phải chúng phải cùng kiểu. Vì thế chúng ta phải chuyển tong thành  str


Sau khi đã viết mã xong, ta sẽ thực thi hàm vừa tạo.

Ta sẽ thấy chương trình hiển thị kết quả đúng như mong muốn.

Cách truyền tham số có giá trị mặc định trong Python


Khi định nghĩa hàm, ta có thể gán giá trị mặc định cho tham số.

Khi gọi hàm, nếu ta không truyền giá trị cho tham số, thì tham số sẽ tự động được gán giá trị mặc định.

Nếu ta có truyền giá trị cho tham số, thì tham số sẽ chứa giá trị được truyền.

Ta truyền giá trị mặc định cho tham số sẽ có lợi, khi ta quên truyền giá trị cho tham số thì sẽ không bị lỗi.

Ví dụ dưới đây có định nghĩa một hàm, có một tham số là country, đồng thời ta truyền giá trị mặc định cho tham số vừa tạo là "[ ]0.


def my_function[country = "Norway"]:

      print["I am from " + country]




Kết quả sau khi gọi hàm có truyền đối số hoặc không truyền đối số:


Để trả về một giá trị từ hàm, ta sử dụng lệnh return.

Lệnh return còn được dùng để thoát ra khỏi hàm, lúc này điều khiển của chương trình sẽ quay về nơi gọi hàm.

Trong ví dụ dưới đây, ta đã định nghĩa hàm [ ]3, có một tham số [ ]4. Hàm này trả về tích của [ ]5.

Sau đó ta gọi hàm vừa tạo.

Kết quả được hiển thị như bên dưới:

Chúc mừng bạn đã biết thêm về Function trong Python


Như vậy là qua bài này bạn đã hiểu về cách tạo Function [hàm] trong Python, cách truyền tham số, gọi hàm và sử dụng tham số mặc định trong Python.

Hàm là xương sống của bất kỳ ngôn ngữ lập trình nào. Chúng ta sẽ sử dụng hàm liên tục trong quá trình HỌC PYTHON.

Những bài trước mình đã học cách xây dựng và train deep learning model bằng Pytorch. Tuy nhiên, khi train xong model mình cần lưu được model đã train, để sau có thể dùng để dự đoán hoặc tiếp tục train mà không cần train lại từ đầu. Bài này mình sẽ hướng dẫn lưu và load model trong Pytorch.

Nội dung

State_dict là gì?

State_dict của model là một Python dict, với key là tên của layer và value là parameter của layer đó, bao gồm weight và bias. Bên cạnh model, optimizer [torch.optim] cũng có state_dict, có chứa những thông tin về optimizer’s state, cũng như các hyperparameter đi cùng.

Vì state_dict là Python dict, nên có thể dễ dàng cập nhật, thay đổi, lưu và load lên. Ví dụ như model CNN mình build ở bài Neural Network

class Net[nn.Module]:
    def __init__[self]:
        super[].__init__[]
        self.conv1 = nn.Conv2d[3, 16, kernel_size=3, padding=1]
        self.conv2 = nn.Conv2d[16, 8, kernel_size=3, padding=1]
        self.fc1 = nn.Linear[8 * 8 * 8, 32]
        # bài toán phân loại 10 lớp nên output ra 10 nodes
        self.fc2 = nn.Linear[32, 10]
        
    def forward[self, x]:
        out = F.max_pool2d[torch.tanh[self.conv1[x]], 2]
        out = F.max_pool2d[torch.tanh[self.conv2[out]], 2]
        # flatten về dạng vector để cho vào neural network
        out = out.view[-1, 8 * 8 * 8]
        out = torch.tanh[self.fc1[out]]
        out = self.fc2[out]
        return out

# Initialize model
model = Net[]

# Initialize optimizer
optimizer = optim.SGD[model.parameters[], lr=0.001, momentum=0.9]

Mình có thể in state_dict của model và optimizer.

# Print model's state_dict
print["Model's state_dict:"]
for param_tensor in model.state_dict[]:
    print[param_tensor, "\t", model.state_dict[][param_tensor].size[]]
'''
Output:
Model's state_dict:
conv1.weight 	 torch.Size[[16, 3, 3, 3]]
conv1.bias 	 torch.Size[[16]]
conv2.weight 	 torch.Size[[8, 16, 3, 3]]
conv2.bias 	 torch.Size[[8]]
fc1.weight 	 torch.Size[[32, 512]]
fc1.bias 	 torch.Size[[32]]
fc2.weight 	 torch.Size[[10, 32]]
fc2.bias 	 torch.Size[[10]]
'''

Mọi người thấy là state_dict của model có key là tên layer như conv1.weight, conv1.bias,…,fc2.weight, fc2.bias còn value là các tensor hệ số tương ứng với các layer đó.

# Print optimizer's state_dict
print["Optimizer's state_dict:"]
for var_name in optimizer.state_dict[]:
    print[var_name, "\t", optimizer.state_dict[][var_name]]
'''
Optimizer's state_dict:
state 	 {}
param_groups 	 [{'lr': 0.03, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': True, 'params': [0, 1, 2, 3, 4, 5, 6, 7]}]
'''

Tại mình chưa train nên state vẫn chưa có gì. Còn param_groups mọi người thấy các hyperparameter của optimizer như learning rate, momentum,…. Tuy nhiên sau khi mình train 1 vài epoch:

# Print optimizer's state_dict
print["Optimizer's state_dict:"]
for var_name in optimizer.state_dict[]:
    print[var_name, "\t", optimizer.state_dict[][var_name]]
'''
state 	 {..., 7: {'momentum_buffer': tensor[[-0.1845,  0.0265, -0.1256,  0.0954,  0.1391,  0.0451, -0.1127,  0.0178,
         0.0500,  0.0489]]}}
param_groups 	 [{'lr': 0.03, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': True, 'params': [0, 1, 2, 3, 4, 5, 6, 7]}]
'''

Mọi người thấy là do optimizer mình có dùng momentum nên giờ state sẽ lưu lại giá trị cộng dồn của các tham số tương ứng, state giờ sẽ là 1 dict, với key là index của layer [0-7] còn value là giá trị cộng dồn của các hệ số [weight, bias].

Lưu và load model cho inference

Lưu state_dict của model

torch.save[model.state_dict[], PATH]

trong đó PATH là đường dẫn đến file lưu model, thông thường pytorch model lưu dưới dạng .pt hoặc .pth

Khi load model thì mình cần dựng lại kiến trúc của model trước, sau đó sẽ gọi hàm để load state_dict vào model.

model = Net[]
model.load_state_dict[torch.load[PATH]]

*lưu ý: hàm load_sate_dict nhận input là 1 dict nên mình cần load state_dict của model nên bằng hàm torch.load trước. Gọi thẳng trực tiếp model.load_state_dict[PATH] sẽ lỗi.

Lưu cả model

Thông thường Pytorch sẽ lưu model dưới dạng .pt hoặc .pth

torch.save[model, PATH]

Vì mình lưu cả model nên khi load mình không cần dựng lại kiến trúc của model trước mà có thể load thẳng lên

model = torch.load[PATH]

Mọi người sẽ thấy lưu cả model thì tiện hơn rất nhiều, không cần định nghĩa lại model và không cần quan tâm đến state_dict là gì. Khi mọi người lưu cả model thì Pytorch sẽ dùng pickle module của Python để lưu. Tuy nhiên, pickle thì không lưu trực tiếp model class [class định nghĩa model, dùng để định nghĩa kiến trúc model] mà lưu đường dẫn tới file chứa model class. Thế nên khi load model, nếu mình refactor code và đường dẫn đến file chứa model class thay đổi thì code sẽ lỗi và không load model lên được.

Lưu và load checkpoint để tiếp tục training

Khi mình lưu model để tiếp tục training thì bên cạnh model state_dict, mình còn phải lưu thêm các thông tin như optimizer state_dict, số epoch, loss hiện tại.

torch.save[{
            'epoch': epoch,
            'model_state_dict': model.state_dict[],
            'optimizer_state_dict': optimizer.state_dict[],
            'loss': loss
            }, PATH]

Ở lần sau mình train tiếp, thì mình load các thông số đã lưu lên để cho tiếp tục training

checkpoint = torch.load[PATH]
model.load_state_dict[checkpoint['model_state_dict']]
optimizer.load_state_dict[checkpoint['optimizer_state_dict']]
epoch = checkpoint['epoch']
loss = checkpoint['loss']

# train model
model.train[]
# tiếp tục train model

Load_state_dict argument

Strict

Bình thường khi mọi người load state_dict của model thì tất cả các layer của model phải khớp với các key trong state_dict mà đã lưu trước đó.

# Print model's state_dict
print["Model's state_dict:"]
for param_tensor in model.state_dict[]:
    print[param_tensor, "\t", model.state_dict[][param_tensor].size[]]
'''
Output:
Model's state_dict:
conv1.weight 	 torch.Size[[16, 3, 3, 3]]
conv1.bias 	 torch.Size[[16]]
conv2.weight 	 torch.Size[[8, 16, 3, 3]]
conv2.bias 	 torch.Size[[8]]
fc1.weight 	 torch.Size[[32, 512]]
fc1.bias 	 torch.Size[[32]]
fc2.weight 	 torch.Size[[10, 32]]
fc2.bias 	 torch.Size[[10]]
'''
0

Khi state_dict của model đã lưu thiếu một vài key hoặc có nhiều hơn một vài key với model hiện tại của mọi người thì hàm load_state_dict sẽ báo lỗi. Để giải quyết trường hợp này thì hàm load_state_dict hỗ trợ thuộc tính strict [mặc định là True], nếu strict là False thì model sẽ chỉ load những key-value mà 2 bên match với nhau.

# Print model's state_dict
print["Model's state_dict:"]
for param_tensor in model.state_dict[]:
    print[param_tensor, "\t", model.state_dict[][param_tensor].size[]]
'''
Output:
Model's state_dict:
conv1.weight 	 torch.Size[[16, 3, 3, 3]]
conv1.bias 	 torch.Size[[16]]
conv2.weight 	 torch.Size[[8, 16, 3, 3]]
conv2.bias 	 torch.Size[[8]]
fc1.weight 	 torch.Size[[32, 512]]
fc1.bias 	 torch.Size[[32]]
fc2.weight 	 torch.Size[[10, 32]]
fc2.bias 	 torch.Size[[10]]
'''
1

Map_location

Khi mọi người load lưu và load trên device khác nhau, ví dụ như save model trên gpu và load model trên cpu hoặc save model trên cpu và load model trên gpu, thì khi load model mọi người cần truyền map_location với device tương ứng.

Chủ Đề