Tôi đã có phần mềm mạng thần kinh thú vị tuyệt vời trong những năm 90 và tôi đã lo lắng để thử tạo một số sử dụng Tensorflow.
Khung máy trí thông minh của Google là độ nóng mới ngay bây giờ. Và khi Tensorflow trở nên có thể cài đặt trên Raspberry PI, làm việc với nó trở nên rất dễ thực hiện. Trong một thời gian ngắn, tôi đã tạo ra một mạng lưới thần kinh được tính vào nhị phân. Vì vậy, tôi nghĩ rằng tôi đã vượt qua những gì tôi đã học được cho đến nay. Hy vọng điều này giúp bất cứ ai khác muốn thử nó, hoặc đối với bất kỳ ai chỉ muốn một số cái nhìn sâu sắc về các mạng lưới thần kinh.
Tensorflow là gì?
Để trích dẫn trang web TensorFlow, Tensorflow là một “thư viện phần mềm nguồn mở cho tính toán số bằng cách sử dụng biểu đồ dòng dữ liệu”. Chúng ta có ý nghĩa gì với “biểu đồ dòng dữ liệu”? Chà, đó là phần thực sự tuyệt vời. Nhưng trước khi chúng ta có thể trả lời rằng, chúng ta sẽ cần nói một chút về cấu trúc cho một mạng lưới thần kinh đơn giản.
Mạng lưới thần kinh nhị phân
Khái niệm cơ bản của một mạng lưới thần kinh
Một mạng lưới thần kinh đơn giản có một số đơn vị đầu vào nơi đầu vào đi. Nó cũng có các đơn vị ẩn, được gọi là vì quan điểm của người dùng bị ẩn theo nghĩa đen. Và có các đơn vị đầu ra, từ đó chúng tôi nhận được kết quả. Tắt sang một bên cũng là các đơn vị Bias, nơi để giúp kiểm soát các giá trị phát ra từ các đơn vị ẩn và đầu ra. Kết nối tất cả các đơn vị này là một loạt các trọng lượng, chỉ là số, mỗi đơn vị được liên kết với hai đơn vị.
Cách chúng tôi thấm nhuần trí thông minh vào mạng lưới thần kinh này là gán giá trị cho tất cả các trọng số đó. Đó là những gì đào tạo một mạng lưới thần kinh, tìm các giá trị phù hợp cho những trọng lượng đó. Sau khi được đào tạo, trong ví dụ của chúng tôi, chúng tôi sẽ đặt các đơn vị đầu vào thành các chữ số nhị phân 0, 0 và 0 tương ứng, Tensorflow sẽ làm công việc với mọi thứ ở giữa và các đơn vị đầu ra sẽ chứa một cách kỳ diệu các chữ số nhị phân 0, 0 và 1 tương ứng. Trong trường hợp bạn bỏ lỡ điều đó, nó biết rằng số tiếp theo sau nhị phân 000 001. Đối với 001, nó sẽ phun ra 010, và như vậy lên đến 111, trong đó nó sẽ phun ra 000. Khi những trọng lượng đó được đặt một cách thích hợp, nó Tôi sẽ biết cách đếm.
Mạng lưới thần kinh nhị phân với ma trận
Một bước trong “chạy” mạng thần kinh là nhân giá trị của từng trọng lượng theo giá trị của đơn vị đầu vào của nó, sau đó để lưu kết quả vào đơn vị ẩn liên quan.
Chúng ta có thể vẽ lại các đơn vị và trọng số dưới dạng mảng, hoặc những gì được gọi là danh sách trong Python. Từ quan điểm toán học, chúng là ma trận. Chúng tôi chỉ vẽ lại một phần trong số chúng trong sơ đồ. Nhân Ma trận đầu vào với Ma trận trọng lượng liên quan đến phép nhân Matrix đơn giản dẫn đến ma trận / danh sách / danh sách / mảng ẩn phần tử.
Từ ma trận đến tensors
Trong Tensorflow, những danh sách đó được gọi là Tensors. Và bước nhân ma trận được gọi là một hoạt động hoặc OP trong lập trình viên nói, một thuật ngữ bạn sẽ phải làm quen nếu bạn có kế hoạch đọc tài liệu Tensorflow. Đưa nó thêm, toàn bộ mạng lưới thần kinh là một tập hợp các cây chen và các ops hoạt động trên chúng. hoàn toàn họ tạo ra một biểu đồ.
Biểu đồ đầy đủ của bộ đếm nhị phân
Layer1 mở rộng.
Hiển thị ở đây là các ảnh chụp nhanh của Tensorboard, một công cụ để trực quan hóa biểu đồ cũng như kiểm tra các giá trị Tensor trong và sau khi đào tạo. Tensors là các dòng, và được viết trên các dòng là kích thước của Tensor. Kết nối TENSORS là tất cả các OPS, mặc dù một số thứ bạn sẽ thấy có thể được nhấp đúp vào để mở rộng chi tiết hơn, như chúng ta đã thực hiện cho Lớp1 trong ảnh chụp nhanh thứ hai.
Ở dưới cùng là x, tên chúng tôi đã cung cấp cho một bộ giữ chỗ cho phép chúng tôi cung cấp các giá trị cho Tensor đầu vào. Dòng đi lên và bên trái từ đó là Tensor đầu vào. Tiếp tục theo dõi dòng đó và bạn sẽ tìm thấy Matmul OP, việc nhân ma trận với độ căng đầu vào đó và Tensor là dòng khác dẫn vào Matmul Op. Tensor đó đại diện cho trọng lượng.
Tất cả những điều này chỉ là để cảm nhận cho bạn một biểu đồ và đồ sỏi và ops của nó là, cho bạn một ý tưởng tốt hơn về những gì chúng tôi có nghĩa là Tensorflow là một “thư viện phần mềm cho tính toán số bằng cách sử dụng biểu đồ dòng dữ liệu”. Nhưng tại sao chúng ta muốn tạo những biểu đồ này?
Tại sao tạo đồ thị?
API hiện đang ổn định là một cho Python, một ngôn ngữ được diễn giải. Mạng lưới thần kinh đang tính toán chuyên sâu và một lớn có thể có hàng ngàn hoặc thậm chí hàng triệu trọng lượng. Điện toán bằng cách diễn giải từng bước sẽ mất mãi mãi.
Vì vậy, thay vào đó, chúng tôi thay thế tạo ra một biểu đồ được tạo thành từ đồ ten và ops, mô tả cách bố trí của mạng thần kinh, tất cả các hoạt động toán học và thậm chí các giá trị ban đầu cho các biến. Chỉ sau khi chúng ta đã tạo biểu đồ này, sau đó chúng ta đã chuyển nó đến những gì Tensorflow gọi một phiên. Điều này được gọi là thực hiện hoãn lại. Phiên chạy biểu đồ bằng cách sử dụng mã rất hiệu quả. Không chỉ vậy, mà nhiều hoạt động, chẳng hạn như phép nhân Matrix, là những hoạt động có thể được thực hiện trên GPU được hỗ trợ (Đơn vị xử lý đồ họa) và phiên sẽ làm điều đó cho bạn. Ngoài ra, Tensorflow là Bililt để có thể phân phối xử lý trên nhiều máy và / hoặc GPU. Cho nó biểu đồ hoàn chỉnh cho phép nó làm điều đó.
Tạo biểu đồ bộ đếm nhị phân
Và đây là mã cho mạng thần kinh quầy nhị phân của chúng tôi. Bạn có thể tìm thấy mã nguồn đầy đủ trên trang GitHub này. Lưu ý rằng có thêm mã trong đó để lưu thông tin để sử dụng với Tensorboard.
Chúng ta sẽ bắt đầu với mã để tạo biểu đồ của TENSORS và OPS.
Nhập khẩu Tensorflow như TF
sess = tf.interactiveesession ()
Num_inputs = 3.
Num_hidden = 5.
Num_outputs = 3.
Trước tiên, chúng tôi nhập mô-đun Tensorflow, tạo một phiên để sử dụng sau và, để làm cho mã của chúng tôi dễ hiểu hơn, chúng tôi tạo một vài biến chứa số lượng đơn vị trong mạng của chúng tôi.
x = tf.placeolder (tf.float32, hình dạng = [không, num_inputs], tên = ‘x’)
Y_ = tf.placeolder (tf.float32, hình dạng = [không, num_outputs], tên = ‘Y_’)
Sau đó, chúng tôi tạo trình giữ chỗ cho các đơn vị đầu vào và đầu ra của chúng tôi. Một trình giữ chỗ là một Tensorflow OP cho những thứ chúng tôi sẽ cung cấp các giá trị cho sau này. X và Y_ hiện đang tau tát trong một biểu đồ mới và mỗi loại có một bộ giữ chỗ OP liên kết với nó.
Bạn có thể tự hỏi tại sao chúng ta xác định các hình dạng là [none, num_inputs] và [none, num_outputs], danh sách hai chiều và tại sao không có kích thước đầu tiên? Trong tổng quan về các mạng thần kinh ở trên, có vẻ như chúng ta sẽ cung cấp cho nó một đầu vào tại một thời điểm và đào tạo nó để tạo ra một đầu ra nhất định. Mặc dù hiệu quả hơn, nếu chúng tôi cung cấp cho nó nhiều cặp đầu vào / đầu ra tại một thời điểm, những gì được gọi là một lô. Kích thước đầu tiên là dành cho số cặp đầu vào / đầu ra trong mỗi lô. Chúng tôi sẽ không biết có bao nhiêu trong một mẻ cho đến khi chúng tôi thực sự cho một sau. Và trên thực tế, chúng tôi đang sử dụng biểu đồ giống nhau để đào tạo, thử nghiệm và để sử dụng thực tế để kích thước hàng loạt sẽ không giống nhau. Vì vậy, chúng tôi sử dụng đối tượng giữ chỗ Python, không có kích thước của kích thước đầu tiên cho bây giờ.
W_fc1 = tf.truncated_normal ([num_inputs, num_hden], trung bình = 0,5, stddev = 0,707)
W_fc1 = tf.variable (w_fc1, tên = ‘w_fc1’)
b_fc1 = tf.truncated_normal ([num_hidden], trung bình = 0,5, stddev = 0,707)
b_fc1 = tf.variable (b_fc1, tên = ‘b_fc1’)
h_fc1 = tf.nn.relu (tf.matmul (x, w_fc1) + b_fc1)
Tiếp theo là tạo lớp một trong các biểu đồ mạng thần kinh: các trọng số W_FC1, các thành Biases b_fc1 và các đơn vị ẩn h_fc1. “FC” là một quy ước có nghĩa là “được kết nối đầy đủ”, vì các trọng số kết nối mọi đơn vị đầu vào với mọi đơn vị ẩn.
TF.Trunsated_normal dẫn đến một số ops và tensors sau này sẽ gán các số ngẫu nhiên, ngẫu nhiên cho tất cả các trọng số.
Các OPS biến được đưa ra một giá trị để khởi tạo với các số ngẫu nhiên trong trường hợp này và giữ dữ liệu của chúng trên nhiều lần chạy. Họ cũng tiện dụng để tiết kiệm mạng thần kinh vào một tệp, một cái gì đó bạn sẽ muốn làm một khi nó được đào tạo.
Bạn có thể thấy nơi chúng tôi sẽ thực hiện phép nhân ma trận bằng cách sử dụng MatMul Op. Chúng tôi cũng chèn thêm một op sẽ thêm vào trọng lượng thiên vị. Relu OP thực hiện những gì chúng ta gọi là một hàm kích hoạt. Phép nhân ma trận và bổ sung là các hoạt động tuyến tính. Có một số lượng rất hạn chế một mạng lưới thần kinh có thể học chỉ sử dụng các hoạt động tuyến tính. Chức năng kích hoạt cung cấp một số phi tuyến tính. Trong trường hợp chức năng kích hoạt RELU, nó đặt bất kỳ giá trị nào dưới 0 đến 0 và tất cả các giá trị khác không được thay đổi. tin hay không, làm điều đó mở ra một thế giới khác của những thứ có thể học được.
W_fc2 = tf.truncated_normal ([num_hidden, num_outputs], trung bình = 0,5, stddev = 0,707)
W_fc2 = tf.variable (w_fc2, tên = ‘w_fc2’)
b_fc2 = tf.truncated_normal ([num_outputs], trung bình = 0,5, stddev = 0,707)
b_fc2 = tf.variable (b_fc2, tên = ‘b_fc2’)
y = tf.matmul (h_fc1, w_fc2) + b_fc2
Các trọng lượng và thiên vị đối với lớp hai được thiết lập giống như lớp một nhưng lớp đầu ra là khác nhau. Chúng tôi một lần nữa sẽ thực hiện phép nhân ma trận, lần này nhân các trọng số và các đơn vị ẩn, sau đó thêm trọng lượng thiên vị. Chúng tôi đã để lại hàm kích hoạt cho bit mã tiếp theo.
Kết quả = tf.sigmoid (y, tên = ‘Kết quả’)
cross_entropy = tf.reduce_mean (
tf.nn.sigmoid_cross_entropy_with_logits (logits = y, nhãn = y_))
Sigmoid là một chức năng kích hoạt khác, giống như relu chúng ta gặp phải ở trên, ở đó để cung cấp phi tuyến tính. Tôi đã sử dụng sigmoid ở đây một phần vì phương trình sigmoid dẫn đến các giá trị trong khoảng từ 0 đến 1, lý tưởng cho ví dụ phản hồi nhị phân của chúng tôi. Tôi cũng đã sử dụng nó vì nó tốt cho đầu ra nơi có nhiều đơn vị đầu ra có thể có giá trị lớn. Trong trường hợp của chúng tôi, để đại diện cho số nhị phân 111, tất cả các đơn vị đầu ra có thể có giá trị lớn. Khi thực hiện phân loại hình ảnh, chúng tôi muốn một cái gì đó khá khác nhau, chúng tôi sẽ chỉ muốn một đơn vị đầu ra để bắn với giá trị lớn. Ví dụ: chúng tôi muốn đơn vị đầu ra đại diện cho hươu cao cổ có giá trị lớn nếu hình ảnh chứa hươu cao cổ. Một cái gì đó như Softmax sẽ là một lựa chọn tốt để phân loại hình ảnh.
Khi kiểm tra chặt chẽ, có vẻ như có một số sự trùng lặp. Chúng ta dường như đang chèn sigmoid hai lần. Chúng ta thực sự đang tạo ra hai khác nhau, song song outputs ở đây. TENSOR CROSS_ENTROPY sẽ được sử dụng trong quá trình đào tạo của mạng trung tính. Tensor kết quả sẽ được sử dụng khi chúng tôi chạy mạng lưới thần kinh được đào tạo sau này cho bất kỳ mục đích nào được tạo ra, cho vui trong trường hợp của chúng tôi. Tôi không biết nếu đây là cách tốt nhất để làm điều này, nhưng đó là cách tôi nghĩ ra.
Train_STEP = tf.train.rmspropopoptimizer (0,25, động lượng = 0,5) .minimize (cross_entropy)
Mảnh cuối cùng chúng tôi thêm vào biểu đồ của chúng tôi là đào tạo. Đây là OP hoặc OPS sẽ điều chỉnh tất cả các trọng số dựa trên dữ liệu đào tạo. Hãy nhớ rằng, chúng tôi vẫn chỉ tạo ra một biểu đồ ở đây. Việc đào tạo thực tế sẽ xảy ra sau này khi chúng ta chạy biểu đồ.
Có một vài người tối ưu hóa để chọn. Tôi đã chọn TF.train.rmspropoptimizer bởi vì, giống như sigmoid, nó hoạt động tốt cho các trường hợp tất cả các giá trị đầu ra có thể lớn. Để phân loại mọi thứ như khi thực hiện phân loại hình ảnh, tf.train.gradientdescentoptimizer có thể tốt hơn.
Đào tạo và sử dụng bộ đếm nhị phân
Đã tạo biểu đồ, đã đến lúc thực hiện khóa đào tạo. Khi nó được đào tạo, sau đó chúng ta có thể sử dụng nó.
InputVals = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1] Cái gì
[1, 1, 0], [1, 1, 1]]
TargetVals = [[0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0] Cái gì
[1, 1, 1], [0, 0, 0]]
Đầu tiên, chúng tôi có một số dữ liệu đào tạo: InputVals và TargetVals. InputVals chứa các đầu vào và cho mỗi người có giá trị mục tiêu TargetVals tương ứng. Đối với các luồng đầu vào [0] Chúng ta có [0, 0, 0] và đầu ra dự kiến là TargetVals [0], là [0, 0, 1], v.v.
Nếu do_training == 1:
sess.run (tf.global_varia_initializer ())
Đối với i trong phạm vi (10001):
Nếu i% 100 == 0:
Train_error = cross_entropy.eval (feed_dict = {x: inputvals, y_: targetvals})
In (“bước% d, lỗi đào tạo% g”% (i, Train_Error))
Nếu Train_Error <0,0005:
nghỉ
sess.run (train_step, feed_dict = {x: inputvals, y_: targetvals})
Nếu Save_Trained == 1:
In ("Lưu mạng thần kinh thành% s. *"% (save_file))
Saver = tf.train.saver ()
Saver.Save (Sess, Save_file)
do_training và lưu_trained có thể được mã hóa cứng và thay đổi cho mỗi lần sử dụng hoặc có thể được đặt bằng cách sử dụng các đối số dòng lệnh.
Trước tiên chúng ta đi qua tất cả các Ops biến đó và để chúng khởi tạo tầm cỡ của họ.
Sau đó, trong tối đa 10001 lần, chúng tôi chạy biểu đồ từ dưới lên đến TAXE_STEP Tensor, điều cuối cùng chúng tôi đã thêm vào biểu đồ của chúng tôi. Chúng tôi chuyển các luồng inputVals và TargetVals để Train_STEP, mà chúng tôi đã thêm bằng RMSPropopTimizer. Đây là bước điều chỉnh tất cả các trọng số sao cho các đầu vào đã cho sẽ dẫn đến một cái gì đó gần với các đầu ra mục tiêu tương ứng. Nếu lỗi giữa các đầu ra mục tiêu và đầu ra thực tế đủ nhỏ sớm hơn, thì chúng ta sẽ thoát ra khỏi vòng lặp.
Nếu bạn có hàng ngàn cặp đầu vào / đầu ra thì bạn có thể cung cấp cho nó một tập hợp con của chúng tại một thời điểm, hàng loạt chúng tôi đã nói trước đó. Nhưng ở đây chúng tôi chỉ có tám, và vì vậy chúng tôi cho tất cả chúng mỗi lần.
Nếu chúng ta muốn, chúng ta cũng có thể lưu mạng vào một tệp. Khi nó được đào tạo tốt, chúng ta không cần phải đào tạo lại.
khác: # Nếu chúng ta không được đào tạo thì chúng ta phải tải từ tệp
In ("Đang tải mạng thần kinh từ% s"% (save_file))
Saver = tf.train.saver ()
Saver.Restore (Sess, Save_File)
# LƯU Ý: Khôi phục cả hai tải và khởi tạo các biến
Nếu chúng ta không đào tạo thì thay vào đó chúng tôi tải mạng được đào tạo từ một tệp. Tệp chỉ chứa các giá trị cho các cấu trúc có ops biến. Nó không chứa cấu trúc của biểu đồ. Vì vậy, ngay cả khi chạy một biểu đồ đã được đào tạo, chúng ta vẫn cần mã để tạo biểu đồ. Có một cách để lưu và tải các biểu đồ từ các tệp bằng cách sử dụng Metagraphs nhưng chúng tôi sẽ không làm điều đó ở đây.
In ('\ ncunting bắt đầu bằng: 0 0 0')
res = sess.run (kết quả, feed_dict = {x: [[0, 0, 0]]})
In ('% g% g% g'% (res [0] [0], res [0] [1], res [0] [2]))