You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ML-For-Beginners/translations/th/8-Reinforcement/2-Gym/README.md

33 KiB

ข้อกำหนดเบื้องต้น

ในบทเรียนนี้ เราจะใช้ไลบรารีที่เรียกว่า OpenAI Gym เพื่อจำลอง สภาพแวดล้อม ต่างๆ คุณสามารถรันโค้ดของบทเรียนนี้ในเครื่องของคุณเอง (เช่น จาก Visual Studio Code) ซึ่งการจำลองจะเปิดในหน้าต่างใหม่ หากคุณรันโค้ดออนไลน์ คุณอาจต้องปรับแต่งโค้ดเล็กน้อยตามที่อธิบายไว้ ที่นี่

OpenAI Gym

ในบทเรียนก่อน กฎของเกมและสถานะถูกกำหนดโดยคลาส Board ซึ่งเราได้สร้างขึ้นเอง ในที่นี้เราจะใช้ สภาพแวดล้อมจำลอง พิเศษ ซึ่งจะจำลองฟิสิกส์ของการทรงตัวของเสา หนึ่งในสภาพแวดล้อมจำลองที่ได้รับความนิยมมากที่สุดสำหรับการฝึกอัลกอริทึมการเรียนรู้แบบเสริมกำลังคือ Gym ซึ่งได้รับการดูแลโดย OpenAI โดยการใช้ Gym นี้ เราสามารถสร้าง สภาพแวดล้อม ต่างๆ ตั้งแต่การจำลอง CartPole ไปจนถึงเกม Atari

หมายเหตุ: คุณสามารถดูสภาพแวดล้อมอื่นๆ ที่มีใน OpenAI Gym ที่นี่

ก่อนอื่น มาติดตั้ง Gym และนำเข้าไลบรารีที่จำเป็น (code block 1):

import sys
!{sys.executable} -m pip install gym 

import gym
import matplotlib.pyplot as plt
import numpy as np
import random

แบบฝึกหัด - การเริ่มต้นสภาพแวดล้อม CartPole

ในการทำงานกับปัญหาการทรงตัวของ CartPole เราจำเป็นต้องเริ่มต้นสภาพแวดล้อมที่เกี่ยวข้อง สภาพแวดล้อมแต่ละแห่งจะมี:

  • Observation space ที่กำหนดโครงสร้างของข้อมูลที่เราได้รับจากสภาพแวดล้อม สำหรับปัญหา CartPole เราจะได้รับตำแหน่งของเสา ความเร็ว และค่าบางอย่างอื่นๆ

  • Action space ที่กำหนดการกระทำที่เป็นไปได้ ในกรณีของเรา Action space เป็นแบบไม่ต่อเนื่อง และประกอบด้วยสองการกระทำ - ซ้าย และ ขวา (code block 2)

  1. ในการเริ่มต้น ให้พิมพ์โค้ดต่อไปนี้:

    env = gym.make("CartPole-v1")
    print(env.action_space)
    print(env.observation_space)
    print(env.action_space.sample())
    

