Redis
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> Redis

Keras dự đoán sẽ không quay trở lại bên trong nhiệm vụ cần tây

Tôi gặp phải vấn đề chính xác này, và người đàn ông có phải nó là một cái lỗ thỏ. Tôi muốn đăng giải pháp của tôi ở đây vì nó có thể tiết kiệm cho ai đó một ngày làm việc:

Cấu trúc dữ liệu theo chuỗi cụ thể của TensorFlow

Trong TensorFlow, có hai cấu trúc dữ liệu chính đang hoạt động đằng sau khi bạn gọi model.predict (hoặc keras.models.load_model hoặc keras.backend.clear_session hoặc gần như bất kỳ chức năng nào khác tương tác với phần phụ trợ TensorFlow):

  • Biểu đồ TensorFlow, biểu thị cấu trúc mô hình Keras của bạn
  • Phiên TensorFlow, là kết nối giữa biểu đồ hiện tại của bạn và thời gian chạy TensorFlow

Điều gì đó không rõ ràng rõ ràng trong tài liệu mà không có một số nghiên cứu là cả phiên và biểu đồ đều là thuộc tính của chuỗi hiện tại . Xem tài liệu API tại đây và tại đây.

Sử dụng mô hình TensorFlow trong các chủ đề khác nhau

Điều tự nhiên là bạn muốn tải mô hình của mình một lần và sau đó gọi .predict() trên đó nhiều lần sau đó:

from keras.models import load_model

MY_MODEL = load_model('path/to/model/file')

def some_worker_function(inputs):
    return MY_MODEL.predict(inputs)

Trong ngữ cảnh máy chủ web hoặc nhóm công nhân như Celery, điều này có nghĩa là bạn sẽ tải mô hình khi nhập mô-đun có chứa load_model dòng, sau đó một chuỗi khác sẽ thực thi some_worker_function , chạy dự đoán trên biến toàn cục có chứa mô hình Keras. Tuy nhiên, việc cố gắng chạy dự đoán trên một mô hình được tải trong một luồng khác sẽ tạo ra lỗi "tensor không phải là một phần tử của biểu đồ này". Cảm ơn một số bài đăng SO đã đề cập đến chủ đề này, chẳng hạn như ValueError:Tensor Tensor (...) không phải là một phần tử của biểu đồ này. Khi sử dụng mô hình keras biến toàn cục. Để làm cho điều này hoạt động, bạn cần phải bám vào biểu đồ TensorFlow đã được sử dụng - như chúng ta đã thấy trước đó, biểu đồ là một thuộc tính của luồng hiện tại. Mã được cập nhật trông giống như sau:

from keras.models import load_model
import tensorflow as tf

MY_MODEL = load_model('path/to/model/file')
MY_GRAPH = tf.get_default_graph()

def some_worker_function(inputs):
    with MY_GRAPH.as_default():
        return MY_MODEL.predict(inputs)

Điều hơi ngạc nhiên ở đây là: mã trên là đủ nếu bạn đang sử dụng Thread s, nhưng bị treo vô thời hạn nếu bạn đang sử dụng Process es. Và theo mặc định, Celery sử dụng các quy trình để quản lý tất cả các nhóm công nhân của nó. Vì vậy, tại thời điểm này, mọi thứ vẫn vẫn không hoạt động trên Cần tây.

Tại sao điều này chỉ hoạt động trên Thread s?

Trong Python, Thread s chia sẻ cùng một bối cảnh thực thi toàn cục như quy trình mẹ. Từ tài liệu Python _thread:

Mô-đun này cung cấp các nguyên tắc cấp thấp để làm việc với nhiều luồng (còn được gọi là các quy trình hoặc tác vụ nhẹ) - nhiều luồng điều khiển chia sẻ không gian dữ liệu toàn cầu của chúng.

Bởi vì các luồng không phải là các quy trình riêng biệt thực tế, chúng sử dụng cùng một trình thông dịch python và do đó phải tuân theo Global Interpeter Lock (GIL) khét tiếng. Có lẽ quan trọng hơn đối với cuộc điều tra này, họ chia sẻ không gian dữ liệu toàn cục với gốc.

Ngược lại với điều này, Process es là thực tế các quy trình mới được tạo ra bởi chương trình. Điều này có nghĩa là:

  • Phiên bản trình thông dịch Python mới (và không có GIL)
  • Không gian địa chỉ chung bị trùng lặp

Lưu ý sự khác biệt ở đây. Trong khi Thread s có quyền truy cập vào một biến Phiên toàn cầu được chia sẻ (được lưu trữ nội bộ trong tensorflow_backend mô-đun của Keras), Process có các bản sao của biến Phiên.

Sự hiểu biết tốt nhất của tôi về vấn đề này là biến Phiên được cho là đại diện cho một kết nối duy nhất giữa ứng dụng khách (quy trình) và thời gian chạy TensorFlow, nhưng do bị trùng lặp trong quy trình phân nhánh, thông tin kết nối này không được điều chỉnh đúng cách. Điều này khiến TensorFlow bị treo khi cố gắng sử dụng Phiên được tạo trong một quy trình khác. Nếu ai đó có cái nhìn sâu sắc hơn về cách điều này đang hoạt động dưới mui xe trong TensorFlow, tôi rất muốn nghe nó!

Giải pháp / Cách giải quyết

Tôi đã điều chỉnh Celery để nó sử dụng Thread s thay vì Process es để gộp. Có một số nhược điểm đối với cách tiếp cận này (xem bình luận GIL ở trên), nhưng điều này cho phép chúng tôi tải mô hình chỉ một lần. Chúng tôi không thực sự ràng buộc CPU vì thời gian chạy TensorFlow tối đa hóa tất cả các lõi CPU (nó có thể vượt qua GIL vì nó không được viết bằng Python). Bạn phải cung cấp cho Celery một thư viện riêng để thực hiện gộp chung dựa trên luồng; tài liệu đề xuất hai tùy chọn:gevent hoặc eventlet . Sau đó, bạn chuyển thư viện bạn chọn vào worker thông qua --pool đối số dòng lệnh.

Ngoài ra, có vẻ như (như bạn đã phát hiện ra @ pX0r) rằng các chương trình phụ trợ Keras khác như Theano không gặp vấn đề này. Điều đó có ý nghĩa, vì những vấn đề này có liên quan chặt chẽ đến chi tiết triển khai TensorFlow. Cá nhân tôi vẫn chưa thử Theano, vì vậy số dặm của bạn có thể thay đổi.

Tôi biết câu hỏi này đã được đăng một thời gian trước, nhưng vấn đề vẫn còn đó, vì vậy hy vọng điều này sẽ giúp ích cho ai đó!



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Có cách nào để làm việc với các phiên mà không bị khóa trên trang ASP.Net MVC không?

  2. Php7 Redis Client trên Alpine OS

  3. Redis, Node.js và Socket.io:Xác thực máy chủ chéo và hiểu node.js

  4. Làm lại danh sách các khóa lồng nhau

  5. Rails Redis thiết lập maxmemory và maxmemory-policy