Chủ Nhật, 2 tháng 12, 2012

Kinect và ứng dụng trong mobile robot (Phần 2)


2.Tìm hiểu và sử dụng thư viện Kinect


Thư viện Kinect là thư viện do Microsoft tạo ra để tạo môi trường cho người dùng có thể dễ dàng xây dựng những ứng dụng một cách nhanh chóng trên cả PC lẫn dòng máy chơi game Xbox 360. Thư viện này hỗ trợ cho cả 3 ngôn ngữ thông dụng là C#, C++ và VB đồng thời cũng tương thích với win7 và 8. Hiện tại, phiên bản mới nhất là SDK for Kinect version 1.6 đã cải tiến nhiều tính năng nên dễ sử dụng và tỏ ra là một lựa chọn hiệu quả hơn so với các thư viện mã nguồn mở. Tuy nhiên để sử dụng thư viện này cho các ứng dụng thương mại thì cần trả tiền bản quyền cho Microsoft.
Yêu cầu hệ thống :
·        Microsoft Kinect SDK – Các bạn có thể download tại đây .
·        Visual Studio 2010 .
·        Kinect
Để bắt đầu với tìm hiểu, ở đây sẽ sử dụng C#.

2.1 Tạo project:

Bước đầu tiên cần thực hiện là tạo một project mới, có thể là dạng Windows Forms hay dạng WPF.
Bước tiếp theo là thực hiện add reference để có thể thao tác với Kinect SDK. Bấm chuột phải vào phần References ở cửa sổ bên trái  và chọn Add reference sau đó tìm file Microsoft.Kinect.dll trong tab .Net
Chú ý rằng nếu sử dụng các phiên bản beta thì file cần add là Microsoft.Research.Kinect.

 2.2Thiết lập cho Kinect

Hầu như tất cả các chương trình Kinect đều bắt đầu như nhau.
Đầu tiên là tìm kiếm các senser đã kết nối với máy tính và kiểm tra tình trạng của chúng. (Chú ý rằng các phiên bản trước thì code sẽ hơi khác so với bản 1.6)
       Để làm việc này chúng ta khai báo một đối tượng thuộc lớp KinectSenser
Khai báo thêm  thư viện kinect       using Microsoft.Kinect;
Trong sự kiện  WindowLoaded chúng ta sử dụng lệnh foreach để kiểm tra tất cả các sensor đc kết nối.

          foreach (var SensorKetNoi in KinectSensor.KinectSensors)
            {
                if (SensorKetNoi.Status == KinectStatus.Connected)
                {
                    this.sensor = SensorKetNoi;
                    break;
                }
            }

Khi tất cả các senser đã được kết nối, ta tiến hành cho phép nhận các dòng dữ liệu cần thiết cho ứng dụng như độ sâu, âm thanh hoặc ảnh màu từ cảm biến sau đó khởi động cảm biến và viết các hàm để xử lý dữ liệu nhận được (Có thể là xuất ảnh ra màn hình, tính toán khoảng cách, nhận dạng…)
if (null != this.sensor)
     {
                this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                this.sensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
this.sensor.SkeletonStream.Enable();
            // Khởi động sensor!
      }

2.3 Nhận và hiển thị dữ liệu từ cảm biến.

            Dữ liệu gửi về dưới dạng data stream. NUI API cho phép lập trình kiểm soát và truy nhập dữ liệu.
Các bước làm bao gồm:
1.      Xác định dòng dữ liệu cần thiết.
2.      Cho phép mở dòng dữ liệu (Enable Data Streaming)
3.      Tạo bộ đệm để lưu trữ dữ liệu sensor.
4.      Giải phóng bộ đệm để có thể sử dụng trong khung hình tiếp theo.
Trong việc hiển thị dữ liệu, các hàm hỗ trợ trong SDK rất phức tạp, các bạn có thể down Coding4Fun.Kinect.Toolkit về sau đó add reference đến file coding4Fun.Kinect.winForm.dll hoặc coding4Fun.Kinect hoặc coding.4Fun.kinect.Wpf.dll
(bằng cách chuột phải lên refeference -> chọn thẻ browse-> dẫn đến thư mục  Coding4Fun.Kinect.Toolkit)
Khi sử dụng bạn chú ý thêm  using Coding4Fun.Kinect.WinForm;

2.3.1  ColorStream:

ColorStream có nhiều độ phân giải và định dạng tùy thuộc vào các lựa chọn colorStream là RGB, YUV hay Bayer.
SDK cung cấp một số tùy chọn cho phép tối ưu hóa camera ứng với các tác động môi trường như:
-         Tăng giảm độ sáng
-         Thay đổi màu sắc, độ tương phản
Tất cả được hỗ trợ trong class ColorCameraSetting.
Để hiển thị các thành phần dữ liệu mầu sắc bằng C# chúng ta cần tiến hành các công việc sau:
-         Khởi tạo cảm biến để tạo dữ liệu màu (đã đề cập ở trên)
-         Xử lý sự kiện và hiển thị lên Forms.
a.      Tạo sự kiện báo dữ liệu đã sẵn sàng:
if (this.sensor != null)
          {
            this.sensor.ColorFrameReady += this.SensorColorFrameReady;
          }

b.      Xử lý sự kiện và hiển thị lên Forms.
Ví dụ bên dưới được thực hiện với windows Forms với sự hỗ trợ của công cụ Coding4Fun.Kinect.Toolkit . Để hiển thị với WPF các bạn có thể tham khảo thêm ở địa chỉ.
private void SensorColorFrameReady(object sender,                                         
                                     ColorImageFrameReadyEventArgs e)
          {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
              if (colorFrame != null)
              {
                  colorImage.Image = colorFrame.ToBitmap();
             
              }
            } 
          }


2.3.2 Depth Stream

Mỗi khung hình của dữ liệu Depth Stream được tạo thành từ các pixels chứa khoảng cách (bằng mm) từ mặt phẳng camera đến đối tượng.
Các ứng dụng có thể sử dụng depth data để bám theo chuyển động hoặc nhận dạng đối tượng.
            Dữ liệu về khoảng cách tính bằng mm là bộ số (x,y) chứa tọa độ trong field of view của sensor.

 Có 3 tùy chọn độ phân giải là 640x480 (mặc định), 320x240 vào 80x60. Tất cả được quy định trong DepthImageFormat Enumeration.
            Việc hiển thị dữ liệu cho DepthStream hoàn toàn tương tự ColorStream.
if (this.sensor != null)
          {
            this.sensor.DepthFrameReady += this.SensorDepthFrameReady;
          }
private void SensorDepthFrameReady (object sender,                                         
                                     ColorImageFrameReadyEventArgs e)
          {
            using (DepthImageFrame DepthFrame = e.OpenColorImageFrame())
            {
              if (DepthFrame != null)
              {
                  DepthImage.Image = DepthFrame.ToBitmap();
             
              }
            } 
          }

2.4 Điều khiển góc nghiêng sensor

            Góc nghiêng của sensor trong kinect có giá trị từ -27 đến 27, giá trị này tính theo phương vuông góc với trọng lực, tức là nếu góc bằng 0 thì phương của camera sẽ vuông góc với trọng lực.
Để điều khiển góc nghiên của sensor ta sử dụng thuộc tính sensor.ElevationAngle
Thuộc tính này cho phép ta có thể get hoặc set giá trị cho góc sensor.
Ví dụ sau mô tả việc hiển thị góc và đặt giá trị góc nghiêng bằng một thanh cuộn ngang kết hợp với 1 nút bấm và hiển thị giá trị đó lên một label.
private void hScr_dieuChinhGoc_ValueChanged(object sender, EventArgs e)
        {
            lbl_gocnghieng.Text = hScr_dieuChinhGoc.Value.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            sensor.ElevationAngle = hScr_dieuChinhGoc.Value;
        }

2.5 Demo sử dụng Kinect với WindowsForms

Demo này tổng hợp lại các ví dụ ở trên trong đó sử dụng các thành phần sau:
-         2 PictureBox là colorImage và DepthImage để hiển thị dữ liệu ảnh mầu và dữ liệu độ sâu.
-         1 HscrollBar là hScr_dieuChinhGoc kết hợp với 1 Button để đặt giá trị góc quay.
-         Các lable lbl_HienThiGocNghieng và lbl_gocnghieng để hiển thị giá trị đo góc.
v Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Kinect;
using Coding4Fun.Kinect.WinForm;

namespace DemoWinForm2
{
    public partial class Form1 : Form
    {
        private KinectSensor sensor;// Khai báo sensor
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {  
            //Kiểm tra các sensor được kết nối
            foreach(var sensorKetnoi in KinectSensor.KinectSensors)
            {
                if(sensorKetnoi.Status==KinectStatus.Connected)
                {
                    this.sensor = sensorKetnoi;
                    break;
                }
            }
            if(this.sensor!=null)
            {  
 // Enable dòng dữ liệu và thiết lập các tùy chọn cho dữ liệu ảnh
                this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
// Enable dòng dữ liệu và thiết lập các tùy chọn cho dữ liệu độ sâu
                this.sensor.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
                // Khởi động sensor
                this.sensor.Start();

                // Hiển thị góc nghiêng ban đầu của sensor.
                lbl_gocnghieng.Text = sensor.ElevationAngle.ToString();

                // Các sự kiện thông báo dữ liệu đã sẵn sàng.
                this.sensor.ColorFrameReady += this.SensorColorFrameReady;
                this.sensor.DepthFrameReady += this.SensorDepthFrameReady;
             
            }
        }
       