เพื่อดูว่าสภาพแวดล้อมทำงานอย่างไร ลองรันการจำลองสั้นๆ เป็นเวลา 100 ขั้นตอน ในแต่ละขั้นตอน เราจะให้การกระทำหนึ่งอย่างที่ต้องทำ - ในการจำลองนี้ เราเพียงแค่สุ่มเลือกการกระทำจาก action_space

  1. รันโค้ดด้านล่างและดูผลลัพธ์ที่ได้

    จำไว้ว่าควรรันโค้ดนี้ในเครื่อง Python ที่ติดตั้งในเครื่องของคุณ! (code block 3)

    env.reset()
    
    for i in range(100):
       env.render()
       env.step(env.action_space.sample())
    env.close()
    

    คุณควรเห็นภาพที่คล้ายกับภาพนี้:

    non-balancing cartpole

  2. ระหว่างการจำลอง เราจำเป็นต้องได้รับข้อมูลการสังเกตเพื่อที่จะตัดสินใจว่าจะทำอะไรต่อไป ในความเป็นจริง ฟังก์ชัน step จะคืนค่าการสังเกตปัจจุบัน ฟังก์ชันรางวัล และธง done ที่ระบุว่าควรดำเนินการจำลองต่อไปหรือไม่: (code block 4)

    env.reset()
    
    done = False
    while not done:
       env.render()
       obs, rew, done, info = env.step(env.action_space.sample())
       print(f"{obs} -> {rew}")
    env.close()
    

    คุณจะเห็นผลลัพธ์ที่คล้ายกับนี้ในผลลัพธ์ของโน้ตบุ๊ก:

    [ 0.03403272 -0.24301182  0.02669811  0.2895829 ] -> 1.0
    [ 0.02917248 -0.04828055  0.03248977  0.00543839] -> 1.0
    [ 0.02820687  0.14636075  0.03259854 -0.27681916] -> 1.0
    [ 0.03113408  0.34100283  0.02706215 -0.55904489] -> 1.0
    [ 0.03795414  0.53573468  0.01588125 -0.84308041] -> 1.0
    ...
    [ 0.17299878  0.15868546 -0.20754175 -0.55975453] -> 1.0
    [ 0.17617249  0.35602306 -0.21873684 -0.90998894] -> 1.0
    

    เวกเตอร์การสังเกตที่คืนค่ามาในแต่ละขั้นตอนของการจำลองประกอบด้วยค่าต่อไปนี้:

    • ตำแหน่งของรถเข็น
    • ความเร็วของรถเข็น
    • มุมของเสา
    • อัตราการหมุนของเสา
  3. รับค่าต่ำสุดและค่าสูงสุดของตัวเลขเหล่านั้น: (code block 5)

    print(env.observation_space.low)
    print(env.observation_space.high)
    

    คุณอาจสังเกตเห็นว่าค่ารางวัลในแต่ละขั้นตอนของการจำลองมีค่าเท่ากับ 1 เสมอ นั่นเป็นเพราะเป้าหมายของเราคือการอยู่รอดให้นานที่สุดเท่าที่จะเป็นไปได้ กล่าวคือ รักษาเสาให้อยู่ในตำแหน่งแนวตั้งในระดับที่เหมาะสมให้นานที่สุด

    ในความเป็นจริง การจำลอง CartPole ถือว่าแก้ปัญหาได้หากเราสามารถรับรางวัลเฉลี่ย 195 ในการทดลองต่อเนื่อง 100 ครั้ง

การทำสถานะให้เป็นแบบไม่ต่อเนื่อง

ใน Q-Learning เราจำเป็นต้องสร้าง Q-Table ที่กำหนดว่าจะทำอะไรในแต่ละสถานะ เพื่อที่จะทำสิ่งนี้ได้ เราจำเป็นต้องให้สถานะเป็นแบบ ไม่ต่อเนื่อง กล่าวคือ ควรมีจำนวนค่าที่ไม่ต่อเนื่องที่จำกัด ดังนั้นเราจำเป็นต้อง ทำสถานะให้เป็นแบบไม่ต่อเนื่อง โดยการแมปค่าการสังเกตไปยังชุดสถานะที่จำกัด

มีวิธีการบางอย่างที่เราสามารถทำได้:

  • แบ่งเป็นช่วง หากเรารู้ช่วงของค่าบางค่า เราสามารถแบ่งช่วงนี้ออกเป็นจำนวน ช่วง และแทนค่าด้วยหมายเลขช่วงที่มันอยู่ วิธีนี้สามารถทำได้โดยใช้เมธอด digitize ของ numpy ในกรณีนี้ เราจะทราบขนาดของสถานะอย่างแม่นยำ เพราะมันจะขึ้นอยู่กับจำนวนช่วงที่เราเลือกสำหรับการทำให้เป็นแบบดิจิทัล

เราสามารถใช้การแทรกเชิงเส้นเพื่อปรับค่ามาอยู่ในช่วงที่จำกัด (เช่น จาก -20 ถึง 20) และจากนั้นแปลงตัวเลขเป็นจำนวนเต็มโดยการปัดเศษ วิธีนี้จะให้การควบคุมขนาดของสถานะน้อยลง โดยเฉพาะอย่างยิ่งหากเราไม่ทราบช่วงที่แน่นอนของค่าขาเข้า ตัวอย่างเช่น ในกรณีของเรา 2 ใน 4 ค่าจะไม่มีขอบเขตบน/ล่าง ซึ่งอาจส่งผลให้มีจำนวนสถานะที่ไม่มีที่สิ้นสุด

