Ghi nhật ký Python hoạt động như thế nào?

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

Ghi nhật ký Python hoạt động như thế 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, điều tự nhiên là 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. 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 chỉ đơn giản là 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

  1. GỠ LỖI
  2. THÔNG TIN
  3. CẢNH BÁO
  4. LỖI
  5. 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 a thông báo cảnh báo

LỖI. gốc. Đây một thông báo lỗi message

CỰC QUAN TRỌNG. gốc. Đây a thông báo quan trọng

This is because the root logger, by default, only prints the log messages of a severity level of WARNING or above. However, using the root logger this way is not much different from using the print() function

The settings for the root logger are not set in stone. We can configure the root logger to output to a particular file, change its default severity level, and format the output.  Here’s an example

1

2

3

4

5

6

7

8

9

10

11

nhập ghi nhật ký

 

logging. basicConfig(filename = 'file. log',

                    level = logging. DEBUG,

                    format = '%(asctime)s. %(levelname)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')

Running this script will produce no output to the screen but will have the following in the newly created file file.log

1

2

3

4

5

2022-03-22 20. 41. 08,151. DEBUG. root. Debug message

2022-03-22 20. 41. 08,152. THÔNG TIN. root. Info message

2022-03-22 20. 41. 08,152. WARNING. root. Warning message

2022-03-22 20. 41. 08,152. ERROR. root. Error message

2022-03-22 20. 41. 08,152. BẠO KÍCH. root. Critical message

The call to logging.basicConfig() is to alter the root logger. In our example, we set the handler to output to a file instead of the screen, adjust the logging level such that all log messages of level DEBUG or above are handled, and also change the format of the log message output to include the time

Note that now all five messages were output, so the default level that the root logger logs is now “DEBUG. ” The log record attributes (such as %(asctime)s) that can be used to format the output can be found

Although there is a default logger, we usually want to make and use other loggers that can be configured separately. This is because we may want a different severity level or format for different loggers. A new logger can be created with

1

logger = logging. getLogger("logger_name")

Internally, the loggers are organized in a hierarchy. A logger created with

1

logger = logging. getLogger("parent. child")

will be a child logger created under the logger with the name “parent,” which, in turn, is under the root logger. Using a dot in the string signifies that the child logger is a child of the parent logger. In the above case, a logger with the name “parent.child” is created as well as one with the name "parent" implicitly

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

logger = logging. getLogger("parent. child")

 

# Emit a log message of level INFO, by default this is not print to the screen

logger. info("this is info level")

 

# Create `parent` logger

parentlogger = logging. getLogger("parent")

 

# Set parent's level to INFO and assign a new handler

handler = logging. StreamHandler()

handler. setFormatter(ghi nhật ký. Trình định dạng("%(asctime)s. %(name)s. %(tên cấp độ)s. %(message)s"))

parentlogger. setLevel(ghi nhật ký. THÔNG TIN)

parentlogger. addHandler(trình xử lý)

 

# Cho phép thiết bị ghi nhật ký con gửi lại thông điệp tường trình

nhật ký. thông tin("đây lại là cấp độ thông tin")

Đoạn mã này sẽ chỉ xuất ra một dòng

1

2022-03-28 19:23. 29,315. cha mẹ. con. THÔNG TIN. đây thông tin cấp lại

được tạo bởi đối tượng StreamHandler với chuỗi định dạng tùy chỉnh. Điều này chỉ xảy ra sau khi chúng tôi định cấu hình lại trình ghi nhật ký cho parent vì nếu không, cấu hình của trình ghi gốc sẽ chiếm ưu thế và không có thông báo nào ở cấp INFO sẽ được in

Cấu hình nâng cao để ghi nhật ký

Như chúng ta đã thấy trong ví dụ trước, chúng ta có thể định cấu hình bộ ghi mà chúng ta đã tạo

Ngưỡng cấp độ

Giống như cấu hình cơ bản của bộ ghi gốc, chúng tôi cũng có thể định cấu hình đích đầu ra, mức độ nghiêm trọng và định dạng của bộ ghi. Sau đây là cách chúng tôi có thể đặt ngưỡng cấp độ của bộ ghi thành INFO

1

2