        // Xử lý các sự kiện.
         private void SensorColorFrameReady(object sender,                                             
                                             ColorImageFrameReadyEventArgs e)
          {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
              if (colorFrame != null)
              {
                  colorImage.Image = colorFrame.ToBitmap();
             
              }
            } 
          }
         private void SensorDepthFrameReady(object sender,
                                              DepthImageFrameReadyEventArgs e)
         {
             using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
             {
                 if (depthFrame != null)
                 {
                     depthImage.Image= depthFrame.ToBitmap();
                 }
                
             }
         }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (sensor != null)
            {
// Đưa góc nghiêng về 0 trước khi tắt sensor.

                sensor.ElevationAngle = 0;
                sensor.Stop();

            }
        }
       
        // Các hàm xử lý sự kiện để điều chỉnh góc nghiêng.
        private void hScr_dieuChinhGoc_ValueChanged(object sender, EventArgs e)
        {
            lbl_gocnghieng.Text = hScr_dieuChinhGoc.Value.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            sensor.ElevationAngle = hScr_dieuChinhGoc.Value;
        }
                    
    }
}

v Kết quả:
Trên đây là những tìm hiểu mang tính chất tổng hợp kiến thức, tuy rằng vẫn đang còn sơ lược nhưng có thể sẽ hữu ích với những bạn mới bắt đầu tiếp cận với Kinect.

Kinect và ứng dụng trong mobile robot (Phần 1)


1.Giới thiệu cơ bản về Kinect






Kinect là sản phẩm của Microsoft  dựa trên công nghệ  camera được phát triển bởi PrimeSense,  những  sản phẩm đầu tiên được bán tại  Bắc  Mỹ  vào  ngày 4  tháng 11 năm 2010 .
 Kinect được coi như là một thiết bị  ngoại vi cho Xbox 360, cho phép giao tiếp với con người thông qua các cử chỉ, đem lại những cảm giác thú vị cho người chơi game trên Xbox. Khả  năng hiểu được cử  chỉ  con người của Kinect dựa trên hai đặc tính chính  sau: thông tin về  độ  sâu  ảnh (depth map), khả  năng phát hiện và bám theo đặc tính cơ thể người (body skeleton tracking).
Bên cạnh phục vụ  cho mục đích chơi game,  sản phẩm Kinect còn được dùng vào  mục đích  nghiên cứu xử  lý  ảnh 3D, phát hiện cử  chỉ  (gesture recognition),  bám theo  người  (body tracking)  và nhiều mục đích khác. Lý do chính cho sự  thành công của sản phẩm Kinect là giá cả  khá rẻ  (khoảng 140$ trên 1 sản phẩm) cho thiết bị  có khả  năng cung cấp các thông tin 3D với chất lượng chấp nhận được.

1.1  cấu trúc phần cứng.

Bên trong Kinect bao gồm 1 camera RGB, cảm biến độ sâu , một dãy các microphone và 1 động cơ điều khiển góc nâng.

1.1.1       Camera RGB

Là một camera có 3 kênh dữ liệu có độ phân giải 1280x960. Camera này có khả năng chụp lại ảnh ảnh mầu.

1.1.2       Cảm biến độ sâu

Độ sâu thu về nhờ sự kết hợp của 2 bộ phận là bộ phát hồng ngoại IR và camera hồng ngoại đọc các tín hiệu phản hồi về từ đó tính toán ra bản đồ độ sâu.

1.1.3       DãyMicrophone

Dãy Micro bao gồm 4 micro được bố trí dọc theo thân Kinect có khả năng thu lại âm thanh đồng thời xác định hướng của âm thanh. Dãy Microphone này được dùng trong các ứng dụng điều khiển bằng giọng nói.
Ngoài ra Kinect còn có 1 cảm biến đo gia tốc để xác định hướng và 1 động cơ dùng để điều khiển góc ngẩng camera.
Trong số những cảm biến kể trên của Kinect, cảm biến độ sâu có khả năng ứng  dụng cao trong đề tài robot tránh mục tiêu.

1.2  Nguyên lý các cảm biến độ sâu.

Cặp cảm biến IR camera và IR projector sẽ phối hợp với nhau để tạo ra giá trị độ sâu bằng công nghệ Light Coding của PrimeSense.

