Tài liệu PyTorch https://docs.pytorch.org/docs/main/index.html
PyTorch là một thư viện tensor được tối ưu hóa cho học sâu sử dụng GPU và CPU.
Kết quả hoàn toàn có thể tái tạo không được đảm bảo giữa các phiên bản PyTorch, các commit riêng lẻ, hoặc các nền tảng khác nhau. Hơn nữa, kết quả có thể không tái tạo được giữa việc thực thi trên CPU và GPU, ngay cả khi sử dụng cùng một seed.
Tuy nhiên, có một số bước bạn có thể thực hiện để hạn chế số lượng nguồn gây ra hành vi không xác định cho một nền tảng, thiết bị, và phiên bản PyTorch cụ thể.
- Thứ nhất, bạn có thể kiểm soát các nguồn ngẫu nhiên có thể gây ra nhiều lần thực thi ứng dụng của bạn hoạt động khác nhau.
- Thứ hai, bạn có thể cấu hình PyTorch để tránh sử dụng các thuật toán không xác định cho một số thao tác, để nhiều lần gọi các thao tác đó, với cùng đầu vào, sẽ tạo ra cùng một kết quả.
reproducible
adj. Có thể tái tạo; có thể sao chép; có thể nhân giống
behave [bɪ'heɪv]
v. Hành vi; biểu hiện; cử chỉ; phép tắc
facilitate [fəˈsɪlɪteɪt]
v. Thúc đẩy; làm cho dễ dàng
Các thao tác xác định thường chậm hơn các thao tác không xác định, vì vậy hiệu suất chạy đơn có thể giảm cho mô hình của bạn. Tuy nhiên, tính xác định có thể tiết kiệm thời gian trong quá trình phát triển bằng cách thúc đẩy thử nghiệm, gỡ lỗi và kiểm thử hồi quy.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import random
import numpy as np
import torch
initial_seed = 54321
print(f"seed ban đầu: {initial_seed}")
# Seed ngẫu nhiên Python
random.seed(initial_seed)
# Seed băm Python (ảnh hưởng đến thứ tự của các thao tác trên tập hợp, từ điển, v.v.)
os.environ['PYTHONHASHSEED'] = str(initial_seed)
# Seed ngẫu nhiên NumPy
np.random.seed(initial_seed)
# Seed ngẫu nhiên PyTorch CPU
torch.manual_seed(initial_seed)
# Seed ngẫu nhiên PyTorch GPU (đa và đơn GPU)
if torch.cuda.is_available():
torch.cuda.manual_seed(initial_seed)
torch.cuda.manual_seed_all(initial_seed)
# Cấu hình hành vi xác định của CuDNN
# Lưu ý: Điều này có thể làm giảm hiệu suất một chút vì tắt tối ưu hóa thuật toán tự động
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
# Bắt buộc sử dụng thuật toán xác định (PyTorch)
# Nếu một số thao tác không có triển khai xác định, việc gọi phương thức này có thể gây ra lỗi
# torch.use_deterministic_algorithms(True)
/home/user/miniconda3/bin/python /home/user/project/reproducibility_example.py
seed ban đầu: 54321
Process finished with exit code 0
- Kiểm soát các nguồn ngẫu nhiên
torch.manual_seed()(hàm Python, trongtorch)torch.cuda.manual_seed()(hàm Python, trongtorch.cuda)torch.cuda.manual_seed_all()(hàm Python, trongtorch.cuda)
1.1. torch.manual_seed()
https://docs.pytorch.org/docs/main/generated/torch.manual_seed.html
torch.manual_seed(seed)
Trong PyTorch, torch.manual_seed(seed) được sử dụng để đặt seed cho trình tạo số ngẫu nhiên (RNG) trên tất cả các thiết bị (CPU, GPU/CUDA, MPS, v.v.). Điều này rất quan trọng để đảm bảo tính tái tạo được của mã.
Đặt seed để tạo số ngẫu nhiên trên tất cả các thiết bị. Trả về một đối tượng torch.Generator.
Đặt seed để tạo số ngẫu nhiên, đảm bảo kết quả là xác định.
Tham số
- seed (
int): Seed mong muốn.
Giá trị phải nằm trong phạm vi bao gồm [-0x8000_0000_0000_0000, 0xffff_ffff_ffff_ffff]. Nếu không, sẽ引发 RuntimeError. Các đầu vào âm được ánh xạ sang các giá trị dương bằng công thức 0xffff_ffff_ffff_ffff + seed.
Kiểu trả về
- Đối tượng
torch.Generator
Một số thao tác PyTorch có thể sử dụng số ngẫu nhiên bên trong. torch.svd_lowrank() làm điều này, ví dụ. Do đó, gọi nó nhiều lần liên tiếp với cùng các đối số đầu vào có thể cho kết quả khác nhau. Tuy nhiên, miễn là torch.manual_seed() được đặt thành một hằng số ở đầu ứng dụng và tất cả các nguồn không xác định khác đã được loại bỏ, cùng một chuỗi số ngẫu nhiên sẽ được tạo mỗi khi ứng dụng được chạy trong cùng một môi trường.
Cũng có thể thu được kết quả giống hệt từ một thao tác sử dụng số ngẫu nhiên bằng cách đặt torch.manual_seed() thành cùng một giá trị giữa các lần gọi tiếp theo.
1.2. torch.cuda.manual_seed()
https://docs.pytorch.org/docs/stable/generated/torch.cuda.manual_seed.html
torch.cuda.manual_seed(seed)
Đặt seed để tạo số ngẫu nhiên cho GPU hiện tại. Việc gọi hàm này là an toàn nếu CUDA không khả dụng; trong trường hợp đó, nó sẽ bị bỏ qua một cách im lặng. Đặt seed cho GPU hiện tại để tạo số ngẫu nhiên, đảm bảo kết quả là xác định.
Tham số
- seed (
int): Seed mong muốn.
Nếu bạn đang làm việc với mô hình đa GPU, hàm này không đủ để đạt được tính xác định. Để đặt seed cho tất cả các GPU, hãy sử dụng torch.cuda.manual_seed_all().
insufficient /ˌɪnsəˈfɪʃnt/:adj. Không đủ, không đủ khả năng, thiếu năng lực
1.3. torch.cuda.manual_seed_all()
https://docs.pytorch.org/docs/stable/generated/torch.cuda.manual_seed_all.html
torch.cuda.manual_seed_all(seed)
Đặt seed để tạo số ngẫu nhiên trên tất cả các GPU. Việc gọi hàm này là an toàn nếu CUDA không khả dụng; trong trường hợp đó, nó sẽ bị bỏ qua một cách im lặng. Đặt seed cho tất cả các GPU để tạo số ngẫu nhiên, đảm bảo kết quả là xác định.
Tham số
- seed (
int): Seed mong muốn.
1.4. Python random - Tạo số giả ngẫu
https://docs.python.org/3/library/random.html
random.seed(a=None, version=2)
Khởi tạo trình tạo số ngẫu nhiên.
Nếu a bị bỏ qua hoặc là None, thời gian hệ thống hiện tại sẽ được sử dụng. Nếu các nguồn ngẫu nhiên được cung cấp bởi hệ điều hành, chúng sẽ được sử dụng thay vì thời gian hệ thống (xem hàm os.urandom() để biết chi tiết về tính khả dụng).
Nếu a là một int, giá trị tuyệt đối của nó sẽ được sử dụng trực tiếp.
Với phiên bản 2 (mặc định), một đối tượng str, bytes, hoặc bytearray sẽ được chuyển đổi thành int và tất cả các bit của nó sẽ được sử dụng.
Với phiên bản 1 (được cung cấp để tái tạo các chuỗi ngẫu nhiên từ các phiên bản Python cũ hơn), thuật toán cho str và bytes tạo ra một phạm vi seed hẹp hơn.
random.random()
Trả về số thực ngẫu nhiên tiếp theo trong khoảng 0.0 ≤ X < 1.0
random.uniform(a, b)
Trả về một số thực ngẫu nhiên N N N sao cho a ≤ N ≤ b a \leq N \leq b a≤N≤b cho a ≤ b a \leq b a≤b và b ≤ N ≤ a b \leq N \leq a b≤N≤a cho b < a b < a b<a.
Giá trị cuối cùng b b b có thể hoặc không được bao gồm trong khoảng tùy thuộc vào việc làm tròn số thực trong biểu thức a + ( b − a ) ∗ random ( ) a + (b - a) * \text{random}() a+(b−a)∗random().
random.randint(a, b)
Trả về một số nguyên ngẫu nhiên N N N sao cho a ≤ N ≤ b a \leq N \leq b a≤N≤b. Bí danh cho randrange ( a , b + 1 ) \text{randrange}(a, b+1) randrange(a,b+1).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random
seed_value = 22
random.seed(seed_value) # Đặt seed
print(f"seed_value: {seed_value}")
print(f"Số thực ngẫu nhiên: {random.random()}")
print(f"Số thực ngẫu nhiên: {random.random()}")
print(f"Số thực ngẫu nhiên: {random.random()}")
print(f"Số nguyên ngẫu nhiên (1-100): {random.randint(1, 100)}")
print(f"Số nguyên ngẫu nhiên (1-100): {random.randint(1, 100)}")
print(f"Số nguyên ngẫu nhiên (1-100): {random.randint(1, 100)}")
random.seed(seed_value) # Đặt seed
print(f"\nseed_value: {seed_value}")
print(f"Số thực ngẫu nhiên: {random.random()}")
print(f"Số thực ngẫu nhiên: {random.random()}")
print(f"Số thực ngẫu nhiên: {random.random()}")
print(f"Số nguyên ngẫu nhiên (1-100): {random.randint(1, 100)}")
print(f"Số nguyên ngẫu nhiên (1-100): {random.randint(1, 100)}")
print(f"Số nguyên ngẫu nhiên (1-100): {random.randint(1, 100)}")
/home/user/miniconda3/bin/python /home/user/project/random_example.py
seed_value: 22
Số thực ngẫu nhiên: 0.13436424411240122
Số thực ngẫu nhiên: 0.8474337369372327
Số thực ngẫu nhiên: 0.763774618976614
Số nguyên ngẫu nhiên (1-100): 42
Số nguyên ngẫu nhiên (1-100): 88
Số nguyên ngẫu nhiên (1-100): 95
seed_value: 22
Số thực ngẫu nhiên: 0.13436424411240122
Số thực ngẫu nhiên: 0.8474337369372327
Số thực ngẫu nhiên: 0.763774618976614
Số nguyên ngẫu nhiên (1-100): 42
Số nguyên ngẫu nhiên (1-100): 88
Số nguyên ngẫu nhiên (1-100): 95
Process finished with exit code 0
1.5. Trình tạo số ngẫu nhiên NumPy
Nếu bạn hoặc bất kỳ thư viện nào bạn đang sử dụng phụ thuộc vào NumPy, bạn có thể đặt seed cho trình tạo số ngẫu nhiên toàn cục của NumPy.
Tuy nhiên, một số ứng dụng và thư viện có thể sử dụng các đối tượng Trình tạo số ngẫu nhiên NumPy, không phải trình tạo toàn cục https://numpy.org/doc/stable/reference/random/generator.html, và những đối tượng đó cũng cần được đặt seed một cách nhất quán.
numpy.random.default_rng(seed=None)
Xây dựng một Trình tạo mới với BitGenerator mặc định (PCG64).
Tham số
seed: {None, int, array_like[ints], SeedSequence, BitGenerator, Generator, RandomState}, tùy chọn
Một seed để khởi tạo BitGenerator. Nếu là None, entropy mới, không thể đoán trước sẽ được lấy từ hệ điều hành. Nếu một int hoặc array_like[ints] được truyền, thì tất cả các giá trị phải không âm và sẽ được truyền cho SeedSequence để suy ra trạng thái ban đầu của BitGenerator. Một người cũng có thể truyền một instance SeedSequence. Ngoài ra, khi truyền một BitGenerator, nó sẽ được bao bọc bởi Generator. Nếu truyền một Generator, nó sẽ được trả về không thay đổi. Khi truyền một instance RandomState cũ, nó sẽ được ép kiểu thành Generator.
Trả về
Generator
Đối tượng trình tạo đã được khởi tạo.
Ghi chú
Nếu seed không phải là BitGenerator hoặc Generator, một BitGenerator mới sẽ được khởi tạo. Hàm này không quản lý một instance toàn cục mặc định.
random.Generator.random(size=None, dtype=np.float64, out=None)
Trả về các số thực ngẫu nhiên trong khoảng bán mở [ 0.0 , 1.0 ) [0.0, 1.0) [0.0,1.0).
Kết quả lấy từ phân phối "liên tục đều" trên khoảng đã nêu. Kết quả lấy từ phân phối "liên tục đều" trên khoảng đã nêu.
Để lấy mẫu phân phối đều [ a , b ) , b > a [a, b), b > a [a,b),b>a sử dụng random.Generator.uniform(low=0.0, high=1.0, size=None) hoặc nhân đầu ra của random.Generator.random(size=None, dtype=np.float64, out=None) với (b - a) và cộng a:
(b - a) * random() + a
Tham số
size: int hoặc tuple of ints, tùy chọn
Hình dạng đầu ra. Nếu hình dạng đã cho là, ví dụ, (m, n, k), thì m * n * k mẫu được vẽ. Mặc định là None, trong trường hợp đó một giá trị duy nhất được trả về.
dtype: dtype, tùy chọn
Kiểu dữ liệu mong muốn của kết quả, chỉ float64 và float32 được hỗ trợ. Byteorder phải là bản địa. Giá trị mặc định là np.float64.
out: ndarray, tùy chọn
Mảng đầu ra thay thế để đặt kết quả. Nếu size không phải là None, nó phải có cùng hình dạng với size đã cung cấp và phải khớp với kiểu của các giá trị đầu ra.
Trả về
out: float hoặc ndarray of floats
Mảng các số thực ngẫu nhiên có hình dạng size (trừ khi size=None, trong trường hợp đó một số thực duy nhất được trả về).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
seed = 98765
rng = np.random.default_rng(seed)
print(f"seed: {seed}")
print(f"rng: {rng}")
rfloat1 = rng.random()
print(f"rfloat1: {rfloat1}, type(rfloat1): {type(rfloat1)}")
rfloat2 = rng.random()
print(f"rfloat2: {rfloat2}, type(rfloat2): {type(rfloat2)}")
arr1 = rng.random((4, 4))
print(f"arr1.shape: {arr1.shape}, type(arr1[0]): {type(arr1[0])}")
print(f"arr1:\n{arr1}")
arr2 = rng.random((4, 4))
print(f"arr2.shape: {arr2.shape}, type(arr2[0]): {type(arr2[0])}")
print(f"arr2:\n{arr2}")
rng = np.random.default_rng(seed)
print(f"\nseed: {seed}")
print(f"rng: {rng}")
rfloat1 = rng.random()
print(f"rfloat1: {rfloat1}, type(rfloat1): {type(rfloat1)}")
rfloat2 = rng.random()
print(f"rfloat2: {rfloat2}, type(rfloat2): {type(rfloat2)}")
arr1 = rng.random((4, 4))
print(f"arr1.shape: {arr1.shape}, type(arr1[0]): {type(arr1[0])}")
print(f"arr1:\n{arr1}")
arr2 = rng.random((4, 4))
print(f"arr2.shape: {arr2.shape}, type(arr2[0]): {type(arr2[0])}")
print(f"arr2:\n{arr2}")
/home/user/miniconda3/bin/python /home/user/project/numpy_example.py
seed: 98765
rng: Generator(PCG64)
rfloat1: 0.7248204338775774, type(rfloat1): <class 'float'>
rfloat2: 0.1834045080617419, type(rfloat2): <class 'float'>
arr1.shape: (4, 4), type(arr1[0]): <class 'numpy.ndarray'>
arr1:
[[0.9457293 0.11587794 0.80309455 0.87985233]
[0.18287915 0.78253742 0.94084023 0.61667278]
[0.07402969 0.73989851 0.92270829 0.03987515]
[0.39083696 0.89838915 0.47567089 0.36928405]]
arr2.shape: (4, 4), type(arr2[0]): <class 'numpy.ndarray'>
arr2:
[[0.8838273 0.34347188 0.81374641 0.23138231]
[0.49235117 0.05973503 0.74662402 0.51387277]
[0.05994213 0.43779146 0.82835965 0.18615186]
[0.4786654 0.02589436 0.54970699 0.06996595]]
seed: 98765
rng: Generator(PCG64)
rfloat1: 0.7248204338775774, type(rfloat1): <class 'float'>
rfloat2: 0.1834045080617419, type(rfloat2): <class 'float'>
arr1.shape: (4, 4), type(arr1[0]): <class 'numpy.ndarray'>
arr1:
[[0.9457293 0.11587794 0.80309455 0.87985233]
[0.18287915 0.78253742 0.94084023 0.61667278]
[0.07402969 0.73989851 0.92270829 0.03987515]
[0.39083696 0.89838915 0.47567089 0.36928405]]
arr2.shape: (4, 4), type(arr2[0]): <class 'numpy.ndarray'>
arr2:
[[0.8838273 0.34347188 0.81374641 0.23138231]
[0.49235117 0.05973503 0.74662402 0.51387277]
[0.05994213 0.43779146 0.82835965 0.18615186]
[0.4786654 0.02589436 0.54970699 0.06996595]]
Process finished with exit code 0
1.6. Tối ưu hóa benchmarking cho phép chập CUDA
Thư viện cuDNN, được sử dụng bởi các thao tác chập CUDA, có thể là nguồn gây ra hành vi không xác định trên nhiều lần thực thi ứng dụng. Khi một phép chập cuDNN được gọi với một tập hợp tham số kích thước mới, một tính năng tùy chọn có thể chạy nhiều thuật toán chập, benchmarking chúng để tìm thuật toán nhanh nhất. Sau đó, thuật toán nhanh nhất sẽ được sử dụng nhất quán trong phần còn lại của quá trình cho tập hợp tham số kích thước tương ứng. Do nhiễu benchmarking và phần cứng khác nhau, benchmark có thể chọn các thuật toán khác nhau trong các lần chạy tiếp theo, ngay cả trên cùng một máy.
Tắt tính năng benchmarking với torch.backends.cudnn.benchmark = False khiến cuDNN chọn thuật toán một cách xác định, có thể với chi phí giảm hiệu suất.
Tuy nhiên, nếu bạn không cần khả năng tái tạo trên nhiều lần thực thi ứng dụng, hiệu suất có thể được cải thiện nếu tính năng benchmarking được bật với torch.backends.cudnn.benchmark = True.
Lưu ý rằng cài đặt này khác với cài đặt torch.backends.cudnn.deterministic được thảo luận bên dưới.
torch.backends.cudnn.benchmark = False: Tắt trình tối ưu hóa tự động của cuDNN, ngăn nó chọn các thuật toán khác nhau trong các lần chạy khác nhau do sự khác biệt nhỏ trong môi trường đánh giá.
1.N. Ví dụ
1.N.1. Ví dụ đơn giản
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Tác giả: Nguyễn Văn A
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import torch
torch.manual_seed(654321)
torch.cuda.manual_seed_all(654321)
print(torch.rand([1, 5]))
print(torch.rand([1, 5]))
print(torch.rand([1, 5]))
print("9" * 16)
torch.manual_seed(654321)
torch.cuda.manual_seed_all(654321)
print(torch.rand([1, 5]))
print(torch.rand([1, 5]))
print(torch.rand([1, 5]))
/home/user/miniconda3/envs/pytorch_env/bin/python /home/user/project/simple_example.py
tensor([[0.2931, 0.9420, 0.4453, 0.8454, 0.6453]])
tensor([[0.3610, 0.3428, 0.8425, 0.8137, 0.9145]])
tensor([[0.6341, 0.8423, 0.4015, 0.6168, 0.9472]])
9999999999999999
tensor([[0.2931, 0.9420, 0.4453, 0.8454, 0.6453]])
tensor([[0.3610, 0.3428, 0.8425, 0.8137, 0.9145]])
tensor([[0.6341, 0.8423, 0.4015, 0.6168, 0.9472]])
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import torch
torch.manual_seed(33)
print(f"torch.randn(2): {torch.randn(2)}")
print(f"torch.randn(2): {torch.randn(2)}")
torch.manual_seed(33)
print(f"\ntorch.randn(2): {torch.randn(2)}")
print(f"torch.randn(2): {torch.randn(2)}")
print(f"torch.randn(2): {torch.randn(2)}")
torch.manual_seed(33)
print(f"\ntorch.randn(2): {torch.randn(2)}")
/home/user/miniconda3/bin/python /home/user/project/normal_example.py
torch.randn(2): tensor([1.2302, -0.4255])
torch.randn(2): tensor([-0.5436, 0.7245])
torch.randn(2): tensor([1.2302, -0.4255])
torch.randn(2): tensor([-0.5436, 0.7245])
torch.randn(2): tensor([0.9179, 0.2166])
torch.randn(2): tensor([1.2302, -0.4255])
Process finished with exit code 0
- Tránh các thuật toán không xác định
torch.use_deterministic_algorithms() cho phép bạn cấu hình PyTorch để sử dụng các thuật toán xác định thay vì các thuật toán không xác định wherever available, và ném ra lỗi nếu một thao tác được biết là không xác định (và không có triển khai xác định thay thế).
Vui lòng kiểm tra tài liệu cho torch.use_deterministic_algorithms() để có danh sách đầy đủ các thao tác bị ảnh hưởng. Nếu một thao tác không hoạt động chính xác theo tài liệu, hoặc nếu bạn cần triển khai xác định của một thao tác không có nó, vui lòng gửi một issue: https://github.com/pytorch/pytorch/issues?q=label:%22module:%20determinism%22
Ví dụ, chạy triển khai CUDA không xác định của torch.Tensor.index_add_() sẽ gây ra lỗi:
>>> import torch
>>> torch.use_deterministic_algorithms(True)
>>> torch.randn(2, 2).cuda().index_add_(0, torch.tensor([0, 1]), torch.randn(2, 2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: index_add_cuda_ does not have a deterministic implementation, but you set
'torch.use_deterministic_algorithms(True)'. ...
Khi torch.bmm() được gọi với tensor thưa-dense CUDA, nó thường sử dụng thuật toán không xác định, nhưng khi cờ xác định được bật, triển khai thay thế xác định của nó sẽ được sử dụng:
>>> import torch
>>> torch.use_deterministic_algorithms(True)
>>> torch.bmm(torch.randn(2, 2, 2).to_sparse().cuda(), torch.randn(2, 2, 2).cuda())
tensor([[[ 1.1900, -2.3409],
[ 0.4796, 0.8003]],
[[ 0.1509, 1.8027],
[ 0.0333, -1.1444]]], device='cuda:0')
2.1. Tính xác định của phép chập CUDA
Trong khi tắt benchmarking phép chập CUDA (được thảo luận ở trên) đảm bảo rằng CUDA chọn cùng một thuật toán mỗi khi ứng dụng được chạy, thuật toán đó tự bản thân có thể không xác định, trừ khi torch.use_deterministic_algorithms(True) hoặc torch.backends.cudnn.deterministic = True được đặt. Cài đặt sau chỉ kiểm soát hành vi này, không giống như torch.use_deterministic_algorithms() sẽ làm cho các thao tác PyTorch khác cũng hoạt động một cách xác định.
2.2. RNN và LSTM CUDA
Trong một số phiên bản CUDA, mạng RNN và LSTM có thể có hành vi không xác định. Xem torch.nn.RNN() và torch.nn.LSTM() để biết chi tiết và cách khắc phục.
2.3. Điền bộ nhớ chưa được khởi tạo
Các thao tác như torch.empty() và torch.Tensor.resize_() có thể trả về tensor với bộ nhớ chưa được khởi tạo chứa các giá trị không xác định. Sử dụng một tensor như vậy làm đầu vào cho một thao tác khác là không hợp lệ nếu tính xác định được yêu cầu, vì đầu ra sẽ không xác định. Nhưng không có gì thực sự ngăn chặn mã không hợp lệ này được chạy. Vì vậy, để an toàn, torch.utils.deterministic.fill_uninitialized_memory được đặt thành True theo mặc định, sẽ điền bộ nhớ chưa được khởi tạo với một giá trị đã biết nếu torch.use_deterministic_algorithms(True) được đặt. Điều này sẽ ngăn khả năng xảy ra loại hành vi không xác định này.
Tuy nhiên, việc điền bộ nhớ chưa được khởi tạo có hại cho hiệu suất. Vì vậy, nếu chương trình của bạn hợp lệ và không sử dụng bộ nhớ chưa được khởi tạo làm đầu vào cho một thao tác, thì cài đặt này có thể được tắt để có hiệu suất tốt hơn.
detrimental [ˌdetrɪˈment(ə)l]
adj. Có hại
2.4. DataLoader
DataLoader sẽ đặt lại seed cho các worker theo https://docs.pytorch.org/docs/stable/data.html#data-loading-randomness algorithm.
Nếu DataLoader của bạn sử dụng đa luồng (num_workers > 0), mỗi tiến trình worker sẽ kế thừa seed từ tiến trình chính. Để tránh mỗi worker trong mỗi epoch nhận được cùng một chuỗi ngẫu nhiên, bạn nên sử dụng worker_init_fn() để đặt lại seed trong DataLoader
Sử dụng worker_init_fn() và generator để bảo toàn khả năng tái tạo:
def seed_worker(worker_id):
worker_seed = torch.initial_seed() % 2**32
numpy.random.seed(worker_seed)
random.seed(worker_seed)
g = torch.Generator()
g.manual_seed(0)
DataLoader(
train_dataset,
batch_size=batch_size,
num_workers=num_workers,
worker_init_fn=seed_worker,
generator=g,
)