4. Đề nghị cho bảo vệ hay không?
5.2 Làm giàu dữ liệu
Mô hình học sâu có xu hướng quá khớp (overfitting) với tập dữ liệu nhỏ vì có quá ít ví dụ để đào tạo, dẫn đến một mô hình có hiệu suất kém. Tăng dữ liệu là một kỹ thuật để tạo ra nhiều trường hợp dữ liệu huấn luyện hơn bằng cách tạo các mẫu mới thông qua chuyển đổi ngẫu nhiên các dữ liệu hiện có. Phương pháp này giúp tăng kích thước của tập huấn luyện. Các phép biến đổi phổ biến là lật ngang, điều chỉnh độ sáng được minh họa trong Hình 6.5 Ngoài ra, việc tăng dữ liệu chỉ được thực hiện trên dữ liệu huấn luyện, không phải xác thực hoặc tập kiểm tra.
Hình 5.4 Làm giàu dữ liệu bằng cách thay đổi độ sáng
5.3 Quá trình đào tạo
Dữ liệu được lưu trữ sau đó được sao chép vào máy tính, được trang bị Core-i5 9300H, 2.4GHz, Ram 8GB, tôi đã đào tạo mạng để tăng tốc độ đào tạo. Với mô hình phân loại, tôi chia tập dữ liệu thành hai tập con: tập huấn luyện (85%) và tập kiểm thử (15%). Tập dữ liệu đào tạo chứa 900 mẫu, bộ kiểm tra chứa 150 mẫu.
Tôi đã sử dụng app Visual Studio Code để viết chương trình huấn luyện mạng thần kinh nhân tạo cho mô hình nhận dạng. Đây là một ứng dụng rất dễ dùng và giúp đơn giản việc debug rất nhiều.
Hình 5.5 Giao diện lập trình với Visual Studio Code
Trước khi chạy huấn luyện mô hình thì chúng ta cần thiết lập những thông số sau: Image size = 224: Mạng VGG16 yêu cầu kích thước ảnh đầu vào là 224 x 224. Batchsize: 8. Đây là số lượng mẫu dữ liệu trong một batch.
Hình 5.6 Thiết lập batchsize và imagesize
Optimizer: RMSprop. Đây là một phương thức tối ưu việc cập nhật các trọng số của mô hình.
Number of Epochs : 50. Đây là số lần thông qua toàn bộ tập dữ liệu đào tạo. Learning rate: 1e-5. Đây là một siêu tham số kiểm soát trọng số của mạng, điều chỉnh độ mất mát.
Hình 5.7 Khai báo các thông số cần thiết
Hình 5.8 Mô hình đang được huấn luyện
Hình 5.10 Thay đổi độ chính xác trong suốt quá trình đào tạo
5.4 Kết quả thực nghiệm
Sau khi được đào tạo trên máy tính, mô hình đã được sao chép trở lại Jetson Nano. Sau đó được đưa vào hệ thống Machine Vision được thiết kế từ trước và chạy đồng thời cùng PLC, hệ thống bang tải và cơ cấu chấp hành, sau khi cảm biến phát hiện được vật thì khoảng thời gian từ lúc camera chụp hình đến lúc xử lý xong ảnh là ~1.5-2s/sp. Do camera và máy tính nhúng không phải dùng cho công nghiệp nên tốc độ xử lý sẽ không được lý tưởng. Hình ảnh thử nghiệm cho dự đoán của mô hình có thể nhìn thấy trong hình 5.12.
Mô hình được đào tạo đã có thể đạt được một độ chính xác gần như tuyệt đối, hệ thống có thể hoạt động đúng với yêu cầu đặt ra là phát hiện sản phẩm lỗi bất kể vết móp nằm ở phía nào của lon đi nữa.
Hình 5.12 Kết quả thực nghiệm: Trên cùng là hình ảnh và phía dưới là đầu ra sau thông qua chức năng Softmax của mô hình. (a) Bình thường, (b) Móp đầu, (c) Móp
trên, (d) Móp giữa
Chương 6
KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
Trong đề tài này, tôi đã trình bày một hệ thống Machine Vision phát hiện sản phẩm lỗi dựa trên phương pháp xử lý ảnh và công nghệ AI tiên tiến. Công việc này giải quyết rất nhiều vấn đề có trong sản xuất mà không cần đến giác quan của con người. Có hai phương pháp đã được sử dụng trong luận án này: Xử lý tín hiệu ảnh và mô hình Phát hiện đối tượng (độ chính xác đào tạo: 98%). Tôi quyết định kết hợp hai phương pháp này lại với nhau để tăng độ chính xác, đồng thời giảm đáng kể thời gian xử lý từ lúc chụp đến lúc xuất tín hiệu.
Kết quả đáng khích lệ cho thấy mô hình mạng thần kinh tích chập hoạt động rất tốt với việc xử lý dữ liệu trong thời gian thực. Bất chấp sự phức tạp của mạng lưới thần kinh, các nền tảng điện toán nhúng như Raspberry Pi hay NVIDIA Jetson Nano Kit đủ mạnh để hỗ trợ tầm nhìn và các ứng dụng điều khiển thời gian thực dựa trên học tập sâu. Do sự phức tạp của mạng, mỗi máy tính nhúng chỉ có thể xử lý một mô hình, vì vậy nếu chúng ta cần thêm một mô hình để xử lý một tác vụ khác thì sẽ cần đến một chiếc máy tính nhúng thứ hai.
Vấn đề chúng quan sát thấy trong việc kiểm tra mạng là độ trễ camera. Nó được định nghĩa là khoảng thời gian từ khi cảm biến phát hiện vật đến lúc máy tính thực sự đọc dữ liệu hình ảnh được số hóa. Thật không may, thời gian này có thể dài đáng kể tùy thuộc vào máy ảnh và hiệu suất của Jetson, khoảng 100-120 mili giây. Điều này là cao hơn đáng kể so với độ trễ của nhận thức của con người, được biết là nhanh như mili giây. Độ trễ camera cao hơn có thể ảnh hưởng tiêu cực đến hiệu suất điều khiển, đặc biệt là đối với các ứng dụng quan trọng về an toàn, bởi vì mạng lưới thần kinh sâu sẽ phân tích các cảnh cũ.
Có nhiều lĩnh vực chúng ta có thể khám phá để đẩy dự án này đi xa hơn và thu được kết quả thậm chí thuyết phục hơn. Trong tương lai, tôi tiếp tục nghiên cứu các cách để đạt được độ chính xác dự đoán tốt hơn trong việc đào tạo mạng, xác định và sử dụng camera có độ trễ thấp, cũng như tăng them khả năng nhận dạng đa dạng hơn của máy tính với bộ dữ liệu lớn hơn. Hơn nữa, tôi sẽ tiếp tục nghiên cứu, mở rộng phạm vi ứng dụng của hệ thống Machine Vision ngoài việc phân loại để hạn chế tối thiểu tác động của con người đến khu vực sản xuất, nhằm đảm bảo an toàn và tối ưu hóa sản lượng.
TÀI LIỆU THAM KHẢO Tiếng Việt
[1] Vũ Hữu Tiệp.” Machine Learning Co Ban”. Nha xuat ban Khoa Hoc va Ky Thuat.
[2] Nguyễn Thanh Tuấn (2019). “Deep Learning Cơ Bản”. Ebook
Tiếng Anh
[3] LeCun, Y., Boser, B., Denker, J. S., Henderson, D., Howard, R. E., Hubbard, W., & Jackel, L. D. (1989). “Backpropagation applied to handwritten zip code recognition. Neural computation”, 1(4), pp. 541-551.
[4] Krizhevsky, A., Sutskever, I., & Hinton, G. E. (2012). “Imagenet classification with deep convolutional neural networks. In Advances in neural information processing systems” , pp. 1097-1105.
[5] N. Otterness, M. Yang, S. Rust, E. Park, J. H. Anderson, F. D. Smith, Berg, and S. Wang (2017).” An Evaluation of the NVIDIA TX1 for Supporting Real-Time Computer-Vision Workloads. In IEEE Real-Time and Embedded Technology and Applications Symposium (RTAS)”, pages 353–364. IEEE,
[6] Srikanth Tammina (2019). “Transfer learning using VGG-16 with Deep Convolutional Neural Network for Classifying Images”. ISSN 2250-3153. [7] Aurélien Géron (2019). “Hands-on Machine Learning with Scikit-Learn, Keras,
and TensorFlow”. O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, pages 431-469.
[8] Ding, Zhengming, and Yun Fu (2016). "Robust Transfer Metric Learning for Image Classification." .IEEE Transactions on Image Processing.
PHỤ LỤC
Phụ lục 1: Chương trình huấn luyện mô hình nhận dạng
#Import packages
from keras.applications.vgg16 import VGG16 from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator from keras.layers import Dense, Conv2D, MaxPool2D , Flatten from keras.applications.vgg16 import preprocess_input
from keras.layers import Dense import numpy as np
import keras
from keras import models, layers, optimizers from keras.callbacks import TensorBoard import os, glob
from sklearn.model_selection import train_test_split from keras.utils import np_utils
from keras import backend as K import os
import matplotlib.pyplot as plt
from keras.callbacks import TensorBoard
vgg_conv = VGG16(weights='imagenet', include_top=False, input_shape=(224, 22 4, 3))
# Freeze the layers except the last 4 layers for layer in vgg_conv.layers[:-8]:
layer.trainable = False
# Check the trainable status of the individual layers # for layer in vgg_conv.layers:
model = models.Sequential()
# Add the vgg convolutional base model model.add(vgg_conv) # model.add(Conv2D(input_shape=(224,224,3),filters=16,kernel_size=(3,3),paddin g="same", activation="relu")) # model.add(MaxPool2D(pool_size=(2,2),strides=(2,2))) # model.add(Conv2D(filters=32,kernel_size=(3,3),padding="same", activation="rel u")) # model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
# model.add(Conv2D(filters=64, kernel_size=(3,3), padding="same", activation="re lu"))
# model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
# model.add(Conv2D(filters=126, kernel_size=(3,3), padding="same", activation=" relu"))
# model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
# model.add(Conv2D(filters=256, kernel_size=(3,3), padding="same", activation=" relu"))
# model.add(MaxPool2D(pool_size=(2,2),strides=(2,2)))
# model.add(Conv2D(filters=512, kernel_size=(3,3), padding="same", activation=" relu"))
# model.add(MaxPool2D(pool_size=(2,2),strides=(2,2))) # Add new layers
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu')) model.add(layers.Dense(2, activation='softmax'))
# Show a summary of the model. Check the number of trainable parameters model.summary()
train_datagen = ImageDataGenerator(rescale=1./255, horizontal_flip=True)
validation_datagen = ImageDataGenerator(rescale=1./255, horizontal_flip=True)
# Change the batchsize according to your system RAM train_batchsize = 8
val_batchsize = 8 image_size = 224
logsdir = os.path.join(os.getcwd(),"logs_0410") train_dir = "D:\\Do an\\Dataset\\data\\train\\" validation_dir = "D:\\Do an\\Dataset\\data\\test\\" train_generator = train_datagen.flow_from_directory( train_dir, target_size=(image_size, image_size), batch_size=train_batchsize, class_mode='categorical') validation_generator = validation_datagen.flow_from_directory( validation_dir, target_size=(image_size, image_size), batch_size=val_batchsize, class_mode='categorical', shuffle=False)
checkpoint_path = os.path.join(logsdir, "{epoch:04d}.h5") tensorboard = [TensorBoard(log_dir=logsdir,
histogram_freq=0, write_graph=True, write_images=False), keras.callbacks.ModelCheckpoint(checkpoint_path,
verbose=0, save_best_only=False, save_weights_only=False),] # Compile the model
optimizer=optimizers.Adam(lr=1e-5), metrics=['acc'])
# Train the model
history = model.fit_generator( train_generator, steps_per_epoch=train_generator.samples/train_generator.batch_size , epochs=20, validation_data=validation_generator, validation_steps=validation_generator.samples/validation_generator. batch_size, verbose=1, callbacks=tensorboard) acc = history.history['acc'] val_acc = history.history['val_acc'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(len(acc)) #Show plots
plt.plot(epochs, acc, 'b', label='Training acc') plt.plot(epochs, val_acc, 'r', label='Validation acc') plt.title('Training and validation accuracy')
plt.legend() plt.figure()
plt.plot(epochs, loss, 'b', label='Training loss') plt.plot(epochs, val_loss, 'r', label='Validation loss') plt.title('Training and validation loss')
plt.legend() plt.show()
Phụ lục 2: Chương trình chạy mô hình và xử lý ảnh phát hiện lỗi #Import Pakages import keras import cv2 import numpy as np import time import keras import os
from keras.models import load_model
from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot as plt
import matplotlib matplotlib.use('TkAgg')
def findContours(img, numberOfContours, reverse = True): # tìm đường biên của o bj
# if dim(img) == 3:
# raise Exception "The function should be give 1 channel but got 3 channels" #cv2.CHAIN_APPROX_SIMPLE or cv2.CHAIN_APPROX_NONE
contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_AP PROX_SIMPLE)
# reverse = True : Sort follow max area. If False, sort follow min area
contours = sorted(contours, key = cv2.contourArea, reverse = reverse)[:numberO fContours]
return contours
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # chuyển thành ảnh g ray
img_sub = cv2.subtract(img[:,:,0], img_gray) # lấy kênh red - ảnh gray img_sub[:100,:] = 255
#ret, img_bw = cv2.threshold(img_sub, 0, 255, cv2.THRESH_BINARY_INV + c v2.THRESH_OTSU)
ret, img_bw = cv2.threshold(img_sub, 20, 255, cv2.THRESH_BINARY_INV) kernel = np.ones((7,7),np.uint8)
img_bw = cv2.dilate(img_bw ,kernel,iterations = 3) contours = findContours(img_bw, 1) # tìm đường bao x_min, y_min, w, h = cv2.boundingRect(contours[0]) return img_bw, x_min, y_min, w, h
def predict_img(img, model, threshold):
img_bw, x_min, y_min, w, h = segmentation(img)
img_obj = img[y_min - 10: y_min + 830, x_min - 20: x_min + 400]
idx_left = np.where(img_bw[y_min + 100: y_min+750, x_min + 20 : x_min + 21 ] == 0)
idx_right = np.where(img_bw[y_min + 100: y_min+750, x_min - 20 + w: x_min + w - 19] == 0) if len(idx_left[0]) > 150 or len(idx_right[0]) > 150: print("Defective Can") print(len(idx_left[0]), len(idx_right[0])) return False if img_obj.shape[0] != img_obj.shape[1]*2: img_obj = cv2.resize(img_obj, (420, 840)) #bot print(img_obj.shape)
img = img_obj[420: 840, :] img = cv2.resize(img, (224, 224)) img = img*1./255 img = img.reshape(-1,224,224,3) output = model.predict(img) # [[0.3, 0.7]] if output[0][1] < threshold: return False #mid img = img_obj[210: 630, :] img = cv2.resize(img, (224, 224)) img = img*1./255 img = img.reshape(-1,224,224,3) output = model.predict(img) if output[0][1] < threshold: return False #top img = img_obj[0: 420, :] img = cv2.resize(img, (224, 224)) img = img*1./255 img = img.reshape(-1,224,224,3) output = model.predict(img) if output[0][1] < threshold: return False return True model = load_model("0012.h5") img = cv2.imread("virtual.jpg")
img = img*1./255 img = img.reshape(-1,224,224,3) _ = model.predict(img) print("Loaded model") import sys sys.path.append('/opt/nvidia/jetson-gpio/lib/python/') sys.path.append('/opt/nvidia/jetson-gpio/lib/python/Jetson/GPIO') import RPi.GPIO as GPIO
import time # Pin Definitions
#output_pin = 18 # BOARD pin 12, BCM pin 18 # Pin Setup:
# Board pin-numbering scheme GPIO.setmode(GPIO.BCM)
# set pin as an output pin with optional initial state of HIGH GPIO.setup(18, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(23, GPIO.IN) # set pin as an input pin path = "/home/phamviet/Desktop/DATN/loi"
files = [i for i in os.listdir(path) if i.endswith(".jpg")] n = 0
cap_1 = cv2.VideoCapture(0) # camera 1 cap_2 = cv2.VideoCapture(1) # camera 2
try:
while(True):
_, image_1 = cap_1.read() _, image_2 = cap_2.read() image_1 = cv2.transpose(image_1,0) image_2 = cv2.transpose(image_2,0) #image_1 = cv2.flip(image_1, 0)
if GPIO.input(23) == GPIO.LOW: # tin hieu tu cam bien gui ve cv2.imshow("", cv2.resize(image_1, (240, 320)))
if cv2.waitKey(1) == 27: break
continue
print("Co object")
flag_inspection_1 = predict_img(image_1, model, 0.5) flag_inspection_2 = predict_img(image_2, model, 0.5) if flag_inspection_1 and flag_inspection_2:
print("Ok") cv2.circle(image_1, (650, 70), 50, (0,255,0), -1) else: print("Defect") GPIO.output(18, GPIO.HIGH) time.sleep(0.5) GPIO.output(18, GPIO.LOW) cv2.circle(image_1, (650, 70), 50, (0,0,255), -1) n = n + 1 cv2.imshow("", cv2.resize(image_1, (360, 640))) print("time: ", time.time()- start)
break finally:
GPIO.cleanup()