You are on page 1of 10

TRƯỜNG ĐẠI HỌC BÁCH KHOA

KHOA Công Nghệ Thông Tin


BỘ MÔN: Công Nghệ Phần Mềm
ĐỀ THI VÀ BÀI LÀM
Tên học phần: Trí tuệ nhân tạo
Mã học phần: Hình thức thi: Tự luận có giám sát
Đề số: A102.01 Thời gian làm bài: 70 phút (không kể thời gian chép/phát đề)
Được sử dụng tài liệu khi làm bài.

Họ tên: ……………………………Lớp:……………………………MSSV:……………………...
Sinh viên làm bài trực tiếp trên tệp này, lưu tệp với định dạng MSSV_HọTên.pdf và nộp bài thông qua MSTeam:
Câu 1 (4 điểm): Cho tập dữ liệu input.csv với 80 mẫu dữ liệu, mỗi mẫu có 4 đặc trưng ( chiều dài đài hoa, chiều
rộng đài hoa, chiều dài cánh hoa, chiều rộng cánh hoa) và tên loài hoa tương ứng.

a) (3 điểm) Hãy viết chương trình phân loại hoa sử dụng Logistic Regression. Nêu rõ hình thức phân loại
trong chương trình như thế nào (Ví dụ: có bao nhiêu tế bào nơ-ron, mỗi nơ-ron phụ trách công việc gì,
làm sao để phân loại,…)?
# Trả lời: Dán code vào bên dưới
import pandas as pd
import numpy as np

# Hàm sigmoid
def sigmoid(x):
return 1 / (1 + np.exp(-x))

# Load data từ file csv, excel,...


def get_data(file_name):
data = pd.read_csv(file_name).values
N, d = data.shape
x = data[:, 0:d-1].reshape(-1, d-1)
y = data[:, d - 1].reshape(-1, 1)
return x,y

def prepare_data(x, y, train = True):


N = x.shape[0]
y_train = np.array([])
x_train = np.array([])
if train:
for d in y:
if d == "Iris-setosa":
y_train = np.append(y_train, 1)
else :
y_train = np.append(y_train, 0)

y_train = y_train.reshape(-1, 1)
# Thêm cột 1 vào dữ liệu x
x_train = np.hstack((np.ones((N, 1)), x))
return x_train, y_train
def train_model(x, y):
# Khởi tạo vector trọng số
w = np.array([0.,0.1,0.1,0.1,0.1]).reshape(-1,1)

# Số lần lặp bước 2


numOfIteration = 1000
cost = np.zeros((numOfIteration,1))
learning_rate = 0.01

for i in range(1, numOfIteration):

# Tính giá trị dự đoán


y_predict = sigmoid(np.array(np.dot(x, w), dtype=np.float32))
cost[i] = -np.sum(np.multiply(y, np.log(y_predict)) + np.multiply(1-y, np.log(1-y_predict)))
# Gradient descent
w = w - learning_rate * np.dot(x.T, y_predict-y)
# print(cost[i])
return w

if __name__ == "__main__":
X, Y = get_data('input.csv')

x_train, y_train = prepare_data(X, Y)


W = train_model(x_train, y_train)
y_predict = sigmoid(np.array(np.dot(x_train,W), dtype=np.float32))

x_val, y_val = get_data('output_01.csv')


x_val, y_val = prepare_data(x_val, y_val, False)
y_val_predict = sigmoid(np.array(np.dot(x_val,W), dtype=np.float32))

# Threshold
t = 0.8
for i, val in enumerate(y_val_predict):
result = "Irish-setosa" if val > t else "Iris-versicolor"
print(f"Bông hoa có độ dài đài hoa {x_val[i][1]} cm, " +
f"độ rộng đài hoa {x_val[i][2]} cm, độ dài cánh hoa {x_val[i][3]} cm, độ rộng cánh hoa
{x_val[i][4]} cm là {result}")

# Trả lời: Mô tả mô hình phân loại bằng hình ảnh hoặc bằng lời.
- Model

- Loss function :

- Tối ưu hoá tham số w_k sử dụng gradient descent:


- Biểu diễn bài toán bằng ma trận:

- Hỉnh ảnh của mô hình phân loại :

- Mô hình phân loại chỉ gồm input layer và output layer. Output layer chỉ có 1 tế bào neuron và
hàm activation function của nó là hàm sigmoid.
b) (1 điểm) Hãy thực thi chương trình và cho biết nhãn của 10 mẫu dữ liệu trong output1.csv
# Trả lời: Dán code thực thi thành công
# Trả lời: Dán kết quả nhãn ứng với 10 mẫu dữ liệu

