Ghi nhật ký là một cách để lưu trữ thông tin về tập lệnh của bạn và theo dõi các sự kiện xảy ra. Khi viết bất kỳ tập lệnh phức tạp nào bằng Python, việc ghi nhật ký là điều cần thiết để gỡ lỗi phần mềm khi bạn phát triển phần mềm đó. Nếu không đăng nhập, việc tìm nguồn gốc của sự cố trong mã của bạn có thể cực kỳ tốn thời gian
Sau khi hoàn thành hướng dẫn này, bạn sẽ biết
- Tại sao chúng tôi muốn sử dụng mô-đun ghi nhật ký
- Cách sử dụng mô-đun ghi nhật ký
- Cách tùy chỉnh cơ chế ghi nhật ký
Bắt đầu dự án của bạn với cuốn sách mới Python for Machine Learning của tôi, bao gồm các hướng dẫn từng bước và các tệp mã nguồn Python cho tất cả các ví dụ
Bắt đầu nàoĐăng nhập bằng Python
Ảnh của ilaria88. Một số quyền được bảo lưu.
Hướng dẫn tổng quan
Hướng dẫn này được chia thành bốn phần;
- Lợi ích của việc ghi nhật ký
- ghi nhật ký cơ bản
- Cấu hình nâng cao để đăng nhập
- Một ví dụ về việc sử dụng ghi nhật ký
Lợi ích của việc ghi nhật ký
Bạn có thể yêu cầu. “Tại sao không chỉ sử dụng in ấn?”
Khi bạn chạy một thuật toán và muốn xác nhận rằng nó đang làm những gì bạn mong đợi, thì việc thêm một số câu lệnh print[]
tại các vị trí chiến lược để hiển thị trạng thái của chương trình là điều đương nhiên. Tính năng in có thể giúp gỡ lỗi các tập lệnh đơn giản hơn, nhưng khi mã của bạn ngày càng phức tạp hơn, tính năng in sẽ thiếu tính linh hoạt và mạnh mẽ mà tính năng ghi nhật ký có được
Với tính năng ghi nhật ký, bạn có thể xác định nơi xuất phát lệnh gọi ghi nhật ký, phân biệt mức độ nghiêm trọng giữa các thông báo và ghi thông tin vào một tệp, điều mà việc in ấn không thể thực hiện được. Ví dụ: chúng ta có thể bật và tắt thông báo từ một mô-đun cụ thể của chương trình lớn hơn. Chúng tôi cũng có thể tăng hoặc giảm mức độ chi tiết của thông báo ghi nhật ký mà không cần thay đổi nhiều mã
Ghi nhật ký cơ bản
Python có một thư viện tích hợp sẵn, logging,
cho mục đích này. Thật đơn giản để tạo một “logger” để ghi lại các tin nhắn hoặc thông tin mà bạn muốn xem
Hệ thống ghi nhật ký trong Python hoạt động theo một không gian tên phân cấp và các mức độ nghiêm trọng khác nhau. Tập lệnh Python có thể tạo trình ghi nhật ký trong một không gian tên và mỗi khi một thông báo được ghi, tập lệnh phải chỉ định mức độ nghiêm trọng của nó. Thông báo đã ghi có thể đi đến những nơi khác nhau tùy thuộc vào trình xử lý mà chúng tôi thiết lập cho không gian tên. Trình xử lý phổ biến nhất là chỉ cần in trên màn hình, giống như hàm print[]
phổ biến. Khi chúng tôi bắt đầu chương trình, chúng tôi có thể đăng ký một trình xử lý mới và thiết lập mức độ nghiêm trọng mà trình xử lý sẽ phản ứng
Có 5 cấp độ ghi nhật ký khác nhau cho biết mức độ nghiêm trọng của nhật ký, thể hiện ở mức độ nghiêm trọng tăng dần
- GỠ LỖI
- THÔNG TIN
- CẢNH BÁO
- LỖI
- BẠO KÍCH
Một ví dụ rất đơn giản về ghi nhật ký được hiển thị bên dưới, sử dụng trình ghi nhật ký mặc định hoặc trình ghi nhật ký gốc
1
2
3
4
5
6
7
nhập ghi nhật ký
ghi nhật ký. gỡ lỗi['Thông báo gỡ lỗi']
ghi nhật ký. thông tin['Thông tin thông báo']
ghi nhật ký. cảnh báo['Thông báo cảnh báo']
ghi nhật ký. lỗi['Thông báo lỗi']
ghi nhật ký. quan trọng['Thông báo quan trọng']
Chúng sẽ phát ra các thông điệp tường trình có mức độ nghiêm trọng khác nhau. Trong khi có năm dòng ghi nhật ký, bạn chỉ có thể thấy ba dòng đầu ra nếu bạn chạy tập lệnh này, như sau
1
2
3
CẢNH BÁO. gốc. Đây là a thông báo cảnh báo
LỖI. gốc. Đây là một thông báo lỗi message
CỰC QUAN TRỌNG. gốc. Đây là a thông báo quan trọng
Điều này là do theo mặc định, trình ghi nhật ký gốc chỉ in các thông báo nhật ký ở mức độ nghiêm trọng CẢNH BÁO trở lên. Tuy nhiên, sử dụng root logger theo cách này không khác mấy so với sử dụng hàm print[]
Các cài đặt cho trình ghi gốc không được đặt cố định. Chúng tôi có thể định cấu hình bộ ghi gốc để xuất ra một tệp cụ thể, thay đổi mức độ nghiêm trọng mặc định của nó và định dạng đầu ra. Đây là một ví dụ
1
2
3
4
5
6
7
8
9
10
11
nhập ghi nhật ký
ghi nhật ký. basicConfig[tên tệp = ' . nhật ký',
cấp độ = ghi nhật ký. GỠ LỖI,
định dạng = '%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s']
ghi nhật ký. gỡ lỗi['Thông báo gỡ lỗi']
ghi nhật ký. thông tin['Thông tin thông báo']
ghi nhật ký. cảnh báo['Thông báo cảnh báo']
ghi nhật ký. lỗi['Thông báo lỗi']
ghi nhật ký. quan trọng['Thông báo quan trọng']
Chạy tập lệnh này sẽ không tạo ra kết quả nào trên màn hình nhưng sẽ có phần sau trong tệp mới tạo file.log
1
2
3
4
5
2022-03-22 20. 41. 08,151. GỠ LỖI. nguồn gốc. Thông báo gỡ lỗi
2022-03-22 20. 41. 08,152. THÔNG TIN. nguồn gốc. tin nhắn thông tin
2022-03-22 20. 41. 08,152. CẢNH BÁO. nguồn gốc. Tin nhắn cảnh báo
2022-03-22 20. 41. 08,152. LỖI. nguồn gốc. Thông báo lỗi
2022-03-22 20. 41. 08,152. BẠO KÍCH. nguồn gốc. thông điệp quan trọng
Lệnh gọi tới logging.basicConfig[]
là thay đổi trình ghi nhật ký gốc. Trong ví dụ của chúng tôi, chúng tôi đặt trình xử lý xuất thành tệp thay vì màn hình, điều chỉnh cấp độ ghi nhật ký sao cho tất cả thông báo tường trình ở cấp độ GỠ LỖI hoặc cao hơn đều được xử lý, đồng thời thay đổi định dạng của đầu ra thông báo tường trình để bao gồm thời gian
Lưu ý rằng bây giờ tất cả năm thông báo đã được xuất ra, do đó, mức mặc định mà bộ ghi nhật ký gốc hiện là “DEBUG. ” Có thể tìm thấy các thuộc tính bản ghi nhật ký [chẳng hạn như %[asctime]s
] để định dạng đầu ra trong tài liệu ghi nhật ký
Mặc dù có một trình ghi nhật ký mặc định nhưng chúng tôi thường muốn tạo và sử dụng các trình ghi nhật ký khác có thể được cấu hình riêng. Điều này là do chúng tôi có thể muốn một mức độ nghiêm trọng hoặc định dạng khác nhau cho các trình ghi nhật ký khác nhau. Một logger mới có thể được tạo ra với
1
ghi nhật ký = ghi nhật ký. getLogger["logger_name"]
Trong nội bộ, các logger được tổ chức theo thứ bậc. Một logger được tạo bằng
1
ghi nhật ký = ghi nhật ký. getLogger["parent. child"]
sẽ là một trình ghi nhật ký con được tạo bên dưới trình ghi nhật ký có tên “parent
”, đến lượt nó, nằm dưới trình ghi nhật ký gốc. Sử dụng dấu chấm trong chuỗi biểu thị rằng trình ghi con là con của trình ghi gốc. Trong trường hợp trên, một bộ ghi có tên “parent.child
” được tạo cũng như một bộ ghi có tên "parent"
ngầm định
Upon creation, a child logger has all the properties of its parent logger until reconfigured. We can demonstrate this with the following example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
nhập ghi nhật ký
# Create `parent. child` logger
ghi nhật ký = ghi nhật ký. getLogger["parent. child"]
# Emit a log message of level INFO, by default this is not print to the screen
logger. thông tin["đây là cấp độ thông tin"]
# Create `parent` logger
parentlogger = logging. getLogger["parent"]
# Đặt cấp độ của cha mẹ thành INFO và chỉ định trình xử lý mới
trình xử lý = ghi nhật ký. StreamHandler[]
handler. setFormatter[logging. Formatter["%[asctime]s. %[name]s. %[levelname]s. %[message]s"]]
parentlogger. setLevel[ghi nhật ký. INFO]
parentlogger. addHandler[handler]
# Let child logger emit a log message again
nhật ký. info["this is info level again"]
This code snippet will output only one line
1
2022-03-28 19. 23. 29,315. parent. child. INFO. this is info level again
which is created by the StreamHandler object with the customized format string. It happens only after we reconfigured the logger for parent
because otherwise, the root logger’s configuration prevails, and no messages at level INFO will be printed
Advanced Configuration to Logging
As we saw in the last example, we can configure the loggers we made
Threshold of Level
Like the basic configuration of the root logger, we can also configure the output destination, severity level, and formatting of a logger. The following is how we can set the threshold of the level of a logger to INFO
1
2
parent_logger = logging. getLogger["parent"]
parent_logger. setLevel[logging. INFO]
Now commands with severity level INFO and higher will be logged by the parent_logger. But if this is all you did, you will not see anything from logging,
0 because there are no handlers assigned for this logger. In fact, there are no handlers for root logger as well unless you set up one with logging.basicConfig[]
Log Handlers
We can configure the output destination of our logger with handlers. Handlers are responsible for sending the log messages to the correct destination. There are several types of handlers; the most common ones are logging,
2 and logging,
3. With logging,
2, the logger will output to the terminal, while with logging,
3, the logger will output to a particular file
Đây là một ví dụ về việc sử dụng logging,
2 để xuất nhật ký ra thiết bị đầu cuối
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
nhập ghi nhật ký
# Set up root logger, and add a file handler to root logger
ghi nhật ký. basicConfig[tên tệp = ' . nhật ký',
level = logging. CẢNH BÁO,
định dạng = '%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s']
# Tạo trình ghi nhật ký, đặt cấp độ và thêm trình xử lý luồng
parent_logger = logging. getLogger["parent"]
parent_logger. setLevel[logging. INFO]
parent_shandler = logging. StreamHandler[]
parent_logger. addHandler[parent_shandler]
# Thông báo nhật ký nghiêm trọng INFO hoặc cao hơn sẽ được xử lý
parent_logger. debug['Debug message']
parent_logger. thông tin['Thông tin thông báo']
parent_logger. cảnh báo['Thông báo cảnh báo']
parent_logger. lỗi['Thông báo lỗi']
parent_logger. quan trọng['Thông báo quan trọng']
Trong đoạn mã trên, có hai trình xử lý được tạo. Một logging,
3 được tạo bởi logging.basicConfig[]
cho trình ghi nhật ký gốc và một logging,
2 được tạo cho trình ghi nhật ký parent
Lưu ý rằng mặc dù có một logging,
2 gửi nhật ký đến thiết bị đầu cuối, các nhật ký từ bộ ghi nhật ký parent
vẫn được gửi đến file.log
vì nó là con của bộ ghi nhật ký gốc và trình xử lý của bộ ghi nhật ký gốc cũng đang hoạt động đối với các thông điệp nhật ký của bộ ghi nhật ký con. We can see that the logs to the terminal include INFO level messages and above
1
2
3
4
Info message
Warning message
Thông báo lỗi
thông điệp quan trọng
Nhưng đầu ra của thiết bị đầu cuối không được định dạng, vì chúng tôi chưa sử dụng print[]
4. Tuy nhiên, nhật ký của file.log
đã thiết lập print[]
4 và nó sẽ giống như sau
1
2
3
4
2022-03-22 23. 07. 12,533. THÔNG TIN. cha mẹ. tin nhắn thông tin
2022-03-22 23. 07. 12,533. CẢNH BÁO. cha mẹ. Tin nhắn cảnh báo
2022-03-22 23. 07. 12,533. LỖI. cha mẹ. Thông báo lỗi
2022-03-22 23. 07. 12,533. BẠO KÍCH. cha mẹ. thông điệp quan trọng
Ngoài ra, chúng ta có thể sử dụng logging,
3 trong ví dụ trên của print[]
8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nhập ghi nhật ký
# Set up root logger, and add a file handler to root logger
ghi nhật ký. basicConfig[tên tệp = ' . nhật ký',
level = logging. CẢNH BÁO,
định dạng = '%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s']
# Tạo trình ghi nhật ký, đặt cấp độ và thêm trình xử lý luồng
parent_logger = logging. getLogger["parent"]
parent_logger. setLevel[logging. INFO]
parent_fhandler = ghi nhật ký. Trình xử lý tệp['parent. log']
parent_fhandler. setLevel[ghi nhật ký. CẢNH BÁO]
parent_logger. addHandler[parent_fhandler]
# Thông báo nhật ký nghiêm trọng INFO hoặc cao hơn sẽ được xử lý
parent_logger. debug['Debug message']
parent_logger. thông tin['Thông tin thông báo']
parent_logger. cảnh báo['Thông báo cảnh báo']
parent_logger. lỗi['Thông báo lỗi']
parent_logger. quan trọng['Thông báo quan trọng']
Ví dụ trên đã chứng minh rằng bạn cũng có thể đặt cấp độ của trình xử lý. Cấp độ print[]
9 lọc ra các nhật ký không ở cấp độ CẢNH BÁO hoặc cao hơn. Tuy nhiên, nếu bạn đặt cấp độ của trình xử lý thành GỠ LỖI, thì điều đó cũng giống như không đặt cấp độ vì nhật ký GỠ LỖI đã được lọc ra theo cấp độ của trình ghi nhật ký, đó là THÔNG TIN
Trong trường hợp này, đầu ra của file.log
0 là
1
2
3
Warning message
Thông báo lỗi
thông điệp quan trọng
trong khi đó của file.log
giống như trước đây. Tóm lại, khi một thông điệp nhật ký được ghi lại bởi một bộ ghi nhật ký,
- Cấp độ của trình ghi nhật ký sẽ xác định xem thông báo có đủ nghiêm trọng để xử lý hay không. Nếu cấp độ của trình ghi nhật ký không được đặt, thì cấp độ của trình ghi gốc [và cuối cùng là trình ghi nhật ký gốc] sẽ được sử dụng cho việc xem xét này
- Nếu thông báo nhật ký sẽ được xử lý, thì tất cả các trình xử lý đã từng được thêm dọc theo hệ thống phân cấp bộ ghi nhật ký cho đến bộ ghi nhật ký gốc sẽ nhận được một bản sao của thông báo. Mỗi cấp độ của trình xử lý sẽ xác định xem trình xử lý cụ thể này có tôn trọng thông báo này hay không
Trình định dạng
Để cấu hình định dạng của logger, chúng tôi sử dụng một print[]
4. Nó cho phép chúng tôi đặt định dạng của nhật ký, tương tự như cách chúng tôi đã làm như vậy trong file.log
3 của trình ghi nhật ký gốc. Đây là cách chúng tôi có thể thêm trình định dạng vào trình xử lý của mình
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
nhập ghi nhật ký
# Set up root logger, and add a file handler to root logger
ghi nhật ký. basicConfig[tên tệp = ' . nhật ký',
level = logging. CẢNH BÁO,
định dạng = '%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s']
# Tạo trình ghi nhật ký, đặt cấp độ và thêm trình xử lý luồng
parent_logger = logging. getLogger["parent"]
parent_logger. setLevel[logging. INFO]
parent_fhandler = ghi nhật ký. Trình xử lý tệp['parent. log']
parent_fhandler. setLevel[ghi nhật ký. CẢNH BÁO]
parent_formatter = ghi nhật ký. Trình định dạng['%[asctime]s. %[tên cấp độ]s. %[message]s']
parent_fhandler. setFormatter[parent_formatter]
parent_logger. addHandler[parent_fhandler]
# Thông báo nhật ký nghiêm trọng INFO hoặc cao hơn sẽ được xử lý
parent_logger. debug['Debug message']
parent_logger. thông tin['Thông tin thông báo']
parent_logger. cảnh báo['Thông báo cảnh báo']
parent_logger. lỗi['Thông báo lỗi']
parent_logger. quan trọng['Thông báo quan trọng']
Đầu tiên, chúng tôi tạo một trình định dạng, sau đó đặt trình xử lý của chúng tôi để sử dụng trình định dạng đó. Nếu muốn, chúng tôi có thể tạo một số trình ghi nhật ký, trình xử lý và trình định dạng khác nhau để chúng tôi có thể kết hợp và kết hợp dựa trên sở thích của mình
Trong ví dụ này, file.log
0 sẽ có
1
2
3
2022-03-23 13. 28. 31,302. CẢNH BÁO. Tin nhắn cảnh báo
2022-03-23 13. 28. 31,302. LỖI. Error message
2022-03-23 13. 28. 31,303. BẠO KÍCH. thông điệp quan trọng
và file.log
được liên kết với trình xử lý tại bộ ghi gốc sẽ có
1
2
3
4
2022-03-23 13. 28. 31,302. THÔNG TIN. cha mẹ. tin nhắn thông tin
2022-03-23 13. 28. 31,302. CẢNH BÁO. cha mẹ. Tin nhắn cảnh báo
2022-03-23 13. 28. 31,302. LỖI. cha mẹ. Thông báo lỗi
2022-03-23 13. 28. 31,303. BẠO KÍCH. cha mẹ. Critical message
Dưới đây là trực quan hóa luồng trình ghi nhật ký, trình xử lý và trình định dạng từ tài liệu của mô-đun ghi nhật ký
Biểu đồ luồng của trình ghi nhật ký và trình xử lý trong mô-đun ghi nhật ký
Một ví dụ về việc sử dụng ghi nhật ký
Hãy coi thuật toán Nadam là một ví dụ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# gradient descent optimization with nadam for a two-dimensional test function
from math import sqrt
từ numpy nhập asarray
from numpy. ngẫu nhiên nhập ranh giới
từ numpy. ngẫu nhiên nhập hạt
# hàm mục tiêu
def mục tiêu[x, y]:
return x**2. 0 + y**2. 0
# đạo hàm của hàm mục tiêu
def đạo hàm[x, y]:
trả về xáo trộn[[x * 2.0, y * 2. 0]]
# thuật toán giảm độ dốc với nadam
def nadam[mục tiêu, derivative, bounds, n_iter, alpha, mu, nu, eps=1e-8]:
# generate an initial point
x = giới hạn[. , 0] + rand . [len[bounds]] * [bounds[:, 1] - giới hạn . [:, 0]]
điểm = mục tiêu[x[0], x[1]]
# khởi tạo đường trung bình động giảm dần
m = [0. 0 for _ in range[bounds. shape[0]]]
n = [0. 0 cho _ trong phạm vi . bounds.shape[0]]]
# chạy giảm độ dốc
cho t trong phạm vi[n_iter]:
# tính độ dốc g[t]
g = đạo hàm[x[0], x[1]]
# xây dựng giải pháp từng biến một
cho i trong phạm vi[bounds.shape[0]].
# m[t] = mu * m[t-1] + [1 - mu] * g[t]
m[i] = mu * m[i] + [1.0 - mu] * g[i]
# n[t] = nu * n[t-1] + [1 - nu] * g[t]^2
n[i] = nu * n[i] + [1. 0 - nu] * g[i]**2
# mhat = [mu * m[t] / [1 - mu]] + [[1 - mu] * g[t] / [1 - mu]]
mhat = [mu * m[i] / [1.0 - mu]] . 0 [[1 - mu] * g[i] / [1.0 - mu]]
# nhat = nu * n[t] / [1 - nu]
nhat = nu * n[i] / [1.0 - nu]
# x[t] = x[t-1] - alpha / [sqrt[nhat] + eps] * mhat
x[i] = x[i] - alpha / [sqrt[nhat] + eps] * mhat
# đánh giá điểm ứng viên
điểm = mục tiêu[x[0], x[1]]
# báo cáo tiến độ
in['>%d f[%s] = %. 5f' % [t, x, score]]
return [x, điểm]
# gieo trình tạo số giả ngẫu nhiên
hạt[1]
# xác định phạm vi cho đầu vào
giới hạn = xáo trộn[[[-1.0, 1. 0], [-1. 0, 1. 0]]]
# xác định tổng số lần lặp
n_iter = 50
# kích thước bước
alpha = 0. 02
# yếu tố cho độ dốc trung bình
mu = 0. 8
# hệ số cho độ dốc bình phương trung bình
nu = 0. 999
# thực hiện tìm kiếm giảm độ dốc với nadam
best, score = nadam[objective, derivative, bounds, n_iter, alpha, mu, nu]
in['Xong. ']
in['f[%s] = %f' % [best, score]]
Trường hợp sử dụng đơn giản nhất là sử dụng ghi nhật ký để thay thế hàm print[]
. Chúng ta có thể thực hiện thay đổi sau. Trước tiên, hãy tạo một trình ghi nhật ký có tên file.log
7 trước khi chúng tôi chạy bất kỳ mã nào và gán một logging,
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
. . .
nhập ghi nhật ký
. . .
# Thêm. Tạo logger và chỉ định trình xử lý
ghi nhật ký = ghi nhật ký. getLogger["nadam"]
trình xử lý = ghi nhật ký. StreamHandler[]
trình xử lý. setFormatter[ghi nhật ký. Formatter["%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s"]]
nhật ký. addHandler[trình xử lý]
nhật ký. setLevel[ghi nhật ký. DEBUG]
# gieo trình tạo số giả ngẫu nhiên
hạt[1]
.. . # đoạn mã còn lại
Chúng tôi phải chỉ định một trình xử lý vì chúng tôi chưa bao giờ định cấu hình bộ ghi gốc và đây sẽ là trình xử lý duy nhất từng được tạo. Then, in the function file.log
9, we re-create a logger logging.basicConfig[]
0 but since it has already been set up, the level and handlers persisted. Ở cuối mỗi vòng lặp for bên ngoài trong file.log
9, chúng tôi đã thay thế hàm print[]
bằng logging.basicConfig[]
3 để hệ thống ghi nhật ký xử lý thông báo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
. . .
# thuật toán giảm độ dốc với nadam
def nadam[mục tiêu, derivative, bounds, n_iter, alpha, mu, nu, eps=1e-8]:
# Tạo trình ghi nhật ký
ghi nhật ký = ghi nhật ký. getLogger["nadam"]
# tạo điểm ban đầu
x = bounds[. , 0] + rand . [len[bounds]] * [bounds[:, 1] - giới hạn . [:, 0]]
điểm = mục tiêu[x[0], x[1]]
# khởi tạo đường trung bình động giảm dần
m = [0. 0 cho _ trong phạm vi . bounds.hình dạng[0]]]
n = [0. 0 cho _ trong phạm vi . bounds.shape[0]]]
# chạy giảm độ dốc
cho t trong phạm vi[n_iter]:
# calculate gradient g[t]
g = đạo hàm[x[0], x[1]]
# xây dựng giải pháp cho từng biến một
cho i trong phạm vi[bounds.shape[0]].
# m[t] = mu * m[t-1] + [1 - mu] * g[t]
m[i] = mu * m[i] + [1.0 - mu] * g[i]
# n[t] = nu * n[t-1] + [1 - nu] * g[t]^2
n[i] = nu * n[i] + [1.0 - nu] * g[i]**2
# mhat = [mu * m[t] / [1 - mu]] + [[1 - mu] * g[t] / [1 - mu]]
mhat = [mu * m[i] / [1.0 - mu]] . 0 [[1 - mu] * g[i] / [1.0 - mu]]
# nhat = nu * n[t] / [1 - nu]
nhat = nu * n[i] / [1.0 - nu]
# x[t] = x[t-1] - alpha / [sqrt[nhat] + eps] * mhat
x[i] = x[i] - alpha / [sqrt[nhat] + eps] * mhat
# evaluate candidate point
điểm = mục tiêu[x[0], x[1]]
# báo cáo tiến độ bằng trình ghi nhật ký
máy ghi. thông tin['>%d f[%s] = %. 5f' % [t, x, score]]
return [x, score]
. . .
Nếu chúng tôi quan tâm đến cơ chế sâu hơn của thuật toán Nadam, chúng tôi có thể thêm nhiều nhật ký hơn. Sau đây là mã hoàn chỉnh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# gradient descent optimization with nadam for a two-dimensional test function
nhập ghi nhật ký
from math import sqrt
từ numpy nhập asarray
from numpy. ngẫu nhiên nhập ranh giới
từ numpy. ngẫu nhiên nhập hạt
# hàm mục tiêu
def mục tiêu[x, y]:
return x**2. 0 + y**2. 0
# đạo hàm của hàm mục tiêu
def đạo hàm[x, y]:
return asarray[[x * 2. 0, y * 2. 0]]
# thuật toán giảm độ dốc với nadam
def nadam[mục tiêu, derivative, bounds, n_iter, alpha, mu, nu, eps=1e-8]:
ghi nhật ký = ghi nhật ký. getLogger["nadam"]
# tạo điểm ban đầu
x = bounds[. , 0] + rand . [len[bounds]] * [bounds[:, 1] - giới hạn . [:, 0]]
điểm = mục tiêu[x[0], x[1]]
# khởi tạo đường trung bình động giảm dần
m = [0. 0 cho _ trong phạm vi . bounds.hình dạng[0]]]
n = [0. 0 cho _ trong phạm vi . bounds.shape[0]]]
# chạy giảm độ dốc
cho t trong phạm vi[n_iter]:
iterlogger = ghi nhật ký. getLogger["nadam. iter"]
# calculate gradient g[t]
g = đạo hàm[x[0], x[1]]
# xây dựng giải pháp cho từng biến một
cho i trong phạm vi[bounds.shape[0]].
# m[t] = mu * m[t-1] + [1 - mu] * g[t]
m[i] = mu * m[i] + [1.0 - mu] * g[i]
# n[t] = nu * n[t-1] + [1 - nu] * g[t]^2
n[i] = nu * n[i] + [1.0 - nu] * g[i]**2
# mhat = [mu * m[t] / [1 - mu]] + [[1 - mu] * g[t] / [1 - mu]]
mhat = [mu * m[i] / [1.0 - mu]] . 0 [[1 - mu] * g[i] / [1.0 - mu]]
# nhat = nu * n[t] / [1 - nu]
nhat = nu * n[i] / [1.0 - nu]
# x[t] = x[t-1] - alpha / [sqrt[nhat] + eps] * mhat
x[i] = x[i] - alpha / [sqrt[nhat] + eps] * mhat
iterlogger. thông tin["Lặp %d biến %d. mhat=%f nhat=%f", t, i, mhat, nhat]
# evaluate candidate point
điểm = mục tiêu[x[0], x[1]]
# tiến trình báo cáo
máy ghi. thông tin['>%d f[%s] = %. 5f' % [t, x, score]]
return [x, score]
# Create logger and assign handler
ghi nhật ký = ghi nhật ký. getLogger["nadam"]
trình xử lý = ghi nhật ký. StreamHandler[]
trình xử lý. setFormatter[ghi nhật ký. Formatter["%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s"]]
nhật ký. addHandler[trình xử lý]
nhật ký. setLevel[ghi nhật ký. DEBUG]
logger = logging. getLogger["nadam. iter"]
logger. setLevel[logging. INFO]
# gieo trình tạo số giả ngẫu nhiên
hạt[1]
# xác định phạm vi cho đầu vào
giới hạn = xáo trộn[[[-1.0, 1. 0], [-1. 0, 1. 0]]]
# xác định tổng số lần lặp
n_iter = 50
# kích thước bước
alpha = 0. 02
# yếu tố cho độ dốc trung bình
mu = 0. 8
# hệ số cho độ dốc bình phương trung bình
nu = 0. 999
# thực hiện tìm kiếm giảm độ dốc với nadam
best, score = nadam[objective, derivative, bounds, n_iter, alpha, mu, nu]
in['Xong. ']
in['f[%s] = %f' % [best, score]]
We prepared two level of loggers, file.log
7 and logging.basicConfig[]
5, and set them in different levels. Trong vòng lặp bên trong của file.log
9, chúng tôi sử dụng bộ ghi con để in một số biến nội bộ. When you run this script, it will print the following
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2022-03-29 12. 24. 59,421. INFO. nadam. iter. Iteration 0 variable 0. mhat=-0. 597442 nhat=0. 110055
2022-03-29 12. 24. 59,421. INFO. nadam. iter. Iteration 0 variable 1. mhat=1. 586336 nhat=0. 775909
2022-03-29 12. 24. 59,421. INFO. nadam. >0 f[[-0. 12993798 0. 40463097]] = 0. 18061
2022-03-29 12. 24. 59,421. INFO. nadam. iter. Iteration 1 variable 0. mhat=-0. 680200 nhat=0. 177413
2022-03-29 12. 24. 59,421. INFO. nadam. iter. Iteration 1 variable 1. mhat=2. 020702 nhat=1. 429384
2022-03-29 12. 24. 59,421. INFO. nadam. >1 f[[-0. 09764012 0. 37082777]] = 0. 14705
2022-03-29 12. 24. 59,421. INFO. nadam. iter. Iteration 2 variable 0. mhat=-0. 687764 nhat=0. 215332
2022-03-29 12. 24. 59,421. INFO. nadam. iter. Iteration 2 variable 1. mhat=2. 304132 nhat=1. 977457
2022-03-29 12. 24. 59,421. INFO. nadam. >2 f[[-0. 06799761 0. 33805721]] = 0. 11891
...
2022-03-29 12. 24. 59,449. INFO. nadam. iter. Lặp lại 49 biến 0. mhat=-0. 000482 nhat=0. 246709
2022-03-29 12. 24. 59,449. INFO. nadam. iter. Iteration 49 variable 1. mhat=-0. 018244 nhat=3. 966938
2022-03-29 12. 24. 59,449. INFO. nadam. >49 f[[-5. 54299505e-05 -1. 00116899e-03]] = 0. 00000
Done
f[[-5. 54299505e-05 -1. 00116899e-03]] = 0. 000001
Setting different loggers not only allows us to set a different level or handlers, but it also lets us differentiate where the log message comes from by looking at the logger’s name from the message printed
In fact, one handy trick is to create a logging decorator and apply the decorator to some functions. We can keep track of every time that function is called. For example, we created a decorator below and applied it to the functions logging.basicConfig[]
7 and logging.basicConfig[]
8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
. . .
# A Python decorator to log the function call and return value
def loggingdecorator[name].
logger = logging. getLogger[name]
def _decor[fn].
function_name = fn. __name__
def _fn[*args, **kwargs].
ret = fn[*args, **kwargs]
argstr = [str[x] for x in args]
argstr += [key+"="+str[val] for key,val in kwargs. items[]]
logger. debug["%s[%s] -> %s", function_name, ", ". join[argstr], ret]
return ret
return _fn
return _decor
# hàm mục tiêu
@loggingdecorator["nadam. function"]
def mục tiêu[x, y]:
return x**2. 0 + y**2. 0
# đạo hàm của hàm mục tiêu
@loggingdecorator["nadam. function"]
def đạo hàm[x, y]:
return asarray[[x * 2. 0, y * 2. 0]]
Then we will see the following in the log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2022-03-29 13. 14. 07,542. DEBUG. nadam. function. objective[-0. 165955990594852, 0. 4406489868843162] -> 0. 22171292045649288
2022-03-29 13. 14. 07,542. DEBUG. nadam. function. derivative[-0. 165955990594852, 0. 4406489868843162] -> [-0. 33191198 0. 88129797]
2022-03-29 13. 14. 07,542. INFO. nadam. iter. Iteration 0 variable 0. mhat=-0. 597442 nhat=0. 110055
2022-03-29 13. 14. 07,542. INFO. nadam. iter. Iteration 0 variable 1. mhat=1. 586336 nhat=0. 775909
2022-03-29 13. 14. 07,542. DEBUG. nadam. function. objective[-0. 12993797816930272, 0. 4046309737819536] -> 0. 18061010311445824
2022-03-29 13. 14. 07,543. INFO. nađam. >0 f[[-0. 12993798 0. 40463097]] = 0. 18061
2022-03-29 13. 14. 07,543. DEBUG. nadam. function. derivative[-0. 12993797816930272, 0. 4046309737819536] -> [-0. 25987596 0. 80926195]
2022-03-29 13. 14. 07,543. INFO. nadam. iter. Iteration 1 variable 0. mhat=-0. 680200 nhat=0. 177413
2022-03-29 13. 14. 07,543. INFO. nadam. lặp đi lặp lại. Lặp 1 biến 1. mhat=2. 020702 nhat=1. 429384
2022-03-29 13. 14. 07,543. GỠ LỖI. nađam. function. mục tiêu[-0. 09764011794760165, 0. 3708277653552375] -> 0. 14704682419118062
2022-03-29 13. 14. 07,543. THÔNG TIN. nađam. >1 f[[-0. 09764012 0. 37082777]] = 0. 14705
2022-03-29 13. 14. 07,543. GỠ LỖI. nadam. hàm số. đạo hàm[-0. 09764011794760165, 0. 3708277653552375] -> [-0. 19528024 0. 74165553]
2022-03-29 13. 14. 07,543. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 2 biến 0. mhat=-0. 687764 nhat=0. 215332
...
nơi chúng ta có thể thấy các tham số và giá trị trả về của mỗi cuộc gọi đến hai chức năng đó trong thông báo được ghi bởi bộ ghi nhật ký logging.basicConfig[]
9
Bạn muốn bắt đầu với Python cho Machine Learning?
Tham gia khóa học xử lý sự cố email miễn phí trong 7 ngày của tôi ngay bây giờ [có mã mẫu]
Nhấp để đăng ký và cũng nhận được phiên bản PDF Ebook miễn phí của khóa học
Tải xuống khóa học nhỏ MIỄN PHÍ của bạn
Khi chúng tôi nhận được ngày càng nhiều thông báo tường trình, màn hình thiết bị đầu cuối sẽ trở nên rất bận rộn. Một cách giúp bạn dễ dàng theo dõi các vấn đề hơn là đánh dấu nhật ký bằng màu sắc bằng mô-đun %[asctime]s
0. Bạn cần cài đặt mô-đun trước
1
pip cài đặt colorama
Dưới đây là ví dụ về cách bạn có thể sử dụng mô-đun %[asctime]s
0 với mô-đun %[asctime]s
2 để thay đổi màu nhật ký và độ sáng của văn bản
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
nhập ghi nhật ký
nhập colorama
từ colorama nhập Fore, Back, Style
# Khởi tạo thiết bị đầu cuối cho màu sắc
colorama. init[tự động đặt lại = True]
# Thiết lập nhật ký như bình thường
ghi nhật ký = ghi nhật ký. getLogger["color"]
nhật ký. setLevel[ghi nhật ký. DEBUG]
trình xử lý = ghi nhật ký. StreamHandler[]
trình định dạng = ghi nhật ký. Trình định dạng['%[asctime]s. %[tên cấp độ]s. %[name]s. %[message]s']
người xử lý. setFormatter[bộ định dạng]
nhật ký. addHandler[handler]
# Phát ra thông điệp tường trình với màu sắc
nhật ký. debug['Debug message']
nhật ký. vào[Đối với. XANH LỤC + 'Thông báo thông tin']
nhật ký. cảnh báo[Trước. BLUE + 'Warning message']
nhật ký. lỗi[Trước. VÀNG + Kiểu dáng. BRIGHT + 'Error message']
nhật ký. quan trọng[Trước. ĐỎ + Quay lại. VÀNG + Kiểu dáng. SÁNG + 'Thông báo quan trọng']
Từ thiết bị đầu cuối, bạn sẽ thấy như sau
where the %[asctime]s
3, %[asctime]s
4, and %[asctime]s
5 from the %[asctime]s
0 module control the foreground, background, and brightness style of the text printed. This is leveraging the ANSI escape characters and works only on ANSI-supported terminals. Hence this is not suitable for logging to a text file
In fact, we may derive the print[]
4 class with
1
2
3
4
5
6
7
8
9
. . .
colors = {"DEBUG". Fore. BLUE, "INFO". Fore. CYAN,
"WARNING". Fore. YELLOW, "ERROR". Fore. RED, "CRITICAL". Fore. MAGENTA}
class ColoredFormatter[logging. Formatter].
def format[self, record].
msg = logging. Formatter. format[self, record]
if record. tên cấp độ trong màu sắc.
msg = colors[record. levelname] + msg + Fore. RESET
return msg
and use this instead of %[asctime]s
8. The following is how we can further modify the Nadam example to add color
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# gradient descent optimization with nadam for a two-dimensional test function
nhập ghi nhật ký
nhập colorama
từ colorama nhập Fore
from math import sqrt
từ numpy nhập asarray
from numpy. ngẫu nhiên nhập ranh giới
từ numpy. ngẫu nhiên nhập hạt
def loggingdecorator[name].
logger = logging. getLogger[name]
def _decor[fn].
function_name = fn. __name__
def _fn[*args, **kwargs].
ret = fn[*args, **kwargs]
argstr = [str[x] for x in args]
argstr += [key+"="+str[val] for key,val in kwargs. items[]]
logger. debug["%s[%s] -> %s", function_name, ", ". join[argstr], ret]
return ret
return _fn
return _decor
# hàm mục tiêu
@loggingdecorator["nadam. function"]
def mục tiêu[x, y]:
return x**2. 0 + y**2. 0
# đạo hàm của hàm mục tiêu
@loggingdecorator["nadam. function"]
def đạo hàm[x, y]:
return asarray[[x * 2. 0, y * 2. 0]]
# thuật toán giảm độ dốc với nadam
def nadam[mục tiêu, derivative, bounds, n_iter, alpha, mu, nu, eps=1e-8]:
ghi nhật ký = ghi nhật ký. getLogger["nadam"]
# tạo điểm ban đầu
x = bounds[. , 0] + rand . [len[bounds]] * [bounds[:, 1] - giới hạn . [:, 0]]
điểm = mục tiêu[x[0], x[1]]
# khởi tạo đường trung bình động giảm dần
m = [0. 0 cho _ trong phạm vi . bounds.hình dạng[0]]]
n = [0. 0 cho _ trong phạm vi . bounds.shape[0]]]
# chạy giảm độ dốc
cho t trong phạm vi[n_iter]:
iterlogger = ghi nhật ký. getLogger["nadam. iter"]
# calculate gradient g[t]
g = đạo hàm[x[0], x[1]]
# xây dựng giải pháp cho từng biến một
cho i trong phạm vi[bounds.shape[0]].
# m[t] = mu * m[t-1] + [1 - mu] * g[t]
m[i] = mu * m[i] + [1.0 - mu] * g[i]
# n[t] = nu * n[t-1] + [1 - nu] * g[t]^2
n[i] = nu * n[i] + [1.0 - nu] * g[i]**2
# mhat = [mu * m[t] / [1 - mu]] + [[1 - mu] * g[t] / [1 - mu]]
mhat = [mu * m[i] / [1.0 - mu]] . 0 [[1 - mu] * g[i] / [1.0 - mu]]
# nhat = nu * n[t] / [1 - nu]
nhat = nu * n[i] / [1.0 - nu]
# x[t] = x[t-1] - alpha / [sqrt[nhat] + eps] * mhat
x[i] = x[i] - alpha / [sqrt[nhat] + eps] * mhat
iterlogger. thông tin["Lặp %d biến %d. mhat=%f nhat=%f", t, i, mhat, nhat]
# evaluate candidate point
điểm = mục tiêu[x[0], x[1]]
# tiến trình báo cáo
máy ghi. cảnh báo['>%d f[%s] = %. 5f' % [t, x, score]]
return [x, score]
# Chuẩn bị định dạng màu
colorama. init[tự động đặt lại = True]
colors = {"DEBUG". Fore. BLUE, "INFO". Fore. CYAN,
"WARNING". Fore. YELLOW, "ERROR". Fore. RED, "CRITICAL". Fore. MAGENTA}
class ColoredFormatter[logging. Formatter].
def format[self, record].
msg = logging. Formatter. format[self, record]
if record. tên cấp độ trong màu sắc.
msg = colors[record. levelname] + msg + Fore. RESET
return msg
# Create logger and assign handler
ghi nhật ký = ghi nhật ký. getLogger["nadam"]
trình xử lý = ghi nhật ký. StreamHandler[]
trình xử lý. setFormatter[ColoredFormatter[" . %[tên cấp độ]s. %[name]s. %[tin nhắn]s"]]
nhật ký. addHandler[trình xử lý]
nhật ký. setLevel[ghi nhật ký. DEBUG]
logger = logging. getLogger["nadam. iter"]
nhật ký. setLevel[ghi nhật ký. DEBUG]
# gieo trình tạo số giả ngẫu nhiên
hạt[1]
# xác định phạm vi cho đầu vào
giới hạn = xáo trộn[[[-1.0, 1. 0], [-1. 0, 1. 0]]]
# xác định tổng số lần lặp
n_iter = 50
# kích thước bước
alpha = 0. 02
# yếu tố cho độ dốc trung bình
mu = 0. 8
# hệ số cho độ dốc bình phương trung bình
nu = 0. 999
# thực hiện tìm kiếm giảm độ dốc với nadam
best, score = nadam[objective, derivative, bounds, n_iter, alpha, mu, nu]
in['Xong. ']
in['f[%s] = %f' % [best, score]]
Nếu chúng ta chạy nó trên một thiết bị đầu cuối hỗ trợ, chúng ta sẽ thấy đầu ra sau
Lưu ý rằng đầu ra đầy màu sắc có thể giúp chúng tôi phát hiện mọi hành vi bất thường dễ dàng hơn. Ghi nhật ký giúp gỡ lỗi và cũng cho phép chúng tôi dễ dàng kiểm soát mức độ chi tiết mà chúng tôi muốn xem bằng cách chỉ thay đổi một vài dòng mã