Submitted by khao_lek on 17 January, 2008 - 17:30.
โชว์codeหน่อยได้ไหมคับ
»
Submitted by house on 17 January, 2008 - 17:41.
>
def DCT(S, N, U):
Pi = math.pi
F2 = lambda Sl:Sl[0] * math.cos(float(U) * Pi *(Sl[1]+0.5)/float(N))
s = sum(map(F2, zip(S,range(N))))
if U == 0:
Cu = 1.0/math.sqrt(8);
else:
Cu = 0.5;
return Cu*s
def DCT2(S, N):
# start by do DCT on row
res = map( lambda x: [x]*N, [0]*N )
for u in range(N):
for v in range(N):
res[u][v] = DCT(S[u], N, v)
#redo it again on column, we will get res2 as DCT2 matrix
res2 = map( lambda x: [x]*N, [0]*N)
for u in range(N):
for v in range(N):
r = getcol(res, N, u)
res2[v][u] = DCT(r, N, v)
return res2[:]
</blockcode>
Submitted by bow_der_kleine on 18 January, 2008 - 15:37.
ดูแล้วโค้ดยังขาดอยู่หลายจุด ผมเลยเติมให้ครับ
from numpy import *
from numpy.randomimport *
importmathimporttimedef getcol(S,col):
returnlist(array(S)[:,col])def DCT(S, N, U):
Pi = math.pi
F2 = lambda Sl:Sl[0] * math.cos(float(U) * Pi *(Sl[1]+0.5)/float(N))
s = sum(map(F2, zip(S,range(N))))if U == 0:
Cu = 1.0/math.sqrt(8);
else:
Cu = 0.5;
return Cu*s
def DCT2(S, N):
# start by do DCT on row
res = map(lambda x: [x]*N, [0]*N )for u inrange(N):
for v inrange(N):
res[u][v] = DCT(S[u], N, v)#redo it again on column, we will get res2 as DCT2 matrix
res2 = map(lambda x: [x]*N, [0]*N)for u inrange(N):
for v inrange(N):
r = getcol(res, u)
res2[v][u] = DCT(r, N, v)return res2[:]
s = randint(1, 256, (40,40))
begin = time.time()
DCT2(s,40)printtime.time()-begin
ผมลองเขียนใหม่ดู โดยลด for และ map ลง เปลี่ยนไปใช้การคูณ matrix แทน
from numpy import *
from numpy.randomimport *
importtimedef dct(s):
row = s.shape[0]
col = s.shape[1]
res = zeros_like(s)
cu_row = zeros_like(s)+0.5
cu_row[:,0] = 1.0/8**0.5
cu_col = zeros_like(s)+0.5
cu_col[0,:] = 1.0/8**0.5
cu_mat = cu_row*cu_col
row_range = arange(row)
col_range = arange(col)
s = matrix(s)for i in row_range :
for j in col_range :
cos_row = matrix(cos(pi/row*(row_range+0.5)*i))
cos_col = matrix(cos(pi/col*(col_range+0.5)*j)).T
res[i][j] = cos_row * (s * cos_col)
res = cu_mat*res
return res
แม้ว่าจะเหลือโค้ดเดิมน้อยมาก แต่ผมก็ลอกมาของคุณ house นั่นแหละครับ
โชว์codeหน่อยได้ไหมคับ
> def DCT(S, N, U): Pi = math.pi F2 = lambda Sl:Sl[0] * math.cos(float(U) * Pi *(Sl[1]+0.5)/float(N)) s = sum(map(F2, zip(S,range(N)))) if U == 0: Cu = 1.0/math.sqrt(8); else: Cu = 0.5; return Cu*s def DCT2(S, N): # start by do DCT on row res = map( lambda x: [x]*N, [0]*N ) for u in range(N): for v in range(N): res[u][v] = DCT(S[u], N, v) #redo it again on column, we will get res2 as DCT2 matrix res2 = map( lambda x: [x]*N, [0]*N) for u in range(N): for v in range(N): r = getcol(res, N, u) res2[v][u] = DCT(r, N, v) return res2[:] </blockcode>จะว่าไปก็ไม่แค่ numpy หรอกครับ ผมจับจุดพวก list, sequence ไม่ถูกเลยต่างหาก ว่าเขียนแบบไหนเร็วแบบไหนช้า
หลักการใช้ Numpy ง่าย ๆ คือ ตัด for ออกให้หมดครับ ลองอ่าน Numerical Programming ดูครับ
รู้สึกว่าโค้ดที่ให้ยังไม่สมบูรณ์ครับ ไม่รู้จะใส่ S, N ใน DCT2 เป็นอะไร ขอตัวอย่างแบบครบถ้วนได้ไหมครับ ผมอยากลองใช้ Numpy เขียนดู
S เป็น array 2 D ขนาด N*N ครับ
getcol(S,N,U) return column ที่ U ใน S ครับ
ถ้า numpy คงราวๆนี้มั้ง S[:][U]
อ่อ ผมอ่านแล้วยังงงๆอยู่ึครับ เช่นผมต้องการ apply function F เข้ากับทุกสมาชิกใน array แต่ F ต้องการ argument เป็นตำแหน่งของสมาชิกใน array ด้วย (คือ ต้องการทั้ง A[i] และ i) เราจะเขียนยังไงครับ
สมการเดิมอยู่ที่ http://en.wikipedia.org/wiki/Jpeg#Discrete_cosine_transform ครับ ตรง G(u,v) แต่ผมใช้การคำนวณสองครั้งด้วย http://en.wikipedia.org/wiki/Discrete_cosine_transform#DCT-II แทน เพราะเขาอ้างว่าทำให้ process ได้เร็วกว่าครับ
ดูแล้วโค้ดยังขาดอยู่หลายจุด ผมเลยเติมให้ครับ
ผมลองเขียนใหม่ดู โดยลด for และ map ลง เปลี่ยนไปใช้การคูณ matrix แทน
แม้ว่าจะเหลือโค้ดเดิมน้อยมาก แต่ผมก็ลอกมาของคุณ house นั่นแหละครับ
ส่วนที่ผมคิดว่าแก้ได้ง่าย และเร็วมีดังนี้ครับ
res = map( lambda x: [x]*N, [0]*N )
แก้เป็น
res = zeros_like(s)
เป็นการสร้าง array โดยใช้โมดูลที่มีมาให้ (ใน Numpy ยิ่งเราเขียนเองน้อยเท่าไร ยิ่งดี และยิ่งเร็ว)
หรือ def DCT2(S, N) ส่งแค่ S ก็น่าจะพอแล้วครับ N ใช้ S.shape หาเอา หากส่งทั้งสองตัว นอกจากจะต้องมี argument มากขึ้นแล้ว อาจเกิดอาการ mismatch ได้
ตัวแปร Cu ก็เป็นอีกตัวครับ ที่แก้ได้เร็ว ยิ่งเราใช้ if มากเท่าไร โปรแกรมยิ่งช้าครับ ซึ่งโปรแกรมของคุณ house ใช้ if ถึง NxN
F2 = lambda Sl:Sl[0] * math.cos(float(U) * Pi *(Sl[1]+0.5)/float(N))
ผมคิดว่าน่าจะเขียนเป็น function ไปเลยดีกว่าครับ เพราะวิธีนี้จะกิน memory ค่อนข้างมาก คือทุกครั้งที่เรียก DCT() จะมีฟังก์ชั่นใหม่ถูกสร้างขึ้นหนึ่งครั้ง หากทำเป็นฟังก์ชั่นไปเลย สร้างครั้งเดียวใช้ได้ตลอดไป
ส่วน A[i] และ i ให้ส่งไปสองตัวได้เลยครับ
แต่สรุปแล้ว ผมไม่สามารถลด for ออกไปได้ทั้งหมด ซึ่งในกรณีนี้ ผมแนะนำว่าควรไปหา library ที่มีอยู่แล้ว หรือเขียนด้วย fortran แล้วใช้ f2py เอา ซึ่ง syntax ของ fortran90 ไม่หนีจาก Numpy มากครับ อาจจะ copy and paste ได้เลยด้วยซ้ำ
อยากให้อธิบาย lambda หน่อยได้ไหมครับ
อยากรู้นะครับ (การประยุกต์ใช้เหมือนกับอะไร, วิธีการใช้งาน และ การสร้าง คราวๆ ก็ได้นะครับ)
lamba คือฟังก์ชั่นบรรทัดเดียว ลองดูตัวอย่าง
F = lambda a,b: a+bเหมือนกับ
ขอบคุณครับ
ขอบคุณครับ