Câu 2 (2 điểm): Cho không gian Oxyz với 10 điểm có tọa độ tương ứng (0,4,1), (1,3,3) (4,0,2),(3,1,4),(2,1,2),
(0,4,2), (1,2,3) (4,0,3),(3,2,4),(và (2,3,4).
a) (1 điểm) Viết hàm thực thi thuật toán k-means

# Trả lời: Dán code vào bên dưới


data = [(0,4,1), (1,3,3), (4,0,2), (3,1,4), (2,1,2), (0,4,2), (1,2,3), (4,0,3), (3,2,4), (2,3,4)]

def sum(x,y):
c = [x[i]+y[i] for i in range(len(x))]
return c

def div(x,y):
c = [x[i]//y for i in range(len(x))]
return c

def distance(x,y):
sum = 0
for i in range(len(x)):
sum = sum + (x[i]-y[i])**2
return sum

def argmin(x,c):
min = 100000000
mini = 0
for i in range(len(c)):
dis = distance(x,c[i])
if dis < min:
min = dis
mini = i
return mini

def k_means(k,data):
#B0 Phân nhóm ngẫu nhiên
l = [rd.choice(list(range(k))) for _ in range(len(data))]

while True:
#B1 Tính trọng tâm tất cả các nhóm
c = [[0]*len(data[0]) for _ in range(k)]
count = [0 for _ in range(k)]

for i in range(len(data)):
c[l[i]] = sum(c[l[i]],data[i])
count[l[i]] = count[l[i]]+1
for i in range(k):
if count[i]>0:
c[i] = div(c[i],count[i])
else:
c[i] = rd.choice(data)

#B2 Phân lại nhóm


check = False
for i in range(len(data)):
lnew = argmin(data[i],c)
if lnew!=l[i]:
l[i] = lnew
check = True

#Kiểm tra xem có thay đổi so với vòng lặp trước hay không
if not check:
break
return l,c

b) (1 điểm) Nếu sử dụng thuật toán k-means với k = 3 thì kết quả phân nhóm sẽ như thế nào? (các điểm
thuộc mỗi nhóm, trọng tâm của mỗi nhóm).

# Trả lời: viết câu trả lời vào bên dưới


- Các điểm thuộc nhóm 1 bao gồm (4,0,2) , (3,1,4), (2,1,2), (4,0,3) và (3,2,4) có trọng tâm là
(3,0,3).
- Các điểm thuộc nhóm 2 bao gồm (0,4,1), (0,4,2) có trọng tâm là (0,4,1).
- Các điểm thuộc nhóm 3 bao gồm (1,3,3), (1,2,3), (2,3,4) có trọng tâm là (1,2,3).

Câu 3 (4 điểm): Cho cây G = (V,E) như hình vẽ với V là tập đỉnh và E là tập cạnh, trọng số tại đỉnh là hàm ước
lượng khoảng cách từ đỉnh đó đến trạng thái đích( giá trị các nhỏ thì càng gần trạng thái đích), trọng số trên
cạnh thể hiện chi phí phải trả khi đi qua cạnh.