ในตัวอย่างของเรา เราจะใช้วิธีที่สอง ตามที่คุณอาจสังเกตเห็นในภายหลัง แม้จะไม่มีขอบเขตบน/ล่าง ค่าดังกล่าวมักจะไม่ค่อยมีค่าที่อยู่นอกช่วงที่จำกัด ดังนั้นสถานะที่มีค่าที่สุดขั้วจะเกิดขึ้นได้ยาก

  1. นี่คือฟังก์ชันที่จะรับค่าการสังเกตจากโมเดลของเราและสร้างทูเพิลของค่าจำนวนเต็ม 4 ค่า: (code block 6)

    def discretize(x):
        return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
    
  2. ลองสำรวจวิธีการทำให้เป็นแบบไม่ต่อเนื่องด้วยช่วงอีกวิธีหนึ่ง: (code block 7)

    def create_bins(i,num):
        return np.arange(num+1)*(i[1]-i[0])/num+i[0]
    
    print("Sample bins for interval (-5,5) with 10 bins\n",create_bins((-5,5),10))
    
    ints = [(-5,5),(-2,2),(-0.5,0.5),(-2,2)] # intervals of values for each parameter
    nbins = [20,20,10,10] # number of bins for each parameter
    bins = [create_bins(ints[i],nbins[i]) for i in range(4)]
    
    def discretize_bins(x):
        return tuple(np.digitize(x[i],bins[i]) for i in range(4))
    
  3. ตอนนี้ลองรันการจำลองสั้นๆ และสังเกตค่าของสภาพแวดล้อมที่ไม่ต่อเนื่อง ลองใช้ทั้ง discretize และ discretize_bins และดูว่ามีความแตกต่างหรือไม่

    discretize_bins คืนหมายเลขช่วง ซึ่งเริ่มต้นที่ 0 ดังนั้นสำหรับค่าของตัวแปรขาเข้าที่อยู่รอบๆ 0 จะคืนค่าจากกลางช่วง (10) ใน discretize เราไม่ได้สนใจช่วงของค่าผลลัพธ์ ทำให้ค่าของสถานะไม่ถูกเลื่อน และ 0 ตรงกับ 0 (code block 8)

    env.reset()
    
    done = False
    while not done:
       #env.render()
       obs, rew, done, info = env.step(env.action_space.sample())
       #print(discretize_bins(obs))
       print(discretize(obs))
    env.close()
    

    ยกเลิกการคอมเมนต์บรรทัดที่เริ่มต้นด้วย env.render หากคุณต้องการดูว่าสภาพแวดล้อมทำงานอย่างไร มิฉะนั้นคุณสามารถรันมันในพื้นหลัง ซึ่งจะเร็วกว่า เราจะใช้การรันแบบ "มองไม่เห็น" นี้ในระหว่างกระบวนการ Q-Learning ของเรา

โครงสร้างของ Q-Table

ในบทเรียนก่อน สถานะเป็นคู่ของตัวเลขง่ายๆ จาก 0 ถึง 8 และดังนั้นจึงสะดวกที่จะแสดง Q-Table ด้วยเทนเซอร์ numpy ที่มีรูปร่าง 8x8x2 หากเราใช้การทำให้เป็นแบบไม่ต่อเนื่องด้วยช่วง ขนาดของเวกเตอร์สถานะของเราก็จะทราบเช่นกัน ดังนั้นเราสามารถใช้วิธีเดียวกันและแสดงสถานะด้วยอาร์เรย์ที่มีรูปร่าง 20x20x10x10x2 (ที่นี่ 2 คือมิติของ Action space และมิติแรกสอดคล้องกับจำนวนช่วงที่เราเลือกใช้สำหรับแต่ละพารามิเตอร์ใน Observation space)

อย่างไรก็ตาม บางครั้งขนาดที่แน่นอนของ Observation space อาจไม่ทราบ ในกรณีของฟังก์ชัน discretize เราอาจไม่สามารถมั่นใจได้ว่าสถานะของเราจะอยู่ในขอบเขตที่แน่นอน เพราะค่าบางค่าของต้นฉบับไม่มีขอบเขต ดังนั้นเราจะใช้วิธีที่แตกต่างออกไปเล็กน้อยและแสดง Q-Table ด้วยดิกชันนารี

  1. ใช้คู่ (state,action) เป็นคีย์ของดิกชันนารี และค่าจะสอดคล้องกับค่าของ Q-Table (code block 9)

    Q = {}
    actions = (0,1)
    
    def qvalues(state):
        return [Q.get((state,a),0) for a in actions]
    

    ที่นี่เรายังได้กำหนดฟังก์ชัน qvalues() ซึ่งคืนค่ารายการ Q-Table สำหรับสถานะที่กำหนดซึ่งสอดคล้องกับการกระทำที่เป็นไปได้ทั้งหมด หากไม่มีรายการใน Q-Table เราจะคืนค่า 0 เป็นค่าเริ่มต้น