Kĩ thuật Light Coding dùng nguồn sáng hồng ngoại chiếu liên tục kết hợp với một camera hồng ngoại để tính khoảng cách. Việc tính toán này được thực hiện bằng chip PS1080 Soc của PrimeSen.
Projector sẽ  chiếu một chùm sáng hồng ngoại, tạo nên những đốm sáng ở  không gian phía trước Kinect, tập hợp đốm sáng  được phát ra  này  là cố  định.  Những đốm sáng này được tạo ra nhờ  một nguồn sáng truyền qua lưới nhiễu xạ  (diffraction gratings). Tập hợp các đốm sáng này được IR camera chụp lại, thông qua giải thuật đặc biệt được tích hợp trong  PS1080 SoC  cho ra bản đồ độ sâu.  Bản chất của giải thuật này là các phép toán hình học dựa trên  quan hệ  giữa hai cảm biến IR camera và Projector.

 1.3  Các dữ liệu đo được từ cảm biến.


Các cảm biến của Kinect được điều khiển đồng thời thu thập và xử lý dữ liệu thông qua chip PS1080 có tần số 12MHz, sau đó được lưu trữ vào bộ nhớ Flash. Các dữ liệu này có thể truyền vào máy tính thông qua cổng USB 2.0.

Các tín hiệu thu thập bao gồm dữ liệu về độ sâu, màu sắc và âm thanh trong đó tín hiệu về độ sâu là dữ liệu quan trọng có nhiều dụng.
Sở dĩ dữ liệu về chiều độ sâu có tầm quan trọng như vậy bởi nó giúp việc nhận dạng các vật thể đơn giản hơn nhiều so với xử lý ảnh thông thường.  Các thuật toán xử lý ảnh thông thường dựa vào sự tương đồng về mầu sắc, tuy nhiên, có thể những vật có mầu sắc tương tự nhau nhưng không cùng một vật thể  hoặc các phần của cùng một đối tượng nhưng có mầu khác nhau,do vậy gây khó khăn trong quá trình nhận dạng. Trong khi đó, với thông tin về độ sâu,  các vật thể được phân biệt với nhau thông qua vị trí. Những điểm có khoảng cách gần nhau có xu hướng cùng một đối tượng mà không phân biệt mầu sắc.  Chỉ khi độ sâu giảm đột ngột như ở cạnh và ở một số phần nhỏ của đối tượng thì khi đó, hình ảnh trên bản đồ độ sâu mới có sự thay đổi.
Một ưu điểm nữa của bản đồ độ sau đó là dữ liệu có thể được nén cao hơn so với  ảnh mầu thông thường do đó thích hợp trong việc truyền dẫn nhanh tín hiệu.
Các thuật toán nhận dạng đối với ảnh độ sâu đơn giản hơn và thậm chí có thể tái tạo lại vật thể 3D.
Từ những phân tích trên ta có thể thấy được những ưu điểm của bản đồ độ sâu và nó rất thích hợp để ứng dụng trong các đề tài về robot tự hành.

Thứ Năm, 10 tháng 5, 2012

Chương trình Matlab giúp biến đổi hàm truyền liên tục sang rời rac (demo:D)

Vì tính toán biến đổi hàm truyền bằng tay rất lâu nên mình đã thử viết một chương trình Matlab để hỗ trợ việc biến đổi này.
Sử dụng hàm này rất đơn giản. Mọi người down về 1 thư mục rồi chỉnh lại đường dẫn của Matlab đến thư mục ấy.
Khi sử dụng chỉ cần cung cấp cho nó 2 vecto chứa hệ số của tử và mẫu (hệ số đa thức nhỏ dần).

VD    Biến đổi z của hàm truyền có dạng 
          1 
G= -------------- 
       2 
      s  + 10 s

khi đó chỉ cần nhập lệnh:

>> l2z(1,[1 10 0])
chương trình sẽ cho kết quả :

Ham truyen lien tuc: 

      1 
  --------- 
    2 
  s  + 10 s
Ham truyen roi rac: 

         (9 exp(10) + 1) z + exp(10) - 11 
  ------------------------------------------------------------------
                              2 
  100 exp(10) z  + (- 100 exp(10) - 100) z + 100

