owned this note
owned this note
Published
Linked with GitHub
# 人工智慧期末作業
### 第一題 排課系統 有使用到老師的排課分數計算
```python=
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 7 17:48:03 2024
@author: yan10
"""
import numpy as np
from random import random, randint, choice
courses = [
{'teacher': ' ', 'name':' ', 'hours': -1}, ## 那一節沒上課
{'teacher': '甲', 'name':'機率', 'hours': 2},
{'teacher': '甲', 'name':'線代', 'hours': 3},
{'teacher': '甲', 'name':'離散', 'hours': 3},
{'teacher': '乙', 'name':'視窗', 'hours': 3},
{'teacher': '乙', 'name':'科學', 'hours': 3},
{'teacher': '乙', 'name':'系統', 'hours': 3},
{'teacher': '乙', 'name':'計概', 'hours': 3},
{'teacher': '丙', 'name':'軟工', 'hours': 3},
{'teacher': '丙', 'name':'行動', 'hours': 3},
{'teacher': '丙', 'name':'網路', 'hours': 3},
{'teacher': '丁', 'name':'媒體', 'hours': 3},
{'teacher': '丁', 'name':'工數', 'hours': 3},
{'teacher': '丁', 'name':'動畫', 'hours': 3},
{'teacher': '丁', 'name':'電子', 'hours': 4},
{'teacher': '丁', 'name':'嵌入', 'hours': 3},
{'teacher': '戊', 'name':'網站', 'hours': 3},
{'teacher': '戊', 'name':'網頁', 'hours': 3},
{'teacher': '戊', 'name':'演算', 'hours': 3},
{'teacher': '戊', 'name':'結構', 'hours': 3},
{'teacher': '戊', 'name':'智慧', 'hours': 3}
]
teachers = ['甲', '乙', '丙', '丁', '戊']
rooms = ['A', 'B']
slots = [
'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17',
'A21', 'A22', 'A23', 'A24', 'A25', 'A26', 'A27',
'A31', 'A32', 'A33', 'A34', 'A35', 'A36', 'A37',
'A41', 'A42', 'A43', 'A44', 'A45', 'A46', 'A47',
'A51', 'A52', 'A53', 'A54', 'A55', 'A56', 'A57',
'B11', 'B12', 'B13', 'B14', 'B15', 'B16', 'B17',
'B21', 'B22', 'B23', 'B24', 'B25', 'B26', 'B27',
'B31', 'B32', 'B33', 'B34', 'B35', 'B36', 'B37',
'B41', 'B42', 'B43', 'B44', 'B45', 'B46', 'B47',
'B51', 'B52', 'B53', 'B54', 'B55', 'B56', 'B57',
]
def hillClimbing(x, height, neighbor, max_fail=10000):
fail = 0
while True:
nx = neighbor(x)
if height(nx)>height(x):
x = nx
fail = 0
else:
fail += 1
if fail > max_fail:
return x
class SolutionScheduling:
def neighbor(self,x):
change = self.v
choose=randint(0,1)
choose1 = randint(0, len(slots)-1)
choose2 = randint(0, len(slots)-1)
temp = change[choose1]
change[choose1] = change[choose2]
change[choose2] = temp
if choose == 0 :
i=randint(0, len(slots)-1)
change[i]=randint(0, len(courses)-1)
else :
i=randint(0, len(slots)-1)
j=randint(0, len(slots)-1)
tmp=change[i]
change[i]=change[j]
change[j]=tmp
return change
def height(self,fills):
courseCounts = [0] * len(courses)
score = 0
for si in range(len(slots)):
courseCounts[fills[si]] += 1
# 連續上課:好 隔天:不好 跨越中午:不好
if si < len(slots)-1 and fills[si] == fills[si+1] and si%7 != 6 and si%7 != 3:
score += 0.1
if si % 7 == 0 and fills[si] != 0: # 早上 8:00: 不好
score -= 0.12
for ci in range(len(courses)):
if (courses[ci]['hours'] >= 0):
score -= abs(courseCounts[ci] - courses[ci]['hours']) # 課程總時數不對: 不好
return score
def str(self):
outs = []
fills = self.v
for i in range(len(slots)):
c = courses[fills[i]]
if i%7 == 0:
outs.append('\n')
outs.append(slots[i] + ':' + c['name'])
return 'height={:f} {:s}\n\n'.format(self.height(self.v), ' '.join(outs))
def __init__(self):
self.v = [ randint(0, len(courses)-1) for i in range(len(slots))]
print("Initial schedule:", self.v)
print("Initial height:", self.height(self.v))
print("Initial solution:", self.str())
final_solution = hillClimbing(self.v, self.height, self.neighbor)
print("Final solution:", final_solution)
print("Final height:", self.height(final_solution))
print("Final solution:", self.str())
SolutionScheduling()
```
## 第二題 旅行員推銷問題
```python=
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 18 14:48:16 2024
@author: yan10
"""
import random
citys = [
(0,3),(0,0),
(0,2),(0,1),
(1,0),(1,3),
(2,0),(2,3),
(3,0),(3,3),
(3,1),(3,2)
]
def distance(p1, p2):
## print('p1=', p1)
x1, y1 = p1
x2, y2 = p2
return ((x2-x1)**2+(y2-y1)**2)**0.5
def pathLength(p):
dist = 0
plen = len(p)
for i in range(plen):
dist += distance(citys[p[i]], citys[p[(i+1)%plen]])
# dist += distance(citys[i], citys[p[i]])
return dist
#path = [i for i in range(len(citys))]
l = len(citys)
path = [(i+1)%l for i in range(l)]
print(path)
print('pathLength=', pathLength(path))
def neighbor(p):
p2 = p.copy()
ran = len(p2)
city1 = random.randint(0, ran-1)
city2 = random.randint(0, ran-1)
temp = p2[city1]
p2[city1] = p2[city2]
p2[city2] = temp
##print(p2)
return p2
def hillClimbing(x,pathLength, neighbor,max_fail=10000):
fail = 0
while True:
nx = neighbor(x)
if pathLength(nx) < pathLength(x) and pathLength(nx) != 0:
x = nx
fail = 0
else:
fail += 1
if fail > max_fail:
return x
result = pathLength(hillClimbing(path,pathLength,neighbor))
print('path=',hillClimbing(path,pathLength,neighbor))
print('pathLength=', result)
```
## 第三題線性規劃 使用python函式庫的pulp
```python=
import pulp
import pandas
myprolp = pulp.LpProblem('ans', sense=pulp.LpMaximize)
x =pulp.LpVariable('x')
y =pulp.LpVariable('y')
z =pulp.LpVariable('z')
myprolp += 3*x +2*y + 5*z
# 條件式
myprolp += (x+y <=10)
myprolp += (2*x+z <=9)
myprolp += (y+2*z<=11)
myprolp += (x>=0)
myprolp += (y>=0)
myprolp += (z>=0)
myprolp.solve()
#print("Status:", myprolp.status)
for i in myprolp.variables():
print(i.name, "=", i.varValue)
```
## 第五題 為 micrograd 加上一個梯度下降法函數 gradientDescendent
```python=
## gd.py
import math
import numpy as np
from numpy.linalg import norm
# 函數 f 對變數 k 的偏微分: df / dk
def df(f, p, k, h=0.01):
p1 = p.copy()
p1[k] = p[k]+h
return (f(p1) - f(p)) / h
# 函數 f 在點 p 上的梯度
def grad(f, p, h=0.01):
gp = p.copy()
for k in range(len(p)):
gp[k] = df(f, p, k, h)
return gp
# 使用梯度下降法尋找函數最低點
def gradientDescendent(f, p0, h=0.01, max_loops=100000, dump_period=1000):
p = p0.copy()
print(p)
for i in range(max_loops):
fp = f(p)
fp.backward()
#gp = grad(f, p) # 計算梯度 gp
gp = []
for value in p:
gp.append(value.grad)
glen = norm(gp) # norm = 梯度的長度 (步伐大小)
if i%dump_period == 0:
print("gp=", gp)
if glen < 0.00001: # 如果步伐已經很小了,那麼就停止吧!
break
gh = np.multiply(gp, -1*h) # gh = 逆梯度方向的一小步
p += gh # 向 gh 方向走一小步
answer=[]
for k in p:
answer.append(k.data)
print(answer)
return p # 傳回最低點!
```
```python=
## gdArray.py
import gd as gd;
from micrograd.engine import Value
def f(p):
[x, y,z] = p
return (x-1)**2+(y-2)**2+(z-3)**2
#return (x-2)**2+3*(y-0.5)**2+(z-3)**2
# return x*x + 3*y*y + z*z - 4*x - 3*y - 5*z + 8
p = [Value(2.0), Value(1.0),Value(3.0)]
print(p)
print(gd.gradientDescendent(f, p))
```
## 第六題 請為 macrograd 加上一個 crossEntropyLoss 層,然後用 mnist 測試
```python=
# 來源 -- https://github.com/newcodevelop/micrograd/blob/master/micrograd/engine.py
# 有參考老師 https://github.com/ccc112b/py2gpt/blob/master/03b-MacroGrad/macrograd/engine.py
# 推薦網頁https://r23456999.medium.com/%E4%BD%95%E8%AC%82-cross-entropy-%E4%BA%A4%E5%8F%89%E7%86%B5-b6d4cef9189d
import numpy as np
class Tensor:
def __init__(self, data, _children=(), _op=''):
self.data = np.array(data)
self.grad = np.zeros(self.data.shape)
# internal variables used for autograd graph construction
self._backward = lambda: None
self._prev = set(_children)
self._op = _op # the op that produced this node, for graphviz / debugging / etc
@property
def shape(self):
return self.data.shape
def __add__(self, other):
# assert self.shape == other.shape
other = other if isinstance(other, Tensor) else Tensor(np.zeros(self.shape)+other) # 讓維度一致
out = Tensor(self.data + other.data, (self, other), '+')
def _backward():
# print('self.grad = ', self.grad)
# print('other.grad = ', other.grad)
# print('out.grad = ', out.grad, 'op=', out._op)
self.grad += out.grad
other.grad += out.grad
out._backward = _backward
return out
def __mul__(self, other):
other = other if isinstance(other, Tensor) else Tensor(np.zeros(self.shape)+other) # 讓維度一致
# other = other if isinstance(other, Tensor) else Tensor(other)
out = Tensor(self.data * other.data, (self, other), '*')
def _backward():
print('self.shape=', self.shape)
print('other.shape=', other.shape)
print('out.shape=', out.shape)
self.grad += other.data * out.grad
other.grad += self.data * out.grad
out._backward = _backward
return out
def __pow__(self, other):
assert isinstance(other, (int, float)), "only supporting int/float powers for now"
out = Tensor(self.data**other, (self,), f'**{other}')
def _backward():
self.grad += (other * self.data**(other-1)) * out.grad
out._backward = _backward
return out
def relu(self):
out = Tensor(np.maximum(0, self.data), (self,), 'relu') # Tensor(0 if self.data < 0 else self.data, (self,), 'ReLU')
def _backward():
self.grad += (out.data > 0) * out.grad
out._backward = _backward
return out
def matmul(self,other):
other = other if isinstance(other, Tensor) else Tensor(other)
out = Tensor(np.matmul(self.data , other.data), (self, other), 'matmul')
def _backward():
self.grad += np.dot(out.grad,other.data.T)
other.grad += np.dot(self.data.T,out.grad)
out._backward = _backward
return out
def softmax(self):
out = Tensor(np.exp(self.data) / np.sum(np.exp(self.data), axis=1)[:, None], (self,), 'softmax')
softmax = out.data
def _backward():
s = np.sum(out.grad * softmax, 1)
t = np.reshape(s, [-1, 1]) # reshape 為 n*1
self.grad += (out.grad - t) * softmax
out._backward = _backward
return out
def log(self):
out = Tensor(np.log(self.data),(self,),'log')
def _backward():
self.grad += out.grad/self.data
out._backward = _backward
return out
def sum(self,axis = None):
out = Tensor(np.sum(self.data,axis = axis), (self,), 'SUM')
def _backward():
output_shape = np.array(self.data.shape)
output_shape[axis] = 1
tile_scaling = self.data.shape // output_shape
grad = np.reshape(out.grad, output_shape)
self.grad += np.tile(grad, tile_scaling)
out._backward = _backward
return out
def cross_entropy(self, yb):
log = self.log()
zb = yb*log
out = zb.sum(axis=1)
ans = -out.sum()
return ans
def backward(self):
# topological order all of the children in the graph
topo = []
visited = set()
def build_topo(v):
if v not in visited:
visited.add(v)
for child in v._prev:
build_topo(child)
topo.append(v)
build_topo(self)
# go one variable at a time and apply the chain rule to get its gradient
self.grad = 1
for v in reversed(topo):
#print(v)
v._backward()
def __neg__(self): # -self
return self * -1
def __radd__(self, other): # other + self
return self + other
def __sub__(self, other): # self - other
return self + (-other)
def __rsub__(self, other): # other - self
return other + (-self)
def __rmul__(self, other): # other * self
return self * other
def __truediv__(self, other): # self / other
return self * other**-1
def __rtruediv__(self, other): # other / self
return other * self**-1
def __repr__(self):
return f"Tensor(data={self.data}, grad={self.grad})"
```
## 第七題 請自己定義一個神經網路模型,並在 MNIST 資料集上訓練並跑出正確率 準確率到達98%
[第七題](https://github.com/weichen11011/ai/blob/master/hw7/lentrelu.py)
## 第八題 請自己設計一個固定的策略(不需要學習)解決 CartPole 問題,讓你的竿子盡量撐得久不會倒下來
```python=
# -*- coding: utf-8 -*-
"""
Created on Sun May 5 06:13:01 2024
@author: yan10
"""
import gymnasium as gym
env = gym.make("CartPole-v1", render_mode="human") # 若改用這個,會畫圖
# env = gym.make("CartPole-v1", render_mode="rgb_array")
observation, info = env.reset(seed=42)
score = 0
def action(observation):
if observation[3]>0:
action = 1
else:
action = 0
return action
for _ in range(1000):
env.render()
observation, reward, terminated, truncated, info = env.step(action(observation))
#print('observation=', observation)
score += reward
if terminated or truncated:
observation, info = env.reset()
print('done, score=', score)
score = 0
env.close()
```
## 第九題 請呼叫 LLM 大語言模型 api (groq, openai) 去做一個小應用
>透過在問題前面輸入語言(ch,en)便可選擇輸出的回答語言
>EX: python groqChat.py en 問題
```python=
import os
import sys
from groq import Groq
language = sys.argv[1].lower()
if (language == 'ch'):
question = " ".join(sys.argv[2:]) + "請用中文回答"
elif (language == 'en'):
question = " ".join(sys.argv[2:]) + "請用英文回答"
print(f"選擇的語言:{language}")
print("問題:", question)
client = Groq(
api_key="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",
)
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": question,
}
],
model="llama3-8b-8192",
)
print(chat_completion.choices[0].message.content)
```
## 第十題 請自己設計 RAG 或 ReAct 的程式 (可以用 langchain 或 dspy)
>參考網站 [Langchain](https://python.langchain.com/v0.1/docs/get_started/introduction)
```python=
import os
from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_groq import ChatGroq
# set up API key
os.environ["TAVILY_API_KEY"] = "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"
tools = [TavilySearchResults(max_results=1)]
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/react")
# Choose the LLM to use
llm = ChatGroq(api_key="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")
# Construct the ReAct agent
agent = create_react_agent(llm, tools, prompt)
# Create an agent executor by passing in the agent and tools
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
question = input ("請輸入問題: ")
agent_executor.invoke({"input": "question"})
```
##