มาเริ่ม Q-Learning กันเถอะ

ตอนนี้เราพร้อมที่จะสอน Peter ให้ทรงตัวแล้ว!

  1. ก่อนอื่น มาตั้งค่าพารามิเตอร์ไฮเปอร์บางตัว: (code block 10)

    # hyperparameters
    alpha = 0.3
    gamma = 0.9
    epsilon = 0.90
    

    ที่นี่ alpha คือ learning rate ที่กำหนดว่าเราควรปรับค่าปัจจุบันของ Q-Table ในแต่ละขั้นตอนมากน้อยเพียงใด ในบทเรียนก่อนเราเริ่มต้นด้วย 1 และจากนั้นลด alpha ลงในระหว่างการฝึก ในตัวอย่างนี้เราจะคงค่าคงที่ไว้เพื่อความเรียบง่าย และคุณสามารถทดลองปรับค่าของ alpha ได้ในภายหลัง

    gamma คือ discount factor ที่แสดงว่าเราควรให้ความสำคัญกับรางวัลในอนาคตมากกว่ารางวัลปัจจุบันมากน้อยเพียงใด

    epsilon คือ exploration/exploitation factor ที่กำหนดว่าเราควรเลือกการสำรวจมากกว่าการใช้ประโยชน์หรือไม่ ในอัลกอริทึมของเรา เราจะเลือกการกระทำถัดไปตามค่าของ Q-Table ในเปอร์เซ็นต์ของกรณีที่กำหนดโดย epsilon และในจำนวนที่เหลือเราจะดำเนินการแบบสุ่ม สิ่งนี้จะช่วยให้เราสำรวจพื้นที่การค้นหาที่เราไม่เคยเห็นมาก่อน

    ในแง่ของการทรงตัว - การเลือกการกระทำแบบสุ่ม (การสำรวจ) จะทำหน้าที่เป็นการผลักแบบสุ่มในทิศทางที่ผิด และเสาจะต้องเรียนรู้วิธีการฟื้นฟูสมดุลจาก "ข้อผิดพลาด" เหล่านั้น

ปรับปรุงอัลกอริทึม

เรายังสามารถปรับปรุงอัลกอริทึมของเราจากบทเรียนก่อน:

  • คำนวณรางวัลสะสมเฉลี่ย ในการจำลองจำนวนหนึ่ง เราจะพิมพ์ความคืบหน้าทุกๆ 5000 รอบ และเราจะเฉลี่ยรางวัลสะสมในช่วงเวลานั้น หมายความว่าหากเราได้คะแนนมากกว่า 195 เราสามารถถือว่าปัญหาได้รับการแก้ไขแล้ว ด้วยคุณภาพที่สูงกว่าที่กำหนด

  • คำนวณผลลัพธ์สะสมเฉลี่ยสูงสุด Qmax และเราจะเก็บ Q-Table ที่สอดคล้องกับผลลัพธ์นั้น เมื่อคุณรันการฝึก คุณจะสังเกตเห็นว่าบางครั้งผลลัพธ์สะสมเฉลี่ยเริ่มลดลง และเราต้องการเก็บค่าของ Q-Table ที่สอดคล้องกับโมเดลที่ดีที่สุดที่สังเกตได้ระหว่างการฝึก

  1. เก็บรางวัลสะสมทั้งหมดในแต่ละการจำลองไว้ในเวกเตอร์ rewards เพื่อการพล็อตในภายหลัง (code block 11)

    def probs(v,eps=1e-4):
        v = v-v.min()+eps
        v = v/v.sum()
        return v
    
    Qmax = 0
    cum_rewards = []
    rewards = []
    for epoch in range(100000):
        obs = env.reset()
        done = False
        cum_reward=0
        # == do the simulation ==
        while not done:
            s = discretize(obs)
            if random.random()<epsilon:
                # exploitation - chose the action according to Q-Table probabilities
                v = probs(np.array(qvalues(s)))
                a = random.choices(actions,weights=v)[0]
            else:
                # exploration - randomly chose the action
                a = np.random.randint(env.action_space.n)
    
            obs, rew, done, info = env.step(a)
            cum_reward+=rew
            ns = discretize(obs)
            Q[(s,a)] = (1 - alpha) * Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns)))
        cum_rewards.append(cum_reward)
        rewards.append(cum_reward)
        # == Periodically print results and calculate average reward ==
        if epoch%5000==0:
            print(f"{epoch}: {np.average(cum_rewards)}, alpha={alpha}, epsilon={epsilon}")
            if np.average(cum_rewards) > Qmax:
                Qmax = np.average(cum_rewards)
                Qbest = Q
            cum_rewards=[]
    