parent_logger = ghi nhật ký. getLogger("parent")

parent_logger. setLevel(ghi nhật ký. THÔNG TIN)

Giờ đây, các lệnh có mức độ nghiêm trọng INFO trở lên sẽ được ghi lại bởi parent_logger. Nhưng nếu đây là tất cả những gì bạn đã làm, bạn sẽ không thấy bất cứ điều gì từ logging,0 bởi vì không có trình xử lý nào được chỉ định cho trình ghi nhật ký này. Trên thực tế, cũng không có trình xử lý nào cho trình ghi nhật ký gốc trừ khi bạn thiết lập một trình xử lý với logging.basicConfig()

Trình xử lý nhật ký

Chúng tôi có thể định cấu hình đích đầu ra của trình ghi nhật ký của mình bằng các trình xử lý. Trình xử lý chịu trách nhiệm gửi thông điệp tường trình đến đúng đích. Có một số loại trình xử lý; . Với logging,2, bộ ghi sẽ xuất ra thiết bị đầu cuối, trong khi với logging,3, bộ ghi sẽ xuất ra một tệp cụ thể

Đâ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ý

 

# Thiết lập bộ ghi gốc và thêm trình xử lý tệp vào bộ ghi gốc

logging. basicConfig(filename = 'file. log',

                    cấp độ = ghi nhật ký. CẢNH BÁO,

                    format = '%(asctime)s. %(levelname)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 = ghi nhật ký. getLogger("parent")

parent_logger. setLevel(ghi nhật ký. THÔNG TIN)

parent_shandler = ghi nhật ký. 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. gỡ lỗi('Thông báo gỡ lỗi')

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 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 các bản ghi đến thiết bị đầu cuối, các bản ghi từ bộ ghi nhật ký parent vẫn được gửi đến file.log vì nó là phần tử 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 phần tử con. Chúng ta có thể thấy rằng các bản ghi vào thiết bị đầu cuối bao gồm các thông báo cấp INFO trở lên

1

2

3

4

tin nhắn thông tin

Tin nhắn cảnh báo

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. Nhật ký của file.log, tuy nhiên, đã 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ý

 

# Thiết lập bộ ghi gốc và thêm trình xử lý tệp vào bộ ghi gốc

logging. basicConfig(filename = 'file. log',

                    cấp độ = ghi nhật ký. CẢNH BÁO,

                    format = '%(asctime)s. %(levelname)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 = ghi nhật ký. getLogger("parent")

parent_logger. setLevel(ghi nhật ký. THÔNG TIN)

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. gỡ lỗi('Thông báo gỡ lỗi')

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.log0 là

1

2

3

Tin nhắn cảnh báo

Thông báo lỗi

thông điệp quan trọng

trong khi đó của file.log vẫn 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ý,

  1. 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
  2. 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.log3 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ý

 

# Thiết lập bộ ghi gốc và thêm trình xử lý tệp vào bộ ghi gốc

logging. basicConfig(filename = 'file. log',

                    cấp độ = ghi nhật ký. CẢNH BÁO,

                    format = '%(asctime)s. %(levelname)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 = ghi nhật ký. getLogger("parent")

parent_logger. setLevel(ghi nhật ký. THÔNG TIN)

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. gỡ lỗi('Thông báo gỡ lỗi')

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.log0 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. Thông báo lỗi

2022-03-23 ​​13. 28. 31,303. BẠO KÍCH. thông điệp quan trọng

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ẹ. thông điệp quan trọng

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ừ

Ghi nhật ký Python hoạt động như thế nào?

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

# tối ưu hóa độ dốc gốc với nadam cho chức năng kiểm tra hai chiều

từ toán học nhập sqrt

từ numpy nhập asarray

từ 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):

# tạo điểm ban đầu

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 cho _ trong phạm vi . bounds.hình dạng[0])]