a) (2 điểm) Hãy viết đoạn code biểu diễn đồ thị trên bằng cách khởi tạo tập đỉnh V, tập cạnh E, trọng số trên
đỉnh và trọng số trên cạnh.
# Trả lời: Dán code vào bên dưới
data = defaultdict(list)
# Trọng số của đỉnh là khoảng cách ước lượng đến đích từ đỉnh đó
# Trọng số trên cạnh là chi phí phải trả khi đi qua cạnh
# Giá trị cuối cùng trong value của 1 key là trọng số của key đó
data['S'] = ['A', 5, 'B', 6, 'C', 5, 10]
data['A'] = ['D', 6, 'E', 7, 9]
data['B'] = ['F', 3, 'G', 4, 8]
data['C'] = ['H', 6, 'K', 4, 7]
data['D'] = ['M', 5, 'N', 8, 6]
data['E'] = ['I', 8, 5]
data['F'] = ['J', 4, 'L', 4, 4]
data['K'] = ['Z', 2, 3]
data['G'] = [10]
data['H'] = [10]
data['M'] = [8]
data['N'] = [10]
data['I'] = [6]
data['J'] = [9]
data['L'] = [0]
data['Z'] = [0]

b) (2 điểm) Hãy viết chương trình sử dụng thuật toán A* để tìm đường đi từ đỉnh “S” đến các đỉnh có trọng
số trên đỉnh bằng 0. Trong chương trình, hãy in ra thứ tự đỉnh khám phá trong quá trình tìm kiếm.
# Trả lời: Dán code vào bên dưới
data = defaultdict(list)
# Trọng số của đỉnh là khoảng cách ước lượng đến đích từ đỉnh đó
# Trọng số trên cạnh là chi phí phải trả khi đi qua cạnh
data['S'] = ['A', 5, 'B', 6, 'C', 5, 10]
data['A'] = ['D', 6, 'E', 7, 9]
data['B'] = ['F', 3, 'G', 4, 8]
data['C'] = ['H', 6, 'K', 4, 7]
data['D'] = ['M', 5, 'N', 8, 6]
data['E'] = ['I', 8, 5]
data['F'] = ['J', 4, 'L', 4, 4]
data['K'] = ['Z', 2, 3]
data['G'] = [10]
data['H'] = [10]
data['M'] = [8]
data['N'] = [10]
data['I'] = [6]
data['J'] = [9]
data['L'] = [0]
data['Z'] = [0]

class Node:
def __init__(self, name, par=None, g=0, h=0):
self.name = name
self.par = par
self.g = g
self.h = h
def __lt__(self, other):
if other == None:
return False
return self.g + self.h < other.g + other.h
def __eq__(self, other):
if other == None:
return False
return self.name == other.name

def equal(O, G):


return O.name == G.name

def Check(tmp, c):


if tmp == None:
return False
return (tmp in c.queue)

def Path(O):
print(O.name)
if O.par != None:
Path(O.par)
else:
return

def AStart(S=Node('S'), G=Node('I')):


Open = PriorityQueue()
Closed = PriorityQueue()
S.h = data[S.name][-1]
# 1. Cho đỉnh xuất phát vào Open
Open.put(S)
# 2-6. Nếu Open rỗng thì tìm kiếm thất bại, kết thúc việc tìm kiếm.
while True:
if Open.empty() == True:
print('Tim kiem that bai')
return
# 3. Lấy đỉnh đầu trong Open ra gọi là O và cho vào Closed
O = Open.get()
Closed.put(O)
print('Duyet qua: ', O.name, O.g, O.h)

# 4. Nếu O là đỉnh đích thì tìm kiếm thành công, kết thúc việc tìm kiếm
if equal(O, G) == True:
print('Tim kiem thanh cong')
Path(O)
print("Khoang cach: ", O.g+O.h)
return
# 5. Tìm tất cả các đỉnh con của ʘ không thuộc open và closed cho vào open theo thứ tự tăng dần
đối với hàm f(X)=g(X)+h’(X).
i=0
while i < len(data[O.name])-1:
name = data[O.name][i]

g = O.g + data[O.name][i+1]
h = data[name][-1]
tmp = Node(name=name, g=g, h=h)
tmp.par = O

ok1 = Check(tmp, Open)


ok2 = Check(tmp, Closed)
if not ok1 and not ok2:
Open.put(tmp)
i += 2

if __name__ == "__main__":
AStart(G=Node('L'))
AStart(G=Node('Z'))

# Trả lời: Dán kết quả thực thi vào bên dưới
Đà Nẵng, ngày 06 tháng 12 năm 2022
GIẢNG VIÊN BIÊN SOẠN ĐỀ THI TRƯỞNG BỘ MÔN
(đã duyệt)

You might also like