สิ่งที่คุณอาจสังเกตเห็นจากผลลัพธ์เหล่านั้น:

  • ใกล้เป้าหมายของเรา เราใกล้จะบรรลุเป้าหมายในการได้รับรางวัลสะสม 195 ในการรันการจำลองต่อเนื่อง 100+ ครั้ง หรือเราอาจบรรลุเป้าหมายแล้ว! แม้ว่าเราจะได้ตัวเลขที่น้อยกว่า เราก็ยังไม่ทราบ เพราะเราเฉลี่ยมากกว่า 5000 รอบ และมีเพียง 100 รอบที่จำเป็นในเกณฑ์อย่างเป็นทางการ

  • รางวัลเริ่มลดลง บางครั้งรางวัลเริ่มลดลง ซึ่งหมายความว่าเราอาจ "ทำลาย" ค่าที่เรียนรู้แล้วใน Q-Table ด้วยค่าที่ทำให้สถานการณ์แย่ลง

การสังเกตนี้จะเห็นได้ชัดเจนขึ้นหากเราพล็อตความคืบหน้าการฝึก

การพล็อตความคืบหน้าการฝึก

ระหว่างการฝึก เราได้เก็บค่ารางวัลสะสมในแต่ละรอบไว้ในเวกเตอร์ rewards นี่คือสิ่งที่มันดูเหมือนเมื่อเราพล็อตมันกับหมายเลขรอบ:

plt.plot(rewards)

raw progress

จากกราฟนี้ ไม่สามารถบอกอะไรได้ เพราะลักษณะของกระบวนการฝึกแบบสุ่มทำให้ความยาวของเซสชันการฝึกแตกต่างกันมาก เพื่อให้กราฟนี้มีความหมายมากขึ้น เราสามารถคำนวณ ค่าเฉลี่ยเคลื่อนที่ ในการทดลองชุดหนึ่ง เช่น 100 สิ่งนี้สามารถทำได้อย่างสะดวกโดยใช้ np.convolve: (code block 12)

def running_average(x,window):
    return np.convolve(x,np.ones(window)/window,mode='valid')

plt.plot(running_average(rewards,100))

training progress

การปรับพารามิเตอร์ไฮเปอร์

เพื่อให้การเรียนรู้มีเสถียรภาพมากขึ้น มีเหตุผลที่จะปรับพารามิเตอร์ไฮเปอร์บางตัวระหว่างการฝึก โดยเฉพาะ:

  • สำหรับ learning rate alpha เราอาจเริ่มต้นด้วยค่าที่ใกล้เคียงกับ 1 และจากนั้นลดค่าพารามิเตอร์ลงเรื่อยๆ เมื่อเวลาผ่านไป เราจะได้รับค่าความน่าจะเป็นที่ดีใน Q-Table และดังนั้นเราควรปรับค่าพวกนั้นเล็กน้อย และไม่เขียนทับด้วยค่าที่ใหม่ทั้งหมด

  • เพิ่ม epsilon เราอาจต้องการเพิ่ม epsilon อย่างช้าๆ เพื่อสำรวจน้อยลงและใช้ประโยชน์มากขึ้น อาจมีเหตุผลที่จะเริ่มต้นด้วยค่าที่ต่ำของ epsilon และเพิ่มขึ้นจนเกือบถึง 1