n = [0. 0 cho _ trong phạm vi . bounds.hình dạng[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.hình dạng[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], [- . 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

tốt nhất, điểm = 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.log7 trước khi chúng tôi chạy bất kỳ mã nào và chỉ định 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ý. Trình định dạng("%(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ý. GỠ LỖI)

# 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. Sau đó, trong chức năng file.log9, chúng tôi tạo lại một trình ghi nhật ký logging.basicConfig()0 nhưng vì nó đã được thiết lập nên cấp độ và trình xử lý vẫn tồn tại. Ở cuối mỗi vòng lặp for bên ngoài trong file.log9, 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 = giới hạn[:, 0] + rand . (len(bounds)) * (bounds[:, 1] - giới hạn . [:, 0])

    score = objective(x[0], x[1])

    # initialize decaying moving averages

    m = [0. 0 for _ in range(bounds. shape[0])]

    n = [0. 0 for _ in range(bounds. shape[0])]

    # run the gradient descent

    for t in range(n_iter).

        # calculate gradient g(t)

        g = đạo hàm(x[0], x[1])

        # build a solution one variable at a time

        for i in range(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)) + ((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

        score = objective(x[0], x[1])

        # report progress using logger

        logger. info('>%d f(%s) = %. 5f' % (t, x, score))

    return [x, score]

 

.. .

If we are interested in the deeper mechanics of the Nadam algorithm, we may add more logs. The following is the complete code

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

# tối ưu hóa độ dốc gốc với nadam cho chức năng kiểm tra hai chiều

nhập ghi nhật ký

từ toán học nhập sqrt

từ numpy nhập asarray

từ 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 = giới hạn[:, 0] + rand . (len(bounds)) * (bounds[:, 1] - giới hạn . [:, 0])

    score = objective(x[0], x[1])

    # initialize decaying moving averages

    m = [0. 0 for _ in range(bounds. shape[0])]

    n = [0. 0 for _ in range(bounds. shape[0])]

    # run the gradient descent

    for t in range(n_iter).

        iterlogger = logging. getLogger("nadam. iter")

        # calculate gradient g(t)

        g = đạo hàm(x[0], x[1])

        # build a solution one variable at a time

        for i in range(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)) + ((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. info("Iteration %d variable %d. mhat=%f nhat=%f", t, i, mhat, nhat)

        # evaluate candidate point

        score = objective(x[0], x[1])

        # report progress

        logger. info('>%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ý. Trình định dạng("%(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ý. GỠ LỖI)

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], [- . 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

tốt nhất, điểm = nadam(objective, derivative, bounds, n_iter, alpha, mu, nu)

in('Xong. ')

in('f(%s) = %f' % (best, score))

We prepared two level of loggers, file.log7 and logging.basicConfig()5, and set them in different levels. In the inner loop of file.log9, we use the child logger to print some internal variables. 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. THÔNG TIN. nadam. >1 f([-0. 09764012  0. 37082777]) = 0. 14705

2022-03-29 12. 24. 59,421. 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

2022-03-29 12. 24. 59,421. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 2 biến 1. mhat=2. 304132 nhat=1. 977457

2022-03-29 12. 24. 59,421. THÔNG TIN. nadam. >2 f([-0. 06799761  0. 33805721]) = 0. 11891

...

2022-03-29 12. 24. 59,449. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 49 biến 0. mhat=-0. 000482 nhat=0. 246709

2022-03-29 12. 24. 59,449. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 49 biến 1. mhat=-0. 018244 nhat=3. 966938

2022-03-29 12. 24. 59,449. THÔNG TIN. nadam. >49 f([-5. 54299505e-05 -1. 00116899e-03]) = 0. 00000

Xong

f([-5. 54299505e-05 -1. 00116899e-03]) = 0. 000001

Đặt các trình ghi nhật ký khác nhau không chỉ cho phép chúng tôi đặt cấp độ hoặc trình xử lý khác nhau mà còn cho phép chúng tôi phân biệt thông báo nhật ký đến từ đâu bằng cách xem tên của trình ghi nhật ký từ thông báo được in

Trên thực tế, một mẹo hữu ích là tạo trình trang trí ghi nhật ký và áp dụng trình trang trí cho một số chức năng. Chúng ta có thể theo dõi mỗi khi chức năng đó được gọi. Ví dụ: chúng tôi đã tạo một trình trang trí bên dưới và áp dụng nó cho các chức năng logging.basicConfig()7 và 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

.. .

 

# Trình trang trí Python để ghi nhật ký lệnh gọi hàm và giá trị trả về

def loggingdecorator(name):

    ghi nhật ký = ghi nhật ký. getLogger(tên)

    def _decor(fn):

        tên_hàm = 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.mặt hàng()]

            máy ghi. gỡ lỗi("%s(%s) -> %s" . function_name, ", ".tham gia(argstr), ret)

            return ret

        return _fn

    return _decor

 

# hàm mục tiêu

@loggingdecorator("nadam. chức năng")

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. chức năng")

def đạo hàm(x, y):

    return asarray([x * 2. 0, y * 2. 0])

Sau đó, chúng ta sẽ thấy những điều sau đây trong nhật ký

1

2

3

4

5

6

7

8

9

10

11

12

13

14

2022-03-29 13. 14. 07,542. GỠ LỖI. nadam. hàm số. mục tiêu(-0. 165955990594852, 0. 4406489868843162) -> 0. 22171292045649288

2022-03-29 13. 14. 07,542. GỠ LỖI. nadam. hàm số. đạo hàm(-0. 165955990594852, 0. 4406489868843162) -> [-0. 33191198  0. 88129797]

2022-03-29 13. 14. 07,542. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 0 biến 0. mhat=-0. 597442 nhat=0. 110055

2022-03-29 13. 14. 07,542. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 0 biến 1. mhat=1. 586336 nhat=0. 775909

2022-03-29 13. 14. 07,542. GỠ LỖI. nadam. hàm số. mục tiêu(-0. 12993797816930272, 0. 4046309737819536) -> 0. 18061010311445824

2022-03-29 13. 14. 07,543. THÔNG TIN. nadam. >0 f([-0. 12993798  0. 40463097]) = 0. 18061

2022-03-29 13. 14. 07,543. GỠ LỖI. nadam. hàm số. đạo hàm(-0. 12993797816930272, 0. 4046309737819536) -> [-0. 25987596  0. 80926195]

2022-03-29 13. 14. 07,543. THÔNG TIN. nadam. lặp đi lặp lại. Lặp lại 1 biến 0. mhat=-0. 680200 nhat=0. 177413

2022-03-29 13. 14. 07,543. THÔNG TIN. 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. nadam. hàm số. mục tiêu(-0. 09764011794760165, 0. 3708277653552375) -> 0. 14704682419118062

2022-03-29 13. 14. 07,543. THÔNG TIN. nadam. >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 hàm đó 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 theo dõi các vấn đề dễ dàng hơn là đánh dấu nhật ký bằng màu với mô-đun %(asctime)s0. 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)s0 với mô-đun %(asctime)s2 để 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ý. GỠ LỖI)

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ý. gỡ lỗi('Thông báo gỡ lỗi')

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 + 'Thông báo cảnh báo')

nhật ký. lỗi(Trước. VÀNG + Kiểu dáng. SÁNG + 'Thông báo lỗi')

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

Ghi nhật ký Python hoạt động như thế nào?

trong đó %(asctime)s3, %(asctime)s4 và %(asctime)s5 từ mô-đun %(asctime)s0 kiểm soát kiểu nền trước, nền sau và độ sáng của văn bản được in. Điều này đang tận dụng các ký tự thoát ANSI và chỉ hoạt động trên các thiết bị đầu cuối được ANSI hỗ trợ. Do đó, điều này không phù hợp để đăng nhập vào tệp văn bản

Trên thực tế, chúng ta có thể dẫn xuất lớp print()4 với

1

2

3

4

5

6

7

8

9

.. .

colors = {"DEBUG". Dành cho. XANH DƯƠNG, "THÔNG TIN". Cho. CYAN,

          "CẢNH BÁO". Cho. VÀNG, "ERROR". Trước. ĐỎ, "CẤM". Trước. MAGENTA}

lớp ColoredFormatter(ghi nhật ký. Trình định dạng).

    def định dạng(chính, record):

        tin nhắn = ghi nhật ký. Trình định dạng. định dạng(bản thân, bản ghi)

        nếu ghi. tên cấp độ trong màu sắc.

            tin nhắn = màu sắc[record.tên cấp độ] + tin nhắn + . Fore.ĐẶT LẠI

        trả về tin nhắn

và sử dụng cái này thay cho %(asctime)s8. Sau đây là cách chúng ta có thể sửa đổi thêm ví dụ Nadam để thêm màu

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

# tối ưu hóa độ dốc gốc với nadam cho chức năng kiểm tra hai chiều

nhập ghi nhật ký

nhập colorama

từ colorama nhập Fore

 

từ toán học nhập sqrt

từ numpy nhập asarray

từ numpy. ngẫu nhiên nhập ranh giới

từ numpy. ngẫu nhiên nhập hạt

 

def loggingdecorator(name):

    ghi nhật ký = ghi nhật ký. getLogger(tên)

    def _decor(fn):

        tên_hàm = 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.mặt hàng()]

            máy ghi. gỡ lỗi("%s(%s) -> %s" . function_name, ", ".tham gia(argstr), ret)

            return ret

        return _fn

    return _decor

 

# hàm mục tiêu

@loggingdecorator("nadam. chức năng")

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. chức năng")

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 = giới hạn[:, 0] + rand . (len(bounds)) * (bounds[:, 1] - giới hạn . [:, 0])

    score = objective(x[0], x[1])

    # initialize decaying moving averages

    m = [0. 0 for _ in range(bounds. shape[0])]

    n = [0. 0 for _ in range(bounds. shape[0])]

    # run the gradient descent

    for t in range(n_iter).

        iterlogger = logging. getLogger("nadam. iter")

        # calculate gradient g(t)

        g = đạo hàm(x[0], x[1])

        # build a solution one variable at a time

        for i in range(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)) + ((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. info("Iteration %d variable %d. mhat=%f nhat=%f", t, i, mhat, nhat)

        # evaluate candidate point

        score = objective(x[0], x[1])

        # report progress

        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". Dành cho. XANH DƯƠNG, "THÔNG TIN". Cho. CYAN,

          "CẢNH BÁO". Cho. VÀNG, "ERROR". Trước. ĐỎ, "CẤM". Trước. MAGENTA}

lớp ColoredFormatter(ghi nhật ký. Trình định dạng).

    def định dạng(chính, record):

        tin nhắn = ghi nhật ký. Trình định dạng. định dạng(bản thân, bản ghi)

        nếu ghi. tên cấp độ trong màu sắc.

            tin nhắn = màu sắc[record.tên cấp độ] + tin nhắn + . Fore.ĐẶT LẠI

        trả về tin nhắn

 

# 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ý. GỠ LỖI)

logger = logging. getLogger("nadam. iter")

nhật ký. setLevel(ghi nhật ký. GỠ LỖI)

# 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], [- . 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

tốt nhất, điểm = 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

Ghi nhật ký Python hoạt động như thế nào?

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ã

Cách ghi nhật ký được sử dụng trong Python?

Mô-đun ghi nhật ký . Với mô-đun ghi nhật ký đã được nhập, bạn có thể sử dụng thứ gọi là “trình ghi nhật ký” để ghi nhật ký các tin nhắn mà bạn muốn xem. integrate your log messages with the ones from those libraries to produce a homogeneous log for your application. With the logging module imported, you can use something called a “logger” to log messages that you want to see.

Ghi nhật ký Python có được tích hợp sẵn không?

Python có ghi nhật ký mô-đun tích hợp sẵn cho phép ghi thông báo trạng thái vào một tệp hoặc bất kỳ luồng đầu ra nào khác.

Ghi nhật ký Python có sử dụng log4j không?

log4j là gói ghi nhật ký phổ biến được viết bằng Java. log4j đã được chuyển sang các ngôn ngữ C, C++, C#, Perl, Python, Ruby và Eiffel .

Ghi nhật ký Python có dễ bị tấn công không?

Rất may, Việc ghi nhật ký của Python không dễ bị thực thi mã từ xa . Tuy nhiên, điều quan trọng vẫn là phải cẩn thận với dữ liệu không đáng tin cậy. Bài viết này sẽ mô tả một số cạm bẫy phổ biến và cách thực hành phổ biến của việc ghi chuỗi f có thể — trong một số trường hợp — khiến bạn dễ bị tấn công bởi các kiểu tấn công khác.