ở đây không biểu diễn chu kì trích mẫu, vì vậy các bạn phải nhân thêm chu kì trích mẫu T vào trong các hàm exp(). (Mình đã  thử sửa nhưng mãi không được :">)
Nhược điểm lớn nhất của hàm này là nếu đầu vào có dạng số thập phân thì chương trình sẽ tự động chuyển số thập phân đó về dạng phân số rồi tính toán. 
Do đó có thể kết quả sẽ rất dài, tuy nhiên mình thấy đề thầy ra chủ yếu là số chẵn nên hi vọng hàm này sẽ giúp mọi người kiểm tra lại kết quả tính toán bằng tay. 


Click để down chương trình Demo
update thêm chương trình có tính cả trễ. Hướng dẫn có trong ghi chú của file :D
Ver 1.1 :D

Thứ Sáu, 4 tháng 5, 2012

Thứ Sáu, 23 tháng 3, 2012

Mạng nơron Phần 1 (sưu tầm ^^)

Mạng nơron nhân tạo

(trích blog http://thanhtra.nguyen.free.fr)


Phần 1. Con người và máy tính


Ngày nay không ai có thể phủ nhận vai trò cực kỳ quan trọng của máy tính trong nghiên cứu khoa học kỹ thuật cũng như trong đời sống. Máy tính đã làm được những điều kỳ diệu và giải được những vấn đề tưởng chừng nan giải. Càng ngày càng có nhiều người tự hỏi, liệu máy tính đã thông minh hơn con người hay chưa? Chúng tôi sẽ không trả lời câu hỏi ấy. Thay vào đó, chúng tôi sẽ nêu ra những khác biệt chủ yếu giữa cách làm việc của máy tính và bộ óc con người.
Một máy tính, dù có mạnh đến đâu chăng nữa, đều phải làm việc theo một chương trình chính xác đã được hoạch định trước bởi các chuyên gia. Bài toán càng phức tạp thì việc lập trình càng công phu. Trong khi đó con người làm việc bằng cách học tập và rèn luyện. Trong khi làm việc con người có khả năng liên tưởng, kết nối sự việc này với sự việc khác, và quan trọng hơn hết, họ có thể sáng tạo.
Do có khả năng liên tưởng, con người có thể dễ dàng làm nhiều điều mà việc lập trình cho máy tính đòi hỏi rất nhiều công sức. Chẳng hạn như việc nhận dạng hay trò chơi ô chữ. Một em bé có thể tự học hỏi để nhận dạng và phân loại đồ vật chung quanh mình, biết được cái gì là thức ăn, cái gì là đồ chơi. Một người bình thường cũng có thể đoán được vài chữ trong một ô chữ. Nhưng thật khó mà dạy cho máy tính làm được những việc ấy. Bạn hãy thử thiết kế một máy tính có khả năng làm như thế !
Từ lâu các nhà khoa học đã nhận thấy những ưu điểm ấy của bộ óc con người và tìm cách bắt chước để thực hiện những máy tính có khả năng học tập, nhận dạng và phân loại. Các mạng nơron nhân tạo (Artificial Neural Network, ANN) đã ra đời từ những nỗ lực đó. ANN là một lãnh vực nghiên cứu rộng lớn và chỉ mới phát triển mạnh khoảng 15 năm gần đây thôi. Tuy có nhiều kết quả khích lệ, nhưng ANN hãy còn xa mới đạt được sự hoàn chỉnh như bộ óc con người.

Phần 2. Nơron và sự học tập


Sau đây là những thành phần chính trong cấu trúc của một nơron:



  • Soma là thân của nơron.
  • Các dendrites là các dây mảnh, dài, gắn liền với soma, chúng truyền dữ liệu (dưới dạng xung điện thế) đến cho soma xử lý. Bên trong soma các dữ liệu đó được tổng hợp lại. Có thể xem gần đúng sự tổng hợp ấy như là một phép lấy tổng tất cả các dữ liệu mà nơron nhận được.
  • Một loại dây dẫn tín hiệu khác cũng gắn với soma là các axon. Khác với dendrites, axons có khả năng phát các xung điện thế, chúng là các dây dẫn tín hiệu từ nơron đi các nơi khác. Chỉ khi nào điện thế trong soma vượt quá một giá trị ngưỡng nào đó (threshold) thì axon mới phát một xung điện thế, còn nếu không thì nó ở trạng thái nghỉ.
  • Axon nối với các dendrites của các nơron khác thông qua những mối nối đặc biệt gọi là synapse. Khi điện thế của synapse tăng lên do các xung phát ra từ axon thì synapse sẽ nhả ra một số chất hoá học (neurotransmitters); các chất này mở "cửa" trên dendrites để cho các ions truyền qua. Chính dòng ions này làm thay đổi điện thế trên dendrites, tạo ra các xung dữ liệu lan truyền tới các nơron khác.
Có thể tóm tắt hoạt động của một nơron như sau: nơron lấy tổng tất cả các điện thế vào mà nó nhận được, và phát ra một xung điện thế nếu tổng ấy lớn hơn một ngưỡng nào đó. Các nơron nối với nhau ở các synapses. Synapse được gọi là mạnh khi nó cho phép truyền dẫn dễ dàng tín hiệu qua các nơron khác. Ngược lại, một synapse yếu sẽ truyền dẫn tín hiệu rất khó khăn.
Các synapses đóng vai trò rất quan trọng trong sự học tập. Khi chúng ta học tập thì hoạt động của các synapses được tăng cường, tạo nên nhiều liên kết mạnh giữa các nơron. Có thể nói rằng người nào học càng giỏi thì càng có nhiều synapses và các synapses ấy càng mạnh mẽ, hay nói cách khác, thì liên kết giữa các nơron càng nhiều, càng nhạy bén. Hãy nhớ kỹ nguyên tắc này, vì chúng ta sẽ dùng nó trong việc học tập của các ANNs.



Phần 3. Mô hình nơron



Mô hình McCulloch-Pitts (1943)

Sau đây là mô hình của một nơron nhân tạo:

Nơron này sẽ hoạt động như sau: giả sử có N inputs, nơron sẽ có N weights (trọng số) tương ứng với N đường truyền inputs. Nơron sẽ lấy tổng cótrọng số của tất cả các inputs. Nói như thế có nghĩa là nơron sẽ lấy input thứ nhất, nhân với weight trên đường input thứ nhất, lấy input thứ hai nhân với weight của đường input thứ hai v.v..., rồi lấy tổng của tất cả các kết quả thu được. Đường truyền nào có weight càng lớn thì tín hiệu truyền qua đó càng lớn, như vậy có thể xem weight là đại lượng tương đương với synapse trong nơron sinh học. Có thể viết kết quả lấy tổng của nơron như sau:

Kết quả này sẽ được so sánh với threshold t của nơron, nếu nó lớn hơn t thì nơron cho output là 1, còn nếu nhỏ hơn thì output là 0. Ngoài ra ta cũng có thể trừ tổng nói trên cho t, rồi so sánh kết quả thu được với 0, nếu kết quả là dương thì nơron cho ouput bằng 1, nếu kết quả âm thì output là 0. Dưới dạng toán học ta có thể viết output của nơron như sau:

Trong đó f là hàm Heaviside:

f được gọi là threshold function hay transfer function của nơron, còn giá trị (-t) còn được gọi là bias hay offset của nơron.
Nếu chúng ta đưa thêm một input nữa vào, input thứ 0, có giá trị luôn luôn bằng 1 và weight luôn luôn bằng bias (-t) thì output của nơron còn có thể viết dưới dạng:

Lưu ý là chỉ số của tổng bây giờ bắt đầu từ 0 chứ không phải bằng 1 như trước nữa.
Nếu các bạn đã quen lập trình, thì các bạn chắc cũng nhận xét là chúng ta có thể dễ dàng viết một chương trình ngắn để mô phỏng hoạt động của nơron nhân tạo nói trên. Các bạn có kiến thức về điện tử cũng có thể tạo một mạch đơn giản để thực hiện một nơron nhân tạo.

Dạy nơron học như thế nào ?

Giả sử chúng ta muốn dạy nơron phân biệt chữ A và B. Khi đưa input là A chúng ta muốn nơron cho output là 1, còn khi input là B thì nơron phải cho output bằng 0.

Hình ảnh của hai chữ A và B có thể phân tích thành nhiều ô nhỏ như sau:
 
Các bạn cũng thấy là trong ví dụ trên mỗi chữ gồm 5x10=50 ô, mỗi ô có thể có chứa dấu x hay không chứa gì cả. Chúng ta có thể mã hóa một ô có chứa dấu x bằng số 1, và một ô trống bằng số 0. Như vậy mỗi chữ được mã hóa bằng một dãy 50 số 1 và 0. Nói cách khác, với mỗi chữ ta phải dùng 50 đường truyền để đưa 50 inputs là các số 0, 1 vào nơron.
Hãy bắt đầu bằng cách cho các weights những giá trị ngẫu nhiên, lúc này nơron chưa biết gì hết. Bây giờ hãy input chữ A. Nơron sẽ lấy tổng có trọng số của các inputs và so sánh kết quả với 0. Nếu kết quả dương thì output là 1, âm thì output là 0. Khả năng nơron đoán đúng là 50%, vì các weights đang có giá trị hoàn toàn ngẫu nhiên. Nếu nơron đoán đúng thì chúng ta không cần làm gì cả, nhưng khi nơron đoán sai (output bằng 0), thì chúng ta phải tăng các weights của các inputs đang hoạt động (các inputs khác không) lên, sao cho lần tới tổng có trọng số sẽ vượt quá threshold và tạo nên output là 1.
Ngược lại, khi đưa chữ B vào và nơron đoán sai (output bằng 1), thì ta phải giảm các weights của các inputs đang hoạt động xuống, sao cho lần tới tổng có trọng số sẽ nhỏ hơn threshold và buộc nơron phải cho output bằng 0.
Như vậy, khi dạy chữ B thành công rồi thì nơron có quên đi chữ đã học trước đó là A không ? Không, vì khi input là các chữ khác nhau thì nhóm các đường inputs đang hoạt động cũng khác nhau hoặc là không hoàn toàn trùng nhau. Nhớ là chúng ta chỉ biến đổi weights của các inputs đang hoạt động thôi. Chúng ta chỉ việc lập đi lập lại quá trình dạy như trên cho tới khi nơron học thuộc bài mới thôi.
Phương pháp dạy vừa rồi được gọi là Hebbian Learning, vì nó được Donald Hebb đề nghị năm 1949. Phương pháp dạy bằng cách biến đổi weights của các đường truyền này có làm bạn liên tưởng tới sự tăng cường các synapses trong bộ óc con người không ? Lưu ý là ta cũng có thể lập trình để thực hiện Hebbian Learning trên máy tính một cách dễ dàng.




Phần 4. Perceptron


Trong phần này, chúng ta sẽ áp dụng ngay những kiến thức vừa rồi cho một mạng nơron đơn giản là Perceptron, do Frank Rosenblatt đề nghị năm 1962. Perceptron là một mạng chỉ có một lớp nơron (lớp này có thể có một hay nhiều nơron), có cấu trúc như sau:


Tạo ra một Perceptron

Như đã nhận xét trong phần 3, chúng ta có thể lập trình để mô phỏng nơron nhân tạo và việc dạy học cho nơron. Trong MatLab ta có thể thực hiện điều đó tương đối dễ dàng. Trước hết hãy mở MatLab. Trong cửa sổ chính của MatLab (MatLab Command Window) bạn chỉ cần gõ dòng lệnh sau đây để tạo một Perceptron tên là net, có một nơron, và nhận input là một số có giá trị trong khoảng từ -1 đến 1:
net = newp([-1 1],1)
Trong MatLab [-1 1] là một ma trận một hàng và hai cột, có hai yếu tố là -1 và 1. Nếu muốn tạo một Perceptron có một nơron, nhận input là một cặp số, số thứ nhất có giá trị trong khoảng -1,1, và số thứ hai có giá trị trong khoảng 0,1, ta viết:
net = newp([-1 1;0 1],1)
Trong cách viết ma trận dấu ";" được dùng để tách các hàng, [-1 1;0 1] là một ma trận có hai hàng và hai cột, hàng thứ nhất chứa min, max của thành phần input thứ nhất, hàng thứ hai chứa min, max của thành phần input thứ hai:
-1 1
 0 1
Sau khi bạn kết thúc dòng lệnh và gõ Enter, MatLab sẽ tạo ra Perceptron, gán nó cho biến net và biểu thị các tính chất và biến số của mạng net. Tạm thời chúng ta không quan tâm tới các tính chất và biến số đó. Để MatLab không biểu thị chúng ra, ta chỉ cần thêm dấu ";" vào cuối dòng lệnh. Ví dụ, dòng lệnh sau đây sẽ tạo ra một perceptron có hai nơron, nhận input là một bộ ba số, mỗi số có min, max trong khoảng từ -10 đến 10, mà không biểu thị kết quả:
net = newp([-10 10;-10 10;-10 10],2);
Ngoài ra bạn có thể dùng ";" ở sau bất kỳ dòng lệnh nào trong MatLab để MatLab không biểu thị kết quả của dòng lệnh ấy ra. Trước khi tiếp tục các bạn hãy xóa biến net ra khỏi bộ nhớ, muốn thế hãy gõ:
clear net
Còn nếu muốn xóa tất cả các biến đang tồn tại trong bộ nhớ của MatLab, hãy dùng:
clear
Để xóa màn hình của Command Window bạn dùng:
clc
Khi bạn viết sai một câu lệnh và gõ Enter thì MatLab sẽ báo lỗi ngay. Tuy nhiên bạn không thể đưa con trỏ vào câu lệnh đó để sửa chữa đâu. Bạn phải nhấn nút mũi tên lên trên bàn phím để MatLab hiển thị lần lượt các câu lệnh đã gõ trước đó. Khi tới câu lệnh cần sửa đổi thì bạn ngừng lại để sửa.

Cho Perceptron hoạt động

Bây giờ trong MatLab Command Window các bạn hãy tạo một Perceptron có một nơron, nhận input là một số thay đổi trong khoảng từ -100 tới 100, và đặt tên cho nó là Bi:
Bi = newp([-100 100],1);
Perceptron Bi đang có các weights ngẫu nhiên, nó chưa có một kiến thức nào đặc biệt cả. Hãy đưa một số nào đó trong khoảng -100, 100, số 97 chẳng hạn, và xem nó cho output là gì:
y = sim(Bi,97)
Trong dòng lệnh vừa rồi, các bạn vừa bảo Bi nhận diện con số 97 bằng lệnh sim(Bi,97), gán output của Bi cho biến số y, và biểu thị y ra màn hình. Hãy thử bảo Bi nhận diện một số inputs khác xem sao.

Dạy Bi phân biệt các số âm, dương

Bây giờ chúng ta hãy dạy Bi phân biệt các số âm, dương trong khoảng -100, 100. Muốn thế trước hết ta chọn một bộ các số âm, dương làm ví dụ để dạy, chẳng hạn như bộ gồm hai số -2 và 65 sau đây:
examples = {-2 65}
Chúng ta muốn khi đưa một số âm thì Bi phải trả lời là 0, còn khi đưa một số dương thì nó phải trả lời là 1. Vì vậy ta cũng phải soạn một bộ lời giải tương ứng để dạy cho Bi. Trong trường hợp này bộ lời giải sẽ gồm hai số 0 và 1, lời giải 0 tương ứng với ví dụ -2 và lời giải 1 tương ứng với ví dụ 65:
answers = {0 1}
Để dạy cho Bi bộ ví dụ trên ta gõ như sau:
Bi = train(Bi,examples,answers);
Hàm train sẽ dùng bộ ví dụ examples và bộ lời giải answers để dạy cho Bi. Bi sẽ được dạy bộ ví dụ đó nhiều lần nếu cần thiết, cho tới chừng nào nó hết nhầm lẫn mới thôi. Trong MatLab mỗi vòng dạy qua tất cả các ví dụ được gọi là một epoch, còn sự nhầm lẫn của Bi được ước lượng bằng một đại lượng ký hiệu là MAE (Mean Average Error).
Bây giờ Bi đã học bài xong, ta hãy thử tài của nó xem sao. Trước hết hãy xem nó có thuộc bài hay không bằng cách bảo nó phân loại trở lại các số trong bộ ví dụ:
y = sim(Bi,examples)
Cuối cùng hãy thử tài suy đoán của Bi bằng cách bảo nó phân loại các số không nằm trong bài học:
tests = {-78 45 35.3 -24.6 pi 0}
y = sim(Bi,tests)
Các bạn sẽ thấy Bi phân loại được hết các số vừa rồi, chỉ trừ trường hợp số 0, nó cho rằng 0 là số âm ! Nhưng tôi không trách nó đâu, vì số 0 là một số đặc biệt.

Bi học lý luận

Chắc các bạn đều biết phép toán logic OR, chúng ta sẽ dạy cho Bi phép toán đó. Cho một cặp số nằm trong khoảng 0,1, kết quả của phép toán OR được cho trong bảng sau:

OR01
001
111

Bộ ví dụ sẽ gồm 4 cặp số, mỗi cặp được cho dưới dạng một ma trận hai hàng, một cột. Do đó trước hết Bi phải được trang bị để có thể đọc các inputs gồm 2 số. Ngoài ra, bộ lời giải sẽ gồm 4 số 0,1 tương ứng với từng trường hợp trong bộ ví dụ. Ta gõ lần lượt các dòng lệnh sau:
clear
clc
Bi = newp([0 1;0 1],1);
examples = {[0;0] [0;1] [1;0] [1;1]}
answers = {0 1 1 1}
Bạn hãy dạy cho Bi bằng bộ ví dụ và bộ lời giải trên. Sau đó hãy ôn lại bài và thử tài suy đoán của Bi bằng cách làm nhiễu các inputs một chút như sau:
tests = {[0.01;0] [0;0.96] [1;0.01] [0.95;0.96]}

Một bài học lý luận khác

Bi giỏi quá phải không các bạn ? Các bạn hãy thử dạy Bi phép toán logic XOR (Exclusive OR) xem sao. Sau đây là bảng giá trị của XOR:

XOR01
001
110

Nếu cần bạn có thể tăng số vòng dạy (epochs) lên, để ấn định số epochs là 500 chẳng hạn bạn dùng dòng lệnh sau:
Bi.trainParam.epochs = 500;
Nếu bạn đã quen với cách lập trình định hướng đối tượng (object-oriented) thì có lẽ cách viết như trên rất quen thuộc với bạn. Bi là một Perceptron, các thông số dạy học trainParam là một thuộc tính của Bi, vì vậy để xem xét các thông số ấy ta viết:
Bi.trainParam
Số các vòng dạy epochs lại là một yếu tố trong các thông số dạy học trainParam, vì thế để biết giá trị của epochs ta dùng dấu "." thêm một lần nữa:
Bi.trainParam.epochs