งานที่ 1: ลองปรับค่าพารามิเตอร์ต่าง ๆ และดูว่าคุณสามารถทำให้ผลตอบแทนรวมสูงขึ้นได้หรือไม่ คุณได้คะแนนเกิน 195 หรือยัง? งานที่ 2: เพื่อแก้ปัญหาอย่างเป็นทางการ คุณจำเป็นต้องได้ค่าเฉลี่ยรางวัล 195 ในการทดลอง 100 ครั้งติดต่อกัน วัดผลระหว่างการฝึกและตรวจสอบให้แน่ใจว่าคุณได้แก้ปัญหาอย่างเป็นทางการแล้ว!

ดูผลลัพธ์ในทางปฏิบัติ

มันน่าสนใจที่จะเห็นว่ารูปแบบที่ฝึกมาแล้วทำงานอย่างไร ลองรันการจำลองและใช้กลยุทธ์การเลือกการกระทำแบบเดียวกับที่ใช้ระหว่างการฝึก โดยสุ่มตามการแจกแจงความน่าจะเป็นใน Q-Table: (code block 13)

obs = env.reset()
done = False
while not done:
   s = discretize(obs)
   env.render()
   v = probs(np.array(qvalues(s)))
   a = random.choices(actions,weights=v)[0]
   obs,_,done,_ = env.step(a)
env.close()

คุณควรเห็นบางสิ่งที่คล้ายกับนี้:

a balancing cartpole


🚀ความท้าทาย

งานที่ 3: ในที่นี้ เราใช้สำเนาสุดท้ายของ Q-Table ซึ่งอาจไม่ใช่ตัวที่ดีที่สุด อย่าลืมว่าเราได้บันทึก Q-Table ที่มีประสิทธิภาพดีที่สุดไว้ในตัวแปร Qbest! ลองใช้ตัวอย่างเดียวกันกับ Q-Table ที่มีประสิทธิภาพดีที่สุดโดยคัดลอก Qbest ไปยัง Q และดูว่าคุณสังเกตเห็นความแตกต่างหรือไม่

งานที่ 4: ในที่นี้ เราไม่ได้เลือกการกระทำที่ดีที่สุดในแต่ละขั้นตอน แต่สุ่มตามการแจกแจงความน่าจะเป็นที่เกี่ยวข้อง จะสมเหตุสมผลกว่าหรือไม่ถ้าเลือกการกระทำที่ดีที่สุดเสมอ ซึ่งมีค่าที่สูงที่สุดใน Q-Table? สิ่งนี้สามารถทำได้โดยใช้ฟังก์ชัน np.argmax เพื่อค้นหาหมายเลขการกระทำที่สอดคล้องกับค่าที่สูงที่สุดใน Q-Table ลองใช้กลยุทธ์นี้และดูว่ามันช่วยปรับปรุงการทรงตัวหรือไม่

แบบทดสอบหลังการบรรยาย

งานที่ได้รับมอบหมาย

ฝึก Mountain Car

สรุป

ตอนนี้เราได้เรียนรู้วิธีการฝึกตัวแทนเพื่อให้ได้ผลลัพธ์ที่ดีเพียงแค่ให้ฟังก์ชันรางวัลที่กำหนดสถานะที่ต้องการของเกม และให้โอกาสพวกเขาสำรวจพื้นที่ค้นหาอย่างชาญฉลาด เราได้ใช้ Q-Learning algorithm สำเร็จในกรณีของสภาพแวดล้อมแบบไม่ต่อเนื่องและต่อเนื่อง แต่มีการกระทำแบบไม่ต่อเนื่อง

สิ่งสำคัญคือต้องศึกษาสถานการณ์ที่สถานะการกระทำเป็นแบบต่อเนื่อง และเมื่อพื้นที่การสังเกตมีความซับซ้อนมากขึ้น เช่น ภาพจากหน้าจอเกม Atari ในปัญหาเหล่านี้เรามักต้องใช้เทคนิคการเรียนรู้ของเครื่องที่ทรงพลังมากขึ้น เช่น neural networks เพื่อให้ได้ผลลัพธ์ที่ดี หัวข้อที่ก้าวหน้ากว่านี้จะเป็นเนื้อหาในหลักสูตร AI ขั้นสูงของเราในอนาคต


ข้อจำกัดความรับผิดชอบ:
เอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI Co-op Translator แม้ว่าเราจะพยายามให้การแปลมีความถูกต้องมากที่สุด แต่โปรดทราบว่าการแปลอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาดั้งเดิมควรถือเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ ขอแนะนำให้ใช้บริการแปลภาษามืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความผิดที่เกิดจากการใช้การแปลนี้